builder: Allow template parsing to be used with subclasses
authorBenjamin Otte <otte@redhat.com>
Fri, 31 Mar 2023 11:01:47 +0000 (13:01 +0200)
committerBenjamin Otte <otte@redhat.com>
Sat, 1 Apr 2023 18:49:40 +0000 (20:49 +0200)
Whenn setting gtk_builder_set_allow_template_parents(), the builder
instance will accept
  <template class="GtkWidget">
for a GtkBox instance.

It's going to be used with the new GtkColumnViewCell objects, so that
it's backwards compatible with ui file factories that use GtkListItem.

gtk/gtkbuilder.c
gtk/gtkbuilderparser.c
gtk/gtkbuilderprivate.h

index fd221f79c8d06985e19712d00bf7ba248a13d696..8171cb8bf91bd496ed8e15ea01b3bc9635905754 100644 (file)
@@ -264,6 +264,7 @@ typedef struct
   char *filename;
   char *resource_prefix;
   GType template_type;
+  gboolean allow_template_parents;
   GObject *current_object;
   GtkBuilderScope *scope;
 } GtkBuilderPrivate;
@@ -1334,6 +1335,15 @@ gtk_builder_add_objects_from_file (GtkBuilder   *builder,
   return TRUE;
 }
 
+void
+gtk_builder_set_allow_template_parents (GtkBuilder *builder,
+                                        gboolean    allow_parents)
+{
+  GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
+
+  priv->allow_template_parents = allow_parents;
+}
+
 /**
  * gtk_builder_extend_with_template:
  * @builder: a `GtkBuilder`
@@ -1385,6 +1395,18 @@ gtk_builder_extend_with_template (GtkBuilder   *builder,
   name = g_type_name (template_type);
   if (gtk_builder_get_object (builder, name) != object)
     gtk_builder_expose_object (builder, name, object);
+  if (priv->allow_template_parents)
+    {
+      GType subtype;
+      for (subtype = g_type_parent (template_type);
+           subtype != G_TYPE_OBJECT;
+           subtype = g_type_parent (subtype))
+        {
+          name = g_type_name (subtype);
+          if (gtk_builder_get_object (builder, name) != object)
+            gtk_builder_expose_object (builder, name, object);
+        }
+    }
 
   filename = g_strconcat ("<", name, " template>", NULL);
   _gtk_builder_parser_parse_buffer (builder, filename,
@@ -2815,10 +2837,13 @@ _gtk_builder_get_absolute_filename (GtkBuilder  *builder,
 }
 
 GType
-_gtk_builder_get_template_type (GtkBuilder *builder)
+gtk_builder_get_template_type (GtkBuilder *builder,
+                               gboolean   *out_allow_parents)
 {
   GtkBuilderPrivate *priv = gtk_builder_get_instance_private (builder);
 
+  *out_allow_parents = priv->allow_template_parents;
+
   return priv->template_type;
 }
 
index a1a7bd68c023db94a4e0a7215bbe4b960ff52624..d4f1f66f5e2877c854165953638c55254e86b7b0 100644 (file)
@@ -697,11 +697,11 @@ parse_template (GtkBuildableParseContext  *context,
   const char *parent_class = NULL;
   int line;
   gpointer line_ptr;
-  gboolean has_duplicate;
+  gboolean has_duplicate, allow_parents;
   GType template_type;
   GType parsed_type;
 
-  template_type = _gtk_builder_get_template_type (data->builder);
+  template_type = gtk_builder_get_template_type (data->builder, &allow_parents);
 
   if (!g_markup_collect_attributes (element_name, names, values, error,
                                     G_MARKUP_COLLECT_STRING, "class", &object_class,
@@ -729,7 +729,8 @@ parse_template (GtkBuildableParseContext  *context,
     }
 
   parsed_type = g_type_from_name (object_class);
-  if (template_type != parsed_type)
+  if (template_type != parsed_type &&
+      (!allow_parents || !g_type_is_a (template_type, parsed_type)))
     {
       g_set_error (error,
                    GTK_BUILDER_ERROR,
@@ -768,10 +769,11 @@ parse_template (GtkBuildableParseContext  *context,
 
   object_info = g_new0 (ObjectInfo, 1);
   object_info->tag_type = TAG_TEMPLATE;
-  object_info->type = parsed_type;
-  object_info->oclass = g_type_class_ref (parsed_type);
-  object_info->id = g_strdup (object_class);
   object_info->object = gtk_builder_get_object (data->builder, object_class);
+  object_info->type = template_type;
+  object_info->oclass = g_type_class_ref (template_type);
+  object_info->id = g_strdup (object_class);
+  g_assert (object_info->object);
   state_push (data, object_info);
 
   has_duplicate = g_hash_table_lookup_extended (data->object_ids, object_class, NULL, &line_ptr);
index 7e717eaf2ac158fb3e3739d8234e85167d0c4632..218e33628a36f4d08d6f98a4ae4c2ec644e76ca6 100644 (file)
@@ -264,7 +264,10 @@ void      _gtk_builder_menu_start (ParserData   *parser_data,
                                    GError      **error);
 void      _gtk_builder_menu_end   (ParserData  *parser_data);
 
-GType     _gtk_builder_get_template_type (GtkBuilder *builder);
+GType     gtk_builder_get_template_type (GtkBuilder *builder,
+                                         gboolean *out_allow_parents);
+void      gtk_builder_set_allow_template_parents (GtkBuilder *builder,
+                                                  gboolean    allow_parents);
 
 void     _gtk_builder_prefix_error        (GtkBuilder                *builder,
                                            GtkBuildableParseContext  *context,