vcl/Library_vclplug_gtk3.mk                  |    1 
 vcl/Library_vclplug_gtk3_kde5.mk             |    1 
 vcl/Library_vclplug_gtk4.mk                  |    1 
 vcl/inc/unx/gtk/gtkgdi.hxx                   |    1 
 vcl/unx/gtk3/custom-theme.cxx                |  778 +++++++++++++++++++++++++++
 vcl/unx/gtk3/custom-theme.hxx                |   25 
 vcl/unx/gtk3/salnativewidgets-gtk.cxx        |   34 -
 vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.cxx |   12 
 vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.hxx |   12 
 vcl/unx/gtk4/custom-theme.cxx                |   12 
 vcl/unx/gtk4/custom-theme.hxx                |   12 
 11 files changed, 881 insertions(+), 8 deletions(-)

New commits:
commit 44ccd392be12dad23e216fb3eb2c2e5b275eee75
Author:     Sahil Gautam <[email protected]>
AuthorDate: Thu Nov 28 17:05:20 2024 +0530
Commit:     Sahil Gautam <[email protected]>
CommitDate: Fri Nov 29 23:38:35 2024 +0100

    LibreOffice Theme Part 2: GTK Color Customization
    
    Most of the UI is covered by themes. The icon theme changes
    automatically to light or dark based on the window color. Further
    improvements will be based on the feedback from the users.
    
    Change-Id: Ia63ee608fe7870bc7cc86abb892f5fd5d6f1d8ab
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168829
    Reviewed-by: Michael Weghorn <[email protected]>
    Reviewed-by: Sahil Gautam <[email protected]>
    Tested-by: Jenkins

