[gtk+/composite-templates] Removed gtk_builder_add_to_parent_*() functions, instead you can use gtk_builder_expose_object() to



commit 26b70cd81f31901e2bb0d7e7d6db77c51b50165a
Author: Juan Pablo Ugarte <juanpablougarte gmail com>
Date:   Mon Nov 12 14:57:47 2012 -0300

    Removed gtk_builder_add_to_parent_*() functions, instead you can use gtk_builder_expose_object()
    to expose the template object and simply call gtk_builder_add_from_*()
    
    Added test_expose_object() test case

 docs/reference/gtk/gtk3-sections.txt |    1 +
 gtk/gtkbuilder.c                     |  175 ++++++++--------------------------
 gtk/gtkbuilder.h                     |   16 ---
 gtk/gtkbuilder.rnc                   |   10 ++-
 gtk/gtkbuilderparser.c               |  101 ++++++++------------
 gtk/gtkbuilderprivate.h              |    7 +-
 gtk/gtkcontainer.c                   |   25 ++----
 gtk/tests/builder.c                  |  124 +++++++++++++++++++-----
 8 files changed, 201 insertions(+), 258 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 9e159b1..006bc1b 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -536,6 +536,7 @@ gtk_builder_add_objects_from_string
 gtk_builder_add_objects_from_resource
 gtk_builder_get_object
 gtk_builder_get_objects
+gtk_builder_expose_object
 gtk_builder_connect_signals
 gtk_builder_connect_signals_full
 gtk_builder_set_translation_domain
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index 1c6c573..f5c4899 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -140,7 +140,7 @@
  * a custom #GtkBuilderConnectFunc to gtk_builder_connect_signals_full(). The
  * 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.  Extenral objects can also be referred 
+ * g_signal_connect_data() functions.  External objects can also be referred 
  * to by specifying the "external-object" attribute in the same way as described 
  * with the &lt;property&gt; element. A "last_modification_time" attribute is also 
  * allowed, but it does not have a meaning to the builder.
@@ -896,8 +896,6 @@ gtk_builder_new (void)
 
 static guint
 gtk_builder_add_from_file_real (GtkBuilder   *builder,
-                                GObject      *parent,
-                                const gchar  *template_id,
                                 const gchar  *filename,
                                 gchar       **object_ids,
                                 GError      **error)
