From 6ee0389f6879222e1bb9aab55a118eb27f13d7f9 Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Fri, 16 Feb 2024 10:43:25 +0100 Subject: [PATCH 1/3] gopenuriportal: Rename functions and switch to GFile as argument We want to add the support for the activation token, to get it we use `g_app_launch_context_get_startup_notify_id` which takes a list of files, so that we don't have to create a GFile twice simply change the signature of the functions. Fortunately this isn't a public API. --- gio/gappinfo.c | 21 ++++++++++++++------- gio/gopenuriportal.c | 38 ++++++++++++++++++++------------------ gio/gopenuriportal.h | 20 ++++++++++---------- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/gio/gappinfo.c b/gio/gappinfo.c index c54fc677b..c6c92283b 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -1203,6 +1203,7 @@ g_app_info_launch_default_for_uri (const char *uri, #ifdef G_OS_UNIX if (!res && glib_should_use_portal ()) { + GFile *file = NULL; const char *parent_window = NULL; /* Reset any error previously set by launch_default_for_uri */ @@ -1211,7 +1212,9 @@ g_app_info_launch_default_for_uri (const char *uri, if (launch_context && launch_context->priv->envp) parent_window = g_environ_getenv (launch_context->priv->envp, "PARENT_WINDOW_ID"); - return g_openuri_portal_open_uri (uri, parent_window, error); + file = g_file_new_for_uri (uri); + res = g_openuri_portal_open_file (file, parent_window, error); + g_object_unref (file); } #endif @@ -1241,7 +1244,7 @@ launch_default_for_uri_portal_open_uri_cb (GObject *object, GTask *task = G_TASK (user_data); GError *error = NULL; - if (g_openuri_portal_open_uri_finish (result, &error)) + if (g_openuri_portal_open_file_finish (result, &error)) g_task_return_boolean (task, TRUE); else g_task_return_error (task, g_steal_pointer (&error)); @@ -1258,6 +1261,7 @@ launch_default_for_uri_portal_open_uri (GTask *task, GError *error) if (glib_should_use_portal ()) { + GFile *file; const char *parent_window = NULL; /* Reset any error previously set by launch_default_for_uri */ @@ -1267,11 +1271,14 @@ launch_default_for_uri_portal_open_uri (GTask *task, GError *error) parent_window = g_environ_getenv (data->context->priv->envp, "PARENT_WINDOW_ID"); - g_openuri_portal_open_uri_async (data->uri, - parent_window, - cancellable, - launch_default_for_uri_portal_open_uri_cb, - g_steal_pointer (&task)); + file = g_file_new_for_uri (data->uri); + g_openuri_portal_open_file_async (file, + parent_window, + cancellable, + launch_default_for_uri_portal_open_uri_cb, + g_steal_pointer (&task)); + g_object_unref (file); + return; } #endif diff --git a/gio/gopenuriportal.c b/gio/gopenuriportal.c index 083d27132..019752280 100644 --- a/gio/gopenuriportal.c +++ b/gio/gopenuriportal.c @@ -80,11 +80,10 @@ init_openuri_portal (void) } gboolean -g_openuri_portal_open_uri (const char *uri, - const char *parent_window, - GError **error) +g_openuri_portal_open_file (GFile *file, + const char *parent_window, + GError **error) { - GFile *file = NULL; GVariantBuilder opt_builder; gboolean res; @@ -97,7 +96,6 @@ g_openuri_portal_open_uri (const char *uri, g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT); - file = g_file_new_for_uri (uri); if (g_file_is_native (file)) { char *path = NULL; @@ -138,6 +136,10 @@ g_openuri_portal_open_uri (const char *uri, } else { + char *uri = NULL; + + uri = g_file_get_uri (file); + res = gxdp_open_uri_call_open_uri_sync (openuri, parent_window ? parent_window : "", uri, @@ -145,10 +147,9 @@ g_openuri_portal_open_uri (const char *uri, NULL, NULL, error); + g_free (uri); } - g_object_unref (file); - return res; } @@ -245,15 +246,14 @@ open_call_done (GObject *source, } void -g_openuri_portal_open_uri_async (const char *uri, - const char *parent_window, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +g_openuri_portal_open_file_async (GFile *file, + const char *parent_window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GDBusConnection *connection; GTask *task; - GFile *file; GVariant *opts = NULL; int i; guint signal_id; @@ -308,7 +308,6 @@ g_openuri_portal_open_uri_async (const char *uri, else task = NULL; - file = g_file_new_for_uri (uri); if (g_file_is_native (file)) { char *path = NULL; @@ -349,6 +348,10 @@ g_openuri_portal_open_uri_async (const char *uri, } else { + char *uri = NULL; + + uri = g_file_get_uri (file); + gxdp_open_uri_call_open_uri (openuri, parent_window ? parent_window : "", uri, @@ -356,14 +359,13 @@ g_openuri_portal_open_uri_async (const char *uri, cancellable, task ? open_call_done : NULL, task); + g_free (uri); } - - g_object_unref (file); } gboolean -g_openuri_portal_open_uri_finish (GAsyncResult *result, - GError **error) +g_openuri_portal_open_file_finish (GAsyncResult *result, + GError **error) { return g_task_propagate_boolean (G_TASK (result), error); } diff --git a/gio/gopenuriportal.h b/gio/gopenuriportal.h index 6cf8b15a3..c32bddd44 100644 --- a/gio/gopenuriportal.h +++ b/gio/gopenuriportal.h @@ -25,18 +25,18 @@ G_BEGIN_DECLS -gboolean g_openuri_portal_open_uri (const char *uri, - const char *parent_window, - GError **error); +gboolean g_openuri_portal_open_file (GFile *file, + const char *parent_window, + GError **error); -void g_openuri_portal_open_uri_async (const char *uri, - const char *parent_window, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void g_openuri_portal_open_file_async (GFile *file, + const char *parent_window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); -gboolean g_openuri_portal_open_uri_finish (GAsyncResult *result, - GError **error); +gboolean g_openuri_portal_open_file_finish (GAsyncResult *result, + GError **error); G_END_DECLS From 6210708f050d389e83d921b9e5c09db1a988d510 Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Mon, 22 Jul 2024 14:24:22 +0200 Subject: [PATCH 2/3] gappinfo: Allow giving no GAppInfo for getting startup notify id On Wayland the activation token returned by `g_app_launch_context_get_startup_notify_id()` doesn't depend on the `GAppInfo`. The token is only used to hand over focus to the application that is launched. In some cases it's not even possible to know what application will actually be used to open the files. For example when using portals within a sandbox. Therefore, allow providing no `GAppInfo`. This also makes clear in the docs that the `files` argument can be `NULL`. --- gio/gappinfo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gio/gappinfo.c b/gio/gappinfo.c index c6c92283b..2b7e5a5eb 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -1782,8 +1782,8 @@ g_app_launch_context_get_display (GAppLaunchContext *context, /** * g_app_launch_context_get_startup_notify_id: * @context: the launch context - * @info: the app info - * @files: (element-type GFile): list of [iface@Gio.File] objects + * @info: (nullable): the app info + * @files: (nullable): (element-type GFile): a list of [iface@Gio.File] objects * * Initiates startup notification for the application and returns the * `XDG_ACTIVATION_TOKEN` or `DESKTOP_STARTUP_ID` for the launched operation, @@ -1798,6 +1798,7 @@ g_app_launch_context_get_display (GAppLaunchContext *context, * [freedesktop.org Startup Notification Protocol](http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt). * * Support for the XDG Activation Protocol was added in GLib 2.76. + * Since GLib 2.82 @info and @files can be `NULL`, but if it's not supported the returned token may be `NULL`. * * Returns: (nullable): a startup notification ID for the application, or `NULL` if * not supported. @@ -1810,7 +1811,7 @@ g_app_launch_context_get_startup_notify_id (GAppLaunchContext *context, GAppLaunchContextClass *class; g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL); - g_return_val_if_fail (G_IS_APP_INFO (info), NULL); + g_return_val_if_fail (info == NULL || G_IS_APP_INFO (info), NULL); class = G_APP_LAUNCH_CONTEXT_GET_CLASS (context); From 23b858a3def2b510c285e8b272cc3eaf8b9df923 Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Fri, 16 Feb 2024 11:19:56 +0100 Subject: [PATCH 3/3] gappinfo: Pass activation token from launch context to open_uri/file portal The `activation_token` option was added to the portal in v4, so let's actually pass a activation token if we have one. Fixes: https://gitlab.gnome.org/GNOME/glib/-/issues/2868 --- gio/gappinfo.c | 54 ++++++++++++++++++++++++++++++++++++-------- gio/gopenuriportal.c | 12 ++++++++++ gio/gopenuriportal.h | 2 ++ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/gio/gappinfo.c b/gio/gappinfo.c index 2b7e5a5eb..65a5735df 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -25,6 +25,7 @@ #include "gappinfo.h" #include "gappinfoprivate.h" #include "gcontextspecificgroup.h" +#include "gdesktopappinfo.h" #include "gtask.h" #include "gcancellable.h" @@ -1205,16 +1206,32 @@ g_app_info_launch_default_for_uri (const char *uri, { GFile *file = NULL; const char *parent_window = NULL; + char *startup_id = NULL; /* Reset any error previously set by launch_default_for_uri */ g_clear_error (error); - if (launch_context && launch_context->priv->envp) - parent_window = g_environ_getenv (launch_context->priv->envp, "PARENT_WINDOW_ID"); - file = g_file_new_for_uri (uri); - res = g_openuri_portal_open_file (file, parent_window, error); + + if (launch_context) + { + GList *file_list; + + if (launch_context->priv->envp) + parent_window = g_environ_getenv (launch_context->priv->envp, "PARENT_WINDOW_ID"); + + file_list = g_list_prepend (NULL, file); + + startup_id = g_app_launch_context_get_startup_notify_id (launch_context, + NULL, + file_list); + g_list_free (file_list); + } + + res = g_openuri_portal_open_file (file, parent_window, startup_id, error); + g_object_unref (file); + g_free (startup_id); } #endif @@ -1263,21 +1280,37 @@ launch_default_for_uri_portal_open_uri (GTask *task, GError *error) { GFile *file; const char *parent_window = NULL; + char *startup_id = NULL; /* Reset any error previously set by launch_default_for_uri */ g_error_free (error); - if (data->context && data->context->priv->envp) - parent_window = g_environ_getenv (data->context->priv->envp, - "PARENT_WINDOW_ID"); - file = g_file_new_for_uri (data->uri); + + if (data->context) + { + GList *file_list; + + if (data->context->priv->envp) + parent_window = g_environ_getenv (data->context->priv->envp, + "PARENT_WINDOW_ID"); + + file_list = g_list_prepend (NULL, file); + + startup_id = g_app_launch_context_get_startup_notify_id (data->context, + NULL, + file_list); + g_list_free (file_list); + } + g_openuri_portal_open_file_async (file, parent_window, + startup_id, cancellable, launch_default_for_uri_portal_open_uri_cb, g_steal_pointer (&task)); g_object_unref (file); + g_free (startup_id); return; } @@ -1783,7 +1816,7 @@ g_app_launch_context_get_display (GAppLaunchContext *context, * g_app_launch_context_get_startup_notify_id: * @context: the launch context * @info: (nullable): the app info - * @files: (nullable): (element-type GFile): a list of [iface@Gio.File] objects + * @files: (nullable) (element-type GFile): a list of [iface@Gio.File] objects * * Initiates startup notification for the application and returns the * `XDG_ACTIVATION_TOKEN` or `DESKTOP_STARTUP_ID` for the launched operation, @@ -1798,7 +1831,8 @@ g_app_launch_context_get_display (GAppLaunchContext *context, * [freedesktop.org Startup Notification Protocol](http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt). * * Support for the XDG Activation Protocol was added in GLib 2.76. - * Since GLib 2.82 @info and @files can be `NULL`, but if it's not supported the returned token may be `NULL`. + * Since GLib 2.82 @info and @files can be `NULL`. If that’s not supported by the backend, + * the returned token will be `NULL`. * * Returns: (nullable): a startup notification ID for the application, or `NULL` if * not supported. diff --git a/gio/gopenuriportal.c b/gio/gopenuriportal.c index 019752280..631d9cfc7 100644 --- a/gio/gopenuriportal.c +++ b/gio/gopenuriportal.c @@ -82,6 +82,7 @@ init_openuri_portal (void) gboolean g_openuri_portal_open_file (GFile *file, const char *parent_window, + const char *startup_id, GError **error) { GVariantBuilder opt_builder; @@ -96,6 +97,11 @@ g_openuri_portal_open_file (GFile *file, g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT); + if (startup_id) + g_variant_builder_add (&opt_builder, "{sv}", + "activation_token", + g_variant_new_string (startup_id)); + if (g_file_is_native (file)) { char *path = NULL; @@ -248,6 +254,7 @@ open_call_done (GObject *source, void g_openuri_portal_open_file_async (GFile *file, const char *parent_window, + const char *startup_id, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -303,6 +310,11 @@ g_openuri_portal_open_file_async (GFile *file, g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token)); g_free (token); + if (startup_id) + g_variant_builder_add (&opt_builder, "{sv}", + "activation_token", + g_variant_new_string (startup_id)); + opts = g_variant_builder_end (&opt_builder); } else diff --git a/gio/gopenuriportal.h b/gio/gopenuriportal.h index c32bddd44..69bb4ce68 100644 --- a/gio/gopenuriportal.h +++ b/gio/gopenuriportal.h @@ -27,10 +27,12 @@ G_BEGIN_DECLS gboolean g_openuri_portal_open_file (GFile *file, const char *parent_window, + const char *startup_id, GError **error); void g_openuri_portal_open_file_async (GFile *file, const char *parent_window, + const char *startup_id, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);