1 /* xscreensaver-command, Copyright (c) 1991-2013 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-%s 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. You shouldn't\n\
112 really need to do this, since xscreensaver notices when the\n\
113 .xscreensaver file has changed and re-reads it as needed.\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, year); exit (1); \
151 static int watch (Display *);
154 main (int argc, char **argv)
162 Atom XA_WATCH = 0; /* kludge: not really an atom */
166 s = strrchr (progname, '/');
167 if (s) progname = s+1;
169 screensaver_version = (char *) malloc (5);
170 memcpy (screensaver_version, screensaver_id + 17, 4);
171 screensaver_version [4] = 0;
173 s = strchr (screensaver_id, '-');
174 s = strrchr (s, '-');
176 strncpy (year, s, 4);
179 for (i = 1; i < argc; i++)
181 const char *s = argv [i];
183 if (s[0] == '-' && s[1] == '-') s++;
186 if (!strncmp (s, "-display", L)) dpyname = argv [++i];
187 else if (cmd) USAGE();
188 else if (!strncmp (s, "-activate", L)) cmd = &XA_ACTIVATE;
189 else if (!strncmp (s, "-deactivate", L)) cmd = &XA_DEACTIVATE;
190 else if (!strncmp (s, "-cycle", L)) cmd = &XA_CYCLE;
191 else if (!strncmp (s, "-next", L)) cmd = &XA_NEXT;
192 else if (!strncmp (s, "-prev", L)) cmd = &XA_PREV;
193 else if (!strncmp (s, "-select", L)) cmd = &XA_SELECT;
194 else if (!strncmp (s, "-exit", L)) cmd = &XA_EXIT;
195 else if (!strncmp (s, "-restart", L)) cmd = &XA_RESTART;
196 else if (!strncmp (s, "-demo", L)) cmd = &XA_DEMO;
197 else if (!strncmp (s, "-preferences",L)) cmd = &XA_PREFS;
198 else if (!strncmp (s, "-prefs",L)) cmd = &XA_PREFS;
199 else if (!strncmp (s, "-lock", L)) cmd = &XA_LOCK;
200 else if (!strncmp (s, "-throttle", L)) cmd = &XA_THROTTLE;
201 else if (!strncmp (s, "-unthrottle", L)) cmd = &XA_UNTHROTTLE;
202 else if (!strncmp (s, "-version", L)) cmd = &XA_SCREENSAVER_VERSION;
203 else if (!strncmp (s, "-time", L)) cmd = &XA_SCREENSAVER_STATUS;
204 else if (!strncmp (s, "-watch", L)) cmd = &XA_WATCH;
207 if (cmd == &XA_SELECT || cmd == &XA_DEMO)
211 if (i+1 < argc && (1 == sscanf(argv[i+1], " %ld %c", &a, &c)))
223 /* no command may have a negative argument. */
227 /* SELECT must have a non-zero argument. */
228 if (cmd == &XA_SELECT)
233 /* no command other than SELECT and DEMO may have a non-zero argument. */
234 if (cmd != &XA_DEMO && cmd != &XA_SELECT)
240 /* For backward compatibility: -demo with no arguments used to send a
241 "DEMO 0" ClientMessage to the xscreensaver process, which brought up
242 the built-in demo mode dialog. Now that the demo mode dialog is no
243 longer built in, we bring it up by just running the "xscreensaver-demo"
246 Note that "-DEMO <n>" still sends a ClientMessage.
248 if (cmd == &XA_PREFS ||
249 (cmd == &XA_DEMO && arg == 0))
252 char *new_argv[] = { "xscreensaver-demo", 0, 0, 0, 0, 0 };
257 new_argv[ac++] = "-display";
258 new_argv[ac++] = dpyname;
261 if (cmd == &XA_PREFS)
262 new_argv[ac++] = "-prefs";
266 execvp (new_argv[0], new_argv); /* shouldn't return */
268 sprintf (buf, "%s: could not exec %s", progname, new_argv[0]);
277 if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
283 "%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
287 dpy = XOpenDisplay (dpyname);
290 fprintf (stderr, "%s: can't open display %s\n", progname,
291 (dpyname ? dpyname : "(null)"));
295 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
296 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
297 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
298 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
299 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
300 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
301 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
302 XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
303 XA_RESTART = XInternAtom (dpy, "RESTART", False);
304 XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
305 XA_NEXT = XInternAtom (dpy, "NEXT", False);
306 XA_PREV = XInternAtom (dpy, "PREV", False);
307 XA_SELECT = XInternAtom (dpy, "SELECT", False);
308 XA_EXIT = XInternAtom (dpy, "EXIT", False);
309 XA_DEMO = XInternAtom (dpy, "DEMO", False);
310 XA_PREFS = XInternAtom (dpy, "PREFS", False);
311 XA_LOCK = XInternAtom (dpy, "LOCK", False);
312 XA_BLANK = XInternAtom (dpy, "BLANK", False);
313 XA_THROTTLE = XInternAtom (dpy, "THROTTLE", False);
314 XA_UNTHROTTLE = XInternAtom (dpy, "UNTHROTTLE", False);
318 if (cmd == &XA_WATCH)
324 if (*cmd == XA_ACTIVATE || *cmd == XA_LOCK ||
325 *cmd == XA_NEXT || *cmd == XA_PREV || *cmd == XA_SELECT)
326 /* People never guess that KeyRelease deactivates the screen saver too,
327 so if we're issuing an activation command, wait a second.
328 No need to do this if stdin is not a tty, meaning we're not being
329 run from the command line.
334 i = xscreensaver_command (dpy, *cmd, arg, True, NULL);
344 Window window = RootWindow (dpy, 0);
345 XWindowAttributes xgwa;
350 XGetWindowAttributes (dpy, window, &xgwa);
351 XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
355 XNextEvent (dpy, &event);
356 if (event.xany.type == PropertyNotify &&
357 event.xproperty.state == PropertyNewValue &&
358 event.xproperty.atom == XA_SCREENSAVER_STATUS)
362 unsigned long nitems, bytesafter;
363 unsigned char *dataP = 0;
365 if (XGetWindowProperty (dpy,
366 RootWindow (dpy, 0), /* always screen #0 */
367 XA_SCREENSAVER_STATUS,
368 0, 999, False, XA_INTEGER,
369 &type, &format, &nitems, &bytesafter,
377 Bool changed = False;
378 Bool running = False;
379 PROP32 *data = (PROP32 *) dataP;
381 if (type != XA_INTEGER || nitems < 3)
384 if (last) XFree (last);
385 if (data) XFree (data);
386 fprintf (stderr, "%s: bad status format on root window.\n",
391 tt = (time_t) data[1];
392 if (tt <= (time_t) 666000000L) /* early 1991 */
396 if (s[strlen(s)-1] == '\n')
399 if (!last || data[0] != last[0])
402 if (data[0] == XA_BLANK)
403 printf ("BLANK %s\n", s);
404 else if (data[0] == XA_LOCK)
405 printf ("LOCK %s\n", s);
406 else if (data[0] == 0)
407 printf ("UNBLANK %s\n", s);
417 for (i = 2; i < nitems; i++)
419 if (data[i] != last[i])
426 if (running && changed)
429 fprintf (stdout, "RUN");
430 for (i = 2; i < nitems; i++)
431 fprintf (stdout, " %d", (int) data[i]);
432 fprintf (stdout, "\n");
437 if (last) XFree (last);
442 if (last) XFree (last);
443 if (dataP) XFree (dataP);
444 fprintf (stderr, "%s: no saver status on root window.\n",