wip: Add async api to choose a file

This is an experiment to replace explicit use
of chooser dialogs with an async API.
This commit is contained in:
Matthias Clasen
2022-10-22 23:52:23 -04:00
parent d0af6f812d
commit 951773452a
2 changed files with 165 additions and 0 deletions

View File

@@ -183,6 +183,34 @@ GDK_AVAILABLE_IN_ALL
const char * gtk_file_chooser_get_choice (GtkFileChooser *chooser,
const char *id);
typedef void (*GtkFileChooserPrepareCallback) (GtkFileChooser *chooser,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_file (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
void gtk_choose_file_full (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GtkFileChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
gboolean gtk_choose_file_finish (GtkFileChooser *chooser,
GAsyncResult *result,
GError **error);
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_H__ */

View File

@@ -735,3 +735,140 @@ gtk_file_chooser_dialog_new (const char *title,
return result;
}
static void
cancelled_cb (GCancellable *cancellable,
GtkDialog *dialog)
{
gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
}
static void
choose_response_cb (GtkDialog *dialog,
int response,
GTask *task)
{
GCancellable *cancellable = g_task_get_cancellable (task);
if (cancellable)
g_signal_handlers_disconnect_by_func (cancellable, cancelled_cb, dialog);
if (response == GTK_RESPONSE_OK)
g_task_return_boolean (task, TRUE);
else
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
g_object_unref (task);
gtk_window_destroy (GTK_WINDOW (dialog));
}
/**
* gtk_choose_file:
* @parent: (nullable): parent window
* @title: title for the font chooser
* @action: the action for the file chooser
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a file chooser to let the user
* pick a file.
*
* The @callback will be called when the dialog is closed.
* It should call [function@Gtk.choose_file_finish] to
* find out whether the operation was completed successfully,
* and use [class@Gtk.FileChooser] API to obtain the results.
*/
void
gtk_choose_file (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gtk_choose_file_full (parent, title, action, NULL, NULL, cancellable, callback, user_data);
}
/**
* gtk_choose_file_full:
* @parent: (nullable): parent window
* @title: title for the file chooser
* @action: the action for the file chooser
* @prepare: (nullable) (scope call): callback to set up the file chooser
* @prepare_data: (closure prepare): data to pass to @prepare
* @cancellable: (nullable): a `GCancellable` to cancel the operation
* @callback: (scope async): callback to call when the action is complete
* @user_data: (closure callback): data to pass to @callback
*
* This function presents a file chooser to let the user
* choose a file.
*
* In addition to [function@Gtk.choose_file], this function takes
* a @prepare callback that lets you set up the file chooser according
* to your needs.
*
* The @callback will be called when the dialog is closed.
* It should use [function@Gtk.choose_file_finish] to find
* out whether the operation was completed successfully,
* and use [class@Gtk.FileChooser] API to obtain the results.
*/
void
gtk_choose_file_full (GtkWindow *parent,
const char *title,
GtkFileChooserAction action,
GtkFileChooserPrepareCallback prepare,
gpointer prepare_data,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GtkWidget *dialog;
GTask *task;
const char *button[] = {
N_("_Open"),
N_("_Save"),
N_("_Select")
};
dialog = gtk_file_chooser_dialog_new (title, parent, action,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_(button[action]), GTK_RESPONSE_OK,
NULL);
if (prepare)
prepare (GTK_FILE_CHOOSER (dialog), prepare);
if (cancellable)
g_signal_connect (cancellable, "cancelled", G_CALLBACK (cancelled_cb), dialog);
task = g_task_new (dialog, cancellable, callback, user_data);
g_task_set_source_tag (task, gtk_choose_file_full);
g_signal_connect (dialog, "response", G_CALLBACK (choose_response_cb), task);
gtk_window_present (GTK_WINDOW (dialog));
}
/**
* gtk_choose_file_finish:
* @chooser: the `GtkFileChooser`
* @result: `GAsyncResult` that was passed to @callback
* @error: return location for an error
*
* Finishes a gtk_choose_file() or gtk_choose_file_full() call
* and returns whether the operation was successful.
*
* If this function returns `TRUE`, you can use
* [class@Gtk.FileChooser] API to get the results.
*
* Returns: `TRUE` if the operation was successful
*/
gboolean
gtk_choose_file_finish (GtkFileChooser *chooser,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}