[Xfce4-commits] <libxfce4ui:master> Add new function xfce_spawn_on_screen_with_child_watch().

Nick Schermer noreply at xfce.org
Thu Dec 17 22:08:01 CET 2009


Updating branch refs/heads/master
         to 198674ebaa599a086e52dd1b37b5457bd8ebb72c (commit)
       from 43abf64e7606ddffabe66814ffac07d5c1596be2 (commit)

commit 198674ebaa599a086e52dd1b37b5457bd8ebb72c
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Dec 17 22:00:51 2009 +0100

    Add new function xfce_spawn_on_screen_with_child_watch().
    
    New function to spawn a command with child watch. For the callback
    a closure is used (void__int). Although the PID is not returned,
    this is good enough for most implementations.
    
    Internal change to use environ again instead of the glib code,
    which only resulted in a lot of string copying.
    
    Use seconds timeout to the startup expire time.

 configure.in.in               |    6 +-
 docs/libxfce4ui-sections.txt  |    1 +
 docs/tmpl/xfce-spawn.sgml     |   18 ++-
 libxfce4ui/libxfce4ui.symbols |    1 +
 libxfce4ui/xfce-spawn.c       |  415 ++++++++++++++++++++++++++++-------------
 libxfce4ui/xfce-spawn.h       |   41 +++--
 6 files changed, 330 insertions(+), 152 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/docs/libxfce4ui-sections.txt b/docs/libxfce4ui-sections.txt
index cc44425..31bb41c 100644
--- a/docs/libxfce4ui-sections.txt
+++ b/docs/libxfce4ui-sections.txt
@@ -15,6 +15,7 @@ LIBXFCE4UI_CHECK_VERSION
 
 <SECTION>
 <FILE>xfce-spawn</FILE>
+xfce_spawn_on_screen_with_child_watch
 xfce_spawn_on_screen
 xfce_spawn_command_line_on_screen
 </SECTION>
diff --git a/docs/tmpl/xfce-spawn.sgml b/docs/tmpl/xfce-spawn.sgml
index 0aca5cb..6167d5b 100644
--- a/docs/tmpl/xfce-spawn.sgml
+++ b/docs/tmpl/xfce-spawn.sgml
@@ -17,6 +17,22 @@ startup notification and they show up on the correct screen and workspace.
 
 <!-- ##### SECTION Stability_Level ##### -->
 
+<!-- ##### FUNCTION xfce_spawn_on_screen_with_child_watch ##### -->
+<para>
+
+</para>
+
+ at screen: 
+ at working_directory: 
+ at argv: 
+ at envp: 
+ at flags: 
+ at startup_notify: 
+ at startup_timestamp: 
+ at startup_icon_name: 
+ at child_watch_closure: 
+ at error: 
+ at Returns: 
 
 <!-- ##### FUNCTION xfce_spawn_on_screen ##### -->
 <para>
@@ -30,7 +46,7 @@ startup notification and they show up on the correct screen and workspace.
 @flags: 
 @startup_notify: 
 @startup_timestamp: 
- at icon_name: 
+ at startup_icon_name: 
 @error: 
 @Returns: 
 
diff --git a/libxfce4ui/libxfce4ui.symbols b/libxfce4ui/libxfce4ui.symbols
index 304b589..9e9b9fe 100644
--- a/libxfce4ui/libxfce4ui.symbols
+++ b/libxfce4ui/libxfce4ui.symbols
@@ -87,6 +87,7 @@ 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_with_child_watch
 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..6c29c64 100644
--- a/libxfce4ui/xfce-spawn.c
+++ b/libxfce4ui/xfce-spawn.c
@@ -29,12 +29,18 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h> /* for _NSGetEnviron */
+#endif
 
 #include <gdk/gdk.h>
 
 #ifdef GDK_WINDOWING_X11
 #include <X11/Xatom.h>
 #include <gdk/gdkx.h>
+#else
+/* no x11, no sn */
+#undef HAVE_LIBSTARTUP_NOTIFICATION
 #endif
 
 #ifdef HAVE_LIBSTARTUP_NOTIFICATION
