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);
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\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);
892 /* Returns the area of the screen which the xscreensaver window should cover.
893 Normally this is the whole screen, but if the X server's root window is
894 actually larger than the monitor's displayable area, then we want to
895 operate in the currently-visible portion of the desktop instead.
898 get_screen_viewport (saver_screen_info *ssi,
899 int *x_ret, int *y_ret,
900 int *w_ret, int *h_ret,
901 int target_x, int target_y,
904 int w = WidthOfScreen (ssi->screen);
905 int h = HeightOfScreen (ssi->screen);
907 #ifdef HAVE_XF86VMODE
908 saver_info *si = ssi->global;
911 XF86VidModeModeLine ml;
914 Bool placement_only_p = (target_x != -1 && target_y != -1);
917 xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
918 XineramaIsActive (si->dpy));
919 #else /* !HAVE_XINERAMA */
920 /* Even if we don't have the client-side Xinerama lib, check to see if
921 the server supports Xinerama, so that we know to ignore the VidMode
922 extension -- otherwise a server crash could result. Yay. */
923 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
925 #endif /* !HAVE_XINERAMA */
928 if (xinerama_p && placement_only_p)
931 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
934 /* Find the screen that contains the mouse. */
937 for (i = 0; i < nscreens; i++)
939 if (target_x >= xsi[i].x_org &&
940 target_y >= xsi[i].y_org &&
941 target_x < xsi[i].x_org + xsi[i].width &&
942 target_y < xsi[i].y_org + xsi[i].height)
946 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
948 xsi[which].width, xsi[which].height,
949 xsi[i].x_org, xsi[i].y_org);
951 fprintf (stderr, "; mouse at %d,%d",
953 fprintf (stderr, ".\n");
956 if (which == -1) which = 0; /* didn't find it? Use the first. */
957 *x_ret = xsi[which].x_org;
958 *y_ret = xsi[which].y_org;
959 *w_ret = xsi[which].width;
960 *h_ret = xsi[which].height;
965 #endif /* HAVE_XINERAMA */
967 if (!xinerama_p && /* Xinerama + VidMode = broken. */
968 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
969 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml) &&
970 XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y))
975 *w_ret = ml.hdisplay;
976 *h_ret = ml.vdisplay;
978 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
979 /* There is no viewport -- the screen does not scroll. */
983 /* Apparently some versions of XFree86 return nonsense here!
984 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
985 So, sanity-check the values and give up if they are out of range.
987 if (*x_ret < 0 || *x_ret >= w ||
988 *y_ret < 0 || *y_ret >= h ||
989 *w_ret <= 0 || *w_ret > w ||
990 *h_ret <= 0 || *h_ret > h)
992 static int warned_once = 0;
995 fprintf (stderr, "\n"
996 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
997 "%s: The XVidMode server extension is returning nonsense.\n"
998 "%s: Please report this bug to your X server vendor.\n\n",
999 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1010 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1011 blurb(), ssi->number,
1012 *w_ret, *h_ret, *x_ret, *y_ret);
1015 /* Apparently, though the server stores the X position in increments of
1016 1 pixel, it will only make changes to the *display* in some other
1017 increment. With XF86_SVGA on a Thinkpad, the display only updates
1018 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1019 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1020 mode, because I don't have enough video memory to find out.
1022 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1023 server's *target* scroll position rather than the server's *actual*
1024 scroll position. David Dawes agrees, and says they may fix this in
1025 XFree86 4.0, but it's notrivial.
1027 He also confirms that this behavior is server-dependent, so the
1028 actual scroll position cannot be reliably determined by the client.
1029 So... that means the only solution is to provide a ``sandbox''
1030 around the blackout window -- we make the window be up to N pixels
1031 larger than the viewport on both the left and right sides. That
1032 means some part of the outer edges of each hack might not be
1033 visible, but screw it.
1035 I'm going to guess that 16 pixels is enough, and that the Y dimension
1036 doesn't have this problem.
1038 The drawback of doing this, of course, is that some of the screenhacks
1039 will still look pretty stupid -- for example, "slidescreen" will cut
1040 off the left and right edges of the grid, etc.
1043 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1045 /* Round X position down to next lower multiple of FUDGE.
1046 Increase width by 2*FUDGE in case some server rounds up.
1048 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1049 *w_ret += (FUDGE * 2);
1055 *w_ret != ml.hdisplay ||
1056 *h_ret != ml.vdisplay)
1057 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1058 *w_ret, *h_ret, *x_ret, *y_ret);
1061 fprintf (stderr, "%s.\n", msg);
1066 #endif /* HAVE_XF86VMODE */
1075 static Bool error_handler_hit_p = False;
1078 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1080 error_handler_hit_p = True;
1085 /* Returns True if successful, False if an X error occurred.
1086 We need this because other programs might have done things to
1087 our window that will cause XChangeWindowAttributes() to fail:
1088 if that happens, we give up, destroy the window, and re-create
1092 safe_XChangeWindowAttributes (Display *dpy, Window window,
1094 XSetWindowAttributes *attrs)
1096 XErrorHandler old_handler;
1098 error_handler_hit_p = False;
1099 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1101 XChangeWindowAttributes (dpy, window, mask, attrs);
1104 XSetErrorHandler (old_handler);
1107 return (!error_handler_hit_p);
1111 /* This might not be necessary, but just in case. */
1113 safe_XConfigureWindow (Display *dpy, Window window,
1114 unsigned long mask, XWindowChanges *changes)
1116 XErrorHandler old_handler;
1118 error_handler_hit_p = False;
1119 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1121 XConfigureWindow (dpy, window, mask, changes);
1124 XSetErrorHandler (old_handler);
1127 return (!error_handler_hit_p);
1130 /* This might not be necessary, but just in case. */
1132 safe_XDestroyWindow (Display *dpy, Window window)
1134 XErrorHandler old_handler;
1136 error_handler_hit_p = False;
1137 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1139 XDestroyWindow (dpy, window);
1142 XSetErrorHandler (old_handler);
1145 return (!error_handler_hit_p);
1150 safe_XKillClient (Display *dpy, XID id)
1152 XErrorHandler old_handler;
1154 error_handler_hit_p = False;
1155 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1157 XKillClient (dpy, id);
1160 XSetErrorHandler (old_handler);
1163 return (!error_handler_hit_p);
1168 initialize_screensaver_window_1 (saver_screen_info *ssi)
1170 saver_info *si = ssi->global;
1171 saver_preferences *p = &si->prefs;
1172 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1174 /* This resets the screensaver window as fully as possible, since there's
1175 no way of knowing what some random client may have done to us in the
1176 meantime. We could just destroy and recreate the window, but that has
1177 its own set of problems...
1180 XSetWindowAttributes attrs;
1181 unsigned long attrmask;
1182 int x, y, width, height;
1183 static Bool printed_visual_info = False; /* only print the message once. */
1184 Window horked_window = 0;
1186 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1187 (p->verbose_p && !si->screen_blanked_p));
1189 black.red = black.green = black.blue = 0;
1191 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1194 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1195 /* It's not the default visual, so we have no choice but to install. */
1196 install_cmap_p = True;
1202 ssi->cmap = XCreateColormap (si->dpy,
1203 RootWindowOfScreen (ssi->screen),
1204 ssi->current_visual, AllocNone);
1205 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1206 ssi->black_pixel = black.pixel;
1211 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1214 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1215 if (ssi->cmap != ssi->demo_cmap &&
1216 ssi->cmap != def_cmap)
1217 XFreeColormap (si->dpy, ssi->cmap);
1219 ssi->cmap = def_cmap;
1220 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1223 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1224 CWBackPixel | CWBackingPixel | CWBorderPixel);
1225 attrs.override_redirect = True;
1227 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1228 actually be reading these events during normal operation; but we still
1229 need to see Button events for demo-mode to work properly.
1231 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1232 ButtonPressMask | ButtonReleaseMask |
1235 attrs.backing_store = NotUseful;
1236 attrs.colormap = ssi->cmap;
1237 attrs.background_pixel = ssi->black_pixel;
1238 attrs.backing_pixel = ssi->black_pixel;
1239 attrs.border_pixel = ssi->black_pixel;
1241 if (p->debug_p) width = width / 2;
1243 if (!p->verbose_p || printed_visual_info)
1245 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1247 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1248 describe_visual (stderr, ssi->screen, ssi->current_visual,
1253 fprintf (stderr, "%s: using visual: ", blurb());
1254 describe_visual (stderr, ssi->screen, ssi->current_visual,
1256 fprintf (stderr, "%s: default visual: ", blurb());
1257 describe_visual (stderr, ssi->screen,
1258 DefaultVisualOfScreen (ssi->screen),
1259 ssi->install_cmap_p);
1261 printed_visual_info = True;
1263 #ifdef HAVE_MIT_SAVER_EXTENSION
1264 if (si->using_mit_saver_extension)
1266 XScreenSaverInfo *info;
1267 Window root = RootWindowOfScreen (ssi->screen);
1270 /* This call sets the server screensaver timeouts to what we think
1271 they should be (based on the resources and args xscreensaver was
1272 started with.) It's important that we do this to sync back up
1273 with the server - if we have turned on prematurely, as by an
1274 ACTIVATE ClientMessage, then the server may decide to activate
1275 the screensaver while it's already active. That's ok for us,
1276 since we would know to ignore that ScreenSaverActivate event,
1277 but a side effect of this would be that the server would map its
1278 saver window (which we then hide again right away) meaning that
1279 the bits currently on the screen get blown away. Ugly. */
1281 /* #### Ok, that doesn't work - when we tell the server that the
1282 screensaver is "off" it sends us a Deactivate event, which is
1283 sensible... but causes the saver to never come on. Hmm. */
1284 disable_builtin_screensaver (si, True);
1288 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1289 window that the server itself uses for saving the screen.
1290 However, using this window in any way, in particular, calling
1291 XScreenSaverSetAttributes() as below, tends to make the X server
1292 crash. So fuck it, let's try and get along without using it...
1294 It's also inconvenient to use this window because it doesn't
1295 always exist (though the ID is constant.) So to use this
1296 window, we'd have to reimplement the ACTIVATE ClientMessage to
1297 tell the *server* to tell *us* to turn on, to cause the window
1298 to get created at the right time. Gag. */
1299 XScreenSaverSetAttributes (si->dpy, root,
1300 0, 0, width, height, 0,
1301 current_depth, InputOutput, visual,
1303 XSync (si->dpy, False);
1306 info = XScreenSaverAllocInfo ();
1307 XScreenSaverQueryInfo (si->dpy, root, info);
1308 ssi->server_mit_saver_window = info->window;
1309 if (! ssi->server_mit_saver_window) abort ();
1312 #endif /* HAVE_MIT_SAVER_EXTENSION */
1314 if (ssi->screensaver_window)
1316 XWindowChanges changes;
1317 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1320 changes.width = width;
1321 changes.height = height;
1322 changes.border_width = 0;
1324 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1325 changesmask, &changes) &&
1326 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1329 horked_window = ssi->screensaver_window;
1330 ssi->screensaver_window = 0;
1334 if (!ssi->screensaver_window)
1336 ssi->screensaver_window =
1337 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1338 x, y, width, height,
1339 0, ssi->current_depth, InputOutput,
1340 ssi->current_visual, attrmask, &attrs);
1347 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1348 blurb(), (unsigned long) horked_window);
1349 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1351 safe_XDestroyWindow (si->dpy, horked_window);
1356 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1357 blurb(), ssi->number,
1358 (unsigned long) ssi->screensaver_window);
1361 store_saver_id (ssi); /* store window name and IDs */
1366 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1368 BlackPixelOfScreen (ssi->screen),
1369 BlackPixelOfScreen (ssi->screen),
1371 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1373 XFreePixmap (si->dpy, bit);
1376 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1379 XUndefineCursor (si->dpy, ssi->screensaver_window);
1381 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1385 initialize_screensaver_window (saver_info *si)
1388 for (i = 0; i < si->nscreens; i++)
1389 initialize_screensaver_window_1 (&si->screens[i]);
1394 raise_window (saver_info *si,
1395 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1397 saver_preferences *p = &si->prefs;
1401 inhibit_fade = True;
1403 if (si->emergency_lock_p)
1404 inhibit_fade = True;
1407 initialize_screensaver_window (si);
1409 reset_watchdog_timer (si, True);
1411 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1413 Window *current_windows = (Window *)
1414 calloc(sizeof(Window), si->nscreens);
1415 Colormap *current_maps = (Colormap *)
1416 calloc(sizeof(Colormap), si->nscreens);
1418 for (i = 0; i < si->nscreens; i++)
1420 saver_screen_info *ssi = &si->screens[i];
1421 current_windows[i] = ssi->screensaver_window;
1422 current_maps[i] = (between_hacks_p
1424 : DefaultColormapOfScreen (ssi->screen));
1425 /* Ensure that the default background of the window is really black,
1426 not a pixmap or something. (This does not clear the window.) */
1427 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1431 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1433 XGrabServer (si->dpy); /* ############ DANGER! */
1435 /* Clear the stderr layer on each screen.
1438 for (i = 0; i < si->nscreens; i++)
1440 saver_screen_info *ssi = &si->screens[i];
1441 if (ssi->stderr_overlay_window)
1442 /* Do this before the fade, since the stderr cmap won't fade
1443 even if we uninstall it (beats me...) */
1447 /* Note! The server is grabbed, and this will take several seconds
1449 fade_screens (si->dpy, current_maps, current_windows,
1450 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1453 free(current_windows);
1455 current_windows = 0;
1457 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1459 #ifdef HAVE_MIT_SAVER_EXTENSION
1460 for (i = 0; i < si->nscreens; i++)
1462 saver_screen_info *ssi = &si->screens[i];
1463 if (ssi->server_mit_saver_window &&
1464 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1465 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1467 #endif /* HAVE_MIT_SAVER_EXTENSION */
1469 XUngrabServer (si->dpy);
1470 XSync (si->dpy, False); /* ###### (danger over) */
1474 for (i = 0; i < si->nscreens; i++)
1476 saver_screen_info *ssi = &si->screens[i];
1478 XClearWindow (si->dpy, ssi->screensaver_window);
1479 if (!dont_clear || ssi->stderr_overlay_window)
1481 XMapRaised (si->dpy, ssi->screensaver_window);
1482 #ifdef HAVE_MIT_SAVER_EXTENSION
1483 if (ssi->server_mit_saver_window &&
1484 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1485 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1486 #endif /* HAVE_MIT_SAVER_EXTENSION */
1490 for (i = 0; i < si->nscreens; i++)
1492 saver_screen_info *ssi = &si->screens[i];
1494 XInstallColormap (si->dpy, ssi->cmap);
1500 mouse_screen (saver_info *si)
1502 saver_preferences *p = &si->prefs;
1504 if (si->nscreens == 1)
1509 for (i = 0; i < si->nscreens; i++)
1511 saver_screen_info *ssi = &si->screens[i];
1512 Window pointer_root, pointer_child;
1513 int root_x, root_y, win_x, win_y;
1515 if (XQueryPointer (si->dpy,
1516 RootWindowOfScreen (ssi->screen),
1517 &pointer_root, &pointer_child,
1518 &root_x, &root_y, &win_x, &win_y, &mask))
1521 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1522 blurb(), i, si->nscreens);
1527 /* couldn't figure out where the mouse is? Oh well. */
1534 blank_screen (saver_info *si)
1541 /* Note: we do our grabs on the root window, not on the screensaver window.
1542 If we grabbed on the saver window, then the demo mode and lock dialog
1543 boxes wouldn't get any events.
1545 By "the root window", we mean "the root window that contains the mouse."
1546 We use to always grab the mouse on screen 0, but that has the effect of
1547 moving the mouse to screen 0 from whichever screen it was on, on
1550 mscreen = mouse_screen (si);
1551 w = RootWindowOfScreen(si->screens[mscreen].screen);
1552 ok = grab_keyboard_and_mouse (si, w,
1553 (si->demoing_p ? 0 : si->screens[0].cursor),
1557 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1558 /* If we're using a server extension, then failure to get a grab is
1559 not a big deal -- even without the grab, we will still be able
1560 to un-blank when there is user activity, since the server will
1567 for (i = 0; i < si->nscreens; i++)
1569 saver_screen_info *ssi = &si->screens[i];
1571 save_real_vroot (ssi);
1572 store_vroot_property (si->dpy,
1573 ssi->screensaver_window,
1574 ssi->screensaver_window);
1576 #ifdef HAVE_XF86VMODE
1579 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1580 !XF86VidModeGetViewPort (si->dpy, i,
1583 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1585 #endif /* HAVE_XF86VMODE */
1588 raise_window (si, False, False, False);
1590 si->screen_blanked_p = True;
1591 si->blank_time = time ((time_t) 0);
1592 si->last_wall_clock_time = 0;
1594 store_saver_status (si); /* store blank time */
1601 unblank_screen (saver_info *si)
1603 saver_preferences *p = &si->prefs;
1604 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1607 monitor_power_on (si);
1608 reset_watchdog_timer (si, False);
1615 Window *current_windows = (Window *)
1616 calloc(sizeof(Window), si->nscreens);
1618 for (i = 0; i < si->nscreens; i++)
1620 saver_screen_info *ssi = &si->screens[i];
1621 current_windows[i] = ssi->screensaver_window;
1622 /* Ensure that the default background of the window is really black,
1623 not a pixmap or something. (This does not clear the window.) */
1624 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1628 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1631 XSync (si->dpy, False);
1632 XGrabServer (si->dpy); /* ############ DANGER! */
1633 XSync (si->dpy, False);
1635 /* Clear the stderr layer on each screen.
1637 for (i = 0; i < si->nscreens; i++)
1639 saver_screen_info *ssi = &si->screens[i];
1643 XUngrabServer (si->dpy);
1644 XSync (si->dpy, False); /* ###### (danger over) */
1647 fade_screens (si->dpy, 0, current_windows,
1648 p->fade_seconds/1000, p->fade_ticks,
1651 free(current_windows);
1652 current_windows = 0;
1654 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1658 for (i = 0; i < si->nscreens; i++)
1660 saver_screen_info *ssi = &si->screens[i];
1663 Colormap c = DefaultColormapOfScreen (ssi->screen);
1664 /* avoid technicolor */
1665 XClearWindow (si->dpy, ssi->screensaver_window);
1666 if (c) XInstallColormap (si->dpy, c);
1668 XUnmapWindow (si->dpy, ssi->screensaver_window);
1673 /* If the focus window does has a non-default colormap, then install
1674 that colormap as well. (On SGIs, this will cause both the root map
1675 and the focus map to be installed simultaniously. It'd be nice to
1676 pick up the other colormaps that had been installed, too; perhaps
1677 XListInstalledColormaps could be used for that?)
1682 XGetInputFocus (si->dpy, &focus, &revert_to);
1683 if (focus && focus != PointerRoot && focus != None)
1685 XWindowAttributes xgwa;
1687 XGetWindowAttributes (si->dpy, focus, &xgwa);
1688 if (xgwa.colormap &&
1689 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1690 XInstallColormap (si->dpy, xgwa.colormap);
1695 for (i = 0; i < si->nscreens; i++)
1697 saver_screen_info *ssi = &si->screens[i];
1698 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1701 store_saver_status (si); /* store unblank time */
1702 ungrab_keyboard_and_mouse (si);
1703 restore_real_vroot (si);
1705 /* Unmap the windows a second time, dammit -- just to avoid a race
1706 with the screen-grabbing hacks. (I'm not sure if this is really
1707 necessary; I'm stabbing in the dark now.)
1709 for (i = 0; i < si->nscreens; i++)
1710 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1712 si->screen_blanked_p = False;
1713 si->blank_time = time ((time_t) 0);
1714 si->last_wall_clock_time = 0;
1716 store_saver_status (si); /* store unblank time */
1720 /* Transfer any grabs from the old window to the new.
1721 Actually I think none of this is necessary, since we always
1722 hold our grabs on the root window, but I wrote this before
1723 re-discovering that...
1726 maybe_transfer_grabs (saver_screen_info *ssi,
1727 Window old_w, Window new_w,
1730 saver_info *si = ssi->global;
1732 /* If the old window held our mouse grab, transfer the grab to the new
1733 window. (Grab the server while so doing, to avoid a race condition.)
1735 if (old_w == si->mouse_grab_window)
1737 XGrabServer (si->dpy); /* ############ DANGER! */
1739 grab_mouse (si, ssi->screensaver_window,
1740 (si->demoing_p ? 0 : ssi->cursor),
1742 XUngrabServer (si->dpy);
1743 XSync (si->dpy, False); /* ###### (danger over) */
1746 /* If the old window held our keyboard grab, transfer the grab to the new
1747 window. (Grab the server while so doing, to avoid a race condition.)
1749 if (old_w == si->keyboard_grab_window)
1751 XGrabServer (si->dpy); /* ############ DANGER! */
1753 grab_kbd(si, ssi->screensaver_window, ssi->number);
1754 XUngrabServer (si->dpy);
1755 XSync (si->dpy, False); /* ###### (danger over) */
1762 select_visual (saver_screen_info *ssi, const char *visual_name)
1764 saver_info *si = ssi->global;
1765 saver_preferences *p = &si->prefs;
1766 Bool install_cmap_p = p->install_cmap_p;
1767 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1771 if (visual_name && *visual_name)
1773 if (!strcmp(visual_name, "default-i") ||
1774 !strcmp(visual_name, "Default-i") ||
1775 !strcmp(visual_name, "Default-I")
1778 visual_name = "default";
1779 install_cmap_p = True;
1781 else if (!strcmp(visual_name, "default-n") ||
1782 !strcmp(visual_name, "Default-n") ||
1783 !strcmp(visual_name, "Default-N"))
1785 visual_name = "default";
1786 install_cmap_p = False;
1788 else if (!strcmp(visual_name, "gl") ||
1789 !strcmp(visual_name, "Gl") ||
1790 !strcmp(visual_name, "GL"))
1792 new_v = ssi->best_gl_visual;
1793 if (!new_v && p->verbose_p)
1794 fprintf (stderr, "%s: no GL visuals.\n", progname);
1798 new_v = get_visual (ssi->screen, visual_name, True, False);
1802 new_v = ssi->default_visual;
1807 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1808 /* It's not the default visual, so we have no choice but to install. */
1809 install_cmap_p = True;
1811 ssi->install_cmap_p = install_cmap_p;
1814 ((ssi->current_visual != new_v) ||
1815 (install_cmap_p != was_installed_p)))
1817 Colormap old_c = ssi->cmap;
1818 Window old_w = ssi->screensaver_window;
1822 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1823 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1825 fprintf (stderr, "%s: from ", blurb());
1826 describe_visual (stderr, ssi->screen, ssi->current_visual,
1832 ssi->current_visual = new_v;
1833 ssi->current_depth = visual_depth(ssi->screen, new_v);
1835 ssi->screensaver_window = 0;
1837 initialize_screensaver_window_1 (ssi);
1839 /* stderr_overlay_window is a child of screensaver_window, so we need
1840 to destroy that as well (actually, we just need to invalidate and
1841 drop our pointers to it, but this will destroy it, which is ok so
1842 long as it happens before old_w itself is destroyed.) */
1845 raise_window (si, True, True, False);
1846 store_vroot_property (si->dpy,
1847 ssi->screensaver_window, ssi->screensaver_window);
1849 /* Transfer any grabs from the old window to the new. */
1850 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1852 /* Now we can destroy the old window without horking our grabs. */
1853 XDestroyWindow (si->dpy, old_w);
1856 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1857 blurb(), ssi->number, (unsigned long) old_w);
1860 old_c != DefaultColormapOfScreen (ssi->screen) &&
1861 old_c != ssi->demo_cmap)
1862 XFreeColormap (si->dpy, old_c);