1 /* xscreensaver, Copyright (c) 1991-2001 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
12 /* ========================================================================
13 * First we wait until the keyboard and mouse become idle for the specified
14 * amount of time. We do this in one of three different ways: periodically
15 * checking with the XIdle server extension; selecting key and mouse events
16 * on (nearly) all windows; or by waiting for the MIT-SCREEN-SAVER extension
17 * to send us a "you are idle" event.
19 * Then, we map a full screen black window (or, in the case of the
20 * MIT-SCREEN-SAVER extension, use the one it gave us.)
22 * We place a __SWM_VROOT property on this window, so that newly-started
23 * clients will think that this window is a "virtual root" window.
25 * If there is an existing "virtual root" window (one that already had
26 * an __SWM_VROOT property) then we remove that property from that window.
27 * Otherwise, clients would see that window (the real virtual root) instead
28 * of ours (the impostor.)
30 * Then we pick a random program to run, and start it. Two assumptions
31 * are made about this program: that it has been specified with whatever
32 * command-line options are necessary to make it run on the root window;
33 * and that it has been compiled with vroot.h, so that it is able to find
34 * the root window when a virtual-root window manager (or this program) is
37 * Then, we wait for keyboard or mouse events to be generated on the window.
38 * When they are, we kill the inferior process, unmap the window, and restore
39 * the __SWM_VROOT property to the real virtual root window if there was one.
41 * While we are waiting, we also set up timers so that, after a certain
42 * amount of time has passed, we can start a different screenhack. We do
43 * this by killing the running child process with SIGTERM, and then starting
44 * a new one in the same way.
46 * If there was a real virtual root, meaning that we removed the __SWM_VROOT
47 * property from it, meaning we must (absolutely must) restore it before we
48 * exit, then we set up signal handlers for most signals (SIGINT, SIGTERM,
49 * etc.) that do this. Most Xlib and Xt routines are not reentrant, so it
50 * is not generally safe to call them from signal handlers; however, this
51 * program spends most of its time waiting, so the window of opportunity
52 * when code could be called reentrantly is fairly small; and also, the worst
53 * that could happen is that the call would fail. If we've gotten one of
54 * these signals, then we're on our way out anyway. If we didn't restore the
55 * __SWM_VROOT property, that would be very bad, so it's worth a shot. Note
56 * that this means that, if you're using a virtual-root window manager, you
57 * can really fuck up the world by killing this process with "kill -9".
59 * This program accepts ClientMessages of type SCREENSAVER; these messages
60 * may contain the atom ACTIVATE or DEACTIVATE, meaning to turn the
61 * screensaver on or off now, regardless of the idleness of the user,
62 * and a few other things. The included "xscreensaver-command" program
63 * sends these messsages.
65 * If we don't have the XIdle, MIT-SCREEN-SAVER, or SGI SCREEN_SAVER
66 * extensions, then we do the XAutoLock trick: notice every window that
67 * gets created, and wait 30 seconds or so until its creating process has
68 * settled down, and then select KeyPress events on those windows which
69 * already select for KeyPress events. It's important that we not select
70 * KeyPress on windows which don't select them, because that would
71 * interfere with event propagation. This will break if any program
72 * changes its event mask to contain KeyRelease or PointerMotion more than
73 * 30 seconds after creating the window, but such programs do not seem to
74 * occur in nature (I've never seen it happen in all these years.)
76 * The reason that we can't select KeyPresses on windows that don't have
77 * them already is that, when dispatching a KeyPress event, X finds the
78 * lowest (leafmost) window in the hierarchy on which *any* client selects
79 * for KeyPress, and sends the event to that window. This means that if a
80 * client had a window with subwindows, and expected to receive KeyPress
81 * events on the parent window instead of the subwindows, then that client
82 * would malfunction if some other client selected KeyPress events on the
83 * subwindows. It is an incredible misdesign that one client can make
84 * another client malfunction in this way.
86 * To detect mouse motion, we periodically wake up and poll the mouse
87 * position and button/modifier state, and notice when something has
88 * changed. We make this check every five seconds by default, and since the
89 * screensaver timeout has a granularity of one minute, this makes the
90 * chance of a false positive very small. We could detect mouse motion in
91 * the same way as keyboard activity, but that would suffer from the same
92 * "client changing event mask" problem that the KeyPress events hack does.
93 * I think polling is more reliable.
95 * None of this crap happens if we're using one of the extensions, so install
96 * one of them if the description above sounds just too flaky to live. It
97 * is, but those are your choices.
99 * A third idle-detection option could be implemented (but is not): when
100 * running on the console display ($DISPLAY is `localhost`:0) and we're on a
101 * machine where /dev/tty and /dev/mouse have reasonable last-modification
102 * times, we could just stat() those. But the incremental benefit of
103 * implementing this is really small, so forget I said anything.
106 * - Have a second terminal handy.
107 * - Be careful where you set your breakpoints, you don't want this to
108 * stop under the debugger with the keyboard grabbed or the blackout
110 * - If you run your debugger under XEmacs, try M-ESC (x-grab-keyboard)
111 * to keep your emacs window alive even when xscreensaver has grabbed.
112 * - Go read the code related to `debug_p'.
113 * - You probably can't set breakpoints in functions that are called on
114 * the other side of a call to fork() -- if your subprocesses are
115 * dying with signal 5, Trace/BPT Trap, you're losing in this way.
116 * - If you aren't using a server extension, don't leave this stopped
117 * under the debugger for very long, or the X input buffer will get
118 * huge because of the keypress events it's selecting for. This can
119 * make your X server wedge with "no more input buffers."
121 * ======================================================================== */
129 #include <X11/Xlib.h>
130 #include <X11/Xatom.h>
131 #include <X11/Intrinsic.h>
132 #include <X11/StringDefs.h>
133 #include <X11/Shell.h>
135 #include <netdb.h> /* for gethostbyname() */
138 # include <X11/Xmu/Error.h>
140 # include <Xmu/Error.h>
142 #else /* !HAVE_XMU */
144 #endif /* !HAVE_XMU */
146 #ifdef HAVE_XIDLE_EXTENSION
147 # include <X11/extensions/xidle.h>
148 #endif /* HAVE_XIDLE_EXTENSION */
150 #include "xscreensaver.h"
152 #include "yarandom.h"
153 #include "resources.h"
157 saver_info *global_si_kludge = 0; /* I hate C so much... */
164 static Atom XA_SCREENSAVER_RESPONSE;
165 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
166 static Atom XA_RESTART, XA_SELECT;
167 static Atom XA_THROTTLE, XA_UNTHROTTLE;
168 Atom XA_DEMO, XA_PREFS, XA_EXIT, XA_LOCK, XA_BLANK;
171 static XrmOptionDescRec options [] = {
172 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
173 { "-cycle", ".cycle", XrmoptionSepArg, 0 },
174 { "-lock-mode", ".lock", XrmoptionNoArg, "on" },
175 { "-no-lock-mode", ".lock", XrmoptionNoArg, "off" },
176 { "-no-lock", ".lock", XrmoptionNoArg, "off" },
177 { "-lock-timeout", ".lockTimeout", XrmoptionSepArg, 0 },
178 { "-lock-vts", ".lockVTs", XrmoptionNoArg, "on" },
179 { "-no-lock-vts", ".lockVTs", XrmoptionNoArg, "off" },
180 { "-visual", ".visualID", XrmoptionSepArg, 0 },
181 { "-install", ".installColormap", XrmoptionNoArg, "on" },
182 { "-no-install", ".installColormap", XrmoptionNoArg, "off" },
183 { "-verbose", ".verbose", XrmoptionNoArg, "on" },
184 { "-silent", ".verbose", XrmoptionNoArg, "off" },
185 { "-timestamp", ".timestamp", XrmoptionNoArg, "on" },
186 { "-capture-stderr", ".captureStderr", XrmoptionNoArg, "on" },
187 { "-no-capture-stderr", ".captureStderr", XrmoptionNoArg, "off" },
188 { "-xidle-extension", ".xidleExtension", XrmoptionNoArg, "on" },
189 { "-no-xidle-extension", ".xidleExtension", XrmoptionNoArg, "off" },
190 { "-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "on" },
191 { "-no-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "off" },
192 { "-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "on" },
193 { "-no-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "off" },
194 { "-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "on" },
195 { "-no-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "off" },
196 { "-splash", ".splash", XrmoptionNoArg, "on" },
197 { "-no-splash", ".splash", XrmoptionNoArg, "off" },
198 { "-nosplash", ".splash", XrmoptionNoArg, "off" },
199 { "-idelay", ".initialDelay", XrmoptionSepArg, 0 },
200 { "-nice", ".nice", XrmoptionSepArg, 0 },
202 /* Actually these are built in to Xt, but just to be sure... */
203 { "-synchronous", ".synchronous", XrmoptionNoArg, "on" },
204 { "-xrm", NULL, XrmoptionResArg, NULL }
207 static char *defaults[] = {
208 #include "XScreenSaver_ad.h"
213 ERROR! You must not include vroot.h in this file.
217 do_help (saver_info *si)
222 xscreensaver %s, copyright (c) 1991-2001 by Jamie Zawinski <jwz@jwz.org>\n\
223 The standard Xt command-line options are accepted; other options include:\n\
225 -timeout <minutes> When the screensaver should activate.\n\
226 -cycle <minutes> How long to let each hack run before switching.\n\
227 -lock-mode Require a password before deactivating.\n\
228 -lock-timeout <minutes> Grace period before locking; default 0.\n\
229 -visual <id-or-class> Which X visual to run on.\n\
230 -install Install a private colormap.\n\
232 -no-splash Don't display a splash-screen at startup.\n\
233 -help This message.\n\
235 See the manual for other options and X resources.\n\
237 The `xscreensaver' program should be left running in the background.\n\
238 Use the `xscreensaver-demo' and `xscreensaver-command' programs to\n\
239 manipulate a running xscreensaver.\n\
241 The `*programs' resource controls which graphics demos will be launched by\n\
242 the screensaver. See `man xscreensaver' or the web page for more details.\n\
244 Just getting started? Try this:\n\
249 For updates, check http://www.jwz.org/xscreensaver/\n\
261 time_t now = time ((time_t *) 0);
262 char *str = (char *) ctime (&now);
263 char *nl = (char *) strchr (str, '\n');
264 if (nl) *nl = 0; /* take off that dang newline */
268 static Bool blurb_timestamp_p = False; /* kludge */
273 if (!blurb_timestamp_p)
277 static char buf[255];
278 char *ct = timestring();
279 int n = strlen(progname);
281 strncpy(buf, progname, n);
284 strncpy(buf+n, ct+11, 8);
285 strcpy(buf+n+9, ": ");
292 saver_ehandler (Display *dpy, XErrorEvent *error)
294 saver_info *si = global_si_kludge; /* I hate C so much... */
296 if (!real_stderr) real_stderr = stderr;
298 fprintf (real_stderr, "\n"
299 "#######################################"
300 "#######################################\n\n"
301 "%s: X Error! PLEASE REPORT THIS BUG.\n\n"
302 "#######################################"
303 "#######################################\n\n",
305 if (XmuPrintDefaultErrorMessage (dpy, error, real_stderr))
307 fprintf (real_stderr, "\n");
308 if (si->prefs.xsync_p)
310 saver_exit (si, -1, "because of synchronous X Error");
314 fprintf (real_stderr,
315 "#######################################"
316 "#######################################\n\n");
317 fprintf (real_stderr,
318 " If at all possible, please re-run xscreensaver with the command\n"
319 " line arguments `-sync -verbose -no-capture', and reproduce this\n"
320 " bug. That will cause xscreensaver to dump a `core' file to the\n"
321 " current directory. Please include the stack trace from that core\n"
322 " file in your bug report. *DO NOT* mail the core file itself!\n"
323 " That won't work.\n"
325 " http://www.jwz.org/xscreensaver/bugs.html explains how to create\n"
326 " the most useful bug reports, and how to examine core files.\n"
328 " The more information you can provide, the better. But please\n"
329 " report this bug, regardless!\n"
331 fprintf (real_stderr,
332 "#######################################"
333 "#######################################\n\n");
335 saver_exit (si, -1, 0);
339 fprintf (real_stderr, " (nonfatal.)\n");
344 /* This error handler is used only while the X connection is being set up;
345 after we've got a connection, we don't use this handler again. The only
346 reason for having this is so that we can present a more idiot-proof error
347 message than "cannot open display."
350 startup_ehandler (String name, String type, String class,
351 String defalt, /* one can't even spel properly
352 in this joke of a language */
353 String *av, Cardinal *ac)
357 saver_info *si = global_si_kludge; /* I hate C so much... */
358 XrmDatabase *db = XtAppGetErrorDatabase(si->app);
360 XtAppGetErrorDatabaseText(si->app, name, type, class, defalt,
361 fmt, sizeof(fmt)-1, *db);
363 fprintf (stderr, "%s: ", blurb());
365 memset (p, 0, sizeof(p));
366 if (*ac > countof (p)) *ac = countof (p);
367 memcpy ((char *) p, (char *) av, (*ac) * sizeof(*av));
368 fprintf (stderr, fmt, /* Did I mention that I hate C? */
369 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
370 fprintf (stderr, "\n");
372 describe_uids (si, stderr);
374 if (si->orig_uid && !strncmp (si->orig_uid, "root/", 5))
376 fprintf (stderr, "\n"
377 "%s: This is probably because you're logging in as root. You\n"
378 " shouldn't log in as root: you should log in as a normal user,\n"
379 " and then `su' as needed. If you insist on logging in as\n"
380 " root, you will have to turn off X's security features before\n"
381 " xscreensaver will work.\n"
383 " Please read the manual and FAQ for more information:\n",
388 fprintf (stderr, "\n"
389 "%s: Errors at startup are usually authorization problems.\n"
390 " But you're not logging in as root (good!) so something\n"
391 " else must be wrong. Did you read the manual and the FAQ?\n",
395 fprintf (stderr, "\n"
396 " http://www.jwz.org/xscreensaver/faq.html\n"
397 " http://www.jwz.org/xscreensaver/man.html\n"
406 /* The zillions of initializations.
409 /* Set progname, version, etc. This is done very early.
412 set_version_string (saver_info *si, int *argc, char **argv)
414 progclass = "XScreenSaver";
416 /* progname is reset later, after we connect to X. */
417 progname = strrchr(argv[0], '/');
418 if (progname) progname++;
419 else progname = argv[0];
421 if (strlen(progname) > 100) /* keep it short. */
424 /* The X resource database blows up if argv[0] has a "." in it. */
427 while ((s = strchr (s, '.')))
431 si->version = (char *) malloc (5);
432 memcpy (si->version, screensaver_id + 17, 4);
437 /* Initializations that potentially take place as a priveleged user:
438 If the xscreensaver executable is setuid root, then these initializations
439 are run as root, before discarding privileges.
442 privileged_initialization (saver_info *si, int *argc, char **argv)
445 /* before hack_uid() for proper permissions */
446 lock_priv_init (*argc, argv, si->prefs.verbose_p);
447 #endif /* NO_LOCKING */
453 /* Figure out what locking mechanisms are supported.
456 lock_initialization (saver_info *si, int *argc, char **argv)
459 si->locking_disabled_p = True;
460 si->nolock_reason = "not compiled with locking support";
461 #else /* !NO_LOCKING */
463 /* Finish initializing locking, now that we're out of privileged code. */
464 if (! lock_init (*argc, argv, si->prefs.verbose_p))
466 si->locking_disabled_p = True;
467 si->nolock_reason = "error getting password";
469 #endif /* NO_LOCKING */
475 /* Open the connection to the X server, and intern our Atoms.
478 connect_to_server (saver_info *si, int *argc, char **argv)
480 Widget toplevel_shell;
483 char *d = getenv ("DISPLAY");
486 char ndpy[] = "DISPLAY=:0.0";
487 /* if (si->prefs.verbose_p) */ /* sigh, too early to test this... */
489 "%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
494 #endif /* HAVE_PUTENV */
496 XSetErrorHandler (saver_ehandler);
498 XtAppSetErrorMsgHandler (si->app, startup_ehandler);
499 toplevel_shell = XtAppInitialize (&si->app, progclass,
500 options, XtNumber (options),
501 argc, argv, defaults, 0, 0);
502 XtAppSetErrorMsgHandler (si->app, 0);
504 si->dpy = XtDisplay (toplevel_shell);
505 si->prefs.db = XtDatabase (si->dpy);
506 XtGetApplicationNameAndClass (si->dpy, &progname, &progclass);
508 if(strlen(progname) > 100) /* keep it short. */
511 db = si->prefs.db; /* resources.c needs this */
513 XA_VROOT = XInternAtom (si->dpy, "__SWM_VROOT", False);
514 XA_SCREENSAVER = XInternAtom (si->dpy, "SCREENSAVER", False);
515 XA_SCREENSAVER_VERSION = XInternAtom (si->dpy, "_SCREENSAVER_VERSION",False);
516 XA_SCREENSAVER_ID = XInternAtom (si->dpy, "_SCREENSAVER_ID", False);
517 XA_SCREENSAVER_STATUS = XInternAtom (si->dpy, "_SCREENSAVER_STATUS", False);
518 XA_SCREENSAVER_RESPONSE = XInternAtom (si->dpy, "_SCREENSAVER_RESPONSE",
520 XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False);
521 XA_ACTIVATE = XInternAtom (si->dpy, "ACTIVATE", False);
522 XA_DEACTIVATE = XInternAtom (si->dpy, "DEACTIVATE", False);
523 XA_RESTART = XInternAtom (si->dpy, "RESTART", False);
524 XA_CYCLE = XInternAtom (si->dpy, "CYCLE", False);
525 XA_NEXT = XInternAtom (si->dpy, "NEXT", False);
526 XA_PREV = XInternAtom (si->dpy, "PREV", False);
527 XA_SELECT = XInternAtom (si->dpy, "SELECT", False);
528 XA_EXIT = XInternAtom (si->dpy, "EXIT", False);
529 XA_DEMO = XInternAtom (si->dpy, "DEMO", False);
530 XA_PREFS = XInternAtom (si->dpy, "PREFS", False);
531 XA_LOCK = XInternAtom (si->dpy, "LOCK", False);
532 XA_BLANK = XInternAtom (si->dpy, "BLANK", False);
533 XA_THROTTLE = XInternAtom (si->dpy, "THROTTLE", False);
534 XA_UNTHROTTLE = XInternAtom (si->dpy, "UNTHROTTLE", False);
536 return toplevel_shell;
540 /* Handle the command-line arguments that were not handled for us by Xt.
541 Issue an error message and exit if there are unknown options.
544 process_command_line (saver_info *si, int *argc, char **argv)
547 for (i = 1; i < *argc; i++)
549 if (!strcmp (argv[i], "-debug"))
550 /* no resource for this one, out of paranoia. */
551 si->prefs.debug_p = True;
553 else if (!strcmp (argv[i], "-h") ||
554 !strcmp (argv[i], "-help") ||
555 !strcmp (argv[i], "--help"))
560 const char *s = argv[i];
561 fprintf (stderr, "%s: unknown option \"%s\". Try \"-help\".\n",
564 if (s[0] == '-' && s[1] == '-') s++;
565 if (!strcmp (s, "-activate") ||
566 !strcmp (s, "-deactivate") ||
567 !strcmp (s, "-cycle") ||
568 !strcmp (s, "-next") ||
569 !strcmp (s, "-prev") ||
570 !strcmp (s, "-exit") ||
571 !strcmp (s, "-restart") ||
572 !strcmp (s, "-demo") ||
573 !strcmp (s, "-prefs") ||
574 !strcmp (s, "-preferences") ||
575 !strcmp (s, "-lock") ||
576 !strcmp (s, "-version") ||
577 !strcmp (s, "-time"))
580 if (!strcmp (s, "-demo") || !strcmp (s, "-prefs"))
581 fprintf (stderr, "\n\
582 Perhaps you meant to run the `xscreensaver-demo' program instead?\n");
584 fprintf (stderr, "\n\
585 However, `%s' is an option to the `xscreensaver-command' program.\n", s);
588 The `xscreensaver' program is a daemon that runs in the background.\n\
589 You control a running xscreensaver process by sending it messages\n\
590 with `xscreensaver-demo' or `xscreensaver-command'.\n\
591 . See the man pages for details, or check the web page:\n\
592 http://www.jwz.org/xscreensaver/\n\n");
594 /* Since version 1.21 renamed the "-lock" option to "-lock-mode",
595 suggest that explicitly. */
596 if (!strcmp (s, "-lock"))
598 Or perhaps you meant either the \"-lock-mode\" or the\n\
599 \"-lock-timeout <minutes>\" options to xscreensaver?\n\n");
608 /* Print out the xscreensaver banner to the tty if applicable;
609 Issue any other warnings that are called for at this point.
612 print_banner (saver_info *si)
614 saver_preferences *p = &si->prefs;
616 /* This resource gets set some time before the others, so that we know
617 whether to print the banner (and so that the banner gets printed before
618 any resource-database-related error messages.)
620 p->verbose_p = (p->debug_p || get_boolean_resource ("verbose", "Boolean"));
622 /* Ditto, for the locking_disabled_p message. */
623 p->lock_p = get_boolean_resource ("lock", "Boolean");
627 "%s %s, copyright (c) 1991-2001 "
628 "by Jamie Zawinski <jwz@jwz.org>.\n",
629 progname, si->version);
632 fprintf (stderr, "\n"
633 "%s: Warning: running in DEBUG MODE. Be afraid.\n"
635 "\tNote that in debug mode, the xscreensaver window will only\n"
636 "\tcover the left half of the screen. (The idea is that you\n"
637 "\tcan still see debugging output in a shell, if you position\n"
638 "\tit on the right side of the screen.)\n"
640 "\tDebug mode is NOT SECURE. Do not run with -debug in\n"
641 "\tuntrusted environments.\n"
647 if (!si->uid_message || !*si->uid_message)
648 describe_uids (si, stderr);
651 if (si->orig_uid && *si->orig_uid)
652 fprintf (stderr, "%s: initial effective uid/gid was %s.\n",
653 blurb(), si->orig_uid);
654 fprintf (stderr, "%s: %s\n", blurb(), si->uid_message);
657 fprintf (stderr, "%s: in process %lu.\n", blurb(),
658 (unsigned long) getpid());
661 /* If locking was not able to be initalized for some reason, explain why.
662 (This has to be done after we've read the lock_p resource.)
664 if (p->lock_p && si->locking_disabled_p)
667 fprintf (stderr, "%s: locking is disabled (%s).\n", blurb(),
669 if (strstr (si->nolock_reason, "passw"))
670 fprintf (stderr, "%s: does xscreensaver need to be setuid? "
671 "consult the manual.\n", blurb());
672 else if (strstr (si->nolock_reason, "running as "))
674 "%s: locking only works when xscreensaver is launched\n"
675 "\t by a normal, non-privileged user (e.g., not \"root\".)\n"
676 "\t See the manual for details.\n",
682 /* Examine all of the display's screens, and populate the `saver_screen_info'
683 structures. Make sure this is called after hack_environment() sets $PATH.
686 initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
688 Bool found_any_writable_cells = False;
691 si->nscreens = ScreenCount(si->dpy);
692 si->screens = (saver_screen_info *)
693 calloc(sizeof(saver_screen_info), si->nscreens);
695 si->default_screen = &si->screens[DefaultScreen(si->dpy)];
697 for (i = 0; i < si->nscreens; i++)
699 saver_screen_info *ssi = &si->screens[i];
701 ssi->screen = ScreenOfDisplay (si->dpy, i);
703 /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
704 ssi->default_visual =
705 get_visual_resource (ssi->screen, "visualID", "VisualID", False);
707 ssi->current_visual = ssi->default_visual;
708 ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
710 /* Execute a subprocess to find the GL visual. */
711 ssi->best_gl_visual = get_best_gl_visual (ssi);
713 if (ssi == si->default_screen)
714 /* Since this is the default screen, use the one already created. */
715 ssi->toplevel_shell = toplevel_shell;
717 /* Otherwise, each screen must have its own unmapped root widget. */
718 ssi->toplevel_shell =
719 XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass,
721 XtNscreen, ssi->screen,
722 XtNvisual, ssi->current_visual,
723 XtNdepth, visual_depth (ssi->screen,
724 ssi->current_visual),
727 if (! found_any_writable_cells)
729 /* Check to see whether fading is ever possible -- if any of the
730 screens on the display has a PseudoColor visual, then fading can
731 work (on at least some screens.) If no screen has a PseudoColor
732 visual, then don't bother ever trying to fade, because it will
733 just cause a delay without causing any visible effect.
735 if (has_writable_cells (ssi->screen, ssi->current_visual) ||
736 get_visual (ssi->screen, "PseudoColor", True, False) ||
737 get_visual (ssi->screen, "GrayScale", True, False))
738 found_any_writable_cells = True;
742 si->fading_possible_p = found_any_writable_cells;
744 #ifdef HAVE_XF86VMODE_GAMMA
745 si->fading_possible_p = True; /* if we can gamma fade, go for it */
750 /* If any server extensions have been requested, try and initialize them.
751 Issue warnings if requests can't be honored.
754 initialize_server_extensions (saver_info *si)
756 saver_preferences *p = &si->prefs;
758 Bool server_has_xidle_extension_p = False;
759 Bool server_has_sgi_saver_extension_p = False;
760 Bool server_has_mit_saver_extension_p = False;
761 Bool system_has_proc_interrupts_p = False;
762 const char *piwhy = 0;
764 si->using_xidle_extension = p->use_xidle_extension;
765 si->using_sgi_saver_extension = p->use_sgi_saver_extension;
766 si->using_mit_saver_extension = p->use_mit_saver_extension;
767 si->using_proc_interrupts = p->use_proc_interrupts;
769 #ifdef HAVE_XIDLE_EXTENSION
770 server_has_xidle_extension_p = query_xidle_extension (si);
772 #ifdef HAVE_SGI_SAVER_EXTENSION
773 server_has_sgi_saver_extension_p = query_sgi_saver_extension (si);
775 #ifdef HAVE_MIT_SAVER_EXTENSION
776 server_has_mit_saver_extension_p = query_mit_saver_extension (si);
778 #ifdef HAVE_PROC_INTERRUPTS
779 system_has_proc_interrupts_p = query_proc_interrupts_available (si, &piwhy);
782 if (!server_has_xidle_extension_p)
783 si->using_xidle_extension = False;
784 else if (p->verbose_p)
786 if (si->using_xidle_extension)
787 fprintf (stderr, "%s: using XIDLE extension.\n", blurb());
789 fprintf (stderr, "%s: not using server's XIDLE extension.\n", blurb());
792 if (!server_has_sgi_saver_extension_p)
793 si->using_sgi_saver_extension = False;
794 else if (p->verbose_p)
796 if (si->using_sgi_saver_extension)
797 fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb());
800 "%s: not using server's SGI SCREEN_SAVER extension.\n",
804 if (!server_has_mit_saver_extension_p)
805 si->using_mit_saver_extension = False;
806 else if (p->verbose_p)
808 if (si->using_mit_saver_extension)
809 fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n",
813 "%s: not using server's lame MIT-SCREEN-SAVER extension.\n",
817 if (!system_has_proc_interrupts_p)
819 si->using_proc_interrupts = False;
820 if (p->verbose_p && piwhy)
821 fprintf (stderr, "%s: not using /proc/interrupts: %s.\n", blurb(),
824 else if (p->verbose_p)
826 if (si->using_proc_interrupts)
828 "%s: consulting /proc/interrupts for keyboard activity.\n",
832 "%s: not consulting /proc/interrupts for keyboard activity.\n",
838 /* For the case where we aren't using an server extensions, select user events
839 on all the existing windows, and launch timers to select events on
840 newly-created windows as well.
842 If a server extension is being used, this does nothing.
845 select_events (saver_info *si)
847 saver_preferences *p = &si->prefs;
850 if (si->using_xidle_extension ||
851 si->using_mit_saver_extension ||
852 si->using_sgi_saver_extension)
855 if (p->initial_delay)
859 fprintf (stderr, "%s: waiting for %d second%s...", blurb(),
860 (int) p->initial_delay/1000,
861 (p->initial_delay == 1000 ? "" : "s"));
865 usleep (p->initial_delay);
867 fprintf (stderr, " done.\n");
872 fprintf (stderr, "%s: selecting events on extant windows...", blurb());
877 /* Select events on the root windows of every screen. This also selects
878 for window creation events, so that new subwindows will be noticed.
880 for (i = 0; i < si->nscreens; i++)
881 start_notice_events_timer (si, RootWindowOfScreen (si->screens[i].screen),
885 fprintf (stderr, " done.\n");
890 maybe_reload_init_file (saver_info *si)
892 saver_preferences *p = &si->prefs;
893 if (init_file_changed_p (p))
896 fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
897 blurb(), init_file_name());
901 /* If a server extension is in use, and p->timeout has changed,
902 we need to inform the server of the new timeout. */
903 disable_builtin_screensaver (si, False);
905 /* If the DPMS settings in the init file have changed,
906 change the settings on the server to match. */
907 sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
908 p->dpms_standby / 1000,
909 p->dpms_suspend / 1000,
918 - wait until the user is idle;
920 - wait until the user is active;
921 - unblank the screen;
926 main_loop (saver_info *si)
928 saver_preferences *p = &si->prefs;
933 Bool was_locked = False;
934 sleep_until_idle (si, True);
939 fprintf (stderr, "%s: demoing %d at %s.\n", blurb(),
940 si->selection_mode, timestring());
943 fprintf (stderr, "%s: blanking screen at %s.\n", blurb(),
947 maybe_reload_init_file (si);
949 if (! blank_screen (si))
951 /* We were unable to grab either the keyboard or mouse.
952 This means we did not (and must not) blank the screen.
953 If we were to blank the screen while some other program
954 is holding both the mouse and keyboard grabbed, then
955 we would never be able to un-blank it! We would never
956 see any events, and the display would be wedged.
958 So, just go around the loop again and wait for the
959 next bout of idleness.
963 "%s: unable to grab keyboard or mouse! Blanking aborted.\n",
968 kill_screenhack (si);
970 if (!si->throttled_p)
971 spawn_screenhack (si, True);
972 else if (p->verbose_p)
973 fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
975 /* Don't start the cycle timer in demo mode. */
976 if (!si->demoing_p && p->cycle)
977 si->cycle_id = XtAppAddTimeOut (si->app,
979 /* see comment in cycle_timer() */
988 Time lock_timeout = p->lock_timeout;
990 if (si->emergency_lock_p && p->lock_p && lock_timeout)
992 int secs = p->lock_timeout / 1000;
995 "%s: locking now, instead of waiting for %d:%02d:%02d.\n",
997 (secs / (60 * 60)), ((secs / 60) % 60), (secs % 60));
1001 si->emergency_lock_p = False;
1003 if (!si->demoing_p && /* if not going into demo mode */
1004 p->lock_p && /* and locking is enabled */
1005 !si->locking_disabled_p && /* and locking is possible */
1006 lock_timeout == 0) /* and locking is not timer-deferred */
1007 set_locked_p (si, True); /* then lock right now. */
1009 /* locked_p might be true already because of the above, or because of
1010 the LOCK ClientMessage. But if not, and if we're supposed to lock
1011 after some time, set up a timer to do so.
1016 si->lock_id = XtAppAddTimeOut (si->app, lock_timeout,
1017 activate_lock_timer,
1020 #endif /* !NO_LOCKING */
1023 ok_to_unblank = True;
1026 sleep_until_idle (si, False); /* until not idle */
1027 maybe_reload_init_file (si);
1032 saver_screen_info *ssi = si->default_screen;
1033 if (si->locking_disabled_p) abort ();
1036 si->dbox_up_p = True;
1037 suspend_screenhack (si, True);
1038 XUndefineCursor (si->dpy, ssi->screensaver_window);
1040 ok_to_unblank = unlock_p (si);
1042 si->dbox_up_p = False;
1043 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1044 suspend_screenhack (si, False); /* resume */
1046 if (!ok_to_unblank &&
1047 !screenhack_running_p (si))
1049 /* If the lock dialog has been dismissed and we're not about to
1050 unlock the screen, and there is currently no hack running,
1051 then launch one. (There might be no hack running if DPMS
1052 had kicked in. But DPMS is off now, so bring back the hack)
1055 XtRemoveTimeOut (si->cycle_id);
1057 cycle_timer ((XtPointer) si, 0);
1060 #endif /* !NO_LOCKING */
1062 } while (!ok_to_unblank);
1066 fprintf (stderr, "%s: unblanking screen at %s.\n",
1067 blurb(), timestring ());
1069 /* Kill before unblanking, to stop drawing as soon as possible. */
1070 kill_screenhack (si);
1071 unblank_screen (si);
1073 set_locked_p (si, False);
1074 si->emergency_lock_p = False;
1076 si->selection_mode = 0;
1078 /* If we're throttled, and the user has explicitly unlocked the screen,
1079 then unthrottle. If we weren't locked, then don't unthrottle
1080 automatically, because someone might have just bumped the desk... */
1083 if (si->throttled_p && p->verbose_p)
1084 fprintf (stderr, "%s: unthrottled.\n", blurb());
1085 si->throttled_p = False;
1090 XtRemoveTimeOut (si->cycle_id);
1096 XtRemoveTimeOut (si->lock_id);
1101 fprintf (stderr, "%s: awaiting idleness.\n", blurb());
1105 static void analyze_display (saver_info *si);
1108 main (int argc, char **argv)
1112 saver_info *si = &the_si;
1113 saver_preferences *p = &si->prefs;
1116 memset(si, 0, sizeof(*si));
1117 global_si_kludge = si; /* I hate C so much... */
1119 # undef ya_rand_init
1122 save_argv (argc, argv);
1123 set_version_string (si, &argc, argv);
1124 privileged_initialization (si, &argc, argv);
1125 hack_environment (si);
1127 shell = connect_to_server (si, &argc, argv);
1128 process_command_line (si, &argc, argv);
1131 load_init_file (p); /* must be before initialize_per_screen_info() */
1132 initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
1134 /* We can only issue this warnings now. */
1135 if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p))
1137 "%s: there are no PseudoColor or GrayScale visuals.\n"
1138 "%s: ignoring the request for fading/unfading.\n",
1141 for (i = 0; i < si->nscreens; i++)
1142 if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen))
1145 lock_initialization (si, &argc, argv);
1147 if (p->xsync_p) XSynchronize (si->dpy, True);
1148 blurb_timestamp_p = p->timestamp_p; /* kludge */
1150 if (p->verbose_p) analyze_display (si);
1151 initialize_server_extensions (si);
1153 si->blank_time = time ((time_t) 0); /* must be before ..._window */
1154 initialize_screensaver_window (si);
1159 disable_builtin_screensaver (si, True);
1160 sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
1161 p->dpms_standby / 1000,
1162 p->dpms_suspend / 1000,
1166 initialize_stderr (si);
1168 make_splash_dialog (si);
1170 main_loop (si); /* doesn't return */
1175 /* Processing ClientMessage events.
1180 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1185 /* Sometimes some systems send us ClientMessage events with bogus atoms in
1186 them. We only look up the atom names for printing warning messages,
1187 so don't bomb out when it happens...
1190 XGetAtomName_safe (Display *dpy, Atom atom)
1193 XErrorHandler old_handler;
1194 if (!atom) return 0;
1197 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1198 result = XGetAtomName (dpy, atom);
1200 XSetErrorHandler (old_handler);
1208 sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned long) atom);
1209 return strdup (buf);
1215 clientmessage_response (saver_info *si, Window w, Bool error,
1216 const char *stderr_msg,
1217 const char *protocol_msg)
1221 saver_preferences *p = &si->prefs;
1222 if (error || p->verbose_p)
1223 fprintf (stderr, "%s: %s\n", blurb(), stderr_msg);
1225 L = strlen(protocol_msg);
1226 proto = (char *) malloc (L + 2);
1227 proto[0] = (error ? '-' : '+');
1228 strcpy (proto+1, protocol_msg);
1231 XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8,
1232 PropModeReplace, (unsigned char *) proto, L);
1233 XSync (si->dpy, False);
1238 handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
1240 saver_preferences *p = &si->prefs;
1242 Window window = event->xclient.window;
1244 /* Preferences might affect our handling of client messages. */
1245 maybe_reload_init_file (si);
1247 if (event->xclient.message_type != XA_SCREENSAVER)
1250 str = XGetAtomName_safe (si->dpy, event->xclient.message_type);
1251 fprintf (stderr, "%s: unrecognised ClientMessage type %s received\n",
1252 blurb(), (str ? str : "(null)"));
1253 if (str) XFree (str);
1256 if (event->xclient.format != 32)
1258 fprintf (stderr, "%s: ClientMessage of format %d received, not 32\n",
1259 blurb(), event->xclient.format);
1263 type = event->xclient.data.l[0];
1264 if (type == XA_ACTIVATE)
1268 clientmessage_response(si, window, False,
1269 "ACTIVATE ClientMessage received.",
1271 si->selection_mode = 0;
1272 si->demoing_p = False;
1274 if (si->throttled_p && p->verbose_p)
1275 fprintf (stderr, "%s: unthrottled.\n", blurb());
1276 si->throttled_p = False;
1278 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1280 XForceScreenSaver (si->dpy, ScreenSaverActive);
1288 clientmessage_response(si, window, True,
1289 "ClientMessage ACTIVATE received while already active.",
1292 else if (type == XA_DEACTIVATE)
1296 if (si->throttled_p && p->verbose_p)
1297 fprintf (stderr, "%s: unthrottled.\n", blurb());
1298 si->throttled_p = False;
1300 clientmessage_response(si, window, False,
1301 "DEACTIVATE ClientMessage received.",
1303 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1305 XForceScreenSaver (si->dpy, ScreenSaverReset);
1313 clientmessage_response(si, window, True,
1314 "ClientMessage DEACTIVATE received while inactive.",
1317 else if (type == XA_CYCLE)
1321 clientmessage_response(si, window, False,
1322 "CYCLE ClientMessage received.",
1324 si->selection_mode = 0; /* 0 means randomize when its time. */
1325 si->demoing_p = False;
1327 if (si->throttled_p && p->verbose_p)
1328 fprintf (stderr, "%s: unthrottled.\n", blurb());
1329 si->throttled_p = False;
1332 XtRemoveTimeOut (si->cycle_id);
1334 cycle_timer ((XtPointer) si, 0);
1337 clientmessage_response(si, window, True,
1338 "ClientMessage CYCLE received while inactive.",
1341 else if (type == XA_NEXT || type == XA_PREV)
1343 clientmessage_response(si, window, False,
1345 ? "NEXT ClientMessage received."
1346 : "PREV ClientMessage received."),
1348 si->selection_mode = (type == XA_NEXT ? -1 : -2);
1349 si->demoing_p = False;
1351 if (si->throttled_p && p->verbose_p)
1352 fprintf (stderr, "%s: unthrottled.\n", blurb());
1353 si->throttled_p = False;
1358 XtRemoveTimeOut (si->cycle_id);
1360 cycle_timer ((XtPointer) si, 0);
1365 else if (type == XA_SELECT)
1369 long which = event->xclient.data.l[1];
1371 sprintf (buf, "SELECT %ld ClientMessage received.", which);
1372 sprintf (buf2, "activating (%ld).", which);
1373 clientmessage_response (si, window, False, buf, buf2);
1375 if (which < 0) which = 0; /* 0 == "random" */
1376 si->selection_mode = which;
1377 si->demoing_p = False;
1379 if (si->throttled_p && p->verbose_p)
1380 fprintf (stderr, "%s: unthrottled.\n", blurb());
1381 si->throttled_p = False;
1386 XtRemoveTimeOut (si->cycle_id);
1388 cycle_timer ((XtPointer) si, 0);
1393 else if (type == XA_EXIT)
1395 /* Ignore EXIT message if the screen is locked. */
1396 if (until_idle_p || !si->locked_p)
1398 clientmessage_response (si, window, False,
1399 "EXIT ClientMessage received.",
1403 unblank_screen (si);
1404 kill_screenhack (si);
1405 XSync (si->dpy, False);
1407 saver_exit (si, 0, 0);
1410 clientmessage_response (si, window, True,
1411 "EXIT ClientMessage received while locked.",
1412 "screen is locked.");
1414 else if (type == XA_RESTART)
1416 /* The RESTART message works whether the screensaver is active or not,
1417 unless the screen is locked, in which case it doesn't work.
1419 if (until_idle_p || !si->locked_p)
1421 clientmessage_response (si, window, False,
1422 "RESTART ClientMessage received.",
1426 unblank_screen (si);
1427 kill_screenhack (si);
1428 XSync (si->dpy, False);
1433 if (real_stdout) fflush (real_stdout);
1434 if (real_stderr) fflush (real_stderr);
1435 /* make sure error message shows up before exit. */
1436 if (real_stderr && stderr != real_stderr)
1437 dup2 (fileno(real_stderr), fileno(stderr));
1439 restart_process (si);
1440 exit (1); /* shouldn't get here; but if restarting didn't work,
1441 make this command be the same as EXIT. */
1444 clientmessage_response (si, window, True,
1445 "RESTART ClientMessage received while locked.",
1446 "screen is locked.");
1448 else if (type == XA_DEMO)
1450 long arg = event->xclient.data.l[1];
1451 Bool demo_one_hack_p = (arg == 300);
1453 if (demo_one_hack_p)
1457 long which = event->xclient.data.l[2];
1460 sprintf (buf, "DEMO %ld ClientMessage received.", which);
1461 sprintf (buf2, "demoing (%ld).", which);
1462 clientmessage_response (si, window, False, buf, buf2);
1464 if (which < 0) which = 0; /* 0 == "random" */
1465 si->selection_mode = which;
1466 si->demoing_p = True;
1468 if (si->throttled_p && p->verbose_p)
1469 fprintf (stderr, "%s: unthrottled.\n", blurb());
1470 si->throttled_p = False;
1475 clientmessage_response (si, window, True,
1476 "DEMO ClientMessage received while active.",
1481 clientmessage_response (si, window, True,
1482 "obsolete form of DEMO ClientMessage.",
1483 "obsolete form of DEMO ClientMessage.");
1486 else if (type == XA_PREFS)
1488 clientmessage_response (si, window, True,
1489 "the PREFS client-message is obsolete.",
1490 "the PREFS client-message is obsolete.");
1492 else if (type == XA_LOCK)
1495 clientmessage_response (si, window, True,
1496 "not compiled with support for locking.",
1497 "locking not enabled.");
1498 #else /* !NO_LOCKING */
1499 if (si->locking_disabled_p)
1500 clientmessage_response (si, window, True,
1501 "LOCK ClientMessage received, but locking is disabled.",
1502 "locking not enabled.");
1503 else if (si->locked_p)
1504 clientmessage_response (si, window, True,
1505 "LOCK ClientMessage received while already locked.",
1510 char *response = (until_idle_p
1511 ? "activating and locking."
1513 sprintf (buf, "LOCK ClientMessage received; %s", response);
1514 clientmessage_response (si, window, False, buf, response);
1515 set_locked_p (si, True);
1516 si->selection_mode = 0;
1517 si->demoing_p = False;
1519 if (si->lock_id) /* we're doing it now, so lose the timeout */
1521 XtRemoveTimeOut (si->lock_id);
1527 if (si->using_mit_saver_extension ||
1528 si->using_sgi_saver_extension)
1530 XForceScreenSaver (si->dpy, ScreenSaverActive);
1539 #endif /* !NO_LOCKING */
1541 else if (type == XA_THROTTLE)
1543 if (si->throttled_p)
1544 clientmessage_response (si, window, True,
1545 "THROTTLE ClientMessage received, but "
1546 "already throttled.",
1547 "already throttled.");
1551 char *response = "throttled.";
1552 si->throttled_p = True;
1553 si->selection_mode = 0;
1554 si->demoing_p = False;
1555 sprintf (buf, "THROTTLE ClientMessage received; %s", response);
1556 clientmessage_response (si, window, False, buf, response);
1561 XtRemoveTimeOut (si->cycle_id);
1563 cycle_timer ((XtPointer) si, 0);
1567 else if (type == XA_UNTHROTTLE)
1569 if (! si->throttled_p)
1570 clientmessage_response (si, window, True,
1571 "UNTHROTTLE ClientMessage received, but "
1577 char *response = "unthrottled.";
1578 si->throttled_p = False;
1579 si->selection_mode = 0;
1580 si->demoing_p = False;
1581 sprintf (buf, "UNTHROTTLE ClientMessage received; %s", response);
1582 clientmessage_response (si, window, False, buf, response);
1587 XtRemoveTimeOut (si->cycle_id);
1589 cycle_timer ((XtPointer) si, 0);
1597 str = XGetAtomName_safe (si->dpy, type);
1601 if (strlen (str) > 80)
1602 strcpy (str+70, "...");
1603 sprintf (buf, "unrecognised screensaver ClientMessage %s received.",
1610 "unrecognised screensaver ClientMessage 0x%x received.",
1611 (unsigned int) event->xclient.data.l[0]);
1614 clientmessage_response (si, window, True, buf, buf);
1620 /* Some random diagnostics printed in -verbose mode.
1624 analyze_display (saver_info *si)
1628 const char *name; const char *desc; Bool useful_p;
1631 { "SCREEN_SAVER", "SGI Screen-Saver",
1632 # ifdef HAVE_SGI_SAVER_EXTENSION
1637 }, { "SCREEN-SAVER", "SGI Screen-Saver",
1638 # ifdef HAVE_SGI_SAVER_EXTENSION
1643 }, { "MIT-SCREEN-SAVER", "MIT Screen-Saver",
1644 # ifdef HAVE_MIT_SAVER_EXTENSION
1649 }, { "XIDLE", "XIdle",
1650 # ifdef HAVE_XIDLE_EXTENSION
1655 }, { "SGI-VIDEO-CONTROL", "SGI Video-Control",
1656 # ifdef HAVE_SGI_VC_EXTENSION
1661 }, { "READDISPLAY", "SGI Read-Display",
1662 # ifdef HAVE_READ_DISPLAY_EXTENSION
1667 }, { "MIT-SHM", "Shared Memory",
1668 # ifdef HAVE_XSHM_EXTENSION
1673 }, { "DOUBLE-BUFFER", "Double-Buffering",
1674 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
1679 }, { "DPMS", "Power Management",
1680 # ifdef HAVE_DPMS_EXTENSION
1691 }, { "XFree86-VidModeExtension", "XF86 Video-Mode",
1692 # ifdef HAVE_XF86VMODE
1697 }, { "XINERAMA", "Xinerama",
1702 fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
1703 DisplayString(si->dpy));
1704 fprintf (stderr, "%s: vendor is %s, %d\n", blurb(),
1705 ServerVendor(si->dpy), VendorRelease(si->dpy));
1707 fprintf (stderr, "%s: useful extensions:\n", blurb());
1708 for (i = 0; i < countof(exts); i++)
1710 int op = 0, event = 0, error = 0;
1711 if (XQueryExtension (si->dpy, exts[i].name, &op, &event, &error))
1712 fprintf (stderr, "%s: %s%s\n", blurb(),
1714 (exts[i].useful_p ? "" :
1715 " \t<== unsupported at compile-time!"));
1718 for (i = 0; i < si->nscreens; i++)
1720 unsigned long colormapped_depths = 0;
1721 unsigned long non_mapped_depths = 0;
1722 XVisualInfo vi_in, *vi_out;
1725 vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
1726 if (!vi_out) continue;
1727 for (j = 0; j < out_count; j++)
1728 if (vi_out[j].class == PseudoColor)
1729 colormapped_depths |= (1 << vi_out[j].depth);
1731 non_mapped_depths |= (1 << vi_out[j].depth);
1732 XFree ((char *) vi_out);
1734 if (colormapped_depths)
1736 fprintf (stderr, "%s: screen %d colormapped depths:", blurb(), i);
1737 for (j = 0; j < 32; j++)
1738 if (colormapped_depths & (1 << j))
1739 fprintf (stderr, " %d", j);
1740 fprintf (stderr, "\n");
1742 if (non_mapped_depths)
1744 fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i);
1745 for (j = 0; j < 32; j++)
1746 if (non_mapped_depths & (1 << j))
1747 fprintf (stderr, " %d", j);
1748 fprintf (stderr, "\n");
1754 display_is_on_console_p (saver_info *si)
1756 Bool not_on_console = True;
1757 char *dpystr = DisplayString (si->dpy);
1758 char *tail = (char *) strchr (dpystr, ':');
1759 if (! tail || strncmp (tail, ":0", 2))
1760 not_on_console = True;
1763 char dpyname[255], localname[255];
1764 strncpy (dpyname, dpystr, tail-dpystr);
1765 dpyname [tail-dpystr] = 0;
1767 !strcmp(dpyname, "unix") ||
1768 !strcmp(dpyname, "localhost"))
1769 not_on_console = False;
1770 else if (gethostname (localname, sizeof (localname)))
1771 not_on_console = True; /* can't find hostname? */
1774 /* We have to call gethostbyname() on the result of gethostname()
1775 because the two aren't guarenteed to be the same name for the
1776 same host: on some losing systems, one is a FQDN and the other
1777 is not. Here in the wide wonderful world of Unix it's rocket
1778 science to obtain the local hostname in a portable fashion.
1780 And don't forget, gethostbyname() reuses the structure it
1781 returns, so we have to copy the fucker before calling it again.
1782 Thank you master, may I have another.
1784 struct hostent *h = gethostbyname (dpyname);
1786 not_on_console = True;
1791 strcpy (hn, h->h_name);
1792 l = gethostbyname (localname);
1793 not_on_console = (!l || !!(strcmp (l->h_name, hn)));
1797 return !not_on_console;