1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2003 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 */
50 /* This file doesn't need the Xt headers, so stub these types out... */
52 #define XtAppContext void*
53 #define XrmDatabase void*
54 #define XtIntervalId void*
55 #define XtPointer void*
58 #include "xscreensaver.h"
63 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
65 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
66 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
67 Atom XA_SCREENSAVER_STATUS;
70 extern saver_info *global_si_kludge; /* I hate C so much... */
72 static void maybe_transfer_grabs (saver_screen_info *ssi,
73 Window old_w, Window new_w, int new_screen);
75 #define ALL_POINTER_EVENTS \
76 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
77 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
78 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
79 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
83 grab_string(int status)
87 case GrabSuccess: return "GrabSuccess";
88 case AlreadyGrabbed: return "AlreadyGrabbed";
89 case GrabInvalidTime: return "GrabInvalidTime";
90 case GrabNotViewable: return "GrabNotViewable";
91 case GrabFrozen: return "GrabFrozen";
95 sprintf(foo, "unknown status: %d", status);
102 grab_kbd(saver_info *si, Window w, int screen_no)
104 saver_preferences *p = &si->prefs;
105 int status = XGrabKeyboard (si->dpy, w, True,
106 /* I don't really understand Sync vs Async,
107 but these seem to work... */
108 GrabModeSync, GrabModeAsync,
110 if (status == GrabSuccess)
112 si->keyboard_grab_window = w;
113 si->keyboard_grab_screen = screen_no;
117 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
118 blurb(), screen_no, (unsigned long) w, grab_string(status));
124 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
126 saver_preferences *p = &si->prefs;
127 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
128 GrabModeAsync, GrabModeAsync, w,
129 cursor, CurrentTime);
130 if (status == GrabSuccess)
132 si->mouse_grab_window = w;
133 si->mouse_grab_screen = screen_no;
137 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
138 blurb(), screen_no, (unsigned long) w, grab_string(status));
144 ungrab_kbd(saver_info *si)
146 saver_preferences *p = &si->prefs;
147 XUngrabKeyboard(si->dpy, CurrentTime);
149 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
150 blurb(), si->keyboard_grab_screen,
151 (unsigned long) si->keyboard_grab_window);
152 si->keyboard_grab_window = 0;
157 ungrab_mouse(saver_info *si)
159 saver_preferences *p = &si->prefs;
160 XUngrabPointer(si->dpy, CurrentTime);
162 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
163 blurb(), si->mouse_grab_screen,
164 (unsigned long) si->mouse_grab_window);
165 si->mouse_grab_window = 0;
170 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
173 Status mstatus = 0, kstatus = 0;
177 for (i = 0; i < retries; i++)
179 XSync (si->dpy, False);
180 kstatus = grab_kbd (si, window, screen_no);
181 if (kstatus == GrabSuccess)
184 /* else, wait a second and try to grab again. */
188 if (kstatus != GrabSuccess)
189 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
190 blurb(), grab_string(kstatus));
192 for (i = 0; i < retries; i++)
194 XSync (si->dpy, False);
195 mstatus = grab_mouse (si, window, cursor, screen_no);
196 if (mstatus == GrabSuccess)
199 /* else, wait a second and try to grab again. */
203 if (mstatus != GrabSuccess)
204 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
205 blurb(), grab_string(mstatus));
207 return (kstatus == GrabSuccess ||
208 mstatus == GrabSuccess);
212 ungrab_keyboard_and_mouse (saver_info *si)
220 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
222 Window old = si->mouse_grab_window;
225 return grab_mouse (si, to, cursor, to_screen_no);
228 saver_preferences *p = &si->prefs;
231 XSync (si->dpy, False);
232 XGrabServer (si->dpy); /* ############ DANGER! */
233 XSync (si->dpy, False);
236 fprintf(stderr, "%s: grabbing server...\n", blurb());
239 status = grab_mouse (si, to, cursor, to_screen_no);
241 if (status != GrabSuccess) /* Augh! */
243 sleep (1); /* Note dramatic evil of sleeping
244 with server grabbed. */
245 XSync (si->dpy, False);
246 status = grab_mouse (si, to, cursor, to_screen_no);
249 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
250 grab_mouse (si, old, cursor, to_screen_no);
252 XUngrabServer (si->dpy);
253 XSync (si->dpy, False); /* ###### (danger over) */
256 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
263 /* Prints an error message to stderr and returns True if there is another
264 xscreensaver running already. Silently returns False otherwise. */
266 ensure_no_screensaver_running (Display *dpy, Screen *screen)
270 Window root = RootWindowOfScreen (screen);
271 Window root2, parent, *kids;
273 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
275 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
281 for (i = 0; i < nkids; i++)
285 unsigned long nitems, bytesafter;
288 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
289 False, XA_STRING, &type, &format, &nitems,
290 &bytesafter, (unsigned char **) &version)
295 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
296 False, XA_STRING, &type, &format, &nitems,
297 &bytesafter, (unsigned char **) &id)
303 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
304 blurb(), DisplayString (dpy), (int) kids [i], id);
309 if (kids) XFree ((char *) kids);
311 XSetErrorHandler (old_handler);
317 /* Virtual-root hackery */
320 ERROR! You must not include vroot.h in this file.
324 store_vroot_property (Display *dpy, Window win, Window value)
329 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
331 (win == screensaver_window ? "ScreenSaver" :
332 (win == real_vroot ? "VRoot" :
333 (win == real_vroot_value ? "Vroot_value" : "???"))),
335 (value == screensaver_window ? "ScreenSaver" :
336 (value == real_vroot ? "VRoot" :
337 (value == real_vroot_value ? "Vroot_value" : "???"))));
339 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
340 (unsigned char *) &value, 1);
344 remove_vroot_property (Display *dpy, Window win)
348 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
349 (win == screensaver_window ? "ScreenSaver" :
350 (win == real_vroot ? "VRoot" :
351 (win == real_vroot_value ? "Vroot_value" : "???"))));
353 XDeleteProperty (dpy, win, XA_VROOT);
357 static Bool safe_XKillClient (Display *dpy, XID id);
359 #ifdef HAVE_XF86VMODE
360 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
361 #endif /* HAVE_XF86VMODE */
365 kill_xsetroot_data_1 (Display *dpy, Window window,
366 Atom prop, const char *atom_name,
371 unsigned long nitems, bytesafter;
374 /* If the user has been using xv or xsetroot as a screensaver (to display
375 an image on the screensaver window, as a kind of slideshow) then the
376 pixmap and its associated color cells have been put in RetainPermanent
377 CloseDown mode. Since we're not destroying the xscreensaver window,
378 but merely unmapping it, we need to free these resources or those
379 colormap cells will stay allocated while the screensaver is off. (We
380 could just delete the screensaver window and recreate it later, but
381 that could cause other problems.) This code does an atomic read-and-
382 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
383 cause the RetainPermanent resources of the client which created it
384 (and which no longer exists) to be freed.
386 Update: it seems that Gnome and KDE do this same trick, but with the
387 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
388 "_XSETROOT_ID". So, we'll kill those too.
390 if (XGetWindowProperty (dpy, window, prop, 0, 1,
391 True, AnyPropertyType, &type, &format, &nitems,
392 &bytesafter, (unsigned char **) &dataP)
396 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
397 nitems == 1 && bytesafter == 0)
400 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
401 blurb(), atom_name, *dataP);
402 safe_XKillClient (dpy, *dataP);
406 "%s: deleted unrecognised %s property: \n"
407 "\t%lu, %lu; type: %lu, format: %d, "
408 "nitems: %lu, bytesafter %ld\n",
410 (unsigned long) dataP, (dataP ? *dataP : 0), type,
411 format, nitems, bytesafter);
417 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
419 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
420 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
422 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
427 save_real_vroot (saver_screen_info *ssi)
429 saver_info *si = ssi->global;
430 Display *dpy = si->dpy;
431 Screen *screen = ssi->screen;
433 Window root = RootWindowOfScreen (screen);
434 Window root2, parent, *kids;
436 XErrorHandler old_handler;
438 /* It's possible that a window might be deleted between our call to
439 XQueryTree() and our call to XGetWindowProperty(). Don't die if
440 that happens (but just ignore that window, it's not the one we're
441 interested in anyway.)
444 old_handler = XSetErrorHandler (BadWindow_ehandler);
448 ssi->real_vroot_value = 0;
449 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
455 for (i = 0; i < nkids; i++)
459 unsigned long nitems, bytesafter;
463 /* Skip this window if it is the xscreensaver window of any other
464 screen (this can happen in the Xinerama case.)
466 for (j = 0; j < si->nscreens; j++)
468 saver_screen_info *ssi2 = &si->screens[j];
469 if (kids[i] == ssi2->screensaver_window)
473 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
474 &type, &format, &nitems, &bytesafter,
475 (unsigned char **) &vrootP)
482 if (*vrootP == ssi->screensaver_window) abort ();
484 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
485 blurb(), (int) ssi->real_vroot, (int) kids [i]);
488 ssi->real_vroot = kids [i];
489 ssi->real_vroot_value = *vrootP;
495 XSetErrorHandler (old_handler);
500 remove_vroot_property (si->dpy, ssi->real_vroot);
504 XFree ((char *) kids);
509 restore_real_vroot_1 (saver_screen_info *ssi)
511 saver_info *si = ssi->global;
512 saver_preferences *p = &si->prefs;
513 if (p->verbose_p && ssi->real_vroot)
515 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
516 blurb(), (unsigned long) ssi->real_vroot);
517 remove_vroot_property (si->dpy, ssi->screensaver_window);
520 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
522 ssi->real_vroot_value = 0;
523 /* make sure the property change gets there before this process
524 terminates! We might be doing this because we have intercepted
525 SIGTERM or something. */
526 XSync (si->dpy, False);
533 restore_real_vroot (saver_info *si)
536 Bool did_any = False;
537 for (i = 0; i < si->nscreens; i++)
539 saver_screen_info *ssi = &si->screens[i];
540 if (restore_real_vroot_1 (ssi))
547 /* Signal hackery to ensure that the vroot doesn't get left in an
552 signal_name(int signal)
555 case SIGHUP: return "SIGHUP";
556 case SIGINT: return "SIGINT";
557 case SIGQUIT: return "SIGQUIT";
558 case SIGILL: return "SIGILL";
559 case SIGTRAP: return "SIGTRAP";
561 case SIGABRT: return "SIGABRT";
563 case SIGFPE: return "SIGFPE";
564 case SIGKILL: return "SIGKILL";
565 case SIGBUS: return "SIGBUS";
566 case SIGSEGV: return "SIGSEGV";
567 case SIGPIPE: return "SIGPIPE";
568 case SIGALRM: return "SIGALRM";
569 case SIGTERM: return "SIGTERM";
571 case SIGSTOP: return "SIGSTOP";
574 case SIGCONT: return "SIGCONT";
577 case SIGUSR1: return "SIGUSR1";
580 case SIGUSR2: return "SIGUSR2";
583 case SIGEMT: return "SIGEMT";
586 case SIGSYS: return "SIGSYS";
589 case SIGCHLD: return "SIGCHLD";
592 case SIGPWR: return "SIGPWR";
595 case SIGWINCH: return "SIGWINCH";
598 case SIGURG: return "SIGURG";
601 case SIGIO: return "SIGIO";
604 case SIGVTALRM: return "SIGVTALRM";
607 case SIGXCPU: return "SIGXCPU";
610 case SIGXFSZ: return "SIGXFSZ";
613 case SIGDANGER: return "SIGDANGER";
618 sprintf(buf, "signal %d\n", signal);
627 restore_real_vroot_handler (int sig)
629 saver_info *si = global_si_kludge; /* I hate C so much... */
631 signal (sig, SIG_DFL);
632 if (restore_real_vroot (si))
633 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
634 blurb(), signal_name(sig));
635 kill (getpid (), sig);
639 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
641 # ifdef HAVE_SIGACTION
644 a.sa_handler = handler;
645 sigemptyset (&a.sa_mask);
648 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
649 of this signal from inside its handler, or else when we execvp() the
650 process again, it starts up with SIGHUP blocked, meaning that killing
651 it with -HUP only works *once*. You'd think that execvp() would reset
652 all the signal masks, but it doesn't.
654 # if defined(SA_NOMASK)
655 a.sa_flags |= SA_NOMASK;
656 # elif defined(SA_NODEFER)
657 a.sa_flags |= SA_NODEFER;
660 if (sigaction (sig, &a, 0) < 0)
661 # else /* !HAVE_SIGACTION */
662 if (((long) signal (sig, handler)) == -1L)
663 # endif /* !HAVE_SIGACTION */
666 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
668 saver_exit (si, 1, 0);
672 static RETSIGTYPE saver_sighup_handler (int sig);
675 handle_signals (saver_info *si)
677 catch_signal (si, SIGHUP, saver_sighup_handler);
679 catch_signal (si, SIGINT, restore_real_vroot_handler);
680 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
681 catch_signal (si, SIGILL, restore_real_vroot_handler);
682 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
684 catch_signal (si, SIGIOT, restore_real_vroot_handler);
686 catch_signal (si, SIGABRT, restore_real_vroot_handler);
688 catch_signal (si, SIGEMT, restore_real_vroot_handler);
690 catch_signal (si, SIGFPE, restore_real_vroot_handler);
691 catch_signal (si, SIGBUS, restore_real_vroot_handler);
692 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
694 catch_signal (si, SIGSYS, restore_real_vroot_handler);
696 catch_signal (si, SIGTERM, restore_real_vroot_handler);
698 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
701 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
704 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
710 saver_sighup_handler (int sig)
712 saver_info *si = global_si_kludge; /* I hate C so much... */
714 /* Re-establish SIGHUP handler */
715 catch_signal (si, SIGHUP, saver_sighup_handler);
717 fprintf (stderr, "%s: %s received: restarting...\n",
718 blurb(), signal_name(sig));
720 kill_screenhack (si);
721 XSync (si->dpy, False);
722 restart_process (si); /* Does not return */
729 saver_exit (saver_info *si, int status, const char *dump_core_reason)
731 saver_preferences *p = &si->prefs;
732 static Bool exiting = False;
741 vrs = restore_real_vroot (si);
742 emergency_kill_subproc (si);
743 shutdown_stderr (si);
745 if (p->verbose_p && vrs)
746 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
750 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
751 if (status == 0) status = 1;
752 else if (status == 1) status = -1;
755 bugp = !!dump_core_reason;
757 if (si->prefs.debug_p && !dump_core_reason)
758 dump_core_reason = "because of -debug";
760 if (dump_core_reason)
762 /* Note that the Linux man page for setuid() says If uid is
763 different from the old effective uid, the process will be
764 forbidden from leaving core dumps.
766 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
768 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
773 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
774 "\t\t\tfor bug reporting information.\n\n",
777 # if defined(HAVE_GETCWD)
778 if (!getcwd (cwd, sizeof(cwd)))
779 # elif defined(HAVE_GETWD)
782 strcpy(cwd, "unknown.");
784 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
785 describe_uids (si, real_stderr);
787 /* Do this to drop a core file, so that we can get a stack trace. */
795 /* Managing the actual screensaver window */
798 window_exists_p (Display *dpy, Window window)
800 XErrorHandler old_handler;
801 XWindowAttributes xgwa;
803 old_handler = XSetErrorHandler (BadWindow_ehandler);
804 XGetWindowAttributes (dpy, window, &xgwa);
806 XSetErrorHandler (old_handler);
807 return (xgwa.screen != 0);
811 store_saver_id (saver_screen_info *ssi)
813 XClassHint class_hints;
814 saver_info *si = ssi->global;
815 unsigned long pid = (unsigned long) getpid ();
817 struct passwd *p = getpwuid (getuid ());
818 const char *name, *host;
821 /* First store the name and class on the window.
823 class_hints.res_name = progname;
824 class_hints.res_class = progclass;
825 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
826 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
828 /* Then store the xscreensaver version number.
830 XChangeProperty (si->dpy, ssi->screensaver_window,
831 XA_SCREENSAVER_VERSION,
832 XA_STRING, 8, PropModeReplace,
833 (unsigned char *) si->version,
834 strlen (si->version));
836 /* Now store the XSCREENSAVER_ID property, that says what user and host
837 xscreensaver is running as.
840 if (p && p->pw_name && *p->pw_name)
844 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
850 # if defined(HAVE_UNAME)
853 if (uname (&uts) < 0)
859 host = getenv("SYS$NODE");
860 # else /* !HAVE_UNAME && !VMS */
862 # endif /* !HAVE_UNAME && !VMS */
864 id = (char *) malloc (strlen(name) + strlen(host) + 50);
865 sprintf (id, "%lu (%s@%s)", pid, name, host);
867 XChangeProperty (si->dpy, ssi->screensaver_window,
868 XA_SCREENSAVER_ID, XA_STRING,
870 (unsigned char *) id, strlen (id));
876 store_saver_status (saver_info *si)
879 int size = si->nscreens + 2;
882 status = (CARD32 *) calloc (size, sizeof(CARD32));
884 status[0] = (CARD32) (si->screen_blanked_p
885 ? (si->locked_p ? XA_LOCK : XA_BLANK)
887 status[1] = (CARD32) si->blank_time;
889 for (i = 0; i < si->nscreens; i++)
891 saver_screen_info *ssi = &si->screens[i];
892 status [2 + i] = ssi->current_hack + 1;
895 XChangeProperty (si->dpy,
896 RootWindow (si->dpy, 0), /* always screen #0 */
897 XA_SCREENSAVER_STATUS,
898 XA_INTEGER, 32, PropModeReplace,
899 (unsigned char *) status, size);
905 /* Returns the area of the screen which the xscreensaver window should cover.
906 Normally this is the whole screen, but if the X server's root window is
907 actually larger than the monitor's displayable area, then we want to
908 operate in the currently-visible portion of the desktop instead.
911 get_screen_viewport (saver_screen_info *ssi,
912 int *x_ret, int *y_ret,
913 int *w_ret, int *h_ret,
914 int target_x, int target_y,
917 int w = WidthOfScreen (ssi->screen);
918 int h = HeightOfScreen (ssi->screen);
920 #ifdef HAVE_XF86VMODE
921 saver_info *si = ssi->global;
924 XF86VidModeModeLine ml;
926 Bool xinerama_p = si->xinerama_p;
928 #ifndef HAVE_XINERAMA
929 /* Even if we don't have the client-side Xinerama lib, check to see if
930 the server supports Xinerama, so that we know to ignore the VidMode
931 extension -- otherwise a server crash could result. Yay. */
932 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
933 #endif /* !HAVE_XINERAMA */
938 int mouse_p = (target_x != -1 && target_y != -1);
942 /* If a mouse position wasn't passed in, assume we're talking about
950 /* Find the Xinerama rectangle that contains the mouse position. */
951 for (i = 0; i < si->nscreens; i++)
953 if (target_x >= si->screens[i].x &&
954 target_y >= si->screens[i].y &&
955 target_x < si->screens[i].x + si->screens[i].width &&
956 target_y < si->screens[i].y + si->screens[i].height)
959 if (which == -1) which = 0; /* didn't find it? Use the first. */
960 *x_ret = si->screens[which].x;
961 *y_ret = si->screens[which].y;
962 *w_ret = si->screens[which].width;
963 *h_ret = si->screens[which].height;
967 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
969 si->screens[which].width, si->screens[which].height,
970 si->screens[which].x, si->screens[which].y);
972 fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
973 fprintf (stderr, ".\n");
978 #endif /* HAVE_XINERAMA */
980 if (!xinerama_p && /* Xinerama + VidMode = broken. */
981 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
982 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
983 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
988 *w_ret = ml.hdisplay;
989 *h_ret = ml.vdisplay;
991 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
992 /* There is no viewport -- the screen does not scroll. */
996 /* Apparently some versions of XFree86 return nonsense here!
997 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
998 So, sanity-check the values and give up if they are out of range.
1000 if (*x_ret < 0 || *x_ret >= w ||
1001 *y_ret < 0 || *y_ret >= h ||
1002 *w_ret <= 0 || *w_ret > w ||
1003 *h_ret <= 0 || *h_ret > h)
1005 static int warned_once = 0;
1008 fprintf (stderr, "\n"
1009 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1010 "%s: The XVidMode server extension is returning nonsense.\n"
1011 "%s: Please report this bug to your X server vendor.\n\n",
1012 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1023 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1024 blurb(), ssi->number,
1025 *w_ret, *h_ret, *x_ret, *y_ret);
1028 /* Apparently, though the server stores the X position in increments of
1029 1 pixel, it will only make changes to the *display* in some other
1030 increment. With XF86_SVGA on a Thinkpad, the display only updates
1031 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1032 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1033 mode, because I don't have enough video memory to find out.
1035 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1036 server's *target* scroll position rather than the server's *actual*
1037 scroll position. David Dawes agrees, and says they may fix this in
1038 XFree86 4.0, but it's notrivial.
1040 He also confirms that this behavior is server-dependent, so the
1041 actual scroll position cannot be reliably determined by the client.
1042 So... that means the only solution is to provide a ``sandbox''
1043 around the blackout window -- we make the window be up to N pixels
1044 larger than the viewport on both the left and right sides. That
1045 means some part of the outer edges of each hack might not be
1046 visible, but screw it.
1048 I'm going to guess that 16 pixels is enough, and that the Y dimension
1049 doesn't have this problem.
1051 The drawback of doing this, of course, is that some of the screenhacks
1052 will still look pretty stupid -- for example, "slidescreen" will cut
1053 off the left and right edges of the grid, etc.
1056 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1058 /* Round X position down to next lower multiple of FUDGE.
1059 Increase width by 2*FUDGE in case some server rounds up.
1061 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1062 *w_ret += (FUDGE * 2);
1068 *w_ret != ml.hdisplay ||
1069 *h_ret != ml.vdisplay)
1070 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1071 *w_ret, *h_ret, *x_ret, *y_ret);
1074 fprintf (stderr, "%s.\n", msg);
1079 #endif /* HAVE_XF86VMODE */
1088 static Bool error_handler_hit_p = False;
1091 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1093 error_handler_hit_p = True;
1098 /* Returns True if successful, False if an X error occurred.
1099 We need this because other programs might have done things to
1100 our window that will cause XChangeWindowAttributes() to fail:
1101 if that happens, we give up, destroy the window, and re-create
1105 safe_XChangeWindowAttributes (Display *dpy, Window window,
1107 XSetWindowAttributes *attrs)
1109 XErrorHandler old_handler;
1111 error_handler_hit_p = False;
1112 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1114 XChangeWindowAttributes (dpy, window, mask, attrs);
1117 XSetErrorHandler (old_handler);
1120 return (!error_handler_hit_p);
1124 /* This might not be necessary, but just in case. */
1126 safe_XConfigureWindow (Display *dpy, Window window,
1127 unsigned long mask, XWindowChanges *changes)
1129 XErrorHandler old_handler;
1131 error_handler_hit_p = False;
1132 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1134 XConfigureWindow (dpy, window, mask, changes);
1137 XSetErrorHandler (old_handler);
1140 return (!error_handler_hit_p);
1143 /* This might not be necessary, but just in case. */
1145 safe_XDestroyWindow (Display *dpy, Window window)
1147 XErrorHandler old_handler;
1149 error_handler_hit_p = False;
1150 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1152 XDestroyWindow (dpy, window);
1155 XSetErrorHandler (old_handler);
1158 return (!error_handler_hit_p);
1163 safe_XKillClient (Display *dpy, XID id)
1165 XErrorHandler old_handler;
1167 error_handler_hit_p = False;
1168 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1170 XKillClient (dpy, id);
1173 XSetErrorHandler (old_handler);
1176 return (!error_handler_hit_p);
1180 #ifdef HAVE_XF86VMODE
1182 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1185 XErrorHandler old_handler;
1187 error_handler_hit_p = False;
1188 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1190 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1193 XSetErrorHandler (old_handler);
1196 return (error_handler_hit_p
1201 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1202 untrappable I/O error instead of an X error -- so one must call
1203 safe_XF86VidModeGetViewPort first, and assume that both have the
1204 same error condition. Thank you XFree, may I have another.
1207 #endif /* HAVE_XF86VMODE */
1211 initialize_screensaver_window_1 (saver_screen_info *ssi)
1213 saver_info *si = ssi->global;
1214 saver_preferences *p = &si->prefs;
1215 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1217 /* This resets the screensaver window as fully as possible, since there's
1218 no way of knowing what some random client may have done to us in the
1219 meantime. We could just destroy and recreate the window, but that has
1220 its own set of problems...
1223 XSetWindowAttributes attrs;
1224 unsigned long attrmask;
1225 int x, y, width, height;
1226 static Bool printed_visual_info = False; /* only print the message once. */
1227 Window horked_window = 0;
1229 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1230 (p->verbose_p && !si->screen_blanked_p));
1232 black.red = black.green = black.blue = 0;
1234 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1237 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1238 /* It's not the default visual, so we have no choice but to install. */
1239 install_cmap_p = True;
1245 ssi->cmap = XCreateColormap (si->dpy,
1246 RootWindowOfScreen (ssi->screen),
1247 ssi->current_visual, AllocNone);
1248 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1249 ssi->black_pixel = black.pixel;
1254 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1257 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1258 if (ssi->cmap != ssi->demo_cmap &&
1259 ssi->cmap != def_cmap)
1260 XFreeColormap (si->dpy, ssi->cmap);
1262 ssi->cmap = def_cmap;
1263 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1266 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1267 CWBackPixel | CWBackingPixel | CWBorderPixel);
1268 attrs.override_redirect = True;
1270 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1271 actually be reading these events during normal operation; but we still
1272 need to see Button events for demo-mode to work properly.
1274 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1275 ButtonPressMask | ButtonReleaseMask |
1278 attrs.backing_store = NotUseful;
1279 attrs.colormap = ssi->cmap;
1280 attrs.background_pixel = ssi->black_pixel;
1281 attrs.backing_pixel = ssi->black_pixel;
1282 attrs.border_pixel = ssi->black_pixel;
1284 if (p->debug_p && !p->quad_p) width = width / 2;
1286 if (!p->verbose_p || printed_visual_info)
1288 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1290 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1291 describe_visual (stderr, ssi->screen, ssi->current_visual,
1296 fprintf (stderr, "%s: using visual: ", blurb());
1297 describe_visual (stderr, ssi->screen, ssi->current_visual,
1299 fprintf (stderr, "%s: default visual: ", blurb());
1300 describe_visual (stderr, ssi->screen,
1301 DefaultVisualOfScreen (ssi->screen),
1302 ssi->install_cmap_p);
1304 printed_visual_info = True;
1306 #ifdef HAVE_MIT_SAVER_EXTENSION
1307 if (si->using_mit_saver_extension)
1309 XScreenSaverInfo *info;
1310 Window root = RootWindowOfScreen (ssi->screen);
1313 /* This call sets the server screensaver timeouts to what we think
1314 they should be (based on the resources and args xscreensaver was
1315 started with.) It's important that we do this to sync back up
1316 with the server - if we have turned on prematurely, as by an
1317 ACTIVATE ClientMessage, then the server may decide to activate
1318 the screensaver while it's already active. That's ok for us,
1319 since we would know to ignore that ScreenSaverActivate event,
1320 but a side effect of this would be that the server would map its
1321 saver window (which we then hide again right away) meaning that
1322 the bits currently on the screen get blown away. Ugly. */
1324 /* #### Ok, that doesn't work - when we tell the server that the
1325 screensaver is "off" it sends us a Deactivate event, which is
1326 sensible... but causes the saver to never come on. Hmm. */
1327 disable_builtin_screensaver (si, True);
1331 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1332 window that the server itself uses for saving the screen.
1333 However, using this window in any way, in particular, calling
1334 XScreenSaverSetAttributes() as below, tends to make the X server
1335 crash. So fuck it, let's try and get along without using it...
1337 It's also inconvenient to use this window because it doesn't
1338 always exist (though the ID is constant.) So to use this
1339 window, we'd have to reimplement the ACTIVATE ClientMessage to
1340 tell the *server* to tell *us* to turn on, to cause the window
1341 to get created at the right time. Gag. */
1342 XScreenSaverSetAttributes (si->dpy, root,
1343 0, 0, width, height, 0,
1344 current_depth, InputOutput, visual,
1346 XSync (si->dpy, False);
1349 info = XScreenSaverAllocInfo ();
1350 XScreenSaverQueryInfo (si->dpy, root, info);
1351 ssi->server_mit_saver_window = info->window;
1352 if (! ssi->server_mit_saver_window) abort ();
1355 #endif /* HAVE_MIT_SAVER_EXTENSION */
1357 if (ssi->screensaver_window)
1359 XWindowChanges changes;
1360 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1363 changes.width = width;
1364 changes.height = height;
1365 changes.border_width = 0;
1367 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1368 changesmask, &changes) &&
1369 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1372 horked_window = ssi->screensaver_window;
1373 ssi->screensaver_window = 0;
1377 if (!ssi->screensaver_window)
1379 ssi->screensaver_window =
1380 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1381 x, y, width, height,
1382 0, ssi->current_depth, InputOutput,
1383 ssi->current_visual, attrmask, &attrs);
1390 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1391 blurb(), (unsigned long) horked_window);
1392 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1394 safe_XDestroyWindow (si->dpy, horked_window);
1399 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1400 blurb(), ssi->number,
1401 (unsigned long) ssi->screensaver_window);
1404 store_saver_id (ssi); /* store window name and IDs */
1409 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1411 BlackPixelOfScreen (ssi->screen),
1412 BlackPixelOfScreen (ssi->screen),
1414 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1416 XFreePixmap (si->dpy, bit);
1419 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1422 XUndefineCursor (si->dpy, ssi->screensaver_window);
1424 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1428 initialize_screensaver_window (saver_info *si)
1431 for (i = 0; i < si->nscreens; i++)
1432 initialize_screensaver_window_1 (&si->screens[i]);
1437 raise_window (saver_info *si,
1438 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1440 saver_preferences *p = &si->prefs;
1444 inhibit_fade = True;
1446 if (si->emergency_lock_p)
1447 inhibit_fade = True;
1450 initialize_screensaver_window (si);
1452 reset_watchdog_timer (si, True);
1454 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1456 Window *current_windows = (Window *)
1457 calloc(sizeof(Window), si->nscreens);
1458 Colormap *current_maps = (Colormap *)
1459 calloc(sizeof(Colormap), si->nscreens);
1461 for (i = 0; i < si->nscreens; i++)
1463 saver_screen_info *ssi = &si->screens[i];
1464 current_windows[i] = ssi->screensaver_window;
1465 current_maps[i] = (between_hacks_p
1467 : DefaultColormapOfScreen (ssi->screen));
1468 /* Ensure that the default background of the window is really black,
1469 not a pixmap or something. (This does not clear the window.) */
1470 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1474 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1476 XGrabServer (si->dpy); /* ############ DANGER! */
1478 /* Clear the stderr layer on each screen.
1481 for (i = 0; i < si->nscreens; i++)
1483 saver_screen_info *ssi = &si->screens[i];
1484 if (ssi->stderr_overlay_window)
1485 /* Do this before the fade, since the stderr cmap won't fade
1486 even if we uninstall it (beats me...) */
1490 /* Note! The server is grabbed, and this will take several seconds
1492 fade_screens (si->dpy, current_maps,
1493 current_windows, si->nscreens,
1494 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1497 free(current_windows);
1499 current_windows = 0;
1501 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1503 #ifdef HAVE_MIT_SAVER_EXTENSION
1504 for (i = 0; i < si->nscreens; i++)
1506 saver_screen_info *ssi = &si->screens[i];
1507 if (ssi->server_mit_saver_window &&
1508 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1509 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1511 #endif /* HAVE_MIT_SAVER_EXTENSION */
1513 XUngrabServer (si->dpy);
1514 XSync (si->dpy, False); /* ###### (danger over) */
1518 for (i = 0; i < si->nscreens; i++)
1520 saver_screen_info *ssi = &si->screens[i];
1522 XClearWindow (si->dpy, ssi->screensaver_window);
1523 if (!dont_clear || ssi->stderr_overlay_window)
1525 XMapRaised (si->dpy, ssi->screensaver_window);
1526 #ifdef HAVE_MIT_SAVER_EXTENSION
1527 if (ssi->server_mit_saver_window &&
1528 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1529 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1530 #endif /* HAVE_MIT_SAVER_EXTENSION */
1534 for (i = 0; i < si->nscreens; i++)
1536 saver_screen_info *ssi = &si->screens[i];
1538 XInstallColormap (si->dpy, ssi->cmap);
1544 mouse_screen (saver_info *si)
1546 saver_preferences *p = &si->prefs;
1547 Window pointer_root, pointer_child;
1548 int root_x, root_y, win_x, win_y;
1552 if (si->nscreens == 1)
1555 for (i = 0; i < si->nscreens; i++)
1557 saver_screen_info *ssi = &si->screens[i];
1558 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1559 &pointer_root, &pointer_child,
1560 &root_x, &root_y, &win_x, &win_y, &mask) &&
1563 root_x < ssi->x + ssi->width &&
1564 root_y < ssi->y + ssi->height)
1567 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1568 blurb(), i, si->nscreens);
1573 /* couldn't figure out where the mouse is? Oh well. */
1579 blank_screen (saver_info *si)
1586 /* Note: we do our grabs on the root window, not on the screensaver window.
1587 If we grabbed on the saver window, then the demo mode and lock dialog
1588 boxes wouldn't get any events.
1590 By "the root window", we mean "the root window that contains the mouse."
1591 We use to always grab the mouse on screen 0, but that has the effect of
1592 moving the mouse to screen 0 from whichever screen it was on, on
1595 mscreen = mouse_screen (si);
1596 w = RootWindowOfScreen(si->screens[mscreen].screen);
1597 ok = grab_keyboard_and_mouse (si, w,
1598 (si->demoing_p ? 0 : si->screens[0].cursor),
1602 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1603 /* If we're using a server extension, then failure to get a grab is
1604 not a big deal -- even without the grab, we will still be able
1605 to un-blank when there is user activity, since the server will
1612 for (i = 0; i < si->nscreens; i++)
1614 saver_screen_info *ssi = &si->screens[i];
1615 if (ssi->real_screen_p)
1616 save_real_vroot (ssi);
1617 store_vroot_property (si->dpy,
1618 ssi->screensaver_window,
1619 ssi->screensaver_window);
1621 #ifdef HAVE_XF86VMODE
1624 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1625 !safe_XF86VidModeGetViewPort (si->dpy, i,
1628 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1630 #endif /* HAVE_XF86VMODE */
1633 raise_window (si, False, False, False);
1635 si->screen_blanked_p = True;
1636 si->blank_time = time ((time_t) 0);
1637 si->last_wall_clock_time = 0;
1639 store_saver_status (si); /* store blank time */
1646 unblank_screen (saver_info *si)
1648 saver_preferences *p = &si->prefs;
1649 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1652 monitor_power_on (si);
1653 reset_watchdog_timer (si, False);
1660 Window *current_windows = (Window *)
1661 calloc(sizeof(Window), si->nscreens);
1663 for (i = 0; i < si->nscreens; i++)
1665 saver_screen_info *ssi = &si->screens[i];
1666 current_windows[i] = ssi->screensaver_window;
1667 /* Ensure that the default background of the window is really black,
1668 not a pixmap or something. (This does not clear the window.) */
1669 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1673 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1676 XSync (si->dpy, False);
1677 XGrabServer (si->dpy); /* ############ DANGER! */
1678 XSync (si->dpy, False);
1680 /* Clear the stderr layer on each screen.
1682 for (i = 0; i < si->nscreens; i++)
1684 saver_screen_info *ssi = &si->screens[i];
1688 XUngrabServer (si->dpy);
1689 XSync (si->dpy, False); /* ###### (danger over) */
1691 fade_screens (si->dpy, 0,
1692 current_windows, si->nscreens,
1693 p->fade_seconds/1000, p->fade_ticks,
1696 free(current_windows);
1697 current_windows = 0;
1699 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1703 for (i = 0; i < si->nscreens; i++)
1705 saver_screen_info *ssi = &si->screens[i];
1708 Colormap c = DefaultColormapOfScreen (ssi->screen);
1709 /* avoid technicolor */
1710 XClearWindow (si->dpy, ssi->screensaver_window);
1711 if (c) XInstallColormap (si->dpy, c);
1713 XUnmapWindow (si->dpy, ssi->screensaver_window);
1718 /* If the focus window does has a non-default colormap, then install
1719 that colormap as well. (On SGIs, this will cause both the root map
1720 and the focus map to be installed simultaniously. It'd be nice to
1721 pick up the other colormaps that had been installed, too; perhaps
1722 XListInstalledColormaps could be used for that?)
1727 XGetInputFocus (si->dpy, &focus, &revert_to);
1728 if (focus && focus != PointerRoot && focus != None)
1730 XWindowAttributes xgwa;
1732 XGetWindowAttributes (si->dpy, focus, &xgwa);
1733 if (xgwa.colormap &&
1734 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1735 XInstallColormap (si->dpy, xgwa.colormap);
1740 for (i = 0; i < si->nscreens; i++)
1742 saver_screen_info *ssi = &si->screens[i];
1743 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1746 store_saver_status (si); /* store unblank time */
1747 ungrab_keyboard_and_mouse (si);
1748 restore_real_vroot (si);
1750 /* Unmap the windows a second time, dammit -- just to avoid a race
1751 with the screen-grabbing hacks. (I'm not sure if this is really
1752 necessary; I'm stabbing in the dark now.)
1754 for (i = 0; i < si->nscreens; i++)
1755 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1757 si->screen_blanked_p = False;
1758 si->blank_time = time ((time_t) 0);
1759 si->last_wall_clock_time = 0;
1761 store_saver_status (si); /* store unblank time */
1765 /* Transfer any grabs from the old window to the new.
1766 Actually I think none of this is necessary, since we always
1767 hold our grabs on the root window, but I wrote this before
1768 re-discovering that...
1771 maybe_transfer_grabs (saver_screen_info *ssi,
1772 Window old_w, Window new_w,
1775 saver_info *si = ssi->global;
1777 /* If the old window held our mouse grab, transfer the grab to the new
1778 window. (Grab the server while so doing, to avoid a race condition.)
1780 if (old_w == si->mouse_grab_window)
1782 XGrabServer (si->dpy); /* ############ DANGER! */
1784 grab_mouse (si, ssi->screensaver_window,
1785 (si->demoing_p ? 0 : ssi->cursor),
1787 XUngrabServer (si->dpy);
1788 XSync (si->dpy, False); /* ###### (danger over) */
1791 /* If the old window held our keyboard grab, transfer the grab to the new
1792 window. (Grab the server while so doing, to avoid a race condition.)
1794 if (old_w == si->keyboard_grab_window)
1796 XGrabServer (si->dpy); /* ############ DANGER! */
1798 grab_kbd(si, ssi->screensaver_window, ssi->number);
1799 XUngrabServer (si->dpy);
1800 XSync (si->dpy, False); /* ###### (danger over) */
1807 select_visual (saver_screen_info *ssi, const char *visual_name)
1809 saver_info *si = ssi->global;
1810 saver_preferences *p = &si->prefs;
1811 Bool install_cmap_p = p->install_cmap_p;
1812 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1816 if (visual_name && *visual_name)
1818 if (!strcmp(visual_name, "default-i") ||
1819 !strcmp(visual_name, "Default-i") ||
1820 !strcmp(visual_name, "Default-I")
1823 visual_name = "default";
1824 install_cmap_p = True;
1826 else if (!strcmp(visual_name, "default-n") ||
1827 !strcmp(visual_name, "Default-n") ||
1828 !strcmp(visual_name, "Default-N"))
1830 visual_name = "default";
1831 install_cmap_p = False;
1833 else if (!strcmp(visual_name, "gl") ||
1834 !strcmp(visual_name, "Gl") ||
1835 !strcmp(visual_name, "GL"))
1837 new_v = ssi->best_gl_visual;
1838 if (!new_v && p->verbose_p)
1839 fprintf (stderr, "%s: no GL visuals.\n", progname);
1843 new_v = get_visual (ssi->screen, visual_name, True, False);
1847 new_v = ssi->default_visual;
1852 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1853 /* It's not the default visual, so we have no choice but to install. */
1854 install_cmap_p = True;
1856 ssi->install_cmap_p = install_cmap_p;
1859 ((ssi->current_visual != new_v) ||
1860 (install_cmap_p != was_installed_p)))
1862 Colormap old_c = ssi->cmap;
1863 Window old_w = ssi->screensaver_window;
1867 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1868 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1870 fprintf (stderr, "%s: from ", blurb());
1871 describe_visual (stderr, ssi->screen, ssi->current_visual,
1877 ssi->current_visual = new_v;
1878 ssi->current_depth = visual_depth(ssi->screen, new_v);
1880 ssi->screensaver_window = 0;
1882 initialize_screensaver_window_1 (ssi);
1884 /* stderr_overlay_window is a child of screensaver_window, so we need
1885 to destroy that as well (actually, we just need to invalidate and
1886 drop our pointers to it, but this will destroy it, which is ok so
1887 long as it happens before old_w itself is destroyed.) */
1890 raise_window (si, True, True, False);
1891 store_vroot_property (si->dpy,
1892 ssi->screensaver_window, ssi->screensaver_window);
1894 /* Transfer any grabs from the old window to the new. */
1895 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1897 /* Now we can destroy the old window without horking our grabs. */
1898 XDestroyWindow (si->dpy, old_w);
1901 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1902 blurb(), ssi->number, (unsigned long) old_w);
1905 old_c != DefaultColormapOfScreen (ssi->screen) &&
1906 old_c != ssi->demo_cmap)
1907 XFreeColormap (si->dpy, old_c);