1 /*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 #include "settings.h"
10 // KWin
11 #include "decorationbridge.h"
12 #include "composite.h"
13 #include "virtualdesktops.h"
14 #include "workspace.h"
15 #include "appmenu.h"
16
17 #include <config-kwin.h>
18
19 #include <KDecoration2/DecorationSettings>
20
21 #include <KConfigGroup>
22
23 #include <QFontDatabase>
24
25 namespace KWin
26 {
27 namespace Decoration
28 {
SettingsImpl(KDecoration2::DecorationSettings * parent)29 SettingsImpl::SettingsImpl(KDecoration2::DecorationSettings *parent)
30 : QObject()
31 , DecorationSettingsPrivate(parent)
32 , m_borderSize(KDecoration2::BorderSize::Normal)
33 {
34 readSettings();
35
36 auto c = connect(Compositor::self(), &Compositor::compositingToggled,
37 parent, &KDecoration2::DecorationSettings::alphaChannelSupportedChanged);
38 connect(VirtualDesktopManager::self(), &VirtualDesktopManager::countChanged, this,
39 [parent](uint previous, uint current) {
40 if (previous != 1 && current != 1) {
41 return;
42 }
43 Q_EMIT parent->onAllDesktopsAvailableChanged(current > 1);
44 }
45 );
46 // prevent changes in Decoration due to Compositor being destroyed
47 connect(Compositor::self(), &Compositor::aboutToDestroy, this,
48 [c] { disconnect(c); }
49 );
50 connect(Workspace::self(), &Workspace::configChanged, this, &SettingsImpl::readSettings);
51 connect(DecorationBridge::self(), &DecorationBridge::metaDataLoaded, this, &SettingsImpl::readSettings);
52 }
53
54 SettingsImpl::~SettingsImpl() = default;
55
isAlphaChannelSupported() const56 bool SettingsImpl::isAlphaChannelSupported() const
57 {
58 return Compositor::self()->compositing();
59 }
60
isOnAllDesktopsAvailable() const61 bool SettingsImpl::isOnAllDesktopsAvailable() const
62 {
63 return VirtualDesktopManager::self()->count() > 1;
64 }
65
isCloseOnDoubleClickOnMenu() const66 bool SettingsImpl::isCloseOnDoubleClickOnMenu() const
67 {
68 return m_closeDoubleClickMenu;
69 }
70
71 static QHash<KDecoration2::DecorationButtonType, QChar> s_buttonNames;
initButtons()72 static void initButtons()
73 {
74 if (!s_buttonNames.isEmpty()) {
75 return;
76 }
77 s_buttonNames[KDecoration2::DecorationButtonType::Menu] = QChar('M');
78 s_buttonNames[KDecoration2::DecorationButtonType::ApplicationMenu] = QChar('N');
79 s_buttonNames[KDecoration2::DecorationButtonType::OnAllDesktops] = QChar('S');
80 s_buttonNames[KDecoration2::DecorationButtonType::ContextHelp] = QChar('H');
81 s_buttonNames[KDecoration2::DecorationButtonType::Minimize] = QChar('I');
82 s_buttonNames[KDecoration2::DecorationButtonType::Maximize] = QChar('A');
83 s_buttonNames[KDecoration2::DecorationButtonType::Close] = QChar('X');
84 s_buttonNames[KDecoration2::DecorationButtonType::KeepAbove] = QChar('F');
85 s_buttonNames[KDecoration2::DecorationButtonType::KeepBelow] = QChar('B');
86 s_buttonNames[KDecoration2::DecorationButtonType::Shade] = QChar('L');
87 }
88
buttonsToString(const QVector<KDecoration2::DecorationButtonType> & buttons)89 static QString buttonsToString(const QVector<KDecoration2::DecorationButtonType> &buttons)
90 {
91 auto buttonToString = [](KDecoration2::DecorationButtonType button) -> QChar {
92 const auto it = s_buttonNames.constFind(button);
93 if (it != s_buttonNames.constEnd()) {
94 return it.value();
95 }
96 return QChar();
97 };
98 QString ret;
99 for (auto button : buttons) {
100 ret.append(buttonToString(button));
101 }
102 return ret;
103 }
104
readDecorationButtons(const KConfigGroup & config,const char * key,const QVector<KDecoration2::DecorationButtonType> & defaultValue) const105 QVector< KDecoration2::DecorationButtonType > SettingsImpl::readDecorationButtons(const KConfigGroup &config,
106 const char *key,
107 const QVector< KDecoration2::DecorationButtonType > &defaultValue) const
108 {
109 initButtons();
110 auto buttonsFromString = [](const QString &buttons) -> QVector<KDecoration2::DecorationButtonType> {
111 QVector<KDecoration2::DecorationButtonType> ret;
112 for (auto it = buttons.begin(); it != buttons.end(); ++it) {
113 for (auto it2 = s_buttonNames.constBegin(); it2 != s_buttonNames.constEnd(); ++it2) {
114 if (it2.value() == (*it)) {
115 ret << it2.key();
116 }
117 }
118 }
119 return ret;
120 };
121 return buttonsFromString(config.readEntry(key, buttonsToString(defaultValue)));
122 }
123
stringToSize(const QString & name)124 static KDecoration2::BorderSize stringToSize(const QString &name)
125 {
126 static const QMap<QString, KDecoration2::BorderSize> s_sizes = QMap<QString, KDecoration2::BorderSize>({
127 {QStringLiteral("None"), KDecoration2::BorderSize::None},
128 {QStringLiteral("NoSides"), KDecoration2::BorderSize::NoSides},
129 {QStringLiteral("Tiny"), KDecoration2::BorderSize::Tiny},
130 {QStringLiteral("Normal"), KDecoration2::BorderSize::Normal},
131 {QStringLiteral("Large"), KDecoration2::BorderSize::Large},
132 {QStringLiteral("VeryLarge"), KDecoration2::BorderSize::VeryLarge},
133 {QStringLiteral("Huge"), KDecoration2::BorderSize::Huge},
134 {QStringLiteral("VeryHuge"), KDecoration2::BorderSize::VeryHuge},
135 {QStringLiteral("Oversized"), KDecoration2::BorderSize::Oversized}
136 });
137 auto it = s_sizes.constFind(name);
138 if (it == s_sizes.constEnd()) {
139 // non sense values are interpreted just like normal
140 return KDecoration2::BorderSize::Normal;
141 }
142 return it.value();
143 }
144
readSettings()145 void SettingsImpl::readSettings()
146 {
147 KConfigGroup config = kwinApp()->config()->group(QStringLiteral("org.kde.kdecoration2"));
148 const auto &left = readDecorationButtons(config, "ButtonsOnLeft", QVector<KDecoration2::DecorationButtonType >({
149 KDecoration2::DecorationButtonType::Menu,
150 KDecoration2::DecorationButtonType::OnAllDesktops
151 }));
152 if (left != m_leftButtons) {
153 m_leftButtons = left;
154 Q_EMIT decorationSettings()->decorationButtonsLeftChanged(m_leftButtons);
155 }
156 const auto &right = readDecorationButtons(config, "ButtonsOnRight", QVector<KDecoration2::DecorationButtonType >({
157 KDecoration2::DecorationButtonType::ContextHelp,
158 KDecoration2::DecorationButtonType::Minimize,
159 KDecoration2::DecorationButtonType::Maximize,
160 KDecoration2::DecorationButtonType::Close
161 }));
162 if (right != m_rightButtons) {
163 m_rightButtons = right;
164 Q_EMIT decorationSettings()->decorationButtonsRightChanged(m_rightButtons);
165 }
166 ApplicationMenu::self()->setViewEnabled(left.contains(KDecoration2::DecorationButtonType::ApplicationMenu) || right.contains(KDecoration2::DecorationButtonType::ApplicationMenu));
167 const bool close = config.readEntry("CloseOnDoubleClickOnMenu", false);
168 if (close != m_closeDoubleClickMenu) {
169 m_closeDoubleClickMenu = close;
170 Q_EMIT decorationSettings()->closeOnDoubleClickOnMenuChanged(m_closeDoubleClickMenu);
171 }
172 m_autoBorderSize = config.readEntry("BorderSizeAuto", true);
173
174 auto size = stringToSize(config.readEntry("BorderSize", QStringLiteral("Normal")));
175 if (m_autoBorderSize) {
176 /* Falls back to Normal border size, if the plugin does not provide a valid recommendation. */
177 size = stringToSize(DecorationBridge::self()->recommendedBorderSize());
178 }
179 if (size != m_borderSize) {
180 m_borderSize = size;
181 Q_EMIT decorationSettings()->borderSizeChanged(m_borderSize);
182 }
183 const QFont font = QFontDatabase::systemFont(QFontDatabase::TitleFont);
184 if (font != m_font) {
185 m_font = font;
186 Q_EMIT decorationSettings()->fontChanged(m_font);
187 }
188
189 Q_EMIT decorationSettings()->reconfigured();
190 }
191
192 }
193 }
194