1 /* xscreensaver-command, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
20 #include <sys/types.h>
26 /* #include <X11/Xproto.h> / * for CARD32 */
28 #include <X11/Xatom.h>
29 #include <X11/Xutil.h> /* for XGetClassHint() */
32 #include <X11/Intrinsic.h> /* only needed to get through xscreensaver.h */
35 /* You might think that to read an array of 32-bit quantities out of a
36 server-side property, you would pass an array of 32-bit data quantities
37 into XGetWindowProperty(). You would be wrong. You have to use an array
38 of longs, even if long is 64 bits (using 32 of each 64.)
46 ERROR! you must not include vroot.h in this file
52 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
53 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO, XA_EXIT;
54 Atom XA_BLANK, XA_LOCK;
55 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
56 static Atom XA_RESTART, XA_PREFS, XA_THROTTLE, XA_UNTHROTTLE;
58 static char *screensaver_version;
60 __extension__ /* don't warn about "string length is greater than the
61 length ISO C89 compilers are required to support" in the
64 static char *usage = "\n\
65 usage: %s -<option>\n\
67 This program provides external control of a running xscreensaver process.\n\
68 Version %s, copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>.\n\
70 The xscreensaver program is a daemon that runs in the background.\n\
71 You control a running xscreensaver process by sending it messages\n\
72 with this program, xscreensaver-command. See the man pages for\n\
73 details. These are the arguments understood by xscreensaver-command:\n\
75 -demo Ask the xscreensaver process to enter interactive demo mode.\n\
77 -prefs Ask the xscreensaver process to bring up the preferences\n\
80 -activate Turn on the screensaver (blank the screen), as if the user\n\
81 had been idle for long enough.\n\
83 -deactivate Turns off the screensaver (un-blank the screen), as if user\n\
84 activity had been detected.\n\
86 -cycle If the screensaver is active (the screen is blanked), then\n\
87 stop the current graphics demo and run a new one (chosen\n\
90 -next Like either -activate or -cycle, depending on which is more\n\
91 appropriate, except that the graphics hack that will be run\n\
92 is the next one in the list, instead of a randomly-chosen\n\
93 one. In other words, repeatedly executing -next will cause\n\
94 the xscreensaver process to invoke each graphics demo\n\
95 sequentially. (Though using the -demo option is probably\n\
96 an easier way to accomplish that.)\n\
98 -prev Like -next, but goes in the other direction.\n\
100 -select <N> Like -activate, but runs the Nth element in the list of\n\
101 hacks. By knowing what is in the `programs' list, and in\n\
102 what order, you can use this to activate the screensaver\n\
103 with a particular graphics demo. (The first element in the\n\
104 list is numbered 1, not 0.)\n\
106 -exit Causes the xscreensaver process to exit gracefully.\n\
107 This does nothing if the display is currently locked.\n\
108 (Note that one must *never* kill xscreensaver with -9!)\n\
110 -restart Causes the screensaver process to exit and then restart with\n\
111 the same command line arguments as last time. Do this after\n\
112 you've changed your X resource settings, to cause\n\
113 xscreensaver to notice the changes.\n\
115 -lock Tells the running xscreensaver process to lock the screen\n\
116 immediately. This is like -activate, but forces locking as\n\
117 well, even if locking is not the default. If the saver is\n\
118 already active, this causes it to be locked as well.\n\
120 -version Prints the version of xscreensaver that is currently running\n\
121 on the display -- that is, the actual version number of the\n\
122 running xscreensaver background process, rather than the\n\
123 version number of xscreensaver-command.\n\
125 -time Prints the time at which the screensaver last activated or\n\
126 deactivated (roughly, how long the user has been idle or\n\
127 non-idle -- but not quite, since it only tells you when the\n\
128 screen became blanked or un-blanked.)\n\
130 -watch Prints a line each time the screensaver changes state: when\n\
131 the screen blanks, locks, unblanks, or when the running hack\n\
132 is changed. This option never returns; it is intended for\n\
133 by shell scripts that want to react to the screensaver in\n\
136 See the man page for more details.\n\
137 For updates, check http://www.jwz.org/xscreensaver/\n\
140 /* Note: The "-throttle" command is deprecated -- it predates the XDPMS
141 extension. Instead of using -throttle, users should instead just
142 power off the monitor (e.g., "xset dpms force off".) In a few
143 minutes, the xscreensaver daemon will notice that the monitor is
144 off, and cease running hacks.
147 #define USAGE() do { \
148 fprintf (stderr, usage, progname, screensaver_version); exit (1); \
151 static int watch (Display *);
154 main (int argc, char **argv)
162 Atom XA_WATCH = 0; /* kludge: not really an atom */
165 s = strrchr (progname, '/');
166 if (s) progname = s+1;
168 screensaver_version = (char *) malloc (5);
169 memcpy (screensaver_version, screensaver_id + 17, 4);
170 screensaver_version [4] = 0;
172 for (i = 1; i < argc; i++)
174 const char *s = argv [i];
176 if (s[0] == '-' && s[1] == '-') s++;
179 if (!strncmp (s, "-display", L)) dpyname = argv [++i];
180 else if (cmd) USAGE();
181 else if (!strncmp (s, "-activate", L)) cmd = &XA_ACTIVATE;
182 else if (!strncmp (s, "-deactivate", L)) cmd = &XA_DEACTIVATE;
183 else if (!strncmp (s, "-cycle", L)) cmd = &XA_CYCLE;
184 else if (!strncmp (s, "-next", L)) cmd = &XA_NEXT;
185 else if (!strncmp (s, "-prev", L)) cmd = &XA_PREV;
186 else if (!strncmp (s, "-select", L)) cmd = &XA_SELECT;
187 else if (!strncmp (s, "-exit", L)) cmd = &XA_EXIT;
188 else if (!strncmp (s, "-restart", L)) cmd = &XA_RESTART;
189 else if (!strncmp (s, "-demo", L)) cmd = &XA_DEMO;
190 else if (!strncmp (s, "-preferences",L)) cmd = &XA_PREFS;
191 else if (!strncmp (s, "-prefs",L)) cmd = &XA_PREFS;
192 else if (!strncmp (s, "-lock", L)) cmd = &XA_LOCK;
193 else if (!strncmp (s, "-throttle", L)) cmd = &XA_THROTTLE;
194 else if (!strncmp (s, "-unthrottle", L)) cmd = &XA_UNTHROTTLE;
195 else if (!strncmp (s, "-version", L)) cmd = &XA_SCREENSAVER_VERSION;
196 else if (!strncmp (s, "-time", L)) cmd = &XA_SCREENSAVER_STATUS;
197 else if (!strncmp (s, "-watch", L)) cmd = &XA_WATCH;
200 if (cmd == &XA_SELECT || cmd == &XA_DEMO)
204 if (i+1 < argc && (1 == sscanf(argv[i+1], " %ld %c", &a, &c)))
216 /* no command may have a negative argument. */
220 /* SELECT must have a non-zero argument. */
221 if (cmd == &XA_SELECT)
226 /* no command other than SELECT and DEMO may have a non-zero argument. */
227 if (cmd != &XA_DEMO && cmd != &XA_SELECT)
233 /* For backward compatibility: -demo with no arguments used to send a
234 "DEMO 0" ClientMessage to the xscreensaver process, which brought up
235 the built-in demo mode dialog. Now that the demo mode dialog is no
236 longer built in, we bring it up by just running the "xscreensaver-demo"
239 Note that "-DEMO <n>" still sends a ClientMessage.
241 if (cmd == &XA_PREFS ||
242 (cmd == &XA_DEMO && arg == 0))
245 char *new_argv[] = { "xscreensaver-demo", 0, 0, 0, 0, 0 };
250 new_argv[ac++] = "-display";
251 new_argv[ac++] = dpyname;
254 if (cmd == &XA_PREFS)
255 new_argv[ac++] = "-prefs";
259 execvp (new_argv[0], new_argv); /* shouldn't return */
261 sprintf (buf, "%s: could not exec %s", progname, new_argv[0]);
270 if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
276 "%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
280 dpy = XOpenDisplay (dpyname);
283 fprintf (stderr, "%s: can't open display %s\n", progname,
284 (dpyname ? dpyname : "(null)"));
288 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
289 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
290 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
291 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
292 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
293 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
294 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
295 XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
296 XA_RESTART = XInternAtom (dpy, "RESTART", False);
297 XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
298 XA_NEXT = XInternAtom (dpy, "NEXT", False);
299 XA_PREV = XInternAtom (dpy, "PREV", False);
300 XA_SELECT = XInternAtom (dpy, "SELECT", False);
301 XA_EXIT = XInternAtom (dpy, "EXIT", False);
302 XA_DEMO = XInternAtom (dpy, "DEMO", False);
303 XA_PREFS = XInternAtom (dpy, "PREFS", False);
304 XA_LOCK = XInternAtom (dpy, "LOCK", False);
305 XA_BLANK = XInternAtom (dpy, "BLANK", False);
306 XA_THROTTLE = XInternAtom (dpy, "THROTTLE", False);
307 XA_UNTHROTTLE = XInternAtom (dpy, "UNTHROTTLE", False);
311 if (cmd == &XA_WATCH)
317 if (*cmd == XA_ACTIVATE || *cmd == XA_LOCK ||
318 *cmd == XA_NEXT || *cmd == XA_PREV || *cmd == XA_SELECT)
319 /* People never guess that KeyRelease deactivates the screen saver too,
320 so if we're issuing an activation command, wait a second. */
323 i = xscreensaver_command (dpy, *cmd, arg, True, NULL);
333 Window window = RootWindow (dpy, 0);
334 XWindowAttributes xgwa;
339 XGetWindowAttributes (dpy, window, &xgwa);
340 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
344 XNextEvent (dpy, &event);
345 if (event.xany.type == PropertyNotify &&
346 event.xproperty.state == PropertyNewValue &&
347 event.xproperty.atom == XA_SCREENSAVER_STATUS)
351 unsigned long nitems, bytesafter;
352 unsigned char *dataP = 0;
354 if (XGetWindowProperty (dpy,
355 RootWindow (dpy, 0), /* always screen #0 */
356 XA_SCREENSAVER_STATUS,
357 0, 999, False, XA_INTEGER,
358 &type, &format, &nitems, &bytesafter,
366 Bool changed = False;
367 Bool running = False;
368 PROP32 *data = (PROP32 *) dataP;
370 if (type != XA_INTEGER || nitems < 3)
373 if (last) XFree (last);
374 if (data) XFree (data);
375 fprintf (stderr, "%s: bad status format on root window.\n",
380 tt = (time_t) data[1];
381 if (tt <= (time_t) 666000000L) /* early 1991 */
385 if (s[strlen(s)-1] == '\n')
388 if (!last || data[0] != last[0])
391 if (data[0] == XA_BLANK)
392 printf ("BLANK %s\n", s);
393 else if (data[0] == XA_LOCK)
394 printf ("LOCK %s\n", s);
395 else if (data[0] == 0)
396 printf ("UNBLANK %s\n", s);
406 for (i = 2; i < nitems; i++)
408 if (data[i] != last[i])
415 if (running && changed)
418 fprintf (stdout, "RUN");
419 for (i = 2; i < nitems; i++)
420 fprintf (stdout, " %d", (int) data[i]);
421 fprintf (stdout, "\n");
426 if (last) XFree (last);
431 if (last) XFree (last);
432 if (dataP) XFree (dataP);
433 fprintf (stderr, "%s: no saver status on root window.\n",