From 703f18ce660a6020ccc6164c6ac5e19b0d7f71db Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 11 Apr 2020 21:56:32 -0400 Subject: [PATCH] Redo gtk_show_uri_on_window Make this a full async function, and add a simple wrapper. Call gtk_show_uri_full() if you need control over the results, and use gtk_show_uri() if you are fine with ignoring any errors. --- docs/reference/gtk/gtk4-sections.txt | 4 +- gtk/gtkshow.c | 190 +++++++++++++++++++++------ gtk/gtkshow.h | 20 ++- 3 files changed, 169 insertions(+), 45 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 338ea2b06a..7638136709 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -5105,7 +5105,9 @@ gtk_mount_operation_set_parent gtk_mount_operation_get_parent gtk_mount_operation_set_display gtk_mount_operation_get_display -gtk_show_uri_on_window +gtk_show_uri_full +gtk_show_uri_full_finish +gtk_show_uri GTK_IS_MOUNT_OPERATION GTK_IS_MOUNT_OPERATION_CLASS diff --git a/gtk/gtkshow.c b/gtk/gtkshow.c index ee9ae82cfb..2163b120a1 100644 --- a/gtk/gtkshow.c +++ b/gtk/gtkshow.c @@ -24,73 +24,102 @@ #include "gtkshow.h" #include "gtkwindowprivate.h" +#include "gtkmessagedialog.h" +#include "gtkintl.h" + +typedef struct { + GtkWindow *parent; + GAppLaunchContext *context; + char *uri; + GTask *task; +} GtkShowUriData; + +static void +gtk_show_uri_data_free (GtkShowUriData *data) +{ + if (data->parent) + gtk_window_unexport_handle (data->parent); + g_clear_object (&data->parent); + g_clear_object (&data->context); + g_free (data->uri); + g_clear_object (&data->task); + g_free (data); +} static void launch_uri_done (GObject *source, GAsyncResult *result, - gpointer data) + gpointer user_data) { - GtkWindow *window = data; + GtkShowUriData *data = user_data; + GError *error = NULL; - g_app_info_launch_default_for_uri_finish (result, NULL); + if (g_app_info_launch_default_for_uri_finish (result, &error)) + g_task_return_boolean (data->task, TRUE); + else + g_task_return_error (data->task, error); - if (window) - gtk_window_unexport_handle (window); + gtk_show_uri_data_free (data); } static void window_handle_exported (GtkWindow *window, - const char *handle_str, + const char *handle, gpointer user_data) { - GAppLaunchContext *context = user_data; - const char *uri; + GtkShowUriData *data = user_data; - uri = (const char *)g_object_get_data (G_OBJECT (context), "uri"); + if (handle) + g_app_launch_context_setenv (data->context, "PARENT_WINDOW_ID", handle); - g_app_launch_context_setenv (context, "PARENT_WINDOW_ID", handle_str); - - g_app_info_launch_default_for_uri_async (uri, G_APP_LAUNCH_CONTEXT (context), NULL, launch_uri_done, window); - - g_object_unref (context); + g_app_info_launch_default_for_uri_async (data->uri, + data->context, + g_task_get_cancellable (data->task), + launch_uri_done, + data); } /** - * gtk_show_uri_on_window: + * gtk_show_uri_full: * @parent: (allow-none): parent window * @uri: the uri to show - * @timestamp: a timestamp to prevent focus stealing - * @error: a #GError that is returned in case of errors + * @timestamp: timestamp from the event that triggered this call, or %GDK_CURRENT_TIME + * @cancellable: (allow-none): a #GCancellable to cancel the launch + * @callback (allow-none): a callback to call when the action is complete + * @user_data: data to pass to @callback + * @destroy: destroy notify for @user_data * - * This is a convenience function for launching the default application - * to show the uri. The uri must be of a form understood by GIO (i.e. you - * need to install gvfs to get support for uri schemes such as http:// + * This function launches the default application for showing + * a given uri. + * + * The uri must be of a form understood by GIO (i.e. you need + * to install gvfs to get support for uri schemes such as http:// * or ftp://, as only local files are handled by GIO itself). * Typical examples are * - `file:///home/gnome/pict.jpg` * - `http://www.gnome.org` * - `mailto:me@gnome.org` * - * Ideally the timestamp is taken from the event triggering - * the gtk_show_uri_on_window() call. If timestamp is not known you can take - * %GDK_CURRENT_TIME. + * The @callback will be called when the launch is completed. + * It should call gtk_show_uri_finish() to obtain the result. * * This is the recommended call to be used as it passes information * necessary for sandbox helpers to parent their dialogs properly. - * - * Returns: %TRUE on success, %FALSE on error */ -gboolean -gtk_show_uri_on_window (GtkWindow *parent, - const char *uri, - guint32 timestamp, - GError **error) +void +gtk_show_uri_full (GtkWindow *parent, + const char *uri, + guint32 timestamp, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GtkShowUriData *data; GdkAppLaunchContext *context; - gboolean ret; GdkDisplay *display; - g_return_val_if_fail (uri != NULL, FALSE); + g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent)); + g_return_if_fail (uri != NULL); if (parent) display = gtk_widget_get_display (GTK_WIDGET (parent)); @@ -100,13 +129,94 @@ gtk_show_uri_on_window (GtkWindow *parent, context = gdk_display_get_app_launch_context (display); gdk_app_launch_context_set_timestamp (context, timestamp); - g_object_set_data_full (G_OBJECT (context), "uri", g_strdup (uri), g_free); + data = g_new0 (GtkShowUriData, 1); + data->parent = parent ? g_object_ref (parent) : NULL; + data->context = G_APP_LAUNCH_CONTEXT (context); + data->uri = g_strdup (uri); + data->task = g_task_new (parent, cancellable, callback, user_data); + g_task_set_source_tag (data->task, gtk_show_uri); - if (parent && gtk_window_export_handle (parent, window_handle_exported, context)) - return TRUE; - - ret = g_app_info_launch_default_for_uri (uri, G_APP_LAUNCH_CONTEXT (context), error); - g_object_unref (context); - - return ret; + if (parent) + gtk_window_export_handle (parent, window_handle_exported, data); + else + window_handle_exported (parent, NULL, data); +} + +/** + * gtk_show_uri_full_finish: + * @parent: the #GtkWindow passed to gtk_show_uri() + * @result: #GASyncResult that was passed to @callback + * @error: return location for an error + * + * Finished the gtk_show_uri() call and returns the result + * of the operation. + * + * Returns: %TRUE if the URI was shown successfully. + * Otherwise, %FALSE is returned and @error is set + */ +gboolean +gtk_show_uri_full_finish (GtkWindow *parent, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE); + g_return_val_if_fail (g_task_is_valid (result, parent), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_show_uri, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +static void +show_uri_done (GObject *object, + GAsyncResult *result, + gpointer data) +{ + GtkWindow *parent = GTK_WINDOW (object); + GError *error = NULL; + + if (!gtk_show_uri_full_finish (parent, result, &error)) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_DESTROY_WITH_PARENT | + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", _("Could not show link")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), NULL); + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_window_present (GTK_WINDOW (dialog)); + G_GNUC_END_IGNORE_DEPRECATIONS + } +} + +/** + * gtk_show_uri: + * @parent: (allow-none): parent window + * @uri: the uri to show + * @timestamp: timestamp from the event that triggered this call, or %GDK_CURRENT_TIME + * + * This function launches the default application for showing + * a given uri, or shows an error dialog if that fails. + * + * The uri must be of a form understood by GIO (i.e. you need + * to install gvfs to get support for uri schemes such as http:// + * or ftp://, as only local files are handled by GIO itself). + * Typical examples are + * - `file:///home/gnome/pict.jpg` + * - `http://www.gnome.org` + * - `mailto:me@gnome.org` + */ +void +gtk_show_uri (GtkWindow *parent, + const char *uri, + guint32 timestamp) +{ + gtk_show_uri_full (parent, uri, timestamp, NULL, show_uri_done, NULL); } diff --git a/gtk/gtkshow.h b/gtk/gtkshow.h index ac187ff079..0c5cea6fba 100644 --- a/gtk/gtkshow.h +++ b/gtk/gtkshow.h @@ -30,10 +30,22 @@ G_BEGIN_DECLS GDK_AVAILABLE_IN_ALL -gboolean gtk_show_uri_on_window (GtkWindow *parent, - const char *uri, - guint32 timestamp, - GError **error); +void gtk_show_uri_full (GtkWindow *parent, + const char *uri, + guint32 timestamp, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GDK_AVAILABLE_IN_ALL +gboolean gtk_show_uri_full_finish (GtkWindow *parent, + GAsyncResult *result, + GError **error); + +GDK_AVAILABLE_IN_ALL +void gtk_show_uri (GtkWindow *parent, + const char *uri, + guint32 timestamp); G_END_DECLS