New command line syntax, and new atom protocol. Wait for multiple
authormdw <mdw>
Fri, 20 Aug 1999 07:29:55 +0000 (07:29 +0000)
committermdw <mdw>
Fri, 20 Aug 1999 07:29:55 +0000 (07:29 +0000)
properties and listen for multiple (or all) values.

xwait.1
xwait.c

diff --git a/xwait.1 b/xwait.1
index 336c595..4c09801 100644 (file)
--- a/xwait.1
+++ b/xwait.1
@@ -3,6 +3,7 @@
 .SH NAME
 xwait \- wait until prodded by another X client
 .SH SYNOPSIS
+.ll +5i
 .B xwait
 .RB [ \-f ]
 .RB [ \-d
@@ -11,6 +12,10 @@ xwait \- wait until prodded by another X client
 .IR atom ]
 .RB [ \-m
 .IR message ]
+.RI [ \c
+.IB atom : msg , msg \c
+\&...]
+.ll -5i
 .SH DESCRIPTION
 The
 .B xwait
@@ -24,10 +29,10 @@ programs.  It's mostly useful for putting at the end of a user's
 .B .xinitrc
 file, so that it can be triggered to end the session.
 .PP
-The property, and the value to listen for, can be configured at
-the command line.  When
+The properties, and the values to listen for, can be configured at the
+command line.  When
 .B xwait
-exits, it removes the property from the root window.
+exits, it removes the properties from the root window.
 .SS OPTIONS
 .TP 5
 .B \-f, \-\-force
@@ -46,15 +51,33 @@ Sets
 .B xwait
 to listen for the property named
 .IR atom .
-The default property to listen to is
-.BR XWAIT_PROPERTY .
+Use of this option is deprecated.
 .TP 5
 .BI "\-m, \-\-msg " message
 Sets
 .B xwait
 to wait for the given property to be set to
 .IR message .
-The default message to wait for is
+Use of this option is deprecated.
+.SS "Argument format"
+The
+.B \-a
+and
+.B \-m
+options are deprecated, though retained for compatibility reasons.
+It's recommended that you use the non-option specification instead.
+.PP
+Each argument specifies an atom name and a list of message strings to
+listen to.  Multiple properties may be listened for, and multiple
+messages may be accepted for each property.  If no messages are
+specified then all values are considered to be acceptable.  The program
+exits when any property is set to an acceptable value.
+.PP
+If no atoms are given on the command line,
+.B xwait
+will wait for
+.B XWAIT_PROPERTY
+to be set to
 .BR XWAIT_MESSAGE .
 .SH AUTHOR
 Mark Wooding (mdw@nsict.org).
diff --git a/xwait.c b/xwait.c
index c74d2e2..a6b2332 100644 (file)
--- a/xwait.c
+++ b/xwait.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: xwait.c,v 1.7 1999/06/19 23:42:37 mdw Exp $
+ * $Id: xwait.c,v 1.8 1999/08/20 07:29:55 mdw Exp $
  *
  * Wait until prodded by another X client
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: xwait.c,v $
+ * Revision 1.8  1999/08/20 07:29:55  mdw
+ * New command line syntax, and new atom protocol.  Wait for multiple
+ * properties and listen for multiple (or all) values.
+ *
  * Revision 1.7  1999/06/19 23:42:37  mdw
  * Improve signal handling.
  *
 
 #include <mLib/mdwopt.h>
 #include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
 
+#include "xatom.h"
 #include "xwait.h"
 
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct xwait_msg {
+  struct xwait_msg *next;              /* Next message in the list */
+  Atom a;                              /* The message atom */
+} xwait_msg;
+
+typedef struct xwait_atom {
+  struct xwait_atom *next;             /* Next atom in the list */
+  Atom a;                              /* The actual atom */
+  xwait_msg *m;                                /* List of interesting messages */
+} xwait_atom;
+
+/*----- Static variables --------------------------------------------------*/
+
+static xwait_atom *atoms = 0;
+static Display *dpy;
+
 /*----- Main code ---------------------------------------------------------*/
 
 /* --- @sigchld@ --- */
@@ -86,6 +111,56 @@ static void sigchld(int sig)
   errno = e;
 }
 
