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
43static int
44 winListInstalledColormaps(ScreenPtr pScreen, Colormap * pmaps);
45
46static void
47 winStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs);
48
49static void
50 winInstallColormap(ColormapPtr pmap);
51
52static void
53 winUninstallColormap(ColormapPtr pmap);
54
55static void
56
57winResolveColor(unsigned short *pred,
58                unsigned short *pgreen,
59                unsigned short *pblue, VisualPtr pVisual);
60
61static Bool
62 winCreateColormap(ColormapPtr pmap);
63
64static void
65 winDestroyColormap(ColormapPtr pmap);
66
67static Bool
68 winGetPaletteDIB(ScreenPtr pScreen, ColormapPtr pcmap);
69
70static Bool
71 winGetPaletteDD(ScreenPtr pScreen, ColormapPtr pcmap);
72
73/*
74 * Set screen functions for colormaps
75 */
76
77void
78winSetColormapFunctions(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 */
95static int
96winListInstalledColormaps(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 */
111static void
112winInstallColormap(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 */
154static void
155winUninstallColormap(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 */
187static void
188winStoreColors(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 */
235static void
236winResolveColor(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 */
248static Bool
249winCreateColormap(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 */
296static void
297winDestroyColormap(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
323static Bool
324winGetPaletteDIB(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
399static Bool
400winGetPaletteDD(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
486Bool
487winCreateDefColormap(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