1 /*
2 * SPDX-FileCopyrightText: 2019 Mikhail Zolotukhin <zomial@protonmail.com>
3 * SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7
8 #include <QDBusConnection>
9 #include <QDBusMessage>
10 #include <QFont>
11 #include <QGuiApplication>
12
13 #include <KColorScheme>
14 #include <KPluginFactory>
15
16 #include "gtkconfig.h"
17
18 K_PLUGIN_CLASS_WITH_JSON(GtkConfig, "gtkconfig.json")
19
GtkConfig(QObject * parent,const QVariantList &)20 GtkConfig::GtkConfig(QObject *parent, const QVariantList &)
21 : KDEDModule(parent)
22 , configValueProvider(new ConfigValueProvider())
23 , themePreviewer(new ThemePreviewer(this))
24 , kdeglobalsConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig()))
25 , kwinConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kwinrc"))))
26 , kcminputConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kcminputrc"))))
27 , breezeConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("breezerc"))))
28 {
29 QDBusConnection dbus = QDBusConnection::sessionBus();
30 dbus.registerService(QStringLiteral("org.kde.GtkConfig"));
31 dbus.registerObject(QStringLiteral("/GtkConfig"), this, QDBusConnection::ExportScriptableSlots);
32
33 connect(kdeglobalsConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKdeglobalsSettingsChange);
34 connect(kwinConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKWinSettingsChange);
35 connect(kcminputConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKCMInputSettingsChange);
36 connect(breezeConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onBreezeSettingsChange);
37
38 ConfigEditor::removeLegacyGtk2Strings();
39 applyAllSettings();
40 }
41
~GtkConfig()42 GtkConfig::~GtkConfig()
43 {
44 QDBusConnection dbus = QDBusConnection::sessionBus();
45 dbus.unregisterService(QStringLiteral("org.kde.GtkConfig"));
46 dbus.unregisterObject(QStringLiteral("/GtkConfig"));
47 }
48
setGtkTheme(const QString & themeName) const49 void GtkConfig::setGtkTheme(const QString &themeName) const
50 {
51 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-theme-name"), themeName);
52 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("gtk-theme"), themeName);
53 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-theme-name"), themeName);
54 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-theme-name"), themeName);
55 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Net/ThemeName"), themeName);
56
57 // Window decorations are part of the theme, in case of Breeze we inject custom ones from KWin
58 setWindowDecorationsAppearance();
59 }
60
gtkTheme() const61 QString GtkConfig::gtkTheme() const
62 {
63 return ConfigEditor::gtk3ConfigValueSettingsIni(QStringLiteral("gtk-theme-name"));
64 }
65
showGtkThemePreview(const QString & themeName) const66 void GtkConfig::showGtkThemePreview(const QString &themeName) const
67 {
68 themePreviewer->showGtk3App(themeName);
69 }
70
setFont() const71 void GtkConfig::setFont() const
72 {
73 const QString configFontName = configValueProvider->fontName();
74 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-font-name"), configFontName);
75 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("font-name"), configFontName);
76 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-font-name"), configFontName);
77 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-font-name"), configFontName);
78 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/FontName"), configFontName);
79 }
80
setIconTheme() const81 void GtkConfig::setIconTheme() const
82 {
83 const QString iconThemeName = configValueProvider->iconThemeName();
84 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-icon-theme-name"), iconThemeName);
85 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("icon-theme"), iconThemeName);
86 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-icon-theme-name"), iconThemeName);
87 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-icon-theme-name"), iconThemeName);
88 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Net/IconThemeName"), iconThemeName);
89 }
90
setCursorTheme() const91 void GtkConfig::setCursorTheme() const
92 {
93 const QString cursorThemeName = configValueProvider->cursorThemeName();
94 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-cursor-theme-name"), cursorThemeName);
95 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("cursor-theme"), cursorThemeName);
96 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-cursor-theme-name"), cursorThemeName);
97 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-cursor-theme-name"), cursorThemeName);
98 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/CursorThemeName"), cursorThemeName);
99 }
100
setCursorSize() const101 void GtkConfig::setCursorSize() const
102 {
103 const int cursorSize = configValueProvider->cursorSize();
104 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-cursor-theme-size"), cursorSize);
105 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("cursor-size"), cursorSize);
106 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-cursor-theme-size"), cursorSize);
107 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-cursor-theme-size"), cursorSize);
108 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/CursorThemeSize"), cursorSize);
109 }
110
setIconsOnButtons() const111 void GtkConfig::setIconsOnButtons() const
112 {
113 const bool iconsOnButtonsConfigValue = configValueProvider->iconsOnButtons();
114 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-button-images"), iconsOnButtonsConfigValue);
115 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-button-images"), iconsOnButtonsConfigValue);
116 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-button-images"), iconsOnButtonsConfigValue);
117 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/ButtonImages"), iconsOnButtonsConfigValue);
118 }
119
setIconsInMenus() const120 void GtkConfig::setIconsInMenus() const
121 {
122 const bool iconsInMenusConfigValue = configValueProvider->iconsInMenus();
123 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-menu-images"), iconsInMenusConfigValue);
124 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-menu-images"), iconsInMenusConfigValue);
125 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-menu-images"), iconsInMenusConfigValue);
126 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/MenuImages"), iconsInMenusConfigValue);
127 }
128
setToolbarStyle() const129 void GtkConfig::setToolbarStyle() const
130 {
131 const int toolbarStyle = configValueProvider->toolbarStyle();
132 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-toolbar-style"), toolbarStyle);
133 ConfigEditor::setGtkConfigValueGSettingsAsEnum(QStringLiteral("toolbar-style"), toolbarStyle);
134 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-toolbar-style"), toolbarStyle);
135 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-toolbar-style"), toolbarStyle);
136 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/ToolbarStyle"), toolbarStyle);
137 }
138
setScrollbarBehavior() const139 void GtkConfig::setScrollbarBehavior() const
140 {
141 const bool scrollbarBehavior = configValueProvider->scrollbarBehavior();
142 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-primary-button-warps-slider"), scrollbarBehavior);
143 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-primary-button-warps-slider"), scrollbarBehavior);
144 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-primary-button-warps-slider"), scrollbarBehavior);
145 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/PrimaryButtonWarpsSlider"), scrollbarBehavior);
146 }
147
setDarkThemePreference() const148 void GtkConfig::setDarkThemePreference() const
149 {
150 const bool preferDarkTheme = configValueProvider->preferDarkTheme();
151 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-application-prefer-dark-theme"), preferDarkTheme);
152 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-application-prefer-dark-theme"), preferDarkTheme);
153 }
154
setWindowDecorationsAppearance() const155 void GtkConfig::setWindowDecorationsAppearance() const
156 {
157 if (gtkTheme() == QStringLiteral("Breeze")) { // Only Breeze GTK supports custom decoration buttons
158 const auto windowDecorationsButtonsImages = configValueProvider->windowDecorationsButtonsImages();
159 ConfigEditor::setCustomClientSideDecorations(windowDecorationsButtonsImages);
160 } else {
161 ConfigEditor::disableCustomClientSideDecorations();
162 }
163 }
164
setWindowDecorationsButtonsOrder() const165 void GtkConfig::setWindowDecorationsButtonsOrder() const
166 {
167 const QString windowDecorationsButtonOrder = configValueProvider->windowDecorationsButtonsOrder();
168 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("button-layout"), windowDecorationsButtonOrder, QStringLiteral("org.gnome.desktop.wm.preferences"));
169 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-decoration-layout"), windowDecorationsButtonOrder);
170 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-decoration-layout"), windowDecorationsButtonOrder);
171 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/DecorationLayout"), windowDecorationsButtonOrder);
172 }
173
setEnableAnimations() const174 void GtkConfig::setEnableAnimations() const
175 {
176 const bool enableAnimations = configValueProvider->enableAnimations();
177 ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-enable-animations"), enableAnimations);
178 ConfigEditor::setGtkConfigValueGSettings(QStringLiteral("enable-animations"), enableAnimations);
179 ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-enable-animations"), enableAnimations);
180 ConfigEditor::setGtk4ConfigValueSettingsIni(QStringLiteral("gtk-enable-animations"), enableAnimations);
181 ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/EnableAnimations"), enableAnimations);
182 }
183
setColors() const184 void GtkConfig::setColors() const
185 {
186 const QMap<QString, QColor> colors = configValueProvider->colors();
187 ConfigEditor::setGtk3Colors(colors);
188 }
189
applyAllSettings() const190 void GtkConfig::applyAllSettings() const
191 {
192 setFont();
193 setIconTheme();
194 setCursorTheme();
195 setCursorSize();
196 setIconsOnButtons();
197 setIconsInMenus();
198 setToolbarStyle();
199 setScrollbarBehavior();
200 setDarkThemePreference();
201 setWindowDecorationsAppearance();
202 setWindowDecorationsButtonsOrder();
203 setEnableAnimations();
204 setColors();
205 }
206
onKdeglobalsSettingsChange(const KConfigGroup & group,const QByteArrayList & names) const207 void GtkConfig::onKdeglobalsSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const
208 {
209 if (group.name() == QStringLiteral("KDE")) {
210 if (names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
211 setEnableAnimations();
212 }
213 if (names.contains(QByteArrayLiteral("ShowIconsInMenuItems"))) {
214 setIconsInMenus();
215 }
216 if (names.contains(QByteArrayLiteral("ShowIconsOnPushButtons"))) {
217 setIconsOnButtons();
218 }
219 if (names.contains(QByteArrayLiteral("ScrollbarLeftClickNavigatesByPage"))) {
220 setScrollbarBehavior();
221 }
222 } else if (group.name() == QStringLiteral("Icons")) {
223 if (names.contains(QByteArrayLiteral("Theme"))) {
224 setIconTheme();
225 }
226 } else if (group.name() == QStringLiteral("General")) {
227 if (names.contains(QByteArrayLiteral("font"))) {
228 setFont();
229 }
230 if (names.contains(QByteArrayLiteral("ColorScheme")) || names.contains(QByteArrayLiteral("AccentColor"))) {
231 setColors();
232 setDarkThemePreference();
233 setWindowDecorationsAppearance(); // Decorations' color can depend on the current color scheme
234 }
235 } else if (group.name() == QStringLiteral("Toolbar style")) {
236 if (names.contains(QByteArrayLiteral("ToolButtonStyle"))) {
237 setToolbarStyle();
238 }
239 }
240 }
241
onKWinSettingsChange(const KConfigGroup & group,const QByteArrayList & names) const242 void GtkConfig::onKWinSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const
243 {
244 if (group.name() == QStringLiteral("org.kde.kdecoration2")) {
245 if (names.contains(QByteArrayLiteral("ButtonsOnRight")) //
246 || names.contains(QByteArrayLiteral("ButtonsOnLeft"))) {
247 setWindowDecorationsButtonsOrder();
248 }
249 if (names.contains(QByteArrayLiteral("theme"))) {
250 setWindowDecorationsAppearance();
251 }
252 }
253 }
254
onKCMInputSettingsChange(const KConfigGroup & group,const QByteArrayList & names) const255 void GtkConfig::onKCMInputSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const
256 {
257 if (group.name() == QStringLiteral("Mouse")) {
258 if (names.contains("cursorTheme")) {
259 setCursorTheme();
260 }
261 if (names.contains("cursorSize")) {
262 setCursorSize();
263 }
264 }
265 }
266
onBreezeSettingsChange(const KConfigGroup & group,const QByteArrayList & names) const267 void GtkConfig::onBreezeSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const
268 {
269 if (group.name() == QStringLiteral("Common") //
270 && names.contains("OutlineCloseButton")) {
271 setWindowDecorationsAppearance();
272 }
273 }
274
275 #include "gtkconfig.moc"
276