mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-30 15:31:34 +00:00
builder: Add <binding> tag
The tag contains an expression that it then gtk_expression_bind()s to the object it is contained in.
This commit is contained in:
parent
713a6676ff
commit
934bfc8887
@ -219,6 +219,7 @@
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkbuilderscopeprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkexpression.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkintl.h"
|
||||
@ -685,8 +686,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);
|
||||
@ -1013,17 +1028,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)
|
||||
@ -1034,26 +1038,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);
|
||||
_free_binding_info (info, NULL);
|
||||
}
|
||||
else if (common_info->tag_type == TAG_BINDING_EXPRESSION)
|
||||
{
|
||||
BindingExpressionInfo *info = l->data;
|
||||
GtkExpression *expression;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
@ -1446,6 +1524,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)
|
||||
@ -1686,6 +1781,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)
|
||||
@ -1777,6 +1874,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)
|
||||
{
|
||||
@ -1845,7 +1966,13 @@ end_element (GtkBuildableParseContext *context,
|
||||
CommonInfo *parent_info = state_peek_info (data, CommonInfo);
|
||||
g_assert (parent_info != NULL);
|
||||
|
||||
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;
|
||||
|
||||
@ -1996,6 +2123,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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user