[libdazzle] shortcuts: add support for including external CSS resources



commit a8feaf6a659ca63c6800e3c9009b542d95319093
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jun 15 18:02:48 2017 -0700

    shortcuts: add support for including external CSS resources
    
    This can be handy for situations where we still rely on CSS for
    @bindingset type stuff. This will be necessary to incremntally port
    the VIM engine in Builder.

 src/shortcuts/dzl-shortcut-manager.c    |   22 ++++++-
 src/shortcuts/dzl-shortcut-private.h    |    2 +
 src/shortcuts/dzl-shortcut-theme-load.c |   26 +++++++
 src/shortcuts/dzl-shortcut-theme.c      |  114 +++++++++++++++++++++++++++++++
 src/shortcuts/dzl-shortcut-theme.h      |    4 +
 5 files changed, 166 insertions(+), 2 deletions(-)
---
diff --git a/src/shortcuts/dzl-shortcut-manager.c b/src/shortcuts/dzl-shortcut-manager.c
index 91e8b06..d8db57a 100644
--- a/src/shortcuts/dzl-shortcut-manager.c
+++ b/src/shortcuts/dzl-shortcut-manager.c
@@ -177,6 +177,7 @@ dzl_shortcut_manager_reload (DzlShortcutManager *self,
        */
       theme_name = g_strdup (dzl_shortcut_theme_get_name (priv->theme));
       parent_theme_name = g_strdup (dzl_shortcut_theme_get_parent_name (priv->theme));
+      _dzl_shortcut_theme_detach (priv->theme);
       g_clear_object (&priv->theme);
     }
 
@@ -282,10 +283,15 @@ dzl_shortcut_manager_finalize (GObject *object)
       priv->root = NULL;
     }
 
+  if (priv->theme != NULL)
+    {
+      _dzl_shortcut_theme_detach (priv->theme);
+      g_clear_object (&priv->theme);
+    }
+
   g_clear_pointer (&priv->seen_entries, g_hash_table_unref);
   g_clear_pointer (&priv->themes, g_ptr_array_unref);
   g_clear_pointer (&priv->user_dir, g_free);
-  g_clear_object (&priv->theme);
   g_clear_object (&priv->internal_theme);
 
   G_OBJECT_CLASS (dzl_shortcut_manager_parent_class)->finalize (object);
@@ -578,8 +584,20 @@ dzl_shortcut_manager_set_theme (DzlShortcutManager *self,
    * could be transitioning between incorrect contexts.
    */
 
-  if (g_set_object (&priv->theme, theme))
+  if (priv->theme != theme)
     {
+      if (priv->theme != NULL)
+        {
+          _dzl_shortcut_theme_detach (priv->theme);
+          g_clear_object (&priv->theme);
+        }
+
+      if (theme != NULL)
+        {
+          priv->theme = g_object_ref (theme);
+          _dzl_shortcut_theme_attach (priv->theme);
+        }
+
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_THEME]);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_THEME_NAME]);
     }
diff --git a/src/shortcuts/dzl-shortcut-private.h b/src/shortcuts/dzl-shortcut-private.h
index 837a91d..8f11f6c 100644
--- a/src/shortcuts/dzl-shortcut-private.h
+++ b/src/shortcuts/dzl-shortcut-private.h
@@ -103,6 +103,8 @@ gboolean               _dzl_gtk_widget_activate_action          (GtkWidget
                                                                  GVariant                   *parameter);
 GNode                 *_dzl_shortcut_manager_get_root           (DzlShortcutManager         *self);
 DzlShortcutTheme      *_dzl_shortcut_manager_get_internal_theme (DzlShortcutManager         *self);
