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>
21 #include <sys/select.h>
27 #include <X11/Xproto.h> /* for CARD32 */
29 #include <X11/Xatom.h>
30 #include <X11/Xutil.h> /* for XGetClassHint() */
36 ERROR! you must not include vroot.h in this file
39 extern char *progname;
40 extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
41 extern Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_TIME;
42 extern Atom XA_VROOT, XA_SELECT, XA_DEMO;
45 static XErrorHandler old_handler = 0;
46 static Bool got_badwindow = False;
48 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
50 /* When we notice a window being created, we spawn a timer that waits
51 30 seconds or so, and then selects events on that window. This error
52 handler is used so that we can cope with the fact that the window
53 may have been destroyed <30 seconds after it was created.
55 if (error->error_code == BadWindow)
62 fprintf (stderr, "%s: ", progname);
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;
94 if (XGetWindowProperty (dpy, kids[i],
95 XA_SCREENSAVER_VERSION,
96 0, 200, False, XA_STRING,
97 &type, &format, &nitems, &bytesafter,
98 (unsigned char **) &v)
107 fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
108 DisplayString (dpy));
114 send_xscreensaver_command (Display *dpy, Atom command, long arg,
118 Window window = find_screensaver_window (dpy, &v);
119 XWindowAttributes xgwa;
122 *window_ret = window;
127 /* Select for property change events, so that we can read the response. */
128 XGetWindowAttributes (dpy, window, &xgwa);
129 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
131 if (command == XA_SCREENSAVER_TIME ||
132 command == XA_SCREENSAVER_VERSION)
135 memset (&hint, 0, sizeof(hint));
138 fprintf (stderr, "%s: version property not set on window 0x%x?\n",
139 progname, (unsigned int) window);
143 XGetClassHint(dpy, window, &hint);
146 fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
147 progname, (unsigned int) window);
151 fprintf (stdout, "%s %s", hint.res_class, v);
153 if (command != XA_SCREENSAVER_TIME)
155 fprintf (stdout, "\n");
161 unsigned long nitems, bytesafter;
162 unsigned char *data = 0;
163 Bool active_p = False;
165 if (XGetWindowProperty (dpy, window, XA_VROOT,
166 0, 0, False, XA_WINDOW,
167 &type, &format, &nitems, &bytesafter,
173 if (data) free (data);
176 if (XGetWindowProperty (dpy, window,
178 0, 1, False, XA_INTEGER,
179 &type, &format, &nitems, &bytesafter,
182 && type == XA_INTEGER
185 CARD32 time32 = *((CARD32 *)data);
186 time_t tt = (time_t) time32;
189 fprintf (stdout, ": screen blanked since ");
191 /* suggestions for a better way to phrase this are welcome. */
192 fprintf (stdout, ": screen non-blanked since ");
193 fprintf (stdout, "%s", ctime(&tt));
194 if (data) free (data);
198 if (data) free (data);
199 fprintf (stdout, "\n");
201 fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
202 progname, (unsigned int) window,
203 hint.res_class, (v ? v : "???"));
208 /* No need to read a response for these commands. */
219 else if (arg == 0 && command == XA_SELECT)
221 else if (arg != 0 && command == XA_DEMO)
223 arg1 = 300; /* version number of the XA_DEMO protocol, */
224 arg2 = arg; /* since it didn't use to take an argument. */
227 event.xany.type = ClientMessage;
228 event.xclient.display = dpy;
229 event.xclient.window = window;
230 event.xclient.message_type = XA_SCREENSAVER;
231 event.xclient.format = 32;
232 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
233 event.xclient.data.l[0] = (long) command;
234 event.xclient.data.l[1] = arg1;
235 event.xclient.data.l[2] = arg2;
236 if (! XSendEvent (dpy, window, False, 0L, &event))
238 fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
239 progname, (unsigned int) window);
249 xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p)
251 int fd = ConnectionNumber (dpy);
261 memset(&tv, 0, sizeof(tv));
263 status = select (fd+1, &fds, 0, &fds, &tv);
268 sprintf (buf, "%s: waiting for reply", progname);
272 else if (status == 0)
274 fprintf (stderr, "%s: no response to command.\n", progname);
280 XNextEvent (dpy, &event);
281 if (event.xany.type == PropertyNotify &&
282 event.xproperty.state == PropertyNewValue &&
283 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
288 unsigned long nitems, bytesafter;
291 old_handler = XSetErrorHandler (BadWindow_ehandler);
294 st2 = XGetWindowProperty (dpy, window,
295 XA_SCREENSAVER_RESPONSE,
298 &type, &format, &nitems, &bytesafter,
299 (unsigned char **) &msg);
304 "%s: xscreensaver window has been deleted.\n",
309 if (st2 == Success && type != None)
311 if (type != XA_STRING || format != 8)
314 "%s: unrecognized response property.\n",
316 if (msg) XFree (msg);
319 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
322 "%s: unrecognized response message.\n",
324 if (msg) XFree (msg);
329 int ret = (msg[0] == '+' ? 0 : -1);
330 if (verbose_p || ret != 0)
331 fprintf ((ret < 0 ? stderr : stdout),
346 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p)
349 int status = send_xscreensaver_command (dpy, command, arg, &w);
351 status = xscreensaver_command_response (dpy, w, verbose_p);
359 server_xscreensaver_version (Display *dpy,
364 Window window = find_screensaver_window (dpy, 0);
368 unsigned long nitems, bytesafter;
381 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
382 False, XA_STRING, &type, &format, &nitems,
383 &bytesafter, (unsigned char **) &v);
386 *version_ret = strdup (v);
391 if (user_ret || host_ret)
394 const char *user = 0;
395 const char *host = 0;
397 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
398 False, XA_STRING, &type, &format, &nitems,
399 &bytesafter, (unsigned char **) &id);
402 const char *old_tag = " on host ";
403 const char *s = strstr (id, old_tag);
406 /* found ID of the form "1234 on host xyz". */
408 host = s + strlen (old_tag);
412 char *o = 0, *p = 0, *c = 0;
413 o = strchr (id, '(');
414 if (o) p = strchr (o, '@');
415 if (p) c = strchr (p, ')');
418 /* found ID of the form "1234 (user@host)". */
428 if (user && *user && *user != '?')
429 *user_ret = strdup (user);
433 if (host && *host && *host != '?')
434 *host_ret = strdup (host);