[gtk/wip/baedert/parser: 2/3] builder css parser prototype 1



commit c0425696e6eae39d5fee8f493ba6d3b148ffa00f
Author: Timm Bäder <tbaeder redhat com>
Date:   Mon Feb 24 10:55:22 2020 +0100

    builder css parser prototype 1

 gtk/gtkbuildable.c               |  12 +++
 gtk/gtkbuildable.h               |  50 ++++++++++-
 gtk/gtkbuildercssparser.c        | 190 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkbuildercssparserprivate.h |  26 ++++++
 gtk/gtklockbutton.cssui          |  31 +++++++
 gtk/gtkwidget.c                  |  64 ++++++++++++-
 gtk/meson.build                  |   1 +
 7 files changed, 369 insertions(+), 5 deletions(-)
---
diff --git a/gtk/gtkbuildable.c b/gtk/gtkbuildable.c
index 7211c3b300..d87c22570f 100644
--- a/gtk/gtkbuildable.c
+++ b/gtk/gtkbuildable.c
@@ -40,6 +40,18 @@
 #include "gtkintl.h"
 
 
+
+typedef GtkCssBuildableIface GtkCssBuildableInterface;
+G_DEFINE_INTERFACE (GtkCssBuildable, gtk_css_buildable, G_TYPE_OBJECT)
+
+static void
+gtk_css_buildable_default_init (GtkCssBuildableInterface *iface)
+{
+  g_message ("%s!!!!", __FUNCTION__);
+}
+
+
+
 typedef GtkBuildableIface GtkBuildableInterface;
 G_DEFINE_INTERFACE (GtkBuildable, gtk_buildable, G_TYPE_OBJECT)
 
diff --git a/gtk/gtkbuildable.h b/gtk/gtkbuildable.h
index 7808f0445d..36bbed636b 100644
--- a/gtk/gtkbuildable.h
+++ b/gtk/gtkbuildable.h
@@ -25,8 +25,56 @@
 
 #include <gtk/gtkbuilder.h>
 
+// TODO FUCK
+#include "css/gtkcssparserprivate.h"
+
 G_BEGIN_DECLS
 
+
+
+#define GTK_TYPE_CSS_BUILDABLE            (gtk_css_buildable_get_type ())
+#define GTK_CSS_BUILDABLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CSS_BUILDABLE, 
GtkCssBuildable))
+#define GTK_CSS_BUILDABLE_CLASS(obj)      (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_TYPE_CSS_BUILDABLE, 
GtkCssBuildableIface))
+#define GTK_IS_CSS_BUILDABLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CSS_BUILDABLE))
+#define GTK_CSS_BUILDABLE_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_CSS_BUILDABLE, 
GtkCssBuildableIface))
+
+
+typedef struct _GtkCssBuildable      GtkCssBuildable; /* Dummy typedef */
+typedef struct _GtkCssBuildableIface GtkCssBuildableIface;
+
+
+struct _GtkCssBuildableIface
+{
+  GTypeInterface g_iface;
+
+  /* We set one value on the buildable TODO: Take multiple?*/
+  gboolean    (* set_gvalue)   (GtkCssBuildable *self,
+                                const char      *property_name,
+                                size_t           property_name_len,
+                                const GValue    *value);
+
+  /* Add child objects to the buildable */
+  gboolean    (* add_children) (GtkCssBuildable  *self,
+                                const char       *property_name,
+                                size_t            property_name_len,
+                                int               n_children,
+                                GObject         **children);
+
+
+  gboolean    (* parse_declaration) (GtkCssBuildable *self,
+                                     GtkCssParser    *parser,
+                                     const char      *decl_name,
+                                     size_t           decl_name_len);
+};
+
+
+GDK_AVAILABLE_IN_ALL
+GType     gtk_css_buildable_get_type               (void) G_GNUC_CONST;
+
+
+
+
+
 #define GTK_TYPE_BUILDABLE            (gtk_buildable_get_type ())
 #define GTK_BUILDABLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_BUILDABLE, GtkBuildable))
 #define GTK_BUILDABLE_CLASS(obj)      (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_TYPE_BUILDABLE, 
GtkBuildableIface))
@@ -101,7 +149,7 @@ struct _GtkBuildableParser
  *  content below <child>. To handle an element, the implementation
  *  must fill in the @parser and @user_data and return %TRUE.
  *  #GtkWidget implements this to parse keyboard accelerators specified
