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 /* When we notice a window being created, we spawn a timer that waits
54 30 seconds or so, and then selects events on that window. This error
55 handler is used so that we can cope with the fact that the window
56 may have been destroyed <30 seconds after it was created.
58 if (error->error_code == BadWindow)
65 fprintf (stderr, "%s: ", progname);
66 return (*old_handler) (dpy, error);
73 find_screensaver_window (Display *dpy, char **version)
76 Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
77 Window root2, parent, *kids;
80 if (version) *version = 0;
82 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
88 if (! (kids && nkids))
90 for (i = 0; i < nkids; i++)
94 unsigned long nitems, bytesafter;
97 if (XGetWindowProperty (dpy, kids[i],
98 XA_SCREENSAVER_VERSION,
99 0, 200, False, XA_STRING,
100 &type, &format, &nitems, &bytesafter,
101 (unsigned char **) &v)
110 fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
111 DisplayString (dpy));
117 send_xscreensaver_command (Display *dpy, Atom command, long arg,
121 Window window = find_screensaver_window (dpy, &v);
122 XWindowAttributes xgwa;
125 *window_ret = window;
130 /* Select for property change events, so that we can read the response. */
131 XGetWindowAttributes (dpy, window, &xgwa);
132 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
134 if (command == XA_SCREENSAVER_TIME ||
135 command == XA_SCREENSAVER_VERSION)
138 memset (&hint, 0, sizeof(hint));
141 fprintf (stderr, "%s: version property not set on window 0x%x?\n",
142 progname, (unsigned int) window);
146 XGetClassHint(dpy, window, &hint);
149 fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
150 progname, (unsigned int) window);
154 fprintf (stdout, "%s %s", hint.res_class, v);
156 if (command != XA_SCREENSAVER_TIME)
158 fprintf (stdout, "\n");
164 unsigned long nitems, bytesafter;
165 unsigned char *data = 0;
166 Bool active_p = False;
168 if (XGetWindowProperty (dpy, window, XA_VROOT,
169 0, 0, False, XA_WINDOW,
170 &type, &format, &nitems, &bytesafter,
176 if (data) free (data);
179 if (XGetWindowProperty (dpy, window,
181 0, 1, False, XA_INTEGER,
182 &type, &format, &nitems, &bytesafter,
185 && type == XA_INTEGER
188 CARD32 time32 = *((CARD32 *)data);
189 time_t tt = (time_t) time32;
192 fprintf (stdout, ": screen blanked since ");
194 /* suggestions for a better way to phrase this are welcome. */
195 fprintf (stdout, ": screen non-blanked since ");
196 fprintf (stdout, "%s", ctime(&tt));
197 if (data) free (data);
201 if (data) free (data);
202 fprintf (stdout, "\n");
204 fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
205 progname, (unsigned int) window,
206 hint.res_class, (v ? v : "???"));
211 /* No need to read a response for these commands. */
222 else if (arg == 0 && command == XA_SELECT)
224 else if (arg != 0 && command == XA_DEMO)
226 arg1 = 300; /* version number of the XA_DEMO protocol, */
227 arg2 = arg; /* since it didn't use to take an argument. */
230 event.xany.type = ClientMessage;
231 event.xclient.display = dpy;
232 event.xclient.window = window;
233 event.xclient.message_type = XA_SCREENSAVER;
234 event.xclient.format = 32;
235 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
236 event.xclient.data.l[0] = (long) command;
237 event.xclient.data.l[1] = arg1;
238 event.xclient.data.l[2] = arg2;
239 if (! XSendEvent (dpy, window, False, 0L, &event))
241 fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
242 progname, (unsigned int) window);
252 xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p)
254 int fd = ConnectionNumber (dpy);
264 memset(&tv, 0, sizeof(tv));
266 status = select (fd+1, &fds, 0, &fds, &tv);
271 sprintf (buf, "%s: waiting for reply", progname);
275 else if (status == 0)
277 fprintf (stderr, "%s: no response to command.\n", progname);
283 XNextEvent (dpy, &event);
284 if (event.xany.type == PropertyNotify &&
285 event.xproperty.state == PropertyNewValue &&
286 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
291 unsigned long nitems, bytesafter;
294 old_handler = XSetErrorHandler (BadWindow_ehandler);
297 st2 = XGetWindowProperty (dpy, window,
298 XA_SCREENSAVER_RESPONSE,
301 &type, &format, &nitems, &bytesafter,
302 (unsigned char **) &msg);
307 "%s: xscreensaver window has been deleted.\n",
312 if (st2 == Success && type != None)
314 if (type != XA_STRING || format != 8)
317 "%s: unrecognized response property.\n",
319 if (msg) XFree (msg);
322 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
325 "%s: unrecognized response message.\n",
327 if (msg) XFree (msg);
332 int ret = (msg[0] == '+' ? 0 : -1);
333 if (verbose_p || ret != 0)
334 fprintf ((ret < 0 ? stderr : stdout),
349 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p)
352 int status = send_xscreensaver_command (dpy, command, arg, &w);
354 status = xscreensaver_command_response (dpy, w, verbose_p);
362 server_xscreensaver_version (Display *dpy,
367 Window window = find_screensaver_window (dpy, 0);
371 unsigned long nitems, bytesafter;
384 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
385 False, XA_STRING, &type, &format, &nitems,
386 &bytesafter, (unsigned char **) &v);
389 *version_ret = strdup (v);
394 if (user_ret || host_ret)
397 const char *user = 0;
398 const char *host = 0;
400 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
401 False, XA_STRING, &type, &format, &nitems,
402 &bytesafter, (unsigned char **) &id);
405 const char *old_tag = " on host ";
406 const char *s = strstr (id, old_tag);
409 /* found ID of the form "1234 on host xyz". */
411 host = s + strlen (old_tag);
415 char *o = 0, *p = 0, *c = 0;
416 o = strchr (id, '(');
417 if (o) p = strchr (o, '@');
418 if (p) c = strchr (p, ')');
421 /* found ID of the form "1234 (user@host)". */
431 if (user && *user && *user != '?')
432 *user_ret = strdup (user);
436 if (host && *host && *host != '?')
437 *host_ret = strdup (host);