[gnome-builder] theme: auto load theme overrides and icons for plugins



commit 77a17d14d866fa32e2e27e89b43f901922577be7
Author: Christian Hergert <chergert redhat com>
Date:   Tue Dec 1 23:55:14 2015 -0800

    theme: auto load theme overrides and icons for plugins
    
    Place theme overrides in:
    
     /org/gnome/builder/plugins/<plugin-name>/theme/
    
    and name them such as:
    
      Adwaita.css
      Adwaita-dark.css
      ...
    
    Place icons in:
    
      /org/gnome/builder/plugins/<plugin-name>/icons/scalable/icon-name.svg

 libide/Makefile.am               |    2 +
 libide/ide-application-private.h |    4 +-
 libide/ide-application.c         |    9 +--
 libide/ide-css-provider.c        |   84 ++++++++++++++++++---
 libide/ide-css-provider.h        |    2 +-
 libide/ide-theme-manager.c       |  157 ++++++++++++++++++++++++++++++++++++++
 libide/ide-theme-manager.h       |   34 ++++++++
 7 files changed, 274 insertions(+), 18 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 2886125..f68c4e2 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -317,6 +317,8 @@ libide_1_0_la_SOURCES = \
        ide-source-view-movements.h \
        ide-text-iter.c \
        ide-text-iter.h \
+       ide-theme-manager.c \
+       ide-theme-manager.h \
        ide-tree-private.h \
        ide-workbench-actions.c \
        ide-workbench-private.h \
diff --git a/libide/ide-application-private.h b/libide/ide-application-private.h
index 622bd74..5259a24 100644
--- a/libide/ide-application-private.h
+++ b/libide/ide-application-private.h
@@ -25,6 +25,7 @@
 #include "ide-application.h"
 #include "ide-keybindings.h"
 #include "ide-recent-projects.h"
+#include "ide-theme-manager.h"
 #include "ide-worker-manager.h"
 
 G_BEGIN_DECLS
@@ -42,7 +43,6 @@ struct _IdeApplication
   gchar              **tool_arguments;
 
   PeasPluginInfo      *worker;
-
   IdeWorkerManager    *worker_manager;
 
   IdeKeybindings      *keybindings;
@@ -50,6 +50,8 @@ struct _IdeApplication
   IdeRecentProjects   *recent_projects;
 
   GDateTime           *started_at;
+
+  IdeThemeManager     *theme_manager;
 };
 
 void     ide_application_discover_plugins   (IdeApplication   *self) G_GNUC_INTERNAL;
diff --git a/libide/ide-application.c b/libide/ide-application.c
index 6db7d8f..cb40426 100644
--- a/libide/ide-application.c
+++ b/libide/ide-application.c
@@ -41,6 +41,7 @@
 #include "ide-internal.h"
 #include "ide-macros.h"
 #include "ide-resources.h"
+#include "ide-theme-manager.h"
 #include "ide-workbench.h"
 #include "ide-worker.h"
 
@@ -84,14 +85,9 @@ ide_application_register_theme_overrides (IdeApplication *self)
 
   g_assert (IDE_IS_APPLICATION (self));
 
-  gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
-                                    "/org/gnome/builder/icons/");
+  self->theme_manager = ide_theme_manager_new ();
 
-  provider = ide_css_provider_new ();
   screen = gdk_screen_get_default ();
-  gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
-                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
-
   gtk_settings = gtk_settings_get_for_screen (screen);
   settings = g_settings_new ("org.gnome.builder");
   g_settings_bind (settings, "night-mode",
@@ -358,6 +354,7 @@ ide_application_finalize (GObject *object)
   g_clear_object (&self->worker_manager);
   g_clear_object (&self->keybindings);
   g_clear_object (&self->recent_projects);
+  g_clear_object (&self->theme_manager);
 
   G_OBJECT_CLASS (ide_application_parent_class)->finalize (object);
 }
diff --git a/libide/ide-css-provider.c b/libide/ide-css-provider.c
index 7495399..c617fa4 100644
--- a/libide/ide-css-provider.c
+++ b/libide/ide-css-provider.c
@@ -25,17 +25,27 @@
 
 struct _IdeCssProvider
 {
-  GtkCssProvider parent_instance;
-
-  GtkSettings *settings;
+  GtkCssProvider  parent_instance;
+  GtkSettings    *settings;
+  gchar          *base_path;
 };
 
 G_DEFINE_TYPE (IdeCssProvider, ide_css_provider, GTK_TYPE_CSS_PROVIDER)
 
