[gtk+/wip/css: 4/14] styleprovider: Add a custom object for a list of style providers



commit 66335f66575384ac7ff9a0057eca65cb464a1f7e
Author: Benjamin Otte <otte redhat com>
Date:   Fri Mar 16 05:14:41 2012 +0100

    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.

 gtk/Makefile.am              |    2 +
 gtk/gtkstylecascade.c        |  352 +++++++++++++++++++++++++++++++++++++++++
 gtk/gtkstylecascadeprivate.h |   66 ++++++++
 gtk/gtkstylecontext.c        |  356 +++++++++---------------------------------
 4 files changed, 491 insertions(+), 285 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index e40232e..3aac754 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -490,6 +490,7 @@ gtk_private_h_sources =		\
 	gtkshadowprivate.h      \
 	gtksizegroup-private.h	\
 	gtksocketprivate.h	\
+	gtkstylecascadeprivate.h \
 	gtkstylecontextprivate.h \
 	gtkstylepropertiesprivate.h \
 	gtkstylepropertyprivate.h \
@@ -755,6 +756,7 @@ gtk_base_c_sources = 		\
 	gtkstatusbar.c		\
 	gtkstatusicon.c		\
 	gtkstock.c		\
+	gtkstylecascade.c	\
 	gtkstylecontext.c	\
 	gtkstyleproperties.c	\
 	gtkstyleproperty.c	\
diff --git a/gtk/gtkstylecascade.c b/gtk/gtkstylecascade.c
new file mode 100644
index 0000000..a0cdfe5
--- /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;
+  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;
+        }
+    }
+}
+
diff --git a/gtk/gtkstylecascadeprivate.h b/gtk/gtkstylecascadeprivate.h
new file mode 100644
index 0000000..cd29025
--- /dev/null
+++ b/gtk/gtkstylecascadeprivate.h
@@ -0,0 +1,66 @@
+/* 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/>.
+ */
+
+#ifndef __GTK_STYLECASCADE_PRIVATE_H__
+#define __GTK_STYLECASCADE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkstyleproviderprivate.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_STYLE_CASCADE           (_gtk_style_cascade_get_type ())
+#define GTK_STYLE_CASCADE(obj)           (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_STYLE_CASCADE, GtkStyleCascade))
+#define GTK_STYLE_CASCADE_CLASS(cls)     (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_STYLE_CASCADE, GtkStyleCascadeClass))
+#define GTK_IS_STYLE_CASCADE(obj)        (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_STYLE_CASCADE))
+#define GTK_IS_STYLE_CASCADE_CLASS(obj)  (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_STYLE_CASCADE))
+#define GTK_STYLE_CASCADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_STYLE_CASCADE, GtkStyleCascadeClass))
+
+typedef struct _GtkStyleCascade           GtkStyleCascade;
+typedef struct _GtkStyleCascadeClass      GtkStyleCascadeClass;
+
+struct _GtkStyleCascade
+{
+  GObject object;
+
+  GtkStyleCascade *parent;
+  GArray *providers;
+};
+
+struct _GtkStyleCascadeClass
+{
+  GObjectClass  parent_class;
+};
+
+GType                 _gtk_style_cascade_get_type               (void) G_GNUC_CONST;
+
+GtkStyleCascade *     _gtk_style_cascade_new                    (void);
+GtkStyleCascade *     _gtk_style_cascade_get_for_screen         (GdkScreen           *screen);
+
+void                  _gtk_style_cascade_set_parent             (GtkStyleCascade     *cascade,
+                                                                 GtkStyleCascade     *parent);
+
+void                  _gtk_style_cascade_add_provider           (GtkStyleCascade     *cascade,
+                                                                 GtkStyleProvider    *provider,
+                                                                 guint                priority);
+void                  _gtk_style_cascade_remove_provider        (GtkStyleCascade     *cascade,
+                                                                 GtkStyleProvider    *provider);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_STYLECASCADE_PRIVATE_H__ */
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 6a20656..c09121f 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -36,6 +36,7 @@
 #include "gtkiconfactory.h"
 #include "gtkwidgetpath.h"
 #include "gtkwidgetprivate.h"
