[gtk+/gtk-style-context: 120/347] GtkStyleContext: Add gtk_style_context_save/restore().



commit 3fe319e887bb892c95bb6b89fde3f5073c3cc301
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sat Jul 3 20:53:50 2010 +0200

    GtkStyleContext: Add gtk_style_context_save/restore().
    
    This API will be used to have savepoints when adding and removing
    style classes information.

 gtk/gtkstylecontext.c |  314 ++++++++++++++++++++++++++++++++++---------------
 gtk/gtkstylecontext.h |    3 +
 2 files changed, 223 insertions(+), 94 deletions(-)
---
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 7b13323..71f8c83 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -33,6 +33,7 @@
 
 typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
 typedef struct GtkStyleProviderData GtkStyleProviderData;
+typedef struct GtkStyleRegion GtkStyleRegion;
 typedef struct GtkChildClass GtkChildClass;
 typedef struct PropertyValue PropertyValue;
 
@@ -55,6 +56,12 @@ struct PropertyValue
   GValue      value;
 };
 
+struct GtkStyleRegion
+{
+  GArray *style_classes;
+  GArray *child_style_classes;
+};
+
 struct GtkStyleContextPrivate
 {
   GdkScreen *screen;
@@ -70,8 +77,7 @@ struct GtkStyleContextPrivate
   GArray *property_cache;
 
   GtkStateFlags state_flags;
-  GList *style_classes;
-  GList *child_style_classes;
+  GSList *regions;
 
   GtkThemingEngine *theming_engine;
 };
@@ -115,10 +121,47 @@ gtk_style_context_class_init (GtkStyleContextClass *klass)
   g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
 }
 
+static GtkStyleRegion *
+style_region_new (void)
+{
+  GtkStyleRegion *region;
+
+  region = g_slice_new0 (GtkStyleRegion);
+  region->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
+  region->child_style_classes = g_array_new (FALSE, FALSE, sizeof (GtkChildClass));
+
+  return region;
+}
+
+static void
+style_region_free (GtkStyleRegion *region)
+{
+  g_array_free (region->style_classes, TRUE);
+  g_array_free (region->child_style_classes, TRUE);
+  g_slice_free (GtkStyleRegion, region);
+}
+
+static GtkStyleRegion *
+style_region_copy (const GtkStyleRegion *region)
+{
+  GtkStyleRegion *copy;
+
+  copy = style_region_new ();
+  g_array_insert_vals (copy->style_classes, 0,
+                       region->style_classes->data,
+                       region->style_classes->len);
+
+  g_array_insert_vals (copy->child_style_classes, 0,
+                       region->child_style_classes->data,
+                       region->child_style_classes->len);
+  return copy;
+}
+
 static void
 gtk_style_context_init (GtkStyleContext *style_context)
 {
   GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
 
   priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
                                                             GTK_TYPE_STYLE_CONTEXT,
@@ -126,6 +169,10 @@ gtk_style_context_init (GtkStyleContext *style_context)
 
   priv->store = gtk_style_set_new ();
   priv->theming_engine = (GtkThemingEngine *) gtk_theming_engine_load (NULL);
+
+  /* Create default region */
+  region = style_region_new ();
+  priv->regions = g_slist_prepend (priv->regions, region);
 }
 
 static GtkStyleProviderData *
@@ -186,6 +233,9 @@ gtk_style_context_finalize (GObject *object)
 
   clear_property_cache (GTK_STYLE_CONTEXT (object));
 
+  g_slist_foreach (priv->regions, (GFunc) style_region_free, NULL);
+  g_slist_free (priv->regions);
+
   g_slist_foreach (priv->icon_factories, (GFunc) g_object_unref, NULL);
   g_slist_free (priv->icon_factories);
 
@@ -549,41 +599,136 @@ gtk_style_context_get_path (GtkStyleContext *context)
 }
 
 void
-gtk_style_context_set_class (GtkStyleContext *context,
-                             const gchar     *class_name)
+gtk_style_context_save (GtkStyleContext *context)
 {
   GtkStyleContextPrivate *priv;
-  GQuark class_quark;
-  GList *link;
+  GtkStyleRegion *region;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
-  g_return_if_fail (class_name != NULL);
 
   priv = context->priv;
-  class_quark = g_quark_from_string (class_name);
 
-  link = priv->style_classes;
+  g_assert (priv->regions != NULL);
 
-  while (link)
+  region = style_region_copy (priv->regions->data);
+  priv->regions = g_slist_prepend (priv->regions, region);
+}
+
+void
+gtk_style_context_restore (GtkStyleContext *context)
+{
+  GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
+
+  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+
+  priv = context->priv;
+
+  if (priv->regions)
+    {
+      region = priv->regions->data;
+      priv->regions = g_slist_remove (priv->regions, region);
+      style_region_free (region);
+    }
+
+  if (!priv->regions)
     {
-      GQuark link_quark;
+      g_warning ("Unpaired gtk_style_context_restore() call");
 
-      link_quark = GPOINTER_TO_UINT (link->data);
+      /* Create default region */
+      region = style_region_new ();
+      priv->regions = g_slist_prepend (priv->regions, region);
+    }
+}
 
