Bug 541650: [GTK4] GdkEvents are private and can no longer be created

Handle GdkEventCrossing cases.

Change-Id: I4ec60d2dcc7e84575b09b65e010d660b6dcd795e
Signed-off-by: Eric Williams <ericwill@redhat.com>
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 cbaa2a9..3a9e943 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
@@ -997,6 +997,22 @@
 }
 #endif
 
+#ifndef NO__1gdk_1event_1get_1crossing_1mode
+JNIEXPORT jboolean JNICALL GDK_NATIVE(_1gdk_1event_1get_1crossing_1mode)
+	(JNIEnv *env, jclass that, jintLong arg0, jintArray arg1)
+{
+	jint *lparg1=NULL;
+	jboolean rc = 0;
+	GDK_NATIVE_ENTER(env, that, _1gdk_1event_1get_1crossing_1mode_FUNC);
+	if (arg1) if ((lparg1 = (*env)->GetIntArrayElements(env, arg1, NULL)) == NULL) goto fail;
+	rc = (jboolean)gdk_event_get_crossing_mode((GdkEvent *)arg0, (GdkCrossingMode *)lparg1);
+fail:
+	if (arg1 && lparg1) (*env)->ReleaseIntArrayElements(env, arg1, lparg1, 0);
+	GDK_NATIVE_EXIT(env, that, _1gdk_1event_1get_1crossing_1mode_FUNC);
+	return rc;
+}
+#endif
+
 #ifndef NO__1gdk_1event_1get_1event_1type
 JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1event_1get_1event_1type)
 	(JNIEnv *env, jclass that, jintLong arg0)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
index d1f09f7..542b9a0 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.h
@@ -446,6 +446,7 @@
 #define NO__1gdk_1event_1get_1focus_1in
 #define NO__1gdk_1event_1get_1string
 #define NO__1gdk_1event_1get_1key_1group
+#define NO__1gdk_1event_1get_1crossing_1mode
 #endif
 
 #include "os_custom.h"
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 4b5964e..9bcbfa3 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
@@ -104,6 +104,7 @@
 	"_1gdk_1event_1get",
 	"_1gdk_1event_1get_1button",
 	"_1gdk_1event_1get_1coords",
+	"_1gdk_1event_1get_1crossing_1mode",
 	"_1gdk_1event_1get_1event_1type",
 	"_1gdk_1event_1get_1focus_1in",
 	"_1gdk_1event_1get_1key_1group",
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 7ad9719..dba5be2 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
@@ -114,6 +114,7 @@
 	_1gdk_1event_1get_FUNC,
 	_1gdk_1event_1get_1button_FUNC,
 	_1gdk_1event_1get_1coords_FUNC,
+	_1gdk_1event_1get_1crossing_1mode_FUNC,
 	_1gdk_1event_1get_1event_1type_FUNC,
 	_1gdk_1event_1get_1focus_1in_FUNC,
 	_1gdk_1event_1get_1key_1group_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 3e69853..5eba0c0 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
@@ -985,6 +985,20 @@
 	}
 	/**
 	 * @param event cast=(GdkEvent *)
+	 * @param mode cast=(GdkCrossingMode *)
+	 */
+	public static final native boolean _gdk_event_get_crossing_mode(long /*int*/ event, int [] mode);
+	/** [GTK4 only, if-def'd in os.h] */
+	public static final boolean gdk_event_get_crossing_mode(long /*int*/ event, int [] mode) {
+		lock.lock();
+		try {
+			return _gdk_event_get_crossing_mode(event, mode);
+		} finally {
+			lock.unlock();
+		}
+	}
+	/**
+	 * @param event cast=(GdkEvent *)
 	 * @param button cast=(guint *)
 	 */
 	public static final native boolean _gdk_event_get_button(long /*int*/ event, int[] button);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index 7673768..660d185 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -3475,10 +3475,29 @@
 
 	if (display.currentControl == this) return 0;
 	GdkEventCrossing gdkEvent = new GdkEventCrossing ();
-	OS.memmove (gdkEvent, event, GdkEventCrossing.sizeof);
-	lastInput.x = (int) gdkEvent.x;
-	lastInput.y = (int) gdkEvent.y;
+	long /*int*/ childGdkResource = 0;
+	int [] crossingMode = new int[1];
+	int [] state = new int [1];
+	GDK.gdk_event_get_state(event, state);
+	int time = GDK.gdk_event_get_time(event);
+	double [] eventRX = new double [1];
+	double [] eventRY = new double [1];
+	GDK.gdk_event_get_root_coords(event, eventRX, eventRY);
+	double [] eventX = new double [1];
+	double [] eventY = new double [1];
+	GDK.gdk_event_get_coords(event, eventX, eventY);
+	lastInput.x = (int) eventX[0];
+	lastInput.y = (int) eventY[0];
 	if (containedInRegion(lastInput.x, lastInput.y)) return 0;
+	if (GTK.GTK4) {
+		GDK.gdk_event_get_crossing_mode(event, crossingMode);
+		// TODO_GTK4: GTK devs are still deciding whether or not
+		// to provide API for GdkEventCrossing->child_surface.
+	} else {
+		OS.memmove(gdkEvent, event, GdkEventCrossing.sizeof);
+		crossingMode[0] = gdkEvent.mode;
+		childGdkResource = gdkEvent.subwindow;
+	}
 
 	/*
 	 * It is possible to send out too many enter/exit events if entering a
@@ -3486,16 +3505,16 @@
 	 * events if the GdkEventCrossing subwindow field is set and the control
 	 * requests to check the field.
 	 */
