Compare commits

...

4 Commits

Author SHA1 Message Date
Matthias Clasen
1c55ab2634 testsuite: Enable the remaining template tests
These are no longer failing.
2020-05-11 08:19:22 -04:00
Matthias Clasen
cc2f017007 widget: work around teardown ordering issues
Many widgets do things on unmap; with us propagating
disposal more eagerly, we now end up in a situation where
widgets are already half-disposed when we reach the
widget dispose() implementation which unmaps, unroots
and unparents the widget. Work around this problem by
unmapping first thing in gtk_widget_destroy() - that
ensures that the widget is still intact when unmap()
is run.

This was causing crashes in several widgets such as
GtkStack, GtkFontChooserWidget or GtkScrolledWindow.
2020-05-11 08:19:22 -04:00
Matthias Clasen
8dfa7870ca Clean up bin disposal
When all the GtkBin subclasses were converted to widgets with
their own dispose(), we made them call gtk_widget_unparent()
on their child. Unfortunately, this is not sufficient to break
reference cycles. We need to call gtk_widget_destroy() on
them to make sure that the dispose is propagated.

The main offender here is the treeview, which keeps a bunch
of row references which are holding references to itself.

This was showing up as leaks when running anything using a file
chooser or print dialog with GTK_WIDGET_ASSERT_COMPONENTS=1.
2020-05-11 08:19:22 -04:00
Matthias Clasen
26d2cd70fa widget: Improve automatic component tracking
Print out when components get finalized 'too late', e.g.
in an idle after dispose. This happens sometimes, and
it is useful to differentiate this situation from an
actual, permanent leak.

One example where this shows up is the property action
in examples/exampleapplication9, which keeps a label
alive until the actions are unexported on the bus,
in an idle.
2020-05-11 08:19:22 -04:00
16 changed files with 45 additions and 32 deletions

View File

@@ -187,7 +187,7 @@ gtk_aspect_frame_dispose (GObject *object)
{
GtkAspectFrame *self = GTK_ASPECT_FRAME (object);
g_clear_pointer (&self->child, gtk_widget_unparent);
g_clear_pointer (&self->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_aspect_frame_parent_class)->dispose (object);
}

View File

@@ -450,7 +450,7 @@ gtk_button_dispose (GObject *object)
GtkButton *button = GTK_BUTTON (object);
GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_destroy);
g_clear_object (&priv->action_helper);
G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);

View File

@@ -2402,7 +2402,7 @@ gtk_combo_box_dispose (GObject* object)
/* destroy things (unparent will kill the latest ref from us)
* last unref on button will destroy the arrow
*/
gtk_widget_unparent (priv->box);
gtk_widget_destroy (priv->box);
priv->box = NULL;
priv->button = NULL;
priv->arrow = NULL;

View File

@@ -3101,7 +3101,7 @@ gtk_file_chooser_widget_dispose (GObject *object)
impl->external_entry = NULL;
}
g_clear_pointer (&impl->box, gtk_widget_unparent);
g_clear_pointer (&impl->box, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_file_chooser_widget_parent_class)->dispose (object);
}

View File

@@ -424,7 +424,7 @@ gtk_flow_box_child_dispose (GObject *object)
GtkFlowBoxChild *self = GTK_FLOW_BOX_CHILD (object);
GtkFlowBoxChildPrivate *priv = CHILD_PRIV (self);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_flow_box_child_parent_class)->dispose (object);
}

View File

@@ -240,8 +240,8 @@ gtk_frame_dispose (GObject *object)
GtkFrame *frame = GTK_FRAME (object);
GtkFramePrivate *priv = gtk_frame_get_instance_private (frame);
g_clear_pointer (&priv->label_widget, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->label_widget, gtk_widget_destroy);
g_clear_pointer (&priv->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_frame_parent_class)->dispose (object);
}

View File

@@ -3376,7 +3376,7 @@ gtk_list_box_row_dispose (GObject *object)
GtkListBoxRowPrivate *priv = ROW_PRIV (row);
g_clear_object (&priv->action_helper);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_list_box_row_parent_class)->dispose (object);
}

View File

@@ -270,10 +270,10 @@ gtk_overlay_dispose (GObject *object)
GtkOverlay *overlay = GTK_OVERLAY (object);
GtkWidget *child;
g_clear_pointer (&overlay->child, gtk_widget_unparent);
g_clear_pointer (&overlay->child, gtk_widget_destroy);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (overlay))))
gtk_widget_unparent (child);
gtk_widget_destroy (child);
G_OBJECT_CLASS (gtk_overlay_parent_class)->dispose (object);
}

View File

@@ -1025,7 +1025,7 @@ gtk_popover_dispose (GObject *object)
GtkPopover *popover = GTK_POPOVER (object);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
g_clear_pointer (&priv->contents_widget, gtk_widget_unparent);
g_clear_pointer (&priv->contents_widget, gtk_widget_destroy);
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
G_OBJECT_CLASS (gtk_popover_parent_class)->dispose (object);

View File

@@ -175,7 +175,7 @@ gtk_revealer_dispose (GObject *obj)
GtkRevealer *revealer = GTK_REVEALER (obj);
GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_revealer_parent_class)->dispose (obj);
}

View File

