diff options
author | Xi Yan | 2018-11-01 14:36:20 +0000 |
---|---|---|
committer | Alexander Kurtakov | 2018-11-05 15:32:53 +0000 |
commit | f23577f6c6622ec6291ce641439c3c80d35e9ca5 (patch) | |
tree | 60ebb826aba487b937348fa0a3d8c914cfc1e3ef | |
parent | 492144bd4e220e6daeac4fcc4a3f65f4ffef6f95 (diff) | |
download | eclipse.platform.swt-f23577f6c6622ec6291ce641439c3c80d35e9ca5.tar.gz eclipse.platform.swt-f23577f6c6622ec6291ce641439c3c80d35e9ca5.tar.xz eclipse.platform.swt-f23577f6c6622ec6291ce641439c3c80d35e9ca5.zip |
Bug 540692 - [GTK] Replace GtkFileChooserDialog with
GtkFileChooserNative
Replace GtkFileChooserDialog with GtkFileChooserNative for GTK3.20+.
Change-Id: If705c899098d2598eb4400b96d1cf48474c53629
Signed-off-by: Xi Yan <xixiyan@redhat.com>
6 files changed, 236 insertions, 1 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 f0e00540c2..2b2e90c7da 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 @@ -4854,6 +4854,36 @@ JNIEXPORT jintLong JNICALL GTK_NATIVE(_1gtk_1file_1chooser_1get_1uris) } #endif +#ifndef NO__1gtk_1file_1chooser_1native_1new +JNIEXPORT jintLong JNICALL GTK_NATIVE(_1gtk_1file_1chooser_1native_1new) + (JNIEnv *env, jclass that, jbyteArray arg0, jintLong arg1, jint arg2, jbyteArray arg3, jbyteArray arg4) +{ + jbyte *lparg0=NULL; + jbyte *lparg3=NULL; + jbyte *lparg4=NULL; + jintLong rc = 0; + GTK_NATIVE_ENTER(env, that, _1gtk_1file_1chooser_1native_1new_FUNC); + if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; + if (arg3) if ((lparg3 = (*env)->GetByteArrayElements(env, arg3, NULL)) == NULL) goto fail; + if (arg4) if ((lparg4 = (*env)->GetByteArrayElements(env, arg4, NULL)) == NULL) goto fail; +/* + rc = (jintLong)gtk_file_chooser_native_new((const gchar *)lparg0, (GtkWindow *)arg1, arg2, (const gchar *)lparg3, (const gchar *)lparg4); +*/ + { + GTK_LOAD_FUNCTION(fp, gtk_file_chooser_native_new) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(const gchar *, GtkWindow *, jint, const gchar *, const gchar *))fp)((const gchar *)lparg0, (GtkWindow *)arg1, arg2, (const gchar *)lparg3, (const gchar *)lparg4); + } + } +fail: + if (arg4 && lparg4) (*env)->ReleaseByteArrayElements(env, arg4, lparg4, JNI_ABORT); + if (arg3 && lparg3) (*env)->ReleaseByteArrayElements(env, arg3, lparg3, JNI_ABORT); + if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT); + GTK_NATIVE_EXIT(env, that, _1gtk_1file_1chooser_1native_1new_FUNC); + return rc; +} +#endif + #ifndef NO__1gtk_1file_1chooser_1set_1current_1folder JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1file_1chooser_1set_1current_1folder) (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1) @@ -6539,6 +6569,18 @@ JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1misc_1set_1alignment) } #endif +#ifndef NO__1gtk_1native_1dialog_1run +JNIEXPORT jint JNICALL GTK_NATIVE(_1gtk_1native_1dialog_1run) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jint rc = 0; + GTK_NATIVE_ENTER(env, that, _1gtk_1native_1dialog_1run_FUNC); + rc = (jint)gtk_native_dialog_run((GtkNativeDialog *)arg0); + GTK_NATIVE_EXIT(env, that, _1gtk_1native_1dialog_1run_FUNC); + return rc; +} +#endif + #ifndef NO__1gtk_1notebook_1get_1current_1page JNIEXPORT jint JNICALL GTK_NATIVE(_1gtk_1notebook_1get_1current_1page) (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 1fab85850f..87fadcaa98 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 @@ -424,6 +424,7 @@ char * GTK_nativeFunctionNames[] = { "_1gtk_1file_1chooser_1get_1filter", "_1gtk_1file_1chooser_1get_1uri", "_1gtk_1file_1chooser_1get_1uris", + "_1gtk_1file_1chooser_1native_1new", "_1gtk_1file_1chooser_1set_1current_1folder", "_1gtk_1file_1chooser_1set_1current_1folder_1uri", "_1gtk_1file_1chooser_1set_1current_1name", @@ -566,6 +567,7 @@ char * GTK_nativeFunctionNames[] = { "_1gtk_1micro_1version", "_1gtk_1minor_1version", "_1gtk_1misc_1set_1alignment", + "_1gtk_1native_1dialog_1run", "_1gtk_1notebook_1get_1current_1page", "_1gtk_1notebook_1get_1scrollable", "_1gtk_1notebook_1insert_1page", 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 1c158c076a..3f279b26bb 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 @@ -422,6 +422,7 @@ typedef enum { _1gtk_1file_1chooser_1get_1filter_FUNC, _1gtk_1file_1chooser_1get_1uri_FUNC, _1gtk_1file_1chooser_1get_1uris_FUNC, + _1gtk_1file_1chooser_1native_1new_FUNC, _1gtk_1file_1chooser_1set_1current_1folder_FUNC, _1gtk_1file_1chooser_1set_1current_1folder_1uri_FUNC, _1gtk_1file_1chooser_1set_1current_1name_FUNC, @@ -564,6 +565,7 @@ typedef enum { _1gtk_1micro_1version_FUNC, _1gtk_1minor_1version_FUNC, _1gtk_1misc_1set_1alignment_FUNC, + _1gtk_1native_1dialog_1run_FUNC, _1gtk_1notebook_1get_1current_1page_FUNC, _1gtk_1notebook_1get_1scrollable_FUNC, _1gtk_1notebook_1insert_1page_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 1f7ce3e475..2236ca1f4d 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 @@ -100,6 +100,8 @@ public class GTK extends OS { public static final int GTK_RESPONSE_APPLY = 0xfffffff6; public static final int GTK_RESPONSE_CANCEL = 0xfffffffa; public static final int GTK_RESPONSE_OK = 0xfffffffb; + public static final int GTK_RESPONSE_ACCEPT = -3; + public static final int GTK_RESPONSE_DELETE_EVENT = -4; public static final int GTK_SCROLL_NONE = 0; public static final int GTK_SCROLL_JUMP = 1; public static final int GTK_SCROLL_STEP_BACKWARD = 2; @@ -2392,6 +2394,22 @@ public class GTK extends OS { } /** * @method flags=dynamic + * @param title cast=(const gchar *),flags=no_out + * @param parent cast=(GtkWindow *) + * @param accept_label cast=(const gchar *),flags=no_out + * @param cancel_label cast=(const gchar *),flags=no_out + */ + public static final native long /*int*/ _gtk_file_chooser_native_new(byte[] title, long /*int*/ parent, int action, byte[] accept_label, byte[] cancel_label); + public static final long /*int*/ gtk_file_chooser_native_new(byte[] title, long /*int*/ parent, int action, byte[] accept_label, byte[] cancel_label) { + lock.lock(); + try { + return _gtk_file_chooser_native_new(title, parent, action, accept_label, cancel_label); + } finally { + lock.unlock(); + } + } + /** + * @method flags=dynamic */ public static final native void _gtk_event_controller_handle_event(long /*int*/ gesture, long /*int*/ event); public static final void gtk_event_controller_handle_event(long /*int*/ gesture, long /*int*/ event) { @@ -3932,6 +3950,16 @@ public class GTK extends OS { lock.unlock(); } } + /** @param dialog cast=(GtkNativeDialog *) */ + public static final native int _gtk_native_dialog_run(long /*int*/ dialog); + public static final int gtk_native_dialog_run(long /*int*/ dialog) { + lock.lock(); + try { + return _gtk_native_dialog_run(dialog); + } finally { + lock.unlock(); + } + } /** @param notebook cast=(GtkNotebook *) */ public static final native int _gtk_notebook_get_current_page(long /*int*/ notebook); public static final int gtk_notebook_get_current_page(long /*int*/ notebook) { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/DirectoryDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/DirectoryDialog.java index 22eb5e7e23..b5aa7bf88d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/DirectoryDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/DirectoryDialog.java @@ -121,7 +121,115 @@ public String getMessage () { * </ul> */ public String open () { + if (GTK.GTK_VERSION >= OS.VERSION(3, 20, 0)) { + return openNativeChooserDialog(); + } else { return openChooserDialog (); + } +} +/** + * Open the file chooser dialog using the GtkFileChooserNative API (GTK3.20+) for running applications + * without direct filesystem access (such as Flatpak). API for GtkFileChoosernative does not + * give access to any GtkWindow or GtkWidget for the dialog, thus this method omits calls that + * requires such access. These are be handled by the GtkNativeDialog API. + * + * @return a string describing the absolute path of the first selected file, or null + */ +String openNativeChooserDialog () { + byte [] titleBytes = Converter.wcsToMbcs (title, true); + long /*int*/ shellHandle = parent.topHandle (); + Display display = parent != null ? parent.getDisplay (): Display.getCurrent (); + long /*int*/ handle = 0; + handle = GTK.gtk_file_chooser_native_new(titleBytes, shellHandle, GTK.GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK.GTK_NAMED_LABEL_OK, GTK.GTK_NAMED_LABEL_CANCEL); + if (handle == 0) error (SWT.ERROR_NO_HANDLES); + + if (filterPath != null && filterPath.length () > 0) { + StringBuilder stringBuilder = new StringBuilder (); + /* filename must be a full path */ + if (!filterPath.startsWith (SEPARATOR)) { + stringBuilder.append (SEPARATOR); + } + stringBuilder.append (filterPath); + byte [] buffer = Converter.wcsToMbcs (stringBuilder.toString (), true); + /* + * in GTK version 2.10, gtk_file_chooser_set_current_folder requires path + * to be true canonical path. So using realpath to convert the path to + * true canonical path. + */ + if (OS.IsAIX) { + byte [] outputBuffer = new byte [PATH_MAX]; + long /*int*/ ptr = OS.realpath (buffer, outputBuffer); + if (ptr != 0) { + GTK.gtk_file_chooser_set_current_folder (handle, ptr); + } + /* We are not doing free here because realpath returns the address of outputBuffer + * which is created in this code and we let the garbage collector to take care of this + */ + } else { + long /*int*/ ptr = OS.realpath (buffer, null); + if (ptr != 0) { + GTK.gtk_file_chooser_set_current_folder (handle, ptr); + OS.g_free (ptr); + } + } + } + if (message.length () > 0) { + byte [] buffer = Converter.wcsToMbcs (message, true); + long /*int*/ box = GTK.gtk_box_new (GTK.GTK_ORIENTATION_HORIZONTAL, 0); + GTK.gtk_box_set_homogeneous (box, false); + if (box == 0) error (SWT.ERROR_NO_HANDLES); + long /*int*/ label = GTK.gtk_label_new (buffer); + if (label == 0) error (SWT.ERROR_NO_HANDLES); + GTK.gtk_container_add (box, label); + GTK.gtk_widget_show (label); + GTK.gtk_label_set_line_wrap (label, true); + GTK.gtk_label_set_justify (label, GTK.GTK_JUSTIFY_CENTER); + GTK.gtk_file_chooser_set_extra_widget (handle, box); + } + String answer = null; + display.addIdleProc (); + int signalId = 0; + long /*int*/ 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.sendPreExternalEventDispatchEvent (); + int response = GTK.gtk_native_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.sendPostExternalEventDispatchEvent (); + if ((style & SWT.RIGHT_TO_LEFT) != 0) { + OS.g_signal_remove_emission_hook (signalId, hookId); + } + if (response == GTK.GTK_RESPONSE_ACCEPT) { + long /*int*/ path = GTK.gtk_file_chooser_get_filename (handle); + if (path != 0) { + long /*int*/ utf8Ptr = OS.g_filename_to_utf8 (path, -1, null, null, null); + if (utf8Ptr == 0) utf8Ptr = OS.g_filename_display_name (path); + if (path != utf8Ptr) OS.g_free (path); + if (utf8Ptr != 0) { + long /*int*/ [] items_written = new long /*int*/ [1]; + long /*int*/ utf16Ptr = OS.g_utf8_to_utf16 (utf8Ptr, -1, null, items_written, null); + OS.g_free (utf8Ptr); + if (utf16Ptr != 0) { + int clength = (int)/*64*/items_written [0]; + char [] chars = new char [clength]; + C.memmove (chars, utf16Ptr, clength * 2); + OS.g_free (utf16Ptr); + answer = new String (chars); + filterPath = answer; + } + } + } + } + display.removeIdleProc (); + return answer; } String openChooserDialog () { byte [] titleBytes = Converter.wcsToMbcs (title, true); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/FileDialog.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/FileDialog.java index 892ef19c4c..e5fb1bfc44 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/FileDialog.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/FileDialog.java @@ -302,7 +302,60 @@ public boolean getOverwrite () { * </ul> */ public String open () { - return openChooserDialog (); + if (GTK.GTK_VERSION >= OS.VERSION(3, 20, 0)) { + return openNativeChooserDialog(); + } else { + return openChooserDialog(); + } +} +/** + * Open the file chooser dialog using the GtkFileChooserNative API (GTK3.20+) for running applications + * without direct filesystem access (such as Flatpak). API for GtkFileChoosernative does not + * give access to any GtkWindow or GtkWidget for the dialog, thus this method omits calls that + * requires such access. These are be handled by the GtkNativeDialog API. + * + * @return a string describing the absolute path of the first selected file, or null + */ +String openNativeChooserDialog () { + assert GTK.GTK_VERSION >= OS.VERSION(3, 20, 0); + byte [] titleBytes = Converter.wcsToMbcs (title, true); + int action = (style & SWT.SAVE) != 0 ? GTK.GTK_FILE_CHOOSER_ACTION_SAVE : GTK.GTK_FILE_CHOOSER_ACTION_OPEN; + long /*int*/ shellHandle = parent.topHandle (); + Display display = parent != null ? parent.getDisplay (): Display.getCurrent (); + handle = GTK.gtk_file_chooser_native_new(titleBytes, shellHandle, action, GTK.GTK_NAMED_LABEL_OK, GTK.GTK_NAMED_LABEL_CANCEL); + if (handle == 0) error (SWT.ERROR_NO_HANDLES); + + if (uriMode) { + GTK.gtk_file_chooser_set_local_only (handle, false); + } + presetChooserDialog (); + display.addIdleProc (); + String answer = null; + int signalId = 0; + long /*int*/ 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.sendPreExternalEventDispatchEvent (); + int response = 0; + response = GTK.gtk_native_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.sendPostExternalEventDispatchEvent (); + if ((style & SWT.RIGHT_TO_LEFT) != 0) { + OS.g_signal_remove_emission_hook (signalId, hookId); + } + if (response == GTK.GTK_RESPONSE_ACCEPT) { + answer = computeResultChooserDialog (); + } + display.removeIdleProc (); + return answer; } String openChooserDialog () { byte [] titleBytes = Converter.wcsToMbcs (title, true); |