@@ -917,8 +915,8 @@ gtk_builder_add_from_file_real (GtkBuilder   *builder,
   builder->priv->filename = g_strdup (filename);
   builder->priv->resource_prefix = NULL;
 
-  _gtk_builder_parser_parse_buffer (builder, parent, template_id, filename,
-                                    buffer, length, object_ids, &tmp_error);
+  _gtk_builder_parser_parse_buffer (builder, filename, buffer, length,
+                                    object_ids, &tmp_error);
 
   g_free (buffer);
 
@@ -957,41 +955,7 @@ gtk_builder_add_from_file (GtkBuilder   *builder,
   g_return_val_if_fail (filename != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
   
-  return gtk_builder_add_from_file_real (builder, NULL, NULL, filename,
-                                         NULL, error);
-}
-
-/**
- * gtk_builder_add_to_parent_from_file:
- * @builder: a #GtkBuilder
- * @parent: the parent container where children will be added, or %NULL
- * @template_id: the template id to use, or %NULL
- * @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
- * <template> instead of <object> with id @template_id.
- * The 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  *template_id,
-                                     const gchar  *filename,
-                                     GError      **error)
-{
-  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
-  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
-  g_return_val_if_fail (template_id != NULL, 0);
-  g_return_val_if_fail (filename != NULL, 0);
-  g_return_val_if_fail (error == NULL || *error == NULL, 0);
-
-  return gtk_builder_add_from_file_real (builder, parent, template_id,
-                                         filename, NULL, error);
+  return gtk_builder_add_from_file_real (builder, filename, NULL, error);
 }
 
 /**
@@ -1030,14 +994,11 @@ gtk_builder_add_objects_from_file (GtkBuilder   *builder,
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  return gtk_builder_add_from_file_real (builder, NULL, NULL, filename,
-                                         object_ids, error);
+  return gtk_builder_add_from_file_real (builder, filename, object_ids, error);
 }
 
 static guint
 gtk_builder_add_from_resource_real (GtkBuilder   *builder,
-                                    GObject      *parent,
-                                    const gchar  *template_id,
                                     const gchar  *path,
                                     gchar       **object_ids,
                                     GError      **error)
@@ -1068,7 +1029,7 @@ gtk_builder_add_from_resource_real (GtkBuilder   *builder,
 
   filename_for_errors = g_strconcat ("<resource>", path, NULL);
 
-  _gtk_builder_parser_parse_buffer (builder, parent, template_id, filename_for_errors,
+  _gtk_builder_parser_parse_buffer (builder, filename_for_errors,
                                     g_bytes_get_data (data, NULL), g_bytes_get_size (data),
                                     object_ids, &tmp_error);
 
@@ -1110,42 +1071,7 @@ gtk_builder_add_from_resource (GtkBuilder   *builder,
   g_return_val_if_fail (resource_path != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  return gtk_builder_add_from_resource_real (builder, NULL, NULL,
-                                             resource_path, NULL,
-                                             error);
-}
-
-/**
- * gtk_builder_add_to_parent_from_resource:
- * @builder: a #GtkBuilder
- * @parent: the parent container where children will be added, or %NULL
- * @template_id: the template id to use, or %NULL
- * @resource_path: the resource path to parse
- * @error: (allow-none): return location for an error, or %NULL
- *
- * Like gtk_builder_add_from_resource() except the format will expect
- * <template> instead of <object> with id @template_id.
- * The 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_resource (GtkBuilder   *builder,
-                                         GObject      *parent,
-                                         const gchar  *template_id,
-                                         const gchar  *resource_path,
-                                         GError      **error)
-{
-  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
-  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
-  g_return_val_if_fail (template_id != NULL, 0);
-  g_return_val_if_fail (resource_path != NULL, 0);
-  g_return_val_if_fail (error == NULL || *error == NULL, 0);
-
-  return gtk_builder_add_from_resource_real (builder, parent, template_id,
-                                             resource_path, NULL, error);
+  return gtk_builder_add_from_resource_real (builder, resource_path, NULL, error);
 }
 
 /**
@@ -1184,15 +1110,12 @@ gtk_builder_add_objects_from_resource (GtkBuilder   *builder,
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  return gtk_builder_add_from_resource_real (builder, NULL, NULL,
-                                             resource_path, object_ids,
-                                             error);
+  return gtk_builder_add_from_resource_real (builder, resource_path,
+                                             object_ids, error);
 }
 
 static guint
 gtk_builder_add_from_string_real (GtkBuilder   *builder,
-                                  GObject      *parent,
-                                  const gchar  *template_id,
                                   const gchar  *buffer,
                                   gsize         length,
                                   gchar       **object_ids,
@@ -1205,8 +1128,8 @@ gtk_builder_add_from_string_real (GtkBuilder   *builder,
   builder->priv->filename = g_strdup (".");
   builder->priv->resource_prefix = NULL;
 
-  _gtk_builder_parser_parse_buffer (builder, parent, template_id, "<input>",
-                                    buffer, length, object_ids, &tmp_error);
+  _gtk_builder_parser_parse_buffer (builder, "<input>", buffer, length,
+                                    object_ids, &tmp_error);
   if (tmp_error != NULL)
     {
       g_propagate_error (error, tmp_error);
@@ -1243,46 +1166,7 @@ gtk_builder_add_from_string (GtkBuilder   *builder,
   g_return_val_if_fail (buffer != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
   
-  return gtk_builder_add_from_string_real (builder, NULL, NULL,
-                                           buffer, length,
-                                           NULL, error);
-}
-
-
-/**
- * gtk_builder_add_to_parent_from_string:
- * @builder: a #GtkBuilder
- * @parent: the parent container where children will be added, or %NULL
- * @template_id: the template id to use, or %NULL
- * @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
- * <template> instead of <object> with id @template_id.
- * The 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  *template_id,
-                                       const gchar  *buffer,
-                                       gsize         length,
-                                       GError      **error)
-{
-  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
-  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
-  g_return_val_if_fail (template_id != NULL, 0);
-  g_return_val_if_fail (buffer != NULL, 0);
-  g_return_val_if_fail (error == NULL || *error == NULL, 0);
-
-  return gtk_builder_add_from_string_real (builder, parent, template_id,
-                                           buffer, length,
-                                           NULL, error);
+  return gtk_builder_add_from_string_real (builder, buffer, length, NULL, error);
 }
 
 /**
@@ -1322,11 +1206,25 @@ gtk_builder_add_objects_from_string (GtkBuilder   *builder,
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  return gtk_builder_add_from_string_real (builder, NULL, NULL,
-                                           buffer, length,
+  return gtk_builder_add_from_string_real (builder, buffer, length,
                                            object_ids, error);
 }
 
+GObject *
+_gtk_builder_get_external_object (GtkBuilder    *builder,
+                                  const gchar   *name)
+{
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), NULL);
+
+  if (builder->priv->external_objects)
+    {
+      g_return_val_if_fail (name != NULL, NULL);
+      return g_hash_table_lookup (builder->priv->external_objects, name);
+    }
+  else
+    return NULL;
+}
+
 /**
  * gtk_builder_get_object:
  * @builder: a #GtkBuilder
@@ -1434,10 +1332,19 @@ gtk_builder_get_translation_domain (GtkBuilder *builder)
  * @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.
- */
+ * Adds @object to a pool of objects external to the objects built by builder.
+ * Objects exposed in this pool can be referred to by xml fragments by 
+ * specifying the "external-object" boolean attribute.
+ *
+ * To make this function even more useful a new special entry point element
+ * &lt;template&gt; is defined. It is similar to &lt;object&gt; with the only difference
+ * it can only be defined as a toplevel element (that is it has to be a child of
+ * &lt;interface&gt;) and its id has to reference an external object exposed with this
+ * function. This way you can change properties and even add children to an
+ * external object using builder, not just reference it.
+ *
+ * Since: 3.8
+ **/
 void         
 gtk_builder_expose_object (GtkBuilder    *builder,
                            const gchar   *name,
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index e2a73ac..3338162 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -140,22 +140,6 @@ 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  *template_id,
-                                                      const gchar  *filename,
-                                                      GError      **error);
-guint        gtk_builder_add_to_parent_from_string   (GtkBuilder   *builder,
-                                                      GObject      *parent,
-                                                      const gchar  *template_id,
-                                                      const gchar  *buffer,
-                                                      gsize         length,
-                                                      GError      **error);
-guint        gtk_builder_add_to_parent_from_resource (GtkBuilder   *builder,
-                                                      GObject      *parent,
-                                                      const gchar  *template_id,
-                                                      const gchar  *resource_path,
-                                                      GError      **error);
 GObject*     gtk_builder_get_object              (GtkBuilder    *builder,
                                                   const gchar   *name);
 GSList*      gtk_builder_get_objects             (GtkBuilder    *builder);
diff --git a/gtk/gtkbuilder.rnc b/gtk/gtkbuilder.rnc
index a2b4032..bb8bfff 100644
--- a/gtk/gtkbuilder.rnc
+++ b/gtk/gtkbuilder.rnc
@@ -1,6 +1,6 @@
 start = element interface {
   attribute domain { text } ?,
-  ( requires | object | menu ) *
+  ( requires | object | template | menu ) *
 }
 
 requires = element requires {
@@ -16,9 +16,17 @@ object = element object {
   (property | signal | child | ANY) *
 }
 
+object = element template {
+  attribute id { xsd:ID },
+  attribute class { text },
+  attribute parent { text } ?,
+  (property | signal | child | ANY) *
+}
+
 property = element property {
   attribute name { text },
   attribute translatable { "yes" | "no" } ?,
+  attribute external-object { "yes" | "no" } ?,
   attribute comments { text } ?,
   attribute context { text } ?,
   text ?
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index 1cfc0a9..bef907c 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -417,7 +417,7 @@ parse_object (GMarkupParseContext  *context,
           return;
         }
     }
-  else if (data->template_object && !data->inside_requested_template)
+  else if (data->template_level && !data->template_object)
     return;
 
   object_info = g_slice_new0 (ObjectInfo);
@@ -684,12 +684,24 @@ parse_template (ParserData   *data,
                 const gchar **values,
                 GError      **error)
 {
-  GObject *parent = data->template_object;
   const gchar *parent_class = NULL;
   const gchar *class_name = NULL;
   const gchar *id = NULL;
+  const GSList *l, *p;
+  GObject *parent;
   gint i;
 
+  data->template_level++;
+
+  if (data->template_level > 1 ||
+      !((l = g_markup_parse_context_get_element_stack (data->ctx)) &&
+      (p = g_slist_next (l)) && g_strcmp0 (p->data, "interface") == 0))
+    {
+      error_generic (error, GTK_BUILDER_ERROR_INVALID_TAG, data,
+                     element_name, "non toplevel template found");
+      return;
+    }
+
   for (i = 0; names[i] != NULL; i++)
     {
       if (strcmp (names[i], "class") == 0)
@@ -717,17 +729,12 @@ parse_template (ParserData   *data,
       return;
     }
 
-  if (parent)
+  if (data->requested_objects == NULL &&
+      (parent = _gtk_builder_get_external_object (data->builder, id)))
     {
-      const gchar *template_name= _gtk_builder_object_get_name (parent);
       GType class_type, parent_type = G_OBJECT_TYPE (parent);
       ObjectInfo *object_info;
 
-      if (!data->inside_requested_template && g_strcmp0 (template_name, id) == 0)
-        data->inside_requested_template = TRUE;
-      else
-        return;
-
       if (!(class_type = g_type_from_name (class_name)))
         {
           error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
@@ -754,19 +761,13 @@ parse_template (ParserData   *data,
 
       /* push parent to build its children from the template */
       object_info = g_slice_new0 (ObjectInfo);
-      object_info->object = parent;
+      object_info->object = data->template_object = parent;
       object_info->object_type = parent_type;
       object_info->id = g_strdup (_gtk_builder_object_get_name (parent));
       object_info->tag.name = "object";
 
       state_push (data, object_info);
     }
-  else
-    {
-      error_invalid_tag (data, element_name, NULL, error);
-      return;
-    }
-
 }
 
 /* Called by GtkBuilder */
@@ -1016,14 +1017,10 @@ start_element (GMarkupParseContext *context,
     parse_requires (data, element_name, names, values, error);
   else if (strcmp (element_name, "template") == 0)
     parse_template (data, element_name, names, values, error);
-  else if (data->template_object && !data->inside_requested_template)
-    {
-      /* If outside a requested template, ignore this tag */
-      return;
-    }
   else if (strcmp (element_name, "object") == 0)
     parse_object (context, data, element_name, names, values, error);
-  else if (data->requested_objects && !data->inside_requested_object)
+  else if ((data->requested_objects && !data->inside_requested_object) ||
+           (data->template_level && !data->template_object))
     {
       /* If outside a requested object, simply ignore this tag */
       return;
@@ -1109,8 +1106,29 @@ end_element (GMarkupParseContext *context,
   else if (strcmp (element_name, "interface") == 0)
     {
     }
+  else if (strcmp (element_name, "template") == 0)
+    {
+      data->template_level--;
+
+      /* Yes its a template! */
+      if (data->template_object)
+        {
+          ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
+
+          object_info->properties = g_slist_reverse (object_info->properties);
+
+          /* This is just to apply properties to the external object */
+          _gtk_builder_construct (data->builder, object_info, error);
+
+          if (object_info->signals)
+            _gtk_builder_add_signals (data->builder, object_info->signals);
+
+          free_object_info (object_info);
+          data->template_object = NULL;
+        }
+    }
   else if ((data->requested_objects && !data->inside_requested_object) ||
-           (data->template_object && !data->inside_requested_template))
+           (data->template_level && !data->template_object)) 
     {
       /* If outside a requested object or template, simply ignore this tag */
       return;
@@ -1201,27 +1219,6 @@ end_element (GMarkupParseContext *context,
   else if (strcmp (element_name, "placeholder") == 0)
     {
     }
-  else if (strcmp (element_name, "template") == 0)
-    {
-      if (data->template_object && data->inside_requested_template)
-        {
-          ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
-
-          object_info->properties = g_slist_reverse (object_info->properties);
-
-          /* This is just to apply properties to the external object */
-          _gtk_builder_construct (data->builder, object_info, error);
-
-          if (object_info->signals)
-            _gtk_builder_add_signals (data->builder, object_info->signals);
-
-          free_object_info (object_info);
-
-          data->template_object = NULL;
-
-          data->inside_requested_template = FALSE;
-        }
-    }
   else
     {
       g_assert_not_reached ();
@@ -1294,8 +1291,6 @@ static const GMarkupParser parser = {
 
 void
 _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
-                                  GObject      *parent,
-                                  const gchar  *template_id,
                                   const gchar  *filename,
                                   const gchar  *buffer,
                                   gsize         length,
@@ -1338,20 +1333,6 @@ _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
       data->inside_requested_object = TRUE;
     }
 
-  if (parent)
-    {
-      data->inside_requested_template = FALSE;
-      
-      if (template_id)
-        {
-          GTK_NOTE (BUILDER, g_print ("parsing with contextual parent %s class %s ptr %p\n",
-                                      template_id, G_OBJECT_TYPE_NAME (parent), parent));
-
-          data->template_object = parent;
-          gtk_builder_expose_object (builder, template_id, parent);
-        }
-    }
-
   data->ctx = g_markup_parse_context_new (&parser, 
                                           G_MARKUP_TREAT_CDATA_AS_TEXT, 
                                           data, NULL);
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index eb7051d..c859159 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -109,16 +109,15 @@ typedef struct {
   gint cur_object_level;
 
   GHashTable *object_ids;
+
   GObject *template_object;
-  gboolean inside_requested_template;
+  gint template_level;
 } ParserData;
 
 typedef GType (*GTypeGetFunc) (void);
 
 /* Things only GtkBuilder should use */
 void _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
-                                       GObject      *parent,
-                                       const gchar  *template_id,
                                        const gchar  *filename,
                                        const gchar  *buffer,
                                        gsize         length,
@@ -165,6 +164,8 @@ void      _gtk_builder_menu_start (ParserData   *parser_data,
                                    GError      **error);
 void      _gtk_builder_menu_end   (ParserData  *parser_data);
 
+GObject * _gtk_builder_get_external_object (GtkBuilder    *builder,
+                                            const gchar   *name);
 const gchar * _gtk_builder_object_get_name (GObject *object);
 
 #endif /* __GTK_BUILDER_PRIVATE_H__ */
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 7d581aa..7196979 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -1667,25 +1667,14 @@ gtk_container_constructor (GType                  type,
       guint ret;
         
       builder = gtk_builder_new ();
+      gtk_builder_expose_object (builder, "this", object);
 
-      switch (cpriv->tmpl_type)
-        {
-          case TMPL_STRING:
-            ret = gtk_builder_add_to_parent_from_string (builder, object,
-                                                         "this",
-                                                         cpriv->tmpl,
-                                                         -1, &error);
-          break;
-          case TMPL_RESOURCE:
-            ret = gtk_builder_add_to_parent_from_resource (builder, object,
-                                                           "this",
-                                                           cpriv->tmpl,
-                                                           &error);
-          break;
-          default:
-            ret = 0;
-          break;
-        }
+      if (cpriv->tmpl_type == TMPL_STRING)
+        ret = gtk_builder_add_from_string (builder, cpriv->tmpl, -1, &error);
+      else if (cpriv->tmpl_type == TMPL_RESOURCE)
+        ret = gtk_builder_add_from_resource (builder, cpriv->tmpl, &error);
+      else
+        ret = 0;
 
       if (ret)
         {
diff --git a/gtk/tests/builder.c b/gtk/tests/builder.c
index 5cca2cb..f87b4d6 100644
--- a/gtk/tests/builder.c
+++ b/gtk/tests/builder.c
@@ -2716,21 +2716,29 @@ test_level_bar (void)
 }
 
 static void
-test_add_to_parent (void)
+test_template_real (gboolean use_add_objects)
 {
   GError *error = NULL;
   GtkBuilder *builder;
-  GtkWidget *mybox;
+  GtkWidget *mybox, *mygrid;
   gboolean expand = FALSE, fill = FALSE;
   GtkPackType pack_type = GTK_PACK_START;
   guint padding = 0;
   const gchar buffer[] =
     "<interface>\n"
-    /* This template should get ignored */
     "  <template class=\"GtkGrid\" id=\"mygrid\">\n"
     "    <property name=\"visible\">True</property>\n"
     "    <child>\n"
-    "      <object class=\"GtkLabel\" id=\"label\">\n"
+    "      <object class=\"GtkLabel\" id=\"gridlabel\">\n"
+    "        <property name=\"visible\">True</property>\n"
+    "      </object>\n"
+    "   </child>\n"
+    "  </template>\n"
+    /* This template should get ignored */
+    "  <template class=\"GtkGrid\" id=\"mygrid2\">\n"
+    "    <property name=\"visible\">True</property>\n"
+    "    <child>\n"
+    "      <object class=\"GtkLabel\" id=\"grid2label\">\n"
     "        <property name=\"visible\">True</property>\n"
     "      </object>\n"
     "   </child>\n"
@@ -2742,7 +2750,7 @@ test_add_to_parent (void)
     "    <property name=\"orientation\">vertical</property>\n"
     "    <property name=\"spacing\">8</property>\n"
     "    <child>\n"
-    "      <object class=\"GtkLabel\" id=\"label\">\n"
+    "      <object class=\"GtkLabel\" id=\"boxlabel\">\n"
     "        <property name=\"visible\">True</property>\n"
     "        <property name=\"can_focus\">False</property>\n"
     "        <property name=\"label\" translatable=\"yes\">label</property>\n"
@@ -2769,35 +2777,98 @@ test_add_to_parent (void)
     "      </packing>\n"
     "    </child>\n"
     "  </template>\n"
+    "  <object class=\"GtkWindow\" id=\"window\">"
+    "    <child>\n"
+    "      <object class=\"GtkLabel\" id=\"winlabel\">\n"
+    "        <property name=\"visible\">True</property>\n"
+    "      </object>\n"
+    "   </child>\n"
+    "  </object>"
     "</interface>";
 
   builder = gtk_builder_new ();
   mybox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
   g_object_ref_sink (mybox);
-  gtk_builder_add_to_parent_from_string (builder, G_OBJECT (mybox), "mybox",
-                                         buffer, -1, &error);
-  if (error) g_warning ("%s", error->message);
-  g_assert (error == NULL);
 
-  /* Check template properties */
-  g_assert (gtk_box_get_spacing (GTK_BOX (mybox)) == 8);
-  g_assert (gtk_orientable_get_orientation (GTK_ORIENTABLE (mybox)) == GTK_ORIENTATION_VERTICAL);
-
-  /* Check if children are built */
-  g_assert (GTK_IS_LABEL (gtk_builder_get_object (builder, "label")));
-  g_assert (GTK_IS_BUTTON (gtk_builder_get_object (builder, "button")));
-
-  /* Check child packing properties */
-  gtk_box_query_child_packing (GTK_BOX (mybox),
-                               GTK_WIDGET (gtk_builder_get_object (builder, "label")),
-                               &expand, &fill, &padding, &pack_type);
-  g_assert (expand);
-  g_assert (fill);
-  g_assert (padding == 16);
-  g_assert (pack_type == GTK_PACK_END);
+  mygrid = gtk_grid_new ();
+  g_object_ref_sink (mygrid);
+  
+  gtk_builder_expose_object (builder, "mybox", G_OBJECT (mybox));
+
+  if (use_add_objects)
+    {
+      gchar *objs[] = {"window", NULL};
+      gtk_builder_add_objects_from_string (builder, buffer, -1, objs, &error);
+
+      if (error) g_warning ("%s", error->message);
+      
+      /* Check if requested object creation works */
+      g_assert (GTK_IS_WINDOW (gtk_builder_get_object (builder, "window")));
+
+      /* Templates should be ignored if we requested a specific object */
+      g_assert (gtk_builder_get_object (builder, "winlabel"));
+    }
+  else
+    {
+      gtk_builder_add_from_string (builder, buffer, -1, &error);
+
+      if (error) g_warning ("%s", error->message);
+      g_assert (error == NULL);
+
+      /* Check template properties */
+      g_assert (gtk_box_get_spacing (GTK_BOX (mybox)) == 8);
+      g_assert (gtk_orientable_get_orientation (GTK_ORIENTABLE (mybox)) == GTK_ORIENTATION_VERTICAL);
+
+      /* Check if children are built */
+      g_assert (GTK_IS_LABEL (gtk_builder_get_object (builder, "boxlabel")));
+      g_assert (GTK_IS_BUTTON (gtk_builder_get_object (builder, "button")));
+
+      /* Check child packing properties */
+      gtk_box_query_child_packing (GTK_BOX (mybox),
+                                   GTK_WIDGET (gtk_builder_get_object (builder, "boxlabel")),
+                                   &expand, &fill, &padding, &pack_type);
+      g_assert (expand);
+      g_assert (fill);
+      g_assert (padding == 16);
+      g_assert (pack_type == GTK_PACK_END);        
+    }
 
   g_object_unref (builder);
   g_object_unref (mybox);
+  g_object_unref (mygrid);
+}
+
+static void
+test_template (void)
+{
+  test_template_real (FALSE);
+  test_template_real (TRUE);
+}
+
+static void
+test_expose_object (void)
+{
+  GtkBuilder *builder;
+  GError *error = NULL;
+  GtkWidget *image;
+  GObject *obj;
+  const gchar buffer[] =
+    "<interface>"
+    "  <object class=\"GtkButton\" id=\"button\">"
+    "    <property name=\"image\" external-object=\"True\">external_image</property>"
+    "  </object>"
+    "</interface>";
+
+  image = gtk_image_new ();
+  builder = gtk_builder_new ();
+  gtk_builder_expose_object (builder, "external_image", G_OBJECT (image));
+  gtk_builder_add_from_string (builder, buffer, -1, &error);
+  g_assert (error == NULL);
+
+  obj = gtk_builder_get_object (builder, "button");
+  g_assert (GTK_IS_BUTTON (obj));
+
+  g_assert (gtk_button_get_image (GTK_BUTTON (obj)) == image);
 }
 
 int
@@ -2848,7 +2919,8 @@ main (int argc, char **argv)
   g_test_add_func ("/Builder/MessageDialog", test_message_dialog);
   g_test_add_func ("/Builder/GMenu", test_gmenu);
   g_test_add_func ("/Builder/LevelBar", test_level_bar);
-  g_test_add_func ("/Builder/Add to Parent", test_add_to_parent);
+  g_test_add_func ("/Builder/Template", test_template);
+  g_test_add_func ("/Builder/Expose Object", test_expose_object);
 
   return g_test_run();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]