Skip to content

Commit 5f5ff9e

Browse files
committed
[Gtk4] Support MenuListener adding sub menues
Map SHOW/HIDE signals for all menues. Dynamically recreate the menu model on each such signal to allow MenuListeners to add/remove MenuItems.
1 parent 469fa0e commit 5f5ff9e

File tree

4 files changed

+87
-8
lines changed

4 files changed

+87
-8
lines changed

bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,18 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1popover_1menu_1bar_1new_1from_1model)
22002200
}
22012201
#endif
22022202

2203+
#ifndef NO_gtk_1popover_1menu_1get_1menu_1model
2204+
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1popover_1menu_1get_1menu_1model)
2205+
(JNIEnv *env, jclass that, jlong arg0)
2206+
{
2207+
jlong rc = 0;
2208+
GTK4_NATIVE_ENTER(env, that, gtk_1popover_1menu_1get_1menu_1model_FUNC);
2209+
rc = (jlong)gtk_popover_menu_get_menu_model((GtkPopoverMenu *)arg0);
2210+
GTK4_NATIVE_EXIT(env, that, gtk_1popover_1menu_1get_1menu_1model_FUNC);
2211+
return rc;
2212+
}
2213+
#endif
2214+
22032215
#ifndef NO_gtk_1popover_1menu_1new_1from_1model_1full
22042216
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1popover_1menu_1new_1from_1model_1full)
22052217
(JNIEnv *env, jclass that, jlong arg0, jint arg1)

bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ typedef enum {
180180
gtk_1picture_1set_1can_1shrink_FUNC,
181181
gtk_1picture_1set_1paintable_FUNC,
182182
gtk_1popover_1menu_1bar_1new_1from_1model_FUNC,
183+
gtk_1popover_1menu_1get_1menu_1model_FUNC,
183184
gtk_1popover_1menu_1new_1from_1model_1full_FUNC,
184185
gtk_1popover_1menu_1set_1menu_1model_FUNC,
185186
gtk_1popover_1set_1has_1arrow_FUNC,

bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,11 @@ public class GTK4 {
549549
* @param flags cast=(GtkPopoverMenuFlags)
550550
*/
551551
public static final native long gtk_popover_menu_new_from_model_full(long model, int flags);
552+
/**
553+
* @param popover cast=(GtkPopoverMenu *)
554+
* @return cast=(GMenuModel *)
555+
*/
556+
public static final native long gtk_popover_menu_get_menu_model(long popover);
552557
/**
553558
* @param popover cast=(GtkPopoverMenu *)
554559
* @param model cast=(GMenuModel *)

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Menu.java

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -824,13 +824,22 @@ public boolean getVisible () {
824824

825825
@Override
826826
long gtk_map (long widget) {
827-
if (GTK.GTK4 && (style & SWT.BAR) != 0) {
828-
/*
829-
* The GtkPopoverMenuBar has been mapped, which means its internal
830-
* GtkPopoverMenuBarItem children now exist. Find the GtkPopoverMenu child for each,
831-
* and connect SHOW/HIDE signals so that SWT MenuListeners on DROP_DOWN are notified.
832-
*/
833-
connectDropDownMenuSignals();
827+
if (GTK.GTK4) {
828+
if ((style & SWT.BAR) != 0) {
829+
/*
830+
* The GtkPopoverMenuBar has been mapped, which means its internal
831+
* GtkPopoverMenuBarItem children now exist. Find the GtkPopoverMenu child for each,
832+
* and connect SHOW/HIDE signals so that SWT MenuListeners on DROP_DOWN are notified.
833+
*/
834+
connectDropDownMenuSignals();
835+
} else if ((style & SWT.POP_UP) != 0) {
836+
/*
837+
* The POP_UP GtkPopoverMenu has been mapped. Its handle IS the GtkPopoverMenu,
838+
* and nested GtkPopoverMenu children for any CASCADE submenus already exist in
839+
* its widget tree. Connect SHOW/HIDE signals for those nested submenus now.
840+
*/
841+
connectCascadeSubMenuSignals(this, handle);
842+
}
834843
}
835844
return super.gtk_map(widget);
836845
}
@@ -845,16 +854,67 @@ private void connectDropDownMenuSignals() {
845854
if (menuItem.menu != null && menuItem.menu.popoverHandle == 0) {
846855
long popover = findGtkPopoverMenuChild(barItem);
847856
if (popover != 0) {
857+
OS.g_object_ref(popover);
848858
menuItem.menu.popoverHandle = popover;
849859
display.addWidget(popover, menuItem.menu);
850860
OS.g_signal_connect_closure_by_id(popover, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
851861
OS.g_signal_connect_closure_by_id(popover, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
862+
/*
863+
* Also connect SHOW/HIDE signals for nested CASCADE submenus.
864+
*/
865+
connectCascadeSubMenuSignals(menuItem.menu);
852866
}
853867
}
854868
barItem = GTK4.gtk_widget_get_next_sibling(barItem);
855869
}
856870
}
857871

872+
private void connectCascadeSubMenuSignals(Menu menu) {
873+
connectCascadeSubMenuSignals(menu, menu.popoverHandle);
874+
}
875+
876+
private void connectCascadeSubMenuSignals(Menu menu, long parentPopoverHandle) {
877+
if (menu == null || parentPopoverHandle == 0 || menu.items == null) return;
878+
for (MenuItem item : menu.items) {
879+
if ((item.style & SWT.CASCADE) != 0 && item.menu != null) {
880+
/*
881+
* item.menu is the CASCADE submenu (always SWT.DROP_DOWN style).
882+
* Its popoverHandle is 0 until we find and register its GtkPopoverMenu.
883+
* Skip if already connected (popoverHandle != 0).
884+
*/
885+
if (item.menu.popoverHandle != 0) continue;
886+
long nestedPopover = findNestedPopoverForModel(parentPopoverHandle, item.menu.modelHandle);
887+
if (nestedPopover != 0) {
888+
OS.g_object_ref(nestedPopover);
889+
item.menu.popoverHandle = nestedPopover;
890+
display.addWidget(nestedPopover, item.menu);
891+
OS.g_signal_connect_closure_by_id(nestedPopover, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
892+
OS.g_signal_connect_closure_by_id(nestedPopover, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
893+
// Recurse to handle further nested CASCADE submenus
894+
connectCascadeSubMenuSignals(item.menu);
895+
}
896+
}
897+
}
898+
}
899+
900+
private long findNestedPopoverForModel(long parentWidget, long targetModel) {
901+
if (parentWidget == 0 || targetModel == 0) return 0;
902+
long child = GTK4.gtk_widget_get_first_child(parentWidget);
903+
while (child != 0) {
904+
if (GTK4.GTK_IS_POPOVER_MENU(child)) {
905+
long model = GTK4.gtk_popover_menu_get_menu_model(child);
906+
if (model == targetModel) {
907+
return child;
908+
}
909+
}
910+
long found = findNestedPopoverForModel(child, targetModel);
911+
if (found != 0) return found;
912+
child = GTK4.gtk_widget_get_next_sibling(child);
913+
}
914+
return 0;
915+
}
916+
917+
858918
private long findGtkPopoverMenuChild(long barItem) {
859919
long child = GTK4.gtk_widget_get_first_child(barItem);
860920
while (child != 0) {
@@ -955,7 +1015,7 @@ void hookEvents() {
9551015
if ((style & SWT.DROP_DOWN) == 0) {
9561016
OS.g_signal_connect_closure_by_id(handle, display.signalIds[SHOW], 0, display.getClosure(SHOW), false);
9571017
OS.g_signal_connect_closure_by_id(handle, display.signalIds[HIDE], 0, display.getClosure(HIDE), false);
958-
if ((style & SWT.BAR) != 0) {
1018+
if ((style & (SWT.BAR | SWT.POP_UP)) != 0) {
9591019
/*
9601020
* Connect MAP signal on the GtkPopoverMenuBar so that once it is
9611021
* realized and its internal GtkPopoverMenuBarItem children exist,
@@ -1102,6 +1162,7 @@ void deregister() {
11021162
super.deregister();
11031163
if (GTK.GTK4 && (style & SWT.DROP_DOWN) != 0 && popoverHandle != 0) {
11041164
display.removeWidget(popoverHandle);
1165+
OS.g_object_unref(popoverHandle);
11051166
popoverHandle = 0;
11061167
}
11071168
}

0 commit comments

Comments
 (0)