+ ssi->cmap = def_cmap;
+ ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
+ }
+
+ attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
+ CWBackPixel | CWBackingPixel | CWBorderPixel);
+ attrs.override_redirect = True;
+
+ /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
+ actually be reading these events during normal operation; but we still
+ need to see Button events for demo-mode to work properly.
+ */
+ attrs.event_mask = (KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask);
+
+ attrs.backing_store = NotUseful;
+ attrs.colormap = ssi->cmap;
+ attrs.background_pixel = ssi->black_pixel;
+ attrs.backing_pixel = ssi->black_pixel;
+ attrs.border_pixel = ssi->black_pixel;
+
+ if (p->debug_p
+# ifdef QUAD_MODE
+ && !p->quad_p
+# endif
+ )
+ width = width / 2;
+
+ if (!p->verbose_p || printed_visual_info)
+ ;
+ else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
+ {
+ fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
+ describe_visual (stderr, ssi->screen, ssi->current_visual,
+ install_cmap_p);
+ }
+ else
+ {
+ fprintf (stderr, "%s: using visual: ", blurb());
+ describe_visual (stderr, ssi->screen, ssi->current_visual,
+ install_cmap_p);
+ fprintf (stderr, "%s: default visual: ", blurb());
+ describe_visual (stderr, ssi->screen,
+ DefaultVisualOfScreen (ssi->screen),
+ ssi->install_cmap_p);
+ }
+ printed_visual_info = True;
+
+#ifdef HAVE_MIT_SAVER_EXTENSION
+ if (si->using_mit_saver_extension)
+ {
+ XScreenSaverInfo *info;
+ Window root = RootWindowOfScreen (ssi->screen);
+
+#if 0
+ /* This call sets the server screensaver timeouts to what we think
+ they should be (based on the resources and args xscreensaver was
+ started with.) It's important that we do this to sync back up
+ with the server - if we have turned on prematurely, as by an
+ ACTIVATE ClientMessage, then the server may decide to activate
+ the screensaver while it's already active. That's ok for us,
+ since we would know to ignore that ScreenSaverActivate event,
+ but a side effect of this would be that the server would map its
+ saver window (which we then hide again right away) meaning that
+ the bits currently on the screen get blown away. Ugly. */
+
+ /* #### Ok, that doesn't work - when we tell the server that the
+ screensaver is "off" it sends us a Deactivate event, which is
+ sensible... but causes the saver to never come on. Hmm. */
+ disable_builtin_screensaver (si, True);
+#endif /* 0 */
+
+#if 0
+ /* #### The MIT-SCREEN-SAVER extension gives us access to the
+ window that the server itself uses for saving the screen.
+ However, using this window in any way, in particular, calling
+ XScreenSaverSetAttributes() as below, tends to make the X server
+ crash. So fuck it, let's try and get along without using it...
+
+ It's also inconvenient to use this window because it doesn't
+ always exist (though the ID is constant.) So to use this
+ window, we'd have to reimplement the ACTIVATE ClientMessage to
+ tell the *server* to tell *us* to turn on, to cause the window
+ to get created at the right time. Gag. */
+ XScreenSaverSetAttributes (si->dpy, root,
+ 0, 0, width, height, 0,
+ current_depth, InputOutput, visual,
+ attrmask, &attrs);
+ XSync (si->dpy, False);
+#endif /* 0 */
+
+ info = XScreenSaverAllocInfo ();
+ XScreenSaverQueryInfo (si->dpy, root, info);
+ ssi->server_mit_saver_window = info->window;
+ if (! ssi->server_mit_saver_window) abort ();
+ XFree (info);
+ }
+#endif /* HAVE_MIT_SAVER_EXTENSION */
+
+ if (ssi->screensaver_window)
+ {
+ XWindowChanges changes;
+ unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
+ changes.x = x;
+ changes.y = y;
+ changes.width = width;
+ changes.height = height;
+ changes.border_width = 0;
+
+ if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
+ changesmask, &changes) &&
+ safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
+ attrmask, &attrs)))
+ {
+ horked_window = ssi->screensaver_window;
+ ssi->screensaver_window = 0;
+ }
+ }
+
+ if (!ssi->screensaver_window)
+ {
+ ssi->screensaver_window =
+ XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
+ x, y, width, height,
+ 0, ssi->current_depth, InputOutput,
+ ssi->current_visual, attrmask, &attrs);
+
+ reset_stderr (ssi);
+
+ if (horked_window)
+ {
+ fprintf (stderr,
+ "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
+ blurb(), (unsigned long) horked_window);
+ maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
+ ssi->number);
+ safe_XDestroyWindow (si->dpy, horked_window);
+ horked_window = 0;
+ }
+
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
+ blurb(), ssi->number,
+ (unsigned long) ssi->screensaver_window);
+ }
+
+ store_saver_id (ssi); /* store window name and IDs */
+
+ if (!ssi->cursor)
+ {
+ Pixmap bit;
+ bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
+ "\000", 1, 1,
+ BlackPixelOfScreen (ssi->screen),
+ BlackPixelOfScreen (ssi->screen),
+ 1);
+ ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
+ 0, 0);
+ XFreePixmap (si->dpy, bit);
+ }
+
+ XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
+
+ if (si->demoing_p)
+ XUndefineCursor (si->dpy, ssi->screensaver_window);
+ else
+ XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
+}
+
+void
+initialize_screensaver_window (saver_info *si)
+{
+ int i;
+ for (i = 0; i < si->nscreens; i++)
+ initialize_screensaver_window_1 (&si->screens[i]);
+}
+
+
+/* Called when the RANDR (Resize and Rotate) extension tells us that the
+ size of the screen has changed while the screen was blanked. If we
+ don't do this, then the screen saver will no longer fully fill the
+ screen, and some of the underlying desktop may be visible.
+ */
+void
+resize_screensaver_window (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ int i;
+
+ /* First update the size info in the saver_screen_info structs.
+ */
+
+# ifdef HAVE_XINERAMA
+ if (si->xinerama_p)
+ {
+ /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
+ However, maybe they will someday, so I'm guessing that the right thing
+ to do in that case will be to re-query the Xinerama rectangles after
+ a RANDR size change is received: presumably, if the resolution of one
+ or more of the monitors has changed, then the Xinerama rectangle
+ corresponding to that monitor will also have been updated.
+ */
+ int nscreens;
+ XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
+
+ if (nscreens != si->nscreens) {
+ /* Apparently some Xinerama implementations let you use a hot-key
+ to change the number of screens in use! This is, of course,
+ documented nowhere. Let's try to do something marginally less
+ bad than crashing.
+ */
+ fprintf (stderr, "%s: bad craziness: xinerama screen count changed "
+ "from %d to %d!\n", blurb(), si->nscreens, nscreens);
+ if (nscreens > si->nscreens)
+ nscreens = si->nscreens;
+ }
+
+ if (!xsi) abort();
+ for (i = 0; i < nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (p->verbose_p &&
+ (ssi->x != xsi[i].x_org ||
+ ssi->y != xsi[i].y_org ||
+ ssi->width != xsi[i].width ||
+ ssi->height != xsi[i].height))
+ fprintf (stderr,
+ "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
+ blurb(), i,
+ ssi->width, ssi->height, ssi->x, ssi->y,
+ xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
+
+ ssi->x = xsi[i].x_org;
+ ssi->y = xsi[i].y_org;
+ ssi->width = xsi[i].width;
+ ssi->height = xsi[i].height;
+ }
+ XFree (xsi);
+ }
+ else
+# endif /* HAVE_XINERAMA */
+ {
+ /* Not Xinerama -- get the real sizes of the root windows. */
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
+ &xgwa);
+
+ if (p->verbose_p &&
+ (ssi->x != xgwa.x ||
+ ssi->y != xgwa.y ||
+ ssi->width != xgwa.width ||
+ ssi->height != xgwa.height))
+ fprintf (stderr,
+ "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
+ blurb(), i,
+ ssi->width, ssi->height, ssi->x, ssi->y,
+ xgwa.width, xgwa.height, xgwa.x, xgwa.y);
+
+ ssi->x = xgwa.x;
+ ssi->y = xgwa.y;
+ ssi->width = xgwa.width;
+ ssi->height = xgwa.height;
+ }
+ }
+
+ /* Next, ensure that the screensaver windows are the right size, taking
+ into account both the new size of the screen in question's root window,
+ and any viewport within that.
+ */
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ XWindowAttributes xgwa;
+ XWindowChanges changes;
+ int x, y, width, height;
+ unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
+
+ XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
+ get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
+ (p->verbose_p && !si->screen_blanked_p));
+ if (xgwa.x == x &&
+ xgwa.y == y &&
+ xgwa.width == width &&
+ xgwa.height == height)
+ continue; /* no change! */
+
+ changes.x = x;
+ changes.y = y;
+ changes.width = width;
+ changes.height = height;
+ changes.border_width = 0;
+
+ if (p->debug_p
+# ifdef QUAD_MODE
+ && !p->quad_p
+# endif
+ )
+ changes.width = changes.width / 2;
+
+ if (p->verbose_p)
+ fprintf (stderr,
+ "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
+ blurb(), i, (unsigned long) ssi->screensaver_window,
+ xgwa.width, xgwa.height, xgwa.x, xgwa.y,
+ width, height, x, y);
+ if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
+ changesmask, &changes))
+ {
+ fprintf (stderr,
+ "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
+ blurb(), i, (unsigned long) ssi->screensaver_window);
+ }
+ }
+}
+
+
+void
+raise_window (saver_info *si,
+ Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
+{
+ saver_preferences *p = &si->prefs;
+ int i;
+
+ if (si->demoing_p)
+ inhibit_fade = True;
+
+ if (si->emergency_lock_p)
+ inhibit_fade = True;
+
+ if (!dont_clear)
+ initialize_screensaver_window (si);
+
+ reset_watchdog_timer (si, True);
+
+ if (p->fade_p && si->fading_possible_p && !inhibit_fade)
+ {
+ Window *current_windows = (Window *)
+ calloc(sizeof(Window), si->nscreens);
+ Colormap *current_maps = (Colormap *)
+ calloc(sizeof(Colormap), si->nscreens);
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ current_windows[i] = ssi->screensaver_window;
+ current_maps[i] = (between_hacks_p
+ ? ssi->cmap
+ : DefaultColormapOfScreen (ssi->screen));
+ /* Ensure that the default background of the window is really black,
+ not a pixmap or something. (This does not clear the window.) */
+ XSetWindowBackground (si->dpy, ssi->screensaver_window,
+ ssi->black_pixel);
+ }
+
+ if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
+
+ XGrabServer (si->dpy); /* ############ DANGER! */
+
+ /* Clear the stderr layer on each screen.
+ */
+ if (!dont_clear)
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (ssi->stderr_overlay_window)
+ /* Do this before the fade, since the stderr cmap won't fade
+ even if we uninstall it (beats me...) */
+ clear_stderr (ssi);
+ }
+
+ /* Note! The server is grabbed, and this will take several seconds
+ to complete! */
+ fade_screens (si->dpy, current_maps,
+ current_windows, si->nscreens,
+ p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
+
+ free(current_maps);
+ free(current_windows);
+ current_maps = 0;
+ current_windows = 0;
+
+ if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
+
+#ifdef HAVE_MIT_SAVER_EXTENSION
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (ssi->server_mit_saver_window &&
+ window_exists_p (si->dpy, ssi->server_mit_saver_window))
+ XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
+ }
+#endif /* HAVE_MIT_SAVER_EXTENSION */
+
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+ }
+ else
+ {
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (!dont_clear)
+ XClearWindow (si->dpy, ssi->screensaver_window);
+ if (!dont_clear || ssi->stderr_overlay_window)
+ clear_stderr (ssi);
+ XMapRaised (si->dpy, ssi->screensaver_window);
+#ifdef HAVE_MIT_SAVER_EXTENSION
+ if (ssi->server_mit_saver_window &&
+ window_exists_p (si->dpy, ssi->server_mit_saver_window))
+ XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
+#endif /* HAVE_MIT_SAVER_EXTENSION */
+ }
+ }
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (ssi->cmap)
+ XInstallColormap (si->dpy, ssi->cmap);
+ }
+}
+
+
+int
+mouse_screen (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ Window pointer_root, pointer_child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ int i;
+
+ if (si->nscreens == 1)
+ return 0;
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
+ &pointer_root, &pointer_child,
+ &root_x, &root_y, &win_x, &win_y, &mask) &&
+ root_x >= ssi->x &&
+ root_y >= ssi->y &&
+ root_x < ssi->x + ssi->width &&
+ root_y < ssi->y + ssi->height)
+ {
+ if (p->verbose_p)
+ fprintf (stderr, "%s: mouse is on screen %d of %d\n",
+ blurb(), i, si->nscreens);
+ return i;
+ }
+ }
+
+ /* couldn't figure out where the mouse is? Oh well. */
+ return 0;
+}
+
+
+Bool
+blank_screen (saver_info *si)
+{
+ int i;
+ Bool ok;
+ Window w;
+ int mscreen;
+
+ /* Note: we do our grabs on the root window, not on the screensaver window.
+ If we grabbed on the saver window, then the demo mode and lock dialog
+ boxes wouldn't get any events.
+
+ By "the root window", we mean "the root window that contains the mouse."
+ We use to always grab the mouse on screen 0, but that has the effect of
+ moving the mouse to screen 0 from whichever screen it was on, on
+ multi-head systems.
+ */
+ mscreen = mouse_screen (si);
+ w = RootWindowOfScreen(si->screens[mscreen].screen);
+ ok = grab_keyboard_and_mouse (si, w,
+ (si->demoing_p ? 0 : si->screens[0].cursor),
+ mscreen);
+
+
+# if 0
+ if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
+ /* If we're using a server extension, then failure to get a grab is
+ not a big deal -- even without the grab, we will still be able
+ to un-blank when there is user activity, since the server will
+ tell us. */
+ /* #### No, that's not true: if we don't have a keyboard grab,
+ then we can't read passwords to unlock.
+ */
+ ok = True;
+# endif /* 0 */
+
+ if (!ok)
+ return False;
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (ssi->real_screen_p)
+ save_real_vroot (ssi);
+ store_vroot_property (si->dpy,
+ ssi->screensaver_window,
+ ssi->screensaver_window);
+
+#ifdef HAVE_XF86VMODE
+ {
+ int ev, er;
+ if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
+ !safe_XF86VidModeGetViewPort (si->dpy, i,
+ &ssi->blank_vp_x,
+ &ssi->blank_vp_y))
+ ssi->blank_vp_x = ssi->blank_vp_y = -1;
+ }
+#endif /* HAVE_XF86VMODE */
+ }
+
+ raise_window (si, False, False, False);
+
+ si->screen_blanked_p = True;
+ si->blank_time = time ((time_t) 0);
+ si->last_wall_clock_time = 0;
+
+ store_saver_status (si); /* store blank time */
+
+ return True;
+}
+
+
+void
+unblank_screen (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ Bool unfade_p = (si->fading_possible_p && p->unfade_p);
+ int i;
+
+ monitor_power_on (si);
+ reset_watchdog_timer (si, False);
+
+ if (si->demoing_p)
+ unfade_p = False;
+
+ if (unfade_p)
+ {
+ Window *current_windows = (Window *)
+ calloc(sizeof(Window), si->nscreens);
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ current_windows[i] = ssi->screensaver_window;
+ /* Ensure that the default background of the window is really black,
+ not a pixmap or something. (This does not clear the window.) */
+ XSetWindowBackground (si->dpy, ssi->screensaver_window,
+ ssi->black_pixel);
+ }
+
+ if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
+
+
+ XSync (si->dpy, False);
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ XSync (si->dpy, False);
+
+ /* Clear the stderr layer on each screen.
+ */
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ clear_stderr (ssi);
+ }
+
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+
+ fade_screens (si->dpy, 0,
+ current_windows, si->nscreens,
+ p->fade_seconds/1000, p->fade_ticks,
+ False, False);
+
+ free(current_windows);
+ current_windows = 0;
+
+ if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
+ }
+ else
+ {
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ if (ssi->cmap)
+ {
+ Colormap c = DefaultColormapOfScreen (ssi->screen);
+ /* avoid technicolor */
+ XClearWindow (si->dpy, ssi->screensaver_window);
+ if (c) XInstallColormap (si->dpy, c);
+ }
+ XUnmapWindow (si->dpy, ssi->screensaver_window);
+ }
+ }
+
+
+ /* If the focus window does has a non-default colormap, then install
+ that colormap as well. (On SGIs, this will cause both the root map
+ and the focus map to be installed simultaneously. It'd be nice to
+ pick up the other colormaps that had been installed, too; perhaps
+ XListInstalledColormaps could be used for that?)
+ */
+ {
+ Window focus = 0;
+ int revert_to;
+ XGetInputFocus (si->dpy, &focus, &revert_to);
+ if (focus && focus != PointerRoot && focus != None)
+ {
+ XWindowAttributes xgwa;
+ xgwa.colormap = 0;
+ XGetWindowAttributes (si->dpy, focus, &xgwa);
+ if (xgwa.colormap &&
+ xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
+ XInstallColormap (si->dpy, xgwa.colormap);
+ }
+ }
+
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
+ }
+
+ store_saver_status (si); /* store unblank time */
+ ungrab_keyboard_and_mouse (si);
+ restore_real_vroot (si);
+
+ /* Unmap the windows a second time, dammit -- just to avoid a race
+ with the screen-grabbing hacks. (I'm not sure if this is really
+ necessary; I'm stabbing in the dark now.)
+ */
+ for (i = 0; i < si->nscreens; i++)
+ XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
+
+ si->screen_blanked_p = False;
+ si->blank_time = time ((time_t) 0);
+ si->last_wall_clock_time = 0;
+
+ store_saver_status (si); /* store unblank time */
+}
+
+
+/* Transfer any grabs from the old window to the new.
+ Actually I think none of this is necessary, since we always
+ hold our grabs on the root window, but I wrote this before
+ re-discovering that...
+ */
+static void
+maybe_transfer_grabs (saver_screen_info *ssi,
+ Window old_w, Window new_w,
+ int new_screen_no)
+{
+ saver_info *si = ssi->global;
+
+ /* If the old window held our mouse grab, transfer the grab to the new
+ window. (Grab the server while so doing, to avoid a race condition.)
+ */
+ if (old_w == si->mouse_grab_window)
+ {
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ ungrab_mouse (si);
+ grab_mouse (si, ssi->screensaver_window,
+ (si->demoing_p ? 0 : ssi->cursor),
+ new_screen_no);
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+ }
+
+ /* If the old window held our keyboard grab, transfer the grab to the new
+ window. (Grab the server while so doing, to avoid a race condition.)
+ */
+ if (old_w == si->keyboard_grab_window)
+ {
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ ungrab_kbd(si);
+ grab_kbd(si, ssi->screensaver_window, ssi->number);
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+ }
+}
+
+
+
+Bool
+select_visual (saver_screen_info *ssi, const char *visual_name)
+{
+ saver_info *si = ssi->global;
+ saver_preferences *p = &si->prefs;
+ Bool install_cmap_p = p->install_cmap_p;
+ Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
+ Visual *new_v = 0;
+ Bool got_it;
+
+ /* On some systems (most recently, MacOS X) OpenGL programs get confused
+ when you kill one and re-start another on the same window. So maybe
+ it's best to just always destroy and recreate the xscreensaver window
+ when changing hacks, instead of trying to reuse the old one?
+ */
+ Bool always_recreate_window_p = True;
+
+ if (visual_name && *visual_name)
+ {
+ if (!strcmp(visual_name, "default-i") ||
+ !strcmp(visual_name, "Default-i") ||
+ !strcmp(visual_name, "Default-I")
+ )
+ {
+ visual_name = "default";
+ install_cmap_p = True;
+ }
+ else if (!strcmp(visual_name, "default-n") ||
+ !strcmp(visual_name, "Default-n") ||
+ !strcmp(visual_name, "Default-N"))
+ {
+ visual_name = "default";
+ install_cmap_p = False;
+ }
+ else if (!strcmp(visual_name, "gl") ||
+ !strcmp(visual_name, "Gl") ||
+ !strcmp(visual_name, "GL"))
+ {
+ new_v = ssi->best_gl_visual;
+ if (!new_v && p->verbose_p)
+ fprintf (stderr, "%s: no GL visuals.\n", progname);
+ }
+
+ if (!new_v)
+ new_v = get_visual (ssi->screen, visual_name, True, False);
+ }
+ else
+ {
+ new_v = ssi->default_visual;
+ }
+
+ got_it = !!new_v;
+
+ if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
+ /* It's not the default visual, so we have no choice but to install. */
+ install_cmap_p = True;
+
+ ssi->install_cmap_p = install_cmap_p;
+
+ if (new_v &&
+ (always_recreate_window_p ||
+ (ssi->current_visual != new_v) ||
+ (install_cmap_p != was_installed_p)))
+ {
+ Colormap old_c = ssi->cmap;
+ Window old_w = ssi->screensaver_window;
+
+ if (p->verbose_p)
+ {
+ fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
+ describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
+#if 0
+ fprintf (stderr, "%s: from ", blurb());
+ describe_visual (stderr, ssi->screen, ssi->current_visual,
+ was_installed_p);