- *  in <accelerator> elements. 
+ *  in <accelerator> elements.
  *  Note that @user_data must be freed in @custom_tag_end or @custom_finished.
  * @custom_tag_end: Called for the end tag of each custom element that is
  *  handled by the buildable (see @custom_tag_start).
diff --git a/gtk/gtkbuildercssparser.c b/gtk/gtkbuildercssparser.c
new file mode 100644
index 0000000000..cff05edabc
--- /dev/null
+++ b/gtk/gtkbuildercssparser.c
@@ -0,0 +1,190 @@
+
+
+#include "gtkbuildercssparserprivate.h"
+#include "gtkbuildable.h"
+
+GtkBuilderCssParser *
+gtk_builder_css_parser_new (void)
+{
+  return g_new0 (GtkBuilderCssParser, 1);
+}
+
+static GObject *
+parse_object (GtkBuilderCssParser *self,
+              GObject             *template_object)
+{
+  GtkCssParser *parser = self->css_parser;
+  GObject *object = NULL;
+  GObjectClass *object_class;
+  const char *type_name;
+  GType type;
+
+  gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY);
+
+  /* Get us the ident, which will determine what we parse and how we parse it */
+  if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_IDENT))
+    {
+      gtk_css_parser_error_syntax (parser, "Expected type name");
+      goto fail;
+    }
+
+  type_name = gtk_css_parser_get_token (parser)->string.string;
+  type = g_type_from_name (type_name);
+
+  if (type == G_TYPE_INVALID)
+    {
+      gtk_css_parser_error_syntax (parser, "Unknown type name '%s'", type_name);
+      goto fail;
+    }
+
+  if (template_object)
+    {
+      object = g_object_ref (template_object);
+      // TODO Check that typeof(object) == given type
+    }
+  else
+    {
+      object = g_object_new (type, NULL);
+    }
+
+  gtk_css_parser_consume_token (parser);
+
+  object_class = G_OBJECT_GET_CLASS (object);
+
+  gtk_css_parser_end_block_prelude (parser);
+  while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+    {
+      gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_OPEN_CURLY);
+
+      if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_IDENT))
+        {
+          gtk_css_parser_error_syntax (parser, "Expected property name");
+        }
+      else
+        {
+          const char *prop_name = gtk_css_parser_get_token (parser)->string.string;
+          GParamSpec *pspec;
+
+          pspec = g_object_class_find_property (object_class, prop_name);
+          if (!pspec)
+            {
+              char *prop_name_dup = g_strdup (prop_name);
+              gboolean parsed = FALSE;
+
+              if (GTK_IS_CSS_BUILDABLE (object))
+                {
+                  GtkCssBuildableIface *iface = GTK_CSS_BUILDABLE_GET_IFACE (object);
+                  /*g_message ("%s Is a  css buildalbe!!", G_OBJECT_TYPE_NAME (object));*/
+
+                  /* TODO: WALK UP HIERARCHY AND SHIT */
+                  parsed = iface->parse_declaration (GTK_CSS_BUILDABLE (object),
+                                                     parser,
+                                                     prop_name,
+                                                     strlen (prop_name));
+                }
+
+              if (!parsed)
+                {
+                  gtk_css_parser_error_syntax (parser, "Invalid property '%s' for class '%s'",
+                                               prop_name, G_OBJECT_TYPE_NAME (object));
+                  goto fail;
+                }
+            }
+          else
+            {
+              // TODO: Validate pspec for correct flags, e.g. writable etc.
+              gtk_css_parser_consume_token (parser);
+              if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COLON))
+                {
+                  gtk_css_parser_error_syntax (parser, "Expected ':' after property name");
+                  goto fail;
+                }
+
+              g_message ("parsing property %s", pspec->name);
+              if (pspec->value_type == G_TYPE_BOOLEAN)
+                {
+                  const GtkCssToken *token = gtk_css_parser_get_token (parser);
+
+                  if (token->type != GTK_CSS_TOKEN_IDENT)
+                    {
+                      gtk_css_parser_error_syntax (parser, "Invalid boolean value: '%s'",
+                                                   token->string.string);
+                      goto fail;
+                    }
+                  else
+                    {
+                      if (strcmp (token->string.string, "true") == 0)
+                        g_object_set (object, pspec->name, TRUE, NULL);
+                      else if (strcmp (token->string.string, "false") == 0)
+                        g_object_set (object, pspec->name, FALSE, NULL);
+                      else
+                        {
+                          gtk_css_parser_error_syntax (parser, "Invalid boolean value: '%s'",
+                                                       token->string.string);
+                          goto fail;
+                        }
+
+                      gtk_css_parser_consume_token (parser);
+                    }
+                }
+              else
+                g_warning ("TODO: Add parser for properties of type %s", g_type_name (pspec->value_type));
+            }
+        }
+
+      gtk_css_parser_end_block (parser); /* Property block */
+    }
+
+  gtk_css_parser_end_block (parser);
+  return object;
+
+fail:
+  gtk_css_parser_end_block (parser);
+
+  if (object)
+    g_object_unref (object);
+
+  return NULL;
+}
+
+static void
+parse_objects (GtkBuilderCssParser *self,
+               GObject             *template_object)
+{
+  const GtkCssToken *token;
+  GtkCssParser *parser = self->css_parser;
+
+  for (token = gtk_css_parser_get_token (parser);
+       !gtk_css_token_is (token, GTK_CSS_TOKEN_EOF);
+       token = gtk_css_parser_get_token (parser))
+    {
+      parse_object (self, template_object);
+    }
+}
+
+static void
+parser_error_func (GtkCssParser         *parser,
+                   const GtkCssLocation *start,
+                   const GtkCssLocation *end,
+                   const GError         *error,
+                   gpointer              user_data)
+{
+  GtkCssSection *section = gtk_css_section_new (gtk_css_parser_get_file (parser), start, end);
+
+  g_warning ("%s: %s", error->message, gtk_css_section_to_string (section));
+
+  gtk_css_section_unref (section);
+}
+
+
+void
+gtk_builder_css_parser_extend_with_template (GtkBuilderCssParser *self,
+                                             GType                template_type,
+                                             GObject             *template_object,
+                                             GBytes              *bytes)
+{
+  self->css_parser = gtk_css_parser_new_for_bytes (bytes, NULL, NULL, parser_error_func,
+                                                   NULL, NULL);
+
+  parse_objects (self, template_object);
+}
diff --git a/gtk/gtkbuildercssparserprivate.h b/gtk/gtkbuildercssparserprivate.h
new file mode 100644
index 0000000000..c14c96916a
--- /dev/null
+++ b/gtk/gtkbuildercssparserprivate.h
@@ -0,0 +1,26 @@
+#ifndef __GTK_BUILDER_CSS_PARSER_PRIVATE_H__
+#define __GTK_BUILDER_CSS_PARSER_PRIVATE_H__
+
+#include "gtkwidget.h"
+#include <gtk/css/gtkcss.h>
+#include "gtk/css/gtkcssparserprivate.h"
+
+typedef struct _GtkBuilderCssParser GtkBuilderCssParser;
+
+struct _GtkBuilderCssParser
+{
+  GtkCssParser *css_parser;
+};
+
+
+GtkBuilderCssParser *       gtk_builder_css_parser_new         (void);
+
+void                        gtk_builder_css_parser_extend_with_template (GtkBuilderCssParser *self,
+                                                                         GType                template_type,
+                                                                         GObject             *object,
+                                                                         GBytes              *buffer);
+
+
+
+
+#endif
diff --git a/gtk/gtklockbutton.cssui b/gtk/gtklockbutton.cssui
new file mode 100644
index 0000000000..6d3c5ae730
--- /dev/null
+++ b/gtk/gtklockbutton.cssui
@@ -0,0 +1,31 @@
+GtkLockButton {
+  can-focus: true;
+  receives-default: true;
+
+  children: {
+    GtkBox {
+      id: "box";
+      halign: center;
+      valign: center;
+      spacing: 6;
+      children: GtkImage {
+        icon-name: "missing-image";
+      }
+    }
+    GtkStack {
+      id: "stack";
+      children: {
+        GtkLabel {
+          id: "label_lock";
+          xalign: 0;
+          label: _("Lock");
+        }
+        GtkLabel {
+          id: "label_unlock";
+          xalign: 0;
+          label: _("Unlock");
+        }
+      }
+    }
+  }
+}
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 65ced5f895..39da78f557 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -651,6 +651,7 @@ static gboolean         gtk_widget_real_can_activate_accel      (GtkWidget *widg
                                                                  guint      signal_id);
 
 static void             gtk_widget_buildable_interface_init     (GtkBuildableIface  *iface);
