Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GTK4] Migrate DirectoryDialog from GtkFileChooser to GtkFileDialog #1421

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/gtk4.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,54 @@ JNIEXPORT jboolean JNICALL GTK4_NATIVE(gtk_1file_1chooser_1set_1file)
}
#endif

#ifndef NO_gtk_1file_1dialog_1new
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1file_1dialog_1new)
(JNIEnv *env, jclass that)
{
jlong rc = 0;
GTK4_NATIVE_ENTER(env, that, gtk_1file_1dialog_1new_FUNC);
rc = (jlong)gtk_file_dialog_new();
GTK4_NATIVE_EXIT(env, that, gtk_1file_1dialog_1new_FUNC);
return rc;
}
#endif

#ifndef NO_gtk_1file_1dialog_1select_1folder
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1file_1dialog_1select_1folder)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlong arg2, jlong arg3, jlong arg4)
{
GTK4_NATIVE_ENTER(env, that, gtk_1file_1dialog_1select_1folder_FUNC);
gtk_file_dialog_select_folder((GtkFileDialog *)arg0, (GtkWindow *)arg1, (GCancellable *)arg2, (GAsyncReadyCallback)arg3, (gpointer)arg4);
GTK4_NATIVE_EXIT(env, that, gtk_1file_1dialog_1select_1folder_FUNC);
}
#endif

#ifndef NO_gtk_1file_1dialog_1select_1folder_1finish
JNIEXPORT jlong JNICALL GTK4_NATIVE(gtk_1file_1dialog_1select_1folder_1finish)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2)
{
jlong *lparg2=NULL;
jlong rc = 0;
GTK4_NATIVE_ENTER(env, that, gtk_1file_1dialog_1select_1folder_1finish_FUNC);
if (arg2) if ((lparg2 = (*env)->GetLongArrayElements(env, arg2, NULL)) == NULL) goto fail;
rc = (jlong)gtk_file_dialog_select_folder_finish((GtkFileDialog *)arg0, (GAsyncResult *)arg1, (GError *)lparg2);
fail:
if (arg2 && lparg2) (*env)->ReleaseLongArrayElements(env, arg2, lparg2, 0);
GTK4_NATIVE_EXIT(env, that, gtk_1file_1dialog_1select_1folder_1finish_FUNC);
return rc;
}
#endif

#ifndef NO_gtk_1file_1dialog_1set_1initial_1folder
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1file_1dialog_1set_1initial_1folder)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
{
GTK4_NATIVE_ENTER(env, that, gtk_1file_1dialog_1set_1initial_1folder_FUNC);
gtk_file_dialog_set_initial_folder((GtkFileDialog *)arg0, (GFile *)arg1);
GTK4_NATIVE_EXIT(env, that, gtk_1file_1dialog_1set_1initial_1folder_FUNC);
}
#endif

