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