+enum {
+  PROP_0,
+  PROP_BASE_PATH,
+  LAST_PROP
+};
+
+static GParamSpec *properties [LAST_PROP];
+
 GtkCssProvider *
-ide_css_provider_new (void)
+ide_css_provider_new (const gchar *base_path)
 {
-  return g_object_new (IDE_TYPE_CSS_PROVIDER, NULL);
+  return g_object_new (IDE_TYPE_CSS_PROVIDER,
+                       "base-path", base_path,
+                       NULL);
 }
 
 static void
@@ -57,16 +67,20 @@ ide_css_provider_update (IdeCssProvider *self)
                 "gtk-application-prefer-dark-theme", &prefer_dark_theme,
                 NULL);
 
-  resource_path = g_strdup_printf ("/org/gnome/builder/theme/%s%s.css",
-                                   theme_name,
-                                   prefer_dark_theme ? "-dark" : "");
+  resource_path = g_strdup_printf ("%s/theme/%s%s.css",
+                                   self->base_path,
+                                   theme_name, prefer_dark_theme ? "-dark" : "");
 
   if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &len, &flags, NULL))
     {
       g_free (resource_path);
-      resource_path = g_strdup ("/org/gnome/builder/theme/shared.css");
+      resource_path = g_strdup_printf ("%s/theme/shared.css", self->base_path);
     }
 
+  /* Nothing to load */
+  if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &len, &flags, NULL))
+    return;
+
   IDE_TRACE_MSG ("Loading css overrides \"%s\"", resource_path);
 
   gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (self), resource_path);
@@ -151,20 +165,70 @@ ide_css_provider_finalize (GObject *object)
   IdeCssProvider *self = (IdeCssProvider *)object;
 
   g_clear_object (&self->settings);
+  g_clear_pointer (&self->base_path, g_free);
 
   G_OBJECT_CLASS (ide_css_provider_parent_class)->finalize (object);
 }
 
 static void
