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)
132 send_xscreensaver_command (Display *dpy, Atom command, long arg,
133 Window *window_ret, char **error_ret)
136 Window window = find_screensaver_window (dpy, &v);
137 XWindowAttributes xgwa;
141 *window_ret = window;
145 sprintf (err, "no screensaver is running on display %s",
146 DisplayString (dpy));
150 *error_ret = strdup (err);
154 if (command == XA_EXIT)
155 /* Don't print an error if xscreensaver is already dead. */
158 fprintf (stderr, "%s: %s\n", progname, err);
162 /* Select for property change events, so that we can read the response. */
163 XGetWindowAttributes (dpy, window, &xgwa);
164 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
166 if (command == XA_SCREENSAVER_STATUS ||
167 command == XA_SCREENSAVER_VERSION)
170 memset (&hint, 0, sizeof(hint));
173 sprintf (err, "version property not set on window 0x%x?",
174 (unsigned int) window);
176 *error_ret = strdup (err);
178 fprintf (stderr, "%s: %s\n", progname, err);
182 XGetClassHint(dpy, window, &hint);
185 sprintf (err, "class hints not set on window 0x%x?",
186 (unsigned int) window);
188 *error_ret = strdup (err);
190 fprintf (stderr, "%s: %s\n", progname, err);
194 fprintf (stdout, "%s %s", hint.res_class, v);
196 if (command != XA_SCREENSAVER_STATUS)
198 fprintf (stdout, "\n");
204 unsigned long nitems, bytesafter;
207 if (XGetWindowProperty (dpy,
209 XA_SCREENSAVER_STATUS,
210 0, 999, False, XA_INTEGER,
211 &type, &format, &nitems, &bytesafter,
212 (unsigned char **) &data)
221 if (type != XA_INTEGER || nitems < 3)
224 if (data) free (data);
225 fprintf (stdout, "\n");
227 fprintf (stderr, "bad status format on root window.\n");
231 blanked = (Atom) data[0];
232 tt = (time_t) data[1];
234 if (tt <= (time_t) 666000000L) /* early 1991 */
237 if (blanked == XA_BLANK)
238 fputs (": screen blanked since ", stdout);
239 else if (blanked == XA_LOCK)
240 fputs (": screen locked since ", stdout);
241 else if (blanked == 0)
242 /* suggestions for a better way to phrase this are welcome. */
243 fputs (": screen non-blanked since ", stdout);
245 /* `blanked' has an unknown value - fail. */
249 if (s[strlen(s)-1] == '\n')
254 int nhacks = nitems - 2;
257 for (i = 0; i < nhacks; i++)
264 if (any && nhacks == 1)
265 fprintf (stdout, " (hack #%d)\n", data[2]);
268 fprintf (stdout, " (hacks: ");
269 for (i = 0; i < nhacks; i++)
271 fprintf (stdout, "#%d", data[2 + i]);
273 fputs (", ", stdout);
275 fputs (")\n", stdout);
278 fputs ("\n", stdout);
281 if (data) free (data);
285 if (data) free (data);
286 fprintf (stdout, "\n");
288 fprintf (stderr, "no saver status on root window.\n");
293 /* No need to read a response for these commands. */
304 else if (arg == 0 && command == XA_SELECT)
306 else if (arg != 0 && command == XA_DEMO)
308 arg1 = 300; /* version number of the XA_DEMO protocol, */
309 arg2 = arg; /* since it didn't use to take an argument. */
312 event.xany.type = ClientMessage;
313 event.xclient.display = dpy;
314 event.xclient.window = window;
315 event.xclient.message_type = XA_SCREENSAVER;
316 event.xclient.format = 32;
317 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
318 event.xclient.data.l[0] = (long) command;
319 event.xclient.data.l[1] = arg1;
320 event.xclient.data.l[2] = arg2;
321 if (! XSendEvent (dpy, window, False, 0L, &event))
323 sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n",
324 (unsigned int) window);
326 *error_ret = strdup (err);
328 fprintf (stderr, "%s: %s\n", progname, err);
338 xscreensaver_command_response (Display *dpy, Window window,
339 Bool verbose_p, Bool exiting_p,
342 int fd = ConnectionNumber (dpy);
353 memset(&tv, 0, sizeof(tv));
355 status = select (fd+1, &fds, 0, &fds, &tv);
362 sprintf (buf, "error waiting for reply");
363 *error_ret = strdup (buf);
367 sprintf (buf, "%s: error waiting for reply", progname);
372 else if (status == 0)
374 sprintf (err, "no response to command.");
376 *error_ret = strdup (err);
378 fprintf (stderr, "%s: %s\n", progname, err);
384 XNextEvent (dpy, &event);
385 if (event.xany.type == PropertyNotify &&
386 event.xproperty.state == PropertyNewValue &&
387 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
392 unsigned long nitems, bytesafter;
396 if (old_handler) abort();
397 old_handler = XSetErrorHandler (BadWindow_ehandler);
398 st2 = XGetWindowProperty (dpy, window,
399 XA_SCREENSAVER_RESPONSE,
402 &type, &format, &nitems, &bytesafter,
403 (unsigned char **) &msg);
405 XSetErrorHandler (old_handler);
413 sprintf (err, "xscreensaver window unexpectedly deleted.");
416 *error_ret = strdup (err);
418 fprintf (stderr, "%s: %s\n", progname, err);
423 if (st2 == Success && type != None)
425 if (type != XA_STRING || format != 8)
427 sprintf (err, "unrecognized response property.");
430 *error_ret = strdup (err);
432 fprintf (stderr, "%s: %s\n", progname, err);
434 if (msg) XFree (msg);
437 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
439 sprintf (err, "unrecognized response message.");
442 *error_ret = strdup (err);
444 fprintf (stderr, "%s: %s\n", progname, err);
446 if (msg) XFree (msg);
451 int ret = (msg[0] == '+' ? 0 : -1);
452 sprintf (err, "%s: %s\n", progname, msg+1);
455 *error_ret = strdup (err);
456 else if (verbose_p || ret != 0)
457 fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
470 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p,
474 int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret);
476 status = xscreensaver_command_response (dpy, w, verbose_p,
477 (command == XA_EXIT),
482 return (status < 0 ? status : 0);
487 server_xscreensaver_version (Display *dpy,
492 Window window = find_screensaver_window (dpy, 0);
496 unsigned long nitems, bytesafter;
511 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
512 False, XA_STRING, &type, &format, &nitems,
513 &bytesafter, (unsigned char **) &v);
516 *version_ret = strdup (v);
521 if (user_ret || host_ret)
524 const char *user = 0;
525 const char *host = 0;
527 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
528 False, XA_STRING, &type, &format, &nitems,
529 &bytesafter, (unsigned char **) &id);
532 const char *old_tag = " on host ";
533 const char *s = strstr (id, old_tag);
536 /* found ID of the form "1234 on host xyz". */
538 host = s + strlen (old_tag);
542 char *o = 0, *p = 0, *c = 0;
543 o = strchr (id, '(');
544 if (o) p = strchr (o, '@');
545 if (p) c = strchr (p, ')');
548 /* found ID of the form "1234 (user@host)". */
558 if (user && *user && *user != '?')
559 *user_ret = strdup (user);
563 if (host && *host && *host != '?')
564 *host_ret = strdup (host);