[gtk/ebassi/template-fini] Add a counterpart to gtk_widget_init_template()
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/ebassi/template-fini] Add a counterpart to gtk_widget_init_template()
- Date: Sat, 27 Nov 2021 18:42:45 +0000 (UTC)
commit 041495c710a6a59e254b79c3e72f93de611acf0a
Author: Emmanuele Bassi <ebassi gnome org>
Date: Sat Nov 27 18:40:11 2021 +0000
Add a counterpart to gtk_widget_init_template()
Children added through a template still need to be unparented when the
widget is disposed. Instead of doing so manually, we should have a dual
of the gtk_widget_init_template() functions that clears all the bound
objects, and calls `gtk_widget_unparent()` on the direct children of the
widget.
gtk/gtkwidget.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gtk/gtkwidget.h | 2 ++
2 files changed, 63 insertions(+)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 092f763bdc..29105a6141 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -10938,6 +10938,67 @@ get_auto_child_hash (GtkWidget *widget,
return auto_child_hash;
}
+/**
+ * gtk_widget_clear_template:
+ * @widget: the widget whose template has to be cleared
+ *
+ * Clears and finalizes child widgets defined in templates.
+ *
+ * This function must be called in the `dispose()` implementation
+ * of the widget class which assigned itself a template using
+ * [method@Gtk.WidgetClass.set_template], and called
+ * [method@Gtk.Widget.init_template] in its instance initialization
+ * function.
+ *
+ * Since: 4.6
+ */
+void
+gtk_widget_clear_template (GtkWidget *widget)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ GtkWidgetTemplate *template = GTK_WIDGET_GET_CLASS (widget)->priv->template;
+ g_return_if_fail (template != NULL);
+
+ GType class_type = G_OBJECT_TYPE (widget);
+
+ /* Build the automatic child data */
+ for (GSList *l = template->children; l; l = l->next)
+ {
+ AutomaticChildClass *child_class = l->data;
+
+ GHashTable *auto_child_hash = get_auto_child_hash (widget, class_type, FALSE);
+ if (auto_child_hash == NULL)
+ continue;
+
+ GObject *child = g_hash_table_lookup (auto_child_hash, child_class->name);
+ if (G_UNLIKELY (child == NULL))
+ {
+ g_critical ("Unable to retrieve child object '%s' from class "
+ "template for type '%s' while clearing a '%s'",
+ child_class->name, g_type_name (class_type), G_OBJECT_TYPE_NAME (widget));
+ break;
+ }
+
+ if (child_class->offset != 0)
+ {
+ gpointer field_p;
+
+ /* Nullify the field in the instance/private data */
+ field_p = G_STRUCT_MEMBER_P (widget, child_class->offset);
+ (* (gpointer *) field_p) = NULL;
+ }
+
+ /* Unparent direct children of the widget; objects inside the
+ * auto_child_hash get an additional reference upon insertion
+ */
+ if (GTK_IS_WIDGET (child) && _gtk_widget_get_parent (GTK_WIDGET (child)) == widget)
+ gtk_widget_unparent (GTK_WIDGET (child));
+
+ g_hash_table_remove (auto_child_hash, child_class->name);
+ }
+}
+
/**
* gtk_widget_init_template:
* @widget: a `GtkWidget`
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 0788fcdd81..9072b7016d 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -851,6 +851,8 @@ void gtk_widget_class_bind_template_child_full (GtkWidgetClass *
const char *name,
gboolean internal_child,
gssize struct_offset);
+GDK_AVAILABLE_IN_4_6
+void gtk_widget_clear_template (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_widget_insert_action_group (GtkWidget *widget,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]