+ide_css_provider_get_property (GObject    *object,
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  IdeCssProvider *self = IDE_CSS_PROVIDER(object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PATH:
+      g_value_set_string (value, self->base_path);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
+ide_css_provider_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  IdeCssProvider *self = IDE_CSS_PROVIDER(object);
+
+  switch (prop_id)
+    {
+    case PROP_BASE_PATH:
+      self->base_path = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
+static void
 ide_css_provider_class_init (IdeCssProviderClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkCssProviderClass *provider_class = GTK_CSS_PROVIDER_CLASS (klass);
 
-  object_class->finalize = ide_css_provider_finalize;
   object_class->constructed = ide_css_provider_constructed;
+  object_class->finalize = ide_css_provider_finalize;
+  object_class->get_property = ide_css_provider_get_property;
+  object_class->set_property = ide_css_provider_set_property;
 
   provider_class->parsing_error = ide_css_provider_parsing_error;
+
+  properties [PROP_BASE_PATH] =
+    g_param_spec_string ("base-path",
+                         "Base Path",
+                         "The base resource path to discover themes",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, LAST_PROP, properties);
 }
 
 static void
diff --git a/libide/ide-css-provider.h b/libide/ide-css-provider.h
index cd36e30..0c6b18a 100644
--- a/libide/ide-css-provider.h
+++ b/libide/ide-css-provider.h
@@ -27,7 +27,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCssProvider, ide_css_provider, IDE, CSS_PROVIDER, GtkCssProvider)
 
-GtkCssProvider *ide_css_provider_new (void);
+GtkCssProvider *ide_css_provider_new (const gchar *base_path);
 
 G_END_DECLS
 
diff --git a/libide/ide-theme-manager.c b/libide/ide-theme-manager.c
new file mode 100644
index 0000000..6d86407
--- /dev/null
+++ b/libide/ide-theme-manager.c
@@ -0,0 +1,157 @@
+/* ide-theme-manager.c
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-theme-manager"
+
+#include <libpeas/peas.h>
+
+#include "ide-css-provider.h"
+#include "ide-theme-manager.h"
+
+struct _IdeThemeManager
+{
+  GObject         parent_instance;
+
+  GtkCssProvider *app_provider;
+  GHashTable     *plugin_providers;
+};
+
+G_DEFINE_TYPE (IdeThemeManager, ide_theme_manager, G_TYPE_OBJECT)
+
+static void
+provider_destroy_notify (gpointer data)
+{
+  GtkStyleProvider *provider = data;
+  GdkScreen *screen = gdk_screen_get_default ();
+
+  g_assert (GTK_IS_STYLE_PROVIDER (provider));
+  g_assert (GDK_IS_SCREEN (screen));
+
+  gtk_style_context_remove_provider_for_screen (screen, provider);
+  g_object_unref (provider);
+}
+
+static void
+ide_theme_manager_load_plugin (IdeThemeManager *self,
+                               PeasPluginInfo  *plugin_info,
+                               PeasEngine      *engine)
+{
+  GtkCssProvider *provider;
+  const gchar *module_name;
+  GdkScreen *screen;
+  gchar *path;
+
+  g_assert (IDE_IS_THEME_MANAGER (self));
+  g_assert (plugin_info != NULL);
+  g_assert (PEAS_IS_ENGINE (engine));
+
+  module_name = peas_plugin_info_get_module_name (plugin_info);
+  screen = gdk_screen_get_default ();
+
+  path = g_strdup_printf ("/org/gnome/builder/plugins/%s", module_name);
+  provider = ide_css_provider_new (path);
+  gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1);
+  g_hash_table_insert (self->plugin_providers, g_strdup (module_name), provider);
+  g_free (path);
+
+  path = g_strdup_printf ("/org/gnome/builder/plugins/%s/icons/", module_name);
+  gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), path);
+  g_free (path);
+}
+
+static void
+ide_theme_manager_unload_plugin (IdeThemeManager *self,
+                                 PeasPluginInfo  *plugin_info,
+                                 PeasEngine      *engine)
+{
+  g_assert (IDE_IS_THEME_MANAGER (self));
+  g_assert (plugin_info != NULL);
+  g_assert (PEAS_IS_ENGINE (engine));
+
+  g_hash_table_remove (self->plugin_providers,
+                       peas_plugin_info_get_module_name (plugin_info));
+
+  /* XXX: No opposite to gtk_icon_theme_add_resource_path() */
+}
+
+static void
+ide_theme_manager_finalize (GObject *object)
+{
+  IdeThemeManager *self = (IdeThemeManager *)object;
+
+  g_clear_pointer (&self->app_provider, provider_destroy_notify);
+  g_clear_pointer (&self->plugin_providers, g_hash_table_unref);
+
+  G_OBJECT_CLASS (ide_theme_manager_parent_class)->finalize (object);
+}
+
+static void
+ide_theme_manager_class_init (IdeThemeManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_theme_manager_finalize;
+}
+
+static void
+ide_theme_manager_init (IdeThemeManager *self)
+{
+  PeasEngine *engine = peas_engine_get_default ();
+  GdkScreen *screen = gdk_screen_get_default ();
+  const GList *list;
+
+  self->plugin_providers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                                  provider_destroy_notify);
+
+  self->app_provider = ide_css_provider_new ("/org/gnome/builder");
+  gtk_style_context_add_provider_for_screen (screen,
+                                             GTK_STYLE_PROVIDER (self->app_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+  gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
+                                    "/org/gnome/builder/icons/");
+
+  g_signal_connect_object (engine,
+                           "load-plugin",
+                           G_CALLBACK (ide_theme_manager_load_plugin),
+                           self,
+                           G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (engine,
+                           "unload-plugin",
+                           G_CALLBACK (ide_theme_manager_unload_plugin),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  list = peas_engine_get_plugin_list (engine);
+
+  for (; list != NULL; list = list->next)
+    {
+      PeasPluginInfo *plugin_info = list->data;
+
+      if (peas_plugin_info_is_loaded (plugin_info))
+        ide_theme_manager_load_plugin (self, plugin_info, engine);
+    }
+}
+
+IdeThemeManager *
+ide_theme_manager_new (void)
+{
+  return g_object_new (IDE_TYPE_THEME_MANAGER, NULL);
+}
diff --git a/libide/ide-theme-manager.h b/libide/ide-theme-manager.h
new file mode 100644
index 0000000..6851834
--- /dev/null
+++ b/libide/ide-theme-manager.h
@@ -0,0 +1,34 @@
+/* ide-theme-manager.h
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_THEME_MANAGER_H
+#define IDE_THEME_MANAGER_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_THEME_MANAGER (ide_theme_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeThemeManager, ide_theme_manager, IDE, THEME_MANAGER, GObject)
+
+IdeThemeManager *ide_theme_manager_new (void);
+
+G_END_DECLS
+
+#endif /* IDE_THEME_MANAGER_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]