[gtk/prop-list: 17/154] expression: Make property expression allow subexpressions
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/prop-list: 17/154] expression: Make property expression allow subexpressions
- Date: Tue, 3 Dec 2019 01:30:07 +0000 (UTC)
commit 91ad2c44ca977c32611ee2ea7487370ed18ba382
Author: Benjamin Otte <otte redhat com>
Date: Sat Nov 23 05:21:17 2019 +0100
expression: Make property expression allow subexpressions
gtk/gtkbuilderparser.c | 50 ++++++++++++++++--
gtk/gtkbuilderprivate.h | 13 +++--
gtk/gtkexpression.c | 129 ++++++++++++++++++++++++++++++++++++++-------
gtk/gtkexpression.h | 1 +
testsuite/gtk/expression.c | 8 +--
5 files changed, 173 insertions(+), 28 deletions(-)
---
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index 4a8930e282..b363d5ae09 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -994,6 +994,11 @@ free_expression_info (ExpressionInfo *info)
g_slist_free_full (info->closure.params, (GDestroyNotify) free_expression_info);
break;
+ case EXPRESSION_PROPERTY:
+ g_clear_pointer (&info->property.expression, free_expression_info);
+ g_free (info->property.property_name);
+ break;
+
default:
g_assert_not_reached ();
break;
@@ -1020,7 +1025,19 @@ check_expression_parent (ParserData *data)
{
ExpressionInfo *expr_info = (ExpressionInfo *) common_info;
- return expr_info->expression_type = EXPRESSION_CLOSURE;
+ switch (expr_info->expression_type)
+ {
+ case EXPRESSION_CLOSURE:
+ return TRUE;
+ case EXPRESSION_CONSTANT:
+ return FALSE;
+ case EXPRESSION_PROPERTY:
+ return expr_info->property.expression == NULL;
+ case EXPRESSION_EXPRESSION:
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
}
return FALSE;
@@ -1173,8 +1190,9 @@ parse_lookup_expression (ParserData *data,
info = g_slice_new0 (ExpressionInfo);
info->tag_type = TAG_EXPRESSION;
- info->expression_type = EXPRESSION_EXPRESSION;
- info->expression = gtk_property_expression_new (type, property_name);
+ info->expression_type = EXPRESSION_PROPERTY;
+ info->property.this_type = type;
+ info->property.property_name = g_strdup (property_name);
state_push (data, info);
}
@@ -1256,6 +1274,29 @@ expression_info_construct (GtkBuilder *builder,
}
break;
+ case EXPRESSION_PROPERTY:
+ {
+ GtkExpression *expression;
+
+ if (info->property.expression)
+ {
+ expression = expression_info_construct (builder, info->property.expression, error);
+ if (expression == NULL)
+ return NULL;
+ free_expression_info (info->property.expression);
+ }
+ else
+ expression = NULL;
+
+ expression = gtk_property_expression_new (info->property.this_type,
+ expression,
+ info->property.property_name);
+ g_free (info->property.property_name);
+ info->expression_type = EXPRESSION_EXPRESSION;
+ info->expression = expression;
+ }
+ break;
+
default:
g_return_val_if_reached (NULL);
}
@@ -1760,6 +1801,9 @@ end_element (GtkBuildableParseContext *context,
case EXPRESSION_CLOSURE:
expr_info->closure.params = g_slist_prepend (expr_info->closure.params, expression_info);
break;
+ case EXPRESSION_PROPERTY:
+ expr_info->property.expression = expression_info;
+ break;
case EXPRESSION_EXPRESSION:
case EXPRESSION_CONSTANT:
default:
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index 8ad1438e05..0e9f73b3fd 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -75,12 +75,14 @@ typedef struct {
gint col;
} PropertyInfo;
-typedef struct {
+typedef struct _ExpressionInfo ExpressionInfo;
+struct _ExpressionInfo {
guint tag_type;
enum {
EXPRESSION_EXPRESSION,
EXPRESSION_CONSTANT,
- EXPRESSION_CLOSURE
+ EXPRESSION_CLOSURE,
+ EXPRESSION_PROPERTY
} expression_type;
union {
GtkExpression *expression;
@@ -95,8 +97,13 @@ typedef struct {
gboolean swapped;
GSList *params;
} closure;
+ struct {
+ GType this_type;
+ char *property_name;
+ ExpressionInfo *expression;
+ } property;
};
-} ExpressionInfo;
+};
typedef struct {
guint tag_type;
diff --git a/gtk/gtkexpression.c b/gtk/gtkexpression.c
index 20f8a53324..fe382fb09c 100644
--- a/gtk/gtkexpression.c
+++ b/gtk/gtkexpression.c
@@ -417,12 +417,17 @@ struct _GtkPropertyExpression
{
GtkExpression parent;
+ GtkExpression *expr;
+
GParamSpec *pspec;
};
static void
gtk_property_expression_finalize (GtkExpression *expr)
{
+ GtkPropertyExpression *self = (GtkPropertyExpression *) expr;
+
+ g_clear_pointer (&self->expr, gtk_expression_unref);
}
static gboolean
@@ -431,17 +436,56 @@ gtk_property_expression_is_static (GtkExpression *expr)
return FALSE;
}
+static GObject *
+gtk_property_expression_get_object (GtkPropertyExpression *self,
+ gpointer this)
+{
+ GValue expr_value = G_VALUE_INIT;
+ GObject *object;
+
+ if (self->expr == NULL)
+ {
+ if (this)
+ return g_object_ref (this);
+ else
+ return NULL;
+ }
+
+ if (!gtk_expression_evaluate (self->expr, this, &expr_value))
+ return NULL;
+
+ if (!G_VALUE_HOLDS_OBJECT (&expr_value))
+ {
+ g_value_unset (&expr_value);
+ return NULL;
+ }
+
+ object = g_value_dup_object (&expr_value);
+ g_value_unset (&expr_value);
+
+ if (!G_TYPE_CHECK_INSTANCE_TYPE (object, self->pspec->owner_type))
+ {
+ g_object_unref (object);
+ return NULL;
+ }
+
+ return object;
+}
+
static gboolean
gtk_property_expression_evaluate (GtkExpression *expr,
gpointer this,
GValue *value)
{
GtkPropertyExpression *self = (GtkPropertyExpression *) expr;
+ GObject *object;
- if (!G_TYPE_CHECK_INSTANCE_TYPE (this, self->pspec->owner_type))
+ object = gtk_property_expression_get_object (self, this);
+ if (object == NULL)
return FALSE;
- g_object_get_property (this, self->pspec->name, value);
+ g_object_get_property (object, self->pspec->name, value);
+ g_object_unref (object);
return TRUE;
}
@@ -451,17 +495,28 @@ struct _GtkPropertyExpressionWatch
GtkExpressionWatch watch;
GClosure *closure;
+ GtkExpressionWatch *expr_watch;
};
static void
-gtk_property_expression_watch (GtkExpression *expr,
- gpointer this_,
- GtkExpressionWatch *watch)
+gtk_property_expression_watch_destroy_closure (GtkPropertyExpressionWatch *pwatch)
{
- GtkPropertyExpressionWatch *pwatch = (GtkPropertyExpressionWatch *) watch;
- GtkPropertyExpression *self = (GtkPropertyExpression *) expr;
- GObject *object = this_;
+ if (pwatch->closure == NULL)
+ return;
+
+ g_closure_invalidate (pwatch->closure);
+ g_closure_unref (pwatch->closure);
+ pwatch->closure = NULL;
+}
+
+static void
+gtk_property_expression_watch_create_closure (GtkPropertyExpressionWatch *pwatch)
+{
+ GtkExpressionWatch *watch = (GtkExpressionWatch *) pwatch;
+ GtkPropertyExpression *self = (GtkPropertyExpression *) watch->expression;
+ GObject *object;
+ object = gtk_property_expression_get_object (self, watch->this);
if (object == NULL)
return;
@@ -474,6 +529,38 @@ gtk_property_expression_watch (GtkExpression *expr,
{
g_assert_not_reached ();
}
+
+ g_object_unref (object);
+}
+
+static void
+gtk_property_expression_watch_expr_notify_cb (gpointer data)
+{
+ GtkPropertyExpressionWatch *pwatch = data;
+
+ gtk_property_expression_watch_destroy_closure (pwatch);
+ gtk_property_expression_watch_create_closure (pwatch);
+ gtk_expression_watch_notify (data);
+}
+
+static void
+gtk_property_expression_watch (GtkExpression *expr,
+ gpointer this,
+ GtkExpressionWatch *watch)
+{
+ GtkPropertyExpressionWatch *pwatch = (GtkPropertyExpressionWatch *) watch;
+ GtkPropertyExpression *self = (GtkPropertyExpression *) expr;
+
+ if (self->expr && !gtk_expression_is_static (self->expr))
+ {
+ pwatch->expr_watch = gtk_expression_watch (self->expr,
+ this,
+ gtk_property_expression_watch_expr_notify_cb,
+ pwatch,
+ NULL);
+ }
+
+ gtk_property_expression_watch_create_closure (pwatch);
}
static void
@@ -482,11 +569,9 @@ gtk_property_expression_unwatch (GtkExpression *expr,
{
GtkPropertyExpressionWatch *pwatch = (GtkPropertyExpressionWatch *) watch;
- if (pwatch->closure == NULL)
- return;
+ gtk_property_expression_watch_destroy_closure (pwatch);
- g_closure_invalidate (pwatch->closure);
- g_closure_unref (pwatch->closure);
+ g_clear_pointer (&pwatch->expr_watch, gtk_expression_watch_unwatch);
}
static const GtkExpressionClass GTK_PROPERTY_EXPRESSION_CLASS =
@@ -504,20 +589,27 @@ static const GtkExpressionClass GTK_PROPERTY_EXPRESSION_CLASS =
/**
* gtk_property_expression_new:
* @this_type: The type to expect for the this type
+ * @expression: (nullable) (transfer full): Expression to
+ * evaluate to get the object to query or %NULL to
+ * query the `this` object
* @property_name: name of the property
*
- * Creates an expression that looks up a property on the
- * passed in object when it is evaluated.
- * If gtk_expresson_evaluate() is called with an object of
- * another type, this expression's evaluation will fail.
+ * Creates an expression that looks up a property via the
+ * given @expression or the `this` argument when @expression
+ * is %NULL.
+ *
+ * If the resulting object conforms to @this_type, its property
+ * named @property_name will be queried.
+ * Otherwise, this expression's evaluation will fail.
*
* The given @this_type must have a property with @property_name.
*
* Returns: a new #GtkExpression
**/
GtkExpression *
-gtk_property_expression_new (GType this_type,
- const char *property_name)
+gtk_property_expression_new (GType this_type,
+ GtkExpression *expression,
+ const char *property_name)
{
GtkPropertyExpression *result;
GParamSpec *pspec;
@@ -545,6 +637,7 @@ gtk_property_expression_new (GType this_type,
result = gtk_expression_alloc (>K_PROPERTY_EXPRESSION_CLASS, pspec->value_type);
result->pspec = pspec;
+ result->expr = expression;
return (GtkExpression *) result;
}
diff --git a/gtk/gtkexpression.h b/gtk/gtkexpression.h
index 5c3f1e1a5d..4e2e75be6e 100644
--- a/gtk/gtkexpression.h
+++ b/gtk/gtkexpression.h
@@ -68,6 +68,7 @@ void gtk_expression_watch_unwatch (GtkExpressionWa
GDK_AVAILABLE_IN_ALL
GtkExpression * gtk_property_expression_new (GType this_type,
+ GtkExpression *expression,
const char
*property_name);
GDK_AVAILABLE_IN_ALL
GtkExpression * gtk_constant_expression_new (GType value_type,
diff --git a/testsuite/gtk/expression.c b/testsuite/gtk/expression.c
index f0871853a4..6077315949 100644
--- a/testsuite/gtk/expression.c
+++ b/testsuite/gtk/expression.c
@@ -39,7 +39,7 @@ test_property (void)
guint counter = 0;
filter = GTK_STRING_FILTER (gtk_string_filter_new ());
- expr = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, "search");
+ expr = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, NULL, "search");
watch = gtk_expression_watch (expr, filter, inc_counter, &counter, NULL);
g_assert (gtk_expression_evaluate (expr, filter, &value));
@@ -80,9 +80,9 @@ test_closure (void)
guint counter = 0;
filter = GTK_STRING_FILTER (gtk_string_filter_new ());
- pexpr[0] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, "search");
- pexpr[1] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, "ignore-case");
- pexpr[2] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, "match-substring");
+ pexpr[0] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, NULL, "search");
+ pexpr[1] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, NULL, "ignore-case");
+ pexpr[2] = gtk_property_expression_new (GTK_TYPE_STRING_FILTER, NULL, "match-substring");
expr = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
3,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]