X-Git-Url: https://git.distorted.org.uk/~mdw/xtoys/blobdiff_plain/f3b35b6bbd646fb0e676ef3d64c91b38ff9f9162..e571b0f1645bf296026f09b2c43854b178bc4e31:/xwait.c diff --git a/xwait.c b/xwait.c index 06e0e5c..a6b2332 100644 --- a/xwait.c +++ b/xwait.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: xwait.c,v 1.3 1998/11/21 22:30:27 mdw Exp $ + * $Id: xwait.c,v 1.8 1999/08/20 07:29:55 mdw Exp $ * * Wait until prodded by another X client * @@ -29,6 +29,22 @@ /*----- 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. + * + * Revision 1.6 1998/12/11 09:50:07 mdw + * Minor modifications to work with mLib and mgLib. + * + * Revision 1.5 1998/11/30 22:36:53 mdw + * Tidy up tabbing in help texts very slightly. + * + * Revision 1.4 1998/11/21 22:41:19 mdw + * Reap children which die before I get my signal handler installed. + * * Revision 1.3 1998/11/21 22:30:27 mdw * Support GNU-style long options throughout, and introduce proper help * text to all programs. Update manual pages to match. @@ -44,6 +60,7 @@ /*----- Header files ------------------------------------------------------*/ +#include #include #include #include @@ -56,18 +73,92 @@ #include #include -#include "mdwopt.h" -#include "quis.h" +#include +#include +#include +#include + +#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@ --- */ static void sigchld(int sig) { + int e = errno; while (waitpid(-1, 0, WNOHANG) > 0) ; + 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@ --- */ @@ -79,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) { @@ -135,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 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; @@ -150,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; @@ -168,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'"); } } } @@ -203,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); } } @@ -226,45 +320,66 @@ int main(int argc, char *argv[]) sa.sa_handler = sigchld; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGCHLD); - sa.sa_flags = 0; + sa.sa_flags = SA_NOCLDSTOP; +#ifdef SA_RESTART + sa.sa_flags |= SA_RESTART; +#endif sigaction(SIGCHLD, &sa, 0); } + /* --- Now reap any which have been waiting around so far --- */ + + { + sigset_t ss, oss; + + sigemptyset(&ss); + sigaddset(&ss, SIGCHLD); + sigprocmask(SIG_BLOCK, &ss, &oss); + sigchld(SIGCHLD); + 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); }