+static void             gtk_widget_css_buildable_interface_init (GtkCssBuildableIface *iface);
 static void             gtk_widget_buildable_set_name           (GtkBuildable       *buildable,
                                                                  const gchar        *name);
 static const gchar *    gtk_widget_buildable_get_name           (GtkBuildable       *buildable);
@@ -743,9 +744,16 @@ gtk_widget_get_type (void)
 
       const GInterfaceInfo buildable_info =
       {
-       (GInterfaceInitFunc) gtk_widget_buildable_interface_init,
-       (GInterfaceFinalizeFunc) NULL,
-       NULL /* interface data */
+        (GInterfaceInitFunc) gtk_widget_buildable_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL /* interface data */
+      };
+
+      const GInterfaceInfo css_buildable_info =
+      {
+        (GInterfaceInitFunc) gtk_widget_css_buildable_interface_init,
+        (GInterfaceFinalizeFunc) NULL,
+        NULL /* interface data */
       };
 
       const GInterfaceInfo constraint_target_info =
@@ -767,6 +775,9 @@ gtk_widget_get_type (void)
                                    &accessibility_info) ;
       g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
                                    &buildable_info) ;
+      g_type_add_interface_static (widget_type, GTK_TYPE_CSS_BUILDABLE,
+                                   &css_buildable_info) ;
+
       g_type_add_interface_static (widget_type, GTK_TYPE_CONSTRAINT_TARGET,
                                    &constraint_target_info) ;
     }
