[glib/wip/subprocess-2013: 5/6] subprocess WIP



commit d8913abf3b05f701da53cbe39f661a68ffb4d217
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Jan 18 13:01:11 2013 -0500

    subprocess WIP

 gio/Makefile.am                                    |    6 +-
 gio/gio.h                                          |    2 +-
 gio/gioenums.h                                     |   26 +-
 gio/giotypes.h                                     |    4 +-
 gio/gsubprocess.c                                  |  234 +++++----
 gio/gsubprocess.h                                  |   68 ++--
 gio/gsubprocesscontext.c                           |  307 -----------
 gio/gsubprocesscontext.h                           |  118 -----
 ...ext-private.h => gsubprocesslauncher-private.h} |   22 +-
 gio/gsubprocesslauncher.c                          |  536 ++++++++++++++++++++
 gio/gsubprocesslauncher.h                          |  102 ++++
 11 files changed, 824 insertions(+), 601 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fd0e4c0..57767d8 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -424,9 +424,9 @@ libgio_2_0_la_SOURCES =		\
 	gsocketlistener.c	\
 	gsocketoutputstream.c	\
 	gsocketoutputstream.h	\
+	gsubprocesslauncher.c	\
 	gsubprocess.c		\
-	gsubprocesscontext.c	\
-	gsubprocesscontext-private.h	\
+	gsubprocesslauncher-private.h	\
 	gproxy.c		\
 	gproxyaddress.c         \
 	gproxyaddressenumerator.c \
@@ -592,7 +592,7 @@ gio_headers =			\
 	gsrvtarget.h		\
 	gtask.h			\
 	gsubprocess.h		\
-	gsubprocesscontext.h	\
+	gsubprocesslauncher.h	\
 	gtcpconnection.h	\
 	gtcpwrapperconnection.h \
 	gthreadedsocketservice.h\
diff --git a/gio/gio.h b/gio/gio.h
index f52e01b..45e9eff 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -124,7 +124,7 @@
 #include <gio/gsrvtarget.h>
 #include <gio/gtask.h>
 #include <gio/gsubprocess.h>
-#include <gio/gsubprocesscontext.h>
+#include <gio/gsubprocesslauncher.h>
 #include <gio/gtcpconnection.h>
 #include <gio/gtcpwrapperconnection.h>
 #include <gio/gtestdbus.h>
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 53798aa..7b7dd6b 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1659,23 +1659,25 @@ typedef enum /*< flags >*/ {
 } GTestDBusFlags;
 
 /**
- * GSubprocessStreamDisposition:
- * @G_SUBPROCESS_STREAM_DISPOSITION_NULL: Redirect to operating system's null output stream
- * @G_SUBPROCESS_STREAM_DISPOSITION_INHERIT: Keep the stream from the parent process
- * @G_SUBPROCESS_STREAM_DISPOSITION_PIPE: Open a private unidirectional channel between the processes
- * @G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE: Only applicable to standard error; causes it to be merged with standard output
+ * GSubprocessFlags:
+ * @G_SUBPROCESS_FLAGS_NONE: No flags.
  *
- * Flags to define the behaviour of the standard input/output/error of
- * a #GSubprocess.
+ * Flags to define the behaviour of a #GSubprocess.
  *
  * Since: 2.36
  **/
 typedef enum {
-  G_SUBPROCESS_STREAM_DISPOSITION_NULL,
-  G_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
-  G_SUBPROCESS_STREAM_DISPOSITION_PIPE,
-  G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE
-} GSubprocessStreamDisposition;
+  G_SUBPROCESS_FLAGS_NONE                  = 0,
+  G_SUBPROCESS_FLAGS_SEARCH_PATH           = (1u << 0),
+  G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP = (1u << 1),
+  G_SUBPROCESS_FLAGS_STDIN_PIPE            = (1u << 2),
+  G_SUBPROCESS_FLAGS_STDIN_INHERIT         = (1u << 3),
+  G_SUBPROCESS_FLAGS_STDOUT_PIPE           = (1u << 4),
+  G_SUBPROCESS_FLAGS_STDOUT_SILENCE        = (1u << 5),
+  G_SUBPROCESS_FLAGS_STDERR_PIPE           = (1u << 6),
+  G_SUBPROCESS_FLAGS_STDERR_SILENCE        = (1u << 7),
+  G_SUBPROCESS_FLAGS_STDERR_MERGE          = (1u << 8)
+} GSubprocessFlags;
 
 G_END_DECLS
 
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 30c6701..733bc48 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -478,13 +478,13 @@ typedef struct _GTestDBus GTestDBus;
  */
 typedef struct _GSubprocess                   GSubprocess;
 /**
- * GSubprocessContext:
+ * GSubprocessLauncher:
  *
  * Options for launching a child process.
  *
  * Since: 2.36
  */
-typedef struct _GSubprocessContext            GSubprocessContext;
+typedef struct _GSubprocessLauncher           GSubprocessLauncher;
 
 G_END_DECLS
 
diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c
index 8e70aaa..a2e4105 100644
--- a/gio/gsubprocess.c
+++ b/gio/gsubprocess.c
@@ -38,7 +38,7 @@
 
 #include "config.h"
 #include "gsubprocess.h"
-#include "gsubprocesscontext-private.h"
+#include "gsubprocesslauncher-private.h"
 #include "gasyncresult.h"
 #include "giostream.h"
 #include "gmemoryinputstream.h"
@@ -77,7 +77,11 @@ struct _GSubprocess
 {
   GObject parent;
 
-  GSubprocessContext *context;
+  /* only used during construction */
+  GSubprocessFlags flags;
+  gchar **argv;
+
+  GSubprocessLauncher *launcher;
   GPid pid;
 
   guint pid_valid : 1;
@@ -96,7 +100,8 @@ G_DEFINE_TYPE_WITH_CODE (GSubprocess, g_subprocess, G_TYPE_OBJECT,
 enum
 {
   PROP_0,
-  PROP_CONTEXT,
+  PROP_FLAGS,
+  PROP_ARGV,
   N_PROPS
 };
 
@@ -143,27 +148,12 @@ g_subprocess_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_CONTEXT:
-      self->context = g_value_dup_object (value);
+    case PROP_FLAGS:
+      self->flags = g_value_get_flags (value);
       break;
 
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-static void
-g_subprocess_get_property (GObject    *object,
-                           guint       prop_id,
-                           GValue     *value,
-                           GParamSpec *pspec)
-{
-  GSubprocess *self = G_SUBPROCESS (object);
-
-  switch (prop_id)
-    {
-    case PROP_CONTEXT:
-      g_value_set_object (value, self->context);
+    case PROP_ARGV:
+      self->argv = g_value_dup_boxed (value);
       break;
 
     default:
@@ -177,18 +167,14 @@ g_subprocess_class_init (GSubprocessClass *class)
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
   gobject_class->finalize = g_subprocess_finalize;
-  gobject_class->get_property = g_subprocess_get_property;
   gobject_class->set_property = g_subprocess_set_property;
 
-  /**
-   * GSubprocess:context:
-   *
-   *
-   * Since: 2.36
-   */
-  g_subprocess_pspecs[PROP_CONTEXT] = g_param_spec_object ("context", P_("Context"), P_("Subprocess options"), G_TYPE_SUBPROCESS_CONTEXT,
-							   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-							   G_PARAM_STATIC_STRINGS);
+  g_subprocess_pspecs[PROP_FLAGS] = g_param_spec_flags ("flags", P_("Flags"), P_("Subprocess flags"),
+                                                        G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE |
+                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+  g_subprocess_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", P_("Arguments"), P_("Argument vector"),
+                                                       G_TYPE_STRV, G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (gobject_class, N_PROPS, g_subprocess_pspecs);
 }
@@ -326,92 +312,79 @@ initable_init (GInitable     *initable,
    *
    * First, stdin.
    */
+  if (self->flags & G_SUBPROCESS_FLAGS_STDIN_INHERIT)
+    spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
+  else if (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE)
+    pipe_ptrs[0] = &pipe_fds[0];
 #ifdef G_OS_UNIX
-  if (self->context->stdin_fd != -1)
-    child_data.fds[0] = self->context->stdin_fd;
-  else if (self->context->stdin_path != NULL)
+  else if (self->launcher)
     {
-      child_data.fds[0] = close_fds[0] = unix_open_file (self->context->stdin_path, 
-							 O_RDONLY, error);
-      if (child_data.fds[0] == -1)
-	goto out;
+      if (self->launcher->stdin_fd != -1)
+        child_data.fds[0] = self->launcher->stdin_fd;
+      else if (self->launcher->stdin_path != NULL)
+        {
+          child_data.fds[0] = close_fds[0] = unix_open_file (self->launcher->stdin_path, O_RDONLY, error);
+          if (child_data.fds[0] == -1)
+            goto out;
+        }
     }
-  else
 #endif
-  if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
-    ; /* nothing */
-  else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
-    spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
-  else if (self->context->stdin_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
-    pipe_ptrs[0] = &pipe_fds[0];
-  else
-    g_assert_not_reached ();
 
   /* Next, stdout. */
+  if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
+    spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
+  else if (self->flags & G_SUBPROCESS_FLAGS_STDOUT_PIPE)
+    pipe_ptrs[1] = &pipe_fds[1];
 #ifdef G_OS_UNIX
-  if (self->context->stdout_fd != -1)
-    child_data.fds[1] = self->context->stdout_fd;
-  else if (self->context->stdout_path != NULL)
+  else if (self->launcher)
     {
-      child_data.fds[1] = close_fds[1] = unix_open_file (self->context->stdout_path, 
-							 O_CREAT | O_WRONLY, error);
-      if (child_data.fds[1] == -1)
-	goto out;
+      if (self->launcher->stdout_fd != -1)
+        child_data.fds[1] = self->launcher->stdout_fd;
+      else if (self->launcher->stdout_path != NULL)
+        {
+          child_data.fds[1] = close_fds[1] = unix_open_file (self->launcher->stdout_path,
+                                                             O_CREAT | O_WRONLY, error);
+          if (child_data.fds[1] == -1)
+            goto out;
+        }
     }
-  else
 #endif
-  if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
-    spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
-  else if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
-    ; /* Nothing */
-  else if (self->context->stdout_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
-    pipe_ptrs[1] = &pipe_fds[1];
-  else
-    g_assert_not_reached ();
 
   /* Finally, stderr. */
+  if (self->flags & G_SUBPROCESS_FLAGS_STDERR_SILENCE)
+    spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
+  else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
+    pipe_ptrs[2] = &pipe_fds[2];
 #ifdef G_OS_UNIX
-  if (self->context->stderr_fd != -1)
-    child_data.fds[2] = self->context->stderr_fd;
-  else if (self->context->stderr_path != NULL)
+  if (self->launcher)
     {
-      child_data.fds[2] = close_fds[2] = unix_open_file (self->context->stderr_path, 
-							 O_CREAT | O_WRONLY, error);
-      if (child_data.fds[2] == -1)
-	goto out;
+      if (self->launcher->stderr_fd != -1)
+        child_data.fds[2] = self->launcher->stderr_fd;
+      else if (self->launcher->stderr_path != NULL)
+        {
+          child_data.fds[2] = close_fds[2] = unix_open_file (self->launcher->stderr_path,
+                                                             O_CREAT | O_WRONLY, error);
+          if (child_data.fds[2] == -1)
+            goto out;
+        }
     }
-  else
 #endif
-  if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_NULL)
-    spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
-  else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
-    ; /* Nothing */
-  else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_PIPE)
-    pipe_ptrs[2] = &pipe_fds[2];
-  else if (self->context->stderr_disposition == G_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE)
-    /* This will work because stderr gets setup after stdout. */
-    child_data.fds[2] = 1;
-  else
-    g_assert_not_reached ();
-
-  if (self->context->keep_descriptors)
-    spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
 
-  if (self->context->search_path)
+  if (self->flags & G_SUBPROCESS_FLAGS_SEARCH_PATH)
     spawn_flags |= G_SPAWN_SEARCH_PATH;
-  else if (self->context->search_path_from_envp)
+
+  else if (self->flags & G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP)
     spawn_flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP;
-  else if (!g_path_is_absolute (((gchar**)self->context->argv->pdata)[0]))
-    spawn_flags |= G_SPAWN_SEARCH_PATH;
 
+  spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
   spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD;
   spawn_flags |= G_SPAWN_CLOEXEC_PIPES;
 
-  child_data.child_setup_func = self->context->child_setup_func;
-  child_data.child_setup_data = self->context->child_setup_data;
-  success = g_spawn_async_with_pipes (self->context->cwd,
-				      (char**)self->context->argv->pdata,
-				      self->context->envp,
+  child_data.child_setup_func = self->launcher ? self->launcher->child_setup_func : NULL;
+  child_data.child_setup_data = self->launcher ? self->launcher->child_setup_user_data : NULL;
+  success = g_spawn_async_with_pipes (self->launcher ? self->launcher->cwd : NULL,
+                                      self->argv,
+                                      self->launcher ? self->launcher->envp : NULL,
                                       spawn_flags,
                                       child_setup, &child_data,
                                       &self->pid,
@@ -439,23 +412,66 @@ initable_iface_init (GInitableIface *initable_iface)
 }
 
 /**
- * g_subprocess_new:
+ * g_subprocess_new: (skip)
+ *
+ * Create a new process with the given flags and varargs argument list.
+ *
+ * The argument list must be terminated with %NULL.
+ *
+ * Returns: A newly created #GSubprocess, or %NULL on error (and @error
+ *   will be set)
+ *
+ * Since: 2.36
+ */
+GSubprocess *
+g_subprocess_new (GSubprocessFlags   flags,
+                  GError           **error,
+                  const gchar       *argv0,
+                  ...)
+{
+  GSubprocess *result;
+  GPtrArray *args;
+  const gchar *arg;
+  va_list ap;
+
+  g_return_val_if_fail (argv0 != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  args = g_ptr_array_new ();
+
+  va_start (ap, argv0);
+  g_ptr_array_add (args, (gchar *) argv0);
+  while ((arg = va_arg (ap, const gchar *)))
+    g_ptr_array_add (args, (gchar *) arg);
+
+  result = g_subprocess_newv ((const gchar * const *) args->pdata, flags, error);
+
+  g_ptr_array_free (args, TRUE);
+
+  return result;
+}
+
+/**
+ * g_subprocess_newv:
+ *
+ * Create a new process with the given flags and argument list.
  *
- * Create a new process, using the parameters specified by
- * GSubprocessContext.
+ * The argument list is expected to be %NULL-terminated.
  *
- * Returns: (transfer full): A newly created %GSubprocess, or %NULL on error (and @error will be set)
+ * Returns: A newly created #GSubprocess, or %NULL on error (and @error
+ *   will be set)
  *
  * Since: 2.36
+ * Rename to: g_subprocess_new
  */
-GLIB_AVAILABLE_IN_2_36
 GSubprocess *
-g_subprocess_new (GSubprocessContext   *context,
-		  GError              **error)
+g_subprocess_newv (const gchar * const  *argv,
+                   GSubprocessFlags      flags,
+                   GError              **error)
 {
-  return g_initable_new (G_TYPE_SUBPROCESS,
-                         NULL, error,
-                         "context", context,
+  return g_initable_new (G_TYPE_SUBPROCESS, NULL, error,
+                         "argv", argv,
+                         "flags", flags,
                          NULL);
 }
 
@@ -566,10 +582,10 @@ g_subprocess_on_child_exited (GPid       pid,
  * Since: 2.36
  */
 void
-g_subprocess_wait (GSubprocess                *self,
-		   GCancellable               *cancellable,
-		   GAsyncReadyCallback         callback,
-		   gpointer                    user_data)
+g_subprocess_wait_async (GSubprocess         *self,
+                         GCancellable        *cancellable,
+                         GAsyncReadyCallback  callback,
+                         gpointer             user_data)
 {
   GSource *source;
   GSubprocessWatchData *data;
diff --git a/gio/gsubprocess.h b/gio/gsubprocess.h
index 2af5363..acd29a2 100644
--- a/gio/gsubprocess.h
+++ b/gio/gsubprocess.h
@@ -36,68 +36,68 @@ G_BEGIN_DECLS
 #define G_IS_SUBPROCESS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS))
 
 GLIB_AVAILABLE_IN_2_36
-GType            g_subprocess_get_type (void) G_GNUC_CONST;
+GType            g_subprocess_get_type                  (void) G_GNUC_CONST;
 
 /**** Core API ****/
 
 GLIB_AVAILABLE_IN_2_36
-GSubprocess *    g_subprocess_new (GSubprocessContext   *context,
-				   GError               **error);
+GSubprocess *    g_subprocess_new                       (GSubprocessFlags        flags,
+                                                         GError                **error,
+                                                         const gchar            *argv0,
+                                                         ...) G_GNUC_NULL_TERMINATED;
+GLIB_AVAILABLE_IN_2_36
+GSubprocess *    g_subprocess_newv                      (const gchar * const  *argv,
+                                                         GSubprocessFlags      flags,
+                                                         GError              **error);
 
 GLIB_AVAILABLE_IN_2_36
-GOutputStream *    g_subprocess_get_stdin_pipe (GSubprocess       *self);
+GOutputStream *    g_subprocess_get_stdin_pipe          (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-GInputStream *   g_subprocess_get_stdout_pipe (GSubprocess      *self);
+GInputStream *   g_subprocess_get_stdout_pipe           (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-GInputStream *   g_subprocess_get_stderr_pipe (GSubprocess      *self);
+GInputStream *   g_subprocess_get_stderr_pipe           (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-void             g_subprocess_wait (GSubprocess                *self,
-				    GCancellable               *cancellable,
-				    GAsyncReadyCallback         callback,
-				    gpointer                    user_data);
+GPid             g_subprocess_get_pid                   (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-gboolean         g_subprocess_wait_finish (GSubprocess                *self,
-					   GAsyncResult               *result,
-					   int                        *out_exit_status,
-					   GError                    **error);
+void             g_subprocess_request_exit              (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-gboolean         g_subprocess_wait_sync (GSubprocess   *self,
-					 int           *out_exit_status,
-					 GCancellable  *cancellable,
-					 GError       **error);
+void             g_subprocess_force_exit                (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-gboolean         g_subprocess_wait_sync_check (GSubprocess   *self,
-					       GCancellable  *cancellable,
-					       GError       **error);
+gboolean         g_subprocess_wait                      (GSubprocess          *self,
+                                                         GCancellable         *cancellable,
+                                                         GError              **error);
 
 GLIB_AVAILABLE_IN_2_36
-GPid             g_subprocess_get_pid (GSubprocess     *self);
+void             g_subprocess_wait_async                (GSubprocess          *self,
+                                                         GCancellable         *cancellable,
+                                                         GAsyncReadyCallback   callback,
+                                                         gpointer              user_data);
 
 GLIB_AVAILABLE_IN_2_36
-gboolean         g_subprocess_request_exit (GSubprocess       *self);
+gboolean         g_subprocess_wait_finish               (GSubprocess          *self,
+                                                         GAsyncResult         *result,
+                                                         GError              **error);
 
 GLIB_AVAILABLE_IN_2_36
-void             g_subprocess_force_exit (GSubprocess       *self);
+gboolean         g_subprocess_get_successful            (GSubprocess          *self);
 
-/** High level helpers **/
+GLIB_AVAILABLE_IN_2_36
+gboolean         g_subprocess_get_if_exited             (GSubprocess          *self);
 
 GLIB_AVAILABLE_IN_2_36
-GSubprocess *    g_subprocess_new_simple_argl (GSubprocessStreamDisposition stdout_disposition,
-					       GSubprocessStreamDisposition stderr_disposition,
-					       GError                     **error,
-					       const char                  *first_arg,
-					       ...) G_GNUC_NULL_TERMINATED;
+gint             g_subprocess_get_exit_status           (GSubprocess          *self);
+
+GLIB_AVAILABLE_IN_2_36
+gboolean         g_subprocess_get_if_signaled           (GSubprocess          *self);
+
 GLIB_AVAILABLE_IN_2_36
-GSubprocess *    g_subprocess_new_simple_argv (char                       **argv,
-					       GSubprocessStreamDisposition stdout_disposition,
-					       GSubprocessStreamDisposition stderr_disposition,
-					       GError                     **error);
+gint             g_subprocess_get_term_signal           (GSubprocess          *self);
 
 G_END_DECLS
 
diff --git a/gio/gsubprocesscontext-private.h b/gio/gsubprocesslauncher-private.h
similarity index 73%
rename from gio/gsubprocesscontext-private.h
rename to gio/gsubprocesslauncher-private.h
index 39ceafa..812722f 100644
--- a/gio/gsubprocesscontext-private.h
+++ b/gio/gsubprocesslauncher-private.h
@@ -21,29 +21,19 @@
 #ifndef __G_SUBPROCESS_CONTEXT_PRIVATE_H__
 #define __G_SUBPROCESS_CONTEXT_PRIVATE_H__
 
-#include "gsubprocesscontext.h"
+#include "gsubprocesslauncher.h"
 
 G_BEGIN_DECLS
 
-struct _GSubprocessContext
+struct _GSubprocessLauncher
 {
   GObject parent;
 
-  GSpawnFlags flags;
-  GPtrArray *argv;
-  gboolean has_argv0;
+  GSubprocessFlags flags;
   char **envp;
   char *cwd;
 
-  GSubprocessStreamDisposition stdin_disposition;
-  GSubprocessStreamDisposition stdout_disposition;
-  GSubprocessStreamDisposition stderr_disposition;
-
-  guint keep_descriptors : 1;
-  guint search_path : 1;
-  guint search_path_from_envp : 1;
-  guint unused_flags : 29;
-
+#ifdef G_OS_UNIX
   gint stdin_fd;
   gchar *stdin_path;
 
@@ -54,7 +44,9 @@ struct _GSubprocessContext
   gchar *stderr_path;
 
   GSpawnChildSetupFunc child_setup_func;
-  gpointer child_setup_data;
+  gpointer child_setup_user_data;
+  GDestroyNotify child_setup_destroy_notify;
+#endif
 };
 
 G_END_DECLS
diff --git a/gio/gsubprocesslauncher.c b/gio/gsubprocesslauncher.c
new file mode 100644
index 0000000..9ebb9e8
--- /dev/null
+++ b/gio/gsubprocesslauncher.c
@@ -0,0 +1,536 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright  2012 Red Hat, Inc.
+ * Copyright  2012 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Colin Walters <walters verbum org>
+ *          Ryan Lortie <desrt desrt ca>
+ */
+
+/**
+ * SECTION:gsubprocess
+ * @title: GSubprocess Launcher
+ * @short_description: Environment options for launching a child process
+ *
+ * This class contains a set of options for launching child processes,
+ * such as where its standard input and output will be directed, the
+ * argument list, the environment, and more.
+ *
+ * While the #GSubprocess class has high level functions covering
+ * popular cases, use of this class allows access to more advanced
+ * options.  It can also be used to launch multiple subprocesses with
+ * a similar configuration.
+ *
+ * Since: 2.36
+ */
+
+#define ALL_STDIN_FLAGS         (G_SUBPROCESS_FLAGS_STDIN_PIPE |        \
+                                 G_SUBPROCESS_FLAGS_STDIN_INHERIT)
+#define ALL_STDOUT_FLAGS        (G_SUBPROCESS_FLAGS_STDOUT_PIPE |       \
+                                 G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
+#define ALL_STDERR_FLAGS        (G_SUBPROCESS_FLAGS_STDERR_PIPE |       \
+                                 G_SUBPROCESS_FLAGS_STDERR_SILENCE |    \
+                                 G_SUBPROCESS_FLAGS_STDERR_MERGE)
+
+#include "config.h"
+
+#include "gsubprocesslauncher-private.h"
+#include "gioenumtypes.h"
+
+typedef GObjectClass GSubprocessLauncherClass;
+
+G_DEFINE_TYPE (GSubprocessLauncher, g_subprocess_launcher, G_TYPE_OBJECT);
+
+static void
+g_subprocess_launcher_finalize (GObject *object)
+{
+  GSubprocessLauncher *self = G_SUBPROCESS_LAUNCHER (object);
+
+  g_strfreev (self->envp);
+  g_free (self->cwd);
+
+  g_free (self->stdin_path);
+  g_free (self->stdout_path);
+  g_free (self->stderr_path);
+
+  if (self->child_setup_destroy_notify)
+    (* self->child_setup_destroy_notify) (self->child_setup_user_data);
+
+  if (G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->finalize != NULL)
+    G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->finalize (object);
+}
+
+static void
+g_subprocess_launcher_init (GSubprocessLauncher  *self)
+{
+  self->envp = g_listenv ();
+
+  self->stdin_fd = -1;
+  self->stdout_fd = -1;
+  self->stderr_fd = -1;
+}
+
+static void
+g_subprocess_launcher_class_init (GSubprocessLauncherClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->finalize = g_subprocess_launcher_finalize;
+}
+
+/**
+ * g_subprocess_launcher_new:
+ *
+ * Creates a new #GSubprocessLauncher.
+ *
+ * The launcher is created with the default options.  A copy of the
+ * environment of the calling process is made at the time of this call
+ * and will be used as the environment that the process is launched in.
+ *
+ * Since: 2.36
+ **/
+GSubprocessLauncher *
+g_subprocess_launcher_new (void)
+{
+  return g_object_new (G_TYPE_SUBPROCESS_LAUNCHER, NULL);
+}
+
+
+/**
+ * g_subprocess_launcher_set_environ:
+ * @self: a #GSubprocess
+ * @environ: the replacement environment
+ *
+ * Replace the entire environment of processes launched from this
+ * launcher with the given 'environ' variable.
+ *
+ * Typically you will build this variable by using g_listenv() to copy
+ * the process 'environ' and using the functions g_environ_setenv(),
+ * g_environ_unsetenv(), etc.
+ *
+ * As an alternative, you can use g_subprocess_launcher_setenv(),
+ * g_subprocess_launcher_unsetenv(), etc.
+ *
+ * All strings in this array are expected to be in the GLib file name
+ * encoding.  On UNIX, this means that they can be arbitrary byte
+ * strings.  On Windows, they should be in UTF-8.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_environ (GSubprocessLauncher  *self,
+                                   gchar               **environ)
+{
+  g_strfreev (self->envp);
+  self->envp = g_strdupv (environ);
+}
+
+/**
+ * g_subprocess_launcher_setenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to set, must not contain '='
+ * @value: the new value for the variable
+ * @overwrite: whether to change the variable if it already exists
+ *
+ * Sets the environment variable @variable in the environment of
+ * processes launched from this launcher.
+ *
+ * Both the variable's name and value should be in the GLib file name
+ * encoding. On UNIX, this means that they can be arbitrary byte
+ * strings. On Windows, they should be in UTF-8.
+ *
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_setenv (GSubprocessLauncher *self,
+                              const gchar         *variable,
+                              const gchar         *value,
+                              gboolean             overwrite)
+{
+  self->envp = g_environ_setenv (self->envp, variable, value, overwrite);
+}
+
+/**
+ * g_subprocess_launcher_unsetsenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to unset, must not contain '='
+ *
+ * Removes the environment variable @variable from the environment of
+ * processes launched from this launcher.
+ *
+ * The variable name should be in the GLib file name encoding.  On UNIX,
+ * this means that they can be arbitrary byte strings.  On Windows, they
+ * should be in UTF-8.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
+                                const gchar         *variable)
+{
+  self->envp = g_environ_unsetenv (self->envp, variable);
+}
+
+/**
+ * g_subprocess_launcher_getenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to get
+ *
+ * Returns the value of the environment variable @variable in the
+ * environment of processes launched from this launcher.
+ *
+ * The returned string is in the GLib file name encoding.  On UNIX, this
+ * means that it can be an arbitrary byte string.  On Windows, it will
+ * be UTF-8.
+ *
+ * Returns: the value of the environment variable, %NULL if unset
+ *
+ * Since: 2.36
+ **/
+const gchar *
+g_subprocess_launcher_getenv (GSubprocessLauncher *self,
+                              const gchar         *variable)
+{
+  return g_environ_getenv (self->envp, variable);
+}
+
+/**
+ * g_subprocess_launcher_set_cwd:
+ * @self: a #GSubprocess
+ * @cwd: the cwd for launched processes
+ *
+ * Sets the current working directory that processes will be launched
+ * with.
+ *
+ * By default processes are launched with the current working directory
+ * of the launching process at the time of launch.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
+                               const gchar         *cwd)
+{
+  g_free (self->cwd);
+  self->cwd = g_strdup (cwd);
+}
+
+static gboolean
+verify_disposition (const gchar      *stream_name,
+                    GSubprocessFlags  filtered_flags,
+                    gint              fd,
+                    const gchar      *filename)
+{
+  guint n_bits;
+
+  if (!filtered_flags)
+    n_bits = 0;
+  else if (((filtered_flags - 1) & filtered_flags) == 0)
+    n_bits = 1;
+  else
+    n_bits = 2; /* ...or more */
+
+  if (n_bits + (fd >= 0) + (filename != NULL) > 1)
+    {
+      GString *err;
+
+      err = g_string_new (NULL);
+      if (n_bits)
+        {
+          GFlagsClass *class;
+          GFlagsValue *value;
+
+          class = g_type_class_peek (G_TYPE_SUBPROCESS_FLAGS);
+          while ((value = g_flags_get_first_value (class, filtered_flags)))
+            {
+              g_string_append_printf (err, " %s", value->value_name);
+              filtered_flags &= value->value;
+            }
+
+          g_type_class_unref (class);
+        }
+
+      if (fd >= 0)
+        g_string_append_printf (err, " g_subprocess_launcher_set_%s_fd()", stream_name);
+
+      if (filename)
+        g_string_append_printf (err, " g_subprocess_launcher_set_%s_file_path()", stream_name);
+
+      g_critical ("You may specify at most one disposition for the %s stream, but you specified:%s.",
+                  stream_name, err->str);
+      g_string_free (err, TRUE);
+
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * g_subprocess_launcher_set_flags:
+ * @self: a #GSubprocessLauncher
+ * @flags: #GSubprocessFlags
+ *
+ * Sets the flags on the launcher.
+ *
+ * The default flags are %G_SUBPROCESS_FLAGS_NONE.
+ *
+ * You may not set flags that specify conflicting options for how to
+ * handle a particular stdio stream (eg: specifying both
+ * %G_SUBPROCESS_FLAGS_STDIN_PIPE and
+ * %G_SUBPROCESS_FLAGS_STDIN_INHERIT).
+ *
+ * You may also not set a flag that conflicts with a previous call to a
+ * function like g_subprocess_launcher_set_stdin_file_path() or
+ * g_subprocess_launcher_set_stdout_fd().
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
+                                 GSubprocessFlags     flags)
+{
+  if (verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, self->stdin_fd, self->stdin_path) &&
+      verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, self->stdout_fd, self->stdout_path) &&
+      verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, self->stderr_fd, self->stderr_path))
+    self->flags = flags;
+}
+
+#ifdef G_OS_UNIX
+/**
+ * g_subprocess_launcher_set_stdin_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stdin for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file must exist or spawning the process will fail.
+ *
+ * You may not set a stdin file path if a stdin fd is already set or if
+ * the launcher flags contain any flags directing stdin elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
+                                           const gchar         *path)
+{
+  if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, self->stdin_fd, path))
+    {
+      g_free (self->stdin_path);
+      self->stdin_path = g_strdup (path);
+    }
+}
+
+/**
+ * g_subprocess_launcher_set_stdin_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stdin for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that if your intention is to have the stdin of the calling
+ * process inherited by the child then %G_SUBPROCESS_FLAGS_STDIN_INHERIT
+ * is a better way to go about doing that.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process.  It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned.  The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stdin fd if a stdin file path is already set or if
+ * the launcher flags contain any flags directing stdin elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdin_fd (GSubprocessLauncher *self,
+                                    gint                 fd)
+{
+  if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+    self->stdin_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_stdout_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stdout for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file will be created or truncated when the process is spawned, as
+ * would be the case if using '>' at the shell.
+ *
+ * You may not set a stdout file path if a stdout fd is already set or
+ * if the launcher flags contain any flags directing stdout elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
+                                            const gchar         *path)
+{
+  if (verify_disposition ("stdout", self->flags & ALL_STDIN_FLAGS, self->stdout_fd, path))
+    {
+      g_free (self->stdout_path);
+      self->stdout_path = g_strdup (path);
+    }
+}
+
+/**
+ * g_subprocess_launcher_set_stdout_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stdout for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that the default behaviour is to pass stdout through to the
+ * stdout of the parent process.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process.  It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned.  The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stdout fd if a stdout file path is already set or
+ * if the launcher flags contain any flags directing stdout elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stdout_fd (GSubprocessLauncher *self,
+                                     gint                 fd)
+{
+  if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+    self->stdout_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_stderr_file_path:
+ * @self: a #GSubprocessLauncher
+ * @path: a filename or %NULL
+ *
+ * Sets the file path to use as the stderr for spawned processes.
+ *
+ * If @path is %NULL then any previously given path is unset.
+ *
+ * The file will be created or truncated when the process is spawned, as
+ * would be the case if using '2>' at the shell.
+ *
+ * If you want to send both stdout and stderr to the same file then use
+ * %G_SUBPROCESS_FLAGS_STDERR_MERGE.
+ *
+ * You may not set a stderr file path if a stderr fd is already set or
+ * if the launcher flags contain any flags directing stderr elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
+                                            const gchar         *path)
+{
+  if (verify_disposition ("stderr", self->flags & ALL_STDIN_FLAGS, self->stderr_fd, path))
+    {
+      g_free (self->stderr_path);
+      self->stderr_path = g_strdup (path);
+    }
+}
+
+/**
+ * g_subprocess_launcher_set_stderr_fd:
+ * @self: a #GSubprocessLauncher
+ * @fd: a file descriptor, or -1
+ *
+ * Sets the file descriptor to use as the stderr for spawned processes.
+ *
+ * If @fd is -1 then any previously given fd is unset.
+ *
+ * Note that the default behaviour is to pass stderr through to the
+ * stderr of the parent process.
+ *
+ * The passed @fd is noted but will not be touched in the current
+ * process.  It is therefore necessary that it be kept open by the
+ * caller until the subprocess is spawned.  The file descriptor will
+ * also not be explicitly closed on the child side, so it must be marked
+ * O_CLOEXEC if that's what you want.
+ *
+ * You may not set a stderr fd if a stderr file path is already set or
+ * if the launcher flags contain any flags directing stderr elsewhere.
+ *
+ * This feature is only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_stderr_fd (GSubprocessLauncher *self,
+                                     gint                 fd)
+{
+  if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
+    self->stderr_fd = fd;
+}
+
+/**
+ * g_subprocess_launcher_set_child_setup:
+ * @self: a #GSubprocessLauncher
+ * @child_setup: a #GSpawnChildSetupFunc to use as the child setup function
+ * @user_data: user data for @child_setup
+ * @destroy_notify: a #GDestroyNotify for @user_data
+ *
+ * Sets up a child setup function.
+ *
+ * The child setup function will be called after fork() but before
+ * exec() on the child's side.
+ *
+ * @destroy_notify will not be automatically called on the child's side
+ * of the fork().  It will only be called when the last reference on the
+ * #GSubprocessLauncher is dropped or when a new child setup function is
+ * given.
+ *
+ * %NULL can be given as @child_setup to disable the functionality.
+ *
+ * Child setup functions are only available on UNIX.
+ *
+ * Since: 2.36
+ **/
+void
+g_subprocess_launcher_set_child_setup (GSubprocessLauncher  *self,
+                                       GSpawnChildSetupFunc  child_setup,
+                                       gpointer              user_data,
+                                       GDestroyNotify        destroy_notify)
+{
+  if (self->child_setup_destroy_notify)
+    (* self->child_setup_destroy_notify) (self->child_setup_user_data);
+
+  self->child_setup_func = child_setup;
+  self->child_setup_user_data = user_data;
+  self->child_setup_destroy_notify = destroy_notify;
+}
+#endif
diff --git a/gio/gsubprocesslauncher.h b/gio/gsubprocesslauncher.h
new file mode 100644
index 0000000..642f8bc
--- /dev/null
+++ b/gio/gsubprocesslauncher.h
@@ -0,0 +1,102 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright  2012 Colin Walters <walters verbum org>
+ * Copyright  2012 Canonical Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SUBPROCESS_LAUNCHER_H__
+#define __G_SUBPROCESS_LAUNCHER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SUBPROCESS_LAUNCHER         (g_subprocess_launcher_get_type ())
+#define G_SUBPROCESS_LAUNCHER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SUBPROCESS_LAUNCHER, GSubprocessLauncher))
+#define G_IS_SUBPROCESS_LAUNCHER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS_LAUNCHER))
+
+GLIB_AVAILABLE_IN_2_36
+GType                   g_subprocess_launcher_get_type                  (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_2_36
+GSubprocessLauncher *   g_subprocess_launcher_new                       (void);
+
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_environ               (GSubprocessLauncher   *self,
+                                                                         gchar                **environ);
+
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_setenv                    (GSubprocessLauncher   *self,
+                                                                         const gchar           *variable,
+                                                                         const gchar           *value,
+                                                                         gboolean               overwrite);
+
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_unsetenv                  (GSubprocessLauncher *self,
+                                                                         const gchar         *variable);
+
+GLIB_AVAILABLE_IN_2_36
+const gchar *           g_subprocess_launcher_getenv                    (GSubprocessLauncher   *self,
+                                                                         const gchar           *variable);
+
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_cwd                   (GSubprocessLauncher   *self,
+                                                                         const gchar           *cwd);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_flags                 (GSubprocessLauncher   *self,
+                                                                         GSubprocessFlags       flags);
+
+/* Extended I/O control, only available on UNIX */
+#ifdef G_OS_UNIX
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stdin_file_path       (GSubprocessLauncher   *self,
+                                                                         const gchar           *path);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stdin_fd              (GSubprocessLauncher   *self,
+                                                                         gint                   fd);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stdout_file_path      (GSubprocessLauncher   *self,
+                                                                         const gchar           *path);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stdout_fd             (GSubprocessLauncher   *self,
+                                                                         gint                   fd);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stderr_file_path      (GSubprocessLauncher   *self,
+                                                                         const gchar           *path);
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_stderr_fd             (GSubprocessLauncher   *self,
+                                                                         gint                   fd);
+
+/* Child setup, only available on UNIX */
+GLIB_AVAILABLE_IN_2_36
+void                    g_subprocess_launcher_set_child_setup           (GSubprocessLauncher   *self,
+                                                                         GSpawnChildSetupFunc   child_setup,
+                                                                         gpointer               user_data,
+                                                                         GDestroyNotify         destroy_notify);
+#endif
+
+G_END_DECLS
+
+#endif /* __G_SUBPROCESS_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]