500 lines
14 KiB
C++
500 lines
14 KiB
C++
/*
|
|
Library for Aurorae window decoration themes.
|
|
SPDX-FileCopyrightText: 2009, 2010, 2012 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
#include "auroraetheme.h"
|
|
#include "themeconfig.h"
|
|
// Qt
|
|
#include <QDebug>
|
|
#include <QHash>
|
|
#include <QStandardPaths>
|
|
// KDE
|
|
#include <KConfig>
|
|
#include <KConfigGroup>
|
|
|
|
Q_LOGGING_CATEGORY(AURORAE, "aurorae", QtCriticalMsg)
|
|
|
|
namespace Aurorae {
|
|
|
|
/************************************************
|
|
* AuroraeThemePrivate
|
|
************************************************/
|
|
class AuroraeThemePrivate
|
|
{
|
|
public:
|
|
AuroraeThemePrivate();
|
|
~AuroraeThemePrivate();
|
|
void initButtonFrame(AuroraeButtonType type);
|
|
QString themeName;
|
|
Aurorae::ThemeConfig themeConfig;
|
|
QHash< AuroraeButtonType, QString > pathes;
|
|
bool activeCompositing;
|
|
KDecoration2::BorderSize borderSize;
|
|
KDecoration2::BorderSize buttonSize;
|
|
QString dragMimeType;
|
|
QString decorationPath;
|
|
};
|
|
|
|
AuroraeThemePrivate::AuroraeThemePrivate()
|
|
:activeCompositing(true)
|
|
, borderSize(KDecoration2::BorderSize::Normal)
|
|
, buttonSize(KDecoration2::BorderSize::Normal)
|
|
{
|
|
}
|
|
|
|
AuroraeThemePrivate::~AuroraeThemePrivate()
|
|
{
|
|
}
|
|
|
|
void AuroraeThemePrivate::initButtonFrame(AuroraeButtonType type)
|
|
{
|
|
QString file(QLatin1String("aurorae/themes/") + themeName + QLatin1Char('/') + AuroraeTheme::mapButtonToName(type) + QLatin1String(".svg"));
|
|
QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
|
|
if (path.isEmpty()) {
|
|
// let's look for svgz
|
|
file += QLatin1String("z");
|
|
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
|
|
}
|
|
if (!path.isEmpty()) {
|
|
pathes[ type ] = path;
|
|
} else {
|
|
qCDebug(AURORAE) << "No button for: " << AuroraeTheme::mapButtonToName(type);
|
|
}
|
|
}
|
|
|
|
/************************************************
|
|
* AuroraeTheme
|
|
************************************************/
|
|
AuroraeTheme::AuroraeTheme(QObject* parent)
|
|
: QObject(parent)
|
|
, d(new AuroraeThemePrivate)
|
|
{
|
|
connect(this, &AuroraeTheme::themeChanged, this, &AuroraeTheme::borderSizesChanged);
|
|
connect(this, &AuroraeTheme::buttonSizesChanged, this, &AuroraeTheme::borderSizesChanged);
|
|
}
|
|
|
|
AuroraeTheme::~AuroraeTheme()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
bool AuroraeTheme::isValid() const
|
|
{
|
|
return !d->themeName.isNull();
|
|
}
|
|
|
|
void AuroraeTheme::loadTheme(const QString &name)
|
|
{
|
|
KConfig conf(QStringLiteral("auroraerc"));
|
|
KConfig config(QLatin1String("aurorae/themes/") + name + QLatin1Char('/') + name + QLatin1String("rc"),
|
|
KConfig::FullConfig, QStandardPaths::GenericDataLocation);
|
|
KConfigGroup themeGroup(&conf, name);
|
|
loadTheme(name, config);
|
|
}
|
|
|
|
void AuroraeTheme::loadTheme(const QString &name, const KConfig &config)
|
|
{
|
|
d->themeName = name;
|
|
QString file(QLatin1String("aurorae/themes/") + d->themeName + QLatin1String("/decoration.svg"));
|
|
QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
|
|
if (path.isEmpty()) {
|
|
file += QLatin1String("z");
|
|
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file);
|
|
}
|
|
if (path.isEmpty()) {
|
|
qCDebug(AURORAE) << "Could not find decoration svg: aborting";
|
|
d->themeName.clear();
|
|
return;
|
|
}
|
|
d->decorationPath = path;
|
|
|
|
// load the buttons
|
|
d->initButtonFrame(MinimizeButton);
|
|
d->initButtonFrame(MaximizeButton);
|
|
d->initButtonFrame(RestoreButton);
|
|
d->initButtonFrame(CloseButton);
|
|
d->initButtonFrame(AllDesktopsButton);
|
|
d->initButtonFrame(KeepAboveButton);
|
|
d->initButtonFrame(KeepBelowButton);
|
|
d->initButtonFrame(ShadeButton);
|
|
d->initButtonFrame(HelpButton);
|
|
|
|
d->themeConfig.load(config);
|
|
emit themeChanged();
|
|
}
|
|
|
|
bool AuroraeTheme::hasButton(AuroraeButtonType button) const
|
|
{
|
|
return d->pathes.contains(button);
|
|
}
|
|
|
|
QLatin1String AuroraeTheme::mapButtonToName(AuroraeButtonType type)
|
|
{
|
|
switch(type) {
|
|
case MinimizeButton:
|
|
return QLatin1String("minimize");
|
|
case MaximizeButton:
|
|
return QLatin1String("maximize");
|
|
case RestoreButton:
|
|
return QLatin1String("restore");
|
|
case CloseButton:
|
|
return QLatin1String("close");
|
|
case AllDesktopsButton:
|
|
return QLatin1String("alldesktops");
|
|
case KeepAboveButton:
|
|
return QLatin1String("keepabove");
|
|
case KeepBelowButton:
|
|
return QLatin1String("keepbelow");
|
|
case ShadeButton:
|
|
return QLatin1String("shade");
|
|
case HelpButton:
|
|
return QLatin1String("help");
|
|
case MenuButton:
|
|
return QLatin1String("menu");
|
|
case AppMenuButton:
|
|
return QLatin1String("appmenu");
|
|
default:
|
|
return QLatin1String("");
|
|
}
|
|
}
|
|
|
|
const QString &AuroraeTheme::themeName() const
|
|
{
|
|
return d->themeName;
|
|
}
|
|
|
|
void AuroraeTheme::borders(int& left, int& top, int& right, int& bottom, bool maximized) const
|
|
{
|
|
const qreal titleHeight = qMax((qreal)d->themeConfig.titleHeight(),
|
|
d->themeConfig.buttonHeight()*buttonSizeFactor() +
|
|
d->themeConfig.buttonMarginTop());
|
|
if (maximized) {
|
|
const qreal title = titleHeight + d->themeConfig.titleEdgeTopMaximized() + d->themeConfig.titleEdgeBottomMaximized();
|
|
switch ((DecorationPosition)d->themeConfig.decorationPosition()) {
|
|
case DecorationTop:
|
|
left = right = bottom = 0;
|
|
top = title;
|
|
break;
|
|
case DecorationBottom:
|
|
left = right = top = 0;
|
|
bottom = title;
|
|
break;
|
|
case DecorationLeft:
|
|
top = right = bottom = 0;
|
|
left = title;
|
|
break;
|
|
case DecorationRight:
|
|
left = top = bottom = 0;
|
|
right = title;
|
|
break;
|
|
default:
|
|
left = right = bottom = top = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
int minMargin;
|
|
int maxMargin;
|
|
switch (d->borderSize) {
|
|
case KDecoration2::BorderSize::NoSides:
|
|
case KDecoration2::BorderSize::Tiny:
|
|
minMargin = 1;
|
|
maxMargin = 4;
|
|
break;
|
|
case KDecoration2::BorderSize::Normal:
|
|
minMargin = 4;
|
|
maxMargin = 6;
|
|
break;
|
|
case KDecoration2::BorderSize::Large:
|
|
minMargin = 6;
|
|
maxMargin = 8;
|
|
break;
|
|
case KDecoration2::BorderSize::VeryLarge:
|
|
minMargin = 8;
|
|
maxMargin = 12;
|
|
break;
|
|
case KDecoration2::BorderSize::Huge:
|
|
minMargin = 12;
|
|
maxMargin = 20;
|
|
break;
|
|
case KDecoration2::BorderSize::VeryHuge:
|
|
minMargin = 23;
|
|
maxMargin = 30;
|
|
break;
|
|
case KDecoration2::BorderSize::Oversized:
|
|
minMargin = 36;
|
|
maxMargin = 48;
|
|
break;
|
|
default:
|
|
minMargin = 0;
|
|
maxMargin = 0;
|
|
}
|
|
|
|
left = qBound(minMargin, d->themeConfig.borderLeft(), maxMargin);
|
|
right = qBound(minMargin, d->themeConfig.borderRight(), maxMargin);
|
|
bottom = qBound(minMargin, d->themeConfig.borderBottom(), maxMargin);
|
|
|
|
if (d->borderSize == KDecoration2::BorderSize::None) {
|
|
left = 0;
|
|
right = 0;
|
|
bottom = 0;
|
|
} else if (d->borderSize == KDecoration2::BorderSize::NoSides) {
|
|
left = 0;
|
|
right = 0;
|
|
}
|
|
|
|
const qreal title = titleHeight + d->themeConfig.titleEdgeTop() + d->themeConfig.titleEdgeBottom();
|
|
switch ((DecorationPosition)d->themeConfig.decorationPosition()) {
|
|
case DecorationTop:
|
|
top = title;
|
|
break;
|
|
case DecorationBottom:
|
|
bottom = title;
|
|
break;
|
|
case DecorationLeft:
|
|
left = title;
|
|
break;
|
|
case DecorationRight:
|
|
right = title;
|
|
break;
|
|
default:
|
|
left = right = bottom = top = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int AuroraeTheme::bottomBorder() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, false);
|
|
return bottom;
|
|
}
|
|
|
|
int AuroraeTheme::leftBorder() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, false);
|
|
return left;
|
|
}
|
|
|
|
int AuroraeTheme::rightBorder() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, false);
|
|
return right;
|
|
}
|
|
|
|
int AuroraeTheme::topBorder() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, false);
|
|
return top;
|
|
}
|
|
|
|
int AuroraeTheme::bottomBorderMaximized() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, true);
|
|
return bottom;
|
|
}
|
|
|
|
int AuroraeTheme::leftBorderMaximized() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, true);
|
|
return left;
|
|
}
|
|
|
|
int AuroraeTheme::rightBorderMaximized() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, true);
|
|
return right;
|
|
}
|
|
|
|
int AuroraeTheme::topBorderMaximized() const
|
|
{
|
|
int left, top, right, bottom;
|
|
left = top = right = bottom = 0;
|
|
borders(left, top, right, bottom, true);
|
|
return top;
|
|
}
|
|
|
|
void AuroraeTheme::padding(int& left, int& top, int& right, int& bottom) const
|
|
{
|
|
left = d->themeConfig.paddingLeft();
|
|
top = d->themeConfig.paddingTop();
|
|
right = d->themeConfig.paddingRight();
|
|
bottom = d->themeConfig.paddingBottom();
|
|
}
|
|
|
|
#define THEME_CONFIG( prototype ) \
|
|
int AuroraeTheme::prototype ( ) const \
|
|
{ \
|
|
return d->themeConfig.prototype( ); \
|
|
}
|
|
|
|
THEME_CONFIG(paddingBottom)
|
|
THEME_CONFIG(paddingLeft)
|
|
THEME_CONFIG(paddingRight)
|
|
THEME_CONFIG(paddingTop)
|
|
THEME_CONFIG(buttonWidth)
|
|
THEME_CONFIG(buttonWidthMinimize)
|
|
THEME_CONFIG(buttonWidthMaximizeRestore)
|
|
THEME_CONFIG(buttonWidthClose)
|
|
THEME_CONFIG(buttonWidthAllDesktops)
|
|
THEME_CONFIG(buttonWidthKeepAbove)
|
|
THEME_CONFIG(buttonWidthKeepBelow)
|
|
THEME_CONFIG(buttonWidthShade)
|
|
THEME_CONFIG(buttonWidthHelp)
|
|
THEME_CONFIG(buttonWidthMenu)
|
|
THEME_CONFIG(buttonWidthAppMenu)
|
|
THEME_CONFIG(buttonHeight)
|
|
THEME_CONFIG(buttonSpacing)
|
|
THEME_CONFIG(buttonMarginTop)
|
|
THEME_CONFIG(explicitButtonSpacer)
|
|
THEME_CONFIG(animationTime)
|
|
THEME_CONFIG(titleEdgeLeft)
|
|
THEME_CONFIG(titleEdgeRight)
|
|
THEME_CONFIG(titleEdgeTop)
|
|
THEME_CONFIG(titleEdgeLeftMaximized)
|
|
THEME_CONFIG(titleEdgeRightMaximized)
|
|
THEME_CONFIG(titleEdgeTopMaximized)
|
|
THEME_CONFIG(titleBorderLeft)
|
|
THEME_CONFIG(titleBorderRight)
|
|
THEME_CONFIG(titleHeight)
|
|
|
|
#undef THEME_CONFIG
|
|
|
|
#define THEME_CONFIG_TYPE( rettype, prototype ) \
|
|
rettype AuroraeTheme::prototype ( ) const \
|
|
{\
|
|
return d->themeConfig.prototype(); \
|
|
}
|
|
|
|
THEME_CONFIG_TYPE(QColor, activeTextColor)
|
|
THEME_CONFIG_TYPE(QColor, inactiveTextColor)
|
|
THEME_CONFIG_TYPE(Qt::Alignment, alignment)
|
|
THEME_CONFIG_TYPE(Qt::Alignment, verticalAlignment)
|
|
|
|
#undef THEME_CONFIG_TYPE
|
|
|
|
QString AuroraeTheme::decorationPath() const
|
|
{
|
|
return d->decorationPath;
|
|
}
|
|
|
|
#define BUTTON_PATH( prototype, buttonType ) \
|
|
QString AuroraeTheme::prototype ( ) const \
|
|
{ \
|
|
if (hasButton( buttonType )) { \
|
|
return d->pathes[ buttonType ]; \
|
|
} else { \
|
|
return QString(); \
|
|
} \
|
|
}\
|
|
|
|
BUTTON_PATH(minimizeButtonPath, MinimizeButton)
|
|
BUTTON_PATH(maximizeButtonPath, MaximizeButton)
|
|
BUTTON_PATH(restoreButtonPath, RestoreButton)
|
|
BUTTON_PATH(closeButtonPath, CloseButton)
|
|
BUTTON_PATH(allDesktopsButtonPath, AllDesktopsButton)
|
|
BUTTON_PATH(keepAboveButtonPath, KeepAboveButton)
|
|
BUTTON_PATH(keepBelowButtonPath, KeepBelowButton)
|
|
BUTTON_PATH(shadeButtonPath, ShadeButton)
|
|
BUTTON_PATH(helpButtonPath, HelpButton)
|
|
|
|
#undef BUTTON_PATH
|
|
|
|
void AuroraeTheme::titleEdges(int &left, int &top, int &right, int &bottom, bool maximized) const
|
|
{
|
|
if (maximized) {
|
|
left = d->themeConfig.titleEdgeLeftMaximized();
|
|
top = d->themeConfig.titleEdgeTopMaximized();
|
|
right = d->themeConfig.titleEdgeRightMaximized();
|
|
bottom = d->themeConfig.titleEdgeBottomMaximized();
|
|
} else {
|
|
left = d->themeConfig.titleEdgeLeft();
|
|
top = d->themeConfig.titleEdgeTop();
|
|
right = d->themeConfig.titleEdgeRight();
|
|
bottom = d->themeConfig.titleEdgeBottom();
|
|
}
|
|
}
|
|
|
|
bool AuroraeTheme::isCompositingActive() const
|
|
{
|
|
return d->activeCompositing;
|
|
}
|
|
|
|
void AuroraeTheme::setCompositingActive(bool active)
|
|
{
|
|
d->activeCompositing = active;
|
|
}
|
|
|
|
void AuroraeTheme::setBorderSize(KDecoration2::BorderSize size)
|
|
{
|
|
if (d->borderSize == size) {
|
|
return;
|
|
}
|
|
d->borderSize = size;
|
|
emit borderSizesChanged();
|
|
}
|
|
|
|
void AuroraeTheme::setButtonSize(KDecoration2::BorderSize size)
|
|
{
|
|
if (d->buttonSize == size) {
|
|
return;
|
|
}
|
|
d->buttonSize = size;
|
|
emit buttonSizesChanged();
|
|
}
|
|
|
|
void AuroraeTheme::setTabDragMimeType(const QString &mime)
|
|
{
|
|
d->dragMimeType = mime;
|
|
}
|
|
|
|
const QString &AuroraeTheme::tabDragMimeType() const
|
|
{
|
|
return d->dragMimeType;
|
|
}
|
|
|
|
qreal AuroraeTheme::buttonSizeFactor() const
|
|
{
|
|
switch (d->buttonSize) {
|
|
case KDecoration2::BorderSize::Tiny:
|
|
return 0.8;
|
|
case KDecoration2::BorderSize::Large:
|
|
return 1.2;
|
|
case KDecoration2::BorderSize::VeryLarge:
|
|
return 1.4;
|
|
case KDecoration2::BorderSize::Huge:
|
|
return 1.6;
|
|
case KDecoration2::BorderSize::VeryHuge:
|
|
return 1.8;
|
|
case KDecoration2::BorderSize::Oversized:
|
|
return 2.0;
|
|
case KDecoration2::BorderSize::Normal: // fall through
|
|
default:
|
|
return 1.0;
|
|
}
|
|
}
|
|
|
|
DecorationPosition AuroraeTheme::decorationPosition() const
|
|
{
|
|
return (DecorationPosition)d->themeConfig.decorationPosition();
|
|
}
|
|
|
|
} // namespace
|