*** empty log message ***
authorroot <root>
Thu, 19 Jan 2006 09:47:15 +0000 (09:47 +0000)
committerroot <root>
Thu, 19 Jan 2006 09:47:15 +0000 (09:47 +0000)
12 files changed:
Changes
src/hookinc.h
src/init.C
src/iom.C
src/iom.h
src/iom_conf.h
src/main.C
src/perl/mark-urls
src/perl/selection
src/perl/selection-popup
src/rxvt.h
src/urxvt.pm

diff --git a/Changes b/Changes
index ee60a95d642bffcdb054c559d353f854a8a164aa..2596d87a61ab51e56f49bd82b00cd14c91ea38cb 100644 (file)
--- a/Changes
+++ b/Changes
@@ -14,7 +14,6 @@ WISH: support tex fonts
 
 9.0
 TODO: distributed clipboard example
-TODO: use correct %ENV for perl exec'ed processes.
         - setuid/setgid operation is now _encouraged_: security has been
           improved by moving privileged operations into a separate process
           and permanently dropping privileges within the terminal. This
@@ -54,6 +53,7 @@ TODO: use correct %ENV for perl exec'ed processes.
         - made some fixes to xpm offset and scaling code.
         - perl-overlays and refresh hooks were not applied in correct order.
         - changed coordinate-system of view_start/nsaved to be top to bottom.
+        - iom extended to support listening for child exits.
 
 7.0  Fri Jan 13 14:02:18 CET 2006
        - added sections for DISTRIBUTION MAINTAINERS and about
index d081424914dd2e2186afba01f34b298b5803545d..108ad66b2bcc5172d49996bba27cc6bce9b23515 100644 (file)
@@ -4,6 +4,8 @@
   def (DESTROY)
   def (RESET)
   def (START)
+  def (CHILD_START)
+  def (CHILD_EXIT)
 
   def (SEL_BEGIN)
   def (SEL_EXTEND)
index 08c110b881c82943e3084d97df63605e3933c5d1..a2e58d07b82bdac4c2a55ac7d0c2ebeba4c3130c 100644 (file)
@@ -1443,6 +1443,10 @@ rxvt_term::run_command (const char *const *argv)
 #endif
 
         pty->close_tty ();
+
+        child_ev.start (cmd_pid);
+
+        HOOK_INVOKE ((this, HOOK_CHILD_START, DT_INT, cmd_pid, DT_END));
         break;
     }
 }
index 3ec1ab833d833731a2ec5379207a2a1007c00f93..e42dee86880f2d10da04d8fc2d67b3514fc7f4e7 100644 (file)
--- a/src/iom.C
+++ b/src/iom.C
 #include <cstdio>
 #include <cstdlib>
 #include <cerrno>
+#include <cassert>
 
+#include <sys/types.h>
 #include <sys/time.h>
 
-#include <assert.h>
-
 #if 1 // older unices need these includes for select (2)
 # include <unistd.h>
-# include <sys/types.h>
 # include <time.h>
 #endif
 
-// for IOM_SIG
+#if IOM_CHILD
+# include <sys/wait.h>
+#endif
+
 #if IOM_SIG
 # include <csignal>
 # include <fcntl.h>
@@ -72,28 +74,63 @@ struct sig_vec : io_manager_vec<sig_watcher> {
 };
 static vector<sig_vec *> sw;
 #endif
+#if IOM_CHILD
+static io_manager_vec<child_watcher>  pw;
+#endif
 
 // this is a dummy time watcher to ensure that the first
 // time watcher is _always_ valid, this gets rid of a lot
 // of null-pointer-checks
 // (must come _before_ iom is being defined)
 static struct tw0 : time_watcher
+{
+  void cb (time_watcher &w)
   {
-    void cb (time_watcher &w)
-    {
-      // should never get called
-      // reached end-of-time, or tstamp has a bogus definition,
-      // or compiler initialisation order broken, or something else :)
-      abort ();
-    }
+    // should never get called
+    // reached end-of-time, or tstamp has a bogus definition,
+    // or compiler initialisation order broken, or something else :)
+    abort ();
+  }
 
-    tw0 ()
-      : time_watcher (this, &tw0::cb)
-      { }
-  } tw0;
+  tw0 ()
+  : time_watcher (this, &tw0::cb)
+  { }
+} tw0;
 
 tstamp NOW;
 
