[gtk+] tests: Rework the way foreigndrawing works



commit bc020fdeb73f6a906a867e1ad28a0886ea5361e7
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Jan 4 15:34:50 2016 -0500

    tests: Rework the way foreigndrawing works
    
    Instead of the weird PathElt struct, generate a quick-n-dirty parser
    that parses CSS selectors into GtkWidgetPath elements.
    
    Based on a patch by Benjamin Otte.

 tests/foreigndrawing.c |  160 +++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 124 insertions(+), 36 deletions(-)
---
diff --git a/tests/foreigndrawing.c b/tests/foreigndrawing.c
index eb4a61a..3320cb6 100644
--- a/tests/foreigndrawing.c
+++ b/tests/foreigndrawing.c
@@ -18,15 +18,107 @@
 
 #include <gtk/gtk.h>
 
-typedef struct {
-  GType type;
-  const gchar *name;
-  const gchar *class1;
-  const gchar *class2;
-} PathElt;
+#include <string.h>
+
+static void
+append_element (GtkWidgetPath *path,
+                const char    *selector)
+{
+  static const struct {
+    const char    *name;
+    GtkStateFlags  state_flag;
+  } pseudo_classes[] = {
+    { "active",        GTK_STATE_FLAG_ACTIVE },
+    { "hover",         GTK_STATE_FLAG_PRELIGHT },
+    { "selected",      GTK_STATE_FLAG_SELECTED },
+    { "disabled",      GTK_STATE_FLAG_INSENSITIVE },
+    { "indeterminate", GTK_STATE_FLAG_INCONSISTENT },
+    { "focus",         GTK_STATE_FLAG_FOCUSED },
+    { "backdrop",      GTK_STATE_FLAG_BACKDROP },
+    { "dir(ltr)",      GTK_STATE_FLAG_DIR_LTR },
+    { "dir(rtl)",      GTK_STATE_FLAG_DIR_RTL },
+    { "link",          GTK_STATE_FLAG_LINK },
+    { "visited",       GTK_STATE_FLAG_VISITED },
+    { "checked",       GTK_STATE_FLAG_CHECKED },
+    { "drop(active)",  GTK_STATE_FLAG_DROP_ACTIVE }
+  };
+  const char *next;
+  char *name;
+  char type;
+  guint i;
+
+  next = strpbrk (selector, "#.:");
+  if (next == NULL)
+    next = selector + strlen (selector);
+
+  name = g_strndup (selector, next - selector);
+  if (g_ascii_isupper (selector[0]))
+    {
+      GType gtype;
+      gtype = g_type_from_name (name);
+      if (gtype == G_TYPE_INVALID)
+        {
+          g_critical ("Unknown type name `%s'", name);
+          g_free (name);
+          return;
+        }
+      gtk_widget_path_append_type (path, gtype);
+    }
+  else
+    {
+      /* Omit type, we're using name */
+      gtk_widget_path_append_type (path, G_TYPE_NONE);
+      gtk_widget_path_iter_set_object_name (path, -1, name);
+    }
+  g_free (name);
+
+  while (*next != '\0')
+    {
+      type = *next;
+      selector = next + 1;
+      next = strpbrk (selector, "#.:");
+      if (next == NULL)
+        next = selector + strlen (selector);
+      name = g_strndup (selector, next - selector);
+
+      switch (type)
+        {
+        case '#':
+          gtk_widget_path_iter_set_name (path, -1, name);
+          break;
+
+        case '.':
+          gtk_widget_path_iter_add_class (path, -1, name);
+          break;
+
+        case ':':
+          for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
+            {
+              if (g_str_equal (pseudo_classes[i].name, name))
+                {
+                  gtk_widget_path_iter_set_state (path,
+                                                  -1,
+                                                  gtk_widget_path_iter_get_state (path, -1)
+                                                  | pseudo_classes[i].state_flag);
+                  break;
+                }
+            }
+          if (i == G_N_ELEMENTS (pseudo_classes))
+            g_critical ("Unknown pseudo-class :%s", name);
+          break;
+
+        default:
+          g_assert_not_reached ();
+          break;
+        }
+
+      g_free (name);
+    }
+}
 
 static GtkStyleContext *
