mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
expression: Allow passing a this object to bind()
This gives a bit more control over the arguments passed to expressions.
This commit is contained in:
parent
22e6fa3a64
commit
b43c8ae646
@ -401,7 +401,7 @@ setup_listitem_cb (GtkListItemFactory *factory,
|
|||||||
"location");
|
"location");
|
||||||
/* Now create the label and bind the expression to it. */
|
/* Now create the label and bind the expression to it. */
|
||||||
location_label = gtk_label_new (NULL);
|
location_label = gtk_label_new (NULL);
|
||||||
gtk_expression_bind (expression, location_label, "label");
|
gtk_expression_bind (expression, location_label, "label", location_label);
|
||||||
gtk_box_append (GTK_BOX (box), location_label);
|
gtk_box_append (GTK_BOX (box), location_label);
|
||||||
|
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ setup_listitem_cb (GtkListItemFactory *factory,
|
|||||||
expression = gtk_expression_ref (clock_expression);
|
expression = gtk_expression_ref (clock_expression);
|
||||||
/* Now create the widget and bind the expression to it. */
|
/* Now create the widget and bind the expression to it. */
|
||||||
picture = gtk_picture_new ();
|
picture = gtk_picture_new ();
|
||||||
gtk_expression_bind (expression, picture, "paintable");
|
gtk_expression_bind (expression, picture, "paintable", picture);
|
||||||
gtk_box_append (GTK_BOX (box), picture);
|
gtk_box_append (GTK_BOX (box), picture);
|
||||||
|
|
||||||
|
|
||||||
@ -430,7 +430,7 @@ setup_listitem_cb (GtkListItemFactory *factory,
|
|||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
/* Now create the label and bind the expression to it. */
|
/* Now create the label and bind the expression to it. */
|
||||||
time_label = gtk_label_new (NULL);
|
time_label = gtk_label_new (NULL);
|
||||||
gtk_expression_bind (expression, time_label, "label");
|
gtk_expression_bind (expression, time_label, "label", time_label);
|
||||||
gtk_box_append (GTK_BOX (box), time_label);
|
gtk_box_append (GTK_BOX (box), time_label);
|
||||||
|
|
||||||
gtk_expression_unref (clock_expression);
|
gtk_expression_unref (clock_expression);
|
||||||
|
@ -1064,11 +1064,13 @@ gtk_builder_create_bindings (GtkBuilder *builder,
|
|||||||
BindingInfo *info = l->data;
|
BindingInfo *info = l->data;
|
||||||
GObject *source;
|
GObject *source;
|
||||||
|
|
||||||
source = _gtk_builder_lookup_object (builder, info->source, info->line, info->col);
|
source = gtk_builder_lookup_object (builder, info->source, info->line, info->col, error);
|
||||||
if (source)
|
if (source)
|
||||||
g_object_bind_property (source, info->source_property,
|
g_object_bind_property (source, info->source_property,
|
||||||
info->target, info->target_pspec->name,
|
info->target, info->target_pspec->name,
|
||||||
info->flags);
|
info->flags);
|
||||||
|
else
|
||||||
|
error = NULL;
|
||||||
|
|
||||||
_free_binding_info (info, NULL);
|
_free_binding_info (info, NULL);
|
||||||
}
|
}
|
||||||
@ -1076,17 +1078,39 @@ gtk_builder_create_bindings (GtkBuilder *builder,
|
|||||||
{
|
{
|
||||||
BindingExpressionInfo *info = l->data;
|
BindingExpressionInfo *info = l->data;
|
||||||
GtkExpression *expression;
|
GtkExpression *expression;
|
||||||
|
GObject *object;
|
||||||
|
|
||||||
expression = expression_info_construct (builder, info->expr, error);
|
if (info->object_name)
|
||||||
if (expression == NULL)
|
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "%s:%d:%d: ", priv->filename, info->line, info->col);
|
object = gtk_builder_lookup_object (builder, info->object_name, info->line, info->col, error);
|
||||||
error = NULL;
|
if (object == NULL)
|
||||||
result = FALSE;
|
{
|
||||||
|
error = NULL;
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (priv->current_object)
|
||||||
|
{
|
||||||
|
object = priv->current_object;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_expression_bind (expression, info->target, info->target_pspec->name);
|
object = info->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
{
|
||||||
|
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, object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free_binding_expression_info (info);
|
free_binding_expression_info (info);
|
||||||
|
@ -954,7 +954,8 @@ parse_binding (ParserData *data,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
BindingExpressionInfo *info;
|
BindingExpressionInfo *info;
|
||||||
const gchar *name = NULL;
|
const char *name = NULL;
|
||||||
|
const char *object_name = NULL;
|
||||||
ObjectInfo *object_info;
|
ObjectInfo *object_info;
|
||||||
GParamSpec *pspec = NULL;
|
GParamSpec *pspec = NULL;
|
||||||
|
|
||||||
@ -969,6 +970,7 @@ parse_binding (ParserData *data,
|
|||||||
|
|
||||||
if (!g_markup_collect_attributes (element_name, names, values, error,
|
if (!g_markup_collect_attributes (element_name, names, values, error,
|
||||||
G_MARKUP_COLLECT_STRING, "name", &name,
|
G_MARKUP_COLLECT_STRING, "name", &name,
|
||||||
|
G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "object", &object_name,
|
||||||
G_MARKUP_COLLECT_INVALID))
|
G_MARKUP_COLLECT_INVALID))
|
||||||
{
|
{
|
||||||
_gtk_builder_prefix_error (data->builder, &data->ctx, error);
|
_gtk_builder_prefix_error (data->builder, &data->ctx, error);
|
||||||
@ -1013,6 +1015,7 @@ parse_binding (ParserData *data,
|
|||||||
info->tag_type = TAG_BINDING_EXPRESSION;
|
info->tag_type = TAG_BINDING_EXPRESSION;
|
||||||
info->target = NULL;
|
info->target = NULL;
|
||||||
info->target_pspec = pspec;
|
info->target_pspec = pspec;
|
||||||
|
info->object_name = g_strdup (object_name);
|
||||||
gtk_buildable_parse_context_get_position (&data->ctx, &info->line, &info->col);
|
gtk_buildable_parse_context_get_position (&data->ctx, &info->line, &info->col);
|
||||||
|
|
||||||
state_push (data, info);
|
state_push (data, info);
|
||||||
@ -1538,6 +1541,7 @@ free_binding_expression_info (BindingExpressionInfo *info)
|
|||||||
{
|
{
|
||||||
if (info->expr)
|
if (info->expr)
|
||||||
free_expression_info (info->expr);
|
free_expression_info (info->expr);
|
||||||
|
g_free (info->object_name);
|
||||||
g_slice_free (BindingExpressionInfo, info);
|
g_slice_free (BindingExpressionInfo, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,7 @@ typedef struct
|
|||||||
guint tag_type;
|
guint tag_type;
|
||||||
GObject *target;
|
GObject *target;
|
||||||
GParamSpec *target_pspec;
|
GParamSpec *target_pspec;
|
||||||
|
char *object_name;
|
||||||
ExpressionInfo *expr;
|
ExpressionInfo *expr;
|
||||||
gint line;
|
gint line;
|
||||||
gint col;
|
gint col;
|
||||||
|
@ -1287,8 +1287,7 @@ gtk_expression_watch_evaluate (GtkExpressionWatch *watch,
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GtkExpressionWatch *watch;
|
GtkExpressionWatch *watch;
|
||||||
GtkExpression *expression;
|
GObject *target;
|
||||||
GObject *object;
|
|
||||||
GParamSpec *pspec;
|
GParamSpec *pspec;
|
||||||
} GtkExpressionBind;
|
} GtkExpressionBind;
|
||||||
|
|
||||||
@ -1303,7 +1302,12 @@ invalidate_binds (gpointer unused,
|
|||||||
{
|
{
|
||||||
GtkExpressionBind *bind = l->data;
|
GtkExpressionBind *bind = l->data;
|
||||||
|
|
||||||
bind->object = NULL;
|
/* This guarantees we neither try to update bindings
|
||||||
|
* (which would wreck havoc because the object is
|
||||||
|
* dispose()ing itself) nor try to destroy bindings
|
||||||
|
* anymore, so destruction can be done in free_binds().
|
||||||
|
*/
|
||||||
|
bind->target = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1316,8 +1320,10 @@ free_binds (gpointer data)
|
|||||||
{
|
{
|
||||||
GtkExpressionBind *bind = l->data;
|
GtkExpressionBind *bind = l->data;
|
||||||
|
|
||||||
bind->object = NULL;
|
g_assert (bind->target == NULL);
|
||||||
gtk_expression_watch_unwatch (bind->watch);
|
if (bind->watch)
|
||||||
|
gtk_expression_watch_unwatch (bind->watch);
|
||||||
|
g_slice_free (GtkExpressionBind, bind);
|
||||||
}
|
}
|
||||||
g_slist_free (data);
|
g_slist_free (data);
|
||||||
}
|
}
|
||||||
@ -1327,19 +1333,30 @@ gtk_expression_bind_free (gpointer data)
|
|||||||
{
|
{
|
||||||
GtkExpressionBind *bind = data;
|
GtkExpressionBind *bind = data;
|
||||||
|
|
||||||
if (bind->object)
|
if (bind->target)
|
||||||
{
|
{
|
||||||
GSList *binds;
|
GSList *binds;
|
||||||
binds = g_object_steal_data (bind->object, "gtk-expression-binds");
|
binds = g_object_steal_data (bind->target, "gtk-expression-binds");
|
||||||
binds = g_slist_remove (binds, bind);
|
binds = g_slist_remove (binds, bind);
|
||||||
if (binds)
|
if (binds)
|
||||||
g_object_set_data_full (bind->object, "gtk-expression-binds", binds, free_binds);
|
g_object_set_data_full (bind->target, "gtk-expression-binds", binds, free_binds);
|
||||||
else
|
else
|
||||||
g_object_weak_unref (bind->object, invalidate_binds, NULL);
|
g_object_weak_unref (bind->target, invalidate_binds, NULL);
|
||||||
}
|
|
||||||
gtk_expression_unref (bind->expression);
|
|
||||||
|
|
||||||
g_slice_free (GtkExpressionBind, bind);
|
g_slice_free (GtkExpressionBind, bind);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If a bind gets unwatched after invalidate_binds() but
|
||||||
|
* before free_binds(), we end up here. This can happen if
|
||||||
|
* the bind was watching itself or if the target's dispose()
|
||||||
|
* function freed the object that was watched.
|
||||||
|
* We make sure we don't destroy the binding or free_binds() will do
|
||||||
|
* bad stuff, but we clear the watch, so free_binds() won't try to
|
||||||
|
* unwatch() it.
|
||||||
|
*/
|
||||||
|
bind->watch = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1348,29 +1365,31 @@ gtk_expression_bind_notify (gpointer data)
|
|||||||
GValue value = G_VALUE_INIT;
|
GValue value = G_VALUE_INIT;
|
||||||
GtkExpressionBind *bind = data;
|
GtkExpressionBind *bind = data;
|
||||||
|
|
||||||
if (bind->object == NULL)
|
if (bind->target == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!gtk_expression_evaluate (bind->expression, bind->object, &value))
|
if (!gtk_expression_watch_evaluate (bind->watch, &value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_object_set_property (bind->object, bind->pspec->name, &value);
|
g_object_set_property (bind->target, bind->pspec->name, &value);
|
||||||
g_value_unset (&value);
|
g_value_unset (&value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_expression_bind:
|
* gtk_expression_bind:
|
||||||
* @self: (transfer full): a #GtkExpression
|
* @self: (transfer full): a #GtkExpression
|
||||||
* @object: (transfer none) (type GObject): the object to bind
|
* @target: (transfer none) (type GObject): the target object to bind to
|
||||||
* @property: name of the property to bind to
|
* @property: name of the property on @target to bind to
|
||||||
|
* @this_: (transfer none) (type GObject): the this argument for
|
||||||
|
* the evaluation of @self
|
||||||
*
|
*
|
||||||
* Bind @object's property named @property to @self.
|
* Bind @target's property named @property to @self.
|
||||||
*
|
*
|
||||||
* The value that @self evaluates to is set via g_object_set() on
|
* The value that @self evaluates to is set via g_object_set() on
|
||||||
* @object. This is repeated whenever @self changes to ensure that
|
* @target. This is repeated whenever @self changes to ensure that
|
||||||
* the object's property stays synchronized with @self.
|
* the object's property stays synchronized with @self.
|
||||||
*
|
*
|
||||||
* If @self's evaluation fails, @object's @property is not updated.
|
* If @self's evaluation fails, @target's @property is not updated.
|
||||||
* You can ensure that this doesn't happen by using a fallback
|
* You can ensure that this doesn't happen by using a fallback
|
||||||
* expression.
|
* expression.
|
||||||
*
|
*
|
||||||
@ -1381,44 +1400,44 @@ gtk_expression_bind_notify (gpointer data)
|
|||||||
**/
|
**/
|
||||||
GtkExpressionWatch *
|
GtkExpressionWatch *
|
||||||
gtk_expression_bind (GtkExpression *self,
|
gtk_expression_bind (GtkExpression *self,
|
||||||
gpointer object,
|
gpointer target,
|
||||||
const char *property)
|
const char *property,
|
||||||
|
gpointer this_)
|
||||||
{
|
{
|
||||||
GtkExpressionBind *bind;
|
GtkExpressionBind *bind;
|
||||||
GParamSpec *pspec;
|
GParamSpec *pspec;
|
||||||
GSList *binds;
|
GSList *binds;
|
||||||
|
|
||||||
g_return_val_if_fail (GTK_IS_EXPRESSION (self), NULL);
|
g_return_val_if_fail (GTK_IS_EXPRESSION (self), NULL);
|
||||||
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
g_return_val_if_fail (G_IS_OBJECT (target), NULL);
|
||||||
g_return_val_if_fail (property != NULL, NULL);
|
g_return_val_if_fail (property != NULL, NULL);
|
||||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property);
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), property);
|
||||||
if (G_UNLIKELY (pspec == NULL))
|
if (G_UNLIKELY (pspec == NULL))
|
||||||
{
|
{
|
||||||
g_critical ("%s: Class '%s' has no property named '%s'",
|
g_critical ("%s: Class '%s' has no property named '%s'",
|
||||||
G_STRFUNC, G_OBJECT_TYPE_NAME (object), property);
|
G_STRFUNC, G_OBJECT_TYPE_NAME (target), property);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (G_UNLIKELY ((pspec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE))
|
if (G_UNLIKELY ((pspec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE))
|
||||||
{
|
{
|
||||||
g_critical ("%s: property '%s' of class '%s' is not writable",
|
g_critical ("%s: property '%s' of class '%s' is not writable",
|
||||||
G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (object));
|
G_STRFUNC, pspec->name, G_OBJECT_TYPE_NAME (target));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bind = g_slice_new0 (GtkExpressionBind);
|
bind = g_slice_new0 (GtkExpressionBind);
|
||||||
binds = g_object_steal_data (object, "gtk-expression-binds");
|
binds = g_object_steal_data (target, "gtk-expression-binds");
|
||||||
if (binds == NULL)
|
if (binds == NULL)
|
||||||
g_object_weak_ref (object, invalidate_binds, NULL);
|
g_object_weak_ref (target, invalidate_binds, NULL);
|
||||||
bind->expression = self;
|
bind->target = target;
|
||||||
bind->object = object;
|
|
||||||
bind->pspec = pspec;
|
bind->pspec = pspec;
|
||||||
bind->watch = gtk_expression_watch (self,
|
bind->watch = gtk_expression_watch (self,
|
||||||
object,
|
this_,
|
||||||
gtk_expression_bind_notify,
|
gtk_expression_bind_notify,
|
||||||
bind,
|
bind,
|
||||||
gtk_expression_bind_free);
|
gtk_expression_bind_free);
|
||||||
binds = g_slist_prepend (binds, bind);
|
binds = g_slist_prepend (binds, bind);
|
||||||
g_object_set_data_full (object, "gtk-expression-binds", binds, free_binds);
|
g_object_set_data_full (target, "gtk-expression-binds", binds, free_binds);
|
||||||
|
|
||||||
gtk_expression_unref (self);
|
gtk_expression_unref (self);
|
||||||
|
|
||||||
|
@ -65,8 +65,9 @@ GtkExpressionWatch * gtk_expression_watch (GtkExpression
|
|||||||
GDestroyNotify user_destroy);
|
GDestroyNotify user_destroy);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GtkExpressionWatch * gtk_expression_bind (GtkExpression *self,
|
GtkExpressionWatch * gtk_expression_bind (GtkExpression *self,
|
||||||
gpointer object,
|
gpointer target,
|
||||||
const char * property);
|
const char * property,
|
||||||
|
gpointer this_);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GtkExpressionWatch * gtk_expression_watch_ref (GtkExpressionWatch *watch);
|
GtkExpressionWatch * gtk_expression_watch_ref (GtkExpressionWatch *watch);
|
||||||
|
Loading…
Reference in New Issue
Block a user