builder: Allow template parsing to be used with subclasses

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.
This commit is contained in:
Benjamin Otte 2023-03-31 13:01:47 +02:00
parent 170d49f067
commit beba8be6b5
3 changed files with 38 additions and 8 deletions

View 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;
}

View 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);

View 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,