+#if IOM_CHILD
+// sig_watcher for child signal(s)
+static struct sw0 : sig_watcher
+{
+  void cb (sig_watcher &w)
+  {
+    // SIGCHLD, call corresponding watchera
+    pid_t pid;
+    int status;
+
+    while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
+      for (int i = pw.size (); i--; )
+        {
+          child_watcher *w = pw[i];
+
+          if (!w)
+            pw.erase_unordered (i);
+          else if (w->pid == pid)
+            {
+              w->stop ();
+              w->call (*w, status);
+            }
+         }
+
+  }
+
+  sw0 ()
+  : sig_watcher (this, &sw0::cb)
+  { }
+} sw0;
+#endif
+
 #if IOM_TIME
 tstamp io_manager::now ()
 {
@@ -115,6 +152,8 @@ static bool iom_valid;
 static struct init {
   init ()
   {
+    iom_valid = true;
+
 #if IOM_SIG
     sigemptyset (&sigs);
 
@@ -128,7 +167,9 @@ static struct init {
     fcntl (sigpipe[1], F_SETFL, O_NONBLOCK); fcntl (sigpipe[1], F_SETFD, FD_CLOEXEC);
 #endif
 
-    iom_valid = true;
+#if IOM_CHILD
+    sw0.start (SIGCHLD);
+#endif
 
 #if IOM_TIME
     io_manager::set_now ();
@@ -273,6 +314,11 @@ void sig_watcher::start (int signum)
 }
 #endif
 
+#if IOM_CHILD
+void io_manager::reg   (child_watcher &w) { io_manager::reg   (w, pw); }
+void io_manager::unreg (child_watcher &w) { io_manager::unreg (w, pw); }
+#endif
+
 void io_manager::loop ()
 {
   init::required ();
index 7cfbe75120aad1cb2c92a0568f369ed36ca24198..42c76318bac9765d879d685326b9c50e28a5e4e4 100644 (file)
--- a/src/iom.h
+++ b/src/iom.h
 // edit iom_conf.h as appropriate.
 #include "iom_conf.h"
 
-#include "callback.h"
-
-#ifndef IOM_IO
-# define IOM_IO 0
-#endif
-#ifndef IOM_TIME
-# define IOM_TIME 0
-#endif
-#ifndef IOM_CHECK
-# define IOM_CHECK 0
-#endif
-#ifndef IOM_IDLE
-# define IOM_IDLE 0
-#endif
-#ifndef IOM_SIG
-# define IOM_SIG 0
+#if IOM_CHILD
+# undef IOM_SIG
+# define IOM_SIG 1
 #endif
 
+#include "callback.h"
+
 typedef double tstamp;
 extern tstamp NOW;
 
@@ -68,6 +57,9 @@ struct idle_watcher;
 #if IOM_SIG
 struct sig_watcher;
 #endif
+#if IOM_CHILD
+struct child_watcher;
+#endif
 
 template<class watcher>
 struct io_manager_vec : vector<watcher *> {
@@ -115,6 +107,9 @@ public:
 #if IOM_SIG
   static void reg (sig_watcher   &w); static void unreg (sig_watcher   &w);
 #endif
+#if IOM_CHILD
+  static void reg (child_watcher &w); static void unreg (child_watcher &w);
+#endif
   
   static void loop ();
 };
@@ -141,7 +136,7 @@ struct io_watcher : watcher, callback2<void, io_watcher &, short> {
 
   template<class O1, class O2>
   io_watcher (O1 *object, void (O2::*method) (io_watcher &, short))
-  : callback2<void, io_watcher &, short> (object,method)
+  : callback2<void, io_watcher &, short> (object, method)
   { }
   ~io_watcher () { stop (); }
 };
@@ -161,7 +156,7 @@ struct time_watcher : watcher, callback1<void, time_watcher &> {
 
   template<class O1, class O2>
   time_watcher (O1 *object, void (O2::*method) (time_watcher &))
-  : callback1<void, time_watcher &> (object,method), at (0)
+  : callback1<void, time_watcher &> (object, method), at (0)
   { }
   ~time_watcher () { stop (); }
 };
@@ -175,7 +170,7 @@ struct check_watcher : watcher, callback1<void, check_watcher &> {
 
   template<class O1, class O2>
   check_watcher (O1 *object, void (O2::*method) (check_watcher &))
-  : callback1<void, check_watcher &> (object,method)
+  : callback1<void, check_watcher &> (object, method)
   { }
   ~check_watcher () { stop (); }
 };
@@ -189,7 +184,7 @@ struct idle_watcher : watcher, callback1<void, idle_watcher &> {
 
   template<class O1, class O2>
   idle_watcher (O1 *object, void (O2::*method) (idle_watcher &))
-    : callback1<void, idle_watcher &> (object,method)
+    : callback1<void, idle_watcher &> (object, method)
     { }
   ~idle_watcher () { stop (); }
 };
@@ -204,11 +199,26 @@ struct sig_watcher : watcher, callback1<void, sig_watcher &> {
 
   template<class O1, class O2>
   sig_watcher (O1 *object, void (O2::*method) (sig_watcher &))
-  : callback1<void, sig_watcher &> (object,method), signum (-1)
+  : callback1<void, sig_watcher &> (object, method), signum (0)
   { }
   ~sig_watcher () { stop (); }
 };
 #endif
 
+#if IOM_CHILD
+struct child_watcher : watcher, callback2<void, child_watcher &, int> {
+  int /*pid_t*/ pid;
+
+  void start (int pid) { this->pid = pid; io_manager::reg (*this); }
+  void stop () { io_manager::unreg (*this); }
+
+  template<class O1, class O2>
+  child_watcher (O1 *object, void (O2::*method) (child_watcher &, int status))
+  : callback2<void, child_watcher &, int> (object, method), pid (0)
+  { }
+  ~child_watcher () { stop (); }
+};
+#endif
+
 #endif
 
index c79022fd49209f3026665cb118e2b51f287f6a50..be08fc627dcd9a2ee9861c36341142f17ca03bfe 100644 (file)
 
 #include <rxvtutil.h>
 
-#define IOM_IO 1
-#define IOM_TIME 1
+#define IOM_IO    1
+#define IOM_TIME  1
 #define IOM_CHECK 1
-#define IOM_SIG 1
+#define IOM_SIG   1
+#define IOM_CHILD 1
 
 #endif
 
index e08736b7586e6a0e782da8e2d99bcca17b4f956b..b98eedb196b6f9b1d525eb6a4a24a18ee4c5e398 100644 (file)
@@ -171,6 +171,7 @@ rxvt_term::rxvt_term ()
 #endif
     termwin_ev (this, &rxvt_term::x_cb),
     vt_ev (this, &rxvt_term::x_cb),
+    child_ev (this, &rxvt_term::child_cb),
     check_ev (this, &rxvt_term::check_cb),
     flush_ev (this, &rxvt_term::flush_cb),
     destroy_ev (this, &rxvt_term::destroy_cb),
@@ -287,9 +288,12 @@ rxvt_term::~rxvt_term ()
 #endif
 }
 
+// child has exited, usually destroys
 void
-rxvt_term::child_exit ()
+rxvt_term::child_cb (child_watcher &w, int status)
 {
+  HOOK_INVOKE ((this, HOOK_CHILD_EXIT, DT_INT, status, DT_END));
+
   cmd_pid = 0;
 
   if (!OPTION (Opt_hold))
@@ -527,22 +531,8 @@ rxvt_term::init (int argc, const char *const *argv)
 
 static struct sig_handlers
 {
-  sig_watcher sw_chld, sw_term, sw_int;
+  sig_watcher sw_term, sw_int;
   
-  void sig_chld (sig_watcher &w)
-  {
-    // we are being called for every SIGCHLD, find the corresponding term
-    int pid;
-
-    while ((pid = waitpid (-1, NULL, WNOHANG)) > 0)
-      for (rxvt_term **t = rxvt_term::termlist.begin (); t < rxvt_term::termlist.end (); t++)
-        if (pid == (*t)->cmd_pid)
-          {
-            (*t)->child_exit ();
-            break;
-          }
-  }
-
   /*
    * Catch a fatal signal and tidy up before quitting
    */
@@ -558,8 +548,7 @@ static struct sig_handlers
   }
 
   sig_handlers ()
-  : sw_chld (this, &sig_handlers::sig_chld),
-    sw_term (this, &sig_handlers::sig_term),
+  : sw_term (this, &sig_handlers::sig_term),
     sw_int  (this, &sig_handlers::sig_term)
   {
   }
@@ -606,7 +595,6 @@ rxvt_init ()
   signal (SIGHUP,  SIG_IGN);
   signal (SIGPIPE, SIG_IGN);
 
-  sig_handlers.sw_chld.start (SIGCHLD);
   sig_handlers.sw_term.start (SIGTERM);
   sig_handlers.sw_int.start  (SIGINT);
 
index d1245903b56521c513954e667ad92f51103d0365..bfd47f1460860cb33512979f9687fff323694251 100644 (file)
@@ -51,7 +51,7 @@ sub on_button_release {
     if ($event->{button} == 2 && ($event->{state} & $mask) == 0) {
        while ($text =~ /$url/g) {
            if ($-[1] <= $col && $+[1] >= $col) {
-               urxvt::exec_async $self->{browser}, $1;
+               $self->exec_async ($self->{browser}, $1);
                return 1;
            }
        }
index ca71f9c3cf7375cde30915e0be63b688395a719e..10e40011c25af0b67116d81123ab6ec266074ac2 100644 (file)
@@ -14,7 +14,8 @@ sub on_init {
 
    for (my $idx = 0; defined (my $res = $self->x_resource ("selection.pattern-$idx")); $idx++) {
       no re 'eval'; # just to be sure
-      $res = utf8::encode $self->locale_decode ($res);
+      $res = $self->locale_decode ($res);
+      utf8::encode $res;
       push @{ $self->{patterns} }, qr/$res/;
    }
 
index bcb0b4e738afd829cd82c1339f4d3c103a9d86ee..82e87d11b81c6bdf927d630f7a3395988478da2a 100644 (file)
@@ -71,7 +71,7 @@ sub on_button_press {
             and $add_button->("shell quote" => sub { $_ = "\Q$_" });
 
          /^(http|ftp|telnet|irc|news):\//
-            and $add_button->("run $self->{browser}" => sub { urxvt::exec_async $self->{browser}, $_ });
+            and $add_button->("run $self->{browser}" => sub { $self->exec_async ($self->{browser}, $_) });
 
          for my $hook (@hook) {
             if (my ($title, $cb) = $hook->($popup)) {
index cac5d4ba50645e79dfa3a3aec3504287209c43a0..4640b511b6a8cb27c902d34431c2e835cbaf8a0a 100644 (file)
@@ -1189,6 +1189,7 @@ struct rxvt_term : zero_initialized, rxvt_vars {
   xevent_watcher scrollbar_ev;
 #endif
 
+  void child_cb (child_watcher &w, int status); child_watcher child_ev;
   void check_cb (check_watcher &w); check_watcher check_ev;
   void destroy_cb (time_watcher &w); time_watcher destroy_ev;
   void flush_cb (time_watcher &w); time_watcher flush_ev;
@@ -1228,7 +1229,6 @@ struct rxvt_term : zero_initialized, rxvt_vars {
 
   rxvt_term ();
   ~rxvt_term ();
-  void child_exit (); // child has exited, usually destroys
   void destroy ();
   void emergency_cleanup ();
 
index e016145d8067687c01d08a78b380831dd680f44c..6b403c5076562d54f6bd79d9a92320887c4043d3 100644 (file)
@@ -145,15 +145,15 @@ $word>:
 And this example matches the same,but replaces it with vi-commands you can
 paste directly into your (vi :) editor:
 
-   URxvt.selection-autotransform.0: s/^([^:[:space:]]+(\\d+):?$/\\x1b:e \\Q$1\\E\\x0d:$2\\x0d/
+   URxvt.selection-autotransform.0: s/^([^:[:space:]]+(\\d+):?$/:e \\Q$1\\E\\x0d:$2\\x0d/
 
 Of course, this can be modified to suit your needs and your editor :)
 
 To expand the example above to typical perl error messages ("XXX at
 FILENAME line YYY."), you need a slightly more elaborate solution:
 
-   URxvt.selection.pattern-0: ( at .*? line \\d+\\.)
-   URxvt.selection-autotransform.0: s/^ at (.*?) line (\\d+)\\.$/\x1b:e \\Q$1\E\\x0d:$2\\x0d/
+   URxvt.selection.pattern-0: ( at .*? line \\d+[,.])
+   URxvt.selection-autotransform.0: s/^ at (.*?) line (\\d+)[,.]$/:e \\Q$1\E\\x0d:$2\\x0d/
 
 The first line tells the selection code to treat the unchanging part of
 every error message as a selection pattern, and the second line transforms
@@ -327,6 +327,15 @@ variables.
 Called at the very end of initialisation of a new terminal, just before
 returning to the mainloop.
 
+=item on_child_start $term, $pid
+
+Called just after the child process has been C<fork>ed.
+
+=item on_child_exit $term, $status
+
+Called just after the child process has exited. C<$status> is the status
+from C<waitpid>.
+
 =item on_sel_make $term, $eventtime
 
 Called whenever a selection has been made by the user, but before the
@@ -746,18 +755,6 @@ sub invoke {
    $retval
 }
 
-sub exec_async(@) {
-   my $pid = fork;
-
-   return
-      if !defined $pid or $pid;
-
-   %ENV = %{ $TERM->env };
-
-   exec @_;
-   _exit 255;
-}
-
 # urxvt::term::extension
 
 package urxvt::term::extension;
@@ -944,6 +941,31 @@ Destroy the terminal object (close the window, free resources
 etc.). Please note that @@RXVT_NAME@@ will not exit as long as any event
 watchers (timers, io watchers) are still active.
 
+=item $term->exec_async ($cmd[, @args])
+
+Works like the combination of the C<fork>/C<exec> builtins, which executes
+("starts") programs in the background. This function takes care of setting
+the user environment before exec'ing the command (e.g. C<PATH>) and should
+be preferred over explicit calls to C<exec> or C<system>.
+
+Returns the pid of the subprocess or C<undef> on error.
+
+=cut
+
+sub exec_async {
+   my $self = shift;
+
+   my $pid = fork;
+
+   return $pid
+      if !defined $pid or $pid;
+
+   %ENV = %{ $self->env };
+
+   exec @_;
+   urxvt::_exit 255;
+}
+
 =item $isset = $term->option ($optval[, $set])
 
 Returns true if the option specified by C<$optval> is enabled, and