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