@@ -8699,6 +8710,30 @@ gtk_widget_buildable_add_child (GtkBuildable  *buildable,
     }
 }
 
+static gboolean
+gtk_widget_css_buildable_parse_declaration (GtkCssBuildable *self,
+                                            GtkCssParser    *parser,
+                                            const char      *decl_name,
+                                            size_t           decl_name_len)
+{
+  g_message (__FUNCTION__);
+  if (decl_name_len == strlen ("children"))
+    {
+      if (strcmp (decl_name, "children") == 0)
+        {
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_widget_css_buildable_interface_init (GtkCssBuildableIface *iface)
+{
+  iface->parse_declaration = gtk_widget_css_buildable_parse_declaration;
+}
+
 static void
 gtk_widget_buildable_interface_init (GtkBuildableIface *iface)
 {
@@ -11323,6 +11358,7 @@ setup_template_child (GtkWidgetTemplate   *template_data,
  * before the construct properties are set. Properties passed to g_object_new()
  * should take precedence over properties set in the private template XML.
  */
+#include "gtkbuildercssparserprivate.h"
 void
 gtk_widget_init_template (GtkWidget *widget)
 {
@@ -11333,10 +11369,30 @@ gtk_widget_init_template (GtkWidget *widget)
   GSList *l;
   GType class_type;
 
+
+  class_type = G_OBJECT_TYPE (widget);
+   if (strcmp (G_OBJECT_TYPE_NAME (widget), "GtkLockButton") == 0 &&
+       g_type_from_name ("GtkLockButton") != G_TYPE_INVALID) {
+      GBytes *css_data;
+      GtkBuilderCssParser *p = gtk_builder_css_parser_new ();
+
+      char *d;
+
+      g_file_get_contents ("../gtk/gtklockbutton.cssui", &d, NULL, NULL);
+
+      css_data = g_bytes_new_static (d, strlen (d));
+
+      gtk_builder_css_parser_extend_with_template (p,
+                                                   class_type,
+                                                   G_OBJECT (widget),
+                                                   css_data);
+    }
+
+
+
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
   object = G_OBJECT (widget);
-  class_type = G_OBJECT_TYPE (widget);
 
   template = GTK_WIDGET_GET_CLASS (widget)->priv->template;
   g_return_if_fail (template != NULL);
diff --git a/gtk/meson.build b/gtk/meson.build
index ca72c02101..c956ba20dd 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -172,6 +172,7 @@ gtk_public_sources = files([
   'gtkbuildable.c',
   'gtkbuilder.c',
   'gtkbuilderparser.c',
+  'gtkbuildercssparser.c',
   'gtkbuilderscope.c',
   'gtkbutton.c',
   'gtkcalendar.c',


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