1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2001 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 #ifdef HAVE_MIT_SAVER_EXTENSION
43 # include <X11/extensions/scrnsaver.h>
44 #endif /* HAVE_MIT_SAVER_EXTENSION */
47 # include <X11/extensions/xf86vmode.h>
48 #endif /* HAVE_XF86VMODE */
51 # include <X11/extensions/Xinerama.h>
52 #endif /* HAVE_XINERAMA */
55 /* This file doesn't need the Xt headers, so stub these types out... */
57 #define XtAppContext void*
58 #define XrmDatabase void*
59 #define XtIntervalId void*
60 #define XtPointer void*
63 #include "xscreensaver.h"
68 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
70 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
71 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
72 Atom XA_SCREENSAVER_STATUS;
75 extern saver_info *global_si_kludge; /* I hate C so much... */
77 static void maybe_transfer_grabs (saver_screen_info *ssi,
78 Window old_w, Window new_w, int new_screen);
80 #define ALL_POINTER_EVENTS \
81 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
82 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
83 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
84 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
88 grab_string(int status)
92 case GrabSuccess: return "GrabSuccess";
93 case AlreadyGrabbed: return "AlreadyGrabbed";
94 case GrabInvalidTime: return "GrabInvalidTime";
95 case GrabNotViewable: return "GrabNotViewable";
96 case GrabFrozen: return "GrabFrozen";
100 sprintf(foo, "unknown status: %d", status);
107 grab_kbd(saver_info *si, Window w, int screen_no)
109 saver_preferences *p = &si->prefs;
110 int status = XGrabKeyboard (si->dpy, w, True,
111 /* I don't really understand Sync vs Async,
112 but these seem to work... */
113 GrabModeSync, GrabModeAsync,
115 if (status == GrabSuccess)
117 si->keyboard_grab_window = w;
118 si->keyboard_grab_screen = screen_no;
122 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
123 blurb(), screen_no, (unsigned long) w, grab_string(status));
129 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
131 saver_preferences *p = &si->prefs;
132 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
133 GrabModeAsync, GrabModeAsync, w,
134 cursor, CurrentTime);
135 if (status == GrabSuccess)
137 si->mouse_grab_window = w;
138 si->mouse_grab_screen = screen_no;
142 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
143 blurb(), screen_no, (unsigned long) w, grab_string(status));
149 ungrab_kbd(saver_info *si)
151 saver_preferences *p = &si->prefs;
152 XUngrabKeyboard(si->dpy, CurrentTime);
154 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
155 blurb(), si->keyboard_grab_screen,
156 (unsigned long) si->keyboard_grab_window);
157 si->keyboard_grab_window = 0;
162 ungrab_mouse(saver_info *si)
164 saver_preferences *p = &si->prefs;
165 XUngrabPointer(si->dpy, CurrentTime);
167 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
168 blurb(), si->mouse_grab_screen,
169 (unsigned long) si->mouse_grab_window);
170 si->mouse_grab_window = 0;
175 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
178 Status mstatus = 0, kstatus = 0;
182 for (i = 0; i < retries; i++)
184 XSync (si->dpy, False);
185 kstatus = grab_kbd (si, window, screen_no);
186 if (kstatus == GrabSuccess)
189 /* else, wait a second and try to grab again. */
193 if (kstatus != GrabSuccess)
194 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
195 blurb(), grab_string(kstatus));
197 for (i = 0; i < retries; i++)
199 XSync (si->dpy, False);
200 mstatus = grab_mouse (si, window, cursor, screen_no);
201 if (mstatus == GrabSuccess)
204 /* else, wait a second and try to grab again. */
208 if (mstatus != GrabSuccess)
209 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
210 blurb(), grab_string(mstatus));
212 return (kstatus == GrabSuccess ||
213 mstatus == GrabSuccess);
217 ungrab_keyboard_and_mouse (saver_info *si)
225 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
227 Window old = si->mouse_grab_window;
230 return grab_mouse (si, to, cursor, to_screen_no);
233 saver_preferences *p = &si->prefs;
236 XSync (si->dpy, False);
237 XGrabServer (si->dpy); /* ############ DANGER! */
238 XSync (si->dpy, False);
241 fprintf(stderr, "%s: grabbing server...\n", blurb());
244 status = grab_mouse (si, to, cursor, to_screen_no);
246 if (status != GrabSuccess) /* Augh! */
248 sleep (1); /* Note dramatic evil of sleeping
249 with server grabbed. */
250 XSync (si->dpy, False);
251 status = grab_mouse (si, to, cursor, to_screen_no);
254 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
255 grab_mouse (si, old, cursor, to_screen_no);
257 XUngrabServer (si->dpy);
258 XSync (si->dpy, False); /* ###### (danger over) */
261 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
268 /* Prints an error message to stderr and returns True if there is another
269 xscreensaver running already. Silently returns False otherwise. */
271 ensure_no_screensaver_running (Display *dpy, Screen *screen)
275 Window root = RootWindowOfScreen (screen);
276 Window root2, parent, *kids;
278 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
280 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
286 for (i = 0; i < nkids; i++)
290 unsigned long nitems, bytesafter;
293 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
294 False, XA_STRING, &type, &format, &nitems,
295 &bytesafter, (unsigned char **) &version)
300 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
301 False, XA_STRING, &type, &format, &nitems,
302 &bytesafter, (unsigned char **) &id)
308 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
309 blurb(), DisplayString (dpy), (int) kids [i], id);
314 if (kids) XFree ((char *) kids);
316 XSetErrorHandler (old_handler);
322 /* Virtual-root hackery */
325 ERROR! You must not include vroot.h in this file.
329 store_vroot_property (Display *dpy, Window win, Window value)
334 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
336 (win == screensaver_window ? "ScreenSaver" :
337 (win == real_vroot ? "VRoot" :
338 (win == real_vroot_value ? "Vroot_value" : "???"))),
340 (value == screensaver_window ? "ScreenSaver" :
341 (value == real_vroot ? "VRoot" :
342 (value == real_vroot_value ? "Vroot_value" : "???"))));
344 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
345 (unsigned char *) &value, 1);
349 remove_vroot_property (Display *dpy, Window win)
353 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
354 (win == screensaver_window ? "ScreenSaver" :
355 (win == real_vroot ? "VRoot" :
356 (win == real_vroot_value ? "Vroot_value" : "???"))));
358 XDeleteProperty (dpy, win, XA_VROOT);
362 static Bool safe_XKillClient (Display *dpy, XID id);
364 #ifdef HAVE_XF86VMODE
365 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
366 #endif /* HAVE_XF86VMODE */
370 kill_xsetroot_data_1 (Display *dpy, Window window,
371 Atom prop, const char *atom_name,
376 unsigned long nitems, bytesafter;
379 /* If the user has been using xv or xsetroot as a screensaver (to display
380 an image on the screensaver window, as a kind of slideshow) then the
381 pixmap and its associated color cells have been put in RetainPermanent
382 CloseDown mode. Since we're not destroying the xscreensaver window,
383 but merely unmapping it, we need to free these resources or those
384 colormap cells will stay allocated while the screensaver is off. (We
385 could just delete the screensaver window and recreate it later, but
386 that could cause other problems.) This code does an atomic read-and-
387 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
388 cause the RetainPermanent resources of the client which created it
389 (and which no longer exists) to be freed.
391 Update: it seems that Gnome and KDE do this same trick, but with the
392 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
393 "_XSETROOT_ID". So, we'll kill those too.
395 if (XGetWindowProperty (dpy, window, prop, 0, 1,
396 True, AnyPropertyType, &type, &format, &nitems,
397 &bytesafter, (unsigned char **) &dataP)
401 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
402 nitems == 1 && bytesafter == 0)
405 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
406 blurb(), atom_name, *dataP);
407 safe_XKillClient (dpy, *dataP);
411 "%s: deleted unrecognised %s property: \n"
412 "\t%lu, %lu; type: %lu, format: %d, "
413 "nitems: %lu, bytesafter %ld\n",
415 (unsigned long) dataP, (dataP ? *dataP : 0), type,
416 format, nitems, bytesafter);
422 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
424 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
425 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
427 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
432 save_real_vroot (saver_screen_info *ssi)
434 saver_info *si = ssi->global;
435 Display *dpy = si->dpy;
436 Screen *screen = ssi->screen;
438 Window root = RootWindowOfScreen (screen);
439 Window root2, parent, *kids;
441 XErrorHandler old_handler;
443 /* It's possible that a window might be deleted between our call to
444 XQueryTree() and our call to XGetWindowProperty(). Don't die if
445 that happens (but just ignore that window, it's not the one we're
446 interested in anyway.)
449 old_handler = XSetErrorHandler (BadWindow_ehandler);
453 ssi->real_vroot_value = 0;
454 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
460 for (i = 0; i < nkids; i++)
464 unsigned long nitems, bytesafter;
467 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
468 &type, &format, &nitems, &bytesafter,
469 (unsigned char **) &vrootP)
476 if (*vrootP == ssi->screensaver_window) abort ();
478 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
479 blurb(), (int) ssi->real_vroot, (int) kids [i]);
482 ssi->real_vroot = kids [i];
483 ssi->real_vroot_value = *vrootP;
487 XSetErrorHandler (old_handler);
492 remove_vroot_property (si->dpy, ssi->real_vroot);
496 XFree ((char *) kids);
501 restore_real_vroot_1 (saver_screen_info *ssi)
503 saver_info *si = ssi->global;
504 saver_preferences *p = &si->prefs;
505 if (p->verbose_p && ssi->real_vroot)
507 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
508 blurb(), (unsigned long) ssi->real_vroot);
509 remove_vroot_property (si->dpy, ssi->screensaver_window);
512 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
514 ssi->real_vroot_value = 0;
515 /* make sure the property change gets there before this process
516 terminates! We might be doing this because we have intercepted
517 SIGTERM or something. */
518 XSync (si->dpy, False);
525 restore_real_vroot (saver_info *si)
528 Bool did_any = False;
529 for (i = 0; i < si->nscreens; i++)
531 saver_screen_info *ssi = &si->screens[i];
532 if (restore_real_vroot_1 (ssi))
539 /* Signal hackery to ensure that the vroot doesn't get left in an
544 signal_name(int signal)
547 case SIGHUP: return "SIGHUP";
548 case SIGINT: return "SIGINT";
549 case SIGQUIT: return "SIGQUIT";
550 case SIGILL: return "SIGILL";
551 case SIGTRAP: return "SIGTRAP";
553 case SIGABRT: return "SIGABRT";
555 case SIGFPE: return "SIGFPE";
556 case SIGKILL: return "SIGKILL";
557 case SIGBUS: return "SIGBUS";
558 case SIGSEGV: return "SIGSEGV";
559 case SIGPIPE: return "SIGPIPE";
560 case SIGALRM: return "SIGALRM";
561 case SIGTERM: return "SIGTERM";
563 case SIGSTOP: return "SIGSTOP";
566 case SIGCONT: return "SIGCONT";
569 case SIGUSR1: return "SIGUSR1";
572 case SIGUSR2: return "SIGUSR2";
575 case SIGEMT: return "SIGEMT";
578 case SIGSYS: return "SIGSYS";
581 case SIGCHLD: return "SIGCHLD";
584 case SIGPWR: return "SIGPWR";
587 case SIGWINCH: return "SIGWINCH";
590 case SIGURG: return "SIGURG";
593 case SIGIO: return "SIGIO";
596 case SIGVTALRM: return "SIGVTALRM";
599 case SIGXCPU: return "SIGXCPU";
602 case SIGXFSZ: return "SIGXFSZ";
605 case SIGDANGER: return "SIGDANGER";
610 sprintf(buf, "signal %d\n", signal);
619 restore_real_vroot_handler (int sig)
621 saver_info *si = global_si_kludge; /* I hate C so much... */
623 signal (sig, SIG_DFL);
624 if (restore_real_vroot (si))
625 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
626 blurb(), signal_name(sig));
627 kill (getpid (), sig);
631 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
633 # ifdef HAVE_SIGACTION
636 a.sa_handler = handler;
637 sigemptyset (&a.sa_mask);
640 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
641 of this signal from inside its handler, or else when we execvp() the
642 process again, it starts up with SIGHUP blocked, meaning that killing
643 it with -HUP only works *once*. You'd think that execvp() would reset
644 all the signal masks, but it doesn't.
646 # if defined(SA_NOMASK)
647 a.sa_flags |= SA_NOMASK;
648 # elif defined(SA_NODEFER)
649 a.sa_flags |= SA_NODEFER;
652 if (sigaction (sig, &a, 0) < 0)
653 # else /* !HAVE_SIGACTION */
654 if (((long) signal (sig, handler)) == -1L)
655 # endif /* !HAVE_SIGACTION */
658 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
660 saver_exit (si, 1, 0);
664 static RETSIGTYPE saver_sighup_handler (int sig);
667 handle_signals (saver_info *si)
669 catch_signal (si, SIGHUP, saver_sighup_handler);
671 catch_signal (si, SIGINT, restore_real_vroot_handler);
672 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
673 catch_signal (si, SIGILL, restore_real_vroot_handler);
674 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
676 catch_signal (si, SIGIOT, restore_real_vroot_handler);
678 catch_signal (si, SIGABRT, restore_real_vroot_handler);
680 catch_signal (si, SIGEMT, restore_real_vroot_handler);
682 catch_signal (si, SIGFPE, restore_real_vroot_handler);
683 catch_signal (si, SIGBUS, restore_real_vroot_handler);
684 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
686 catch_signal (si, SIGSYS, restore_real_vroot_handler);
688 catch_signal (si, SIGTERM, restore_real_vroot_handler);
690 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
693 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
696 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
702 saver_sighup_handler (int sig)
704 saver_info *si = global_si_kludge; /* I hate C so much... */
706 /* Re-establish SIGHUP handler */
707 catch_signal (si, SIGHUP, saver_sighup_handler);
709 fprintf (stderr, "%s: %s received: restarting...\n",
710 blurb(), signal_name(sig));
712 kill_screenhack (si);
713 XSync (si->dpy, False);
714 restart_process (si); /* Does not return */
721 saver_exit (saver_info *si, int status, const char *dump_core_reason)
723 saver_preferences *p = &si->prefs;
724 static Bool exiting = False;
733 vrs = restore_real_vroot (si);
734 emergency_kill_subproc (si);
735 shutdown_stderr (si);
737 if (p->verbose_p && vrs)
738 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
742 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
743 if (status == 0) status = 1;
744 else if (status == 1) status = -1;
747 bugp = !!dump_core_reason;
749 if (si->prefs.debug_p && !dump_core_reason)
750 dump_core_reason = "because of -debug";
752 if (dump_core_reason)
754 /* Note that the Linux man page for setuid() says If uid is
755 different from the old effective uid, the process will be
756 forbidden from leaving core dumps.
758 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
760 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
765 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
766 "\t\t\tfor bug reporting information.\n\n",
769 # if defined(HAVE_GETCWD)
770 if (!getcwd (cwd, sizeof(cwd)))
771 # elif defined(HAVE_GETWD)
774 strcpy(cwd, "unknown.");
776 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
777 describe_uids (si, real_stderr);
779 /* Do this to drop a core file, so that we can get a stack trace. */
787 /* Managing the actual screensaver window */
790 window_exists_p (Display *dpy, Window window)
792 XErrorHandler old_handler;
793 XWindowAttributes xgwa;
795 old_handler = XSetErrorHandler (BadWindow_ehandler);
796 XGetWindowAttributes (dpy, window, &xgwa);
798 XSetErrorHandler (old_handler);
799 return (xgwa.screen != 0);
803 store_saver_id (saver_screen_info *ssi)
805 XClassHint class_hints;
806 saver_info *si = ssi->global;
807 unsigned long pid = (unsigned long) getpid ();
809 struct passwd *p = getpwuid (getuid ());
810 const char *name, *host;
813 /* First store the name and class on the window.
815 class_hints.res_name = progname;
816 class_hints.res_class = progclass;
817 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
818 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
820 /* Then store the xscreensaver version number.
822 XChangeProperty (si->dpy, ssi->screensaver_window,
823 XA_SCREENSAVER_VERSION,
824 XA_STRING, 8, PropModeReplace,
825 (unsigned char *) si->version,
826 strlen (si->version));
828 /* Now store the XSCREENSAVER_ID property, that says what user and host
829 xscreensaver is running as.
832 if (p && p->pw_name && *p->pw_name)
836 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
842 # if defined(HAVE_UNAME)
845 if (uname (&uts) < 0)
851 host = getenv("SYS$NODE");
852 # else /* !HAVE_UNAME && !VMS */
854 # endif /* !HAVE_UNAME && !VMS */
856 id = (char *) malloc (strlen(name) + strlen(host) + 50);
857 sprintf (id, "%lu (%s@%s)", pid, name, host);
859 XChangeProperty (si->dpy, ssi->screensaver_window,
860 XA_SCREENSAVER_ID, XA_STRING,
862 (unsigned char *) id, strlen (id));
868 store_saver_status (saver_info *si)
871 int size = si->nscreens + 2;
874 status = (CARD32 *) calloc (size, sizeof(CARD32));
876 status[0] = (CARD32) (si->screen_blanked_p
877 ? (si->locked_p ? XA_LOCK : XA_BLANK)
879 status[1] = (CARD32) si->blank_time;
881 for (i = 0; i < si->nscreens; i++)
883 saver_screen_info *ssi = &si->screens[i];
884 status [2 + i] = ssi->current_hack + 1;
887 XChangeProperty (si->dpy,
888 RootWindow (si->dpy, 0), /* always screen #0 */
889 XA_SCREENSAVER_STATUS,
890 XA_INTEGER, 32, PropModeReplace,
891 (unsigned char *) status, size);
897 /* Returns the area of the screen which the xscreensaver window should cover.
898 Normally this is the whole screen, but if the X server's root window is
899 actually larger than the monitor's displayable area, then we want to
900 operate in the currently-visible portion of the desktop instead.
903 get_screen_viewport (saver_screen_info *ssi,
904 int *x_ret, int *y_ret,
905 int *w_ret, int *h_ret,
906 int target_x, int target_y,
909 int w = WidthOfScreen (ssi->screen);
910 int h = HeightOfScreen (ssi->screen);
912 #ifdef HAVE_XF86VMODE
913 saver_info *si = ssi->global;
916 XF86VidModeModeLine ml;
919 Bool placement_only_p = (target_x != -1 && target_y != -1);
922 xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
923 XineramaIsActive (si->dpy));
924 #else /* !HAVE_XINERAMA */
925 /* Even if we don't have the client-side Xinerama lib, check to see if
926 the server supports Xinerama, so that we know to ignore the VidMode
927 extension -- otherwise a server crash could result. Yay. */
928 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
930 #endif /* !HAVE_XINERAMA */
933 if (xinerama_p && placement_only_p)
936 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
939 /* Find the screen that contains the mouse. */
942 for (i = 0; i < nscreens; i++)
944 if (target_x >= xsi[i].x_org &&
945 target_y >= xsi[i].y_org &&
946 target_x < xsi[i].x_org + xsi[i].width &&
947 target_y < xsi[i].y_org + xsi[i].height)
951 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
953 xsi[which].width, xsi[which].height,
954 xsi[i].x_org, xsi[i].y_org);
956 fprintf (stderr, "; mouse at %d,%d",
958 fprintf (stderr, ".\n");
961 if (which == -1) which = 0; /* didn't find it? Use the first. */
962 *x_ret = xsi[which].x_org;
963 *y_ret = xsi[which].y_org;
964 *w_ret = xsi[which].width;
965 *h_ret = xsi[which].height;
970 #endif /* HAVE_XINERAMA */
972 if (!xinerama_p && /* Xinerama + VidMode = broken. */
973 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
974 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
975 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
980 *w_ret = ml.hdisplay;
981 *h_ret = ml.vdisplay;
983 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
984 /* There is no viewport -- the screen does not scroll. */
988 /* Apparently some versions of XFree86 return nonsense here!
989 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
990 So, sanity-check the values and give up if they are out of range.
992 if (*x_ret < 0 || *x_ret >= w ||
993 *y_ret < 0 || *y_ret >= h ||
994 *w_ret <= 0 || *w_ret > w ||
995 *h_ret <= 0 || *h_ret > h)
997 static int warned_once = 0;
1000 fprintf (stderr, "\n"
1001 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1002 "%s: The XVidMode server extension is returning nonsense.\n"
1003 "%s: Please report this bug to your X server vendor.\n\n",
1004 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1015 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1016 blurb(), ssi->number,
1017 *w_ret, *h_ret, *x_ret, *y_ret);
1020 /* Apparently, though the server stores the X position in increments of
1021 1 pixel, it will only make changes to the *display* in some other
1022 increment. With XF86_SVGA on a Thinkpad, the display only updates
1023 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1024 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1025 mode, because I don't have enough video memory to find out.
1027 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1028 server's *target* scroll position rather than the server's *actual*
1029 scroll position. David Dawes agrees, and says they may fix this in
1030 XFree86 4.0, but it's notrivial.
1032 He also confirms that this behavior is server-dependent, so the
1033 actual scroll position cannot be reliably determined by the client.
1034 So... that means the only solution is to provide a ``sandbox''
1035 around the blackout window -- we make the window be up to N pixels
1036 larger than the viewport on both the left and right sides. That
1037 means some part of the outer edges of each hack might not be
1038 visible, but screw it.
1040 I'm going to guess that 16 pixels is enough, and that the Y dimension
1041 doesn't have this problem.
1043 The drawback of doing this, of course, is that some of the screenhacks
1044 will still look pretty stupid -- for example, "slidescreen" will cut
1045 off the left and right edges of the grid, etc.
1048 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1050 /* Round X position down to next lower multiple of FUDGE.
1051 Increase width by 2*FUDGE in case some server rounds up.
1053 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1054 *w_ret += (FUDGE * 2);
1060 *w_ret != ml.hdisplay ||
1061 *h_ret != ml.vdisplay)
1062 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1063 *w_ret, *h_ret, *x_ret, *y_ret);
1066 fprintf (stderr, "%s.\n", msg);
1071 #endif /* HAVE_XF86VMODE */
1080 static Bool error_handler_hit_p = False;
1083 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1085 error_handler_hit_p = True;
1090 /* Returns True if successful, False if an X error occurred.
1091 We need this because other programs might have done things to
1092 our window that will cause XChangeWindowAttributes() to fail:
1093 if that happens, we give up, destroy the window, and re-create
1097 safe_XChangeWindowAttributes (Display *dpy, Window window,
1099 XSetWindowAttributes *attrs)
1101 XErrorHandler old_handler;
1103 error_handler_hit_p = False;
1104 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1106 XChangeWindowAttributes (dpy, window, mask, attrs);
1109 XSetErrorHandler (old_handler);
1112 return (!error_handler_hit_p);
1116 /* This might not be necessary, but just in case. */
1118 safe_XConfigureWindow (Display *dpy, Window window,
1119 unsigned long mask, XWindowChanges *changes)
1121 XErrorHandler old_handler;
1123 error_handler_hit_p = False;
1124 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1126 XConfigureWindow (dpy, window, mask, changes);
1129 XSetErrorHandler (old_handler);
1132 return (!error_handler_hit_p);
1135 /* This might not be necessary, but just in case. */
1137 safe_XDestroyWindow (Display *dpy, Window window)
1139 XErrorHandler old_handler;
1141 error_handler_hit_p = False;
1142 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1144 XDestroyWindow (dpy, window);
1147 XSetErrorHandler (old_handler);
1150 return (!error_handler_hit_p);
1155 safe_XKillClient (Display *dpy, XID id)
1157 XErrorHandler old_handler;
1159 error_handler_hit_p = False;
1160 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1162 XKillClient (dpy, id);
1165 XSetErrorHandler (old_handler);
1168 return (!error_handler_hit_p);
1172 #ifdef HAVE_XF86VMODE
1174 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1177 XErrorHandler old_handler;
1179 error_handler_hit_p = False;
1180 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1182 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1185 XSetErrorHandler (old_handler);
1188 return (error_handler_hit_p
1193 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1194 untrappable I/O error instead of an X error -- so one must call
1195 safe_XF86VidModeGetViewPort first, and assume that both have the
1196 same error condition. Thank you XFree, may I have another.
1199 #endif /* HAVE_XF86VMODE */
1203 initialize_screensaver_window_1 (saver_screen_info *ssi)
1205 saver_info *si = ssi->global;
1206 saver_preferences *p = &si->prefs;
1207 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1209 /* This resets the screensaver window as fully as possible, since there's
1210 no way of knowing what some random client may have done to us in the
1211 meantime. We could just destroy and recreate the window, but that has
1212 its own set of problems...
1215 XSetWindowAttributes attrs;
1216 unsigned long attrmask;
1217 int x, y, width, height;
1218 static Bool printed_visual_info = False; /* only print the message once. */
1219 Window horked_window = 0;
1221 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1222 (p->verbose_p && !si->screen_blanked_p));
1224 black.red = black.green = black.blue = 0;
1226 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1229 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1230 /* It's not the default visual, so we have no choice but to install. */
1231 install_cmap_p = True;
1237 ssi->cmap = XCreateColormap (si->dpy,
1238 RootWindowOfScreen (ssi->screen),
1239 ssi->current_visual, AllocNone);
1240 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1241 ssi->black_pixel = black.pixel;
1246 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1249 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1250 if (ssi->cmap != ssi->demo_cmap &&
1251 ssi->cmap != def_cmap)
1252 XFreeColormap (si->dpy, ssi->cmap);
1254 ssi->cmap = def_cmap;
1255 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1258 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1259 CWBackPixel | CWBackingPixel | CWBorderPixel);
1260 attrs.override_redirect = True;
1262 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1263 actually be reading these events during normal operation; but we still
1264 need to see Button events for demo-mode to work properly.
1266 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1267 ButtonPressMask | ButtonReleaseMask |
1270 attrs.backing_store = NotUseful;
1271 attrs.colormap = ssi->cmap;
1272 attrs.background_pixel = ssi->black_pixel;
1273 attrs.backing_pixel = ssi->black_pixel;
1274 attrs.border_pixel = ssi->black_pixel;
1276 if (p->debug_p) width = width / 2;
1278 if (!p->verbose_p || printed_visual_info)
1280 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1282 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1283 describe_visual (stderr, ssi->screen, ssi->current_visual,
1288 fprintf (stderr, "%s: using visual: ", blurb());
1289 describe_visual (stderr, ssi->screen, ssi->current_visual,
1291 fprintf (stderr, "%s: default visual: ", blurb());
1292 describe_visual (stderr, ssi->screen,
1293 DefaultVisualOfScreen (ssi->screen),
1294 ssi->install_cmap_p);
1296 printed_visual_info = True;
1298 #ifdef HAVE_MIT_SAVER_EXTENSION
1299 if (si->using_mit_saver_extension)
1301 XScreenSaverInfo *info;
1302 Window root = RootWindowOfScreen (ssi->screen);
1305 /* This call sets the server screensaver timeouts to what we think
1306 they should be (based on the resources and args xscreensaver was
1307 started with.) It's important that we do this to sync back up
1308 with the server - if we have turned on prematurely, as by an
1309 ACTIVATE ClientMessage, then the server may decide to activate
1310 the screensaver while it's already active. That's ok for us,
1311 since we would know to ignore that ScreenSaverActivate event,
1312 but a side effect of this would be that the server would map its
1313 saver window (which we then hide again right away) meaning that
1314 the bits currently on the screen get blown away. Ugly. */
1316 /* #### Ok, that doesn't work - when we tell the server that the
1317 screensaver is "off" it sends us a Deactivate event, which is
1318 sensible... but causes the saver to never come on. Hmm. */
1319 disable_builtin_screensaver (si, True);
1323 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1324 window that the server itself uses for saving the screen.
1325 However, using this window in any way, in particular, calling
1326 XScreenSaverSetAttributes() as below, tends to make the X server
1327 crash. So fuck it, let's try and get along without using it...
1329 It's also inconvenient to use this window because it doesn't
1330 always exist (though the ID is constant.) So to use this
1331 window, we'd have to reimplement the ACTIVATE ClientMessage to
1332 tell the *server* to tell *us* to turn on, to cause the window
1333 to get created at the right time. Gag. */
1334 XScreenSaverSetAttributes (si->dpy, root,
1335 0, 0, width, height, 0,
1336 current_depth, InputOutput, visual,
1338 XSync (si->dpy, False);
1341 info = XScreenSaverAllocInfo ();
1342 XScreenSaverQueryInfo (si->dpy, root, info);
1343 ssi->server_mit_saver_window = info->window;
1344 if (! ssi->server_mit_saver_window) abort ();
1347 #endif /* HAVE_MIT_SAVER_EXTENSION */
1349 if (ssi->screensaver_window)
1351 XWindowChanges changes;
1352 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1355 changes.width = width;
1356 changes.height = height;
1357 changes.border_width = 0;
1359 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1360 changesmask, &changes) &&
1361 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1364 horked_window = ssi->screensaver_window;
1365 ssi->screensaver_window = 0;
1369 if (!ssi->screensaver_window)
1371 ssi->screensaver_window =
1372 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1373 x, y, width, height,
1374 0, ssi->current_depth, InputOutput,
1375 ssi->current_visual, attrmask, &attrs);
1382 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1383 blurb(), (unsigned long) horked_window);
1384 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1386 safe_XDestroyWindow (si->dpy, horked_window);
1391 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1392 blurb(), ssi->number,
1393 (unsigned long) ssi->screensaver_window);
1396 store_saver_id (ssi); /* store window name and IDs */
1401 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1403 BlackPixelOfScreen (ssi->screen),
1404 BlackPixelOfScreen (ssi->screen),
1406 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1408 XFreePixmap (si->dpy, bit);
1411 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1414 XUndefineCursor (si->dpy, ssi->screensaver_window);
1416 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1420 initialize_screensaver_window (saver_info *si)
1423 for (i = 0; i < si->nscreens; i++)
1424 initialize_screensaver_window_1 (&si->screens[i]);
1429 raise_window (saver_info *si,
1430 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1432 saver_preferences *p = &si->prefs;
1436 inhibit_fade = True;
1438 if (si->emergency_lock_p)
1439 inhibit_fade = True;
1442 initialize_screensaver_window (si);
1444 reset_watchdog_timer (si, True);
1446 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1448 Window *current_windows = (Window *)
1449 calloc(sizeof(Window), si->nscreens);
1450 Colormap *current_maps = (Colormap *)
1451 calloc(sizeof(Colormap), si->nscreens);
1453 for (i = 0; i < si->nscreens; i++)
1455 saver_screen_info *ssi = &si->screens[i];
1456 current_windows[i] = ssi->screensaver_window;
1457 current_maps[i] = (between_hacks_p
1459 : DefaultColormapOfScreen (ssi->screen));
1460 /* Ensure that the default background of the window is really black,
1461 not a pixmap or something. (This does not clear the window.) */
1462 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1466 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1468 XGrabServer (si->dpy); /* ############ DANGER! */
1470 /* Clear the stderr layer on each screen.
1473 for (i = 0; i < si->nscreens; i++)
1475 saver_screen_info *ssi = &si->screens[i];
1476 if (ssi->stderr_overlay_window)
1477 /* Do this before the fade, since the stderr cmap won't fade
1478 even if we uninstall it (beats me...) */
1482 /* Note! The server is grabbed, and this will take several seconds
1484 fade_screens (si->dpy, current_maps, current_windows,
1485 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1488 free(current_windows);
1490 current_windows = 0;
1492 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1494 #ifdef HAVE_MIT_SAVER_EXTENSION
1495 for (i = 0; i < si->nscreens; i++)
1497 saver_screen_info *ssi = &si->screens[i];
1498 if (ssi->server_mit_saver_window &&
1499 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1500 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1502 #endif /* HAVE_MIT_SAVER_EXTENSION */
1504 XUngrabServer (si->dpy);
1505 XSync (si->dpy, False); /* ###### (danger over) */
1509 for (i = 0; i < si->nscreens; i++)
1511 saver_screen_info *ssi = &si->screens[i];
1513 XClearWindow (si->dpy, ssi->screensaver_window);
1514 if (!dont_clear || ssi->stderr_overlay_window)
1516 XMapRaised (si->dpy, ssi->screensaver_window);
1517 #ifdef HAVE_MIT_SAVER_EXTENSION
1518 if (ssi->server_mit_saver_window &&
1519 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1520 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1521 #endif /* HAVE_MIT_SAVER_EXTENSION */
1525 for (i = 0; i < si->nscreens; i++)
1527 saver_screen_info *ssi = &si->screens[i];
1529 XInstallColormap (si->dpy, ssi->cmap);
1535 mouse_screen (saver_info *si)
1537 saver_preferences *p = &si->prefs;
1539 if (si->nscreens == 1)
1544 for (i = 0; i < si->nscreens; i++)
1546 saver_screen_info *ssi = &si->screens[i];
1547 Window pointer_root, pointer_child;
1548 int root_x, root_y, win_x, win_y;
1550 if (XQueryPointer (si->dpy,
1551 RootWindowOfScreen (ssi->screen),
1552 &pointer_root, &pointer_child,
1553 &root_x, &root_y, &win_x, &win_y, &mask))
1556 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1557 blurb(), i, si->nscreens);
1562 /* couldn't figure out where the mouse is? Oh well. */
1569 blank_screen (saver_info *si)
1576 /* Note: we do our grabs on the root window, not on the screensaver window.
1577 If we grabbed on the saver window, then the demo mode and lock dialog
1578 boxes wouldn't get any events.
1580 By "the root window", we mean "the root window that contains the mouse."
1581 We use to always grab the mouse on screen 0, but that has the effect of
1582 moving the mouse to screen 0 from whichever screen it was on, on
1585 mscreen = mouse_screen (si);
1586 w = RootWindowOfScreen(si->screens[mscreen].screen);
1587 ok = grab_keyboard_and_mouse (si, w,
1588 (si->demoing_p ? 0 : si->screens[0].cursor),
1592 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1593 /* If we're using a server extension, then failure to get a grab is
1594 not a big deal -- even without the grab, we will still be able
1595 to un-blank when there is user activity, since the server will
1602 for (i = 0; i < si->nscreens; i++)
1604 saver_screen_info *ssi = &si->screens[i];
1606 save_real_vroot (ssi);
1607 store_vroot_property (si->dpy,
1608 ssi->screensaver_window,
1609 ssi->screensaver_window);
1611 #ifdef HAVE_XF86VMODE
1614 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1615 !safe_XF86VidModeGetViewPort (si->dpy, i,
1618 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1620 #endif /* HAVE_XF86VMODE */
1623 raise_window (si, False, False, False);
1625 si->screen_blanked_p = True;
1626 si->blank_time = time ((time_t) 0);
1627 si->last_wall_clock_time = 0;
1629 store_saver_status (si); /* store blank time */
1636 unblank_screen (saver_info *si)
1638 saver_preferences *p = &si->prefs;
1639 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1642 monitor_power_on (si);
1643 reset_watchdog_timer (si, False);
1650 Window *current_windows = (Window *)
1651 calloc(sizeof(Window), si->nscreens);
1653 for (i = 0; i < si->nscreens; i++)
1655 saver_screen_info *ssi = &si->screens[i];
1656 current_windows[i] = ssi->screensaver_window;
1657 /* Ensure that the default background of the window is really black,
1658 not a pixmap or something. (This does not clear the window.) */
1659 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1663 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1666 XSync (si->dpy, False);
1667 XGrabServer (si->dpy); /* ############ DANGER! */
1668 XSync (si->dpy, False);
1670 /* Clear the stderr layer on each screen.
1672 for (i = 0; i < si->nscreens; i++)
1674 saver_screen_info *ssi = &si->screens[i];
1678 XUngrabServer (si->dpy);
1679 XSync (si->dpy, False); /* ###### (danger over) */
1682 fade_screens (si->dpy, 0, current_windows,
1683 p->fade_seconds/1000, p->fade_ticks,
1686 free(current_windows);
1687 current_windows = 0;
1689 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1693 for (i = 0; i < si->nscreens; i++)
1695 saver_screen_info *ssi = &si->screens[i];
1698 Colormap c = DefaultColormapOfScreen (ssi->screen);
1699 /* avoid technicolor */
1700 XClearWindow (si->dpy, ssi->screensaver_window);
1701 if (c) XInstallColormap (si->dpy, c);
1703 XUnmapWindow (si->dpy, ssi->screensaver_window);
1708 /* If the focus window does has a non-default colormap, then install
1709 that colormap as well. (On SGIs, this will cause both the root map
1710 and the focus map to be installed simultaniously. It'd be nice to
1711 pick up the other colormaps that had been installed, too; perhaps
1712 XListInstalledColormaps could be used for that?)
1717 XGetInputFocus (si->dpy, &focus, &revert_to);
1718 if (focus && focus != PointerRoot && focus != None)
1720 XWindowAttributes xgwa;
1722 XGetWindowAttributes (si->dpy, focus, &xgwa);
1723 if (xgwa.colormap &&
1724 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1725 XInstallColormap (si->dpy, xgwa.colormap);
1730 for (i = 0; i < si->nscreens; i++)
1732 saver_screen_info *ssi = &si->screens[i];
1733 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1736 store_saver_status (si); /* store unblank time */
1737 ungrab_keyboard_and_mouse (si);
1738 restore_real_vroot (si);
1740 /* Unmap the windows a second time, dammit -- just to avoid a race
1741 with the screen-grabbing hacks. (I'm not sure if this is really
1742 necessary; I'm stabbing in the dark now.)
1744 for (i = 0; i < si->nscreens; i++)
1745 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1747 si->screen_blanked_p = False;
1748 si->blank_time = time ((time_t) 0);
1749 si->last_wall_clock_time = 0;
1751 store_saver_status (si); /* store unblank time */
1755 /* Transfer any grabs from the old window to the new.
1756 Actually I think none of this is necessary, since we always
1757 hold our grabs on the root window, but I wrote this before
1758 re-discovering that...
1761 maybe_transfer_grabs (saver_screen_info *ssi,
1762 Window old_w, Window new_w,
1765 saver_info *si = ssi->global;
1767 /* If the old window held our mouse grab, transfer the grab to the new
1768 window. (Grab the server while so doing, to avoid a race condition.)
1770 if (old_w == si->mouse_grab_window)
1772 XGrabServer (si->dpy); /* ############ DANGER! */
1774 grab_mouse (si, ssi->screensaver_window,
1775 (si->demoing_p ? 0 : ssi->cursor),
1777 XUngrabServer (si->dpy);
1778 XSync (si->dpy, False); /* ###### (danger over) */
1781 /* If the old window held our keyboard grab, transfer the grab to the new
1782 window. (Grab the server while so doing, to avoid a race condition.)
1784 if (old_w == si->keyboard_grab_window)
1786 XGrabServer (si->dpy); /* ############ DANGER! */
1788 grab_kbd(si, ssi->screensaver_window, ssi->number);
1789 XUngrabServer (si->dpy);
1790 XSync (si->dpy, False); /* ###### (danger over) */
1797 select_visual (saver_screen_info *ssi, const char *visual_name)
1799 saver_info *si = ssi->global;
1800 saver_preferences *p = &si->prefs;
1801 Bool install_cmap_p = p->install_cmap_p;
1802 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1806 if (visual_name && *visual_name)
1808 if (!strcmp(visual_name, "default-i") ||
1809 !strcmp(visual_name, "Default-i") ||
1810 !strcmp(visual_name, "Default-I")
1813 visual_name = "default";
1814 install_cmap_p = True;
1816 else if (!strcmp(visual_name, "default-n") ||
1817 !strcmp(visual_name, "Default-n") ||
1818 !strcmp(visual_name, "Default-N"))
1820 visual_name = "default";
1821 install_cmap_p = False;
1823 else if (!strcmp(visual_name, "gl") ||
1824 !strcmp(visual_name, "Gl") ||
1825 !strcmp(visual_name, "GL"))
1827 new_v = ssi->best_gl_visual;
1828 if (!new_v && p->verbose_p)
1829 fprintf (stderr, "%s: no GL visuals.\n", progname);
1833 new_v = get_visual (ssi->screen, visual_name, True, False);
1837 new_v = ssi->default_visual;
1842 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1843 /* It's not the default visual, so we have no choice but to install. */
1844 install_cmap_p = True;
1846 ssi->install_cmap_p = install_cmap_p;
1849 ((ssi->current_visual != new_v) ||
1850 (install_cmap_p != was_installed_p)))
1852 Colormap old_c = ssi->cmap;
1853 Window old_w = ssi->screensaver_window;
1857 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1858 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1860 fprintf (stderr, "%s: from ", blurb());
1861 describe_visual (stderr, ssi->screen, ssi->current_visual,
1867 ssi->current_visual = new_v;
1868 ssi->current_depth = visual_depth(ssi->screen, new_v);
1870 ssi->screensaver_window = 0;
1872 initialize_screensaver_window_1 (ssi);
1874 /* stderr_overlay_window is a child of screensaver_window, so we need
1875 to destroy that as well (actually, we just need to invalidate and
1876 drop our pointers to it, but this will destroy it, which is ok so
1877 long as it happens before old_w itself is destroyed.) */
1880 raise_window (si, True, True, False);
1881 store_vroot_property (si->dpy,
1882 ssi->screensaver_window, ssi->screensaver_window);
1884 /* Transfer any grabs from the old window to the new. */
1885 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1887 /* Now we can destroy the old window without horking our grabs. */
1888 XDestroyWindow (si->dpy, old_w);
1891 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1892 blurb(), ssi->number, (unsigned long) old_w);
1895 old_c != DefaultColormapOfScreen (ssi->screen) &&
1896 old_c != ssi->demo_cmap)
1897 XFreeColormap (si->dpy, old_c);