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_TIME;
45 extern Atom XA_VROOT, XA_SELECT, XA_DEMO;
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 old_handler = XSetErrorHandler (BadWindow_ehandler);
103 status = XGetWindowProperty (dpy, kids[i],
104 XA_SCREENSAVER_VERSION,
105 0, 200, False, XA_STRING,
106 &type, &format, &nitems, &bytesafter,
107 (unsigned char **) &v);
109 XSetErrorHandler (old_handler);
115 if (status == Success && type != None)
122 fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
123 DisplayString (dpy));
129 send_xscreensaver_command (Display *dpy, Atom command, long arg,
133 Window window = find_screensaver_window (dpy, &v);
134 XWindowAttributes xgwa;
137 *window_ret = window;
142 /* Select for property change events, so that we can read the response. */
143 XGetWindowAttributes (dpy, window, &xgwa);
144 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
146 if (command == XA_SCREENSAVER_TIME ||
147 command == XA_SCREENSAVER_VERSION)
150 memset (&hint, 0, sizeof(hint));
153 fprintf (stderr, "%s: version property not set on window 0x%x?\n",
154 progname, (unsigned int) window);
158 XGetClassHint(dpy, window, &hint);
161 fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
162 progname, (unsigned int) window);
166 fprintf (stdout, "%s %s", hint.res_class, v);
168 if (command != XA_SCREENSAVER_TIME)
170 fprintf (stdout, "\n");
176 unsigned long nitems, bytesafter;
177 unsigned char *data = 0;
178 Bool active_p = False;
180 if (XGetWindowProperty (dpy, window, XA_VROOT,
181 0, 0, False, XA_WINDOW,
182 &type, &format, &nitems, &bytesafter,
188 if (data) free (data);
191 if (XGetWindowProperty (dpy, window,
193 0, 1, False, XA_INTEGER,
194 &type, &format, &nitems, &bytesafter,
197 && type == XA_INTEGER
200 CARD32 time32 = *((CARD32 *)data);
201 time_t tt = (time_t) time32;
204 fprintf (stdout, ": screen blanked since ");
206 /* suggestions for a better way to phrase this are welcome. */
207 fprintf (stdout, ": screen non-blanked since ");
208 fprintf (stdout, "%s", ctime(&tt));
209 if (data) free (data);
213 if (data) free (data);
214 fprintf (stdout, "\n");
216 fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
217 progname, (unsigned int) window,
218 hint.res_class, (v ? v : "???"));
223 /* No need to read a response for these commands. */
234 else if (arg == 0 && command == XA_SELECT)
236 else if (arg != 0 && command == XA_DEMO)
238 arg1 = 300; /* version number of the XA_DEMO protocol, */
239 arg2 = arg; /* since it didn't use to take an argument. */
242 event.xany.type = ClientMessage;
243 event.xclient.display = dpy;
244 event.xclient.window = window;
245 event.xclient.message_type = XA_SCREENSAVER;
246 event.xclient.format = 32;
247 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
248 event.xclient.data.l[0] = (long) command;
249 event.xclient.data.l[1] = arg1;
250 event.xclient.data.l[2] = arg2;
251 if (! XSendEvent (dpy, window, False, 0L, &event))
253 fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
254 progname, (unsigned int) window);
264 xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p)
266 int fd = ConnectionNumber (dpy);
276 memset(&tv, 0, sizeof(tv));
278 status = select (fd+1, &fds, 0, &fds, &tv);
283 sprintf (buf, "%s: waiting for reply", progname);
287 else if (status == 0)
289 fprintf (stderr, "%s: no response to command.\n", progname);
295 XNextEvent (dpy, &event);
296 if (event.xany.type == PropertyNotify &&
297 event.xproperty.state == PropertyNewValue &&
298 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
303 unsigned long nitems, bytesafter;
307 if (old_handler) abort();
308 old_handler = XSetErrorHandler (BadWindow_ehandler);
309 st2 = XGetWindowProperty (dpy, window,
310 XA_SCREENSAVER_RESPONSE,
313 &type, &format, &nitems, &bytesafter,
314 (unsigned char **) &msg);
316 XSetErrorHandler (old_handler);
322 "%s: xscreensaver window has been deleted.\n",
327 if (st2 == Success && type != None)
329 if (type != XA_STRING || format != 8)
332 "%s: unrecognized response property.\n",
334 if (msg) XFree (msg);
337 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
340 "%s: unrecognized response message.\n",
342 if (msg) XFree (msg);
347 int ret = (msg[0] == '+' ? 0 : -1);
348 if (verbose_p || ret != 0)
349 fprintf ((ret < 0 ? stderr : stdout),
364 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p)
367 int status = send_xscreensaver_command (dpy, command, arg, &w);
369 status = xscreensaver_command_response (dpy, w, verbose_p);
377 server_xscreensaver_version (Display *dpy,
382 Window window = find_screensaver_window (dpy, 0);
386 unsigned long nitems, bytesafter;
401 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
402 False, XA_STRING, &type, &format, &nitems,
403 &bytesafter, (unsigned char **) &v);
406 *version_ret = strdup (v);
411 if (user_ret || host_ret)
414 const char *user = 0;
415 const char *host = 0;
417 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
418 False, XA_STRING, &type, &format, &nitems,
419 &bytesafter, (unsigned char **) &id);
422 const char *old_tag = " on host ";
423 const char *s = strstr (id, old_tag);
426 /* found ID of the form "1234 on host xyz". */
428 host = s + strlen (old_tag);
432 char *o = 0, *p = 0, *c = 0;
433 o = strchr (id, '(');
434 if (o) p = strchr (o, '@');
435 if (p) c = strchr (p, ')');
438 /* found ID of the form "1234 (user@host)". */
448 if (user && *user && *user != '?')
449 *user_ret = strdup (user);
453 if (host && *host && *host != '?')
454 *host_ret = strdup (host);