[gnome-terminal] client: legacy: Implement waiting for child process exit



commit 42f9f7978e3d103af7a5c9eb2c8f0e8d40e0647c
Author: Christian Persch <chpe src gnome org>
Date:   Mon Oct 30 22:41:06 2017 +0100

    client: legacy: Implement waiting for child process exit
    
    Add --wait to make the client wait until the child process exits, and
    then exit the client with the same exit status.
    
    This of course only works if only creating one terminal, not
    when creating multiple terminals at once.

 src/terminal-options.c |   41 +++++++++++++++++++++++++++---
 src/terminal-options.h |    2 +
 src/terminal.c         |   64 +++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 99 insertions(+), 8 deletions(-)
---
diff --git a/src/terminal-options.c b/src/terminal-options.c
index ee9e1b4..ffe39fd 100644
--- a/src/terminal-options.c
+++ b/src/terminal-options.c
@@ -728,6 +728,28 @@ option_working_directory_callback (const gchar *option_name,
 }
 
 static gboolean
+option_wait_cb (const gchar *option_name,
+                const gchar *value,
+                gpointer     data,
+                GError     **error)
+{
+  TerminalOptions *options = data;
+
+  if (options->any_wait) {
+    g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                         _("Can only use --wait once"));
+    return FALSE;
+  }
+
+  options->any_wait = TRUE;
+
+  InitialTab *it = ensure_top_tab (options);
+  it->wait = TRUE;
+
+  return TRUE;
+}
+
+static gboolean
 option_pass_std_cb (const gchar *option_name,
                     const gchar *value,
                     gpointer     data,
@@ -957,6 +979,7 @@ terminal_options_parse (const char *working_directory,
   options->default_title = NULL;
   options->zoom = 1.0;
   options->zoom_set = FALSE;
+  options->any_wait = FALSE;
 
   options->screen_number = -1;
   options->default_working_dir = g_strdup (working_directory);
@@ -1001,11 +1024,12 @@ terminal_options_parse (const char *working_directory,
   retval = g_option_context_parse (context, argcp, argvp, error);
   g_option_context_free (context);
 
-  if (retval)
-    return options;
+  if (!retval) {
+    terminal_options_free (options);
+    return NULL;
+  }
 
-  terminal_options_free (options);
-  return NULL;
+  return options;
 }
 
 /**
@@ -1349,6 +1373,15 @@ get_goption_context (TerminalOptions *options)
       N_("DIRNAME")
     },
     {
+      "wait",
+      0,
+      G_OPTION_FLAG_NO_ARG,
+      G_OPTION_ARG_CALLBACK,
+      option_wait_cb,
+      N_("Wait until the child exits"),
+      NULL
+    },
+    {
       "stdin",
       0,
       G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
diff --git a/src/terminal-options.h b/src/terminal-options.h
index 1d120b5..d2945e2 100644
--- a/src/terminal-options.h
+++ b/src/terminal-options.h
@@ -92,6 +92,7 @@ typedef struct
   char *sm_config_prefix;
 
   guint zoom_set : 1;
+  guint any_wait : 1;
 } TerminalOptions;
 
 typedef struct
@@ -106,6 +107,7 @@ typedef struct
   GArray *fd_array;
   guint zoom_set : 1;
   guint active : 1;
+  guint wait : 1;
 } InitialTab;
 
 typedef struct
diff --git a/src/terminal.c b/src/terminal.c
index 41e5341..05aef55 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/wait.h>
 
 #include <glib.h>
 #include <glib/gstdio.h>
@@ -45,6 +46,50 @@
 GS_DEFINE_CLEANUP_FUNCTION0(TerminalOptions*, gs_local_options_free, terminal_options_free)
 #define gs_free_options __attribute__ ((cleanup(gs_local_options_free)))
 
+/* Wait-for-exit helper */
+
+typedef struct {
+  GMainLoop *loop;
+  int status;
+} RunData;
+
+static void
+receiver_child_exited_cb (TerminalReceiver *receiver,
+                          int status,
+                          RunData *data)
+{
+  data->status = status;
+
+  if (g_main_loop_is_running (data->loop))
+    g_main_loop_quit (data->loop);
+}
+
+static int
+run_receiver (TerminalReceiver *receiver)
+{
+  RunData data = { g_main_loop_new (NULL, FALSE), 0 };
+  gulong id = g_signal_connect (receiver, "child-exited",
+                                G_CALLBACK (receiver_child_exited_cb), &data);
+  g_main_loop_run (data.loop);
+  g_signal_handler_disconnect (receiver, id);
+  g_main_loop_unref (data.loop);
+
+  /* Mangle the exit status */
+  int exit_code;
+  if (WIFEXITED (data.status))
+    exit_code = WEXITSTATUS (data.status);
+  else if (WIFSIGNALED (data.status))
+    exit_code = 128 + (int) WTERMSIG (data.status);
+  else if (WCOREDUMP (data.status))
+    exit_code = 127;
+  else
+    exit_code = 127;
+
+  return exit_code;
+}
+
+/* Factory helpers */
+
 static gboolean
 get_factory_exit_status (const char *message,
                          const char *service_name,
@@ -197,7 +242,7 @@ handle_show_preferences (const char *service_name)
  * @options: a #TerminalOptions
  * @allow_resume: whether to merge the terminal configuration from the
  *   saved session on resume
- * @error: a #GError to fill in
+ * @wait_for_receiver: location to store the #TerminalReceiver to wait for
  *
  * Processes @options. It loads or saves the terminal configuration, or
  * opens the specified windows and tabs.
@@ -208,7 +253,8 @@ handle_show_preferences (const char *service_name)
 static gboolean
 handle_options (TerminalFactory *factory,
                 const char *service_name,
-                TerminalOptions *options)
+                TerminalOptions *options,
+                TerminalReceiver **wait_for_receiver)
 {
   GList *lw;
   const char *encoding;
@@ -300,7 +346,7 @@ handle_options (TerminalFactory *factory,
 
           receiver = terminal_receiver_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
                                                                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
-                                                               G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+                                                               (it->wait ? 0 : 
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS),
                                                                options->server_app_id ? 
options->server_app_id
                                                                                       : 
TERMINAL_APPLICATION_ID,
                                                                object_path,
@@ -338,6 +384,9 @@ handle_options (TerminalFactory *factory,
             else
               continue; /* Continue processing the remaining options! */
           }
+
+          if (it->wait)
+            gs_transfer_out_value (wait_for_receiver, &receiver);
         }
     }
 
@@ -413,7 +462,14 @@ main (int argc, char **argv)
     goto out;
   }
 
-  if (handle_options (factory, service_name, options))
+  TerminalReceiver *receiver = NULL;
+  if (!handle_options (factory, service_name, options, &receiver))
+    goto out;
+
+  if (receiver != NULL) {
+    exit_code = run_receiver (receiver);
+    g_object_unref (receiver);
+  } else
     exit_code = EXIT_SUCCESS;
 
  out:


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