diff --git a/CMakeLists.txt b/CMakeLists.txt index 7712730..62447f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,51 +1,53 @@ project(kde-gtk-config) set(PROJECT_VERSION "5.18.80") cmake_minimum_required(VERSION 3.10) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${ECM_MODULE_PATH}) find_package(Qt5 REQUIRED NO_MODULE COMPONENTS DBus) find_package(KF5CoreAddons REQUIRED) find_package(KF5Config REQUIRED) +find_package(KF5ConfigWidgets REQUIRED) +find_package(KF5GuiAddons REQUIRED) find_package(KF5IconThemes REQUIRED) find_package(KF5DBusAddons REQUIRED) find_package(PkgConfig REQUIRED) find_package(GSettingSchemas REQUIRED) find_package(XSettingsd) pkg_check_modules(GTK+3 REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GTK+2 REQUIRED IMPORTED_TARGET gtk+-2.0) pkg_check_modules(GLib2 REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GObject REQUIRED IMPORTED_TARGET gobject-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) include(ECMSetupVersion) include(ECMInstallIcons) include(ECMMarkAsTest) include(GenerateExportHeader) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDEClangFormat) set_package_properties(XSettingsd PROPERTIES DESCRIPTION "XSettingsd daemon" TYPE RUNTIME PURPOSE "Allows GTK Config kded module to apply settings to GTK applications on the fly" ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake kded/config.h) add_subdirectory(gtkproxies) add_subdirectory(gtk3proxies) add_subdirectory(kded) add_subdirectory(kconf_update) add_subdirectory(color-reload-module) # add clang-format target for all our real source files file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h) kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/kconf_update/CMakeLists.txt b/kconf_update/CMakeLists.txt index bea9787..fa52889 100644 --- a/kconf_update/CMakeLists.txt +++ b/kconf_update/CMakeLists.txt @@ -1,37 +1,39 @@ add_executable(gtk_theme gtktheme.cpp) target_sources(gtk_theme PRIVATE ../kded/configeditor.cpp ) target_link_libraries(gtk_theme PRIVATE Qt5::Core KF5::ConfigCore + KF5::ConfigWidgets + KF5::GuiAddons PkgConfig::GIO PkgConfig::GObject ) target_include_directories(gtk_theme PRIVATE ../kded/ ) target_compile_definitions(gtk_theme PRIVATE QT_NO_SIGNALS_SLOTS_KEYWORDS ) install( TARGETS gtk_theme DESTINATION ${LIB_INSTALL_DIR}/kconf_update_bin/ ) install( FILES gtkconfig.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} ) diff --git a/kded/CMakeLists.txt b/kded/CMakeLists.txt index 96601c3..c3fe61e 100644 --- a/kded/CMakeLists.txt +++ b/kded/CMakeLists.txt @@ -1,32 +1,35 @@ set(kscreen_daemon_SRCS gtkconfig.cpp configeditor.cpp configvalueprovider.cpp themepreviewer.cpp ) add_library(gtkconfig MODULE ${kscreen_daemon_SRCS}) target_compile_definitions(gtkconfig PUBLIC -DQT_NO_SIGNALS_SLOTS_KEYWORDS ) target_include_directories(gtkconfig PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${GTK3_INCLUDE_DIRS} ) target_link_libraries(gtkconfig + PUBLIC Qt5::DBus KF5::CoreAddons KF5::ConfigCore + KF5::ConfigWidgets KF5::DBusAddons KF5::IconThemes PkgConfig::GTK+3 + KF5::GuiAddons PkgConfig::GIO PkgConfig::GObject ) install(TARGETS gtkconfig DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kded) diff --git a/kded/configeditor.cpp b/kded/configeditor.cpp index e044491..fb64beb 100644 --- a/kded/configeditor.cpp +++ b/kded/configeditor.cpp @@ -1,235 +1,293 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include +#include #include #include #include #include #include +#include +#include +#include #include #include +#include +#include #include #include #include #include #include "configeditor.h" void ConfigEditor::setGtk3ConfigValueGSettings(const QString ¶mName, const QVariant ¶mValue, const QString &category) { g_autoptr(GSettings) gsettings = g_settings_new(category.toUtf8().constData()); if (paramValue.type() == QVariant::Type::String) { g_settings_set_string(gsettings, paramName.toUtf8().constData(), paramValue.toString().toUtf8().constData()); } else if (paramValue.type() == QVariant::Type::Int) { g_settings_set_int(gsettings, paramName.toUtf8().constData(), paramValue.toInt()); } else if (paramValue.type() == QVariant::Type::Bool) { g_settings_set_boolean(gsettings, paramName.toUtf8().constData(), paramValue.toBool()); } } void ConfigEditor::setGtk3ConfigValueGSettingsAsEnum(const QString& paramName, int paramValue, const QString& category) { g_autoptr(GSettings) gsettings = g_settings_new(category.toUtf8().constData()); g_settings_set_enum(gsettings, paramName.toUtf8().constData(), paramValue); } void ConfigEditor::setGtk3ConfigValueSettingsIni(const QString ¶mName, const QVariant ¶mValue) { QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QString gtk3ConfigPath = configLocation + QStringLiteral("/gtk-3.0/settings.ini"); KSharedConfig::Ptr gtk3Config = KSharedConfig::openConfig(gtk3ConfigPath, KConfig::NoGlobals); KConfigGroup group = gtk3Config->group(QStringLiteral("Settings")); group.writeEntry(paramName, paramValue); group.sync(); } void ConfigEditor::setGtk3ConfigValueXSettingsd(const QString ¶mName, const QVariant ¶mValue) { QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QDir xsettingsdPath = configLocation + QStringLiteral("/xsettingsd"); if (!xsettingsdPath.exists()) { xsettingsdPath.mkpath(QStringLiteral(".")); } QString xSettingsdConfigPath = xsettingsdPath.path() + QStringLiteral("/xsettingsd.conf"); QFile xSettingsdConfig(xSettingsdConfigPath); QString xSettingsdConfigContents = readFileContents(xSettingsdConfig); replaceValueInXSettingsdContents(xSettingsdConfigContents, paramName, paramValue); xSettingsdConfig.remove(); xSettingsdConfig.open(QIODevice::WriteOnly | QIODevice::Text); xSettingsdConfig.write(xSettingsdConfigContents.toUtf8()); reloadXSettingsd(); } void ConfigEditor::setGtk2ConfigValue(const QString ¶mName, const QVariant ¶mValue) { QString gtkrcPath = qEnvironmentVariable("GTK2_RC_FILES", QDir::homePath() + QStringLiteral("/.gtkrc-2.0")); if (gtkrcPath.contains(QStringLiteral(":/"))) { // I.e. env variable contains multiple paths gtkrcPath = QDir::homePath() + QStringLiteral("/.gtkrc-2.0"); } QFile gtkrc(gtkrcPath); QString gtkrcContents = readFileContents(gtkrc); replaceValueInGtkrcContents(gtkrcContents, paramName, paramValue); gtkrc.remove(); gtkrc.open(QIODevice::WriteOnly | QIODevice::Text); gtkrc.write(gtkrcContents.toUtf8()); reloadGtk2Apps(); } +void ConfigEditor::setGtk3Colors(const QMap &colorsDefinitions) +{ + addImportStatementToGtkCssUserFile(); + modifyColorsCssFile(colorsDefinitions); + addGtkModule(QStringLiteral("colorreload-gtk-module")); +} + + QString ConfigEditor::gtk2ConfigValue(const QString& paramName) { QString gtkrcPath = QDir::homePath() + QStringLiteral("/.gtkrc-2.0"); QFile gtkrc(gtkrcPath); if (gtkrc.open(QIODevice::ReadWrite | QIODevice::Text)) { const QRegularExpression regExp(paramName + QStringLiteral("=[^\n]*($|\n)")); while (!gtkrc.atEnd()) { QString line = gtkrc.readLine(); if (line.contains(regExp)) { return line.split('"')[1]; } } } return QString(); } QString ConfigEditor::gtk3ConfigValueSettingsIni(const QString& paramName) { QString configLocation = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QString gtk3ConfigPath = configLocation + QStringLiteral("/gtk-3.0/settings.ini"); KSharedConfig::Ptr gtk3Config = KSharedConfig::openConfig(gtk3ConfigPath, KConfig::NoGlobals); KConfigGroup group = gtk3Config->group(QStringLiteral("Settings")); return group.readEntry(paramName); } void ConfigEditor::removeLegacyGtk2Strings() { QString gtkrcPath = QDir::homePath() + QStringLiteral("/.gtkrc-2.0"); QFile gtkrc(gtkrcPath); QString gtkrcContents = readFileContents(gtkrc); // Remove "include" lines // Example: // include "/usr/share/themes/Adwaita-dark/gtk-2.0/gtkrc" static const QRegularExpression includeRegExp(QStringLiteral("include .*\n")); gtkrcContents.remove(includeRegExp); // Remove redundant font config lines // Example: // style "user-font" // { // font_name="Noto Sans Regular" // } // widget_class "*" style "user-font" static const QRegularExpression userFontStyleRegexp(QStringLiteral("style(.|\n)*{(.|\n)*}\nwidget_class.*\"user-font\"")); gtkrcContents.remove(userFontStyleRegexp); gtkrc.remove(); gtkrc.open(QIODevice::WriteOnly | QIODevice::Text); gtkrc.write(gtkrcContents.toUtf8()); reloadGtk2Apps(); } +void ConfigEditor::addGtkModule(const QString& moduleName) +{ + const QString currentModulesString = gtk3ConfigValueSettingsIni(QStringLiteral("gtk-modules")); + + if (currentModulesString.contains(moduleName)) { + return; + } + + if (currentModulesString.isEmpty()) { // No modules + setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-modules"), moduleName); + } else { + setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-modules"), QStringLiteral("%1:%2").arg(currentModulesString, moduleName)); + } +} + +void ConfigEditor::addImportStatementToGtkCssUserFile() +{ + QString gtkCssPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/gtk-3.0/gtk.css"); + QFile gtkCss(gtkCssPath); + + if (gtkCss.open(QIODevice::ReadWrite)) { + QByteArray gtkCssContents = gtkCss.readAll(); + + static const QByteArray importStatement = QByteArrayLiteral("@import 'colors.css';"); + if (!gtkCssContents.contains(importStatement)) { + QTextStream gtkCssStream(>kCss); + gtkCssStream << importStatement; + } + } +} + +void ConfigEditor::modifyColorsCssFile(const QMap &colorsDefinitions) +{ + QString colorsCssPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/gtk-3.0/colors.css"); + QFile colorsCss(colorsCssPath); + + if (colorsCss.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QTextStream colorsCssStream(&colorsCss); + + for (auto it = colorsDefinitions.cbegin(); it != colorsDefinitions.cend(); it++) { + colorsCssStream << QStringLiteral("@define-color %1 %2;\n").arg(it.key(), it.value().name()); + } + } +} + QString ConfigEditor::readFileContents(QFile &file) { if (file.open(QIODevice::ReadWrite | QIODevice::Text)) { return file.readAll(); } else { return QString(); } } void ConfigEditor::replaceValueInGtkrcContents(QString >krcContents, const QString ¶mName, const QVariant ¶mValue) { const QRegularExpression regExp(paramName + QStringLiteral("=[^\n]*($|\n)")); QString newConfigString; if (paramValue.type() == QVariant::Type::String) { newConfigString = QStringLiteral("%1=\"%2\"\n").arg(paramName, paramValue.toString()); } else if (paramValue.type() == QVariant::Type::Bool) { // GTK2 does not support 'true' and 'false' as values newConfigString = QStringLiteral("%1=%2\n").arg(paramName, QString::number(paramValue.toInt())); } else { newConfigString = QStringLiteral("%1=%2\n").arg(paramName, paramValue.toString()); } if (gtkrcContents.contains(regExp)) { gtkrcContents.replace(regExp, newConfigString); } else { gtkrcContents = newConfigString + gtkrcContents; } } void ConfigEditor::replaceValueInXSettingsdContents(QString &xSettingsdContents, const QString ¶mName, const QVariant ¶mValue) { const QRegularExpression regExp(paramName + QStringLiteral(" [^\n]*($|\n)")); QString newConfigString; if (paramValue.type() == QVariant::Type::String) { newConfigString = QStringLiteral("%1 \"%2\"\n").arg(paramName, paramValue.toString()); } else if (paramValue.type() == QVariant::Type::Bool) { // XSettigsd does not support 'true' and 'false' as values newConfigString = QStringLiteral("%1 %2\n").arg(paramName, QString::number(paramValue.toInt())); } else { newConfigString = QStringLiteral("%1 %2\n").arg(paramName, paramValue.toString()); } if (xSettingsdContents.contains(regExp)) { xSettingsdContents.replace(regExp, newConfigString); } else { xSettingsdContents = newConfigString + xSettingsdContents; } } void ConfigEditor::reloadGtk2Apps() { QProcess::startDetached(QStandardPaths::findExecutable(QStringLiteral("reload_gtk_apps"))); } pid_t ConfigEditor::pidOfXSettingsd() { QProcess pidof; pidof.start(QStringLiteral("pidof"), QStringList() << QStringLiteral("-s") << QStringLiteral("xsettingsd")); pidof.waitForFinished(); QString xsettingsdPid = QString(pidof.readAllStandardOutput()).remove('\n'); return xsettingsdPid.toInt(); } void ConfigEditor::reloadXSettingsd() { pid_t xSettingsdPid = pidOfXSettingsd(); if (xSettingsdPid == 0) { QProcess::startDetached(QStandardPaths::findExecutable(QStringLiteral("xsettingsd"))); } else { kill(xSettingsdPid, SIGHUP); } } diff --git a/kded/configeditor.h b/kded/configeditor.h index 4c0a49b..b66e008 100644 --- a/kded/configeditor.h +++ b/kded/configeditor.h @@ -1,52 +1,59 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include +class QColor; class QFile; class QVariant; namespace ConfigEditor { void setGtk2ConfigValue(const QString ¶mName, const QVariant ¶mValue); void setGtk3ConfigValueGSettings(const QString ¶mName, const QVariant ¶mValue, const QString &category = QStringLiteral("org.gnome.desktop.interface")); void setGtk3ConfigValueGSettingsAsEnum(const QString ¶mName, int paramValue, const QString &category = QStringLiteral("org.gnome.desktop.interface")); void setGtk3ConfigValueSettingsIni(const QString ¶mName, const QVariant ¶mValue); void setGtk3ConfigValueXSettingsd(const QString ¶mName, const QVariant ¶mValue); + void setGtk3Colors(const QMap &colorsDefinitions); + QString gtk2ConfigValue(const QString& paramName); QString gtk3ConfigValueSettingsIni(const QString& paramName); void removeLegacyGtk2Strings(); + void addGtkModule(const QString &moduleName); + + void addImportStatementToGtkCssUserFile(); + void modifyColorsCssFile(const QMap &colorsDefinitions); void replaceValueInGtkrcContents(QString >krcContents, const QString ¶mName, const QVariant ¶mValue); void replaceValueInXSettingsdContents(QString &xSettingsdContents, const QString ¶mName, const QVariant ¶mValue); QString readFileContents(QFile >krc); void reloadGtk2Apps(); void reloadXSettingsd(); pid_t pidOfXSettingsd(); }; diff --git a/kded/configvalueprovider.cpp b/kded/configvalueprovider.cpp index dd8c936..e834102 100644 --- a/kded/configvalueprovider.cpp +++ b/kded/configvalueprovider.cpp @@ -1,211 +1,410 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include "configvalueprovider.h" ConfigValueProvider::ConfigValueProvider() : kdeglobalsConfig(KSharedConfig::openConfig(QStringLiteral("kdeglobals"))), inputConfig(KSharedConfig::openConfig(QStringLiteral("kcminputrc"))), kwinConfig(KSharedConfig::openConfig(QStringLiteral("kwinrc"))) { } QString ConfigValueProvider::fontName() const { static const QFont defaultFont(QStringLiteral("Noto Sans"), 10); KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("General")); QString fontAsString = configGroup.readEntry(QStringLiteral("font"), defaultFont.toString()); static QFont font; font.fromString(fontAsString); const QString fontStyle = fontStyleHelper(font); return font.family() + QStringLiteral(", ") + fontStyle + ' ' + QString::number(font.pointSize()); } QString ConfigValueProvider::fontStyleHelper(const QFont &font) const { // BUG: 333146 // Since Qt sometimes gives us wrong font style name, // we ought to use this big helper function to construct // the style ourselves. Some fonts will not work auto weight = font.weight(); QString result; if (weight > QFont::Normal) { if (weight >= QFont::Black) { result = QStringLiteral("Black"); } else if (weight >= QFont::ExtraBold) { result = QStringLiteral("Extra Bold"); } else if (weight >= QFont::Bold) { result = QStringLiteral("Bold"); } else if (weight >= QFont::DemiBold) { result = QStringLiteral("Demi Bold"); } else if (weight >= QFont::Medium) { result = QStringLiteral("Medium"); } } else { if (weight <= QFont::Thin) { result = QStringLiteral("Thin"); } else if (weight <= QFont::ExtraLight) { result = QStringLiteral("Extra Light"); } else if (weight <= QFont::Light) { result = QStringLiteral("Light"); } } auto style = font.style(); if (style == QFont::StyleItalic) { result += QLatin1Char(' ') + QStringLiteral("Italic"); } else if (style == QFont::StyleOblique) { result += QLatin1Char(' ') + QStringLiteral("Oblique"); } auto stretch = font.stretch(); if (stretch == QFont::UltraCondensed) { result += QLatin1Char(' ') + QStringLiteral("UltraCondensed"); } else if (stretch == QFont::ExtraCondensed) { result += QLatin1Char(' ') + QStringLiteral("ExtraCondensed"); } else if (stretch == QFont::Condensed) { result += QLatin1Char(' ') + QStringLiteral("Condensed"); } else if (stretch == QFont::SemiCondensed) { result += QLatin1Char(' ') + QStringLiteral("SemiCondensed"); } else if (stretch == QFont::Unstretched) { result += QLatin1Char(' ') + QStringLiteral("Unstretched"); } else if (stretch == QFont::SemiExpanded) { result += QLatin1Char(' ') + QStringLiteral("SemiExpanded"); } else if (stretch == QFont::Expanded) { result += QLatin1Char(' ') + QStringLiteral("Expanded"); } else if (stretch == QFont::ExtraExpanded) { result += QLatin1Char(' ') + QStringLiteral("ExtraExpanded"); } else if (stretch == QFont::UltraExpanded) { result += QLatin1Char(' ') + QStringLiteral("UltraExpanded"); } return result.simplified(); } QString ConfigValueProvider::iconThemeName() const { KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Icons")); return configGroup.readEntry(QStringLiteral("Theme"), QStringLiteral("breeze")); } QString ConfigValueProvider::cursorThemeName() const { KConfigGroup configGroup = inputConfig->group(QStringLiteral("Mouse")); return configGroup.readEntry(QStringLiteral("cursorTheme"), QStringLiteral("breeze_cursors")); } bool ConfigValueProvider::iconsOnButtons() const { KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE")); return configGroup.readEntry(QStringLiteral("ShowIconsOnPushButtons"), true); } bool ConfigValueProvider::iconsInMenus() const { KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE")); return configGroup.readEntry(QStringLiteral("ShowIconsInMenuItems"), true); } int ConfigValueProvider::toolbarStyle() const { KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Toolbar style")); QString kdeConfigValue = configGroup.readEntry(QStringLiteral("ToolButtonStyle"), "TextBesideIcon"); if (kdeConfigValue == QStringLiteral("NoText")) { return GtkToolbarStyle::GTK_TOOLBAR_ICONS; } else if (kdeConfigValue == QStringLiteral("TextOnly")) { return GtkToolbarStyle::GTK_TOOLBAR_TEXT; } else if (kdeConfigValue == QStringLiteral("TextBesideIcon")) { return GtkToolbarStyle::GTK_TOOLBAR_BOTH_HORIZ; } else { return GtkToolbarStyle::GTK_TOOLBAR_BOTH; } } bool ConfigValueProvider::scrollbarBehavior() const { KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE")); bool kdeConfigValue = configGroup.readEntry(QStringLiteral("ScrollbarLeftClickNavigatesByPage"), true); return !kdeConfigValue; // GTK setting is inverted } bool ConfigValueProvider::preferDarkTheme() const { KConfigGroup colorsConfigGroup = kdeglobalsConfig->group(QStringLiteral("Colors:Window")); QColor windowBackgroundColor = colorsConfigGroup.readEntry(QStringLiteral("BackgroundNormal"), QColor(239, 240, 241)); const int windowBackgroundGray = qGray(windowBackgroundColor.rgb()); // We use heuristic to determine if current color scheme is dark or not return windowBackgroundGray < 192; } QString ConfigValueProvider::windowDecorationsButtonsOrder() const { KConfigGroup configGroup = kwinConfig->group(QStringLiteral("org.kde.kdecoration2")); QString buttonsOnLeftKdeConfigValue = configGroup.readEntry(QStringLiteral("ButtonsOnLeft"), "MS"); QString buttonsOnRightKdeConfigValue = configGroup.readEntry(QStringLiteral("ButtonsOnRight"), "HIAX"); QString buttonsOnLeftInGtkNotation = windowDecorationButtonsOrderInGtkNotation(buttonsOnLeftKdeConfigValue); QString buttonsOnRightInGtkNotation = windowDecorationButtonsOrderInGtkNotation(buttonsOnRightKdeConfigValue); return buttonsOnLeftInGtkNotation + QStringLiteral(":") + buttonsOnRightInGtkNotation; } bool ConfigValueProvider::enableAnimations() const { KConfigGroup generalCfg = kdeglobalsConfig->group(QStringLiteral("KDE")); const qreal animationSpeedModifier = qMax(0.0, generalCfg.readEntry("AnimationDurationFactor", 1.0)); return !qFuzzyIsNull(animationSpeedModifier); } +QMap ConfigValueProvider::colors() const +{ + using KCS = KColorScheme; + + // Color Schemes Collection + QHash> csc { + {QStringLiteral("active"), { + {QStringLiteral("view"), KCS(QPalette::Active, KCS::View)}, + {QStringLiteral("window"), KCS(QPalette::Active, KCS::Window)}, + {QStringLiteral("button"), KCS(QPalette::Active, KCS::Button)}, + {QStringLiteral("selection"), KCS(QPalette::Active, KCS::Selection)}, + {QStringLiteral("tooltip"), KCS(QPalette::Active, KCS::Tooltip)}, + {QStringLiteral("complementary"), KCS(QPalette::Active, KCS::Complementary)}, + }}, + {QStringLiteral("inactive"), { + {QStringLiteral("view"), KCS(QPalette::Inactive, KCS::View)}, + {QStringLiteral("window"), KCS(QPalette::Inactive, KCS::Window)}, + {QStringLiteral("button"), KCS(QPalette::Inactive, KCS::Button)}, + {QStringLiteral("selection"), KCS(QPalette::Inactive, KCS::Selection)}, + {QStringLiteral("tooltip"), KCS(QPalette::Inactive, KCS::Tooltip)}, + {QStringLiteral("complementary"), KCS(QPalette::Inactive, KCS::Complementary)}, + }}, + {QStringLiteral("inactive"), { + {QStringLiteral("view"), KCS(QPalette::Disabled, KCS::View)}, + {QStringLiteral("window"), KCS(QPalette::Disabled, KCS::Window)}, + {QStringLiteral("button"), KCS(QPalette::Disabled, KCS::Button)}, + {QStringLiteral("selection"), KCS(QPalette::Disabled, KCS::Selection)}, + {QStringLiteral("tooltip"), KCS(QPalette::Disabled, KCS::Tooltip)}, + {QStringLiteral("complementary"), KCS(QPalette::Disabled, KCS::Complementary)}, + }}, + }; + + // Color mixing + QColor windowForegroundColor = csc["active"]["window"].foreground(KCS::NormalText).color(); + QColor windowBackgroundColor = csc["active"]["window"].background(KCS::NormalBackground).color(); + QColor bordersColor = KColorUtils::mix(windowBackgroundColor, windowForegroundColor, 0.25); + + QColor inactiveWindowForegroundColor = csc["inactive"]["window"].foreground(KCS::NormalText).color(); + QColor inactiveWindowBackgroundColor = csc["inactive"]["window"].background(KCS::NormalBackground).color(); + QColor inactiveBordersColor = KColorUtils::mix(inactiveWindowBackgroundColor, inactiveWindowForegroundColor, 0.25); + + QColor disabledWindowForegroundColor = csc["disabled"]["window"].foreground(KCS::NormalText).color(); + QColor disabledWindowBackgroundColor = csc["disabled"]["window"].background(KCS::NormalBackground).color(); + QColor disabledBordersColor = KColorUtils::mix(disabledWindowBackgroundColor, disabledWindowForegroundColor, 0.25); + + QColor unfocusedDisabledWindowForegroundColor = csc["disabled"]["window"].foreground(KCS::NormalText).color(); + QColor unfocusedDisabledWindowBackgroundColor = csc["disabled"]["window"].background(KCS::NormalBackground).color(); + QColor unfocusedDisabledBordersColor = KColorUtils::mix(unfocusedDisabledWindowBackgroundColor, unfocusedDisabledWindowForegroundColor, 0.25); + + QColor tooltipForegroundColor = csc["active"]["tooltip"].foreground(KCS::NormalText).color(); + QColor tooltipBackgroundColor = csc["active"]["tooltip"].background(KCS::NormalBackground).color(); + QColor tooltipBorderColor = KColorUtils::mix(tooltipBackgroundColor, tooltipForegroundColor, 0.25); + + KConfigGroup windowManagerConfig = kdeglobalsConfig->group(QStringLiteral("WM")); + + return { + /* + * Normal (Non Backdrop, Non Insensitive) + */ + + // General Colors + { "theme_fg_color_breeze", csc["active"]["window"].foreground(KCS::NormalText).color()}, + { "theme_bg_color_breeze", csc["active"]["window"].background(KCS::NormalBackground).color()}, + { "theme_text_color_breeze", csc["active"]["view"].foreground(KCS::NormalText).color()}, + { "theme_base_color_breeze", csc["active"]["view"].background(KCS::NormalBackground).color()}, + { "theme_view_hover_decoration_color_breeze", csc["active"]["view"].decoration(KCS::HoverColor).color()}, + { "theme_hovering_selected_bg_color_breeze", csc["active"]["selection"].decoration(KCS::HoverColor).color()}, + { "theme_selected_bg_color_breeze", csc["active"]["selection"].background(KCS::NormalBackground).color()}, + { "theme_selected_fg_color_breeze", csc["active"]["selection"].foreground(KCS::NormalText).color()}, + { "theme_view_active_decoration_color_breeze", csc["active"]["view"].decoration(KCS::HoverColor).color()}, + + // Button Colors + { "theme_button_background_normal_breeze", csc["active"]["button"].background(KCS::NormalBackground).color()}, + { "theme_button_decoration_hover_breeze", csc["active"]["button"].decoration(KCS::HoverColor).color()}, + { "theme_button_decoration_focus_breeze", csc["active"]["button"].decoration(KCS::FocusColor).color()}, + { "theme_button_foreground_normal_breeze", csc["active"]["button"].foreground(KCS::NormalText).color()}, + { "theme_button_foreground_active_breeze", csc["active"]["selection"].foreground(KCS::NormalText).color()}, + + + // Misc Colors + { "borders_breeze", bordersColor}, + { "warning_color_breeze", csc["active"]["view"].foreground(KCS::NeutralText).color()}, + { "success_color_breeze", csc["active"]["view"].foreground(KCS::PositiveText).color()}, + { "error_color_breeze", csc["active"]["view"].foreground(KCS::NegativeText).color()}, + + /* + * Backdrop (Inactive) + */ + + // General + { "theme_unfocused_fg_color_breeze", csc["inactive"]["window"].foreground(KCS::NormalText).color()}, + { "theme_unfocused_text_color_breeze", csc["inactive"]["view"].foreground(KCS::NormalText).color()}, + { "theme_unfocused_bg_color_breeze", csc["inactive"]["window"].background(KCS::NormalBackground).color()}, + { "theme_unfocused_base_color_breeze", csc["inactive"]["view"].background(KCS::NormalBackground).color()}, + { "theme_unfocused_selected_bg_color_alt_breeze", csc["inactive"]["selection"].background(KCS::NormalBackground).color()}, + { "theme_unfocused_selected_bg_color_breeze", csc["inactive"]["selection"].background(KCS::NormalBackground).color()}, + { "theme_unfocused_selected_fg_color_breeze", csc["inactive"]["selection"].foreground(KCS::NormalText).color()}, + + // Button + { "theme_button_background_backdrop_breeze", csc["inactive"]["button"].background(KCS::NormalBackground).color()}, + { "theme_button_decoration_hover_backdrop_breeze", csc["inactive"]["button"].decoration(KCS::HoverColor).color()}, + { "theme_button_decoration_focus_backdrop_breeze", csc["inactive"]["button"].decoration(KCS::FocusColor).color()}, + { "theme_button_foreground_backdrop_breeze", csc["inactive"]["button"].foreground(KCS::NormalText).color()}, + { "theme_button_foreground_active_backdrop_breeze", csc["inactive"]["selection"].foreground(KCS::NormalText).color()}, + + // Misc Colors + { "unfocused_borders_breeze", inactiveBordersColor}, + { "warning_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::NeutralText).color()}, + { "success_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::PositiveText).color()}, + { "error_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::NegativeText).color()}, + + /* + * Insensitive (Disabled) + */ + + // General + { "insensitive_fg_color_breeze",csc["disabled"]["window"].foreground(KCS::NormalText).color()}, + { "insensitive_base_fg_color_breeze", csc["disabled"]["view"].foreground(KCS::NormalText).color()}, + { "insensitive_bg_color_breeze", csc["disabled"]["window"].background(KCS::NormalBackground).color()}, + { "insensitive_base_color_breeze", csc["disabled"]["view"].background(KCS::NormalBackground).color()}, + { "insensitive_selected_bg_color_breeze", csc["disabled"]["selection"].background(KCS::NormalBackground).color()}, + { "insensitive_selected_fg_color_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()}, + + // Button + { "theme_button_background_insensitive_breeze", csc["disabled"]["button"].background(KCS::NormalBackground).color()}, + { "theme_button_decoration_hover_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::HoverColor).color()}, + { "theme_button_decoration_focus_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::FocusColor).color()}, + { "theme_button_foreground_insensitive_breeze", csc["disabled"]["button"].foreground(KCS::NormalText).color()}, + { "theme_button_foreground_active_insensitive_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()}, + + // Misc Colors + { "insensitive_borders_breeze", disabledBordersColor}, + { "warning_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::NeutralText).color()}, + { "success_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::PositiveText).color()}, + { "error_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::NegativeText).color()}, + + /* + * Insensitive Backdrop (Inactive Disabled) + * These pretty much have the same appearance as regular inactive colors, + * but they're separate in case we decide to make them different in the future. + */ + + // General + { "insensitive_unfocused_fg_color_breeze",csc["disabled"]["window"].foreground(KCS::NormalText).color()}, + { "theme_unfocused_view_text_color_breeze", csc["disabled"]["view"].foreground(KCS::NormalText).color()}, + { "insensitive_unfocused_bg_color_breeze", csc["disabled"]["window"].background(KCS::NormalBackground).color()}, + { "theme_unfocused_view_bg_color_breeze", csc["disabled"]["view"].background(KCS::NormalBackground).color()}, + { "insensitive_unfocused_selected_bg_color_breeze", csc["disabled"]["selection"].background(KCS::NormalBackground).color()}, + { "insensitive_unfocused_selected_fg_color_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()}, + + // Button + { "theme_button_background_backdrop_insensitive_breeze", csc["disabled"]["button"].background(KCS::NormalBackground).color()}, + { "theme_button_decoration_hover_backdrop_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::HoverColor).color()}, + { "theme_button_decoration_focus_backdrop_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::FocusColor).color()}, + { "theme_button_foreground_backdrop_insensitive_breeze", csc["disabled"]["button"].foreground(KCS::NormalText).color()}, + { "theme_button_foreground_active_backdrop_insensitive_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()}, + + // Misc Colors + { "unfocused_insensitive_borders_breeze", unfocusedDisabledBordersColor}, + { "warning_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::NeutralText).color()}, + { "success_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::PositiveText).color()}, + { "error_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::NegativeText).color()}, + + /* + * Ignorant Colors (These colors do not care about backdrop or insensitive states) + */ + + { "link_color_breeze", csc["active"]["view"].foreground(KCS::LinkText).color()}, + { "link_visited_color_breeze", csc["active"]["view"].foreground(KCS::VisitedText).color()}, + + { "tooltip_text_breeze", tooltipForegroundColor}, + { "tooltip_background_breeze", tooltipBackgroundColor}, + { "tooltip_border_breeze", tooltipBorderColor}, + + { "content_view_bg_breeze", csc["active"]["view"].background(KCS::NormalBackground).color()}, + + { "theme_titlebar_background_breeze", windowManagerConfig.readEntry("activeBackground", QColor())}, + { "theme_titlebar_foreground_breeze", windowManagerConfig.readEntry("activeForeground", QColor())}, + { "theme_titlebar_background_light_breeze", csc["active"]["window"].background(KCS::NormalBackground).color()}, + { "theme_titlebar_foreground_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + { "theme_titlebar_background_backdrop_breeze", windowManagerConfig.readEntry("inactiveBackground", QColor())}, + { "theme_titlebar_foreground_insensitive_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + { "theme_titlebar_foreground_insensitive_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + + // Titlebar colors + { "theme_titlebar_background_breeze", windowManagerConfig.readEntry("activeBackground", QColor())}, + { "theme_titlebar_foreground_breeze", windowManagerConfig.readEntry("activeForeground", QColor())}, + { "theme_titlebar_background_light_breeze", csc["active"]["window"].background(KCS::NormalBackground).color()}, + { "theme_titlebar_foreground_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + { "theme_titlebar_background_backdrop_breeze", windowManagerConfig.readEntry("inactiveBackground", QColor())}, + { "theme_titlebar_foreground_insensitive_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + { "theme_titlebar_foreground_insensitive_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())}, + }; +} + QString ConfigValueProvider::windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const { QString gtkNotation; for (const QChar &buttonAbbreviation : kdeConfigValue) { if (buttonAbbreviation == 'X') { gtkNotation += QStringLiteral("close,"); } else if (buttonAbbreviation == 'I') { gtkNotation += QStringLiteral("minimize,"); } else if (buttonAbbreviation == 'A') { gtkNotation += QStringLiteral("maximize,"); } else if (buttonAbbreviation == 'M') { gtkNotation += QStringLiteral("icon,"); } } gtkNotation.chop(1); return gtkNotation; } diff --git a/kded/configvalueprovider.h b/kded/configvalueprovider.h index c7ce153..89be610 100644 --- a/kded/configvalueprovider.h +++ b/kded/configvalueprovider.h @@ -1,51 +1,52 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include class QString; class QFont; class ConfigValueProvider { public: ConfigValueProvider(); QString fontName() const; QString iconThemeName() const; QString cursorThemeName() const; bool iconsOnButtons() const; bool iconsInMenus() const; int toolbarStyle() const; bool scrollbarBehavior() const; bool preferDarkTheme() const; QString windowDecorationsButtonsOrder() const; bool enableAnimations() const; + QMap colors() const; private: QString fontStyleHelper(const QFont &font) const; QString windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const; KSharedConfigPtr kdeglobalsConfig; KSharedConfigPtr inputConfig; KSharedConfigPtr kwinConfig; }; diff --git a/kded/gtkconfig.cpp b/kded/gtkconfig.cpp index 7e6392f..640bd13 100644 --- a/kded/gtkconfig.cpp +++ b/kded/gtkconfig.cpp @@ -1,243 +1,252 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * Copyright (C) 2019 Nicolas Fella * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include +#include #include "gtkconfig.h" #include "configvalueprovider.h" #include "themepreviewer.h" K_PLUGIN_CLASS_WITH_JSON(GtkConfig, "gtkconfig.json") GtkConfig::GtkConfig(QObject *parent, const QVariantList&) : KDEDModule(parent), configValueProvider(new ConfigValueProvider()), themePreviewer(new ThemePreviewer(this)), kdeglobalsConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kdeglobals")))), kwinConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kwinrc")))), kcminputConfigWatcher(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("kcminputrc")))) { QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerService(QStringLiteral("org.kde.GtkConfig")); dbus.registerObject(QStringLiteral("/GtkConfig"), this, QDBusConnection::ExportScriptableSlots); connect(kdeglobalsConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKdeglobalsSettingsChange); connect(kwinConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKWinSettingsChange); connect(kcminputConfigWatcher.data(), &KConfigWatcher::configChanged, this, &GtkConfig::onKCMInputSettingsChange); ConfigEditor::removeLegacyGtk2Strings(); applyAllSettings(); } GtkConfig::~GtkConfig() { QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.unregisterService(QStringLiteral("org.kde.GtkConfig")); dbus.unregisterObject(QStringLiteral("/GtkConfig")); } void GtkConfig::setGtk2Theme(const QString &themeName) const { ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-theme-name"), themeName); } void GtkConfig::setGtk3Theme(const QString &themeName) const { ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("gtk-theme"), themeName); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-theme-name"), themeName); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Net/ThemeName"), themeName); } QString GtkConfig::gtk2Theme() const { return ConfigEditor::gtk2ConfigValue(QStringLiteral("gtk-theme-name")); } QString GtkConfig::gtk3Theme() const { return ConfigEditor::gtk3ConfigValueSettingsIni(QStringLiteral("gtk-theme-name")); } void GtkConfig::showGtk2ThemePreview(const QString& themeName) const { themePreviewer->showGtk2App(themeName); } void GtkConfig::showGtk3ThemePreview(const QString& themeName) const { themePreviewer->showGtk3App(themeName); } void GtkConfig::setFont() const { const QString configFontName = configValueProvider->fontName(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-font-name"), configFontName); ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("font-name"), configFontName); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-font-name"), configFontName); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/FontName"), configFontName); } void GtkConfig::setIconTheme() const { const QString iconThemeName = configValueProvider->iconThemeName(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-icon-theme-name"), iconThemeName); ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("icon-theme"), iconThemeName); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-icon-theme-name"), iconThemeName); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Net/IconThemeName"), iconThemeName); } void GtkConfig::setCursorTheme() const { const QString cursorThemeName = configValueProvider->cursorThemeName(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-cursor-theme-name"), cursorThemeName); ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("cursor-theme"), cursorThemeName); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-cursor-theme-name"), cursorThemeName); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/CursorThemeName"), cursorThemeName); } void GtkConfig::setIconsOnButtons() const { const bool iconsOnButtonsConfigValue = configValueProvider->iconsOnButtons(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-button-images"), iconsOnButtonsConfigValue); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-button-images"), iconsOnButtonsConfigValue); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/ButtonImages"), iconsOnButtonsConfigValue); } void GtkConfig::setIconsInMenus() const { const bool iconsInMenusConfigValue = configValueProvider->iconsInMenus(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-menu-images"), iconsInMenusConfigValue); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-menu-images"), iconsInMenusConfigValue); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/MenuImages"), iconsInMenusConfigValue); } void GtkConfig::setToolbarStyle() const { const int toolbarStyle = configValueProvider->toolbarStyle(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-toolbar-style"), toolbarStyle); ConfigEditor::setGtk3ConfigValueGSettingsAsEnum(QStringLiteral("toolbar-style"), toolbarStyle); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-toolbar-style"), toolbarStyle); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/ToolbarStyle"), toolbarStyle); } void GtkConfig::setScrollbarBehavior() const { const bool scrollbarBehavior = configValueProvider->scrollbarBehavior(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-primary-button-warps-slider"), scrollbarBehavior); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-primary-button-warps-slider"), scrollbarBehavior); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/PrimaryButtonWarpsSlider"), scrollbarBehavior); } void GtkConfig::setDarkThemePreference() const { const bool preferDarkTheme = configValueProvider->preferDarkTheme(); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-application-prefer-dark-theme"), preferDarkTheme); } void GtkConfig::setWindowDecorationsButtonsOrder() const { const QString windowDecorationsButtonOrder = configValueProvider->windowDecorationsButtonsOrder(); ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("button-layout"), windowDecorationsButtonOrder, QStringLiteral("org.gnome.desktop.wm.preferences")); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-decoration-layout"), windowDecorationsButtonOrder); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/DecorationLayout"), windowDecorationsButtonOrder); } void GtkConfig::setEnableAnimations() const { const bool enableAnimations = configValueProvider->enableAnimations(); ConfigEditor::setGtk2ConfigValue(QStringLiteral("gtk-enable-animations"), enableAnimations); ConfigEditor::setGtk3ConfigValueGSettings(QStringLiteral("enable-animations"), enableAnimations); ConfigEditor::setGtk3ConfigValueSettingsIni(QStringLiteral("gtk-enable-animations"), enableAnimations); ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/EnableAnimations"), enableAnimations); } +void GtkConfig::setColors() const +{ + const QMap colors = configValueProvider->colors(); + ConfigEditor::setGtk3Colors(colors); +} + void GtkConfig::applyAllSettings() const { setFont(); setIconTheme(); setCursorTheme(); setIconsOnButtons(); setIconsInMenus(); setToolbarStyle(); setScrollbarBehavior(); setDarkThemePreference(); setWindowDecorationsButtonsOrder(); setEnableAnimations(); + setColors(); } void GtkConfig::onKdeglobalsSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const { if (group.name() == QStringLiteral("KDE")) { if (names.contains(QByteArrayLiteral("AnimationDurationFactor"))) { setEnableAnimations(); } if (names.contains(QByteArrayLiteral("ShowIconsInMenuItems"))) { setIconsInMenus(); } if (names.contains(QByteArrayLiteral("ShowIconsOnPushButtons"))) { setIconsOnButtons(); } if (names.contains(QByteArrayLiteral("ScrollbarLeftClickNavigatesByPage"))) { setScrollbarBehavior(); } } else if (group.name() == QStringLiteral("Icons")) { if (names.contains(QByteArrayLiteral("Theme"))) { setIconTheme(); } } else if (group.name() == QStringLiteral("General")) { if (names.contains(QByteArrayLiteral("font"))) { setFont(); } if (names.contains(QByteArrayLiteral("ColorScheme"))) { + setColors(); setDarkThemePreference(); } } else if (group.name() == QStringLiteral("Toolbar style")) { if (names.contains(QByteArrayLiteral("ToolButtonStyle"))) { setToolbarStyle(); } } } void GtkConfig::onKWinSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const { if (group.name() == QStringLiteral("org.kde.kdecoration2") && (names.contains("ButtonsOnRight") || names.contains("ButtonsOnLeft"))) { setWindowDecorationsButtonsOrder(); } } void GtkConfig::onKCMInputSettingsChange(const KConfigGroup& group, const QByteArrayList& names) const { if (group.name() == QStringLiteral("Mouse") && names.contains("cursorTheme")) { setCursorTheme(); } } #include "gtkconfig.moc" diff --git a/kded/gtkconfig.h b/kded/gtkconfig.h index 111e2c4..e87d69b 100644 --- a/kded/gtkconfig.h +++ b/kded/gtkconfig.h @@ -1,73 +1,74 @@ /* * Copyright (C) 2019 Mikhail Zolotukhin * Copyright (C) 2019 Nicolas Fella * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include "configeditor.h" #include "configvalueprovider.h" #include "themepreviewer.h" class Q_DECL_EXPORT GtkConfig : public KDEDModule { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.GtkConfig") public: GtkConfig(QObject *parent, const QVariantList& args); ~GtkConfig(); void setFont() const; void setIconTheme() const; void setCursorTheme() const; void setIconsOnButtons() const; void setIconsInMenus() const; void setToolbarStyle() const; void setScrollbarBehavior() const; void setDarkThemePreference() const; void setWindowDecorationsButtonsOrder() const; void setEnableAnimations() const; + void setColors() const; void applyAllSettings() const; public Q_SLOTS: Q_SCRIPTABLE void setGtk2Theme(const QString &themeName) const; Q_SCRIPTABLE void setGtk3Theme(const QString &themeName) const; Q_SCRIPTABLE QString gtk2Theme() const; Q_SCRIPTABLE QString gtk3Theme() const; Q_SCRIPTABLE void showGtk2ThemePreview(const QString &themeName) const; Q_SCRIPTABLE void showGtk3ThemePreview(const QString &themeName) const; void onKdeglobalsSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const; void onKWinSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const; void onKCMInputSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const; private: QScopedPointer configValueProvider; QScopedPointer themePreviewer; KConfigWatcher::Ptr kdeglobalsConfigWatcher; KConfigWatcher::Ptr kwinConfigWatcher; KConfigWatcher::Ptr kcminputConfigWatcher; };