Skip to content

Commit f734dc6

Browse files
ptzieglerakurtakov
authored andcommitted
[GTK4] Cleanup GtkEventControllerMotion Enter/Leave events
Support for mouse motion events was already implemented with b70cd16. However, following edge cases were missed: - Moving the cursor out of the shell and back in doesn't fire a "mouse enter" event. Similarly to the way motion events are handled in GTK3, the current control needs to be cleared on a "leave" event. Otherwise the "enter" event is suppressed when the cursor is moved out of and back in a shell again. - Moving from one widget to another fires two "mouse exit" events. One event is fired by "gtk4_motion_event()", the other by "leaveProc()". Only the former should be fired, as it contains the proper "x" and "y" coordinates. Latter is fired because "getCursorControl()" always returns "null". This has been fixed by first calculating the GtkWindow from the GdkSurface and then selecting the widget at the mouse coordinates. The whole implementation has also been restructured so that the X11-based heuristic via the XQueryPointer is only used for GTK3 (because it would simply return early for GTK4 anyway). - The tooltip window isn't moved when hovering over different widgets This is because the tooltip is set for the shell, even though it should be set for the individual widgets. As a result, only the text is updated but the window remains where it was initially shown. Closes #219
1 parent 81f9bd1 commit f734dc6

File tree

5 files changed

+79
-35
lines changed

5 files changed

+79
-35
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,18 @@ JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1named_1action_1new)
16141614
}
16151615
#endif
16161616

1617+
#ifndef NO_gtk_1native_1get_1for_1surface
1618+
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1native_1get_1for_1surface)
1619+
(JNIEnv *env, jclass that, jlong arg0)
1620+
{
1621+
jlong rc = 0;
1622+
GTK4_NATIVE_ENTER(env, that, gtk_1native_1get_1for_1surface_FUNC);
1623+
rc = (jlong)gtk_native_get_for_surface((GdkSurface *)arg0);
1624+
GTK4_NATIVE_EXIT(env, that, gtk_1native_1get_1for_1surface_FUNC);
1625+
return rc;
1626+
}
1627+
#endif
1628+
16171629
#ifndef NO_gtk_1native_1get_1surface
16181630
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1native_1get_1surface)
16191631
(JNIEnv *env, jclass that, jlong arg0)
@@ -2178,6 +2190,18 @@ JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1measure)
21782190
}
21792191
#endif
21802192

