diff options
| author | Eric Williams | 2018-03-20 21:04:02 +0000 |
|---|---|---|
| committer | Eric Williams | 2018-03-22 15:40:33 +0000 |
| commit | 47598b7e6318e7cfae9c33fcf18610194b1c4741 (patch) | |
| tree | 7069c96e3221bf903a2abe476b3db5529bc98034 | |
| parent | baaa06d650c0cab6e9b17c558562bdffed23a299 (diff) | |
| download | eclipse.platform.swt-47598b7e6318e7cfae9c33fcf18610194b1c4741.tar.gz eclipse.platform.swt-47598b7e6318e7cfae9c33fcf18610194b1c4741.tar.xz eclipse.platform.swt-47598b7e6318e7cfae9c33fcf18610194b1c4741.zip | |
Bug 530204: [GTK] Menu appears at mouse regardless of setLocation()I20180322-2000
This patch contains two main parts.
Part 1 - functionality implementation:
This implements functionality for Menu.setLocation() to actually work as
intended. Currently menus are popped up wherever the mouse pointer is,
completely ignoring any coordinates given to setLocation(). The
functionality provided by this patch only works on X11, as Wayland has
no global coordinate system (this has been documented in the javadocs in
an earlier patch).
Part 2 - debugging support:
Menu positioning issues are very hard to pin down, since they cannot be
inspected with GtkInspector. Thankfully, GTK3.22+ has API support to
remedy this. It's now possible to connect a GtkMenu to the "popped-up"
signal. After a GtkMenu is popped up/shown, a callback is triggered. The
parameters to the callback function contain information about the menu's
position/size, straight from GTK's internal machinery. This patch adds
an environment variable, SWT_MENU_LOCATION_DEBUGGING, which (when set)
will enable SWT to make use of GTK's "popped-up" signal. The callback
function in SWT will print certain information about the menu as
provided from GTK. For more information on the "popped-up" signal, see:
https://developer.gnome.org/gtk3/stable/GtkMenu.html#GtkMenu-popped-up
Tested on Wayland and X11 with GTK3.22. GTK3.20- behaviour is unchanged,
as it still uses the older GtkMenu API. No AllNonBrowser JUnit tests
fail. IDE testing shows that menus now behave the same as on Win32 or
Cocoa (best way to test this: give focus to the "Show In" button in the
Open Resource Dialog, and trigger a button press with the keyboard while
having the mouse elsewhere -> menu should open up by the button, not the
mouse).
Change-Id: Ia221734a774d6a18afc4ef879ff883ded7ed81ae
Signed-off-by: Eric Williams <ericwill@redhat.com>
9 files changed, 238 insertions, 21 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c index 74456e0be1..cb6b841575 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c @@ -940,6 +940,18 @@ JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1display_1get_1default) } #endif +#ifndef NO__1gdk_1display_1get_1default_1group +JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1display_1get_1default_1group) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jintLong rc = 0; + GDK_NATIVE_ENTER(env, that, _1gdk_1display_1get_1default_1group_FUNC); + rc = (jintLong)gdk_display_get_default_group((GdkDisplay *)arg0); + GDK_NATIVE_EXIT(env, that, _1gdk_1display_1get_1default_1group_FUNC); + return rc; +} +#endif + #ifndef NO__1gdk_1display_1get_1default_1seat JNIEXPORT jintLong JNICALL GDK_NATIVE(_1gdk_1display_1get_1default_1seat) (JNIEnv *env, jclass that, jintLong arg0) @@ -8267,6 +8279,28 @@ JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1menu_1popup_1at_1pointer) } #endif +#ifndef NO__1gtk_1menu_1popup_1at_1rect +JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1menu_1popup_1at_1rect) + (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jobject arg2, jint arg3, jint arg4, jintLong arg5) +{ + GdkRectangle _arg2, *lparg2=NULL; + GTK_NATIVE_ENTER(env, that, _1gtk_1menu_1popup_1at_1rect_FUNC); + if (arg2) if ((lparg2 = getGdkRectangleFields(env, arg2, &_arg2)) == NULL) goto fail; +/* + gtk_menu_popup_at_rect(arg0, arg1, lparg2, arg3, arg4, arg5); +*/ + { + GTK_LOAD_FUNCTION(fp, gtk_menu_popup_at_rect) + if (fp) { + ((void (CALLING_CONVENTION*)(jintLong, jintLong, GdkRectangle *, jint, jint, jintLong))fp)(arg0, arg1, lparg2, arg3, arg4, arg5); + } + } +fail: + if (arg2 && lparg2) setGdkRectangleFields(env, arg2, lparg2); + GTK_NATIVE_EXIT(env, that, _1gtk_1menu_1popup_1at_1rect_FUNC); +} +#endif + #ifndef NO__1gtk_1menu_1shell_1deactivate JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1menu_1shell_1deactivate) (JNIEnv *env, jclass that, jintLong arg0) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c index 4307c3ffc3..ebfe993ec3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c @@ -78,6 +78,7 @@ char * GDK_nativeFunctionNames[] = { "_1gdk_1device_1warp", "_1gdk_1display_1beep", "_1gdk_1display_1get_1default", + "_1gdk_1display_1get_1default_1group", "_1gdk_1display_1get_1default_1seat", "_1gdk_1display_1get_1device_1manager", "_1gdk_1display_1supports_1cursor_1color", @@ -638,6 +639,7 @@ char * GTK_nativeFunctionNames[] = { "_1gtk_1menu_1popdown", "_1gtk_1menu_1popup", "_1gtk_1menu_1popup_1at_1pointer", + "_1gtk_1menu_1popup_1at_1rect", "_1gtk_1menu_1shell_1deactivate", "_1gtk_1menu_1shell_1insert", "_1gtk_1menu_1shell_1set_1take_1focus", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h index acb4dbf71f..f707a39a38 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h @@ -88,6 +88,7 @@ typedef enum { _1gdk_1device_1warp_FUNC, _1gdk_1display_1beep_FUNC, _1gdk_1display_1get_1default_FUNC, + _1gdk_1display_1get_1default_1group_FUNC, _1gdk_1display_1get_1default_1seat_FUNC, _1gdk_1display_1get_1device_1manager_FUNC, _1gdk_1display_1supports_1cursor_1color_FUNC, @@ -636,6 +637,7 @@ typedef enum { _1gtk_1menu_1popdown_FUNC, _1gtk_1menu_1popup_FUNC, _1gtk_1menu_1popup_1at_1pointer_FUNC, + _1gtk_1menu_1popup_1at_1rect_FUNC, _1gtk_1menu_1shell_1deactivate_FUNC, _1gtk_1menu_1shell_1insert_FUNC, _1gtk_1menu_1shell_1set_1take_1focus_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java index 3ca963de47..6de79fb2c3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java @@ -107,6 +107,16 @@ public class GDK extends OS { public static final int GDK_FUNC_MAXIMIZE = 16; public static final int GDK_FUNC_CLOSE = 32; public static final int GDK_GRAB_SUCCESS = 0x0; + public static final int GDK_GRAVITY_NORTH_WEST = 1; + public static final int GDK_GRAVITY_NORTH = 2; + public static final int GDK_GRAVITY_NORTH_EAST = 3; + public static final int GDK_GRAVITY_WEST = 4; + public static final int GDK_GRAVITY_CENTER = 5; + public static final int GDK_GRAVITY_EAST = 6; + public static final int GDK_GRAVITY_SOUTH_WEST = 7; + public static final int GDK_GRAVITY_SOUTH = 8; + public static final int GDK_GRAVITY_SOUTH_EAST = 9; + public static final int GDK_GRAVITY_STATIC = 10; public static final int GDK_HAND2 = 0x3c; public static final int GDK_Help = 0xFF6A; public static final int GDK_HINT_MIN_SIZE = 1 << 1; @@ -785,6 +795,18 @@ public class GDK extends OS { } } /** + * @param display cast=(GdkDisplay *) + */ + public static final native long /*int*/ _gdk_display_get_default_group(long /*int*/ display); + public static final long /*int*/ gdk_display_get_default_group(long /*int*/ display) { + lock.lock(); + try { + return _gdk_display_get_default_group(display); + } finally { + lock.unlock(); + } + } + /** * @method flags=dynamic */ public static final native long /*int*/ _gdk_display_get_default_seat(long /*int*/ display); diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java index cab6ca3e34..cc80140623 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java @@ -4137,6 +4137,18 @@ public class GTK extends OS { lock.unlock(); } } + /** + * @method flags=dynamic + */ + public static final native void _gtk_menu_popup_at_rect(long /*int*/ menu, long /*int*/ rect_window, GdkRectangle rect, int rect_anchor, int menu_anchor, long /*int*/ trigger_event); + public static void gtk_menu_popup_at_rect(long /*int*/ menu, long /*int*/ rect_window, GdkRectangle rect, int rect_anchor, int menu_anchor, long /*int*/ trigger_event) { + lock.lock(); + try { + _gtk_menu_popup_at_rect(menu, rect_window, rect, rect_anchor, menu_anchor, trigger_event); + } finally { + lock.unlock(); + } + } /** @param menu_shell cast=(GtkMenuShell *) */ public static final native void _gtk_menu_shell_deactivate(long /*int*/ menu_shell); public static final void gtk_menu_shell_deactivate(long /*int*/ menu_shell) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java index dcb4daf37d..5857e0f4f8 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java @@ -319,6 +319,7 @@ public class OS extends C { public static final byte[] move_focus = ascii("move-focus"); public static final byte[] output = ascii("output"); public static final byte[] paste_clipboard = ascii("paste-clipboard"); + public static final byte[] popped_up = ascii("popped-up"); public static final byte[] popup_menu = ascii("popup-menu"); public static final byte[] populate_popup = ascii("populate-popup"); public static final byte[] preedit_changed = ascii("preedit-changed"); @@ -683,6 +684,16 @@ public class OS extends C { public static final int GLIB_VERSION = VERSION(glib_major_version(), glib_minor_version(), glib_micro_version()); private static final boolean MIN_GLIB_2_32 = OS.GLIB_VERSION >= VERSION(2, 32, 0); + /* + * New API in GTK3.22 introduced the "popped-up" signal, which provides + * information about where a menu was actually positioned after it's been + * popped up. Users can set the environment variable SWT_MENU_LOCATION_DEBUGGING + * to 1 in order to help them debug menu positioning issues on GTK3.22+. + * + * For more information see bug 530204. + */ + public static final boolean SWT_MENU_LOCATION_DEBUGGING; + /* Feature in Gtk: with the switch to GtkMenuItems from GtkImageMenuItems * in Gtk3 came a small Gtk shortfall: a small amount of padding on the left hand * side of MenuItems was added. This padding is not accessible to the developer, @@ -704,6 +715,14 @@ public class OS extends C { } SWT_PADDED_MENU_ITEMS = usePadded; + String menuLocationProperty = "SWT_MENU_LOCATION_DEBUGGING"; + String menuLocationCheck = getEnvironmentalVariable(menuLocationProperty); + boolean menuLocationDebuggingEnabled = false; + if (menuLocationCheck != null && menuLocationCheck.equals("1")) { + menuLocationDebuggingEnabled = true; + } + SWT_MENU_LOCATION_DEBUGGING = menuLocationDebuggingEnabled; + System.setProperty("org.eclipse.swt.internal.gtk.version", (GTK.GTK_VERSION >>> 16) + "." + (GTK.GTK_VERSION >>> 8 & 0xFF) + "." + (GTK.GTK_VERSION & 0xFF)); // set GDK backend if we are on X11 diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java index fac4f1d62a..d17b7e5579 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java @@ -116,8 +116,8 @@ public class Display extends Device { boolean wake; int [] max_priority = new int [1], timeout = new int [1]; Callback eventCallback, filterCallback; - long /*int*/ eventProc, filterProc, windowProc2, windowProc3, windowProc4, windowProc5; - Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5; + long /*int*/ eventProc, filterProc, windowProc2, windowProc3, windowProc4, windowProc5, windowProc6; + Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5, windowCallback6; EventTable eventTable, filterTable; static String APP_NAME = "SWT"; //$NON-NLS-1$ static String APP_VERSION = ""; //$NON-NLS-1$ @@ -3627,6 +3627,17 @@ void initializeCallbacks () { signalIds [Widget.MAP_EVENT] = OS.g_signal_lookup (OS.map_event, GTK.GTK_TYPE_WIDGET ()); signalIds [Widget.MNEMONIC_ACTIVATE] = OS.g_signal_lookup (OS.mnemonic_activate, GTK.GTK_TYPE_WIDGET ()); signalIds [Widget.MOTION_NOTIFY_EVENT] = OS.g_signal_lookup (OS.motion_notify_event, GTK.GTK_TYPE_WIDGET ()); + /* + * Connect to the "popped-up" signal on GTK3.22+ if the user has specified the + * SWT_MENU_LOCATION_DEBUGGING environment variable. + */ + if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0) && OS.SWT_MENU_LOCATION_DEBUGGING) { + long /*int*/ menuType = GTK.GTK_TYPE_MENU (); + OS.g_type_class_ref (menuType); + signalIds [Widget.POPPED_UP] = OS.g_signal_lookup (OS.popped_up, menuType); + } else { + signalIds [Widget.POPPED_UP] = 0; + } signalIds [Widget.POPUP_MENU] = OS.g_signal_lookup (OS.popup_menu, GTK.GTK_TYPE_WIDGET ()); signalIds [Widget.REALIZE] = OS.g_signal_lookup (OS.realize, GTK.GTK_TYPE_WIDGET ()); signalIds [Widget.SCROLL_EVENT] = OS.g_signal_lookup (OS.scroll_event, GTK.GTK_TYPE_WIDGET ()); @@ -3742,6 +3753,13 @@ void initializeCallbacks () { closuresProc [Widget.MOVE_CURSOR] = windowProc5; closuresProc [Widget.MOVE_CURSOR_INVERSE] = windowProc5; + if (signalIds [Widget.POPPED_UP] != 0) { + windowCallback6 = new Callback (this, "windowProc", 6); //$NON-NLS-1$ + windowProc6 = windowCallback6.getAddress (); + if (windowProc6 == 0) error (SWT.ERROR_NO_MORE_CALLBACKS); + closuresProc [Widget.POPPED_UP] = windowProc6; + } + for (int i = 0; i < Widget.LAST_SIGNAL; i++) { if (closuresProc[i] != 0) { closures [i] = OS.g_cclosure_new(closuresProc [i], i, 0); @@ -4562,7 +4580,10 @@ void releaseDisplay () { windowCallback3.dispose (); windowCallback3 = null; windowCallback4.dispose (); windowCallback4 = null; windowCallback5.dispose (); windowCallback5 = null; - windowProc2 = windowProc3 = windowProc4 = windowProc5 = 0; + if (windowCallback6 != null) { + windowCallback6.dispose (); windowCallback6 = null; + } + windowProc2 = windowProc3 = windowProc4 = windowProc5 = windowProc6 = 0; /* Dispose xfilter callback */ if (filterProc != 0) { @@ -5878,6 +5899,12 @@ long /*int*/ windowProc (long /*int*/ handle, long /*int*/ arg0, long /*int*/ ar return widget.windowProc (handle, arg0, arg1, arg2, user_data); } +long /*int*/ windowProc (long /*int*/ handle, long /*int*/ arg0, long /*int*/ arg1, long /*int*/ arg2, long /*int*/ arg3, long /*int*/ user_data) { + Widget widget = getWidget (handle); + if (widget == null) return 0; + return widget.windowProc (handle, arg0, arg1, arg2, arg3, user_data); +} + long /*int*/ windowTimerProc (long /*int*/ handle) { Widget widget = getWidget (handle); if (widget == null) return 0; 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 16f8525952..5105b51ada 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 @@ -40,6 +40,10 @@ import org.eclipse.swt.internal.gtk.*; */ public class Menu extends Widget { int x, y; + /** + * Only set to true on X11, as Wayland has no global + * coordinates. See bug 530204. + */ boolean hasLocation; MenuItem cascade, selectedItem; Decorations parent; @@ -232,28 +236,61 @@ void _setVisible (boolean visible) { GTK.gtk_menu_popup (handle, 0, 0, address, data, 0, display.getLastEventTime ()); } else { - /* - * GTK Feature: gtk_menu_popup is deprecated as of GTK3.22 and the new method gtk_menu_popup_at_pointer - * requires an event to hook on to. This requires the popup & events related to the menu be handled - * immediately and not as a post event in display, requiring the current event. - */ - long /*int*/ eventPtr = GTK.gtk_get_current_event(); - if (eventPtr == 0) { + long /*int*/ eventPtr = 0; + if (hasLocation) { + // Create the GdkEvent manually as we need to control + // certain fields like the event window eventPtr = GDK.gdk_event_new(GDK.GDK_BUTTON_PRESS); GdkEventButton event = new GdkEventButton (); event.type = GDK.GDK_BUTTON_PRESS; - // Only assign a window on X11, as on Wayland the window is that of the mouse pointer - if (OS.isX11()) { - event.window = OS.g_object_ref(GTK.gtk_widget_get_window (getShell().handle)); - } event.device = GDK.gdk_get_pointer(GDK.gdk_display_get_default ()); + // Get and (add reference to) the global GdkWindow + event.window = GDK.gdk_display_get_default_group(GDK.gdk_display_get_default()); + OS.g_object_ref(event.window); + /* + * Get the origin of the global GdkWindow to calculate the size of any offsets + * such as client side decorations, or the system tray. + */ + int [] globalWindowOriginY = new int [1]; + int [] globalWindowOriginX = new int [1]; + GDK.gdk_window_get_origin (event.window, globalWindowOriginX, globalWindowOriginY); + // Set the time and save the event in memory event.time = display.getLastEventTime (); OS.memmove (eventPtr, event, GdkEventButton.sizeof); + + // Create the rectangle relative to the parent (in this case, global) GdkWindow + GdkRectangle rect = new GdkRectangle(); + rect.x = this.x - globalWindowOriginX[0]; + rect.y = this.y - globalWindowOriginY[0]; + + // Popup the menu and pin it at the top left corner of the GdkRectangle relative to the global GdkWindow + GTK.gtk_menu_popup_at_rect(handle, event.window, rect, GDK.GDK_GRAVITY_NORTH_WEST, + GDK.GDK_GRAVITY_NORTH_WEST, eventPtr); + GDK.gdk_event_free (eventPtr); + } else { + /* + * GTK Feature: gtk_menu_popup is deprecated as of GTK3.22 and the new method gtk_menu_popup_at_pointer + * requires an event to hook on to. This requires the popup & events related to the menu be handled + * immediately and not as a post event in display, requiring the current event. + */ + eventPtr = GTK.gtk_get_current_event(); + if (eventPtr == 0) { + eventPtr = GDK.gdk_event_new(GDK.GDK_BUTTON_PRESS); + GdkEventButton event = new GdkEventButton (); + event.type = GDK.GDK_BUTTON_PRESS; + // Only assign a window on X11, as on Wayland the window is that of the mouse pointer + if (OS.isX11()) { + event.window = OS.g_object_ref(GTK.gtk_widget_get_window (getShell().handle)); + } + event.device = GDK.gdk_get_pointer(GDK.gdk_display_get_default ()); + event.time = display.getLastEventTime (); + OS.memmove (eventPtr, event, GdkEventButton.sizeof); + } + adjustParentWindowWayland(eventPtr); + verifyMenuPosition(getItemCount()); + GTK.gtk_menu_popup_at_pointer (handle, eventPtr); + GDK.gdk_event_free (eventPtr); } - adjustParentWindow(eventPtr); - verifyMenuPosition(getItemCount()); - GTK.gtk_menu_popup_at_pointer (handle, eventPtr); - GDK.gdk_event_free (eventPtr); } poppedUpCount = getItemCount(); } else { @@ -761,10 +798,40 @@ long /*int*/ gtk_show_help (long /*int*/ widget, long /*int*/ helpType) { } @Override +long /*int*/ gtk_menu_popped_up (long /*int*/ widget, long /*int*/ flipped_rect, long /*int*/ final_rect, long /*int*/ flipped_x, long /*int*/ flipped_y) { + GdkRectangle finalRect = new GdkRectangle (); + OS.memmove (finalRect, final_rect, GDK.GdkRectangle_sizeof()); + GdkRectangle flippedRect = new GdkRectangle (); + OS.memmove (flippedRect, flipped_rect, GDK.GdkRectangle_sizeof()); + boolean flippedX = flipped_x == 1; + boolean flippedY = flipped_y == 1; + System.out.println("SWT_MENU_LOCATION_DEBUGGING enabled, printing positioning info for " + widget); + if (!OS.isX11()) System.out.println("Note: SWT is running on Wayland, coordinates will be parent-relative"); + if (hasLocation) { + System.out.println("hasLocation is true and set coordinates are Point {" + this.x + ", " + this.y + "}"); + } else { + System.out.println("hasLocation is not set, this is most likely a right click menu"); + } + if (flippedX) System.out.println("Menu is inverted along the X-axis"); + if (flippedY) System.out.println("Menu is inverted along the Y-axis"); + System.out.println("Final menu position and size is Rectangle {" + finalRect.x + ", " + finalRect.y + ", " + + finalRect.width + ", " + finalRect.height + "}"); + System.out.println("Flipped menu position and size is Rectangle {" + flippedRect.x + ", " + flippedRect.y + ", " + + flippedRect.width + ", " + flippedRect.height + "}"); + System.out.println(""); + return 0; +} + + +@Override void hookEvents () { super.hookEvents (); OS.g_signal_connect_closure_by_id (handle, display.signalIds [SHOW], 0, display.getClosure (SHOW), false); OS.g_signal_connect_closure_by_id (handle, display.signalIds [HIDE], 0, display.getClosure (HIDE), false); + // Hook into the "popped-up" signal on GTK3.22+ if SWT_MENU_LOCATION_DEBUGGING has been set + if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0) && OS.SWT_MENU_LOCATION_DEBUGGING) { + OS.g_signal_connect_closure_by_id (handle, display.signalIds [POPPED_UP], 0, display.getClosure (POPPED_UP), false); + } OS.g_signal_connect_closure_by_id (handle, display.signalIds [SHOW_HELP], 0, display.getClosure (SHOW_HELP), false); } @@ -1023,7 +1090,10 @@ void setLocationInPixels (int x, int y) { if ((style & (SWT.BAR | SWT.DROP_DOWN)) != 0) return; this.x = x; this.y = y; - hasLocation = true; + // Only set the hasLocation flag on X11. + if (OS.isX11()) { + hasLocation = true; + } } /** @@ -1108,7 +1178,7 @@ void setOrientation (boolean create) { * * @param eventPtr a pointer to the GdkEvent */ -void adjustParentWindow (long /*int*/ eventPtr) { +void adjustParentWindowWayland (long /*int*/ eventPtr) { if (!OS.isX11()) { long /*int*/ display = GDK.gdk_display_get_default (); long /*int*/ pointer = GDK.gdk_get_pointer(display); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java index 2ef3f70b45..119edb85bc 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java @@ -212,7 +212,8 @@ public abstract class Widget { static final int DIRECTION_CHANGED = 82; static final int CREATE_MENU_PROXY = 83; static final int ROW_HAS_CHILD_TOGGLED = 84; - static final int LAST_SIGNAL = 85; + static final int POPPED_UP = 85; + static final int LAST_SIGNAL = 86; static final String IS_ACTIVE = "org.eclipse.swt.internal.control.isactive"; //$NON-NLS-1$ static final String KEY_CHECK_SUBWINDOW = "org.eclipse.swt.internal.control.checksubwindow"; //$NON-NLS-1$ @@ -801,6 +802,27 @@ long /*int*/ gtk_map_event (long /*int*/ widget, long /*int*/ event) { return 0; } +/** + * <p>GTK3.22+ has API which allows clients of GTK to connect a menu to the "popped-up" signal. + * This callback is triggered after the menu is popped up/shown to the user, and provides + * information about the actual position and size of the menu, as shown to the user.</p> + * + * <p>SWT clients can enable this functionality by launching their application with the + * SWT_MENU_LOCATION_DEBUGGING environment variable set to 1. If enabled, the previously mentioned + * positioning and size information will be printed to the console. The information comes from GTK + * internals and is stored in the method parameters.</p> + * + * @param widget the memory address of the menu which was popped up + * @param flipped_rect a pointer to the GdkRectangle containing the flipped location and size of the menu + * @param final_rect a pointer to the GdkRectangle containing the final (after all internal adjustments) + * location and size of the menu + * @param flipped_x a boolean flag indicating whether the menu has been inverted along the X-axis + * @param flipped_y a boolean flag indicating whether the menu has been inverted along the Y-axis + */ +long /*int*/ gtk_menu_popped_up (long /*int*/ widget, long /*int*/ flipped_rect, long /*int*/ final_rect, long /*int*/ flipped_x, long /*int*/ flipped_y) { + return 0; +} + long /*int*/ gtk_mnemonic_activate (long /*int*/ widget, long /*int*/ arg1) { return 0; } @@ -2009,6 +2031,13 @@ long /*int*/ windowProc (long /*int*/ handle, long /*int*/ arg0, long /*int*/ ar } } +long /*int*/ windowProc (long /*int*/ handle, long /*int*/ arg0, long /*int*/ arg1, long /*int*/ arg2, long /*int*/ arg3, long /*int*/ user_data) { + switch ((int)/*64*/user_data) { + case POPPED_UP: return gtk_menu_popped_up (handle, arg0, arg1, arg2, arg3); + default: return 0; + } +} + void gdk_cursor_unref (long /*int*/ cursor) { if (GTK.GTK3) { OS.g_object_unref (cursor); |