+#include "gtkstylecascadeprivate.h"
 #include "gtkstyleproviderprivate.h"
 #include "gtksettings.h"
 
@@ -300,7 +301,6 @@
  * </refsect2>
  */
 
-typedef struct GtkStyleProviderData GtkStyleProviderData;
 typedef struct GtkStyleInfo GtkStyleInfo;
 typedef struct GtkRegion GtkRegion;
 typedef struct PropertyValue PropertyValue;
@@ -313,12 +313,6 @@ struct GtkRegion
   GtkRegionFlags flags;
 };
 
-struct GtkStyleProviderData
-{
-  GtkStyleProvider *provider;
-  guint priority;
-};
-
 struct PropertyValue
 {
   GType       widget_type;
@@ -364,8 +358,7 @@ struct _GtkStyleContextPrivate
 {
   GdkScreen *screen;
 
-  GList *providers;
-  GList *providers_last;
+  GtkStyleCascade *cascade;
 
   GtkStyleContext *parent;
   GtkWidgetPath *widget_path;
@@ -629,32 +622,14 @@ gtk_style_context_init (GtkStyleContext *style_context)
   priv->direction = GTK_TEXT_DIR_LTR;
 
   priv->screen = gdk_screen_get_default ();
+  priv->cascade = _gtk_style_cascade_get_for_screen (priv->screen);
+  g_object_ref (priv->cascade);
 
   /* Create default info store */
   info = style_info_new ();
   priv->info_stack = g_slist_prepend (priv->info_stack, info);
 }
 
-static GtkStyleProviderData *
-style_provider_data_new (GtkStyleProvider *provider,
-                         guint             priority)
-{
-  GtkStyleProviderData *data;
-
-  data = g_slice_new (GtkStyleProviderData);
-  data->provider = g_object_ref (provider);
-  data->priority = priority;
-
-  return data;
-}
-
-static void
-style_provider_data_free (GtkStyleProviderData *data)
-{
-  g_object_unref (data->provider);
-  g_slice_free (GtkStyleProviderData, data);
-}
-
 static void
 animation_info_free (AnimationInfo *info)
 {
@@ -828,7 +803,7 @@ gtk_style_context_finalize (GObject *object)
 
   g_hash_table_destroy (priv->style_data);
 
-  g_list_free_full (priv->providers, (GDestroyNotify) style_provider_data_free);
+  g_object_unref (priv->cascade);
 
   g_slist_free_full (priv->info_stack, (GDestroyNotify) style_info_free);
 
@@ -904,30 +879,6 @@ gtk_style_context_impl_get_property (GObject    *object,
     }
 }
 
-static 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 global;
-      else
-        return local;
-    }
-  else if (local)
-    return local;
-  else if (global)
-    return global;
-
-  return NULL;
-}
-
 static void
 build_properties (GtkStyleContext *context,
                   StyleData       *style_data,
@@ -935,53 +886,16 @@ build_properties (GtkStyleContext *context,
                   GtkStateFlags    state)
 {
   GtkStyleContextPrivate *priv;
-  GList *elem, *list, *global_list = NULL;
   GtkCssLookup *lookup;
 
   priv = context->priv;
-  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);
-    }
 
   lookup = _gtk_css_lookup_new ();
 
-  while ((elem = find_next_candidate (list, global_list)) != NULL)
-    {
-      GtkStyleProviderData *data;
-      GtkStyleProperties *provider_style;
-
-      data = elem->data;
-
-      if (elem == list)
-        list = list->prev;
-      else
-        global_list = global_list->prev;
-
-      if (GTK_IS_STYLE_PROVIDER_PRIVATE (data->provider))
-        {
-          _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (data->provider),
-                                              path,
-                                              state,
-                                              lookup);
-        }
-      else
-        {
-          provider_style = gtk_style_provider_get_style (data->provider, path);
-
-          if (provider_style)
-            {
-              _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (provider_style),
-                                                  path,
-                                                  state,
-                                                  lookup);
-              g_object_unref (provider_style);
-            }
-        }
-    }
+  _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+                                      path,
+                                      state,
+                                      lookup);
 
   style_data->store = _gtk_css_computed_values_new ();
   _gtk_css_lookup_resolve (lookup, context, style_data->store);
