GtkStyleContext: Add gtk_style_context_[add|remove]_provider_for_screen()

These functions allow per-screen style providers. also, the changed signal
will be emitted whenever a style context changes.
This commit is contained in:
Carlos Garnacho 2010-09-11 12:42:35 +02:00
parent f239704094
commit 49ac732a18
2 changed files with 186 additions and 69 deletions

View File

@ -28,6 +28,7 @@
#include "gtkthemingengine.h"
#include "gtkintl.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
#include "gtkanimationdescription.h"
#include "gtktimeline.h"
@ -119,6 +120,8 @@ enum {
guint signals[LAST_SIGNAL] = { 0 };
static GQuark provider_list_quark = 0;
static void gtk_style_context_finalize (GObject *object);
static void gtk_style_context_impl_set_property (GObject *object,
@ -484,24 +487,55 @@ gtk_style_context_impl_get_property (GObject *object,
}
}
GList *
find_next_candidate (GList *local,
GList *global)
{
if (local && global)
{
GtkStyleProviderData *local_data, *global_data;
local_data = local->data;
global_data = global->data;
if (local_data->priority >= global_data->priority)
return local;
else
return global;
}
else if (local)
return local;
else if (global)
return global;
return NULL;
}
static void
rebuild_properties (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
GList *list;
GList *elem, *list, *global_list = NULL;
priv = context->priv;
list = priv->providers;
if (priv->screen)
global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
gtk_style_set_clear (priv->store);
while (list)
while ((elem = find_next_candidate (list, global_list)) != NULL)
{
GtkStyleProviderData *data;
GtkStyleSet *provider_style;
data = list->data;
list = list->next;
data = elem->data;
if (elem == list)
list = list->next;
else
global_list = global_list->next;
provider_style = gtk_style_provider_get_style (data->provider,
priv->widget_path);
@ -525,7 +559,7 @@ static void
rebuild_icon_factories (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
GList *providers;
GList *elem, *list, *global_list = NULL;
priv = context->priv;
@ -533,12 +567,26 @@ rebuild_icon_factories (GtkStyleContext *context)
g_slist_free (priv->icon_factories);
priv->icon_factories = NULL;
for (providers = priv->providers_last; providers; providers = providers->prev)
list = priv->providers_last;
if (priv->screen)
{
global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
global_list = g_list_last (global_list);
}
while ((elem = find_next_candidate (list, global_list)) != NULL)
{
GtkIconFactory *factory;
GtkStyleProviderData *data;
data = providers->data;
data = elem->data;
if (elem == list)
list = list->prev;
else
global_list = global_list->prev;
factory = gtk_style_provider_get_icon_factory (data->provider,
priv->widget_path);
@ -547,28 +595,22 @@ rebuild_icon_factories (GtkStyleContext *context)
}
}
void
gtk_style_context_add_provider (GtkStyleContext *context,
GtkStyleProvider *provider,
guint priority)
static void
style_provider_add (GList **list,
GtkStyleProvider *provider,
guint priority)
{
GtkStyleContextPrivate *priv;
GtkStyleProviderData *new_data;
gboolean added = FALSE;
GList *list;
GList *l = *list;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
priv = context->priv;
new_data = style_provider_data_new (provider, priority);
list = priv->providers;
while (list)
while (l)
{
GtkStyleProviderData *data;
data = list->data;
data = l->data;
/* Provider was already attached to the style
* context, remove in order to add the new data
@ -577,11 +619,11 @@ gtk_style_context_add_provider (GtkStyleContext *context,
{
GList *link;
link = list;
list = list->next;
link = l;
l = l->next;
/* Remove and free link */
priv->providers = g_list_remove_link (priv->providers, link);
*list = g_list_remove_link (*list, link);
style_provider_data_free (link->data);
g_list_free_1 (link);
@ -591,24 +633,59 @@ gtk_style_context_add_provider (GtkStyleContext *context,
if (!added &&
data->priority > priority)
{
priv->providers = g_list_insert_before (priv->providers, list, new_data);
*list = g_list_insert_before (*list, l, new_data);
added = TRUE;
}
list = list->next;
l = l->next;
}
if (!added)
priv->providers = g_list_append (priv->providers, new_data);
*list = g_list_append (*list, new_data);
}
static gboolean
style_provider_remove (GList **list,
GtkStyleProvider *provider)
{
GList *l = *list;
while (l)
{
GtkStyleProviderData *data;
data = l->data;
if (data->provider == provider)
{
*list = g_list_remove_link (*list, l);
style_provider_data_free (l->data);
g_list_free_1 (l);
return TRUE;
}
l = l->next;
}
return FALSE;
}
void
gtk_style_context_add_provider (GtkStyleContext *context,
GtkStyleProvider *provider,
guint priority)
{
GtkStyleContextPrivate *priv;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
priv = context->priv;
style_provider_add (&priv->providers, provider, priority);
priv->providers_last = g_list_last (priv->providers);
if (priv->widget_path)
{
rebuild_properties (context);
clear_property_cache (context);
rebuild_icon_factories (context);
}
gtk_style_context_invalidate (context);
}
void
@ -616,45 +693,81 @@ gtk_style_context_remove_provider (GtkStyleContext *context,
GtkStyleProvider *provider)
{
GtkStyleContextPrivate *priv;
gboolean removed = FALSE;
GList *list;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
priv = context->priv;
list = priv->providers;
while (list)
{
GtkStyleProviderData *data;
data = list->data;
if (data->provider == provider)
{
priv->providers = g_list_remove_link (priv->providers, list);
style_provider_data_free (list->data);
g_list_free_1 (list);
removed = TRUE;
break;
}
list = list->next;
}
if (removed)
if (style_provider_remove (&priv->providers, provider))
{
priv->providers_last = g_list_last (priv->providers);
if (priv->widget_path)
{
rebuild_properties (context);
clear_property_cache (context);
rebuild_icon_factories (context);
}
gtk_style_context_invalidate (context);
}
}
static void
reset_toplevels (GdkScreen *screen)
{
GList *list, *toplevels;
toplevels = gtk_window_list_toplevels ();
g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
for (list = toplevels; list; list = list->next)
{
if (gtk_widget_get_screen (list->data) == screen)
gtk_widget_reset_style (list->data);
g_object_unref (list->data);
}
g_list_free (toplevels);
}
void
gtk_style_context_add_provider_for_screen (GdkScreen *screen,
GtkStyleProvider *provider,
guint priority)
{
GList *providers, *list;
g_return_if_fail (GDK_IS_SCREEN (screen));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
if (G_UNLIKELY (!provider_list_quark))
provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
style_provider_add (&list, provider, priority);
if (list != providers)
g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
reset_toplevels (screen);
}
void
gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
GtkStyleProvider *provider)
{
GList *providers, *list;
g_return_if_fail (GDK_IS_SCREEN (screen));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
if (G_UNLIKELY (!provider_list_quark))
return;
list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
if (style_provider_remove (&list, provider))
{
if (list != providers)
g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
reset_toplevels (screen);
}
}
@ -833,9 +946,7 @@ gtk_style_context_set_path (GtkStyleContext *context,
if (path)
{
priv->widget_path = gtk_widget_path_copy (path);
rebuild_properties (context);
clear_property_cache (context);
rebuild_icon_factories (context);
gtk_style_context_invalidate (context);
}
}
@ -1040,7 +1151,7 @@ gtk_style_context_set_class (GtkStyleContext *context,
if (priv->widget_path)
{
gtk_widget_path_iter_add_class (priv->widget_path, 0, class_name);
rebuild_properties (context);
gtk_style_context_invalidate (context);
}
}
}
@ -1074,7 +1185,7 @@ gtk_style_context_unset_class (GtkStyleContext *context,
if (priv->widget_path)
{
gtk_widget_path_iter_remove_class (priv->widget_path, 0, class_name);
rebuild_properties (context);
gtk_style_context_invalidate (context);
}
}
}
@ -1192,7 +1303,7 @@ gtk_style_context_set_region (GtkStyleContext *context,
if (priv->widget_path)
{
gtk_widget_path_iter_add_region (priv->widget_path, 0, class_name, flags);
rebuild_properties (context);
gtk_style_context_invalidate (context);
}
}
}
@ -1226,7 +1337,7 @@ gtk_style_context_unset_region (GtkStyleContext *context,
if (priv->widget_path)
{
gtk_widget_path_iter_remove_region (priv->widget_path, 0, class_name);
rebuild_properties (context);
gtk_style_context_invalidate (context);
}
}
}

View File

@ -51,6 +51,12 @@ struct GtkStyleContextClass
GType gtk_style_context_get_type (void) G_GNUC_CONST;
void gtk_style_context_add_provider_for_screen (GdkScreen *screen,
GtkStyleProvider *provider,
guint priority);
void gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
GtkStyleProvider *provider);
void gtk_style_context_add_provider (GtkStyleContext *context,
GtkStyleProvider *provider,
guint priority);