diff --git a/gio/Makefile.am b/gio/Makefile.am
index 7c7f247c0..13a85edb1 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -819,7 +819,7 @@ gio.def: libgio-2.0.la
gio-2.0.lib: libgio-2.0.la gio.def
$(AM_V_GEN) lib.exe -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgio-2.0-$(LT_CURRENT_MINUS_AGE).dll -def:$(builddir)/gio.def -out:$@
-bin_PROGRAMS = gio-querymodules glib-compile-schemas glib-compile-resources gsettings
+bin_PROGRAMS = gio-querymodules glib-compile-schemas glib-compile-resources gsettings gio-launch-desktop
glib_compile_resources_LDADD = libgio-2.0.la \
$(top_builddir)/gobject/libgobject-2.0.la \
@@ -840,6 +840,8 @@ gio_querymodules_LDADD = libgio-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gio_launch_desktop_SOURCES = gio-launch-desktop.c
+
gconstructor_as_data.h: $(top_srcdir)/glib/gconstructor.h data-to-c.py
$(AM_V_GEN) $(srcdir)/data-to-c.py $(top_srcdir)/glib/gconstructor.h gconstructor_code $@
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index a2aa760c7..4eac5ada2 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -155,6 +155,7 @@ static guint n_desktop_file_dirs;
static const guint desktop_file_dir_user_config_index = 0;
static guint desktop_file_dir_user_data_index;
static GMutex desktop_file_dir_lock;
+static const gchar *gio_launch_desktop_path = NULL;
/* Monitor 'changed' signal handler {{{2 */
static void desktop_file_dir_reset (DesktopFileDir *dir);
@@ -2562,41 +2563,6 @@ create_files_for_uris (GList *uris)
return g_list_reverse (res);
}
-typedef struct
-{
- GSpawnChildSetupFunc user_setup;
- gpointer user_setup_data;
-
- char *pid_envvar;
-} ChildSetupData;
-
-static void
-child_setup (gpointer user_data)
-{
- ChildSetupData *data = user_data;
-
- if (data->pid_envvar)
- {
- pid_t pid = getpid ();
- char buf[20];
- int i;
-
- /* Write the pid into the space already reserved for it in the
- * environment array. We can't use sprintf because it might
- * malloc, so we do it by hand. It's simplest to write the pid
- * out backwards first, then copy it over.
- */
- for (i = 0; pid; i++, pid /= 10)
- buf[i] = (pid % 10) + '0';
- for (i--; i >= 0; i--)
- *(data->pid_envvar++) = buf[i];
- *data->pid_envvar = '\0';
- }
-
- if (data->user_setup)
- data->user_setup (data->user_setup_data);
-}
-
static void
notify_desktop_launch (GDBusConnection *session_bus,
GDesktopAppInfo *info,
@@ -2683,7 +2649,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
char **argv, **envp;
int argc;
- ChildSetupData data;
g_return_val_if_fail (info != NULL, FALSE);
@@ -2705,6 +2670,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GList *launched_uris;
GList *iter;
char *sn_id = NULL;
+ char **wrapped_argv;
+ int i;
old_uris = dup_uris;
if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
@@ -2723,25 +2690,11 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
goto out;
}
- data.user_setup = user_setup;
- data.user_setup_data = user_setup_data;
-
if (info->filename)
- {
- envp = g_environ_setenv (envp,
- "GIO_LAUNCHED_DESKTOP_FILE",
- info->filename,
- TRUE);
- envp = g_environ_setenv (envp,
- "GIO_LAUNCHED_DESKTOP_FILE_PID",
- "XXXXXXXXXXXXXXXXXXXX", /* filled in child_setup */
- TRUE);
- data.pid_envvar = (char *)g_environ_getenv (envp, "GIO_LAUNCHED_DESKTOP_FILE_PID");
- }
- else
- {
- data.pid_envvar = NULL;
- }
+ envp = g_environ_setenv (envp,
+ "GIO_LAUNCHED_DESKTOP_FILE",
+ info->filename,
+ TRUE);
sn_id = NULL;
if (launch_context)
@@ -2760,12 +2713,35 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
g_list_free_full (launched_files, g_object_unref);
}
+ if (g_once_init_enter (&gio_launch_desktop_path))
+ {
+ const gchar *tmp;
+
+ /* Allow test suite to specify path to gio-launch-desktop */
+ tmp = g_getenv ("GIO_LAUNCH_DESKTOP");
+
+ /* Fall back on usual searching in $PATH */
+ if (tmp == NULL)
+ tmp = "gio-launch-desktop";
+ g_once_init_leave (&gio_launch_desktop_path, tmp);
+ }
+
+ wrapped_argv = g_new (char *, argc + 2);
+ wrapped_argv[0] = g_strdup (gio_launch_desktop_path);
+
+ for (i = 0; i < argc; i++)
+ wrapped_argv[i + 1] = g_steal_pointer (&argv[i]);
+
+ wrapped_argv[i + 1] = NULL;
+ g_free (argv);
+ argv = NULL;
+
if (!g_spawn_async (info->path,
- argv,
+ wrapped_argv,
envp,
spawn_flags,
- child_setup,
- &data,
+ user_setup,
+ user_setup_data,
&pid,
error))
{
@@ -2805,8 +2781,8 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
g_free (sn_id);
g_list_free (launched_uris);
- g_strfreev (argv);
- argv = NULL;
+ g_strfreev (wrapped_argv);
+ wrapped_argv = NULL;
}
while (dup_uris != NULL);
@@ -3046,11 +3022,12 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
* launch applications. Ordinary applications should use
* g_app_info_launch_uris().
*
- * If the application is launched via traditional UNIX fork()/exec()
- * then @spawn_flags, @user_setup and @user_setup_data are used for the
- * call to g_spawn_async(). Additionally, @pid_callback (with
- * @pid_callback_data) will be called to inform about the PID of the
- * created process.
+ * If the application is launched via GSpawn, then @spawn_flags, @user_setup
+ * and @user_setup_data are used for the call to g_spawn_async().
+ * Additionally, @pid_callback (with @pid_callback_data) will be called to
+ * inform about the PID of the created process. See g_spawn_async_with_pipes()
+ * for information on certain parameter conditions that can enable an
+ * optimized posix_spawn() codepath to be used.
*
* If application launching occurs via some other mechanism (eg: D-Bus
* activation) then @spawn_flags, @user_setup, @user_setup_data,
diff --git a/gio/gio-launch-desktop.c b/gio/gio-launch-desktop.c
new file mode 100644
index 000000000..03845df28
--- /dev/null
+++ b/gio/gio-launch-desktop.c
@@ -0,0 +1,52 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2018 Endless Mobile, 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.1 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 .
+ *
+ * Author: Daniel Drake
+ */
+
+/*
+ * gio-launch-desktop: GDesktopAppInfo helper
+ * Executable wrapper to set GIO_LAUNCHED_DESKTOP_FILE_PID
+ * There are complications when doing this in a fork()/exec() codepath,
+ * and it cannot otherwise be done with posix_spawn().
+ * This wrapper is designed to be minimal and lightweight.
+ * It does not even link against glib.
+ */
+
+#include
+#include
+#include
+#include
+
+int
+main (int argc, char *argv[])
+{
+ pid_t pid = getpid ();
+ char buf[50];
+ int r;
+
+ if (argc < 2)
+ return -1;
+
+ r = snprintf (buf, sizeof (buf), "GIO_LAUNCHED_DESKTOP_FILE_PID=%ld", (long) pid);
+ if (r >= sizeof (buf))
+ return -1;
+
+ putenv (buf);
+
+ return execvp (argv[1], argv + 1);
+}
diff --git a/gio/meson.build b/gio/meson.build
index 9544ab395..89246fea3 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -411,6 +411,12 @@ if host_system != 'windows'
contenttype_sources += files('gcontenttype.c')
appinfo_sources += files('gdesktopappinfo.c')
gio_unix_include_headers += files('gdesktopappinfo.h')
+
+ executable('gio-launch-desktop', 'gio-launch-desktop.c',
+ install : true,
+ c_args : gio_c_args,
+ # intl.lib is not compatible with SAFESEH
+ link_args : noseh_link_args)
endif
subdir('xdgmime')
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 599823893..e0bc6c7c2 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -15,7 +15,9 @@ LDADD = \
AM_CPPFLAGS = $(gio_INCLUDES) $(GLIB_DEBUG_FLAGS) -I$(top_builddir)/gio -I$(top_srcdir)/gio
DEFS = -DG_LOG_DOMAIN=\"GLib-GIO\" -DTEST_SERVICES=\""$(abs_top_builddir)/gio/tests/services"\"
AM_CFLAGS = $(GLIB_WARN_CFLAGS)
-AM_TESTS_ENVIRONMENT += GIO_MODULE_DIR=
+AM_TESTS_ENVIRONMENT += \
+ GIO_MODULE_DIR= \
+ GIO_LAUNCH_DESKTOP="$(top_builddir)/gio/gio-launch-desktop"
# -----------------------------------------------------------------------------
# Test programs buildable on all platforms
diff --git a/gio/tests/meson.build b/gio/tests/meson.build
index 558f3d721..cde1372ad 100644
--- a/gio/tests/meson.build
+++ b/gio/tests/meson.build
@@ -74,6 +74,7 @@ test_env = [
'G_TEST_SRCDIR=' + meson.current_source_dir(),
'G_TEST_BUILDDIR=' + meson.current_build_dir(),
'GIO_MODULE_DIR=',
+ 'GIO_LAUNCH_DESKTOP=' + meson.build_root() + '/gio/gio-launch-desktop',
]
test_c_args = [