[Xfce4-commits] <libxfce4ui:nick/spawn-child-watch> Add new API for watching the child process.
Nick Schermer
noreply at xfce.org
Wed Nov 4 15:54:03 CET 2009
Updating branch refs/heads/nick/spawn-child-watch
to 5eccdbe947a9f2398ac45d0551dfcb383632156e (commit)
from c5360220766505587f39bf7a861b19e764d64635 (commit)
commit 5eccdbe947a9f2398ac45d0551dfcb383632156e
Author: Nick Schermer <nick at xfce.org>
Date: Wed Nov 4 15:47:22 2009 +0100
Add new API for watching the child process.
xfce_spawn_on_screen_watch:
Same function as xfce_spawn_on_screen, but with callback
functions for watching the child, like you normally would
do with g_child_watch_add(_full), but since we already
need a child watch for startup notification and 2 watches
on the same pid are not possible, this is a good alternative.
xfce_spawn_(un)ref:
Functions for handling the ref count of the structure returned
from xfce_spawn_on_screen_watch().
configure.in.in | 6 +-
libxfce4ui/libxfce4ui.symbols | 4 +
libxfce4ui/xfce-spawn.c | 560 ++++++++++++++++++++++++++++++-----------
libxfce4ui/xfce-spawn.h | 54 +++--
4 files changed, 454 insertions(+), 170 deletions(-)
diff --git a/configure.in.in b/configure.in.in
index 7158fba..e82ba23 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -106,8 +106,10 @@ dnl ***************************************
dnl *** Check for standard header files ***
dnl ***************************************
AC_HEADER_STDC()
-AC_CHECK_HEADERS([errno.h fcntl.h limits.h locale.h math.h memory.h \
- signal.h stdarg.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([crt_externs.h errno.h fcntl.h limits.h locale.h math.h \
+ memory.h signal.h stdarg.h stdlib.h string.h unistd.h])
+AC_CHECK_DECLS([environ])
+AC_CHECK_FUNCS([_NSGetEnviron])
dnl ******************************
dnl *** Check for i18n support ***
diff --git a/libxfce4ui/libxfce4ui.symbols b/libxfce4ui/libxfce4ui.symbols
index 304b589..c67b7b0 100644
--- a/libxfce4ui/libxfce4ui.symbols
+++ b/libxfce4ui/libxfce4ui.symbols
@@ -87,6 +87,10 @@ xfce_gtk_window_center_on_active_screen
/* xfce-spawn functions */
#if IN_HEADER(__XFCE_SPAWN_H__)
#if IN_SOURCE(__XFCE_SPAWN_C__)
+xfce_spawn_on_screen_watch G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC
+xfce_spawn_ref
+xfce_spawn_unref
+xfce_spawn_set_callback
xfce_spawn_on_screen
xfce_spawn_command_line_on_screen
#endif
diff --git a/libxfce4ui/xfce-spawn.c b/libxfce4ui/xfce-spawn.c
index 2ba5fc5..03751e3 100644
--- a/libxfce4ui/xfce-spawn.c
+++ b/libxfce4ui/xfce-spawn.c
@@ -29,6 +29,9 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h> /* for _NSGetEnviron */
+#endif
#include <gdk/gdk.h>
@@ -46,52 +49,61 @@
#include <libxfce4ui/libxfce4ui-private.h>
#include <libxfce4ui/libxfce4ui-alias.h>
-/* the maximum time for an application to startup */
-#define XFCE_SPAWN_STARTUP_TIMEOUT (30 * 1000)
+#ifdef HAVE__NSGETENVIRON
+/* for support under apple/darwin */
+#define environ (*_NSGetEnviron())
+#elif !HAVE_DECL_ENVIRON
+/* try extern if environ is not defined in unistd.h */
+extern gchar **environ;
+#endif
+/* the maximum time (seconds) for an application to startup */
+#define XFCE_SPAWN_STARTUP_TIMEOUT (30)
-#ifdef HAVE_LIBSTARTUP_NOTIFICATION
-typedef struct
+
+struct _XfceSpawn
{
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+ /* startup notification data */
SnLauncherContext *sn_launcher;
guint timeout_id;
+#endif
+
+ /* child watch information */
guint watch_id;
GPid pid;
-} XfceSpawnData;
+ /* child watch functions from the user */
+ GChildWatchFunc cw_function;
+ gpointer cw_data;
+ GDestroyNotify cw_notify;
+ /* ref count of the structure, 0 means we
+ * can free directly, otherwise we wait for an unref */
+ gint ref_count;
+};
+
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
static gboolean
xfce_spawn_startup_timeout (gpointer user_data)
{
- XfceSpawnData *spawn_data = user_data;
- GTimeVal now;
- gdouble elapsed;
- glong tv_sec;
- glong tv_usec;
+ XfceSpawn *spawn = user_data;
+ GTimeVal now;
+ gdouble elapsed;
+ glong tv_sec;
+ glong tv_usec;
- GDK_THREADS_ENTER ();
+ _libxfce4ui_return_val_if_fail (spawn->sn_launcher != NULL, FALSE);
/* determine the amount of elapsed time */
g_get_current_time (&now);
- sn_launcher_context_get_last_active_time (spawn_data->sn_launcher, &tv_sec, &tv_usec);
- elapsed = (((gdouble) now.tv_sec - tv_sec) * G_USEC_PER_SEC + (now.tv_usec - tv_usec)) / 1000.0;
+ sn_launcher_context_get_last_active_time (spawn->sn_launcher, &tv_sec, &tv_usec);
+ elapsed = now.tv_sec - tv_sec + ((gdouble) (now.tv_usec - tv_usec) / G_USEC_PER_SEC);
- /* check if the timeout was reached */
- if (elapsed >= XFCE_SPAWN_STARTUP_TIMEOUT)
- {
- /* abort the startup notification */
- sn_launcher_context_complete (spawn_data->sn_launcher);
- sn_launcher_context_unref (spawn_data->sn_launcher);
- spawn_data->sn_launcher = NULL;
- }
-
- GDK_THREADS_LEAVE ();
-
- /* keep the startup timeout if not elapsed */
- return (elapsed < XFCE_SPAWN_STARTUP_TIMEOUT);
+ return elapsed < XFCE_SPAWN_STARTUP_TIMEOUT;
}
@@ -99,23 +111,28 @@ xfce_spawn_startup_timeout (gpointer user_data)
static void
xfce_spawn_startup_timeout_destroy (gpointer user_data)
{
- XfceSpawnData *spawn_data = user_data;
+ XfceSpawn *spawn = user_data;
+ GPid pid;
- g_return_if_fail (spawn_data->sn_launcher == NULL);
+ spawn->timeout_id = 0;
- /* cancel the watch (if any) */
- if (spawn_data->watch_id != 0)
- g_source_remove (spawn_data->watch_id);
-
- /* make sure we don't leave zombies */
- g_child_watch_add_full (G_PRIORITY_LOW, spawn_data->pid,
- (GChildWatchFunc) g_spawn_close_pid,
- NULL, NULL);
+ if (G_LIKELY (spawn->sn_launcher != NULL))
+ {
+ /* abort the startup notification */
+ sn_launcher_context_complete (spawn->sn_launcher);
+ sn_launcher_context_unref (spawn->sn_launcher);
+ spawn->sn_launcher = NULL;
+ }
- /* release the startup data */
- g_slice_free (XfceSpawnData, spawn_data);
+ if (spawn->watch_id != 0 && spawn->ref_count == 0)
+ {
+ /* free spawn data and add watch to close pid so we don't leave zombies */
+ pid = spawn->pid;
+ g_source_remove (spawn->watch_id);
+ g_child_watch_add (pid, (GChildWatchFunc) g_spawn_close_pid, NULL);
+ }
}
-
+#endif
static void
@@ -123,26 +140,43 @@ xfce_spawn_startup_watch (GPid pid,
gint status,
gpointer user_data)
{
- XfceSpawnData *spawn_data = user_data;
+ XfceSpawn *spawn = user_data;
- g_return_if_fail (spawn_data->sn_launcher != NULL);
- g_return_if_fail (spawn_data->watch_id != 0);
- g_return_if_fail (spawn_data->pid == pid);
+ _libxfce4ui_return_if_fail (spawn->pid == pid);
- /* abort the startup notification (application exited) */
- sn_launcher_context_complete (spawn_data->sn_launcher);
- sn_launcher_context_unref (spawn_data->sn_launcher);
- spawn_data->sn_launcher = NULL;
+ if (spawn->cw_function != NULL)
+ spawn->cw_function (pid, status, spawn->cw_data);
- /* cancel the startup notification timeout */
- g_source_remove (spawn_data->timeout_id);
+ g_spawn_close_pid (pid);
}
+static void
+xfce_spawn_startup_watch_destroy (gpointer user_data)
+{
+ XfceSpawn *spawn = user_data;
+
+ spawn->watch_id = 0;
+
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+ if (spawn->timeout_id != 0)
+ g_source_remove (spawn->timeout_id);
+#endif
+
+ if (spawn->cw_notify != NULL)
+ spawn->cw_notify (spawn->cw_data);
+ else if (spawn->ref_count == 0)
+ g_slice_free (XfceSpawn, spawn);
+}
+
+
+
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
static gint
xfce_spawn_get_active_workspace_number (GdkScreen *screen)
{
+#ifdef GDK_WINDOWING_X11
GdkWindow *root;
gulong bytes_after_ret = 0;
gulong nitems_ret = 0;
@@ -189,93 +223,62 @@ xfce_spawn_get_active_workspace_number (GdkScreen *screen)
gdk_error_trap_pop ();
return ws_num;
+#else
+ /* dunno what to do on non-X11 window systems */
+ return 0;
+#endif
}
#endif
-/**
- * xfce_spawn_on_screen:
- * @screen : a #GdkScreen or %NULL to use the active screen,
- * see xfce_gdk_screen_get_active().
- * @working_directory : child's current working directory or %NULL to
- * inherit parent's.
- * @argv : child's argument vector.
- * @envp : child's environment vector or %NULL to inherit
- * parent's.
- * @flags : flags from #GSpawnFlags.
- * @startup_notify : whether to use startup notification.
- * @startup_timestamp : the timestamp to pass to startup notification, use
- * the event time here if possible to make focus
- * stealing prevention work property. If you don't
- * have direct access to the event time you could use
- * gtk_get_current_event_time() or if nothing is
- * available 0 is valid too.
- * @icon_name : application icon or %NULL.
- * @error : return location for errors or %NULL.
- *
- * Like gdk_spawn_on_screen(), but also supports startup notification
- * (if Libxfce4ui was built with startup notification support).
- *
- * Return value: %TRUE on success, %FALSE if @error is set.
- **/
-gboolean
-xfce_spawn_on_screen (GdkScreen *screen,
- const gchar *working_directory,
- gchar **argv,
- gchar **envp,
- GSpawnFlags flags,
- gboolean startup_notify,
- guint32 startup_timestamp,
- const gchar *icon_name,
- GError **error)
+static gboolean
+xfce_spawn_internal (GdkScreen *screen,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ gboolean startup_notify,
+ guint32 startup_timestamp,
+ const gchar *startup_icon_name,
+ GChildWatchFunc watch_function,
+ gpointer watch_data,
+ GDestroyNotify watch_notify,
+ XfceSpawn **spawn_return,
+ GError **error)
{
- gboolean succeed;
- gchar **cenvp;
- gint n;
- gint n_cenvp;
- gchar *display_name;
- GPid pid;
+ guint n;
+ guint n_cenvp;
+ gchar **cenvp;
+ gchar *display_name;
+ GPid pid;
+ gboolean succeed;
+ XfceSpawn *spawn;
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
- SnLauncherContext *sn_launcher = NULL;
- XfceSpawnData *spawn_data;
- SnDisplay *sn_display = NULL;
- gint sn_workspace;
+ SnLauncherContext *sn_launcher = NULL;
+ SnDisplay *sn_display = NULL;
+ gint sn_workspace;
+ const gchar *prgname;
#endif
g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- /* lookup the screen with the pointer */
- if (screen == NULL)
+ /* use the screen that currently contains the pointer */
+ if (G_UNLIKELY (screen == NULL))
screen = xfce_gdk_screen_get_active (NULL);
- /* setup the child environment, without startup id and display */
+ /* setup the child environment (stripping $DESKTOP_STARTUP_ID and $DISPLAY) */
if (G_LIKELY (envp == NULL))
- {
- /* use the portable g_listenv, but note that this function only returns the
- * variable names, not with values, therefore the call to g_getenv */
- envp = g_listenv ();
- cenvp = g_new0 (gchar *, g_strv_length (envp) + 3);
- for (n = n_cenvp = 0; envp[n] != NULL; n++)
- if (strcmp (envp[n], "DESKTOP_STARTUP_ID") != 0
- && strcmp (envp[n], "DISPLAY") != 0)
- cenvp[n_cenvp++] = g_strconcat (envp[n], "=", g_getenv (envp[n]), NULL);
-
- /* cleanup */
- g_strfreev (envp);
- envp = NULL;
- }
- else
- {
- cenvp = g_new0 (gchar *, g_strv_length (envp) + 3);
- for (n = n_cenvp = 0; envp[n] != NULL; n++)
- if (strncmp (envp[n], "DESKTOP_STARTUP_ID", 18) != 0
- && strncmp (envp[n], "DISPLAY", 7) != 0)
- cenvp[n_cenvp++] = g_strdup (envp[n]);
- }
-
- /* add the real display name */
+ envp = (gchar **) environ;
+ for (n = 0; envp[n] != NULL; ++n);
+ cenvp = g_new0 (gchar *, n + 3);
+ for (n_cenvp = n = 0; envp[n] != NULL; ++n)
+ if (strncmp (envp[n], "DESKTOP_STARTUP_ID", 18) != 0
+ && strncmp (envp[n], "DISPLAY", 7) != 0)
+ cenvp[n_cenvp++] = g_strdup (envp[n]);
+
+ /* add the real display name for the screen */
display_name = gdk_screen_make_display_name (screen);
cenvp[n_cenvp++] = g_strconcat ("DISPLAY=", display_name, NULL);
g_free (display_name);
@@ -290,16 +293,28 @@ xfce_spawn_on_screen (GdkScreen *screen,
if (G_LIKELY (sn_display != NULL))
{
+ /* create a new sn context */
sn_launcher = sn_launcher_context_new (sn_display, GDK_SCREEN_XNUMBER (screen));
- if (G_LIKELY (sn_launcher != NULL && !sn_launcher_context_get_initiated (sn_launcher)))
+ if (G_LIKELY (sn_launcher != NULL))
{
/* initiate the sn launcher context */
sn_workspace = xfce_spawn_get_active_workspace_number (screen);
- sn_launcher_context_set_binary_name (sn_launcher, argv[0]);
sn_launcher_context_set_workspace (sn_launcher, sn_workspace);
- sn_launcher_context_set_icon_name (sn_launcher, (icon_name != NULL) ? icon_name : "applications-other");
- sn_launcher_context_initiate (sn_launcher, g_get_prgname (), argv[0], startup_timestamp);
+
+ sn_launcher_context_set_binary_name (sn_launcher, argv[0]);
+
+ if (startup_icon_name == NULL)
+ startup_icon_name = "applications-other";
+ sn_launcher_context_set_icon_name (sn_launcher, startup_icon_name);
+
+ if (G_LIKELY (!sn_launcher_context_get_initiated (sn_launcher)))
+ {
+ prgname = g_get_prgname ();
+ if (prgname == NULL)
+ prgname = "unknown";
+ sn_launcher_context_initiate (sn_launcher, prgname, argv[0], startup_timestamp);
+ }
/* add the real startup id to the child environment */
cenvp[n_cenvp++] = g_strconcat ("DESKTOP_STARTUP_ID=", sn_launcher_context_get_startup_id (sn_launcher), NULL);
@@ -314,46 +329,278 @@ xfce_spawn_on_screen (GdkScreen *screen,
/* try to spawn the new process */
succeed = g_spawn_async (working_directory, argv, cenvp, flags, NULL, NULL, &pid, error);
+ /* release the child environment */
+ g_strfreev (cenvp);
+
+ if (G_LIKELY (succeed))
+ {
+ if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) != 0
+ || spawn_return != NULL)
+ {
+ spawn = g_slice_new0 (XfceSpawn);
+ spawn->pid = pid;
+ spawn->cw_function = watch_function;
+ spawn->cw_data = watch_data;
+ spawn->cw_notify = watch_notify;
+ spawn->ref_count = (spawn_return == NULL) ? 0 : 1;
+
+ spawn->watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid,
+ xfce_spawn_startup_watch,
+ spawn,
+ xfce_spawn_startup_watch_destroy);
+
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
- if (G_LIKELY (sn_launcher != NULL))
+ if (G_LIKELY (sn_launcher != NULL))
+ {
+ spawn->sn_launcher = sn_launcher;
+ spawn->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_LOW,
+ XFCE_SPAWN_STARTUP_TIMEOUT,
+ xfce_spawn_startup_timeout,
+ spawn,
+ xfce_spawn_startup_timeout_destroy);
+ }
+#endif
+
+ if (G_UNLIKELY (spawn_return != NULL))
+ *spawn_return = spawn;
+ }
+ }
+ else
{
- if (G_UNLIKELY (!succeed))
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+ if (G_LIKELY (sn_launcher != NULL))
{
/* abort the startup notification sequence */
sn_launcher_context_complete (sn_launcher);
sn_launcher_context_unref (sn_launcher);
}
- else
- {
- /* schedule a startup notification timeout */
- spawn_data = g_slice_new0 (XfceSpawnData);
- spawn_data->sn_launcher = sn_launcher;
- spawn_data->timeout_id = g_timeout_add_full (G_PRIORITY_LOW, XFCE_SPAWN_STARTUP_TIMEOUT, xfce_spawn_startup_timeout,
- spawn_data, xfce_spawn_startup_timeout_destroy);
- spawn_data->watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid, xfce_spawn_startup_watch, spawn_data, NULL);
- spawn_data->pid = pid;
- }
- }
- else if (G_LIKELY (succeed))
- {
- /* make sure we don't leave zombies */
- g_child_watch_add_full (G_PRIORITY_LOW, pid, (GChildWatchFunc) g_spawn_close_pid, NULL, NULL);
+#endif
}
- /* release the sn display */
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+ /* release the startup notification display */
if (G_LIKELY (sn_display != NULL))
sn_display_unref (sn_display);
#endif
- /* cleanup */
- g_strfreev (cenvp);
-
return succeed;
}
/**
+ * xfce_spawn_on_screen_watch:
+ * @screen : a #GdkScreen or %NULL to use the active screen,
+ * see xfce_gdk_screen_get_active().
+ * @working_directory : child's current working directory or %NULL to
+ * inherit parent's.
+ * @argv : child's argument vector.
+ * @envp : child's environment vector or %NULL to inherit
+ * parent's.
+ * @flags : flags from #GSpawnFlags.
+ * @startup_notify : whether to use startup notification.
+ * @startup_timestamp : the timestamp to pass to startup notification, use
+ * the event time here if possible to make focus
+ * stealing prevention work property. If you don't
+ * have direct access to the event time you could use
+ * gtk_get_current_event_time() or if nothing is
+ * available 0 is valid too.
+ * @startup_icon_name : application icon or %NULL. This icon is used in
+ * for example the tasklist when the application is
+ * starting.
+ * @watch_function : function that is called when the child exists, like
+ * you would use with g_child_watch_add(), but glib
+ * only allows 1 callback per process id.
+ * @watch_data : data to pass to @watch_function.
+ * @watch_notify : a function to call when @watch_data is no longer
+ * in use, or %NULL.
+ * @error : return location for errors or %NULL.
+ *
+ * Same as xfce_spawn_on_screen() but with support for watching the child
+ * and allowing to set a custom @envp.
+ *
+ * Returns: A new #XfceSpawn data structure with a ref count of 1
+ * or %NULL on when @error is set.
+ **/
+XfceSpawn *
+xfce_spawn_on_screen_watch (GdkScreen *screen,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ gboolean startup_notify,
+ guint32 startup_timestamp,
+ const gchar *startup_icon_name,
+ GChildWatchFunc watch_function,
+ gpointer watch_data,
+ GDestroyNotify watch_notify,
+ GError **error)
+{
+ XfceSpawn *spawn = NULL;
+
+ g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail ((flags & G_SPAWN_DO_NOT_REAP_CHILD) != 0, NULL);
+
+ xfce_spawn_internal (screen,
+ working_directory,
+ argv,
+ envp,
+ flags,
+ startup_notify,
+ startup_timestamp,
+ startup_icon_name,
+ watch_function,
+ watch_data,
+ watch_notify,
+ &spawn,
+ error);
+
+ return spawn;
+}
+
+
+
+/**
+ * xfce_spawn_ref:
+ * @spawn: the #XfceSpawn data from xfce_spawn_on_screen_watch().
+ *
+ * Increase the reference count on the @spawn data.
+ **/
+void
+xfce_spawn_ref (XfceSpawn *spawn)
+{
+ g_return_if_fail (spawn->ref_count > 0);
+ spawn->ref_count++;
+}
+
+
+
+/**
+ * xfce_spawn_unref:
+ * @spawn: the #XfceSpawn data from xfce_spawn_on_screen_watch().
+ *
+ * Decrease the reference count. If the reference count is 0, the
+ * watch functions will be set to %NULL and the spawn function will
+ * take care of freeing the data.
+ **/
+void
+xfce_spawn_unref (XfceSpawn *spawn)
+{
+ g_return_if_fail (spawn->ref_count > 0);
+
+ if (spawn->ref_count > 0
+ && --spawn->ref_count == 0)
+ {
+ /* unset the user watch data and functions */
+ spawn->cw_function = NULL;
+ spawn->cw_data = NULL;
+ spawn->cw_notify = NULL;
+
+ if (spawn->watch_id == 0)
+ {
+ /* free the data if the child already exited */
+ g_slice_free (XfceSpawn, spawn);
+ }
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+ else if (spawn->timeout_id == 0)
+ {
+ /* timeout already exited, remove our watch and
+ * add a child watch for closing the pid */
+ xfce_spawn_startup_timeout_destroy (spawn);
+ }
+#endif
+ }
+}
+
+
+
+/**
+ * xfce_spawn_set_callback:
+ * @spawn : the #XfceSpawn data from xfce_spawn_on_screen_watch().
+ * @watch_function : the @watch_function that should be called when the
+ * startup is finished or %NULL. Note that you should not
+ * handle g_spawn_close_pid() .
+ * @watch_data : the data to pass to callback function
+ * @watch_notify : a function to call when @watch_data is no longer in use,
+ * or %NULL.
+ *
+ * Use this function to set a new callback function for @spawn. You do
+ * not have to call this function before calling xfce_spawn_unref()
+ * to unset your functions, xfce_spawn_unref() will take care of all
+ * that.
+ **/
+void
+xfce_spawn_set_callback (XfceSpawn *spawn,
+ GChildWatchFunc watch_function,
+ gpointer watch_data,
+ GDestroyNotify watch_notify)
+{
+ g_return_if_fail (spawn->ref_count > 0);
+
+ /* set the new functions */
+ spawn->cw_function = watch_function;
+ spawn->cw_data = watch_data;
+ spawn->cw_notify = watch_notify;
+}
+
+
+
+/**
+ * xfce_spawn_on_screen:
+ * @screen : a #GdkScreen or %NULL to use the active screen,
+ * see xfce_gdk_screen_get_active().
+ * @working_directory : child's current working directory or %NULL to
+ * inherit parent's.
+ * @argv : child's argument vector.
+ * @envp : child's environment vector or %NULL to inherit
+ * parent's.
+ * @flags : flags from #GSpawnFlags.
+ * @startup_notify : whether to use startup notification.
+ * @startup_timestamp : the timestamp to pass to startup notification, use
+ * the event time here if possible to make focus
+ * stealing prevention work property. If you don't
+ * have direct access to the event time you could use
+ * gtk_get_current_event_time() or if nothing is
+ * available 0 is valid too.
+ * @startup_icon_name : application icon name or %NULL.
+ * @error : return location for errors or %NULL.
+ *
+ * Like gdk_spawn_on_screen(), but also supports startup notification
+ * (if Libxfce4ui is built with startup notification support).
+ *
+ * Return value: %TRUE on success, %FALSE if @error is set.
+ **/
+gboolean
+xfce_spawn_on_screen (GdkScreen *screen,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ gboolean startup_notify,
+ guint32 startup_timestamp,
+ const gchar *startup_icon_name,
+ GError **error)
+{
+ g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return xfce_spawn_internal (screen,
+ working_directory,
+ argv,
+ envp,
+ flags,
+ startup_notify,
+ startup_timestamp,
+ startup_icon_name,
+ NULL, NULL, NULL, /* watch functions */
+ NULL, /* spawn data return */
+ error);
+}
+
+
+
+/**
* xfce_spawn_command_line_on_screen:
* @screen : a #GdkScreen or %NULL to use the active screen, see xfce_gdk_screen_get_active().
* @command_line : command line to run.
@@ -376,7 +623,7 @@ xfce_spawn_command_line_on_screen (GdkScreen *screen,
GError **error)
{
gchar **argv;
- gboolean succeed;
+ gboolean result;
g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -400,15 +647,22 @@ xfce_spawn_command_line_on_screen (GdkScreen *screen,
argv[4] = NULL;
}
- /* execute the function */
- succeed = xfce_spawn_on_screen (screen, NULL, argv, NULL,
- G_SPAWN_SEARCH_PATH, startup_notify,
- gtk_get_current_event_time (), NULL, error);
+ /* try to spawn the command line */
+ result = xfce_spawn_internal (screen,
+ NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ startup_notify,
+ gtk_get_current_event_time (), /* best guess for timestamp */
+ NULL,
+ NULL, NULL, NULL, /* watch functions */
+ NULL, /* spawn data return */
+ error);
- /* cleanup */
g_strfreev (argv);
- return succeed;
+ return result;
}
diff --git a/libxfce4ui/xfce-spawn.h b/libxfce4ui/xfce-spawn.h
index e262206..f7e7b3d 100644
--- a/libxfce4ui/xfce-spawn.h
+++ b/libxfce4ui/xfce-spawn.h
@@ -29,21 +29,45 @@
G_BEGIN_DECLS
-gboolean xfce_spawn_on_screen (GdkScreen *screen,
- const gchar *working_directory,
- gchar **argv,
- gchar **envp,
- GSpawnFlags flags,
- gboolean startup_notify,
- guint32 startup_timestamp,
- const gchar *icon_name,
- GError **error);
-
-gboolean xfce_spawn_command_line_on_screen (GdkScreen *screen,
- const gchar *command_line,
- gboolean in_terminal,
- gboolean startup_notify,
- GError **error);
+typedef struct _XfceSpawn XfceSpawn;
+
+XfceSpawn *xfce_spawn_on_screen_watch (GdkScreen *screen,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ gboolean startup_notify,
+ guint32 startup_timestamp,
+ const gchar *startup_icon_name,
+ GChildWatchFunc watch_function,
+ gpointer watch_data,
+ GDestroyNotify watch_notify,
+ GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+void xfce_spawn_ref (XfceSpawn *spawn);
+
+void xfce_spawn_unref (XfceSpawn *spawn);
+
+void xfce_spawn_set_callback (XfceSpawn *spawn,
+ GChildWatchFunc watch_function,
+ gpointer watch_data,
+ GDestroyNotify watch_notify);
+
+gboolean xfce_spawn_on_screen (GdkScreen *screen,
+ const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ gboolean startup_notify,
+ guint32 startup_timestamp,
+ const gchar *startup_icon_name,
+ GError **error);
+
+gboolean xfce_spawn_command_line_on_screen (GdkScreen *screen,
+ const gchar *command_line,
+ gboolean in_terminal,
+ gboolean startup_notify,
+ GError **error);
G_END_DECLS
More information about the Xfce4-commits
mailing list