diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2022-05-16 14:10:20 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2022-07-11 18:24:37 +0100 |
commit | 7857c1a66bd8f026d72d661751471de8f2b2e508 (patch) | |
tree | 1ad44c26ff410d220703df85afced460d0066bca /gtk/gtkwidget.c | |
parent | 636827800525770715bba96671edb2fc0234ccc2 (diff) | |
download | gtk+-7857c1a66bd8f026d72d661751471de8f2b2e508.tar.gz |
Add gtk_widget_clear_template()
The dual of gtk_widget_init_template(), which should be used to clear
the template data associated with a specific GtkWidget type.
Diffstat (limited to 'gtk/gtkwidget.c')
-rw-r--r-- | gtk/gtkwidget.c | 83 |
1 files changed, 73 insertions, 10 deletions
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 3d1a46897d..432e10301b 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -7437,16 +7437,7 @@ gtk_widget_real_destroy (GtkWidget *object) GObject *child_object = gtk_widget_get_template_child (widget, class_type, child_class->name); - - g_assert (child_object); - - if (!G_IS_OBJECT (child_object)) - { - g_critical ("Automated component '%s' of class '%s' seems to" - " have been prematurely finalized", - child_class->name, g_type_name (class_type)); - } - else + if (G_IS_OBJECT (child_object)) { FinalizeAssertion *assertion = g_slice_new0 (FinalizeAssertion); assertion->child_class = child_class; @@ -10979,6 +10970,78 @@ out: } /** + * gtk_widget_clear_template: + * @widget: the widget with a template + * @widget_type: the type of the widget to finalize the template for + * + * Clears the template data for the given widget. + * + * This function is the opposite of [method@Gtk.Widget.init_template], and + * it is used to clear all the template data from a widget instance. + * + * You should call this function inside the `GObjectClass.dispose()` + * implementation of any widget that called `gtk_widget_init_template()`. + * Typically, you will want to call this function last, right before + * chaining up to the parent type's dispose implementation, e.g. + * + * ```c + * static void + * some_widget_dispose (GObject *gobject) + * { + * SomeWidget *self = SOME_WIDGET (gobject); + * + * // Clear the template data for SomeWidget + * gtk_widget_clear_template (GTK_WIDGET (self), SOME_TYPE_WIDGET); + * + * G_OBJECT_CLASS (some_widget_parent_class)->dispose (gobject); + * } + * ``` + * + * Since: 4.8 + */ +void +gtk_widget_clear_template (GtkWidget *widget, + GType widget_type) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (g_type_name (widget_type) != NULL); + + GtkWidgetTemplate *template = GTK_WIDGET_GET_CLASS (widget)->priv->template; + g_return_if_fail (template != NULL); + + /* Tear down the automatic child data */ + GHashTable *auto_child_hash = get_auto_child_hash (widget, widget_type, FALSE); + + for (GSList *l = template->children; l != NULL; l = l->next) + { + AutomaticChildClass *child_class = l->data; + + /* This will drop the reference on the template children */ + if (auto_child_hash != NULL) + { + gpointer child = g_hash_table_lookup (auto_child_hash, child_class->name); + + g_assert (child != NULL); + + /* We have to explicitly unparent direct children of this widget */ + if (GTK_IS_WIDGET (child) && _gtk_widget_get_parent (child) == widget) + gtk_widget_unparent (child); + + g_hash_table_remove (auto_child_hash, child_class->name); + } + + /* Nullify the field last, to avoid re-entrancy issues */ + if (child_class->offset != 0) + { + gpointer field_p; + + field_p = G_STRUCT_MEMBER_P (widget, child_class->offset); + (* (gpointer *) field_p) = NULL; + } + } +} + +/** * gtk_widget_class_set_template: * @widget_class: A `GtkWidgetClass` * @template_bytes: A `GBytes` holding the `GtkBuilder` XML |