[gtk+/parser: 8/80] API: gtk: Add gtk_css_provider_to_string()



commit ec6ff1e2323d65cfa2c0f4ea3e454e3d8db7d5e9
Author: Benjamin Otte <otte redhat com>
Date:   Wed Apr 6 22:03:35 2011 +0200

    API: gtk: Add gtk_css_provider_to_string()
    
    This is intented to convert the contents of a CSS provider back to a
    string.
    It is not complete yet but good enough for starting a testsuite. :)

 docs/reference/gtk/gtk3-sections.txt |    1 +
 gtk/gtk.symbols                      |    1 +
 gtk/gtkcssprovider.c                 |  317 ++++++++++++++++++++++++++++++++++
 gtk/gtkcssprovider.h                 |    2 +
 4 files changed, 321 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 95f5715..e200398 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -5660,6 +5660,7 @@ gtk_css_provider_load_from_data
 gtk_css_provider_load_from_file
 gtk_css_provider_load_from_path
 gtk_css_provider_new
+gtk_css_provider_to_string
 GTK_CSS_PROVIDER_ERROR
 GtkCssProviderError
 <SUBSECTION Standard>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 83a2d21..7ae4ce8 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -695,6 +695,7 @@ gtk_css_provider_load_from_data
 gtk_css_provider_load_from_file
 gtk_css_provider_load_from_path
 gtk_css_provider_new
+gtk_css_provider_to_string
 #ifdef G_OS_UNIX
 gtk_custom_paper_unix_dialog_get_type G_GNUC_CONST
 #endif
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 9f24097..306bc38 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -4254,3 +4254,320 @@ gtk_css_provider_get_named (const gchar *name,
 
   return provider;
 }
