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%x... %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%x... %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%x).\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%x).\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, kstatus;
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);
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;
462 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
463 &type, &format, &nitems, &bytesafter,
464 (unsigned char **) &vrootP)
471 if (*vrootP == ssi->screensaver_window) abort ();
473 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
474 blurb(), (int) ssi->real_vroot, (int) kids [i]);
477 ssi->real_vroot = kids [i];
478 ssi->real_vroot_value = *vrootP;
482 XSetErrorHandler (old_handler);
487 remove_vroot_property (si->dpy, ssi->real_vroot);
491 XFree ((char *) kids);
496 restore_real_vroot_1 (saver_screen_info *ssi)
498 saver_info *si = ssi->global;
499 saver_preferences *p = &si->prefs;
500 if (p->verbose_p && ssi->real_vroot)
502 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
503 blurb(), (unsigned long) ssi->real_vroot);
504 remove_vroot_property (si->dpy, ssi->screensaver_window);
507 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
509 ssi->real_vroot_value = 0;
510 /* make sure the property change gets there before this process
511 terminates! We might be doing this because we have intercepted
512 SIGTERM or something. */
513 XSync (si->dpy, False);
520 restore_real_vroot (saver_info *si)
523 Bool did_any = False;
524 for (i = 0; i < si->nscreens; i++)
526 saver_screen_info *ssi = &si->screens[i];
527 if (restore_real_vroot_1 (ssi))
534 /* Signal hackery to ensure that the vroot doesn't get left in an
539 signal_name(int signal)
542 case SIGHUP: return "SIGHUP";
543 case SIGINT: return "SIGINT";
544 case SIGQUIT: return "SIGQUIT";
545 case SIGILL: return "SIGILL";
546 case SIGTRAP: return "SIGTRAP";
548 case SIGABRT: return "SIGABRT";
550 case SIGFPE: return "SIGFPE";
551 case SIGKILL: return "SIGKILL";
552 case SIGBUS: return "SIGBUS";
553 case SIGSEGV: return "SIGSEGV";
554 case SIGPIPE: return "SIGPIPE";
555 case SIGALRM: return "SIGALRM";
556 case SIGTERM: return "SIGTERM";
558 case SIGSTOP: return "SIGSTOP";
561 case SIGCONT: return "SIGCONT";
564 case SIGUSR1: return "SIGUSR1";
567 case SIGUSR2: return "SIGUSR2";
570 case SIGEMT: return "SIGEMT";
573 case SIGSYS: return "SIGSYS";
576 case SIGCHLD: return "SIGCHLD";
579 case SIGPWR: return "SIGPWR";
582 case SIGWINCH: return "SIGWINCH";
585 case SIGURG: return "SIGURG";
588 case SIGIO: return "SIGIO";
591 case SIGVTALRM: return "SIGVTALRM";
594 case SIGXCPU: return "SIGXCPU";
597 case SIGXFSZ: return "SIGXFSZ";
600 case SIGDANGER: return "SIGDANGER";
605 sprintf(buf, "signal %d\n", signal);
614 restore_real_vroot_handler (int sig)
616 saver_info *si = global_si_kludge; /* I hate C so much... */
618 signal (sig, SIG_DFL);
619 if (restore_real_vroot (si))
620 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
621 blurb(), signal_name(sig));
622 kill (getpid (), sig);
626 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
628 # ifdef HAVE_SIGACTION
631 a.sa_handler = handler;
632 sigemptyset (&a.sa_mask);
635 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
636 of this signal from inside its handler, or else when we execvp() the
637 process again, it starts up with SIGHUP blocked, meaning that killing
638 it with -HUP only works *once*. You'd think that execvp() would reset
639 all the signal masks, but it doesn't.
641 # if defined(SA_NOMASK)
642 a.sa_flags |= SA_NOMASK;
643 # elif defined(SA_NODEFER)
644 a.sa_flags |= SA_NODEFER;
647 if (sigaction (sig, &a, 0) < 0)
648 # else /* !HAVE_SIGACTION */
649 if (((long) signal (sig, handler)) == -1L)
650 # endif /* !HAVE_SIGACTION */
653 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
655 saver_exit (si, 1, 0);
659 static RETSIGTYPE saver_sighup_handler (int sig);
662 handle_signals (saver_info *si)
664 catch_signal (si, SIGHUP, saver_sighup_handler);
666 catch_signal (si, SIGINT, restore_real_vroot_handler);
667 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
668 catch_signal (si, SIGILL, restore_real_vroot_handler);
669 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
671 catch_signal (si, SIGIOT, restore_real_vroot_handler);
673 catch_signal (si, SIGABRT, restore_real_vroot_handler);
675 catch_signal (si, SIGEMT, restore_real_vroot_handler);
677 catch_signal (si, SIGFPE, restore_real_vroot_handler);
678 catch_signal (si, SIGBUS, restore_real_vroot_handler);
679 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
681 catch_signal (si, SIGSYS, restore_real_vroot_handler);
683 catch_signal (si, SIGTERM, restore_real_vroot_handler);
685 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
688 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
691 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
697 saver_sighup_handler (int sig)
699 saver_info *si = global_si_kludge; /* I hate C so much... */
701 /* Re-establish SIGHUP handler */
702 catch_signal (si, SIGHUP, saver_sighup_handler);
704 fprintf (stderr, "%s: %s received: restarting...\n",
705 blurb(), signal_name(sig));
707 kill_screenhack (si);
708 XSync (si->dpy, False);
709 restart_process (si); /* Does not return */
716 saver_exit (saver_info *si, int status, const char *dump_core_reason)
718 saver_preferences *p = &si->prefs;
719 static Bool exiting = False;
728 vrs = restore_real_vroot (si);
729 emergency_kill_subproc (si);
730 shutdown_stderr (si);
732 if (p->verbose_p && vrs)
733 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
737 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
738 if (status == 0) status = 1;
739 else if (status == 1) status = -1;
742 bugp = !!dump_core_reason;
744 if (si->prefs.debug_p && !dump_core_reason)
745 dump_core_reason = "because of -debug";
747 if (dump_core_reason)
749 /* Note that the Linux man page for setuid() says If uid is
750 different from the old effective uid, the process will be
751 forbidden from leaving core dumps.
753 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
755 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
760 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
761 "\t\tfor bug reporting information.\n\n",
764 # if defined(HAVE_GETCWD)
765 if (!getcwd (cwd, sizeof(cwd)))
766 # elif defined(HAVE_GETWD)
769 strcpy(cwd, "unknown.");
771 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
772 describe_uids (si, real_stderr);
774 /* Do this to drop a core file, so that we can get a stack trace. */
782 /* Managing the actual screensaver window */
785 window_exists_p (Display *dpy, Window window)
787 XErrorHandler old_handler;
788 XWindowAttributes xgwa;
790 old_handler = XSetErrorHandler (BadWindow_ehandler);
791 XGetWindowAttributes (dpy, window, &xgwa);
793 XSetErrorHandler (old_handler);
794 return (xgwa.screen != 0);
798 store_saver_id (saver_screen_info *ssi)
800 XClassHint class_hints;
801 saver_info *si = ssi->global;
802 unsigned long pid = (unsigned long) getpid ();
804 struct passwd *p = getpwuid (getuid ());
805 const char *name, *host;
808 /* First store the name and class on the window.
810 class_hints.res_name = progname;
811 class_hints.res_class = progclass;
812 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
813 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
815 /* Then store the xscreensaver version number.
817 XChangeProperty (si->dpy, ssi->screensaver_window,
818 XA_SCREENSAVER_VERSION,
819 XA_STRING, 8, PropModeReplace,
820 (unsigned char *) si->version,
821 strlen (si->version));
823 /* Now store the XSCREENSAVER_ID property, that says what user and host
824 xscreensaver is running as.
827 if (p && p->pw_name && *p->pw_name)
831 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
837 # if defined(HAVE_UNAME)
840 if (uname (&uts) < 0)
846 host = getenv("SYS$NODE");
847 # else /* !HAVE_UNAME && !VMS */
849 # endif /* !HAVE_UNAME && !VMS */
851 id = (char *) malloc (strlen(name) + strlen(host) + 50);
852 sprintf (id, "%lu (%s@%s)", pid, name, host);
854 XChangeProperty (si->dpy, ssi->screensaver_window,
855 XA_SCREENSAVER_ID, XA_STRING,
857 (unsigned char *) id, strlen (id));
863 store_saver_status (saver_info *si)
866 int size = si->nscreens + 2;
869 status = (CARD32 *) calloc (size, sizeof(CARD32));
871 status[0] = (CARD32) (si->screen_blanked_p
872 ? (si->locked_p ? XA_LOCK : XA_BLANK)
874 status[1] = (CARD32) si->blank_time;
876 for (i = 0; i < si->nscreens; i++)
878 saver_screen_info *ssi = &si->screens[i];
879 status [2 + i] = ssi->current_hack + 1;
882 XChangeProperty (si->dpy,
883 RootWindow (si->dpy, 0), /* always screen #0 */
884 XA_SCREENSAVER_STATUS,
885 XA_INTEGER, 32, PropModeReplace,
886 (unsigned char *) status, size);
891 /* Returns the area of the screen which the xscreensaver window should cover.
892 Normally this is the whole screen, but if the X server's root window is
893 actually larger than the monitor's displayable area, then we want to
894 operate in the currently-visible portion of the desktop instead.
897 get_screen_viewport (saver_screen_info *ssi,
898 int *x_ret, int *y_ret,
899 int *w_ret, int *h_ret,
900 int target_x, int target_y,
903 int w = WidthOfScreen (ssi->screen);
904 int h = HeightOfScreen (ssi->screen);
906 #ifdef HAVE_XF86VMODE
907 saver_info *si = ssi->global;
910 XF86VidModeModeLine ml;
913 Bool placement_only_p = (target_x != -1 && target_y != -1);
916 xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
917 XineramaIsActive (si->dpy));
918 #else /* !HAVE_XINERAMA */
919 /* Even if we don't have the client-side Xinerama lib, check to see if
920 the server supports Xinerama, so that we know to ignore the VidMode
921 extension -- otherwise a server crash could result. Yay. */
922 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
924 #endif /* !HAVE_XINERAMA */
927 if (xinerama_p && placement_only_p)
930 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
933 /* Find the screen that contains the mouse. */
936 for (i = 0; i < nscreens; i++)
938 if (target_x >= xsi[i].x_org &&
939 target_y >= xsi[i].y_org &&
940 target_x < xsi[i].x_org + xsi[i].width &&
941 target_y < xsi[i].y_org + xsi[i].height)
945 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
947 xsi[which].width, xsi[which].height,
948 xsi[i].x_org, xsi[i].y_org);
950 fprintf (stderr, "; mouse at %d,%d",
952 fprintf (stderr, ".\n");
955 if (which == -1) which = 0; /* didn't find it? Use the first. */
956 *x_ret = xsi[which].x_org;
957 *y_ret = xsi[which].y_org;
958 *w_ret = xsi[which].width;
959 *h_ret = xsi[which].height;
964 #endif /* HAVE_XINERAMA */
966 if (!xinerama_p && /* Xinerama + VidMode = broken. */
967 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
968 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml) &&
969 XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y))
974 *w_ret = ml.hdisplay;
975 *h_ret = ml.vdisplay;
977 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
978 /* There is no viewport -- the screen does not scroll. */
982 /* Apparently some versions of XFree86 return nonsense here!
983 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
984 So, sanity-check the values and give up if they are out of range.
986 if (*x_ret < 0 || *x_ret >= w ||
987 *y_ret < 0 || *y_ret >= h ||
988 *w_ret <= 0 || *w_ret > w ||
989 *h_ret <= 0 || *h_ret > h)
991 static int warned_once = 0;
994 fprintf (stderr, "\n"
995 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
996 "%s: The XVidMode server extension is returning nonsense.\n"
997 "%s: Please report this bug to your X server vendor.\n\n",
998 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1009 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1010 blurb(), ssi->number,
1011 *w_ret, *h_ret, *x_ret, *y_ret);
1014 /* Apparently, though the server stores the X position in increments of
1015 1 pixel, it will only make changes to the *display* in some other
1016 increment. With XF86_SVGA on a Thinkpad, the display only updates
1017 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1018 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1019 mode, because I don't have enough video memory to find out.
1021 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1022 server's *target* scroll position rather than the server's *actual*
1023 scroll position. David Dawes agrees, and says they may fix this in
1024 XFree86 4.0, but it's notrivial.
1026 He also confirms that this behavior is server-dependent, so the
1027 actual scroll position cannot be reliably determined by the client.
1028 So... that means the only solution is to provide a ``sandbox''
1029 around the blackout window -- we make the window be up to N pixels
1030 larger than the viewport on both the left and right sides. That
1031 means some part of the outer edges of each hack might not be
1032 visible, but screw it.
1034 I'm going to guess that 16 pixels is enough, and that the Y dimension
1035 doesn't have this problem.
1037 The drawback of doing this, of course, is that some of the screenhacks
1038 will still look pretty stupid -- for example, "slidescreen" will cut
1039 off the left and right edges of the grid, etc.
1042 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1044 /* Round X position down to next lower multiple of FUDGE.
1045 Increase width by 2*FUDGE in case some server rounds up.
1047 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1048 *w_ret += (FUDGE * 2);
1054 *w_ret != ml.hdisplay ||
1055 *h_ret != ml.vdisplay)
1056 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1057 *w_ret, *h_ret, *x_ret, *y_ret);
1060 fprintf (stderr, "%s.\n", msg);
1065 #endif /* HAVE_XF86VMODE */
1074 static Bool error_handler_hit_p = False;
1077 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1079 error_handler_hit_p = True;
1084 /* Returns True if successful, False if an X error occurred.
1085 We need this because other programs might have done things to
1086 our window that will cause XChangeWindowAttributes() to fail:
1087 if that happens, we give up, destroy the window, and re-create
1091 safe_XChangeWindowAttributes (Display *dpy, Window window,
1093 XSetWindowAttributes *attrs)
1095 XErrorHandler old_handler;
1097 error_handler_hit_p = False;
1098 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1100 XChangeWindowAttributes (dpy, window, mask, attrs);
1103 XSetErrorHandler (old_handler);
1106 return (!error_handler_hit_p);
1110 /* This might not be necessary, but just in case. */
1112 safe_XConfigureWindow (Display *dpy, Window window,
1113 unsigned long mask, XWindowChanges *changes)
1115 XErrorHandler old_handler;
1117 error_handler_hit_p = False;
1118 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1120 XConfigureWindow (dpy, window, mask, changes);
1123 XSetErrorHandler (old_handler);
1126 return (!error_handler_hit_p);
1129 /* This might not be necessary, but just in case. */
1131 safe_XDestroyWindow (Display *dpy, Window window)
1133 XErrorHandler old_handler;
1135 error_handler_hit_p = False;
1136 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1138 XDestroyWindow (dpy, window);
1141 XSetErrorHandler (old_handler);
1144 return (!error_handler_hit_p);
1149 safe_XKillClient (Display *dpy, XID id)
1151 XErrorHandler old_handler;
1153 error_handler_hit_p = False;
1154 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1156 XKillClient (dpy, id);
1159 XSetErrorHandler (old_handler);
1162 return (!error_handler_hit_p);
1167 initialize_screensaver_window_1 (saver_screen_info *ssi)
1169 saver_info *si = ssi->global;
1170 saver_preferences *p = &si->prefs;
1171 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1173 /* This resets the screensaver window as fully as possible, since there's
1174 no way of knowing what some random client may have done to us in the
1175 meantime. We could just destroy and recreate the window, but that has
1176 its own set of problems...
1179 XSetWindowAttributes attrs;
1180 unsigned long attrmask;
1181 int x, y, width, height;
1182 static Bool printed_visual_info = False; /* only print the message once. */
1183 Window horked_window = 0;
1185 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1186 (p->verbose_p && !si->screen_blanked_p));
1188 black.red = black.green = black.blue = 0;
1190 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1193 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1194 /* It's not the default visual, so we have no choice but to install. */
1195 install_cmap_p = True;
1201 ssi->cmap = XCreateColormap (si->dpy,
1202 RootWindowOfScreen (ssi->screen),
1203 ssi->current_visual, AllocNone);
1204 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1205 ssi->black_pixel = black.pixel;
1210 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1213 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1214 if (ssi->cmap != ssi->demo_cmap &&
1215 ssi->cmap != def_cmap)
1216 XFreeColormap (si->dpy, ssi->cmap);
1218 ssi->cmap = def_cmap;
1219 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1222 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1223 CWBackPixel | CWBackingPixel | CWBorderPixel);
1224 attrs.override_redirect = True;
1226 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1227 actually be reading these events during normal operation; but we still
1228 need to see Button events for demo-mode to work properly.
1230 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1231 ButtonPressMask | ButtonReleaseMask |
1234 attrs.backing_store = NotUseful;
1235 attrs.colormap = ssi->cmap;
1236 attrs.background_pixel = ssi->black_pixel;
1237 attrs.backing_pixel = ssi->black_pixel;
1238 attrs.border_pixel = ssi->black_pixel;
1240 if (p->debug_p) width = width / 2;
1242 if (!p->verbose_p || printed_visual_info)
1244 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1246 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1247 describe_visual (stderr, ssi->screen, ssi->current_visual,
1252 fprintf (stderr, "%s: using visual: ", blurb());
1253 describe_visual (stderr, ssi->screen, ssi->current_visual,
1255 fprintf (stderr, "%s: default visual: ", blurb());
1256 describe_visual (stderr, ssi->screen,
1257 DefaultVisualOfScreen (ssi->screen),
1258 ssi->install_cmap_p);
1260 printed_visual_info = True;
1262 #ifdef HAVE_MIT_SAVER_EXTENSION
1263 if (si->using_mit_saver_extension)
1265 XScreenSaverInfo *info;
1266 Window root = RootWindowOfScreen (ssi->screen);
1269 /* This call sets the server screensaver timeouts to what we think
1270 they should be (based on the resources and args xscreensaver was
1271 started with.) It's important that we do this to sync back up
1272 with the server - if we have turned on prematurely, as by an
1273 ACTIVATE ClientMessage, then the server may decide to activate
1274 the screensaver while it's already active. That's ok for us,
1275 since we would know to ignore that ScreenSaverActivate event,
1276 but a side effect of this would be that the server would map its
1277 saver window (which we then hide again right away) meaning that
1278 the bits currently on the screen get blown away. Ugly. */
1280 /* #### Ok, that doesn't work - when we tell the server that the
1281 screensaver is "off" it sends us a Deactivate event, which is
1282 sensible... but causes the saver to never come on. Hmm. */
1283 disable_builtin_screensaver (si, True);
1287 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1288 window that the server itself uses for saving the screen.
1289 However, using this window in any way, in particular, calling
1290 XScreenSaverSetAttributes() as below, tends to make the X server
1291 crash. So fuck it, let's try and get along without using it...
1293 It's also inconvenient to use this window because it doesn't
1294 always exist (though the ID is constant.) So to use this
1295 window, we'd have to reimplement the ACTIVATE ClientMessage to
1296 tell the *server* to tell *us* to turn on, to cause the window
1297 to get created at the right time. Gag. */
1298 XScreenSaverSetAttributes (si->dpy, root,
1299 0, 0, width, height, 0,
1300 current_depth, InputOutput, visual,
1302 XSync (si->dpy, False);
1305 info = XScreenSaverAllocInfo ();
1306 XScreenSaverQueryInfo (si->dpy, root, info);
1307 ssi->server_mit_saver_window = info->window;
1308 if (! ssi->server_mit_saver_window) abort ();
1311 #endif /* HAVE_MIT_SAVER_EXTENSION */
1313 if (ssi->screensaver_window)
1315 XWindowChanges changes;
1316 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1319 changes.width = width;
1320 changes.height = height;
1321 changes.border_width = 0;
1323 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1324 changesmask, &changes) &&
1325 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1328 horked_window = ssi->screensaver_window;
1329 ssi->screensaver_window = 0;
1333 if (!ssi->screensaver_window)
1335 ssi->screensaver_window =
1336 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1337 x, y, width, height,
1338 0, ssi->current_depth, InputOutput,
1339 ssi->current_visual, attrmask, &attrs);
1346 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1347 blurb(), (unsigned long) horked_window);
1348 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1350 safe_XDestroyWindow (si->dpy, horked_window);
1355 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1356 blurb(), ssi->number,
1357 (unsigned long) ssi->screensaver_window);
1360 store_saver_id (ssi); /* store window name and IDs */
1365 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1367 BlackPixelOfScreen (ssi->screen),
1368 BlackPixelOfScreen (ssi->screen),
1370 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1372 XFreePixmap (si->dpy, bit);
1375 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1378 XUndefineCursor (si->dpy, ssi->screensaver_window);
1380 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1384 initialize_screensaver_window (saver_info *si)
1387 for (i = 0; i < si->nscreens; i++)
1388 initialize_screensaver_window_1 (&si->screens[i]);
1393 raise_window (saver_info *si,
1394 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1396 saver_preferences *p = &si->prefs;
1400 inhibit_fade = True;
1402 if (si->emergency_lock_p)
1403 inhibit_fade = True;
1406 initialize_screensaver_window (si);
1408 reset_watchdog_timer (si, True);
1410 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1412 Window *current_windows = (Window *)
1413 calloc(sizeof(Window), si->nscreens);
1414 Colormap *current_maps = (Colormap *)
1415 calloc(sizeof(Colormap), si->nscreens);
1417 for (i = 0; i < si->nscreens; i++)
1419 saver_screen_info *ssi = &si->screens[i];
1420 current_windows[i] = ssi->screensaver_window;
1421 current_maps[i] = (between_hacks_p
1423 : DefaultColormapOfScreen (ssi->screen));
1424 /* Ensure that the default background of the window is really black,
1425 not a pixmap or something. (This does not clear the window.) */
1426 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1430 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1432 XGrabServer (si->dpy); /* ############ DANGER! */
1434 /* Clear the stderr layer on each screen.
1437 for (i = 0; i < si->nscreens; i++)
1439 saver_screen_info *ssi = &si->screens[i];
1440 if (ssi->stderr_overlay_window)
1441 /* Do this before the fade, since the stderr cmap won't fade
1442 even if we uninstall it (beats me...) */
1446 /* Note! The server is grabbed, and this will take several seconds
1448 fade_screens (si->dpy, current_maps, current_windows,
1449 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1452 free(current_windows);
1454 current_windows = 0;
1456 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1458 #ifdef HAVE_MIT_SAVER_EXTENSION
1459 for (i = 0; i < si->nscreens; i++)
1461 saver_screen_info *ssi = &si->screens[i];
1462 if (ssi->server_mit_saver_window &&
1463 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1464 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1466 #endif /* HAVE_MIT_SAVER_EXTENSION */
1468 XUngrabServer (si->dpy);
1469 XSync (si->dpy, False); /* ###### (danger over) */
1473 for (i = 0; i < si->nscreens; i++)
1475 saver_screen_info *ssi = &si->screens[i];
1477 XClearWindow (si->dpy, ssi->screensaver_window);
1478 if (!dont_clear || ssi->stderr_overlay_window)
1480 XMapRaised (si->dpy, ssi->screensaver_window);
1481 #ifdef HAVE_MIT_SAVER_EXTENSION
1482 if (ssi->server_mit_saver_window &&
1483 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1484 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1485 #endif /* HAVE_MIT_SAVER_EXTENSION */
1489 for (i = 0; i < si->nscreens; i++)
1491 saver_screen_info *ssi = &si->screens[i];
1493 XInstallColormap (si->dpy, ssi->cmap);
1499 mouse_screen (saver_info *si)
1501 saver_preferences *p = &si->prefs;
1503 if (si->nscreens == 1)
1508 for (i = 0; i < si->nscreens; i++)
1510 saver_screen_info *ssi = &si->screens[i];
1511 Window pointer_root, pointer_child;
1512 int root_x, root_y, win_x, win_y;
1514 if (XQueryPointer (si->dpy,
1515 RootWindowOfScreen (ssi->screen),
1516 &pointer_root, &pointer_child,
1517 &root_x, &root_y, &win_x, &win_y, &mask))
1520 fprintf (stderr, "%s: mouse is on screen %d\n",
1521 blurb(), i, si->nscreens);
1526 /* couldn't figure out where the mouse is? Oh well. */
1533 blank_screen (saver_info *si)
1540 /* Note: we do our grabs on the root window, not on the screensaver window.
1541 If we grabbed on the saver window, then the demo mode and lock dialog
1542 boxes wouldn't get any events.
1544 By "the root window", we mean "the root window that contains the mouse."
1545 We use to always grab the mouse on screen 0, but that has the effect of
1546 moving the mouse to screen 0 from whichever screen it was on, on
1549 mscreen = mouse_screen (si);
1550 w = RootWindowOfScreen(si->screens[mscreen].screen);
1551 ok = grab_keyboard_and_mouse (si, w,
1552 (si->demoing_p ? 0 : si->screens[0].cursor),
1556 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1557 /* If we're using a server extension, then failure to get a grab is
1558 not a big deal -- even without the grab, we will still be able
1559 to un-blank when there is user activity, since the server will
1566 for (i = 0; i < si->nscreens; i++)
1568 saver_screen_info *ssi = &si->screens[i];
1570 save_real_vroot (ssi);
1571 store_vroot_property (si->dpy,
1572 ssi->screensaver_window,
1573 ssi->screensaver_window);
1575 #ifdef HAVE_XF86VMODE
1578 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1579 !XF86VidModeGetViewPort (si->dpy, i,
1582 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1584 #endif /* HAVE_XF86VMODE */
1587 raise_window (si, False, False, False);
1589 si->screen_blanked_p = True;
1590 si->blank_time = time ((time_t) 0);
1591 si->last_wall_clock_time = 0;
1593 store_saver_status (si); /* store blank time */
1600 unblank_screen (saver_info *si)
1602 saver_preferences *p = &si->prefs;
1603 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1606 monitor_power_on (si);
1607 reset_watchdog_timer (si, False);
1614 Window *current_windows = (Window *)
1615 calloc(sizeof(Window), si->nscreens);
1617 for (i = 0; i < si->nscreens; i++)
1619 saver_screen_info *ssi = &si->screens[i];
1620 current_windows[i] = ssi->screensaver_window;
1621 /* Ensure that the default background of the window is really black,
1622 not a pixmap or something. (This does not clear the window.) */
1623 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1627 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1630 XSync (si->dpy, False);
1631 XGrabServer (si->dpy); /* ############ DANGER! */
1632 XSync (si->dpy, False);
1634 /* Clear the stderr layer on each screen.
1636 for (i = 0; i < si->nscreens; i++)
1638 saver_screen_info *ssi = &si->screens[i];
1642 XUngrabServer (si->dpy);
1643 XSync (si->dpy, False); /* ###### (danger over) */
1646 fade_screens (si->dpy, 0, current_windows,
1647 p->fade_seconds/1000, p->fade_ticks,
1650 free(current_windows);
1651 current_windows = 0;
1653 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1657 for (i = 0; i < si->nscreens; i++)
1659 saver_screen_info *ssi = &si->screens[i];
1662 Colormap c = DefaultColormapOfScreen (ssi->screen);
1663 /* avoid technicolor */
1664 XClearWindow (si->dpy, ssi->screensaver_window);
1665 if (c) XInstallColormap (si->dpy, c);
1667 XUnmapWindow (si->dpy, ssi->screensaver_window);
1672 /* If the focus window does has a non-default colormap, then install
1673 that colormap as well. (On SGIs, this will cause both the root map
1674 and the focus map to be installed simultaniously. It'd be nice to
1675 pick up the other colormaps that had been installed, too; perhaps
1676 XListInstalledColormaps could be used for that?)
1681 XGetInputFocus (si->dpy, &focus, &revert_to);
1682 if (focus && focus != PointerRoot && focus != None)
1684 XWindowAttributes xgwa;
1686 XGetWindowAttributes (si->dpy, focus, &xgwa);
1687 if (xgwa.colormap &&
1688 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1689 XInstallColormap (si->dpy, xgwa.colormap);
1694 for (i = 0; i < si->nscreens; i++)
1696 saver_screen_info *ssi = &si->screens[i];
1697 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1700 store_saver_status (si); /* store unblank time */
1701 ungrab_keyboard_and_mouse (si);
1702 restore_real_vroot (si);
1704 /* Unmap the windows a second time, dammit -- just to avoid a race
1705 with the screen-grabbing hacks. (I'm not sure if this is really
1706 necessary; I'm stabbing in the dark now.)
1708 for (i = 0; i < si->nscreens; i++)
1709 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1711 si->screen_blanked_p = False;
1712 si->blank_time = time ((time_t) 0);
1713 si->last_wall_clock_time = 0;
1715 store_saver_status (si); /* store unblank time */
1719 /* Transfer any grabs from the old window to the new.
1720 Actually I think none of this is necessary, since we always
1721 hold our grabs on the root window, but I wrote this before
1722 re-discovering that...
1725 maybe_transfer_grabs (saver_screen_info *ssi,
1726 Window old_w, Window new_w,
1729 saver_info *si = ssi->global;
1731 /* If the old window held our mouse grab, transfer the grab to the new
1732 window. (Grab the server while so doing, to avoid a race condition.)
1734 if (old_w == si->mouse_grab_window)
1736 XGrabServer (si->dpy); /* ############ DANGER! */
1738 grab_mouse (si, ssi->screensaver_window,
1739 (si->demoing_p ? 0 : ssi->cursor),
1741 XUngrabServer (si->dpy);
1742 XSync (si->dpy, False); /* ###### (danger over) */
1745 /* If the old window held our keyboard grab, transfer the grab to the new
1746 window. (Grab the server while so doing, to avoid a race condition.)
1748 if (old_w == si->keyboard_grab_window)
1750 XGrabServer (si->dpy); /* ############ DANGER! */
1752 grab_kbd(si, ssi->screensaver_window, ssi->number);
1753 XUngrabServer (si->dpy);
1754 XSync (si->dpy, False); /* ###### (danger over) */
1761 select_visual (saver_screen_info *ssi, const char *visual_name)
1763 saver_info *si = ssi->global;
1764 saver_preferences *p = &si->prefs;
1765 Bool install_cmap_p = p->install_cmap_p;
1766 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1770 if (visual_name && *visual_name)
1772 if (!strcmp(visual_name, "default-i") ||
1773 !strcmp(visual_name, "Default-i") ||
1774 !strcmp(visual_name, "Default-I")
1777 visual_name = "default";
1778 install_cmap_p = True;
1780 else if (!strcmp(visual_name, "default-n") ||
1781 !strcmp(visual_name, "Default-n") ||
1782 !strcmp(visual_name, "Default-N"))
1784 visual_name = "default";
1785 install_cmap_p = False;
1787 else if (!strcmp(visual_name, "gl") ||
1788 !strcmp(visual_name, "Gl") ||
1789 !strcmp(visual_name, "GL"))
1791 new_v = ssi->best_gl_visual;
1792 if (!new_v && p->verbose_p)
1793 fprintf (stderr, "%s: no GL visuals.\n", progname);
1797 new_v = get_visual (ssi->screen, visual_name, True, False);
1801 new_v = ssi->default_visual;
1806 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1807 /* It's not the default visual, so we have no choice but to install. */
1808 install_cmap_p = True;
1810 ssi->install_cmap_p = install_cmap_p;
1813 ((ssi->current_visual != new_v) ||
1814 (install_cmap_p != was_installed_p)))
1816 Colormap old_c = ssi->cmap;
1817 Window old_w = ssi->screensaver_window;
1821 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1822 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1824 fprintf (stderr, "%s: from ", blurb());
1825 describe_visual (stderr, ssi->screen, ssi->current_visual,
1831 ssi->current_visual = new_v;
1832 ssi->current_depth = visual_depth(ssi->screen, new_v);
1834 ssi->screensaver_window = 0;
1836 initialize_screensaver_window_1 (ssi);
1838 /* stderr_overlay_window is a child of screensaver_window, so we need
1839 to destroy that as well (actually, we just need to invalidate and
1840 drop our pointers to it, but this will destroy it, which is ok so
1841 long as it happens before old_w itself is destroyed.) */
1844 raise_window (si, True, True, False);
1845 store_vroot_property (si->dpy,
1846 ssi->screensaver_window, ssi->screensaver_window);
1848 /* Transfer any grabs from the old window to the new. */
1849 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1851 /* Now we can destroy the old window without horking our grabs. */
1852 XDestroyWindow (si->dpy, old_w);
1855 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1856 blurb(), ssi->number, (unsigned long) old_w);
1859 old_c != DefaultColormapOfScreen (ssi->screen) &&
1860 old_c != ssi->demo_cmap)
1861 XFreeColormap (si->dpy, old_c);