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 const 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);
906 - wait until the user is idle;
908 - wait until the user is active;
909 - unblank the screen;
914 main_loop (saver_info *si)
916 saver_preferences *p = &si->prefs;
921 Bool was_locked = False;
922 sleep_until_idle (si, True);
927 fprintf (stderr, "%s: demoing %d at %s.\n", blurb(),
928 si->selection_mode, timestring());
931 fprintf (stderr, "%s: blanking screen at %s.\n", blurb(),
935 maybe_reload_init_file (si);
937 if (! blank_screen (si))
939 /* We were unable to grab either the keyboard or mouse.
940 This means we did not (and must not) blank the screen.
941 If we were to blank the screen while some other program
942 is holding both the mouse and keyboard grabbed, then
943 we would never be able to un-blank it! We would never
944 see any events, and the display would be wedged.
946 So, just go around the loop again and wait for the
947 next bout of idleness.
951 "%s: unable to grab keyboard or mouse! Blanking aborted.\n",
956 kill_screenhack (si);
958 if (!si->throttled_p)
959 spawn_screenhack (si, True);
960 else if (p->verbose_p)
961 fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
963 /* Don't start the cycle timer in demo mode. */
964 if (!si->demoing_p && p->cycle)
965 si->cycle_id = XtAppAddTimeOut (si->app,
967 /* see comment in cycle_timer() */
976 Time lock_timeout = p->lock_timeout;
978 if (si->emergency_lock_p && p->lock_p && lock_timeout)
980 int secs = p->lock_timeout / 1000;
983 "%s: locking now, instead of waiting for %d:%02d:%02d.\n",
985 (secs / (60 * 60)), ((secs / 60) % 60), (secs % 60));
989 si->emergency_lock_p = False;
991 if (!si->demoing_p && /* if not going into demo mode */
992 p->lock_p && /* and locking is enabled */
993 !si->locking_disabled_p && /* and locking is possible */
994 lock_timeout == 0) /* and locking is not timer-deferred */
995 set_locked_p (si, True); /* then lock right now. */
997 /* locked_p might be true already because of the above, or because of
998 the LOCK ClientMessage. But if not, and if we're supposed to lock
999 after some time, set up a timer to do so.
1004 si->lock_id = XtAppAddTimeOut (si->app, lock_timeout,
1005 activate_lock_timer,
1008 #endif /* !NO_LOCKING */
1011 ok_to_unblank = True;
1014 sleep_until_idle (si, False); /* until not idle */
1015 maybe_reload_init_file (si);
1020 saver_screen_info *ssi = si->default_screen;
1021 if (si->locking_disabled_p) abort ();
1024 si->dbox_up_p = True;
1025 suspend_screenhack (si, True);
1026 XUndefineCursor (si->dpy, ssi->screensaver_window);
1028 ok_to_unblank = unlock_p (si);
1030 si->dbox_up_p = False;
1031 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1032 suspend_screenhack (si, False); /* resume */
1034 if (!ok_to_unblank &&
1035 !screenhack_running_p (si))
1037 /* If the lock dialog has been dismissed and we're not about to
1038 unlock the screen, and there is currently no hack running,
1039 then launch one. (There might be no hack running if DPMS
1040 had kicked in. But DPMS is off now, so bring back the hack)
1043 XtRemoveTimeOut (si->cycle_id);
1045 cycle_timer ((XtPointer) si, 0);
1048 #endif /* !NO_LOCKING */
1050 } while (!ok_to_unblank);
1054 fprintf (stderr, "%s: unblanking screen at %s.\n",
1055 blurb(), timestring ());
1057 /* Kill before unblanking, to stop drawing as soon as possible. */
1058 kill_screenhack (si);
1059 unblank_screen (si);
1061 set_locked_p (si, False);
1062 si->emergency_lock_p = False;
1064 si->selection_mode = 0;
1066 /* If we're throttled, and the user has explicitly unlocked the screen,
1067 then unthrottle. If we weren't locked, then don't unthrottle
1068 automatically, because someone might have just bumped the desk... */
1071 if (si->throttled_p && p->verbose_p)
1072 fprintf (stderr, "%s: unthrottled.\n", blurb());
1073 si->throttled_p = False;
1078 XtRemoveTimeOut (si->cycle_id);
1084 XtRemoveTimeOut (si->lock_id);
1089 fprintf (stderr, "%s: awaiting idleness.\n", blurb());
1093 static void analyze_display (saver_info *si);
1096 main (int argc, char **argv)
1100 saver_info *si = &the_si;
1101 saver_preferences *p = &si->prefs;
1104 memset(si, 0, sizeof(*si));
1105 global_si_kludge = si; /* I hate C so much... */
1107 # undef ya_rand_init
1110 save_argv (argc, argv);
1111 set_version_string (si, &argc, argv);
1112 privileged_initialization (si, &argc, argv);
1113 hack_environment (si);
1115 shell = connect_to_server (si, &argc, argv);
1116 process_command_line (si, &argc, argv);
1119 load_init_file (p); /* must be before initialize_per_screen_info() */
1120 initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
1122 /* We can only issue this warnings now. */
1123 if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p))
1125 "%s: there are no PseudoColor or GrayScale visuals.\n"
1126 "%s: ignoring the request for fading/unfading.\n",
1129 for (i = 0; i < si->nscreens; i++)
1130 if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen))
1133 lock_initialization (si, &argc, argv);
1135 if (p->xsync_p) XSynchronize (si->dpy, True);
1136 blurb_timestamp_p = p->timestamp_p; /* kludge */
1138 if (p->verbose_p) analyze_display (si);
1139 initialize_server_extensions (si);
1141 si->blank_time = time ((time_t) 0); /* must be before ..._window */
1142 initialize_screensaver_window (si);
1146 disable_builtin_screensaver (si, True);
1147 initialize_stderr (si);
1149 make_splash_dialog (si);
1151 main_loop (si); /* doesn't return */
1156 /* Processing ClientMessage events.
1160 clientmessage_response (saver_info *si, Window w, Bool error,
1161 const char *stderr_msg,
1162 const char *protocol_msg)
1166 saver_preferences *p = &si->prefs;
1167 if (error || p->verbose_p)
1168 fprintf (stderr, "%s: %s\n", blurb(), stderr_msg);
1170 L = strlen(protocol_msg);
1171 proto = (char *) malloc (L + 2);
1172 proto[0] = (error ? '-' : '+');
1173 strcpy (proto+1, protocol_msg);
1176 XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8,
1177 PropModeReplace, (unsigned char *) proto, L);
1178 XSync (si->dpy, False);
1183 handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
1185 saver_preferences *p = &si->prefs;
1187 Window window = event->xclient.window;
1189 /* Preferences might affect our handling of client messages. */
1190 maybe_reload_init_file (si);
1192 if (event->xclient.message_type != XA_SCREENSAVER)
1195 str = XGetAtomName (si->dpy, event->xclient.message_type);
1196 fprintf (stderr, "%s: unrecognised ClientMessage type %s received\n",
1197 blurb(), (str ? str : "(null)"));
1198 if (str) XFree (str);
1201 if (event->xclient.format != 32)
1203 fprintf (stderr, "%s: ClientMessage of format %d received, not 32\n",
1204 blurb(), event->xclient.format);
1208 type = event->xclient.data.l[0];
1209 if (type == XA_ACTIVATE)
1213 clientmessage_response(si, window, False,
1214 "ACTIVATE ClientMessage received.",
1216 si->selection_mode = 0;
1217 si->demoing_p = False;
1219 if (si->throttled_p && p->verbose_p)
1220 fprintf (stderr, "%s: unthrottled.\n", blurb());
1221 si->throttled_p = False;
1223 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1225 XForceScreenSaver (si->dpy, ScreenSaverActive);
1233 clientmessage_response(si, window, True,
1234 "ClientMessage ACTIVATE received while already active.",
1237 else if (type == XA_DEACTIVATE)
1241 if (si->throttled_p && p->verbose_p)
1242 fprintf (stderr, "%s: unthrottled.\n", blurb());
1243 si->throttled_p = False;
1245 clientmessage_response(si, window, False,
1246 "DEACTIVATE ClientMessage received.",
1248 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1250 XForceScreenSaver (si->dpy, ScreenSaverReset);
1258 clientmessage_response(si, window, True,
1259 "ClientMessage DEACTIVATE received while inactive.",
1262 else if (type == XA_CYCLE)
1266 clientmessage_response(si, window, False,
1267 "CYCLE ClientMessage received.",
1269 si->selection_mode = 0; /* 0 means randomize when its time. */
1270 si->demoing_p = False;
1272 if (si->throttled_p && p->verbose_p)
1273 fprintf (stderr, "%s: unthrottled.\n", blurb());
1274 si->throttled_p = False;
1277 XtRemoveTimeOut (si->cycle_id);
1279 cycle_timer ((XtPointer) si, 0);
1282 clientmessage_response(si, window, True,
1283 "ClientMessage CYCLE received while inactive.",
1286 else if (type == XA_NEXT || type == XA_PREV)
1288 clientmessage_response(si, window, False,
1290 ? "NEXT ClientMessage received."
1291 : "PREV ClientMessage received."),
1293 si->selection_mode = (type == XA_NEXT ? -1 : -2);
1294 si->demoing_p = False;
1296 if (si->throttled_p && p->verbose_p)
1297 fprintf (stderr, "%s: unthrottled.\n", blurb());
1298 si->throttled_p = False;
1303 XtRemoveTimeOut (si->cycle_id);
1305 cycle_timer ((XtPointer) si, 0);
1310 else if (type == XA_SELECT)
1314 long which = event->xclient.data.l[1];
1316 sprintf (buf, "SELECT %ld ClientMessage received.", which);
1317 sprintf (buf2, "activating (%ld).", which);
1318 clientmessage_response (si, window, False, buf, buf2);
1320 if (which < 0) which = 0; /* 0 == "random" */
1321 si->selection_mode = which;
1322 si->demoing_p = False;
1324 if (si->throttled_p && p->verbose_p)
1325 fprintf (stderr, "%s: unthrottled.\n", blurb());
1326 si->throttled_p = False;
1331 XtRemoveTimeOut (si->cycle_id);
1333 cycle_timer ((XtPointer) si, 0);
1338 else if (type == XA_EXIT)
1340 /* Ignore EXIT message if the screen is locked. */
1341 if (until_idle_p || !si->locked_p)
1343 clientmessage_response (si, window, False,
1344 "EXIT ClientMessage received.",
1348 unblank_screen (si);
1349 kill_screenhack (si);
1350 XSync (si->dpy, False);
1352 saver_exit (si, 0, 0);
1355 clientmessage_response (si, window, True,
1356 "EXIT ClientMessage received while locked.",
1357 "screen is locked.");
1359 else if (type == XA_RESTART)
1361 /* The RESTART message works whether the screensaver is active or not,
1362 unless the screen is locked, in which case it doesn't work.
1364 if (until_idle_p || !si->locked_p)
1366 clientmessage_response (si, window, False,
1367 "RESTART ClientMessage received.",
1371 unblank_screen (si);
1372 kill_screenhack (si);
1373 XSync (si->dpy, False);
1378 if (real_stdout) fflush (real_stdout);
1379 if (real_stderr) fflush (real_stderr);
1380 /* make sure error message shows up before exit. */
1381 if (real_stderr && stderr != real_stderr)
1382 dup2 (fileno(real_stderr), fileno(stderr));
1384 restart_process (si);
1385 exit (1); /* shouldn't get here; but if restarting didn't work,
1386 make this command be the same as EXIT. */
1389 clientmessage_response (si, window, True,
1390 "RESTART ClientMessage received while locked.",
1391 "screen is locked.");
1393 else if (type == XA_DEMO)
1395 long arg = event->xclient.data.l[1];
1396 Bool demo_one_hack_p = (arg == 300);
1398 if (demo_one_hack_p)
1402 long which = event->xclient.data.l[2];
1405 sprintf (buf, "DEMO %ld ClientMessage received.", which);
1406 sprintf (buf2, "demoing (%ld).", which);
1407 clientmessage_response (si, window, False, buf, buf2);
1409 if (which < 0) which = 0; /* 0 == "random" */
1410 si->selection_mode = which;
1411 si->demoing_p = True;
1413 if (si->throttled_p && p->verbose_p)
1414 fprintf (stderr, "%s: unthrottled.\n", blurb());
1415 si->throttled_p = False;
1420 clientmessage_response (si, window, True,
1421 "DEMO ClientMessage received while active.",
1426 clientmessage_response (si, window, True,
1427 "obsolete form of DEMO ClientMessage.",
1428 "obsolete form of DEMO ClientMessage.");
1431 else if (type == XA_PREFS)
1433 clientmessage_response (si, window, True,
1434 "the PREFS client-message is obsolete.",
1435 "the PREFS client-message is obsolete.");
1437 else if (type == XA_LOCK)
1440 clientmessage_response (si, window, True,
1441 "not compiled with support for locking.",
1442 "locking not enabled.");
1443 #else /* !NO_LOCKING */
1444 if (si->locking_disabled_p)
1445 clientmessage_response (si, window, True,
1446 "LOCK ClientMessage received, but locking is disabled.",
1447 "locking not enabled.");
1448 else if (si->locked_p)
1449 clientmessage_response (si, window, True,
1450 "LOCK ClientMessage received while already locked.",
1455 char *response = (until_idle_p
1456 ? "activating and locking."
1458 sprintf (buf, "LOCK ClientMessage received; %s", response);
1459 clientmessage_response (si, window, False, buf, response);
1460 set_locked_p (si, True);
1461 si->selection_mode = 0;
1462 si->demoing_p = False;
1464 if (si->lock_id) /* we're doing it now, so lose the timeout */
1466 XtRemoveTimeOut (si->lock_id);
1472 if (si->using_mit_saver_extension ||
1473 si->using_sgi_saver_extension)
1475 XForceScreenSaver (si->dpy, ScreenSaverActive);
1484 #endif /* !NO_LOCKING */
1486 else if (type == XA_THROTTLE)
1488 if (si->throttled_p)
1489 clientmessage_response (si, window, True,
1490 "THROTTLE ClientMessage received, but "
1491 "already throttled.",
1492 "already throttled.");
1496 char *response = "throttled.";
1497 si->throttled_p = True;
1498 si->selection_mode = 0;
1499 si->demoing_p = False;
1500 sprintf (buf, "THROTTLE ClientMessage received; %s", response);
1501 clientmessage_response (si, window, False, buf, response);
1506 XtRemoveTimeOut (si->cycle_id);
1508 cycle_timer ((XtPointer) si, 0);
1512 else if (type == XA_UNTHROTTLE)
1514 if (! si->throttled_p)
1515 clientmessage_response (si, window, True,
1516 "UNTHROTTLE ClientMessage received, but "
1522 char *response = "unthrottled.";
1523 si->throttled_p = False;
1524 si->selection_mode = 0;
1525 si->demoing_p = False;
1526 sprintf (buf, "UNTHROTTLE ClientMessage received; %s", response);
1527 clientmessage_response (si, window, False, buf, response);
1532 XtRemoveTimeOut (si->cycle_id);
1534 cycle_timer ((XtPointer) si, 0);
1542 str = (type ? XGetAtomName(si->dpy, type) : 0);
1546 if (strlen (str) > 80)
1547 strcpy (str+70, "...");
1548 sprintf (buf, "unrecognised screensaver ClientMessage %s received.",
1555 "unrecognised screensaver ClientMessage 0x%x received.",
1556 (unsigned int) event->xclient.data.l[0]);
1559 clientmessage_response (si, window, True, buf, buf);
1565 /* Some random diagnostics printed in -verbose mode.
1569 analyze_display (saver_info *si)
1573 const char *name; const char *desc; Bool useful_p;
1576 { "SCREEN_SAVER", "SGI Screen-Saver",
1577 # ifdef HAVE_SGI_SAVER_EXTENSION
1582 }, { "SCREEN-SAVER", "SGI Screen-Saver",
1583 # ifdef HAVE_SGI_SAVER_EXTENSION
1588 }, { "MIT-SCREEN-SAVER", "MIT Screen-Saver",
1589 # ifdef HAVE_MIT_SAVER_EXTENSION
1594 }, { "XIDLE", "XIdle",
1595 # ifdef HAVE_XIDLE_EXTENSION
1600 }, { "SGI-VIDEO-CONTROL", "SGI Video-Control",
1601 # ifdef HAVE_SGI_VC_EXTENSION
1606 }, { "READDISPLAY", "SGI Read-Display",
1607 # ifdef HAVE_READ_DISPLAY_EXTENSION
1612 }, { "MIT-SHM", "Shared Memory",
1613 # ifdef HAVE_XSHM_EXTENSION
1618 }, { "DOUBLE-BUFFER", "Double-Buffering",
1619 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
1624 }, { "DPMS", "Power Management",
1625 # ifdef HAVE_DPMS_EXTENSION
1636 }, { "XFree86-VidModeExtension", "XF86 Video-Mode",
1637 # ifdef HAVE_XF86VMODE
1642 }, { "XINERAMA", "Xinerama",
1647 fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
1648 DisplayString(si->dpy));
1649 fprintf (stderr, "%s: vendor is %s, %d\n", blurb(),
1650 ServerVendor(si->dpy), VendorRelease(si->dpy));
1652 fprintf (stderr, "%s: useful extensions:\n", blurb());
1653 for (i = 0; i < countof(exts); i++)
1655 int op = 0, event = 0, error = 0;
1656 if (XQueryExtension (si->dpy, exts[i].name, &op, &event, &error))
1657 fprintf (stderr, "%s: %s%s\n", blurb(),
1659 (exts[i].useful_p ? "" :
1660 " \t<== unsupported at compile-time!"));
1663 for (i = 0; i < si->nscreens; i++)
1665 unsigned long colormapped_depths = 0;
1666 unsigned long non_mapped_depths = 0;
1667 XVisualInfo vi_in, *vi_out;
1670 vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
1671 if (!vi_out) continue;
1672 for (j = 0; j < out_count; j++)
1673 if (vi_out[j].class == PseudoColor)
1674 colormapped_depths |= (1 << vi_out[j].depth);
1676 non_mapped_depths |= (1 << vi_out[j].depth);
1677 XFree ((char *) vi_out);
1679 if (colormapped_depths)
1681 fprintf (stderr, "%s: screen %d colormapped depths:", blurb(), i);
1682 for (j = 0; j < 32; j++)
1683 if (colormapped_depths & (1 << j))
1684 fprintf (stderr, " %d", j);
1685 fprintf (stderr, "\n");
1687 if (non_mapped_depths)
1689 fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i);
1690 for (j = 0; j < 32; j++)
1691 if (non_mapped_depths & (1 << j))
1692 fprintf (stderr, " %d", j);
1693 fprintf (stderr, "\n");
1699 display_is_on_console_p (saver_info *si)
1701 Bool not_on_console = True;
1702 char *dpystr = DisplayString (si->dpy);
1703 char *tail = (char *) strchr (dpystr, ':');
1704 if (! tail || strncmp (tail, ":0", 2))
1705 not_on_console = True;
1708 char dpyname[255], localname[255];
1709 strncpy (dpyname, dpystr, tail-dpystr);
1710 dpyname [tail-dpystr] = 0;
1712 !strcmp(dpyname, "unix") ||
1713 !strcmp(dpyname, "localhost"))
1714 not_on_console = False;
1715 else if (gethostname (localname, sizeof (localname)))
1716 not_on_console = True; /* can't find hostname? */
1719 /* We have to call gethostbyname() on the result of gethostname()
1720 because the two aren't guarenteed to be the same name for the
1721 same host: on some losing systems, one is a FQDN and the other
1722 is not. Here in the wide wonderful world of Unix it's rocket
1723 science to obtain the local hostname in a portable fashion.
1725 And don't forget, gethostbyname() reuses the structure it
1726 returns, so we have to copy the fucker before calling it again.
1727 Thank you master, may I have another.
1729 struct hostent *h = gethostbyname (dpyname);
1731 not_on_console = True;
1736 strcpy (hn, h->h_name);
1737 l = gethostbyname (localname);
1738 not_on_console = (!l || !!(strcmp (l->h_name, hn)));
1742 return !not_on_console;