summaryrefslogtreecommitdiff
path: root/gtk/gtkcssprovider.c
diff options
context:
space:
mode:
authorWilliam Jon McCann <jmccann@redhat.com>2012-09-11 16:50:20 -0400
committerMatthias Clasen <mclasen@redhat.com>2012-09-16 20:20:44 -0400
commit1f5dea9eba4de5a54e9370fe8e4b90e6c0cec200 (patch)
treed6d730f4658a3ee101a746c23623b7dd72c6a85e /gtk/gtkcssprovider.c
parent5debed5ae247c1dd440cb71d0a6d328df74b0844 (diff)
downloadgtk+-1f5dea9eba4de5a54e9370fe8e4b90e6c0cec200.tar.gz
Bind the themes to the lifecycle of the screen
https://bugzilla.gnome.org/show_bug.cgi?id=683896
Diffstat (limited to 'gtk/gtkcssprovider.c')
-rw-r--r--gtk/gtkcssprovider.c311
1 files changed, 176 insertions, 135 deletions
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index d4a3196a56..f91dbbe3eb 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)
{