1 /* xscreensaver-command, Copyright (c) 1991-1998
2 * by Jamie Zawinski <jwz@jwz.org>
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
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,
108 (unsigned char **) &v);
110 XSetErrorHandler (old_handler);
116 got_badwindow = False;
119 if (status == Success && type != None)
131 send_xscreensaver_command (Display *dpy, Atom command, long arg,
132 Window *window_ret, char **error_ret)
135 Window window = find_screensaver_window (dpy, &v);
136 XWindowAttributes xgwa;
140 *window_ret = window;
144 sprintf (err, "no screensaver is running on display %s",
145 DisplayString (dpy));
149 *error_ret = strdup (err);
153 if (command == XA_EXIT)
154 /* Don't print an error if xscreensaver is already dead. */
157 fprintf (stderr, "%s: %s\n", progname, err);
161 /* Select for property change events, so that we can read the response. */
162 XGetWindowAttributes (dpy, window, &xgwa);
163 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
165 if (command == XA_SCREENSAVER_STATUS ||
166 command == XA_SCREENSAVER_VERSION)
169 memset (&hint, 0, sizeof(hint));
172 sprintf (err, "version property not set on window 0x%x?",
173 (unsigned int) window);
175 *error_ret = strdup (err);
177 fprintf (stderr, "%s: %s\n", progname, err);
181 XGetClassHint(dpy, window, &hint);
184 sprintf (err, "class hints not set on window 0x%x?",
185 (unsigned int) window);
187 *error_ret = strdup (err);
189 fprintf (stderr, "%s: %s\n", progname, err);
193 fprintf (stdout, "%s %s", hint.res_class, v);
195 if (command != XA_SCREENSAVER_STATUS)
197 fprintf (stdout, "\n");
203 unsigned long nitems, bytesafter;
206 if (XGetWindowProperty (dpy,
208 XA_SCREENSAVER_STATUS,
209 0, 999, False, XA_INTEGER,
210 &type, &format, &nitems, &bytesafter,
211 (unsigned char **) &data)
220 if (type != XA_INTEGER || nitems < 3)
223 if (data) free (data);
224 fprintf (stdout, "\n");
226 fprintf (stderr, "bad status format on root window.\n");
230 blanked = (Atom) data[0];
231 tt = (time_t) data[1];
233 if (tt <= (time_t) 666000000L) /* early 1991 */
236 if (blanked == XA_BLANK)
237 fputs (": screen blanked since ", stdout);
238 else if (blanked == XA_LOCK)
239 fputs (": screen locked since ", stdout);
240 else if (blanked == 0)
241 /* suggestions for a better way to phrase this are welcome. */
242 fputs (": screen non-blanked since ", stdout);
244 /* `blanked' has an unknown value - fail. */
248 if (s[strlen(s)-1] == '\n')
253 int nhacks = nitems - 2;
256 for (i = 0; i < nhacks; i++)
263 if (any && nhacks == 1)
264 fprintf (stdout, " (hack #%d)\n", data[2]);
267 fprintf (stdout, " (hacks: ");
268 for (i = 0; i < nhacks; i++)
270 fprintf (stdout, "#%d", data[2 + i]);
272 fputs (", ", stdout);
274 fputs (")\n", stdout);
277 fputs ("\n", stdout);
280 if (data) free (data);
284 if (data) free (data);
285 fprintf (stdout, "\n");
287 fprintf (stderr, "no saver status on root window.\n");
292 /* No need to read a response for these commands. */
303 else if (arg == 0 && command == XA_SELECT)
305 else if (arg != 0 && command == XA_DEMO)
307 arg1 = 300; /* version number of the XA_DEMO protocol, */
308 arg2 = arg; /* since it didn't use to take an argument. */
311 event.xany.type = ClientMessage;
312 event.xclient.display = dpy;
313 event.xclient.window = window;
314 event.xclient.message_type = XA_SCREENSAVER;
315 event.xclient.format = 32;
316 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
317 event.xclient.data.l[0] = (long) command;
318 event.xclient.data.l[1] = arg1;
319 event.xclient.data.l[2] = arg2;
320 if (! XSendEvent (dpy, window, False, 0L, &event))
322 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
323 (unsigned int) window);
325 *error_ret = strdup (err);
327 fprintf (stderr, "%s: %s\n", progname, err);
337 xscreensaver_command_response (Display *dpy, Window window,
338 Bool verbose_p, Bool exiting_p,
341 int fd = ConnectionNumber (dpy);
352 memset(&tv, 0, sizeof(tv));
354 status = select (fd+1, &fds, 0, &fds, &tv);
361 sprintf (buf, "error waiting for reply");
362 *error_ret = strdup (buf);
366 sprintf (buf, "%s: error waiting for reply", progname);
371 else if (status == 0)
373 sprintf (err, "no response to command.");
375 *error_ret = strdup (err);
377 fprintf (stderr, "%s: %s\n", progname, err);
383 XNextEvent (dpy, &event);
384 if (event.xany.type == PropertyNotify &&
385 event.xproperty.state == PropertyNewValue &&
386 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
391 unsigned long nitems, bytesafter;
395 if (old_handler) abort();
396 old_handler = XSetErrorHandler (BadWindow_ehandler);
397 st2 = XGetWindowProperty (dpy, window,
398 XA_SCREENSAVER_RESPONSE,
401 &type, &format, &nitems, &bytesafter,
402 (unsigned char **) &msg);
404 XSetErrorHandler (old_handler);
412 sprintf (err, "xscreensaver window unexpectedly deleted.");
415 *error_ret = strdup (err);
417 fprintf (stderr, "%s: %s\n", progname, err);
422 if (st2 == Success && type != None)
424 if (type != XA_STRING || format != 8)
426 sprintf (err, "unrecognized response property.");
429 *error_ret = strdup (err);
431 fprintf (stderr, "%s: %s\n", progname, err);
433 if (msg) XFree (msg);
436 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
438 sprintf (err, "unrecognized response message.");
441 *error_ret = strdup (err);
443 fprintf (stderr, "%s: %s\n", progname, err);
445 if (msg) XFree (msg);
450 int ret = (msg[0] == '+' ? 0 : -1);
451 sprintf (err, "%s: %s\n", progname, msg+1);
454 *error_ret = strdup (err);
455 else if (verbose_p || ret != 0)
456 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
469 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
473 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
475 status = xscreensaver_command_response (dpy, w, verbose_p,
476 (command == XA_EXIT),
481 return (status < 0 ? status : 0);
486 server_xscreensaver_version (Display *dpy,
491 Window window = find_screensaver_window (dpy, 0);
495 unsigned long nitems, bytesafter;
510 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
511 False, XA_STRING, &type, &format, &nitems,
512 &bytesafter, (unsigned char **) &v);
515 *version_ret = strdup (v);
520 if (user_ret || host_ret)
523 const char *user = 0;
524 const char *host = 0;
526 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
527 False, XA_STRING, &type, &format, &nitems,
528 &bytesafter, (unsigned char **) &id);
531 const char *old_tag = " on host ";
532 const char *s = strstr (id, old_tag);
535 /* found ID of the form "1234 on host xyz". */
537 host = s + strlen (old_tag);
541 char *o = 0, *p = 0, *c = 0;
542 o = strchr (id, '(');
543 if (o) p = strchr (o, '@');
544 if (p) c = strchr (p, ')');
547 /* found ID of the form "1234 (user@host)". */
557 if (user && *user && *user != '?')
558 *user_ret = strdup (user);
562 if (host && *host && *host != '?')
563 *host_ret = strdup (host);