chiark / gitweb /
45bb4261cc47c0e0ef09dd220abdb4ca125e2ae0
[xtoys] / xwait.c
1 /* -*-c-*-
2  *
3  * $Id: xwait.c,v 1.2 1998/11/18 21:25:06 mdw Exp $
4  *
5  * Wait until prodded by another X client
6  *
7  * (c) 1998 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the Edgeware X tools collection.
13  *
14  * X tools is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * X tools is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with X tools; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: xwait.c,v $
32  * Revision 1.2  1998/11/18 21:25:06  mdw
33  * Reap dead children as they arrive.  The previous shell may have
34  * carelessly left them behind.
35  *
36  * Revision 1.1  1998/11/16 23:00:49  mdw
37  * Initial versions.
38  *
39  */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <unistd.h>
51
52 #include <X11/Xlib.h>
53 #include <X11/Xutil.h>
54
55 #include "xwait.h"
56
57 /*----- Main code ---------------------------------------------------------*/
58
59 /* --- @sigchld@ --- */
60
61 static void sigchld(int sig)
62 {
63   while (waitpid(-1, 0, WNOHANG) > 0)
64     ;
65 }
66
67 /* --- @main@ --- */
68
69 int main(int argc, char *argv[])
70 {
71   char *display = 0;
72   Display *dpy;
73   Atom xwait_die;
74   XEvent ev;
75   char *atom = XWAIT_DIE;
76   char *msg = XWAIT_DIE_MSG;
77   unsigned f = 0;
78
79   enum {
80     f_force = 1
81   };
82
83   /* --- Parse options --- */
84
85   for (;;) {
86     int i = getopt(argc, argv, "d:a:m:f");
87     if (i < 0)
88       break;
89     switch (i) {
90       case 'd':
91         display = optarg;
92         break;
93       case 'a':
94         atom = optarg;
95         break;
96       case 'm':
97         msg = optarg;
98         break;
99       case 'f':
100         f |= f_force;
101         break;
102       default:
103         fprintf(stderr,
104                 "Usage: xwait [-f] [-d DISPLAY] [-a ATOM] [-m MSG]\n");
105         exit(EXIT_FAILURE);
106         break;
107     }
108   }
109
110   /* --- Connect to the X display --- */
111
112   dpy = XOpenDisplay(display);
113   if (!dpy) {
114     fprintf(stderr, "xwait: couldn't open display\n");
115     exit(EXIT_FAILURE);
116   }
117
118   /* --- Fetch the property name atom --- */
119
120   xwait_die = XInternAtom(dpy, atom, False);
121
122   /* --- Mark ourselves as listening to all the screens --- */
123
124   {
125     int i;
126     int nsc = ScreenCount(dpy);
127
128     /* --- First pass: make sure there's not a process already here --- */
129
130     if ((f & f_force) == 0) {
131       for (i = 0; i < nsc; i++) {
132         Window win = RootWindow(dpy, i);
133         XTextProperty prop;
134
135         if (XGetTextProperty(dpy, win, &prop, xwait_die)) {
136           fprintf(stderr, "xwait: already waiting for `%s'\n", atom);
137           exit(EXIT_FAILURE);
138         }
139       }
140     }
141
142     /* --- Second pass: set up listening to the property --- */
143
144     for (i = 0; i < nsc; i++) {
145       Window win = RootWindow(dpy, i);
146       XTextProperty prop;
147       char *imsg = "XWAIT_READY";
148
149       XStringListToTextProperty(&imsg, 1, &prop);
150       XSetTextProperty(dpy, win, &prop, xwait_die);
151       XSelectInput(dpy, win, PropertyChangeMask);
152     }
153   }
154
155   /* --- Set up a handler when children die --- *
156    *
157    * I don't fork any children?  Why is this useful?  Because I've been
158    * execed from a shell which started lots of background processes, and
159    * they'll zombie themselves otherwise.
160    */
161
162   {
163     struct sigaction sa;
164
165     sa.sa_handler = sigchld;
166     sigemptyset(&sa.sa_mask);
167     sigaddset(&sa.sa_mask, SIGCHLD);
168     sa.sa_flags = 0;
169     sigaction(SIGCHLD, &sa, 0);
170   }
171
172   /* --- Now wait for an event --- */
173
174   for (;;) {
175     XNextEvent(dpy, &ev);
176     switch (ev.type) {
177       case PropertyNotify:
178         if (ev.xproperty.atom == xwait_die) {
179           XTextProperty prop;
180           char **sl;
181           int c;
182
183           if (XGetTextProperty(dpy, ev.xproperty.window, &prop, xwait_die)) {
184             XTextPropertyToStringList(&prop, &sl, &c);
185             if (strcmp(sl[0], msg) == 0)
186               goto exit;
187             XFreeStringList(sl);
188           }
189         }
190     }
191   }
192
193   /* --- Finished: remove the property from all the screens --- */
194
195 exit:
196   {
197     int i;
198     int nsc = ScreenCount(dpy);
199
200     for (i = 0; i < nsc; i++)
201       XDeleteProperty(dpy, RootWindow(dpy, i), xwait_die);
202   }
203
204   /* --- Go away --- */
205
206   XCloseDisplay(dpy);
207   return (0);
208 }
209
210 /*----- That's all, folks -------------------------------------------------*/