Skip to content

Commit 3f24428

Browse files
committed
Stop touching menu widgets that GTK already destroyed
A GtkMenu owns its items, so ~Menu() destroying the menu widget took every item widget with it; the MenuItem destructors then disconnected signal handlers on freed memory, which GLib reported as "invalid unclassed pointer in cast to 'GObject'" — eleven criticals when the window example shut down. Hold the widget pointers through g_object_add_weak_pointer() so GTK clears them on destruction and the existing null checks skip the cleanup. This works whichever side goes first, unlike fixing the destruction order.
1 parent d9ba959 commit 3f24428

1 file changed

Lines changed: 28 additions & 3 deletions

File tree

‎src/platform/linux/menu_linux.cpp‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,19 @@ class MenuItem::Impl {
9090
radio_group_(-1),
9191
accelerator_("", ModifierKey::None),
9292
activate_handler_id_(0),
93-
toggled_handler_id_(0) {}
93+
toggled_handler_id_(0) {
94+
// The parent GtkMenu owns the item and may destroy it before this object is
95+
// destroyed; let GTK clear the pointer instead of leaving it dangling.
96+
if (gtk_menu_item_) {
97+
g_object_add_weak_pointer(G_OBJECT(gtk_menu_item_), (gpointer*)&gtk_menu_item_);
98+
}
99+
}
100+
101+
~Impl() {
102+
if (gtk_menu_item_) {
103+
g_object_remove_weak_pointer(G_OBJECT(gtk_menu_item_), (gpointer*)&gtk_menu_item_);
104+
}
105+
}
94106

95107
void ApplyRadioGroup() {
96108
if (!gtk_menu_item_ || type_ != MenuItemType::Radio || radio_group_ < 0) {
@@ -227,7 +239,8 @@ MenuItem::~MenuItem() {
227239
}
228240

229241
// Note: We don't destroy the gtk_menu_item_ here because it's owned by the parent Menu
230-
// and will be destroyed when the Menu container is destroyed
242+
// and will be destroyed when the Menu container is destroyed. When that already
243+
// happened, the weak pointer left gtk_menu_item_ null and this block is skipped.
231244
}
232245
}
233246

@@ -464,7 +477,19 @@ void* MenuItem::GetNativeObjectInternal() const {
464477
class Menu::Impl {
465478
public:
466479
Impl(MenuId id, GtkWidget* menu)
467-
: id_(id), gtk_menu_(menu), map_handler_id_(0), unmap_handler_id_(0) {}
480+
: id_(id), gtk_menu_(menu), map_handler_id_(0), unmap_handler_id_(0) {
481+
// A submenu is owned by the item it hangs off, so it too can be destroyed
482+
// from underneath this object.
483+
if (gtk_menu_) {
484+
g_object_add_weak_pointer(G_OBJECT(gtk_menu_), (gpointer*)&gtk_menu_);
485+
}
486+
}
487+
488+
~Impl() {
489+
if (gtk_menu_) {
490+
g_object_remove_weak_pointer(G_OBJECT(gtk_menu_), (gpointer*)&gtk_menu_);
491+
}
492+
}
468493

469494
MenuId id_;
470495
GtkWidget* gtk_menu_;

0 commit comments

Comments
 (0)