gio/gdesktopappinfo: Also use document portal for desktop file snaps

When a snap is launched from its non-dbus-activable desktop file we may
still need to use the portal to pass the URIs to the program, so that it
can access to them even if confined.

In fact most snaps are not dbus-activable, but they rely on the classic
desktop file activation.
This commit is contained in:
Marco Trevisan (Treviño)
2025-09-20 05:55:53 +02:00
parent 29fdcec8f3
commit bc35a1496d
5 changed files with 173 additions and 7 deletions

View File

@@ -2951,6 +2951,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gboolean completed = FALSE;
GList *old_uris;
GList *dup_uris;
GList *ruris = NULL;
char **argv, **envp;
int argc;
@@ -2964,6 +2965,30 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
else
envp = g_get_environ ();
#ifdef G_OS_UNIX
if (uris && info->keyfile)
{
char *snap_instance;
char *app_id = NULL;
snap_instance = g_desktop_app_info_get_string (info, "X-SnapInstanceName");
if (snap_instance && *snap_instance)
app_id = g_strconcat ("snap.", snap_instance, NULL);
g_free (snap_instance);
if (app_id)
{
ruris = g_document_portal_add_documents (uris, app_id, NULL);
if (ruris != NULL)
uris = ruris;
}
g_clear_pointer (&app_id, g_free);
}
#endif
/* The GList* passed to expand_application_parameters() will be modified
* internally by expand_macro(), so we need to pass a copy of it instead,
* and also use that copy to control the exit condition of the loop below.
@@ -3153,6 +3178,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
out:
g_strfreev (argv);
g_strfreev (envp);
g_list_free_full (ruris, g_free);
return completed;
}

View File

@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include "fake-document-portal.h"
#include "gdbus-sessionbus.h"
G_DECLARE_FINAL_TYPE (TestLaunchContext, test_launch_context, TEST,
LAUNCH_CONTEXT, GAppLaunchContext);
@@ -1432,6 +1435,76 @@ test_default_uri_handler_async (void)
g_free (file_path);
}
static void
launch_snap_uris_with_portal (void)
{
GDesktopAppInfo *appinfo;
GError *error = NULL;
gboolean retval;
const gchar *path;
const gchar *path2;
gboolean invoked = FALSE;
gboolean launched = FALSE;
gboolean failed = FALSE;
gboolean child_waited = FALSE;
GAppLaunchContext *context;
GList *uris = NULL;
GFakeDocumentPortalThread *thread = NULL;
/* Run a fake-document-portal */
session_bus_up ();
thread = g_fake_document_portal_thread_new (session_bus_get_address (),
"snap.snap-app");
g_fake_document_portal_thread_run (thread);
path = g_test_get_filename (G_TEST_BUILT, "snap-app_appinfo-test.desktop", NULL);
appinfo = g_desktop_app_info_new_from_filename (path);
g_assert_true (G_IS_APP_INFO (appinfo));
path2 = g_test_get_filename (G_TEST_BUILT, "appinfo-test.desktop", NULL);
g_assert_true (g_file_test (path2, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR));
context = g_object_new (test_launch_context_get_type (), NULL);
g_signal_connect (context, "launch-started",
G_CALLBACK (on_launch_started),
&invoked);
g_signal_connect (context, "launched",
G_CALLBACK (on_launched),
&launched);
g_signal_connect (context, "launch-failed",
G_CALLBACK (on_launch_failed),
&failed);
g_app_launch_context_setenv (context, "DOCUMENT_PORTAL_MOUNT_POINT",
g_fake_document_portal_thread_get_mount_point (thread));
uris = g_list_append (uris, g_strconcat ("file://", path, NULL));
uris = g_list_append (uris, g_strconcat ("file://", path2, NULL));
retval = g_desktop_app_info_launch_uris_as_manager (appinfo, uris,
context,
G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
wait_child_completed,
&child_waited,
&error);
g_assert_no_error (error);
g_assert_true (retval);
g_assert_true (invoked);
g_assert_true (launched);
g_assert_true (child_waited);
g_assert_false (failed);
g_clear_list (&uris, g_free);
g_object_unref (appinfo);
g_assert_finalize_object (context);
g_fake_document_portal_thread_stop (thread);
g_clear_object (&thread);
session_bus_down ();
}
/* Test if Desktop-File Id is correctly formed */
static void
test_id (void)
@@ -2062,6 +2135,7 @@ main (int argc,
g_test_add_func ("/desktop-app-info/launch-as-manager/fail", test_launch_as_manager_fail);
g_test_add_func ("/desktop-app-info/launch-default-uri-handler", test_default_uri_handler);
g_test_add_func ("/desktop-app-info/launch-default-uri-handler-async", test_default_uri_handler_async);
g_test_add_func ("/desktop-app-info/launch-snap-uri-with-portal", launch_snap_uris_with_portal);
g_test_add_func ("/desktop-app-info/id", test_id);
for (i = 0; i < G_N_ELEMENTS (supported_terminals); i++)

View File

@@ -370,13 +370,6 @@ if host_machine.system() != 'windows'
'install' : false,
'extra_programs' : ['appinfo-test'],
},
'desktop-app-info' : {
'install' : false,
'depends' : gio_launch_desktop,
'extra_programs' : ['apps', 'appinfo-test'],
# FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148
'can_fail' : host_system == 'gnu',
},
}
endif
@@ -384,6 +377,7 @@ if host_machine.system() != 'windows'
'basic-application' : {},
'dbus-launch' : {},
'appinfo-test' : {},
'snapinfo-test' : {},
}
if not glib_have_cocoa
@@ -622,6 +616,14 @@ if host_machine.system() != 'windows'
'dbus-appinfo' : {
'extra_sources' : [extra_sources, fake_document_portal_sources],
},
'desktop-app-info' : {
'install' : false,
'depends' : gio_launch_desktop,
'extra_programs' : ['apps', 'appinfo-test', 'snapinfo-test'],
# FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148
'can_fail' : host_system == 'gnu',
'extra_sources' : [extra_sources, fake_document_portal_sources],
},
}
endif
@@ -750,6 +752,7 @@ appinfo_test_desktop_files = [
'appinfo-test-path',
'appinfo-test',
'appinfo-test2',
'snap-app_appinfo-test',
]
foreach appinfo_test_desktop_file : appinfo_test_desktop_files

