[gtk+] style cascade: Allow cascades with more ancestors



commit 76bacfde6e5305021c765ae690972efb1832682d
Author: Philip Chimento <philip endlessm com>
Date:   Wed Jun 15 23:02:11 2016 -0400

    style cascade: Allow cascades with more ancestors
    
    Previously a style cascade's parent could not have a parent itself. That
    represented the two levels at which you could add a style provider: at
    the screen level, with gtk_style_context_add_provider_for_screen(), and
    at the style context level, with gtk_style_context_add_provider().
    
    This commit changes no functionality, but this change will be necessary
    for adding style providers in the future that apply to a subtree of the
    widget tree. It relaxes the requirement that a style cascade's parent
    must not have a parent, since in the future a style context may be
    affected by any number of parent widgets' style contexts.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751409

 gtk/gtkstylecascade.c        |   99 +++++++++++--------
 testsuite/gtk/stylecontext.c |  230 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 288 insertions(+), 41 deletions(-)
---
diff --git a/gtk/gtkstylecascade.c b/gtk/gtkstylecascade.c
index 6afa40c..2c890f5 100644
--- a/gtk/gtkstylecascade.c
+++ b/gtk/gtkstylecascade.c
@@ -27,8 +27,9 @@ 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 */
+  int  n_cascades;
+  int *cascade_index;  /* each one points at last index that was returned, */
+                       /* not next one that should be returned */
 };
 
 struct _GtkStyleProviderData
@@ -42,56 +43,57 @@ static GtkStyleProvider *
 gtk_style_cascade_iter_next (GtkStyleCascade     *cascade,
                              GtkStyleCascadeIter *iter)
 {
-  if (iter->parent_index > 0)
-    {
-      if (iter->index > 0)
-        {
-          GtkStyleProviderData *data, *parent_data;
+  GtkStyleCascade *cas;
+  int ix, highest_priority_index = 0;
+  GtkStyleProviderData *highest_priority_data = NULL;
 
-          data = &g_array_index (cascade->providers, GtkStyleProviderData, iter->index - 1);
-          parent_data = &g_array_index (cascade->parent->providers, GtkStyleProviderData, iter->parent_index 
- 1);
+  for (cas = cascade, ix = 0; ix < iter->n_cascades; cas = cas->parent, ix++)
+    {
+      if (iter->cascade_index[ix] <= 0)
+        continue;
 
-          if (data->priority >= parent_data->priority)
-            {
-              iter->index--;
-              return data->provider;
-            }
-          else
-            {
-              iter->parent_index--;
-              return parent_data->provider;
-            }
-        }
-      else
+      GtkStyleProviderData *data = &g_array_index (cas->providers,
+                                                   GtkStyleProviderData,
+                                                   iter->cascade_index[ix] - 1);
+      if (highest_priority_data == NULL || data->priority > highest_priority_data->priority)
         {
-          iter->parent_index--;
-          return g_array_index (cascade->parent->providers, GtkStyleProviderData, 
iter->parent_index).provider;
+          highest_priority_index = ix;
+          highest_priority_data = data;
         }
     }
-  else
+
+  if (highest_priority_data != NULL)
     {
-      if (iter->index > 0)
-        {
-          iter->index--;
-          return g_array_index (cascade->providers, GtkStyleProviderData, iter->index).provider;
-        }
-      else
-        {
-          return NULL;
-        }
+      iter->cascade_index[highest_priority_index]--;
+      return highest_priority_data->provider;
     }
+  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;
+  GtkStyleCascade *cas = cascade;
+  int ix;
+
+  iter->n_cascades = 1;
+  while ((cas = cas->parent) != NULL)
+    iter->n_cascades++;
+
+  iter->cascade_index = g_new (int, iter->n_cascades);
+  for (cas = cascade, ix = 0; ix < iter->n_cascades; cas = cas->parent, ix++)
+    iter->cascade_index[ix] = cas->providers->len;
 
   return gtk_style_cascade_iter_next (cascade, iter);
 }
 
+static void
+gtk_style_cascade_iter_clear (GtkStyleCascadeIter *iter)
+{
+  g_free (iter->cascade_index);
+}
+
 static gboolean
 gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
                                       GtkWidgetPath    *path,
@@ -112,9 +114,13 @@ gtk_style_cascade_get_style_property (GtkStyleProvider *provider,
                                                  state,
                                                  pspec,
                                                  value))
