1 /* xscreensaver-command, Copyright (c) 1991-1998
2 * by Jamie Zawinski <jwz@jwz.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
10 * implied warranty.
11 */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21
22 #ifdef HAVE_SYS_SELECT_H
23 # include <sys/select.h>
24 #endif /* HAVE_SYS_SELECT_H */
25
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29
30 #include <X11/Xproto.h> /* for CARD32 */
31 #include <X11/Xlib.h>
32 #include <X11/Xatom.h>
33 #include <X11/Xutil.h> /* for XGetClassHint() */
34 #include <X11/Xos.h>
35
36 /* for xawtv */
37 #include <X11/Intrinsic.h>
38 extern XtAppContext app_context;
39
40 #include "remote.h"
41
42 #ifdef _VROOT_H_
43 ERROR! you must not include vroot.h in this file
44 #endif
45
46 static char *progname = "fixme";
47 static Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
48 static Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_EXIT;
49 static Atom XA_VROOT, XA_SELECT, XA_DEMO, XA_BLANK, XA_LOCK;
50
51
52 static XErrorHandler old_handler = 0;
53 static Bool got_badwindow = False;
54 static int
55 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
56 {
57 if (error->error_code == BadWindow)
58 {
59 got_badwindow = True;
60 return 0;
61 }
62 else
63 {
64 fprintf (stderr, "%s: ", progname);
65 if (!old_handler) abort();
66 return (*old_handler) (dpy, error);
67 }
68 }
69
70
71
72 static Window
73 find_screensaver_window (Display *dpy, char **version)
74 {
75 unsigned int i;
76 Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
77 Window root2, parent, *kids;
78 unsigned int nkids;
79
80 if (version) *version = 0;
81
82 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
83 abort ();
84 if (root != root2)
85 abort ();
86 if (parent)
87 abort ();
88 if (! (kids && nkids))
89 return 0;
90 for (i = 0; i < nkids; i++)
91 {
92 Atom type;
93 int format;
94 unsigned long nitems, bytesafter;
95 char *v;
96 int status;
97
98 /* We're walking the list of root-level windows and trying to find
99 the one that has a particular property on it. We need to trap
100 BadWindows errors while doing this, because it's possible that
101 some random window might get deleted in the meantime. (That
102 window won't have been the one we're looking for.)
103 */
104 XSync (dpy, False);
105 if (old_handler) abort();
106 got_badwindow = False;
107 old_handler = XSetErrorHandler (BadWindow_ehandler);
108 status = XGetWindowProperty (dpy, kids[i],
109 XA_SCREENSAVER_VERSION,
110 0, 200, False, XA_STRING,
111 &type, &format, &nitems, &bytesafter,
112 (unsigned char **) &v);
113 XSync (dpy, False);
114 XSetErrorHandler (old_handler);
115 old_handler = 0;
116
117 if (got_badwindow)
118 {
119 status = BadWindow;
120 got_badwindow = False;
121 }
122
123 if (status == Success && type != None)
124 {
125 if (version)
126 *version = v;
127 return kids[i];
128 }
129 }
130 return 0;
131 }
132
133
134 static int
135 send_xscreensaver_command (Display *dpy, Atom command, long arg,
136 Window *window_ret, char **error_ret)
137 {
138 char *v = 0;
139 Window window = find_screensaver_window (dpy, &v);
140 XWindowAttributes xgwa;
141 char err[2048];
142
143 if (window_ret)
144 *window_ret = window;
145
146 if (!window)
147 {
148 sprintf (err, "no screensaver is running on display %s",
149 DisplayString (dpy));
150
151 if (error_ret)
152 {
153 *error_ret = strdup (err);
154 return -1;
155 }
156
157 if (command == XA_EXIT)
158 /* Don't print an error if xscreensaver is already dead. */
159 return 1;
160
161 fprintf (stderr, "%s: %s\n", progname, err);
162 return -1;
163 }
164
165 /* Select for property change events, so that we can read the response. */
166 XGetWindowAttributes (dpy, window, &xgwa);
167 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
168
169 if (command == XA_SCREENSAVER_STATUS ||
170 command == XA_SCREENSAVER_VERSION)
171 {
172 XClassHint hint;
173 memset (&hint, 0, sizeof(hint));
174 if (!v || !*v)
175 {
176 sprintf (err, "version property not set on window 0x%x?",
177 (unsigned int) window);
178 if (error_ret)
179 *error_ret = strdup (err);
180 else
181 fprintf (stderr, "%s: %s\n", progname, err);
182 return -1;
183 }
184
185 XGetClassHint(dpy, window, &hint);
186 if (!hint.res_class)
187 {
188 sprintf (err, "class hints not set on window 0x%x?",
189 (unsigned int) window);
190 if (error_ret)
191 *error_ret = strdup (err);
192 else
193 fprintf (stderr, "%s: %s\n", progname, err);
194 return -1;
195 }
196
197 fprintf (stdout, "%s %s", hint.res_class, v);
198
199 if (command != XA_SCREENSAVER_STATUS)
200 {
201 fprintf (stdout, "\n");
202 }
203 else
204 {
205 Atom type;
206 int format;
207 unsigned long nitems, bytesafter;
208 CARD32 *data = 0;
209
210 if (XGetWindowProperty (dpy,
211 RootWindow (dpy, 0),
212 XA_SCREENSAVER_STATUS,
213 0, 999, False, XA_INTEGER,
214 &type, &format, &nitems, &bytesafter,
215 (unsigned char **) &data)
216 == Success
217 && type
218 && data)
219 {
220 Atom blanked;
221 time_t tt;
222 char *s;
223
224 if (type != XA_INTEGER || nitems < 3)
225 {
226 STATUS_LOSE:
227 if (data) free (data);
228 fprintf (stdout, "\n");
229 fflush (stdout);
230 fprintf (stderr, "bad status format on root window.\n");
231 return -1;
232 }
233
234 blanked = (Atom) data[0];
235 tt = (time_t) data[1];
236
237 if (tt <= (time_t) 666000000L) /* early 1991 */
238 goto STATUS_LOSE;
239
240 if (blanked == XA_BLANK)
241 fputs (": screen blanked since ", stdout);
242 else if (blanked == XA_LOCK)
243 fputs (": screen locked since ", stdout);
244 else if (blanked == 0)
245 /* suggestions for a better way to phrase this are welcome. */
246 fputs (": screen non-blanked since ", stdout);
247 else
248 /* `blanked' has an unknown value - fail. */
249 goto STATUS_LOSE;
250
251 s = ctime(&tt);
252 if (s[strlen(s)-1] == '\n')
253 s[strlen(s)-1] = 0;
254 fputs (s, stdout);
255
256 {
257 int nhacks = nitems - 2;
258 Bool any = False;
259 int i;
260 for (i = 0; i < nhacks; i++)
261 if (data[i + 2] > 0)
262 {
263 any = True;
264 break;
265 }
266
267 if (any && nhacks == 1)
268 fprintf (stdout, " (hack #%ld)\n", data[2]);
269 else if (any)
270 {
271 fprintf (stdout, " (hacks: ");
272 for (i = 0; i < nhacks; i++)
273 {
274 fprintf (stdout, "#%ld", data[2 + i]);
275 if (i != nhacks-1)
276 fputs (", ", stdout);
277 }
278 fputs (")\n", stdout);
279 }
280 else
281 fputs ("\n", stdout);
282 }
283
284 if (data) free (data);
285 }
286 else
287 {
288 if (data) free (data);
289 fprintf (stdout, "\n");
290 fflush (stdout);
291 fprintf (stderr, "no saver status on root window.\n");
292 return -1;
293 }
294 }
295
296 /* No need to read a response for these commands. */
297 return 1;
298 }
299 else
300 {
301 XEvent event;
302 long arg1 = arg;
303 long arg2 = 0;
304
305 if (arg < 0)
306 abort();
307 else if (arg == 0 && command == XA_SELECT)
308 abort();
309 else if (arg != 0 && command == XA_DEMO)
310 {
311 arg1 = 300; /* version number of the XA_DEMO protocol, */
312 arg2 = arg; /* since it didn't use to take an argument. */
313 }
314
315 event.xany.type = ClientMessage;
316 event.xclient.display = dpy;
317 event.xclient.window = window;
318 event.xclient.message_type = XA_SCREENSAVER;
319 event.xclient.format = 32;
320 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
321 event.xclient.data.l[0] = (long) command;
322 event.xclient.data.l[1] = arg1;
323 event.xclient.data.l[2] = arg2;
324 if (! XSendEvent (dpy, window, False, 0L, &event))
325 {
326 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
327 (unsigned int) window);
328 if (error_ret)
329 *error_ret = strdup (err);
330 else
331 fprintf (stderr, "%s: %s\n", progname, err);
332 return -1;
333 }
334 }
335 XSync (dpy, 0);
336 return 0;
337 }
338
339
340 static int
341 xscreensaver_command_response (Display *dpy, Window window,
342 Bool verbose_p, Bool exiting_p,
343 char **error_ret)
344 {
345 int fd = ConnectionNumber (dpy);
346 int timeout = 10;
347 int status;
348 fd_set fds;
349 struct timeval tv;
350 char err[2048];
351
352 while (1)
353 {
354 FD_ZERO(&fds);
355 FD_SET(fd, &fds);
356 memset(&tv, 0, sizeof(tv));
357 tv.tv_sec = timeout;
358 status = select (fd+1, &fds, 0, &fds, &tv);
359
360 if (status < 0)
361 {
362 char buf[1024];
363 if (error_ret)
364 {
365 sprintf (buf, "error waiting for reply");
366 *error_ret = strdup (buf);
367 }
368 else
369 {
370 sprintf (buf, "%s: error waiting for reply", progname);
371 perror (buf);
372 }
373 return status;
374 }
375 else if (status == 0)
376 {
377 sprintf (err, "no response to command.");
378 if (error_ret)
379 *error_ret = strdup (err);
380 else
381 fprintf (stderr, "%s: %s\n", progname, err);
382 return -1;
383 }
384 else
385 {
386 XEvent event;
387 XtAppNextEvent(app_context,&event);
388 if (event.xany.type == PropertyNotify &&
389 event.xproperty.state == PropertyNewValue &&
390 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
391 {
392 Status st2;
393 Atom type;
394 int format;
395 unsigned long nitems, bytesafter;
396 char *msg = 0;
397
398 XSync (dpy, False);
399 if (old_handler) abort();
400 old_handler = XSetErrorHandler (BadWindow_ehandler);
401 st2 = XGetWindowProperty (dpy, window,
402 XA_SCREENSAVER_RESPONSE,
403 0, 1024, True,
404 AnyPropertyType,
405 &type, &format, &nitems, &bytesafter,
406 (unsigned char **) &msg);
407 XSync (dpy, False);
408 XSetErrorHandler (old_handler);
409 old_handler = 0;
410
411 if (got_badwindow)
412 {
413 if (exiting_p)
414 return 0;
415
416 sprintf (err, "xscreensaver window unexpectedly deleted.");
417
418 if (error_ret)
419 *error_ret = strdup (err);
420 else
421 fprintf (stderr, "%s: %s\n", progname, err);
422
423 return -1;
424 }
425
426 if (st2 == Success && type != None)
427 {
428 if (type != XA_STRING || format != 8)
429 {
430 sprintf (err, "unrecognized response property.");
431
432 if (error_ret)
433 *error_ret = strdup (err);
434 else
435 fprintf (stderr, "%s: %s\n", progname, err);
436
437 if (msg) XFree (msg);
438 return -1;
439 }
440 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
441 {
442 sprintf (err, "unrecognized response message.");
443
444 if (error_ret)
445 *error_ret = strdup (err);
446 else
447 fprintf (stderr, "%s: %s\n", progname, err);
448
449 if (msg) XFree (msg);
450 return -1;
451 }
452 else
453 {
454 int ret = (msg[0] == '+' ? 0 : -1);
455 sprintf (err, "%s: %s\n", progname, msg+1);
456
457 if (error_ret)
458 *error_ret = strdup (err);
459 else if (verbose_p || ret != 0)
460 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
461
462 XFree (msg);
463 return ret;
464 }
465 }
466 } else {
467 XtDispatchEvent(&event);
468 }
469 }
470 }
471 }
472
473
474 int
475 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
476 char **error_ret)
477 {
478 Window w = 0;
479 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
480 if (status == 0)
481 status = xscreensaver_command_response (dpy, w, verbose_p,
482 (command == XA_EXIT),
483 error_ret);
484
485 fflush (stdout);
486 fflush (stderr);
487 return (status < 0 ? status : 0);
488 }
489
490
491 void
492 server_xscreensaver_version (Display *dpy,
493 char **version_ret,
494 char **user_ret,
495 char **host_ret)
496 {
497 Window window = find_screensaver_window (dpy, 0);
498
499 Atom type;
500 int format;
501 unsigned long nitems, bytesafter;
502
503 if (version_ret)
504 *version_ret = 0;
505 if (user_ret)
506 *user_ret = 0;
507 if (host_ret)
508 *host_ret = 0;
509
510 if (!window)
511 return;
512
513 if (version_ret)
514 {
515 char *v = 0;
516 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
517 False, XA_STRING, &type, &format, &nitems,
518 &bytesafter, (unsigned char **) &v);
519 if (v)
520 {
521 *version_ret = strdup (v);
522 XFree (v);
523 }
524 }
525
526 if (user_ret || host_ret)
527 {
528 char *id = 0;
529 const char *user = 0;
530 const char *host = 0;
531
532 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
533 False, XA_STRING, &type, &format, &nitems,
534 &bytesafter, (unsigned char **) &id);
535 if (id && *id)
536 {
537 const char *old_tag = " on host ";
538 const char *s = strstr (id, old_tag);
539 if (s)
540 {
541 /* found ID of the form "1234 on host xyz". */
542 user = 0;
543 host = s + strlen (old_tag);
544 }
545 else
546 {
547 char *o = 0, *p = 0, *c = 0;
548 o = strchr (id, '(');
549 if (o) p = strchr (o, '@');
550 if (p) c = strchr (p, ')');
551 if (c)
552 {
553 /* found ID of the form "1234 (user@host)". */
554 user = o+1;
555 host = p+1;
556 *p = 0;
557 *c = 0;
558 }
559 }
560
561 }
562
563 if (user && *user && *user != '?')
564 *user_ret = strdup (user);
565 else
566 *user_ret = 0;
567
568 if (host && *host && *host != '?')
569 *host_ret = strdup (host);
570 else
571 *host_ret = 0;
572
573 if (id)
574 XFree (id);
575 }
576 }
577
578 void xscreensaver_init(Display *dpy)
579 {
580 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
581 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
582 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
583 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
584 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
585 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
586 XA_SELECT = XInternAtom (dpy, "SELECT", False);
587 XA_EXIT = XInternAtom (dpy, "EXIT", False);
588 XA_DEMO = XInternAtom (dpy, "DEMO", False);
589 XA_LOCK = XInternAtom (dpy, "LOCK", False);
590 XA_BLANK = XInternAtom (dpy, "BLANK", False);
591 }
592
|
This page was automatically generated by the
LXR engine.
|