+#endif /* HAVE_SGI_VIDEO */
+
+ grab_screen_image_1 (screen, window);
+}
+
+
+/* When we are grabbing and manipulating a screen image, it's important that
+ we use the same colormap it originally had. So, if the screensaver was
+ started with -install, we need to copy the contents of the default colormap
+ into the screensaver's colormap.
+ */
+static void
+copy_default_colormap_contents (Screen *screen,
+ Colormap to_cmap,
+ Visual *to_visual)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Visual *from_visual = DefaultVisualOfScreen (screen);
+ Colormap from_cmap = XDefaultColormapOfScreen (screen);
+
+ XColor *old_colors, *new_colors;
+ unsigned long *pixels;
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+ int from_cells, to_cells, max_cells, got_cells;
+ int i;
+
+ if (from_cmap == to_cmap)
+ return;
+
+ vi_in.screen = XScreenNumberOfScreen (screen);
+ vi_in.visualid = XVisualIDFromVisual (from_visual);
+ vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+ from_cells = vi_out [0].colormap_size;
+ XFree ((char *) vi_out);
+
+ vi_in.screen = XScreenNumberOfScreen (screen);
+ vi_in.visualid = XVisualIDFromVisual (to_visual);
+ vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+ to_cells = vi_out [0].colormap_size;
+ XFree ((char *) vi_out);
+
+ max_cells = (from_cells > to_cells ? to_cells : from_cells);
+
+ old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
+ new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
+ pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
+ for (i = 0; i < max_cells; i++)
+ old_colors[i].pixel = i;
+ XQueryColors (dpy, from_cmap, old_colors, max_cells);
+
+ got_cells = max_cells;
+ allocate_writable_colors (dpy, to_cmap, pixels, &got_cells);
+
+#ifdef DEBUG
+ if (got_cells != max_cells)
+ fprintf(stderr, "%s: got only %d of %d cells\n", progname,
+ got_cells, max_cells);
+#endif /* DEBUG */
+
+ if (got_cells <= 0) /* we're screwed */
+ ;
+ else if (got_cells == max_cells && /* we're golden */
+ from_cells == to_cells)
+ XStoreColors (dpy, to_cmap, old_colors, got_cells);
+ else /* try to cope... */
+ {
+ for (i = 0; i < got_cells; i++)
+ {
+ XColor *c = old_colors + i;
+ int j;
+ for (j = 0; j < got_cells; j++)
+ if (pixels[j] == c->pixel)
+ {
+ /* only store this color value if this is one of the pixels
+ we were able to allocate. */
+ XStoreColors (dpy, to_cmap, c, 1);
+ break;
+ }
+ }
+ }
+
+
+#ifdef DEBUG
+ fprintf(stderr, "%s: installing copy of default colormap\n", progname);
+#endif /* DEBUG */
+
+ free (old_colors);
+ free (new_colors);
+ free (pixels);
+}
+
+
+\f
+/* The SGI ReadDisplay extension.
+ This extension lets you get back a 24-bit image of the screen, taking into
+ account the colors with which all windows are *currently* displayed, even
+ if those windows have different visuals. Without this extension, presence
+ of windows with different visuals or colormaps will result in technicolor
+ when one tries to grab the screen image.
+ */
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+
+static Bool
+read_display (Screen *screen, Window window, Pixmap into_pixmap,
+ Bool dont_wait)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ int rd_event_base = 0;
+ int rd_error_base = 0;
+ unsigned long hints = 0;
+ XImage *image = 0;
+ XGCValues gcv;
+ int class;
+ GC gc;
+ Bool install_p = False;
+
+ /* Check to see if the server supports the extension, and bug out if not.
+ */
+ if (! XReadDisplayQueryExtension (dpy, &rd_event_base, &rd_error_base))
+ return False;
+
+ /* If this isn't a visual we know how to handle, bug out. We handle:
+ = TrueColor in depths 8, 12, 16, and 32;
+ = PseudoColor and DirectColor in depths 8 and 12.
+ */
+ XGetWindowAttributes(dpy, window, &xgwa);
+ class = visual_class (screen, xgwa.visual);
+ if (class == TrueColor)
+ {
+ if (xgwa.depth != 8 && xgwa.depth != 12 && xgwa.depth != 16 &&
+ xgwa.depth != 24 && xgwa.depth != 32)
+ return False;
+ }
+ else if (class == PseudoColor || class == DirectColor)
+ {
+ if (xgwa.depth != 8 && xgwa.depth != 12)
+ return False;
+ else
+ /* Install a colormap that makes this visual behave like
+ a TrueColor visual of the same depth. */
+ install_p = True;
+ }
+
+
+ /* Try and read the screen.
+ */
+ hints = (XRD_TRANSPARENT | XRD_READ_POINTER);
+ image = XReadDisplay (dpy, window, xgwa.x, xgwa.y, xgwa.width, xgwa.height,
+ hints, &hints);
+ if (!image)
+ return False;
+ if (!image->data)
+ {
+ XDestroyImage(image);
+ return False;
+ }
+
+ /* XReadDisplay tends to LIE about the depth of the image it read.
+ It is returning an XImage which has `depth' and `bits_per_pixel'
+ confused!
+
+ That is, on a 24-bit display, where all visuals claim depth 24, and
+ where XGetImage would return an XImage with depth 24, and where
+ XPutImage will get a BadMatch with images that are not depth 24,
+ XReadDisplay is returning images with depth 32! Fuckwits!
+
+ So if the visual is of depth 24, but the image came back as depth 32,
+ hack it to be 24 lest we get a BadMatch from XPutImage.
+
+ I wonder what happens on an 8-bit SGI... Probably it still returns
+ an image claiming depth 32? Certainly it can't be 8. So, let's just
+ smash it to 32...
+ */
+ if (image->depth == 32 /* && xgwa.depth == 24 */ )
+ image->depth = 24;
+
+ /* If the visual of the window/pixmap into which we're going to draw is
+ less deep than the screen itself, then we need to convert the grabbed bits
+ to match the depth by clipping off the less significant bit-planes of each
+ color component.
+ */
+ if (image->depth > xgwa.depth)
+ {
+ int x, y;
+ /* We use the same image->data in both images -- that's ok, because
+ since we're reading from B and writing to A, and B uses more bytes
+ per pixel than A, the write pointer won't overrun the read pointer.
+ */
+ XImage *image2 = XCreateImage (dpy, xgwa.visual, xgwa.depth,
+ ZPixmap, 0, image->data,
+ xgwa.width, xgwa.height,
+ 8, 0);
+ if (!image2)
+ return False;
+
+#ifdef DEBUG
+ fprintf(stderr, "%s: converting from depth %d to depth %d\n",
+ progname, image->depth, xgwa.depth);
+#endif /* DEBUG */
+
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ /* #### really these shift values should be determined from the
+ mask values -- but that's a pain in the ass, and anyway,
+ this is an SGI-specific extension so hardcoding assumptions
+ about the SGI server's behavior isn't *too* heinous... */
+ unsigned long pixel = XGetPixel(image, x, y);
+ unsigned int r = (pixel & image->red_mask);
+ unsigned int g = (pixel & image->green_mask) >> 8;
+ unsigned int b = (pixel & image->blue_mask) >> 16;
+
+ if (xgwa.depth == 8)
+ pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
+ else if (xgwa.depth == 12)
+ pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
+ else if (xgwa.depth == 16)
+ pixel = ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10));
+ else
+ abort();
+
+ XPutPixel(image2, x, y, pixel);
+ }
+ image->data = 0;
+ XDestroyImage(image);
+ image = image2;
+ }
+
+
+ /* Now actually put the bits into the window or pixmap -- note the design
+ bogosity of this extension, where we've been forced to take 24 bit data
+ from the server to the client, and then push it back from the client to
+ the server, *without alteration*. We should have just been able to tell
+ the server, "put a screen image in this drawable", instead of having to
+ go through the intermediate step of converting it to an Image. Geez.
+ (Assuming that the window is of screen depth; we happen to handle less
+ deep windows, but that's beside the point.)
+ */
+ gcv.function = GXcopy;
+ gc = XCreateGC (dpy, window, GCFunction, &gcv);
+
+ if (into_pixmap)