Release 970101
[wine] / objects / color.c
1 /*
2  * Color functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  * Copyright 1996 Alex Korobka
6  */
7
8 #include <stdlib.h>
9 #include <X11/Xlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "windows.h"
13 #include "options.h"
14 #include "gdi.h"
15 #include "color.h"
16 #include "stddebug.h"
17 #include "debug.h"
18 #include "xmalloc.h"
19
20 /* Palette indexed mode:
21
22  *      logical palette -> mapping -> pixel
23  *                                   
24  *
25  * Windows needs contiguous color space ( from 0 to n ) but 
26  * it is possible only with the private colormap. Otherwise we
27  * have to map DC palette indices to real pixel values. With 
28  * private colormaps it boils down to the identity mapping. The
29  * other special case is when we have a fixed color visual with 
30  * the screendepth > 8 - we abandon palette mappings altogether 
31  * because pixel values can be calculated without X server 
32  * assistance.
33  *
34  * For some info about general Windows palette management read
35  * http://198.105.232.5/MSDN/LIBRARY/TECHNOTE/CH3.HTM 
36  */
37
38 typedef struct
39
40     Colormap    colorMap;
41     UINT16      size;
42     UINT16      flags;
43 } CSPACE;
44
45 static CSPACE cSpace = {0, 0, 0};
46
47 static int COLOR_Redshift   = 0; /* to handle abortive COLOR_VIRTUAL visuals */
48 static int COLOR_Redmax     = 0;
49 static int COLOR_Greenshift = 0;
50 static int COLOR_Greenmax   = 0;
51 static int COLOR_Blueshift  = 0;
52 static int COLOR_Bluemax    = 0;
53 static int COLOR_Graymax    = 0;
54
55 /* System color space. 
56  *
57  * First 10 and last 10 colors in COLOR_sysPalette are
58  * "guarded". RealizePalette changes only the rest of colorcells. For
59  * currently inactive window it changes only DC palette mappings.
60  */
61
62 #define NB_RESERVED_COLORS              20 /* number of fixed colors in system palette */
63 #define NB_COLORCUBE_START_INDEX        63
64
65 Visual*                 visual = NULL;
66
67 static PALETTEENTRY* COLOR_sysPal = NULL;    /* current system palette */
68 static int COLOR_gapStart = 256;
69 static int COLOR_gapEnd = -1;
70 static int COLOR_gapFilled = 0;
71 static int COLOR_max = 256;
72
73   /* First free dynamic color cell, 0 = full palette, -1 = fixed palette */
74 static int            COLOR_firstFree = 0; 
75 static unsigned char  COLOR_freeList[256];
76
77   /* Maps entry in the system palette to X pixel value */
78 int* COLOR_PaletteToPixel = NULL;
79
80   /* Maps pixel to the entry in the system palette */
81 int* COLOR_PixelToPalette = NULL;
82
83 static const PALETTEENTRY __sysPalTemplate[NB_RESERVED_COLORS] = 
84 {
85     /* first 10 entries in the system palette */
86     /* red  green blue  flags */
87     { 0x00, 0x00, 0x00, PC_SYS_USED },
88     { 0x80, 0x00, 0x00, PC_SYS_USED },
89     { 0x00, 0x80, 0x00, PC_SYS_USED },
90     { 0x80, 0x80, 0x00, PC_SYS_USED },
91     { 0x00, 0x00, 0x80, PC_SYS_USED },
92     { 0x80, 0x00, 0x80, PC_SYS_USED },
93     { 0x00, 0x80, 0x80, PC_SYS_USED },
94     { 0xc0, 0xc0, 0xc0, PC_SYS_USED },
95     { 0xc0, 0xdc, 0xc0, PC_SYS_USED },
96     { 0xa6, 0xca, 0xf0, PC_SYS_USED },
97
98     /* ... c_min/2 dynamic colorcells */
99
100     /* ... gap (for sparse palettes) */
101
102     /* ... c_min/2 dynamic colorcells */
103
104     { 0xff, 0xfb, 0xf0, PC_SYS_USED },
105     { 0xa0, 0xa0, 0xa4, PC_SYS_USED },
106     { 0x80, 0x80, 0x80, PC_SYS_USED },
107     { 0xff, 0x00, 0x00, PC_SYS_USED },
108     { 0x00, 0xff, 0x00, PC_SYS_USED },
109     { 0xff, 0xff, 0x00, PC_SYS_USED },
110     { 0x00, 0x00, 0xff, PC_SYS_USED },
111     { 0xff, 0x00, 0xff, PC_SYS_USED },
112     { 0x00, 0xff, 0xff, PC_SYS_USED },
113     { 0xff, 0xff, 0xff, PC_SYS_USED }     /* last 10 */
114 };
115
116    /* Map an EGA index (0..15) to a pixel value in the system color space.  */
117
118 int COLOR_mapEGAPixel[16];
119
120 /***********************************************************************
121  *      Misc auxiliary functions
122  */
123 Colormap COLOR_GetColormap(void)
124 {
125     return cSpace.colorMap;
126 }
127
128 UINT16 COLOR_GetSystemPaletteSize(void)
129 {
130     return (cSpace.flags & COLOR_PRIVATE) ? cSpace.size : 256;
131 }
132
133 UINT16 COLOR_GetSystemPaletteFlags(void)
134 {
135     return cSpace.flags;
136 }
137
138 COLORREF COLOR_GetSystemPaletteEntry(BYTE i)
139 {
140  return *(COLORREF*)(COLOR_sysPal + i) & 0x00ffffff;
141 }
142
143 void COLOR_FormatSystemPalette(void)
144 {
145  /* Build free list so we'd have an easy way to find
146   * out if there are any available colorcells. 
147   */
148
149   int i, j = COLOR_firstFree = NB_RESERVED_COLORS/2;
150
151   COLOR_sysPal[j].peFlags = 0;
152   for( i = NB_RESERVED_COLORS/2 + 1 ; i < 256 - NB_RESERVED_COLORS/2 ; i++ )
153     if( i < COLOR_gapStart || i > COLOR_gapEnd )
154       {
155         COLOR_sysPal[i].peFlags = 0;  /* unused tag */
156         COLOR_freeList[j] = i;    /* next */
157         j = i;
158       }
159   COLOR_freeList[j] = 0;
160 }
161
162 BOOL32 COLOR_CheckSysColor(COLORREF c)
163 {
164   int i;
165   for( i = 0; i < NB_RESERVED_COLORS; i++ )
166        if( c == (*(COLORREF*)(__sysPalTemplate + i) & 0x00ffffff) )
167            return 0;
168   return 1;
169 }
170
171 void COLOR_FillDefaultColors(void)
172 {
173  /* initialize unused entries to what Windows uses as a color 
174   * cube - based on Greg Kreider's code. 
175   */
176
177   int i = 0, idx = 0;
178   int red, no_r, inc_r;
179   int green, no_g, inc_g; 
180   int blue, no_b, inc_b;
181
182   while (i*i*i < (cSpace.size - NB_RESERVED_COLORS)) i++;
183   no_r = no_g = no_b = --i;
184   if ((no_r * (no_g+1) * no_b) < (cSpace.size - NB_RESERVED_COLORS)) no_g++;
185   if ((no_r * no_g * (no_b+1)) < (cSpace.size - NB_RESERVED_COLORS)) no_b++;
186   inc_r = (255 - NB_COLORCUBE_START_INDEX)/no_r;
187   inc_g = (255 - NB_COLORCUBE_START_INDEX)/no_g;
188   inc_b = (255 - NB_COLORCUBE_START_INDEX)/no_b;
189
190   idx = COLOR_firstFree;
191
192   if( idx != -1 )
193     for (blue = NB_COLORCUBE_START_INDEX; blue < 256 && idx; blue += inc_b )
194      for (green = NB_COLORCUBE_START_INDEX; green < 256 && idx; green += inc_g )
195       for (red = NB_COLORCUBE_START_INDEX; red < 256 && idx; red += inc_r )
196       {
197          /* weird but true */
198
199          if( red == NB_COLORCUBE_START_INDEX && green == red && blue == green ) continue;
200
201          COLOR_sysPal[idx].peRed = red;
202          COLOR_sysPal[idx].peGreen = green;
203          COLOR_sysPal[idx].peBlue = blue;
204          
205          /* set X color */
206
207          if( cSpace.flags & COLOR_VIRTUAL )
208          {
209             if (COLOR_Redmax != 255) no_r = (red * COLOR_Redmax) / 255;
210             if (COLOR_Greenmax != 255) no_g = (green * COLOR_Greenmax) / 255;
211             if (COLOR_Bluemax != 255) no_b = (blue * COLOR_Bluemax) / 255;
212
213             COLOR_PaletteToPixel[idx] = (no_r << COLOR_Redshift) | (no_g << COLOR_Greenshift) | (no_b << COLOR_Blueshift);
214          }
215          else if( !(cSpace.flags & COLOR_FIXED) )
216          {
217            XColor color = { color.pixel = (COLOR_PaletteToPixel)? COLOR_PaletteToPixel[idx] : idx ,
218                             COLOR_sysPal[idx].peRed << 8,
219                             COLOR_sysPal[idx].peGreen << 8,
220                             COLOR_sysPal[idx].peGreen << 8,
221                             (DoRed | DoGreen | DoBlue) };
222            XStoreColor(display, cSpace.colorMap, &color);
223          }
224
225          idx = COLOR_freeList[idx];
226       }
227
228   /* try to fill some entries in the "gap" with
229    * what's already in the colormap - they will be
230    * mappable to but not changeable. */
231
232   if( COLOR_gapStart < COLOR_gapEnd && COLOR_PixelToPalette )
233   {
234     XColor      xc;
235     int         r, g, b, max;
236
237     max = COLOR_max - (256 - (COLOR_gapEnd - COLOR_gapStart));
238     for ( i = 0, idx = COLOR_gapStart; i < 256 && idx <= COLOR_gapEnd; i++ )
239       if( COLOR_PixelToPalette[i] == 0 )
240         {
241           xc.pixel = i;
242
243           XQueryColor(display, cSpace.colorMap, &xc);
244           r = xc.red>>8; g = xc.green>>8; b = xc.blue>>8;
245
246           if( xc.pixel < 256 && COLOR_CheckSysColor(RGB(r, g, b)) &&
247               XAllocColor(display, cSpace.colorMap, &xc) )
248           {
249              COLOR_PixelToPalette[xc.pixel] = idx;
250              COLOR_PaletteToPixel[idx] = xc.pixel;
251            *(COLORREF*)(COLOR_sysPal + idx) = RGB(r, g, b);
252              COLOR_sysPal[idx++].peFlags |= PC_SYS_USED;
253              if( --max <= 0 ) break;
254           }
255         }
256     COLOR_gapFilled = idx - COLOR_gapStart;    
257   }
258 }
259
260 /***********************************************************************
261  *           COLOR_BuildPrivateMap/COLOR_BuildSharedMap
262  *
263  * Allocate colorcells and initialize mapping tables.
264  */
265 static BOOL COLOR_BuildPrivateMap(CSPACE* cs)
266 {
267     /* Private colormap - identity mapping */
268
269     XColor color;
270     int i; 
271
272     COLOR_sysPal = (PALETTEENTRY*)xmalloc(sizeof(PALETTEENTRY)*cs->size);
273
274     dprintf_palette(stddeb,"\tbuilding private map - %i palette entries\n", cs->size);
275
276       /* Allocate system palette colors */ 
277
278     for( i=0; i < cs->size; i++ )
279     {
280        if( i < NB_RESERVED_COLORS/2 )
281        {
282          color.red   = __sysPalTemplate[i].peRed * 65535 / 255;
283          color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
284          color.blue  = __sysPalTemplate[i].peBlue * 65535 / 255;
285          COLOR_sysPal[i] = __sysPalTemplate[i];
286        }
287        else if( i >= cs->size - NB_RESERVED_COLORS/2 )
288        {
289          int j = NB_RESERVED_COLORS + i - cs->size;
290          color.red   = __sysPalTemplate[j].peRed * 65535 / 255;
291          color.green = __sysPalTemplate[j].peGreen * 65535 / 255;
292          color.blue  = __sysPalTemplate[j].peBlue * 65535 / 255;
293          COLOR_sysPal[i] = __sysPalTemplate[j];
294        }
295
296        color.flags = DoRed | DoGreen | DoBlue;
297        color.pixel = i;
298        XStoreColor(display, cs->colorMap, &color);
299
300        /* Set EGA mapping if color is from the first or last eight */
301
302        if (i < 8)
303            COLOR_mapEGAPixel[i] = color.pixel;
304        else if (i >= cs->size - 8 )
305            COLOR_mapEGAPixel[i - (cs->size - 16)] = color.pixel;
306     }
307
308     COLOR_PixelToPalette = COLOR_PaletteToPixel = NULL;
309
310     COLOR_gapStart = 256; COLOR_gapEnd = -1;
311
312     COLOR_firstFree = (cs->size > NB_RESERVED_COLORS)?NB_RESERVED_COLORS/2 : -1;
313     return FALSE;
314 }
315
316 static BOOL COLOR_BuildSharedMap(CSPACE* cs)
317 {
318    XColor               color;
319    unsigned long        sysPixel[NB_RESERVED_COLORS];
320    unsigned long*       pixDynMapping = NULL;
321    unsigned long        plane_masks[1];
322    int                  i, j, warn = 0;
323    int                  diff, r, g, b, max = 256, bp = 0, wp = 1;
324    int                  step = 1;
325
326    /* read "AllocSystemColors" from wine.conf */
327
328    COLOR_max = PROFILE_GetWineIniInt( "options", "AllocSystemColors", 256);
329    if (COLOR_max > 256) COLOR_max = 256;
330    else if (COLOR_max < 20) COLOR_max = 20;
331    dprintf_palette(stddeb,"COLOR_Init: %d colors configured.\n", COLOR_max);
332    
333    dprintf_palette(stddeb,"\tbuilding shared map - %i palette entries\n", cs->size);
334
335    /* Be nice and allocate system colors as read-only */
336
337    for( i = 0; i < NB_RESERVED_COLORS; i++ )
338      { 
339         color.red   = __sysPalTemplate[i].peRed * 65535 / 255;
340         color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
341         color.blue  = __sysPalTemplate[i].peBlue * 65535 / 255;
342         color.flags = DoRed | DoGreen | DoBlue;
343
344         if (!XAllocColor( display, cSpace.colorMap, &color ))
345         { 
346              XColor     best, c;
347              
348              if( !warn++ ) 
349              {
350                   dprintf_palette(stddeb, "Not enough colors for the full system palette.\n");
351
352                   bp = BlackPixel(display, DefaultScreen(display));
353                   wp = WhitePixel(display, DefaultScreen(display));
354
355                   max = (0xffffffff)>>(32 - screenDepth);
356                   if( max > 256 ) 
357                   {
358                       step = max/256;
359                       max = 256;
360                   }
361              }
362
363              /* reinit color (XAllocColor() may change it)
364               * and map to the best shared colorcell */
365
366              color.red   = __sysPalTemplate[i].peRed * 65535 / 255;
367              color.green = __sysPalTemplate[i].peGreen * 65535 / 255;
368              color.blue  = __sysPalTemplate[i].peBlue * 65535 / 255;
369
370              best.pixel = best.red = best.green = best.blue = 0;
371              for( c.pixel = 0, diff = 0x7fffffff; c.pixel < max; c.pixel += step )
372              {
373                 XQueryColor(display, cSpace.colorMap, &c);
374                 r = (c.red - color.red)>>8; 
375                 g = (c.green - color.green)>>8; 
376                 b = (c.blue - color.blue)>>8;
377                 r = r*r + g*g + b*b;
378                 if( r < diff ) { best = c; diff = r; }
379              }
380
381              if( XAllocColor(display, cSpace.colorMap, &best) )
382                  color.pixel = best.pixel;
383              else color.pixel = (i < NB_RESERVED_COLORS/2)? bp : wp;
384         }
385
386         sysPixel[i] = color.pixel;
387
388         dprintf_palette(stddeb,"\tsyscolor(%lx) -> pixel %i\n",
389                       *(COLORREF*)(__sysPalTemplate+i), (int)color.pixel);
390
391         /* Set EGA mapping if color in the first or last eight */
392
393         if (i < 8)
394             COLOR_mapEGAPixel[i] = color.pixel;
395         else if (i >= NB_RESERVED_COLORS - 8 )
396             COLOR_mapEGAPixel[i - (NB_RESERVED_COLORS-16)] = color.pixel;
397      }
398
399    /* now allocate changeable set */
400
401    if( !(cSpace.flags & COLOR_FIXED) )  
402      {
403         int c_min = 0, c_max = cs->size, c_val;
404
405         dprintf_palette(stddeb,"\tdynamic colormap... ");
406
407         /* comment this out if you want to debug palette init */
408
409         XGrabServer(display);
410
411         /* let's become the first client that actually follows 
412          * X guidelines and does binary search...
413          */
414
415         pixDynMapping = (unsigned long*)xmalloc(sizeof(long)*cs->size);
416         while( c_max - c_min > 0 )
417           {
418              c_val = (c_max + c_min)/2 + (c_max + c_min)%2;
419
420              if( !XAllocColorCells(display, cs->colorMap, False,
421                                    plane_masks, 0, pixDynMapping, c_val) )
422                  c_max = c_val - 1;
423              else
424                {
425                  XFreeColors(display, cs->colorMap, pixDynMapping, c_val, 0);
426                  c_min = c_val;
427                }
428           }
429
430         if( c_min > COLOR_max - NB_RESERVED_COLORS) 
431             c_min = COLOR_max - NB_RESERVED_COLORS;
432
433         c_min = (c_min/2) + (c_min/2);          /* need even set for split palette */
434
435         if( c_min > 0 )
436           if( !XAllocColorCells(display, cs->colorMap, False,
437                                 plane_masks, 0, pixDynMapping, c_min) )
438             {
439               fprintf(stderr,"Inexplicable failure during colorcell allocation.\n");
440               c_min = 0;
441             }
442
443         cs->size = c_min + NB_RESERVED_COLORS;
444
445         XUngrabServer(display);
446
447         dprintf_palette(stddeb,"adjusted size %i colorcells\n", cs->size);
448      }
449    else if( cSpace.flags & COLOR_VIRTUAL ) 
450         {
451           /* virtual colorspace - ToPhysical takes care of 
452            * color translations but we have to allocate full palette 
453            * to maintain compatibility
454            */
455           cs->size = 256;
456           dprintf_palette(stddeb,"\tvirtual colorspace - screendepth %i\n", screenDepth);
457         }
458    else cs->size = NB_RESERVED_COLORS;  /* system palette only - however we can alloc a bunch
459                                          * of colors and map to them */
460
461    dprintf_palette(stddeb,"Shared system palette uses %i colors.\n", cs->size);
462
463    /* set gap to account for pixel shortage. It has to be right in the center
464     * of the system palette because otherwise raster ops get screwed. */
465
466    if( cs->size >= 256 )
467      { COLOR_gapStart = 256; COLOR_gapEnd = -1; }
468    else
469      { COLOR_gapStart = cs->size/2; COLOR_gapEnd = 255 - cs->size/2; }
470
471    COLOR_firstFree = ( cs->size > NB_RESERVED_COLORS && 
472                       (cs->flags & COLOR_VIRTUAL || !(cs->flags & COLOR_FIXED)) ) 
473                      ? NB_RESERVED_COLORS/2 : -1;
474
475    COLOR_sysPal = (PALETTEENTRY*)xmalloc(sizeof(PALETTEENTRY)*256);
476
477    /* setup system palette entry <-> pixel mappings and fill in 20 fixed entries */
478
479    if( screenDepth <= 8 )
480      {
481        COLOR_PixelToPalette = (int*)xmalloc(sizeof(int)*256);
482        memset( COLOR_PixelToPalette, 0, 256*sizeof(int) );
483      }
484
485    /* for hicolor visuals PaletteToPixel mapping is used to skip
486     * RGB->pixel calculation in COLOR_ToPhysical(). 
487     */
488
489    COLOR_PaletteToPixel = (int*)xmalloc(sizeof(int)*256);
490
491    for( i = j = 0; i < 256; i++ )
492    {
493       if( i >= COLOR_gapStart && i <= COLOR_gapEnd ) 
494       {
495          COLOR_PaletteToPixel[i] = 0;
496          COLOR_sysPal[i].peFlags = 0;   /* mark as unused */
497          continue;
498       }
499
500       if( i < NB_RESERVED_COLORS/2 )
501       {
502         COLOR_PaletteToPixel[i] = sysPixel[i];
503         COLOR_sysPal[i] = __sysPalTemplate[i];
504       }
505       else if( i >= 256 - NB_RESERVED_COLORS/2 )
506       {
507         COLOR_PaletteToPixel[i] = sysPixel[(i + NB_RESERVED_COLORS) - 256]; 
508         COLOR_sysPal[i] = __sysPalTemplate[(i + NB_RESERVED_COLORS) - 256];
509       }
510       else if( pixDynMapping )
511              COLOR_PaletteToPixel[i] = pixDynMapping[j++];
512            else
513              COLOR_PaletteToPixel[i] = i;
514
515       dprintf_palette(stddeb,"\tindex %i -> pixel %i\n", i, COLOR_PaletteToPixel[i]);
516
517       if( COLOR_PixelToPalette )
518           COLOR_PixelToPalette[COLOR_PaletteToPixel[i]] = i;
519    }
520
521    if( pixDynMapping ) free(pixDynMapping);
522    return TRUE;
523 }
524
525
526 /***********************************************************************
527  *           COLOR_InitPalette
528  *
529  * Create the system palette.
530  */
531 static HPALETTE16 COLOR_InitPalette(void)
532 {
533     int                 i;
534     HPALETTE16          hpalette;
535     LOGPALETTE *        palPtr;
536     PALETTEOBJ*         palObj;
537
538     memset(COLOR_freeList, 0, 256*sizeof(unsigned char));
539
540     /* calculate max palette size */
541
542     cSpace.size = visual->map_entries;
543
544     if (cSpace.flags & COLOR_PRIVATE)
545         COLOR_BuildPrivateMap( &cSpace );
546     else
547         COLOR_BuildSharedMap( &cSpace );
548
549     /* Build free list */
550
551     if( COLOR_firstFree != -1 )
552         COLOR_FormatSystemPalette();
553
554     COLOR_FillDefaultColors();
555
556     /* create default palette (20 system colors) */
557
558     palPtr = xmalloc( sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY) );
559     if (!palPtr) return FALSE;
560
561     palPtr->palVersion = 0x300;
562     palPtr->palNumEntries = NB_RESERVED_COLORS;
563     for( i = 0; i < NB_RESERVED_COLORS; i ++ )
564     {
565         palPtr->palPalEntry[i].peRed = __sysPalTemplate[i].peRed;
566         palPtr->palPalEntry[i].peGreen = __sysPalTemplate[i].peGreen;
567         palPtr->palPalEntry[i].peBlue = __sysPalTemplate[i].peBlue;
568         palPtr->palPalEntry[i].peFlags = 0;  
569     }
570     hpalette = CreatePalette( palPtr );
571
572     palObj = (PALETTEOBJ*) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
573
574     palObj->mapping = xmalloc( sizeof(int) * 20 );
575
576     free( palPtr );
577     return hpalette;
578 }
579
580
581 /***********************************************************************
582  *           COLOR_Computeshifts
583  *
584  * Calculate conversion parameters for direct mapped visuals
585  */
586 static void COLOR_Computeshifts(unsigned long maskbits, int *shift, int *max)
587 {
588     int i;
589
590     if (maskbits==0)
591     {
592         *shift=0;
593         *max=0;
594         return;
595     }
596
597     for(i=0;!(maskbits&1);i++)
598         maskbits >>= 1;
599
600     *shift = i;
601     *max = maskbits;
602 }
603
604
605 /***********************************************************************
606  *           COLOR_Init
607  *
608  * Initialize color map and system palette.
609  *
610  */
611 HPALETTE16 COLOR_Init(void)
612 {
613     visual = DefaultVisual( display, DefaultScreen(display) );
614
615     dprintf_palette(stddeb,"COLOR_Init: initializing palette manager...");
616
617     switch(visual->class)
618     {
619     case DirectColor:
620         cSpace.flags |= COLOR_VIRTUAL;
621     case GrayScale:
622     case PseudoColor:
623         if (Options.usePrivateMap)
624         {
625             XSetWindowAttributes win_attr;
626
627             cSpace.flags |= COLOR_PRIVATE;
628             cSpace.colorMap = XCreateColormap( display, rootWindow,
629                                                  visual, AllocAll );
630             if (cSpace.colorMap)
631             {
632                if( rootWindow != DefaultRootWindow(display) )
633                  {
634                     win_attr.colormap = cSpace.colorMap;
635                     XChangeWindowAttributes( display, rootWindow,
636                                          CWColormap, &win_attr );
637                  }
638                break;
639             }
640         }
641         cSpace.colorMap = DefaultColormapOfScreen( screen );
642         break;
643
644     case StaticGray:
645         cSpace.colorMap = DefaultColormapOfScreen( screen );
646         cSpace.flags |= COLOR_FIXED;
647         COLOR_Graymax = (1<<screenDepth)-1;
648         break;
649
650     case TrueColor:
651         cSpace.flags |= COLOR_VIRTUAL;
652     case StaticColor:
653         cSpace.colorMap = DefaultColormapOfScreen( screen );
654         cSpace.flags |= COLOR_FIXED;
655         COLOR_Computeshifts(visual->red_mask, &COLOR_Redshift, &COLOR_Redmax);
656         COLOR_Computeshifts(visual->green_mask, &COLOR_Greenshift, &COLOR_Greenmax);
657         COLOR_Computeshifts(visual->blue_mask, &COLOR_Blueshift, &COLOR_Bluemax);
658         break;  
659     }
660
661     dprintf_palette(stddeb," visual class %i\n", visual->class);
662
663     return COLOR_InitPalette();
664 }
665
666 /***********************************************************************
667  *           COLOR_Cleanup
668  *
669  * Free external colors we grabbed in the FillDefaultPalette()
670  */
671 void COLOR_Cleanup(void)
672 {
673   if( COLOR_gapFilled )
674       XFreeColors(display, cSpace.colorMap, 
675                   (unsigned long*)(COLOR_PaletteToPixel + COLOR_gapStart), 
676                   COLOR_gapFilled, 0);
677 }
678
679 /***********************************************************************
680  *           COLOR_IsSolid
681  *
682  * Check whether 'color' can be represented with a solid color.
683  */
684 BOOL32 COLOR_IsSolid( COLORREF color )
685 {
686     int i;
687     const PALETTEENTRY *pEntry = COLOR_sysPal;
688
689     if (color & 0xff000000) return TRUE;                /* indexed color */
690
691     if (!color || (color == 0xffffff)) return TRUE;     /* black or white */
692
693     for (i = 0; i < 256 ; i++, pEntry++)
694     {
695       if( i < COLOR_gapStart || i > COLOR_gapEnd )
696         if ((GetRValue(color) == pEntry->peRed) &&
697             (GetGValue(color) == pEntry->peGreen) &&
698             (GetBValue(color) == pEntry->peBlue)) return TRUE;
699     }
700     return FALSE;
701 }
702
703
704 /***********************************************************************
705  *           COLOR_PaletteLookupPixel
706  */
707 int COLOR_PaletteLookupPixel( PALETTEENTRY* palPalEntry, int size,
708                               int* mapping, COLORREF col, BOOL32 skipReserved )
709 {
710     int i, best = 0, diff = 0x7fffffff;
711     int r,g,b;
712
713     for( i = 0; i < size && diff ; i++ )
714     {
715         if( !(palPalEntry[i].peFlags & PC_SYS_USED) ||
716             (skipReserved && palPalEntry[i].peFlags  & PC_SYS_RESERVED) )
717             continue;
718
719         r = palPalEntry[i].peRed - GetRValue(col);
720         g = palPalEntry[i].peGreen - GetGValue(col);
721         b = palPalEntry[i].peBlue - GetBValue(col);
722
723         r = r*r + g*g + b*b;
724
725         if( r < diff ) { best = i; diff = r; }
726     }
727     return (mapping) ? mapping[best] : best;
728 }
729
730 /***********************************************************************
731  *           COLOR_LookupSystemPixel
732  */
733 int COLOR_LookupSystemPixel(COLORREF col)
734 {
735  int            i, best = 0, diff = 0x7fffffff;
736  int            size = COLOR_GetSystemPaletteSize();
737  int            r,g,b;
738
739  for( i = 0; i < size && diff ; i++ )
740     {
741       if( i == NB_RESERVED_COLORS/2 ) i = size - NB_RESERVED_COLORS/2;
742
743       r = COLOR_sysPal[i].peRed - GetRValue(col);
744       g = COLOR_sysPal[i].peGreen - GetGValue(col);
745       b = COLOR_sysPal[i].peBlue - GetBValue(col);
746
747       r = r*r + g*g + b*b;
748
749       if( r < diff ) { best = i; diff = r; }
750     }
751  
752  return (COLOR_PaletteToPixel)? COLOR_PaletteToPixel[best] : best;
753 }
754
755 /***********************************************************************
756  *           COLOR_PaletteLookupExactIndex
757  */
758 int COLOR_PaletteLookupExactIndex( PALETTEENTRY* palPalEntry, int size,
759                                    COLORREF col )
760 {
761     int i;
762     BYTE r = GetRValue(col), g = GetGValue(col), b = GetBValue(col);
763     for( i = 0; i < size; i++ )
764     {
765         if( palPalEntry[i].peFlags & PC_SYS_USED )      /* skips gap */
766             if( palPalEntry[i].peRed == r &&
767                 palPalEntry[i].peGreen == g &&
768                 palPalEntry[i].peBlue == b )
769                 return i;
770     }
771     return -1;
772 }
773
774 /***********************************************************************
775  *           COLOR_LookupNearestColor
776  */
777 COLORREF COLOR_LookupNearestColor( PALETTEENTRY* palPalEntry, int size, COLORREF color )
778 {
779   unsigned char         spec_type = color >> 24;
780   int                   i;
781
782   /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
783
784   if( spec_type == 2 ) /* PALETTERGB */
785     color = *(COLORREF*)
786              (palPalEntry + COLOR_PaletteLookupPixel(palPalEntry,size,NULL,color,FALSE));
787
788   else if( spec_type == 1 ) /* PALETTEINDEX */
789     if( (i = color & 0x0000ffff) >= size ) 
790       {
791         fprintf(stderr, "\tRGB(%lx) : idx %d is out of bounds, assuming NULL\n", color, i);
792         color = *(COLORREF*)palPalEntry;
793       }
794     else color = *(COLORREF*)(palPalEntry + i);
795
796   color &= 0x00ffffff;
797   return (0x00ffffff & *(COLORREF*)
798          (COLOR_sysPal + COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL, color, FALSE)));
799 }
800
801 /***********************************************************************
802  *           COLOR_ToLogical
803  *
804  * Return RGB color for given X pixel.
805  */
806 COLORREF COLOR_ToLogical(int pixel)
807 {
808     XColor color;
809
810     /* truecolor visual */
811
812     if (screenDepth >= 24) return pixel;
813
814     /* check for hicolor visuals first */
815
816     if ( cSpace.flags & COLOR_FIXED && !COLOR_Graymax )
817     {
818          color.red = (pixel >> COLOR_Redshift) & COLOR_Redmax;
819          color.green = (pixel >> COLOR_Greenshift) & COLOR_Greenmax;
820          color.blue = (pixel >> COLOR_Blueshift) & COLOR_Bluemax;
821          return RGB((color.red * 255)/COLOR_Redmax,
822                     (color.green * 255)/COLOR_Greenmax,
823                     (color.blue * 255)/COLOR_Bluemax);
824     }
825
826     /* check if we can bypass X */
827
828     if ((screenDepth <= 8) && (pixel < 256) && 
829        !(cSpace.flags & (COLOR_VIRTUAL | COLOR_FIXED)) )
830          return  ( *(COLORREF*)(COLOR_sysPal + 
831                    ((COLOR_PixelToPalette)?COLOR_PixelToPalette[pixel]:pixel)) ) & 0x00ffffff;
832
833     color.pixel = pixel;
834     XQueryColor(display, cSpace.colorMap, &color);
835     return RGB(color.red >> 8, color.green >> 8, color.blue >> 8);
836 }
837
838
839 /***********************************************************************
840  *           COLOR_ToPhysical
841  *
842  * Return the physical color closest to 'color'.
843  */
844 int COLOR_ToPhysical( DC *dc, COLORREF color )
845 {
846     WORD                 index = 0;
847     unsigned char        spec_type;
848     HPALETTE16           hPal = (dc)? dc->w.hPalette: STOCK_DEFAULT_PALETTE;
849
850     spec_type = color >> 24;
851
852     if( spec_type == 0xff )
853     {
854         spec_type = 0; /* 'write' seems to need that for 'Page 1' text */
855         color &= 0xffffff;
856     }
857
858     if( spec_type > 2 )
859     {  
860         fprintf(stderr, "COLOR_ToPhysical : invalid RGB specifier for: %08lx\n", color);
861         spec_type = 0;
862     }
863
864     if (dc && (dc->w.bitsPerPixel == 1) && (spec_type == 0))
865     {
866         /* monochrome */
867         if (((color >> 16) & 0xff) +
868             ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2)
869              return 1;   /* white */
870         else return 0;   /* black */
871     }
872
873     if ( cSpace.flags & COLOR_FIXED )
874     {
875         /* there is no colormap limitation; we are going to have to compute
876          * the pixel value from the visual information stored earlier 
877          */
878
879         unsigned        long red, green, blue;
880         unsigned        idx = 0;
881         PALETTEOBJ *    palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hPal, PALETTE_MAGIC );
882
883         switch(spec_type)
884         {
885           case 2: /* PALETTERGB - not sure if we really need to search palette */
886         
887             idx = COLOR_PaletteLookupPixel( palPtr->logpalette.palPalEntry,
888                                             palPtr->logpalette.palNumEntries,
889                                             NULL, color, FALSE);
890
891             if( palPtr->mapping ) return palPtr->mapping[idx];
892
893             color = *(COLORREF*)(palPtr->logpalette.palPalEntry + idx);
894             break;
895
896           case 1: /* PALETTEINDEX */
897
898             if ( (idx = color & 0xffff) >= palPtr->logpalette.palNumEntries)
899             {
900                 fprintf(stderr, "\tRGB(%lx) : idx %d is out of bounds, assuming black\n", color, idx);
901                 return 0;
902             }
903
904             if( palPtr->mapping ) return palPtr->mapping[idx];
905
906             color = *(COLORREF*)(palPtr->logpalette.palPalEntry + idx);
907
908             /* fall through and out */
909
910           case 0: /* RGB */
911           default:
912         }
913
914         red = GetRValue(color); green = GetGValue(color); blue = GetBValue(color);
915
916         if (COLOR_Graymax)
917         {
918             /* grayscale only; return scaled value */
919             return ( (red * 30 + green * 69 + blue * 11) * COLOR_Graymax) / 25500;
920         }
921         else
922         {
923             /* scale each individually and construct the TrueColor pixel value */
924             if (COLOR_Redmax != 255) red = (red * COLOR_Redmax) / 255;
925             if (COLOR_Greenmax != 255) green = (green * COLOR_Greenmax) / 255;
926             if (COLOR_Bluemax != 255) blue = (blue * COLOR_Bluemax) / 255;
927
928             return (red << COLOR_Redshift) | (green << COLOR_Greenshift) | (blue << COLOR_Blueshift);
929         }
930     }
931     else 
932     {
933         PALETTEOBJ* palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hPal, PALETTE_MAGIC);
934
935         /* palPtr can be NULL when DC is being destroyed */
936
937         if( !palPtr ) return 0;
938         else if( !palPtr->mapping ) 
939             dprintf_palette(stddeb,"\tpalette %04x is not realized\n", dc->w.hPalette);
940
941         switch(spec_type)       /* we have to peruse DC and system palette */
942         {
943             default:
944             case 0:  /* RGB */
945                 index = COLOR_PaletteLookupPixel( COLOR_sysPal, 256, 
946                                                   COLOR_PaletteToPixel, color, FALSE);
947
948                 /* dprintf_palette(stddeb,"\tRGB(%lx) -> pixel %i\n", color, index);
949                  */
950                 break;
951             case 1:  /* PALETTEINDEX */
952                 index = color & 0xffff;
953
954                 if( index >= palPtr->logpalette.palNumEntries )
955                     fprintf(stderr, "\tRGB(%lx) : index %i is out of bounds\n", color, index); 
956                 else if( palPtr->mapping ) index = palPtr->mapping[index];
957
958                 /*  dprintf_palette(stddeb,"\tPALETTEINDEX(%04x) -> pixel %i\n", (WORD)color, index);
959                  */
960                 break;
961             case 2:  /* PALETTERGB */
962                 index = COLOR_PaletteLookupPixel( palPtr->logpalette.palPalEntry, 
963                                              palPtr->logpalette.palNumEntries,
964                                              palPtr->mapping, color, FALSE);
965                 /* dprintf_palette(stddeb,"\tPALETTERGB(%lx) -> pixel %i\n", color, index);
966                  */
967                 break;
968         }
969     }
970
971     return index;
972 }
973
974 /***********************************************************************
975  *           COLOR_SetMapping
976  *
977  * Set the color-mapping table for selected palette. 
978  * Return number of entries which mapping has changed.
979  */
980 int COLOR_SetMapping( PALETTEOBJ* palPtr, BOOL32 mapOnly )
981 {
982     int  i, index;
983     char flag;
984     int  prevMapping = (palPtr->mapping) ? 1 : 0;
985     int  iRemapped = 0;
986
987     /* reset dynamic system palette entries */
988
989     if( !mapOnly && COLOR_firstFree != -1)
990          COLOR_FormatSystemPalette();
991
992     /* initialize palette mapping table */
993  
994     palPtr->mapping = (int*)xrealloc(palPtr->mapping, sizeof(int)*
995                                      palPtr->logpalette.palNumEntries);
996
997     for( i = 0; i < palPtr->logpalette.palNumEntries; i++ )
998     {
999         index = -1;
1000         flag = PC_SYS_USED;
1001
1002         switch( palPtr->logpalette.palPalEntry[i].peFlags & 0x07 )
1003         {
1004         case PC_EXPLICIT:   /* palette entries are indices into system palette */
1005             index = *(WORD*)(palPtr->logpalette.palPalEntry + i);
1006             if( index > 255 || (index >= COLOR_gapStart && index <= COLOR_gapEnd) ) 
1007             {
1008                 fprintf(stderr,"PC_EXPLICIT: idx %d out of system palette, assuming black.\n", index); 
1009                 index = 0;
1010             }
1011             break;
1012
1013         case PC_RESERVED:   /* forbid future mappings to this entry */
1014             flag |= PC_SYS_RESERVED;
1015
1016             /* fall through */
1017         default:            /* try to collapse identical colors */
1018             index = COLOR_PaletteLookupExactIndex(COLOR_sysPal, 256,  
1019                              *(COLORREF*)(palPtr->logpalette.palPalEntry + i));
1020             /* fall through */
1021         case PC_NOCOLLAPSE: 
1022             if( index < 0 )
1023             {
1024                 if( COLOR_firstFree > 0 && !(cSpace.flags & COLOR_FIXED) )
1025                 {
1026                     XColor color;
1027                     index = COLOR_firstFree;  /* ought to be available */
1028                     COLOR_firstFree = COLOR_freeList[index];
1029
1030                     color.pixel = (COLOR_PaletteToPixel) ? COLOR_PaletteToPixel[index] : index;
1031                     color.red = palPtr->logpalette.palPalEntry[i].peRed << 8;
1032                     color.green = palPtr->logpalette.palPalEntry[i].peGreen << 8;
1033                     color.blue = palPtr->logpalette.palPalEntry[i].peBlue << 8;
1034                     color.flags = DoRed | DoGreen | DoBlue;
1035                     XStoreColor(display, cSpace.colorMap, &color);
1036
1037                     COLOR_sysPal[index] = palPtr->logpalette.palPalEntry[i];
1038                     COLOR_sysPal[index].peFlags = flag;
1039                     COLOR_freeList[index] = 0;
1040
1041                     if( COLOR_PaletteToPixel ) index = COLOR_PaletteToPixel[index];
1042                     break;
1043                 }
1044                 else if ( cSpace.flags & COLOR_VIRTUAL ) 
1045                 {
1046                     index = COLOR_ToPhysical( NULL, 0x00ffffff &
1047                              *(COLORREF*)(palPtr->logpalette.palPalEntry + i));
1048                     break;     
1049                 }
1050
1051                 /* we have to map to existing entry in the system palette */
1052
1053                 index = COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL, 
1054                        *(COLORREF*)(palPtr->logpalette.palPalEntry + i), TRUE);
1055             }
1056             palPtr->logpalette.palPalEntry[i].peFlags |= PC_SYS_USED;
1057
1058             if( COLOR_PaletteToPixel ) index = COLOR_PaletteToPixel[index];
1059             break;
1060         }
1061
1062         if( !prevMapping || palPtr->mapping[i] != index ) iRemapped++;
1063         palPtr->mapping[i] = index;
1064
1065         dprintf_palette(stddeb,"\tentry %i (%lx) -> pixel %i\n", i, 
1066                                 *(COLORREF*)(palPtr->logpalette.palPalEntry + i), index);
1067         
1068     }
1069     return iRemapped;
1070 }