@@ -46,23 +52,36 @@
 #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
 {
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+  /* startup notification data */
   SnLauncherContext *sn_launcher;
   guint              timeout_id;
+#endif
+
+  /* child watch data */
   guint              watch_id;
   GPid               pid;
+  GClosure          *closure;
 } XfceSpawnData;
 
 
 
-
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
 static gboolean
 xfce_spawn_startup_timeout (gpointer user_data)
 {
@@ -72,74 +91,103 @@ xfce_spawn_startup_timeout (gpointer user_data)
   glong          tv_sec;
   glong          tv_usec;
 
-  GDK_THREADS_ENTER ();
+  g_return_val_if_fail (spawn_data->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;
+  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;
-    }
+  return elapsed < XFCE_SPAWN_STARTUP_TIMEOUT;
+}
 
-  GDK_THREADS_LEAVE ();
 
-  /* keep the startup timeout if not elapsed */
-  return (elapsed < XFCE_SPAWN_STARTUP_TIMEOUT);
+
+static void
+xfce_spawn_startup_timeout_destroy (gpointer user_data)
+{
+  XfceSpawnData *spawn_data = user_data;
+  GPid           pid;
+
+  spawn_data->timeout_id = 0;
+
+  if (G_LIKELY (spawn_data->sn_launcher != NULL))
+   {
+     /* 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;
+   }
+
+  /* if there is no closure to watch the child, also stop
+   * the child watch */
+  if (G_LIKELY (spawn_data->closure == NULL
+                && spawn_data->watch_id != 0))
+    {
+      pid = spawn_data->pid;
+      g_source_remove (spawn_data->watch_id);
+      g_child_watch_add (pid, (GChildWatchFunc) g_spawn_close_pid, NULL);
+    }
 }
+#endif
 
 
 
 static void
-xfce_spawn_startup_timeout_destroy (gpointer user_data)
+xfce_spawn_startup_watch (GPid     pid,
+                          gint     status,
+                          gpointer user_data)
 {
   XfceSpawnData *spawn_data = user_data;
+  GValue         instance_and_params[2] = { { 0, }, { 0, } };
 
-  g_return_if_fail (spawn_data->sn_launcher == NULL);
+  g_return_if_fail (spawn_data->pid == pid);
 
-  /* cancel the watch (if any) */
-  if (spawn_data->watch_id != 0)
-    g_source_remove (spawn_data->watch_id);
+  if (G_UNLIKELY (spawn_data->closure != NULL))
+    {
+      /* xfce spawn has no instance */
+      g_value_init (&instance_and_params[0], G_TYPE_POINTER);
+      g_value_set_pointer (&instance_and_params[0], NULL);
 
-  /* 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);
+      g_value_init (&instance_and_params[1], G_TYPE_INT);
+      g_value_set_int (&instance_and_params[1], status);
 
-  /* release the startup data */
-  g_slice_free (XfceSpawnData, spawn_data);
+      g_closure_set_marshal (spawn_data->closure, g_cclosure_marshal_VOID__INT);
+
+      g_closure_invoke (spawn_data->closure, NULL,
+                        2, instance_and_params, NULL);
+    }
+
+  /* don't leave zombies */
+  g_spawn_close_pid (pid);
 }
 
 
 
 static void
-xfce_spawn_startup_watch (GPid     pid,
-                          gint     status,
-                          gpointer user_data)
+xfce_spawn_startup_watch_destroy (gpointer user_data)
 {
   XfceSpawnData *spawn_data = 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);
+  spawn_data->watch_id = 0;
+
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+  if (spawn_data->timeout_id != 0)
+    g_source_remove (spawn_data->timeout_id);
+#endif
 
-  /* 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 (G_UNLIKELY (spawn_data->closure != NULL))
+    {
+      g_closure_invalidate (spawn_data->closure);
+      g_closure_unref (spawn_data->closure);
+    }
 
-  /* cancel the startup notification timeout */
-  g_source_remove (spawn_data->timeout_id);
+  g_slice_free (XfceSpawnData, spawn_data);
 }
 
 
 
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
 static gint
 xfce_spawn_get_active_workspace_number (GdkScreen *screen)
 {
@@ -195,87 +243,108 @@ xfce_spawn_get_active_workspace_number (GdkScreen *screen)
 
 
 /**
- * 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.
+ * xfce_spawn_on_screen_with_closure:
+ * @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. #G_SPAWN_DO_NOT_REAP_CHILD
+ *                        is not allowed, you should use the
+ *                        @child_watch_closure for this.
+ * @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.
+ * @child_watch_closure : closure that is triggered when the child exists
+ *                        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).
+ * Like xfce_spawn_on_screen(), but allows to attach a closure to watch the
+ * child's exit status. This because only one g_child_watch_add() is allowed on
+ * Unix (per PID) and this is already internally needed for a proper
+ * startup notification implementation.
+ *
+ * <example>
+ * <title>Spawning with a child watch</title>
+ * <programlisting>
+ * static void
+ * child_watch_callback (GObject *object,
+ *                       gint     status)
+ * {
+ *   g_message ("Child exit status is %d", status);
+ * }
+ *
+ * static void
+ * spawn_something (void)
+ * {
+ *   GClosure *child_watch;
+ *
+ *   child_watch = g_cclosure_new_swap (G_CALLBACK (child_watch_callback),
+ *                                      object, NULL);
+ *   xfce_spawn_on_screen_with_child_watch (...,
+ *                                          child_watch,
+ *                                          ...);
+ * }
+ * </programlisting>
+ * </example>
  *
  * 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)
+xfce_spawn_on_screen_with_child_watch (GdkScreen    *screen,
+                                       const gchar  *working_directory,
+                                       gchar       **argv,
+                                       gchar       **envp,
+                                       GSpawnFlags   flags,
+                                       gboolean      startup_notify,
+                                       guint32       startup_timestamp,
+                                       const gchar  *startup_icon_name,
+                                       GClosure     *child_watch_closure,
+                                       GError      **error)
 {
-  gboolean           succeed;
-  gchar            **cenvp;
-  gint               n;
-  gint               n_cenvp;
-  gchar             *display_name;
-  GPid               pid;
+  gboolean            succeed;
+  gchar             **cenvp;
+  guint               n;
+  guint               n_cenvp;
+  gchar              *display_name;
+  GPid                pid;
+  XfceSpawnData      *spawn_data;
 #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        *startup_id;
+  const gchar        *prgname;
 #endif
 
   g_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), FALSE);
+  g_return_val_if_fail ((flags & G_SPAWN_DO_NOT_REAP_CHILD) == 0, FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
   /* lookup the screen with the pointer */
   if (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))