-	if (gdkEvent.subwindow != 0 && checkSubwindow ()) return 0;
-	if (gdkEvent.mode != GDK.GDK_CROSSING_NORMAL && gdkEvent.mode != GDK.GDK_CROSSING_UNGRAB) return 0;
-	if ((gdkEvent.state & (GDK.GDK_BUTTON1_MASK | GDK.GDK_BUTTON2_MASK | GDK.GDK_BUTTON3_MASK)) != 0) return 0;
+	if (childGdkResource != 0 && checkSubwindow ()) return 0;
+	if (crossingMode [0] != GDK.GDK_CROSSING_NORMAL && crossingMode[0] != GDK.GDK_CROSSING_UNGRAB) return 0;
+	if ((state[0] & (GDK.GDK_BUTTON1_MASK | GDK.GDK_BUTTON2_MASK | GDK.GDK_BUTTON3_MASK)) != 0) return 0;
 	if (display.currentControl != null && !display.currentControl.isDisposed ()) {
 		display.removeMouseHoverTimeout (display.currentControl.handle);
-		display.currentControl.sendMouseEvent (SWT.MouseExit,  0, gdkEvent.time, gdkEvent.x_root, gdkEvent.y_root, false, gdkEvent.state);
+		display.currentControl.sendMouseEvent (SWT.MouseExit,  0, time, eventRX[0], eventRY[0], false, state[0]);
 	}
 	if (!isDisposed ()) {
 		display.currentControl = this;
-		return sendMouseEvent (SWT.MouseEnter, 0, gdkEvent.time, gdkEvent.x_root, gdkEvent.y_root, false, gdkEvent.state) ? 0 : 1;
+		return sendMouseEvent (SWT.MouseEnter, 0, time, eventRX[0], eventRY[0], false, state[0]) ? 0 : 1;
 	}
 	return 0;
 }
@@ -3748,16 +3767,31 @@
 long /*int*/ gtk_leave_notify_event (long /*int*/ widget, long /*int*/ event) {
 	if (display.currentControl != this) return 0;
 	GdkEventCrossing gdkEvent = new GdkEventCrossing ();
-	OS.memmove (gdkEvent, event, GdkEventCrossing.sizeof);
-	lastInput.x = (int) gdkEvent.x;
-	lastInput.y = (int) gdkEvent.y;
+	int [] crossingMode = new int[1];
+	int [] state = new int [1];
+	GDK.gdk_event_get_state(event, state);
+	int time = GDK.gdk_event_get_time(event);
+	double [] eventRX = new double [1];
+	double [] eventRY = new double [1];
+	GDK.gdk_event_get_root_coords(event, eventRX, eventRY);
+	double [] eventX = new double [1];
+	double [] eventY = new double [1];
+	GDK.gdk_event_get_coords(event, eventX, eventY);
+	lastInput.x = (int) eventX[0];
+	lastInput.y = (int) eventY[0];
 	if (containedInRegion(lastInput.x, lastInput.y)) return 0;
+	if (GTK.GTK4) {
+		GDK.gdk_event_get_crossing_mode(event, crossingMode);
+	} else {
+		OS.memmove(gdkEvent, event, GdkEventCrossing.sizeof);
+		crossingMode[0] = gdkEvent.mode;
+	}
 	display.removeMouseHoverTimeout (handle);
 	int result = 0;
 	if (sendLeaveNotify () || display.getCursorControl () == null) {
-		if (gdkEvent.mode != GDK.GDK_CROSSING_NORMAL && gdkEvent.mode != GDK.GDK_CROSSING_UNGRAB) return 0;
-		if ((gdkEvent.state & (GDK.GDK_BUTTON1_MASK | GDK.GDK_BUTTON2_MASK | GDK.GDK_BUTTON3_MASK)) != 0) return 0;
-		result = sendMouseEvent (SWT.MouseExit, 0, gdkEvent.time, gdkEvent.x_root, gdkEvent.y_root, false, gdkEvent.state) ? 0 : 1;
+		if (crossingMode[0] != GDK.GDK_CROSSING_NORMAL && crossingMode[0] != GDK.GDK_CROSSING_UNGRAB) return 0;
+		if ((state[0] & (GDK.GDK_BUTTON1_MASK | GDK.GDK_BUTTON2_MASK | GDK.GDK_BUTTON3_MASK)) != 0) return 0;
+		result = sendMouseEvent (SWT.MouseExit, 0, time, eventRX[0], eventRY[0], false, state[0]) ? 0 : 1;
 		display.currentControl = null;
 	}
 	return result;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
index 9d72b13..0226498 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
@@ -1519,11 +1519,16 @@
 long /*int*/ gtk_leave_notify_event (long /*int*/ widget, long /*int*/ event) {
 	if (widget == shellHandle) {
 		if (isCustomResize ()) {
-			GdkEventCrossing gdkEvent = new GdkEventCrossing ();
-			OS.memmove (gdkEvent, event, GdkEventCrossing.sizeof);
-			if ((gdkEvent.state & GDK.GDK_BUTTON1_MASK) == 0) {
-				long /*int*/ window = gtk_widget_get_window (shellHandle);
-				GDK.gdk_window_set_cursor (window, 0);
+			int [] state = new int [1];
+			GDK.gdk_event_get_state(event, state);
+			if ((state[0] & GDK.GDK_BUTTON1_MASK) == 0) {
+				if (GTK.GTK4) {
+					long /*int*/ surface = gtk_widget_get_surface (shellHandle);
+					GDK.gdk_surface_set_cursor(surface, 0);
+				} else {
+					long /*int*/ window = gtk_widget_get_window (shellHandle);
+					GDK.gdk_window_set_cursor (window, 0);
+				}
 				display.resizeMode = 0;
 			}
 		}