[vte] lib: Add async spawning



commit fb296872feb8e4104760b54c31d83ff75412bc21
Author: Christian Persch <chpe gnome org>
Date:   Fri Nov 25 22:07:52 2016 +0100

    lib: Add async spawning
    
    Add vte_pty_spawn_async/finish for async spawning of a
    child process on a VtePty, and a vte_terminal_spawn_async
    convenience function that wraps creating the PTY and spawning
    the child process, and can cope with the terminal being
    destroyed between starting the spawning and the operation
    being finished.
    
    This is a partial solution to bug 772354; a full solution
    will require glib changes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=772354

 doc/reference/vte-docs.xml     |    5 +-
 doc/reference/vte-sections.txt |    6 ++
 src/pty.cc                     |  181 +++++++++++++++++++++++++++++++++++++++
 src/vte.cc                     |    1 +
 src/vte/vtepty.h               |   20 +++++
 src/vte/vteterminal.h          |   20 +++++
 src/vteapp.c                   |   45 ++++++----
 src/vtegtk.cc                  |  184 ++++++++++++++++++++++++++++++++++++++++
 src/vteinternal.hh             |   15 +++
 src/vtepty-private.h           |    2 +
 10 files changed, 461 insertions(+), 18 deletions(-)
---
diff --git a/doc/reference/vte-docs.xml b/doc/reference/vte-docs.xml
index 5ef2eac..89a4e15 100644
--- a/doc/reference/vte-docs.xml
+++ b/doc/reference/vte-docs.xml
@@ -98,8 +98,11 @@
     <title>Index of new symbols in 0.46</title>
     <xi:include href="xml/api-index-0.46.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-0-48" role="0.48">
+    <title>Index of new symbols in 0.48</title>
+    <xi:include href="xml/api-index-0.48.xml"><xi:fallback /></xi:include>
+  </index>
 
- 
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 
   <appendix id="licence">
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index 56ae775..737fb7b 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -82,6 +82,8 @@ vte_get_features
 
 <SUBSECTION>
 vte_terminal_spawn_sync
+VteTerminalSpawnAsyncCallback
+vte_terminal_spawn_async
 vte_terminal_get_pty
 vte_terminal_set_pty
 vte_terminal_pty_new_sync
@@ -162,6 +164,10 @@ vte_pty_get_size
 vte_pty_set_term
 vte_pty_set_utf8
 
+<SUBSECTION>
+vte_pty_spawn_async
+vte_pty_spawn_finish
+
 <SUBSECTION Standard>
 vte_pty_flags_get_type
 VTE_TYPE_PTY_FLAGS
diff --git a/src/pty.cc b/src/pty.cc
index 3172889..d01245d 100644
--- a/src/pty.cc
+++ b/src/pty.cc
@@ -31,6 +31,7 @@
 #include <vte/vte.h>
 #include "vtepty-private.h"
 #include "vtetypes.hh"