@@ -2617,7 +2617,7 @@ gtk_scrolled_window_dispose (GObject *object)
GtkScrolledWindow *self = GTK_SCROLLED_WINDOW (object);
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (self);
g_clear_pointer (&priv->child, gtk_widget_unparent);
g_clear_pointer (&priv->child, gtk_widget_destroy);
remove_indicator (self, &priv->hindicator);
remove_indicator (self, &priv->vindicator);

View File

@@ -248,7 +248,7 @@ gtk_search_bar_dispose (GObject *object)
gtk_search_bar_set_key_capture_widget (bar, NULL);
gtk_search_bar_set_entry (bar, NULL);
g_clear_pointer (&bar->revealer, gtk_widget_unparent);
g_clear_pointer (&bar->revealer, gtk_widget_destroy);
bar->child = NULL;
bar->box_center = NULL;

View File

@@ -319,7 +319,7 @@ gtk_viewport_dispose (GObject *object)
clear_focus_change_handler (viewport);
g_clear_pointer (&viewport->child, gtk_widget_unparent);
g_clear_pointer (&viewport->child, gtk_widget_destroy);
G_OBJECT_CLASS (gtk_viewport_parent_class)->dispose (object);

View File

@@ -2631,6 +2631,8 @@ gtk_widget_destroy (GtkWidget *widget)
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_unmap (widget);
if (!priv->in_destruction)
g_object_run_dispose (G_OBJECT (widget));
}
@@ -7220,6 +7222,7 @@ typedef struct {
GType widget_type;
GObject *object;
gboolean did_finalize;
gboolean too_late;
} FinalizeAssertion;
static void
@@ -7228,7 +7231,15 @@ finalize_assertion_weak_ref (gpointer data,
{
FinalizeAssertion *assertion = (FinalizeAssertion *)data;
assertion->did_finalize = TRUE;
if (assertion->too_late)
{
g_critical ("Automated component '%s' of class '%s' finalized after gtk_widget_destroy().\n",
assertion->child_class->name,
g_type_name (assertion->widget_type));
g_slice_free (FinalizeAssertion, assertion);
}
}
#endif /* G_ENABLE_CONSISTENCY_CHECKS */
static void
@@ -7304,18 +7315,21 @@ gtk_widget_real_destroy (GtkWidget *object)
#ifdef G_ENABLE_CONSISTENCY_CHECKS
for (l = assertions; l; l = l->next)
{
FinalizeAssertion *assertion = l->data;
{
FinalizeAssertion *assertion = l->data;
if (!assertion->did_finalize)
g_critical ("Automated component '%s' of class '%s' did not finalize in gtk_widget_destroy(). "
"Current reference count is %d",
assertion->child_class->name,
g_type_name (assertion->widget_type),
assertion->object->ref_count);
g_slice_free (FinalizeAssertion, assertion);
}
if (!assertion->did_finalize)
{
g_critical ("Automated component '%s' of class '%s' did not finalize in gtk_widget_destroy(). "
"Current reference count is %d",
assertion->child_class->name,
g_type_name (assertion->widget_type),
assertion->object->ref_count);
assertion->too_late = TRUE;
}
else
g_slice_free (FinalizeAssertion, assertion);
}
g_slist_free (assertions);
#endif /* G_ENABLE_CONSISTENCY_CHECKS */

View File

@@ -2404,8 +2404,9 @@ gtk_window_dispose (GObject *object)
gtk_window_set_focus (window, NULL);
gtk_window_set_default_widget (window, NULL);
g_clear_pointer (&priv->child, gtk_widget_unparent);
unset_titlebar (window);
g_clear_pointer (&priv->child, gtk_widget_destroy);
g_clear_pointer (&priv->title_box, gtk_widget_destroy);
priv->titlebar = NULL;
G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
}

View File

@@ -468,8 +468,7 @@ main (int argc, char **argv)
g_test_add_func ("/template/GtkColorChooserDialog/show", test_color_chooser_dialog_show);
g_test_add_func ("/template/GtkFileChooserWidget/basic", test_file_chooser_widget_basic);
g_test_add_func ("/template/GtkFileChooserDialog/basic", test_file_chooser_dialog_basic);
if (0)
g_test_add_func ("/template/GtkFileChooserDialog/show", test_file_chooser_dialog_show);
g_test_add_func ("/template/GtkFileChooserDialog/show", test_file_chooser_dialog_show);
g_test_add_func ("/template/GtkFileChooserButton/basic", test_file_chooser_button_basic);
g_test_add_func ("/template/GtkFontButton/basic", test_font_button_basic);
g_test_add_func ("/template/GtkFontChooserWidget/basic", test_font_chooser_widget_basic);
@@ -480,8 +479,7 @@ main (int argc, char **argv)
g_test_add_func ("/template/GtkPageSetupUnixDialog/basic", test_page_setup_unix_dialog_basic);
g_test_add_func ("/template/GtkPageSetupUnixDialog/show", test_page_setup_unix_dialog_show);
g_test_add_func ("/template/GtkPrintUnixDialog/basic", test_print_unix_dialog_basic);
if (0)
g_test_add_func ("/template/GtkPrintUnixDialog/show", test_print_unix_dialog_show);
g_test_add_func ("/template/GtkPrintUnixDialog/show", test_print_unix_dialog_show);
#endif
return g_test_run();