[gtk+/composite-widget-templates] Added gtk_builder_expose_object(), gtk_builder_add_to_parent_from_file() and gtk_builder_add_to_pare
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/composite-widget-templates] Added gtk_builder_expose_object(), gtk_builder_add_to_parent_from_file() and gtk_builder_add_to_pare
- Date: Mon, 7 Jun 2010 18:45:19 +0000 (UTC)
commit 6a8a584a9506ad2e70f69525b302069025c00008
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Mon Jun 7 14:30:28 2010 -0400
Added gtk_builder_expose_object(), gtk_builder_add_to_parent_from_file() and
gtk_builder_add_to_parent_from_string().
Adding the needed GtkBuilder framework for composite containers. First the
expose_object() api is based on the work Marco Diego Aurélio Mesquita did
in bug 447972 with some bugs fixed and things cleared up. Next the
gtk_builder_add_to_parent_from_[file/string]() variants are used to extend
containers inline by adding themselves and letting the builder add the
children defined in a template file.
gtk/gtkbuilder.c | 213 +++++++++++++++++++++++++++++++++++++++++------
gtk/gtkbuilder.h | 12 +++
gtk/gtkbuilderparser.c | 41 ++++++++-
gtk/gtkbuilderprivate.h | 5 +-
4 files changed, 241 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index c6d3b08..150feef 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -148,22 +148,27 @@
* (can be specified by their name, nick or integer value), flags (can be
* specified by their name, nick, integer value, optionally combined with "|",
* e.g. "GTK_VISIBLE|GTK_REALIZED") and colors (in a format understood by
- * gdk_color_parse()). Objects can be referred to by their name. Pixbufs can be
- * specified as a filename of an image file to load. In general, GtkBuilder
- * allows forward references to objects — an object doesn't have to be
- * constructed before it can be referred to. The exception to this rule is that
- * an object has to be constructed before it can be used as the value of a
- * construct-only property.
+ * gdk_color_parse()). Pixbufs can be specified as a filename of an image file to load.
+ * Objects can be referred to by their name and by default refer to objects declared
+ * in the local xml fragment, however external objects exposed via gtk_builder_expose_object()
+ * can be referred to by specifying the "external-object" attribute.
+ *
+ * In general, GtkBuilder allows forward references to objects &mdash declared
+ * in the local xml; an object doesn't have to be constructed before it can be referred to.
+ * The exception to this rule is that an object has to be constructed before
+ * it can be used as the value of a construct-only property.
*
* Signal handlers are set up with the <signal> element. The "name"
* attribute specifies the name of the signal, and the "handler" attribute
* specifies the function to connect to the signal. By default, GTK+ tries to
* find the handler using g_module_symbol(), but this can be changed by passing
* a custom #GtkBuilderConnectFunc to gtk_builder_connect_signals_full(). The
- * remaining attributes, "after", "swapped" and "object", have the same meaning
+ * attributes "after", "swapped" and "object", have the same meaning
* as the corresponding parameters of the g_signal_connect_object() or
- * g_signal_connect_data() functions. A "last_modification_time" attribute
- * is also allowed, but it does not have a meaning to the builder.
+ * g_signal_connect_data() functions. Extenral objects can also be referred
+ * to by specifying the "external-object" attribute in the same way as described
+ * with the <property> element. A "last_modification_time" attribute is also
+ * allowed, but it does not have a meaning to the builder.
*
* Sometimes it is necessary to refer to widgets which have implicitly been
* constructed by GTK+ as part of a composite widget, to set properties on them
@@ -278,6 +283,7 @@ struct _GtkBuilderPrivate
{
gchar *domain;
GHashTable *objects;
+ GHashTable *external_objects;
GSList *delayed_properties;
GSList *signals;
gchar *filename;
@@ -327,6 +333,8 @@ gtk_builder_init (GtkBuilder *builder)
builder->priv->domain = NULL;
builder->priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
+ builder->priv->external_objects = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
}
@@ -343,6 +351,7 @@ gtk_builder_finalize (GObject *object)
g_free (priv->filename);
g_hash_table_destroy (priv->objects);
+ g_hash_table_destroy (priv->external_objects);
g_slist_foreach (priv->signals, (GFunc) _free_signal_info, NULL);
g_slist_free (priv->signals);
@@ -498,10 +507,27 @@ gtk_builder_get_parameters (GtkBuilder *builder,
if (G_IS_PARAM_SPEC_OBJECT (pspec) &&
(G_PARAM_SPEC_VALUE_TYPE (pspec) != GDK_TYPE_PIXBUF))
{
- if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+ GObject *object;
+
+ if (prop->external)
+ {
+ object = g_hash_table_lookup (builder->priv->external_objects, prop->data);
+
+ if (!object)
+ {
+ g_warning ("Failed to get external object property "
+ "%s of %s with value `%s'",
+ prop->name, object_name, prop->data);
+ continue;
+ }
+
+ g_value_init (¶meter.value, G_OBJECT_TYPE (object));
+ g_value_set_object (¶meter.value, object);
+ }
+ else if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
{
- GObject *object;
- object = gtk_builder_get_object (builder, prop->data);
+ object = gtk_builder_get_object (builder, prop->data);
+
if (!object)
{
g_warning ("Failed to get constuct only property "
@@ -512,7 +538,7 @@ gtk_builder_get_parameters (GtkBuilder *builder,
g_value_init (¶meter.value, G_OBJECT_TYPE (object));
g_value_set_object (¶meter.value, object);
}
- else
+ else
{
property = g_slice_new (DelayedProperty);
property->object = g_strdup (object_name);
@@ -570,6 +596,9 @@ gtk_builder_get_internal_child (GtkBuilder *builder,
obj = gtk_buildable_get_internal_child (GTK_BUILDABLE (info->object),
builder,
childname);
+ if (!obj && GTK_IS_CONTAINER (info->object))
+ obj = (GObject *)gtk_container_get_composite_child (GTK_CONTAINER (info->object), childname);
+
};
if (!obj)
@@ -893,7 +922,64 @@ gtk_builder_add_from_file (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (filename);
- _gtk_builder_parser_parse_buffer (builder, filename,
+ _gtk_builder_parser_parse_buffer (builder, NULL, filename,
+ buffer, length,
+ NULL,
+ &tmp_error);
+
+ g_free (buffer);
+
+ if (tmp_error != NULL)
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * gtk_builder_add_to_parent_from_file:
+ * @builder: a #GtkBuilder
+ * @parent: the parent object to be assumed in context while parsing the file
+ * @filename: the name of the file to parse
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Like gtk_builder_add_from_file() except the format will expect
+ * <child> instead of <object> as its first elements and expose
+ * @parent in the build context, children defined in the UI fragment
+ * will be added to @parent.
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: ...
+ **/
+guint
+gtk_builder_add_to_parent_from_file (GtkBuilder *builder,
+ GObject *parent,
+ const gchar *filename,
+ GError **error)
+{
+ gchar *buffer;
+ gsize length;
+ GError *tmp_error;
+
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+ g_return_val_if_fail (filename != NULL, 0);
+ g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+ tmp_error = NULL;
+
+ if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ g_free (builder->priv->filename);
+ builder->priv->filename = g_strdup (filename);
+
+ _gtk_builder_parser_parse_buffer (builder, parent, filename,
buffer, length,
NULL,
&tmp_error);
@@ -960,7 +1046,7 @@ gtk_builder_add_objects_from_file (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (filename);
- _gtk_builder_parser_parse_buffer (builder, filename,
+ _gtk_builder_parser_parse_buffer (builder, NULL, filename,
buffer, length,
object_ids,
&tmp_error);
@@ -1010,7 +1096,56 @@ gtk_builder_add_from_string (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (".");
- _gtk_builder_parser_parse_buffer (builder, "<input>",
+ _gtk_builder_parser_parse_buffer (builder, NULL, "<input>",
+ buffer, length,
+ NULL,
+ &tmp_error);
+ if (tmp_error != NULL)
+ {
+ g_propagate_error (error, tmp_error);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * gtk_builder_add_to_parent_from_string:
+ * @builder: a #GtkBuilder
+ * @parent: the parent object to be assumed in context while parsing
+ * @buffer: the string to parse
+ * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
+ * @error: (allow-none): return location for an error, or %NULL
+ *
+ * Like gtk_builder_add_from_string() except the format will expect
+ * <child> instead of <object> as its first elements and expose
+ * @parent in the build context, children defined in the UI fragment
+ * will be added to @parent.
+ *
+ * Returns: A positive value on success, 0 if an error occurred
+ *
+ * Since: ...
+ **/
+guint
+gtk_builder_add_to_parent_from_string (GtkBuilder *builder,
+ GObject *parent,
+ const gchar *buffer,
+ gsize length,
+ GError **error)
+{
+ GError *tmp_error;
+
+ g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+ g_return_val_if_fail (buffer != NULL, 0);
+ g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+ tmp_error = NULL;
+
+ g_free (builder->priv->filename);
+ builder->priv->filename = g_strdup (".");
+
+ _gtk_builder_parser_parse_buffer (builder, parent, "<input>",
buffer, length,
NULL,
&tmp_error);
@@ -1067,7 +1202,7 @@ gtk_builder_add_objects_from_string (GtkBuilder *builder,
g_free (builder->priv->filename);
builder->priv->filename = g_strdup (".");
- _gtk_builder_parser_parse_buffer (builder, "<input>",
+ _gtk_builder_parser_parse_buffer (builder, NULL, "<input>",
buffer, length,
object_ids,
&tmp_error);
@@ -1182,6 +1317,30 @@ gtk_builder_get_translation_domain (GtkBuilder *builder)
return builder->priv->domain;
}
+/**
+ * gtk_builder_expose_object:
+ * @builder: a #GtkBuilder
+ * @name: the name of the object exposed to the builder
+ * @object: the object to expose
+ *
+ * Adds @object to a pool of objects external to the
+ * objects built by builder. Objects exposed in the pool
+ * can be referred to by xml fragments in the builder.
+ */
+void
+gtk_builder_expose_object (GtkBuilder *builder,
+ const gchar *name,
+ GObject *object)
+{
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+ g_return_if_fail (name && name[0]);
+ g_return_if_fail (G_IS_OBJECT (object));
+
+ g_hash_table_insert (builder->priv->external_objects,
+ g_strdup (name), g_object_ref (object));
+}
+
+
typedef struct {
GModule *module;
gpointer data;
@@ -1211,7 +1370,6 @@ gtk_builder_connect_signals_default (GtkBuilder *builder,
g_signal_connect_data (object, signal_name, func, args->data, NULL, flags);
}
-
/**
* gtk_builder_connect_signals:
* @builder: a #GtkBuilder
@@ -1307,7 +1465,7 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
for (l = builder->priv->signals; l; l = l->next)
{
SignalInfo *signal = (SignalInfo*)l->data;
-
+
g_assert (signal != NULL);
g_assert (signal->name != NULL);
@@ -1319,14 +1477,19 @@ gtk_builder_connect_signals_full (GtkBuilder *builder,
if (signal->connect_object_name)
{
- connect_object = g_hash_table_lookup (builder->priv->objects,
- signal->connect_object_name);
+ if (signal->external)
+ connect_object = g_hash_table_lookup (builder->priv->external_objects,
+ signal->connect_object_name);
+ else
+ connect_object = g_hash_table_lookup (builder->priv->objects,
+ signal->connect_object_name);
+
if (!connect_object)
- g_warning ("Could not lookup object %s on signal %s of object %s",
- signal->connect_object_name, signal->name,
- signal->object_name);
+ g_warning ("Could not lookup object %s on signal %s of object %s.",
+ signal->connect_object_name, signal->name,
+ signal->object_name);
}
-
+
func (builder, object, signal->name, signal->handler,
connect_object, signal->flags, user_data);
}
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index bb711e2..a509286 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -133,9 +133,21 @@ guint gtk_builder_add_objects_from_string (GtkBuilder *builder,
gsize length,
gchar **object_ids,
GError **error);
+guint gtk_builder_add_to_parent_from_file (GtkBuilder *builder,
+ GObject *parent,
+ const gchar *filename,
+ GError **error);
+guint gtk_builder_add_to_parent_from_string (GtkBuilder *builder,
+ GObject *parent,
+ const gchar *buffer,
+ gsize length,
+ GError **error);
GObject* gtk_builder_get_object (GtkBuilder *builder,
const gchar *name);
GSList* gtk_builder_get_objects (GtkBuilder *builder);
+void gtk_builder_expose_object (GtkBuilder *builder,
+ const gchar *name,
+ GObject *object);
void gtk_builder_connect_signals (GtkBuilder *builder,
gpointer user_data);
void gtk_builder_connect_signals_full (GtkBuilder *builder,
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index b4f6855..c034da5 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -437,6 +437,7 @@ parse_child (ParserData *data,
{
ObjectInfo* object_info;
ChildInfo *child_info;
+ GObject *object;
guint i;
object_info = state_peek_info (data, ObjectInfo);
@@ -445,6 +446,9 @@ parse_child (ParserData *data,
error_invalid_tag (data, element_name, NULL, error);
return;
}
+
+ GTK_NOTE (BUILDER, g_print ("parsing child of parent type %s\n",
+ object_info->object ? G_OBJECT_TYPE_NAME (object_info->object) : "(none)"));
child_info = g_slice_new0 (ChildInfo);
state_push (data, child_info);
@@ -461,7 +465,9 @@ parse_child (ParserData *data,
child_info->parent = (CommonInfo*)object_info;
- object_info->object = builder_construct (data, object_info, error);
+ object = builder_construct (data, object_info, error);
+ object_info->object = object;
+
}
static void
@@ -483,6 +489,7 @@ parse_property (ParserData *data,
gchar *name = NULL;
gchar *context = NULL;
gboolean translatable = FALSE;
+ gboolean external = FALSE;
ObjectInfo *object_info;
int i;
@@ -511,6 +518,11 @@ parse_property (ParserData *data,
{
context = g_strdup (values[i]);
}
+ else if (strcmp (names[i], "external-object") == 0)
+ {
+ if (!_gtk_builder_boolean_from_string (values[i], &external, error))
+ return;
+ }
else
{
error_invalid_attribute (data, element_name, names[i], error);
@@ -525,10 +537,11 @@ parse_property (ParserData *data,
}
info = g_slice_new0 (PropertyInfo);
- info->name = name;
+ info->name = name;
info->translatable = translatable;
- info->context = context;
- info->text = g_string_new ("");
+ info->context = context;
+ info->text = g_string_new ("");
+ info->external = external;
state_push (data, info);
info->tag.name = element_name;
@@ -556,6 +569,7 @@ parse_signal (ParserData *data,
gboolean after = FALSE;
gboolean swapped = FALSE;
gboolean swapped_set = FALSE;
+ gboolean external = FALSE;
ObjectInfo *object_info;
int i;
@@ -583,6 +597,11 @@ parse_signal (ParserData *data,
return;
swapped_set = TRUE;
}
+ else if (strcmp (names[i], "external-object") == 0)
+ {
+ if (!_gtk_builder_boolean_from_string (values[i], &external, error))
+ return;
+ }
else if (strcmp (names[i], "object") == 0)
object = g_strdup (values[i]);
else if (strcmp (names[i], "last_modification_time") == 0)
@@ -617,6 +636,7 @@ parse_signal (ParserData *data,
info->flags |= G_CONNECT_AFTER;
if (swapped)
info->flags |= G_CONNECT_SWAPPED;
+ info->external = external;
info->connect_object_name = object;
state_push (data, info);
@@ -1113,6 +1133,7 @@ static const GMarkupParser parser = {
void
_gtk_builder_parser_parse_buffer (GtkBuilder *builder,
+ GObject *parent,
const gchar *filename,
const gchar *buffer,
gsize length,
@@ -1137,6 +1158,18 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
data->object_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
+ if (parent)
+ {
+ ObjectInfo *object_info = g_slice_new0 (ObjectInfo);
+
+ GTK_NOTE (BUILDER, g_print ("parsing with contextual parent info ptr %p\n", object_info));
+
+ object_info->object = parent;
+ object_info->id = g_strdup ("__container");
+ state_push (data, object_info);
+ object_info->tag.name = "object";
+ }
+
data->requested_objects = NULL;
if (requested_objs)
{
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index e633a28..dc2e16d 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -57,8 +57,9 @@ typedef struct {
gchar *name;
GString *text;
gchar *data;
- gboolean translatable;
gchar *context;
+ guint8 translatable : 1;
+ guint8 external : 1;
} PropertyInfo;
typedef struct {
@@ -66,6 +67,7 @@ typedef struct {
gchar *object_name;
gchar *name;
gchar *handler;
+ gboolean external;
GConnectFlags flags;
gchar *connect_object_name;
} SignalInfo;
@@ -109,6 +111,7 @@ typedef GType (*GTypeGetFunc) (void);
/* Things only GtkBuilder should use */
void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
+ GObject *parent,
const gchar *filename,
const gchar *buffer,
gsize length,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]