1 /* xscreensaver-command, Copyright (c) 1991-2009 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_SELECT_H
23 # include <sys/select.h>
24 #endif /* HAVE_SYS_SELECT_H */
30 #include <X11/Xproto.h> /* for CARD32 */
32 #include <X11/Xatom.h>
33 #include <X11/Xutil.h> /* for XGetClassHint() */
39 ERROR! you must not include vroot.h in this file
42 extern char *progname;
43 extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
44 extern Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_EXIT;
45 extern Atom XA_VROOT, XA_SELECT, XA_DEMO, XA_BLANK, XA_LOCK;
48 static XErrorHandler old_handler = 0;
49 static Bool got_badwindow = False;
51 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
53 if (error->error_code == BadWindow)
60 fprintf (stderr, "%s: ", progname);
61 if (!old_handler) abort();
62 return (*old_handler) (dpy, error);
69 find_screensaver_window (Display *dpy, char **version)
72 Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
73 Window root2, parent, *kids;
76 if (version) *version = 0;
78 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
84 if (! (kids && nkids))
86 for (i = 0; i < nkids; i++)
90 unsigned long nitems, bytesafter;
94 /* We're walking the list of root-level windows and trying to find
95 the one that has a particular property on it. We need to trap
96 BadWindows errors while doing this, because it's possible that
97 some random window might get deleted in the meantime. (That
98 window won't have been the one we're looking for.)
101 if (old_handler) abort();
102 got_badwindow = False;
103 old_handler = XSetErrorHandler (BadWindow_ehandler);
104 status = XGetWindowProperty (dpy, kids[i],
105 XA_SCREENSAVER_VERSION,
106 0, 200, False, XA_STRING,
107 &type, &format, &nitems, &bytesafter,
110 XSetErrorHandler (old_handler);
116 got_badwindow = False;
119 if (status == Success && type != None)
121 Window ret = kids[i];
123 *version = (char *) v;
129 if (kids) XFree (kids);
135 send_xscreensaver_command (Display *dpy, Atom command, long arg,
136 Window *window_ret, char **error_ret)
140 Window window = find_screensaver_window (dpy, &v);
141 XWindowAttributes xgwa;
145 *window_ret = window;
149 sprintf (err, "no screensaver is running on display %s",
150 DisplayString (dpy));
154 *error_ret = strdup (err);
159 if (command == XA_EXIT)
161 /* Don't print an error if xscreensaver is already dead. */
166 fprintf (stderr, "%s: %s\n", progname, err);
171 /* Select for property change events, so that we can read the response. */
172 XGetWindowAttributes (dpy, window, &xgwa);
173 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
175 if (command == XA_SCREENSAVER_STATUS ||
176 command == XA_SCREENSAVER_VERSION)
179 memset (&hint, 0, sizeof(hint));
182 sprintf (err, "version property not set on window 0x%x?",
183 (unsigned int) window);
185 *error_ret = strdup (err);
187 fprintf (stderr, "%s: %s\n", progname, err);
193 XGetClassHint(dpy, window, &hint);
196 sprintf (err, "class hints not set on window 0x%x?",
197 (unsigned int) window);
199 *error_ret = strdup (err);
201 fprintf (stderr, "%s: %s\n", progname, err);
207 fprintf (stdout, "%s %s", hint.res_class, v);
209 if (command != XA_SCREENSAVER_STATUS)
211 fprintf (stdout, "\n");
217 unsigned long nitems, bytesafter;
218 unsigned char *dataP = 0;
220 if (XGetWindowProperty (dpy,
222 XA_SCREENSAVER_STATUS,
223 0, 999, False, XA_INTEGER,
224 &type, &format, &nitems, &bytesafter,
233 Atom *data = (Atom *) dataP;
235 if (type != XA_INTEGER || nitems < 3)
238 if (data) free (data);
239 fprintf (stdout, "\n");
241 fprintf (stderr, "bad status format on root window.\n");
246 blanked = (Atom) data[0];
247 tt = (time_t) data[1];
249 if (tt <= (time_t) 666000000L) /* early 1991 */
252 if (blanked == XA_BLANK)
253 fputs (": screen blanked since ", stdout);
254 else if (blanked == XA_LOCK)
255 fputs (": screen locked since ", stdout);
256 else if (blanked == 0)
257 /* suggestions for a better way to phrase this are welcome. */
258 fputs (": screen non-blanked since ", stdout);
260 /* `blanked' has an unknown value - fail. */
264 if (s[strlen(s)-1] == '\n')
269 int nhacks = nitems - 2;
272 for (i = 0; i < nhacks; i++)
279 if (any && nhacks == 1)
280 fprintf (stdout, " (hack #%d)\n", (int) data[2]);
283 fprintf (stdout, " (hacks: ");
284 for (i = 0; i < nhacks; i++)
286 fprintf (stdout, "#%d", (int) data[2 + i]);
288 fputs (", ", stdout);
290 fputs (")\n", stdout);
293 fputs ("\n", stdout);
296 if (data) free (data);
300 if (dataP) XFree (dataP);
301 fprintf (stdout, "\n");
303 fprintf (stderr, "no saver status on root window.\n");
309 /* No need to read a response for these commands. */
321 else if (arg == 0 && command == XA_SELECT)
323 else if (arg != 0 && command == XA_DEMO)
325 arg1 = 5000; /* version number of the XA_DEMO protocol, */
326 arg2 = arg; /* since it didn't use to take an argument. */
329 event.xany.type = ClientMessage;
330 event.xclient.display = dpy;
331 event.xclient.window = window;
332 event.xclient.message_type = XA_SCREENSAVER;
333 event.xclient.format = 32;
334 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
335 event.xclient.data.l[0] = (long) command;
336 event.xclient.data.l[1] = arg1;
337 event.xclient.data.l[2] = arg2;
338 if (! XSendEvent (dpy, window, False, 0L, &event))
340 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
341 (unsigned int) window);
343 *error_ret = strdup (err);
345 fprintf (stderr, "%s: %s\n", progname, err);
361 xscreensaver_command_event_p (Display *dpy, XEvent *event, XPointer arg)
363 return (event->xany.type == PropertyNotify &&
364 event->xproperty.state == PropertyNewValue &&
365 event->xproperty.atom == XA_SCREENSAVER_RESPONSE);
370 xscreensaver_command_response (Display *dpy, Window window,
371 Bool verbose_p, Bool exiting_p,
377 Bool got_event = False;
379 while (!(got_event = XCheckIfEvent(dpy, &event,
380 &xscreensaver_command_event_p, 0)) &&
383 # if defined(HAVE_SELECT)
384 /* Wait for an event, but don't wait longer than 1 sec. Note that we
385 might do this multiple times if an event comes in, but it wasn't
386 the event we're waiting for.
388 int fd = XConnectionNumber(dpy);
395 select (fd+1, &rset, 0, 0, &tv);
396 # else /* !HAVE_SELECT */
398 # endif /* !HAVE_SELECT */
403 sprintf (err, "no response to command.");
405 *error_ret = strdup (err);
407 fprintf (stderr, "%s: %s\n", progname, err);
416 unsigned long nitems, bytesafter;
417 unsigned char *msg = 0;
420 if (old_handler) abort();
421 old_handler = XSetErrorHandler (BadWindow_ehandler);
422 st2 = XGetWindowProperty (dpy, window,
423 XA_SCREENSAVER_RESPONSE,
426 &type, &format, &nitems, &bytesafter,
429 XSetErrorHandler (old_handler);
437 sprintf (err, "xscreensaver window unexpectedly deleted.");
440 *error_ret = strdup (err);
442 fprintf (stderr, "%s: %s\n", progname, err);
447 if (st2 == Success && type != None)
449 if (type != XA_STRING || format != 8)
451 sprintf (err, "unrecognized response property.");
454 *error_ret = strdup (err);
456 fprintf (stderr, "%s: %s\n", progname, err);
458 if (msg) XFree (msg);
461 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
463 sprintf (err, "unrecognized response message.");
466 *error_ret = strdup (err);
468 fprintf (stderr, "%s: %s\n", progname, err);
470 if (msg) XFree (msg);
475 int ret = (msg[0] == '+' ? 0 : -1);
476 sprintf (err, "%s: %s\n", progname, (char *) msg+1);
479 *error_ret = strdup (err);
480 else if (verbose_p || ret != 0)
481 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
489 return -1; /* warning suppression: not actually reached */
494 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
498 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
500 status = xscreensaver_command_response (dpy, w, verbose_p,
501 (command == XA_EXIT),
506 return (status < 0 ? status : 0);
511 server_xscreensaver_version (Display *dpy,
516 Window window = find_screensaver_window (dpy, 0);
520 unsigned long nitems, bytesafter;
534 unsigned char *v = 0;
535 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
536 False, XA_STRING, &type, &format, &nitems,
540 *version_ret = strdup ((char *) v);
545 if (user_ret || host_ret)
547 unsigned char *id = 0;
548 const char *user = 0;
549 const char *host = 0;
551 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
552 False, XA_STRING, &type, &format, &nitems,
556 const char *old_tag = " on host ";
557 const char *s = strstr ((char *) id, old_tag);
560 /* found ID of the form "1234 on host xyz". */
562 host = s + strlen (old_tag);
566 char *o = 0, *p = 0, *c = 0;
567 o = strchr ((char *) id, '(');
568 if (o) p = strchr (o, '@');
569 if (p) c = strchr (p, ')');
572 /* found ID of the form "1234 (user@host)". */
582 if (user && *user && *user != '?')
583 *user_ret = strdup (user);
587 if (host && *host && *host != '?')
588 *host_ret = strdup (host);