diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2021-11-27 18:40:11 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2021-11-27 18:40:11 +0000 |
commit | 041495c710a6a59e254b79c3e72f93de611acf0a (patch) | |
tree | 9a51e709b06b956bd8cd5473f7c8187fbd167776 | |
parent | c742debea8d7f2c93f06a5b506851698291cb2da (diff) | |
download | gtk+-ebassi/template-fini.tar.gz |
Add a counterpart to gtk_widget_init_template()ebassi/template-fini
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.
-rw-r--r-- | gtk/gtkwidget.c | 61 | ||||
-rw-r--r-- | gtk/gtkwidget.h | 2 |
2 files changed, 63 insertions, 0 deletions
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 092f763bdc..29105a6141 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -10939,6 +10939,67 @@ get_auto_child_hash (GtkWidget *widget, } /** + * 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, |