xqueryptr.c: Add new program to interrogate the pointer position.
[xtoys] / xatom.c
CommitLineData
01a2fe8e
MW
1/* -*-c-*-
2 *
3 * Set and fetch X atom properties
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Edgeware X tools collection.
11 *
12 * X tools is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * X tools is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with X tools; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27/*----- Header files ------------------------------------------------------*/
28
29#include <errno.h>
30#include <signal.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include <sys/wait.h>
36
37#include <X11/cursorfont.h>
01a2fe8e 38#include <X11/Xlib.h>
01a2fe8e
MW
39
40#include <mLib/mdwopt.h>
41#include <mLib/quis.h>
42#include <mLib/alloc.h>
43#include <mLib/report.h>
44
45#include "libxatom.h"
46
47/*----- Static variables --------------------------------------------------*/
48
166194b0 49static Display *dpy = 0;
01a2fe8e
MW
50static Window window = None;
51
52/*----- Command implementations -------------------------------------------*/
53
54static void help(char **);
55static int c_help(int argc, char **argv)
56 { help(argv + 1); return (0); }
57
58static int c_get(int argc, char **argv)
59{
60 Atom p, a;
61 char *name;
62
63 if (argc != 2)
64 die(EXIT_FAILURE, "Usage: get PROPERTY");
166194b0
MW
65 if ((p = XInternAtom(dpy, argv[1], True)) == None ||
66 (a = xatom_get(dpy, window, p)) == None)
01a2fe8e 67 return (0);
166194b0 68 name = XGetAtomName(dpy, a);
01a2fe8e
MW
69 puts(name);
70 return (0);
71}
72
73static int c_set(int argc, char **argv)
74{
75 Atom p, a;
76
77 if (argc != 3)
78 die(EXIT_FAILURE, "Usage: set PROPERTY VALUE");
166194b0
MW
79 p = XInternAtom(dpy, argv[1], False);
80 a = XInternAtom(dpy, argv[2], False);
81 xatom_set(dpy, window, p, a);
01a2fe8e
MW
82 return (0);
83}
84
85static int c_delete(int argc, char **argv)
86{
87 Atom p;
88
89 if (argc != 2)
90 die(EXIT_FAILURE, "Usage: delete PROPERTY");
166194b0 91 if ((p = XInternAtom(dpy, argv[1], True)) == None)
01a2fe8e 92 return (0);
166194b0 93 xatom_delete(dpy, window, p);
01a2fe8e
MW
94 return (0);
95}
96
97static int c_wait(int argc, char **argv)
98{
99 Atom p, a, *aa = 0;
100 int n;
101 char *name;
102
103 if (argc < 2)
104 die(EXIT_FAILURE, "Usage: wait PROPERTY [VALUE...]");
105
166194b0 106 p = XInternAtom(dpy, argv[1], False);
01a2fe8e
MW
107 n = argc - 2;
108 if (n) {
109 aa = xmalloc(n * sizeof(Atom));
166194b0 110 XInternAtoms(dpy, argv + 2, n, False, aa);
01a2fe8e
MW
111 }
112
166194b0 113 a = xatom_wait(dpy, window, p, aa, n);
01a2fe8e 114 if (n != 1) {
166194b0 115 name = XGetAtomName(dpy, a);
01a2fe8e
MW
116 puts(name);
117 XFree(name);
118 }
119 if (aa)
120 xfree(aa);
121 return (0);
122}
123
124/*----- Utilities ---------------------------------------------------------*/
125
126/* --- @choosewindow@ --- *
127 *
128 * Arguments: ---
129 *
130 * Returns: An X window id.
131 *
132 * Use: Allows the user to select a window using the mouse.
133 */
134
135static Window choosewindow(void)
136{
166194b0 137 Cursor cross = XCreateFontCursor(dpy, XC_crosshair);
01a2fe8e
MW
138 XEvent event;
139
166194b0
MW
140 XGrabPointer(dpy,
141 DefaultRootWindow(dpy),
01a2fe8e
MW
142 False,
143 ButtonPressMask,
144 GrabModeAsync,
145 GrabModeAsync,
146 None,
147 cross,
148 CurrentTime);
149
150 for (;;) {
166194b0 151 XNextEvent(dpy, &event);
01a2fe8e
MW
152 switch (event.type) {
153 case ButtonPress:
154 switch (event.xbutton.button) {
155 case 3:
166194b0 156 XUngrabPointer(dpy, event.xbutton.time);
01a2fe8e
MW
157 die(EXIT_FAILURE, "aborted window selection");
158 break;
159 case 1:
160 window = event.xbutton.subwindow;
161 if (window == None)
162 window = event.xbutton.window;
166194b0 163 XUngrabPointer(dpy, event.xbutton.time);
01a2fe8e
MW
164 return (window);
165 }
166 break;
167 }
168 }
169}
170
171/* --- @autoreap@ --- *
172 *
173 * Arguments: ---
174 *
175 * Returns: ---
176 *
177 * Use: Causes child processes to be reaped as reports of their
178 * demises come in. Their exit statuses are simply discarded.
179 *
180 * This program needs to reap child processes even though it
181 * didn't create them and doesn't know what to do with their
182 * statuses because it's often used in shell scripts of the form
183 *
184 * ... start lots of stuff ...
185 * exec xatom wait GODOT ARRIVED
186 */
187
188static void reap(int sig)
189 { int e = errno; while (waitpid(-1, 0, WNOHANG) > 0) ; errno = e; }
190
191static void autoreap(void)
192{
193 struct sigaction sa;
194 sigset_t ss, oss;
195
196 sa.sa_handler = reap;
197 sigemptyset(&sa.sa_mask);
198 sigaddset(&sa.sa_mask, SIGCHLD);
199 sa.sa_flags = SA_NOCLDSTOP;
200#ifdef SA_RESTART
201 sa.sa_flags |= SA_RESTART;
202#endif
203 sigaction(SIGCHLD, &sa, 0);
204
205 sigemptyset(&ss);
206 sigaddset(&ss, SIGCHLD);
207 sigprocmask(SIG_BLOCK, &ss, &oss);
208 reap(SIGCHLD);
209 sigprocmask(SIG_SETMASK, &oss, 0);
210}
211
212/*----- Command dispatch --------------------------------------------------*/
213
214static const struct cmd {
215 const char *name;
216 int (*cmd)(int, char **);
217 const char *usage;
218 const char *help;
219} cmds[] = {
220 { "help", c_help, "help [COMMANDS...]" },
221 { "get", c_get, "get PROPERTY" },
222 { "set", c_set, "set PROPERTY VALUE" },
223 { "delete", c_delete, "delete PROPERTY" },
224 { "wait", c_wait, "wait PROPERTY [VALUE...]" },
225 { 0 }
226};
227
228const struct cmd *findcmd(const char *name)
229{
230 const struct cmd *c, *chosen = 0;
231 size_t sz = strlen(name);
232
233 for (c = cmds; c->name; c++) {
234 if (strncmp(name, c->name, sz) == 0) {
235 if (c->name[sz] == 0) {
c1c9f4d2
MW
236 chosen = c;
237 break;
01a2fe8e 238 } else if (chosen)
c1c9f4d2 239 die(EXIT_FAILURE, "ambiguous command name `%s'", name);
01a2fe8e 240 else
c1c9f4d2 241 chosen = c;
01a2fe8e
MW
242 }
243 }
244 if (!chosen)
245 die(EXIT_FAILURE, "unknown command name `%s'", name);
246 return (chosen);
247}
248
249/*----- Help and version information --------------------------------------*/
250
251static void version(void)
252 { pquis(stdout, "$ version " VERSION "\n"); }
253
254static void usage(FILE *fp)
255 { pquis(fp, "Usage: $ [-d DISPLAY] SUBCOMMAND [ARGUMENTS...]\n"); }
256
257static void help(char **av)
258{
259 const struct cmd *c;
260
261 version(); putchar('\n');
262 if (!*av) {
263 usage(stdout);
264 fputs("\n\
265Sets, retrieves and waits for properties on an X window.\n\
266\n\
267Global command-line options:\n\
268\n\
269-h, --help [COMMAND] Display this help, or help on COMMAND.\n\
270-v, --version Display program's version number.\n\
271-u, --usage Display short usage summary.\n\
272\n\
273-d, --display=DISPLAY Connect to X DISPLAY.\n\
274-w, --window=WINDOW Use properties on WINDOW instead of root.\n\
275\n\
276The following subcommands are understood:\n\n",
277 stdout);
278 for (c = cmds; c->name; c++)
279 printf("%s\n", c->usage);
280 } else {
281 while (*av) {
282 c = findcmd(*av++);
283 printf("Usage: %s [-OPTIONS] %s\n", QUIS, c->usage);
284 if (c->help) {
285 putchar('\n');
286 pquis(stdout, c->help);
287 }
288 if (*av) putchar('\n');
289 }
290 }
291}
292
293/*----- Main program ------------------------------------------------------*/
294
295int main(int argc, char *argv[])
296{
166194b0 297 const char *display = 0;
01a2fe8e
MW
298 const char *win = 0;
299
300 unsigned f = 0;
301#define F_BOGUS 1u
302
303 ego(argv[0]);
304
305 /* --- Parse arguments --- */
306
307 for (;;) {
308 static struct option opt[] = {
c1c9f4d2
MW
309 { "help", 0, 0, 'h' },
310 { "usage", 0, 0, 'u' },
311 { "version", 0, 0, 'v' },
312 { "display", OPTF_ARGREQ, 0, 'd' },
01a2fe8e
MW
313 { "window", OPTF_ARGREQ, 0, 'w' },
314 { 0, 0, 0, 0 }
315 };
316
317 int i = mdwopt(argc, argv, "+huvd:w:", opt, 0, 0, 0);
318 if (i < 0) break;
319 switch (i) {
320 case 'h': help(argv + optind); exit(0);
321 case 'u': usage(stdout); exit(0);
322 case 'v': version(); exit(0);
166194b0 323 case 'd': display = optarg; break;
01a2fe8e
MW
324 case 'w': win = optarg; break;
325 default: f |= F_BOGUS; break;
326 }
327 }
328 if ((f & F_BOGUS) || optind >= argc) {
329 usage(stderr);
330 exit(EXIT_FAILURE);
331 }
332
333 /* --- Initialize --- */
334
335 autoreap();
166194b0 336 if ((dpy = XOpenDisplay(display)) == 0)
01a2fe8e
MW
337 die(EXIT_FAILURE, "couldn't open display");
338
339 /* --- Select a target window --- */
340
341 if (!win)
166194b0 342 window = DefaultRootWindow(dpy);
01a2fe8e
MW
343 else if (strcmp(win, "choose") == 0)
344 window = choosewindow();
345 else
346 window = (Window)strtoul(win, 0, 0);
347
348 /* --- Dispatch the command --- */
349
350 argc -= optind;
351 argv += optind;
352 optind = 0;
353 return (findcmd(argv[0])->cmd(argc, argv));
354
355#undef F_BOGUS
356}
357
358/*----- That's all, folks -------------------------------------------------*/