#ifndef NO_gtk_1frame_1set_1child
JNIEXPORT void JNICALL GTK4_NATIVE(gtk_1frame_1set_1child)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ typedef enum {
gtk_1file_1chooser_1get_1files_FUNC,
gtk_1file_1chooser_1set_1current_1folder_FUNC,
gtk_1file_1chooser_1set_1file_FUNC,
gtk_1file_1dialog_1new_FUNC,
gtk_1file_1dialog_1select_1folder_FUNC,
gtk_1file_1dialog_1select_1folder_1finish_FUNC,
gtk_1file_1dialog_1set_1initial_1folder_FUNC,
gtk_1frame_1set_1child_FUNC,
gtk_1gesture_1click_1new_FUNC,
gtk_1gesture_1drag_1new_FUNC,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2021, 2023 Syntevo and others.
* Copyright (c) 2021, 2024 Syntevo and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -191,7 +191,29 @@ public class GTK4 {
* @param error cast=(GError **)
*/
public static final native boolean gtk_file_chooser_set_file(long chooser, long file, long error);


/* GtkFileDialog */
public static final native long gtk_file_dialog_new();
/**
* @param self cast=(GtkFileDialog *)
* @param parent cast=(GtkWindow *)
* @param cancellable cast=(GCancellable *)
* @param callback cast=(GAsyncReadyCallback)
* @param user_data cast=(gpointer)
*/
public static final native void gtk_file_dialog_select_folder(long self, long parent, long cancellable, long callback, long user_data);
/**
* @param self cast=(GtkFileDialog *)
* @param result cast=(GAsyncResult *)
* @param error cast=(GError *)
Copy link
Member

@akurtakov akurtakov Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be '(GError **)'. What you have here fails with

gtk4.c:737:103: error: passing argument 3 of ‘gtk_file_dialog_select_folder_finish’ from incompatible pointer type [-Wincompatible-pointer-types]
  737 |         rc = (jlong)gtk_file_dialog_select_folder_finish((GtkFileDialog *)arg0, (GAsyncResult *)arg1, (GError *)lparg2);
      |                                                                                                       ^~~~~~~~~~~~~~~~
      |                                                                                                       |
      |                                                                                                       GError * {aka struct _GError *}
In file included from /usr/include/gtk-4.0/gtk/gtk.h:134,
                 from gtk4.h:23,
                 from gtk4_structs.h:18,
                 from gtk4.c:19:
/usr/include/gtk-4.0/gtk/gtkfiledialog.h:118:77: note: expected ‘GError **’ {aka ‘struct _GError **’} but argument is of type ‘GError *’ {aka ‘struct _GError *’}
  118 |                                                       GError              **error);
      |                                                       ~~~~~~~~~~~~~~~~~~~~~~^~~~~

*/
public static final native long gtk_file_dialog_select_folder_finish(long self, long result, long[] error);
/**
* @param self cast=(GtkFileDialog *)
* @param folder cast=(GFile *)
*/
public static final native void gtk_file_dialog_set_initial_folder(long self, long folder);

/* GtkScrolledWindow */
public static final native long gtk_scrolled_window_new();
/** @param scrolled_window cast=(GtkScrolledWindow *) */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2020 Red Hat Inc. and others.
* Copyright (c) 2020, 2024 Red Hat Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -14,7 +14,9 @@
package org.eclipse.swt.internal;

import java.lang.reflect.*;
import java.util.function.*;

import org.eclipse.swt.*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this unused import.

import org.eclipse.swt.internal.gtk.*;
import org.eclipse.swt.widgets.*;

Expand All @@ -28,6 +30,41 @@
public class SyncDialogUtil {
static int responseID;
static Callback dialogResponseCallback;
static Function<Long, Long> dialogAsyncFinish;
static Long dialogAsyncValue;

/**
* This method implements the {@code AsyncReadyCallback} mechanism that is
* used in GTK4. Most operations within GTK4 are executed asynchronously,
* where the user is given the option to respond to the completion of such
* an operation via a callback method, in order to e.g. process the result
* or to apply additional cleanup tasks.<br>
* When calling this method, the asynchronous operation is initiated via the
* {code asyncOpen} parameter. Callers have to ensure that the callback
* address is used as argument for the {@code AsyncReadyCallback} parameter.
* From within the callback routine, the {@code asyncFinish} function is
* called, receiving the {@code AsyncResult} of the callback as argument and
* returning the {@code long} value of the callback function.<br>
* This method blocks until the callback method has been called. It is
* therefore essential that callers use the address of the {@link Callback}
* as address for the {@code AsyncReadyCallback} object.
*/
static public long run(Display display, Consumer<Long> asyncOpen, Function<Long, Long> asyncFinish) {
initializeResponseCallback();

dialogAsyncFinish = asyncFinish;
asyncOpen.accept(dialogResponseCallback.getAddress());

while (!display.isDisposed()) {
if (dialogAsyncValue != null) {
break;
}
display.readAndDispatch();
}

disposeResponseCallback();
return dialogAsyncValue;
}

/**
* A blocking call that waits for the handling of the signal before returning
Expand All @@ -53,21 +90,23 @@ static public int run(Display display, long handle, boolean isNativeDialog) {
}

disposeResponseCallback();
return responseID;
return (int) responseID;
}

/**
* 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.
*/
static void initializeResponseCallback() {
dialogResponseCallback = new Callback(SyncDialogUtil.class, "dialogResponseProc", void.class, new Type[] {long.class, int.class, long.class});
dialogResponseCallback = new Callback(SyncDialogUtil.class, "dialogResponseProc", void.class, new Type[] {long.class, long.class, long.class});
dialogAsyncValue = null;
responseID = -1;
}

static void disposeResponseCallback() {
dialogResponseCallback.dispose();
dialogResponseCallback = null;
dialogAsyncFinish = null;
}

/**
Expand All @@ -77,7 +116,10 @@ static void disposeResponseCallback() {
*
* Note: Native dialogs are platform dialogs that don't use GtkDialog or GtkWindow.
*/
static void dialogResponseProc(long dialog, int response_id, long user_data) {
responseID = response_id;
static void dialogResponseProc(long dialog, long response_id, long user_data) {
if (dialogAsyncFinish != null) {
dialogAsyncValue = dialogAsyncFinish.apply(response_id);
}
responseID = (int) response_id;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -165,8 +165,12 @@ Optional<String> openNativeChooserDialog () {
byte [] titleBytes = Converter.wcsToMbcs (title, true);
long shellHandle = parent.topHandle ();
Display display = parent != null ? parent.getDisplay (): Display.getCurrent ();
long handle = 0;
handle = GTK.gtk_file_chooser_native_new(titleBytes, shellHandle, GTK.GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, null, null);
long handle;
if (GTK.GTK4) {
handle = GTK4.gtk_file_dialog_new();
} else {
handle = GTK.gtk_file_chooser_native_new(titleBytes, shellHandle, GTK.GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, null, null);
}
if (handle == 0) error (SWT.ERROR_NO_HANDLES);

if (filterPath != null && filterPath.length () > 0) {
Expand All @@ -186,7 +190,7 @@ Optional<String> openNativeChooserDialog () {
if (ptr != 0) {
if (GTK.GTK4) {
long file = OS.g_file_new_for_path(buffer);
GTK4.gtk_file_chooser_set_current_folder (handle, file, 0);
GTK4.gtk_file_dialog_set_initial_folder (handle, file);
OS.g_object_unref(file);
} else {
GTK3.gtk_file_chooser_set_current_folder (handle, ptr);
Expand All @@ -207,8 +211,12 @@ Optional<String> openNativeChooserDialog () {
}

int response;
long file = 0;
if (GTK.GTK4) {
response = SyncDialogUtil.run(display, handle, true);
file = SyncDialogUtil.run(display,
asyncCallback -> GTK4.gtk_file_dialog_select_folder(handle, shellHandle, 0, asyncCallback, 0),
asyncResult -> GTK4.gtk_file_dialog_select_folder_finish(handle, asyncResult, null));
response = file != 0 ? GTK.GTK_RESPONSE_ACCEPT : GTK.GTK_RESPONSE_CANCEL;
} else {
display.externalEventLoop = true;
display.sendPreExternalEventDispatchEvent ();
Expand All @@ -223,7 +231,6 @@ Optional<String> openNativeChooserDialog () {
if (response == GTK.GTK_RESPONSE_ACCEPT) {
long path;
if (GTK.GTK4) {
long file = GTK4.gtk_file_chooser_get_file (handle);
path = OS.g_file_get_path(file);
} else {
path = GTK3.gtk_file_chooser_get_filename (handle);
Expand Down
Loading