-        return TRUE;
+        {
+          gtk_style_cascade_iter_clear (&iter);
+          return TRUE;
+        }
     }
 
+  gtk_style_cascade_iter_clear (&iter);
   return FALSE;
 }
 
@@ -141,9 +147,13 @@ gtk_style_cascade_get_settings (GtkStyleProviderPrivate *provider)
           
       settings = _gtk_style_provider_private_get_settings (GTK_STYLE_PROVIDER_PRIVATE (item));
       if (settings)
-        return settings;
+        {
+          gtk_style_cascade_iter_clear (&iter);
+          return settings;
+        }
     }
 
+  gtk_style_cascade_iter_clear (&iter);
   return NULL;
 }
 
@@ -164,7 +174,10 @@ gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider,
         {
           color = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (item), name);
           if (color)
-            return color;
+            {
+              gtk_style_cascade_iter_clear (&iter);
+              return color;
+            }
         }
       else
         {
@@ -172,6 +185,7 @@ gtk_style_cascade_get_color (GtkStyleProviderPrivate *provider,
         }
     }
 
+  gtk_style_cascade_iter_clear (&iter);
   return NULL;
 }
 
@@ -201,9 +215,13 @@ gtk_style_cascade_get_keyframes (GtkStyleProviderPrivate *provider,
           
       keyframes = _gtk_style_provider_private_get_keyframes (GTK_STYLE_PROVIDER_PRIVATE (item), name);
       if (keyframes)
-        return keyframes;
+        {
+          gtk_style_cascade_iter_clear (&iter);
+          return keyframes;
+        }
     }
 
+  gtk_style_cascade_iter_clear (&iter);
   return NULL;
 }
 
@@ -236,6 +254,7 @@ gtk_style_cascade_lookup (GtkStyleProviderPrivate *provider,
           g_warn_if_reached ();
         }
     }
+  gtk_style_cascade_iter_clear (&iter);
 }
 
 static void
