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: */
