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
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_SELECT_H
24 # include <sys/select.h>
25 #endif /* HAVE_SYS_SELECT_H */
31 #include <X11/Xproto.h> /* for CARD32 */
33 #include <X11/Xatom.h>
34 #include <X11/Xutil.h> /* for XGetClassHint() */
40 ERROR! you must not include vroot.h in this file
43 extern char *progname;
44 extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
45 extern Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_EXIT;
46 extern Atom XA_VROOT, XA_SELECT, XA_DEMO, XA_BLANK, XA_LOCK;
49 static XErrorHandler old_handler = 0;
50 static Bool got_badwindow = False;
52 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
54 if (error->error_code == BadWindow)
61 fprintf (stderr, "%s: ", progname);
62 if (!old_handler) abort();
63 return (*old_handler) (dpy, error);
70 find_screensaver_window (Display *dpy, char **version)
73 Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
74 Window root2, parent, *kids;
77 if (version) *version = 0;
79 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
85 if (! (kids && nkids))
87 for (i = 0; i < nkids; i++)
91 unsigned long nitems, bytesafter;
95 /* We're walking the list of root-level windows and trying to find
96 the one that has a particular property on it. We need to trap
97 BadWindows errors while doing this, because it's possible that
98 some random window might get deleted in the meantime. (That
99 window won't have been the one we're looking for.)
102 if (old_handler) abort();
103 got_badwindow = False;
104 old_handler = XSetErrorHandler (BadWindow_ehandler);
105 status = XGetWindowProperty (dpy, kids[i],
106 XA_SCREENSAVER_VERSION,
107 0, 200, False, XA_STRING,
108 &type, &format, &nitems, &bytesafter,
109 (unsigned char **) &v);
111 XSetErrorHandler (old_handler);
117 got_badwindow = False;
120 if (status == Success && type != None)
122 Window ret = kids[i];
130 if (kids) XFree (kids);
136 send_xscreensaver_command (Display *dpy, Atom command, long arg,
137 Window *window_ret, char **error_ret)
141 Window window = find_screensaver_window (dpy, &v);
142 XWindowAttributes xgwa;
146 *window_ret = window;
150 sprintf (err, "no screensaver is running on display %s",
151 DisplayString (dpy));
155 *error_ret = strdup (err);
160 if (command == XA_EXIT)
162 /* Don't print an error if xscreensaver is already dead. */
167 fprintf (stderr, "%s: %s\n", progname, err);
172 /* Select for property change events, so that we can read the response. */
173 XGetWindowAttributes (dpy, window, &xgwa);
174 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
176 if (command == XA_SCREENSAVER_STATUS ||
177 command == XA_SCREENSAVER_VERSION)
180 memset (&hint, 0, sizeof(hint));
183 sprintf (err, "version property not set on window 0x%x?",
184 (unsigned int) window);
186 *error_ret = strdup (err);
188 fprintf (stderr, "%s: %s\n", progname, err);
194 XGetClassHint(dpy, window, &hint);
197 sprintf (err, "class hints not set on window 0x%x?",
198 (unsigned int) window);
200 *error_ret = strdup (err);
202 fprintf (stderr, "%s: %s\n", progname, err);
209 fprintf (stdout, "%s %s", hint.res_class, v);
211 if (command != XA_SCREENSAVER_STATUS)
213 fprintf (stdout, "\n");
219 unsigned long nitems, bytesafter;
222 if (XGetWindowProperty (dpy,
224 XA_SCREENSAVER_STATUS,
225 0, 999, False, XA_INTEGER,
226 &type, &format, &nitems, &bytesafter,
227 (unsigned char **) &data)
236 if (type != XA_INTEGER || nitems < 3)
239 if (data) free (data);
240 fprintf (stdout, "\n");
242 fprintf (stderr, "bad status format on root window.\n");
247 blanked = (Atom) data[0];
248 tt = (time_t) data[1];
250 if (tt <= (time_t) 666000000L) /* early 1991 */
253 if (blanked == XA_BLANK)
254 fputs (": screen blanked since ", stdout);
255 else if (blanked == XA_LOCK)
256 fputs (": screen locked since ", stdout);
257 else if (blanked == 0)
258 /* suggestions for a better way to phrase this are welcome. */
259 fputs (": screen non-blanked since ", stdout);
261 /* `blanked' has an unknown value - fail. */
265 if (s[strlen(s)-1] == '\n')
270 int nhacks = nitems - 2;
273 for (i = 0; i < nhacks; i++)
280 if (any && nhacks == 1)
281 fprintf (stdout, " (hack #%d)\n", (int) data[2]);
284 fprintf (stdout, " (hacks: ");
285 for (i = 0; i < nhacks; i++)
287 fprintf (stdout, "#%d", (int) data[2 + i]);
289 fputs (", ", stdout);
291 fputs (")\n", stdout);
294 fputs ("\n", stdout);
297 if (data) free (data);
301 if (data) free (data);
302 fprintf (stdout, "\n");
304 fprintf (stderr, "no saver status on root window.\n");
310 /* No need to read a response for these commands. */
322 else if (arg == 0 && command == XA_SELECT)
324 else if (arg != 0 && command == XA_DEMO)
326 arg1 = 300; /* version number of the XA_DEMO protocol, */
327 arg2 = arg; /* since it didn't use to take an argument. */
330 event.xany.type = ClientMessage;
331 event.xclient.display = dpy;
332 event.xclient.window = window;
333 event.xclient.message_type = XA_SCREENSAVER;
334 event.xclient.format = 32;
335 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
336 event.xclient.data.l[0] = (long) command;
337 event.xclient.data.l[1] = arg1;
338 event.xclient.data.l[2] = arg2;
339 if (! XSendEvent (dpy, window, False, 0L, &event))
341 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
342 (unsigned int) window);
344 *error_ret = strdup (err);
346 fprintf (stderr, "%s: %s\n", progname, err);
362 xscreensaver_command_response (Display *dpy, Window window,
363 Bool verbose_p, Bool exiting_p,
366 int fd = ConnectionNumber (dpy);
377 memset(&tv, 0, sizeof(tv));
379 status = select (fd+1, &fds, 0, &fds, &tv);
386 sprintf (buf, "error waiting for reply");
387 *error_ret = strdup (buf);
391 sprintf (buf, "%s: error waiting for reply", progname);
396 else if (status == 0)
398 sprintf (err, "no response to command.");
400 *error_ret = strdup (err);
402 fprintf (stderr, "%s: %s\n", progname, err);
408 XNextEvent (dpy, &event);
409 if (event.xany.type == PropertyNotify &&
410 event.xproperty.state == PropertyNewValue &&
411 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
416 unsigned long nitems, bytesafter;
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,
427 (unsigned char **) &msg);
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, msg+1);
479 *error_ret = strdup (err);
480 else if (verbose_p || ret != 0)
481 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
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;
535 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
536 False, XA_STRING, &type, &format, &nitems,
537 &bytesafter, (unsigned char **) &v);
540 *version_ret = strdup (v);
545 if (user_ret || host_ret)
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,
553 &bytesafter, (unsigned char **) &id);
556 const char *old_tag = " on host ";
557 const char *s = strstr (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 (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);