File indexing completed on 2024-04-14 05:20:40

0001 /*
0002  * SPDX-FileCopyrightText: 2019 Mikhail Zolotukhin <zomial@protonmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include <QColor>
0008 #include <QDir>
0009 #include <QFont>
0010 #include <QList>
0011 #include <QMap>
0012 #include <QString>
0013 #include <QSvgGenerator>
0014 
0015 #include <KColorScheme>
0016 #include <KColorUtils>
0017 #include <KConfig>
0018 #include <KConfigGroup>
0019 #include <KWindowSystem>
0020 
0021 #include <gtk/gtk.h>
0022 
0023 #include <algorithm>
0024 
0025 #include "configvalueprovider.h"
0026 #include "decorationpainter.h"
0027 
0028 constexpr int MAX_GDK_SCALE = 5;
0029 
0030 constexpr int DEFAULT_DPI = 96;
0031 constexpr int MIN_FONT_DPI = DEFAULT_DPI / 2;
0032 constexpr int MAX_FONT_DPI = DEFAULT_DPI * 5;
0033 
0034 ConfigValueProvider::ConfigValueProvider()
0035     : kdeglobalsConfig(KSharedConfig::openConfig())
0036     , fontsConfig(KSharedConfig::openConfig(QStringLiteral("kcmfonts")))
0037     , inputConfig(KSharedConfig::openConfig(QStringLiteral("kcminputrc")))
0038     , kwinConfig(KSharedConfig::openConfig(QStringLiteral("kwinrc")))
0039     , generatedCSDTempPath(QDir::tempPath() + QStringLiteral("/plasma-csd-generator"))
0040 {
0041 }
0042 
0043 QString ConfigValueProvider::fontName() const
0044 {
0045     static const QFont defaultFont(QStringLiteral("Noto Sans"), 10);
0046 
0047     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("General"));
0048     QString fontAsString = configGroup.readEntry(QStringLiteral("font"), defaultFont.toString());
0049     static QFont font;
0050     font.fromString(fontAsString);
0051     const QString fontStyle = fontStyleHelper(font);
0052     return font.family() + QStringLiteral(", ") + fontStyle + ' ' + QString::number(font.pointSize());
0053 }
0054 
0055 QString ConfigValueProvider::fontStyleHelper(const QFont &font) const
0056 {
0057     // BUG: 333146
0058     // Since Qt sometimes gives us wrong font style name,
0059     // we ought to use this big helper function to construct
0060     // the style ourselves. Some fonts will not work
0061     auto weight = font.weight();
0062     QString result;
0063     if (weight > QFont::Normal) {
0064         if (weight >= QFont::Black) {
0065             result = QStringLiteral("Black");
0066         } else if (weight >= QFont::ExtraBold) {
0067             result = QStringLiteral("Extra Bold");
0068         } else if (weight >= QFont::Bold) {
0069             result = QStringLiteral("Bold");
0070         } else if (weight >= QFont::DemiBold) {
0071             result = QStringLiteral("Demi Bold");
0072         } else if (weight >= QFont::Medium) {
0073             result = QStringLiteral("Medium");
0074         }
0075     } else {
0076         if (weight <= QFont::Thin) {
0077             result = QStringLiteral("Thin");
0078         } else if (weight <= QFont::ExtraLight) {
0079             result = QStringLiteral("Extra Light");
0080         } else if (weight <= QFont::Light) {
0081             result = QStringLiteral("Light");
0082         }
0083     }
0084 
0085     auto style = font.style();
0086     if (style == QFont::StyleItalic) {
0087         result += QLatin1Char(' ') + QStringLiteral("Italic");
0088     } else if (style == QFont::StyleOblique) {
0089         result += QLatin1Char(' ') + QStringLiteral("Oblique");
0090     }
0091 
0092     auto stretch = font.stretch();
0093     if (stretch == QFont::UltraCondensed) {
0094         result += QLatin1Char(' ') + QStringLiteral("UltraCondensed");
0095     } else if (stretch == QFont::ExtraCondensed) {
0096         result += QLatin1Char(' ') + QStringLiteral("ExtraCondensed");
0097     } else if (stretch == QFont::Condensed) {
0098         result += QLatin1Char(' ') + QStringLiteral("Condensed");
0099     } else if (stretch == QFont::SemiCondensed) {
0100         result += QLatin1Char(' ') + QStringLiteral("SemiCondensed");
0101     } else if (stretch == QFont::Unstretched) {
0102         result += QLatin1Char(' ') + QStringLiteral("Unstretched");
0103     } else if (stretch == QFont::SemiExpanded) {
0104         result += QLatin1Char(' ') + QStringLiteral("SemiExpanded");
0105     } else if (stretch == QFont::Expanded) {
0106         result += QLatin1Char(' ') + QStringLiteral("Expanded");
0107     } else if (stretch == QFont::ExtraExpanded) {
0108         result += QLatin1Char(' ') + QStringLiteral("ExtraExpanded");
0109     } else if (stretch == QFont::UltraExpanded) {
0110         result += QLatin1Char(' ') + QStringLiteral("UltraExpanded");
0111     }
0112 
0113     return result.simplified();
0114 }
0115 
0116 QString ConfigValueProvider::iconThemeName() const
0117 {
0118     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Icons"));
0119     return configGroup.readEntry(QStringLiteral("Theme"), QStringLiteral("breeze"));
0120 }
0121 
0122 QString ConfigValueProvider::cursorThemeName() const
0123 {
0124     KConfigGroup configGroup = inputConfig->group(QStringLiteral("Mouse"));
0125     return configGroup.readEntry(QStringLiteral("cursorTheme"), QStringLiteral("breeze_cursors"));
0126 }
0127 
0128 QString ConfigValueProvider::soundThemeName() const
0129 {
0130     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Sounds"));
0131     return configGroup.readEntry(QStringLiteral("Theme"), QStringLiteral("ocean"));
0132 }
0133 
0134 bool ConfigValueProvider::eventSoundsEnabled() const
0135 {
0136     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Sounds"));
0137     return configGroup.readEntry(QStringLiteral("Enable"), true);
0138 }
0139 
0140 int ConfigValueProvider::cursorSize() const
0141 {
0142     KConfigGroup configGroup = inputConfig->group(QStringLiteral("Mouse"));
0143     return configGroup.readEntry(QStringLiteral("cursorSize"), 24);
0144 }
0145 
0146 bool ConfigValueProvider::iconsOnButtons() const
0147 {
0148     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE"));
0149     return configGroup.readEntry(QStringLiteral("ShowIconsOnPushButtons"), true);
0150 }
0151 
0152 bool ConfigValueProvider::iconsInMenus() const
0153 {
0154     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE"));
0155     return configGroup.readEntry(QStringLiteral("ShowIconsInMenuItems"), true);
0156 }
0157 
0158 int ConfigValueProvider::toolbarStyle() const
0159 {
0160     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("Toolbar style"));
0161     QString kdeConfigValue = configGroup.readEntry(QStringLiteral("ToolButtonStyle"), "TextBesideIcon");
0162 
0163     if (kdeConfigValue == QStringLiteral("NoText")) {
0164         return GtkToolbarStyle::GTK_TOOLBAR_ICONS;
0165     } else if (kdeConfigValue == QStringLiteral("TextOnly")) {
0166         return GtkToolbarStyle::GTK_TOOLBAR_TEXT;
0167     } else if (kdeConfigValue == QStringLiteral("TextBesideIcon")) {
0168         return GtkToolbarStyle::GTK_TOOLBAR_BOTH_HORIZ;
0169     } else {
0170         return GtkToolbarStyle::GTK_TOOLBAR_BOTH;
0171     }
0172 }
0173 
0174 bool ConfigValueProvider::scrollbarBehavior() const
0175 {
0176     KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KDE"));
0177     bool kdeConfigValue = configGroup.readEntry(QStringLiteral("ScrollbarLeftClickNavigatesByPage"), false);
0178     return !kdeConfigValue; // GTK setting is inverted
0179 }
0180 
0181 bool ConfigValueProvider::preferDarkTheme() const
0182 {
0183     KConfigGroup colorsConfigGroup = kdeglobalsConfig->group(QStringLiteral("Colors:Window"));
0184     QColor windowBackgroundColor = colorsConfigGroup.readEntry(QStringLiteral("BackgroundNormal"), QColor(239, 240, 241));
0185     const int windowBackgroundGray = qGray(windowBackgroundColor.rgb());
0186 
0187     // We use heuristic to determine if current color scheme is dark or not
0188     return windowBackgroundGray < 192;
0189 }
0190 
0191 QStringList ConfigValueProvider::windowDecorationsButtonsImages() const
0192 {
0193     static const QList<QString> buttonTypes{
0194         QStringLiteral("close"),
0195         QStringLiteral("maximize"),
0196         QStringLiteral("maximized"),
0197         QStringLiteral("minimize"),
0198     };
0199 
0200     static const QList<QString> buttonStates{
0201         // Focused titlebars
0202         QStringLiteral("normal"),
0203         QStringLiteral("active"), // aka pressed
0204         QStringLiteral("hover"),
0205         // Unfocused titlebars
0206         QStringLiteral("backdrop-normal"),
0207         QStringLiteral("backdrop-active"),
0208         QStringLiteral("backdrop-hover"),
0209     };
0210 
0211     KConfigGroup decorationGroup = kwinConfig->group(QStringLiteral("org.kde.kdecoration2"));
0212     const QString themeName = decorationGroup.readEntry(QStringLiteral("theme"), QStringLiteral("Breeze"));
0213 
0214     auto decorationPainter = DecorationPainter::fromThemeName(themeName);
0215     QStringList decorationsImages{};
0216 
0217     for (const auto &buttonType : buttonTypes) {
0218         for (const auto &buttonState : buttonStates) {
0219             QSvgGenerator svgGenerator{};
0220 
0221             QString filePath = generatedCSDTempPath.filePath(QStringLiteral("%1-%2.svg").arg(buttonType, buttonState));
0222 
0223             svgGenerator.setFileName(filePath);
0224             svgGenerator.setViewBox(DecorationPainter::ButtonGeometry);
0225 
0226             QPainter painter{&svgGenerator};
0227             decorationPainter->paintButton(painter, buttonType, buttonState);
0228             painter.end();
0229 
0230             decorationsImages.append(filePath);
0231         }
0232     }
0233 
0234     return decorationsImages;
0235 }
0236 
0237 QString ConfigValueProvider::windowDecorationsButtonsOrder() const
0238 {
0239     KConfigGroup configGroup = kwinConfig->group(QStringLiteral("org.kde.kdecoration2"));
0240     QString buttonsOnLeftKdeConfigValue = configGroup.readEntry(QStringLiteral("ButtonsOnLeft"), "MS");
0241     QString buttonsOnRightKdeConfigValue = configGroup.readEntry(QStringLiteral("ButtonsOnRight"), "HIAX");
0242 
0243     QString buttonsOnLeftInGtkNotation = windowDecorationButtonsOrderInGtkNotation(buttonsOnLeftKdeConfigValue);
0244     QString buttonsOnRightInGtkNotation = windowDecorationButtonsOrderInGtkNotation(buttonsOnRightKdeConfigValue);
0245 
0246     return buttonsOnLeftInGtkNotation + QStringLiteral(":") + buttonsOnRightInGtkNotation;
0247 }
0248 
0249 bool ConfigValueProvider::enableAnimations() const
0250 {
0251     KConfigGroup generalCfg = kdeglobalsConfig->group(QStringLiteral("KDE"));
0252     const qreal animationSpeedModifier = qMax(0.0, generalCfg.readEntry("AnimationDurationFactor", 1.0));
0253 
0254     return !qFuzzyIsNull(animationSpeedModifier);
0255 }
0256 
0257 int ConfigValueProvider::doubleClickInterval() const
0258 {
0259     KConfigGroup generalCfg = kdeglobalsConfig->group("KDE");
0260     return generalCfg.readEntry("DoubleClickInterval", 400);
0261 }
0262 
0263 QMap<QString, QColor> ConfigValueProvider::colors() const
0264 {
0265     using KCS = KColorScheme;
0266 
0267     // Color Schemes Collection
0268     QHash<QString, QHash<QString, KCS>> csc{
0269         {QStringLiteral("active"),
0270          {
0271              {QStringLiteral("view"), KCS(QPalette::Active, KCS::View)},
0272              {QStringLiteral("window"), KCS(QPalette::Active, KCS::Window)},
0273              {QStringLiteral("button"), KCS(QPalette::Active, KCS::Button)},
0274              {QStringLiteral("selection"), KCS(QPalette::Active, KCS::Selection)},
0275              {QStringLiteral("tooltip"), KCS(QPalette::Active, KCS::Tooltip)},
0276              {QStringLiteral("complementary"), KCS(QPalette::Active, KCS::Complementary)},
0277              {QStringLiteral("header"), KCS(QPalette::Active, KCS::Header)},
0278          }},
0279         {QStringLiteral("inactive"),
0280          {
0281              {QStringLiteral("view"), KCS(QPalette::Inactive, KCS::View)},
0282              {QStringLiteral("window"), KCS(QPalette::Inactive, KCS::Window)},
0283              {QStringLiteral("button"), KCS(QPalette::Inactive, KCS::Button)},
0284              {QStringLiteral("selection"), KCS(QPalette::Inactive, KCS::Selection)},
0285              {QStringLiteral("tooltip"), KCS(QPalette::Inactive, KCS::Tooltip)},
0286              {QStringLiteral("complementary"), KCS(QPalette::Inactive, KCS::Complementary)},
0287              {QStringLiteral("header"), KCS(QPalette::Inactive, KCS::Header)},
0288          }},
0289         {QStringLiteral("disabled"),
0290          {
0291              {QStringLiteral("view"), KCS(QPalette::Disabled, KCS::View)},
0292              {QStringLiteral("window"), KCS(QPalette::Disabled, KCS::Window)},
0293              {QStringLiteral("button"), KCS(QPalette::Disabled, KCS::Button)},
0294              {QStringLiteral("selection"), KCS(QPalette::Disabled, KCS::Selection)},
0295              {QStringLiteral("tooltip"), KCS(QPalette::Disabled, KCS::Tooltip)},
0296              {QStringLiteral("complementary"), KCS(QPalette::Disabled, KCS::Complementary)},
0297              {QStringLiteral("header"), KCS(QPalette::Disabled, KCS::Header)},
0298          }},
0299     };
0300 
0301     // Color mixing
0302     QColor windowForegroundColor = csc["active"]["window"].foreground(KCS::NormalText).color();
0303     QColor windowBackgroundColor = csc["active"]["window"].background(KCS::NormalBackground).color();
0304     QColor bordersColor = KColorUtils::mix(windowBackgroundColor, windowForegroundColor, 0.25);
0305 
0306     QColor inactiveWindowForegroundColor = csc["inactive"]["window"].foreground(KCS::NormalText).color();
0307     QColor inactiveWindowBackgroundColor = csc["inactive"]["window"].background(KCS::NormalBackground).color();
0308     QColor inactiveBordersColor = KColorUtils::mix(inactiveWindowBackgroundColor, inactiveWindowForegroundColor, 0.25);
0309 
0310     QColor disabledWindowForegroundColor = csc["disabled"]["window"].foreground(KCS::NormalText).color();
0311     QColor disabledWindowBackgroundColor = csc["disabled"]["window"].background(KCS::NormalBackground).color();
0312     QColor disabledBordersColor = KColorUtils::mix(disabledWindowBackgroundColor, disabledWindowForegroundColor, 0.25);
0313 
0314     QColor unfocusedDisabledWindowForegroundColor = csc["disabled"]["window"].foreground(KCS::NormalText).color();
0315     QColor unfocusedDisabledWindowBackgroundColor = csc["disabled"]["window"].background(KCS::NormalBackground).color();
0316     QColor unfocusedDisabledBordersColor = KColorUtils::mix(unfocusedDisabledWindowBackgroundColor, unfocusedDisabledWindowForegroundColor, 0.25);
0317 
0318     QColor tooltipForegroundColor = csc["active"]["tooltip"].foreground(KCS::NormalText).color();
0319     QColor tooltipBackgroundColor = csc["active"]["tooltip"].background(KCS::NormalBackground).color();
0320     QColor tooltipBorderColor = KColorUtils::mix(tooltipBackgroundColor, tooltipForegroundColor, 0.25);
0321 
0322     KConfigGroup windowManagerConfig = kdeglobalsConfig->group(QStringLiteral("WM"));
0323 
0324     QMap<QString, QColor> result = {
0325         /*
0326          * Normal (Non Backdrop, Non Insensitive)
0327          */
0328 
0329         // General Colors
0330         {"theme_fg_color_breeze", csc["active"]["window"].foreground(KCS::NormalText).color()},
0331         {"theme_bg_color_breeze", csc["active"]["window"].background(KCS::NormalBackground).color()},
0332         {"theme_text_color_breeze", csc["active"]["view"].foreground(KCS::NormalText).color()},
0333         {"theme_base_color_breeze", csc["active"]["view"].background(KCS::NormalBackground).color()},
0334         {"theme_view_hover_decoration_color_breeze", csc["active"]["view"].decoration(KCS::HoverColor).color()},
0335         {"theme_hovering_selected_bg_color_breeze", csc["active"]["selection"].decoration(KCS::HoverColor).color()},
0336         {"theme_selected_bg_color_breeze", csc["active"]["selection"].background(KCS::NormalBackground).color()},
0337         {"theme_selected_fg_color_breeze", csc["active"]["selection"].foreground(KCS::NormalText).color()},
0338         {"theme_view_active_decoration_color_breeze", csc["active"]["view"].decoration(KCS::HoverColor).color()},
0339 
0340         // Button Colors
0341         {"theme_button_background_normal_breeze", csc["active"]["button"].background(KCS::NormalBackground).color()},
0342         {"theme_button_decoration_hover_breeze", csc["active"]["button"].decoration(KCS::HoverColor).color()},
0343         {"theme_button_decoration_focus_breeze", csc["active"]["button"].decoration(KCS::FocusColor).color()},
0344         {"theme_button_foreground_normal_breeze", csc["active"]["button"].foreground(KCS::NormalText).color()},
0345         {"theme_button_foreground_active_breeze", csc["active"]["selection"].foreground(KCS::NormalText).color()},
0346 
0347         // Misc Colors
0348         {"borders_breeze", bordersColor},
0349         {"warning_color_breeze", csc["active"]["view"].foreground(KCS::NeutralText).color()},
0350         {"success_color_breeze", csc["active"]["view"].foreground(KCS::PositiveText).color()},
0351         {"error_color_breeze", csc["active"]["view"].foreground(KCS::NegativeText).color()},
0352 
0353         /*
0354          * Backdrop (Inactive)
0355          */
0356 
0357         // General
0358         {"theme_unfocused_fg_color_breeze", csc["inactive"]["window"].foreground(KCS::NormalText).color()},
0359         {"theme_unfocused_text_color_breeze", csc["inactive"]["view"].foreground(KCS::NormalText).color()},
0360         {"theme_unfocused_bg_color_breeze", csc["inactive"]["window"].background(KCS::NormalBackground).color()},
0361         {"theme_unfocused_base_color_breeze", csc["inactive"]["view"].background(KCS::NormalBackground).color()},
0362         {"theme_unfocused_selected_bg_color_alt_breeze", csc["inactive"]["selection"].background(KCS::NormalBackground).color()},
0363         {"theme_unfocused_selected_bg_color_breeze", csc["inactive"]["selection"].background(KCS::NormalBackground).color()},
0364         {"theme_unfocused_selected_fg_color_breeze", csc["inactive"]["selection"].foreground(KCS::NormalText).color()},
0365 
0366         // Button
0367         {"theme_button_background_backdrop_breeze", csc["inactive"]["button"].background(KCS::NormalBackground).color()},
0368         {"theme_button_decoration_hover_backdrop_breeze", csc["inactive"]["button"].decoration(KCS::HoverColor).color()},
0369         {"theme_button_decoration_focus_backdrop_breeze", csc["inactive"]["button"].decoration(KCS::FocusColor).color()},
0370         {"theme_button_foreground_backdrop_breeze", csc["inactive"]["button"].foreground(KCS::NormalText).color()},
0371         {"theme_button_foreground_active_backdrop_breeze", csc["inactive"]["selection"].foreground(KCS::NormalText).color()},
0372 
0373         // Misc Colors
0374         {"unfocused_borders_breeze", inactiveBordersColor},
0375         {"warning_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::NeutralText).color()},
0376         {"success_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::PositiveText).color()},
0377         {"error_color_backdrop_breeze", csc["inactive"]["view"].foreground(KCS::NegativeText).color()},
0378 
0379         /*
0380          * Insensitive (Disabled)
0381          */
0382 
0383         // General
0384         {"insensitive_fg_color_breeze", csc["disabled"]["window"].foreground(KCS::NormalText).color()},
0385         {"insensitive_base_fg_color_breeze", csc["disabled"]["view"].foreground(KCS::NormalText).color()},
0386         {"insensitive_bg_color_breeze", csc["disabled"]["window"].background(KCS::NormalBackground).color()},
0387         {"insensitive_base_color_breeze", csc["disabled"]["view"].background(KCS::NormalBackground).color()},
0388         {"insensitive_selected_bg_color_breeze", csc["disabled"]["selection"].background(KCS::NormalBackground).color()},
0389         {"insensitive_selected_fg_color_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()},
0390 
0391         // Button
0392         {"theme_button_background_insensitive_breeze", csc["disabled"]["button"].background(KCS::NormalBackground).color()},
0393         {"theme_button_decoration_hover_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::HoverColor).color()},
0394         {"theme_button_decoration_focus_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::FocusColor).color()},
0395         {"theme_button_foreground_insensitive_breeze", csc["disabled"]["button"].foreground(KCS::NormalText).color()},
0396         {"theme_button_foreground_active_insensitive_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()},
0397 
0398         // Misc Colors
0399         {"insensitive_borders_breeze", disabledBordersColor},
0400         {"warning_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::NeutralText).color()},
0401         {"success_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::PositiveText).color()},
0402         {"error_color_insensitive_breeze", csc["disabled"]["view"].foreground(KCS::NegativeText).color()},
0403 
0404         /*
0405          * Insensitive Backdrop (Inactive Disabled)
0406          * These pretty much have the same appearance as regular inactive colors,
0407          * but they're separate in case we decide to make them different in the future.
0408          */
0409 
0410         // General
0411         {"insensitive_unfocused_fg_color_breeze", csc["disabled"]["window"].foreground(KCS::NormalText).color()},
0412         {"theme_unfocused_view_text_color_breeze", csc["disabled"]["view"].foreground(KCS::NormalText).color()},
0413         {"insensitive_unfocused_bg_color_breeze", csc["disabled"]["window"].background(KCS::NormalBackground).color()},
0414         {"theme_unfocused_view_bg_color_breeze", csc["disabled"]["view"].background(KCS::NormalBackground).color()},
0415         {"insensitive_unfocused_selected_bg_color_breeze", csc["disabled"]["selection"].background(KCS::NormalBackground).color()},
0416         {"insensitive_unfocused_selected_fg_color_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()},
0417 
0418         // Button
0419         {"theme_button_background_backdrop_insensitive_breeze", csc["disabled"]["button"].background(KCS::NormalBackground).color()},
0420         {"theme_button_decoration_hover_backdrop_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::HoverColor).color()},
0421         {"theme_button_decoration_focus_backdrop_insensitive_breeze", csc["disabled"]["button"].decoration(KCS::FocusColor).color()},
0422         {"theme_button_foreground_backdrop_insensitive_breeze", csc["disabled"]["button"].foreground(KCS::NormalText).color()},
0423         {"theme_button_foreground_active_backdrop_insensitive_breeze", csc["disabled"]["selection"].foreground(KCS::NormalText).color()},
0424 
0425         // Misc Colors
0426         {"unfocused_insensitive_borders_breeze", unfocusedDisabledBordersColor},
0427         {"warning_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::NeutralText).color()},
0428         {"success_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::PositiveText).color()},
0429         {"error_color_insensitive_backdrop_breeze", csc["disabled"]["view"].foreground(KCS::NegativeText).color()},
0430 
0431         /*
0432          * Ignorant Colors (These colors do not care about backdrop or insensitive states)
0433          */
0434 
0435         {"link_color_breeze", csc["active"]["view"].foreground(KCS::LinkText).color()},
0436         {"link_visited_color_breeze", csc["active"]["view"].foreground(KCS::VisitedText).color()},
0437 
0438         {"tooltip_text_breeze", tooltipForegroundColor},
0439         {"tooltip_background_breeze", tooltipBackgroundColor},
0440         {"tooltip_border_breeze", tooltipBorderColor},
0441 
0442         {"content_view_bg_breeze", csc["active"]["view"].background(KCS::NormalBackground).color()},
0443 
0444     };
0445     // Handle Headers (menu bars and some of toolbars)
0446     if (KCS::isColorSetSupported(kdeglobalsConfig, KCS::Header)) {
0447         // If we have a separate Header color set, use it for both titlebar and header coloring...
0448         result.insert({{"theme_header_background_breeze", csc["active"]["header"].background().color()},
0449                        {"theme_header_foreground_breeze", csc["active"]["header"].foreground().color()},
0450                        {"theme_header_background_light_breeze", csc["active"]["window"].background().color()},
0451                        {"theme_header_foreground_backdrop_breeze", csc["inactive"]["header"].foreground().color()},
0452                        {"theme_header_background_backdrop_breeze", csc["inactive"]["header"].background().color()},
0453                        {"theme_header_foreground_insensitive_breeze", csc["inactive"]["header"].foreground().color()},
0454                        {"theme_header_foreground_insensitive_backdrop_breeze", csc["inactive"]["header"].foreground().color()},
0455 
0456                        {"theme_titlebar_background_breeze", csc["active"]["header"].background().color()},
0457                        {"theme_titlebar_foreground_breeze", csc["active"]["header"].foreground().color()},
0458                        {"theme_titlebar_background_light_breeze", csc["active"]["window"].background().color()},
0459                        {"theme_titlebar_foreground_backdrop_breeze", csc["inactive"]["header"].foreground().color()},
0460                        {"theme_titlebar_background_backdrop_breeze", csc["inactive"]["header"].background().color()},
0461                        {"theme_titlebar_foreground_insensitive_breeze", csc["inactive"]["header"].foreground().color()},
0462                        {"theme_titlebar_foreground_insensitive_backdrop_breeze", csc["inactive"]["header"].foreground().color()}});
0463     } else {
0464         //... if we don't we'll use regular window colors for headerbar and WM group for a titlebar
0465         result.insert({
0466             {"theme_header_background_breeze", csc["active"]["window"].background().color()},
0467             {"theme_header_foreground_breeze", csc["active"]["window"].foreground().color()},
0468             {"theme_header_background_light_breeze", csc["active"]["window"].background().color()},
0469             {"theme_header_foreground_backdrop_breeze", csc["inactive"]["window"].foreground().color()},
0470             {"theme_header_background_backdrop_breeze", csc["inactive"]["window"].background().color()},
0471             {"theme_header_foreground_insensitive_breeze", csc["inactive"]["window"].foreground().color()},
0472             {"theme_header_foreground_insensitive_backdrop_breeze", csc["inactive"]["window"].foreground().color()},
0473 
0474             {"theme_titlebar_background_breeze", windowManagerConfig.readEntry("activeBackground", QColor())},
0475             {"theme_titlebar_foreground_breeze", windowManagerConfig.readEntry("activeForeground", QColor())},
0476             {"theme_titlebar_background_light_breeze", csc["active"]["window"].background(KCS::NormalBackground).color()},
0477             {"theme_titlebar_foreground_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())},
0478             {"theme_titlebar_background_backdrop_breeze", windowManagerConfig.readEntry("inactiveBackground", QColor())},
0479             {"theme_titlebar_foreground_insensitive_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())},
0480             {"theme_titlebar_foreground_insensitive_backdrop_breeze", windowManagerConfig.readEntry("inactiveForeground", QColor())},
0481         });
0482     }
0483 
0484     return result;
0485 }
0486 
0487 double ConfigValueProvider::x11GlobalScaleFactor() const
0488 {
0489     double scaleFactor;
0490 
0491     if (KWindowSystem::isPlatformX11()) {
0492         KConfigGroup configGroup = kdeglobalsConfig->group(QStringLiteral("KScreen"));
0493         scaleFactor = configGroup.readEntry(QStringLiteral("ScaleFactor"), 1.0);
0494     } else {
0495         KConfigGroup xwaylandGroup = kwinConfig->group(QStringLiteral("Xwayland"));
0496         scaleFactor = xwaylandGroup.readEntry(QStringLiteral("Scale"), 1.0);
0497     }
0498 
0499     return std::clamp(scaleFactor, 1.0, double(MAX_GDK_SCALE));
0500 }
0501 
0502 int ConfigValueProvider::fontDpi() const
0503 {
0504     KConfigGroup configGroup = fontsConfig->group(QStringLiteral("General"));
0505     int fontDpi = 96; // On wayland we want to enforce a scale of one for the fonts as we'll use wayland scaling
0506 
0507     if (KWindowSystem::isPlatformX11()) {
0508         fontDpi = configGroup.readEntry(QStringLiteral("forceFontDPI"), 0);
0509     }
0510 
0511     if (fontDpi <= 0) {
0512         return 0;
0513     }
0514 
0515     return std::clamp(fontDpi, MIN_FONT_DPI, MAX_FONT_DPI);
0516 }
0517 
0518 QString ConfigValueProvider::windowDecorationButtonsOrderInGtkNotation(const QString &kdeConfigValue) const
0519 {
0520     QString gtkNotation;
0521 
0522     for (const QChar &buttonAbbreviation : kdeConfigValue) {
0523         if (buttonAbbreviation == 'X') {
0524             gtkNotation += QStringLiteral("close,");
0525         } else if (buttonAbbreviation == 'I') {
0526             gtkNotation += QStringLiteral("minimize,");
0527         } else if (buttonAbbreviation == 'A') {
0528             gtkNotation += QStringLiteral("maximize,");
0529         } else if (buttonAbbreviation == 'M') {
0530             gtkNotation += QStringLiteral("icon,");
0531         }
0532     }
0533     gtkNotation.chop(1);
0534 
0535     return gtkNotation;
0536 }