diff --git a/gresources/nemo-desktop-preferences.glade b/gresources/nemo-desktop-preferences.glade index f0e6acdcf..0d3442d56 100644 --- a/gresources/nemo-desktop-preferences.glade +++ b/gresources/nemo-desktop-preferences.glade @@ -1,37 +1,37 @@ - + 50 200 100 - 10 - 10 + 10 + 10 75 200 100 - 10 - 10 + 10 + 10 True - False - 6 + False + 6 vertical 5 True - False - 10 + False + 10 10 True - False + False start Desktop Layout @@ -47,9 +47,9 @@ True - False + False end - False + False No desktop icons Show desktop icons on primary monitor only @@ -73,7 +73,7 @@ True - False + False Desktop Icons 0 @@ -89,47 +89,47 @@ True - False - 10 - 0 - 0 - in + False + 10 + 0 + 0 + in True - False + False True - False + False vertical True - False + False vertical True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Computer @@ -142,13 +142,13 @@ True - True + True center False True - end + end 1 @@ -173,12 +173,12 @@ True - False + False vertical True - False + False False @@ -189,25 +189,25 @@ True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Home @@ -220,13 +220,13 @@ True - True + True center False True - end + end 1 @@ -251,12 +251,12 @@ True - False + False vertical True - False + False False @@ -267,25 +267,25 @@ True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Trash @@ -298,13 +298,13 @@ True - True + True center False True - end + end 1 @@ -329,12 +329,12 @@ True - False + False vertical True - False + False False @@ -345,25 +345,25 @@ True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Mounted Drives @@ -376,13 +376,13 @@ True - True + True center False True - end + end 1 @@ -407,12 +407,12 @@ True - False + False vertical True - False + False False @@ -423,25 +423,25 @@ True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Network @@ -454,13 +454,13 @@ True - True + True center False True - end + end 1 @@ -499,7 +499,7 @@ True - False + False Options 0 @@ -515,47 +515,47 @@ True - False - 2 - 0 - 0 - in + False + 10 + 0 + 0 + in True - False + False True - False + False vertical True - False + False vertical True - False + False True - True + True False False True - False - 20 - 20 - 5 + False + 20 + 20 + 5 20 True - False + False Show icons from missing monitors @@ -568,13 +568,13 @@ True - True + True center False True - end + end 1 @@ -610,5 +610,258 @@ 4 + + + True + False + Text Shadow + 0 + + + + + + False + True + 5 + + + + + True + False + 10 + 0 + 0 + in + + + True + False + vertical + + + True + False + 8 + 8 + True + spread + + + True + True + False + False + + + 160 + 60 + True + False + 0 + + + True + False + center + 8 + 8 + Desktop label preview + center + True + 15 + + + + + + + + + True + True + 0 + + + + + True + True + False + False + shadow_radio_normal + + + 160 + 60 + True + False + 0 + + + True + False + center + 8 + 8 + Desktop label preview + center + True + 15 + + + + + + + + + True + True + 1 + + + + + True + True + False + False + shadow_radio_normal + + + 160 + 60 + True + False + 0 + + + True + False + center + 8 + 8 + Desktop label preview + center + True + 15 + + + + + + + + + True + True + 2 + + + + + False + True + 0 + + + + + True + False + + + False + True + 1 + + + + + True + False + + + True + True + False + False + + + True + False + 20 + 20 + 5 + 20 + + + True + False + Use theme if supported + + + False + True + 6 + 0 + + + + + True + True + center + + + False + True + end + 1 + + + + + + + + + False + True + 2 + + + + + + + + False + True + 6 + + diff --git a/gresources/nemo-style-application.css b/gresources/nemo-style-application.css index ea7b95283..7f1a34bde 100644 --- a/gresources/nemo-style-application.css +++ b/gresources/nemo-style-application.css @@ -1,4 +1,5 @@ -/* Desktop text stuff */ +/* Desktop window structure — always applied regardless of theme. + * The desktop window must be transparent so the wallpaper shows through. */ .nemo-window.nemo-desktop-window notebook, .nemo-window.nemo-desktop-window paned { @@ -11,37 +12,17 @@ box-shadow: none; } -NemoDesktopWindow GtkPaned { - background-color: transparent; -} - .nemo-canvas-item { border-radius: 3px; } +/* Custom widget property — controls nemo behavior, not appearance. */ .nemo-desktop { -NemoIconContainer-activate-prelight-icon-label: true; } -.nemo-desktop.nemo-canvas-item { - color: #eeeeee; - text-shadow: 1px 1px alpha(black, 0.8); -} - -.nemo-desktop.nemo-canvas-item:hover { - background-color: alpha(black, 0.5); - background-image: none; - text-shadow: none; -} - -.nemo-desktop.nemo-canvas-item:selected { - background-color: alpha(@theme_selected_bg_color, 0.8); - background-image: none; - text-shadow: none; - color: #f5f5f5; -} - -/* EelEditableLabel (icon labels) */ +/* EelEditableLabel (inline rename entry on desktop). + * Always applied so the rename box stays legible over any wallpaper. */ .nemo-desktop.view .entry, .nemo-desktop.view .entry:active, .nemo-desktop.view .entry:focus, diff --git a/gresources/nemo-style-desktop.css b/gresources/nemo-style-desktop.css new file mode 100644 index 000000000..12658bedf --- /dev/null +++ b/gresources/nemo-style-desktop.css @@ -0,0 +1,45 @@ +/* Desktop icon label text shadows. + * + * Nemo applies one of these classes (shadow-normal / shadow-darker / + * shadow-darkest) to the icon container based on the user's preference. + * If "Use GTK theme" is enabled and the current theme provides its own + * .nemo-desktop styling, this entire stylesheet is not loaded — the + * theme controls text appearance directly. + */ + +/* Shadow variant: Normal (traditional nemo default) */ +.nemo-desktop.nemo-canvas-item.shadow-normal { + color: #eeeeee; + text-shadow: 1px 1px alpha(black, 0.8); +} + +/* Shadow variant: Darker */ +.nemo-desktop.nemo-canvas-item.shadow-darker { + color: #eeeeee; + text-shadow: 1px 1px black; +} + +/* Shadow variant: Darkest */ +.nemo-desktop.nemo-canvas-item.shadow-darkest { + color: #eeeeee; + text-shadow: 1px 1px black, 1px 0px alpha(black, 0.6), 0px 1px alpha(black, 0.6); +} + +/* Hover for shadow modes */ +.nemo-desktop.nemo-canvas-item.shadow-normal:hover, +.nemo-desktop.nemo-canvas-item.shadow-darker:hover, +.nemo-desktop.nemo-canvas-item.shadow-darkest:hover { + background-color: alpha(black, 0.5); + background-image: none; + text-shadow: none; +} + +/* Selected for shadow modes */ +.nemo-desktop.nemo-canvas-item.shadow-normal:selected, +.nemo-desktop.nemo-canvas-item.shadow-darker:selected, +.nemo-desktop.nemo-canvas-item.shadow-darkest:selected { + background-color: alpha(@theme_selected_bg_color, 0.8); + background-image: none; + text-shadow: none; + color: #f5f5f5; +} diff --git a/gresources/nemo.gresource.xml b/gresources/nemo.gresource.xml index 7d0870e7f..2b4ee3d61 100644 --- a/gresources/nemo.gresource.xml +++ b/gresources/nemo.gresource.xml @@ -26,5 +26,6 @@ nemo-style-fallback.css nemo-style-fallback-mandatory.css nemo-style-application.css + nemo-style-desktop.css diff --git a/libnemo-extension/nemo-desktop-preferences.c b/libnemo-extension/nemo-desktop-preferences.c index 6b7352224..f3daf9d0f 100644 --- a/libnemo-extension/nemo-desktop-preferences.c +++ b/libnemo-extension/nemo-desktop-preferences.c @@ -3,12 +3,32 @@ #include #include #include +#include #include "nemo-desktop-preferences.h" +#define NUM_SHADOW_OPTIONS 3 + +static const gchar *shadow_options[NUM_SHADOW_OPTIONS] = { + "normal", + "darker", + "darkest", +}; + +static const gchar *preview_bg_css = + ".shadow-preview-bg {" + " background-image: linear-gradient(to bottom, #7ba4d4, #d4e6f7);" + "}"; + typedef struct { GtkBuilder *builder; GSettings *desktop_settings; + GtkCssProvider *desktop_css_provider; + GtkCssProvider *preview_bg_provider; + GtkWidget *shadow_radios[NUM_SHADOW_OPTIONS]; + GtkWidget *shadow_labels[NUM_SHADOW_OPTIONS]; + gulong shadow_setting_handler; + gulong font_changed_handler; } NemoDesktopPreferencesPrivate; struct _NemoDesktopPreferences @@ -43,6 +63,141 @@ bind_builder_string_combo (GtkBuilder *builder, "active-id", G_SETTINGS_BIND_DEFAULT); } +static void +update_preview_fonts (NemoDesktopPreferencesPrivate *priv) +{ + gchar *font_str; + PangoFontDescription *font_desc; + gint i; + + font_str = g_settings_get_string (priv->desktop_settings, "font"); + font_desc = pango_font_description_from_string (font_str); + g_free (font_str); + + for (i = 0; i < NUM_SHADOW_OPTIONS; i++) { + PangoAttrList *attrs = pango_attr_list_new (); + pango_attr_list_insert (attrs, pango_attr_font_desc_new (font_desc)); + gtk_label_set_attributes (GTK_LABEL (priv->shadow_labels[i]), attrs); + pango_attr_list_unref (attrs); + } + + pango_font_description_free (font_desc); +} + +static void +on_shadow_button_toggled (GtkToggleButton *button, gpointer user_data) +{ + NemoDesktopPreferencesPrivate *priv = user_data; + const gchar *id; + + if (!gtk_toggle_button_get_active (button)) + return; + + id = g_object_get_data (G_OBJECT (button), "shadow-id"); + g_settings_set_string (priv->desktop_settings, "desktop-text-shadow", id); +} + +static void +on_shadow_setting_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + NemoDesktopPreferences *preferences = NEMO_DESKTOP_PREFERENCES (user_data); + NemoDesktopPreferencesPrivate *priv = preferences->priv; + gchar *current; + gint i; + + current = g_settings_get_string (priv->desktop_settings, "desktop-text-shadow"); + + for (i = 0; i < NUM_SHADOW_OPTIONS; i++) { + if (g_strcmp0 (current, shadow_options[i]) == 0) { + g_signal_handlers_block_by_func (priv->shadow_radios[i], + on_shadow_button_toggled, priv); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->shadow_radios[i]), TRUE); + g_signal_handlers_unblock_by_func (priv->shadow_radios[i], + on_shadow_button_toggled, priv); + break; + } + } + + g_free (current); +} + +static void +on_desktop_font_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + NemoDesktopPreferences *preferences = NEMO_DESKTOP_PREFERENCES (user_data); + update_preview_fonts (preferences->priv); +} + +static void +add_provider_to_widget (GtkWidget *widget, GtkCssProvider *provider) +{ + gtk_style_context_add_provider (gtk_widget_get_style_context (widget), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +} + +static void +setup_shadow_preview_buttons (NemoDesktopPreferences *preferences) +{ + NemoDesktopPreferencesPrivate *priv = preferences->priv; + gchar *current; + gint i; + + priv->desktop_css_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (priv->desktop_css_provider, + "/org/nemo/nemo-style-desktop.css"); + + priv->preview_bg_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (priv->preview_bg_provider, preview_bg_css, -1, NULL); + + current = g_settings_get_string (priv->desktop_settings, "desktop-text-shadow"); + + for (i = 0; i < NUM_SHADOW_OPTIONS; i++) { + gchar *name; + + name = g_strdup_printf ("shadow_radio_%s", shadow_options[i]); + priv->shadow_radios[i] = GTK_WIDGET (gtk_builder_get_object (priv->builder, name)); + g_free (name); + + name = g_strdup_printf ("shadow_frame_%s", shadow_options[i]); + add_provider_to_widget (GTK_WIDGET (gtk_builder_get_object (priv->builder, name)), + priv->preview_bg_provider); + g_free (name); + + name = g_strdup_printf ("shadow_label_%s", shadow_options[i]); + priv->shadow_labels[i] = GTK_WIDGET (gtk_builder_get_object (priv->builder, name)); + g_free (name); + + add_provider_to_widget (priv->shadow_labels[i], priv->desktop_css_provider); + + g_object_set_data (G_OBJECT (priv->shadow_radios[i]), "shadow-id", + (gpointer) shadow_options[i]); + + g_signal_connect (priv->shadow_radios[i], "toggled", + G_CALLBACK (on_shadow_button_toggled), priv); + + if (g_strcmp0 (current, shadow_options[i]) == 0) { + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->shadow_radios[i]), TRUE); + } + } + + g_free (current); + + update_preview_fonts (priv); + + priv->shadow_setting_handler = + g_signal_connect (priv->desktop_settings, "changed::desktop-text-shadow", + G_CALLBACK (on_shadow_setting_changed), preferences); + + priv->font_changed_handler = + g_signal_connect (priv->desktop_settings, "changed::font", + G_CALLBACK (on_desktop_font_changed), preferences); +} + static void nemo_desktop_preferences_init (NemoDesktopPreferences *preferences) { @@ -96,6 +251,13 @@ nemo_desktop_preferences_init (NemoDesktopPreferences *preferences) "orphan_switch", "show-orphaned-desktop-icons"); + bind_builder_bool (priv->builder, + priv->desktop_settings, + "use_theme_switch", + "desktop-text-shadow-use-theme"); + + setup_shadow_preview_buttons (preferences); + gtk_widget_show_all (GTK_WIDGET (preferences)); } @@ -103,9 +265,23 @@ static void nemo_desktop_preferences_dispose (GObject *object) { NemoDesktopPreferences *preferences = NEMO_DESKTOP_PREFERENCES (object); + NemoDesktopPreferencesPrivate *priv = preferences->priv; + + if (priv->desktop_settings != NULL) { + if (priv->shadow_setting_handler > 0) { + g_signal_handler_disconnect (priv->desktop_settings, priv->shadow_setting_handler); + priv->shadow_setting_handler = 0; + } + if (priv->font_changed_handler > 0) { + g_signal_handler_disconnect (priv->desktop_settings, priv->font_changed_handler); + priv->font_changed_handler = 0; + } + } - g_clear_object (&preferences->priv->builder); - g_clear_object (&preferences->priv->desktop_settings); + g_clear_object (&priv->desktop_css_provider); + g_clear_object (&priv->preview_bg_provider); + g_clear_object (&priv->builder); + g_clear_object (&priv->desktop_settings); G_OBJECT_CLASS (nemo_desktop_preferences_parent_class)->dispose (object); } diff --git a/libnemo-private/meson.build b/libnemo-private/meson.build index 47ac9f868..19b4cc167 100644 --- a/libnemo-private/meson.build +++ b/libnemo-private/meson.build @@ -69,6 +69,7 @@ nemo_private_sources = [ 'nemo-signaller.c', 'nemo-thumbnails.c', 'nemo-trash-monitor.c', + 'nemo-theme-utils.c', 'nemo-tree-view-drag-dest.c', 'nemo-ui-utilities.c', 'nemo-undo-manager.c', diff --git a/libnemo-private/nemo-global-preferences.h b/libnemo-private/nemo-global-preferences.h index 91f404854..8b593cf0f 100644 --- a/libnemo-private/nemo-global-preferences.h +++ b/libnemo-private/nemo-global-preferences.h @@ -226,6 +226,8 @@ typedef enum #define NEMO_PREFERENCES_DESKTOP_VOLUMES_VISIBLE "volumes-visible" #define NEMO_PREFERENCES_DESKTOP_NETWORK_VISIBLE "network-icon-visible" #define NEMO_PREFERENCES_DESKTOP_BACKGROUND_FADE "background-fade" +#define NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW "desktop-text-shadow" +#define NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW_USE_THEME "desktop-text-shadow-use-theme" #define NEMO_PREFERENCES_DESKTOP_IGNORED_DESKTOP_HANDLERS "ignored-desktop-handlers" /* bulk rename utility */ diff --git a/libnemo-private/nemo-icon-container.c b/libnemo-private/nemo-icon-container.c index e35283290..1903bf5cb 100644 --- a/libnemo-private/nemo-icon-container.c +++ b/libnemo-private/nemo-icon-container.c @@ -7152,6 +7152,38 @@ nemo_icon_container_get_is_desktop (NemoIconContainer *container) return container->details->is_desktop; } +static const gchar *shadow_class_names[] = { + "shadow-normal", + "shadow-darker", + "shadow-darkest" +}; + +static void +update_desktop_shadow_class (NemoIconContainer *container) +{ + GtkStyleContext *context; + gchar *setting, *class_name; + gint i; + + context = gtk_widget_get_style_context (GTK_WIDGET (container)); + + for (i = 0; i < G_N_ELEMENTS (shadow_class_names); i++) { + gtk_style_context_remove_class (context, shadow_class_names[i]); + } + + /* The class is always applied. When the user has opted into theme-driven + * styling and the theme supports it, nemo-theme-utils skips loading the + * shadow stylesheet, so the class simply matches no rules. */ + setting = g_settings_get_string (nemo_desktop_preferences, + NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW); + class_name = g_strdup_printf ("shadow-%s", setting); + gtk_style_context_add_class (context, class_name); + g_free (class_name); + g_free (setting); + + gtk_widget_queue_draw (GTK_WIDGET (container)); +} + void nemo_icon_container_set_is_desktop (NemoIconContainer *container, gboolean is_desktop) @@ -7166,6 +7198,9 @@ nemo_icon_container_set_is_desktop (NemoIconContainer *container, g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, text_ellipsis_limit_changed_container_callback, container); + g_signal_handlers_disconnect_by_func (nemo_desktop_preferences, + update_desktop_shadow_class, + container); if (is_desktop) { GtkStyleContext *context; @@ -7173,10 +7208,17 @@ nemo_icon_container_set_is_desktop (NemoIconContainer *container, context = gtk_widget_get_style_context (GTK_WIDGET (container)); gtk_style_context_add_class (context, "nemo-desktop"); + update_desktop_shadow_class (container); + g_signal_connect_swapped (nemo_desktop_preferences, "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT, G_CALLBACK (text_ellipsis_limit_changed_container_callback), container); + + g_signal_connect_swapped (nemo_desktop_preferences, + "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW, + G_CALLBACK (update_desktop_shadow_class), + container); } else { g_signal_connect_swapped (nemo_icon_view_preferences, "changed::" NEMO_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT, diff --git a/libnemo-private/nemo-theme-utils.c b/libnemo-private/nemo-theme-utils.c new file mode 100644 index 000000000..916f91c85 --- /dev/null +++ b/libnemo-private/nemo-theme-utils.c @@ -0,0 +1,294 @@ +#include "nemo-theme-utils.h" +#include "nemo-global-preferences.h" + +#include + +static GtkCssProvider *mandatory_css_provider = NULL; +static GtkCssProvider *desktop_css_provider = NULL; +static gboolean theme_has_desktop_support = FALSE; + +static gboolean +css_provider_load_from_resource (GtkCssProvider *provider, + const char *resource_path, + GError **error) +{ + GBytes *data; + gboolean retval; + + data = g_resources_lookup_data (resource_path, 0, error); + if (!data) + return FALSE; + + retval = gtk_css_provider_load_from_data (provider, + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + error); + g_bytes_unref (data); + + return retval; +} + +static gchar * +load_file_contents_from_resource (const char *resource_path, + GError **error) +{ + GBytes *data; + gchar *retval; + + data = g_resources_lookup_data (resource_path, 0, error); + + if (!data) { + return NULL; + } + + retval = g_strdup ((gchar *) g_bytes_get_data (data, NULL)); + + g_bytes_unref (data); + + return retval; +} + +static void +add_css_provider_at_priority (const gchar *rpath, guint priority) +{ + GtkCssProvider *provider; + GError *error = NULL; + + provider = gtk_css_provider_new (); + + if (!css_provider_load_from_resource (provider, rpath, &error)) + { + g_warning ("Failed to load css file '%s': %s", rpath, error->message); + g_clear_error (&error); + goto out; + } + + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + priority); + +out: + g_object_unref (provider); +} + +static void +add_fallback_mandatory_css_provider (const gchar *theme_name) +{ + GtkCssProvider *current_provider; + g_autofree gchar *css = NULL; + g_autofree gchar *init_fallback_css = NULL; + g_autofree gchar *final_fallback_css = NULL; + GError *error = NULL; + + current_provider = gtk_css_provider_get_named (theme_name, NULL); + + css = gtk_css_provider_to_string (current_provider); + + if (!g_strstr_len (css, -1, "nemo")) { + g_warning ("The theme appears to have no nemo support. Adding some..."); + + init_fallback_css = load_file_contents_from_resource ("/org/nemo/nemo-style-fallback-mandatory.css", + &error); + + if (!init_fallback_css) { + g_warning ("Failed to load fallback mandatory css file: %s", error->message); + g_clear_error (&error); + + goto out; + } + } else { + goto out; + } + + if (g_strstr_len (css, -1, "theme_selected_bg_color")) { + final_fallback_css = g_strdup (init_fallback_css); + + goto apply; + } + + /* Some themes don't prefix colors with theme_ - remove this from our fallback css */ + if (g_strstr_len (css, -1, "@define-color selected_bg_color")) { + g_warning ("Replacing theme_selected_bg_color with selected_bg_color"); + final_fallback_css = eel_str_replace_substring (init_fallback_css, + "@theme_", + "@"); + } else { + /* If we can find neither, just bail out */ + g_warning ("Theme lacks both theme_selected_bg_color and selected_bg_color - " + "cannot apply fallback CSS"); + goto out; + } + +apply: + mandatory_css_provider = gtk_css_provider_new (); + + gtk_css_provider_load_from_data (mandatory_css_provider, + final_fallback_css, + -1, + &error); + + if (error) { + g_warning ("Failed to create a fallback provider: %s", error->message); + g_clear_error (&error); + g_clear_object (&mandatory_css_provider); + goto out; + } + + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (mandatory_css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +out: + ; +} + +static const char *supported_theme_hints[] = { + "mint", + "arc", + "numix", + "matcha" +}; + +static gboolean +is_known_supported_theme (const gchar *theme_name) +{ + gint i; + gchar *name; + gboolean ret; + + name = g_utf8_casefold (theme_name, -1); + ret = FALSE; + + for (i = 0; i < G_N_ELEMENTS (supported_theme_hints); i++) { + gchar *hint; + + hint = g_utf8_casefold (supported_theme_hints[i], -1); + + if (g_strstr_len (name, -1, hint)) { + ret = TRUE; + } + + g_free (hint); + + if (ret) { + break; + } + } + + g_free (name); + + return ret; +} + +static void +check_desktop_support (const gchar *theme_name) +{ + GtkCssProvider *provider; + gchar *css; + + provider = gtk_css_provider_get_named (theme_name, NULL); + css = gtk_css_provider_to_string (provider); + + theme_has_desktop_support = (g_strstr_len (css, -1, "nemo-desktop") != NULL); + + g_free (css); +} + +static void +update_desktop_provider (void) +{ + gboolean use_theme; + gboolean should_load; + + use_theme = g_settings_get_boolean (nemo_desktop_preferences, + NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW_USE_THEME); + + /* Load our desktop CSS unless the user opted into the theme's own + * desktop styling AND the theme actually provides it. */ + should_load = !(use_theme && theme_has_desktop_support); + + if (should_load && desktop_css_provider == NULL) { + GtkCssProvider *provider; + GError *error = NULL; + + provider = gtk_css_provider_new (); + + if (!css_provider_load_from_resource (provider, "/org/nemo/nemo-style-desktop.css", &error)) { + g_warning ("Failed to load desktop css: %s", error->message); + g_clear_error (&error); + g_object_unref (provider); + return; + } + + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + desktop_css_provider = provider; + } else if (!should_load && desktop_css_provider != NULL) { + gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (desktop_css_provider)); + g_clear_object (&desktop_css_provider); + } +} + +static void +process_theme (GtkSettings *gtk_settings) +{ + gchar *theme_name; + + if (mandatory_css_provider != NULL) { + gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (mandatory_css_provider)); + g_clear_object (&mandatory_css_provider); + } + + g_object_get (gtk_settings, + "gtk-theme-name", &theme_name, + NULL); + + if (!is_known_supported_theme (theme_name)) { + g_warning ("Current gtk theme is not known to have nemo support (%s) - checking...", theme_name); + add_fallback_mandatory_css_provider (theme_name); + } + + check_desktop_support (theme_name); + update_desktop_provider (); + + gtk_style_context_reset_widgets (gdk_screen_get_default ()); + g_free (theme_name); +} + +static void +on_use_theme_setting_changed (GSettings *settings, const gchar *key, gpointer user_data) +{ + update_desktop_provider (); + gtk_style_context_reset_widgets (gdk_screen_get_default ()); +} + +void +nemo_theme_utils_init_styles (void) +{ + static gboolean initialized = FALSE; + GtkSettings *gtk_settings; + + if (initialized) + return; + + initialized = TRUE; + + add_css_provider_at_priority ("/org/nemo/nemo-style-fallback.css", + GTK_STYLE_PROVIDER_PRIORITY_FALLBACK); + + add_css_provider_at_priority ("/org/nemo/nemo-style-application.css", + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + gtk_settings = gtk_settings_get_default (); + + g_signal_connect_swapped (gtk_settings, "notify::gtk-theme-name", + G_CALLBACK (process_theme), gtk_settings); + + g_signal_connect (nemo_desktop_preferences, + "changed::" NEMO_PREFERENCES_DESKTOP_TEXT_SHADOW_USE_THEME, + G_CALLBACK (on_use_theme_setting_changed), NULL); + + process_theme (gtk_settings); +} diff --git a/libnemo-private/nemo-theme-utils.h b/libnemo-private/nemo-theme-utils.h new file mode 100644 index 000000000..d74958d35 --- /dev/null +++ b/libnemo-private/nemo-theme-utils.h @@ -0,0 +1,8 @@ +#ifndef NEMO_THEME_UTILS_H +#define NEMO_THEME_UTILS_H + +#include + +void nemo_theme_utils_init_styles (void); + +#endif /* NEMO_THEME_UTILS_H */ diff --git a/libnemo-private/org.nemo.gschema.xml b/libnemo-private/org.nemo.gschema.xml index abc2814d4..49d01653b 100644 --- a/libnemo-private/org.nemo.gschema.xml +++ b/libnemo-private/org.nemo.gschema.xml @@ -626,6 +626,21 @@ Fade the background on change If set to true, then Nemo will use a fade effect to change the desktop background. + + + + + + + 'normal' + Desktop icon text shadow level + Controls the text shadow for desktop icon labels. Values: "normal", "darker", "darkest". + + + false + Use GTK theme for desktop icon text styling + If true and the current GTK theme provides desktop icon styling, use the theme instead of the built-in shadow setting. + diff --git a/src/nemo-application.c b/src/nemo-application.c index 062d105f7..4bede796f 100644 --- a/src/nemo-application.c +++ b/src/nemo-application.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,6 @@ #include #include #include -#include #include #define GNOME_DESKTOP_USE_UNSTABLE_API @@ -100,209 +100,6 @@ static NemoApplication *singleton = NULL; /* The saving of the accelerator map was requested */ static gboolean save_of_accel_map_requested = FALSE; -static GtkCssProvider *mandatory_css_provider = NULL; - -static gboolean -css_provider_load_from_resource (GtkCssProvider *provider, - const char *resource_path, - GError **error) -{ - GBytes *data; - gboolean retval; - - data = g_resources_lookup_data (resource_path, 0, error); - if (!data) - return FALSE; - - retval = gtk_css_provider_load_from_data (provider, - g_bytes_get_data (data, NULL), - g_bytes_get_size (data), - error); - g_bytes_unref (data); - - return retval; -} - -static gchar * -load_file_contents_from_resource (const char *resource_path, - GError **error) -{ - GBytes *data; - gchar *retval; - - data = NULL; - - data = g_resources_lookup_data (resource_path, 0, error); - - if (!data) { - return FALSE; - } - - retval = g_strdup ((gchar *) g_bytes_get_data (data, NULL)); - - g_bytes_unref (data); - - return retval; -} - -static void -add_css_provider_at_priority (const gchar *rpath, guint priority) -{ - GtkCssProvider *provider; - GError *error = NULL; - - provider = gtk_css_provider_new (); - - if (!css_provider_load_from_resource (provider, rpath, &error)) - { - g_warning ("Failed to load fallback css file: %s", error->message); - if (error->message != NULL) - g_error_free (error); - goto out; - } - - gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), - GTK_STYLE_PROVIDER (provider), - priority); - -out: - g_object_unref (provider); -} - -static void -add_fallback_mandatory_css_provider (const gchar *theme_name) -{ - GtkCssProvider *current_provider; - gchar *css, *init_fallback_css, *final_fallback_css; - GError *error = NULL; - - current_provider = gtk_css_provider_get_named (theme_name, NULL); - - css = gtk_css_provider_to_string (current_provider); - - init_fallback_css = NULL; - - if (!g_strstr_len (css, -1, "nemo")) { - g_warning ("The theme appears to have no nemo support. Adding some..."); - - init_fallback_css = load_file_contents_from_resource ("/org/nemo/nemo-style-fallback-mandatory.css", - &error); - - if (!init_fallback_css) { - g_warning ("Failed to load fallback mandatory css file: %s", error->message); - g_clear_error (&error); - - goto out; - } - } else { - goto out; - } - - final_fallback_css = NULL; - - /* Our fallback uses @theme_ prefixed names for colors. If the active theme does also, skip - * to apply */ - if (g_strstr_len (css, -1, "theme_selected_bg_color")) { - final_fallback_css = g_strdup (init_fallback_css); - - goto apply; - } - - /* Some themes don't prefix colors with theme_ - remove this from our fallback css */ - if (g_strstr_len (css, -1, "@define-color selected_bg_color")) { - g_warning ("Replacing theme_selected_bg_color with selected_bg_color"); - final_fallback_css = eel_str_replace_substring (init_fallback_css, - "@theme_", - "@"); - } else { - /* If we can find neither, just bail out */ - goto out; - } - -apply: - g_free (init_fallback_css); - - mandatory_css_provider = gtk_css_provider_new (); - - gtk_css_provider_load_from_data (mandatory_css_provider, - final_fallback_css, - -1, - &error); - - if (error) { - g_warning ("Failed to create a fallback provider: %s", error->message); - g_clear_error (&error); - goto out; - } - - gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), - GTK_STYLE_PROVIDER (mandatory_css_provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); -out: - g_free (css); -} - -static const char *supported_theme_hints[] = { - "mint", - "arc", - "numix", - "matcha" -}; - -static gboolean -is_known_supported_theme (const gchar *theme_name) -{ - gint i; - gchar *name; - gboolean ret; - - name = g_utf8_casefold (theme_name, -1); - ret = FALSE; - - for (i = 0; i < G_N_ELEMENTS (supported_theme_hints); i++) { - gchar *hint; - - hint = g_utf8_casefold (supported_theme_hints[i], -1); - - if (g_strstr_len (name, -1, hint)) { - ret = TRUE; - } - - g_free (hint); - - if (ret) { - break; - } - } - - g_free (name); - - return ret; -} - -static void -process_system_theme (GtkSettings *gtk_settings) -{ - gchar *theme_name; - - if (mandatory_css_provider != NULL) { - gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (mandatory_css_provider)); - g_clear_object (&mandatory_css_provider); - } - - g_object_get (gtk_settings, - "gtk-theme-name", &theme_name, - NULL); - - if (!is_known_supported_theme (theme_name)) { - g_warning ("Current gtk theme is not known to have nemo support (%s) - checking...", theme_name); - add_fallback_mandatory_css_provider (theme_name); - } - - gtk_style_context_reset_widgets (gdk_screen_get_default ()); - g_free (theme_name); -} - static void init_icons_and_styles (void) { @@ -314,20 +111,7 @@ init_icons_and_styles (void) NEMO_STATUSBAR_ICON_SIZE, NEMO_STATUSBAR_ICON_SIZE); - add_css_provider_at_priority ("/org/nemo/nemo-style-fallback.css", - GTK_STYLE_PROVIDER_PRIORITY_FALLBACK); - - add_css_provider_at_priority ("/org/nemo/nemo-style-application.css", - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - GtkSettings *gtk_settings = gtk_settings_get_default (); - /* We create our own 'runtime theme' when we encounter one that doesn't - * include nemo support. We must listen for the theme changing so this - * customization can be removed (then re-applied only if necessary for the - * new theme). */ - g_signal_connect_swapped (gtk_settings, "notify::gtk-theme-name", G_CALLBACK (process_system_theme), gtk_settings); - - process_system_theme (gtk_settings); + nemo_theme_utils_init_styles (); } static gboolean @@ -631,7 +415,6 @@ nemo_application_quit_mainloop (GApplication *app) nemo_icon_info_clear_caches (); save_accel_map (NULL); g_object_unref (NEMO_APPLICATION (app)->undo_manager); - g_clear_object (&mandatory_css_provider); nemo_application_notify_unmount_done (NEMO_APPLICATION (app), NULL);