gdesktopappinfo: add g_desktop_app_info_launch_uris_as_manager_with_fds variant

Add an app-launching function which allows standard file descriptors
to be passed to the child process.

This will be used by gnome-shell to pass systemd journal descriptors
as stdout/stderr. gnome-shell's child_setup function can then be
eliminated, which will enable use of the posix_spawn optimized
gspawn codepath for desktop app launching.
This commit is contained in:
Daniel Drake 2018-06-06 06:59:59 -06:00
parent 742efe6232
commit 156d009696
4 changed files with 143 additions and 19 deletions

View File

@ -1618,6 +1618,7 @@ g_desktop_app_info_get_boolean
g_desktop_app_info_has_key
GDesktopAppLaunchCallback
g_desktop_app_info_launch_uris_as_manager
g_desktop_app_info_launch_uris_as_manager_with_fds
<SUBSECTION>
g_desktop_app_info_list_actions
g_desktop_app_info_get_action_name

View File

@ -2641,6 +2641,9 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
gpointer pid_callback_data,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
GError **error)
{
gboolean completed = FALSE;
@ -2736,14 +2739,17 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
g_free (argv);
argv = NULL;
if (!g_spawn_async (info->path,
wrapped_argv,
envp,
spawn_flags,
user_setup,
user_setup_data,
&pid,
error))
if (!g_spawn_async_with_fds (info->path,
wrapped_argv,
envp,
spawn_flags,
user_setup,
user_setup_data,
&pid,
stdin_fd,
stdout_fd,
stderr_fd,
error))
{
if (sn_id)
g_app_launch_context_launch_failed (launch_context, sn_id);
@ -2916,6 +2922,9 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
gpointer pid_callback_data,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
GError **error)
{
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
@ -2929,7 +2938,8 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
else
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
spawn_flags, user_setup, user_setup_data,
pid_callback, pid_callback_data, error);
pid_callback, pid_callback_data,
stdin_fd, stdout_fd, stderr_fd, error);
if (session_bus != NULL)
{
@ -2954,6 +2964,7 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
launch_context,
_SPAWN_FLAGS_DEFAULT,
NULL, NULL, NULL, NULL,
-1, -1, -1,
error);
}
@ -3004,6 +3015,61 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
return res;
}
/**
* g_desktop_app_info_launch_uris_as_manager_with_fds:
* @appinfo: a #GDesktopAppInfo
* @uris: (element-type utf8): List of URIs
* @launch_context: (nullable): a #GAppLaunchContext
* @spawn_flags: #GSpawnFlags, used for each process
* @user_setup: (scope async) (nullable): a #GSpawnChildSetupFunc, used once
* for each process.
* @user_setup_data: (closure user_setup) (nullable): User data for @user_setup
* @pid_callback: (scope call) (nullable): Callback for child processes
* @pid_callback_data: (closure pid_callback) (nullable): User data for @callback
* @stdin_fd: file descriptor to use for child's stdin, or -1
* @stdout_fd: file descriptor to use for child's stdout, or -1
* @stderr_fd: file descriptor to use for child's stderr, or -1
* @error: return location for a #GError, or %NULL
*
* Equivalent to g_desktop_app_info_launch_uris_as_manager() but allows
* you to pass in file descriptors for the stdin, stdout and stderr streams
* of the launched process.
*
* If application launching occurs via some non-spawn mechanism (e.g. D-Bus
* activation) then @stdin_fd, @stdout_fd and @stderr_fd are ignored.
*
* Returns: %TRUE on successful launch, %FALSE otherwise.
*
* Since: 2.58
*/
gboolean
g_desktop_app_info_launch_uris_as_manager_with_fds (GDesktopAppInfo *appinfo,
GList *uris,
GAppLaunchContext *launch_context,
GSpawnFlags spawn_flags,
GSpawnChildSetupFunc user_setup,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
gpointer pid_callback_data,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
GError **error)
{
return g_desktop_app_info_launch_uris_internal ((GAppInfo*)appinfo,
uris,
launch_context,
spawn_flags,
user_setup,
user_setup_data,
pid_callback,
pid_callback_data,
stdin_fd,
stdout_fd,
stderr_fd,
error);
}
/**
* g_desktop_app_info_launch_uris_as_manager:
* @appinfo: a #GDesktopAppInfo
@ -3046,15 +3112,16 @@ g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo *appinfo,
gpointer pid_callback_data,
GError **error)
{
return g_desktop_app_info_launch_uris_internal ((GAppInfo*)appinfo,
uris,
launch_context,
spawn_flags,
user_setup,
user_setup_data,
pid_callback,
pid_callback_data,
error);
return g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
uris,
launch_context,
spawn_flags,
user_setup,
user_setup_data,
pid_callback,
pid_callback_data,
-1, -1, -1,
error);
}
/* OnlyShowIn API support {{{2 */
@ -4629,7 +4696,8 @@ g_desktop_app_info_launch_action (GDesktopAppInfo *info,
if (exec_line)
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL, NULL);
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL,
-1, -1, -1, NULL);
}
if (session_bus != NULL)

View File

@ -169,6 +169,20 @@ gboolean g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo
gpointer pid_callback_data,
GError **error);
GLIB_AVAILABLE_IN_2_58
gboolean g_desktop_app_info_launch_uris_as_manager_with_fds (GDesktopAppInfo *appinfo,
GList *uris,
GAppLaunchContext *launch_context,
GSpawnFlags spawn_flags,
GSpawnChildSetupFunc user_setup,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
gpointer pid_callback_data,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
GError **error);
GLIB_AVAILABLE_IN_2_40
gchar *** g_desktop_app_info_search (const gchar *search_string);

View File

@ -788,6 +788,46 @@ test_show_in (void)
assert_shown ("gcr-prompter.desktop", TRUE, "KDE:GNOME-Classic");
}
/* Test g_desktop_app_info_launch_uris_as_manager() and
* g_desktop_app_info_launch_uris_as_manager_with_fds()
*/
static void
test_launch_as_manager (void)
{
GDesktopAppInfo *appinfo;
GError *error = NULL;
gboolean retval;
const gchar *path;
if (g_getenv ("DISPLAY") == NULL || g_getenv ("DISPLAY")[0] == '\0')
{
g_test_skip ("No DISPLAY. Skipping test.");
return;
}
path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
appinfo = g_desktop_app_info_new_from_filename (path);
g_assert_nonnull (appinfo);
retval = g_desktop_app_info_launch_uris_as_manager (appinfo, NULL, NULL, 0,
NULL, NULL,
NULL, NULL,
&error);
g_assert_no_error (error);
g_assert_true (retval);
retval = g_desktop_app_info_launch_uris_as_manager_with_fds (appinfo,
NULL, NULL, 0,
NULL, NULL,
NULL, NULL,
-1, -1, -1,
&error);
g_assert_no_error (error);
g_assert_true (retval);
g_object_unref (appinfo);
}
int
main (int argc,
char *argv[])
@ -816,6 +856,7 @@ main (int argc,
g_test_add_func ("/desktop-app-info/search", test_search);
g_test_add_func ("/desktop-app-info/implements", test_implements);
g_test_add_func ("/desktop-app-info/show-in", test_show_in);
g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
result = g_test_run ();