-get_style (PathElt *pelt, GtkStyleContext *parent)
+get_style (GtkStyleContext *parent,
+           const char      *selector)
 {
   GtkWidgetPath *path;
   GtkStyleContext *context;
@@ -36,17 +128,13 @@ get_style (PathElt *pelt, GtkStyleContext *parent)
   else
     path = gtk_widget_path_new ();
 
-  gtk_widget_path_append_type (path, pelt->type);
-  if (pelt->name)
-    gtk_widget_path_iter_set_object_name (path, -1, pelt->name);
-  if (pelt->class1)
-    gtk_widget_path_iter_add_class (path, -1, pelt->class1);
-  if (pelt->class2)
-    gtk_widget_path_iter_add_class (path, -1, pelt->class2);
+  append_element (path, selector);
 
   context = gtk_style_context_new ();
   gtk_style_context_set_path (context, path);
   gtk_style_context_set_parent (context, parent);
+  /* XXX: Why is this necessary? */
+  gtk_style_context_set_state (context, gtk_widget_path_iter_get_state (path, -1));
   gtk_widget_path_unref (path);
 
   return context;
@@ -67,15 +155,15 @@ draw_horizontal_scrollbar (GtkWidget     *widget,
   GtkStyleContext *slider_context;
 
   /* This information is taken from the GtkScrollbar docs, see "CSS nodes" */
-  PathElt path[3] = {
-    { GTK_TYPE_SCROLLBAR, "scrollbar", "horizontal", NULL },
-    { G_TYPE_NONE, "trough", NULL, NULL },
-    { G_TYPE_NONE, "slider", NULL, NULL }
+  const char *path[3] = {
+    "scrollbar.horizontal",
+    "trough",
+    "slider"
   };
 
-  scrollbar_context = get_style (&path[0], NULL);
-  trough_context = get_style (&path[1], scrollbar_context);
-  slider_context = get_style (&path[2], trough_context);
+  scrollbar_context = get_style (NULL, path[0]);
+  trough_context = get_style (scrollbar_context, path[1]);
+  slider_context = get_style (trough_context, path[2]);
 
   gtk_style_context_set_state (scrollbar_context, state);
   gtk_style_context_set_state (trough_context, state);
@@ -106,13 +194,13 @@ draw_text (GtkWidget     *widget,
   PangoLayout *layout;
 
   /* This information is taken from the GtkLabel docs, see "CSS nodes" */
-  PathElt path[2] = {
-    { GTK_TYPE_LABEL, "label", "view", NULL },
-    { G_TYPE_NONE, "selection", NULL, NULL }
+  const char *path[2] = {
+    "label.view",
+    "selection"
   };
 
-  label_context = get_style (&path[0], NULL);
-  selection_context = get_style (&path[1], label_context);
+  label_context = get_style (NULL, path[0]);
+  selection_context = get_style (label_context, path[1]);
 
   gtk_style_context_set_state (label_context, state);
 
@@ -144,13 +232,13 @@ draw_check (GtkWidget     *widget,
   GtkStyleContext *check_context;
 
   /* This information is taken from the GtkCheckButton docs, see "CSS nodes" */
-  PathElt path[2] = {
-    { GTK_TYPE_LABEL, "checkbutton", NULL, NULL },
-    { G_TYPE_NONE, "check", NULL, NULL }
+  const char *path[2] = {
+    "checkbutton",
+    "check"
   };
 
-  button_context = get_style (&path[0], NULL);
-  check_context = get_style (&path[1], button_context);
+  button_context = get_style (NULL, path[0]);
+  check_context = get_style (button_context, path[1]);
 
   gtk_style_context_set_state (check_context, state);
 
@@ -174,13 +262,13 @@ draw_radio (GtkWidget     *widget,
   GtkStyleContext *check_context;
 
   /* This information is taken from the GtkRadioButton docs, see "CSS nodes" */
-  PathElt path[2] = {
-    { GTK_TYPE_LABEL, "radiobutton", NULL, NULL },
-    { G_TYPE_NONE, "radio", NULL, NULL }
+  const char *path[2] = {
+    "radiobutton",
+    "radio"
   };
 
-  button_context = get_style (&path[0], NULL);
-  check_context = get_style (&path[1], button_context);
+  button_context = get_style (NULL, path[0]);
+  check_context = get_style (button_context, path[1]);
 
   gtk_style_context_set_state (check_context, state);
 


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