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,
111 XSetErrorHandler (old_handler);
117 got_badwindow = False;
120 if (status == Success && type != None)
122 Window ret = kids[i];
124 *version = (char *) v;
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;
220 unsigned char *dataP = 0;
222 if (XGetWindowProperty (dpy,
224 XA_SCREENSAVER_STATUS,
225 0, 999, False, XA_INTEGER,
226 &type, &format, &nitems, &bytesafter,
235 Atom *data = (Atom *) dataP;
237 if (type != XA_INTEGER || nitems < 3)
240 if (data) free (data);
241 fprintf (stdout, "\n");
243 fprintf (stderr, "bad status format on root window.\n");
248 blanked = (Atom) data[0];
249 tt = (time_t) data[1];
251 if (tt <= (time_t) 666000000L) /* early 1991 */
254 if (blanked == XA_BLANK)
255 fputs (": screen blanked since ", stdout);
256 else if (blanked == XA_LOCK)
257 fputs (": screen locked since ", stdout);
258 else if (blanked == 0)
259 /* suggestions for a better way to phrase this are welcome. */
260 fputs (": screen non-blanked since ", stdout);
262 /* `blanked' has an unknown value - fail. */
266 if (s[strlen(s)-1] == '\n')
271 int nhacks = nitems - 2;
274 for (i = 0; i < nhacks; i++)
281 if (any && nhacks == 1)
282 fprintf (stdout, " (hack #%d)\n", (int) data[2]);
285 fprintf (stdout, " (hacks: ");
286 for (i = 0; i < nhacks; i++)
288 fprintf (stdout, "#%d", (int) data[2 + i]);
290 fputs (", ", stdout);
292 fputs (")\n", stdout);
295 fputs ("\n", stdout);
298 if (data) free (data);
302 if (dataP) XFree (dataP);
303 fprintf (stdout, "\n");
305 fprintf (stderr, "no saver status on root window.\n");
311 /* No need to read a response for these commands. */
323 else if (arg == 0 && command == XA_SELECT)
325 else if (arg != 0 && command == XA_DEMO)
327 arg1 = 300; /* version number of the XA_DEMO protocol, */
328 arg2 = arg; /* since it didn't use to take an argument. */
331 event.xany.type = ClientMessage;
332 event.xclient.display = dpy;
333 event.xclient.window = window;
334 event.xclient.message_type = XA_SCREENSAVER;
335 event.xclient.format = 32;
336 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
337 event.xclient.data.l[0] = (long) command;
338 event.xclient.data.l[1] = arg1;
339 event.xclient.data.l[2] = arg2;
340 if (! XSendEvent (dpy, window, False, 0L, &event))
342 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
343 (unsigned int) window);
345 *error_ret = strdup (err);
347 fprintf (stderr, "%s: %s\n", progname, err);
363 xscreensaver_command_response (Display *dpy, Window window,
364 Bool verbose_p, Bool exiting_p,
367 int fd = ConnectionNumber (dpy);
378 memset(&tv, 0, sizeof(tv));
380 status = select (fd+1, &fds, 0, &fds, &tv);
387 sprintf (buf, "error waiting for reply");
388 *error_ret = strdup (buf);
392 sprintf (buf, "%s: error waiting for reply", progname);
397 else if (status == 0)
399 sprintf (err, "no response to command.");
401 *error_ret = strdup (err);
403 fprintf (stderr, "%s: %s\n", progname, err);
409 XNextEvent (dpy, &event);
410 if (event.xany.type == PropertyNotify &&
411 event.xproperty.state == PropertyNewValue &&
412 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
417 unsigned long nitems, bytesafter;
418 unsigned char *msg = 0;
421 if (old_handler) abort();
422 old_handler = XSetErrorHandler (BadWindow_ehandler);
423 st2 = XGetWindowProperty (dpy, window,
424 XA_SCREENSAVER_RESPONSE,
427 &type, &format, &nitems, &bytesafter,
430 XSetErrorHandler (old_handler);
438 sprintf (err, "xscreensaver window unexpectedly deleted.");
441 *error_ret = strdup (err);
443 fprintf (stderr, "%s: %s\n", progname, err);
448 if (st2 == Success && type != None)
450 if (type != XA_STRING || format != 8)
452 sprintf (err, "unrecognized response property.");
455 *error_ret = strdup (err);
457 fprintf (stderr, "%s: %s\n", progname, err);
459 if (msg) XFree (msg);
462 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
464 sprintf (err, "unrecognized response message.");
467 *error_ret = strdup (err);
469 fprintf (stderr, "%s: %s\n", progname, err);
471 if (msg) XFree (msg);
476 int ret = (msg[0] == '+' ? 0 : -1);
477 sprintf (err, "%s: %s\n", progname, (char *) msg+1);
480 *error_ret = strdup (err);
481 else if (verbose_p || ret != 0)
482 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
495 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
499 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
501 status = xscreensaver_command_response (dpy, w, verbose_p,
502 (command == XA_EXIT),
507 return (status < 0 ? status : 0);
512 server_xscreensaver_version (Display *dpy,
517 Window window = find_screensaver_window (dpy, 0);
521 unsigned long nitems, bytesafter;
535 unsigned char *v = 0;
536 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
537 False, XA_STRING, &type, &format, &nitems,
541 *version_ret = strdup ((char *) v);
546 if (user_ret || host_ret)
548 unsigned char *id = 0;
549 const char *user = 0;
550 const char *host = 0;
552 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
553 False, XA_STRING, &type, &format, &nitems,
557 const char *old_tag = " on host ";
558 const char *s = strstr ((char *) id, old_tag);
561 /* found ID of the form "1234 on host xyz". */
563 host = s + strlen (old_tag);
567 char *o = 0, *p = 0, *c = 0;
568 o = strchr ((char *) id, '(');
569 if (o) p = strchr (o, '@');
570 if (p) c = strchr (p, ')');
573 /* found ID of the form "1234 (user@host)". */
583 if (user && *user && *user != '?')
584 *user_ret = strdup (user);
588 if (host && *host && *host != '?')
589 *host_ret = strdup (host);