+#include "vtespawn.hh"
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -321,6 +322,8 @@ __vte_pty_merge_environ (char **envp,
  * @child_setup: function to run in the child just before exec()
  * @child_setup_data: user data for @child_setup
  * @child_pid: a location to store the child PID, or %NULL
+ * @timeout: a timeout value in ms, or %NULL
+ * @cancellable: a #GCancellable, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Uses g_spawn_async() to spawn the command in @argv. The child's environment will
@@ -347,6 +350,8 @@ __vte_pty_spawn (VtePty *pty,
                  GSpawnChildSetupFunc child_setup,
                  gpointer child_setup_data,
                  GPid *child_pid /* out */,
+                 int timeout,
+                 GCancellable *cancellable,
                  GError **error)
 {
        VtePtyPrivate *priv = pty->priv;
@@ -1002,3 +1007,179 @@ vte_pty_get_fd (VtePty *pty)
 
         return priv->pty_fd;
 }
+
+typedef struct {
+        VtePty* m_pty;
+        char* m_working_directory;
+        char** m_argv;
+        char** m_envv;
+        GSpawnFlags m_spawn_flags;
+        GSpawnChildSetupFunc m_child_setup;
+        gpointer m_child_setup_data;
+        GDestroyNotify m_child_setup_data_destroy;
+        int m_timeout;
+} AsyncSpawnData;
+
+static AsyncSpawnData*
+async_spawn_data_new (VtePty* pty,
+                      char const* working_directory,
+                      char** argv,
+                      char** envv,
+                      GSpawnFlags spawn_flags,
+                      GSpawnChildSetupFunc child_setup,
+                      gpointer child_setup_data,
+                      GDestroyNotify child_setup_data_destroy,
+                      int timeout)
+{
+        auto data = g_new(AsyncSpawnData, 1);
+
+        data->m_pty = (VtePty*)g_object_ref(pty);
+        data->m_working_directory = g_strdup(working_directory);
+        data->m_argv = g_strdupv(argv);
+        data->m_envv = envv ? g_strdupv(envv) : nullptr;
+        data->m_spawn_flags = spawn_flags;
+        data->m_child_setup = child_setup;
+        data->m_child_setup_data = child_setup_data;
+        data->m_child_setup_data_destroy = child_setup_data_destroy;
+        data->m_timeout = timeout;
+
+        return data;
+}
+
+static void
+async_spawn_data_free(gpointer data_)
+{
+        AsyncSpawnData *data = reinterpret_cast<AsyncSpawnData*>(data_);
+
+        g_free(data->m_working_directory);
+        g_strfreev(data->m_argv);
+        g_strfreev(data->m_envv);
+        if (data->m_child_setup_data && data->m_child_setup_data_destroy)
+                data->m_child_setup_data_destroy(data->m_child_setup_data);
+}
+
+static void
+async_spawn_run_in_thread(GTask *task,
+                          gpointer object,
+                          gpointer data_,
+                          GCancellable *cancellable)
+{
+        AsyncSpawnData *data = reinterpret_cast<AsyncSpawnData*>(data_);
+
+        GPid pid;
+        GError *error = NULL;
+        if (__vte_pty_spawn(data->m_pty,
+                            data->m_working_directory,
+                            data->m_argv,
+                            data->m_envv,
+                            (GSpawnFlags)data->m_spawn_flags,
+                            data->m_child_setup, data->m_child_setup_data,
+                            &pid,
+                            data->m_timeout,
+                            cancellable,
+                            &error))
+                g_task_return_pointer(task, g_memdup(&pid, sizeof(pid)), g_free);
+        else
+                g_task_return_error(task, error);
+}
+
+/**
+ * vte_pty_spawn_async:
+ * @pty: a #VtePty
+ * @working_directory: (allow-none): the name of a directory the command should start
+ *   in, or %NULL to use the current working directory
+ * @argv: (array zero-terminated=1) (element-type filename): child's argument vector
+ * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment
+ *   variables to be added to the environment before starting the process, or %NULL
+ * @spawn_flags: flags from #GSpawnFlags
+ * @child_setup: (allow-none) (scope async): an extra child setup function to run in the child just before 
exec(), or %NULL
+ * @child_setup_data: (closure child_setup): user data for @child_setup, or %NULL
+ * @child_setup_data_destroy: (destroy child_setup_data): a #GDestroyNotify for @child_setup_data, or %NULL
+ * @timeout: a timeout value in ms, or -1 to wait indefinitely
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ *
+ * Starts the specified command under the pseudo-terminal @pty.
+ * The @argv and @envv lists should be %NULL-terminated.
+ * The "TERM" environment variable is automatically set to a default value,
+ * but can be overridden from @envv.
+ * @pty_flags controls logging the session to the specified system log files.
+ *
+ * Note that %G_SPAWN_DO_NOT_REAP_CHILD will always be added to @spawn_flags.
+ *
+ * Note that all open file descriptors will be closed in the child. If you want
+ * to keep some file descriptor open for use in the child process, you need to
+ * use a child setup function that unsets the FD_CLOEXEC flag on that file
+ * descriptor.
+ *
+ * See vte_pty_new(), g_spawn_async() and vte_terminal_watch_child() for more information.
+ *
+ * Since: 0.48
+ */
+void
+vte_pty_spawn_async(VtePty *pty,
+                    const char *working_directory,
+                    char **argv,
+                    char **envv,
+                    GSpawnFlags spawn_flags_,
+                    GSpawnChildSetupFunc child_setup,
+                    gpointer child_setup_data,
+                    GDestroyNotify child_setup_data_destroy,
+                    int timeout,
+                    GCancellable *cancellable,
+                    GAsyncReadyCallback callback,
+                    gpointer user_data)
+{
+        g_return_if_fail(argv != nullptr);
+        g_return_if_fail(!child_setup_data || child_setup);
+        g_return_if_fail(!child_setup_data_destroy || child_setup_data);
+        g_return_if_fail(cancellable == nullptr || G_IS_CANCELLABLE (cancellable));
+        g_return_if_fail(callback);
+
+        /* FIXMEchpe: is this flag needed */
+        guint spawn_flags = (guint)spawn_flags_;
+        spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
+
+        auto data = async_spawn_data_new(pty,
+                                         working_directory, argv, envv,
+                                         GSpawnFlags(spawn_flags),
+                                         child_setup, child_setup_data, child_setup_data_destroy,
+                                         timeout);
+
+        auto task = g_task_new(pty, cancellable, callback, user_data);
+        g_task_set_source_tag(task, (void*)vte_pty_spawn_async);
+        g_task_set_task_data(task, data, async_spawn_data_free);
+        g_task_run_in_thread(task, async_spawn_run_in_thread);
+        g_object_unref(task);
+}
+
+/**
+ * vte_pty_spawn_finish:
+ * @pty: a #VtePty
+ * @result: a #GAsyncResult
+ * @child_pid: (out) (allow-none) (transfer full): a location to store the child PID, or %NULL
+ * @error: (allow-none): return location for a #GError, or %NULL
+ *
+ * Returns: %TRUE on success, or %FALSE on error with @error filled in
+ *
+ * Since: 0.48
+ */
+gboolean
+vte_pty_spawn_finish(VtePty *pty,
+                     GAsyncResult *result,
+                     GPid *child_pid /* out */,
+                     GError **error)
+{
+        g_return_val_if_fail (VTE_IS_PTY (pty), FALSE);
+        g_return_val_if_fail (G_IS_TASK (result), FALSE);
+        g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+        gpointer pidptr = g_task_propagate_pointer(G_TASK(result), error);
+        if (pidptr == nullptr) {
+                *child_pid = -1;
+                return FALSE;
+        }
+
+        *child_pid = *(GPid*)pidptr;
+        *error = nullptr;
+        return TRUE;
+}
diff --git a/src/vte.cc b/src/vte.cc
index 14f6bf5..c9d1160 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -3385,6 +3385,7 @@ VteTerminalPrivate::spawn_sync(VtePtyFlags pty_flags,
                              (GSpawnFlags)spawn_flags,
                              child_setup, child_setup_data,
                              &pid,
+                             -1 /* no timeout */, cancellable,
                              error)) {
                 g_object_unref(new_pty);
                 return false;
diff --git a/src/vte/vtepty.h b/src/vte/vtepty.h
index bc03bed..17c9721 100644
--- a/src/vte/vtepty.h
+++ b/src/vte/vtepty.h
@@ -95,6 +95,26 @@ gboolean vte_pty_set_utf8 (VtePty *pty,
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(VtePty, g_object_unref)
 #endif
 
+_VTE_PUBLIC
+void vte_pty_spawn_async(VtePty *pty,
+                         const char *working_directory,
+                         char **argv,
+                         char **envv,
+                         GSpawnFlags spawn_flags,
+                         GSpawnChildSetupFunc child_setup,
+                         gpointer child_setup_data,
+                         GDestroyNotify child_setup_data_destroy,
+                         int timeout,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(3);
+
+_VTE_PUBLIC
+gboolean vte_pty_spawn_finish(VtePty *pty,
+                              GAsyncResult *result,
+                              GPid *child_pid /* out */,
+                              GError **error) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(2);
+
 G_END_DECLS
 
 #endif /* __VTE_VTE_PTY_H__ */
diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h
index 7836271..7f34206 100644
--- a/src/vte/vteterminal.h
+++ b/src/vte/vteterminal.h
@@ -153,6 +153,26 @@ gboolean vte_terminal_spawn_sync(VteTerminal *terminal,
                                  GCancellable *cancellable,
                                  GError **error) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(4);
 
+typedef void (* VteTerminalSpawnAsyncCallback) (VteTerminal *terminal,
+                                                GPid pid,
+                                                GError *error,
+                                                gpointer user_data);
+
+_VTE_PUBLIC
+void vte_terminal_spawn_async(VteTerminal *terminal,
+                              VtePtyFlags pty_flags,
+                              const char *working_directory,
+                              char **argv,
+                              char **envv,
+                              GSpawnFlags spawn_flags_,
+                              GSpawnChildSetupFunc child_setup,
+                              gpointer child_setup_data,
+                              GDestroyNotify child_setup_data_destroy,
+                              int timeout,
+                              GCancellable *cancellable,
+                              VteTerminalSpawnAsyncCallback callback,
+                              gpointer user_data) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(4);
+
 /* Send data to the terminal to display, or to the terminal's forked command
  * to handle in some way.  If it's 'cat', they should be the same. */
 _VTE_PUBLIC
diff --git a/src/vteapp.c b/src/vteapp.c
index e80325b..71d0e61 100644
--- a/src/vteapp.c
+++ b/src/vteapp.c
@@ -589,6 +589,20 @@ add_dingus (VteTerminal *terminal,
         }
 }
 
+static void
+spawn_cb (VteTerminal *terminal,
+          GPid pid,
+          GError *error,
+          gpointer user_data)
+{
+        if (pid == -1) {
+                g_printerr("Spawning failed: %s\n", error->message);
+                return;
+        }
+
+        g_printerr("Spawning succeded, PID %ld\n", (long)pid);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1109,7 +1123,6 @@ main(int argc, char **argv)
                        GError *err = NULL;
                        char **command_argv = NULL;
                        int command_argc;
-                       GPid pid = -1;
                         char *free_me = NULL;
 
                        _VTE_DEBUG_IF(VTE_DEBUG_MISC)
@@ -1124,23 +1137,21 @@ main(int argc, char **argv)
                        if (command == NULL || *command == '\0')
                                command = "/bin/sh";
 
-                       if (!g_shell_parse_argv(command, &command_argc, &command_argv, &err) ||
-                           !vte_terminal_spawn_sync(terminal,
-                                                           pty_flags,
-                                                           NULL,
-                                                           command_argv,
-                                                           env_add,
-                                                           G_SPAWN_SEARCH_PATH,
-                                                           NULL, NULL,
-                                                           &pid,
-                                                            NULL /* cancellable */,
-                                                           &err)) {
-                               g_warning("Failed to fork: %s\n", err->message);
+                       if (!g_shell_parse_argv(command, &command_argc, &command_argv, &err)) {
+                               g_warning("Failed to parse argv: %s\n", err->message);
                                g_error_free(err);
-                       } else {
-                               g_print("Fork succeeded, PID %d\n", pid);
-                       }
+                        }
 
+                        vte_terminal_spawn_async(terminal,
+                                                 pty_flags,
+                                                 working_directory,
+                                                 command_argv,
+                                                 env_add,
+                                                 G_SPAWN_SEARCH_PATH_FROM_ENVP,
+                                                 NULL, NULL, NULL,
+                                                 30 * 1000 /* 30s */,
+                                                 NULL /* cancellable */,
+                                                 spawn_cb, NULL);
                         g_free (free_me);
                        g_strfreev(command_argv);
                } else {
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 924b5a0..c6bc2d4 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -2283,6 +2283,190 @@ vte_terminal_spawn_sync(VteTerminal *terminal,
                                          error);
 }
 
+typedef struct {
+        GWeakRef wref;
+        VteTerminalSpawnAsyncCallback callback;
+        gpointer user_data;
+} SpawnAsyncCallbackData;
+
+static gpointer
+spawn_async_callback_data_new(VteTerminal *terminal,
+                     VteTerminalSpawnAsyncCallback callback,
+                     gpointer user_data)
+{
+        SpawnAsyncCallbackData *data = g_new0 (SpawnAsyncCallbackData, 1);
+
+        g_weak_ref_init(&data->wref, terminal);
+        data->callback = callback;
+        data->user_data = user_data;
+
+        return data;
+}
+
+static void
+spawn_async_callback_data_free (SpawnAsyncCallbackData *data)
+{
+        g_weak_ref_clear(&data->wref);
+        g_free(data);
+}
+
+static void
+spawn_async_cb (GObject *source,
+                GAsyncResult *result,
+                gpointer user_data)
+{
+        SpawnAsyncCallbackData *data = reinterpret_cast<SpawnAsyncCallbackData*>(user_data);
+        VtePty *pty = VTE_PTY(source);
+
+        GPid pid = -1;
+        GError *error = nullptr;
+        vte_pty_spawn_finish(pty, result, &pid, &error);
+
+        /* Now get a ref to the terminal */
+        VteTerminal* terminal = (VteTerminal*)g_weak_ref_get(&data->wref);
+
+        /* Automatically watch the child */
+        if (terminal) {
+                if (pid != -1)
+                        vte_terminal_watch_child(terminal, pid);
+                else
+                        vte_terminal_set_pty(terminal, nullptr);
+        }
+
+        if (data->callback)
+                data->callback(terminal, pid, error, data->user_data);
+
+        g_clear_error(&error);
+
+        if (terminal == nullptr) {
+                /* If the terminal was destroyed, we need to abort the child process, if any */
+                if (pid != -1) {
+#ifdef HAVE_GETPGID
+                        pid_t pgrp;
+                        pgrp = getpgid(pid);
+                        if (pgrp != -1) {
+                                kill(-pgrp, SIGHUP);
+                        }
+#endif
+                        kill(pid, SIGHUP);
+                }
+        }
+
+        spawn_async_callback_data_free(data);
+}
+
+
+/**
+ * VteTerminalSpawnAsyncCallback:
+ * @terminal: the #VteTerminal
+ * @pid: a #GPid
+ * @error: a #GError, or %NULL
+ * @user_data: user data that was passed to vte_terminal_spawn_async
+ *
+ * Callback for vte_terminal_spawn_async().
+ *
+ * On success, @pid contains the PID of the spawned process, and @error
+ * is %NULL.
+ * On failure, @pid is -1 and @error contains the error information.
+ *
+ * Since: 0.48
+ */
+
+/**
+ * vte_terminal_spawn_async:
+ * @terminal: a #VteTerminal
+ * @pty_flags: flags from #VtePtyFlags
+ * @working_directory: (allow-none): the name of a directory the command should start
+ *   in, or %NULL to use the current working directory
+ * @argv: (array zero-terminated=1) (element-type filename): child's argument vector
+ * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment
+ *   variables to be added to the environment before starting the process, or %NULL
+ * @spawn_flags_: flags from #GSpawnFlags
+ * @child_setup: (allow-none) (scope async): an extra child setup function to run in the child just before 
exec(), or %NULL
+ * @child_setup_data: (closure child_setup): user data for @child_setup, or %NULL
+ * @child_setup_data_destroy: (destroy child_setup_data): a #GDestroyNotify for @child_setup_data, or %NULL
+ * @timeout: a timeout value in ms, or -1 to wait indefinitely
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: a #VteTerminalSpawnAsyncCallback, or %NULL
+ * @user_data: user data for @callback, or %NULL
+ *
+ * A convenience function that wraps creating the #VtePty and spawning
+ * the child process on it. See vte_pty_new_sync(), vte_pty_spawn_async(),
+ * and vte_pty_spawn_finish() for more information.
+ *
+ * When the operation is finished successfully, @callback will be called
+ * with the child #GPid, and a %NULL #GError. The child PID will already be
+ * watched via vte_terminal_watch_child().
+ *
+ * When the operation fails, @callback will be called with a -1 #GPid,
+ * and a non-%NULL #GError containing the error information.
+ *
+ * Note that if @terminal has been destroyed before the operation is called,
+ * @callback will be called with a %NULL @terminal; you must not do anything
+ * in the callback besides freeing any resources associated with @user_data,
+ * but taking care not to access the now-destroyed #VteTerminal. Note that
+ * in this case, if spawning was successful, the child process will be aborted
+ * automatically.
+ *
+ * Since: 0.48
+ */
+void
+vte_terminal_spawn_async(VteTerminal *terminal,
+                         VtePtyFlags pty_flags,
+                         const char *working_directory,
+                         char **argv,
+                         char **envv,
+                         GSpawnFlags spawn_flags_,
+                         GSpawnChildSetupFunc child_setup,
+                         gpointer child_setup_data,
+                         GDestroyNotify child_setup_data_destroy,
+                         int timeout,
+                         GCancellable *cancellable,
+                         VteTerminalSpawnAsyncCallback callback,
+                         gpointer user_data)
+{
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+        g_return_if_fail(argv != nullptr);
+        g_return_if_fail(!child_setup_data || child_setup);
+        g_return_if_fail(!child_setup_data_destroy || child_setup_data);
+        g_return_if_fail(cancellable == nullptr || G_IS_CANCELLABLE (cancellable));
+
+        GError *error = NULL;
+        VtePty* pty = vte_terminal_pty_new_sync(terminal, pty_flags, cancellable, &error);
+        if (pty == nullptr) {
+                if (child_setup_data_destroy)
+                        child_setup_data_destroy(child_setup_data);
+
+                callback(terminal, -1, error, user_data);
+
+                g_error_free(error);
+                return;
+        }
+
+        vte_terminal_set_pty(terminal, pty);
+
+        guint spawn_flags = (guint)spawn_flags_;
+        /* FIXMEchpe: is this flag needed */
+        spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
+
+        /* We do NOT support this flag. If you want to have some FD open in the child
+         * process, simply use a child setup function that unsets the CLOEXEC flag
+         * on that FD.
+         */
+        spawn_flags &= ~G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
+
+        vte_pty_spawn_async(pty,
+                            working_directory,
+                            argv,
+                            envv,
+                            GSpawnFlags(spawn_flags),
+                            child_setup, child_setup_data, child_setup_data_destroy,
+                            timeout, cancellable,
+                            spawn_async_cb,
+                            spawn_async_callback_data_new(terminal, callback, user_data));
+        g_object_unref(pty);
+}
+
 /**
  * vte_terminal_feed:
  * @terminal: a #VteTerminal
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index cff2157..947eed4 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -773,6 +773,21 @@ public:
                         GPid *child_pid /* out */,
                         GCancellable *cancellable,
                         GError **error);
+#if 0
+        void spawn_async(VtePtyFlags pty_flags,
+                         const char *working_directory,
+                         char **argv,
+                         char **envv,
+                         GSpawnFlags spawn_flags_,
+                         GSpawnChildSetupFunc child_setup,
+                         gpointer child_setup_data,
+                         GDestroyNotify child_setup_data_destroy,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data);
+        bool spawn_finish(GAsyncResult *result,
+                          GPid *child_pid /* out */);
+#endif
 
         void reset(bool clear_tabstops,
                    bool clear_history,
diff --git a/src/vtepty-private.h b/src/vtepty-private.h
index 461ef0e..3f9ce61 100644
--- a/src/vtepty-private.h
+++ b/src/vtepty-private.h
@@ -26,6 +26,8 @@ gboolean __vte_pty_spawn (VtePty *pty,
                           GSpawnChildSetupFunc child_setup,
                           gpointer child_setup_data,
                           GPid *child_pid /* out */,
+                          int timeout,
+                          GCancellable *cancellable,
                           GError **error);
 
 G_END_DECLS


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