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