Bind the themes to the lifecycle of the screen

https://bugzilla.gnome.org/show_bug.cgi?id=683896
This commit is contained in:
William Jon McCann 2012-09-11 16:50:20 -04:00 committed by Matthias Clasen
parent 5debed5ae2
commit 1f5dea9eba
4 changed files with 206 additions and 161 deletions

View File

@ -2607,97 +2607,12 @@ _gtk_css_provider_load_from_resource (GtkCssProvider *css_provider,
return result; return result;
} }
/** static char *
* gtk_css_provider_get_default: _find_theme_path (const gchar *name,
*
* 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)
{
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;
}
/**
* 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) const gchar *variant)
{ {
static GHashTable *themes = NULL; gchar *subpath;
GtkCssProvider *provider; gchar *path = NULL;
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);
if (!provider)
{
gchar *resource_path = NULL;
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_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 (!provider)
{
gchar *subpath, *path = NULL;
if (variant) if (variant)
subpath = g_strdup_printf ("gtk-3.0" G_DIR_SEPARATOR_S "gtk-%s.css", variant); subpath = g_strdup_printf ("gtk-3.0" G_DIR_SEPARATOR_S "gtk-%s.css", variant);
@ -2749,13 +2664,42 @@ gtk_css_provider_get_named (const gchar *name,
g_free (subpath); g_free (subpath);
return path;
}
static gboolean
_provider_load (GtkCssProvider *provider,
const gchar *name,
const gchar *variant)
{
gchar *resource_path;
gboolean loaded = FALSE;
g_assert (provider != NULL);
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_resources_get_info (resource_path, 0, NULL, NULL, NULL))
{
loaded = _gtk_css_provider_load_from_resource (provider, resource_path);
}
g_free (resource_path);
if (!loaded)
{
char *path;
path = _find_theme_path (name, variant);
if (path) if (path)
{ {
char *dir, *resource_file; char *dir;
char *resource_file;
GResource *resource; GResource *resource;
provider = gtk_css_provider_new ();
dir = g_path_get_dirname (path); dir = g_path_get_dirname (path);
resource_file = g_build_filename (dir, "gtk.gresource", NULL); resource_file = g_build_filename (dir, "gtk.gresource", NULL);
resource = g_resource_load (resource_file, NULL); resource = g_resource_load (resource_file, NULL);
@ -2764,34 +2708,131 @@ gtk_css_provider_get_named (const gchar *name,
if (resource != NULL) if (resource != NULL)
g_resources_register (resource); 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) if (resource != NULL)
{ {
g_resources_unregister (resource); g_resources_unregister (resource);
g_resource_unref (resource); g_resource_unref (resource);
} }
g_object_unref (provider);
provider = NULL;
} }
else else
{ {
/* Only set this after load success, as load_from_path will clear it */ /* Only set this after load success, as load_from_path will clear it */
provider->priv->resource = resource; provider->priv->resource = resource;
}
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 (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_hash_table_insert (themes, g_strdup (key), provider);
} }
g_free (path);
g_free (dir);
}
}
if (key != name)
g_free (key); g_free (key);
return provider; 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 static int
compare_properties (gconstpointer a, gconstpointer b, gpointer style) compare_properties (gconstpointer a, gconstpointer b, gpointer style)
{ {

View File

@ -87,7 +87,6 @@ gboolean gtk_css_provider_load_from_path (GtkCssProvider *css_provider,
GError **error); 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, GtkCssProvider * gtk_css_provider_get_named (const gchar *name,
const gchar *variant); const gchar *variant);

View File

@ -22,7 +22,12 @@
G_BEGIN_DECLS 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 G_END_DECLS

View File

@ -2928,15 +2928,15 @@ settings_update_theme (GtkSettings *settings)
if (theme_name && *theme_name) if (theme_name && *theme_name)
{ {
if (prefer_dark_theme) 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) 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 we didn't find the named theme, fall back */
if (!provider) 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); settings_update_provider (priv->screen, &priv->theme_provider, provider);
@ -2971,7 +2971,7 @@ settings_update_key_theme (GtkSettings *settings)
NULL); NULL);
if (key_theme_name && *key_theme_name) 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); settings_update_provider (priv->screen, &priv->key_theme_provider, provider);
g_free (key_theme_name); g_free (key_theme_name);