+/* --- @opendisplay@ --- */
+
+static void opendisplay(const char *d)
+{
+  if (dpy)
+    return;
+  if ((dpy = XOpenDisplay(d)) == 0)
+    die(EXIT_FAILURE, "couldn't open display");
+}
+
+/* --- @addatom@ --- */
+
+static xwait_atom *addatom(const char *a)
+{
+  xwait_atom *xa = CREATE(xwait_atom);
+  opendisplay(0);
+  xa->next = atoms;
+  xa->a = XInternAtom(dpy, a, False);
+  xa->m = 0;
+  atoms = xa;
+  return (xa);
+}
+
+/* --- @addmsg@ --- */
+
+static void addmsg(xwait_atom *xa, const char *a)
+{
+  xwait_msg *xm = CREATE(xwait_msg);
+  opendisplay(0);
+  xm->next = xa->m;
+  xm->a = XInternAtom(dpy, a, False);
+  xa->m = xm;
+}
+
+/* --- @tidy@ --- */
+
+static void tidy(int sig)
+{
+  int i;
+  int nsc = ScreenCount(dpy);
+  xwait_atom *xa;
+
+  for (i = 0; i < nsc; i++) {
+    for (xa = atoms; xa; xa = xa->next)
+      XDeleteProperty(dpy, RootWindow(dpy, i), xa->a);
+  }
+  XCloseDisplay(dpy);
+  exit(0);
+}
+
 /* --- @main@ --- */
 
 static void version(FILE *fp)
@@ -95,40 +170,41 @@ static void version(FILE *fp)
 
 static void usage(FILE *fp)
 {
-  fprintf(fp, "Usage: %s [-f] [-d DISPLAY] [-a ATOM] [-m MSG]\n", QUIS);
+  fprintf(fp, "Usage: %s [-f] [-d DISPLAY] [ATOM:MSG,MSG]...\n", QUIS);
 }
 
 int main(int argc, char *argv[])
 {
-  char *display = 0;
-  Display *dpy;
-  Atom xwait_die;
+  Atom a;
   XEvent ev;
-  char *atom = XWAIT_DIE;
-  char *msg = XWAIT_DIE_MSG;
   unsigned f = 0;
+  xwait_atom *xa = 0;
+  xwait_msg *xm = 0;
 
   enum {
     f_force = 1
   };
 
-  /* --- Parse options --- */
+  /* --- Initialize mLib --- */
 
   ego(argv[0]);
+  sub_init();
+
+  /* --- Parse options --- */
 
   for (;;) {
     static struct option opt[] = {
       { "help",        0,                      0,      'h' },
       { "usage",       0,                      0,      'u' },
       { "version",     0,                      0,      'v' },
-      { "display",     required_argument,      0,      'd' },
-      { "atom",                required_argument,      0,      'a' },
-      { "msg",         required_argument,      0,      'm' },
+      { "display",     OPTF_ARGREQ,            0,      'd' },
+      { "atom",                OPTF_ARGREQ,            0,      'a' },
+      { "msg",         OPTF_ARGREQ,            0,      'm' },
       { "force",       0,                      0,      'f' },
       {        0,              0,                      0,      0 }
     };
 
-    int i = getopt_long(argc, argv, "d:a:m:f", opt, 0);
+    int i = mdwopt(argc, argv, "d:a:m:f", opt, 0, 0, 0);
     if (i < 0)
       break;
     switch (i) {
@@ -151,8 +227,8 @@ int main(int argc, char *argv[])
 "-d, --display=DISPLAY Choose X display to connect to\n"
 "-f, --force           Run even if this property is waited for by another\n"
 "                      process\n"
-"-a, --atom=ATOM\t     Choose property name to listen for\n"
-"-m, --msg=MSG         Choose value of property to wait for\n",
+"-a, --atom=ATOM\t     Choose property name to listen for [deprecated]\n"
+"-m, --msg=MSG         Choose value of property to wait for [deprecated]\n",
           stdout);
        exit(0);
        break;
@@ -166,13 +242,15 @@ int main(int argc, char *argv[])
        break;
        
       case 'd':
-       display = optarg;
+       opendisplay(optarg);
        break;
       case 'a':
-       atom = optarg;
+       xa = addatom(optarg);
        break;
       case 'm':
-       msg = optarg;
+       if (!xa)
+         die(EXIT_FAILURE, "no atom currently defined");
+       addmsg(xa, optarg);
        break;
       case 'f':
        f |= f_force;
@@ -184,34 +262,38 @@ int main(int argc, char *argv[])
     }
   }
 
-  /* --- Connect to the X display --- */
+  /* --- Grind through remaining arguments in the new syntax --- */
 
