diff options
author | Benjamin Otte <otte@redhat.com> | 2012-03-16 05:14:41 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2012-04-17 08:59:07 +0200 |
commit | a2ded8b72a430b388d39718a920bf44413c1836c (patch) | |
tree | 85a736f0c9a884c66b898548de885a4d76525092 /gtk/gtkstylecascade.c | |
parent | 015e3a768f10e01f27adb426f78d76edcad5f89e (diff) | |
download | gtk+-a2ded8b72a430b388d39718a920bf44413c1836c.tar.gz |
styleprovider: Add a custom object for a list of style providers
This way, we don't have to do magic inside GtkStyleContext, but have a
real API.
As a cute bonus, this object implements GtkStyleProvider itself. So we
can just pretend there's only one provider.
Diffstat (limited to 'gtk/gtkstylecascade.c')
-rw-r--r-- | gtk/gtkstylecascade.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/gtk/gtkstylecascade.c b/gtk/gtkstylecascade.c new file mode 100644 index 0000000000..0c427ce819 --- /dev/null +++ b/gtk/gtkstylecascade.c @@ -0,0 +1,352 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2012 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "gtkstylecascadeprivate.h" + +#include "gtkstyleprovider.h" +#include "gtkstyleproviderprivate.h" + +typedef struct _GtkStyleCascadeIter GtkStyleCascadeIter; +typedef struct _GtkStyleProviderData GtkStyleProviderData; + +struct _GtkStyleCascadeIter { + int parent_index; /* pointing at last index that was returned, not next one that should be returned */ + int index; /* pointing at last index that was returned, not next one that should be returned */ +}; + +struct _GtkStyleProviderData +{ + GtkStyleProvider *provider; + guint priority; +}; + +static GtkStyleProvider * +gtk_style_cascade_iter_next (GtkStyleCascade *cascade, + GtkStyleCascadeIter *iter) +{ + if (iter->parent_index > 0) + { + if (iter->index > 0) + { + GtkStyleProviderData *data, *parent_data; + + data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1); + parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index - 1); + + if (data->priority >= parent_data->priority) + { + iter->index--; + return data->provider; + } + else + { + iter->parent_index--; + return parent_data->provider; + } + } + else + { + iter->parent_index--; + return g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index).provider; + } + } + else + { + if (iter->index > 0) + { + iter->index--; + return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider; + } + else + { + return NULL; + } + } +} + +static GtkStyleProvider * +gtk_style_cascade_iter_init (GtkStyleCascade *cascade, + GtkStyleCascadeIter *iter) +{ + iter->parent_index = cascade->parent ? cascade->parent->providers->len : 0; + iter->index = cascade->providers->len; + + return gtk_style_cascade_iter_next (cascade, iter); +} + +static GtkStyleProperties * +gtk_style_cascade_get_style (GtkStyleProvider *provider, + GtkWidgetPath *path) +{ + /* This function is not used anymore by GTK and nobody + * else is ever supposed to call it */ + g_warn_if_reached (); + return NULL; +} + +static gboolean +gtk_style_cascade_get_style_property (GtkStyleProvider *provider, + GtkWidgetPath *path, + GtkStateFlags state, + GParamSpec *pspec, + GValue *value) +{ + GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider); + GtkStyleCascadeIter iter; + GtkStyleProvider *item; + + for (item = gtk_style_cascade_iter_init (cascade, &iter); + item; + item = gtk_style_cascade_iter_next (cascade, &iter)) + { + if (gtk_style_provider_get_style_property (item, + path, + state, + pspec, + value)) + return TRUE; + } + + return FALSE; +} + +static GtkIconFactory * +gtk_style_cascade_get_icon_factory (GtkStyleProvider *provider, + GtkWidgetPath *path) +{ + /* If anyone ever implements get_icon_factory(), I'll + * look at this function. Until then I'll just: */ + return NULL; +} + +static void +gtk_style_cascade_provider_iface_init (GtkStyleProviderIface *iface) +{ + iface->get_style = gtk_style_cascade_get_style; + iface->get_style_property = gtk_style_cascade_get_style_property; + iface->get_icon_factory = gtk_style_cascade_get_icon_factory; +} + +static GtkSymbolicColor * +gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider, + const char *name) +{ + GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider); + GtkStyleCascadeIter iter; + GtkSymbolicColor *symbolic; + GtkStyleProvider *item; + + for (item = gtk_style_cascade_iter_init (cascade, &iter); + item; + item = gtk_style_cascade_iter_next (cascade, &iter)) + { + if (GTK_IS_STYLE_PROVIDER_PRIVATE (item)) + { + symbolic = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name); + if (symbolic) + return symbolic; + } + else + { + /* If somebody hits this code path, shout at them */ + } + } + + return NULL; +} + +static void +gtk_style_cascade_lookup (GtkStyleProviderPrivate *provider, + GtkWidgetPath *path, + GtkStateFlags state, + GtkCssLookup *lookup) +{ + GtkStyleCascade *cascade = GTK_STYLE_CASCADE (provider); + GtkStyleCascadeIter iter; + GtkStyleProvider *item; + + for (item = gtk_style_cascade_iter_init (cascade, &iter); + item; + item = gtk_style_cascade_iter_next (cascade, &iter)) + { + if (GTK_IS_STYLE_PROVIDER_PRIVATE (item)) + { + _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (item), + path, + state, + lookup); + } + else + { + GtkStyleProperties *provider_style = gtk_style_provider_get_style (item, path); + + if (provider_style) + { + _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (provider_style), + path, + state, + lookup); + g_object_unref (provider_style); + } + } + } +} + +static void +gtk_style_cascade_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface) +{ + iface->get_color = gtk_style_cascade_get_color; + iface->lookup = gtk_style_cascade_lookup; +} + +G_DEFINE_TYPE_EXTENDED (GtkStyleCascade, _gtk_style_cascade, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER, + gtk_style_cascade_provider_iface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER_PRIVATE, + gtk_style_cascade_provider_private_iface_init)); + +static void +gtk_style_cascade_dispose (GObject *object) +{ + GtkStyleCascade *cascade = GTK_STYLE_CASCADE (object); + + _gtk_style_cascade_set_parent (cascade, NULL); + g_array_unref (cascade->providers); + + G_OBJECT_CLASS (_gtk_style_cascade_parent_class)->dispose (object); +} + +static void +_gtk_style_cascade_class_init (GtkStyleCascadeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gtk_style_cascade_dispose; +} + +static void +style_provider_data_clear (gpointer data_) +{ + GtkStyleProviderData *data = data_; + + g_object_unref (data->provider); +} + +static void +_gtk_style_cascade_init (GtkStyleCascade *cascade) +{ + cascade->providers = g_array_new (FALSE, FALSE, sizeof (GtkStyleProviderData)); + g_array_set_clear_func (cascade->providers, style_provider_data_clear); +} + +GtkStyleCascade * +_gtk_style_cascade_new (void) +{ + return g_object_new (GTK_TYPE_STYLE_CASCADE, NULL); +} + +GtkStyleCascade * +_gtk_style_cascade_get_for_screen (GdkScreen *screen) +{ + GtkStyleCascade *cascade; + static GQuark quark = 0; + + g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); + + if (G_UNLIKELY (!quark)) + quark = g_quark_from_static_string ("gtk-style-cascade"); + + cascade = g_object_get_qdata (G_OBJECT (screen), quark); + if (cascade == NULL) + { + cascade = _gtk_style_cascade_new (); + g_object_set_qdata_full (G_OBJECT (screen), quark, cascade, g_object_unref); + } + + return cascade; +} + +void +_gtk_style_cascade_set_parent (GtkStyleCascade *cascade, + GtkStyleCascade *parent) +{ + g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade)); + g_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent)); + if (parent) + g_return_if_fail (parent->parent == NULL); + + if (cascade->parent == parent) + return; + + if (parent) + g_object_ref (parent); + + if (cascade->parent) + g_object_unref (cascade->parent); + + cascade->parent = parent; +} + +void +_gtk_style_cascade_add_provider (GtkStyleCascade *cascade, + GtkStyleProvider *provider, + guint priority) +{ + GtkStyleProviderData data; + guint i; + + g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade)); + g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + g_return_if_fail (GTK_STYLE_PROVIDER (cascade) != provider); + + data.provider = g_object_ref (provider); + data.priority = priority; + + /* ensure it gets removed first */ + _gtk_style_cascade_remove_provider (cascade, provider); + + for (i = 0; i < cascade->providers->len; i++) + { + if (g_array_index (cascade->providers, GtkStyleProviderData, i).priority > priority) + break; + } + g_array_insert_val (cascade->providers, i, data); +} + +void +_gtk_style_cascade_remove_provider (GtkStyleCascade *cascade, + GtkStyleProvider *provider) +{ + guint i; + + g_return_if_fail (GTK_IS_STYLE_CASCADE (cascade)); + g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider)); + + for (i = 0; i < cascade->providers->len; i++) + { + GtkStyleProviderData *data = &g_array_index (cascade->providers, GtkStyleProviderData, i); + + if (data->provider == provider) + { + g_array_remove_index (cascade->providers, i); + break; + } + } +} + |