Commit a5d4ddb3 authored by Mikhail Zolotukhin's avatar Mikhail Zolotukhin

[GTK Config] Apply color scheme to GTK3 applications

Summary:
Move from krdb (see D28070) with some refactorings.
Depends on D28070

Test Plan:
{F8178998}

This is how I got it to work, improvements to the process are appreciated
# Apply D28070
# Compile breeze-gtk and then copy `$PREFIX/kde/usr/share/themes/Breeze` to `/usr/share/themes` (replacing the existing Breeze (make a backup)). This is needed because Breeze-Gtk recently changed its color definitions names, which are used in this diff. Old Breeze-Gtk uses different ones and therefore the coloration won't work.
# Run systemsettings and reapply Breeze theme from Application Style KCM
# Restart `kded5`
# Go to colors KCM, open it side by side with GTK3 applications (preferably Gedit NOT Nautilus or Lutris (those ones are kept open if you press cross in headerbar))
# Change the color scheme.
# The application must change the colorscheme

Reviewers: cblack, #plasma, ngraham

Reviewed By: cblack, #plasma, ngraham

Subscribers: ndavis, ngraham, davidre, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D28072
parent 0580098a
......@@ -8,6 +8,8 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${ECM_MODULE_P
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)
......
......@@ -9,6 +9,8 @@ target_link_libraries(gtk_theme
PRIVATE
Qt5::Core
KF5::ConfigCore
KF5::ConfigWidgets
KF5::GuiAddons
PkgConfig::GIO
PkgConfig::GObject
)
......
......@@ -19,12 +19,15 @@ target_include_directories(gtkconfig
)
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
)
......
......@@ -18,15 +18,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QDebug>
#include <QColor>
#include <QDir>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QProcess>
#include <QVariant>
#include <QMap>
#include <QList>
#include <QTextStream>
#include <KSharedConfig>
#include <KConfigGroup>
#include <KColorScheme>
#include <KColorUtils>
#include <string>
#include <csignal>
......@@ -102,6 +107,14 @@ void ConfigEditor::setGtk2ConfigValue(const QString &paramName, const QVariant &
reloadGtk2Apps();
}
void ConfigEditor::setGtk3Colors(const QMap<QString, QColor> &colorsDefinitions)
{
addImportStatementToGtkCssUserFile();
modifyColorsCssFile(colorsDefinitions);
addGtkModule(QStringLiteral("colorreload-gtk-module"));
}
QString ConfigEditor::gtk2ConfigValue(const QString& paramName)
{
QString gtkrcPath = QDir::homePath() + QStringLiteral("/.gtkrc-2.0");
......@@ -159,6 +172,51 @@ void ConfigEditor::removeLegacyGtk2Strings()
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(&gtkCss);
gtkCssStream << importStatement;
}
}
}
void ConfigEditor::modifyColorsCssFile(const QMap<QString, QColor> &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)) {
......
......@@ -22,6 +22,7 @@
#include <unistd.h>
#include <QString>
class QColor;
class QFile;
class QVariant;
......@@ -34,11 +35,17 @@ namespace ConfigEditor
void setGtk3ConfigValueSettingsIni(const QString &paramName, const QVariant &paramValue);
void setGtk3ConfigValueXSettingsd(const QString &paramName, const QVariant &paramValue);
void setGtk3Colors(const QMap<QString, QColor> &colorsDefinitions);
QString gtk2ConfigValue(const QString& paramName);
QString gtk3ConfigValueSettingsIni(const QString& paramName);
void removeLegacyGtk2Strings();
void addGtkModule(const QString &moduleName);
void addImportStatementToGtkCssUserFile();
void modifyColorsCssFile(const QMap<QString, QColor> &colorsDefinitions);
void replaceValueInGtkrcContents(QString &gtkrcContents, const QString &paramName, const QVariant &paramValue);
void replaceValueInXSettingsdContents(QString &xSettingsdContents, const QString &paramName, const QVariant &paramValue);
......
......@@ -21,11 +21,15 @@
#include <QFont>
#include <QString>
#include <QColor>
#include <QMap>
#include <QList>
#include <KConfig>
#include <KIconTheme>
#include <KSharedConfig>
#include <KConfigGroup>
#include <KColorScheme>
#include <KColorUtils>
#include <gtk/gtk.h>
......@@ -190,6 +194,201 @@ bool ConfigValueProvider::enableAnimations() const
return !qFuzzyIsNull(animationSpeedModifier);
}
QMap<QString, QColor> ConfigValueProvider::colors() const
{
using KCS = KColorScheme;
// Color Schemes Collection
QHash<QString, QHash<QString, KCS>> 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;
......
......@@ -40,6 +40,7 @@ public:
bool preferDarkTheme() const;
QString windowDecorationsButtonsOrder() const;
bool enableAnimations() const;
QMap<QString, QColor> colors() const;
private:
QString fontStyleHelper(const QFont &font) const;
......
......@@ -27,6 +27,7 @@
#include <KIconLoader>
#include <KPluginFactory>
#include <KConfigWatcher>
#include <KColorScheme>
#include "gtkconfig.h"
#include "configvalueprovider.h"
......@@ -176,6 +177,12 @@ void GtkConfig::setEnableAnimations() const
ConfigEditor::setGtk3ConfigValueXSettingsd(QStringLiteral("Gtk/EnableAnimations"), enableAnimations);
}
void GtkConfig::setColors() const
{
const QMap<QString, QColor> colors = configValueProvider->colors();
ConfigEditor::setGtk3Colors(colors);
}
void GtkConfig::applyAllSettings() const
{
setFont();
......@@ -188,6 +195,7 @@ void GtkConfig::applyAllSettings() const
setDarkThemePreference();
setWindowDecorationsButtonsOrder();
setEnableAnimations();
setColors();
}
void GtkConfig::onKdeglobalsSettingsChange(const KConfigGroup &group, const QByteArrayList &names) const
......@@ -214,6 +222,7 @@ void GtkConfig::onKdeglobalsSettingsChange(const KConfigGroup &group, const QByt
setFont();
}
if (names.contains(QByteArrayLiteral("ColorScheme"))) {
setColors();
setDarkThemePreference();
}
} else if (group.name() == QStringLiteral("Toolbar style")) {
......
......@@ -47,6 +47,7 @@ public:
void setDarkThemePreference() const;
void setWindowDecorationsButtonsOrder() const;
void setEnableAnimations() const;
void setColors() const;
void applyAllSettings() const;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment