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 return (*old_handler) (dpy, error);
68 find_screensaver_window (Display *dpy, char **version)
71 Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
72 Window root2, parent, *kids;
75 if (version) *version = 0;
77 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
83 if (! (kids && nkids))
85 for (i = 0; i < nkids; i++)
89 unsigned long nitems, bytesafter;
92 if (XGetWindowProperty (dpy, kids[i],
93 XA_SCREENSAVER_VERSION,
94 0, 200, False, XA_STRING,
95 &type, &format, &nitems, &bytesafter,
96 (unsigned char **) &v)
105 fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
106 DisplayString (dpy));
112 send_xscreensaver_command (Display *dpy, Atom command, long arg,
116 Window window = find_screensaver_window (dpy, &v);
117 XWindowAttributes xgwa;
120 *window_ret = window;
125 /* Select for property change events, so that we can read the response. */
126 XGetWindowAttributes (dpy, window, &xgwa);
127 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
129 if (command == XA_SCREENSAVER_TIME ||
130 command == XA_SCREENSAVER_VERSION)
133 memset (&hint, 0, sizeof(hint));
136 fprintf (stderr, "%s: version property not set on window 0x%x?\n",
137 progname, (unsigned int) window);
141 XGetClassHint(dpy, window, &hint);
144 fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
145 progname, (unsigned int) window);
149 fprintf (stdout, "%s %s", hint.res_class, v);
151 if (command != XA_SCREENSAVER_TIME)
153 fprintf (stdout, "\n");
159 unsigned long nitems, bytesafter;
160 unsigned char *data = 0;
161 Bool active_p = False;
163 if (XGetWindowProperty (dpy, window, XA_VROOT,
164 0, 0, False, XA_WINDOW,
165 &type, &format, &nitems, &bytesafter,
171 if (data) free (data);
174 if (XGetWindowProperty (dpy, window,
176 0, 1, False, XA_INTEGER,
177 &type, &format, &nitems, &bytesafter,
180 && type == XA_INTEGER
183 CARD32 time32 = *((CARD32 *)data);
184 time_t tt = (time_t) time32;
187 fprintf (stdout, ": screen blanked since ");
189 /* suggestions for a better way to phrase this are welcome. */
190 fprintf (stdout, ": screen non-blanked since ");
191 fprintf (stdout, "%s", ctime(&tt));
192 if (data) free (data);
196 if (data) free (data);
197 fprintf (stdout, "\n");
199 fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
200 progname, (unsigned int) window,
201 hint.res_class, (v ? v : "???"));
206 /* No need to read a response for these commands. */
217 else if (arg == 0 && command == XA_SELECT)
219 else if (arg != 0 && command == XA_DEMO)
221 arg1 = 300; /* version number of the XA_DEMO protocol, */
222 arg2 = arg; /* since it didn't use to take an argument. */
225 event.xany.type = ClientMessage;
226 event.xclient.display = dpy;
227 event.xclient.window = window;
228 event.xclient.message_type = XA_SCREENSAVER;
229 event.xclient.format = 32;
230 memset (&event.xclient.data, 0, sizeof(event.xclient.data));
231 event.xclient.data.l[0] = (long) command;
232 event.xclient.data.l[1] = arg1;
233 event.xclient.data.l[2] = arg2;
234 if (! XSendEvent (dpy, window, False, 0L, &event))
236 fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
237 progname, (unsigned int) window);
247 xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p)
249 int fd = ConnectionNumber (dpy);
259 memset(&tv, 0, sizeof(tv));
261 status = select (fd+1, &fds, 0, &fds, &tv);
266 sprintf (buf, "%s: waiting for reply", progname);
270 else if (status == 0)
272 fprintf (stderr, "%s: no response to command.\n", progname);
278 XNextEvent (dpy, &event);
279 if (event.xany.type == PropertyNotify &&
280 event.xproperty.state == PropertyNewValue &&
281 event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
286 unsigned long nitems, bytesafter;
289 old_handler = XSetErrorHandler (BadWindow_ehandler);
292 st2 = XGetWindowProperty (dpy, window,
293 XA_SCREENSAVER_RESPONSE,
296 &type, &format, &nitems, &bytesafter,
297 (unsigned char **) &msg);
302 "%s: xscreensaver window has been deleted.\n",
307 if (st2 == Success && type != None)
309 if (type != XA_STRING || format != 8)
312 "%s: unrecognized response property.\n",
314 if (msg) XFree (msg);
317 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
320 "%s: unrecognized response message.\n",
322 if (msg) XFree (msg);
327 int ret = (msg[0] == '+' ? 0 : -1);
328 if (verbose_p || ret != 0)
329 fprintf ((ret < 0 ? stderr : stdout),
344 xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p)
347 int status = send_xscreensaver_command (dpy, command, arg, &w);
349 status = xscreensaver_command_response (dpy, w, verbose_p);
357 server_xscreensaver_version (Display *dpy,
362 Window window = find_screensaver_window (dpy, 0);
366 unsigned long nitems, bytesafter;
379 XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
380 False, XA_STRING, &type, &format, &nitems,
381 &bytesafter, (unsigned char **) &v);
384 *version_ret = strdup (v);
389 if (user_ret || host_ret)
392 const char *user = 0;
393 const char *host = 0;
395 XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
396 False, XA_STRING, &type, &format, &nitems,
397 &bytesafter, (unsigned char **) &id);
400 const char *old_tag = " on host ";
401 const char *s = strstr (id, old_tag);
404 /* found ID of the form "1234 on host xyz". */
406 host = s + strlen (old_tag);
410 char *o = 0, *p = 0, *c = 0;
411 o = strchr (id, '(');
412 if (o) p = strchr (o, '@');
413 if (p) c = strchr (p, ')');
416 /* found ID of the form "1234 (user@host)". */
426 if (user && *user && *user != '?')
427 *user_ret = strdup (user);
431 if (host && *host && *host != '?')
432 *host_ret = strdup (host);