1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2008 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_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
78 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 manditory; 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 manditory.
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.
301 if (kstatus != GrabSuccess) /* Do not blank without a kbd grab. */
303 /* If we didn't get both grabs, release the one we did get. */
304 ungrab_keyboard_and_mouse (si);
308 return True; /* Grab is good, go ahead and blank. */
313 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
315 Window old = si->mouse_grab_window;
318 return grab_mouse (si, to, cursor, to_screen_no);
321 saver_preferences *p = &si->prefs;
324 XSync (si->dpy, False);
325 XGrabServer (si->dpy); /* ############ DANGER! */
326 XSync (si->dpy, False);
329 fprintf(stderr, "%s: grabbing server...\n", blurb());
332 status = grab_mouse (si, to, cursor, to_screen_no);
334 if (status != GrabSuccess) /* Augh! */
336 sleep (1); /* Note dramatic evil of sleeping
337 with server grabbed. */
338 XSync (si->dpy, False);
339 status = grab_mouse (si, to, cursor, to_screen_no);
342 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
343 grab_mouse (si, old, cursor, to_screen_no);
345 XUngrabServer (si->dpy);
346 XSync (si->dpy, False); /* ###### (danger over) */
349 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
356 /* Prints an error message to stderr and returns True if there is another
357 xscreensaver running already. Silently returns False otherwise. */
359 ensure_no_screensaver_running (Display *dpy, Screen *screen)
363 Window root = RootWindowOfScreen (screen);
364 Window root2, parent, *kids;
366 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
368 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
374 for (i = 0; i < nkids; i++)
378 unsigned long nitems, bytesafter;
379 unsigned char *version;
381 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
382 False, XA_STRING, &type, &format, &nitems,
383 &bytesafter, &version)
388 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
389 False, XA_STRING, &type, &format, &nitems,
393 id = (unsigned char *) "???";
396 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
397 blurb(), DisplayString (dpy), (int) kids [i],
402 else if (XGetWindowProperty (dpy, kids[i], XA_WM_COMMAND, 0, 128,
403 False, XA_STRING, &type, &format, &nitems,
404 &bytesafter, &version)
407 && !strcmp ((char *) version, "gnome-screensaver"))
410 "%s: \"%s\" is already running on display %s (window 0x%x)\n",
411 blurb(), (char *) version,
412 DisplayString (dpy), (int) kids [i]);
418 if (kids) XFree ((char *) kids);
420 XSetErrorHandler (old_handler);
426 /* Virtual-root hackery */
429 ERROR! You must not include vroot.h in this file.
433 store_vroot_property (Display *dpy, Window win, Window value)
438 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
440 (win == screensaver_window ? "ScreenSaver" :
441 (win == real_vroot ? "VRoot" :
442 (win == real_vroot_value ? "Vroot_value" : "???"))),
444 (value == screensaver_window ? "ScreenSaver" :
445 (value == real_vroot ? "VRoot" :
446 (value == real_vroot_value ? "Vroot_value" : "???"))));
448 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
449 (unsigned char *) &value, 1);
453 remove_vroot_property (Display *dpy, Window win)
457 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
458 (win == screensaver_window ? "ScreenSaver" :
459 (win == real_vroot ? "VRoot" :
460 (win == real_vroot_value ? "Vroot_value" : "???"))));
462 XDeleteProperty (dpy, win, XA_VROOT);
466 static Bool safe_XKillClient (Display *dpy, XID id);
469 kill_xsetroot_data_1 (Display *dpy, Window window,
470 Atom prop, const char *atom_name,
475 unsigned long nitems, bytesafter;
476 unsigned char *dataP = 0;
478 /* If the user has been using xv or xsetroot as a screensaver (to display
479 an image on the screensaver window, as a kind of slideshow) then the
480 pixmap and its associated color cells have been put in RetainPermanent
481 CloseDown mode. Since we're not destroying the xscreensaver window,
482 but merely unmapping it, we need to free these resources or those
483 colormap cells will stay allocated while the screensaver is off. (We
484 could just delete the screensaver window and recreate it later, but
485 that could cause other problems.) This code does an atomic read-and-
486 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
487 cause the RetainPermanent resources of the client which created it
488 (and which no longer exists) to be freed.
490 Update: it seems that Gnome and KDE do this same trick, but with the
491 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
492 "_XSETROOT_ID". So, we'll kill those too.
494 if (XGetWindowProperty (dpy, window, prop, 0, 1,
495 True, AnyPropertyType, &type, &format, &nitems,
500 Pixmap *pixP = (Pixmap *) dataP;
501 if (pixP && *pixP && type == XA_PIXMAP && format == 32 &&
502 nitems == 1 && bytesafter == 0)
505 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
506 blurb(), atom_name, *pixP);
507 safe_XKillClient (dpy, *pixP);
511 "%s: deleted unrecognised %s property: \n"
512 "\t%lu, %lu; type: %lu, format: %d, "
513 "nitems: %lu, bytesafter %ld\n",
515 (unsigned long) pixP, (pixP ? *pixP : 0), type,
516 format, nitems, bytesafter);
522 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
524 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
525 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
527 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
532 save_real_vroot (saver_screen_info *ssi)
534 saver_info *si = ssi->global;
535 Display *dpy = si->dpy;
536 Screen *screen = ssi->screen;
538 Window root = RootWindowOfScreen (screen);
539 Window root2, parent, *kids;
541 XErrorHandler old_handler;
543 /* It's possible that a window might be deleted between our call to
544 XQueryTree() and our call to XGetWindowProperty(). Don't die if
545 that happens (but just ignore that window, it's not the one we're
546 interested in anyway.)
549 old_handler = XSetErrorHandler (BadWindow_ehandler);
553 ssi->real_vroot_value = 0;
554 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
560 for (i = 0; i < nkids; i++)
564 unsigned long nitems, bytesafter;
565 unsigned char *dataP = 0;
569 /* Skip this window if it is the xscreensaver window of any other
570 screen (this can happen in the Xinerama case.)
572 for (j = 0; j < si->nscreens; j++)
574 saver_screen_info *ssi2 = &si->screens[j];
575 if (kids[i] == ssi2->screensaver_window)
579 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
580 &type, &format, &nitems, &bytesafter,
587 vrootP = (Window *) dataP;
590 if (*vrootP == ssi->screensaver_window) abort ();
592 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
593 blurb(), (int) ssi->real_vroot, (int) kids [i]);
596 ssi->real_vroot = kids [i];
597 ssi->real_vroot_value = *vrootP;
603 XSetErrorHandler (old_handler);
608 remove_vroot_property (si->dpy, ssi->real_vroot);
612 XFree ((char *) kids);
617 restore_real_vroot_1 (saver_screen_info *ssi)
619 saver_info *si = ssi->global;
620 saver_preferences *p = &si->prefs;
621 if (p->verbose_p && ssi->real_vroot)
623 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
624 blurb(), (unsigned long) ssi->real_vroot);
625 if (ssi->screensaver_window)
626 remove_vroot_property (si->dpy, ssi->screensaver_window);
629 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
631 ssi->real_vroot_value = 0;
632 /* make sure the property change gets there before this process
633 terminates! We might be doing this because we have intercepted
634 SIGTERM or something. */
635 XSync (si->dpy, False);
642 restore_real_vroot (saver_info *si)
645 Bool did_any = False;
646 for (i = 0; i < si->nscreens; i++)
648 saver_screen_info *ssi = &si->screens[i];
649 if (restore_real_vroot_1 (ssi))
656 /* Signal hackery to ensure that the vroot doesn't get left in an
661 signal_name(int signal)
664 case SIGHUP: return "SIGHUP";
665 case SIGINT: return "SIGINT";
666 case SIGQUIT: return "SIGQUIT";
667 case SIGILL: return "SIGILL";
668 case SIGTRAP: return "SIGTRAP";
670 case SIGABRT: return "SIGABRT";
672 case SIGFPE: return "SIGFPE";
673 case SIGKILL: return "SIGKILL";
674 case SIGBUS: return "SIGBUS";
675 case SIGSEGV: return "SIGSEGV";
676 case SIGPIPE: return "SIGPIPE";
677 case SIGALRM: return "SIGALRM";
678 case SIGTERM: return "SIGTERM";
680 case SIGSTOP: return "SIGSTOP";
683 case SIGCONT: return "SIGCONT";
686 case SIGUSR1: return "SIGUSR1";
689 case SIGUSR2: return "SIGUSR2";
692 case SIGEMT: return "SIGEMT";
695 case SIGSYS: return "SIGSYS";
698 case SIGCHLD: return "SIGCHLD";
701 case SIGPWR: return "SIGPWR";
704 case SIGWINCH: return "SIGWINCH";
707 case SIGURG: return "SIGURG";
710 case SIGIO: return "SIGIO";
713 case SIGVTALRM: return "SIGVTALRM";
716 case SIGXCPU: return "SIGXCPU";
719 case SIGXFSZ: return "SIGXFSZ";
722 case SIGDANGER: return "SIGDANGER";
727 sprintf(buf, "signal %d\n", signal);
736 restore_real_vroot_handler (int sig)
738 saver_info *si = global_si_kludge; /* I hate C so much... */
740 signal (sig, SIG_DFL);
741 if (restore_real_vroot (si))
742 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
743 blurb(), signal_name(sig));
744 kill (getpid (), sig);
748 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
750 # ifdef HAVE_SIGACTION
753 a.sa_handler = handler;
754 sigemptyset (&a.sa_mask);
757 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
758 of this signal from inside its handler, or else when we execvp() the
759 process again, it starts up with SIGHUP blocked, meaning that killing
760 it with -HUP only works *once*. You'd think that execvp() would reset
761 all the signal masks, but it doesn't.
763 # if defined(SA_NOMASK)
764 a.sa_flags |= SA_NOMASK;
765 # elif defined(SA_NODEFER)
766 a.sa_flags |= SA_NODEFER;
769 if (sigaction (sig, &a, 0) < 0)
770 # else /* !HAVE_SIGACTION */
771 if (((long) signal (sig, handler)) == -1L)
772 # endif /* !HAVE_SIGACTION */
775 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
777 saver_exit (si, 1, 0);
781 static RETSIGTYPE saver_sighup_handler (int sig);
784 handle_signals (saver_info *si)
786 catch_signal (si, SIGHUP, saver_sighup_handler);
788 catch_signal (si, SIGINT, restore_real_vroot_handler);
789 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
790 catch_signal (si, SIGILL, restore_real_vroot_handler);
791 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
793 catch_signal (si, SIGIOT, restore_real_vroot_handler);
795 catch_signal (si, SIGABRT, restore_real_vroot_handler);
797 catch_signal (si, SIGEMT, restore_real_vroot_handler);
799 catch_signal (si, SIGFPE, restore_real_vroot_handler);
800 catch_signal (si, SIGBUS, restore_real_vroot_handler);
801 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
803 catch_signal (si, SIGSYS, restore_real_vroot_handler);
805 catch_signal (si, SIGTERM, restore_real_vroot_handler);
807 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
810 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
813 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
819 saver_sighup_handler (int sig)
821 saver_info *si = global_si_kludge; /* I hate C so much... */
823 /* Re-establish SIGHUP handler */
824 catch_signal (si, SIGHUP, saver_sighup_handler);
826 fprintf (stderr, "%s: %s received: restarting...\n",
827 blurb(), signal_name(sig));
829 if (si->screen_blanked_p)
832 for (i = 0; i < si->nscreens; i++)
833 kill_screenhack (&si->screens[i]);
835 XSync (si->dpy, False);
838 restart_process (si); /* Does not return */
845 saver_exit (saver_info *si, int status, const char *dump_core_reason)
847 saver_preferences *p = &si->prefs;
848 static Bool exiting = False;
857 vrs = restore_real_vroot (si);
858 emergency_kill_subproc (si);
859 shutdown_stderr (si);
861 if (p->verbose_p && vrs)
862 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
866 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
867 if (status == 0) status = 1;
868 else if (status == 1) status = -1;
871 bugp = !!dump_core_reason;
873 if (si->prefs.debug_p && !dump_core_reason)
874 dump_core_reason = "because of -debug";
876 if (dump_core_reason)
878 /* Note that the Linux man page for setuid() says If uid is
879 different from the old effective uid, the process will be
880 forbidden from leaving core dumps.
882 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
884 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
889 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
890 "\t\t\tfor bug reporting information.\n\n",
893 # if defined(HAVE_GETCWD)
894 if (!getcwd (cwd, sizeof(cwd)))
895 # elif defined(HAVE_GETWD)
898 strcpy(cwd, "unknown.");
900 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
901 describe_uids (si, real_stderr);
903 /* Do this to drop a core file, so that we can get a stack trace. */
911 /* Managing the actual screensaver window */
914 window_exists_p (Display *dpy, Window window)
916 XErrorHandler old_handler;
917 XWindowAttributes xgwa;
919 old_handler = XSetErrorHandler (BadWindow_ehandler);
920 XGetWindowAttributes (dpy, window, &xgwa);
922 XSetErrorHandler (old_handler);
923 return (xgwa.screen != 0);
927 store_saver_id (saver_screen_info *ssi)
929 XClassHint class_hints;
930 saver_info *si = ssi->global;
931 unsigned long pid = (unsigned long) getpid ();
933 struct passwd *p = getpwuid (getuid ());
934 const char *name, *host;
937 /* First store the name and class on the window.
939 class_hints.res_name = progname;
940 class_hints.res_class = progclass;
941 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
942 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
944 /* Then store the xscreensaver version number.
946 XChangeProperty (si->dpy, ssi->screensaver_window,
947 XA_SCREENSAVER_VERSION,
948 XA_STRING, 8, PropModeReplace,
949 (unsigned char *) si->version,
950 strlen (si->version));
952 /* Now store the XSCREENSAVER_ID property, that says what user and host
953 xscreensaver is running as.
956 if (p && p->pw_name && *p->pw_name)
960 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
966 # if defined(HAVE_UNAME)
969 if (uname (&uts) < 0)
975 host = getenv("SYS$NODE");
976 # else /* !HAVE_UNAME && !VMS */
978 # endif /* !HAVE_UNAME && !VMS */
980 id = (char *) malloc (strlen(name) + strlen(host) + 50);
981 sprintf (id, "%lu (%s@%s)", pid, name, host);
983 XChangeProperty (si->dpy, ssi->screensaver_window,
984 XA_SCREENSAVER_ID, XA_STRING,
986 (unsigned char *) id, strlen (id));
992 store_saver_status (saver_info *si)
995 int size = si->nscreens + 2;
998 status = (PROP32 *) calloc (size, sizeof(PROP32));
1000 status[0] = (PROP32) (si->screen_blanked_p
1001 ? (si->locked_p ? XA_LOCK : XA_BLANK)
1003 status[1] = (PROP32) si->blank_time;
1005 for (i = 0; i < si->nscreens; i++)
1007 saver_screen_info *ssi = &si->screens[i];
1008 status [2 + i] = ssi->current_hack + 1;
1011 XChangeProperty (si->dpy,
1012 RootWindow (si->dpy, 0), /* always screen #0 */
1013 XA_SCREENSAVER_STATUS,
1014 XA_INTEGER, 32, PropModeReplace,
1015 (unsigned char *) status, size);
1020 static Bool error_handler_hit_p = False;
1023 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1025 error_handler_hit_p = True;
1030 /* Returns True if successful, False if an X error occurred.
1031 We need this because other programs might have done things to
1032 our window that will cause XChangeWindowAttributes() to fail:
1033 if that happens, we give up, destroy the window, and re-create
1037 safe_XChangeWindowAttributes (Display *dpy, Window window,
1039 XSetWindowAttributes *attrs)
1041 XErrorHandler old_handler;
1043 error_handler_hit_p = False;
1044 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1046 XChangeWindowAttributes (dpy, window, mask, attrs);
1049 XSetErrorHandler (old_handler);
1052 return (!error_handler_hit_p);
1056 /* This might not be necessary, but just in case. */
1058 safe_XConfigureWindow (Display *dpy, Window window,
1059 unsigned long mask, XWindowChanges *changes)
1061 XErrorHandler old_handler;
1063 error_handler_hit_p = False;
1064 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1066 XConfigureWindow (dpy, window, mask, changes);
1069 XSetErrorHandler (old_handler);
1072 return (!error_handler_hit_p);
1075 /* This might not be necessary, but just in case. */
1077 safe_XDestroyWindow (Display *dpy, Window window)
1079 XErrorHandler old_handler;
1081 error_handler_hit_p = False;
1082 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1084 XDestroyWindow (dpy, window);
1087 XSetErrorHandler (old_handler);
1090 return (!error_handler_hit_p);
1095 safe_XKillClient (Display *dpy, XID id)
1097 XErrorHandler old_handler;
1099 error_handler_hit_p = False;
1100 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1102 XKillClient (dpy, id);
1105 XSetErrorHandler (old_handler);
1108 return (!error_handler_hit_p);
1112 #ifdef HAVE_XF86VMODE
1114 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1117 XErrorHandler old_handler;
1119 error_handler_hit_p = False;
1120 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1122 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1125 XSetErrorHandler (old_handler);
1128 return (error_handler_hit_p
1133 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1134 untrappable I/O error instead of an X error -- so one must call
1135 safe_XF86VidModeGetViewPort first, and assume that both have the
1136 same error condition. Thank you XFree, may I have another.
1139 #endif /* HAVE_XF86VMODE */
1143 initialize_screensaver_window_1 (saver_screen_info *ssi)
1145 saver_info *si = ssi->global;
1146 saver_preferences *p = &si->prefs;
1147 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1149 /* This resets the screensaver window as fully as possible, since there's
1150 no way of knowing what some random client may have done to us in the
1151 meantime. We could just destroy and recreate the window, but that has
1152 its own set of problems...
1155 XSetWindowAttributes attrs;
1156 unsigned long attrmask;
1157 static Bool printed_visual_info = False; /* only print the message once. */
1158 Window horked_window = 0;
1160 black.red = black.green = black.blue = 0;
1162 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1165 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1166 /* It's not the default visual, so we have no choice but to install. */
1167 install_cmap_p = True;
1173 ssi->cmap = XCreateColormap (si->dpy,
1174 RootWindowOfScreen (ssi->screen),
1175 ssi->current_visual, AllocNone);
1176 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1177 ssi->black_pixel = black.pixel;
1182 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1185 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1186 if (ssi->cmap != ssi->demo_cmap &&
1187 ssi->cmap != def_cmap)
1188 XFreeColormap (si->dpy, ssi->cmap);
1190 ssi->cmap = def_cmap;
1191 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1194 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1195 CWBackPixel | CWBackingPixel | CWBorderPixel);
1196 attrs.override_redirect = True;
1198 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1199 actually be reading these events during normal operation; but we still
1200 need to see Button events for demo-mode to work properly.
1202 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1203 ButtonPressMask | ButtonReleaseMask |
1206 attrs.backing_store = NotUseful;
1207 attrs.colormap = ssi->cmap;
1208 attrs.background_pixel = ssi->black_pixel;
1209 attrs.backing_pixel = ssi->black_pixel;
1210 attrs.border_pixel = ssi->black_pixel;
1212 if (!p->verbose_p || printed_visual_info)
1214 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1216 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1217 describe_visual (stderr, ssi->screen, ssi->current_visual,
1222 fprintf (stderr, "%s: using visual: ", blurb());
1223 describe_visual (stderr, ssi->screen, ssi->current_visual,
1225 fprintf (stderr, "%s: default visual: ", blurb());
1226 describe_visual (stderr, ssi->screen,
1227 DefaultVisualOfScreen (ssi->screen),
1228 ssi->install_cmap_p);
1230 printed_visual_info = True;
1232 #ifdef HAVE_MIT_SAVER_EXTENSION
1233 if (si->using_mit_saver_extension)
1235 XScreenSaverInfo *info;
1236 Window root = RootWindowOfScreen (ssi->screen);
1239 /* This call sets the server screensaver timeouts to what we think
1240 they should be (based on the resources and args xscreensaver was
1241 started with.) It's important that we do this to sync back up
1242 with the server - if we have turned on prematurely, as by an
1243 ACTIVATE ClientMessage, then the server may decide to activate
1244 the screensaver while it's already active. That's ok for us,
1245 since we would know to ignore that ScreenSaverActivate event,
1246 but a side effect of this would be that the server would map its
1247 saver window (which we then hide again right away) meaning that
1248 the bits currently on the screen get blown away. Ugly. */
1250 /* #### Ok, that doesn't work - when we tell the server that the
1251 screensaver is "off" it sends us a Deactivate event, which is
1252 sensible... but causes the saver to never come on. Hmm. */
1253 disable_builtin_screensaver (si, True);
1257 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1258 window that the server itself uses for saving the screen.
1259 However, using this window in any way, in particular, calling
1260 XScreenSaverSetAttributes() as below, tends to make the X server
1261 crash. So fuck it, let's try and get along without using it...
1263 It's also inconvenient to use this window because it doesn't
1264 always exist (though the ID is constant.) So to use this
1265 window, we'd have to reimplement the ACTIVATE ClientMessage to
1266 tell the *server* to tell *us* to turn on, to cause the window
1267 to get created at the right time. Gag. */
1268 XScreenSaverSetAttributes (si->dpy, root,
1269 0, 0, width, height, 0,
1270 current_depth, InputOutput, visual,
1272 XSync (si->dpy, False);
1275 info = XScreenSaverAllocInfo ();
1276 XScreenSaverQueryInfo (si->dpy, root, info);
1277 ssi->server_mit_saver_window = info->window;
1278 if (! ssi->server_mit_saver_window) abort ();
1281 #endif /* HAVE_MIT_SAVER_EXTENSION */
1283 if (ssi->screensaver_window)
1285 XWindowChanges changes;
1286 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1289 changes.width = ssi->width;
1290 changes.height = ssi->height;
1291 changes.border_width = 0;
1293 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1294 changesmask, &changes) &&
1295 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1298 horked_window = ssi->screensaver_window;
1299 ssi->screensaver_window = 0;
1303 if (!ssi->screensaver_window)
1305 ssi->screensaver_window =
1306 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1307 ssi->x, ssi->y, ssi->width, ssi->height,
1308 0, ssi->current_depth, InputOutput,
1309 ssi->current_visual, attrmask, &attrs);
1315 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1316 blurb(), (unsigned long) horked_window);
1317 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1319 safe_XDestroyWindow (si->dpy, horked_window);
1324 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1325 blurb(), ssi->number,
1326 (unsigned long) ssi->screensaver_window);
1329 store_saver_id (ssi); /* store window name and IDs */
1334 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1336 BlackPixelOfScreen (ssi->screen),
1337 BlackPixelOfScreen (ssi->screen),
1339 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1341 XFreePixmap (si->dpy, bit);
1344 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1347 XUndefineCursor (si->dpy, ssi->screensaver_window);
1349 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1353 initialize_screensaver_window (saver_info *si)
1356 for (i = 0; i < si->nscreens; i++)
1357 initialize_screensaver_window_1 (&si->screens[i]);
1361 /* Called when the RANDR (Resize and Rotate) extension tells us that
1362 the size of the screen has changed while the screen was blanked.
1363 Call update_screen_layout() first, then call this to synchronize
1364 the size of the saver windows to the new sizes of the screens.
1367 resize_screensaver_window (saver_info *si)
1369 saver_preferences *p = &si->prefs;
1372 for (i = 0; i < si->nscreens; i++)
1374 saver_screen_info *ssi = &si->screens[i];
1375 XWindowAttributes xgwa;
1377 /* Make sure a window exists -- it might not if a monitor was just
1378 added for the first time.
1380 if (! ssi->screensaver_window)
1382 initialize_screensaver_window_1 (ssi);
1385 "%s: %d: newly added window 0x%lx %dx%d+%d+%d\n",
1386 blurb(), i, (unsigned long) ssi->screensaver_window,
1387 ssi->width, ssi->height, ssi->x, ssi->y);
1390 /* Make sure the window is the right size -- it might not be if
1391 the monitor changed resolution, or if a badly-behaved hack
1394 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1395 if (xgwa.x != ssi->x ||
1397 xgwa.width != ssi->width ||
1398 xgwa.height != ssi->height)
1400 XWindowChanges changes;
1401 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1404 changes.width = ssi->width;
1405 changes.height = ssi->height;
1406 changes.border_width = 0;
1410 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1411 blurb(), i, (unsigned long) ssi->screensaver_window,
1412 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1413 ssi->width, ssi->height, ssi->x, ssi->y);
1415 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1416 changesmask, &changes))
1417 fprintf (stderr, "%s: %d: someone horked our saver window"
1418 " (0x%lx)! Unable to resize it!\n",
1419 blurb(), i, (unsigned long) ssi->screensaver_window);
1422 /* Now (if blanked) make sure that it's mapped and running a hack --
1423 it might not be if we just added it. (We also might be re-using
1424 an old window that existed for a previous monitor that was
1425 removed and re-added.)
1427 Note that spawn_screenhack() calls select_visual() which may destroy
1428 and re-create the window via initialize_screensaver_window_1().
1430 if (si->screen_blanked_p)
1433 XInstallColormap (si->dpy, ssi->cmap);
1434 XMapRaised (si->dpy, ssi->screensaver_window);
1436 spawn_screenhack (ssi);
1438 /* Make sure the act of adding a screen doesn't present as
1439 pointer motion (and thus cause an unblank). */
1444 XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
1445 &ssi->poll_mouse_last_root_x,
1446 &ssi->poll_mouse_last_root_y,
1452 /* Kill off any savers running on no-longer-extant monitors.
1454 for (; i < si->ssi_count; i++)
1456 saver_screen_info *ssi = &si->screens[i];
1458 kill_screenhack (ssi);
1459 if (ssi->screensaver_window)
1461 XUnmapWindow (si->dpy, ssi->screensaver_window);
1462 restore_real_vroot_1 (ssi);
1469 raise_window (saver_info *si,
1470 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1472 saver_preferences *p = &si->prefs;
1476 inhibit_fade = True;
1478 if (si->emergency_lock_p)
1479 inhibit_fade = True;
1482 initialize_screensaver_window (si);
1484 reset_watchdog_timer (si, True);
1486 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1488 Window *current_windows = (Window *)
1489 calloc(sizeof(Window), si->nscreens);
1490 Colormap *current_maps = (Colormap *)
1491 calloc(sizeof(Colormap), si->nscreens);
1493 for (i = 0; i < si->nscreens; i++)
1495 saver_screen_info *ssi = &si->screens[i];
1496 current_windows[i] = ssi->screensaver_window;
1497 current_maps[i] = (between_hacks_p
1499 : DefaultColormapOfScreen (ssi->screen));
1500 /* Ensure that the default background of the window is really black,
1501 not a pixmap or something. (This does not clear the window.) */
1502 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1506 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1508 XGrabServer (si->dpy); /* ############ DANGER! */
1510 /* Clear the stderr layer on each screen.
1513 for (i = 0; i < si->nscreens; i++)
1515 saver_screen_info *ssi = &si->screens[i];
1516 if (ssi->stderr_overlay_window)
1517 /* Do this before the fade, since the stderr cmap won't fade
1518 even if we uninstall it (beats me...) */
1522 /* Note! The server is grabbed, and this will take several seconds
1524 fade_screens (si->dpy, current_maps,
1525 current_windows, si->nscreens,
1526 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1529 free(current_windows);
1531 current_windows = 0;
1533 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1535 #ifdef HAVE_MIT_SAVER_EXTENSION
1536 for (i = 0; i < si->nscreens; i++)
1538 saver_screen_info *ssi = &si->screens[i];
1539 if (ssi->server_mit_saver_window &&
1540 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1541 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1543 #endif /* HAVE_MIT_SAVER_EXTENSION */
1545 XUngrabServer (si->dpy);
1546 XSync (si->dpy, False); /* ###### (danger over) */
1550 for (i = 0; i < si->nscreens; i++)
1552 saver_screen_info *ssi = &si->screens[i];
1554 XClearWindow (si->dpy, ssi->screensaver_window);
1555 if (!dont_clear || ssi->stderr_overlay_window)
1557 XMapRaised (si->dpy, ssi->screensaver_window);
1558 #ifdef HAVE_MIT_SAVER_EXTENSION
1559 if (ssi->server_mit_saver_window &&
1560 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1561 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1562 #endif /* HAVE_MIT_SAVER_EXTENSION */
1566 for (i = 0; i < si->nscreens; i++)
1568 saver_screen_info *ssi = &si->screens[i];
1570 XInstallColormap (si->dpy, ssi->cmap);
1576 mouse_screen (saver_info *si)
1578 saver_preferences *p = &si->prefs;
1579 Window pointer_root, pointer_child;
1580 int root_x, root_y, win_x, win_y;
1584 if (si->nscreens == 1)
1587 for (i = 0; i < si->nscreens; i++)
1589 saver_screen_info *ssi = &si->screens[i];
1590 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1591 &pointer_root, &pointer_child,
1592 &root_x, &root_y, &win_x, &win_y, &mask) &&
1595 root_x < ssi->x + ssi->width &&
1596 root_y < ssi->y + ssi->height)
1599 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1600 blurb(), i, si->nscreens);
1605 /* couldn't figure out where the mouse is? Oh well. */
1611 blank_screen (saver_info *si)
1618 /* Note: we do our grabs on the root window, not on the screensaver window.
1619 If we grabbed on the saver window, then the demo mode and lock dialog
1620 boxes wouldn't get any events.
1622 By "the root window", we mean "the root window that contains the mouse."
1623 We use to always grab the mouse on screen 0, but that has the effect of
1624 moving the mouse to screen 0 from whichever screen it was on, on
1627 mscreen = mouse_screen (si);
1628 w = RootWindowOfScreen(si->screens[mscreen].screen);
1629 ok = grab_keyboard_and_mouse (si, w,
1630 (si->demoing_p ? 0 : si->screens[0].cursor),
1635 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1636 /* If we're using a server extension, then failure to get a grab is
1637 not a big deal -- even without the grab, we will still be able
1638 to un-blank when there is user activity, since the server will
1640 /* #### No, that's not true: if we don't have a keyboard grab,
1641 then we can't read passwords to unlock.
1649 for (i = 0; i < si->nscreens; i++)
1651 saver_screen_info *ssi = &si->screens[i];
1652 if (ssi->real_screen_p)
1653 save_real_vroot (ssi);
1654 store_vroot_property (si->dpy,
1655 ssi->screensaver_window,
1656 ssi->screensaver_window);
1658 #ifdef HAVE_XF86VMODE
1661 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1662 !safe_XF86VidModeGetViewPort (si->dpy, i,
1665 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1667 #endif /* HAVE_XF86VMODE */
1670 raise_window (si, False, False, False);
1672 si->screen_blanked_p = True;
1673 si->blank_time = time ((time_t) 0);
1674 si->last_wall_clock_time = 0;
1676 store_saver_status (si); /* store blank time */
1683 unblank_screen (saver_info *si)
1685 saver_preferences *p = &si->prefs;
1686 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1689 monitor_power_on (si);
1690 reset_watchdog_timer (si, False);
1697 Window *current_windows = (Window *)
1698 calloc(sizeof(Window), si->nscreens);
1700 for (i = 0; i < si->nscreens; i++)
1702 saver_screen_info *ssi = &si->screens[i];
1703 current_windows[i] = ssi->screensaver_window;
1704 /* Ensure that the default background of the window is really black,
1705 not a pixmap or something. (This does not clear the window.) */
1706 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1710 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1713 XSync (si->dpy, False);
1714 XGrabServer (si->dpy); /* ############ DANGER! */
1715 XSync (si->dpy, False);
1717 /* Clear the stderr layer on each screen.
1719 for (i = 0; i < si->nscreens; i++)
1721 saver_screen_info *ssi = &si->screens[i];
1725 XUngrabServer (si->dpy);
1726 XSync (si->dpy, False); /* ###### (danger over) */
1728 fade_screens (si->dpy, 0,
1729 current_windows, si->nscreens,
1730 p->fade_seconds/1000, p->fade_ticks,
1733 free(current_windows);
1734 current_windows = 0;
1736 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1740 for (i = 0; i < si->nscreens; i++)
1742 saver_screen_info *ssi = &si->screens[i];
1745 Colormap c = DefaultColormapOfScreen (ssi->screen);
1746 /* avoid technicolor */
1747 XClearWindow (si->dpy, ssi->screensaver_window);
1748 if (c) XInstallColormap (si->dpy, c);
1750 XUnmapWindow (si->dpy, ssi->screensaver_window);
1755 /* If the focus window does has a non-default colormap, then install
1756 that colormap as well. (On SGIs, this will cause both the root map
1757 and the focus map to be installed simultaneously. It'd be nice to
1758 pick up the other colormaps that had been installed, too; perhaps
1759 XListInstalledColormaps could be used for that?)
1764 XGetInputFocus (si->dpy, &focus, &revert_to);
1765 if (focus && focus != PointerRoot && focus != None)
1767 XWindowAttributes xgwa;
1769 XGetWindowAttributes (si->dpy, focus, &xgwa);
1770 if (xgwa.colormap &&
1771 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1772 XInstallColormap (si->dpy, xgwa.colormap);
1777 for (i = 0; i < si->nscreens; i++)
1779 saver_screen_info *ssi = &si->screens[i];
1780 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1783 store_saver_status (si); /* store unblank time */
1784 ungrab_keyboard_and_mouse (si);
1785 restore_real_vroot (si);
1787 /* Unmap the windows a second time, dammit -- just to avoid a race
1788 with the screen-grabbing hacks. (I'm not sure if this is really
1789 necessary; I'm stabbing in the dark now.)
1791 for (i = 0; i < si->nscreens; i++)
1792 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1794 si->screen_blanked_p = False;
1795 si->blank_time = time ((time_t) 0);
1796 si->last_wall_clock_time = 0;
1798 store_saver_status (si); /* store unblank time */
1802 /* Transfer any grabs from the old window to the new.
1803 Actually I think none of this is necessary, since we always
1804 hold our grabs on the root window, but I wrote this before
1805 re-discovering that...
1808 maybe_transfer_grabs (saver_screen_info *ssi,
1809 Window old_w, Window new_w,
1812 saver_info *si = ssi->global;
1814 /* If the old window held our mouse grab, transfer the grab to the new
1815 window. (Grab the server while so doing, to avoid a race condition.)
1817 if (old_w == si->mouse_grab_window)
1819 XGrabServer (si->dpy); /* ############ DANGER! */
1821 grab_mouse (si, ssi->screensaver_window,
1822 (si->demoing_p ? 0 : ssi->cursor),
1824 XUngrabServer (si->dpy);
1825 XSync (si->dpy, False); /* ###### (danger over) */
1828 /* If the old window held our keyboard grab, transfer the grab to the new
1829 window. (Grab the server while so doing, to avoid a race condition.)
1831 if (old_w == si->keyboard_grab_window)
1833 XGrabServer (si->dpy); /* ############ DANGER! */
1835 grab_kbd(si, ssi->screensaver_window, ssi->number);
1836 XUngrabServer (si->dpy);
1837 XSync (si->dpy, False); /* ###### (danger over) */
1843 get_screen_gl_visual (saver_info *si, int real_screen_number)
1846 int nscreens = ScreenCount (si->dpy);
1848 if (! si->best_gl_visuals)
1849 si->best_gl_visuals = (Visual **)
1850 calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
1852 for (i = 0; i < nscreens; i++)
1853 if (! si->best_gl_visuals[i])
1854 si->best_gl_visuals[i] =
1855 get_best_gl_visual (si, ScreenOfDisplay (si->dpy, i));
1857 if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
1858 return si->best_gl_visuals[real_screen_number];
1863 select_visual (saver_screen_info *ssi, const char *visual_name)
1865 XWindowAttributes xgwa;
1866 saver_info *si = ssi->global;
1867 saver_preferences *p = &si->prefs;
1868 Bool install_cmap_p = p->install_cmap_p;
1869 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1873 /* On some systems (most recently, MacOS X) OpenGL programs get confused
1874 when you kill one and re-start another on the same window. So maybe
1875 it's best to just always destroy and recreate the xscreensaver window
1876 when changing hacks, instead of trying to reuse the old one?
1878 Bool always_recreate_window_p = True;
1880 get_screen_gl_visual (si, 0); /* let's probe all the GL visuals early */
1882 /* We make sure the existing window is actually on ssi->screen before
1883 trying to use it, in case things moved around radically when monitors
1884 were added or deleted. If we don't do this we could get a BadMatch
1885 even though the depths match. I think.
1887 memset (&xgwa, 0, sizeof(xgwa));
1888 if (ssi->screensaver_window)
1889 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1891 if (visual_name && *visual_name)
1893 if (!strcmp(visual_name, "default-i") ||
1894 !strcmp(visual_name, "Default-i") ||
1895 !strcmp(visual_name, "Default-I")
1898 visual_name = "default";
1899 install_cmap_p = True;
1901 else if (!strcmp(visual_name, "default-n") ||
1902 !strcmp(visual_name, "Default-n") ||
1903 !strcmp(visual_name, "Default-N"))
1905 visual_name = "default";
1906 install_cmap_p = False;
1908 else if (!strcmp(visual_name, "gl") ||
1909 !strcmp(visual_name, "Gl") ||
1910 !strcmp(visual_name, "GL"))
1912 new_v = get_screen_gl_visual (si, ssi->real_screen_number);
1913 if (!new_v && p->verbose_p)
1914 fprintf (stderr, "%s: no GL visuals.\n", progname);
1918 new_v = get_visual (ssi->screen, visual_name, True, False);
1922 new_v = ssi->default_visual;
1927 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1928 /* It's not the default visual, so we have no choice but to install. */
1929 install_cmap_p = True;
1931 ssi->install_cmap_p = install_cmap_p;
1933 if ((ssi->screen != xgwa.screen) ||
1935 (always_recreate_window_p ||
1936 (ssi->current_visual != new_v) ||
1937 (install_cmap_p != was_installed_p))))
1939 Colormap old_c = ssi->cmap;
1940 Window old_w = ssi->screensaver_window;
1942 new_v = ssi->current_visual;
1946 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1947 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1949 fprintf (stderr, "%s: from ", blurb());
1950 describe_visual (stderr, ssi->screen, ssi->current_visual,
1956 ssi->current_visual = new_v;
1957 ssi->current_depth = visual_depth(ssi->screen, new_v);
1959 ssi->screensaver_window = 0;
1961 initialize_screensaver_window_1 (ssi);
1963 /* stderr_overlay_window is a child of screensaver_window, so we need
1964 to destroy that as well (actually, we just need to invalidate and
1965 drop our pointers to it, but this will destroy it, which is ok so
1966 long as it happens before old_w itself is destroyed.) */
1969 raise_window (si, True, True, False);
1970 store_vroot_property (si->dpy,
1971 ssi->screensaver_window, ssi->screensaver_window);
1973 /* Transfer any grabs from the old window to the new. */
1974 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1976 /* Now we can destroy the old window without horking our grabs. */
1977 XDestroyWindow (si->dpy, old_w);
1980 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1981 blurb(), ssi->number, (unsigned long) old_w);
1984 old_c != DefaultColormapOfScreen (ssi->screen) &&
1985 old_c != ssi->demo_cmap)
1986 XFreeColormap (si->dpy, old_c);