[glib] GAppLaunchContext: add environment-manipulating functions
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GAppLaunchContext: add environment-manipulating functions
- Date: Sat, 15 Oct 2011 21:32:40 +0000 (UTC)
commit de834bed306565c0652050665eafff4dfcdf0d8b
Author: Dan Winship <danw gnome org>
Date: Sat Oct 15 16:59:59 2011 -0400
GAppLaunchContext: add environment-manipulating functions
Add functions for manipulating the environment under which a
GAppLaunchContext will launch its children, to avoid thread-related
bugs with using setenv() directly.
FIXME: win32 side isn't implemented yet
https://bugzilla.gnome.org/show_bug.cgi?id=659326
docs/reference/gio/gio-sections.txt | 3 +
gio/gappinfo.c | 99 ++++++++++++++++++++++-
gio/gappinfo.h | 66 +++++++++-------
gio/gdesktopappinfo.c | 147 ++++++++++++++++++++--------------
gio/gio.symbols | 3 +
gio/gwin32appinfo.c | 9 ++
6 files changed, 233 insertions(+), 94 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 7d7def3..ecfbc1c 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1269,6 +1269,9 @@ g_app_info_get_default_for_uri_scheme
g_app_info_get_fallback_for_type
g_app_info_get_recommended_for_type
g_app_info_launch_default_for_uri
+g_app_launch_context_setenv
+g_app_launch_context_unsetenv
+g_app_launch_context_get_environment
g_app_launch_context_get_display
g_app_launch_context_get_startup_notify_id
g_app_launch_context_launch_failed
diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index 231a6c5..666d2b0 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -500,10 +500,14 @@ g_app_info_get_icon (GAppInfo *appinfo)
* no way to detect this.
*
* Some URIs can be changed when passed through a GFile (for instance
- * unsupported uris with strange formats like mailto:), so if you have
- * a textual uri you want to pass in as argument, consider using
+ * unsupported URIs with strange formats like mailto:), so if you have
+ * a textual URI you want to pass in as argument, consider using
* g_app_info_launch_uris() instead.
*
+ * The launched application inherits the environment of the launching
+ * process, but it can be modified with g_app_launch_context_setenv() and
+ * g_app_launch_context_unsetenv().
+ *
* On UNIX, this function sets the <envar>GIO_LAUNCHED_DESKTOP_FILE</envar>
* environment variable with the path of the launched desktop file and
* <envar>GIO_LAUNCHED_DESKTOP_FILE_PID</envar> to the process
@@ -733,6 +737,10 @@ g_app_info_delete (GAppInfo *appinfo)
G_DEFINE_TYPE (GAppLaunchContext, g_app_launch_context, G_TYPE_OBJECT);
+struct _GAppLaunchContextPrivate {
+ char **envp;
+};
+
/**
* g_app_launch_context_new:
*
@@ -748,13 +756,96 @@ g_app_launch_context_new (void)
}
static void
+g_app_launch_context_finalize (GObject *object)
+{
+ GAppLaunchContext *context = G_APP_LAUNCH_CONTEXT (object);
+
+ g_strfreev (context->priv->envp);
+
+ G_OBJECT_CLASS (g_app_launch_context_parent_class)->finalize (object);
+}
+
+static void
g_app_launch_context_class_init (GAppLaunchContextClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GAppLaunchContextPrivate));
+
+ object_class->finalize = g_app_launch_context_finalize;
}
static void
-g_app_launch_context_init (GAppLaunchContext *launch_context)
+g_app_launch_context_init (GAppLaunchContext *context)
+{
+ context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context, G_TYPE_APP_LAUNCH_CONTEXT, GAppLaunchContextPrivate);
+}
+
+/**
+ * g_app_launch_context_setenv:
+ * @context: a #GAppLaunchContext
+ * @variable: the environment variable to set
+ * @value: the value for to set the variable to.
+ *
+ * Arranges for @variable to be set to @value in the child's
+ * environment when @context is used to launch an application.
+ *
+ * Since: 2.32
+ */
+void
+g_app_launch_context_setenv (GAppLaunchContext *context,
+ const char *variable,
+ const char *value)
+{
+ if (!context->priv->envp)
+ context->priv->envp = g_get_environ ();
+
+ context->priv->envp =
+ g_environ_setenv (context->priv->envp, variable, value, TRUE);
+}
+
+/**
+ * g_app_launch_context_unsetenv:
+ * @context: a #GAppLaunchContext
+ * @variable: the environment variable to remove
+ *
+ * Arranges for @variable to be unset in the child's environment
+ * when @context is used to launch an application.
+ *
+ * Since: 2.32
+ */
+void
+g_app_launch_context_unsetenv (GAppLaunchContext *context,
+ const char *variable)
{
+ if (!context->priv->envp)
+ context->priv->envp = g_get_environ ();
+
+ context->priv->envp =
+ g_environ_unsetenv (context->priv->envp, variable);
+}
+
+/**
+ * g_app_launch_context_get_environment:
+ * @context: a #GAppLaunchContext
+ *
+ * Gets the complete environment variable list to be passed to
+ * the child process when @context is used to launch an application.
+ * This is a %NULL-terminated array of strings, where each string has
+ * the form <literal>KEY=VALUE</literal>.
+ *
+ * Return value: (array zero-terminated=1) (transfer full): the
+ * child's environment
+ *
+ * Since: 2.32
+ */
+char **
+g_app_launch_context_get_environment (GAppLaunchContext *context)
+{
+ if (!context->priv->envp)
+ context->priv->envp = g_get_environ ();
+
+ return g_strdupv (context->priv->envp);
}
/**
@@ -768,7 +859,7 @@ g_app_launch_context_init (GAppLaunchContext *launch_context)
* application, by setting the <envar>DISPLAY</envar> environment variable.
*
* Returns: a display string for the display.
- **/
+ */
char *
g_app_launch_context_get_display (GAppLaunchContext *context,
GAppInfo *info,
diff --git a/gio/gappinfo.h b/gio/gappinfo.h
index bf44420..b6786d6 100644
--- a/gio/gappinfo.h
+++ b/gio/gappinfo.h
@@ -33,7 +33,7 @@ G_BEGIN_DECLS
#define G_TYPE_APP_INFO (g_app_info_get_type ())
#define G_APP_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_APP_INFO, GAppInfo))
-#define G_IS_APP_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_APP_INFO))
+#define G_IS_APP_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_APP_INFO))
#define G_APP_INFO_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_APP_INFO, GAppInfoIface))
#define G_TYPE_APP_LAUNCH_CONTEXT (g_app_launch_context_get_type ())
@@ -136,12 +136,12 @@ struct _GAppInfoIface
GType g_app_info_get_type (void) G_GNUC_CONST;
GAppInfo * g_app_info_create_from_commandline (const char *commandline,
- const char *application_name,
- GAppInfoCreateFlags flags,
- GError **error);
+ const char *application_name,
+ GAppInfoCreateFlags flags,
+ GError **error);
GAppInfo * g_app_info_dup (GAppInfo *appinfo);
gboolean g_app_info_equal (GAppInfo *appinfo1,
- GAppInfo *appinfo2);
+ GAppInfo *appinfo2);
const char *g_app_info_get_id (GAppInfo *appinfo);
const char *g_app_info_get_name (GAppInfo *appinfo);
const char *g_app_info_get_display_name (GAppInfo *appinfo);
@@ -150,36 +150,36 @@ const char *g_app_info_get_executable (GAppInfo *appin
const char *g_app_info_get_commandline (GAppInfo *appinfo);
GIcon * g_app_info_get_icon (GAppInfo *appinfo);
gboolean g_app_info_launch (GAppInfo *appinfo,
- GList *files,
- GAppLaunchContext *launch_context,
- GError **error);
+ GList *files,
+ GAppLaunchContext *launch_context,
+ GError **error);
gboolean g_app_info_supports_uris (GAppInfo *appinfo);
gboolean g_app_info_supports_files (GAppInfo *appinfo);
gboolean g_app_info_launch_uris (GAppInfo *appinfo,
- GList *uris,
- GAppLaunchContext *launch_context,
- GError **error);
+ GList *uris,
+ GAppLaunchContext *launch_context,
+ GError **error);
gboolean g_app_info_should_show (GAppInfo *appinfo);
gboolean g_app_info_set_as_default_for_type (GAppInfo *appinfo,
- const char *content_type,
- GError **error);
+ const char *content_type,
+ GError **error);
gboolean g_app_info_set_as_default_for_extension (GAppInfo *appinfo,
- const char *extension,
- GError **error);
+ const char *extension,
+ GError **error);
gboolean g_app_info_add_supports_type (GAppInfo *appinfo,
- const char *content_type,
- GError **error);
+ const char *content_type,
+ GError **error);
gboolean g_app_info_can_remove_supports_type (GAppInfo *appinfo);
gboolean g_app_info_remove_supports_type (GAppInfo *appinfo,
- const char *content_type,
- GError **error);
+ const char *content_type,
+ GError **error);
gboolean g_app_info_can_delete (GAppInfo *appinfo);
gboolean g_app_info_delete (GAppInfo *appinfo);
gboolean g_app_info_set_as_last_used_for_type (GAppInfo *appinfo,
- const char *content_type,
- GError **error);
+ const char *content_type,
+ GError **error);
GList * g_app_info_get_all (void);
GList * g_app_info_get_all_for_type (const char *content_type);
@@ -188,12 +188,12 @@ GList * g_app_info_get_fallback_for_type (const gchar *content_type);
void g_app_info_reset_type_associations (const char *content_type);
GAppInfo *g_app_info_get_default_for_type (const char *content_type,
- gboolean must_support_uris);
+ gboolean must_support_uris);
GAppInfo *g_app_info_get_default_for_uri_scheme (const char *uri_scheme);
gboolean g_app_info_launch_default_for_uri (const char *uri,
- GAppLaunchContext *launch_context,
- GError **error);
+ GAppLaunchContext *launch_context,
+ GError **error);
/**
* GAppLaunchContext:
@@ -233,14 +233,22 @@ struct _GAppLaunchContextClass
GType g_app_launch_context_get_type (void) G_GNUC_CONST;
GAppLaunchContext *g_app_launch_context_new (void);
+
+void g_app_launch_context_setenv (GAppLaunchContext *context,
+ const char *variable,
+ const char *value);
+void g_app_launch_context_unsetenv (GAppLaunchContext *context,
+ const char *variable);
+char ** g_app_launch_context_get_environment (GAppLaunchContext *context);
+
char * g_app_launch_context_get_display (GAppLaunchContext *context,
- GAppInfo *info,
- GList *files);
+ GAppInfo *info,
+ GList *files);
char * g_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
- GAppInfo *info,
- GList *files);
+ GAppInfo *info,
+ GList *files);
void g_app_launch_context_launch_failed (GAppLaunchContext *context,
- const char * startup_notify_id);
+ const char * startup_notify_id);
G_END_DECLS
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index 381dbe4..b68d50e 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -1126,9 +1126,8 @@ typedef struct
{
GSpawnChildSetupFunc user_setup;
gpointer user_setup_data;
- char *display;
- char *sn_id;
- char *desktop_file;
+
+ char *pid_envvar;
} ChildSetupData;
static void
@@ -1136,20 +1135,22 @@ child_setup (gpointer user_data)
{
ChildSetupData *data = user_data;
- if (data->display)
- g_setenv ("DISPLAY", data->display, TRUE);
-
- if (data->sn_id)
- g_setenv ("DESKTOP_STARTUP_ID", data->sn_id, TRUE);
-
- if (data->desktop_file)
+ if (data->pid_envvar)
{
- gchar pid[20];
-
- g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
+ pid_t pid = getpid ();
+ char buf[20];
+ int i;
- g_snprintf (pid, 20, "%ld", (long)getpid ());
- g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
+ /* 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)
@@ -1238,7 +1239,7 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
GDBusConnection *session_bus;
gboolean completed = FALSE;
GList *old_uris;
- char **argv;
+ char **argv, **envp;
int argc;
ChildSetupData data;
@@ -1248,66 +1249,89 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+ if (launch_context)
+ envp = g_app_launch_context_get_environment (launch_context);
+ else
+ envp = g_get_environ ();
+
do
{
GPid pid;
GList *launched_uris;
GList *iter;
+ char *display, *sn_id;
old_uris = uris;
if (!expand_application_parameters (info, &uris,
- &argc, &argv, error))
- goto out;
+ &argc, &argv, error))
+ goto out;
/* Get the subset of URIs we're launching with this process */
launched_uris = NULL;
for (iter = old_uris; iter != NULL && iter != uris; iter = iter->next)
- launched_uris = g_list_prepend (launched_uris, iter->data);
+ launched_uris = g_list_prepend (launched_uris, iter->data);
launched_uris = g_list_reverse (launched_uris);
-
+
if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
- {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Unable to find terminal required for application"));
- goto out;
- }
+ goto out;
+ }
data.user_setup = user_setup;
data.user_setup_data = user_setup_data;
- data.display = NULL;
- data.sn_id = NULL;
- data.desktop_file = info->filename;
+ 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");
+ }
+
+ display = NULL;
+ sn_id = NULL;
if (launch_context)
- {
- GList *launched_files = create_files_for_uris (launched_uris);
-
- data.display = g_app_launch_context_get_display (launch_context,
- appinfo,
- launched_files);
-
- if (info->startup_notify)
- data.sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
- appinfo,
- launched_files);
- g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
- g_list_free (launched_files);
- }
+ {
+ GList *launched_files = create_files_for_uris (launched_uris);
+
+ display = g_app_launch_context_get_display (launch_context,
+ appinfo,
+ launched_files);
+ envp = g_environ_setenv (envp, "DISPLAY", display, TRUE);
+
+ if (info->startup_notify)
+ {
+ sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
+ appinfo,
+ launched_files);
+ envp = g_environ_setenv (envp, "DESKTOP_STARTUP_ID", sn_id, TRUE);
+ }
+
+ g_list_foreach (launched_files, (GFunc)g_object_unref, NULL);
+ g_list_free (launched_files);
+ }
if (!g_spawn_async (info->path,
- argv,
- NULL,
- spawn_flags,
- child_setup,
- &data,
- &pid,
- error))
- {
- if (data.sn_id)
- g_app_launch_context_launch_failed (launch_context, data.sn_id);
+ argv,
+ envp,
+ spawn_flags,
+ child_setup,
+ &data,
+ &pid,
+ error))
+ {
+ if (sn_id)
+ g_app_launch_context_launch_failed (launch_context, sn_id);
- g_free (data.sn_id);
- g_free (data.display);
+ g_free (display);
+ g_free (sn_id);
g_list_free (launched_uris);
goto out;
@@ -1319,12 +1343,12 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
notify_desktop_launch (session_bus,
info,
pid,
- data.display,
- data.sn_id,
+ display,
+ sn_id,
launched_uris);
- g_free (data.sn_id);
- g_free (data.display);
+ g_free (display);
+ g_free (sn_id);
g_list_free (launched_uris);
g_strfreev (argv);
@@ -1349,6 +1373,7 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
out:
g_strfreev (argv);
+ g_strfreev (envp);
return completed;
}
@@ -1438,9 +1463,9 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
*
* This guarantee allows additional control over the exact environment
* of the child processes, which is provided via a setup function
- * @setup, as well as the process identifier of each child process via
- * @pid_callback. See g_spawn_async() for more information about the
- * semantics of the @setup function.
+ * @user_setup, as well as the process identifier of each child process
+ * via @pid_callback. See g_spawn_async() for more information about the
+ * semantics of the @user_setup function.
*
* Returns: %TRUE on successful launch, %FALSE otherwise.
*/
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 029c102..0ce8fd5 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -66,6 +66,9 @@ g_app_info_launch_default_for_uri
g_app_info_can_delete
g_app_info_delete
g_app_launch_context_new
+g_app_launch_context_setenv
+g_app_launch_context_unsetenv
+g_app_launch_context_get_environment
g_app_launch_context_get_display
g_app_launch_context_get_startup_notify_id
g_app_launch_context_launch_failed
diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c
index a441251..cb0093f 100644
--- a/gio/gwin32appinfo.c
+++ b/gio/gwin32appinfo.c
@@ -278,6 +278,15 @@ g_win32_app_info_launch (GAppInfo *appinfo,
}
#endif
+ /* FIXME: Need to do something with
+ * g_app_launch_context_get_environment()... ShellExecuteExW()
+ * doesn't have any way to pass an environment though. We need to
+ * either (a) update environment, ShellExecuteExW(), revert
+ * environment; or (b) find an API to figure out what app
+ * ShellExecuteExW() would launch, and then use g_spawn_async()
+ * instead.
+ */
+
for (l = files; l != NULL; l = l->next)
{
char *path = g_file_get_path (l->data);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]