[gtk/wip/baedert/parser: 2/3] builder css parser prototype 1
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/baedert/parser: 2/3] builder css parser prototype 1
- Date: Thu, 12 Mar 2020 18:02:08 +0000 (UTC)
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]