+void                   _dzl_shortcut_theme_attach               (DzlShortcutTheme           *self);
+void                   _dzl_shortcut_theme_detach               (DzlShortcutTheme           *self);
 GtkTreeModel          *_dzl_shortcut_theme_create_model         (DzlShortcutTheme           *self);
 GHashTable            *_dzl_shortcut_theme_get_contexts         (DzlShortcutTheme           *self);
 void                   _dzl_shortcut_theme_set_manager          (DzlShortcutTheme           *self,
diff --git a/src/shortcuts/dzl-shortcut-theme-load.c b/src/shortcuts/dzl-shortcut-theme-load.c
index dc54f54..8b6e32e 100644
--- a/src/shortcuts/dzl-shortcut-theme-load.c
+++ b/src/shortcuts/dzl-shortcut-theme-load.c
@@ -544,6 +544,26 @@ theme_start_element (GMarkupParseContext  *context,
 
       load_state_add_action (state, name);
     }
+  else if (g_strcmp0 (element_name, "resource") == 0)
+    {
+      const gchar *path = NULL;
+      g_autofree gchar *full_path = NULL;
+
+      if (!load_state_check_type (state, LOAD_STATE_THEME, error))
+        return;
+
+      if (!g_markup_collect_attributes (element_name, attr_names, attr_values, error,
+                                        G_MARKUP_COLLECT_STRING, "path", &path,
+                                        G_MARKUP_COLLECT_INVALID))
+        return;
+
+      g_assert (state->self != NULL);
+
+      if (!g_str_has_prefix (path, "resource://"))
+        path = full_path = g_strdup_printf ("resource://%s", path);
+
+      dzl_shortcut_theme_add_css_resource (state->self, path);
+    }
 }
 
 static void
@@ -562,6 +582,12 @@ theme_end_element (GMarkupParseContext  *context,
       if (!load_state_check_type (state, LOAD_STATE_THEME, error))
         return;
     }
