1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2014 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
18 # include <unixlib.h> /* for getpid() */
19 # include "vms-gtod.h" /* for gettimeofday() */
23 # include <pwd.h> /* for getpwuid() */
29 # include <sys/utsname.h> /* for uname() */
30 #endif /* HAVE_UNAME */
33 /* #include <X11/Xproto.h> / * for CARD32 */
35 #include <X11/Xutil.h> /* for XSetClassHint() */
36 #include <X11/Xatom.h>
37 #include <X11/Xos.h> /* for time() */
38 #include <signal.h> /* for the signal names */
42 /* You might think that to store an array of 32-bit quantities onto a
43 server-side property, you would pass an array of 32-bit data quantities
44 into XChangeProperty(). You would be wrong. You have to use an array
45 of longs, even if long is 64 bits (using 32 of each 64.)
49 #ifdef HAVE_MIT_SAVER_EXTENSION
50 # include <X11/extensions/scrnsaver.h>
51 #endif /* HAVE_MIT_SAVER_EXTENSION */
54 # include <X11/extensions/xf86vmode.h>
55 #endif /* HAVE_XF86VMODE */
58 # include <X11/extensions/Xinerama.h>
59 #endif /* HAVE_XINERAMA */
61 /* This file doesn't need the Xt headers, so stub these types out... */
63 #define XtAppContext void*
64 #define XrmDatabase void*
65 #define XtIntervalId void*
66 #define XtPointer void*
69 #include "xscreensaver.h"
74 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
76 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
77 Atom XA_NET_WM_USER_TIME;
78 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
79 Atom XA_SCREENSAVER_STATUS;
81 extern saver_info *global_si_kludge; /* I hate C so much... */
83 static void maybe_transfer_grabs (saver_screen_info *ssi,
84 Window old_w, Window new_w, int new_screen);
86 #define ALL_POINTER_EVENTS \
87 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
88 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
89 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
90 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
94 grab_string(int status)
98 case GrabSuccess: return "GrabSuccess";
99 case AlreadyGrabbed: return "AlreadyGrabbed";
100 case GrabInvalidTime: return "GrabInvalidTime";
101 case GrabNotViewable: return "GrabNotViewable";
102 case GrabFrozen: return "GrabFrozen";
105 static char foo[255];
106 sprintf(foo, "unknown status: %d", status);
113 grab_kbd(saver_info *si, Window w, int screen_no)
115 saver_preferences *p = &si->prefs;
116 int status = XGrabKeyboard (si->dpy, w, True,
117 /* I don't really understand Sync vs Async,
118 but these seem to work... */
119 GrabModeSync, GrabModeAsync,
121 if (status == GrabSuccess)
123 si->keyboard_grab_window = w;
124 si->keyboard_grab_screen = screen_no;
128 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
129 blurb(), screen_no, (unsigned long) w, grab_string(status));
135 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
137 saver_preferences *p = &si->prefs;
138 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
139 GrabModeAsync, GrabModeAsync, w,
140 cursor, CurrentTime);
141 if (status == GrabSuccess)
143 si->mouse_grab_window = w;
144 si->mouse_grab_screen = screen_no;
148 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
149 blurb(), screen_no, (unsigned long) w, grab_string(status));
155 ungrab_kbd(saver_info *si)
157 saver_preferences *p = &si->prefs;
158 XUngrabKeyboard(si->dpy, CurrentTime);
160 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
161 blurb(), si->keyboard_grab_screen,
162 (unsigned long) si->keyboard_grab_window);
163 si->keyboard_grab_window = 0;
168 ungrab_mouse(saver_info *si)
170 saver_preferences *p = &si->prefs;
171 XUngrabPointer(si->dpy, CurrentTime);
173 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
174 blurb(), si->mouse_grab_screen,
175 (unsigned long) si->mouse_grab_window);
176 si->mouse_grab_window = 0;
180 /* Apparently there is this program called "rdesktop" which is a windows
181 terminal server client for Unix. It would seem that this program holds
182 the keyboard GRABBED the whole time it has focus! This is, of course,
183 completely idiotic: the whole point of grabbing is to get events when
184 you do *not* have focus, so grabbing *only when* you have focus is
185 completely redundant -- unless your goal is to make xscreensaver not
186 able to ever lock the screen when your program is running.
188 If xscreensaver blanks while rdesktop still has a keyboard grab, then
189 when we try to prompt for the password, we won't get the characters:
190 they'll be typed into rdesktop.
192 Perhaps rdesktop will release its keyboard grab if it loses focus?
193 What the hell, let's give it a try. If we fail to grab the keyboard
194 four times in a row, we forcibly set focus to "None" and try four
195 more times. (We don't touch focus unless we're already having a hard
196 time getting a grab.)
199 nuke_focus (saver_info *si, int screen_no)
201 saver_preferences *p = &si->prefs;
205 XGetInputFocus (si->dpy, &focus, &rev);
211 if (focus == PointerRoot) strcpy (w, "PointerRoot");
212 else if (focus == None) strcpy (w, "None");
213 else sprintf (w, "0x%lx", (unsigned long) focus);
215 if (rev == RevertToParent) strcpy (r, "RevertToParent");
216 else if (rev == RevertToPointerRoot) strcpy (r, "RevertToPointerRoot");
217 else if (rev == RevertToNone) strcpy (r, "RevertToNone");
218 else sprintf (r, "0x%x", rev);
220 fprintf (stderr, "%s: %d: removing focus from %s / %s.\n",
221 blurb(), screen_no, w, r);
224 XSetInputFocus (si->dpy, None, RevertToNone, CurrentTime);
225 XSync (si->dpy, False);
230 ungrab_keyboard_and_mouse (saver_info *si)
238 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
241 Status mstatus = 0, kstatus = 0;
244 Bool focus_fuckus = False;
248 for (i = 0; i < retries; i++)
250 XSync (si->dpy, False);
251 kstatus = grab_kbd (si, window, screen_no);
252 if (kstatus == GrabSuccess)
255 /* else, wait a second and try to grab again. */
259 if (kstatus != GrabSuccess)
261 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
262 blurb(), grab_string(kstatus));
267 nuke_focus (si, screen_no);
272 for (i = 0; i < retries; i++)
274 XSync (si->dpy, False);
275 mstatus = grab_mouse (si, window, cursor, screen_no);
276 if (mstatus == GrabSuccess)
279 /* else, wait a second and try to grab again. */
283 if (mstatus != GrabSuccess)
284 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
285 blurb(), grab_string(mstatus));
288 /* When should we allow blanking to proceed? The current theory
289 is that a keyboard grab is mandatory; a mouse grab is optional.
291 - If we don't have a keyboard grab, then we won't be able to
292 read a password to unlock, so the kbd grab is mandatory.
293 (We can't conditionalize this on locked_p, because someone
294 might run "xscreensaver-command -lock" at any time.)
296 - If we don't have a mouse grab, then we might not see mouse
297 clicks as a signal to unblank -- but we will still see kbd
298 activity, so that's not a disaster.
300 It has been suggested that we should allow blanking if locking
301 is disabled, and we have a mouse grab but no keyboard grab
302 (that is: kstatus != GrabSuccess &&
303 mstatus == GrabSuccess &&
304 si->locking_disabled_p)
305 That would allow screen blanking (but not locking) while the gdm
306 login screen had the keyboard grabbed, but one would have to use
307 the mouse to unblank. Keyboard characters would go to the gdm
308 login field without unblanking. I have not made this change
309 because I'm not completely convinced it is a safe thing to do.
312 if (kstatus != GrabSuccess) /* Do not blank without a kbd grab. */
314 /* If we didn't get both grabs, release the one we did get. */
315 ungrab_keyboard_and_mouse (si);
319 return True; /* Grab is good, go ahead and blank. */
324 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
326 Window old = si->mouse_grab_window;
329 return grab_mouse (si, to, cursor, to_screen_no);
332 saver_preferences *p = &si->prefs;
335 XSync (si->dpy, False);
336 XGrabServer (si->dpy); /* ############ DANGER! */
337 XSync (si->dpy, False);
340 fprintf(stderr, "%s: grabbing server...\n", blurb());
343 status = grab_mouse (si, to, cursor, to_screen_no);
345 if (status != GrabSuccess) /* Augh! */
347 sleep (1); /* Note dramatic evil of sleeping
348 with server grabbed. */
349 XSync (si->dpy, False);
350 status = grab_mouse (si, to, cursor, to_screen_no);
353 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
354 grab_mouse (si, old, cursor, to_screen_no);
356 XUngrabServer (si->dpy);
357 XSync (si->dpy, False); /* ###### (danger over) */
360 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
367 /* Prints an error message to stderr and returns True if there is another
368 xscreensaver running already. Silently returns False otherwise. */
370 ensure_no_screensaver_running (Display *dpy, Screen *screen)
374 Window root = RootWindowOfScreen (screen);
375 Window root2, parent, *kids;
377 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
379 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
385 for (i = 0; i < nkids; i++)
389 unsigned long nitems, bytesafter;
390 unsigned char *version;
392 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
393 False, XA_STRING, &type, &format, &nitems,
394 &bytesafter, &version)
399 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
400 False, XA_STRING, &type, &format, &nitems,
404 id = (unsigned char *) "???";
407 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
408 blurb(), DisplayString (dpy), (int) kids [i],
413 else if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
414 False, XA_STRING, &type, &format, &nitems,
415 &bytesafter, &version)
418 && !strcmp ((char *) version, "gnome-screensaver"))
421 "%s: \"%s\" is already running on display %s (window 0x%x)\n",
422 blurb(), (char *) version,
423 DisplayString (dpy), (int) kids [i]);
429 if (kids) XFree ((char *) kids);
431 XSetErrorHandler (old_handler);
437 /* Virtual-root hackery */
440 ERROR! You must not include vroot.h in this file.
444 store_vroot_property (Display *dpy, Window win, Window value)
449 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
451 (win == screensaver_window ? "ScreenSaver" :
452 (win == real_vroot ? "VRoot" :
453 (win == real_vroot_value ? "Vroot_value" : "???"))),
455 (value == screensaver_window ? "ScreenSaver" :
456 (value == real_vroot ? "VRoot" :
457 (value == real_vroot_value ? "Vroot_value" : "???"))));
459 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
460 (unsigned char *) &value, 1);
464 remove_vroot_property (Display *dpy, Window win)
468 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
469 (win == screensaver_window ? "ScreenSaver" :
470 (win == real_vroot ? "VRoot" :
471 (win == real_vroot_value ? "Vroot_value" : "???"))));
473 XDeleteProperty (dpy, win, XA_VROOT);
477 static Bool safe_XKillClient (Display *dpy, XID id);
480 kill_xsetroot_data_1 (Display *dpy, Window window,
481 Atom prop, const char *atom_name,
486 unsigned long nitems, bytesafter;
487 unsigned char *dataP = 0;
489 /* If the user has been using xv or xsetroot as a screensaver (to display
490 an image on the screensaver window, as a kind of slideshow) then the
491 pixmap and its associated color cells have been put in RetainPermanent
492 CloseDown mode. Since we're not destroying the xscreensaver window,
493 but merely unmapping it, we need to free these resources or those
494 colormap cells will stay allocated while the screensaver is off. (We
495 could just delete the screensaver window and recreate it later, but
496 that could cause other problems.) This code does an atomic read-and-
497 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
498 cause the RetainPermanent resources of the client which created it
499 (and which no longer exists) to be freed.
501 Update: it seems that Gnome and KDE do this same trick, but with the
502 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
503 "_XSETROOT_ID". So, we'll kill those too.
505 if (XGetWindowProperty (dpy, window, prop, 0, 1,
506 True, AnyPropertyType, &type, &format, &nitems,
511 Pixmap *pixP = (Pixmap *) dataP;
512 if (pixP && *pixP && type == XA_PIXMAP && format == 32 &&
513 nitems == 1 && bytesafter == 0)
516 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
517 blurb(), atom_name, *pixP);
518 safe_XKillClient (dpy, *pixP);
522 "%s: deleted unrecognised %s property: \n"
523 "\t%lu, %lu; type: %lu, format: %d, "
524 "nitems: %lu, bytesafter %ld\n",
526 (unsigned long) pixP, (pixP ? *pixP : 0), type,
527 format, nitems, bytesafter);
533 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
535 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
536 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
538 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
543 save_real_vroot (saver_screen_info *ssi)
545 saver_info *si = ssi->global;
546 Display *dpy = si->dpy;
547 Screen *screen = ssi->screen;
549 Window root = RootWindowOfScreen (screen);
550 Window root2, parent, *kids;
552 XErrorHandler old_handler;
554 /* It's possible that a window might be deleted between our call to
555 XQueryTree() and our call to XGetWindowProperty(). Don't die if
556 that happens (but just ignore that window, it's not the one we're
557 interested in anyway.)
560 old_handler = XSetErrorHandler (BadWindow_ehandler);
564 ssi->real_vroot_value = 0;
565 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
571 for (i = 0; i < nkids; i++)
575 unsigned long nitems, bytesafter;
576 unsigned char *dataP = 0;
580 /* Skip this window if it is the xscreensaver window of any other
581 screen (this can happen in the Xinerama case.)
583 for (j = 0; j < si->nscreens; j++)
585 saver_screen_info *ssi2 = &si->screens[j];
586 if (kids[i] == ssi2->screensaver_window)
590 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
591 &type, &format, &nitems, &bytesafter,
598 vrootP = (Window *) dataP;
601 if (*vrootP == ssi->screensaver_window) abort ();
603 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
604 blurb(), (int) ssi->real_vroot, (int) kids [i]);
607 ssi->real_vroot = kids [i];
608 ssi->real_vroot_value = *vrootP;
614 XSetErrorHandler (old_handler);
619 remove_vroot_property (si->dpy, ssi->real_vroot);
623 XFree ((char *) kids);
628 restore_real_vroot_1 (saver_screen_info *ssi)
630 saver_info *si = ssi->global;
631 saver_preferences *p = &si->prefs;
632 if (p->verbose_p && ssi->real_vroot)
634 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
635 blurb(), (unsigned long) ssi->real_vroot);
636 if (ssi->screensaver_window)
637 remove_vroot_property (si->dpy, ssi->screensaver_window);
640 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
642 ssi->real_vroot_value = 0;
643 /* make sure the property change gets there before this process
644 terminates! We might be doing this because we have intercepted
645 SIGTERM or something. */
646 XSync (si->dpy, False);
653 restore_real_vroot (saver_info *si)
656 Bool did_any = False;
657 for (i = 0; i < si->nscreens; i++)
659 saver_screen_info *ssi = &si->screens[i];
660 if (restore_real_vroot_1 (ssi))
667 /* Signal hackery to ensure that the vroot doesn't get left in an
672 signal_name(int signal)
675 case SIGHUP: return "SIGHUP";
676 case SIGINT: return "SIGINT";
677 case SIGQUIT: return "SIGQUIT";
678 case SIGILL: return "SIGILL";
679 case SIGTRAP: return "SIGTRAP";
681 case SIGABRT: return "SIGABRT";
683 case SIGFPE: return "SIGFPE";
684 case SIGKILL: return "SIGKILL";
685 case SIGBUS: return "SIGBUS";
686 case SIGSEGV: return "SIGSEGV";
687 case SIGPIPE: return "SIGPIPE";
688 case SIGALRM: return "SIGALRM";
689 case SIGTERM: return "SIGTERM";
691 case SIGSTOP: return "SIGSTOP";
694 case SIGCONT: return "SIGCONT";
697 case SIGUSR1: return "SIGUSR1";
700 case SIGUSR2: return "SIGUSR2";
703 case SIGEMT: return "SIGEMT";
706 case SIGSYS: return "SIGSYS";
709 case SIGCHLD: return "SIGCHLD";
712 case SIGPWR: return "SIGPWR";
715 case SIGWINCH: return "SIGWINCH";
718 case SIGURG: return "SIGURG";
721 case SIGIO: return "SIGIO";
724 case SIGVTALRM: return "SIGVTALRM";
727 case SIGXCPU: return "SIGXCPU";
730 case SIGXFSZ: return "SIGXFSZ";
733 case SIGDANGER: return "SIGDANGER";
738 sprintf(buf, "signal %d\n", signal);
747 restore_real_vroot_handler (int sig)
749 saver_info *si = global_si_kludge; /* I hate C so much... */
751 signal (sig, SIG_DFL);
752 if (restore_real_vroot (si))
753 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
754 blurb(), signal_name(sig));
755 kill (getpid (), sig);
759 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
761 # ifdef HAVE_SIGACTION
764 a.sa_handler = handler;
765 sigemptyset (&a.sa_mask);
768 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
769 of this signal from inside its handler, or else when we execvp() the
770 process again, it starts up with SIGHUP blocked, meaning that killing
771 it with -HUP only works *once*. You'd think that execvp() would reset
772 all the signal masks, but it doesn't.
774 # if defined(SA_NOMASK)
775 a.sa_flags |= SA_NOMASK;
776 # elif defined(SA_NODEFER)
777 a.sa_flags |= SA_NODEFER;
780 if (sigaction (sig, &a, 0) < 0)
781 # else /* !HAVE_SIGACTION */
782 if (((long) signal (sig, handler)) == -1L)
783 # endif /* !HAVE_SIGACTION */
786 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
788 saver_exit (si, 1, 0);
792 static RETSIGTYPE saver_sighup_handler (int sig);
795 handle_signals (saver_info *si)
797 catch_signal (si, SIGHUP, saver_sighup_handler);
799 catch_signal (si, SIGINT, restore_real_vroot_handler);
800 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
801 catch_signal (si, SIGILL, restore_real_vroot_handler);
802 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
804 catch_signal (si, SIGIOT, restore_real_vroot_handler);
806 catch_signal (si, SIGABRT, restore_real_vroot_handler);
808 catch_signal (si, SIGEMT, restore_real_vroot_handler);
810 catch_signal (si, SIGFPE, restore_real_vroot_handler);
811 catch_signal (si, SIGBUS, restore_real_vroot_handler);
812 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
814 catch_signal (si, SIGSYS, restore_real_vroot_handler);
816 catch_signal (si, SIGTERM, restore_real_vroot_handler);
818 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
821 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
824 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
830 saver_sighup_handler (int sig)
832 saver_info *si = global_si_kludge; /* I hate C so much... */
834 /* Re-establish SIGHUP handler */
835 catch_signal (si, SIGHUP, saver_sighup_handler);
837 fprintf (stderr, "%s: %s received: restarting...\n",
838 blurb(), signal_name(sig));
840 if (si->screen_blanked_p)
843 for (i = 0; i < si->nscreens; i++)
844 kill_screenhack (&si->screens[i]);
846 XSync (si->dpy, False);
849 restart_process (si); /* Does not return */
856 saver_exit (saver_info *si, int status, const char *dump_core_reason)
858 saver_preferences *p = &si->prefs;
859 static Bool exiting = False;
868 vrs = restore_real_vroot (si);
869 emergency_kill_subproc (si);
870 shutdown_stderr (si);
872 if (p->verbose_p && vrs)
873 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
877 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
878 if (status == 0) status = 1;
879 else if (status == 1) status = -1;
882 bugp = !!dump_core_reason;
884 if (si->prefs.debug_p && !dump_core_reason)
885 dump_core_reason = "because of -debug";
887 if (dump_core_reason)
889 /* Note that the Linux man page for setuid() says If uid is
890 different from the old effective uid, the process will be
891 forbidden from leaving core dumps.
893 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
895 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
900 "%s: see https://www.jwz.org/xscreensaver/bugs.html\n"
901 "\t\t\tfor bug reporting information.\n\n",
904 # if defined(HAVE_GETCWD)
905 if (!getcwd (cwd, sizeof(cwd)))
906 # elif defined(HAVE_GETWD)
909 strcpy(cwd, "unknown.");
911 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
912 describe_uids (si, real_stderr);
914 /* Do this to drop a core file, so that we can get a stack trace. */
922 /* Managing the actual screensaver window */
925 window_exists_p (Display *dpy, Window window)
927 XErrorHandler old_handler;
928 XWindowAttributes xgwa;
930 old_handler = XSetErrorHandler (BadWindow_ehandler);
931 XGetWindowAttributes (dpy, window, &xgwa);
933 XSetErrorHandler (old_handler);
934 return (xgwa.screen != 0);
938 store_saver_id (saver_screen_info *ssi)
940 XClassHint class_hints;
941 saver_info *si = ssi->global;
942 unsigned long pid = (unsigned long) getpid ();
944 struct passwd *p = getpwuid (getuid ());
945 const char *name, *host;
947 # if defined(HAVE_UNAME)
951 /* First store the name and class on the window.
953 class_hints.res_name = progname;
954 class_hints.res_class = progclass;
955 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
956 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
958 /* Then store the xscreensaver version number.
960 XChangeProperty (si->dpy, ssi->screensaver_window,
961 XA_SCREENSAVER_VERSION,
962 XA_STRING, 8, PropModeReplace,
963 (unsigned char *) si->version,
964 strlen (si->version));
966 /* Now store the XSCREENSAVER_ID property, that says what user and host
967 xscreensaver is running as.
970 if (p && p->pw_name && *p->pw_name)
974 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
980 # if defined(HAVE_UNAME)
982 if (uname (&uts) < 0)
988 host = getenv("SYS$NODE");
989 # else /* !HAVE_UNAME && !VMS */
991 # endif /* !HAVE_UNAME && !VMS */
993 id = (char *) malloc (strlen(name) + strlen(host) + 50);
994 sprintf (id, "%lu (%s@%s)", pid, name, host);
996 XChangeProperty (si->dpy, ssi->screensaver_window,
997 XA_SCREENSAVER_ID, XA_STRING,
999 (unsigned char *) id, strlen (id));
1005 store_saver_status (saver_info *si)
1008 int size = si->nscreens + 2;
1011 status = (PROP32 *) calloc (size, sizeof(PROP32));
1013 status[0] = (PROP32) (si->screen_blanked_p || si->locked_p
1014 ? (si->locked_p ? XA_LOCK : XA_BLANK)
1016 status[1] = (PROP32) si->blank_time;
1018 for (i = 0; i < si->nscreens; i++)
1020 saver_screen_info *ssi = &si->screens[i];
1021 status [2 + i] = ssi->current_hack + 1;
1024 XChangeProperty (si->dpy,
1025 RootWindow (si->dpy, 0), /* always screen #0 */
1026 XA_SCREENSAVER_STATUS,
1027 XA_INTEGER, 32, PropModeReplace,
1028 (unsigned char *) status, size);
1033 static Bool error_handler_hit_p = False;
1036 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1038 error_handler_hit_p = True;
1043 /* Returns True if successful, False if an X error occurred.
1044 We need this because other programs might have done things to
1045 our window that will cause XChangeWindowAttributes() to fail:
1046 if that happens, we give up, destroy the window, and re-create
1050 safe_XChangeWindowAttributes (Display *dpy, Window window,
1052 XSetWindowAttributes *attrs)
1054 XErrorHandler old_handler;
1056 error_handler_hit_p = False;
1057 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1059 XChangeWindowAttributes (dpy, window, mask, attrs);
1062 XSetErrorHandler (old_handler);
1065 return (!error_handler_hit_p);
1069 /* This might not be necessary, but just in case. */
1071 safe_XConfigureWindow (Display *dpy, Window window,
1072 unsigned long mask, XWindowChanges *changes)
1074 XErrorHandler old_handler;
1076 error_handler_hit_p = False;
1077 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1079 XConfigureWindow (dpy, window, mask, changes);
1082 XSetErrorHandler (old_handler);
1085 return (!error_handler_hit_p);
1088 /* This might not be necessary, but just in case. */
1090 safe_XDestroyWindow (Display *dpy, Window window)
1092 XErrorHandler old_handler;
1094 error_handler_hit_p = False;
1095 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1097 XDestroyWindow (dpy, window);
1100 XSetErrorHandler (old_handler);
1103 return (!error_handler_hit_p);
1108 safe_XKillClient (Display *dpy, XID id)
1110 XErrorHandler old_handler;
1112 error_handler_hit_p = False;
1113 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1115 XKillClient (dpy, id);
1118 XSetErrorHandler (old_handler);
1121 return (!error_handler_hit_p);
1125 #ifdef HAVE_XF86VMODE
1127 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1130 XErrorHandler old_handler;
1132 error_handler_hit_p = False;
1133 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1135 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1138 XSetErrorHandler (old_handler);
1141 return (error_handler_hit_p
1146 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1147 untrappable I/O error instead of an X error -- so one must call
1148 safe_XF86VidModeGetViewPort first, and assume that both have the
1149 same error condition. Thank you XFree, may I have another.
1152 #endif /* HAVE_XF86VMODE */
1156 initialize_screensaver_window_1 (saver_screen_info *ssi)
1158 saver_info *si = ssi->global;
1159 saver_preferences *p = &si->prefs;
1160 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1162 /* This resets the screensaver window as fully as possible, since there's
1163 no way of knowing what some random client may have done to us in the
1164 meantime. We could just destroy and recreate the window, but that has
1165 its own set of problems...
1168 XSetWindowAttributes attrs;
1169 unsigned long attrmask;
1170 static Bool printed_visual_info = False; /* only print the message once. */
1171 Window horked_window = 0;
1173 black.red = black.green = black.blue = 0;
1175 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1178 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1179 /* It's not the default visual, so we have no choice but to install. */
1180 install_cmap_p = True;
1186 ssi->cmap = XCreateColormap (si->dpy,
1187 RootWindowOfScreen (ssi->screen),
1188 ssi->current_visual, AllocNone);
1189 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1190 ssi->black_pixel = black.pixel;
1195 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1198 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1199 if (ssi->cmap != ssi->demo_cmap &&
1200 ssi->cmap != def_cmap)
1201 XFreeColormap (si->dpy, ssi->cmap);
1203 ssi->cmap = def_cmap;
1204 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1207 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1208 CWBackPixel | CWBackingPixel | CWBorderPixel);
1209 attrs.override_redirect = True;
1211 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1212 actually be reading these events during normal operation; but we still
1213 need to see Button events for demo-mode to work properly.
1215 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1216 ButtonPressMask | ButtonReleaseMask |
1219 attrs.backing_store = NotUseful;
1220 attrs.colormap = ssi->cmap;
1221 attrs.background_pixel = ssi->black_pixel;
1222 attrs.backing_pixel = ssi->black_pixel;
1223 attrs.border_pixel = ssi->black_pixel;
1225 if (!p->verbose_p || printed_visual_info)
1227 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1229 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1230 describe_visual (stderr, ssi->screen, ssi->current_visual,
1235 fprintf (stderr, "%s: using visual: ", blurb());
1236 describe_visual (stderr, ssi->screen, ssi->current_visual,
1238 fprintf (stderr, "%s: default visual: ", blurb());
1239 describe_visual (stderr, ssi->screen,
1240 DefaultVisualOfScreen (ssi->screen),
1241 ssi->install_cmap_p);
1243 printed_visual_info = True;
1245 #ifdef HAVE_MIT_SAVER_EXTENSION
1246 if (si->using_mit_saver_extension)
1248 XScreenSaverInfo *info;
1249 Window root = RootWindowOfScreen (ssi->screen);
1252 /* This call sets the server screensaver timeouts to what we think
1253 they should be (based on the resources and args xscreensaver was
1254 started with.) It's important that we do this to sync back up
1255 with the server - if we have turned on prematurely, as by an
1256 ACTIVATE ClientMessage, then the server may decide to activate
1257 the screensaver while it's already active. That's ok for us,
1258 since we would know to ignore that ScreenSaverActivate event,
1259 but a side effect of this would be that the server would map its
1260 saver window (which we then hide again right away) meaning that
1261 the bits currently on the screen get blown away. Ugly. */
1263 /* #### Ok, that doesn't work - when we tell the server that the
1264 screensaver is "off" it sends us a Deactivate event, which is
1265 sensible... but causes the saver to never come on. Hmm. */
1266 disable_builtin_screensaver (si, True);
1270 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1271 window that the server itself uses for saving the screen.
1272 However, using this window in any way, in particular, calling
1273 XScreenSaverSetAttributes() as below, tends to make the X server
1274 crash. So fuck it, let's try and get along without using it...
1276 It's also inconvenient to use this window because it doesn't
1277 always exist (though the ID is constant.) So to use this
1278 window, we'd have to reimplement the ACTIVATE ClientMessage to
1279 tell the *server* to tell *us* to turn on, to cause the window
1280 to get created at the right time. Gag. */
1281 XScreenSaverSetAttributes (si->dpy, root,
1282 0, 0, width, height, 0,
1283 current_depth, InputOutput, visual,
1285 XSync (si->dpy, False);
1288 info = XScreenSaverAllocInfo ();
1289 XScreenSaverQueryInfo (si->dpy, root, info);
1290 ssi->server_mit_saver_window = info->window;
1291 if (! ssi->server_mit_saver_window) abort ();
1294 #endif /* HAVE_MIT_SAVER_EXTENSION */
1296 if (ssi->screensaver_window)
1298 XWindowChanges changes;
1299 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1302 changes.width = ssi->width;
1303 changes.height = ssi->height;
1304 changes.border_width = 0;
1306 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1307 changesmask, &changes) &&
1308 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1311 horked_window = ssi->screensaver_window;
1312 ssi->screensaver_window = 0;
1316 if (!ssi->screensaver_window)
1318 ssi->screensaver_window =
1319 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1320 ssi->x, ssi->y, ssi->width, ssi->height,
1321 0, ssi->current_depth, InputOutput,
1322 ssi->current_visual, attrmask, &attrs);
1328 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1329 blurb(), (unsigned long) horked_window);
1330 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1332 safe_XDestroyWindow (si->dpy, horked_window);
1337 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1338 blurb(), ssi->number,
1339 (unsigned long) ssi->screensaver_window);
1342 store_saver_id (ssi); /* store window name and IDs */
1347 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1349 BlackPixelOfScreen (ssi->screen),
1350 BlackPixelOfScreen (ssi->screen),
1352 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1354 XFreePixmap (si->dpy, bit);
1357 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1360 XUndefineCursor (si->dpy, ssi->screensaver_window);
1362 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1366 initialize_screensaver_window (saver_info *si)
1369 for (i = 0; i < si->nscreens; i++)
1370 initialize_screensaver_window_1 (&si->screens[i]);
1374 /* Called when the RANDR (Resize and Rotate) extension tells us that
1375 the size of the screen has changed while the screen was blanked.
1376 Call update_screen_layout() first, then call this to synchronize
1377 the size of the saver windows to the new sizes of the screens.
1380 resize_screensaver_window (saver_info *si)
1382 saver_preferences *p = &si->prefs;
1385 for (i = 0; i < si->nscreens; i++)
1387 saver_screen_info *ssi = &si->screens[i];
1388 XWindowAttributes xgwa;
1390 /* Make sure a window exists -- it might not if a monitor was just
1391 added for the first time.
1393 if (! ssi->screensaver_window)
1395 initialize_screensaver_window_1 (ssi);
1398 "%s: %d: newly added window 0x%lx %dx%d+%d+%d\n",
1399 blurb(), i, (unsigned long) ssi->screensaver_window,
1400 ssi->width, ssi->height, ssi->x, ssi->y);
1403 /* Make sure the window is the right size -- it might not be if
1404 the monitor changed resolution, or if a badly-behaved hack
1407 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1408 if (xgwa.x != ssi->x ||
1410 xgwa.width != ssi->width ||
1411 xgwa.height != ssi->height)
1413 XWindowChanges changes;
1414 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1417 changes.width = ssi->width;
1418 changes.height = ssi->height;
1419 changes.border_width = 0;
1423 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1424 blurb(), i, (unsigned long) ssi->screensaver_window,
1425 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1426 ssi->width, ssi->height, ssi->x, ssi->y);
1428 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1429 changesmask, &changes))
1430 fprintf (stderr, "%s: %d: someone horked our saver window"
1431 " (0x%lx)! Unable to resize it!\n",
1432 blurb(), i, (unsigned long) ssi->screensaver_window);
1435 /* Now (if blanked) make sure that it's mapped and running a hack --
1436 it might not be if we just added it. (We also might be re-using
1437 an old window that existed for a previous monitor that was
1438 removed and re-added.)
1440 Note that spawn_screenhack() calls select_visual() which may destroy
1441 and re-create the window via initialize_screensaver_window_1().
1443 if (si->screen_blanked_p)
1446 XInstallColormap (si->dpy, ssi->cmap);
1447 XMapRaised (si->dpy, ssi->screensaver_window);
1449 spawn_screenhack (ssi);
1451 /* Make sure the act of adding a screen doesn't present as
1452 pointer motion (and thus cause an unblank). */
1457 XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
1458 &ssi->last_poll_mouse.root_x,
1459 &ssi->last_poll_mouse.root_y,
1465 /* Kill off any savers running on no-longer-extant monitors.
1467 for (; i < si->ssi_count; i++)
1469 saver_screen_info *ssi = &si->screens[i];
1471 kill_screenhack (ssi);
1472 if (ssi->screensaver_window)
1474 XUnmapWindow (si->dpy, ssi->screensaver_window);
1475 restore_real_vroot_1 (ssi);
1482 raise_window (saver_info *si,
1483 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1485 saver_preferences *p = &si->prefs;
1489 inhibit_fade = True;
1491 if (si->emergency_lock_p)
1492 inhibit_fade = True;
1495 initialize_screensaver_window (si);
1497 reset_watchdog_timer (si, True);
1499 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1501 Window *current_windows = (Window *)
1502 calloc(sizeof(Window), si->nscreens);
1503 Colormap *current_maps = (Colormap *)
1504 calloc(sizeof(Colormap), si->nscreens);
1506 for (i = 0; i < si->nscreens; i++)
1508 saver_screen_info *ssi = &si->screens[i];
1509 current_windows[i] = ssi->screensaver_window;
1510 current_maps[i] = (between_hacks_p
1512 : DefaultColormapOfScreen (ssi->screen));
1513 /* Ensure that the default background of the window is really black,
1514 not a pixmap or something. (This does not clear the window.) */
1515 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1519 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1521 XGrabServer (si->dpy); /* ############ DANGER! */
1523 /* Clear the stderr layer on each screen.
1526 for (i = 0; i < si->nscreens; i++)
1528 saver_screen_info *ssi = &si->screens[i];
1529 if (ssi->stderr_overlay_window)
1530 /* Do this before the fade, since the stderr cmap won't fade
1531 even if we uninstall it (beats me...) */
1535 /* Note! The server is grabbed, and this will take several seconds
1537 fade_screens (si->dpy, current_maps,
1538 current_windows, si->nscreens,
1539 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1542 free(current_windows);
1544 current_windows = 0;
1546 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1548 #ifdef HAVE_MIT_SAVER_EXTENSION
1549 for (i = 0; i < si->nscreens; i++)
1551 saver_screen_info *ssi = &si->screens[i];
1552 if (ssi->server_mit_saver_window &&
1553 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1554 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1556 #endif /* HAVE_MIT_SAVER_EXTENSION */
1558 XUngrabServer (si->dpy);
1559 XSync (si->dpy, False); /* ###### (danger over) */
1563 for (i = 0; i < si->nscreens; i++)
1565 saver_screen_info *ssi = &si->screens[i];
1567 XClearWindow (si->dpy, ssi->screensaver_window);
1568 if (!dont_clear || ssi->stderr_overlay_window)
1570 XMapRaised (si->dpy, ssi->screensaver_window);
1571 #ifdef HAVE_MIT_SAVER_EXTENSION
1572 if (ssi->server_mit_saver_window &&
1573 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1574 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1575 #endif /* HAVE_MIT_SAVER_EXTENSION */
1579 for (i = 0; i < si->nscreens; i++)
1581 saver_screen_info *ssi = &si->screens[i];
1583 XInstallColormap (si->dpy, ssi->cmap);
1589 mouse_screen (saver_info *si)
1591 saver_preferences *p = &si->prefs;
1592 Window pointer_root, pointer_child;
1593 int root_x, root_y, win_x, win_y;
1597 if (si->nscreens == 1)
1600 for (i = 0; i < si->nscreens; i++)
1602 saver_screen_info *ssi = &si->screens[i];
1603 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1604 &pointer_root, &pointer_child,
1605 &root_x, &root_y, &win_x, &win_y, &mask) &&
1608 root_x < ssi->x + ssi->width &&
1609 root_y < ssi->y + ssi->height)
1612 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1613 blurb(), i, si->nscreens);
1618 /* couldn't figure out where the mouse is? Oh well. */
1624 blank_screen (saver_info *si)
1631 /* Note: we do our grabs on the root window, not on the screensaver window.
1632 If we grabbed on the saver window, then the demo mode and lock dialog
1633 boxes wouldn't get any events.
1635 By "the root window", we mean "the root window that contains the mouse."
1636 We use to always grab the mouse on screen 0, but that has the effect of
1637 moving the mouse to screen 0 from whichever screen it was on, on
1640 mscreen = mouse_screen (si);
1641 w = RootWindowOfScreen(si->screens[mscreen].screen);
1642 ok = grab_keyboard_and_mouse (si, w,
1643 (si->demoing_p ? 0 : si->screens[0].cursor),
1648 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1649 /* If we're using a server extension, then failure to get a grab is
1650 not a big deal -- even without the grab, we will still be able
1651 to un-blank when there is user activity, since the server will
1653 /* #### No, that's not true: if we don't have a keyboard grab,
1654 then we can't read passwords to unlock.
1662 for (i = 0; i < si->nscreens; i++)
1664 saver_screen_info *ssi = &si->screens[i];
1665 if (ssi->real_screen_p)
1666 save_real_vroot (ssi);
1667 store_vroot_property (si->dpy,
1668 ssi->screensaver_window,
1669 ssi->screensaver_window);
1671 #ifdef HAVE_XF86VMODE
1674 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1675 !safe_XF86VidModeGetViewPort (si->dpy, i,
1678 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1680 #endif /* HAVE_XF86VMODE */
1683 raise_window (si, False, False, False);
1685 si->screen_blanked_p = True;
1686 si->blank_time = time ((time_t *) 0);
1687 si->last_wall_clock_time = 0;
1689 store_saver_status (si); /* store blank time */
1696 unblank_screen (saver_info *si)
1698 saver_preferences *p = &si->prefs;
1699 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1702 monitor_power_on (si, True);
1703 reset_watchdog_timer (si, False);
1710 Window *current_windows = (Window *)
1711 calloc(sizeof(Window), si->nscreens);
1713 for (i = 0; i < si->nscreens; i++)
1715 saver_screen_info *ssi = &si->screens[i];
1716 current_windows[i] = ssi->screensaver_window;
1717 /* Ensure that the default background of the window is really black,
1718 not a pixmap or something. (This does not clear the window.) */
1719 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1723 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1726 XSync (si->dpy, False);
1727 XGrabServer (si->dpy); /* ############ DANGER! */
1728 XSync (si->dpy, False);
1730 /* Clear the stderr layer on each screen.
1732 for (i = 0; i < si->nscreens; i++)
1734 saver_screen_info *ssi = &si->screens[i];
1738 XUngrabServer (si->dpy);
1739 XSync (si->dpy, False); /* ###### (danger over) */
1741 fade_screens (si->dpy, 0,
1742 current_windows, si->nscreens,
1743 p->fade_seconds/1000, p->fade_ticks,
1746 free(current_windows);
1747 current_windows = 0;
1749 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1753 for (i = 0; i < si->nscreens; i++)
1755 saver_screen_info *ssi = &si->screens[i];
1758 Colormap c = DefaultColormapOfScreen (ssi->screen);
1759 /* avoid technicolor */
1760 XClearWindow (si->dpy, ssi->screensaver_window);
1761 if (c) XInstallColormap (si->dpy, c);
1763 XUnmapWindow (si->dpy, ssi->screensaver_window);
1768 /* If the focus window does has a non-default colormap, then install
1769 that colormap as well. (On SGIs, this will cause both the root map
1770 and the focus map to be installed simultaneously. It'd be nice to
1771 pick up the other colormaps that had been installed, too; perhaps
1772 XListInstalledColormaps could be used for that?)
1777 XGetInputFocus (si->dpy, &focus, &revert_to);
1778 if (focus && focus != PointerRoot && focus != None)
1780 XWindowAttributes xgwa;
1782 XGetWindowAttributes (si->dpy, focus, &xgwa);
1783 if (xgwa.colormap &&
1784 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1785 XInstallColormap (si->dpy, xgwa.colormap);
1790 for (i = 0; i < si->nscreens; i++)
1792 saver_screen_info *ssi = &si->screens[i];
1793 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1796 store_saver_status (si); /* store unblank time */
1797 ungrab_keyboard_and_mouse (si);
1798 restore_real_vroot (si);
1800 /* Unmap the windows a second time, dammit -- just to avoid a race
1801 with the screen-grabbing hacks. (I'm not sure if this is really
1802 necessary; I'm stabbing in the dark now.)
1804 for (i = 0; i < si->nscreens; i++)
1805 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1807 si->screen_blanked_p = False;
1808 si->blank_time = time ((time_t *) 0);
1809 si->last_wall_clock_time = 0;
1811 store_saver_status (si); /* store unblank time */
1815 /* Transfer any grabs from the old window to the new.
1816 Actually I think none of this is necessary, since we always
1817 hold our grabs on the root window, but I wrote this before
1818 re-discovering that...
1821 maybe_transfer_grabs (saver_screen_info *ssi,
1822 Window old_w, Window new_w,
1825 saver_info *si = ssi->global;
1827 /* If the old window held our mouse grab, transfer the grab to the new
1828 window. (Grab the server while so doing, to avoid a race condition.)
1830 if (old_w == si->mouse_grab_window)
1832 XGrabServer (si->dpy); /* ############ DANGER! */
1834 grab_mouse (si, ssi->screensaver_window,
1835 (si->demoing_p ? 0 : ssi->cursor),
1837 XUngrabServer (si->dpy);
1838 XSync (si->dpy, False); /* ###### (danger over) */
1841 /* If the old window held our keyboard grab, transfer the grab to the new
1842 window. (Grab the server while so doing, to avoid a race condition.)
1844 if (old_w == si->keyboard_grab_window)
1846 XGrabServer (si->dpy); /* ############ DANGER! */
1848 grab_kbd(si, ssi->screensaver_window, ssi->number);
1849 XUngrabServer (si->dpy);
1850 XSync (si->dpy, False); /* ###### (danger over) */
1856 get_screen_gl_visual (saver_info *si, int real_screen_number)
1859 int nscreens = ScreenCount (si->dpy);
1861 if (! si->best_gl_visuals)
1862 si->best_gl_visuals = (Visual **)
1863 calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
1865 for (i = 0; i < nscreens; i++)
1866 if (! si->best_gl_visuals[i])
1867 si->best_gl_visuals[i] =
1868 get_best_gl_visual (si, ScreenOfDisplay (si->dpy, i));
1870 if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
1871 return si->best_gl_visuals[real_screen_number];
1876 select_visual (saver_screen_info *ssi, const char *visual_name)
1878 XWindowAttributes xgwa;
1879 saver_info *si = ssi->global;
1880 saver_preferences *p = &si->prefs;
1881 Bool install_cmap_p = p->install_cmap_p;
1882 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1886 /* On some systems (most recently, MacOS X) OpenGL programs get confused
1887 when you kill one and re-start another on the same window. So maybe
1888 it's best to just always destroy and recreate the xscreensaver window
1889 when changing hacks, instead of trying to reuse the old one?
1891 Bool always_recreate_window_p = True;
1893 get_screen_gl_visual (si, 0); /* let's probe all the GL visuals early */
1895 /* We make sure the existing window is actually on ssi->screen before
1896 trying to use it, in case things moved around radically when monitors
1897 were added or deleted. If we don't do this we could get a BadMatch
1898 even though the depths match. I think.
1900 memset (&xgwa, 0, sizeof(xgwa));
1901 if (ssi->screensaver_window)
1902 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1904 if (visual_name && *visual_name)
1906 if (!strcmp(visual_name, "default-i") ||
1907 !strcmp(visual_name, "Default-i") ||
1908 !strcmp(visual_name, "Default-I")
1911 visual_name = "default";
1912 install_cmap_p = True;
1914 else if (!strcmp(visual_name, "default-n") ||
1915 !strcmp(visual_name, "Default-n") ||
1916 !strcmp(visual_name, "Default-N"))
1918 visual_name = "default";
1919 install_cmap_p = False;
1921 else if (!strcmp(visual_name, "gl") ||
1922 !strcmp(visual_name, "Gl") ||
1923 !strcmp(visual_name, "GL"))
1925 new_v = get_screen_gl_visual (si, ssi->real_screen_number);
1926 if (!new_v && p->verbose_p)
1927 fprintf (stderr, "%s: no GL visuals.\n", progname);
1931 new_v = get_visual (ssi->screen, visual_name, True, False);
1935 new_v = ssi->default_visual;
1940 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1941 /* It's not the default visual, so we have no choice but to install. */
1942 install_cmap_p = True;
1944 ssi->install_cmap_p = install_cmap_p;
1946 if ((ssi->screen != xgwa.screen) ||
1948 (always_recreate_window_p ||
1949 (ssi->current_visual != new_v) ||
1950 (install_cmap_p != was_installed_p))))
1952 Colormap old_c = ssi->cmap;
1953 Window old_w = ssi->screensaver_window;
1955 new_v = ssi->current_visual;
1959 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1960 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1962 fprintf (stderr, "%s: from ", blurb());
1963 describe_visual (stderr, ssi->screen, ssi->current_visual,
1969 ssi->current_visual = new_v;
1970 ssi->current_depth = visual_depth(ssi->screen, new_v);
1972 ssi->screensaver_window = 0;
1974 initialize_screensaver_window_1 (ssi);
1976 /* stderr_overlay_window is a child of screensaver_window, so we need
1977 to destroy that as well (actually, we just need to invalidate and
1978 drop our pointers to it, but this will destroy it, which is ok so
1979 long as it happens before old_w itself is destroyed.) */
1982 raise_window (si, True, True, False);
1983 store_vroot_property (si->dpy,
1984 ssi->screensaver_window, ssi->screensaver_window);
1986 /* Transfer any grabs from the old window to the new. */
1987 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1989 /* Now we can destroy the old window without horking our grabs. */
1990 XDestroyWindow (si->dpy, old_w);
1993 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1994 blurb(), ssi->number, (unsigned long) old_w);
1997 old_c != DefaultColormapOfScreen (ssi->screen) &&
1998 old_c != ssi->demo_cmap)
1999 XFreeColormap (si->dpy, old_c);