diff --git a/lib/Makefile.am b/lib/Makefile.am index 25f96cd8..00cbb718 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -174,6 +174,8 @@ libsysprof_ui_@API_VERSION@_la_SOURCES = \ sp-process-model-row.c \ sp-profiler-menu-button.c \ sp-recording-state-view.c \ + sp-theme-manager.c \ + sp-theme-manager.h \ sp-visualizer-list.c \ sp-visualizer-list.h \ sp-visualizer-row.c \ diff --git a/lib/resources/css/SpVisualizerView-Adwaita-dark.css b/lib/resources/css/SpVisualizerView-Adwaita-dark.css new file mode 100644 index 00000000..570457b2 --- /dev/null +++ b/lib/resources/css/SpVisualizerView-Adwaita-dark.css @@ -0,0 +1,6 @@ +visualizers list row { + background-color: #232729; + background-size: 8px 8px; + background-image: repeating-linear-gradient(0deg, #2e2e2e, #2e2e2e 1px, transparent 1px, transparent 8px), + repeating-linear-gradient(-90deg, #2e2e2e, #2e2e2e 1px, transparent 1px, transparent 8px); +} diff --git a/lib/resources/css/SpVisualizerView-Adwaita.css b/lib/resources/css/SpVisualizerView-Adwaita.css new file mode 100644 index 00000000..4a4f1a76 --- /dev/null +++ b/lib/resources/css/SpVisualizerView-Adwaita.css @@ -0,0 +1,7 @@ +visualizers list row { + background-color: #f6f7f8; + background-size: 8px 8px; + background-image: repeating-linear-gradient(0deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 8px), + repeating-linear-gradient(-90deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 8px); +} + diff --git a/lib/resources/css/shared.css b/lib/resources/css/SpVisualizerView-shared.css similarity index 100% rename from lib/resources/css/shared.css rename to lib/resources/css/SpVisualizerView-shared.css diff --git a/lib/resources/libsysprof.gresource.xml b/lib/resources/libsysprof.gresource.xml index a6f73c41..87a95ca4 100644 --- a/lib/resources/libsysprof.gresource.xml +++ b/lib/resources/libsysprof.gresource.xml @@ -1,7 +1,9 @@ - css/shared.css + css/SpVisualizerView-shared.css + css/SpVisualizerView-Adwaita.css + css/SpVisualizerView-Adwaita-dark.css ui/sp-callgraph-view.ui ui/sp-empty-state-view.ui diff --git a/lib/sp-theme-manager.c b/lib/sp-theme-manager.c new file mode 100644 index 00000000..8b61ed1a --- /dev/null +++ b/lib/sp-theme-manager.c @@ -0,0 +1,264 @@ +/* sp-theme-manager.c + * + * Copyright (C) 2016 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define G_LOG_DOMAIN "sp-theme-manager" + +#include "sp-theme-manager.h" + +struct _SpThemeManager +{ + GObject parent_instance; + GHashTable *theme_resources; + guint reload_source; + guint registered_signals : 1; +}; + +typedef struct +{ + guint id; + gchar *key; + gchar *theme_name; + gchar *variant; + gchar *resource; + GtkCssProvider *provider; +} ThemeResource; + +G_DEFINE_TYPE (SpThemeManager, sp_theme_manager, G_TYPE_OBJECT) + +static void +theme_resource_free (gpointer data) +{ + ThemeResource *theme_resource = data; + + if (theme_resource != NULL) + { + g_clear_pointer (&theme_resource->key, g_free); + g_clear_pointer (&theme_resource->theme_name, g_free); + g_clear_pointer (&theme_resource->variant, g_free); + g_clear_pointer (&theme_resource->resource, g_free); + + if (theme_resource->provider != NULL) + { + gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (theme_resource->provider)); + g_clear_object (&theme_resource->provider); + } + + g_slice_free (ThemeResource, theme_resource); + } +} + +static gboolean +theme_resource_matches (ThemeResource *theme_resource, + GtkSettings *settings) +{ + g_autofree gchar *theme_name = NULL; + gboolean dark_theme = FALSE; + + g_assert (theme_resource != NULL); + g_assert (GTK_IS_SETTINGS (settings)); + + if (theme_resource->theme_name == NULL) + return TRUE; + + g_object_get (settings, + "gtk-theme-name", &theme_name, + "gtk-application-prefer-dark-theme", &dark_theme, + NULL); + + if (g_strcmp0 (theme_name, theme_resource->theme_name) == 0) + { + if (dark_theme && g_strcmp0 ("dark", theme_resource->variant) == 0) + return TRUE; + + if (!dark_theme && (!theme_resource->variant || g_strcmp0 ("light", theme_resource->variant) == 0)) + return TRUE; + } + + return FALSE; +} + +static gboolean +sp_theme_manager_do_reload (gpointer data) +{ + SpThemeManager *self = data; + ThemeResource *theme_resource; + GHashTableIter iter; + GtkSettings *settings; + + g_assert (SP_IS_THEME_MANAGER (self)); + + self->reload_source = 0; + + settings = gtk_settings_get_default (); + + g_hash_table_iter_init (&iter, self->theme_resources); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&theme_resource)) + { + if (theme_resource_matches (theme_resource, settings)) + { + if (theme_resource->provider == NULL) + { + theme_resource->provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (theme_resource->provider, theme_resource->resource); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (theme_resource->provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - 1); + g_print ("Registered resource file %s\n", theme_resource->resource); + } + } + else + { + if (theme_resource->provider != NULL) + { + gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (theme_resource->provider)); + g_clear_object (&theme_resource->provider); + g_print ("Unregistered resource file %s\n", theme_resource->resource); + } + } + } + + return G_SOURCE_REMOVE; +} + +static void +sp_theme_manager_queue_reload (SpThemeManager *self) +{ + g_assert (SP_IS_THEME_MANAGER (self)); + + if (self->reload_source == 0) + self->reload_source = gdk_threads_add_idle_full (G_PRIORITY_LOW, + sp_theme_manager_do_reload, + self, + NULL); +} + +static void +sp_theme_manager_finalize (GObject *object) +{ + SpThemeManager *self = (SpThemeManager *)object; + + if (self->reload_source != 0) + { + g_source_remove (self->reload_source); + self->reload_source = 0; + } + + g_clear_pointer (&self->theme_resources, g_hash_table_unref); + + G_OBJECT_CLASS (sp_theme_manager_parent_class)->finalize (object); +} + +static void +sp_theme_manager_class_init (SpThemeManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sp_theme_manager_finalize; +} + +static void +sp_theme_manager_init (SpThemeManager *self) +{ + self->theme_resources = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, theme_resource_free); +} + +/** + * sp_theme_manager_get_default: + * + * Returns: (transfer none): An #SpThemeManager + */ +SpThemeManager * +sp_theme_manager_get_default (void) +{ + static SpThemeManager *instance; + + if (instance == NULL) + instance = g_object_new (SP_TYPE_THEME_MANAGER, NULL); + + return instance; +} + +guint +sp_theme_manager_register_resource (SpThemeManager *self, + const gchar *theme_name, + const gchar *variant, + const gchar *resource) +{ + ThemeResource *theme_resource; + static guint counter; + guint id; + + g_return_val_if_fail (SP_IS_THEME_MANAGER (self), 0); + + theme_resource = g_slice_new0 (ThemeResource); + theme_resource->id = id = ++counter; + theme_resource->key = g_strdup_printf ("%s-%s-%d", + theme_name ? theme_name : "shared", + variant ? variant : "light", + theme_resource->id); + theme_resource->theme_name = g_strdup (theme_name); + theme_resource->variant = g_strdup (variant); + theme_resource->resource = g_strdup (resource); + theme_resource->provider = NULL; + + g_hash_table_insert (self->theme_resources, theme_resource->key, theme_resource); + + if (!self->registered_signals) + { + self->registered_signals = TRUE; + g_signal_connect_object (gtk_settings_get_default (), + "notify::gtk-application-prefer-dark-theme", + G_CALLBACK (sp_theme_manager_queue_reload), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (gtk_settings_get_default (), + "notify::gtk-theme-name", + G_CALLBACK (sp_theme_manager_queue_reload), + self, + G_CONNECT_SWAPPED); + } + + sp_theme_manager_queue_reload (self); + + return id; +} + +void +sp_theme_manager_unregister (SpThemeManager *self, + guint registration_id) +{ + GHashTableIter iter; + ThemeResource *theme_resource; + + g_return_if_fail (SP_IS_THEME_MANAGER (self)); + + g_hash_table_iter_init (&iter, self->theme_resources); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&theme_resource)) + { + if (theme_resource->id == registration_id) + { + /* Provider is unregistered during destroy */ + g_hash_table_iter_remove (&iter); + break; + } + } +} diff --git a/lib/sp-theme-manager.h b/lib/sp-theme-manager.h new file mode 100644 index 00000000..c01098b4 --- /dev/null +++ b/lib/sp-theme-manager.h @@ -0,0 +1,40 @@ +/* sp-theme-manager.h + * + * Copyright (C) 2016 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SP_THEME_MANAGER_H +#define SP_THEME_MANAGER_H + +#include + +G_BEGIN_DECLS + +#define SP_TYPE_THEME_MANAGER (sp_theme_manager_get_type()) + +G_DECLARE_FINAL_TYPE (SpThemeManager, sp_theme_manager, SP, THEME_MANAGER, GObject) + +SpThemeManager *sp_theme_manager_get_default (void); +void sp_theme_manager_unregister (SpThemeManager *self, + guint registration_id); +guint sp_theme_manager_register_resource (SpThemeManager *self, + const gchar *theme_name, + const gchar *variant, + const gchar *resource); + +G_END_DECLS + +#endif /* SP_THEME_MANAGER_H */ diff --git a/lib/sp-visualizer-view.c b/lib/sp-visualizer-view.c index c39521de..c8dbf509 100644 --- a/lib/sp-visualizer-view.c +++ b/lib/sp-visualizer-view.c @@ -20,6 +20,7 @@ #include +#include "sp-theme-manager.h" #include "sp-visualizer-list.h" #include "sp-visualizer-row.h" #include "sp-visualizer-row-private.h" @@ -76,7 +77,6 @@ G_DEFINE_TYPE_EXTENDED (SpVisualizerView, sp_visualizer_view, GTK_TYPE_BIN, 0, static GParamSpec *properties [N_PROPS]; static guint signals [N_SIGNALS]; static GtkBuildableIface *parent_buildable; -static GtkCssProvider *css_provider; static void find_row1 (GtkWidget *widget, @@ -476,6 +476,7 @@ sp_visualizer_view_class_init (SpVisualizerViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + SpThemeManager *theme_manager = sp_theme_manager_get_default (); object_class->finalize = sp_visualizer_view_finalize; object_class->get_property = sp_visualizer_view_get_property; @@ -523,11 +524,9 @@ sp_visualizer_view_class_init (SpVisualizerViewClass *klass) gtk_widget_class_set_css_name (widget_class, "visualizers"); - css_provider = gtk_css_provider_new (); - gtk_css_provider_load_from_resource (css_provider, "/org/gnome/sysprof/css/shared.css"); - gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), - GTK_STYLE_PROVIDER (css_provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION-1); + sp_theme_manager_register_resource (theme_manager, NULL, NULL, "/org/gnome/sysprof/css/SpVisualizerView-shared.css"); + sp_theme_manager_register_resource (theme_manager, "Adwaita", NULL, "/org/gnome/sysprof/css/SpVisualizerView-Adwaita.css"); + sp_theme_manager_register_resource (theme_manager, "Adwaita", "dark", "/org/gnome/sysprof/css/SpVisualizerView-Adwaita-dark.css"); } static void diff --git a/src/resources/theme/shared.css b/src/resources/theme/shared.css index 94da589d..66495490 100644 --- a/src/resources/theme/shared.css +++ b/src/resources/theme/shared.css @@ -15,11 +15,6 @@ visualizers list { background: @theme_bg_color; } -visualizers list row { - background: @content_view_bg; - border-bottom: 1px solid alpha(@borders, 0.2); -} - visualizers list row:backdrop, visualizers list row:last-child { border-bottom: none;