diff --git a/vcl/Library_vclplug_gtk3.mk b/vcl/Library_vclplug_gtk3.mk
index 5e943bf889be..23eb487f3f9b 100644
--- a/vcl/Library_vclplug_gtk3.mk
+++ b/vcl/Library_vclplug_gtk3.mk
@@ -105,6 +105,7 @@ $(eval $(call 
gb_Library_add_exception_objects,vclplug_gtk3,\
     vcl/unx/gtk3/gtkinst \
     vcl/unx/gtk3/gtksys \
     vcl/unx/gtk3/gtkcairo \
+    vcl/unx/gtk3/custom-theme \
     vcl/unx/gtk3/salnativewidgets-gtk \
     vcl/unx/gtk3/gtkframe \
     vcl/unx/gtk3/gtkobject \
diff --git a/vcl/Library_vclplug_gtk3_kde5.mk b/vcl/Library_vclplug_gtk3_kde5.mk
index 71cb643f5a1a..c0c428955a65 100644
--- a/vcl/Library_vclplug_gtk3_kde5.mk
+++ b/vcl/Library_vclplug_gtk3_kde5.mk
@@ -105,6 +105,7 @@ $(eval $(call 
gb_Library_add_exception_objects,vclplug_gtk3_kde5,\
        vcl/unx/gtk3_kde5/gtk3_kde5_customcellrenderer \
        vcl/unx/gtk3_kde5/gtk3_kde5_gtkdata \
        vcl/unx/gtk3_kde5/gtk3_kde5_gtkinst \
+       vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme \
        vcl/unx/gtk3_kde5/gtk3_kde5_gtksys \
        vcl/unx/gtk3_kde5/gtk3_kde5_filepicker \
        vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc \
diff --git a/vcl/Library_vclplug_gtk4.mk b/vcl/Library_vclplug_gtk4.mk
index a383414d17ed..6d7dfec6b2aa 100644
--- a/vcl/Library_vclplug_gtk4.mk
+++ b/vcl/Library_vclplug_gtk4.mk
@@ -95,6 +95,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk4,\
     vcl/unx/gtk4/gtkinst \
     vcl/unx/gtk4/gtksys \
     vcl/unx/gtk4/gtkcairo \
+    vcl/unx/gtk4/custom-theme \
     vcl/unx/gtk4/salnativewidgets-gtk \
     vcl/unx/gtk4/gtkframe \
     vcl/unx/gtk4/gtkobject \
diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx
index d6430d2bb6e0..d07bb91ec214 100644
--- a/vcl/inc/unx/gtk/gtkgdi.hxx
+++ b/vcl/inc/unx/gtk/gtkgdi.hxx
@@ -135,6 +135,7 @@ public:
 #endif
 private:
     GtkWidget              *mpWindow;
+    static GtkCssProvider  *mpCustomThemeProvider;
     static GtkStyleContext *mpWindowStyle;
     static GtkStyleContext *mpButtonStyle;
     static GtkStyleContext *mpLinkButtonStyle;
diff --git a/vcl/unx/gtk3/custom-theme.cxx b/vcl/unx/gtk3/custom-theme.cxx
new file mode 100644
index 000000000000..9e3024dd0bf9
--- /dev/null
+++ b/vcl/unx/gtk3/custom-theme.cxx
@@ -0,0 +1,778 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "custom-theme.hxx"
+#include <vcl/themecolors.hxx>
+#include <gio/gio.h>
+#include <unx/gtk/gtkdata.hxx>
+#include <gtk/gtk.h>
+
+namespace CustomTheme
+{
+void LoadColorsFromTheme(StyleSettings& rStyleSet)
+{
+    const ThemeColors& aThemeColors = ThemeColors::GetThemeColors();
+
+    rStyleSet.SetDialogTextColor(aThemeColors.GetWindowColor());
+    
rStyleSet.SetDefaultActionButtonTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetActionButtonTextColor(aThemeColors.GetButtonTextColor());
+    rStyleSet.SetListBoxWindowTextColor(aThemeColors.GetBaseColor());
+    rStyleSet.SetRadioCheckTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetGroupTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetLabelTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetWindowTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetFieldTextColor(aThemeColors.GetWindowTextColor());
+    rStyleSet.SetShadowColor(aThemeColors.GetShadeColor());
+
+    rStyleSet.BatchSetBackgrounds(aThemeColors.GetBaseColor());
+    rStyleSet.SetDefaultButtonTextColor(aThemeColors.GetButtonTextColor());
+    
rStyleSet.SetDefaultButtonRolloverTextColor(aThemeColors.GetButtonTextColor());
+    
rStyleSet.SetDefaultButtonPressedRolloverTextColor(aThemeColors.GetFaceColor());
+    rStyleSet.SetButtonRolloverTextColor(aThemeColors.GetButtonTextColor());
+    
rStyleSet.SetDefaultActionButtonRolloverTextColor(aThemeColors.GetFaceColor());
+    
rStyleSet.SetDefaultActionButtonPressedRolloverTextColor(aThemeColors.GetFaceColor());
+    rStyleSet.SetActionButtonRolloverTextColor(aThemeColors.GetFaceColor());
+    
rStyleSet.SetActionButtonPressedRolloverTextColor(aThemeColors.GetFaceColor());
+    rStyleSet.SetFlatButtonTextColor(aThemeColors.GetFaceColor());
+    
rStyleSet.SetFlatButtonPressedRolloverTextColor(aThemeColors.GetFaceColor());
+    rStyleSet.SetFlatButtonRolloverTextColor(aThemeColors.GetFaceColor());
+    rStyleSet.SetFieldRolloverTextColor(aThemeColors.GetFaceColor());
+
+    // Some colors like ButtonRolloverTextColor are present in the 
StyleSettings but
+    // not in ThemeColors, hence cannot be customized yet. These will be added 
to
+    // ThemeColors as the themeing system evolves. Leaving as commented for 
now.
+
+    // rStyleSet.SetButtonRolloverTextColor(Color(0));
+    // rStyleSet.SetButtonPressedRolloverTextColor(Color(0));
+    // rStyleSet.SetHelpColor(Color(0));
+    // rStyleSet.SetHelpTextColor(Color(0));
+
+    rStyleSet.SetAccentColor(aThemeColors.GetAccentColor());
+    rStyleSet.SetHighlightColor(aThemeColors.GetAccentColor());
+    rStyleSet.SetHighlightTextColor(aThemeColors.GetActiveTextColor());
+    rStyleSet.SetListBoxWindowHighlightColor(aThemeColors.GetActiveColor());
+    
rStyleSet.SetListBoxWindowHighlightTextColor(aThemeColors.GetActiveTextColor());
+    rStyleSet.SetActiveColor(aThemeColors.GetActiveColor());
+    rStyleSet.SetActiveTextColor(aThemeColors.GetActiveTextColor());
+
+    rStyleSet.SetFieldColor(aThemeColors.GetFieldColor());
+
+    rStyleSet.SetWindowColor(aThemeColors.GetWindowColor());
+    rStyleSet.SetListBoxWindowBackgroundColor(aThemeColors.GetWindowColor());
+
+    rStyleSet.SetActiveTabColor(aThemeColors.GetActiveColor());
+    rStyleSet.SetInactiveTabColor(aThemeColors.GetInactiveColor());
+
+    rStyleSet.SetMenuColor(aThemeColors.GetMenuColor());
+    rStyleSet.SetMenuBarColor(aThemeColors.GetMenuBarColor());
+    rStyleSet.SetMenuBarRolloverColor(aThemeColors.GetMenuBarHighlightColor());
+    rStyleSet.SetMenuBarTextColor(aThemeColors.GetMenuBarTextColor());
+    
rStyleSet.SetMenuBarRolloverTextColor(aThemeColors.GetMenuBarHighlightTextColor());
+    
rStyleSet.SetMenuBarHighlightTextColor(aThemeColors.GetMenuHighlightTextColor());
+    rStyleSet.SetMenuTextColor(aThemeColors.GetMenuTextColor());
+    rStyleSet.SetMenuHighlightColor(aThemeColors.GetMenuHighlightColor());
+    
rStyleSet.SetMenuHighlightTextColor(aThemeColors.GetMenuHighlightTextColor());
+
+    rStyleSet.SetLinkColor(aThemeColors.GetActiveColor());
+
+    Color aVisitedLinkColor = aThemeColors.GetActiveColor();
+    aVisitedLinkColor.Merge(aThemeColors.GetWindowColor(), 100);
+    rStyleSet.SetVisitedLinkColor(aVisitedLinkColor);
+    rStyleSet.SetTabTextColor(aThemeColors.GetMenuBarTextColor());
+    rStyleSet.SetToolTextColor(aThemeColors.GetWindowTextColor());
+    
rStyleSet.SetTabRolloverTextColor(aThemeColors.GetMenuBarHighlightTextColor());
+}
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+void ApplyCustomTheme(GdkDisplay* pGdkDisplay, GtkCssProvider** 
pCustomThemeProvider)
+#else
+void ApplyCustomTheme(GdkScreen* pScreen, GtkCssProvider** 
pCustomThemeProvider)
+#endif
+{
+    if (!ThemeColors::IsThemeLoaded()
+        || 
ThemeColors::IsAutomaticTheme(ThemeColors::GetThemeColors().GetThemeName()))
+        return;
+
+    if ((*pCustomThemeProvider) == nullptr)
+    {
+        (*pCustomThemeProvider) = gtk_css_provider_new();
+        OString aStyleString = CreateStyleString();
+
+        css_provider_load_from_data(*pCustomThemeProvider, 
aStyleString.getStr(),
+                                    aStyleString.getLength());
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+        gtk_style_context_add_provider_for_display(pGdkDisplay,
+                                                   
GTK_STYLE_PROVIDER(*pCustomThemeProvider),
+                                                   
GTK_STYLE_PROVIDER_PRIORITY_USER);
+#else
+        gtk_style_context_add_provider_for_screen(
+            pScreen, GTK_STYLE_PROVIDER(*pCustomThemeProvider), 
GTK_STYLE_PROVIDER_PRIORITY_USER);
+#endif
+    }
+}
+
+OString CreateStyleString()
+{
+    const ThemeColors& aThemeColors = ThemeColors::GetThemeColors();
+
+    Color aSpinBack = aThemeColors.GetBaseColor();
+    aSpinBack.SetAlpha(20);
+
+    Color aPressedColor = ThemeColors::GetThemeColors().GetWindowColor();
+    if (aPressedColor.IsDark())
+        aPressedColor.IncreaseLuminance(30);
+    else
+        aPressedColor.DecreaseLuminance(30);
+
+    OUString aStr =
+        /***************
+             * Base States *
+             ***************/
+        ".background {"
+        "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          ".view {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "textview text {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /*********
+             * Links *
+             *********/
+          "*:link,"
+          "link {"
+          "  color: #"
+        + aThemeColors.GetActiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "*:visited {"
+          "  color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /************
+             * Toolbars *
+             ************/
+          "toolbar {"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          ".toolbar {"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /**************
+             * Tree Views *
+             **************/
+          "treeview.view:selected {"
+          "  background-color: #"
+        + aThemeColors.GetAccentColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHEXString()
+        + ";"
+          "}"
+
+          "treeview.view:drop(active) {"
+          "  border-style: solid none;"
+          "  border-color: alpha(currentColor, 0.08);"
+          "}"
+
+          "treeview.view.expander {"
+          "  color: #"
+        + aThemeColors.GetFaceColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "treeview.view.expander:hover,"
+          "treeview.view.expander:active {"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "treeview.view.expander:disabled {"
+          "  color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          // this part is still left
+          "treeview.view.trough {"
+          "  background-color: rgba(239, 241, 245, 0.12);"
+          "}"
+
+          "treeview.view header button:not(:focus):not(:hover):not(:active) {"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "treeview.view header button,"
+          "treeview.view header button:disabled {"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "treeview.view header button:last-child {"
+          "  border-right-style: none;"
+          "}"
+
+          "treeview.view button.dnd,"
+          "treeview.view header.button.dnd {"
+          "  background-color: #ff0000;"
+          "  color: #89b4fa;"
+          "}"
+
+          /*********
+             * Menus *
+             *********/
+          "menubar,"
+          ".menubar {"
+          "  background-color: #"
+        + aThemeColors.GetMenuBarColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menubar > menuitem,"
+          ".menubar > menuitem {"
+          "  color: #"
+        + aThemeColors.GetMenuBarTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menubar > menuitem:hover,"
+          ".menubar > menuitem:hover {"
+          "  background-color: #"
+        + aThemeColors.GetMenuBarHighlightColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetMenuBarHighlightTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menubar > menuitem:disabled,"
+          ".menubar > menuitem:disabled {"
+          "  color: #"
+        + aThemeColors.GetInactiveTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menubar > menuitem label:disabled,"
+          ".menubar > menuitem label:disabled {"
+          "  color: inherit;"
+          "}"
+
+          "menu {"
+          "  background-color: #"
+        + aThemeColors.GetMenuColor().AsRGBHexString()
+        + ";"
+          "  border: 1px solid #"
+        + aThemeColors.GetMenuBorderColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menu menuitem {"
+          "  color: #"
+        + aThemeColors.GetMenuTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menu menuitem:hover {"
+          "  background-color: #"
+        + aThemeColors.GetMenuHighlightColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetMenuHighlightTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menu menuitem:active {"
+          "  background-color: alpha(currentColor, 0.12);"
+          "}"
+
+          "menu menuitem:disabled {"
+          "  background-color: #"
+        + aThemeColors.GetMenuColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetDisabledTextColor().AsRGBHexString()
+        + ";"
+          " border-left: 1px solid #"
+        + aThemeColors.GetMenuBorderColor().AsRGBHexString()
+        + ";"
+          " border-right: 1px solid #"
+        + aThemeColors.GetMenuBorderColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "menu menuitem accelerator {"
+          "  color: rgba(239, 241, 245, 0.7);" // ???
+          "}"
+
+          "menu menuitem:disabled accelerator {"
+          "  color: rgba(239, 241, 245, 0.32);" // ???
+          "}"
+
+          "menu menuitem label:dir(rtl),"
+          "menu menuitem label:dir(ltr) {"
+          "  color: inherit;"
+          "}"
+
+          /*************
+             * Notebooks *
+             *************/
+
+          "tabbox > tab:hover,"
+          "notebook > header tab:hover {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  border: 1px solid #"
+        + aThemeColors.GetSeparatorColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          "tabbox > tab:checked, notebook > header tab:checked {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  border: 1px solid #"
+        + aThemeColors.GetSeparatorColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          "notebook {"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          "notebook > header {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "  border-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          "notebook > stack:not(:only-child) {"
+          "  background-color: transparent;"
+          "}"
+
+          /************
+             * Scrollbar*
+            *************/
+
+          "scrollbar {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "scrollbar slider {"
+          "  border: 4px solid transparent;"
+          "  background-clip: padding-box;"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "scrollbar slider:hover {"
+          "  background-color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "scrollbar slider:active {"
+          "  background-color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "scrollbar slider:disabled {"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "scrollbar.overlay-indicator:not(.dragging):not(.hovering) {"
+          "  background-color: transparent;"
+          "}"
+
+          /*****************
+             * Check n Radio *
+             * ***************/
+
+          "check:disabled,"
+          "radio:disabled {"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "check:checked,"
+          "check:indeterminate,"
+          "radio:checked,"
+          "radio:indeterminate {"
+          "  color: rgba(17, 17, 27, 0.87);"
+          "  background-color: #"
+        + aThemeColors.GetActiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "check:checked:hover,"
+          "check:indeterminate:hover,"
+          "radio:checked:hover,"
+          "radio:indeterminate:hover {"
+          "  box-shadow: 0 0 0 6px rgba(137, 180, 250, 0.15);"
+          "  background-color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "check:checked:active,"
+          "check:indeterminate:active,"
+          "radio:checked:active,"
+          "radio:indeterminate:active {"
+          "  box-shadow: 0 0 0 6px rgba(137, 180, 250, 0.2);"
+          "  background-color: #"
+        + aThemeColors.GetActiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "check:checked:disabled,"
+          "check:indeterminate:disabled,"
+          "radio:checked:disabled,"
+          "radio:indeterminate:disabled {"
+          "  color: rgba(17, 17, 27, 0.38);"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /***************
+             * Progressbar *
+             * *************/
+
+          "progressbar {"
+          "  color: rgba(239, 241, 245, 0.7);"
+          "  font-size: smaller;"
+          "}"
+
+          "progressbar trough {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "progressbar progress {"
+          "  background-color: #"
+        + aThemeColors.GetActiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "frame > border,"
+          ".frame {"
+          "  border-radius: 0;"
+          "  box-shadow: none;"
+          "}"
+
+          ".frame.view {"
+          "  border-radius: 6px;"
+          "}"
+
+          ".frame.flat {"
+          "  border-style: none;"
+          "}"
+
+          "separator {"
+          "  min-width: 1px;"
+          "  min-height: 1px;"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /***********
+             * Buttons *
+             ***********/
+
+          ".toolbar button:checked,"
+          "#buttonbox_frame button:checked,"
+          "layouttabbar button:checked,"
+          "messagedialog .dialog-action-box button:checked,"
+          "messagedialog .dialog-action-box .linked:not(.vertical) > 
button:checked,"
+          "popover.background.menu button:checked,"
+          "popover.background button.model:checked,"
+          "headerbar 
button:checked:not(.suggested-action):not(.destructive-action),"
+          "toolbar button:checked,"
+          "combobox > .linked:not(.vertical) > 
button:checked:not(:only-child),"
+          "button.flat:checked,"
+          "button.flat:checked:hover {"
+          "  background-color: alpha(#"
+        + aThemeColors.GetButtonColor().AsRGBHexString()
+        + ", 0.1);"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          "button:active {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "button:disabled {"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetInactiveTextColor().AsRGBHexString()
+        + ";"
+          "  border: 1px solid #"
+        + aThemeColors.GetInactiveBorderColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /*****************
+             * GtkSpinButton *
+             *****************/
+
+          "spinbutton > entry,"
+          "spinbutton > entry:focus,"
+          "spinbutton > entry:disabled,"
+          ".background:not(.csd) spinbutton > entry,"
+          ".background:not(.csd) spinbutton > entry:focus,"
+          ".background:not(.csd) spinbutton > entry:disabled {"
+          "  border: none;"
+          "  box-shadow: none;"
+          "  background-color: transparent;"
+          "}"
+
+          "spinbutton > button {"
+          "  border: solid 6px transparent;"
+          "}"
+
+          "spinbutton > button:focus:not(:hover):not(:active):not(:disabled) {"
+          "  box-shadow: inset 0 0 0 9999px transparent;"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "spinbutton,"
+          "entry {"
+          "  background-color: #"
+        + aSpinBack.AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "spinbutton:focus,"
+          "entry:focus {"
+          "  background-color: #"
+        + aSpinBack.AsRGBHexString()
+        + ";"
+          "  box-shadow: inset 0 0 0 2px #"
+        + aThemeColors.GetActiveColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "spinbutton:disabled,"
+          "entry:disabled {"
+          "  box-shadow: inset 0 0 0 2px transparent;"
+          "  background-color: #"
+        + aSpinBack.AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetInactiveTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /**************
+             * ComboBoxes *
+             **************/
+          "button.combo:only-child {"
+          "  background-color: #"
+        + aThemeColors.GetButtonColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "button.combo:only-child:checked {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  box-shadow: 0 0 0 2px #"
+        + aThemeColors.GetButtonColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "button.combo:only-child:disabled {"
+          "  box-shadow: 0 0 0 2px transparent;"
+          "  background-color: #"
+        + aThemeColors.GetInactiveColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetInactiveTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          // this one still needs some digging
+          "button.small-button, toolbar.small-button button, box.small-button 
button {"
+          "  background-color: #"
+        + aThemeColors.GetMenuBarColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          // for the file picker dialog
+          "list {"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "treeview.view header button {"
+          "  background-color: #"
+        + aThemeColors.GetWindowColor().AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          /************
+             * Tooltips *
+             ************/
+          "tooltip {"
+          "  background-color: #"
+        + aThemeColors.GetBaseColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "tooltip * {"
+          "  color: #"
+        + aThemeColors.GetWindowTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "actionbar > revealer > box .linked > "
+          "button:not(.suggested-action):not(.destructive-action), button {"
+          "  background-color: #"
+        + aThemeColors.GetButtonColor().AsRGBHexString()
+        + ";"
+          "  background-image: radial-gradient(circle, transparent 10%, 
transparent 0%);"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+          ""
+          ""
+          "actionbar > revealer > box .linked > "
+          "button:checked:not(.suggested-action):not(.destructive-action), 
button:checked {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          "tabbox>tab button,"
+          "treeview.view header button button.circular,"
+          "scrollbar button,"
+          "notebook>header>tabs>arrow,"
+          "spinbutton>button,"
+          "toolbar button,"
+          "button.flat {"
+          "  background-color: transparent;"
+          "}"
+
+          "button.flat:hover {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  border: 1px solid #"
+        + aThemeColors.GetSeparatorColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          // this alone won't do
+          ".toolbar button:checked,"
+          ".toolbar button:hover,"
+          "toolbar button:checked,"
+          "toolbar button:hover,"
+          "button.flat:checked,"
+          "button.label-button,"
+          "button.flat:checked:hover {"
+          "  background-color: #"
+        + aPressedColor.AsRGBHexString()
+        + ";"
+          "  text-shadow: none;"
+          "}"
+
+          "button.destructive-action:not(:disabled) {"
+          "  background-color: #f38ba8;"
+          "  color: #"
+        + aThemeColors.GetButtonTextColor().AsRGBHexString()
+        + ";"
+          "}"
+
+          ".view:selected {"
+          "  background-color: #"
+        + aThemeColors.GetAccentColor().AsRGBHexString()
+        + ";"
+          "}";
+
+    return OUStringToOString(aStr, RTL_TEXTENCODING_UTF8);
+}
+}
diff --git a/vcl/unx/gtk3/custom-theme.hxx b/vcl/unx/gtk3/custom-theme.hxx
new file mode 100644
index 000000000000..9ab41bf2a8a4
--- /dev/null
+++ b/vcl/unx/gtk3/custom-theme.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <gtk/gtkcssprovider.h>
+#include <gtk/gtk.h>
+#include <vcl/settings.hxx>
+
+namespace CustomTheme
+{
+#if GTK_CHECK_VERSION(4, 0, 0)
+void ApplyCustomTheme(GdkDisplay* pGdkDisplay, GtkCssProvider** 
pCustomThemeProvider);
+#else
+void ApplyCustomTheme(GdkScreen* pScreen, GtkCssProvider** 
pCustomThemeProvider);
+#endif
+
+OString CreateStyleString();
+void LoadColorsFromTheme(StyleSettings& rStyleSet);
+}
diff --git a/vcl/unx/gtk3/salnativewidgets-gtk.cxx 
b/vcl/unx/gtk3/salnativewidgets-gtk.cxx
index e02e642bc534..d107b96167d5 100644
--- a/vcl/unx/gtk3/salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/salnativewidgets-gtk.cxx
@@ -24,9 +24,13 @@
 #include <unx/fontmanager.hxx>
 #include <o3tl/string_view.hxx>
 
+#include <IconThemeSelector.hxx>
+#include "custom-theme.hxx"
+#include <vcl/themecolors.hxx>
 #include "gtkcairo.hxx"
 #include <optional>
 
+GtkCssProvider*  GtkSalGraphics::mpCustomThemeProvider = nullptr;
 GtkStyleContext* GtkSalGraphics::mpWindowStyle = nullptr;
 GtkStyleContext* GtkSalGraphics::mpButtonStyle = nullptr;
 GtkStyleContext* GtkSalGraphics::mpLinkButtonStyle = nullptr;
@@ -2308,6 +2312,12 @@ bool GtkSalGraphics::updateSettings(AllSettings& 
rSettings)
     GtkSettings* pSettings = gtk_widget_get_settings(pTopLevel);
     StyleSettings aStyleSet = rSettings.GetStyleSettings();
 
+#if GTK_CHECK_VERSION(4, 0, 0)
+    CustomTheme::ApplyCustomTheme(gtk_widget_get_display(pTopLevel), 
&mpCustomThemeProvider);
+#else
+    CustomTheme::ApplyCustomTheme(gtk_widget_get_screen(pTopLevel), 
&mpCustomThemeProvider);
+#endif
+
     // text colors
     GdkRGBA text_color;
     style_context_set_state(pStyle, GTK_STATE_FLAG_NORMAL);
@@ -2660,14 +2670,22 @@ bool GtkSalGraphics::updateSettings(AllSettings& 
rSettings)
     aStyleSet.SetMinThumbSize(min_slider_length);
 
     // preferred icon style
-    gchar* pIconThemeName = nullptr;
-    gboolean bDarkIconTheme = false;
-    g_object_get(pSettings, "gtk-icon-theme-name", &pIconThemeName,
-                            "gtk-application-prefer-dark-theme", 
&bDarkIconTheme,
-                            nullptr );
-    OUString sIconThemeName(OUString::createFromAscii(pIconThemeName));
-    aStyleSet.SetPreferredIconTheme(sIconThemeName, bDarkIconTheme);
-    g_free( pIconThemeName );
+    if (!ThemeColors::IsThemeLoaded())
+    {
+        gchar* pIconThemeName = nullptr;
+        gboolean bDarkIconTheme = false;
+        g_object_get(pSettings, "gtk-icon-theme-name", &pIconThemeName,
+                "gtk-application-prefer-dark-theme", &bDarkIconTheme,
+                nullptr );
+        OUString sIconThemeName(OUString::createFromAscii(pIconThemeName));
+        aStyleSet.SetPreferredIconTheme(sIconThemeName, bDarkIconTheme);
+        g_free( pIconThemeName );
+    }
+    else
+    {
+        
aStyleSet.SetPreferredIconTheme(vcl::IconThemeSelector::GetIconThemeForDesktopEnvironment(
+            Application::GetDesktopEnvironment(), 
ThemeColors::GetThemeColors().GetWindowColor().IsDark()));
+    }
 
     aStyleSet.SetToolbarIconSize( ToolbarIconSize::Large );
 
diff --git a/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.cxx 
b/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.cxx
new file mode 100644
index 000000000000..1806b1a83992
--- /dev/null
+++ b/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../gtk3/custom-theme.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.hxx 
b/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.hxx
new file mode 100644
index 000000000000..008f9ada376a
--- /dev/null
+++ b/vcl/unx/gtk3_kde5/gtk3_kde5_custom-theme.hxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../gtk3/custom-theme.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/custom-theme.cxx b/vcl/unx/gtk4/custom-theme.cxx
new file mode 100644
index 000000000000..1806b1a83992
--- /dev/null
+++ b/vcl/unx/gtk4/custom-theme.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../gtk3/custom-theme.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk4/custom-theme.hxx b/vcl/unx/gtk4/custom-theme.hxx
new file mode 100644
index 000000000000..008f9ada376a
--- /dev/null
+++ b/vcl/unx/gtk4/custom-theme.hxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../gtk3/custom-theme.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to