gdesktopappinfo: Add g_desktop_app_info_launch_uris_as_manager()

A new GDesktopAppInfo specific function which provides more control
over launched processes.  Intended basically only for use in GNOME
Shell, where we want:

*) To directly know the GPid for each launched program, without
   having to listen to a DBus signal emitted in our own process
*) Possibly control over the process environment; for example,
   we may want to call setsid() or redirect file descriptors.

And in the future:
*) To avoid recursively calling ourself via DBus, when a later
   patch causes g_app_info_launch() to indirect via the shell.

https://bugzilla.gnome.org/show_bug.cgi?id=606960
This commit is contained in:
Colin Walters 2010-12-20 14:48:53 -05:00
parent bb6c44b9d3
commit e6546debd6
2 changed files with 108 additions and 5 deletions

View File

@ -898,6 +898,8 @@ create_files_for_uris (GList *uris)
typedef struct typedef struct
{ {
GSpawnChildSetupFunc user_setup;
gpointer user_setup_data;
char *display; char *display;
char *sn_id; char *sn_id;
char *desktop_file; char *desktop_file;
@ -923,6 +925,9 @@ child_setup (gpointer user_data)
g_snprintf (pid, 20, "%ld", (long)getpid ()); g_snprintf (pid, 20, "%ld", (long)getpid ());
g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE); g_setenv ("GIO_LAUNCHED_DESKTOP_FILE_PID", pid, TRUE);
} }
if (data->user_setup)
data->user_setup (data->user_setup_data);
} }
static void static void
@ -968,11 +973,18 @@ notify_desktop_launch (GDBusConnection *session_bus,
g_object_unref (msg); g_object_unref (msg);
} }
#define _SPAWN_FLAGS_DEFAULT (G_SPAWN_SEARCH_PATH)
static gboolean static gboolean
g_desktop_app_info_launch_uris (GAppInfo *appinfo, _g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
GList *uris, GList *uris,
GAppLaunchContext *launch_context, GAppLaunchContext *launch_context,
GError **error) GSpawnFlags spawn_flags,
GSpawnChildSetupFunc user_setup,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
gpointer pid_callback_data,
GError **error)
{ {
GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo); GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
GDBusConnection *session_bus; GDBusConnection *session_bus;
@ -1012,6 +1024,8 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
goto out; goto out;
} }
data.user_setup = user_setup;
data.user_setup_data = user_setup_data;
data.display = NULL; data.display = NULL;
data.sn_id = NULL; data.sn_id = NULL;
data.desktop_file = info->filename; data.desktop_file = info->filename;
@ -1035,7 +1049,7 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
if (!g_spawn_async (info->path, if (!g_spawn_async (info->path,
argv, argv,
NULL, NULL,
G_SPAWN_SEARCH_PATH, spawn_flags,
child_setup, child_setup,
&data, &data,
&pid, &pid,
@ -1051,6 +1065,9 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
goto out; goto out;
} }
if (pid_callback != NULL)
pid_callback (info, pid, pid_callback_data);
notify_desktop_launch (session_bus, notify_desktop_launch (session_bus,
info->filename, info->filename,
pid, pid,
@ -1081,6 +1098,19 @@ g_desktop_app_info_launch_uris (GAppInfo *appinfo,
return completed; return completed;
} }
static gboolean
g_desktop_app_info_launch_uris (GAppInfo *appinfo,
GList *uris,
GAppLaunchContext *launch_context,
GError **error)
{
return _g_desktop_app_info_launch_uris_internal (appinfo, uris,
launch_context,
_SPAWN_FLAGS_DEFAULT,
NULL, NULL, NULL, NULL,
error);
}
static gboolean static gboolean
g_desktop_app_info_supports_uris (GAppInfo *appinfo) g_desktop_app_info_supports_uris (GAppInfo *appinfo)
{ {
@ -1129,6 +1159,55 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
return res; return res;
} }
/**
* g_desktop_app_info_launch_uris_as_manager:
* @appinfo: a #GDesktopAppInfo
* @uris: (element-type utf8): List of URIs
* @launch_context: a #GAppLaunchContext
* @spawn_flags: #GSpawnFlags, used for each process
* @user_setup: a #GSpawnChildSetupFunc, used once for each process.
* @user_setup_data: (closure user_setup): User data for @user_setup
* @pid_callback: (scope call): Callback for child processes
* @pid_callback_data: (closure pid_callback): User data for @callback
* @error: a #GError
*
* This function performs the equivalent of g_app_info_launch_uris(),
* but is intended primarily for operating system components that
* launch applications. Ordinary applications should use
* g_app_info_launch_uris().
*
* In contrast to g_app_info_launch_uris(), all processes created will
* always be run directly as children as if by the UNIX fork()/exec()
* calls.
*
* 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.
*/
gboolean
g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo *appinfo,
GList *uris,
GAppLaunchContext *launch_context,
GSpawnFlags spawn_flags,
GSpawnChildSetupFunc user_setup,
gpointer user_setup_data,
GDesktopAppLaunchCallback pid_callback,
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);
}
G_LOCK_DEFINE_STATIC (g_desktop_env); G_LOCK_DEFINE_STATIC (g_desktop_env);
static gchar *g_desktop_env = NULL; static gchar *g_desktop_env = NULL;

View File

@ -93,6 +93,30 @@ GType g_desktop_app_info_lookup_get_type (void) G_GNUC_CON
GAppInfo *g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup, GAppInfo *g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
const char *uri_scheme); const char *uri_scheme);
/**
* GDesktopAppLaunchCallback:
* @appinfo: a #GDesktopAppInfo
* @pid: Process identifier
* @user_data: User data
*
* During invocation, g_desktop_app_info_launch_uris_as_manager() may
* create one or more child processes. This callback is invoked once
* for each, providing the process ID.
*/
typedef void (GDesktopAppLaunchCallback) (GDesktopAppInfo *appinfo,
GPid pid,
gpointer user_data);
gboolean g_desktop_app_info_launch_uris_as_manager (GDesktopAppInfo *appinfo,
GList *uris,
GAppLaunchContext *launch_context,
GSpawnFlags spawn_flags,
GSpawnChildSetupFunc setup,
gpointer user_setup_data,
GDesktopAppLaunchCallback callback,
gpointer pid_callback_data,
GError **error);
#endif /* G_DISABLE_DEPRECATED */ #endif /* G_DISABLE_DEPRECATED */
G_END_DECLS G_END_DECLS