+    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)
     {
-      /* 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]);
+      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 */
+  /* 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);
@@ -291,18 +360,27 @@ xfce_spawn_on_screen (GdkScreen    *screen,
       if (G_LIKELY (sn_display != NULL))
         {
           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]);
+              sn_launcher_context_set_icon_name (sn_launcher, startup_icon_name != NULL ?
+                                                 startup_icon_name : "applications-other");
+
+              if (G_LIKELY (!sn_launcher_context_get_initiated (sn_launcher)))
+                {
+                  prgname = g_get_prgname ();
+                  sn_launcher_context_initiate (sn_launcher, prgname != NULL ?
+                                                prgname : "unknown", 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);
+              startup_id = sn_launcher_context_get_startup_id (sn_launcher);
+              if (G_LIKELY (startup_id != NULL))
+                cenvp[n_cenvp++] = g_strconcat ("DESKTOP_STARTUP_ID=", startup_id, NULL);
 
               /* we want to watch the child process */
               flags |= G_SPAWN_DO_NOT_REAP_CHILD;
@@ -311,49 +389,120 @@ xfce_spawn_on_screen (GdkScreen    *screen,
     }
 #endif
 
+  /* watch the child when the user supplied a closure too */
+  if (child_watch_closure != NULL)
+    flags |= G_SPAWN_DO_NOT_REAP_CHILD;
+
   /* try to spawn the new process */
-  succeed = g_spawn_async (working_directory, argv, cenvp, flags, NULL, NULL, &pid, error);
+  succeed = g_spawn_async (working_directory, argv, cenvp, flags, NULL,
+                           NULL, &pid, error);
 
-#ifdef HAVE_LIBSTARTUP_NOTIFICATION
-  if (G_LIKELY (sn_launcher != NULL))
+  g_strfreev (cenvp);
+
+  if (G_LIKELY (succeed))
     {
-      if (G_UNLIKELY (!succeed))
+      if ((flags & G_SPAWN_DO_NOT_REAP_CHILD) != 0)
         {
-          /* abort the startup notification sequence */
-          sn_launcher_context_complete (sn_launcher);
-          sn_launcher_context_unref (sn_launcher);
-        }
-      else
-        {
-          /* schedule a startup notification timeout */
+          /* setup data to watch the child */
           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;
+          if (child_watch_closure != NULL)
+            {
+              spawn_data->closure = g_closure_ref (child_watch_closure);
+              g_closure_sink (spawn_data->closure);
+            }
+
+          spawn_data->watch_id = g_child_watch_add_full (G_PRIORITY_LOW, pid,
+                                                         xfce_spawn_startup_watch,
+                                                         spawn_data,
+                                                         xfce_spawn_startup_watch_destroy);
+
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
+          if (G_LIKELY (sn_launcher != NULL))
+            {
+              /* start a timeout to stop the startup notification sequence after
+               * a certain about of time, to handle applications that do not
+               * properly implement startup notify */
+              spawn_data->sn_launcher = sn_launcher;
+              spawn_data->timeout_id = g_timeout_add_seconds_full (G_PRIORITY_LOW,
+                                                                   XFCE_SPAWN_STARTUP_TIMEOUT,
+                                                                   xfce_spawn_startup_timeout,
+                                                                   spawn_data,
+                                                                   xfce_spawn_startup_timeout_destroy);
+            }
+#endif
         }
     }
-  else if (G_LIKELY (succeed))
+  else
     {
-      /* make sure we don't leave zombies */
-      g_child_watch_add_full (G_PRIORITY_LOW, pid, (GChildWatchFunc) g_spawn_close_pid, NULL, NULL);
+#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);
+        }
+#endif
     }
 
