wincmap.c revision 9ace9065
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/*
41 * Local prototypes
42 */
43
44static int
45winListInstalledColormaps (ScreenPtr pScreen, Colormap *pmaps);
46
47static void
48winStoreColors (ColormapPtr pmap, int ndef, xColorItem *pdefs);
49
50static void
51winInstallColormap (ColormapPtr pmap);
52
53static void
54winUninstallColormap (ColormapPtr pmap);
55
56static void
57winResolveColor (unsigned short *pred,
58		 unsigned short *pgreen,
59		 unsigned short *pblue,
60		 VisualPtr	pVisual);
61
62static Bool
63winCreateColormap (ColormapPtr pmap);
64
65static void
66winDestroyColormap (ColormapPtr pmap);
67
68static Bool
69winGetPaletteDIB (ScreenPtr pScreen, ColormapPtr pcmap);
70
71static Bool
72winGetPaletteDD (ScreenPtr pScreen, ColormapPtr pcmap);
73
74
75/*
76 * Set screen functions for colormaps
77 */
78
79void
80winSetColormapFunctions (ScreenPtr pScreen)
81{
82  pScreen->CreateColormap = winCreateColormap;
83  pScreen->DestroyColormap = winDestroyColormap;
84  pScreen->InstallColormap = winInstallColormap;
85  pScreen->UninstallColormap = winUninstallColormap;
86  pScreen->ListInstalledColormaps = winListInstalledColormaps;
87  pScreen->StoreColors = winStoreColors;
88  pScreen->ResolveColor = winResolveColor;
89}
90
91
92/* See Porting Layer Definition - p. 30 */
93/*
94 * Walk the list of installed colormaps, filling the pmaps list
95 * with the resource ids of the installed maps, and return
96 * a count of the total number of installed maps.
97 */
98static int
99winListInstalledColormaps (ScreenPtr pScreen, Colormap *pmaps)
100{
101  winScreenPriv(pScreen);
102
103  /*
104   * There will only be one installed colormap, so we only need
105   * to return one id, and the count of installed maps will always
106   * be one.
107   */
108  *pmaps = pScreenPriv->pcmapInstalled->mid;
109  return 1;
110}
111
112
113/* See Porting Layer Definition - p. 30 */
114/* See Programming Windows - p. 663 */
115static void
116winInstallColormap (ColormapPtr pColormap)
117{
118  ScreenPtr		pScreen = pColormap->pScreen;
119  winScreenPriv(pScreen);
120  ColormapPtr		oldpmap = pScreenPriv->pcmapInstalled;
121
122#if CYGDEBUG
123  winDebug ("winInstallColormap\n");
124#endif
125
126  /* Did the colormap actually change? */
127  if (pColormap != oldpmap)
128    {
129#if CYGDEBUG
130      winDebug ("winInstallColormap - Colormap has changed, attempt "
131	      "to install.\n");
132#endif
133
134      /* Was there a previous colormap? */
135      if (oldpmap != (ColormapPtr) None)
136	{
137	  /* There was a previous colormap; tell clients it is gone */
138	  WalkTree (pColormap->pScreen, TellLostMap, (char *)&oldpmap->mid);
139	}
140
141      /* Install new colormap */
142      pScreenPriv->pcmapInstalled = pColormap;
143      WalkTree (pColormap->pScreen, TellGainedMap, (char *)&pColormap->mid);
144
145      /* Call the engine specific colormap install procedure */
146      if (!((*pScreenPriv->pwinInstallColormap) (pColormap)))
147	{
148	  winErrorFVerb (2, "winInstallColormap - Screen specific colormap install "
149		  "procedure failed.  Continuing, but colors may be "
150		  "messed up from now on.\n");
151	}
152    }
153
154  /* Save a pointer to the newly installed colormap */
155  pScreenPriv->pcmapInstalled = pColormap;
156}
157
158
159/* See Porting Layer Definition - p. 30 */
160static void
161winUninstallColormap (ColormapPtr pmap)
162{
163  winScreenPriv(pmap->pScreen);
164  ColormapPtr curpmap = pScreenPriv->pcmapInstalled;
165
166#if CYGDEBUG
167  winDebug ("winUninstallColormap\n");
168#endif
169
170  /* Is the colormap currently installed? */
171  if (pmap != curpmap)
172    {
173      /* Colormap not installed, nothing to do */
174      return;
175    }
176
177  /* Clear the installed colormap flag */
178  pScreenPriv->pcmapInstalled = NULL;
179
180  /*
181   * NOTE: The default colormap does not get "uninstalled" before
182   * it is destroyed.
183   */
184
185  /* Install the default cmap in place of the cmap to be uninstalled */
186  if (pmap->mid != pmap->pScreen->defColormap)
187    {
188      dixLookupResourceByType((pointer) &curpmap, pmap->pScreen->defColormap,
189				RT_COLORMAP, NullClient, DixUnknownAccess);
190      (*pmap->pScreen->InstallColormap) (curpmap);
191    }
192}
193
194
195/* See Porting Layer Definition - p. 30 */
196static void
197winStoreColors (ColormapPtr pmap,
198		int ndef,
199		xColorItem *pdefs)
200{
201  ScreenPtr		pScreen = pmap->pScreen;
202  winScreenPriv(pScreen);
203  winCmapPriv(pmap);
204  int			i;
205  unsigned short	nRed, nGreen, nBlue;
206
207#if CYGDEBUG
208  if (ndef != 1)
209    winDebug ("winStoreColors - ndef: %d\n",
210	    ndef);
211#endif
212
213  /* Save the new colors in the colormap privates */
214  for (i = 0; i < ndef; ++i)
215    {
216      /* Adjust the colors from the X color spec to the Windows color spec */
217      nRed = pdefs[i].red >> 8;
218      nGreen = pdefs[i].green >> 8;
219      nBlue = pdefs[i].blue >> 8;
220
221      /* Copy the colors to a palette entry table */
222      pCmapPriv->peColors[pdefs[0].pixel + i].peRed = nRed;
223      pCmapPriv->peColors[pdefs[0].pixel + i].peGreen = nGreen;
224      pCmapPriv->peColors[pdefs[0].pixel + i].peBlue = nBlue;
225
226      /* Copy the colors to a RGBQUAD table */
227      pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbRed = nRed;
228      pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbGreen = nGreen;
229      pCmapPriv->rgbColors[pdefs[0].pixel + i].rgbBlue = nBlue;
230
231#if CYGDEBUG
232      winDebug ("winStoreColors - nRed %d nGreen %d nBlue %d\n",
233	      nRed, nGreen, nBlue);
234#endif
235    }
236
237  /* Call the engine specific store colors procedure */
238  if (!((pScreenPriv->pwinStoreColors) (pmap, ndef, pdefs)))
239    {
240      winErrorFVerb (2, "winStoreColors - Engine cpecific color storage procedure "
241	      "failed.  Continuing, but colors may be messed up from now "
242	      "on.\n");
243    }
244}
245
246
247/* See Porting Layer Definition - p. 30 */
248static void
249winResolveColor (unsigned short *pred,
250		 unsigned short *pgreen,
251		 unsigned short *pblue,
252		 VisualPtr	pVisual)
253{
254#if CYGDEBUG
255  winDebug ("winResolveColor ()\n");
256#endif
257
258  miResolveColor (pred, pgreen, pblue, pVisual);
259}
260
261
262/* See Porting Layer Definition - p. 29 */
263static Bool
264winCreateColormap (ColormapPtr pmap)
265{
266  winPrivCmapPtr	pCmapPriv = NULL;
267  ScreenPtr		pScreen = pmap->pScreen;
268  winScreenPriv(pScreen);
269
270#if CYGDEBUG
271  winDebug ("winCreateColormap\n");
272#endif
273
274  /* Allocate colormap privates */
275  if (!winAllocateCmapPrivates (pmap))
276    {
277      ErrorF ("winCreateColorma - Couldn't allocate cmap privates\n");
278      return FALSE;
279    }
280
281  /* Get a pointer to the newly allocated privates */
282  pCmapPriv = winGetCmapPriv (pmap);
283
284  /*
285   * FIXME: This is some evil hackery to help in handling some X clients
286   * that expect the top pixel to be white.  This "help" only lasts until
287   * some client overwrites the top colormap entry.
288   *
289   * We don't want to actually allocate the top entry, as that causes
290   * problems with X clients that need 7 planes (128 colors) in the default
291   * colormap, such as Magic 7.1.
292   */
293  pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbRed = 255;
294  pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbGreen = 255;
295  pCmapPriv->rgbColors[WIN_NUM_PALETTE_ENTRIES - 1].rgbBlue = 255;
296  pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peRed = 255;
297  pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peGreen = 255;
298  pCmapPriv->peColors[WIN_NUM_PALETTE_ENTRIES - 1].peBlue = 255;
299
300  /* Call the engine specific colormap initialization procedure */
301  if (!((*pScreenPriv->pwinCreateColormap) (pmap)))
302    {
303      ErrorF ("winCreateColormap - Engine specific colormap creation "
304	      "procedure failed.  Aborting.\n");
305      return FALSE;
306    }
307
308  return TRUE;
309}
310
311
312/* See Porting Layer Definition - p. 29, 30 */
313static void
314winDestroyColormap (ColormapPtr pColormap)
315{
316  winScreenPriv(pColormap->pScreen);
317  winCmapPriv(pColormap);
318
319  /* Call the engine specific colormap destruction procedure */
320  if (!((*pScreenPriv->pwinDestroyColormap) (pColormap)))
321    {
322      winErrorFVerb (2, "winDestroyColormap - Engine specific colormap destruction "
323	      "procedure failed.  Continuing, but it is possible that memory "
324	      "was leaked, or that colors will be messed up from now on.\n");
325    }
326
327  /* Free the colormap privates */
328  free (pCmapPriv);
329  winSetCmapPriv (pColormap, NULL);
330
331#if CYGDEBUG
332  winDebug ("winDestroyColormap - Returning\n");
333#endif
334}
335
336
337/*
338 * Internal function to load the palette used by the Shadow DIB
339 */
340
341static Bool
342winGetPaletteDIB (ScreenPtr pScreen, ColormapPtr pcmap)
343{
344  winScreenPriv(pScreen);
345  int			i;
346  Pixel			pixel; /* Pixel == CARD32 */
347  CARD16		nRed, nGreen, nBlue; /* CARD16 == unsigned short */
348  UINT			uiColorsRetrieved = 0;
349  RGBQUAD		rgbColors[WIN_NUM_PALETTE_ENTRIES];
350
351  /* Get the color table for the screen */
352  uiColorsRetrieved = GetDIBColorTable (pScreenPriv->hdcScreen,
353					0,
354					WIN_NUM_PALETTE_ENTRIES,
355					rgbColors);
356  if (uiColorsRetrieved == 0)
357    {
358      ErrorF ("winGetPaletteDIB - Could not retrieve screen color table\n");
359      return FALSE;
360    }
361
362#if CYGDEBUG
363  winDebug ("winGetPaletteDIB - Retrieved %d colors from DIB\n",
364	  uiColorsRetrieved);
365#endif
366
367  /* Set the DIB color table to the default screen palette */
368  if (SetDIBColorTable (pScreenPriv->hdcShadow,
369			0,
370			uiColorsRetrieved,
371			rgbColors) == 0)
372    {
373      ErrorF ("winGetPaletteDIB - SetDIBColorTable () failed\n");
374      return FALSE;
375    }
376
377  /* Alloc each color in the DIB color table */
378  for (i = 0; i < uiColorsRetrieved; ++i)
379    {
380      pixel = i;
381
382      /* Extract the color values for current palette entry */
383      nRed = rgbColors[i].rgbRed << 8;
384      nGreen = rgbColors[i].rgbGreen << 8;
385      nBlue = rgbColors[i].rgbBlue << 8;
386
387#if CYGDEBUG
388      winDebug ("winGetPaletteDIB - Allocating a color: %d; "
389	      "%d %d %d\n",
390	      pixel, nRed, nGreen, nBlue);
391#endif
392
393      /* Allocate a entry in the X colormap */
394      if (AllocColor (pcmap,
395		      &nRed,
396		      &nGreen,
397		      &nBlue,
398		      &pixel,
399		      0) != Success)
400	{
401	  ErrorF ("winGetPaletteDIB - AllocColor () failed, pixel %d\n",
402		  i);
403	  return FALSE;
404	}
405
406      if (i != pixel
407	  || nRed != rgbColors[i].rgbRed
408	  || nGreen != rgbColors[i].rgbGreen
409	  || nBlue != rgbColors[i].rgbBlue)
410	{
411	  winDebug ("winGetPaletteDIB - Got: %d; "
412		  "%d %d %d\n",
413		  (int) pixel, nRed, nGreen, nBlue);
414	}
415
416      /* FIXME: Not sure that this bit is needed at all */
417      pcmap->red[i].co.local.red = nRed;
418      pcmap->red[i].co.local.green = nGreen;
419      pcmap->red[i].co.local.blue = nBlue;
420    }
421
422  /* System is using a colormap */
423  /* Set the black and white pixel indices */
424  pScreen->whitePixel = uiColorsRetrieved - 1;
425  pScreen->blackPixel = 0;
426
427  return TRUE;
428}
429
430
431/*
432 * Internal function to load the standard system palette being used by DD
433 */
434
435static Bool
436winGetPaletteDD (ScreenPtr pScreen, ColormapPtr pcmap)
437{
438  int			i;
439  Pixel			pixel; /* Pixel == CARD32 */
440  CARD16		nRed, nGreen, nBlue; /* CARD16 == unsigned short */
441  UINT			uiSystemPaletteEntries;
442  LPPALETTEENTRY	ppeColors = NULL;
443  HDC			hdc = NULL;
444
445  /* Get a DC to obtain the default palette */
446  hdc = GetDC (NULL);
447  if (hdc == NULL)
448    {
449      ErrorF ("winGetPaletteDD - Couldn't get a DC\n");
450      return FALSE;
451    }
452
453  /* Get the number of entries in the system palette */
454  uiSystemPaletteEntries = GetSystemPaletteEntries (hdc,
455						    0, 0, NULL);
456  if (uiSystemPaletteEntries == 0)
457    {
458      ErrorF ("winGetPaletteDD - Unable to determine number of "
459	      "system palette entries\n");
460      return FALSE;
461    }
462
463#if CYGDEBUG
464  winDebug ("winGetPaletteDD - uiSystemPaletteEntries %d\n",
465	  uiSystemPaletteEntries);
466#endif
467
468  /* Allocate palette entries structure */
469  ppeColors = malloc (uiSystemPaletteEntries * sizeof (PALETTEENTRY));
470  if (ppeColors == NULL)
471    {
472      ErrorF ("winGetPaletteDD - malloc () for colormap failed\n");
473      return FALSE;
474    }
475
476  /* Get system palette entries */
477  GetSystemPaletteEntries (hdc,
478			   0, uiSystemPaletteEntries, ppeColors);
479
480  /* Allocate an X colormap entry for every system palette entry */
481  for (i = 0; i < uiSystemPaletteEntries; ++i)
482    {
483      pixel = i;
484
485      /* Extract the color values for current palette entry */
486      nRed = ppeColors[i].peRed << 8;
487      nGreen = ppeColors[i].peGreen << 8;
488      nBlue = ppeColors[i].peBlue << 8;
489#if CYGDEBUG
490      winDebug ("winGetPaletteDD - Allocating a color: %d; "
491	      "%d %d %d\n",
492	      pixel, nRed, nGreen, nBlue);
493#endif
494      if (AllocColor (pcmap,
495		      &nRed,
496		      &nGreen,
497		      &nBlue,
498		      &pixel,
499		      0) != Success)
500	{
501	  ErrorF ("winGetPaletteDD - AllocColor () failed, pixel %d\n",
502		  i);
503	  free (ppeColors);
504	  ppeColors = NULL;
505	  return FALSE;
506	}
507
508      pcmap->red[i].co.local.red = nRed;
509      pcmap->red[i].co.local.green = nGreen;
510      pcmap->red[i].co.local.blue = nBlue;
511    }
512
513  /* System is using a colormap */
514  /* Set the black and white pixel indices */
515  pScreen->whitePixel = uiSystemPaletteEntries - 1;
516  pScreen->blackPixel = 0;
517
518  /* Free colormap */
519  free(ppeColors);
520  ppeColors = NULL;
521
522  /* Free the DC */
523  if (hdc != NULL)
524    {
525      ReleaseDC (NULL, hdc);
526      hdc = NULL;
527    }
528
529  return TRUE;
530}
531
532
533/*
534 * Install the standard fb colormap, or the GDI colormap,
535 * depending on the current screen depth.
536 */
537
538Bool
539winCreateDefColormap (ScreenPtr pScreen)
540{
541  winScreenPriv(pScreen);
542  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
543  unsigned short	zero = 0, ones = 0xFFFF;
544  VisualPtr		pVisual = pScreenPriv->pRootVisual;
545  ColormapPtr		pcmap = NULL;
546  Pixel			wp, bp;
547
548#if CYGDEBUG
549  winDebug ("winCreateDefColormap\n");
550#endif
551
552  /* Use standard fb colormaps for non palettized color modes */
553  if (pScreenInfo->dwBPP > 8)
554    {
555      winDebug ("winCreateDefColormap - Deferring to " \
556	      "fbCreateDefColormap ()\n");
557      return fbCreateDefColormap (pScreen);
558    }
559
560  /*
561   *  AllocAll for non-Dynamic visual classes,
562   *  AllocNone for Dynamic visual classes.
563   */
564
565  /*
566   * Dynamic visual classes allow the colors of the color map
567   * to be changed by clients.
568   */
569
570#if CYGDEBUG
571  winDebug ("winCreateDefColormap - defColormap: %d\n",
572	  pScreen->defColormap);
573#endif
574
575  /* Allocate an X colormap, owned by client 0 */
576  if (CreateColormap (pScreen->defColormap,
577		      pScreen,
578		      pVisual,
579		      &pcmap,
580		      (pVisual->class & DynamicClass) ? AllocNone : AllocAll,
581		      0) != Success)
582    {
583      ErrorF ("winCreateDefColormap - CreateColormap failed\n");
584      return FALSE;
585    }
586  if (pcmap == NULL)
587    {
588      ErrorF ("winCreateDefColormap - Colormap could not be created\n");
589      return FALSE;
590    }
591
592#if CYGDEBUG
593  winDebug ("winCreateDefColormap - Created a colormap\n");
594#endif
595
596  /* Branch on the visual class */
597  if (!(pVisual->class & DynamicClass))
598    {
599      /* Branch on engine type */
600      if (pScreenInfo->dwEngine == WIN_SERVER_SHADOW_GDI)
601	{
602	  /* Load the colors being used by the Shadow DIB */
603	  if (!winGetPaletteDIB (pScreen, pcmap))
604	    {
605	      ErrorF ("winCreateDefColormap - Couldn't get DIB colors\n");
606	      return FALSE;
607	    }
608	}
609      else
610	{
611	  /* Load the colors from the default system palette */
612	  if (!winGetPaletteDD (pScreen, pcmap))
613	    {
614	      ErrorF ("winCreateDefColormap - Couldn't get colors "
615		      "for DD\n");
616	      return FALSE;
617	    }
618	}
619    }
620  else
621    {
622      wp = pScreen->whitePixel;
623      bp = pScreen->blackPixel;
624
625      /* Allocate a black and white pixel */
626      if ((AllocColor (pcmap, &ones, &ones, &ones, &wp, 0) !=
627	   Success)
628	  ||
629	  (AllocColor (pcmap, &zero, &zero, &zero, &bp, 0) !=
630	   Success))
631	{
632	  ErrorF ("winCreateDefColormap - Couldn't allocate bp or wp\n");
633	  return FALSE;
634	}
635
636      pScreen->whitePixel = wp;
637      pScreen->blackPixel = bp;
638
639#if 0
640      /* Have to reserve first 10 and last ten pixels in DirectDraw windowed */
641      if (pScreenInfo->dwEngine != WIN_SERVER_SHADOW_GDI)
642	{
643	  int		k;
644	  Pixel		p;
645
646	  for (k = 1; k < 10; ++k)
647	    {
648	      p = k;
649	      if (AllocColor (pcmap, &ones, &ones, &ones, &p, 0) != Success)
650		FatalError ("Foo!\n");
651	    }
652
653	  for (k = 245; k < 255; ++k)
654	    {
655	      p = k;
656	      if (AllocColor (pcmap, &zero, &zero, &zero, &p, 0) != Success)
657		FatalError ("Baz!\n");
658	    }
659	}
660#endif
661    }
662
663  /* Install the created colormap */
664  (*pScreen->InstallColormap)(pcmap);
665
666#if CYGDEBUG
667  winDebug ("winCreateDefColormap - Returning\n");
668#endif
669
670  return TRUE;
671}
672