summaryrefslogtreecommitdiff
path: root/gtk/gtkstylecascade.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2012-03-16 05:14:41 +0100
committerBenjamin Otte <otte@redhat.com>2012-04-17 08:59:07 +0200
commita2ded8b72a430b388d39718a920bf44413c1836c (patch)
tree85a736f0c9a884c66b898548de885a4d76525092 /gtk/gtkstylecascade.c
parent015e3a768f10e01f27adb426f78d76edcad5f89e (diff)
downloadgtk+-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.c352
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;
+ }
+ }
+}
+