GNOME Bugzilla – Bug 778617
GtkListBox: placeholder is not removed properly
Last modified: 2017-04-26 10:25:07 UTC
Created attachment 345744 [details] Text case When the C++ wrapper of a gtk+ widget is deleted in gtkmm, g_object_run_dispose() is called, to dispose of the gtk+ object. This works well in most cases, but not for a GtkListBox with a placeholder widget. The result differs, depending on the order of deletion and it's also different in gtk+3 and gtk+4. 1. gtk+3 1.1 First dispose of the listbox: Nothing unexpected happens. Then dispose of the placeholder: Segfault 1.2 First dispose of the placeholder: Gtk-WARNING **: Tried to remove non-child 0x55e8f7dcf3f0 Then dispose of the listbox: Nothing unexpected happens. 2. gtk+4 2.1 First dispose of the listbox: Gtk-WARNING **: Finalizing GtkListBox 0x55fd39864210, but it still has children left: Gtk-WARNING **: - GtkLabel 0x55fd39710390 Then dispose of the placeholder: Segfault 2.2 First dispose of the placeholder: Gtk-WARNING **: Tried to remove non-child 0x55aa9936e390 Then dispose of the listbox: Gtk-WARNING **: Finalizing GtkListBox 0x55aa994c2240, but it still has children left: Gtk-WARNING **: - GtkLabel 0x55aa9936e390 I think a problem with the placeholder is that it does not quite fit into either of the child groups "internal" or "non-internal" (or external) children. The documentation of gtk_contatiner_foreach() says internal children are "precisely those child widgets that were added to the container by the application with explicit add() calls." A placeholder was added by the application, but not with an add() call. When the listbox is disposed of, gtk_list_box_forall() is called with include_internals == FALSE and callback == gtk_widget_destroy. The placeholder is not destroyed, as it's considered an internal child. When the placeholder (in the test case a GtkLabel) is disposed of, gtk_list_box_remove() is called. The placeholder is not removed, as it's not considered a child.
Created attachment 346912 [details] [review] patch: listbox: Remove placeholder when destroying This patch applies to the master branch. I don't know if it also applies to the gtk-3-22 branch. The patch adds gtk_list_box_destroy(), where a placeholder widget, if any, is unparented. I don't know if destroy is the best place for this code. Other container widgets with internal children unparent such children either in the destroy, dispose or finalize function. In comment 0: s/Text case/Test case/
> The patch adds gtk_list_box_destroy(), where a placeholder widget, if any, is > unparented. I don't know if destroy is the best place for this code. > Other container widgets with internal children unparent such children either > in the destroy, dispose or finalize function. You are right that internal widgets should be unparented in destroy, at least according to the GtkContainer documentation, but it doesn't seem like the placeholder is really an internal child to me. I prepared another patch for this that just changed the placeholder to a non-internal child. As far as I understand the GtkContainer documentation, it's not an internal child since it has been added by the user. But I don't know if that is usable for gtk-3-22. I'm just going to attach that patch as well.
Created attachment 350315 [details] [review] listbox: Properly remove placeholders
Yes, your patch is a good fix. I've tested it in the master branch and in the gtk-3-22 branch, also with the test case in the original gtkmm bug 778535.
Thanks, I've pushed it as https://git.gnome.org/browse/gtk+/commit/?id=5d94ee85842ed91007ebf6bdf6a1f54237987536 and added a placeholder to the widget-factory in https://git.gnome.org/browse/gtk+/commit/?id=4945e28f08a759bbd5f6b3b217b5815882d31ed6. In gtk-3-22 as https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-22&id=b7fdc5b447b44b5b7638a3ac41cac58136bc5ca2