1 /* xscreensaver-command, Copyright (c) 1991-2005 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 = 300; /* 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_response (Display *dpy, Window window,
362 Bool verbose_p, Bool exiting_p,
365 int fd = ConnectionNumber (dpy);
376 memset(&tv, 0, sizeof(tv));
378 status = select (fd+1, &fds, 0, &fds, &tv);
385 sprintf (buf, "error waiting for reply");
386 *error_ret = strdup (buf);
390 sprintf (buf, "%s: error waiting for reply", progname);
395 else if (status == 0)
397 sprintf (err, "no response to command.");
399 *error_ret = strdup (err);
401 fprintf (stderr, "%s: %s\n", progname, err);
407 XNextEvent (dpy, &event);
408 if (event.xany.type == PropertyNotify &&
409 event.xproperty.state == PropertyNewValue &&
410 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
415 unsigned long nitems, bytesafter;
416 unsigned char *msg = 0;
419 if (old_handler) abort();
420 old_handler = XSetErrorHandler (BadWindow_ehandler);
421 st2 = XGetWindowProperty (dpy, window,
422 XA_SCREENSAVER_RESPONSE,
425 &type, &format, &nitems, &bytesafter,
428 XSetErrorHandler (old_handler);
436 sprintf (err, "xscreensaver window unexpectedly deleted.");
439 *error_ret = strdup (err);
441 fprintf (stderr, "%s: %s\n", progname, err);
446 if (st2 == Success && type != None)
448 if (type != XA_STRING || format != 8)
450 sprintf (err, "unrecognized response property.");
453 *error_ret = strdup (err);
455 fprintf (stderr, "%s: %s\n", progname, err);
457 if (msg) XFree (msg);
460 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
462 sprintf (err, "unrecognized response message.");
465 *error_ret = strdup (err);
467 fprintf (stderr, "%s: %s\n", progname, err);
469 if (msg) XFree (msg);
474 int ret = (msg[0] == '+' ? 0 : -1);
475 sprintf (err, "%s: %s\n", progname, (char *) msg+1);
478 *error_ret = strdup (err);
479 else if (verbose_p || ret != 0)
480 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
493 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
497 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
499 status = xscreensaver_command_response (dpy, w, verbose_p,
500 (command == XA_EXIT),
505 return (status < 0 ? status : 0);
510 server_xscreensaver_version (Display *dpy,
515 Window window = find_screensaver_window (dpy, 0);
519 unsigned long nitems, bytesafter;
533 unsigned char *v = 0;
534 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
535 False, XA_STRING, &type, &format, &nitems,
539 *version_ret = strdup ((char *) v);
544 if (user_ret || host_ret)
546 unsigned char *id = 0;
547 const char *user = 0;
548 const char *host = 0;
550 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
551 False, XA_STRING, &type, &format, &nitems,
555 const char *old_tag = " on host ";
556 const char *s = strstr ((char *) id, old_tag);
559 /* found ID of the form "1234 on host xyz". */
561 host = s + strlen (old_tag);
565 char *o = 0, *p = 0, *c = 0;
566 o = strchr ((char *) id, '(');
567 if (o) p = strchr (o, '@');
568 if (p) c = strchr (p, ')');
571 /* found ID of the form "1234 (user@host)". */
581 if (user && *user && *user != '?')
582 *user_ret = strdup (user);
586 if (host && *host && *host != '?')
587 *host_ret = strdup (host);