@@ -1086,82 +1000,6 @@ style_data_lookup (GtkStyleContext *context,
   return data;
 }
 
-static void
-style_provider_add (GList            **list,
-                    GtkStyleProvider  *provider,
-                    guint              priority)
-{
-  GtkStyleProviderData *new_data;
-  gboolean added = FALSE;
-  GList *l = *list;
-
-  new_data = style_provider_data_new (provider, priority);
-
-  while (l)
-    {
-      GtkStyleProviderData *data;
-
-      data = l->data;
-
-      /* Provider was already attached to the style
-       * context, remove in order to add the new data
-       */
-      if (data->provider == provider)
-        {
-          GList *link;
-
-          link = l;
-          l = l->next;
-
-          /* Remove and free link */
-          *list = g_list_remove_link (*list, link);
-          style_provider_data_free (link->data);
-          g_list_free_1 (link);
-
-          continue;
-        }
-
-      if (!added &&
-          data->priority > priority)
-        {
-          *list = g_list_insert_before (*list, l, new_data);
-          added = TRUE;
-        }
-
-      l = l->next;
-    }
-
-  if (!added)
-    *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;
-}
-
 /**
  * gtk_style_context_new:
  *
@@ -1213,8 +1051,18 @@ gtk_style_context_add_provider (GtkStyleContext  *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->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+    {
+      GtkStyleCascade *new_cascade;
+      
+      new_cascade = _gtk_style_cascade_new ();
+      _gtk_style_cascade_set_parent (new_cascade, priv->cascade);
+      g_object_unref (priv->cascade);
+      priv->cascade = new_cascade;
+    }
+
+  _gtk_style_cascade_add_provider (priv->cascade, provider, priority);
 
   gtk_style_context_invalidate (context);
 }
@@ -1239,12 +1087,10 @@ gtk_style_context_remove_provider (GtkStyleContext  *context,
 
   priv = context->priv;
 
-  if (style_provider_remove (&priv->providers, provider))
-    {
-      priv->providers_last = g_list_last (priv->providers);
+  if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+    return;
 
-      gtk_style_context_invalidate (context);
-    }
+  _gtk_style_cascade_remove_provider (priv->cascade, provider);
 }
 
 /**
@@ -1309,21 +1155,13 @@ gtk_style_context_add_provider_for_screen (GdkScreen        *screen,
                                            GtkStyleProvider *provider,
                                            guint             priority)
 {
-  GList *providers, *list;
+  GtkStyleCascade *cascade;
 
   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);
-
-  gtk_style_context_reset_widgets (screen);
+  cascade = _gtk_style_cascade_get_for_screen (screen);
+  _gtk_style_cascade_add_provider (cascade, provider, priority);
 }
 
 /**
@@ -1339,23 +1177,13 @@ void
 gtk_style_context_remove_provider_for_screen (GdkScreen        *screen,
                                               GtkStyleProvider *provider)
 {
-  GList *providers, *list;
+  GtkStyleCascade *cascade;
 
   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);
-
-      gtk_style_context_reset_widgets (screen);
-    }
+  cascade = _gtk_style_cascade_get_for_screen (screen);
+  _gtk_style_cascade_remove_provider (cascade, provider);
 }
 
 /**
@@ -2396,64 +2224,47 @@ _gtk_style_context_peek_style_property (GtkStyleContext *context,
 
   if (priv->widget_path)
     {
-      GList *list, *global, *elem;
-
-      list = priv->providers_last;
-      global = global_list;
-
-      while ((elem = find_next_candidate (list, global)) != NULL)
+      if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade),
+                                                 priv->widget_path, state,
+                                                 pspec, &pcache->value))
         {
-          GtkStyleProviderData *provider_data;
-
-          provider_data = elem->data;
-
-          if (elem == list)
-            list = list->prev;
-          else
-            global = global->prev;
-
-          if (gtk_style_provider_get_style_property (provider_data->provider,
-                                                     priv->widget_path, state,
-                                                     pspec, &pcache->value))
+          /* Resolve symbolic colors to GdkColor/GdkRGBA */
+          if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
             {
-              /* Resolve symbolic colors to GdkColor/GdkRGBA */
-              if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
-                {
-                  GtkSymbolicColor *color;
-                  GdkRGBA rgba;
+              GtkSymbolicColor *color;
+              GdkRGBA rgba;
+
+              color = g_value_dup_boxed (&pcache->value);
 
-                  color = g_value_dup_boxed (&pcache->value);
+              g_value_unset (&pcache->value);
 
-                  g_value_unset (&pcache->value);
+              if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
+                g_value_init (&pcache->value, GDK_TYPE_RGBA);
+              else
+                g_value_init (&pcache->value, GDK_TYPE_COLOR);
 
+              if (_gtk_style_context_resolve_color (context, color, &rgba))
+                {
                   if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
-                    g_value_init (&pcache->value, GDK_TYPE_RGBA);
+                    g_value_set_boxed (&pcache->value, &rgba);
                   else
-                    g_value_init (&pcache->value, GDK_TYPE_COLOR);
-
-                  if (_gtk_style_context_resolve_color (context, color, &rgba))
                     {
-                      if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
-                        g_value_set_boxed (&pcache->value, &rgba);
-                      else
-                        {
-                          GdkColor rgb;
-
-                          rgb.red = rgba.red * 65535. + 0.5;
-                          rgb.green = rgba.green * 65535. + 0.5;
-                          rgb.blue = rgba.blue * 65535. + 0.5;
-
-                          g_value_set_boxed (&pcache->value, &rgb);
-                        }
-                    }
-                  else
-                    g_param_value_set_default (pspec, &pcache->value);
+                      GdkColor rgb;
+
+                      rgb.red = rgba.red * 65535. + 0.5;
+                      rgb.green = rgba.green * 65535. + 0.5;
+                      rgb.blue = rgba.blue * 65535. + 0.5;
 
-                  gtk_symbolic_color_unref (color);
+                      g_value_set_boxed (&pcache->value, &rgb);
+                    }
                 }
+              else
+                g_param_value_set_default (pspec, &pcache->value);
 
-              return &pcache->value;
+              gtk_symbolic_color_unref (color);
             }
