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)) &&
388 sprintf (err, "no response to command.");
390 *error_ret = strdup (err);
392 fprintf (stderr, "%s: %s\n", progname, err);
401 unsigned long nitems, bytesafter;
402 unsigned char *msg = 0;
405 if (old_handler) abort();
406 old_handler = XSetErrorHandler (BadWindow_ehandler);
407 st2 = XGetWindowProperty (dpy, window,
408 XA_SCREENSAVER_RESPONSE,
411 &type, &format, &nitems, &bytesafter,
414 XSetErrorHandler (old_handler);
422 sprintf (err, "xscreensaver window unexpectedly deleted.");
425 *error_ret = strdup (err);
427 fprintf (stderr, "%s: %s\n", progname, err);
432 if (st2 == Success && type != None)
434 if (type != XA_STRING || format != 8)
436 sprintf (err, "unrecognized response property.");
439 *error_ret = strdup (err);
441 fprintf (stderr, "%s: %s\n", progname, err);
443 if (msg) XFree (msg);
446 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
448 sprintf (err, "unrecognized response message.");
451 *error_ret = strdup (err);
453 fprintf (stderr, "%s: %s\n", progname, err);
455 if (msg) XFree (msg);
460 int ret = (msg[0] == '+' ? 0 : -1);
461 sprintf (err, "%s: %s\n", progname, (char *) msg+1);
464 *error_ret = strdup (err);
465 else if (verbose_p || ret != 0)
466 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
474 return -1; /* warning suppression: not actually reached */
479 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
483 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
485 status = xscreensaver_command_response (dpy, w, verbose_p,
486 (command == XA_EXIT),
491 return (status < 0 ? status : 0);
496 server_xscreensaver_version (Display *dpy,
501 Window window = find_screensaver_window (dpy, 0);
505 unsigned long nitems, bytesafter;
519 unsigned char *v = 0;
520 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
521 False, XA_STRING, &type, &format, &nitems,
525 *version_ret = strdup ((char *) v);
530 if (user_ret || host_ret)
532 unsigned char *id = 0;
533 const char *user = 0;
534 const char *host = 0;
536 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
537 False, XA_STRING, &type, &format, &nitems,
541 const char *old_tag = " on host ";
542 const char *s = strstr ((char *) id, old_tag);
545 /* found ID of the form "1234 on host xyz". */
547 host = s + strlen (old_tag);
551 char *o = 0, *p = 0, *c = 0;
552 o = strchr ((char *) id, '(');
553 if (o) p = strchr (o, '@');
554 if (p) c = strchr (p, ')');
557 /* found ID of the form "1234 (user@host)". */
567 if (user && *user && *user != '?')
568 *user_ret = strdup (user);
572 if (host && *host && *host != '?')
573 *host_ret = strdup (host);