mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
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
This commit is contained in:
parent
117e534091
commit
de834bed30
@ -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
|
||||
|
101
gio/gappinfo.c
101
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_class_init (GAppLaunchContextClass *klass)
|
||||
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_init (GAppLaunchContext *launch_context)
|
||||
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 *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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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];
|
||||
pid_t pid = getpid ();
|
||||
char buf[20];
|
||||
int i;
|
||||
|
||||
g_setenv ("GIO_LAUNCHED_DESKTOP_FILE", data->desktop_file, TRUE);
|
||||
|
||||
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);
|
||||
{
|
||||
GList *launched_files = create_files_for_uris (launched_uris);
|
||||
|
||||
data.display = g_app_launch_context_get_display (launch_context,
|
||||
appinfo,
|
||||
launched_files);
|
||||
display = g_app_launch_context_get_display (launch_context,
|
||||
appinfo,
|
||||
launched_files);
|
||||
envp = g_environ_setenv (envp, "DISPLAY", display, TRUE);
|
||||
|
||||
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);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user