+
+          return &pcache->value;
         }
     }
 
@@ -2689,6 +2500,17 @@ gtk_style_context_set_screen (GtkStyleContext *context,
   if (priv->screen == screen)
     return;
 
+  if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+    {
+      g_object_unref (priv->cascade);
+      priv->cascade = _gtk_style_cascade_get_for_screen (screen);
+      g_object_ref (priv->cascade);
+    }
+  else
+    {
+      _gtk_style_cascade_set_parent (priv->cascade, _gtk_style_cascade_get_for_screen (screen));
+    }
+
   priv->screen = screen;
 
   g_object_notify (G_OBJECT (context), "screen");
@@ -2822,45 +2644,9 @@ static GtkSymbolicColor *
 gtk_style_context_color_lookup_func (gpointer    contextp,
                                      const char *name)
 {
-  GtkSymbolicColor *sym_color;
   GtkStyleContext *context = contextp;
-  GtkStyleContextPrivate *priv = context->priv;
-  GList *elem, *list, *global_list = NULL;
-
-  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);
-    }
-
-  sym_color = NULL;
-  
-  while (sym_color == NULL &&
-         (elem = find_next_candidate (list, global_list)) != NULL)
-    {
-      GtkStyleProviderData *data;
-
-      data = elem->data;
-
-      if (elem == list)
-        list = list->prev;
-      else
-        global_list = global_list->prev;
-
-      if (GTK_IS_STYLE_PROVIDER_PRIVATE (data->provider))
-        {
-          sym_color = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (data->provider),
-                                                             name);
-        }
-      else
-        {
-          /* If somebody hits this code path, shout at them */
-          sym_color = NULL;
-        }
-    }
 
-  return sym_color;
+  return _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), name);
 }
 
 GtkCssValue *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]