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