1 /*
2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3  *
4  *Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  *"Software"), to deal in the Software without restriction, including
7  *without limitation the rights to use, copy, modify, merge, publish,
8  *distribute, sublicense, and/or sell copies of the Software, and to
9  *permit persons to whom the Software is furnished to do so, subject to
10  *the following conditions:
11  *
12  *The above copyright notice and this permission notice shall be
13  *included in all copies or substantial portions of the Software.
14  *
15  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  *Except as contained in this notice, the name of the XFree86 Project
24  *shall not be used in advertising or otherwise to promote the sale, use
25  *or other dealings in this Software without prior written authorization
26  *from the XFree86 Project.
27  *
28  * Authors:	Dakshinamurthy Karra
29  *		Suhaib M Siddiqi
30  *		Peter Busch
31  *		Harold L Hunt II
32  */
33 
34 #ifdef HAVE_XWIN_CONFIG_H
35 #include <xwin-config.h>
36 #endif
37 #include "win.h"
38 
39 /*
40  * Local prototypes
41  */
42 
43 static int
44  winListInstalledColormaps(ScreenPtr pScreen, Colormap * pmaps);
45 
46 static void
47  winStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs);
48 
49 static void
50  winInstallColormap(ColormapPtr pmap);
51 
52 static void
53  winUninstallColormap(ColormapPtr pmap);
54 
55 static void
56 
57 winResolveColor(unsigned short *pred,
58                 unsigned short *pgreen,
59                 unsigned short *pblue, VisualPtr pVisual);
60 
61 static Bool
62  winCreateColormap(ColormapPtr pmap);
63 
64 static void
65  winDestroyColormap(ColormapPtr pmap);
66 
67 static Bool
68  winGetPaletteDIB(ScreenPtr pScreen, ColormapPtr pcmap);
69 
70 static Bool
71  winGetPaletteDD(ScreenPtr pScreen, ColormapPtr pcmap);
72 
73 /*
74  * Set screen functions for colormaps
75  */
76 
77 void
winSetColormapFunctions(ScreenPtr pScreen)78 winSetColormapFunctions(ScreenPtr pScreen)
79 {
80     pScreen->CreateColormap = winCreateColormap;
81     pScreen->DestroyColormap = winDestroyColormap;
82     pScreen->InstallColormap = winInstallColormap;
83     pScreen->UninstallColormap = winUninstallColormap;
84     pScreen->ListInstalledColormaps = winListInstalledColormaps;
85     pScreen->StoreColors = winStoreColors;
86     pScreen->ResolveColor = winResolveColor;
87 }
88 
89 /* See Porting Layer Definition - p. 30 */
90 /*
91  * Walk the list of installed colormaps, filling the pmaps list
92  * with the resource ids of the installed maps, and return
93  * a count of the total number of installed maps.
94  */
95 static int
winListInstalledColormaps(ScreenPtr pScreen,Colormap * pmaps)96 winListInstalledColormaps(ScreenPtr pScreen, Colormap * pmaps)
97 {
98     winScreenPriv(pScreen);
99 
100     /*
101      * There will only be one installed colormap, so we only need
102      * to return one id, and the count of installed maps will always
103      * be one.
104      */
105     *pmaps = pScreenPriv->pcmapInstalled->mid;
106     return 1;
107 }
108 
109 /* See Porting Layer Definition - p. 30 */
110 /* See Programming Windows - p. 663 */
111 static void
winInstallColormap(ColormapPtr pColormap)112 winInstallColormap(ColormapPtr pColormap)
113 {
114     ScreenPtr pScreen = pColormap->pScreen;
115 
116     winScreenPriv(pScreen);
117     ColormapPtr oldpmap = pScreenPriv->pcmapInstalled;
118 
119 #if CYGDEBUG
120     winDebug("winInstallColormap\n");
121 #endif
122 
123     /* Did the colormap actually change? */
124     if (pColormap != oldpmap) {
125 #if CYGDEBUG
126         winDebug("winInstallColormap - Colormap has changed, attempt "
127                  "to install.\n");
128 #endif
129 
130         /* Was there a previous colormap? */
131         if (oldpmap != (ColormapPtr) None) {
132             /* There was a previous colormap; tell clients it is gone */
133             WalkTree(pColormap->pScreen, TellLostMap, (char *) &oldpmap->mid);
134         }
135 
136         /* Install new colormap */
137         pScreenPriv->pcmapInstalled = pColormap;
138         WalkTree(pColormap->pScreen, TellGainedMap, (char *) &pColormap->mid);
139 
140         /* Call the engine specific colormap install procedure */
141         if (!((*pScreenPriv->pwinInstallColormap) (pColormap))) {
142             winErrorFVerb(2,
143                           "winInstallColormap - Screen specific colormap install "
144                           "procedure failed.  Continuing, but colors may be "
145                           "messed up from now on.\n");
146         }
147     }
148 
149     /* Save a pointer to the newly installed colormap */
150     pScreenPriv->pcmapInstalled = pColormap;
151 }
152 
153 /* See Porting Layer Definition - p. 30 */
154 static void
winUninstallColormap(ColormapPtr pmap)155 winUninstallColormap(ColormapPtr pmap)
156 {
157     winScreenPriv(pmap->pScreen);
158     ColormapPtr curpmap = pScreenPriv->pcmapInstalled;
159 
160 #if CYGDEBUG
161     winDebug("winUninstallColormap\n");
162 #endif
163 
164     /* Is the colormap currently installed? */
165     if (pmap != curpmap) {
166         /* Colormap not installed, nothing to do */
167         return;
168     }
169 
170     /* Clear the installed colormap flag */
171     pScreenPriv->pcmapInstalled = NULL;
172 
173     /*
174      * NOTE: The default colormap does not get "uninstalled" before
175      * it is destroyed.
176      */
177 
178     /* Install the default cmap in place of the cmap to be uninstalled */
179     if (pmap->mid != pmap->pScreen->defColormap) {
180         dixLookupResourceByType((void *) &curpmap, pmap->pScreen->defColormap,
181                                 RT_COLORMAP, NullClient, DixUnknownAccess);
182         (*pmap->pScreen->InstallColormap) (curpmap);
183     }
184 }
185 
186 /* See Porting Layer Definition - p. 30 */
187 static void
winStoreColors(ColormapPtr pmap,int ndef,xColorItem * pdefs)188 winStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
189 {
190     ScreenPtr pScreen = pmap->pScreen;
191 
192     winScreenPriv(pScreen);
193     winCmapPriv(pmap);
194     int i;
195     unsigned short nRed, nGreen, nBlue;
196 
197 #if CYGDEBUG
198     if (ndef != 1)
199         winDebug("winStoreColors - ndef: %d\n", ndef);
200 #endif
201 
202     /* Save the new colors in the colormap privates */
203     for (i = 0; i < ndef; ++i) {
204         /* Adjust the colors from the X color spec to the Windows color spec */
205         nRed = pdefs[i].red >> 8;
206         nGreen = pdefs[i].green >> 8;
207         nBlue = pdefs[i].blue >> 8;
208 
209         /* Copy the colors to a palette entry table */
210         pCmapPriv->peColors[pdefs[0].pixel + i].peRed = nRed;
211         pCmapPriv->peColors[pdefs[0].pixel + i].peGreen = nGreen;
212         pCmapPriv->peColors[pdefs[0].pixel + i].peBlue = nBlue;
213 
214         /* Copy the colors to a RGBQUAD table */
215         pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbRed = nRed;
216         pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbGreen = nGreen;
217         pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbBlue = nBlue;
218 
219 #if CYGDEBUG
220         winDebug("winStoreColors - nRed %d nGreen %d nBlue %d\n",
221                  nRed, nGreen, nBlue);
222 #endif
223     }
224 
225     /* Call the engine specific store colors procedure */
226     if (!((pScreenPriv->pwinStoreColors) (pmap, ndef, pdefs))) {
227         winErrorFVerb(2,
228                       "winStoreColors - Engine cpecific color storage procedure "
229                       "failed.  Continuing, but colors may be messed up from now "
230                       "on.\n");
231     }
232 }
233 
234 /* See Porting Layer Definition - p. 30 */
235 static void
winResolveColor(unsigned short * pred,unsigned short * pgreen,unsigned short * pblue,VisualPtr pVisual)236 winResolveColor(unsigned short *pred,
237                 unsigned short *pgreen,
238                 unsigned short *pblue, VisualPtr pVisual)
239 {
240 #if CYGDEBUG
241     winDebug("winResolveColor ()\n");
242 #endif
243 
244     miResolveColor(pred, pgreen, pblue, pVisual);
245 }
246 
247 /* See Porting Layer Definition - p. 29 */
248 static Bool
winCreateColormap(ColormapPtr pmap)249 winCreateColormap(ColormapPtr pmap)
250 {
251     winPrivCmapPtr pCmapPriv = NULL;
252     ScreenPtr pScreen = pmap->pScreen;
253 
254     winScreenPriv(pScreen);
255 
256 #if CYGDEBUG
257     winDebug("winCreateColormap\n");
258 #endif
259 
260     /* Allocate colormap privates */
261     if (!winAllocateCmapPrivates(pmap)) {
262         ErrorF("winCreateColorma - Couldn't allocate cmap privates\n");
263         return FALSE;
264     }
265 
266     /* Get a pointer to the newly allocated privates */
267     pCmapPriv = winGetCmapPriv(pmap);
268 
269     /*
270      * FIXME: This is some evil hackery to help in handling some X clients
271      * that expect the top pixel to be white.  This "help" only lasts until
272      * some client overwrites the top colormap entry.
273      *
274      * We don't want to actually allocate the top entry, as that causes
275      * problems with X clients that need 7 planes (128 colors) in the default
276      * colormap, such as Magic 7.1.
277      */
278     pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbRed = 255;
279     pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbGreen = 255;
280     pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbBlue = 255;
281     pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peRed = 255;
282     pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peGreen = 255;
283     pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peBlue = 255;
284 
285     /* Call the engine specific colormap initialization procedure */
286     if (!((*pScreenPriv->pwinCreateColormap) (pmap))) {
287         ErrorF("winCreateColormap - Engine specific colormap creation "
288                "procedure failed.  Aborting.\n");
289         return FALSE;
290     }
291 
292     return TRUE;
293 }
294 
295 /* See Porting Layer Definition - p. 29, 30 */
296 static void
winDestroyColormap(ColormapPtr pColormap)297 winDestroyColormap(ColormapPtr pColormap)
298 {
299     winScreenPriv(pColormap->pScreen);
300     winCmapPriv(pColormap);
301 
302     /* Call the engine specific colormap destruction procedure */
303     if (!((*pScreenPriv->pwinDestroyColormap) (pColormap))) {
304         winErrorFVerb(2,
305                       "winDestroyColormap - Engine specific colormap destruction "
306                       "procedure failed.  Continuing, but it is possible that memory "
307                       "was leaked, or that colors will be messed up from now on.\n");
308     }
309 
310     /* Free the colormap privates */
311     free(pCmapPriv);
312     winSetCmapPriv(pColormap, NULL);
313 
314 #if CYGDEBUG
315     winDebug("winDestroyColormap - Returning\n");
316 #endif
317 }
318 
319 /*
320  * Internal function to load the palette used by the Shadow DIB
321  */
322 
323 static Bool
winGetPaletteDIB(ScreenPtr pScreen,ColormapPtr pcmap)324 winGetPaletteDIB(ScreenPtr pScreen, ColormapPtr pcmap)
325 {
326     winScreenPriv(pScreen);
327     int i;
328     Pixel pixel;                /* Pixel == CARD32 */
329     CARD16 nRed, nGreen, nBlue; /* CARD16 == unsigned short */
330     UINT uiColorsRetrieved = 0;
331     RGBQUAD rgbColors[WIN_NUM_PALETTE_ENTRIES];
332 
333     /* Get the color table for the screen */
334     uiColorsRetrieved = GetDIBColorTable(pScreenPriv->hdcScreen,
335                                          0, WIN_NUM_PALETTE_ENTRIES, rgbColors);
336     if (uiColorsRetrieved == 0) {
337         ErrorF("winGetPaletteDIB - Could not retrieve screen color table\n");
338         return FALSE;
339     }
340 
341 #if CYGDEBUG
342     winDebug("winGetPaletteDIB - Retrieved %d colors from DIB\n",
343              uiColorsRetrieved);
344 #endif
345 
346     /* Set the DIB color table to the default screen palette */
347     if (SetDIBColorTable(pScreenPriv->hdcShadow,
348                          0, uiColorsRetrieved, rgbColors) == 0) {
349         ErrorF("winGetPaletteDIB - SetDIBColorTable () failed\n");
350         return FALSE;
351     }
352 
353     /* Alloc each color in the DIB color table */
354     for (i = 0; i < uiColorsRetrieved; ++i) {
355         pixel = i;
356 
357         /* Extract the color values for current palette entry */
358         nRed = rgbColors[i].rgbRed << 8;
359         nGreen = rgbColors[i].rgbGreen << 8;
360         nBlue = rgbColors[i].rgbBlue << 8;
361 
362 #if CYGDEBUG
363         winDebug("winGetPaletteDIB - Allocating a color: %u; "
364                  "%d %d %d\n", (unsigned int)pixel, nRed, nGreen, nBlue);
365 #endif
366 
367         /* Allocate a entry in the X colormap */
368         if (AllocColor(pcmap, &nRed, &nGreen, &nBlue, &pixel, 0) != Success) {
369             ErrorF("winGetPaletteDIB - AllocColor () failed, pixel %d\n", i);
370             return FALSE;
371         }
372 
373         if (i != pixel
374             || nRed != rgbColors[i].rgbRed
375             || nGreen != rgbColors[i].rgbGreen
376             || nBlue != rgbColors[i].rgbBlue) {
377             winDebug("winGetPaletteDIB - Got: %d; "
378                      "%d %d %d\n", (int) pixel, nRed, nGreen, nBlue);
379         }
380 
381         /* FIXME: Not sure that this bit is needed at all */
382         pcmap->red[i].co.local.red = nRed;
383         pcmap->red[i].co.local.green = nGreen;
384         pcmap->red[i].co.local.blue = nBlue;
385     }
386 
387     /* System is using a colormap */
388     /* Set the black and white pixel indices */
389     pScreen->whitePixel = uiColorsRetrieved - 1;
390     pScreen->blackPixel = 0;
391 
392     return TRUE;
393 }
394 
395 /*
396  * Internal function to load the standard system palette being used by DD
397  */
398 
399 static Bool
winGetPaletteDD(ScreenPtr pScreen,ColormapPtr pcmap)400 winGetPaletteDD(ScreenPtr pScreen, ColormapPtr pcmap)
401 {
402     int i;
403     Pixel pixel;                /* Pixel == CARD32 */
404     CARD16 nRed, nGreen, nBlue; /* CARD16 == unsigned short */
405     UINT uiSystemPaletteEntries;
406     LPPALETTEENTRY ppeColors = NULL;
407     HDC hdc = NULL;
408 
409     /* Get a DC to obtain the default palette */
410     hdc = GetDC(NULL);
411     if (hdc == NULL) {
412         ErrorF("winGetPaletteDD - Couldn't get a DC\n");
413         return FALSE;
414     }
415 
416     /* Get the number of entries in the system palette */
417     uiSystemPaletteEntries = GetSystemPaletteEntries(hdc, 0, 0, NULL);
418     if (uiSystemPaletteEntries == 0) {
419         ErrorF("winGetPaletteDD - Unable to determine number of "
420                "system palette entries\n");
421         return FALSE;
422     }
423 
424 #if CYGDEBUG
425     winDebug("winGetPaletteDD - uiSystemPaletteEntries %d\n",
426              uiSystemPaletteEntries);
427 #endif
428 
429     /* Allocate palette entries structure */
430     ppeColors = malloc(uiSystemPaletteEntries * sizeof(PALETTEENTRY));
431     if (ppeColors == NULL) {
432         ErrorF("winGetPaletteDD - malloc () for colormap failed\n");
433         return FALSE;
434     }
435 
436     /* Get system palette entries */
437     GetSystemPaletteEntries(hdc, 0, uiSystemPaletteEntries, ppeColors);
438 
439     /* Allocate an X colormap entry for every system palette entry */
440     for (i = 0; i < uiSystemPaletteEntries; ++i) {
441         pixel = i;
442 
443         /* Extract the color values for current palette entry */
444         nRed = ppeColors[i].peRed << 8;
445         nGreen = ppeColors[i].peGreen << 8;
446         nBlue = ppeColors[i].peBlue << 8;
447 #if CYGDEBUG
448         winDebug("winGetPaletteDD - Allocating a color: %u; "
449                  "%d %d %d\n", (unsigned int)pixel, nRed, nGreen, nBlue);
450 #endif
451         if (AllocColor(pcmap, &nRed, &nGreen, &nBlue, &pixel, 0) != Success) {
452             ErrorF("winGetPaletteDD - AllocColor () failed, pixel %d\n", i);
453             free(ppeColors);
454             ppeColors = NULL;
455             return FALSE;
456         }
457 
458         pcmap->red[i].co.local.red = nRed;
459         pcmap->red[i].co.local.green = nGreen;
460         pcmap->red[i].co.local.blue = nBlue;
461     }
462 
463     /* System is using a colormap */
464     /* Set the black and white pixel indices */
465     pScreen->whitePixel = uiSystemPaletteEntries - 1;
466     pScreen->blackPixel = 0;
467 
468     /* Free colormap */
469     free(ppeColors);
470     ppeColors = NULL;
471 
472     /* Free the DC */
473     if (hdc != NULL) {
474         ReleaseDC(NULL, hdc);
475         hdc = NULL;
476     }
477 
478     return TRUE;
479 }
480 
481 /*
482  * Install the standard fb colormap, or the GDI colormap,
483  * depending on the current screen depth.
484  */
485 
486 Bool
winCreateDefColormap(ScreenPtr pScreen)487 winCreateDefColormap(ScreenPtr pScreen)
488 {
489     winScreenPriv(pScreen);
490     winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
491     unsigned short zero = 0, ones = 0xFFFF;
492     VisualPtr pVisual = pScreenPriv->pRootVisual;
493     ColormapPtr pcmap = NULL;
494     Pixel wp, bp;
495 
496 #if CYGDEBUG
497     winDebug("winCreateDefColormap\n");
498 #endif
499 
500     /* Use standard fb colormaps for non palettized color modes */
501     if (pScreenInfo->dwBPP > 8) {
502         winDebug("winCreateDefColormap - Deferring to "
503                  "fbCreateDefColormap ()\n");
504         return fbCreateDefColormap(pScreen);
505     }
506 
507     /*
508      *  AllocAll for non-Dynamic visual classes,
509      *  AllocNone for Dynamic visual classes.
510      */
511 
512     /*
513      * Dynamic visual classes allow the colors of the color map
514      * to be changed by clients.
515      */
516 
517 #if CYGDEBUG
518     winDebug("winCreateDefColormap - defColormap: %lu\n", pScreen->defColormap);
519 #endif
520 
521     /* Allocate an X colormap, owned by client 0 */
522     if (CreateColormap(pScreen->defColormap,
523                        pScreen,
524                        pVisual,
525                        &pcmap,
526                        (pVisual->class & DynamicClass) ? AllocNone : AllocAll,
527                        0) != Success) {
528         ErrorF("winCreateDefColormap - CreateColormap failed\n");
529         return FALSE;
530     }
531     if (pcmap == NULL) {
532         ErrorF("winCreateDefColormap - Colormap could not be created\n");
533         return FALSE;
534     }
535 
536 #if CYGDEBUG
537     winDebug("winCreateDefColormap - Created a colormap\n");
538 #endif
539 
540     /* Branch on the visual class */
541     if (!(pVisual->class & DynamicClass)) {
542         /* Branch on engine type */
543         if (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI) {
544             /* Load the colors being used by the Shadow DIB */
545             if (!winGetPaletteDIB(pScreen, pcmap)) {
546                 ErrorF("winCreateDefColormap - Couldn't get DIB colors\n");
547                 return FALSE;
548             }
549         }
550         else {
551             /* Load the colors from the default system palette */
552             if (!winGetPaletteDD(pScreen, pcmap)) {
553                 ErrorF("winCreateDefColormap - Couldn't get colors "
554                        "for DD\n");
555                 return FALSE;
556             }
557         }
558     }
559     else {
560         wp = pScreen->whitePixel;
561         bp = pScreen->blackPixel;
562 
563         /* Allocate a black and white pixel */
564         if ((AllocColor(pcmap, &ones, &ones, &ones, &wp, 0) != Success)
565             || (AllocColor(pcmap, &zero, &zero, &zero, &bp, 0) != Success)) {
566             ErrorF("winCreateDefColormap - Couldn't allocate bp or wp\n");
567             return FALSE;
568         }
569 
570         pScreen->whitePixel = wp;
571         pScreen->blackPixel = bp;
572 
573 #if 0
574         /* Have to reserve first 10 and last ten pixels in DirectDraw windowed */
575         if (pScreenInfo->dwEngine != WIN_SERVER_SHADOW_GDI) {
576             int k;
577             Pixel p;
578 
579             for (k = 1; k < 10; ++k) {
580                 p = k;
581                 if (AllocColor(pcmap, &ones, &ones, &ones, &p, 0) != Success)
582                     FatalError("Foo!\n");
583             }
584 
585             for (k = 245; k < 255; ++k) {
586                 p = k;
587                 if (AllocColor(pcmap, &zero, &zero, &zero, &p, 0) != Success)
588                     FatalError("Baz!\n");
589             }
590         }
591 #endif
592     }
593 
594     /* Install the created colormap */
595     (*pScreen->InstallColormap) (pcmap);
596 
597 #if CYGDEBUG
598     winDebug("winCreateDefColormap - Returning\n");
599 #endif
600 
601     return TRUE;
602 }
603