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