From ef0af4a3cd5af13d65de622e3206492bc63b3b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=8A?= =?UTF-8?q?=D1=80=20=D0=9A=D1=83=D1=80=D1=82=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Fri, 11 Sep 2026 23:38:21 +0300 Subject: [PATCH] [GTK4] Wire menubar drop-downs by menu model, not position Menu.connectDropDownMenuSignals paired the bar's child widgets with the item list positionally. It also runs from the model's "items-changed", i.e. in the middle of an item being created or disposed, when the two are out of step; a positional walk then wired a menu to its neighbour's popover, leaking the Menu and leaving submenus without their SWT.Show. Locate each drop-down's popover by its menu model with findNestedPopoverForModel instead, and drop the now unused findGtkPopoverMenuChild. Assisted-by: Anthropic Claude Code (claude-fable-5-1) --- .../gtk/org/eclipse/swt/widgets/Menu.java | 41 ++++++------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java index 19467e4b2d3..583151ff368 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java @@ -1026,22 +1026,21 @@ private void wireSubMenuPopover(Menu submenu, long popover) { private void connectDropDownMenuSignals() { if (items == null) return; - long barItem = GTK4.gtk_widget_get_first_child(handle); - for (MenuItem menuItem : items) { - if (barItem == 0) break; - if ((menuItem.style & SWT.SEPARATOR) != 0) continue; - if (menuItem.menu != null) { - long popover = findGtkPopoverMenuChild(barItem); - /* Re-wire when the discovered popover differs from the cache (initial or GTK rebuilt it). */ - if (popover != 0 && menuItem.menu.popoverHandle != popover) { - wireSubMenuPopover(menuItem.menu, popover); - } - if (menuItem.menu.popoverHandle != 0) { - connectCascadeSubMenuSignals(menuItem.menu); - } + if (menuItem.menu == null) continue; + /* + * Locate the popover by its menu model, not positionally: this also runs + * from "items-changed" mid create/dispose, when the item list and the + * bar's children are out of step and a positional walk wires the wrong menu. + */ + long popover = findNestedPopoverForModel(handle, menuItem.menu.modelHandle); + /* Re-wire when the discovered popover differs from the cache (initial or GTK rebuilt it). */ + if (popover != 0 && menuItem.menu.popoverHandle != popover) { + wireSubMenuPopover(menuItem.menu, popover); + } + if (menuItem.menu.popoverHandle != 0) { + connectCascadeSubMenuSignals(menuItem.menu); } - barItem = GTK4.gtk_widget_get_next_sibling(barItem); } } @@ -1093,18 +1092,6 @@ private long findNestedPopoverForModel(long parentWidget, long targetModel) { return 0; } - -private long findGtkPopoverMenuChild(long barItem) { - long child = GTK4.gtk_widget_get_first_child(barItem); - while (child != 0) { - if (GTK4.GTK_IS_POPOVER_MENU(child)) { - return child; - } - child = GTK4.gtk_widget_get_next_sibling(child); - } - return 0; -} - @Override long gtk_hide (long widget) { if ((style & SWT.POP_UP) != 0) { @@ -1149,7 +1136,6 @@ long gtk_show (long widget) { return 0; } - @Override long gtk3_show_help (long widget, long helpType) { if (sendHelpEvent (helpType)) { @@ -1184,7 +1170,6 @@ long gtk_menu_popped_up (long widget, long flipped_rect, long final_rect, long f return 0; } - @Override void hookEvents() { super.hookEvents();