From b58ef290dce00f278c6f4e8da1a4013e55d4028d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 12:23:12 -0500 Subject: [PATCH 1/6] filelauncher: Plug a memory leak Oops --- gtk/gtkfilelauncher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gtk/gtkfilelauncher.c b/gtk/gtkfilelauncher.c index 0b433595b1..b68e0fc14e 100644 --- a/gtk/gtkfilelauncher.c +++ b/gtk/gtkfilelauncher.c @@ -70,7 +70,9 @@ gtk_file_launcher_init (GtkFileLauncher *self) static void gtk_file_launcher_finalize (GObject *object) { - //GtkFileLauncher *self = GTK_FILE_LAUNCHER (object); + GtkFileLauncher *self = GTK_FILE_LAUNCHER (object); + + g_clear_object (&self->file); G_OBJECT_CLASS (gtk_file_launcher_parent_class)->finalize (object); } From 0c1c0524c71c59afebfe9e0579e2d120de3ebaea Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 12:10:26 -0500 Subject: [PATCH 2/6] openuri: Some reshuffling This is in preparation of adding a method that takes a uri instead of a GFile. --- gtk/gopenuriportal.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gtk/gopenuriportal.c b/gtk/gopenuriportal.c index 834d8655a5..309725a7f5 100644 --- a/gtk/gopenuriportal.c +++ b/gtk/gopenuriportal.c @@ -258,14 +258,13 @@ canceled (GCancellable *cancellable, } static void -open_uri (GFile *file, - gboolean open_folder, +open_uri (OpenUriData *data, const char *parent_window, const char *activation_token, - GAsyncReadyCallback callback, - gpointer user_data) + GAsyncReadyCallback callback) { - OpenUriData *data = user_data; + GFile *file = data->file; + gboolean open_folder = data->open_folder; GTask *task; GVariant *opts = NULL; int i; @@ -277,9 +276,9 @@ open_uri (GFile *file, connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri)); data->connection = g_object_ref (connection); - task = g_task_new (NULL, NULL, callback, user_data); + task = g_task_new (NULL, NULL, callback, data); g_task_set_check_cancellable (task, FALSE); - g_task_set_task_data (task, user_data, NULL); + g_task_set_task_data (task, data, NULL); if (data->cancellable) data->cancel_handler = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (canceled), task); @@ -431,7 +430,7 @@ window_handle_exported (GtkWindow *window, activation_token = G_APP_LAUNCH_CONTEXT_GET_CLASS (context)->get_startup_notify_id (context, NULL, NULL); g_object_unref (context); - open_uri (data->file, data->open_folder, handle, activation_token, open_uri_done, data); + open_uri (data, handle, activation_token, open_uri_done); g_free (activation_token); } From 4b404f0dea345e5098cea0b2eecaffcbbf1af701 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 12:19:18 -0500 Subject: [PATCH 3/6] Add g_openuri_portal_open_uri_async This avoids a roundtrip through GFile and thus works with random uri schemes. --- gtk/gopenuriportal.c | 51 +++++++++++++++++++++++++++++++++++++++++--- gtk/gopenuriportal.h | 9 ++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/gtk/gopenuriportal.c b/gtk/gopenuriportal.c index 309725a7f5..bc3211eb3d 100644 --- a/gtk/gopenuriportal.c +++ b/gtk/gopenuriportal.c @@ -103,6 +103,7 @@ enum { typedef struct { GtkWindow *parent; GFile *file; + char *uri; gboolean open_folder; GDBusConnection *connection; GCancellable *cancellable; @@ -125,6 +126,7 @@ open_uri_data_free (OpenUriData *data) gtk_window_unexport_handle (data->parent); g_clear_object (&data->parent); g_clear_object (&data->file); + g_free (data->uri); g_clear_object (&data->cancellable); g_clear_object (&data->task); g_free (data->handle); @@ -311,7 +313,7 @@ open_uri (OpenUriData *data, opts = g_variant_builder_end (&opt_builder); - if (g_file_is_native (file)) + if (file && g_file_is_native (file)) { const char *path = NULL; GUnixFDList *fd_list = NULL; @@ -365,12 +367,15 @@ open_uri (OpenUriData *data, } else { - char *uri = g_file_get_uri (file); + char *uri = NULL; + + if (file) + uri = g_file_get_uri (file); data->call = OPEN_URI; gxdp_open_uri_call_open_uri (openuri, parent_window ? parent_window : "", - uri, + uri ? uri : data->uri, opts, NULL, open_call_done, @@ -470,5 +475,45 @@ gboolean g_openuri_portal_open_finish (GAsyncResult *result, GError **error) { + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_async, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +void +g_openuri_portal_open_uri_async (const char *uri, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OpenUriData *data; + + if (!init_openuri_portal ()) + { + g_task_report_new_error (NULL, callback, user_data, NULL, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, + "The OpenURI portal is not available"); + return; + } + + data = g_new0 (OpenUriData, 1); + data->parent = parent ? g_object_ref (parent) : NULL; + data->uri = g_strdup (uri); + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + data->task = g_task_new (parent, cancellable, callback, user_data); + g_task_set_check_cancellable (data->task, FALSE); + g_task_set_source_tag (data->task, g_openuri_portal_open_uri_async); + + if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data)) + window_handle_exported (parent, NULL, data); +} + +gboolean +g_openuri_portal_open_uri_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_uri_async, FALSE); + return g_task_propagate_boolean (G_TASK (result), error); } diff --git a/gtk/gopenuriportal.h b/gtk/gopenuriportal.h index cd3992f6c2..047a9f3896 100644 --- a/gtk/gopenuriportal.h +++ b/gtk/gopenuriportal.h @@ -38,6 +38,15 @@ void g_openuri_portal_open_async (GFile *file, gboolean g_openuri_portal_open_finish (GAsyncResult *result, GError **error); +void g_openuri_portal_open_uri_async (const char *uri, + GtkWindow *window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean g_openuri_portal_open_uri_finish (GAsyncResult *result, + GError **error); + G_END_DECLS #endif From 3080cb7acd52e62a15e9a42193dc74fad00050fa Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 12:22:51 -0500 Subject: [PATCH 4/6] Add GtkUriLauncher --- gtk/gtk.h | 1 + gtk/gtkurilauncher.c | 337 +++++++++++++++++++++++++++++++++++++++++++ gtk/gtkurilauncher.h | 57 ++++++++ gtk/meson.build | 2 + 4 files changed, 397 insertions(+) create mode 100644 gtk/gtkurilauncher.c create mode 100644 gtk/gtkurilauncher.h diff --git a/gtk/gtk.h b/gtk/gtk.h index e07a3f6605..ccb9c98fa3 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -286,6 +286,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkurilauncher.c b/gtk/gtkurilauncher.c new file mode 100644 index 0000000000..e5bb51f697 --- /dev/null +++ b/gtk/gtkurilauncher.c @@ -0,0 +1,337 @@ +/* + * GTK - The GIMP Toolkit + * Copyright (C) 2022 Red Hat, Inc. + * All rights reserved. + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkurilauncher.h" + +#include "gtkdialogerror.h" +#include "gopenuriportal.h" +#include "deprecated/gtkshow.h" +#include + +/** + * GtkUriLauncher: + * + * A `GtkUriLauncher` object collects the arguments that are needed to open a uri + * with an application. + * + * Depending on system configuration, user preferences and available APIs, this + * may or may not show an app chooser dialog or launch the default application + * right away. + * + * The operation is started with the [method@Gtk.UriLauncher.launch] function. + * This API follows the GIO async pattern, and the result can be obtained by + * calling [method@Gtk.UriLauncher.launch_finish]. + * + * Since: 4.10 + */ + +/* {{{ GObject implementation */ + +struct _GtkUriLauncher +{ + GObject parent_instance; + + char *uri; +}; + +enum { + PROP_URI = 1, + + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +G_DEFINE_TYPE (GtkUriLauncher, gtk_uri_launcher, G_TYPE_OBJECT) + +static void +gtk_uri_launcher_init (GtkUriLauncher *self) +{ +} + +static void +gtk_uri_launcher_finalize (GObject *object) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + g_free (self->uri); + + G_OBJECT_CLASS (gtk_uri_launcher_parent_class)->finalize (object); +} + +static void +gtk_uri_launcher_get_property (GObject *object, + unsigned int property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + switch (property_id) + { + case PROP_URI: + g_value_set_string (value, self->uri); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_uri_launcher_set_property (GObject *object, + unsigned int property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + switch (property_id) + { + case PROP_URI: + gtk_uri_launcher_set_uri (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_uri_launcher_class_init (GtkUriLauncherClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gtk_uri_launcher_finalize; + object_class->get_property = gtk_uri_launcher_get_property; + object_class->set_property = gtk_uri_launcher_set_property; + + /** + * GtkUriLauncher:uri: (attributes org.gtk.Property.get=gtk_uri_launcher_get_uri org.gtk.Property.set=gtk_uri_launcher_set_uri) + * + * The uri to launch. + * + * Since: 4.10 + */ + properties[PROP_URI] = + g_param_spec_string ("uri", NULL, NULL, + NULL, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +/* }}} */ +/* {{{ API: Constructor */ + +/** + * gtk_uri_launcher_new: + * @uri: (nullable): the uri to open + * + * Creates a new `GtkUriLauncher` object. + * + * Returns: the new `GtkUriLauncher` + * + * Since: 4.10 + */ +GtkUriLauncher * +gtk_uri_launcher_new (const char *uri) +{ + return g_object_new (GTK_TYPE_URI_LAUNCHER, + "uri", uri, + NULL); +} + + /* }}} */ +/* {{{ API: Getters and setters */ + +/** + * gtk_uri_launcher_get_uri: + * @self: a `GtkUriLauncher` + * + * Gets the uri that will be opened. + * + * Returns: (transfer none) (nullable): the uri + * + * Since: 4.10 + */ +const char * +gtk_uri_launcher_get_uri (GtkUriLauncher *self) +{ + g_return_val_if_fail (GTK_IS_URI_LAUNCHER (self), NULL); + + return self->uri; +} + +/** + * gtk_uri_launcher_set_uri: + * @self: a `GtkUriLauncher` + * @uri: (nullable): the uri + * + * Sets the uri that will be opened. + * + * Since: 4.10 + */ +void +gtk_uri_launcher_set_uri (GtkUriLauncher *self, + const char *uri) +{ + g_return_if_fail (GTK_IS_URI_LAUNCHER (self)); + + if (g_strcmp0 (self->uri, uri) == 0) + return; + + g_free (self->uri); + self->uri = g_strdup (uri); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_URI]); +} + +/* }}} */ +/* {{{ Async implementation */ + +#ifndef G_OS_WIN32 +static void +open_done (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GTask *task = G_TASK (data); + GError *error = NULL; + + if (!g_openuri_portal_open_finish (result, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} +#endif + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +static void +show_uri_done (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GtkWindow *parent = GTK_WINDOW (source); + GTask *task = G_TASK (data); + GError *error = NULL; + + if (!gtk_show_uri_full_finish (parent, result, &error)) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, "Cancelled by user"); + else + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, "%s", error->message); + g_error_free (error); + } + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} +G_GNUC_END_IGNORE_DEPRECATIONS + + /* }}} */ +/* {{{ Async API */ + +/** + * gtk_uri_launcher_launch: + * @self: a `GtkUriLauncher` + * @parent: (nullable): the parent `GtkWindow` + * @cancellable: (nullable): a `GCancellable` to cancel the operation + * @callback: (scope async): a callback to call when the operation is complete + * @user_data: (closure callback): data to pass to @callback + * + * Launch an application to open the uri. + * + * This may present an app chooser dialog to the user. + * + * The @callback will be called when the operation is completed. + * It should call [method@Gtk.UriLauncher.launch_finish] to obtain + * the result. + * + * Since: 4.10 + */ +void +gtk_uri_launcher_launch (GtkUriLauncher *self, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + g_return_if_fail (GTK_IS_URI_LAUNCHER (self)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_check_cancellable (task, FALSE); + g_task_set_source_tag (task, gtk_uri_launcher_launch); + + if (self->uri == NULL) + { + g_task_return_new_error (task, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, + "No uri to launch"); + return; + } + +#ifndef G_OS_WIN32 + if (g_openuri_portal_is_available ()) + g_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task); + else +#endif +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_show_uri_full (parent, self->uri, GDK_CURRENT_TIME, cancellable, show_uri_done, task); +G_GNUC_END_IGNORE_DEPRECATIONS +} + +/** + * gtk_uri_launcher_launch_finish: + * @self: a `GtkUriLauncher` + * @result: a `GAsyncResult` + * @error: return location for a [enum@Gtk.DialogError] or [enum@Gio.Error] error + * + * Finishes the [method@Gtk.UriLauncher.launch] call and + * returns the result. + * + * Returns: `TRUE` if an application was launched, + * or `FALSE` and @error is set + * + * Since: 4.10 + */ +gboolean +gtk_uri_launcher_launch_finish (GtkUriLauncher *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (GTK_IS_URI_LAUNCHER (self), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_uri_launcher_launch, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/* }}} */ +/* vim:set foldmethod=marker expandtab: */ diff --git a/gtk/gtkurilauncher.h b/gtk/gtkurilauncher.h new file mode 100644 index 0000000000..1909ac1327 --- /dev/null +++ b/gtk/gtkurilauncher.h @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_URI_LAUNCHER (gtk_uri_launcher_get_type ()) + +GDK_AVAILABLE_IN_4_10 +G_DECLARE_FINAL_TYPE (GtkUriLauncher, gtk_uri_launcher, GTK, URI_LAUNCHER, GObject) + +GDK_AVAILABLE_IN_4_10 +GtkUriLauncher * gtk_uri_launcher_new (const char *uri); + +GDK_AVAILABLE_IN_4_10 +const char * gtk_uri_launcher_get_uri (GtkUriLauncher *self); +GDK_AVAILABLE_IN_4_10 +void gtk_uri_launcher_set_uri (GtkUriLauncher *self, + const char *uri); + +GDK_AVAILABLE_IN_4_10 +void gtk_uri_launcher_launch (GtkUriLauncher *self, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GDK_AVAILABLE_IN_4_10 +gboolean gtk_uri_launcher_launch_finish (GtkUriLauncher *self, + GAsyncResult *result, + GError **error); + + +G_END_DECLS diff --git a/gtk/meson.build b/gtk/meson.build index 7ac245419a..13d2404630 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -390,6 +390,7 @@ gtk_public_sources = files([ 'gtktreeexpander.c', 'gtktreelistmodel.c', 'gtktreelistrowsorter.c', + 'gtkurilauncher.c', 'gtkversion.c', 'gtkvideo.c', 'gtkviewport.c', @@ -615,6 +616,7 @@ gtk_public_headers = files([ 'gtktreelistmodel.h', 'gtktreelistrowsorter.h', 'gtktypes.h', + 'gtkurilauncher.h', 'gtkvideo.h', 'gtkviewport.h', 'gtkvolumebutton.h', From 7aba9e3295e2125ae9fade1352b23ffc012369fa Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 14:00:39 -0500 Subject: [PATCH 5/6] urilauncher: Add cross-references to the docs --- gtk/gtkfilelauncher.c | 6 ++++-- gtk/gtkurilauncher.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gtk/gtkfilelauncher.c b/gtk/gtkfilelauncher.c index b68e0fc14e..6e4f840876 100644 --- a/gtk/gtkfilelauncher.c +++ b/gtk/gtkfilelauncher.c @@ -29,8 +29,8 @@ /** * GtkFileLauncher: * - * A `GtkFileLauncher` object collects the arguments that are needed to open a uri - * with an application. + * A `GtkFileLauncher` object collects the arguments that are needed to open a + * file with an application. * * Depending on system configuration, user preferences and available APIs, this * may or may not show an app chooser dialog or launch the default application @@ -40,6 +40,8 @@ * This API follows the GIO async pattern, and the result can be obtained by * calling [method@Gtk.FileLauncher.launch_finish]. * + * To launch uris that don't represent files, use [class@Gtk.UriLauncher]. + * * Since: 4.10 */ diff --git a/gtk/gtkurilauncher.c b/gtk/gtkurilauncher.c index e5bb51f697..b2da466fc2 100644 --- a/gtk/gtkurilauncher.c +++ b/gtk/gtkurilauncher.c @@ -40,6 +40,8 @@ * This API follows the GIO async pattern, and the result can be obtained by * calling [method@Gtk.UriLauncher.launch_finish]. * + * To launch a file, use [class@Gtk.FileLauncher]. + * * Since: 4.10 */ From bf4b40f17e20dfc40dbb9045e265f29de6c20bdc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 14 Jan 2023 14:00:56 -0500 Subject: [PATCH 6/6] docs: Update deprecations for gtk_show_uri We have a better replacement now. --- docs/reference/gtk/migrating-4to5.md | 4 ++++ gtk/deprecated/gtkshow.c | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/reference/gtk/migrating-4to5.md b/docs/reference/gtk/migrating-4to5.md index a6bf2262d8..04a8b19c5f 100644 --- a/docs/reference/gtk/migrating-4to5.md +++ b/docs/reference/gtk/migrating-4to5.md @@ -105,3 +105,7 @@ retire it. If you need such a widget, it is relatively trivial to create one using a [class@Gtk.Revealer] with labels and buttons. Other libraries, such as libadwaita, may provide replacements as well. + +## gtk_show_uri is being replaced + +Instead of gtk_show_uri(), you should use GtkUriLauncher or GtkFileLauncher. diff --git a/gtk/deprecated/gtkshow.c b/gtk/deprecated/gtkshow.c index ff57a27550..cd37905cf0 100644 --- a/gtk/deprecated/gtkshow.c +++ b/gtk/deprecated/gtkshow.c @@ -99,7 +99,8 @@ window_handle_exported (GtkWindow *window, * This is the recommended call to be used as it passes information * necessary for sandbox helpers to parent their dialogs properly. * - * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch] instead + * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch] or + * [method@Gtk.UriLauncher.launch] instead */ void gtk_show_uri_full (GtkWindow *parent, @@ -147,7 +148,8 @@ gtk_show_uri_full (GtkWindow *parent, * Returns: %TRUE if the URI was shown successfully. * Otherwise, %FALSE is returned and @error is set * - * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch_finish] instead + * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch_finish] or + * [method@Gtk.UriLauncher.launch_finish] instead */ gboolean gtk_show_uri_full_finish (GtkWindow *parent, @@ -191,7 +193,8 @@ show_uri_done (GObject *object, * This function launches the default application for showing * a given uri, or shows an error dialog if that fails. * - * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch] instead + * Deprecated: 4.10: Use [method@Gtk.FileLauncher.launch] or + * [method@Gtk.UriLauncher.launch] instead */ void gtk_show_uri (GtkWindow *parent,