78c21163fe7877b757b603ceee9a0798f3e2b9d9
[xscreensaver] / utils / grabscreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998
2  *  Jamie Zawinski <jwz@netscape.com>
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 "sgivideo.h"
38 #include "visual.h"
39 #include "resources.h"
40
41 #include "vroot.h"
42 #undef RootWindowOfScreen
43 #undef RootWindow
44 #undef DefaultRootWindow
45
46
47 #ifdef HAVE_READ_DISPLAY_EXTENSION
48 # include <X11/extensions/readdisplay.h>
49   static Bool read_display (Screen *, Window, Pixmap, Bool);
50 #endif /* HAVE_READ_DISPLAY_EXTENSION */
51
52
53 static void copy_default_colormap_contents (Screen *, Colormap, Visual *);
54
55 #if defined(HAVE_READ_DISPLAY_EXTENSION) || defined(HAVE_SGI_VIDEO)
56 static void make_cubic_colormap (Screen *, Window, Visual *);
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 #ifdef DEBUG
68 extern char *progname;
69 #endif /* DEBUG */
70
71
72 static void
73 raise_window(Display *dpy, Window window, Bool dont_wait)
74 {
75 #ifdef DEBUG
76   fprintf(stderr, "%s: raising window 0x%08lX (%s)\n",
77           progname, (unsigned long) window,
78           (dont_wait ? "not waiting" : "waiting"));
79 #endif /* DEBUG */
80
81   if (! dont_wait)
82     {
83       XWindowAttributes xgwa;
84       XSizeHints hints;
85       long supplied = 0;
86       memset(&hints, 0, sizeof(hints));
87       XGetWMNormalHints(dpy, window, &hints, &supplied);
88       XGetWindowAttributes (dpy, window, &xgwa);
89       hints.x = xgwa.x;
90       hints.y = xgwa.y;
91       hints.width = xgwa.width;
92       hints.height = xgwa.height;
93       hints.flags |= (PPosition|USPosition|PSize|USSize);
94       XSetWMNormalHints(dpy, window, &hints);
95     }
96
97   XMapRaised(dpy, window);
98
99   if (! dont_wait)
100     {
101       XEvent event;
102       XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
103       XSync (dpy, True);
104     }
105 }
106
107
108 static Bool
109 xscreensaver_window_p (Display *dpy, Window window)
110 {
111   Atom type;
112   int format;
113   unsigned long nitems, bytesafter;
114   char *version;
115   if (XGetWindowProperty (dpy, window,
116                           XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
117                           0, 1, False, XA_STRING,
118                           &type, &format, &nitems, &bytesafter,
119                           (unsigned char **) &version)
120       == Success
121       && type != None)
122     return True;
123   return False;
124 }
125
126
127
128 static XErrorHandler old_ehandler = 0;
129 static int
130 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
131 {
132   if (error->error_code == BadWindow || error->error_code == BadDrawable)
133     return 0;
134   else if (!old_ehandler)
135     abort();
136   else
137     return (*old_ehandler) (dpy, error);
138 }
139
140
141 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
142    on a window whose depth is not the maximal depth of the screen?  Or
143    something.  Anyway, things don't work unless we: use SubwindowMode for
144    the real root window (or a legitimate virtual root window); but do not
145    use SubwindowMode for the xscreensaver window.  I make no attempt to
146    explain.
147  */
148 Bool
149 use_subwindow_mode_p(Screen *screen, Window window)
150 {
151   if (window != VirtualRootWindowOfScreen(screen))
152     return False;
153   else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
154     return False;
155   else
156     return True;
157 }
158
159
160 /* Install the colormaps of all visible windows, deepest first.
161    This should leave the colormaps of the topmost windows installed
162    (if only N colormaps can be installed at a time, then only the
163    topmost N windows will be shown in the right colors.)
164  */
165 static void
166 install_screen_colormaps (Screen *screen)
167 {
168   int i;
169   Display *dpy = DisplayOfScreen (screen);
170   Window vroot, real_root;
171   Window parent, *kids = 0;
172   unsigned int nkids = 0;
173
174   XSync (dpy, False);
175   old_ehandler = XSetErrorHandler (BadWindow_ehandler);
176
177   vroot = VirtualRootWindowOfScreen (screen);
178   if (XQueryTree (dpy, vroot, &real_root, &parent, &kids, &nkids))
179     for (i = 0; i < nkids; i++)
180       {
181         XWindowAttributes xgwa;
182         Window client;
183 #ifdef HAVE_XMU
184         /* #### need to put XmuClientWindow() in xmu.c, sigh... */
185         if (! (client = XmuClientWindow (dpy, kids[i])))
186 #endif
187           client = kids[i];
188         xgwa.colormap = 0;
189         XGetWindowAttributes (dpy, client, &xgwa);
190         if (xgwa.colormap && xgwa.map_state == IsViewable)
191           XInstallColormap (dpy, xgwa.colormap);
192       }
193   XInstallColormap (dpy, DefaultColormapOfScreen (screen));
194   XSync (dpy, False);
195   XSetErrorHandler (old_ehandler);
196   XSync (dpy, False);
197
198   if (kids)
199     XFree ((char *) kids);
200 }
201
202
203 static void
204 grab_screen_image_1 (Screen *screen, Window window)
205 {
206   Display *dpy = DisplayOfScreen (screen);
207   XWindowAttributes xgwa;
208   Window real_root = XRootWindowOfScreen (screen);  /* not vroot */
209   Bool root_p = (window == real_root);
210   Bool saver_p = xscreensaver_window_p (dpy, window);
211   Bool grab_mouse_p = False;
212   int unmap_time = 0;
213
214   if (saver_p)
215     /* I think this is redundant, but just to be safe... */
216     root_p = False;
217
218   if (saver_p)
219     /* The only time grabbing the mouse is important is if this program
220        is being run while the saver is locking the screen. */
221     grab_mouse_p = True;
222
223   if (!root_p)
224     {
225       double unmap = 0;
226       if (saver_p)
227         {
228           unmap = get_float_resource("grabRootDelay", "Seconds");
229           if (unmap <= 0.00001 || unmap > 20) unmap = 2.5;
230         }
231       else
232         {
233           unmap = get_float_resource("grabWindowDelay", "Seconds");
234           if (unmap <= 0.00001 || unmap > 20) unmap = 0.66;
235         }
236       unmap_time = unmap * 100000;
237     }
238
239 #ifdef DEBUG
240   fprintf(stderr,
241           "\n%s: window 0x%08lX root: %d saver: %d grab: %d wait: %.1f\n",
242           progname, (unsigned long) window,
243           root_p, saver_p, grab_mouse_p, ((double)unmap_time)/1000000.0);
244   {
245     XWindowAttributes xgwa2;
246     XGetWindowAttributes (dpy, window, &xgwa2);
247     fprintf(stderr, "%s: ", progname);
248     describe_visual(stderr, screen, xgwa2.visual);
249   }
250 #endif /* DEBUG */
251
252   if (!root_p)
253     XSetWindowBackgroundPixmap (dpy, window, None);
254
255   if (grab_mouse_p)
256     {
257       /* prevent random viewer of the screen saver (locker) from messing
258          with windows.   We don't check whether it succeeded, because what
259          are our options, really... */
260       XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
261                     GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
262       XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
263                      CurrentTime);
264     }
265
266   if (unmap_time > 0)
267     {
268       XUnmapWindow (dpy, window);
269       install_screen_colormaps (screen);
270       XSync (dpy, True);
271       usleep(unmap_time); /* wait for everyone to swap in and handle exposes */
272     }
273
274   XGetWindowAttributes (dpy, window, &xgwa);
275
276   if (!root_p)
277     {
278 #ifdef HAVE_READ_DISPLAY_EXTENSION
279       if (! read_display(screen, window, 0, saver_p))
280 #endif /* HAVE_READ_DISPLAY_EXTENSION */
281         {
282 #if defined(HAVE_READ_DISPLAY_EXTENSION) && defined(DEBUG)
283           fprintf(stderr, "%s: read_display() failed\n", progname);
284 #endif /* DEBUG */
285           copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
286           raise_window(dpy, window, saver_p);
287         }
288     }
289   else  /* root_p */
290     {
291       Pixmap pixmap;
292       XWindowAttributes xgwa;
293       XGetWindowAttributes(dpy, window, &xgwa);
294       pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
295
296 #ifdef HAVE_READ_DISPLAY_EXTENSION
297       if (! read_display(screen, window, pixmap, True))
298 #endif
299         {
300           Window real_root = XRootWindowOfScreen (xgwa.screen); /* not vroot */
301           XGCValues gcv;
302           GC gc;
303
304 #if defined(HAVE_READ_DISPLAY_EXTENSION) && defined(DEBUG)
305           fprintf(stderr, "%s: read_display() failed\n", progname);
306 #endif /* DEBUG */
307
308           copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
309
310           gcv.function = GXcopy;
311           gcv.subwindow_mode = IncludeInferiors;
312           gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
313           XCopyArea (dpy, real_root, pixmap, gc,
314                      xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
315           XFreeGC (dpy, gc);
316         }
317       XSetWindowBackgroundPixmap (dpy, window, pixmap);
318       XFreePixmap (dpy, pixmap);
319     }
320
321   if (grab_mouse_p)
322     {
323       XUngrabPointer (dpy, CurrentTime);
324       XUngrabKeyboard (dpy, CurrentTime);
325     }
326
327   XSync (dpy, True);
328 }
329
330 void
331 grab_screen_image (Screen *screen, Window window)
332 {
333 #ifdef HAVE_SGI_VIDEO
334   char c, *s = get_string_resource("grabVideoProbability", "Float");
335   double prob = -1;
336   if (!s ||
337       (1 != sscanf (s, " %lf %c", &prob, &c)) ||
338       prob < 0 ||
339       prob > 1)
340     prob = 0.5;
341
342   if ((random() % 100) < ((int) (100 * prob)))
343     {
344       XWindowAttributes xgwa;
345       Display *dpy = DisplayOfScreen (screen);
346       XGetWindowAttributes (dpy, window, &xgwa);
347 # ifdef DEBUG
348       fprintf(stderr, "%s: trying to grab from video...\n", progname);
349 # endif /* DEBUG */
350       if (grab_video_frame (screen, xgwa.visual, window))
351         {
352           if (xgwa.depth < 24)
353             {
354               int class = visual_class (screen, xgwa.visual);
355               if (class == PseudoColor || class == DirectColor)
356                 make_cubic_colormap (screen, window, xgwa.visual);
357             }
358           return;
359         }
360     }
361 #endif /* HAVE_SGI_VIDEO */
362
363   grab_screen_image_1 (screen, window);
364 }
365
366
367 /* When we are grabbing and manipulating a screen image, it's important that
368    we use the same colormap it originally had.  So, if the screensaver was
369    started with -install, we need to copy the contents of the default colormap
370    into the screensaver's colormap.
371  */
372 static void
373 copy_default_colormap_contents (Screen *screen,
374                                 Colormap to_cmap,
375                                 Visual *to_visual)
376 {
377   Display *dpy = DisplayOfScreen (screen);
378   Visual *from_visual = DefaultVisualOfScreen (screen);
379   Colormap from_cmap = XDefaultColormapOfScreen (screen);
380
381   XColor *old_colors, *new_colors;
382   unsigned long *pixels;
383   XVisualInfo vi_in, *vi_out;
384   int out_count;
385   int from_cells, to_cells, max_cells, got_cells;
386   int i;
387
388   if (from_cmap == to_cmap)
389     return;
390
391   vi_in.screen = XScreenNumberOfScreen (screen);
392   vi_in.visualid = XVisualIDFromVisual (from_visual);
393   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
394                            &vi_in, &out_count);
395   if (! vi_out) abort ();
396   from_cells = vi_out [0].colormap_size;
397   XFree ((char *) vi_out);
398
399   vi_in.screen = XScreenNumberOfScreen (screen);
400   vi_in.visualid = XVisualIDFromVisual (to_visual);
401   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
402                            &vi_in, &out_count);
403   if (! vi_out) abort ();
404   to_cells = vi_out [0].colormap_size;
405   XFree ((char *) vi_out);
406
407   max_cells = (from_cells > to_cells ? to_cells : from_cells);
408
409   old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
410   new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
411   pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
412   for (i = 0; i < max_cells; i++)
413     old_colors[i].pixel = i;
414   XQueryColors (dpy, from_cmap, old_colors, max_cells);
415
416   got_cells = max_cells;
417   allocate_writable_colors (dpy, to_cmap, pixels, &got_cells);
418
419 #ifdef DEBUG
420   if (got_cells != max_cells)
421     fprintf(stderr, "%s: got only %d of %d cells\n", progname,
422             got_cells, max_cells);
423 #endif /* DEBUG */
424
425   if (got_cells <= 0)                                    /* we're screwed */
426     ;
427   else if (got_cells == max_cells &&                     /* we're golden */
428            from_cells == to_cells)
429     XStoreColors (dpy, to_cmap, old_colors, got_cells);
430   else                                                   /* try to cope... */
431     {
432       for (i = 0; i < got_cells; i++)
433         {
434           XColor *c = old_colors + i;
435           int j;
436           for (j = 0; j < got_cells; j++)
437             if (pixels[j] == c->pixel)
438               {
439                 /* only store this color value if this is one of the pixels
440                    we were able to allocate. */
441                 XStoreColors (dpy, to_cmap, c, 1);
442                 break;
443               }
444         }
445     }
446
447
448 #ifdef DEBUG
449   fprintf(stderr, "%s: installing copy of default colormap\n", progname);
450 #endif /* DEBUG */
451
452   free (old_colors);
453   free (new_colors);
454   free (pixels);
455 }
456
457
458 \f
459 /* The SGI ReadDisplay extension.
460    This extension lets you get back a 24-bit image of the screen, taking into
461    account the colors with which all windows are *currently* displayed, even
462    if those windows have different visuals.  Without this extension, presence
463    of windows with different visuals or colormaps will result in technicolor
464    when one tries to grab the screen image.
465  */
466
467 #ifdef HAVE_READ_DISPLAY_EXTENSION
468
469 static Bool
470 read_display (Screen *screen, Window window, Pixmap into_pixmap,
471               Bool dont_wait)
472 {
473   Display *dpy = DisplayOfScreen (screen);
474   XWindowAttributes xgwa;
475   int rd_event_base = 0;
476   int rd_error_base = 0;
477   unsigned long hints = 0;
478   XImage *image = 0;
479   XGCValues gcv;
480   int class;
481   GC gc;
482   Bool install_p = False;
483
484   /* Check to see if the server supports the extension, and bug out if not.
485    */
486   if (! XReadDisplayQueryExtension (dpy, &rd_event_base, &rd_error_base))
487     return False;
488
489   /* If this isn't a visual we know how to handle, bug out.  We handle:
490       = TrueColor in depths 8, 12, 16, and 32;
491       = PseudoColor and DirectColor in depths 8 and 12.
492    */
493   XGetWindowAttributes(dpy, window, &xgwa);
494   class = visual_class (screen, xgwa.visual);
495   if (class == TrueColor)
496     {
497       if (xgwa.depth != 8  && xgwa.depth != 12 && xgwa.depth != 16 &&
498           xgwa.depth != 24 && xgwa.depth != 32)
499         return False;
500     }
501   else if (class == PseudoColor || class == DirectColor)
502     {
503       if (xgwa.depth != 8 && xgwa.depth != 12)
504         return False;
505       else
506         /* Install a colormap that makes this visual behave like
507            a TrueColor visual of the same depth. */
508         install_p = True;
509     }
510
511
512   /* Try and read the screen.
513    */
514   hints = (XRD_TRANSPARENT | XRD_READ_POINTER);
515   image = XReadDisplay (dpy, window, xgwa.x, xgwa.y, xgwa.width, xgwa.height,
516                         hints, &hints);
517   if (!image)
518     return False;
519   if (!image->data)
520     {
521       XDestroyImage(image);
522       return False;
523     }
524
525   /* XReadDisplay tends to LIE about the depth of the image it read.
526      It is returning an XImage which has `depth' and `bits_per_pixel'
527      confused!
528
529      That is, on a 24-bit display, where all visuals claim depth 24, and
530      where XGetImage would return an XImage with depth 24, and where
531      XPutImage will get a BadMatch with images that are not depth 24,
532      XReadDisplay is returning images with depth 32!  Fuckwits!
533
534      So if the visual is of depth 24, but the image came back as depth 32,
535      hack it to be 24 lest we get a BadMatch from XPutImage.
536
537      I wonder what happens on an 8-bit SGI...  Probably it still returns
538      an image claiming depth 32?  Certainly it can't be 8.  So, let's just
539      smash it to 32...
540    */
541   if (image->depth == 32 /* && xgwa.depth == 24 */ )
542     image->depth = 24;
543
544   /* If the visual of the window/pixmap into which we're going to draw is
545      less deep than the screen itself, then we need to convert the grabbed bits
546      to match the depth by clipping off the less significant bit-planes of each
547      color component.
548    */
549   if (image->depth > xgwa.depth)
550     {
551       int x, y;
552       /* We use the same image->data in both images -- that's ok, because
553          since we're reading from B and writing to A, and B uses more bytes
554          per pixel than A, the write pointer won't overrun the read pointer.
555        */
556       XImage *image2 = XCreateImage (dpy, xgwa.visual, xgwa.depth,
557                                      ZPixmap, 0, image->data,
558                                      xgwa.width, xgwa.height,
559                                      8, 0);
560       if (!image2)
561         return False;
562
563 #ifdef DEBUG
564       fprintf(stderr, "%s: converting from depth %d to depth %d\n",
565               progname, image->depth, xgwa.depth);
566 #endif /* DEBUG */
567
568       for (y = 0; y < image->height; y++)
569         for (x = 0; x < image->width; x++)
570           {
571             /* #### really these shift values should be determined from the
572                mask values -- but that's a pain in the ass, and anyway,
573                this is an SGI-specific extension so hardcoding assumptions
574                about the SGI server's behavior isn't *too* heinous... */
575             unsigned long pixel = XGetPixel(image, x, y);
576             unsigned int r = (pixel & image->red_mask);
577             unsigned int g = (pixel & image->green_mask) >> 8;
578             unsigned int b = (pixel & image->blue_mask) >> 16;
579
580             if (xgwa.depth == 8)
581               pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
582             else if (xgwa.depth == 12)
583               pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
584             else if (xgwa.depth == 16)
585               pixel = ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10));
586             else
587               abort();
588
589             XPutPixel(image2, x, y, pixel);
590           }
591       image->data = 0;
592       XDestroyImage(image);
593       image = image2;
594     }
595
596
597   /* Now actually put the bits into the window or pixmap -- note the design
598      bogosity of this extension, where we've been forced to take 24 bit data
599      from the server to the client, and then push it back from the client to
600      the server, *without alteration*.  We should have just been able to tell
601      the server, "put a screen image in this drawable", instead of having to
602      go through the intermediate step of converting it to an Image.  Geez.
603      (Assuming that the window is of screen depth; we happen to handle less
604      deep windows, but that's beside the point.)
605    */
606   gcv.function = GXcopy;
607   gc = XCreateGC (dpy, window, GCFunction, &gcv);
608
609   if (into_pixmap)
610     {
611       gcv.function = GXcopy;
612       gc = XCreateGC (dpy, into_pixmap, GCFunction, &gcv);
613       XPutImage (dpy, into_pixmap, gc, image, 0, 0, 0, 0,
614                  xgwa.width, xgwa.height);
615     }
616   else
617     {
618       gcv.function = GXcopy;
619       gc = XCreateGC (dpy, window, GCFunction, &gcv);
620
621       /* Ok, now we'll be needing that window on the screen... */
622       raise_window(dpy, window, dont_wait);
623
624       /* Plop down the bits... */
625       XPutImage (dpy, window, gc, image, 0, 0, 0, 0, xgwa.width, xgwa.height);
626     }
627   XFreeGC (dpy, gc);
628
629   if (image->data)
630     {
631       free(image->data);
632       image->data = 0;
633     }
634   XDestroyImage(image);
635
636   if (install_p)
637     make_cubic_colormap (screen, window, xgwa.visual);
638
639   return True;
640 }
641 #endif /* HAVE_READ_DISPLAY_EXTENSION */
642
643
644 #if defined(HAVE_READ_DISPLAY_EXTENSION) || defined(HAVE_SGI_VIDEO)
645
646 /* Makes and installs a colormap that makes a PseudoColor or DirectColor
647    visual behave like a TrueColor visual of the same depth.
648  */
649 static void
650 make_cubic_colormap (Screen *screen, Window window, Visual *visual)
651 {
652   Display *dpy = DisplayOfScreen (screen);
653   Colormap cmap = XCreateColormap(dpy, window, visual, AllocAll);
654   int nr, ng, nb, cells;
655   int r, g, b;
656   int depth;
657   XColor colors[4097];
658   int i;
659
660   depth = visual_depth(screen, visual);
661   switch (depth)
662     {
663     case 8:  nr = 3; ng = 3; nb = 2; cells = 256;  break;
664     case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
665     default: abort(); break;
666     }
667
668   memset(colors, 0, sizeof(colors));
669   for (i = 0; i < cells; i++)
670     {
671       colors[i].flags = DoRed|DoGreen|DoBlue;
672       colors[i].red = colors[i].green = colors[i].blue = 0;
673     }
674
675   for (r = 0; r < (1 << nr); r++)
676     for (g = 0; g < (1 << ng); g++)
677       for (b = 0; b < (1 << nb); b++)
678         {
679           i = (r | (g << nr) | (b << (nr + ng)));
680           colors[i].pixel = i;
681           if (depth == 8)
682             {
683               colors[i].red   = ((r << 13) | (r << 10) | (r << 7) |
684                                  (r <<  4) | (r <<  1));
685               colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
686                                  (g <<  4) | (g <<  1));
687               colors[i].blue  = ((b << 14) | (b << 12) | (b << 10) |
688                                  (b <<  8) | (b <<  6) | (b <<  4) |
689                                  (b <<  2) | b);
690             }
691           else
692             {
693               colors[i].red   = (r << 12) | (r << 8) | (r << 4) | r;
694               colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
695               colors[i].blue  = (b << 12) | (b << 8) | (b << 4) | b;
696             }
697         }
698
699 #ifdef DEBUG
700   fprintf(stderr, "%s: installing cubic colormap\n", progname);
701 #endif /* DEBUG */
702
703   XStoreColors (dpy, cmap, colors, cells);
704   XSetWindowColormap (dpy, window, cmap);
705
706   /* Gag, install the colormap.
707      This is definitely right in the `if xscreensaver_window_p' case, since
708      it will never get installed otherwise.  But, if we don't do it
709      unconditionally, then the new colormap won't get installed until the
710      window (re-)gains focus.  It's generally very antisocial to install
711      the colormap of a non-OverrideRedirect window (that task belongs to
712      the WM) and if we were being kosher, we would only install this cmap
713      if the old cmap was already installed (or perhaps, if the window had
714      focus.)  But, since this extension only exists on SGIs, and since SGIs
715      can handle four colormaps at once, let's go ahead and install it all
716      the time, so that even if the window pops up and has never had focus,
717      it will still display in the proper colors.
718    */
719   XInstallColormap (dpy, cmap);
720 }
721
722 #endif /* HAVE_READ_DISPLAY_EXTENSION || HAVE_SGI_VIDEO */