1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
|
/* xscreensaver-command, Copyright (c) 1991-2020 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
/* #include <X11/Xproto.h> / * for CARD32 */
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h> /* for XGetClassHint() */
#include <X11/Xos.h>
#include <X11/Intrinsic.h> /* only needed to get through xscreensaver.h */
/* You might think that to read an array of 32-bit quantities out of a
server-side property, you would pass an array of 32-bit data quantities
into XGetWindowProperty(). You would be wrong. You have to use an array
of longs, even if long is 64 bits (using 32 of each 64.)
*/
typedef long PROP32;
#include "remote.h"
#include "version.h"
#ifdef _VROOT_H_
ERROR! you must not include vroot.h in this file
#endif
char *progname;
Atom XA_VROOT;
Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO, XA_EXIT;
Atom XA_BLANK, XA_LOCK, XA_ACTIVATE, XA_SUSPEND, XA_NEXT, XA_PREV;
static Atom XA_DEACTIVATE, XA_CYCLE;
static Atom XA_RESTART, XA_PREFS, XA_THROTTLE, XA_UNTHROTTLE;
static char *screensaver_version;
# ifdef __GNUC__
__extension__ /* don't warn about "string length is greater than the
length ISO C89 compilers are required to support" in the
usage string... */
# endif
static char *usage = "\n\
usage: %s -<option>\n\
\n\
This program provides external control of a running xscreensaver process.\n\
Version %s, copyright (c) 1991-%s Jamie Zawinski <jwz@jwz.org>.\n\
\n\
The xscreensaver program is a daemon that runs in the background.\n\
You control a running xscreensaver process by sending it messages\n\
with this program, xscreensaver-command. See the man pages for\n\
details. These are the arguments understood by xscreensaver-command:\n\
\n\
-quiet Only print output if an error occurs.\n\
-verbose Opposite of -quiet. Default.\n\
\n\
-demo Ask the xscreensaver process to enter interactive demo mode.\n\
\n\
-prefs Ask the xscreensaver process to bring up the preferences\n\
panel.\n\
\n\
-activate Turn on the screensaver (blank the screen), as if the user\n\
had been idle for long enough.\n\
\n\
-deactivate Turns off the screensaver (un-blank the screen), as if user\n\
activity had been detected.\n\
\n\
-cycle If the screensaver is active (the screen is blanked), then\n\
stop the current graphics demo and run a new one (chosen\n\
randomly.)\n\
\n\
-next Like either -activate or -cycle, depending on which is more\n\
appropriate, except that the graphics hack that will be run\n\
is the next one in the list, instead of a randomly-chosen\n\
one. In other words, repeatedly executing -next will cause\n\
the xscreensaver process to invoke each graphics demo\n\
sequentially. (Though using the -demo option is probably\n\
an easier way to accomplish that.)\n\
\n\
-prev Like -next, but goes in the other direction.\n\
\n\
-select <N> Like -activate, but runs the Nth element in the list of\n\
hacks. By knowing what is in the `programs' list, and in\n\
what order, you can use this to activate the screensaver\n\
with a particular graphics demo. (The first element in the\n\
list is numbered 1, not 0.)\n\
\n\
-exit Causes the xscreensaver process to exit gracefully.\n\
This does nothing if the display is currently locked.\n\
(Note that one must *never* kill xscreensaver with -9!)\n\
\n\
-restart Causes the screensaver process to exit and then restart with\n\
the same command line arguments as last time. You shouldn't\n\
really need to do this, since xscreensaver notices when the\n\
.xscreensaver file has changed and re-reads it as needed.\n\
\n\
-lock Tells the running xscreensaver process to lock the screen\n\
immediately. This is like -activate, but forces locking as\n\
well, even if locking is not the default. If the saver is\n\
already active, this causes it to be locked as well.\n\
\n\
-suspend Like -activate, but ignores the lock-timeout, if any, and\n\
immediately powers off the screen without fading out.\n\
This is intended to be run just after your laptop's lid\n\
is closed, and just before the CPU halts.\n\
\n\
-version Prints the version of xscreensaver that is currently running\n\
on the display -- that is, the actual version number of the\n\
running xscreensaver background process, rather than the\n\
version number of xscreensaver-command.\n\
\n\
-time Prints the time at which the screensaver last activated or\n\
deactivated (roughly, how long the user has been idle or\n\
non-idle -- but not quite, since it only tells you when the\n\
screen became blanked or un-blanked.)\n\
\n\
-watch Prints a line each time the screensaver changes state: when\n\
the screen blanks, locks, unblanks, or when the running hack\n\
is changed. This option never returns; it is intended for\n\
use by shell scripts that want to react to the screensaver\n\
in some way.\n\
\n\
See the man page for more details.\n\
For updates, check https://www.jwz.org/xscreensaver/\n\
\n";
/* Note: The "-throttle" command is deprecated -- it predates the XDPMS
extension. Instead of using -throttle, users should instead just
power off the monitor (e.g., "xset dpms force off".) In a few
minutes, the xscreensaver daemon will notice that the monitor is
off, and cease running hacks.
*/
#define USAGE() do { \
fprintf (stderr, usage, progname, screensaver_version, year); exit (1); \
} while(0)
static int watch (Display *);
int
main (int argc, char **argv)
{
Display *dpy;
int i;
char *dpyname = 0;
Atom *cmd = 0;
long arg = 0L;
char *s;
Atom XA_WATCH = 0; /* kludge: not really an atom */
char year[5];
Bool verbose_p = TRUE;
progname = argv[0];
s = strrchr (progname, '/');
if (s) progname = s+1;
screensaver_version = (char *) malloc (5);
memcpy (screensaver_version, screensaver_id + 17, 4);
screensaver_version [4] = 0;
s = strchr (screensaver_id, '-');
s = strrchr (s, '-');
s++;
strncpy (year, s, 4);
year[4] = 0;
for (i = 1; i < argc; i++)
{
const char *s = argv [i];
int L;
if (s[0] == '-' && s[1] == '-') s++;
L = strlen (s);
if (L < 2) USAGE ();
if (!strncmp (s, "-display", L)) dpyname = argv [++i];
else if (cmd) USAGE();
else if (!strncmp (s, "-activate", L)) cmd = &XA_ACTIVATE;
else if (!strncmp (s, "-deactivate", L)) cmd = &XA_DEACTIVATE;
else if (!strncmp (s, "-suspend", L)) cmd = &XA_SUSPEND;
else if (!strncmp (s, "-cycle", L)) cmd = &XA_CYCLE;
else if (!strncmp (s, "-next", L)) cmd = &XA_NEXT;
else if (!strncmp (s, "-prev", L)) cmd = &XA_PREV;
else if (!strncmp (s, "-select", L)) cmd = &XA_SELECT;
else if (!strncmp (s, "-exit", L)) cmd = &XA_EXIT;
else if (!strncmp (s, "-restart", L)) cmd = &XA_RESTART;
else if (!strncmp (s, "-demo", L)) cmd = &XA_DEMO;
else if (!strncmp (s, "-preferences",L)) cmd = &XA_PREFS;
else if (!strncmp (s, "-prefs",L)) cmd = &XA_PREFS;
else if (!strncmp (s, "-lock", L)) cmd = &XA_LOCK;
else if (!strncmp (s, "-throttle", L)) cmd = &XA_THROTTLE;
else if (!strncmp (s, "-unthrottle", L)) cmd = &XA_UNTHROTTLE;
else if (!strncmp (s, "-version", L)) cmd = &XA_SCREENSAVER_VERSION;
else if (!strncmp (s, "-time", L)) cmd = &XA_SCREENSAVER_STATUS;
else if (!strncmp (s, "-watch", L)) cmd = &XA_WATCH;
else if (!strncmp (s, "-quiet", L)) verbose_p = FALSE;
else if (!strncmp (s, "-verbose", L)) verbose_p = TRUE;
else USAGE ();
if (cmd == &XA_SELECT || cmd == &XA_DEMO)
{
long a;
char c;
if (i+1 < argc && (1 == sscanf(argv[i+1], " %ld %c", &a, &c)))
{
arg = a;
i++;
}
}
}
if (!cmd)
USAGE ();
if (arg < 0)
/* no command may have a negative argument. */
USAGE();
else if (arg == 0)
{
/* SELECT must have a non-zero argument. */
if (cmd == &XA_SELECT)
USAGE();
}
else /* arg > 0 */
{
/* no command other than SELECT and DEMO may have a non-zero argument. */
if (cmd != &XA_DEMO && cmd != &XA_SELECT)
USAGE();
}
/* For backward compatibility: -demo with no arguments used to send a
"DEMO 0" ClientMessage to the xscreensaver process, which brought up
the built-in demo mode dialog. Now that the demo mode dialog is no
longer built in, we bring it up by just running the "xscreensaver-demo"
program.
Note that "-DEMO <n>" still sends a ClientMessage.
*/
if (cmd == &XA_PREFS ||
(cmd == &XA_DEMO && arg == 0))
{
char buf [512];
char *new_argv[] = { "xscreensaver-demo", 0, 0, 0, 0, 0 };
int ac = 1;
if (dpyname)
{
new_argv[ac++] = "-display";
new_argv[ac++] = dpyname;
}
if (cmd == &XA_PREFS)
new_argv[ac++] = "-prefs";
fflush(stdout);
fflush(stderr);
execvp (new_argv[0], new_argv); /* shouldn't return */
sprintf (buf, "%s: could not exec %s", progname, new_argv[0]);
perror(buf);
fflush(stdout);
fflush(stderr);
exit (-1);
}
if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
if (!dpyname)
{
dpyname = ":0.0";
fprintf (stderr,
"%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
progname, dpyname);
}
dpy = XOpenDisplay (dpyname);
if (!dpy)
{
fprintf (stderr, "%s: can't open display %s\n", progname,
(dpyname ? dpyname : "(null)"));
exit (1);
}
XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
XA_SUSPEND = XInternAtom (dpy, "SUSPEND", False);
XA_RESTART = XInternAtom (dpy, "RESTART", False);
XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
XA_NEXT = XInternAtom (dpy, "NEXT", False);
XA_PREV = XInternAtom (dpy, "PREV", False);
XA_SELECT = XInternAtom (dpy, "SELECT", False);
XA_EXIT = XInternAtom (dpy, "EXIT", False);
XA_DEMO = XInternAtom (dpy, "DEMO", False);
XA_PREFS = XInternAtom (dpy, "PREFS", False);
XA_LOCK = XInternAtom (dpy, "LOCK", False);
XA_BLANK = XInternAtom (dpy, "BLANK", False);
XA_THROTTLE = XInternAtom (dpy, "THROTTLE", False);
XA_UNTHROTTLE = XInternAtom (dpy, "UNTHROTTLE", False);
XSync (dpy, 0);
if (cmd == &XA_WATCH)
{
i = watch (dpy);
exit (i);
}
if (*cmd == XA_ACTIVATE || *cmd == XA_LOCK || *cmd == XA_SUSPEND ||
*cmd == XA_NEXT || *cmd == XA_PREV || *cmd == XA_SELECT)
/* People never guess that KeyRelease deactivates the screen saver too,
so if we're issuing an activation command, wait a second.
No need to do this if stdin is not a tty, meaning we're not being
run from the command line.
*/
if (isatty(0))
sleep (1);
i = xscreensaver_command (dpy, *cmd, arg, verbose_p, NULL);
if (i < 0) exit (i);
else exit (0);
}
static int
watch (Display *dpy)
{
char *v = 0;
Window window = RootWindow (dpy, 0);
XWindowAttributes xgwa;
XEvent event;
PROP32 *last = 0;
if (v) free (v);
XGetWindowAttributes (dpy, window, &xgwa);
XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask);
while (1)
{
XNextEvent (dpy, &event);
if (event.xany.type == PropertyNotify &&
event.xproperty.state == PropertyNewValue &&
event.xproperty.atom == XA_SCREENSAVER_STATUS)
{
Atom type;
int format;
unsigned long nitems, bytesafter;
unsigned char *dataP = 0;
if (XGetWindowProperty (dpy,
RootWindow (dpy, 0), /* always screen #0 */
XA_SCREENSAVER_STATUS,
0, 999, False, XA_INTEGER,
&type, &format, &nitems, &bytesafter,
&dataP)
== Success
&& type
&& dataP)
{
time_t tt;
char *s;
Bool changed = False;
Bool running = False;
PROP32 *data = (PROP32 *) dataP;
if (type != XA_INTEGER || nitems < 3)
{
STATUS_LOSE:
if (last) XFree (last);
if (data) XFree (data);
fprintf (stderr, "%s: bad status format on root window.\n",
progname);
return -1;
}
tt = (time_t) data[1];
if (tt <= (time_t) 666000000L) /* early 1991 */
goto STATUS_LOSE;
s = ctime(&tt);
if (s[strlen(s)-1] == '\n')
s[strlen(s)-1] = 0;
if (!last || data[0] != last[0])
{
/* State changed. */
if (data[0] == XA_BLANK)
printf ("BLANK %s\n", s);
else if (data[0] == XA_LOCK)
printf ("LOCK %s\n", s);
else if (data[0] == 0)
printf ("UNBLANK %s\n", s);
else
goto STATUS_LOSE;
}
if (!last)
changed = True;
else
{
int i;
for (i = 2; i < nitems; i++)
{
if (data[i] != last[i])
changed = True;
if (data[i])
running = True;
}
}
if (running && changed)
{
int i;
fprintf (stdout, "RUN");
for (i = 2; i < nitems; i++)
fprintf (stdout, " %d", (int) data[i]);
fprintf (stdout, "\n");
}
fflush (stdout);
if (last) XFree (last);
last = data;
}
else
{
if (last) XFree (last);
if (dataP) XFree (dataP);
fprintf (stderr, "%s: no saver status on root window.\n",
progname);
return -1;
}
}
}
}
|