-  dpy = XOpenDisplay(display);
-  if (!dpy) {
-    fprintf(stderr, "xwait: couldn't open display\n");
-    exit(EXIT_FAILURE);
+  while (optind < argc) {
+    char *p = strtok(argv[optind++], ":");
+    if (!p)
+      continue;
+    xa = addatom(p);
+    while ((p = strtok(0, ",")) != 0)
+      addmsg(xa, p);
   }
 
-  /* --- Fetch the property name atom --- */
+  /* --- If there's nothing set, put in some defaults --- */
 
-  xwait_die = XInternAtom(dpy, atom, False);
+  if (!atoms) {
+    xa = addatom(XWAIT_DIE);
+    addmsg(xa, XWAIT_DIE_MSG);
+  }
 
-  /* --- Mark ourselves as listening to all the screens --- */
+  /* --- Attach the atoms to the screens --- */
 
   {
     int i;
+    Atom ready = XInternAtom(dpy, "XWAIT_READY", False);
     int nsc = ScreenCount(dpy);
 
     /* --- First pass: make sure there's not a process already here --- */
 
     if ((f & f_force) == 0) {
       for (i = 0; i < nsc; i++) {
-       Window win = RootWindow(dpy, i);
-       XTextProperty prop;
-
-       if (XGetTextProperty(dpy, win, &prop, xwait_die)) {
-         fprintf(stderr, "xwait: already waiting for `%s'\n", atom);
-         exit(EXIT_FAILURE);
+       for (xa = atoms; xa; xa = xa->next) {
+         if (xatom_get(dpy, RootWindow(dpy, i), xa->a) != None)
+           die(EXIT_FAILURE, "already waiting for `%s'");
        }
       }
     }
@@ -219,13 +301,9 @@ int main(int argc, char *argv[])
     /* --- Second pass: set up listening to the property --- */
 
     for (i = 0; i < nsc; i++) {
-      Window win = RootWindow(dpy, i);
-      XTextProperty prop;
-      char *imsg = "XWAIT_READY";
-
-      XStringListToTextProperty(&imsg, 1, &prop);
-      XSetTextProperty(dpy, win, &prop, xwait_die);
-      XSelectInput(dpy, win, PropertyChangeMask);
+      for (xa = atoms; xa; xa = xa->next)
+       xatom_set(dpy, RootWindow(dpy, i), xa->a, ready);
+      XSelectInput(dpy, RootWindow(dpy, i), PropertyChangeMask);
     }
   }
 
@@ -238,9 +316,6 @@ int main(int argc, char *argv[])
 
   {
     struct sigaction sa;
-    sigset_t ss, oss;
-
-    /* --- Set the handler up --- */
 
     sa.sa_handler = sigchld;
     sigemptyset(&sa.sa_mask);
@@ -250,8 +325,12 @@ int main(int argc, char *argv[])
     sa.sa_flags |= SA_RESTART;
 #endif
     sigaction(SIGCHLD, &sa, 0);
+  }
 
-    /* --- Now reap any which have been waiting around so far --- */
+  /* --- Now reap any which have been waiting around so far --- */
+
+  {
+    sigset_t ss, oss;
 
     sigemptyset(&ss);
     sigaddset(&ss, SIGCHLD);
@@ -260,41 +339,47 @@ int main(int argc, char *argv[])
     sigprocmask(SIG_SETMASK, &oss, 0);
   }
 
+  signal(SIGINT, tidy);
+  signal(SIGTERM, tidy);
+
   /* --- Now wait for an event --- */
 
   for (;;) {
     XNextEvent(dpy, &ev);
     switch (ev.type) {
       case PropertyNotify:
-       if (ev.xproperty.atom == xwait_die) {
-         XTextProperty prop;
-         char **sl;
-         int c;
-
-         if (XGetTextProperty(dpy, ev.xproperty.window, &prop, xwait_die)) {
-           XTextPropertyToStringList(&prop, &sl, &c);
-           if (strcmp(sl[0], msg) == 0)
+       for (xa = atoms; xa; xa = xa->next) {
+         if (ev.xproperty.atom != xa->a)
+           continue;
+         a = xatom_get(dpy, ev.xproperty.window, xa->a);
+         if (a == None)
+           continue;
+         if (xa->m == 0)
+           goto exit;
+         for (xm = xa->m; xm; xm = xm->next) {
+           if (a == xm->a)
              goto exit;
-           XFreeStringList(sl);
          }
        }
+       break;
     }
   }
 
-  /* --- Finished: remove the property from all the screens --- */
+  /* --- Finished: report the result if necessary --- */
 
 exit:
-  {
-    int i;
-    int nsc = ScreenCount(dpy);
-
-    for (i = 0; i < nsc; i++)
-      XDeleteProperty(dpy, RootWindow(dpy, i), xwait_die);
-  }
+  if (atoms->next) {
+    fputs(XGetAtomName(dpy, xa->a), stdout);
+    if (!xa->m || xa->m->next)
+      printf(": %s\n", XGetAtomName(dpy, a));
+    else
+      fputc('\n', stdout);
+  } else if (!xa->m || xa->m->next)
+    printf("%s\n", XGetAtomName(dpy, a));
 
   /* --- Go away --- */
 
-  XCloseDisplay(dpy);
+  tidy(0);
   return (0);
 }