Bug 567371 - [GTK4] Removal of blocking dialog functions
- Changed MessageBox's handling of dialog startup & response return.
Requires changing the async "response" signal to a blocking call named
waitForResponse.
- Swapped where the title and secondary messages are set. This allows
the GTK3 and GTK4 code for this the same. This is done through the use
of gtk_message_dialog_format_secondary_text.
- Added response signal
Change-Id: I89930ff303ffe975969ef47921ff2e9a2845c154
Signed-off-by: Paul D'Pong <sdamrong@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 43cbc89..5149c30 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
@@ -7782,6 +7782,23 @@
}
#endif
+#ifndef NO_gtk_1message_1dialog_1format_1secondary_1text
+JNIEXPORT void JNICALL GTK_NATIVE(gtk_1message_1dialog_1format_1secondary_1text)
+ (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jbyteArray arg2)
+{
+ jbyte *lparg1=NULL;
+ jbyte *lparg2=NULL;
+ GTK_NATIVE_ENTER(env, that, gtk_1message_1dialog_1format_1secondary_1text_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ gtk_message_dialog_format_secondary_text((GtkMessageDialog *)arg0, (const gchar *)lparg1, (const gchar *)lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, 0);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ GTK_NATIVE_EXIT(env, that, gtk_1message_1dialog_1format_1secondary_1text_FUNC);
+}
+#endif
+
#ifndef NO_gtk_1message_1dialog_1new
JNIEXPORT jlong JNICALL GTK_NATIVE(gtk_1message_1dialog_1new)
(JNIEnv *env, jclass that, jlong arg0, jint arg1, jint arg2, jint arg3, jbyteArray arg4, jbyteArray arg5)
@@ -13680,6 +13697,18 @@
}
#endif
+#ifndef NO_gtk_1window_1get_1icon_1name
+JNIEXPORT jlong JNICALL GTK_NATIVE(gtk_1window_1get_1icon_1name)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jlong rc = 0;
+ GTK_NATIVE_ENTER(env, that, gtk_1window_1get_1icon_1name_FUNC);
+ rc = (jlong)gtk_window_get_icon_name((GtkWindow *)arg0);
+ GTK_NATIVE_EXIT(env, that, gtk_1window_1get_1icon_1name_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO_gtk_1window_1get_1mnemonic_1modifier
JNIEXPORT jint JNICALL GTK_NATIVE(gtk_1window_1get_1mnemonic_1modifier)
(JNIEnv *env, jclass that, jlong arg0)
@@ -13961,6 +13990,16 @@
}
#endif
+#ifndef NO_gtk_1window_1set_1icon_1name
+JNIEXPORT void JNICALL GTK_NATIVE(gtk_1window_1set_1icon_1name)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ GTK_NATIVE_ENTER(env, that, gtk_1window_1set_1icon_1name_FUNC);
+ gtk_window_set_icon_name((GtkWindow *)arg0, (const char *)arg1);
+ GTK_NATIVE_EXIT(env, that, gtk_1window_1set_1icon_1name_FUNC);
+}
+#endif
+
#ifndef NO_gtk_1window_1set_1keep_1above
JNIEXPORT void JNICALL GTK_NATIVE(gtk_1window_1set_1keep_1above)
(JNIEnv *env, jclass that, jlong arg0, jboolean arg1)
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 9cab8d3..671dbe8 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
@@ -605,6 +605,7 @@
"gtk_1menu_1shell_1insert",
"gtk_1menu_1shell_1set_1take_1focus",
"gtk_1menu_1tool_1button_1new",
+ "gtk_1message_1dialog_1format_1secondary_1text",
"gtk_1message_1dialog_1new",
"gtk_1native_1dialog_1run",
"gtk_1native_1get_1surface",
@@ -1055,6 +1056,7 @@
"gtk_1window_1get_1focus",
"gtk_1window_1get_1group",
"gtk_1window_1get_1icon_1list",
+ "gtk_1window_1get_1icon_1name",
"gtk_1window_1get_1mnemonic_1modifier",
"gtk_1window_1get_1modal",
"gtk_1window_1get_1position",
@@ -1080,6 +1082,7 @@
"gtk_1window_1set_1destroy_1with_1parent",
"gtk_1window_1set_1geometry_1hints",
"gtk_1window_1set_1icon_1list",
+ "gtk_1window_1set_1icon_1name",
"gtk_1window_1set_1keep_1above",
"gtk_1window_1set_1modal",
"gtk_1window_1set_1resizable",
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 1f5b488..91614f6 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
@@ -603,6 +603,7 @@
gtk_1menu_1shell_1insert_FUNC,
gtk_1menu_1shell_1set_1take_1focus_FUNC,
gtk_1menu_1tool_1button_1new_FUNC,
+ gtk_1message_1dialog_1format_1secondary_1text_FUNC,
gtk_1message_1dialog_1new_FUNC,
gtk_1native_1dialog_1run_FUNC,
gtk_1native_1get_1surface_FUNC,
@@ -1053,6 +1054,7 @@
gtk_1window_1get_1focus_FUNC,
gtk_1window_1get_1group_FUNC,
gtk_1window_1get_1icon_1list_FUNC,
+ gtk_1window_1get_1icon_1name_FUNC,
gtk_1window_1get_1mnemonic_1modifier_FUNC,
gtk_1window_1get_1modal_FUNC,
gtk_1window_1get_1position_FUNC,
@@ -1078,6 +1080,7 @@
gtk_1window_1set_1destroy_1with_1parent_FUNC,
gtk_1window_1set_1geometry_1hints_FUNC,
gtk_1window_1set_1icon_1list_FUNC,
+ gtk_1window_1set_1icon_1name_FUNC,
gtk_1window_1set_1keep_1above_FUNC,
gtk_1window_1set_1modal_FUNC,
gtk_1window_1set_1resizable_FUNC,
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 d658fd4..63a50ca 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
@@ -1842,6 +1842,7 @@
public static final native long gtk_radio_menu_item_new(long group);
public static final native long gtk_separator_menu_item_new();
+
/* GtkPopover */
/** @param popover cast=(GtkPopover *) */
public static final native void gtk_popover_popdown(long popover);
@@ -1858,9 +1859,12 @@
* @param model cast=(GMenuModel *) */
public static final native long gtk_popover_menu_new_from_model(long model);
+
/* GtkMenuButton */
public static final native long gtk_menu_button_new();
+
+ /* GtkMessageDialog */
/**
* @param parent cast=(GtkWindow *)
* @param flags cast=(GtkDialogFlags)
@@ -1870,6 +1874,14 @@
* @param arg cast=(const gchar *)
*/
public static final native long gtk_message_dialog_new(long parent, int flags, int type, int buttons, byte[] message_format, byte[] arg);
+ /**
+ * @param message_dialog cast=(GtkMessageDialog *)
+ * @param message_format cast=(const gchar *)
+ * @param arg cast=(const gchar *)
+ */
+ public static final native void gtk_message_dialog_format_secondary_text(long message_dialog, byte[] message_format, byte[] arg);
+
+
/** @param dialog cast=(GtkNativeDialog *) */
public static final native int gtk_native_dialog_run(long dialog);
/** @param notebook cast=(GtkNotebook *) */
@@ -3881,4 +3893,11 @@
public static final native void gtk_window_set_child(long window, long child);
/** @param window cast=(GtkWindow *) */
public static final native void gtk_window_destroy(long window);
+ /** @param window cast=(GtkWindow *) */
+ public static final native long gtk_window_get_icon_name(long window);
+ /**
+ * @param window cast=(GtkWindow *)
+ * @param name cast=(const char *)
+ * */
+ public static final native void gtk_window_set_icon_name(long window, long name);
}
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 1eb8e6b..0e69e50 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
@@ -361,6 +361,7 @@
public static final byte[] window_state_event = ascii("window-state-event");
public static final byte[] notify_state = ascii("notify::state");
public static final byte[] notify_theme_change = ascii("notify::gtk-application-prefer-dark-theme");
+ public static final byte[] response = ascii("response");
/** Properties */
public static final byte[] active = ascii("active");
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/MessageBox.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/MessageBox.java
index 35b7f2f..6c369ff 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/MessageBox.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/MessageBox.java
@@ -14,6 +14,8 @@
package org.eclipse.swt.widgets;
+import java.lang.reflect.*;
+
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gtk.*;
@@ -45,6 +47,10 @@
String message = "";
long handle;
+
+ /* GTK4 fields used to transform async response callback synchronous */
+ int responseID;
+ Callback dialogResponseCallback;
/**
* Constructs a new instance of this class given only its parent.
*
@@ -153,65 +159,82 @@
if ((style & (SWT.ICON_QUESTION)) != 0) messageType = GTK.GTK_MESSAGE_QUESTION;
if ((style & (SWT.ICON_ERROR)) != 0) messageType = GTK.GTK_MESSAGE_ERROR;
- byte [] format = Converter.wcsToMbcs ("%s", true);
- byte [] buffer = Converter.wcsToMbcs (message, true);
+ byte[] format = Converter.wcsToMbcs("%s", true);
+ byte[] buffer = Converter.wcsToMbcs(title, true);
handle = GTK.gtk_message_dialog_new(parentHandle, dialogFlags, messageType, 0, format, buffer);
if (handle == 0) error(SWT.ERROR_NO_HANDLES);
+
+ // Copy parent's icon
if (parentHandle != 0) {
- long pixbufs = GTK.gtk_window_get_icon_list (parentHandle);
- if (pixbufs != 0) {
- GTK.gtk_window_set_icon_list (handle, pixbufs);
- OS.g_list_free (pixbufs);
+ if (GTK.GTK4) {
+ long iconName = GTK.gtk_window_get_icon_name(parentHandle);
+ if (iconName != 0) {
+ GTK.gtk_window_set_icon_name(handle, iconName);
+ }
+ } else {
+ long pixbufs = GTK.gtk_window_get_icon_list(parentHandle);
+ if (pixbufs != 0) {
+ GTK.gtk_window_set_icon_list(handle, pixbufs);
+ OS.g_list_free (pixbufs);
+ }
}
}
- Display display = parent != null ? parent.getDisplay (): Display.getCurrent ();
- createButtons (display.getDismissalAlignment ());
- buffer = Converter.wcsToMbcs(title, true);
- GTK.gtk_window_set_title(handle,buffer);
- display.addIdleProc ();
- Dialog oldModal = null;
- /*
- * In order to allow the dialog to be modal of it's
- * parent shells, it is required to assign the
- * dialog to the same window group as of the shells.
- */
- long group = GTK.gtk_window_get_group(0);
- GTK.gtk_window_group_add_window (group, handle);
- if (GTK.gtk_window_get_modal (handle)) {
- oldModal = display.getModalDialog ();
- display.setModalDialog (this);
- }
- int signalId = 0;
- long hookId = 0;
- if ((style & SWT.RIGHT_TO_LEFT) != 0) {
- signalId = OS.g_signal_lookup (OS.map, GTK.GTK_TYPE_WIDGET());
- hookId = OS.g_signal_add_emission_hook (signalId, 0, display.emissionProc, handle, 0);
- }
- display.externalEventLoop = true;
- display.sendPreExternalEventDispatchEvent ();
- int response = GTK.gtk_dialog_run (handle);
- /*
- * This call to gdk_threads_leave() is a temporary work around
- * to avoid deadlocks when gdk_threads_init() is called by native
- * code outside of SWT (i.e AWT, etc). It ensures that the current
- * thread leaves the GTK lock acquired by the function above.
- */
- if (!GTK.GTK4) GDK.gdk_threads_leave();
- display.externalEventLoop = false;
- display.sendPostExternalEventDispatchEvent ();
- if ((style & SWT.RIGHT_TO_LEFT) != 0) {
- OS.g_signal_remove_emission_hook (signalId, hookId);
- }
- if (GTK.gtk_window_get_modal (handle)) {
- display.setModalDialog (oldModal);
- }
- display.removeIdleProc ();
+ Display display = parent != null ? parent.getDisplay() : Display.getCurrent();
+ createButtons(display.getDismissalAlignment());
+ GTK.gtk_message_dialog_format_secondary_text(handle, format, Converter.javaStringToCString(message));
+
+ int response;
if (GTK.GTK4) {
- GTK.gtk_window_destroy(handle);
+ initializeResponseCallback();
+ OS.g_signal_connect(handle, OS.response, dialogResponseCallback.getAddress(), 0);
+ GTK.gtk_widget_show(handle);
+
+ response = waitForResponse(display);
+ disposeResponseCallback();
} else {
+ display.addIdleProc ();
+ Dialog oldModal = null;
+ /*
+ * In order to allow the dialog to be modal of it's
+ * parent shells, it is required to assign the
+ * dialog to the same window group as of the shells.
+ */
+ long group = GTK.gtk_window_get_group(0);
+ GTK.gtk_window_group_add_window (group, handle);
+
+ if (GTK.gtk_window_get_modal (handle)) {
+ oldModal = display.getModalDialog ();
+ display.setModalDialog (this);
+ }
+ int signalId = 0;
+ long hookId = 0;
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ signalId = OS.g_signal_lookup (OS.map, GTK.GTK_TYPE_WIDGET());
+ hookId = OS.g_signal_add_emission_hook (signalId, 0, display.emissionProc, handle, 0);
+ }
+ display.externalEventLoop = true;
+ display.sendPreExternalEventDispatchEvent ();
+ response = GTK.gtk_dialog_run (handle);
+ /*
+ * This call to gdk_threads_leave() is a temporary work around
+ * to avoid deadlocks when gdk_threads_init() is called by native
+ * code outside of SWT (i.e AWT, etc). It ensures that the current
+ * thread leaves the GTK lock acquired by the function above.
+ */
+ GDK.gdk_threads_leave();
+ display.externalEventLoop = false;
+ display.sendPostExternalEventDispatchEvent ();
+ if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+ OS.g_signal_remove_emission_hook (signalId, hookId);
+ }
+ if (GTK.gtk_window_get_modal (handle)) {
+ display.setModalDialog (oldModal);
+ }
+ display.removeIdleProc ();
GTK.gtk_widget_destroy(handle);
}
+
return response;
}
@@ -245,4 +268,55 @@
return style;
}
+/**
+ * Initializes the response callback and resets the responseID of the dialog to the default value.
+ * This function should be called before connect the dialog to the "response" signal, as this sets up the callback.
+ *
+ * Note: This function is only used in the GTK4 implementation due to the removal of the blocking call gtk_dialog_run. See bug 567371.
+ */
+private void initializeResponseCallback() {
+ dialogResponseCallback = new Callback(this, "dialogResponseProc", void.class, new Type[] {long.class, int.class, long.class});
+ responseID = -1;
+}
+
+/**
+ * Disposes the response callback.
+ * This function should be called after waitForResponse has returned, as this signifies the end of the signal handling.
+ *
+ * Note: This function is only used in the GTK4 implementation due to the removal of the blocking call gtk_dialog_run. See bug 567371.
+ * @see waitForResponse
+ */
+private void disposeResponseCallback() {
+ dialogResponseCallback.dispose();
+ dialogResponseCallback = null;
+}
+
+/**
+ * A blocking call that waits for the handling of the signal before returning.
+ *
+ * Note: This function is only used in the GTK4 implementation due to the removal of the blocking call gtk_dialog_run. See bug 567371.
+ *
+ * @return the response_id from the dialog presented to the user
+ */
+private int waitForResponse(Display display) {
+ while (!display.isDisposed()) {
+ boolean eventsDispatched = OS.g_main_context_iteration (0, false);
+ if (responseID != -1) {
+ break;
+ } else if (!eventsDispatched) {
+ display.sleep();
+ }
+ }
+
+ return responseID;
+}
+
+/**
+ * Callback function for the "response" signal in GtkDialog widgets.
+ * Destroys the dialog after a response is given.
+ */
+void dialogResponseProc(long dialog, int response_id, long user_date) {
+ responseID = response_id;
+ GTK.gtk_window_destroy(dialog);
+}
}