+
+static void
+gtk_css_provider_print_value (const GValue *value,
+                              GString *     str)
+{
+  char *s;
+
+  if (G_VALUE_TYPE (value) == GTK_TYPE_BORDER)
+    {
+      const GtkBorder *border = g_value_get_boxed (value);
+
+      if (border == NULL)
+        g_string_append (str, "none");
+      else if (border->left != border->right)
+        g_string_append_printf (str, "%d %d %d %d", border->top, border->right, border->bottom, border->left);
+      else if (border->top != border->bottom)
+        g_string_append_printf (str, "%d %d %d", border->top, border->right, border->bottom);
+      else if (border->top != border->left)
+        g_string_append_printf (str, "%d %d", border->top, border->right);
+      else
+        g_string_append_printf (str, "%d", border->top);
+
+      return;
+    }
+  else if (G_VALUE_TYPE (value) == GDK_TYPE_RGBA)
+    {
+      const GdkRGBA *rgba = g_value_get_boxed (value);
+      if (rgba == NULL)
+        g_string_append (str, "none");
+      else
+        {
+          s = gdk_rgba_to_string (g_value_get_boxed (value));
+          g_string_append (str, s);
+          g_free (s);
+        }
+      return;
+    }
+  else if (G_VALUE_TYPE (value) == GTK_TYPE_SYMBOLIC_COLOR)
+    {
+      GtkSymbolicColor *color = g_value_get_boxed (value);
+
+      if (color == NULL)
+        g_string_append (str, "none");
+      else
+        {
+          s = gtk_symbolic_color_to_string (color);
+          g_string_append (str, s);
+          g_free (s);
+        }
+      return;
+    }
+  else if (G_VALUE_TYPE (value) == GTK_TYPE_ANIMATION_DESCRIPTION)
+    {
+      GtkAnimationDescription *desc = g_value_get_boxed (value);
+
+      if (desc == NULL)
+        g_string_append (str, "none");
+      else
+        {
+          s = _gtk_animation_description_to_string (desc);
+          g_string_append (str, s);
+          g_free (s);
+        }
+      return;
+    }
+  else if (G_VALUE_TYPE (value) == GTK_TYPE_GRADIENT)
+    {
+      GtkGradient *gradient = g_value_get_boxed (value);
+
+      if (gradient == NULL)
+        g_string_append (str, "none");
+      else
+        {
+          s = gtk_gradient_to_string (gradient);
+          g_string_append (str, s);
+          g_free (s);
+        }
+      return;
+    }
+  else if (G_VALUE_TYPE (value) == PANGO_TYPE_FONT_DESCRIPTION)
+    {
+      PangoFontDescription *desc = g_value_get_boxed (value);
+
+      if (desc == NULL)
+        g_string_append (str, "none");
+      else
+        {
+          s = pango_font_description_to_string (desc);
+          g_string_append (str, s);
+          g_free (s);
+        }
+      return;
+    }
+  
+  if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ENUM))
+    {
+      GEnumClass *enum_class;
+      GEnumValue *enum_value;
+
+      enum_class = g_type_class_ref (G_VALUE_TYPE (value));
+      enum_value = g_enum_get_value (enum_class, g_value_get_enum (value));
+
+      g_string_append (str, enum_value->value_nick);
+
+      g_type_class_unref (enum_class);
+      return;
+    }
+  
+  /* fall back to boring strdup in the worst case */
+  s = g_strdup_value_contents (value);
+  g_string_append (str, s);
+  g_free (s);
+}
+
+static void
+selector_path_print (const SelectorPath *path,
+                     GString *           str)
+{
+  GSList *walk, *reverse;
+
+  reverse = g_slist_copy (path->elements);
+  reverse = g_slist_reverse (reverse);
+
+  for (walk = reverse; walk; walk = walk->next)
+    {
+      SelectorElement *elem = walk->data;
+
+      switch (elem->elem_type)
+        {
+        case SELECTOR_TYPE_NAME:
+        case SELECTOR_NAME:
+          g_string_append (str, g_quark_to_string (elem->name));
+          break;
+        case SELECTOR_GTYPE:
+          g_string_append (str, g_type_name (elem->type));
+          break;
+        case SELECTOR_REGION:
+          g_string_append (str, g_quark_to_string (elem->region.name));
+          if (elem->region.flags)
+            {
+              char * flag_names[] = {
+                "nth-child(even)",
+                "nth-child(odd)",
+                "first-child",
+                "last-child",
+                "sorted"
+              };
+              guint i;
+
+              for (i = 0; i < G_N_ELEMENTS (flag_names); i++)
+                {
+                  if (elem->region.flags & (1 << i))
+                    {
+                      g_string_append_c (str, ':');
+                      g_string_append (str, flag_names[i]);
+                    }
+                }
+            }
+          break;
+        case SELECTOR_CLASS:
+          g_string_append_c (str, '.');
+          g_string_append (str, g_quark_to_string (elem->name));
+          break;
+        case SELECTOR_GLOB:
+          if (walk->next == NULL ||
+              elem->combinator != COMBINATOR_CHILD ||
+              ((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
+            g_string_append (str, "*");
+          break;
+        default:
+          g_assert_not_reached ();
+        }
+
+      if (walk->next)
+        {
+          switch (elem->combinator)
+            {
+            case COMBINATOR_DESCENDANT:
+              if (elem->elem_type != SELECTOR_CLASS ||
+                  ((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
+                g_string_append_c (str, ' ');
+              break;
+            case COMBINATOR_CHILD:
+              if (((SelectorElement *) walk->next->data)->elem_type != SELECTOR_CLASS)
+                g_string_append (str, " > ");
+              break;
+            default:
+              g_assert_not_reached ();
+            }
+        }
+        
+    }
+
+  if (path->state)
+    {
+      char * state_names[] = {
+        "active",
+        "hover",
+        "selected",
+        "insensitive",
+        "inconsistent",
+        "focus"
+      };
+      guint i;
+
+      for (i = 0; i < G_N_ELEMENTS (state_names); i++)
+        {
+          if (path->state & (1 << i))
+            {
+              g_string_append_c (str, ':');
+              g_string_append (str, state_names[i]);
+            }
+        }
+    }
+
+  g_slist_free (reverse);
+}
+
+static void
+selector_style_info_print (const SelectorStyleInfo *info,
+                           GString                 *str)
+{
+  GList *keys, *walk;
+
+  selector_path_print (info->path, str);
+
+  g_string_append (str, " {\n");
+
+  keys = g_hash_table_get_keys (info->style);
+  /* so the output is identical for identical selector styles */
+  keys = g_list_sort (keys, (GCompareFunc) strcmp);
+
+  for (walk = keys; walk; walk = walk->next)
+    {
+      const char *name = walk->data;
+      const GValue *value = g_hash_table_lookup (info->style, (gpointer) name);
+
+      g_string_append (str, "  ");
+      g_string_append (str, name);
+      g_string_append (str, ": ");
+      gtk_css_provider_print_value (value, str);
+      g_string_append (str, ";\n");
+    }
+
+  g_list_free (keys);
+
+  g_string_append (str, "}\n");
+}
+
+static void
+gtk_css_provider_print_colors (GHashTable *colors,
+                               GString    *str)
+{
+  GList *keys, *walk;
+  char *s;
+
+  keys = g_hash_table_get_keys (colors);
+  /* so the output is identical for identical styles */
+  keys = g_list_sort (keys, (GCompareFunc) strcmp);
+
+  for (walk = keys; walk; walk = walk->next)
+    {
+      const char *name = walk->data;
+      GtkSymbolicColor *symbolic = g_hash_table_lookup (colors, (gpointer) name);
+
+      g_string_append (str, "@define-color ");
+      g_string_append (str, name);
+      g_string_append (str, " ");
+      s = gtk_symbolic_color_to_string (symbolic);
+      g_string_append (str, s);
+      g_free (s);
+      g_string_append (str, ";\n");
+    }
+
+  g_list_free (keys);
+}
+
+/**
+ * gtk_css_provider_to_string:
+ * @provider: the provider to write to a string
+ *
+ * Convertes the @provider into a string representation in CSS
+ * format.
+ * 
+ * Using gtk_css_provider_load_from_data() with the return value
+ * from this function on a new provider created with
+ * gtk_css_provider_new() will basicallu create a duplicate of
+ * this @provider.
+ *
+ * Returns: a new string representing the @provider.
+ **/
+char *
+gtk_css_provider_to_string (GtkCssProvider *provider)
+{
+  GtkCssProviderPrivate *priv;
+  GString *str;
+  guint i;
+
+  g_return_val_if_fail (GTK_IS_CSS_PROVIDER (provider), NULL);
+
+  priv = provider->priv;
+
+  str = g_string_new ("");
+
+  gtk_css_provider_print_colors (priv->symbolic_colors, str);
+
+  for (i = 0; i < priv->selectors_info->len; i++)
+    {
+      if (i > 0)
+        g_string_append (str, "\n");
+      selector_style_info_print (g_ptr_array_index (priv->selectors_info, i),
+                                 str);
+    }
+
+  return g_string_free (str, FALSE);
+}
+
diff --git a/gtk/gtkcssprovider.h b/gtk/gtkcssprovider.h
index add2aff..4943393 100644
--- a/gtk/gtkcssprovider.h
+++ b/gtk/gtkcssprovider.h
@@ -65,6 +65,8 @@ GType gtk_css_provider_get_type (void) G_GNUC_CONST;
 
 GtkCssProvider * gtk_css_provider_new (void);
 
+char *           gtk_css_provider_to_string      (GtkCssProvider  *provider);
+
 gboolean         gtk_css_provider_load_from_data (GtkCssProvider  *css_provider,
                                                   const gchar     *data,
                                                   gssize           length,



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