Bug 574544 - [GTK4] Focus in & focus out event not emitting

- Added gtk_widget_set_focusable
- Removed setting of propagation phase of the GtkEventControllerFocus
- Changed the focusProc callback return value from long to void
- Cleaned up drawCaret class in Canvas
- Caret snippets (74, 43) now work properly (aside from
color/cairo-related issues)

Change-Id: I2ac56fd4449f5fd05d868ea3b0ddbfbb167cb5b3
Signed-off-by: Paul D'Pong <sdamrong@redhat.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/182610
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Alexander Kurtakov <akurtako@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
index 31023d8..24bdf0c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
@@ -1126,6 +1126,16 @@
 }
 #endif
 
+#ifndef NO_gtk_1widget_1set_1focusable
+JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1set_1focusable)
+	(JNIEnv *env, jclass that, jlong arg0, jboolean arg1)
+{
+	GTK4_NATIVE_ENTER(env, that, gtk_1widget_1set_1focusable_FUNC);
+	gtk_widget_set_focusable((GtkWidget *)arg0, arg1);
+	GTK4_NATIVE_EXIT(env, that, gtk_1widget_1set_1focusable_FUNC);
+}
+#endif
+
 #ifndef NO_gtk_1widget_1snapshot_1child
 JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1widget_1snapshot_1child)
 	(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.c
index f6e046d..73ff88e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.c
@@ -114,6 +114,7 @@
 	"gtk_1widget_1get_1root",
 	"gtk_1widget_1measure",
 	"gtk_1widget_1set_1cursor",
+	"gtk_1widget_1set_1focusable",
 	"gtk_1widget_1snapshot_1child",
 	"gtk_1widget_1translate_1coordinates",
 	"gtk_1window_1destroy",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
index 4ab86b6..7001202 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4_stats.h
@@ -124,6 +124,7 @@
 	gtk_1widget_1get_1root_FUNC,
 	gtk_1widget_1measure_FUNC,
 	gtk_1widget_1set_1cursor_FUNC,
+	gtk_1widget_1set_1focusable_FUNC,
 	gtk_1widget_1snapshot_1child_FUNC,
 	gtk_1widget_1translate_1coordinates_FUNC,
 	gtk_1window_1destroy_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
index 421e4cc..a893af2 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk4/GTK4.java
@@ -412,6 +412,11 @@
 	public static final native void gtk_widget_class_add_binding_signal(long widget_class, int keyval, int mods, byte[] signal, byte[] format_string, boolean arg1, boolean arg2, boolean arg3);
 	/** @param widget cast=(GtkWidget *) */
 	public static final native boolean gtk_widget_get_receives_default(long widget);
+	/**
+	 * @param widget cast=(GtkWidget *)
+	 * @param focusable cast(gboolean)
+	 */
+	public static final native void gtk_widget_set_focusable(long widget, boolean focusable);
 
 	/* GtkComboBox */
 	/** @param combo_box cast=(GtkComboBox *) */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
index b33ac01..24fb37f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
@@ -194,11 +194,13 @@
 	return result;
 }
 
-private void drawCaret (long widget, long cairo) {
+private void drawCaret(long widget, long cairo) {
 	if(this.isDisposed()) return;
 	if (cairo == 0) error(SWT.ERROR_NO_HANDLES);
+
 	if (drawFlag) {
 		Cairo.cairo_save(cairo);
+
 		if (caret.image != null && !caret.image.isDisposed() && caret.image.mask == 0) {
 			Cairo.cairo_set_source_rgb(cairo, 1, 1, 1);
 			Cairo.cairo_set_operator(cairo, Cairo.CAIRO_OPERATOR_DIFFERENCE);
@@ -225,14 +227,14 @@
 			int nX = caret.x;
 			if ((style & SWT.MIRRORED) != 0) nX = getClientWidth () - nWidth - nX;
 			Cairo.cairo_rectangle(cairo, nX, caret.y, nWidth, nHeight);
-			}
+		}
+
 		Cairo.cairo_fill(cairo);
 		Cairo.cairo_restore(cairo);
 		drawFlag = false;
 	} else {
 		drawFlag = true;
-		}
-	return;
+	}
 }
 
 @Override
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
index 2404889..215c8b5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
@@ -340,8 +340,13 @@
 
 	handle = OS.g_object_new(display.gtk_fixed_get_type(), 0);
 	if (handle == 0) error(SWT.ERROR_NO_HANDLES);