+  else if (g_strcmp0 (element_name, "resource") == 0)
+    {
+      /* nothing to pop, but we want to propagate any errors */
+      load_state_check_type (state, LOAD_STATE_THEME, error);
+      return;
+    }
   else if (g_strcmp0 (element_name, "property") == 0)
     {
       if (!load_state_check_type (state, LOAD_STATE_PROPERTY, error))
diff --git a/src/shortcuts/dzl-shortcut-theme.c b/src/shortcuts/dzl-shortcut-theme.c
index 80a30ee..fece545 100644
--- a/src/shortcuts/dzl-shortcut-theme.c
+++ b/src/shortcuts/dzl-shortcut-theme.c
@@ -18,6 +18,8 @@
 
 #define G_LOG_DOMAIN "dzl-shortcut-theme"
 
+#include <string.h>
+
 #include "shortcuts/dzl-shortcut-private.h"
 #include "shortcuts/dzl-shortcut-chord.h"
 #include "shortcuts/dzl-shortcut-theme.h"
@@ -43,6 +45,13 @@ typedef struct
   GHashTable *contexts;
 
   /*
+   * A list of additional CSS resources that should be ingreated with this
+   * theme so that everything is applied together. You might use this if
+   * some of your keytheme needs to use CSS keybinding resources.
+   */
+  GHashTable *resource_providers;
+
+  /*
    * Commands and actions can be mapped from a context or directly from the
    * theme for convenience (to avoid having to define them from every context).
    */
@@ -751,6 +760,22 @@ _dzl_shortcut_theme_merge (DzlShortcutTheme *self,
       _dzl_shortcut_context_merge (base_context, context);
     }
 
+  /* Merge any associated resources. */
+  if (layer_priv->resource_providers != NULL)
+    {
+      GHashTableIter iter;
+
+      if (priv->resource_providers == NULL)
+        priv->resource_providers = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
+
+      g_hash_table_iter_init (&iter, layer_priv->resource_providers);
+      while (g_hash_table_iter_next (&iter, &key, &value))
+        {
+          g_hash_table_iter_steal (&iter);
+          g_hash_table_insert (priv->resource_providers, key, value);
+        }
+    }
+
   /*
    * Copy our action and commands chords over. These are all const data, so no
    * need to be tricky about stealing data or what data we are safe to
@@ -759,3 +784,92 @@ _dzl_shortcut_theme_merge (DzlShortcutTheme *self,
   dzl_shortcut_chord_table_foreach (layer_priv->actions_table, copy_chord_to_table, priv->actions_table);
   dzl_shortcut_chord_table_foreach (layer_priv->commands_table, copy_chord_to_table, priv->commands_table);
 }
+
+void
+dzl_shortcut_theme_add_css_resource (DzlShortcutTheme *self,
+                                     const gchar      *path)
+{
+  DzlShortcutThemePrivate *priv = dzl_shortcut_theme_get_instance_private (self);
+  g_autoptr(GtkCssProvider) provider = NULL;
+
+  g_return_if_fail (DZL_IS_SHORTCUT_THEME (self));
+  g_return_if_fail (path != NULL);
+  g_return_if_fail (*path == '/' || g_str_has_prefix (path, "resource://"));
+
+  if (priv->resource_providers == NULL)
+    priv->resource_providers = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
+
+  path = g_intern_string (path);
+
+  provider = gtk_css_provider_new ();
+
+  if (g_str_has_prefix (path, "resource://"))
+    {
+      const gchar *adjpath = path + strlen ("resource://");
+
+      gtk_css_provider_load_from_resource (provider, adjpath);
+      g_hash_table_insert (priv->resource_providers, (gpointer)path, g_steal_pointer (&provider));
+    }
+  else
+    {
+      g_autoptr(GError) error = NULL;
+
+      if (!gtk_css_provider_load_from_path (provider, path, &error))
+        g_warning ("%s", error->message);
+      else
+        g_hash_table_insert (priv->resource_providers, (gpointer)path, g_steal_pointer (&provider));
+    }
+}
+
+void
+dzl_shortcut_theme_remove_css_resource (DzlShortcutTheme *self,
+                                        const gchar      *path)
+{
+  DzlShortcutThemePrivate *priv = dzl_shortcut_theme_get_instance_private (self);
+
+  g_return_if_fail (DZL_IS_SHORTCUT_THEME (self));
+  g_return_if_fail (path != NULL);
+
+  if (priv->resource_providers != NULL)
+    g_hash_table_remove (priv->resource_providers, g_intern_string (path));
+}
+
+void
+_dzl_shortcut_theme_attach (DzlShortcutTheme *self)
+{
+  DzlShortcutThemePrivate *priv = dzl_shortcut_theme_get_instance_private (self);
+
+  g_return_if_fail (DZL_IS_SHORTCUT_THEME (self));
+
+  if (priv->resource_providers != NULL)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      GtkStyleProvider *provider;
+      GHashTableIter iter;
+
+      g_hash_table_iter_init (&iter, priv->resource_providers);
+      while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&provider))
+        gtk_style_context_add_provider_for_screen (screen,
+                                                   provider,
+                                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    }
+}
+
+void
+_dzl_shortcut_theme_detach (DzlShortcutTheme *self)
+{
+  DzlShortcutThemePrivate *priv = dzl_shortcut_theme_get_instance_private (self);
+
+  g_return_if_fail (DZL_IS_SHORTCUT_THEME (self));
+
+  if (priv->resource_providers != NULL)
+    {
+      GdkScreen *screen = gdk_screen_get_default ();
+      GtkStyleProvider *provider;
+      GHashTableIter iter;
+
+      g_hash_table_iter_init (&iter, priv->resource_providers);
+      while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&provider))
+        gtk_style_context_remove_provider_for_screen (screen, provider);
+    }
+}
diff --git a/src/shortcuts/dzl-shortcut-theme.h b/src/shortcuts/dzl-shortcut-theme.h
index f869fee..25206eb 100644
--- a/src/shortcuts/dzl-shortcut-theme.h
+++ b/src/shortcuts/dzl-shortcut-theme.h
@@ -101,6 +101,10 @@ gboolean                dzl_shortcut_theme_save_to_path          (DzlShortcutThe
                                                                   const gchar             *path,
                                                                   GCancellable            *cancellable,
                                                                   GError                 **error);
+void                    dzl_shortcut_theme_add_css_resource      (DzlShortcutTheme        *self,
+                                                                  const gchar             *path);
+void                    dzl_shortcut_theme_remove_css_resource   (DzlShortcutTheme        *self,
+                                                                  const gchar             *path);
 
 G_END_DECLS
 


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