1 /* xscreensaver, Copyright (c) 1991-1995 Jamie Zawinski <jwz@netscape.com>
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
14 /* ========================================================================
15 * First we wait until the keyboard and mouse become idle for the specified
16 * amount of time. We do this in one of three different ways: periodically
17 * checking with the XIdle server extension; selecting key and mouse events
18 * on (nearly) all windows; or by waiting for the MIT-SCREEN-SAVER extension
19 * to send us a "you are idle" event.
21 * Then, we map a full screen black window (or, in the case of the
22 * MIT-SCREEN-SAVER extension, use the one it gave us.)
24 * We place a __SWM_VROOT property on this window, so that newly-started
25 * clients will think that this window is a "virtual root" window.
27 * If there is an existing "virtual root" window (one that already had
28 * an __SWM_VROOT property) then we remove that property from that window.
29 * Otherwise, clients would see that window (the real virtual root) instead
30 * of ours (the impostor.)
32 * Then we pick a random program to run, and start it. Two assumptions
33 * are made about this program: that it has been specified with whatever
34 * command-line options are necessary to make it run on the root window;
35 * and that it has been compiled with vroot.h, so that it is able to find
36 * the root window when a virtual-root window manager (or this program) is
39 * Then, we wait for keyboard or mouse events to be generated on the window.
40 * When they are, we kill the inferior process, unmap the window, and restore
41 * the __SWM_VROOT property to the real virtual root window if there was one.
43 * While we are waiting, we also set up timers so that, after a certain
44 * amount of time has passed, we can start a different screenhack. We do
45 * this by killing the running child process with SIGTERM, and then starting
46 * a new one in the same way.
48 * If there was a real virtual root, meaning that we removed the __SWM_VROOT
49 * property from it, meaning we must (absolutely must) restore it before we
50 * exit, then we set up signal handlers for most signals (SIGINT, SIGTERM,
51 * etc.) that do this. Most Xlib and Xt routines are not reentrant, so it
52 * is not generally safe to call them from signal handlers; however, this
53 * program spends most of its time waiting, so the window of opportunity
54 * when code could be called reentrantly is fairly small; and also, the worst
55 * that could happen is that the call would fail. If we've gotten one of
56 * these signals, then we're on our way out anyway. If we didn't restore the
57 * __SWM_VROOT property, that would be very bad, so it's worth a shot. Note
58 * that this means that, if you're using a virtual-root window manager, you
59 * can really fuck up the world by killing this process with "kill -9".
61 * This program accepts ClientMessages of type SCREENSAVER; these messages
62 * may contain the atom ACTIVATE or DEACTIVATE, meaning to turn the
63 * screensaver on or off now, regardless of the idleness of the user,
64 * and a few other things. The included "xscreensaver_command" program
65 * sends these messsages.
67 * If we don't have the XIdle or MIT-SCREENSAVER extensions, then we do the
68 * XAutoLock trick: notice every window that gets created, and wait 30
69 * seconds or so until its creating process has settled down, and then
70 * select KeyPress events on those windows which already select for
71 * KeyPress events. It's important that we not select KeyPress on windows
72 * which don't select them, because that would interfere with event
73 * propagation. This will break if any program changes its event mask to
74 * contain KeyRelease or PointerMotion more than 30 seconds after creating
75 * the window, but that's probably pretty rare.
77 * The reason that we can't select KeyPresses on windows that don't have
78 * them already is that, when dispatching a KeyPress event, X finds the
79 * lowest (leafmost) window in the hierarchy on which *any* client selects
80 * for KeyPress, and sends the event to that window. This means that if a
81 * client had a window with subwindows, and expected to receive KeyPress
82 * events on the parent window instead of the subwindows, then that client
83 * would malfunction if some other client selected KeyPress events on the
84 * subwindows. It is an incredible misdesign that one client can make
85 * another client malfunction in this way.
87 * To detect mouse motion, we periodically wake up and poll the mouse
88 * position and button/modifier state, and notice when something has
89 * changed. We make this check every five seconds by default, and since the
90 * screensaver timeout has a granularity of one minute, this makes the
91 * chance of a false positive very small. We could detect mouse motion in
92 * the same way as keyboard activity, but that would suffer from the same
93 * "client changing event mask" problem that the KeyPress events hack does.
94 * I think polling is more reliable.
96 * None of this crap happens if we're using one of the extensions, so install
97 * one of them if the description above sounds just too flaky to live. It
98 * is, but those are your choices.
100 * A third idle-detection option could be implement (but is not): when
101 * running on the console display ($DISPLAY is `localhost`:0) and we're on a
102 * machine where /dev/tty and /dev/mouse have reasonable last-modification
103 * times, we could just stat those. But the incremental benefit of
104 * implementing this is really small, so forget I said anything.
107 * - Have a second terminal handy.
108 * - Be careful where you set your breakpoints, you don't want this to
109 * stop under the debugger with the keyboard grabbed or the blackout
111 * - you probably can't set breakpoints in functions that are called on
112 * the other side of a call to fork() -- if your clients are dying
113 * with signal 5, Trace/BPT Trap, you're losing in this way.
114 * - If you aren't using XIdle, don't leave this stopped under the
115 * debugger for very long, or the X input buffer will get huge because
116 * of the keypress events it's selecting for. This can make your X
117 * server wedge with "no more input buffers."
119 * ======================================================================== */
127 #include <X11/Xlib.h>
128 #include <X11/Xatom.h>
129 #include <X11/Intrinsic.h>
131 #include <X11/Xmu/Error.h>
133 #ifdef HAVE_XIDLE_EXTENSION
134 #include <X11/extensions/xidle.h>
135 #endif /* HAVE_XIDLE_EXTENSION */
137 #ifdef HAVE_SAVER_EXTENSION
138 #include <X11/extensions/scrnsaver.h>
139 #endif /* HAVE_SAVER_EXTENSION */
141 #include "yarandom.h"
142 #include "xscreensaver.h"
144 extern char *get_string_resource P((char *, char *));
145 extern Bool get_boolean_resource P((char *, char *));
146 extern int get_integer_resource P((char *, char *));
147 extern unsigned int get_minutes_resource P((char *, char *));
148 extern unsigned int get_seconds_resource P((char *, char *));
150 extern Visual *get_visual_resource P((Display *, char *, char *));
151 extern int get_visual_depth P((Display *, Visual *));
153 extern void notice_events_timer P((XtPointer closure, XtIntervalId *timer));
154 extern void cycle_timer P((void *junk1, XtPointer junk2));
155 extern void activate_lock_timer P((void *junk1, XtPointer junk2));
156 extern void sleep_until_idle P((Bool until_idle_p));
158 extern void ensure_no_screensaver_running P((void));
159 extern void initialize_screensaver_window P((void));
160 extern void disable_builtin_screensaver P((void));
162 extern void hack_environment P((void));
163 extern void grab_keyboard_and_mouse P((void));
164 extern void ungrab_keyboard_and_mouse P((void));
166 extern void save_argv P((int argc, char **argv));
168 extern void initialize_stderr P((void));
170 char *screensaver_version;
182 Widget toplevel_shell;
189 extern Time passwd_timeout;
191 extern Time pointer_timeout;
192 extern Time notice_events_timeout;
193 extern XtIntervalId lock_id, cycle_id;
195 Bool use_xidle_extension;
196 Bool use_saver_extension;
198 Bool lock_p, locked_p;
200 extern char **screenhacks;
201 extern int screenhacks_count;
203 extern int nice_inferior;
204 extern Window screensaver_window;
205 extern Cursor cursor;
206 extern Colormap cmap, cmap2;
207 extern Bool fade_p, unfade_p;
208 extern int fade_seconds, fade_ticks;
209 extern Bool install_cmap_p;
210 extern Bool locking_disabled_p;
211 extern char *nolock_reason;
212 extern Bool demo_mode_p;
213 extern Bool dbox_up_p;
214 extern int next_mode_p;
216 #ifdef HAVE_SAVER_EXTENSION
217 int saver_ext_event_number = 0;
218 int saver_ext_error_number = 0;
219 #endif /* HAVE_SAVER_EXTENSION */
221 static time_t initial_delay;
223 extern Atom XA_VROOT, XA_XSETROOT_ID;
224 extern Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
226 static Atom XA_SCREENSAVER;
227 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
228 static Atom XA_EXIT, XA_RESTART, XA_DEMO, XA_LOCK;
230 #ifdef NO_MOTIF /* kludge */
231 Bool demo_mode_p = 0;
237 # define demo_mode() abort()
239 extern void demo_mode P((void));
242 static XrmOptionDescRec options [] = {
243 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
244 { "-cycle", ".cycle", XrmoptionSepArg, 0 },
245 { "-idelay", ".initialDelay", XrmoptionSepArg, 0 },
246 { "-nice", ".nice", XrmoptionSepArg, 0 },
247 { "-visual", ".visualID", XrmoptionSepArg, 0 },
248 { "-lock-timeout", ".lockTimeout", XrmoptionSepArg, 0 },
249 { "-install", ".installColormap", XrmoptionNoArg, "on" },
250 { "-no-install", ".installColormap", XrmoptionNoArg, "off" },
251 { "-verbose", ".verbose", XrmoptionNoArg, "on" },
252 { "-silent", ".verbose", XrmoptionNoArg, "off" },
253 { "-xidle-extension", ".xidleExtension", XrmoptionNoArg, "on" },
254 { "-no-xidle-extension", ".xidleExtension", XrmoptionNoArg, "off" },
255 { "-ss-extension", ".saverExtension", XrmoptionNoArg, "on" },
256 { "-no-ss-extension", ".saverExtension", XrmoptionNoArg, "off" },
257 { "-lock", ".lock", XrmoptionNoArg, "on" },
258 { "-no-lock", ".lock", XrmoptionNoArg, "off" }
261 static char *defaults[] = {
262 #include "XScreenSaver.ad.h"
270 xscreensaver %s, copyright (c) 1991-1995 by Jamie Zawinski <jwz@netscape.com>.\n\
271 The standard Xt command-line options are accepted; other options include:\n\
273 -timeout <minutes> When the screensaver should activate.\n\
274 -cycle <minutes> How long to let each hack run.\n\
275 -idelay <seconds> How long to sleep before startup.\n\
276 -visual <id-or-class> Which X visual to run on.\n\
277 -demo Enter interactive demo mode on startup.\n\
278 -install Install a private colormap.\n\
279 -no-install Don't.\n\
282 -xidle-extension Use the R5 XIdle server extension.\n\
283 -no-xidle-extension Don't.\n\
284 -ss-extension Use the R6 MIT-SCREEN-SAVER server extension.\n\
285 -no-ss-extension Don't.\n\
286 -lock Require a password before deactivating.\n\
288 -lock-timeout <minutes> Grace period before locking; default 0.\n\
289 -help This message.\n\
291 Use the `xscreensaver-command' program to control a running screensaver.\n\
293 The *programs, *colorPrograms, and *monoPrograms resources control which\n\
294 graphics demos will be launched by the screensaver. See the man page for\n\
296 screensaver_version);
299 printf ("Support for locking was not enabled at compile-time.\n");
302 printf ("Support for demo mode was not enabled at compile-time.\n");
304 #if !defined(HAVE_XIDLE_EXTENSION) && !defined(HAVE_SAVER_EXTENSION)
305 printf ("Support for the XIDLE and MIT-SCREEN-SAVER server extensions\
306 was not\nenabled at compile-time.\n");
307 #endif /* !HAVE_XIDLE_EXTENSION && !HAVE_SAVER_EXTENSION */
315 get_screenhacks P((void))
318 int i, hacks_size = 10;
320 data[0] = get_string_resource ("programs", "Programs");
321 data[1] = ((CellsOfScreen (screen) <= 2)
322 ? get_string_resource ("monoPrograms", "MonoPrograms")
323 : get_string_resource ("colorPrograms", "ColorPrograms"));
325 if (! data[0]) data[0] = data[1], data[1] = 0;
327 screenhacks = (char **) malloc (sizeof (char *) * hacks_size);
328 screenhacks_count = 0;
330 for (i = 0; data[i]; i++)
334 int size = strlen (d);
338 if (d[j] == ' ' || d[j] == '\t' || d[j] == '\n' || d[j] == 0)
343 if (hacks_size <= screenhacks_count)
344 screenhacks = (char **) realloc (screenhacks,
345 (hacks_size = hacks_size * 2) *
347 screenhacks [screenhacks_count++] = d + j;
348 while (d[j] != 0 && d[j] != '\n')
351 while (j > start && (d[j-1] == ' ' || d[j-1] == '\t'))
358 /* shrink all whitespace to one space, for the benefit of the "demo"
359 mode display. We only do this when we can easily tell that the
360 whitespace is not significant (no shell metachars).
362 for (i = 0; i < screenhacks_count; i++)
364 char *s = screenhacks [i];
368 for (j = 0; j < L; j++)
372 case '\'': case '"': case '`': case '\\':
378 for (s2 = s+j+1; *s2 == ' ' || *s2 == '\t'; s2++)
381 for (s2 = s + j + 1; *s2; s2++)
390 if (screenhacks_count)
392 /* Shrink down the screenhacks array to be only as big as it needs to.
393 This doesn't really matter at all. */
394 screenhacks = (char **)
395 realloc (screenhacks, ((screenhacks_count + 1) * sizeof(char *)));
396 screenhacks [screenhacks_count] = 0;
407 get_resources P((void))
409 /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
410 visual = get_visual_resource (dpy, "visualID", "VisualID");
411 timeout = 1000 * get_minutes_resource ("timeout", "Time");
412 cycle = 1000 * get_minutes_resource ("cycle", "Time");
413 lock_timeout = 1000 * get_minutes_resource ("lockTimeout", "Time");
414 nice_inferior = get_integer_resource ("nice", "Nice");
415 verbose_p = get_boolean_resource ("verbose", "Boolean");
416 lock_p = get_boolean_resource ("lock", "Boolean");
417 install_cmap_p = get_boolean_resource ("installColormap", "Boolean");
418 fade_p = get_boolean_resource ("fade", "Boolean");
419 unfade_p = get_boolean_resource ("unfade", "Boolean");
420 fade_seconds = get_seconds_resource ("fadeSeconds", "Time");
421 fade_ticks = get_integer_resource ("fadeTicks", "Integer");
422 shell = get_string_resource ("bourneShell", "BourneShell");
423 initial_delay = get_seconds_resource ("initialDelay", "Time");
424 pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time");
425 notice_events_timeout = 1000 * get_seconds_resource ("windowCreationTimeout",
428 passwd_timeout = 1000 * get_seconds_resource ("passwdTimeout", "Time");
429 if (passwd_timeout == 0) passwd_timeout = 30000;
431 if (timeout < 10000) timeout = 10000;
432 if (cycle != 0 && cycle < 2000) cycle = 2000;
433 if (pointer_timeout == 0) pointer_timeout = 5000;
434 if (notice_events_timeout == 0) notice_events_timeout = 10000;
435 if (fade_seconds == 0 || fade_ticks == 0) fade_p = False;
436 if (! fade_p) unfade_p = False;
438 visual_depth = get_visual_depth (dpy, visual);
440 if (visual_depth <= 1 || CellsOfScreen (screen) <= 2)
441 install_cmap_p = False;
444 locking_disabled_p = True;
445 nolock_reason = "not compiled with locking support";
449 fprintf (stderr, "%s: %snot compiled with support for locking.\n",
450 progname, (verbose_p ? "## " : ""));
452 #else /* ! NO_LOCKING */
453 if (lock_p && locking_disabled_p)
455 fprintf (stderr, "%s: %slocking is disabled (%s).\n", progname,
456 (verbose_p ? "## " : ""), nolock_reason);
459 #endif /* ! NO_LOCKING */
461 /* don't set use_xidle_extension unless it is explicitly specified */
462 if (get_string_resource ("xidleExtension", "Boolean"))
463 use_xidle_extension = get_boolean_resource ("xidleExtension", "Boolean");
465 #ifdef HAVE_XIDLE_EXTENSION /* pick a default */
466 use_xidle_extension = True;
467 #else /* !HAVE_XIDLE_EXTENSION */
468 use_xidle_extension = False;
469 #endif /* !HAVE_XIDLE_EXTENSION */
471 /* don't set use_saver_extension unless it is explicitly specified */
472 if (get_string_resource ("saverExtension", "Boolean"))
473 use_saver_extension = get_boolean_resource ("saverExtension", "Boolean");
475 #ifdef HAVE_SAVER_EXTENSION /* pick a default */
476 use_saver_extension = True;
477 #else /* !HAVE_SAVER_EXTENSION */
478 use_saver_extension = False;
479 #endif /* !HAVE_SAVER_EXTENSION */
488 long now = time ((time_t *) 0);
489 char *str = (char *) ctime (&now);
490 char *nl = (char *) strchr (str, '\n');
491 if (nl) *nl = 0; /* take off that dang newline */
497 # define hack_uid_warn()
498 #else /* !NO_SETUID */
499 extern void hack_uid P((void));
500 extern void hack_uid_warn P((void));
501 #endif /* NO_SETUID */
505 extern Bool unlock_p P((Widget));
506 extern Bool lock_init P((void));
509 static void initialize P((int argc, char **argv));
510 static void main_loop P((void));
517 initialize (argc, argv);
523 saver_ehandler (dpy, error)
527 fprintf (real_stderr, "\nX error in %s:\n", progname);
528 if (XmuPrintDefaultErrorMessage (dpy, error, real_stderr))
531 fprintf (real_stderr, " (nonfatal.)\n");
537 initialize_connection (int argc, char **argv)
539 initialize_connection (argc, argv)
544 toplevel_shell = XtAppInitialize (&app, progclass,
545 options, XtNumber (options),
546 &argc, argv, defaults, 0, 0);
548 dpy = XtDisplay (toplevel_shell);
549 screen = XtScreen (toplevel_shell);
550 db = XtDatabase (dpy);
551 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
553 if (argc == 2 && !strcmp (argv[1], "-help"))
557 fprintf (stderr, "%s: unknown option %s\n", progname, argv [1]);
563 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
564 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
565 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION", False);
566 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
567 XA_XSETROOT_ID = XInternAtom (dpy, "_XSETROOT_ID", False);
568 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
569 XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
570 XA_RESTART = XInternAtom (dpy, "RESTART", False);
571 XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
572 XA_NEXT = XInternAtom (dpy, "NEXT", False);
573 XA_PREV = XInternAtom (dpy, "PREV", False);
574 XA_EXIT = XInternAtom (dpy, "EXIT", False);
575 XA_DEMO = XInternAtom (dpy, "DEMO", False);
576 XA_LOCK = XInternAtom (dpy, "LOCK", False);
579 #ifdef HAVE_SAVER_EXTENSION
582 ignore_all_errors_ehandler (dpy, error)
590 init_saver_extension ()
594 Window root = RootWindowOfScreen (screen);
595 XScreenSaverInfo *info;
596 Pixmap blank_pix = XCreatePixmap (dpy, root, 1, 1, 1);
598 /* Kill off the old MIT-SCREEN-SAVER client if there is one.
599 This tends to generate X errors, though (possibly due to a bug
600 in the server extension itself?) so just ignore errors here. */
601 if (XScreenSaverGetRegistered (dpy, XScreenNumberOfScreen (screen),
602 &kill_id, &kill_type)
603 && kill_id != blank_pix)
605 int (*old_handler) ();
606 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
607 XKillClient (dpy, kill_id);
609 XSetErrorHandler (old_handler);
612 XScreenSaverSelectInput (dpy, root, ScreenSaverNotifyMask);
614 XScreenSaverRegister (dpy, XScreenNumberOfScreen (screen),
615 (XID) blank_pix, XA_PIXMAP);
616 info = XScreenSaverAllocInfo ();
619 /* #### I think this is noticing that the saver is on, and replacing it
620 without turning it off first. */
621 saver = info->window;
622 if (info->state == ScreenSaverOn)
624 if (info->kind != ScreenSaverExternal)
626 XResetScreenSaver (display);
627 XActivateScreenSaver (display);
633 #endif /* HAVE_SAVER_EXTENSION */
636 extern void init_sigchld P((void));
639 initialize (argc, argv)
643 Bool initial_demo_mode_p = False;
644 screensaver_version = (char *) malloc (5);
645 memcpy (screensaver_version, screensaver_id + 17, 4);
646 screensaver_version [4] = 0;
647 progname = argv[0]; /* reset later; this is for the benefit of lock_init() */
650 locking_disabled_p = True;
651 nolock_reason = "not compiled with locking support";
653 locking_disabled_p = False;
656 set_auth_parameters(argc, argv);
659 if (! lock_init ()) /* before hack_uid() for proper permissions */
661 locking_disabled_p = True;
662 nolock_reason = "error getting password";
667 progclass = "XScreenSaver";
669 /* remove -demo switch before saving argv */
672 for (i = 1; i < argc; i++)
673 while (!strcmp ("-demo", argv [i]))
676 initial_demo_mode_p = True;
677 for (j = i; j < argc; j++)
678 argv [j] = argv [j+1];
681 if (argc <= i) break;
684 save_argv (argc, argv);
685 initialize_connection (argc, argv);
686 ensure_no_screensaver_running ();
690 %s %s, copyright (c) 1991-1995 by Jamie Zawinski <jwz@netscape.com>.\n\
691 pid = %d.\n", progname, screensaver_version, getpid ());
692 ensure_no_screensaver_running ();
694 demo_mode_p = initial_demo_mode_p;
695 screensaver_window = 0;
697 initialize_screensaver_window ();
698 srandom ((int) time ((time_t *) 0));
703 if (use_saver_extension)
705 #ifdef HAVE_SAVER_EXTENSION
706 if (! XScreenSaverQueryExtension (dpy,
707 &saver_ext_event_number,
708 &saver_ext_error_number))
711 "%s: %sdisplay %s does not support the MIT-SCREEN-SAVER extension.\n",
712 progname, (verbose_p ? "## " : ""), DisplayString (dpy));
713 use_saver_extension = False;
715 else if (use_xidle_extension)
718 "%s: %sMIT-SCREEN-SAVER extension used instead of XIDLE extension.\n",
719 progname, (verbose_p ? "## " : ""));
720 use_xidle_extension = False;
722 #else /* !HAVE_SAVER_EXTENSION */
724 "%s: %snot compiled with support for the MIT-SCREEN-SAVER extension.\n",
725 progname, (verbose_p ? "## " : ""));
726 use_saver_extension = False;
727 #endif /* !HAVE_SAVER_EXTENSION */
730 if (use_xidle_extension)
732 #ifdef HAVE_XIDLE_EXTENSION
733 int first_event, first_error;
734 if (! XidleQueryExtension (dpy, &first_event, &first_error))
737 "%s: %sdisplay %s does not support the XIdle extension.\n",
738 progname, (verbose_p ? "## " : ""), DisplayString (dpy));
739 use_xidle_extension = False;
741 #else /* !HAVE_XIDLE_EXTENSION */
742 fprintf (stderr, "%s: %snot compiled with support for XIdle.\n",
743 progname, (verbose_p ? "## " : ""));
744 use_xidle_extension = False;
745 #endif /* !HAVE_XIDLE_EXTENSION */
750 disable_builtin_screensaver ();
752 #ifdef HAVE_SAVER_EXTENSION
753 if (use_saver_extension)
754 init_saver_extension ();
755 #endif /* HAVE_SAVER_EXTENSION */
757 if (verbose_p && use_saver_extension)
758 fprintf (stderr, "%s: using MIT-SCREEN-SAVER server extension.\n",
760 if (verbose_p && use_xidle_extension)
761 fprintf (stderr, "%s: using XIdle server extension.\n",
764 initialize_stderr ();
765 XSetErrorHandler (saver_ehandler);
767 if (initial_demo_mode_p)
768 /* If the user wants demo mode, don't wait around before doing it. */
771 if (!use_xidle_extension && !use_saver_extension)
777 printf ("%s: waiting for %d second%s...", progname,
778 (int) initial_delay, (initial_delay == 1 ? "" : "s"));
781 sleep (initial_delay);
787 printf ("%s: selecting events on extant windows...", progname);
790 notice_events_timer ((XtPointer)
791 RootWindowOfScreen (XtScreen (toplevel_shell)),
799 extern void suspend_screenhack P((Bool suspend_p));
807 sleep_until_idle (True);
814 printf ("%s: user is idle; waking up at %s.\n", progname,
817 spawn_screenhack (True);
819 cycle_id = XtAppAddTimeOut (app, cycle,
820 (XtTimerCallbackProc)cycle_timer, 0);
823 if (lock_p && lock_timeout == 0)
825 if (lock_p && !locked_p)
826 /* locked_p might be true already because of ClientMessage */
827 lock_id = XtAppAddTimeOut (app,lock_timeout,
828 (XtTimerCallbackProc)
829 activate_lock_timer,0);
834 sleep_until_idle (False); /* until not idle */
840 if (locking_disabled_p) abort ();
843 /* We used to ungrab the keyboard here, before calling unlock_p()
844 to pop up the dialog box. This left the keyboard ungrabbed
845 for a small window, during an insecure state. Bennett Todd
846 was seeing the bahavior that, when the load was high, he could
847 actually get characters through to a shell under the saver
848 window (he accidentally typed his password there...)
850 So the ungrab has been moved down into pop_passwd_dialog()
851 just after the server is grabbed, closing this window
854 /* ungrab_keyboard_and_mouse (); */
856 suspend_screenhack (True);
857 XUndefineCursor (dpy, screensaver_window);
859 printf ("%s: prompting for password.\n", progname);
860 val = unlock_p (toplevel_shell);
861 if (verbose_p && val == False)
862 printf ("%s: password incorrect!\n", progname);
864 XDefineCursor (dpy, screensaver_window, cursor);
865 suspend_screenhack (False);
867 /* I think this grab is now redundant, but it shouldn't hurt. */
868 grab_keyboard_and_mouse ();
879 XtRemoveTimeOut (cycle_id);
885 XtRemoveTimeOut (lock_id);
890 printf ("%s: user is active; going to sleep at %s.\n", progname,
899 handle_clientmessage (event, until_idle_p)
904 if (event->xclient.message_type != XA_SCREENSAVER)
907 str = XGetAtomName (dpy, event->xclient.message_type);
908 fprintf (stderr, "%s: %sunrecognised ClientMessage type %s received\n",
909 progname, (verbose_p ? "## " : ""),
910 (str ? str : "(null)"));
911 if (str) XFree (str);
914 if (event->xclient.format != 32)
916 fprintf (stderr, "%s: %sClientMessage of format %d received, not 32\n",
917 progname, (verbose_p ? "## " : ""), event->xclient.format);
920 type = event->xclient.data.l[0];
921 if (type == XA_ACTIVATE)
926 printf ("%s: ACTIVATE ClientMessage received.\n", progname);
927 if (use_saver_extension)
929 XForceScreenSaver (dpy, ScreenSaverActive);
938 "%s: %sClientMessage ACTIVATE received while already active.\n",
939 progname, (verbose_p ? "## " : ""));
941 else if (type == XA_DEACTIVATE)
946 printf ("%s: DEACTIVATE ClientMessage received.\n", progname);
947 if (use_saver_extension)
949 XForceScreenSaver (dpy, ScreenSaverReset);
958 "%s: %sClientMessage DEACTIVATE received while inactive.\n",
959 progname, (verbose_p ? "## " : ""));
961 else if (type == XA_CYCLE)
966 printf ("%s: CYCLE ClientMessage received.\n", progname);
968 XtRemoveTimeOut (cycle_id);
974 "%s: %sClientMessage CYCLE received while inactive.\n",
975 progname, (verbose_p ? "## " : ""));
977 else if (type == XA_NEXT || type == XA_PREV)
980 printf ("%s: %s ClientMessage received.\n", progname,
981 (type == XA_NEXT ? "NEXT" : "PREV"));
982 next_mode_p = 1 + (type == XA_PREV);
987 XtRemoveTimeOut (cycle_id);
994 else if (type == XA_EXIT)
996 /* Ignore EXIT message if the screen is locked. */
997 if (until_idle_p || !locked_p)
1000 printf ("%s: EXIT ClientMessage received.\n", progname);
1010 fprintf (stderr, "%s: %sEXIT ClientMessage received while locked.\n",
1011 progname, (verbose_p ? "## " : ""));
1013 else if (type == XA_RESTART)
1015 /* The RESTART message works whether the screensaver is active or not,
1016 unless the screen is locked, in which case it doesn't work.
1018 if (until_idle_p || !locked_p)
1021 printf ("%s: RESTART ClientMessage received.\n", progname);
1031 fprintf(stderr, "%s: %sRESTART ClientMessage received while locked.\n",
1032 progname, (verbose_p ? "## " : ""));
1034 else if (type == XA_DEMO)
1038 "%s: %snot compiled with support for DEMO mode\n",
1039 progname, (verbose_p ? "## " : ""));
1044 printf ("%s: DEMO ClientMessage received.\n", progname);
1049 "%s: %sDEMO ClientMessage received while active.\n",
1050 progname, (verbose_p ? "## " : ""));
1053 else if (type == XA_LOCK)
1056 fprintf (stderr, "%s: %snot compiled with support for LOCK mode\n",
1057 progname, (verbose_p ? "## " : ""));
1059 if (locking_disabled_p)
1061 "%s: %sLOCK ClientMessage received, but locking is disabled.\n",
1062 progname, (verbose_p ? "## " : ""));
1065 "%s: %sLOCK ClientMessage received while already locked.\n",
1066 progname, (verbose_p ? "## " : ""));
1071 printf ("%s: LOCK ClientMessage received;%s locking.\n",
1072 progname, until_idle_p ? " activating and" : "");
1074 if (lock_id) /* we're doing it now, so lose the timeout */
1076 XtRemoveTimeOut (lock_id);
1082 if (use_saver_extension)
1084 XForceScreenSaver (dpy, ScreenSaverActive);
1098 str = (type ? XGetAtomName(dpy, type) : 0);
1101 "%s: %sunrecognised screensaver ClientMessage %s received\n",
1102 progname, (verbose_p ? "## " : ""), str);
1105 "%s: %sunrecognised screensaver ClientMessage 0x%x received\n",
1106 progname, (verbose_p ? "## " : ""),
1107 (unsigned int) event->xclient.data.l[0]);
1108 if (str) XFree (str);