-	if (!GTK.GTK4) GTK3.gtk_widget_set_has_window(handle, true);
-	GTK.gtk_widget_set_can_focus (handle, true);
+
+	if (GTK.GTK4) {
+		GTK4.gtk_widget_set_focusable(handle, true);
+	} else {
+		GTK3.gtk_widget_set_has_window(handle, true);
+	}
+	GTK.gtk_widget_set_can_focus(handle, true);
 
 	if ((style & SWT.EMBEDDED) == 0) {
 		if ((state & CANVAS) != 0) {
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 c41aeb2..3bc074f 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
@@ -457,7 +457,6 @@
 		OS.g_signal_connect(keyController, OS.key_released, display.keyPressReleaseProc, KEY_RELEASED);
 
 		long focusController = GTK4.gtk_event_controller_focus_new();
-		GTK.gtk_event_controller_set_propagation_phase(focusController, GTK.GTK_PHASE_TARGET);
 		GTK4.gtk_widget_add_controller(focusHandle, focusController);
 		OS.g_signal_connect(focusController, OS.enter, display.focusProc, FOCUS_IN);
 		OS.g_signal_connect(focusController, OS.leave, display.focusProc, FOCUS_OUT);
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 7a778be..6a085f6 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
@@ -3577,9 +3577,8 @@
 		closuresProc [Widget.KEY_PRESSED] = keyPressReleaseProc;
 		closuresProc [Widget.KEY_RELEASED] = keyPressReleaseProc;
 
-		focusCallback = new Callback (this, "focusProc", long.class, new Type[] {
-				long.class, long.class}); //$NON-NLS-1$
-		focusProc = focusCallback.getAddress ();
+		focusCallback = new Callback (this, "focusProc", void.class, new Type[] {long.class, long.class}); //$NON-NLS-1$
+		focusProc = focusCallback.getAddress();
 
 		closuresProc [Widget.FOCUS_IN] = focusProc;
 		closuresProc [Widget.FOCUS_OUT] = focusProc;
@@ -6072,11 +6071,11 @@
 	return widget.enterMotionScrollProc(controller, handle, x, y, user_data);
 }
 
-long focusProc (long controller, long user_data) {
+void focusProc(long controller, long user_data) {
 	long handle = GTK.gtk_event_controller_get_widget(controller);
-	Widget widget = getWidget (handle);
-	if (widget == null) return 0;
-	return widget.focusProc(controller, handle, user_data);
+	Widget widget = getWidget(handle);
+
+	if (widget != null) widget.focusProc(controller, handle, user_data);
 }
 
 long keyPressReleaseProc (long controller, int keyval, int keycode, int state, long user_data) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Sash.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Sash.java
index f9b5a23..fce51ca 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Sash.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Sash.java
@@ -20,6 +20,7 @@
 import org.eclipse.swt.internal.*;
 import org.eclipse.swt.internal.gtk.*;
 import org.eclipse.swt.internal.gtk3.*;
+import org.eclipse.swt.internal.gtk4.*;
 
 /**
  * Instances of the receiver represent a selectable user interface object
@@ -145,22 +146,24 @@
 
 	handle = OS.g_object_new(display.gtk_fixed_get_type(), 0);
 	if (handle == 0) error(SWT.ERROR_NO_HANDLES);
-	if (!GTK.GTK4) GTK3.gtk_widget_set_has_window(handle, true);
-	GTK.gtk_widget_set_can_focus(handle, true);
 
-	if ((style & SWT.VERTICAL) != 0) {
-		if (GTK.GTK4) {
+	if (GTK.GTK4) {
+		GTK4.gtk_widget_set_focusable(handle, true);
+		if ((style & SWT.VERTICAL) != 0) {
 			defaultCursor = GDK.gdk_cursor_new_from_name("sb_h_double_arrow", 0);
 		} else {
-			defaultCursor = GDK.gdk_cursor_new_from_name (GDK.gdk_display_get_default(), "sb_h_double_arrow");
+			defaultCursor = GDK.gdk_cursor_new_from_name("sb_v_double_arrow", 0);
 		}
 	} else {
-		if (GTK.GTK4) {
-			defaultCursor = GDK.gdk_cursor_new_from_name("sb_v_double_arrow", 0);
+		GTK3.gtk_widget_set_has_window(handle, true);
+		if ((style & SWT.VERTICAL) != 0) {
+			defaultCursor = GDK.gdk_cursor_new_from_name(GDK.gdk_display_get_default(), "sb_h_double_arrow");
 		} else {
-			defaultCursor = GDK.gdk_cursor_new_from_name (GDK.gdk_display_get_default(), "sb_v_double_arrow");
+			defaultCursor = GDK.gdk_cursor_new_from_name(GDK.gdk_display_get_default(), "sb_v_double_arrow");
 		}
 	}
+
+	GTK.gtk_widget_set_can_focus(handle, true);
 }
 
 void drawBand (int x, int y, int width, int height) {
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 0755dd0..ce72b82 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
@@ -950,8 +950,8 @@
 
 		long focusController = GTK4.gtk_event_controller_focus_new();
 		GTK4.gtk_widget_add_controller(shellHandle, focusController);
-		OS.g_signal_connect (focusController, OS.enter, display.focusProc, FOCUS_IN);
-		OS.g_signal_connect (focusController, OS.leave, display.focusProc, FOCUS_OUT);
+		OS.g_signal_connect(focusController, OS.enter, display.focusProc, FOCUS_IN);
+		OS.g_signal_connect(focusController, OS.leave, display.focusProc, FOCUS_OUT);
 
 		long enterLeaveController = GTK4.gtk_event_controller_motion_new();
 		GTK4.gtk_widget_add_controller(shellHandle, enterLeaveController);
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 800114f..df474fb 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
@@ -2196,20 +2196,17 @@
 	return result;
 }
 
-long focusProc(long controller, long handle, long user_data) {
-	long result = 0;
+void focusProc(long controller, long handle, long user_data) {
 	long event = GTK4.gtk_event_controller_get_current_event(controller);
 
 	switch ((int)user_data) {
 		case FOCUS_IN:
-			result = gtk_focus_in_event(handle, event);
+			gtk_focus_in_event(handle, event);
 			break;
 		case FOCUS_OUT:
-			result = gtk_focus_out_event(handle, event);
+			gtk_focus_out_event(handle, event);
 			break;
 	}
-
-	return result;
 }
 
 long keyPressReleaseProc(long controller, long handle, int keyval, int keycode, int state, long user_data) {