View File

@@ -0,0 +1,12 @@
# SPDX-License-Identifier: CC0-1.0
# SPDX-FileCopyrightText: 2025 Marco Trevisan (Treviño)
[Desktop Entry]
Type=Application
Version=1.0
Name=Snap Test
X-SnapInstanceName=snap-app
X-SnapAppName=appinfo-test
X-SnapCommonID=org.gio.snap-app.appinfo-test
DBusActivatable=false
Exec=@installed_tests_dir@/snapinfo-test %U
StartupNotify=true

51
gio/tests/snapinfo-test.c Normal file
View File

@@ -0,0 +1,51 @@
/**
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2025 Marco Trevisan (Treviño)
*/
#include <stdlib.h>
#include <gio/gio.h>
int
main (int argc, char *argv[])
{
const char *envvar;
const char *document_portal_mount;
char *expected;
char *expected_files[3] = {0};
gint pid_from_env;
g_test_init (&argc, &argv, NULL);
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE");
g_assert_nonnull (envvar);
expected = g_test_build_filename (G_TEST_BUILT, "snap-app_appinfo-test.desktop", NULL);
g_assert_cmpstr (envvar, ==, expected);
g_free (expected);
envvar = g_getenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
g_assert (envvar != NULL);
pid_from_env = atoi (envvar);
g_assert_cmpint (pid_from_env, ==, getpid ());
document_portal_mount = g_getenv ("DOCUMENT_PORTAL_MOUNT_POINT");
g_assert_nonnull (document_portal_mount);
expected_files[0] = g_build_filename (document_portal_mount,
"document-id-0", "snap-app_appinfo-test.desktop",
NULL);
expected_files[1] = g_build_filename (document_portal_mount,
"document-id-1", "appinfo-test.desktop",
NULL);
g_assert_cmpint (argc, ==, 3);
for (size_t i = 0; i < G_N_ELEMENTS (expected_files); ++i)
{
g_assert_cmpstr (argv[i+1], ==, expected_files[i]);
g_clear_pointer (&expected_files[i], g_free);
}
return 0;
}