5ef32e1e9c899005abfb0805ba572f1bdde30ecb
[xscreensaver] / utils / grabscreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998
2  *  Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 /* This file contains code for grabbing an image of the screen to hack its
14    bits.  This is a little tricky, since doing this involves the need to tell
15    the difference between drawing on the actual root window, and on the fake
16    root window used by the screensaver, since at this level the illusion 
17    breaks down...
18  */
19
20 #include "utils.h"
21 #include "yarandom.h"
22
23 #include <X11/Xatom.h>
24 #include <X11/Xutil.h>
25
26 #ifdef HAVE_XMU
27 # ifndef VMS
28 #  include <X11/Xmu/WinUtil.h>
29 # else  /* VMS */
30 #  include <Xmu/WinUtil.h>
31 # endif /* VMS */
32 #endif
33
34 #include "usleep.h"
35 #include "colors.h"
36 #include "grabscreen.h"
37 #include "visual.h"
38 #include "resources.h"
39
40 #include "vroot.h"
41 #undef RootWindowOfScreen
42 #undef RootWindow
43 #undef DefaultRootWindow
44
45
46 #ifdef HAVE_READ_DISPLAY_EXTENSION
47 # include <X11/extensions/readdisplay.h>
48   static Bool read_display (Screen *, Window, Pixmap, Bool);
49 #endif /* HAVE_READ_DISPLAY_EXTENSION */
50
51
52 static void copy_default_colormap_contents (Screen *, Colormap, Visual *);
53
54 #ifdef HAVE_READ_DISPLAY_EXTENSION
55 static void allocate_cubic_colormap (Screen *, Window, Visual *);
56 void remap_image (Screen *, Window, Colormap, XImage *);
57 #endif
58
59
60 static Bool
61 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
62 {
63   return (event->xany.type == MapNotify &&
64           event->xvisibility.window == (Window) window);
65 }
66
67 extern char *progname;
68 Bool grab_verbose_p = False;
69
70 void
71 grabscreen_verbose(void)
72 {
73   grab_verbose_p = True;
74 }
75
76
77 static void
78 raise_window(Display *dpy, Window window, Bool dont_wait)
79 {
80   if (grab_verbose_p)
81     fprintf(stderr, "%s: raising window 0x%08lX (%s)\n",
82             progname, (unsigned long) window,
83             (dont_wait ? "not waiting" : "waiting"));
84
85   if (! dont_wait)
86     {
87       XWindowAttributes xgwa;
88       XSizeHints hints;
89       long supplied = 0;
90       memset(&hints, 0, sizeof(hints));
91       XGetWMNormalHints(dpy, window, &hints, &supplied);
92       XGetWindowAttributes (dpy, window, &xgwa);
93       hints.x = xgwa.x;
94       hints.y = xgwa.y;
95       hints.width = xgwa.width;
96       hints.height = xgwa.height;
97       hints.flags |= (PPosition|USPosition|PSize|USSize);
98       XSetWMNormalHints(dpy, window, &hints);
99
100       XSelectInput (dpy, window, (xgwa.your_event_mask | StructureNotifyMask));
101     }
102
103   XMapRaised(dpy, window);
104
105   if (! dont_wait)
106     {
107       XEvent event;
108       XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
109       XSync (dpy, True);
110     }
111 }
112
113
114 static Bool
115 xscreensaver_window_p (Display *dpy, Window window)
116 {
117   Atom type;
118   int format;
119   unsigned long nitems, bytesafter;
120   char *version;
121   if (XGetWindowProperty (dpy, window,
122                           XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
123                           0, 1, False, XA_STRING,
124                           &type, &format, &nitems, &bytesafter,
125                           (unsigned char **) &version)
126       == Success
127       && type != None)
128     return True;
129   return False;
130 }
131
132
133
134 /* Whether the given window is:
135    - the real root window;
136    - the virtual root window;
137    - a direct child of the root window;
138    - a direct child of the window manager's decorations.
139  */
140 Bool
141 top_level_window_p (Screen *screen, Window window)
142 {
143   Display *dpy = DisplayOfScreen (screen);
144   Window root, parent, *kids;
145   Window vroot = VirtualRootWindowOfScreen(screen);
146   unsigned int nkids;
147
148   if (window == vroot)
149     return True;
150
151   if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
152     return False;
153
154   if (window == root)
155     return True;
156
157   /* If our direct parent is the root (or *a* root), then yes. */
158   if (parent == root || parent == vroot)
159     return True;
160   else
161     {
162       Atom type = None;
163       int format;
164       unsigned long nitems, bytesafter;
165       unsigned char *data;
166
167       /* If our direct parent has the WM_STATE property, then it is a
168          window manager decoration -- yes.
169       */
170       if (XGetWindowProperty (dpy, window,
171                               XInternAtom (dpy, "WM_STATE", True),
172                               0, 0, False, AnyPropertyType,
173                               &type, &format, &nitems, &bytesafter,
174                               (unsigned char **) &data)
175           == Success
176           && type != None)
177         return True;
178     }
179
180   /* Else, no.  We're deep in a tree somewhere.
181    */
182   return False;
183 }
184
185
186
187 static XErrorHandler old_ehandler = 0;
188 static int
189 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
190 {
191   if (error->error_code == BadWindow || error->error_code == BadDrawable)
192     return 0;
193   else if (!old_ehandler)
194     {
195       abort();
196       return 0;
197     }
198   else
199     return (*old_ehandler) (dpy, error);
200 }
201
202
203 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
204    on a window whose depth is not the maximal depth of the screen?  Or
205    something.  Anyway, things don't work unless we: use SubwindowMode for
206    the real root window (or a legitimate virtual root window); but do not
207    use SubwindowMode for the xscreensaver window.  I make no attempt to
208    explain.
209  */
210 Bool
211 use_subwindow_mode_p(Screen *screen, Window window)
212 {
213   if (window != VirtualRootWindowOfScreen(screen))
214     return False;
215   else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
216     return False;
217   else
218     return True;
219 }
220
221
222 /* Install the colormaps of all visible windows, deepest first.
223    This should leave the colormaps of the topmost windows installed
224    (if only N colormaps can be installed at a time, then only the
225    topmost N windows will be shown in the right colors.)
226  */
227 static void
228 install_screen_colormaps (Screen *screen)
229 {
230   int i;
231   Display *dpy = DisplayOfScreen (screen);
232   Window vroot, real_root;
233   Window parent, *kids = 0;
234   unsigned int nkids = 0;
235
236   XSync (dpy, False);
237   old_ehandler = XSetErrorHandler (BadWindow_ehandler);
238
239   vroot = VirtualRootWindowOfScreen (screen);
240   if (XQueryTree (dpy, vroot, &real_root, &parent, &kids, &nkids))
241     for (i = 0; i < nkids; i++)
242       {
243         XWindowAttributes xgwa;
244         Window client;
245 #ifdef HAVE_XMU
246         /* #### need to put XmuClientWindow() in xmu.c, sigh... */
247         if (! (client = XmuClientWindow (dpy, kids[i])))
248 #endif
249           client = kids[i];
250         xgwa.colormap = 0;
251         XGetWindowAttributes (dpy, client, &xgwa);
252         if (xgwa.colormap && xgwa.map_state == IsViewable)
253           XInstallColormap (dpy, xgwa.colormap);
254       }
255   XInstallColormap (dpy, DefaultColormapOfScreen (screen));
256   XSync (dpy, False);
257   XSetErrorHandler (old_ehandler);
258   XSync (dpy, False);
259
260   if (kids)
261     XFree ((char *) kids);
262 }
263
264
265 void
266 grab_screen_image (Screen *screen, Window window)
267 {
268   Display *dpy = DisplayOfScreen (screen);
269   XWindowAttributes xgwa;
270   Window real_root = XRootWindowOfScreen (screen);  /* not vroot */
271   Bool root_p = (window == real_root);
272   Bool saver_p = xscreensaver_window_p (dpy, window);
273   Bool grab_mouse_p = False;
274   int unmap_time = 0;
275
276   if (saver_p)
277     /* I think this is redundant, but just to be safe... */
278     root_p = False;
279
280   if (saver_p)
281     /* The only time grabbing the mouse is important is if this program
282        is being run while the saver is locking the screen. */
283     grab_mouse_p = True;
284
285   if (!root_p)
286     {
287       double unmap = 0;
288       if (saver_p)
289         {
290           unmap = get_float_resource("grabRootDelay", "Seconds");
291           if (unmap <= 0.00001 || unmap > 20) unmap = 2.5;
292         }
293       else
294         {
295           unmap = get_float_resource("grabWindowDelay", "Seconds");
296           if (unmap <= 0.00001 || unmap > 20) unmap = 0.66;
297         }
298       unmap_time = unmap * 100000;
299     }
300
301   if (grab_verbose_p)
302     {
303       XWindowAttributes xgwa2;
304       fprintf(stderr,
305               "\n%s: window 0x%08lX root: %d saver: %d grab: %d wait: %.1f\n",
306               progname, (unsigned long) window,
307               root_p, saver_p, grab_mouse_p, ((double)unmap_time)/1000000.0);
308
309       XGetWindowAttributes (dpy, window, &xgwa2);
310       fprintf(stderr, "%s: ", progname);
311       describe_visual(stderr, screen, xgwa2.visual, False);
312       fprintf (stderr, "\n");
313     }
314
315
316   if (!root_p && !top_level_window_p (screen, window))
317     {
318       if (grab_verbose_p)
319         fprintf (stderr, "%s: not a top-level window: 0x%08lX: not grabbing\n",
320                  progname, (unsigned long) window);
321       return;
322     }
323
324
325   if (!root_p)
326     XSetWindowBackgroundPixmap (dpy, window, None);
327
328   if (grab_mouse_p)
329     {
330       /* prevent random viewer of the screen saver (locker) from messing
331          with windows.   We don't check whether it succeeded, because what
332          are our options, really... */
333       XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
334                     GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
335       XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
336                      CurrentTime);
337     }
338
339   if (unmap_time > 0)
340     {
341       XUnmapWindow (dpy, window);
342       install_screen_colormaps (screen);
343       XSync (dpy, True);
344       usleep(unmap_time); /* wait for everyone to swap in and handle exposes */
345     }
346
347   XGetWindowAttributes (dpy, window, &xgwa);
348
349   if (!root_p)
350     {
351 #ifdef HAVE_READ_DISPLAY_EXTENSION
352       if (! read_display(screen, window, 0, saver_p))
353 #endif /* HAVE_READ_DISPLAY_EXTENSION */
354         {
355 #ifdef HAVE_READ_DISPLAY_EXTENSION
356           if (grab_verbose_p)
357             fprintf(stderr, "%s: read_display() failed\n", progname);
358 #endif /* HAVE_READ_DISPLAY_EXTENSION */
359
360           copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
361           raise_window(dpy, window, saver_p);
362
363           /* Generally it's bad news to call XInstallColormap() explicitly,
364              but this file does a lot of sleazy stuff already...  This is to
365              make sure that the window's colormap is installed, even in the
366              case where the window is OverrideRedirect. */
367           if (xgwa.colormap) XInstallColormap (dpy, xgwa.colormap);
368           XSync (dpy, False);
369         }
370     }
371   else  /* root_p */
372     {
373       Pixmap pixmap;
374       XWindowAttributes xgwa;
375       XGetWindowAttributes(dpy, window, &xgwa);
376       pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
377
378 #ifdef HAVE_READ_DISPLAY_EXTENSION
379       if (! read_display(screen, window, pixmap, True))
380 #endif
381         {
382           Window real_root = XRootWindowOfScreen (xgwa.screen); /* not vroot */
383           XGCValues gcv;
384           GC gc;
385
386 #ifdef HAVE_READ_DISPLAY_EXTENSION
387           if  (grab_verbose_p)
388             fprintf(stderr, "%s: read_display() failed\n", progname);
389 #endif /* HAVE_READ_DISPLAY_EXTENSION */
390
391           copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
392
393           gcv.function = GXcopy;
394           gcv.subwindow_mode = IncludeInferiors;
395           gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
396           XCopyArea (dpy, real_root, pixmap, gc,
397                      xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
398           XFreeGC (dpy, gc);
399         }
400       XSetWindowBackgroundPixmap (dpy, window, pixmap);
401       XFreePixmap (dpy, pixmap);
402     }
403
404   if (grab_verbose_p)
405     fprintf (stderr, "%s: grabbed %d bit screen image to %swindow.\n",
406              progname, xgwa.depth,
407              (root_p ? "real root " : ""));
408
409   if (grab_mouse_p)
410     {
411       XUngrabPointer (dpy, CurrentTime);
412       XUngrabKeyboard (dpy, CurrentTime);
413     }
414
415   XSync (dpy, True);
416 }
417
418
419 /* When we are grabbing and manipulating a screen image, it's important that
420    we use the same colormap it originally had.  So, if the screensaver was
421    started with -install, we need to copy the contents of the default colormap
422    into the screensaver's colormap.
423  */
424 static void
425 copy_default_colormap_contents (Screen *screen,
426                                 Colormap to_cmap,
427                                 Visual *to_visual)
428 {
429   Display *dpy = DisplayOfScreen (screen);
430   Visual *from_visual = DefaultVisualOfScreen (screen);
431   Colormap from_cmap = XDefaultColormapOfScreen (screen);
432
433   XColor *old_colors, *new_colors;
434   unsigned long *pixels;
435   XVisualInfo vi_in, *vi_out;
436   int out_count;
437   int from_cells, to_cells, max_cells, got_cells;
438   int i;
439
440   if (from_cmap == to_cmap)
441     return;
442
443   vi_in.screen = XScreenNumberOfScreen (screen);
444   vi_in.visualid = XVisualIDFromVisual (from_visual);
445   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
446                            &vi_in, &out_count);
447   if (! vi_out) abort ();
448   from_cells = vi_out [0].colormap_size;
449   XFree ((char *) vi_out);
450
451   vi_in.screen = XScreenNumberOfScreen (screen);
452   vi_in.visualid = XVisualIDFromVisual (to_visual);
453   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
454                            &vi_in, &out_count);
455   if (! vi_out) abort ();
456   to_cells = vi_out [0].colormap_size;
457   XFree ((char *) vi_out);
458
459   max_cells = (from_cells > to_cells ? to_cells : from_cells);
460
461   old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
462   new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
463   pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
464   for (i = 0; i < max_cells; i++)
465     old_colors[i].pixel = i;
466   XQueryColors (dpy, from_cmap, old_colors, max_cells);
467
468   got_cells = max_cells;
469   allocate_writable_colors (dpy, to_cmap, pixels, &got_cells);
470
471   if (grab_verbose_p && got_cells != max_cells)
472     fprintf(stderr, "%s: got only %d of %d cells\n", progname,
473             got_cells, max_cells);
474
475   if (got_cells <= 0)                                    /* we're screwed */
476     ;
477   else if (got_cells == max_cells &&                     /* we're golden */
478            from_cells == to_cells)
479     XStoreColors (dpy, to_cmap, old_colors, got_cells);
480   else                                                   /* try to cope... */
481     {
482       for (i = 0; i < got_cells; i++)
483         {
484           XColor *c = old_colors + i;
485           int j;
486           for (j = 0; j < got_cells; j++)
487             if (pixels[j] == c->pixel)
488               {
489                 /* only store this color value if this is one of the pixels
490                    we were able to allocate. */
491                 XStoreColors (dpy, to_cmap, c, 1);
492                 break;
493               }
494         }
495     }
496
497
498   if (grab_verbose_p)
499     fprintf(stderr, "%s: installing copy of default colormap\n", progname);
500
501   free (old_colors);
502   free (new_colors);
503   free (pixels);
504 }
505
506
507 \f
508 /* The SGI ReadDisplay extension.
509    This extension lets you get back a 24-bit image of the screen, taking into
510    account the colors with which all windows are *currently* displayed, even
511    if those windows have different visuals.  Without this extension, presence
512    of windows with different visuals or colormaps will result in technicolor
513    when one tries to grab the screen image.
514  */
515
516 #ifdef HAVE_READ_DISPLAY_EXTENSION
517
518 static Bool
519 read_display (Screen *screen, Window window, Pixmap into_pixmap,
520               Bool dont_wait)
521 {
522   Display *dpy = DisplayOfScreen (screen);
523   XWindowAttributes xgwa;
524   int rd_event_base = 0;
525   int rd_error_base = 0;
526   unsigned long hints = 0;
527   XImage *image = 0;
528   XGCValues gcv;
529   int class;
530   GC gc;
531   Bool remap_p = False;
532
533   /* Check to see if the server supports the extension, and bug out if not.
534    */
535   if (! XReadDisplayQueryExtension (dpy, &rd_event_base, &rd_error_base))
536     {
537       if (grab_verbose_p)
538         fprintf(stderr, "%s: no XReadDisplay extension\n", progname);
539       return False;
540     }
541
542   /* If this isn't a visual we know how to handle, bug out.  We handle:
543       = TrueColor in depths 8, 12, 15, 16, and 32;
544       = PseudoColor and DirectColor in depths 8 and 12.
545    */
546   XGetWindowAttributes(dpy, window, &xgwa);
547   class = visual_class (screen, xgwa.visual);
548   if (class == TrueColor)
549     {
550       if (xgwa.depth != 8  && xgwa.depth != 12 && xgwa.depth != 15 &&
551           xgwa.depth != 16 && xgwa.depth != 24 && xgwa.depth != 32)
552         {
553           if (grab_verbose_p)
554             fprintf(stderr, "%s: TrueColor depth %d unsupported\n",
555                     progname, xgwa.depth);
556           return False;
557         }
558     }
559   else if (class == PseudoColor || class == DirectColor)
560     {
561       if (xgwa.depth != 8 && xgwa.depth != 12)
562         {
563           if (grab_verbose_p)
564             fprintf(stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
565                     progname, xgwa.depth);
566           return False;
567         }
568       else
569         /* Allocate a TrueColor-like spread of colors for the image. */
570         remap_p = True;
571     }
572
573
574   /* Try and read the screen.
575    */
576   hints = (XRD_TRANSPARENT | XRD_READ_POINTER);
577   image = XReadDisplay (dpy, window, xgwa.x, xgwa.y, xgwa.width, xgwa.height,
578                         hints, &hints);
579   if (!image)
580     {
581       if (grab_verbose_p)
582         fprintf(stderr, "%s: XReadDisplay() failed\n", progname);
583       return False;
584     }
585   if (!image->data)
586     {
587       if (grab_verbose_p)
588         fprintf(stderr, "%s: XReadDisplay() returned no data\n", progname);
589       XDestroyImage(image);
590       return False;
591     }
592
593   /* XReadDisplay tends to LIE about the depth of the image it read.
594      It is returning an XImage which has `depth' and `bits_per_pixel'
595      confused!
596
597      That is, on a 24-bit display, where all visuals claim depth 24, and
598      where XGetImage would return an XImage with depth 24, and where
599      XPutImage will get a BadMatch with images that are not depth 24,
600      XReadDisplay is returning images with depth 32!  Fuckwits!
601
602      So if the visual is of depth 24, but the image came back as depth 32,
603      hack it to be 24 lest we get a BadMatch from XPutImage.
604
605      I wonder what happens on an 8-bit SGI...  Probably it still returns
606      an image claiming depth 32?  Certainly it can't be 8.  So, let's just
607      smash it to 32...
608    */
609   if (image->depth == 32 /* && xgwa.depth == 24 */ )
610     image->depth = 24;
611
612   /* If the visual of the window/pixmap into which we're going to draw is
613      less deep than the screen itself, then we need to convert the grabbed bits
614      to match the depth by clipping off the less significant bit-planes of each
615      color component.
616    */
617   if (image->depth > xgwa.depth)
618     {
619       int x, y;
620       /* We use the same image->data in both images -- that's ok, because
621          since we're reading from B and writing to A, and B uses more bytes
622          per pixel than A, the write pointer won't overrun the read pointer.
623        */
624       XImage *image2 = XCreateImage (dpy, xgwa.visual, xgwa.depth,
625                                      ZPixmap, 0, image->data,
626                                      xgwa.width, xgwa.height,
627                                      8, 0);
628       if (!image2)
629         {
630           if (grab_verbose_p)
631             fprintf(stderr, "%s: out of memory?\n", progname);
632           return False;
633         }
634
635       if (grab_verbose_p)
636         fprintf(stderr, "%s: converting from depth %d to depth %d\n",
637                 progname, image->depth, xgwa.depth);
638
639       for (y = 0; y < image->height; y++)
640         for (x = 0; x < image->width; x++)
641           {
642             /* #### really these shift values should be determined from the
643                mask values -- but that's a pain in the ass, and anyway,
644                this is an SGI-specific extension so hardcoding assumptions
645                about the SGI server's behavior isn't *too* heinous... */
646             unsigned long pixel = XGetPixel(image, x, y);
647             unsigned int r = (pixel & image->red_mask);
648             unsigned int g = (pixel & image->green_mask) >> 8;
649             unsigned int b = (pixel & image->blue_mask) >> 16;
650
651             if (xgwa.depth == 8)
652               pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
653             else if (xgwa.depth == 12)
654               pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
655             else if (xgwa.depth == 16 || xgwa.depth == 15)
656               /* Gah! I don't understand why these are in the other order. */
657               pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
658             else
659               abort();
660
661             XPutPixel(image2, x, y, pixel);
662           }
663       image->data = 0;
664       XDestroyImage(image);
665       image = image2;
666     }
667
668   if (remap_p)
669     {
670       allocate_cubic_colormap (screen, window, xgwa.visual);
671       remap_image (screen, window, xgwa.colormap, image);
672     }
673
674   /* Now actually put the bits into the window or pixmap -- note the design
675      bogosity of this extension, where we've been forced to take 24 bit data
676      from the server to the client, and then push it back from the client to
677      the server, *without alteration*.  We should have just been able to tell
678      the server, "put a screen image in this drawable", instead of having to
679      go through the intermediate step of converting it to an Image.  Geez.
680      (Assuming that the window is of screen depth; we happen to handle less
681      deep windows, but that's beside the point.)
682    */
683   gcv.function = GXcopy;
684   gc = XCreateGC (dpy, window, GCFunction, &gcv);
685
686   if (into_pixmap)
687     {
688       gcv.function = GXcopy;
689       gc = XCreateGC (dpy, into_pixmap, GCFunction, &gcv);
690       XPutImage (dpy, into_pixmap, gc, image, 0, 0, 0, 0,
691                  xgwa.width, xgwa.height);
692     }
693   else
694     {
695       gcv.function = GXcopy;
696       gc = XCreateGC (dpy, window, GCFunction, &gcv);
697
698       /* Ok, now we'll be needing that window on the screen... */
699       raise_window(dpy, window, dont_wait);
700
701       /* Plop down the bits... */
702       XPutImage (dpy, window, gc, image, 0, 0, 0, 0, xgwa.width, xgwa.height);
703     }
704   XFreeGC (dpy, gc);
705
706   if (image->data)
707     {
708       free(image->data);
709       image->data = 0;
710     }
711   XDestroyImage(image);
712
713   return True;
714 }
715 #endif /* HAVE_READ_DISPLAY_EXTENSION */
716
717
718 #ifdef HAVE_READ_DISPLAY_EXTENSION
719
720 /* Makes and installs a colormap that makes a PseudoColor or DirectColor
721    visual behave like a TrueColor visual of the same depth.
722  */
723 static void
724 allocate_cubic_colormap (Screen *screen, Window window, Visual *visual)
725 {
726   Display *dpy = DisplayOfScreen (screen);
727   XWindowAttributes xgwa;
728   Colormap cmap;
729   int nr, ng, nb, cells;
730   int r, g, b;
731   int depth;
732   XColor colors[4097];
733   int i;
734
735   XGetWindowAttributes (dpy, window, &xgwa);
736   cmap = xgwa.colormap;
737   depth = visual_depth(screen, visual);
738
739   switch (depth)
740     {
741     case 8:  nr = 3; ng = 3; nb = 2; cells = 256;  break;
742     case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
743     default: abort(); break;
744     }
745
746   memset(colors, 0, sizeof(colors));
747   for (r = 0; r < (1 << nr); r++)
748     for (g = 0; g < (1 << ng); g++)
749       for (b = 0; b < (1 << nb); b++)
750         {
751           i = (r | (g << nr) | (b << (nr + ng)));
752           colors[i].pixel = i;
753           colors[i].flags = DoRed|DoGreen|DoBlue;
754           if (depth == 8)
755             {
756               colors[i].red   = ((r << 13) | (r << 10) | (r << 7) |
757                                  (r <<  4) | (r <<  1));
758               colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
759                                  (g <<  4) | (g <<  1));
760               colors[i].blue  = ((b << 14) | (b << 12) | (b << 10) |
761                                  (b <<  8) | (b <<  6) | (b <<  4) |
762                                  (b <<  2) | b);
763             }
764           else
765             {
766               colors[i].red   = (r << 12) | (r << 8) | (r << 4) | r;
767               colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
768               colors[i].blue  = (b << 12) | (b << 8) | (b << 4) | b;
769             }
770         }
771
772   {
773     int j;
774     int allocated = 0;
775     int interleave = cells / 8;  /* skip around, rather than allocating in
776                                     order, so that we get better coverage if
777                                     we can't allocated all of them. */
778     for (j = 0; j < interleave; j++)
779       for (i = 0; i < cells; i += interleave)
780         if (XAllocColor (dpy, cmap, &colors[i + j]))
781           allocated++;
782
783     if (grab_verbose_p)
784       fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
785                progname, allocated, cells);
786   }
787 }
788
789 static unsigned long
790 find_closest_pixel (XColor *colors, int ncolors,
791                     unsigned long r, unsigned long g, unsigned long b)
792 {
793   unsigned long distance = ~0;
794   int i, found = 0;
795
796   if (ncolors == 0)
797     abort();
798   for (i = 0; i < ncolors; i++)
799     {
800       unsigned long d;
801       int rd, gd, bd;
802
803       rd = r - colors[i].red;
804       gd = g - colors[i].green;
805       bd = b - colors[i].blue;
806       if (rd < 0) rd = -rd;
807       if (gd < 0) gd = -gd;
808       if (bd < 0) bd = -bd;
809       d = (rd << 1) + (gd << 2) + bd;
810       
811       if (d < distance)
812         {
813           distance = d;
814           found = i;
815           if (distance == 0)
816               break;
817         }
818     }
819
820   return found;
821 }
822
823
824 void
825 remap_image (Screen *screen, Window window, Colormap cmap, XImage *image)
826 {
827   Display *dpy = DisplayOfScreen (screen);
828   unsigned long map[4097];
829   int x, y, i;
830   int cells;
831   XColor colors[4097];
832
833   if (image->depth == 8)
834     cells = 256;
835   else if (image->depth == 12)
836     cells = 4096;
837   else
838     abort();
839
840   memset(map,    -1, sizeof(*map));
841   memset(colors, -1, sizeof(*colors));
842
843   for (i = 0; i < cells; i++)
844     colors[i].pixel = i;
845   XQueryColors (dpy, cmap, colors, cells);
846
847   if (grab_verbose_p)
848     fprintf(stderr, "%s: building table for %d bit image\n",
849             progname, image->depth);
850
851   for (i = 0; i < cells; i++)
852     {
853       unsigned short r, g, b;
854
855       if (cells == 256)
856         {
857           /* "RRR GGG BB" In an 8 bit map.  Convert that to
858              "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
859              an even spread. */
860           r = (i & 0x07);
861           g = (i & 0x38) >> 3;
862           b = (i & 0xC0) >> 6;
863
864           r = ((r << 13) | (r << 10) | (r << 7) | (r <<  4) | (r <<  1));
865           g = ((g << 13) | (g << 10) | (g << 7) | (g <<  4) | (g <<  1));
866           b = ((b << 14) | (b << 12) | (b << 10) | (b <<  8) |
867                (b <<  6) | (b <<  4) | (b <<  2) | b);
868         }
869       else
870         {
871           /* "RRRR GGGG BBBB" In a 12 bit map.  Convert that to
872              "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
873              spread. */
874           r = (i & 0x00F);
875           g = (i & 0x0F0) >> 4;
876           b = (i & 0xF00) >> 8;
877
878           r = (r << 12) | (r << 8) | (r << 4) | r;
879           g = (g << 12) | (g << 8) | (g << 4) | g;
880           b = (b << 12) | (b << 8) | (b << 4) | b;
881         }
882
883       map[i] = find_closest_pixel (colors, cells, r, g, b);
884     }
885
886   if (grab_verbose_p)
887     fprintf(stderr, "%s: remapping colors in %d bit image\n",
888             progname, image->depth);
889
890   for (y = 0; y < image->height; y++)
891     for (x = 0; x < image->width; x++)
892       {
893         unsigned long pixel = XGetPixel(image, x, y);
894         if (pixel >= cells) abort();
895         XPutPixel(image, x, y, map[pixel]);
896       }
897 }
898
899
900 #endif /* HAVE_READ_DISPLAY_EXTENSION */