2193+
#ifndef NO_gtk_1widget_1pick
2194+
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1widget_1pick)
2195+
(JNIEnv *env, jclass that, jlong arg0, jdouble arg1, jdouble arg2, jint arg3)
2196+
{
2197+
jlong rc = 0;
2198+
GTK4_NATIVE_ENTER(env, that, gtk_1widget_1pick_FUNC);
2199+
rc = (jlong)gtk_widget_pick((GtkWidget *)arg0, (double)arg1, (double)arg2, (GtkPickFlags)arg3);
2200+
GTK4_NATIVE_EXIT(env, that, gtk_1widget_1pick_FUNC);
2201+
return rc;
2202+
}
2203+
#endif
2204+
21812205
#ifndef NO_gtk_1widget_1set_1cursor
21822206
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1set_1cursor)
21832207
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ typedef enum {
135135
gtk_1label_1set_1wrap_1mode_FUNC,
136136
gtk_1menu_1button_1set_1use_1underline_FUNC,
137137
gtk_1named_1action_1new_FUNC,
138+
gtk_1native_1get_1for_1surface_FUNC,
138139
gtk_1native_1get_1surface_FUNC,
139140
gtk_1picture_1new_FUNC,
140141
gtk_1picture_1set_1can_1shrink_FUNC,
@@ -180,6 +181,7 @@ typedef enum {
180181
gtk_1widget_1insert_1after_FUNC,
181182
gtk_1widget_1insert_1before_FUNC,
182183
gtk_1widget_1measure_FUNC,
184+
gtk_1widget_1pick_FUNC,
183185
gtk_1widget_1set_1cursor_FUNC,
184186
gtk_1widget_1set_1focusable_FUNC,
185187
gtk_1widget_1size_1allocate_FUNC,

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public class GTK4 {
2626
public static final int GTK_EVENT_SEQUENCE_CLAIMED = 1;
2727
public static final int GTK_EVENT_SEQUENCE_DENIED = 2;
2828

29+
public static final int GTK_PICK_DEFAULT = 0;
30+
public static final int GTK_PICK_INSENSITIVE = 1;
31+
public static final int GTK_PICK_NON_TARGETABLE = 2;
32+
2933
/**
3034
* @param context cast=(GtkIMContext *)
3135
* @param event cast=(GdkEvent *)
@@ -130,6 +134,10 @@ public class GTK4 {
130134
/* GTK Initialization */
131135
public static final native boolean gtk_init_check();
132136

137+
/* GtkNative */
138+
/** @param surface cast=(GdkSurface *) */
139+
public static final native long gtk_native_get_for_surface(long surface);
140+
133141
/* GdkToplevel */
134142
/** @param toplevel cast=(GdkToplevel *) */
135143
public static final native int gdk_toplevel_get_state(long toplevel);
@@ -667,6 +675,13 @@ public class GTK4 {
667675
* @param next_sibling cast=(GtkWidget *)
668676
*/
669677
public static final native void gtk_widget_insert_before(long widget, long parent, long next_sibling);
678+
/**
679+
* @param widget cast=(GtkWidget *)
680+
* @param x cast=(double)
681+
* @param y cast=(double)
682+
* @param flags cast=(GtkPickFlags)
683+
*/
684+
public static final native long gtk_widget_pick(long widget, double x, double y, int flags);
670685

671686
/* GtkComboBox */
672687
/** @param combo_box cast=(GtkComboBox *) */

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3622,7 +3622,7 @@ void gtk4_enter_event(long controller, double x, double y, long event) {
36223622
char [] chars = fixMnemonic (toolTipText, false, true);
36233623
buffer = Converter.wcsToMbcs (chars, true);
36243624
}
3625-
long toolHandle = getShell().handle;
3625+
long toolHandle = handle;
36263626
GTK.gtk_widget_set_tooltip_text (toolHandle, buffer);
36273627

36283628
if (display.currentControl == this) return;
@@ -4044,6 +4044,7 @@ void gtk4_leave_event(long controller, long event) {
40444044

40454045
if (sendLeaveNotify() || display.getCursorControl() == null) {
40464046
sendMouseEvent(SWT.MouseExit, 0, 0, 0, 0, false, 0);
4047+
display.currentControl = null;
40474048
}
40484049
}
40494050

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

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,46 +1900,48 @@ public Control getCursorControl () {
19001900
gdkResource = gdk_device_get_surface_at_position (xDouble, yDouble);
19011901
x[0] = (int) xDouble[0];
19021902
y[0] = (int) yDouble[0];
1903+
if (gdkResource != 0) {
1904+
long gtkWindow = GTK4.gtk_native_get_for_surface(gdkResource);
1905+
if (gtkWindow != 0) {
1906+
handle = GTK4.gtk_widget_pick(gtkWindow, xDouble[0], yDouble[0], GTK4.GTK_PICK_DEFAULT);
1907+
}
1908+
}
19031909
} else {
19041910
gdkResource = gdk_device_get_window_at_position (x,y);
1905-
}
1906-
if (gdkResource != 0) {
1907-
if (GTK.GTK4) {
1908-
// TODO: GTK4 need to retrieve handle
1909-
} else {
1911+
if (gdkResource != 0) {
19101912
GDK.gdk_window_get_user_data (gdkResource, user_data);
1911-
}
1912-
handle = user_data [0];
1913-
} else {
1914-
// Feature in GTK. The gdk_device_get_[surface/window]_at_position() functions will not return a
1915-
// surface/window if the pointer is over a foreign embedded window. The fix is to use XQueryPointer
1916-
// to find the containing GDK window (see bug 177368.)
1917-
// However embedding foreign windows is not supported by the Wayland backend for GTK3 and is not
1918-
// supported at all on GTK4, so skip the heuristic in these situations.
1919-
if (OS.isWayland() || GTK.GTK4) return null;
1920-
long gdkDisplay = GDK.gdk_display_get_default();
1921-
if (OS.isX11()) {
1922-
GDK.gdk_x11_display_error_trap_push(gdkDisplay);
1923-
}
1924-
int[] unusedInt = new int[1];
1925-
long [] unusedPtr = new long [1], buffer = new long [1];
1926-
long xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
1927-
do {
1928-
if (OS.XQueryPointer (xDisplay, xParent, unusedPtr, buffer, unusedInt, unusedInt, unusedInt, unusedInt, unusedInt) == 0) {
1929-
handle = 0;
1930-
break;
1913+
handle = user_data [0];
1914+
} else {
1915+
// Feature in GTK. The gdk_device_get_[surface/window]_at_position() functions will not return a
1916+
// surface/window if the pointer is over a foreign embedded window. The fix is to use XQueryPointer
1917+
// to find the containing GDK window (see bug 177368.)
1918+
// However embedding foreign windows is not supported by the Wayland backend for GTK3 and is not
1919+
// supported at all on GTK4, so skip the heuristic in these situations.
1920+
if (OS.isWayland() || GTK.GTK4) return null;
1921+
long gdkDisplay = GDK.gdk_display_get_default();
1922+
if (OS.isX11()) {
1923+
GDK.gdk_x11_display_error_trap_push(gdkDisplay);
19311924
}
1932-
if ((xWindow = buffer [0]) != 0) {
1933-
xParent = xWindow;
1934-
long gdkWindow = GDK.gdk_x11_window_lookup_for_display(gdkDisplay, xWindow);
1935-
if (gdkWindow != 0) {
1936-
GDK.gdk_window_get_user_data (gdkWindow, user_data);
1937-
if (user_data[0] != 0) handle = user_data[0];
1925+
int[] unusedInt = new int[1];
1926+
long [] unusedPtr = new long [1], buffer = new long [1];
1927+
long xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
1928+
do {
1929+
if (OS.XQueryPointer (xDisplay, xParent, unusedPtr, buffer, unusedInt, unusedInt, unusedInt, unusedInt, unusedInt) == 0) {
1930+
handle = 0;
1931+
break;
1932+
}
1933+
if ((xWindow = buffer [0]) != 0) {
1934+
xParent = xWindow;
1935+
long gdkWindow = GDK.gdk_x11_window_lookup_for_display(gdkDisplay, xWindow);
1936+
if (gdkWindow != 0) {
1937+
GDK.gdk_window_get_user_data (gdkWindow, user_data);
1938+
if (user_data[0] != 0) handle = user_data[0];
1939+
}
19381940
}
1941+
} while (xWindow != 0);
1942+
if (OS.isX11()) {
1943+
GDK.gdk_x11_display_error_trap_pop_ignored(gdkDisplay);
19391944
}
1940-
} while (xWindow != 0);
1941-
if (OS.isX11()) {
1942-
GDK.gdk_x11_display_error_trap_pop_ignored(gdkDisplay);
19431945
}
19441946
}
19451947
if (handle == 0) return null;

0 commit comments

Comments
 (0)