Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 245 additions & 0 deletions eel/eel-theme-utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
#include "eel-theme-utils.h"
#include "eel-string.h"

static GtkCssProvider *mandatory_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", 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 */
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
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);

gtk_style_context_reset_widgets (gdk_screen_get_default ());
g_free (theme_name);
}

gboolean
eel_theme_utils_theme_supports_desktop (void)
{
return theme_has_desktop_support;
}

void
eel_theme_utils_init_styles (void)
{
static gboolean initialized = FALSE;

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);

GtkSettings *gtk_settings = gtk_settings_get_default ();

g_signal_connect_swapped (gtk_settings, "notify::gtk-theme-name",
G_CALLBACK (process_theme), gtk_settings);

process_theme (gtk_settings);
}
9 changes: 9 additions & 0 deletions eel/eel-theme-utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef EEL_THEME_UTILS_H
#define EEL_THEME_UTILS_H

#include <gtk/gtk.h>

void eel_theme_utils_init_styles (void);
gboolean eel_theme_utils_theme_supports_desktop (void);

#endif /* EEL_THEME_UTILS_H */
1 change: 1 addition & 0 deletions eel/eel.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <eel/eel-self-checks.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string.h>
#include <eel/eel-theme-utils.h>
#include <eel/eel-vfs-extensions.h>

#endif /* EEL_H */
1 change: 1 addition & 0 deletions eel/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ eel_sources = [
'eel-self-checks.c',
'eel-stock-dialogs.c',
'eel-string.c',
'eel-theme-utils.c',
'eel-vfs-extensions.c',
]

Expand Down
2 changes: 1 addition & 1 deletion gresources/nemo-desktop-preferences.glade
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="margin_bottom">10</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0</property>
<property name="shadow_type">in</property>
Expand Down
39 changes: 36 additions & 3 deletions gresources/nemo-style-application.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,57 @@ NemoDesktopWindow GtkPaned {
-NemoIconContainer-activate-prelight-icon-label: true;
}

.nemo-desktop.nemo-canvas-item {
/* Shadow variant: Normal (traditional nemo default) */
.nemo-desktop.nemo-canvas-item.shadow-normal {
color: #eeeeee;
text-shadow: 1px 1px alpha(black, 0.8);
}

.nemo-desktop.nemo-canvas-item:hover {
/* 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;
}

.nemo-desktop.nemo-canvas-item:selected {
/* 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;
}

/* "Use current theme" hover/selected — provide highlight feedback
without forcing text color or shadow. Lower specificity (2 classes)
than shadow variants above (3 classes), so only applies when no
shadow class is set. */
.nemo-desktop.nemo-canvas-item:hover {
background-color: alpha(black, 0.5);
background-image: none;
}

.nemo-desktop.nemo-canvas-item:selected {
background-color: alpha(@theme_selected_bg_color, 0.8);
background-image: none;
}

/* EelEditableLabel (icon labels) */
.nemo-desktop.view .entry,
.nemo-desktop.view .entry:active,
Expand Down
Loading
Loading