[gtk/wip/otte/listview: 53/183] builder: Add <binding> tag
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 53/183] builder: Add <binding> tag
- Date: Tue, 10 Dec 2019 06:15:22 +0000 (UTC)
commit 0f8d5c7543dac65c8e273d7163de13cdd5b8b35f
Author: Benjamin Otte <otte redhat com>
Date: Mon Nov 25 08:15:31 2019 +0100
builder: Add <binding> tag
The tag contains an expression that it then gtk_expression_bind()s to
the object it is contained in.
gtk/gtkbuilder.c | 64 ++++++++++++++--------
gtk/gtkbuilderparser.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++--
gtk/gtkbuilderprivate.h | 20 ++++++-
3 files changed, 199 insertions(+), 26 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 33410560b8..efc47863d4 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -218,6 +218,7 @@
#include "gtkbuildable.h"
#include "gtkbuilderscopeprivate.h"
#include "gtkdebug.h"
+#include "gtkexpression.h"
#include "gtkmain.h"
#include "gtkintl.h"
#include "gtkprivate.h"
@@ -676,8 +677,22 @@ gtk_builder_take_bindings (GtkBuilder *builder,
for (l = bindings; l; l = l->next)
{
- BindingInfo *info = l->data;
- info->target = target;
+ CommonInfo *common_info = l->data;
+
+ if (common_info->tag_type == TAG_BINDING)
+ {
+ BindingInfo *info = l->data;
+ info->target = target;
+ }
+ else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
+ {
+ BindingExpressionInfo *info = l->data;
+ info->target = target;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
priv->bindings = g_slist_concat (priv->bindings, bindings);
@@ -1004,17 +1019,6 @@ gtk_builder_apply_delayed_properties (GtkBuilder *builder,
return result;
}
-static inline void
-free_binding_info (gpointer data,
- gpointer user)
-{
- BindingInfo *info = data;
-
- g_free (info->source);
- g_free (info->source_property);
- g_slice_free (BindingInfo, data);
-}
-
static inline gboolean
gtk_builder_create_bindings (GtkBuilder *builder,
GError **error)
@@ -1025,26 +1029,44 @@ gtk_builder_create_bindings (GtkBuilder *builder,
for (l = priv->bindings; l; l = l->next)
{
- BindingInfo *info = l->data;
- GObject *source;
+ CommonInfo *common_info = l->data;
- if (result)
+ if (common_info->tag_type == TAG_BINDING)
{
- source = gtk_builder_lookup_object (builder, info->source, info->line, info->col, error);
+ BindingInfo *info = l->data;
+ GObject *source;
+
+ source = _gtk_builder_lookup_object (builder, info->source, info->line, info->col);
if (source)
g_object_bind_property (source, info->source_property,
info->target, info->target_pspec->name,
info->flags);
- else
- result = FALSE;
+
+ _free_binding_info (info, NULL);
}
+ else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
+ {
+ BindingExpressionInfo *info = l->data;
+ GtkExpression *expression;
- free_binding_info (info, NULL);
+ expression = expression_info_construct (builder, info->expr, error);
+ if (expression == NULL)
+ {
+ g_prefix_error (error, "%s:%d:%d: ", priv->filename, info->line, info->col);
+ error = NULL;
+ result = FALSE;
+ }
+ else
+ {
+ gtk_expression_bind (expression, info->target, info->target_pspec->name);
+ }
+
+ free_binding_expression_info (info);
+ }
}
g_slist_free (priv->bindings);
priv->bindings = NULL;
-
return result;
}
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index c746d3bb9e..e0f305dbc4 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -913,7 +913,8 @@ parse_property (ParserData *data,
{
BindingInfo *binfo;
- binfo = g_slice_new (BindingInfo);
+ binfo = g_slice_new0 (BindingInfo);
+ binfo->tag_type = TAG_BINDING;
binfo->target = NULL;
binfo->target_pspec = pspec;
binfo->source = g_strdup (bind_source);
@@ -945,6 +946,78 @@ parse_property (ParserData *data,
state_push (data, info);
}
+static void
+parse_binding (ParserData *data,
+ const gchar *element_name,
+ const gchar **names,
+ const gchar **values,
+ GError **error)
+{
+ BindingExpressionInfo *info;
+ const gchar *name = NULL;
+ ObjectInfo *object_info;
+ GParamSpec *pspec = NULL;
+
+ object_info = state_peek_info (data, ObjectInfo);
+ if (!object_info ||
+ !(object_info->tag_type == TAG_OBJECT ||
+ object_info->tag_type == TAG_TEMPLATE))
+ {
+ error_invalid_tag (data, element_name, NULL, error);
+ return;
+ }
+
+ if (!g_markup_collect_attributes (element_name, names, values, error,
+ G_MARKUP_COLLECT_STRING, "name", &name,
+ G_MARKUP_COLLECT_INVALID))
+ {
+ _gtk_builder_prefix_error (data->builder, &data->ctx, error);
+ return;
+ }
+
+ pspec = g_object_class_find_property (object_info->oclass, name);
+
+ if (!pspec)
+ {
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_PROPERTY,
+ "Invalid property: %s.%s",
+ g_type_name (object_info->type), name);
+ _gtk_builder_prefix_error (data->builder, &data->ctx, error);
+ return;
+ }
+ else if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ {
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_PROPERTY,
+ "%s.%s is a construct-only property",
+ g_type_name (object_info->type), name);
+ _gtk_builder_prefix_error (data->builder, &data->ctx, error);
+ return;
+ }
+ else if (!(pspec->flags & G_PARAM_WRITABLE))
+ {
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_PROPERTY,
+ "%s.%s is a non-writable property",
+ g_type_name (object_info->type), name);
+ _gtk_builder_prefix_error (data->builder, &data->ctx, error);
+ return;
+ }
+
+
+ info = g_slice_new0 (BindingExpressionInfo);
+ info->tag_type = TAG_BINDING_EXPRESSION;
+ info->target = NULL;
+ info->target_pspec = pspec;
+ gtk_buildable_parse_context_get_position (&data->ctx, &info->line, &info->col);
+
+ state_push (data, info);
+}
+
static void
free_property_info (PropertyInfo *info)
{
@@ -1005,8 +1078,13 @@ check_expression_parent (ParserData *data)
return G_PARAM_SPEC_VALUE_TYPE (prop_info->pspec) == GTK_TYPE_EXPRESSION;
}
+ else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
+ {
+ BindingExpressionInfo *expr_info = (BindingExpressionInfo *) common_info;
- if (common_info->tag_type == TAG_EXPRESSION)
+ return expr_info->expr == NULL;
+ }
+ else if (common_info->tag_type == TAG_EXPRESSION)
{
ExpressionInfo *expr_info = (ExpressionInfo *) common_info;
@@ -1194,7 +1272,7 @@ parse_lookup_expression (ParserData *data,
state_push (data, info);
}
-static GtkExpression *
+GtkExpression *
expression_info_construct (GtkBuilder *builder,
ExpressionInfo *info,
GError **error)
@@ -1414,6 +1492,23 @@ _free_signal_info (SignalInfo *info,
g_slice_free (SignalInfo, info);
}
+void
+_free_binding_info (BindingInfo *info,
+ gpointer user)
+{
+ g_free (info->source);
+ g_free (info->source_property);
+ g_slice_free (BindingInfo, info);
+}
+
+void
+free_binding_expression_info (BindingExpressionInfo *info)
+{
+ if (info->expr)
+ free_expression_info (info->expr);
+ g_slice_free (BindingExpressionInfo, info);
+}
+
static void
free_requires_info (RequiresInfo *info,
gpointer user_data)
@@ -1654,6 +1749,8 @@ start_element (GtkBuildableParseContext *context,
}
else if (strcmp (element_name, "property") == 0)
parse_property (data, element_name, names, values, error);
+ else if (strcmp (element_name, "binding") == 0)
+ parse_binding (data, element_name, names, values, error);
else if (strcmp (element_name, "child") == 0)
parse_child (data, element_name, names, values, error);
else if (strcmp (element_name, "signal") == 0)
@@ -1745,6 +1842,30 @@ end_element (GtkBuildableParseContext *context,
else
g_assert_not_reached ();
}
+ else if (strcmp (element_name, "binding") == 0)
+ {
+ BindingExpressionInfo *binfo = state_pop_info (data, BindingExpressionInfo);
+ CommonInfo *info = state_peek_info (data, CommonInfo);
+
+ g_assert (info != NULL);
+
+ if (binfo->expr == NULL)
+ {
+ g_set_error (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_INVALID_TAG,
+ "Binding tag requires an expression");
+ free_binding_expression_info (binfo);
+ }
+ else if (info->tag_type == TAG_OBJECT ||
+ info->tag_type == TAG_TEMPLATE)
+ {
+ ObjectInfo *object_info = (ObjectInfo*)info;
+ object_info->bindings = g_slist_prepend (object_info->bindings, binfo);
+ }
+ else
+ g_assert_not_reached ();
+ }
else if (strcmp (element_name, "object") == 0 ||
strcmp (element_name, "template") == 0)
{
@@ -1812,7 +1933,13 @@ end_element (GtkBuildableParseContext *context,
ExpressionInfo *expression_info = state_pop_info (data, ExpressionInfo);
CommonInfo *parent_info = state_peek_info (data, CommonInfo);
- if (parent_info->tag_type == TAG_PROPERTY)
+ if (parent_info->tag_type == TAG_BINDING_EXPRESSION)
+ {
+ BindingExpressionInfo *expr_info = (BindingExpressionInfo *) parent_info;
+
+ expr_info->expr = expression_info;
+ }
+ else if (parent_info->tag_type == TAG_PROPERTY)
{
PropertyInfo *prop_info = (PropertyInfo *) parent_info;
@@ -1963,6 +2090,12 @@ free_info (CommonInfo *info)
case TAG_CHILD:
free_child_info ((ChildInfo *)info);
break;
+ case TAG_BINDING:
+ _free_binding_info ((BindingInfo *)info, NULL);
+ break;
+ case TAG_BINDING_EXPRESSION:
+ free_binding_expression_info ((BindingExpressionInfo *) info);
+ break;
case TAG_PROPERTY:
free_property_info ((PropertyInfo *)info);
break;
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index 0e9f73b3fd..a5e1f22861 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -25,7 +25,8 @@
enum {
TAG_PROPERTY,
- TAG_MENU,
+ TAG_BINDING,
+ TAG_BINDING_EXPRESSION,
TAG_REQUIRES,
TAG_OBJECT,
TAG_CHILD,
@@ -117,6 +118,7 @@ typedef struct {
typedef struct
{
+ guint tag_type;
GObject *target;
GParamSpec *target_pspec;
gchar *source;
@@ -126,6 +128,16 @@ typedef struct
gint col;
} BindingInfo;
+typedef struct
+{
+ guint tag_type;
+ GObject *target;
+ GParamSpec *target_pspec;
+ ExpressionInfo *expr;
+ gint line;
+ gint col;
+} BindingExpressionInfo;
+
typedef struct {
guint tag_type;
gchar *library;
@@ -212,6 +224,12 @@ gboolean _gtk_builder_finish (GtkBuilder *builder,
GError **error);
void _free_signal_info (SignalInfo *info,
gpointer user_data);
+void _free_binding_info (BindingInfo *info,
+ gpointer user_data);
+void free_binding_expression_info (BindingExpressionInfo *info);
+GtkExpression * expression_info_construct (GtkBuilder *builder,
+ ExpressionInfo *info,
+ GError **error);
/* Internal API which might be made public at some point */
gboolean _gtk_builder_boolean_from_string (const gchar *string,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]