[gtk+] Bind the themes to the lifecycle of the screen



commit 1f5dea9eba4de5a54e9370fe8e4b90e6c0cec200
Author: William Jon McCann <jmccann redhat com>
Date:   Tue Sep 11 16:50:20 2012 -0400

    Bind the themes to the lifecycle of the screen
    
    https://bugzilla.gnome.org/show_bug.cgi?id=683896

 gtk/gtkcssprovider.c        |  311 ++++++++++++++++++++++++-------------------
 gtk/gtkcssprovider.h        |    3 +-
 gtk/gtkcssproviderprivate.h |    7 +-
 gtk/gtksettings.c           |    8 +-
 4 files changed, 187 insertions(+), 142 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index d4a3196..f91dbbe 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -2607,155 +2607,99 @@ _gtk_css_provider_load_from_resource (GtkCssProvider  *css_provider,
   return result;
 }
 
-/**
- * gtk_css_provider_get_default:
- *
- * Returns the provider containing the style settings used as a
- * fallback for all widgets.
- *
- * Returns: (transfer none): The provider used for fallback styling.
- *          This memory is owned by GTK+, and you must not free it.
- **/
-GtkCssProvider *
-gtk_css_provider_get_default (void)
-{
-  static GtkCssProvider *provider;
-
-  if (G_UNLIKELY (!provider))
-    {
-      provider = gtk_css_provider_new ();
-    }
-
-  return provider;
-}
-
-gchar *
-_gtk_css_provider_get_theme_dir (void)
+static char *
+_find_theme_path (const gchar    *name,
+                  const gchar    *variant)
 {
-  const gchar *var;
-  gchar *path;
-
-  var = g_getenv ("GTK_DATA_PREFIX");
+  gchar *subpath;
+  gchar *path = NULL;
 
-  if (var)
-    path = g_build_filename (var, "share", "themes", NULL);
+  if (variant)
+    subpath = g_strdup_printf ("gtk-3.0" G_DIR_SEPARATOR_S "gtk-%s.css", variant);
   else
-    path = g_build_filename (_gtk_get_data_prefix (), "share", "themes", NULL);
+    subpath = g_strdup ("gtk-3.0" G_DIR_SEPARATOR_S "gtk.css");
 
-  return path;
-}
-
-/**
- * gtk_css_provider_get_named:
- * @name: A theme name
- * @variant: (allow-none): variant to load, for example, "dark", or
- *     %NULL for the default
- *
- * Loads a theme from the usual theme paths
- *
- * Returns: (transfer none): a #GtkCssProvider with the theme loaded.
- *     This memory is owned by GTK+, and you must not free it.
- */
-GtkCssProvider *
-gtk_css_provider_get_named (const gchar *name,
-                            const gchar *variant)
-{
-  static GHashTable *themes = NULL;
-  GtkCssProvider *provider;
-  gchar *key;
-
-  if (variant == NULL)
-    key = (gchar *)name;
-  else
-    key = g_strconcat (name, "-", variant, NULL);
-
-  if (G_UNLIKELY (!themes))
-    themes = g_hash_table_new (g_str_hash, g_str_equal);
-
-  provider = g_hash_table_lookup (themes, key);
+  /* First look in the user's config directory
+   */
+  path = g_build_filename (g_get_user_data_dir (), "themes", name, subpath, NULL);
+  if (!g_file_test (path, G_FILE_TEST_EXISTS))
+    {
+      g_free (path);
+      path = NULL;
+    }
 
-  if (!provider)
+  /* Next look in the user's home directory
+   */
+  if (!path)
     {
-      gchar *resource_path = NULL;
+      const gchar *home_dir;
 
-      if (variant)
-        resource_path = g_strdup_printf ("/org/gtk/libgtk/%s-%s.css", name, variant);
-      else
-        resource_path = g_strdup_printf ("/org/gtk/libgtk/%s.css", name);
+      home_dir = g_get_home_dir ();
+      if (home_dir)
+        {
+          path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
 
-      if (g_resources_get_info (resource_path, 0, NULL, NULL, NULL))
-	{
-	  provider = gtk_css_provider_new ();
-	  if (!_gtk_css_provider_load_from_resource (provider, resource_path))
-	    {
-	      g_object_unref (provider);
-	      provider = NULL;
-	    }
-	}
-      g_free (resource_path);
+          if (!g_file_test (path, G_FILE_TEST_EXISTS))
+            {
+              g_free (path);
+              path = NULL;
+            }
+        }
     }
 
-  if (!provider)
+  if (!path)
     {
-      gchar *subpath, *path = NULL;
+      gchar *theme_dir;
 
-      if (variant)
-        subpath = g_strdup_printf ("gtk-3.0" G_DIR_SEPARATOR_S "gtk-%s.css", variant);
-      else
-        subpath = g_strdup ("gtk-3.0" G_DIR_SEPARATOR_S "gtk.css");
+      theme_dir = _gtk_css_provider_get_theme_dir ();
+      path = g_build_filename (theme_dir, name, subpath, NULL);
+      g_free (theme_dir);
 
-      /* First look in the user's config directory
-       */
-      path = g_build_filename (g_get_user_data_dir (), "themes", name, subpath, NULL);
       if (!g_file_test (path, G_FILE_TEST_EXISTS))
         {
           g_free (path);
           path = NULL;
         }
+    }
 
-      /* Next look in the user's home directory
-       */
-      if (!path)
-        {
-          const gchar *home_dir;
+  g_free (subpath);
 
-          home_dir = g_get_home_dir ();
-          if (home_dir)
-            {
-              path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
+  return path;
+}
 
-              if (!g_file_test (path, G_FILE_TEST_EXISTS))
-                {
-                  g_free (path);
-                  path = NULL;
-                }
-            }
-        }
+static gboolean
+_provider_load (GtkCssProvider *provider,
+                const gchar    *name,
+                const gchar    *variant)
+{
+  gchar *resource_path;
+  gboolean loaded = FALSE;
 
-      if (!path)
-        {
-          gchar *theme_dir;
+  g_assert (provider != NULL);
 
-          theme_dir = _gtk_css_provider_get_theme_dir ();
-          path = g_build_filename (theme_dir, name, subpath, NULL);
-          g_free (theme_dir);
+  if (variant)
+    resource_path = g_strdup_printf ("/org/gtk/libgtk/%s-%s.css", name, variant);
+  else
+    resource_path = g_strdup_printf ("/org/gtk/libgtk/%s.css", name);
 
-          if (!g_file_test (path, G_FILE_TEST_EXISTS))
-            {
-              g_free (path);
-              path = NULL;
-            }
-        }
+  if (g_resources_get_info (resource_path, 0, NULL, NULL, NULL))
+    {
+      loaded = _gtk_css_provider_load_from_resource (provider, resource_path);
+    }
+  g_free (resource_path);
 
-      g_free (subpath);
+  if (!loaded)
+    {
+      char *path;
+
+      path = _find_theme_path (name, variant);
 
       if (path)
         {
-          char *dir, *resource_file;
+          char *dir;
+          char *resource_file;
           GResource *resource;
 
-          provider = gtk_css_provider_new ();
-
           dir = g_path_get_dirname (path);
           resource_file = g_build_filename (dir, "gtk.gresource", NULL);
           resource = g_resource_load (resource_file, NULL);
@@ -2764,34 +2708,131 @@ gtk_css_provider_get_named (const gchar *name,
           if (resource != NULL)
             g_resources_register (resource);
 
-          if (!gtk_css_provider_load_from_path (provider, path, NULL))
+          loaded = gtk_css_provider_load_from_path (provider, path, NULL);
+          if (!loaded)
             {
-	      if (resource != NULL)
-		{
-		  g_resources_unregister (resource);
-		  g_resource_unref (resource);
-		}
-              g_object_unref (provider);
-              provider = NULL;
+              if (resource != NULL)
+                {
+                  g_resources_unregister (resource);
+                  g_resource_unref (resource);
+                }
             }
           else
-	    {
-	      /* Only set this after load success, as load_from_path will clear it */
-	      provider->priv->resource = resource;
-	      g_hash_table_insert (themes, g_strdup (key), provider);
-	    }
+            {
+              /* Only set this after load success, as load_from_path will clear it */
+              provider->priv->resource = resource;
+            }
 
-          g_free (path);
           g_free (dir);
         }
+      g_free (path);
+    }
+
+  return loaded;
+}
+
+static void
+destroy_theme_cache (GHashTable *themes)
+{
+  g_hash_table_destroy (themes);
+}
+
+/*
+ * _gtk_css_provider_get_named_for_screen:
+ * @screen: a #GdkScreen.
+ * @name: A theme name
+ * @variant: (allow-none): variant to load, for example, "dark", or
+ *     %NULL for the default
+ *
+ * Loads a theme from the usual theme paths
+ *
+ * Returns: (transfer none): a #GtkCssProvider with the theme loaded.
+ *     This memory is owned by GTK+, and you must not free it.
+ */
+GtkCssProvider *
+_gtk_css_provider_get_named_for_screen (GdkScreen   *screen,
+                                        const gchar *name,
+                                        const gchar *variant)
+{
+  GtkCssProvider *provider;
+  GHashTable *themes;
+  gchar *key;
+
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  themes = g_object_get_data (G_OBJECT (screen), "gtk-themes");
+  if (G_UNLIKELY (!themes))
+    {
+      themes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+      g_object_set_data_full (G_OBJECT (screen),
+                              I_("gtk-themes"),
+                              themes,
+                              (GDestroyNotify)destroy_theme_cache);
     }
 
-  if (key != name)
-    g_free (key);
+  if (name == NULL)
+    key = g_strdup ("");
+  else if (variant == NULL)
+    key = g_strdup (name);
+  else
+    key = g_strconcat (name, "-", variant, NULL);
+
+  provider = g_hash_table_lookup (themes, key);
+
+  if (!provider)
+    {
+      gboolean save = TRUE;
+
+      provider = gtk_css_provider_new ();
+
+      if (name != NULL)
+        save = _provider_load (provider, name, variant);
+
+      if (save)
+        g_hash_table_insert (themes, g_strdup (key), provider);
+    }
+
+  g_free (key);
 
   return provider;
 }
 
+/**
+ * gtk_css_provider_get_default:
+ *
+ * Returns the provider containing the style settings used as a
+ * fallback for all widgets.
+ *
+ * Returns: (transfer none): The provider used for fallback styling.
+ *          This memory is owned by GTK+, and you must not free it.
+ **/
+GtkCssProvider *
+gtk_css_provider_get_default (void)
+{
+  GdkScreen *screen = gdk_screen_get_default ();
+
+  if (screen)
+    return _gtk_css_provider_get_named_for_screen (screen, NULL, NULL);
+  else
+    return NULL;
+}
+
+gchar *
+_gtk_css_provider_get_theme_dir (void)
+{
+  const gchar *var;
+  gchar *path;
+
+  var = g_getenv ("GTK_DATA_PREFIX");
+
+  if (var)
+    path = g_build_filename (var, "share", "themes", NULL);
+  else
+    path = g_build_filename (_gtk_get_data_prefix (), "share", "themes", NULL);
+
+  return path;
+}
+
 static int
 compare_properties (gconstpointer a, gconstpointer b, gpointer style)
 {
diff --git a/gtk/gtkcssprovider.h b/gtk/gtkcssprovider.h
index db0222b..6349d42 100644
--- a/gtk/gtkcssprovider.h
+++ b/gtk/gtkcssprovider.h
@@ -86,8 +86,7 @@ gboolean         gtk_css_provider_load_from_path (GtkCssProvider  *css_provider,
                                                   const gchar     *path,
                                                   GError         **error);
 
-GtkCssProvider * gtk_css_provider_get_default (void);
-
+GtkCssProvider * gtk_css_provider_get_default    (void);
 GtkCssProvider * gtk_css_provider_get_named (const gchar *name,
                                              const gchar *variant);
 
diff --git a/gtk/gtkcssproviderprivate.h b/gtk/gtkcssproviderprivate.h
index 9a24254..240496a 100644
--- a/gtk/gtkcssproviderprivate.h
+++ b/gtk/gtkcssproviderprivate.h
@@ -22,7 +22,12 @@
 
 G_BEGIN_DECLS
 
-gchar *_gtk_css_provider_get_theme_dir (void);
+gchar *         _gtk_css_provider_get_theme_dir        (void);
+
+GtkCssProvider *_gtk_css_provider_get_named_for_screen (GdkScreen   *screen,
+                                                        const gchar *name,
+                                                        const gchar *variant);
+
 
 G_END_DECLS
 
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index cfcc192..b62534b 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -2928,15 +2928,15 @@ settings_update_theme (GtkSettings *settings)
   if (theme_name && *theme_name)
     {
       if (prefer_dark_theme)
-        provider = gtk_css_provider_get_named (theme_name, "dark");
+        provider = _gtk_css_provider_get_named_for_screen (priv->screen, theme_name, "dark");
 
       if (!provider)
-        provider = gtk_css_provider_get_named (theme_name, NULL);
+        provider = _gtk_css_provider_get_named_for_screen (priv->screen, theme_name, NULL);
     }
 
   /* If we didn't find the named theme, fall back */
   if (!provider)
-    provider = gtk_css_provider_get_named ("Raleigh", NULL);
+    provider = _gtk_css_provider_get_named_for_screen (priv->screen, "Raleigh", NULL);
 
   settings_update_provider (priv->screen, &priv->theme_provider, provider);
 
@@ -2971,7 +2971,7 @@ settings_update_key_theme (GtkSettings *settings)
                 NULL);
 
   if (key_theme_name && *key_theme_name)
-    provider = gtk_css_provider_get_named (key_theme_name, "keys");
+    provider = _gtk_css_provider_get_named_for_screen (priv->screen, key_theme_name, "keys");
 
   settings_update_provider (priv->screen, &priv->key_theme_provider, provider);
   g_free (key_theme_name);



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