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_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 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 http://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;
948 /* First store the name and class on the window.
950 class_hints.res_name = progname;
951 class_hints.res_class = progclass;
952 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
953 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
955 /* Then store the xscreensaver version number.
957 XChangeProperty (si->dpy, ssi->screensaver_window,
958 XA_SCREENSAVER_VERSION,
959 XA_STRING, 8, PropModeReplace,
960 (unsigned char *) si->version,
961 strlen (si->version));
963 /* Now store the XSCREENSAVER_ID property, that says what user and host
964 xscreensaver is running as.
967 if (p && p->pw_name && *p->pw_name)
971 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
977 # if defined(HAVE_UNAME)
980 if (uname (&uts) < 0)
986 host = getenv("SYS$NODE");
987 # else /* !HAVE_UNAME && !VMS */
989 # endif /* !HAVE_UNAME && !VMS */
991 id = (char *) malloc (strlen(name) + strlen(host) + 50);
992 sprintf (id, "%lu (%s@%s)", pid, name, host);
994 XChangeProperty (si->dpy, ssi->screensaver_window,
995 XA_SCREENSAVER_ID, XA_STRING,
997 (unsigned char *) id, strlen (id));
1003 store_saver_status (saver_info *si)
1006 int size = si->nscreens + 2;
1009 status = (PROP32 *) calloc (size, sizeof(PROP32));
1011 status[0] = (PROP32) (si->screen_blanked_p
1012 ? (si->locked_p ? XA_LOCK : XA_BLANK)
1014 status[1] = (PROP32) si->blank_time;
1016 for (i = 0; i < si->nscreens; i++)
1018 saver_screen_info *ssi = &si->screens[i];
1019 status [2 + i] = ssi->current_hack + 1;
1022 XChangeProperty (si->dpy,
1023 RootWindow (si->dpy, 0), /* always screen #0 */
1024 XA_SCREENSAVER_STATUS,
1025 XA_INTEGER, 32, PropModeReplace,
1026 (unsigned char *) status, size);
1031 static Bool error_handler_hit_p = False;
1034 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1036 error_handler_hit_p = True;
1041 /* Returns True if successful, False if an X error occurred.
1042 We need this because other programs might have done things to
1043 our window that will cause XChangeWindowAttributes() to fail:
1044 if that happens, we give up, destroy the window, and re-create
1048 safe_XChangeWindowAttributes (Display *dpy, Window window,
1050 XSetWindowAttributes *attrs)
1052 XErrorHandler old_handler;
1054 error_handler_hit_p = False;
1055 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1057 XChangeWindowAttributes (dpy, window, mask, attrs);
1060 XSetErrorHandler (old_handler);
1063 return (!error_handler_hit_p);
1067 /* This might not be necessary, but just in case. */
1069 safe_XConfigureWindow (Display *dpy, Window window,
1070 unsigned long mask, XWindowChanges *changes)
1072 XErrorHandler old_handler;
1074 error_handler_hit_p = False;
1075 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1077 XConfigureWindow (dpy, window, mask, changes);
1080 XSetErrorHandler (old_handler);
1083 return (!error_handler_hit_p);
1086 /* This might not be necessary, but just in case. */
1088 safe_XDestroyWindow (Display *dpy, Window window)
1090 XErrorHandler old_handler;
1092 error_handler_hit_p = False;
1093 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1095 XDestroyWindow (dpy, window);
1098 XSetErrorHandler (old_handler);
1101 return (!error_handler_hit_p);
1106 safe_XKillClient (Display *dpy, XID id)
1108 XErrorHandler old_handler;
1110 error_handler_hit_p = False;
1111 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1113 XKillClient (dpy, id);
1116 XSetErrorHandler (old_handler);
1119 return (!error_handler_hit_p);
1123 #ifdef HAVE_XF86VMODE
1125 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1128 XErrorHandler old_handler;
1130 error_handler_hit_p = False;
1131 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1133 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1136 XSetErrorHandler (old_handler);
1139 return (error_handler_hit_p
1144 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1145 untrappable I/O error instead of an X error -- so one must call
1146 safe_XF86VidModeGetViewPort first, and assume that both have the
1147 same error condition. Thank you XFree, may I have another.
1150 #endif /* HAVE_XF86VMODE */
1154 initialize_screensaver_window_1 (saver_screen_info *ssi)
1156 saver_info *si = ssi->global;
1157 saver_preferences *p = &si->prefs;
1158 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1160 /* This resets the screensaver window as fully as possible, since there's
1161 no way of knowing what some random client may have done to us in the
1162 meantime. We could just destroy and recreate the window, but that has
1163 its own set of problems...
1166 XSetWindowAttributes attrs;
1167 unsigned long attrmask;
1168 static Bool printed_visual_info = False; /* only print the message once. */
1169 Window horked_window = 0;
1171 black.red = black.green = black.blue = 0;
1173 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1176 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1177 /* It's not the default visual, so we have no choice but to install. */
1178 install_cmap_p = True;
1184 ssi->cmap = XCreateColormap (si->dpy,
1185 RootWindowOfScreen (ssi->screen),
1186 ssi->current_visual, AllocNone);
1187 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1188 ssi->black_pixel = black.pixel;
1193 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1196 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1197 if (ssi->cmap != ssi->demo_cmap &&
1198 ssi->cmap != def_cmap)
1199 XFreeColormap (si->dpy, ssi->cmap);
1201 ssi->cmap = def_cmap;
1202 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1205 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1206 CWBackPixel | CWBackingPixel | CWBorderPixel);
1207 attrs.override_redirect = True;
1209 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1210 actually be reading these events during normal operation; but we still
1211 need to see Button events for demo-mode to work properly.
1213 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1214 ButtonPressMask | ButtonReleaseMask |
1217 attrs.backing_store = NotUseful;
1218 attrs.colormap = ssi->cmap;
1219 attrs.background_pixel = ssi->black_pixel;
1220 attrs.backing_pixel = ssi->black_pixel;
1221 attrs.border_pixel = ssi->black_pixel;
1223 if (!p->verbose_p || printed_visual_info)
1225 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1227 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1228 describe_visual (stderr, ssi->screen, ssi->current_visual,
1233 fprintf (stderr, "%s: using visual: ", blurb());
1234 describe_visual (stderr, ssi->screen, ssi->current_visual,
1236 fprintf (stderr, "%s: default visual: ", blurb());
1237 describe_visual (stderr, ssi->screen,
1238 DefaultVisualOfScreen (ssi->screen),
1239 ssi->install_cmap_p);
1241 printed_visual_info = True;
1243 #ifdef HAVE_MIT_SAVER_EXTENSION
1244 if (si->using_mit_saver_extension)
1246 XScreenSaverInfo *info;
1247 Window root = RootWindowOfScreen (ssi->screen);
1250 /* This call sets the server screensaver timeouts to what we think
1251 they should be (based on the resources and args xscreensaver was
1252 started with.) It's important that we do this to sync back up
1253 with the server - if we have turned on prematurely, as by an
1254 ACTIVATE ClientMessage, then the server may decide to activate
1255 the screensaver while it's already active. That's ok for us,
1256 since we would know to ignore that ScreenSaverActivate event,
1257 but a side effect of this would be that the server would map its
1258 saver window (which we then hide again right away) meaning that
1259 the bits currently on the screen get blown away. Ugly. */
1261 /* #### Ok, that doesn't work - when we tell the server that the
1262 screensaver is "off" it sends us a Deactivate event, which is
1263 sensible... but causes the saver to never come on. Hmm. */
1264 disable_builtin_screensaver (si, True);
1268 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1269 window that the server itself uses for saving the screen.
1270 However, using this window in any way, in particular, calling
1271 XScreenSaverSetAttributes() as below, tends to make the X server
1272 crash. So fuck it, let's try and get along without using it...
1274 It's also inconvenient to use this window because it doesn't
1275 always exist (though the ID is constant.) So to use this
1276 window, we'd have to reimplement the ACTIVATE ClientMessage to
1277 tell the *server* to tell *us* to turn on, to cause the window
1278 to get created at the right time. Gag. */
1279 XScreenSaverSetAttributes (si->dpy, root,
1280 0, 0, width, height, 0,
1281 current_depth, InputOutput, visual,
1283 XSync (si->dpy, False);
1286 info = XScreenSaverAllocInfo ();
1287 XScreenSaverQueryInfo (si->dpy, root, info);
1288 ssi->server_mit_saver_window = info->window;
1289 if (! ssi->server_mit_saver_window) abort ();
1292 #endif /* HAVE_MIT_SAVER_EXTENSION */
1294 if (ssi->screensaver_window)
1296 XWindowChanges changes;
1297 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1300 changes.width = ssi->width;
1301 changes.height = ssi->height;
1302 changes.border_width = 0;
1304 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1305 changesmask, &changes) &&
1306 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1309 horked_window = ssi->screensaver_window;
1310 ssi->screensaver_window = 0;
1314 if (!ssi->screensaver_window)
1316 ssi->screensaver_window =
1317 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1318 ssi->x, ssi->y, ssi->width, ssi->height,
1319 0, ssi->current_depth, InputOutput,
1320 ssi->current_visual, attrmask, &attrs);
1326 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1327 blurb(), (unsigned long) horked_window);
1328 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1330 safe_XDestroyWindow (si->dpy, horked_window);
1335 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1336 blurb(), ssi->number,
1337 (unsigned long) ssi->screensaver_window);
1340 store_saver_id (ssi); /* store window name and IDs */
1345 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1347 BlackPixelOfScreen (ssi->screen),
1348 BlackPixelOfScreen (ssi->screen),
1350 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1352 XFreePixmap (si->dpy, bit);
1355 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1358 XUndefineCursor (si->dpy, ssi->screensaver_window);
1360 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1364 initialize_screensaver_window (saver_info *si)
1367 for (i = 0; i < si->nscreens; i++)
1368 initialize_screensaver_window_1 (&si->screens[i]);
1372 /* Called when the RANDR (Resize and Rotate) extension tells us that
1373 the size of the screen has changed while the screen was blanked.
1374 Call update_screen_layout() first, then call this to synchronize
1375 the size of the saver windows to the new sizes of the screens.
1378 resize_screensaver_window (saver_info *si)
1380 saver_preferences *p = &si->prefs;
1383 for (i = 0; i < si->nscreens; i++)
1385 saver_screen_info *ssi = &si->screens[i];
1386 XWindowAttributes xgwa;
1388 /* Make sure a window exists -- it might not if a monitor was just
1389 added for the first time.
1391 if (! ssi->screensaver_window)
1393 initialize_screensaver_window_1 (ssi);
1396 "%s: %d: newly added window 0x%lx %dx%d+%d+%d\n",
1397 blurb(), i, (unsigned long) ssi->screensaver_window,
1398 ssi->width, ssi->height, ssi->x, ssi->y);
1401 /* Make sure the window is the right size -- it might not be if
1402 the monitor changed resolution, or if a badly-behaved hack
1405 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1406 if (xgwa.x != ssi->x ||
1408 xgwa.width != ssi->width ||
1409 xgwa.height != ssi->height)
1411 XWindowChanges changes;
1412 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1415 changes.width = ssi->width;
1416 changes.height = ssi->height;
1417 changes.border_width = 0;
1421 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1422 blurb(), i, (unsigned long) ssi->screensaver_window,
1423 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1424 ssi->width, ssi->height, ssi->x, ssi->y);
1426 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1427 changesmask, &changes))
1428 fprintf (stderr, "%s: %d: someone horked our saver window"
1429 " (0x%lx)! Unable to resize it!\n",
1430 blurb(), i, (unsigned long) ssi->screensaver_window);
1433 /* Now (if blanked) make sure that it's mapped and running a hack --
1434 it might not be if we just added it. (We also might be re-using
1435 an old window that existed for a previous monitor that was
1436 removed and re-added.)
1438 Note that spawn_screenhack() calls select_visual() which may destroy
1439 and re-create the window via initialize_screensaver_window_1().
1441 if (si->screen_blanked_p)
1444 XInstallColormap (si->dpy, ssi->cmap);
1445 XMapRaised (si->dpy, ssi->screensaver_window);
1447 spawn_screenhack (ssi);
1449 /* Make sure the act of adding a screen doesn't present as
1450 pointer motion (and thus cause an unblank). */
1455 XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
1456 &ssi->last_poll_mouse.root_x,
1457 &ssi->last_poll_mouse.root_y,
1463 /* Kill off any savers running on no-longer-extant monitors.
1465 for (; i < si->ssi_count; i++)
1467 saver_screen_info *ssi = &si->screens[i];
1469 kill_screenhack (ssi);
1470 if (ssi->screensaver_window)
1472 XUnmapWindow (si->dpy, ssi->screensaver_window);
1473 restore_real_vroot_1 (ssi);
1480 raise_window (saver_info *si,
1481 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1483 saver_preferences *p = &si->prefs;
1487 inhibit_fade = True;
1489 if (si->emergency_lock_p)
1490 inhibit_fade = True;
1493 initialize_screensaver_window (si);
1495 reset_watchdog_timer (si, True);
1497 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1499 Window *current_windows = (Window *)
1500 calloc(sizeof(Window), si->nscreens);
1501 Colormap *current_maps = (Colormap *)
1502 calloc(sizeof(Colormap), si->nscreens);
1504 for (i = 0; i < si->nscreens; i++)
1506 saver_screen_info *ssi = &si->screens[i];
1507 current_windows[i] = ssi->screensaver_window;
1508 current_maps[i] = (between_hacks_p
1510 : DefaultColormapOfScreen (ssi->screen));
1511 /* Ensure that the default background of the window is really black,
1512 not a pixmap or something. (This does not clear the window.) */
1513 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1517 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1519 XGrabServer (si->dpy); /* ############ DANGER! */
1521 /* Clear the stderr layer on each screen.
1524 for (i = 0; i < si->nscreens; i++)
1526 saver_screen_info *ssi = &si->screens[i];
1527 if (ssi->stderr_overlay_window)
1528 /* Do this before the fade, since the stderr cmap won't fade
1529 even if we uninstall it (beats me...) */
1533 /* Note! The server is grabbed, and this will take several seconds
1535 fade_screens (si->dpy, current_maps,
1536 current_windows, si->nscreens,
1537 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1540 free(current_windows);
1542 current_windows = 0;
1544 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1546 #ifdef HAVE_MIT_SAVER_EXTENSION
1547 for (i = 0; i < si->nscreens; i++)
1549 saver_screen_info *ssi = &si->screens[i];
1550 if (ssi->server_mit_saver_window &&
1551 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1552 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1554 #endif /* HAVE_MIT_SAVER_EXTENSION */
1556 XUngrabServer (si->dpy);
1557 XSync (si->dpy, False); /* ###### (danger over) */
1561 for (i = 0; i < si->nscreens; i++)
1563 saver_screen_info *ssi = &si->screens[i];
1565 XClearWindow (si->dpy, ssi->screensaver_window);
1566 if (!dont_clear || ssi->stderr_overlay_window)
1568 XMapRaised (si->dpy, ssi->screensaver_window);
1569 #ifdef HAVE_MIT_SAVER_EXTENSION
1570 if (ssi->server_mit_saver_window &&
1571 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1572 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1573 #endif /* HAVE_MIT_SAVER_EXTENSION */
1577 for (i = 0; i < si->nscreens; i++)
1579 saver_screen_info *ssi = &si->screens[i];
1581 XInstallColormap (si->dpy, ssi->cmap);
1587 mouse_screen (saver_info *si)
1589 saver_preferences *p = &si->prefs;
1590 Window pointer_root, pointer_child;
1591 int root_x, root_y, win_x, win_y;
1595 if (si->nscreens == 1)
1598 for (i = 0; i < si->nscreens; i++)
1600 saver_screen_info *ssi = &si->screens[i];
1601 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1602 &pointer_root, &pointer_child,
1603 &root_x, &root_y, &win_x, &win_y, &mask) &&
1606 root_x < ssi->x + ssi->width &&
1607 root_y < ssi->y + ssi->height)
1610 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1611 blurb(), i, si->nscreens);
1616 /* couldn't figure out where the mouse is? Oh well. */
1622 blank_screen (saver_info *si)
1629 /* Note: we do our grabs on the root window, not on the screensaver window.
1630 If we grabbed on the saver window, then the demo mode and lock dialog
1631 boxes wouldn't get any events.
1633 By "the root window", we mean "the root window that contains the mouse."
1634 We use to always grab the mouse on screen 0, but that has the effect of
1635 moving the mouse to screen 0 from whichever screen it was on, on
1638 mscreen = mouse_screen (si);
1639 w = RootWindowOfScreen(si->screens[mscreen].screen);
1640 ok = grab_keyboard_and_mouse (si, w,
1641 (si->demoing_p ? 0 : si->screens[0].cursor),
1646 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1647 /* If we're using a server extension, then failure to get a grab is
1648 not a big deal -- even without the grab, we will still be able
1649 to un-blank when there is user activity, since the server will
1651 /* #### No, that's not true: if we don't have a keyboard grab,
1652 then we can't read passwords to unlock.
1660 for (i = 0; i < si->nscreens; i++)
1662 saver_screen_info *ssi = &si->screens[i];
1663 if (ssi->real_screen_p)
1664 save_real_vroot (ssi);
1665 store_vroot_property (si->dpy,
1666 ssi->screensaver_window,
1667 ssi->screensaver_window);
1669 #ifdef HAVE_XF86VMODE
1672 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1673 !safe_XF86VidModeGetViewPort (si->dpy, i,
1676 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1678 #endif /* HAVE_XF86VMODE */
1681 raise_window (si, False, False, False);
1683 si->screen_blanked_p = True;
1684 si->blank_time = time ((time_t) 0);
1685 si->last_wall_clock_time = 0;
1687 store_saver_status (si); /* store blank time */
1694 unblank_screen (saver_info *si)
1696 saver_preferences *p = &si->prefs;
1697 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1700 monitor_power_on (si, True);
1701 reset_watchdog_timer (si, False);
1708 Window *current_windows = (Window *)
1709 calloc(sizeof(Window), si->nscreens);
1711 for (i = 0; i < si->nscreens; i++)
1713 saver_screen_info *ssi = &si->screens[i];
1714 current_windows[i] = ssi->screensaver_window;
1715 /* Ensure that the default background of the window is really black,
1716 not a pixmap or something. (This does not clear the window.) */
1717 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1721 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1724 XSync (si->dpy, False);
1725 XGrabServer (si->dpy); /* ############ DANGER! */
1726 XSync (si->dpy, False);
1728 /* Clear the stderr layer on each screen.
1730 for (i = 0; i < si->nscreens; i++)
1732 saver_screen_info *ssi = &si->screens[i];
1736 XUngrabServer (si->dpy);
1737 XSync (si->dpy, False); /* ###### (danger over) */
1739 fade_screens (si->dpy, 0,
1740 current_windows, si->nscreens,
1741 p->fade_seconds/1000, p->fade_ticks,
1744 free(current_windows);
1745 current_windows = 0;
1747 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1751 for (i = 0; i < si->nscreens; i++)
1753 saver_screen_info *ssi = &si->screens[i];
1756 Colormap c = DefaultColormapOfScreen (ssi->screen);
1757 /* avoid technicolor */
1758 XClearWindow (si->dpy, ssi->screensaver_window);
1759 if (c) XInstallColormap (si->dpy, c);
1761 XUnmapWindow (si->dpy, ssi->screensaver_window);
1766 /* If the focus window does has a non-default colormap, then install
1767 that colormap as well. (On SGIs, this will cause both the root map
1768 and the focus map to be installed simultaneously. It'd be nice to
1769 pick up the other colormaps that had been installed, too; perhaps
1770 XListInstalledColormaps could be used for that?)
1775 XGetInputFocus (si->dpy, &focus, &revert_to);
1776 if (focus && focus != PointerRoot && focus != None)
1778 XWindowAttributes xgwa;
1780 XGetWindowAttributes (si->dpy, focus, &xgwa);
1781 if (xgwa.colormap &&
1782 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1783 XInstallColormap (si->dpy, xgwa.colormap);
1788 for (i = 0; i < si->nscreens; i++)
1790 saver_screen_info *ssi = &si->screens[i];
1791 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1794 store_saver_status (si); /* store unblank time */
1795 ungrab_keyboard_and_mouse (si);
1796 restore_real_vroot (si);
1798 /* Unmap the windows a second time, dammit -- just to avoid a race
1799 with the screen-grabbing hacks. (I'm not sure if this is really
1800 necessary; I'm stabbing in the dark now.)
1802 for (i = 0; i < si->nscreens; i++)
1803 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1805 si->screen_blanked_p = False;
1806 si->blank_time = time ((time_t) 0);
1807 si->last_wall_clock_time = 0;
1809 store_saver_status (si); /* store unblank time */
1813 /* Transfer any grabs from the old window to the new.
1814 Actually I think none of this is necessary, since we always
1815 hold our grabs on the root window, but I wrote this before
1816 re-discovering that...
1819 maybe_transfer_grabs (saver_screen_info *ssi,
1820 Window old_w, Window new_w,
1823 saver_info *si = ssi->global;
1825 /* If the old window held our mouse grab, transfer the grab to the new
1826 window. (Grab the server while so doing, to avoid a race condition.)
1828 if (old_w == si->mouse_grab_window)
1830 XGrabServer (si->dpy); /* ############ DANGER! */
1832 grab_mouse (si, ssi->screensaver_window,
1833 (si->demoing_p ? 0 : ssi->cursor),
1835 XUngrabServer (si->dpy);
1836 XSync (si->dpy, False); /* ###### (danger over) */
1839 /* If the old window held our keyboard grab, transfer the grab to the new
1840 window. (Grab the server while so doing, to avoid a race condition.)
1842 if (old_w == si->keyboard_grab_window)
1844 XGrabServer (si->dpy); /* ############ DANGER! */
1846 grab_kbd(si, ssi->screensaver_window, ssi->number);
1847 XUngrabServer (si->dpy);
1848 XSync (si->dpy, False); /* ###### (danger over) */
1854 get_screen_gl_visual (saver_info *si, int real_screen_number)
1857 int nscreens = ScreenCount (si->dpy);
1859 if (! si->best_gl_visuals)
1860 si->best_gl_visuals = (Visual **)
1861 calloc (nscreens + 1, sizeof (*si->best_gl_visuals));
1863 for (i = 0; i < nscreens; i++)
1864 if (! si->best_gl_visuals[i])
1865 si->best_gl_visuals[i] =
1866 get_best_gl_visual (si, ScreenOfDisplay (si->dpy, i));
1868 if (real_screen_number < 0 || real_screen_number >= nscreens) abort();
1869 return si->best_gl_visuals[real_screen_number];
1874 select_visual (saver_screen_info *ssi, const char *visual_name)
1876 XWindowAttributes xgwa;
1877 saver_info *si = ssi->global;
1878 saver_preferences *p = &si->prefs;
1879 Bool install_cmap_p = p->install_cmap_p;
1880 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1884 /* On some systems (most recently, MacOS X) OpenGL programs get confused
1885 when you kill one and re-start another on the same window. So maybe
1886 it's best to just always destroy and recreate the xscreensaver window
1887 when changing hacks, instead of trying to reuse the old one?
1889 Bool always_recreate_window_p = True;
1891 get_screen_gl_visual (si, 0); /* let's probe all the GL visuals early */
1893 /* We make sure the existing window is actually on ssi->screen before
1894 trying to use it, in case things moved around radically when monitors
1895 were added or deleted. If we don't do this we could get a BadMatch
1896 even though the depths match. I think.
1898 memset (&xgwa, 0, sizeof(xgwa));
1899 if (ssi->screensaver_window)
1900 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1902 if (visual_name && *visual_name)
1904 if (!strcmp(visual_name, "default-i") ||
1905 !strcmp(visual_name, "Default-i") ||
1906 !strcmp(visual_name, "Default-I")
1909 visual_name = "default";
1910 install_cmap_p = True;
1912 else if (!strcmp(visual_name, "default-n") ||
1913 !strcmp(visual_name, "Default-n") ||
1914 !strcmp(visual_name, "Default-N"))
1916 visual_name = "default";
1917 install_cmap_p = False;
1919 else if (!strcmp(visual_name, "gl") ||
1920 !strcmp(visual_name, "Gl") ||
1921 !strcmp(visual_name, "GL"))
1923 new_v = get_screen_gl_visual (si, ssi->real_screen_number);
1924 if (!new_v && p->verbose_p)
1925 fprintf (stderr, "%s: no GL visuals.\n", progname);
1929 new_v = get_visual (ssi->screen, visual_name, True, False);
1933 new_v = ssi->default_visual;
1938 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1939 /* It's not the default visual, so we have no choice but to install. */
1940 install_cmap_p = True;
1942 ssi->install_cmap_p = install_cmap_p;
1944 if ((ssi->screen != xgwa.screen) ||
1946 (always_recreate_window_p ||
1947 (ssi->current_visual != new_v) ||
1948 (install_cmap_p != was_installed_p))))
1950 Colormap old_c = ssi->cmap;
1951 Window old_w = ssi->screensaver_window;
1953 new_v = ssi->current_visual;
1957 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1958 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1960 fprintf (stderr, "%s: from ", blurb());
1961 describe_visual (stderr, ssi->screen, ssi->current_visual,
1967 ssi->current_visual = new_v;
1968 ssi->current_depth = visual_depth(ssi->screen, new_v);
1970 ssi->screensaver_window = 0;
1972 initialize_screensaver_window_1 (ssi);
1974 /* stderr_overlay_window is a child of screensaver_window, so we need
1975 to destroy that as well (actually, we just need to invalidate and
1976 drop our pointers to it, but this will destroy it, which is ok so
1977 long as it happens before old_w itself is destroyed.) */
1980 raise_window (si, True, True, False);
1981 store_vroot_property (si->dpy,
1982 ssi->screensaver_window, ssi->screensaver_window);
1984 /* Transfer any grabs from the old window to the new. */
1985 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1987 /* Now we can destroy the old window without horking our grabs. */
1988 XDestroyWindow (si->dpy, old_w);
1991 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1992 blurb(), ssi->number, (unsigned long) old_w);
1995 old_c != DefaultColormapOfScreen (ssi->screen) &&
1996 old_c != ssi->demo_cmap)
1997 XFreeColormap (si->dpy, old_c);