From 703f18ce660a6020ccc6164c6ac5e19b0d7f71db Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 11 Apr 2020 21:56:32 -0400 Subject: [PATCH 1/2] 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 From 432b741ab7d23fb7a95550e11d40cb3e045d09ff Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 11 Apr 2020 21:58:19 -0400 Subject: [PATCH 2/2] gtk: Port all users to the new gtk_show_uri() We were only handling the error in one place anyway. --- gtk/gtkaboutdialog.c | 29 +++-------------------------- gtk/gtkfilechooserwidget.c | 2 +- gtk/gtklabel.c | 9 ++------- gtk/gtklinkbutton.c | 18 +++--------------- gtk/gtkprintoperation-portal.c | 2 +- gtk/gtkprintoperation-unix.c | 2 +- 6 files changed, 11 insertions(+), 51 deletions(-) diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c index 577eb6e633..1c33631696 100644 --- a/gtk/gtkaboutdialog.c +++ b/gtk/gtkaboutdialog.c @@ -77,7 +77,7 @@ * All parts of the dialog are optional. * * About dialogs often contain links and email addresses. GtkAboutDialog - * displays these as clickable links. By default, it calls gtk_show_uri_on_window() + * displays these as clickable links. By default, it calls gtk_show_uri() * when a user clicks one. The behaviour can be overridden with the * #GtkAboutDialog::activate-link signal. * @@ -345,7 +345,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) * * The signal which gets emitted to activate a URI. * Applications may connect to it to override the default behaviour, - * which is to call gtk_show_uri_on_window(). + * which is to call gtk_show_uri(). * * Returns: %TRUE if the link has been activated */ @@ -979,30 +979,7 @@ static gboolean gtk_about_dialog_activate_link (GtkAboutDialog *about, const gchar *uri) { - GError *error = NULL; - - if (!gtk_show_uri_on_window (GTK_WINDOW (about), uri, GDK_CURRENT_TIME, &error)) - { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (about), - 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_error_free (error); - - 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 (GTK_WINDOW (about), uri, GDK_CURRENT_TIME); return TRUE; } diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index c7f6b34c31..05e9cbe75e 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -1502,7 +1502,7 @@ open_folder_cb (GSimpleAction *action, gchar *uri; uri = g_file_get_uri (file); - gtk_show_uri_on_window (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME, NULL); + gtk_show_uri (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME); g_free (uri); } diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 6f6efaec64..992bc9cc69 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -740,7 +740,7 @@ gtk_label_class_init (GtkLabelClass *class) * * The signal which gets emitted to activate a URI. * Applications may connect to it to override the default behaviour, - * which is to call gtk_show_uri_on_window(). + * which is to call gtk_show_uri(). * * Returns: %TRUE if the link has been activated */ @@ -5816,16 +5816,11 @@ gtk_label_activate_link (GtkLabel *label, { GtkWidget *widget = GTK_WIDGET (label); GtkWidget *toplevel = GTK_WIDGET (gtk_widget_get_root (widget)); - GError *error = NULL; if (!GTK_IS_WINDOW (toplevel)) return FALSE; - if (!gtk_show_uri_on_window (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME, &error)) - { - g_warning ("Unable to show '%s': %s", uri, error->message); - g_error_free (error); - } + gtk_show_uri (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME); return TRUE; } diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c index b99ae2a0d4..ee82086798 100644 --- a/gtk/gtklinkbutton.c +++ b/gtk/gtklinkbutton.c @@ -38,7 +38,7 @@ * The URI bound to a GtkLinkButton can be set specifically using * gtk_link_button_set_uri(), and retrieved using gtk_link_button_get_uri(). * - * By default, GtkLinkButton calls gtk_show_uri_on_window() when the button is + * By default, GtkLinkButton calls gtk_show_uri() when the button is * clicked. This behaviour can be overridden by connecting to the * #GtkLinkButton::activate-link signal and returning %TRUE from the * signal handler. @@ -209,7 +209,7 @@ gtk_link_button_class_init (GtkLinkButtonClass *klass) * The ::activate-link signal is emitted each time the #GtkLinkButton * has been clicked. * - * The default handler will call gtk_show_uri_on_window() with the URI stored inside + * The default handler will call gtk_show_uri() with the URI stored inside * the #GtkLinkButton:uri property. * * To override the default behavior, you can connect to the ::activate-link @@ -495,22 +495,10 @@ gtk_link_button_activate_link (GtkLinkButton *link_button) { GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button); GtkWidget *toplevel; - GError *error; toplevel = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (link_button))); - error = NULL; - gtk_show_uri_on_window (GTK_WINDOW (toplevel), priv->uri, GDK_CURRENT_TIME, &error); - if (error) - { - g_warning ("Unable to show '%s': %s", - priv->uri, - error->message); - g_error_free (error); - - return FALSE; - } - + gtk_show_uri (GTK_WINDOW (toplevel), priv->uri, GDK_CURRENT_TIME); gtk_link_button_set_visited (link_button, TRUE); return TRUE; diff --git a/gtk/gtkprintoperation-portal.c b/gtk/gtkprintoperation-portal.c index 93cb8724e2..eb155a78b6 100644 --- a/gtk/gtkprintoperation-portal.c +++ b/gtk/gtkprintoperation-portal.c @@ -672,6 +672,6 @@ gtk_print_operation_portal_launch_preview (GtkPrintOperation *op, char *uri; uri = g_filename_to_uri (filename, NULL, NULL); - gtk_show_uri_on_window (parent, uri, GDK_CURRENT_TIME, NULL); + gtk_show_uri (parent, uri, GDK_CURRENT_TIME); g_free (uri); } diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c index 16ca75cf1b..45584d28bd 100644 --- a/gtk/gtkprintoperation-unix.c +++ b/gtk/gtkprintoperation-unix.c @@ -312,7 +312,7 @@ gtk_print_operation_unix_launch_preview (GtkPrintOperation *op, g_error_free (error); error = NULL; uri = g_filename_to_uri (filename, NULL, NULL); - gtk_show_uri_on_window (parent, uri, GDK_CURRENT_TIME, &error); + gtk_show_uri (parent, uri, GDK_CURRENT_TIME); g_free (uri); }