+#ifdef HAVE_LIBSTARTUP_NOTIFICATION
   /* release the sn display */
   if (G_LIKELY (sn_display != NULL))
     sn_display_unref (sn_display);
 #endif
 
-  /* cleanup */
-  g_strfreev (cenvp);
-
   return succeed;
 }
 
 
 
 /**
+ * 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. #G_SPAWN_DO_NOT_REAP_CHILD
+ *                      is not allowed, use xfce_spawn_on_screen_with_child_watch()
+ *                      if you want a child watch.
+ * @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.
+ * @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  *startup_icon_name,
+                      GError      **error)
+{
+  return xfce_spawn_on_screen_with_child_watch (screen, working_directory, argv,
+                                                envp, flags, startup_notify,
+                                                startup_timestamp, startup_icon_name,
+                                                NULL, 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.
@@ -382,7 +531,6 @@ xfce_spawn_command_line_on_screen (GdkScreen    *screen,
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
   g_return_val_if_fail (command_line != NULL, FALSE);
 
-  /* parse the command */
   if (in_terminal == FALSE)
     {
       /* parse the command, retrun false with error when this fails */
@@ -400,12 +548,11 @@ 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);
+  succeed = xfce_spawn_on_screen_with_child_watch (screen, NULL, argv, NULL,
+                                                   G_SPAWN_SEARCH_PATH, startup_notify,
+                                                   gtk_get_current_event_time (),
+                                                   NULL, NULL, error);
 
-  /* cleanup */
   g_strfreev (argv);
 
   return succeed;
diff --git a/libxfce4ui/xfce-spawn.h b/libxfce4ui/xfce-spawn.h
index e262206..486f30e 100644
--- a/libxfce4ui/xfce-spawn.h
+++ b/libxfce4ui/xfce-spawn.h
@@ -29,21 +29,32 @@
 
 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);
+gboolean xfce_spawn_on_screen_with_child_watch (GdkScreen    *screen,
+                                                const gchar  *working_directory,
+                                                gchar       **argv,
+                                                gchar       **envp,
+                                                GSpawnFlags   flags,
+                                                gboolean      startup_notify,
+                                                guint32       startup_timestamp,
+                                                const gchar  *startup_icon_name,
+                                                GClosure     *child_watch_closure,
+                                                GError      **error);
+
+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