@@ -303,8 +322,6 @@ _gtk_style_cascade_set_parent (GtkStyleCascade *cascade,
 {
   gtk_internal_return_if_fail (GTK_IS_STYLE_CASCADE (cascade));
   gtk_internal_return_if_fail (parent == NULL || GTK_IS_STYLE_CASCADE (parent));
-  if (parent)
-    gtk_internal_return_if_fail (parent->parent == NULL);
 
   if (cascade->parent == parent)
     return;
diff --git a/testsuite/gtk/stylecontext.c b/testsuite/gtk/stylecontext.c
index cf0e0a2..6ae7ff9 100644
--- a/testsuite/gtk/stylecontext.c
+++ b/testsuite/gtk/stylecontext.c
@@ -1,5 +1,12 @@
 #include <gtk/gtk.h>
 
+typedef struct {
+  GtkStyleContext *context;
+  GtkCssProvider  *blue_provider;
+  GtkCssProvider  *red_provider;
+  GtkCssProvider  *green_provider;
+} PrioritiesFixture;
+
 static void
 test_parse_selectors (void)
 {
@@ -362,6 +369,213 @@ test_style_classes (void)
   g_object_unref (context);
 }
 
+static void
+test_style_priorities_setup (PrioritiesFixture *f,
+                             gconstpointer      unused)
+{
+  GError *error = NULL;
+  f->blue_provider = gtk_css_provider_new ();
+  f->red_provider = gtk_css_provider_new ();
+  f->green_provider = gtk_css_provider_new ();
+  f->context = gtk_style_context_new ();
+  GtkWidgetPath *path = gtk_widget_path_new ();
+
+  gtk_css_provider_load_from_data (f->blue_provider, "* { color: blue; }", -1, &error);
+  g_assert_no_error (error);
+  gtk_css_provider_load_from_data (f->red_provider, "* { color: red; }", -1, &error);
+  g_assert_no_error (error);
+  gtk_css_provider_load_from_data (f->green_provider, "* { color: green; }", -1, &error);
+  g_assert_no_error (error);
+
+  gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
+  gtk_style_context_set_path (f->context, path);
+
+  gtk_widget_path_free (path);
+}
+
+static void
+test_style_priorities_teardown (PrioritiesFixture *f,
+                                gconstpointer      unused)
+{
+  g_object_unref (f->blue_provider);
+  g_object_unref (f->red_provider);
+  g_object_unref (f->green_provider);
+  g_object_unref (f->context);
+}
+
+static void
+test_style_priorities_equal (PrioritiesFixture *f,
+                             gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+  /* When style providers are added to the screen as well as the style context
+  the one specific to the style context should take priority */
+  gdk_rgba_parse (&ref_color, "red");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_screen_only (PrioritiesFixture *f,
+                                   gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+  gdk_rgba_parse (&ref_color, "blue");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_context_only (PrioritiesFixture *f,
+                                    gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+  gdk_rgba_parse (&ref_color, "red");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_screen_higher (PrioritiesFixture *f,
+                                     gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+  gdk_rgba_parse (&ref_color, "blue");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_context_higher (PrioritiesFixture *f,
+                                      gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+  gdk_rgba_parse (&ref_color, "red");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_two_screen (PrioritiesFixture *f,
+                                  gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->red_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+  gdk_rgba_parse (&ref_color, "red");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_two_context (PrioritiesFixture *f,
+                                   gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->blue_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+  gdk_rgba_parse (&ref_color, "red");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_three_screen_higher (PrioritiesFixture *f,
+                                           gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->green_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+
+  gdk_rgba_parse (&ref_color, "green");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
+static void
+test_style_priorities_three_context_higher (PrioritiesFixture *f,
+                                            gconstpointer      unused)
+{
+  GdkRGBA color, ref_color;
+
+  gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                             GTK_STYLE_PROVIDER (f->blue_provider),
+                                             GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->red_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER);
+  gtk_style_context_add_provider (f->context, GTK_STYLE_PROVIDER (f->green_provider),
+                                  GTK_STYLE_PROVIDER_PRIORITY_USER + 1);
+
+  gdk_rgba_parse (&ref_color, "green");
+  gtk_style_context_get_color (f->context, gtk_style_context_get_state (f->context),
+                               &color);
+
+  g_assert_true (gdk_rgba_equal (&ref_color, &color));
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -376,5 +590,21 @@ main (int argc, char *argv[])
   g_test_add_func ("/style/widget-path-parent", test_widget_path_parent);
   g_test_add_func ("/style/classes", test_style_classes);
 
+#define ADD_PRIORITIES_TEST(path, func) \
+  g_test_add ("/style/priorities/" path, PrioritiesFixture, NULL, test_style_priorities_setup, \
+              (func), test_style_priorities_teardown)
+
+  ADD_PRIORITIES_TEST ("equal", test_style_priorities_equal);
+  ADD_PRIORITIES_TEST ("screen-only", test_style_priorities_screen_only);
+  ADD_PRIORITIES_TEST ("context-only", test_style_priorities_context_only);
+  ADD_PRIORITIES_TEST ("screen-higher", test_style_priorities_screen_higher);
+  ADD_PRIORITIES_TEST ("context-higher", test_style_priorities_context_higher);
+  ADD_PRIORITIES_TEST ("two-screen", test_style_priorities_two_screen);
+  ADD_PRIORITIES_TEST ("two-context", test_style_priorities_two_context);
+  ADD_PRIORITIES_TEST ("three-screen-higher", test_style_priorities_three_screen_higher);
+  ADD_PRIORITIES_TEST ("three-context-higher", test_style_priorities_three_context_higher);
+
+#undef ADD_PRIORITIES_TEST
+
   return g_test_run ();
 }


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