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