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
\ e\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;
746 /* If any server extensions have been requested, try and initialize them.
747 Issue warnings if requests can't be honored.
750 initialize_server_extensions (saver_info *si)
752 saver_preferences *p = &si->prefs;
754 Bool server_has_xidle_extension_p = False;
755 Bool server_has_sgi_saver_extension_p = False;
756 Bool server_has_mit_saver_extension_p = False;
757 Bool system_has_proc_interrupts_p = False;
758 const char *piwhy = 0;
760 si->using_xidle_extension = p->use_xidle_extension;
761 si->using_sgi_saver_extension = p->use_sgi_saver_extension;
762 si->using_mit_saver_extension = p->use_mit_saver_extension;
763 si->using_proc_interrupts = p->use_proc_interrupts;
765 #ifdef HAVE_XIDLE_EXTENSION
766 server_has_xidle_extension_p = query_xidle_extension (si);
768 #ifdef HAVE_SGI_SAVER_EXTENSION
769 server_has_sgi_saver_extension_p = query_sgi_saver_extension (si);
771 #ifdef HAVE_MIT_SAVER_EXTENSION
772 server_has_mit_saver_extension_p = query_mit_saver_extension (si);
774 #ifdef HAVE_PROC_INTERRUPTS
775 system_has_proc_interrupts_p = query_proc_interrupts_available (si, &piwhy);
778 if (!server_has_xidle_extension_p)
779 si->using_xidle_extension = False;
780 else if (p->verbose_p)
782 if (si->using_xidle_extension)
783 fprintf (stderr, "%s: using XIDLE extension.\n", blurb());
785 fprintf (stderr, "%s: not using server's XIDLE extension.\n", blurb());
788 if (!server_has_sgi_saver_extension_p)
789 si->using_sgi_saver_extension = False;
790 else if (p->verbose_p)
792 if (si->using_sgi_saver_extension)
793 fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb());
796 "%s: not using server's SGI SCREEN_SAVER extension.\n",
800 if (!server_has_mit_saver_extension_p)
801 si->using_mit_saver_extension = False;
802 else if (p->verbose_p)
804 if (si->using_mit_saver_extension)
805 fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n",
809 "%s: not using server's lame MIT-SCREEN-SAVER extension.\n",
813 if (!system_has_proc_interrupts_p)
815 si->using_proc_interrupts = False;
816 if (p->verbose_p && piwhy)
817 fprintf (stderr, "%s: not using /proc/interrupts: %s.\n", blurb(),
820 else if (p->verbose_p)
822 if (si->using_proc_interrupts)
824 "%s: consulting /proc/interrupts for keyboard activity.\n",
828 "%s: not consulting /proc/interrupts for keyboard activity.\n",
834 /* For the case where we aren't using an server extensions, select user events
835 on all the existing windows, and launch timers to select events on
836 newly-created windows as well.
838 If a server extension is being used, this does nothing.
841 select_events (saver_info *si)
843 saver_preferences *p = &si->prefs;
846 if (si->using_xidle_extension ||
847 si->using_mit_saver_extension ||
848 si->using_sgi_saver_extension)
851 if (p->initial_delay)
855 fprintf (stderr, "%s: waiting for %d second%s...", blurb(),
856 (int) p->initial_delay/1000,
857 (p->initial_delay == 1000 ? "" : "s"));
861 usleep (p->initial_delay);
863 fprintf (stderr, " done.\n");
868 fprintf (stderr, "%s: selecting events on extant windows...", blurb());
873 /* Select events on the root windows of every screen. This also selects
874 for window creation events, so that new subwindows will be noticed.
876 for (i = 0; i < si->nscreens; i++)
877 start_notice_events_timer (si, RootWindowOfScreen (si->screens[i].screen),
881 fprintf (stderr, " done.\n");
886 maybe_reload_init_file (saver_info *si)
888 saver_preferences *p = &si->prefs;
889 if (init_file_changed_p (p))
892 fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
893 blurb(), init_file_name());
897 /* If a server extension is in use, and p->timeout has changed,
898 we need to inform the server of the new timeout. */
899 disable_builtin_screensaver (si, False);
901 /* If the DPMS settings in the init file have changed,
902 change the settings on the server to match. */
903 sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
904 p->dpms_standby / 1000,
905 p->dpms_suspend / 1000,
914 - wait until the user is idle;
916 - wait until the user is active;
917 - unblank the screen;
922 main_loop (saver_info *si)
924 saver_preferences *p = &si->prefs;
929 Bool was_locked = False;
930 sleep_until_idle (si, True);
935 fprintf (stderr, "%s: demoing %d at %s.\n", blurb(),
936 si->selection_mode, timestring());
939 fprintf (stderr, "%s: blanking screen at %s.\n", blurb(),
943 maybe_reload_init_file (si);
945 if (! blank_screen (si))
947 /* We were unable to grab either the keyboard or mouse.
948 This means we did not (and must not) blank the screen.
949 If we were to blank the screen while some other program
950 is holding both the mouse and keyboard grabbed, then
951 we would never be able to un-blank it! We would never
952 see any events, and the display would be wedged.
954 So, just go around the loop again and wait for the
955 next bout of idleness.
959 "%s: unable to grab keyboard or mouse! Blanking aborted.\n",
964 kill_screenhack (si);
966 if (!si->throttled_p)
967 spawn_screenhack (si, True);
968 else if (p->verbose_p)
969 fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
971 /* Don't start the cycle timer in demo mode. */
972 if (!si->demoing_p && p->cycle)
973 si->cycle_id = XtAppAddTimeOut (si->app,
975 /* see comment in cycle_timer() */
984 Time lock_timeout = p->lock_timeout;
986 if (si->emergency_lock_p && p->lock_p && lock_timeout)
988 int secs = p->lock_timeout / 1000;
991 "%s: locking now, instead of waiting for %d:%02d:%02d.\n",
993 (secs / (60 * 60)), ((secs / 60) % 60), (secs % 60));
997 si->emergency_lock_p = False;
999 if (!si->demoing_p && /* if not going into demo mode */
1000 p->lock_p && /* and locking is enabled */
1001 !si->locking_disabled_p && /* and locking is possible */
1002 lock_timeout == 0) /* and locking is not timer-deferred */
1003 set_locked_p (si, True); /* then lock right now. */
1005 /* locked_p might be true already because of the above, or because of
1006 the LOCK ClientMessage. But if not, and if we're supposed to lock
1007 after some time, set up a timer to do so.
1012 si->lock_id = XtAppAddTimeOut (si->app, lock_timeout,
1013 activate_lock_timer,
1016 #endif /* !NO_LOCKING */
1019 ok_to_unblank = True;
1022 sleep_until_idle (si, False); /* until not idle */
1023 maybe_reload_init_file (si);
1028 saver_screen_info *ssi = si->default_screen;
1029 if (si->locking_disabled_p) abort ();
1032 si->dbox_up_p = True;
1033 suspend_screenhack (si, True);
1034 XUndefineCursor (si->dpy, ssi->screensaver_window);
1036 ok_to_unblank = unlock_p (si);
1038 si->dbox_up_p = False;
1039 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1040 suspend_screenhack (si, False); /* resume */
1042 if (!ok_to_unblank &&
1043 !screenhack_running_p (si))
1045 /* If the lock dialog has been dismissed and we're not about to
1046 unlock the screen, and there is currently no hack running,
1047 then launch one. (There might be no hack running if DPMS
1048 had kicked in. But DPMS is off now, so bring back the hack)
1051 XtRemoveTimeOut (si->cycle_id);
1053 cycle_timer ((XtPointer) si, 0);
1056 #endif /* !NO_LOCKING */
1058 } while (!ok_to_unblank);
1062 fprintf (stderr, "%s: unblanking screen at %s.\n",
1063 blurb(), timestring ());
1065 /* Kill before unblanking, to stop drawing as soon as possible. */
1066 kill_screenhack (si);
1067 unblank_screen (si);
1069 set_locked_p (si, False);
1070 si->emergency_lock_p = False;
1072 si->selection_mode = 0;
1074 /* If we're throttled, and the user has explicitly unlocked the screen,
1075 then unthrottle. If we weren't locked, then don't unthrottle
1076 automatically, because someone might have just bumped the desk... */
1079 if (si->throttled_p && p->verbose_p)
1080 fprintf (stderr, "%s: unthrottled.\n", blurb());
1081 si->throttled_p = False;
1086 XtRemoveTimeOut (si->cycle_id);
1092 XtRemoveTimeOut (si->lock_id);
1097 fprintf (stderr, "%s: awaiting idleness.\n", blurb());
1101 static void analyze_display (saver_info *si);
1104 main (int argc, char **argv)
1108 saver_info *si = &the_si;
1109 saver_preferences *p = &si->prefs;
1112 memset(si, 0, sizeof(*si));
1113 global_si_kludge = si; /* I hate C so much... */
1115 # undef ya_rand_init
1118 save_argv (argc, argv);
1119 set_version_string (si, &argc, argv);
1120 privileged_initialization (si, &argc, argv);
1121 hack_environment (si);
1123 shell = connect_to_server (si, &argc, argv);
1124 process_command_line (si, &argc, argv);
1127 load_init_file (p); /* must be before initialize_per_screen_info() */
1128 initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
1130 /* We can only issue this warnings now. */
1131 if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p))
1133 "%s: there are no PseudoColor or GrayScale visuals.\n"
1134 "%s: ignoring the request for fading/unfading.\n",
1137 for (i = 0; i < si->nscreens; i++)
1138 if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen))
1141 lock_initialization (si, &argc, argv);
1143 if (p->xsync_p) XSynchronize (si->dpy, True);
1144 blurb_timestamp_p = p->timestamp_p; /* kludge */
1146 if (p->verbose_p) analyze_display (si);
1147 initialize_server_extensions (si);
1149 si->blank_time = time ((time_t) 0); /* must be before ..._window */
1150 initialize_screensaver_window (si);
1155 disable_builtin_screensaver (si, True);
1156 sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
1157 p->dpms_standby / 1000,
1158 p->dpms_suspend / 1000,
1162 initialize_stderr (si);
1164 make_splash_dialog (si);
1166 main_loop (si); /* doesn't return */
1171 /* Processing ClientMessage events.
1176 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1181 /* Sometimes some systems send us ClientMessage events with bogus atoms in
1182 them. We only look up the atom names for printing warning messages,
1183 so don't bomb out when it happens...
1186 XGetAtomName_safe (Display *dpy, Atom atom)
1189 XErrorHandler old_handler;
1190 if (!atom) return 0;
1193 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1194 result = XGetAtomName (dpy, atom);
1196 XSetErrorHandler (old_handler);
1204 sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned long) atom);
1205 return strdup (buf);
1211 clientmessage_response (saver_info *si, Window w, Bool error,
1212 const char *stderr_msg,
1213 const char *protocol_msg)
1217 saver_preferences *p = &si->prefs;
1218 if (error || p->verbose_p)
1219 fprintf (stderr, "%s: %s\n", blurb(), stderr_msg);
1221 L = strlen(protocol_msg);
1222 proto = (char *) malloc (L + 2);
1223 proto[0] = (error ? '-' : '+');
1224 strcpy (proto+1, protocol_msg);
1227 XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8,
1228 PropModeReplace, (unsigned char *) proto, L);
1229 XSync (si->dpy, False);
1234 handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
1236 saver_preferences *p = &si->prefs;
1238 Window window = event->xclient.window;
1240 /* Preferences might affect our handling of client messages. */
1241 maybe_reload_init_file (si);
1243 if (event->xclient.message_type != XA_SCREENSAVER)
1246 str = XGetAtomName_safe (si->dpy, event->xclient.message_type);
1247 fprintf (stderr, "%s: unrecognised ClientMessage type %s received\n",
1248 blurb(), (str ? str : "(null)"));
1249 if (str) XFree (str);
1252 if (event->xclient.format != 32)
1254 fprintf (stderr, "%s: ClientMessage of format %d received, not 32\n",
1255 blurb(), event->xclient.format);
1259 type = event->xclient.data.l[0];
1260 if (type == XA_ACTIVATE)
1264 clientmessage_response(si, window, False,
1265 "ACTIVATE ClientMessage received.",
1267 si->selection_mode = 0;
1268 si->demoing_p = False;
1270 if (si->throttled_p && p->verbose_p)
1271 fprintf (stderr, "%s: unthrottled.\n", blurb());
1272 si->throttled_p = False;
1274 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1276 XForceScreenSaver (si->dpy, ScreenSaverActive);
1284 clientmessage_response(si, window, True,
1285 "ClientMessage ACTIVATE received while already active.",
1288 else if (type == XA_DEACTIVATE)
1292 if (si->throttled_p && p->verbose_p)
1293 fprintf (stderr, "%s: unthrottled.\n", blurb());
1294 si->throttled_p = False;
1296 clientmessage_response(si, window, False,
1297 "DEACTIVATE ClientMessage received.",
1299 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1301 XForceScreenSaver (si->dpy, ScreenSaverReset);
1309 clientmessage_response(si, window, True,
1310 "ClientMessage DEACTIVATE received while inactive.",
1313 else if (type == XA_CYCLE)
1317 clientmessage_response(si, window, False,
1318 "CYCLE ClientMessage received.",
1320 si->selection_mode = 0; /* 0 means randomize when its time. */
1321 si->demoing_p = False;
1323 if (si->throttled_p && p->verbose_p)
1324 fprintf (stderr, "%s: unthrottled.\n", blurb());
1325 si->throttled_p = False;
1328 XtRemoveTimeOut (si->cycle_id);
1330 cycle_timer ((XtPointer) si, 0);
1333 clientmessage_response(si, window, True,
1334 "ClientMessage CYCLE received while inactive.",
1337 else if (type == XA_NEXT || type == XA_PREV)
1339 clientmessage_response(si, window, False,
1341 ? "NEXT ClientMessage received."
1342 : "PREV ClientMessage received."),
1344 si->selection_mode = (type == XA_NEXT ? -1 : -2);
1345 si->demoing_p = False;
1347 if (si->throttled_p && p->verbose_p)
1348 fprintf (stderr, "%s: unthrottled.\n", blurb());
1349 si->throttled_p = False;
1354 XtRemoveTimeOut (si->cycle_id);
1356 cycle_timer ((XtPointer) si, 0);
1361 else if (type == XA_SELECT)
1365 long which = event->xclient.data.l[1];
1367 sprintf (buf, "SELECT %ld ClientMessage received.", which);
1368 sprintf (buf2, "activating (%ld).", which);
1369 clientmessage_response (si, window, False, buf, buf2);
1371 if (which < 0) which = 0; /* 0 == "random" */
1372 si->selection_mode = which;
1373 si->demoing_p = False;
1375 if (si->throttled_p && p->verbose_p)
1376 fprintf (stderr, "%s: unthrottled.\n", blurb());
1377 si->throttled_p = False;
1382 XtRemoveTimeOut (si->cycle_id);
1384 cycle_timer ((XtPointer) si, 0);
1389 else if (type == XA_EXIT)
1391 /* Ignore EXIT message if the screen is locked. */
1392 if (until_idle_p || !si->locked_p)
1394 clientmessage_response (si, window, False,
1395 "EXIT ClientMessage received.",
1399 unblank_screen (si);
1400 kill_screenhack (si);
1401 XSync (si->dpy, False);
1403 saver_exit (si, 0, 0);
1406 clientmessage_response (si, window, True,
1407 "EXIT ClientMessage received while locked.",
1408 "screen is locked.");
1410 else if (type == XA_RESTART)
1412 /* The RESTART message works whether the screensaver is active or not,
1413 unless the screen is locked, in which case it doesn't work.
1415 if (until_idle_p || !si->locked_p)
1417 clientmessage_response (si, window, False,
1418 "RESTART ClientMessage received.",
1422 unblank_screen (si);
1423 kill_screenhack (si);
1424 XSync (si->dpy, False);
1429 if (real_stdout) fflush (real_stdout);
1430 if (real_stderr) fflush (real_stderr);
1431 /* make sure error message shows up before exit. */
1432 if (real_stderr && stderr != real_stderr)
1433 dup2 (fileno(real_stderr), fileno(stderr));
1435 restart_process (si);
1436 exit (1); /* shouldn't get here; but if restarting didn't work,
1437 make this command be the same as EXIT. */
1440 clientmessage_response (si, window, True,
1441 "RESTART ClientMessage received while locked.",
1442 "screen is locked.");
1444 else if (type == XA_DEMO)
1446 long arg = event->xclient.data.l[1];
1447 Bool demo_one_hack_p = (arg == 300);
1449 if (demo_one_hack_p)
1453 long which = event->xclient.data.l[2];
1456 sprintf (buf, "DEMO %ld ClientMessage received.", which);
1457 sprintf (buf2, "demoing (%ld).", which);
1458 clientmessage_response (si, window, False, buf, buf2);
1460 if (which < 0) which = 0; /* 0 == "random" */
1461 si->selection_mode = which;
1462 si->demoing_p = True;
1464 if (si->throttled_p && p->verbose_p)
1465 fprintf (stderr, "%s: unthrottled.\n", blurb());
1466 si->throttled_p = False;
1471 clientmessage_response (si, window, True,
1472 "DEMO ClientMessage received while active.",
1477 clientmessage_response (si, window, True,
1478 "obsolete form of DEMO ClientMessage.",
1479 "obsolete form of DEMO ClientMessage.");
1482 else if (type == XA_PREFS)
1484 clientmessage_response (si, window, True,
1485 "the PREFS client-message is obsolete.",
1486 "the PREFS client-message is obsolete.");
1488 else if (type == XA_LOCK)
1491 clientmessage_response (si, window, True,
1492 "not compiled with support for locking.",
1493 "locking not enabled.");
1494 #else /* !NO_LOCKING */
1495 if (si->locking_disabled_p)
1496 clientmessage_response (si, window, True,
1497 "LOCK ClientMessage received, but locking is disabled.",
1498 "locking not enabled.");
1499 else if (si->locked_p)
1500 clientmessage_response (si, window, True,
1501 "LOCK ClientMessage received while already locked.",
1506 char *response = (until_idle_p
1507 ? "activating and locking."
1509 sprintf (buf, "LOCK ClientMessage received; %s", response);
1510 clientmessage_response (si, window, False, buf, response);
1511 set_locked_p (si, True);
1512 si->selection_mode = 0;
1513 si->demoing_p = False;
1515 if (si->lock_id) /* we're doing it now, so lose the timeout */
1517 XtRemoveTimeOut (si->lock_id);
1523 if (si->using_mit_saver_extension ||
1524 si->using_sgi_saver_extension)
1526 XForceScreenSaver (si->dpy, ScreenSaverActive);
1535 #endif /* !NO_LOCKING */
1537 else if (type == XA_THROTTLE)
1539 if (si->throttled_p)
1540 clientmessage_response (si, window, True,
1541 "THROTTLE ClientMessage received, but "
1542 "already throttled.",
1543 "already throttled.");
1547 char *response = "throttled.";
1548 si->throttled_p = True;
1549 si->selection_mode = 0;
1550 si->demoing_p = False;
1551 sprintf (buf, "THROTTLE ClientMessage received; %s", response);
1552 clientmessage_response (si, window, False, buf, response);
1557 XtRemoveTimeOut (si->cycle_id);
1559 cycle_timer ((XtPointer) si, 0);
1563 else if (type == XA_UNTHROTTLE)
1565 if (! si->throttled_p)
1566 clientmessage_response (si, window, True,
1567 "UNTHROTTLE ClientMessage received, but "
1573 char *response = "unthrottled.";
1574 si->throttled_p = False;
1575 si->selection_mode = 0;
1576 si->demoing_p = False;
1577 sprintf (buf, "UNTHROTTLE ClientMessage received; %s", response);
1578 clientmessage_response (si, window, False, buf, response);
1583 XtRemoveTimeOut (si->cycle_id);
1585 cycle_timer ((XtPointer) si, 0);
1593 str = XGetAtomName_safe (si->dpy, type);
1597 if (strlen (str) > 80)
1598 strcpy (str+70, "...");
1599 sprintf (buf, "unrecognised screensaver ClientMessage %s received.",
1606 "unrecognised screensaver ClientMessage 0x%x received.",
1607 (unsigned int) event->xclient.data.l[0]);
1610 clientmessage_response (si, window, True, buf, buf);
1616 /* Some random diagnostics printed in -verbose mode.
1620 analyze_display (saver_info *si)
1624 const char *name; const char *desc; Bool useful_p;
1627 { "SCREEN_SAVER", "SGI Screen-Saver",
1628 # ifdef HAVE_SGI_SAVER_EXTENSION
1633 }, { "SCREEN-SAVER", "SGI Screen-Saver",
1634 # ifdef HAVE_SGI_SAVER_EXTENSION
1639 }, { "MIT-SCREEN-SAVER", "MIT Screen-Saver",
1640 # ifdef HAVE_MIT_SAVER_EXTENSION
1645 }, { "XIDLE", "XIdle",
1646 # ifdef HAVE_XIDLE_EXTENSION
1651 }, { "SGI-VIDEO-CONTROL", "SGI Video-Control",
1652 # ifdef HAVE_SGI_VC_EXTENSION
1657 }, { "READDISPLAY", "SGI Read-Display",
1658 # ifdef HAVE_READ_DISPLAY_EXTENSION
1663 }, { "MIT-SHM", "Shared Memory",
1664 # ifdef HAVE_XSHM_EXTENSION
1669 }, { "DOUBLE-BUFFER", "Double-Buffering",
1670 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
1675 }, { "DPMS", "Power Management",
1676 # ifdef HAVE_DPMS_EXTENSION
1687 }, { "XFree86-VidModeExtension", "XF86 Video-Mode",
1688 # ifdef HAVE_XF86VMODE
1693 }, { "XINERAMA", "Xinerama",
1698 fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
1699 DisplayString(si->dpy));
1700 fprintf (stderr, "%s: vendor is %s, %d\n", blurb(),
1701 ServerVendor(si->dpy), VendorRelease(si->dpy));
1703 fprintf (stderr, "%s: useful extensions:\n", blurb());
1704 for (i = 0; i < countof(exts); i++)
1706 int op = 0, event = 0, error = 0;
1707 if (XQueryExtension (si->dpy, exts[i].name, &op, &event, &error))
1708 fprintf (stderr, "%s: %s%s\n", blurb(),
1710 (exts[i].useful_p ? "" :
1711 " \t<== unsupported at compile-time!"));
1714 for (i = 0; i < si->nscreens; i++)
1716 unsigned long colormapped_depths = 0;
1717 unsigned long non_mapped_depths = 0;
1718 XVisualInfo vi_in, *vi_out;
1721 vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
1722 if (!vi_out) continue;
1723 for (j = 0; j < out_count; j++)
1724 if (vi_out[j].class == PseudoColor)
1725 colormapped_depths |= (1 << vi_out[j].depth);
1727 non_mapped_depths |= (1 << vi_out[j].depth);
1728 XFree ((char *) vi_out);
1730 if (colormapped_depths)
1732 fprintf (stderr, "%s: screen %d colormapped depths:", blurb(), i);
1733 for (j = 0; j < 32; j++)
1734 if (colormapped_depths & (1 << j))
1735 fprintf (stderr, " %d", j);
1736 fprintf (stderr, "\n");
1738 if (non_mapped_depths)
1740 fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i);
1741 for (j = 0; j < 32; j++)
1742 if (non_mapped_depths & (1 << j))
1743 fprintf (stderr, " %d", j);
1744 fprintf (stderr, "\n");
1750 display_is_on_console_p (saver_info *si)
1752 Bool not_on_console = True;
1753 char *dpystr = DisplayString (si->dpy);
1754 char *tail = (char *) strchr (dpystr, ':');
1755 if (! tail || strncmp (tail, ":0", 2))
1756 not_on_console = True;
1759 char dpyname[255], localname[255];
1760 strncpy (dpyname, dpystr, tail-dpystr);
1761 dpyname [tail-dpystr] = 0;
1763 !strcmp(dpyname, "unix") ||
1764 !strcmp(dpyname, "localhost"))
1765 not_on_console = False;
1766 else if (gethostname (localname, sizeof (localname)))
1767 not_on_console = True; /* can't find hostname? */
1770 /* We have to call gethostbyname() on the result of gethostname()
1771 because the two aren't guarenteed to be the same name for the
1772 same host: on some losing systems, one is a FQDN and the other
1773 is not. Here in the wide wonderful world of Unix it's rocket
1774 science to obtain the local hostname in a portable fashion.
1776 And don't forget, gethostbyname() reuses the structure it
1777 returns, so we have to copy the fucker before calling it again.
1778 Thank you master, may I have another.
1780 struct hostent *h = gethostbyname (dpyname);
1782 not_on_console = True;
1787 strcpy (hn, h->h_name);
1788 l = gethostbyname (localname);
1789 not_on_console = (!l || !!(strcmp (l->h_name, hn)));
1793 return !not_on_console;