-      if (link_quark == class_quark)
-        return;
-      else if (link_quark > class_quark)
-        {
-          priv->style_classes = g_list_insert_before (priv->style_classes,
-                                                      link, GUINT_TO_POINTER (class_quark));
-          return;
-        }
+static gboolean
+style_class_find (GArray       *array,
+                  GQuark        class_quark,
+                  guint        *position)
+{
+  guint min, max, mid;
+  gboolean found = FALSE;
+
+  min = 0;
+  max = array->len - 1;
+  mid = max - min / 2;
+
+  do
+    {
+      GQuark item;
+
+      mid = min + max / 2;
+      item = g_array_index (array, GQuark, mid);
+
+      if (class_quark == item)
+        found = TRUE;
+      else if (class_quark > item)
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+  while (!found && min < max);
 
-      link = link->next;
+  if (position)
+    *position = mid;
+
+  return found;
+}
+
+static gboolean
+child_style_class_find (GArray       *array,
+                        GQuark        class_quark,
+                        guint        *position)
+{
+  guint min, max, mid;
+  gboolean found = FALSE;
+
+  min = 0;
+  max = array->len - 1;
+  mid = max - min / 2;
+
+  do
+    {
+      GtkChildClass *child_class;
+
+      mid = min + max / 2;
+      child_class = &g_array_index (array, GtkChildClass, mid);
+
+      if (child_class->class_quark == class_quark)
+        found = TRUE;
+      else if (child_class->class_quark > class_quark)
+        min = mid + 1;
+      else
+        max = mid - 1;
     }
+  while (!found && min < max);
+
+  if (position)
+    *position = mid;
+
+  return found;
+}
+
+void
+gtk_style_context_set_class (GtkStyleContext *context,
+                             const gchar     *class_name)
+{
+  GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
+  GQuark class_quark;
+  guint position;
+
+  g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+  g_return_if_fail (class_name != NULL);
+
+  priv = context->priv;
+  class_quark = g_quark_from_string (class_name);
+
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
 
-  priv->style_classes = g_list_append (priv->style_classes,
-                                       GUINT_TO_POINTER (class_quark));
+  if (!style_class_find (region->style_classes, class_quark, &position))
+    g_array_insert_val (region->style_classes, position, class_quark);
 }
 
 void
@@ -591,7 +736,9 @@ gtk_style_context_unset_class (GtkStyleContext *context,
                                const gchar     *class_name)
 {
   GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
   GQuark class_quark;
+  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (class_name != NULL);
@@ -602,8 +749,12 @@ gtk_style_context_unset_class (GtkStyleContext *context,
     return;
 
   priv = context->priv;
-  priv->style_classes = g_list_remove (priv->style_classes,
-                                       GUINT_TO_POINTER (class_quark));
+
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
+
+  if (style_class_find (region->style_classes, class_quark, &position))
+    g_array_remove_index (region->style_classes, position);
 }
 
 gboolean
@@ -611,6 +762,7 @@ gtk_style_context_has_class (GtkStyleContext *context,
                              const gchar     *class_name)
 {
   GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
   GQuark class_quark;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
@@ -623,47 +775,41 @@ gtk_style_context_has_class (GtkStyleContext *context,
 
   priv = context->priv;
 
-  if (g_list_find (priv->style_classes,
-                   GUINT_TO_POINTER (class_quark)))
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
+
+  if (style_class_find (region->style_classes, class_quark, NULL))
     return TRUE;
 
   return FALSE;
 }
 
-static gint
-child_style_class_compare (gconstpointer p1,
-                           gconstpointer p2)
-{
-  const GtkChildClass *c1, *c2;
-
-  c1 = p1;
-  c2 = p2;
-
-  return (gint) c1->class_quark - c2->class_quark;
-}
-
 GList *
 gtk_style_context_list_child_classes (GtkStyleContext *context)
 {
   GtkStyleContextPrivate *priv;
+  GtkStyleRegion *region;
   GList *classes = NULL;
-  GList *link;
+  guint i;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
 
   priv = context->priv;
-  link = priv->child_style_classes;
 
-  while (link)
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
+
+  for (i = 0; i < region->child_style_classes->len; i++)
     {
-      GtkChildClass *link_class;
-      const gchar *child_class;
+      GtkChildClass *child_class;
+      const gchar *class_name;
 
-      link_class = link->data;
-      link = link->next;
+      child_class = &g_array_index (region->child_style_classes,
+                                    GtkChildClass,
+                                    i);
 
-      child_class = g_quark_to_string (link_class->class_quark);
-      classes = g_list_prepend (classes, (gchar *) child_class);
+      class_name = g_quark_to_string (child_class->class_quark);
+      classes = g_list_prepend (classes, (gchar *) class_name);
     }
 
   return classes;
@@ -675,43 +821,28 @@ gtk_style_context_set_child_class (GtkStyleContext    *context,
                                    GtkChildClassFlags  flags)
 {
   GtkStyleContextPrivate *priv;
-  GtkChildClass *child_class;
+  GtkStyleRegion *region;
   GQuark class_quark;
-  GList *link;
+  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (class_name != NULL);
 
   priv = context->priv;
   class_quark = g_quark_from_string (class_name);
-  link = priv->child_style_classes;
 
-  while (link)
-    {
-      GtkChildClass *link_class;
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
 
-      link_class = link->data;
+  if (!child_style_class_find (region->child_style_classes, class_quark, &position))
+    {
+      GtkChildClass child_class;
 
-      if (link_class->class_quark == class_quark)
-        {
-          link_class->flags = flags;
-          return;
-        }
-      else if (link_class->class_quark > class_quark)
-        break;
+      child_class.class_quark = class_quark;
+      child_class.flags = flags;
 
-      link = link->next;
+      g_array_insert_val (region->child_style_classes, position, child_class);
     }
-
-  child_class = g_slice_new0 (GtkChildClass);
-  child_class->class_quark = class_quark;
-  child_class->flags = flags;
-
-  if (link)
-    priv->child_style_classes = g_list_insert_before (priv->child_style_classes,
-                                                      link, child_class);
-  else
-    priv->child_style_classes = g_list_append (priv->child_style_classes, child_class);
 }
 
 void
@@ -719,9 +850,9 @@ gtk_style_context_unset_child_class (GtkStyleContext    *context,
                                      const gchar        *class_name)
 {
   GtkStyleContextPrivate *priv;
-  GtkChildClass child_class;
+  GtkStyleRegion *region;
   GQuark class_quark;
-  GList *link;
+  guint position;
 
   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
   g_return_if_fail (class_name != NULL);
@@ -732,17 +863,12 @@ gtk_style_context_unset_child_class (GtkStyleContext    *context,
     return;
 
   priv = context->priv;
-  child_class.class_quark = class_quark;
 
-  link = g_list_find_custom (priv->child_style_classes,
-                             &child_class, child_style_class_compare);
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
 
-  if (link)
-    {
-      priv->child_style_classes = g_list_remove_link (priv->child_style_classes, link);
-      g_slice_free (GtkChildClass, link->data);
-      g_list_free1 (link);
-    }
+  if (child_style_class_find (region->child_style_classes, class_quark, &position))
+    g_array_remove_index (region->child_style_classes, position);
 }
 
 gboolean
@@ -751,9 +877,9 @@ gtk_style_context_has_child_class (GtkStyleContext    *context,
                                    GtkChildClassFlags *flags_return)
 {
   GtkStyleContextPrivate *priv;
-  GtkChildClass child_class;
+  GtkStyleRegion *region;
   GQuark class_quark;
-  GList *link;
+  guint position;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
   g_return_val_if_fail (class_name != NULL, FALSE);
@@ -767,21 +893,21 @@ gtk_style_context_has_child_class (GtkStyleContext    *context,
     return FALSE;
 
   priv = context->priv;
-  child_class.class_quark = class_quark;
 
-  link = g_list_find_custom (priv->child_style_classes,
-                             &child_class, child_style_class_compare);
+  g_assert (priv->regions != NULL);
+  region = priv->regions->data;
 
-  if (link)
+  if (child_style_class_find (region->child_style_classes, class_quark, &position))
     {
       if (flags_return)
         {
-          GtkChildClass *found_class;
+          GtkChildClass *child_class;
 
-          found_class = link->data;
-          *flags_return = found_class->flags;
-        }
+          child_class = &g_array_index (region->child_style_classes,
+					GtkChildClass, position);
 
+          *flags_return = child_class->flags;
+        }
       return TRUE;
     }
 
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index 1fada4f..f578b26 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -56,6 +56,9 @@ void gtk_style_context_add_provider    (GtkStyleContext  *context,
 void gtk_style_context_remove_provider (GtkStyleContext  *context,
                                         GtkStyleProvider *provider);
 
+void gtk_style_context_save    (GtkStyleContext *context);
+void gtk_style_context_restore (GtkStyleContext *context);
+
 void gtk_style_context_get_property (GtkStyleContext *context,
                                      const gchar     *property,
                                      GtkStateType     state,



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