winshadgdi.c revision 05b261ec
1/*
2 *Copyright (C) 2001-2004 Harold L Hunt II 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 HAROLD L HUNT II 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 Harold L Hunt II
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 Harold L Hunt II.
27 *
28 * Authors:	Harold L Hunt II
29 */
30
31#ifdef HAVE_XWIN_CONFIG_H
32#include <xwin-config.h>
33#endif
34#include "win.h"
35
36
37/*
38 * External symbols
39 */
40
41#ifdef XWIN_MULTIWINDOW
42extern DWORD			g_dwCurrentThreadID;
43#endif
44extern HWND			g_hDlgExit;
45
46
47/*
48 * Local function prototypes
49 */
50
51#ifdef XWIN_MULTIWINDOW
52static wBOOL CALLBACK
53winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam);
54
55static wBOOL CALLBACK
56winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam);
57#endif
58
59static Bool
60winAllocateFBShadowGDI (ScreenPtr pScreen);
61
62static void
63winShadowUpdateGDI (ScreenPtr pScreen,
64		    shadowBufPtr pBuf);
65
66static Bool
67winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen);
68
69static Bool
70winInitVisualsShadowGDI (ScreenPtr pScreen);
71
72static Bool
73winAdjustVideoModeShadowGDI (ScreenPtr pScreen);
74
75static Bool
76winBltExposedRegionsShadowGDI (ScreenPtr pScreen);
77
78static Bool
79winActivateAppShadowGDI (ScreenPtr pScreen);
80
81static Bool
82winRedrawScreenShadowGDI (ScreenPtr pScreen);
83
84static Bool
85winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen);
86
87static Bool
88winInstallColormapShadowGDI (ColormapPtr pColormap);
89
90static Bool
91winStoreColorsShadowGDI (ColormapPtr pmap,
92			 int ndef,
93			 xColorItem *pdefs);
94
95static Bool
96winCreateColormapShadowGDI (ColormapPtr pColormap);
97
98static Bool
99winDestroyColormapShadowGDI (ColormapPtr pColormap);
100
101
102/*
103 * Internal function to get the DIB format that is compatible with the screen
104 */
105
106static
107Bool
108winQueryScreenDIBFormat (ScreenPtr pScreen, BITMAPINFOHEADER *pbmih)
109{
110  winScreenPriv(pScreen);
111  HBITMAP		hbmp;
112#if CYGDEBUG
113  LPDWORD		pdw = NULL;
114#endif
115
116  /* Create a memory bitmap compatible with the screen */
117  hbmp = CreateCompatibleBitmap (pScreenPriv->hdcScreen, 1, 1);
118  if (hbmp == NULL)
119    {
120      ErrorF ("winQueryScreenDIBFormat - CreateCompatibleBitmap failed\n");
121      return FALSE;
122    }
123
124  /* Initialize our bitmap info header */
125  ZeroMemory (pbmih, sizeof (BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD));
126  pbmih->biSize = sizeof (BITMAPINFOHEADER);
127
128  /* Get the biBitCount */
129  if (!GetDIBits (pScreenPriv->hdcScreen,
130		  hbmp,
131		  0, 1,
132		  NULL,
133		  (BITMAPINFO*) pbmih,
134		  DIB_RGB_COLORS))
135    {
136      ErrorF ("winQueryScreenDIBFormat - First call to GetDIBits failed\n");
137      DeleteObject (hbmp);
138      return FALSE;
139    }
140
141#if CYGDEBUG
142  /* Get a pointer to bitfields */
143  pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER));
144
145  winDebug ("winQueryScreenDIBFormat - First call masks: %08x %08x %08x\n",
146	  pdw[0], pdw[1], pdw[2]);
147#endif
148
149  /* Get optimal color table, or the optimal bitfields */
150  if (!GetDIBits (pScreenPriv->hdcScreen,
151		  hbmp,
152		  0, 1,
153		  NULL,
154		  (BITMAPINFO*)pbmih,
155		  DIB_RGB_COLORS))
156    {
157      ErrorF ("winQueryScreenDIBFormat - Second call to GetDIBits "
158	      "failed\n");
159      DeleteObject (hbmp);
160      return FALSE;
161    }
162
163  /* Free memory */
164  DeleteObject (hbmp);
165
166  return TRUE;
167}
168
169
170/*
171 * Internal function to determine the GDI bits per rgb and bit masks
172 */
173
174static
175Bool
176winQueryRGBBitsAndMasks (ScreenPtr pScreen)
177{
178  winScreenPriv(pScreen);
179  BITMAPINFOHEADER	*pbmih = NULL;
180  Bool			fReturn = TRUE;
181  LPDWORD		pdw = NULL;
182  DWORD			dwRedBits, dwGreenBits, dwBlueBits;
183
184  /* Color masks for 8 bpp are standardized */
185  if (GetDeviceCaps (pScreenPriv->hdcScreen, RASTERCAPS) & RC_PALETTE)
186    {
187      /*
188       * RGB BPP for 8 bit palletes is always 8
189       * and the color masks are always 0.
190       */
191      pScreenPriv->dwBitsPerRGB = 8;
192      pScreenPriv->dwRedMask = 0x0L;
193      pScreenPriv->dwGreenMask = 0x0L;
194      pScreenPriv->dwBlueMask = 0x0L;
195      return TRUE;
196    }
197
198  /* Color masks for 24 bpp are standardized */
199  if (GetDeviceCaps (pScreenPriv->hdcScreen, PLANES)
200      * GetDeviceCaps (pScreenPriv->hdcScreen, BITSPIXEL) == 24)
201    {
202      ErrorF ("winQueryRGBBitsAndMasks - GetDeviceCaps (BITSPIXEL) "
203	      "returned 24 for the screen.  Using default 24bpp masks.\n");
204
205      /* 8 bits per primary color */
206      pScreenPriv->dwBitsPerRGB = 8;
207
208      /* Set screen privates masks */
209      pScreenPriv->dwRedMask = WIN_24BPP_MASK_RED;
210      pScreenPriv->dwGreenMask = WIN_24BPP_MASK_GREEN;
211      pScreenPriv->dwBlueMask = WIN_24BPP_MASK_BLUE;
212
213      return TRUE;
214    }
215
216  /* Allocate a bitmap header and color table */
217  pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER)
218				      + 256  * sizeof (RGBQUAD));
219  if (pbmih == NULL)
220    {
221      ErrorF ("winQueryRGBBitsAndMasks - malloc failed\n");
222      return FALSE;
223    }
224
225  /* Get screen description */
226  if (winQueryScreenDIBFormat (pScreen, pbmih))
227    {
228      /* Get a pointer to bitfields */
229      pdw = (DWORD*) ((CARD8*)pbmih + sizeof (BITMAPINFOHEADER));
230
231#if CYGDEBUG
232      winDebug ("%s - Masks: %08x %08x %08x\n", __FUNCTION__,
233	      pdw[0], pdw[1], pdw[2]);
234      winDebug ("%s - Bitmap: %dx%d %d bpp %d planes\n", __FUNCTION__,
235              pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount, pbmih->biPlanes);
236      winDebug ("%s - Compression: %d %s\n", __FUNCTION__,
237              pbmih->biCompression,
238              (pbmih->biCompression == BI_RGB?"(BI_RGB)":
239               (pbmih->biCompression == BI_RLE8?"(BI_RLE8)":
240                (pbmih->biCompression == BI_RLE4?"(BI_RLE4)":
241                 (pbmih->biCompression == BI_BITFIELDS?"(BI_BITFIELDS)":""
242                 )))));
243#endif
244
245      /* Handle BI_RGB case, which is returned by Wine */
246      if (pbmih->biCompression == BI_RGB)
247        {
248	  dwRedBits = 5;
249	  dwGreenBits = 5;
250	  dwBlueBits = 5;
251
252	  pScreenPriv->dwBitsPerRGB = 5;
253
254	  /* Set screen privates masks */
255	  pScreenPriv->dwRedMask = 0x7c00;
256	  pScreenPriv->dwGreenMask = 0x03e0;
257	  pScreenPriv->dwBlueMask = 0x001f;
258        }
259      else
260        {
261          /* Count the number of bits in each mask */
262          dwRedBits = winCountBits (pdw[0]);
263          dwGreenBits = winCountBits (pdw[1]);
264          dwBlueBits = winCountBits (pdw[2]);
265
266	  /* Find maximum bits per red, green, blue */
267	  if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits)
268	    pScreenPriv->dwBitsPerRGB = dwRedBits;
269	  else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits)
270	    pScreenPriv->dwBitsPerRGB = dwGreenBits;
271	  else
272	    pScreenPriv->dwBitsPerRGB = dwBlueBits;
273
274	  /* Set screen privates masks */
275	  pScreenPriv->dwRedMask = pdw[0];
276	  pScreenPriv->dwGreenMask = pdw[1];
277	  pScreenPriv->dwBlueMask = pdw[2];
278	}
279    }
280  else
281    {
282      ErrorF ("winQueryRGBBitsAndMasks - winQueryScreenDIBFormat failed\n");
283      free (pbmih);
284      fReturn = FALSE;
285    }
286
287  /* Free memory */
288  free (pbmih);
289
290  return fReturn;
291}
292
293
294#ifdef XWIN_MULTIWINDOW
295/*
296 * Redraw all ---?
297 */
298
299static wBOOL CALLBACK
300winRedrawAllProcShadowGDI (HWND hwnd, LPARAM lParam)
301{
302  if (hwnd == (HWND)lParam)
303    return TRUE;
304  InvalidateRect (hwnd, NULL, FALSE);
305  UpdateWindow (hwnd);
306  return TRUE;
307}
308
309static wBOOL CALLBACK
310winRedrawDamagedWindowShadowGDI (HWND hwnd, LPARAM lParam)
311{
312  BoxPtr pDamage = (BoxPtr)lParam;
313  RECT rcClient, rcDamage, rcRedraw;
314  POINT topLeft, bottomRight;
315
316  if (IsIconic (hwnd))
317    return TRUE; /* Don't care minimized windows */
318
319  /* Convert the damaged area from Screen coords to Client coords */
320  topLeft.x = pDamage->x1; topLeft.y = pDamage->y1;
321  bottomRight.x = pDamage->x2; bottomRight.y = pDamage->y2;
322  topLeft.x += GetSystemMetrics (SM_XVIRTUALSCREEN);
323  bottomRight.x += GetSystemMetrics (SM_XVIRTUALSCREEN);
324  topLeft.y += GetSystemMetrics (SM_YVIRTUALSCREEN);
325  bottomRight.y += GetSystemMetrics (SM_YVIRTUALSCREEN);
326  ScreenToClient (hwnd, &topLeft);
327  ScreenToClient (hwnd, &bottomRight);
328  SetRect (&rcDamage, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
329
330  GetClientRect (hwnd, &rcClient);
331
332  if (IntersectRect (&rcRedraw, &rcClient, &rcDamage))
333    {
334      InvalidateRect (hwnd, &rcRedraw, FALSE);
335      UpdateWindow (hwnd);
336    }
337  return TRUE;
338}
339#endif
340
341
342/*
343 * Allocate a DIB for the shadow framebuffer GDI server
344 */
345
346static Bool
347winAllocateFBShadowGDI (ScreenPtr pScreen)
348{
349  winScreenPriv(pScreen);
350  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
351  BITMAPINFOHEADER	*pbmih = NULL;
352  DIBSECTION		dibsection;
353  Bool			fReturn = TRUE;
354
355  /* Get device contexts for the screen and shadow bitmap */
356  pScreenPriv->hdcScreen = GetDC (pScreenPriv->hwndScreen);
357  pScreenPriv->hdcShadow = CreateCompatibleDC (pScreenPriv->hdcScreen);
358
359  /* Allocate bitmap info header */
360  pbmih = (BITMAPINFOHEADER*) malloc (sizeof (BITMAPINFOHEADER)
361				      + 256 * sizeof (RGBQUAD));
362  if (pbmih == NULL)
363    {
364      ErrorF ("winAllocateFBShadowGDI - malloc () failed\n");
365      return FALSE;
366    }
367
368  /* Query the screen format */
369  fReturn = winQueryScreenDIBFormat (pScreen, pbmih);
370
371  /* Describe shadow bitmap to be created */
372  pbmih->biWidth = pScreenInfo->dwWidth;
373  pbmih->biHeight = -pScreenInfo->dwHeight;
374
375  ErrorF ("winAllocateFBShadowGDI - Creating DIB with width: %d height: %d "
376	  "depth: %d\n",
377	  (int) pbmih->biWidth, (int) -pbmih->biHeight, pbmih->biBitCount);
378
379  /* Create a DI shadow bitmap with a bit pointer */
380  pScreenPriv->hbmpShadow = CreateDIBSection (pScreenPriv->hdcScreen,
381					      (BITMAPINFO *) pbmih,
382					      DIB_RGB_COLORS,
383					      (VOID**) &pScreenInfo->pfb,
384					      NULL,
385					      0);
386  if (pScreenPriv->hbmpShadow == NULL || pScreenInfo->pfb == NULL)
387    {
388      winW32Error (2, "winAllocateFBShadowGDI - CreateDIBSection failed:");
389      return FALSE;
390    }
391  else
392    {
393#if CYGDEBUG
394      winDebug ("winAllocateFBShadowGDI - Shadow buffer allocated\n");
395#endif
396    }
397
398  /* Get information about the bitmap that was allocated */
399  GetObject (pScreenPriv->hbmpShadow,
400	     sizeof (dibsection),
401	     &dibsection);
402
403#if CYGDEBUG || YES
404  /* Print information about bitmap allocated */
405  winDebug ("winAllocateFBShadowGDI - Dibsection width: %d height: %d "
406	  "depth: %d size image: %d\n",
407	  (int) dibsection.dsBmih.biWidth, (int) dibsection.dsBmih.biHeight,
408	  dibsection.dsBmih.biBitCount,
409	  (int) dibsection.dsBmih.biSizeImage);
410#endif
411
412  /* Select the shadow bitmap into the shadow DC */
413  SelectObject (pScreenPriv->hdcShadow,
414		pScreenPriv->hbmpShadow);
415
416#if CYGDEBUG
417  winDebug ("winAllocateFBShadowGDI - Attempting a shadow blit\n");
418#endif
419
420  /* Do a test blit from the shadow to the screen, I think */
421  fReturn = BitBlt (pScreenPriv->hdcScreen,
422		    0, 0,
423		    pScreenInfo->dwWidth, pScreenInfo->dwHeight,
424		    pScreenPriv->hdcShadow,
425		    0, 0,
426		    SRCCOPY);
427  if (fReturn)
428    {
429#if CYGDEBUG
430      winDebug ("winAllocateFBShadowGDI - Shadow blit success\n");
431#endif
432    }
433  else
434    {
435      winW32Error (2, "winAllocateFBShadowGDI - Shadow blit failure\n");
436#if 0
437      return FALSE;
438#else
439      /* ago: ignore this error. The blit fails with wine, but does not
440       * cause any problems later. */
441
442      fReturn = TRUE;
443#endif
444    }
445
446  /* Look for height weirdness */
447  if (dibsection.dsBmih.biHeight < 0)
448    {
449      dibsection.dsBmih.biHeight = -dibsection.dsBmih.biHeight;
450    }
451
452  /* Set screeninfo stride */
453  pScreenInfo->dwStride = ((dibsection.dsBmih.biSizeImage
454			    / dibsection.dsBmih.biHeight)
455			   * 8) / pScreenInfo->dwBPP;
456
457#if CYGDEBUG || YES
458  winDebug ("winAllocateFBShadowGDI - Created shadow stride: %d\n",
459	  (int) pScreenInfo->dwStride);
460#endif
461
462  /* See if the shadow bitmap will be larger than the DIB size limit */
463  if (pScreenInfo->dwWidth * pScreenInfo->dwHeight * pScreenInfo->dwBPP
464      >= WIN_DIB_MAXIMUM_SIZE)
465    {
466      ErrorF ("winAllocateFBShadowGDI - Requested DIB (bitmap) "
467	      "will be larger than %d MB.  The surface may fail to be "
468	      "allocated on Windows 95, 98, or Me, due to a %d MB limit in "
469	      "DIB size.  This limit does not apply to Windows NT/2000, and "
470	      "this message may be ignored on those platforms.\n",
471	      WIN_DIB_MAXIMUM_SIZE_MB, WIN_DIB_MAXIMUM_SIZE_MB);
472    }
473
474  /* Determine our color masks */
475  if (!winQueryRGBBitsAndMasks (pScreen))
476    {
477      ErrorF ("winAllocateFBShadowGDI - winQueryRGBBitsAndMasks failed\n");
478      return FALSE;
479    }
480
481#ifdef XWIN_MULTIWINDOW
482  /* Redraw all windows */
483  if (pScreenInfo->fMultiWindow)
484    EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0);
485#endif
486
487  return fReturn;
488}
489
490
491/*
492 * Blit the damaged regions of the shadow fb to the screen
493 */
494
495static void
496winShadowUpdateGDI (ScreenPtr pScreen,
497		    shadowBufPtr pBuf)
498{
499  winScreenPriv(pScreen);
500  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
501  RegionPtr		damage = &pBuf->damage;
502  DWORD			dwBox = REGION_NUM_RECTS (damage);
503  BoxPtr		pBox = REGION_RECTS (damage);
504  int			x, y, w, h;
505  HRGN			hrgnTemp = NULL, hrgnCombined = NULL;
506#ifdef XWIN_UPDATESTATS
507  static DWORD		s_dwNonUnitRegions = 0;
508  static DWORD		s_dwTotalUpdates = 0;
509  static DWORD		s_dwTotalBoxes = 0;
510#endif
511  BoxPtr		pBoxExtents = REGION_EXTENTS (pScreen, damage);
512
513  /*
514   * Return immediately if the app is not active
515   * and we are fullscreen, or if we have a bad display depth
516   */
517  if ((!pScreenPriv->fActive && pScreenInfo->fFullScreen)
518      || pScreenPriv->fBadDepth) return;
519
520#ifdef XWIN_UPDATESTATS
521  ++s_dwTotalUpdates;
522  s_dwTotalBoxes += dwBox;
523
524  if (dwBox != 1)
525    {
526      ++s_dwNonUnitRegions;
527      ErrorF ("winShadowUpdatGDI - dwBox: %d\n", dwBox);
528    }
529
530  if ((s_dwTotalUpdates % 100) == 0)
531    ErrorF ("winShadowUpdateGDI - %d%% non-unity regions, avg boxes: %d "
532	    "nu: %d tu: %d\n",
533	    (s_dwNonUnitRegions * 100) / s_dwTotalUpdates,
534	    s_dwTotalBoxes / s_dwTotalUpdates,
535	    s_dwNonUnitRegions, s_dwTotalUpdates);
536#endif /* XWIN_UPDATESTATS */
537
538  /*
539   * Handle small regions with multiple blits,
540   * handle large regions by creating a clipping region and
541   * doing a single blit constrained to that clipping region.
542   */
543  if (!pScreenInfo->fMultiWindow &&
544      (pScreenInfo->dwClipUpdatesNBoxes == 0 ||
545      dwBox < pScreenInfo->dwClipUpdatesNBoxes))
546    {
547      /* Loop through all boxes in the damaged region */
548      while (dwBox--)
549	{
550	  /*
551	   * Calculate x offset, y offset, width, and height for
552	   * current damage box
553	   */
554	  x = pBox->x1;
555	  y = pBox->y1;
556	  w = pBox->x2 - pBox->x1;
557	  h = pBox->y2 - pBox->y1;
558
559	  BitBlt (pScreenPriv->hdcScreen,
560		  x, y,
561		  w, h,
562		  pScreenPriv->hdcShadow,
563		  x, y,
564		  SRCCOPY);
565
566	  /* Get a pointer to the next box */
567	  ++pBox;
568	}
569    }
570  else if (!pScreenInfo->fMultiWindow)
571    {
572      /* Compute a GDI region from the damaged region */
573      hrgnCombined = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2);
574      dwBox--;
575      pBox++;
576      while (dwBox--)
577	{
578	  hrgnTemp = CreateRectRgn (pBox->x1, pBox->y1, pBox->x2, pBox->y2);
579	  CombineRgn (hrgnCombined, hrgnCombined, hrgnTemp, RGN_OR);
580	  DeleteObject (hrgnTemp);
581	  pBox++;
582	}
583
584      /* Install the GDI region as a clipping region */
585      SelectClipRgn (pScreenPriv->hdcScreen, hrgnCombined);
586      DeleteObject (hrgnCombined);
587      hrgnCombined = NULL;
588
589      /*
590       * Blit the shadow buffer to the screen,
591       * constrained to the clipping region.
592       */
593      BitBlt (pScreenPriv->hdcScreen,
594	      pBoxExtents->x1, pBoxExtents->y1,
595	      pBoxExtents->x2 - pBoxExtents->x1,
596	      pBoxExtents->y2 - pBoxExtents->y1,
597	      pScreenPriv->hdcShadow,
598	      pBoxExtents->x1, pBoxExtents->y1,
599	      SRCCOPY);
600
601      /* Reset the clip region */
602      SelectClipRgn (pScreenPriv->hdcScreen, NULL);
603    }
604
605#ifdef XWIN_MULTIWINDOW
606  /* Redraw all multiwindow windows */
607  if (pScreenInfo->fMultiWindow)
608    EnumThreadWindows (g_dwCurrentThreadID,
609		       winRedrawDamagedWindowShadowGDI,
610		       (LPARAM)pBoxExtents);
611#endif
612}
613
614
615/* See Porting Layer Definition - p. 33 */
616/*
617 * We wrap whatever CloseScreen procedure was specified by fb;
618 * a pointer to said procedure is stored in our privates.
619 */
620
621static Bool
622winCloseScreenShadowGDI (int nIndex, ScreenPtr pScreen)
623{
624  winScreenPriv(pScreen);
625  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
626  Bool			fReturn;
627
628#if CYGDEBUG
629  winDebug ("winCloseScreenShadowGDI - Freeing screen resources\n");
630#endif
631
632  /* Flag that the screen is closed */
633  pScreenPriv->fClosed = TRUE;
634  pScreenPriv->fActive = FALSE;
635
636  /* Call the wrapped CloseScreen procedure */
637  WIN_UNWRAP(CloseScreen);
638  fReturn = (*pScreen->CloseScreen) (nIndex, pScreen);
639
640  /* Delete the window property */
641  RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP);
642
643  /* Free the shadow DC; which allows the bitmap to be freed */
644  DeleteDC (pScreenPriv->hdcShadow);
645
646  /* Free the shadow bitmap */
647  DeleteObject (pScreenPriv->hbmpShadow);
648
649  /* Free the screen DC */
650  ReleaseDC (pScreenPriv->hwndScreen, pScreenPriv->hdcScreen);
651
652  /* Delete tray icon, if we have one */
653  if (!pScreenInfo->fNoTrayIcon)
654    winDeleteNotifyIcon (pScreenPriv);
655
656  /* Free the exit confirmation dialog box, if it exists */
657  if (g_hDlgExit != NULL)
658    {
659      DestroyWindow (g_hDlgExit);
660      g_hDlgExit = NULL;
661    }
662
663  /* Kill our window */
664  if (pScreenPriv->hwndScreen)
665    {
666      DestroyWindow (pScreenPriv->hwndScreen);
667      pScreenPriv->hwndScreen = NULL;
668    }
669
670#if defined(XWIN_CLIPBOARD) || defined(XWIN_MULTIWINDOW)
671  /* Destroy the thread startup mutex */
672  pthread_mutex_destroy (&pScreenPriv->pmServerStarted);
673#endif
674
675  /* Invalidate our screeninfo's pointer to the screen */
676  pScreenInfo->pScreen = NULL;
677
678  /* Invalidate the ScreenInfo's fb pointer */
679  pScreenInfo->pfb = NULL;
680
681  /* Free the screen privates for this screen */
682  free ((pointer) pScreenPriv);
683
684  return fReturn;
685}
686
687
688/*
689 * Tell mi what sort of visuals we need.
690 *
691 * Generally we only need one visual, as our screen can only
692 * handle one format at a time, I believe.  You may want
693 * to verify that last sentence.
694 */
695
696static Bool
697winInitVisualsShadowGDI (ScreenPtr pScreen)
698{
699  winScreenPriv(pScreen);
700  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
701
702  /* Display debugging information */
703  ErrorF ("winInitVisualsShadowGDI - Masks %08x %08x %08x BPRGB %d d %d "
704	  "bpp %d\n",
705	  (unsigned int) pScreenPriv->dwRedMask,
706	  (unsigned int) pScreenPriv->dwGreenMask,
707	  (unsigned int) pScreenPriv->dwBlueMask,
708	  (int) pScreenPriv->dwBitsPerRGB,
709	  (int) pScreenInfo->dwDepth,
710	  (int) pScreenInfo->dwBPP);
711
712  /* Create a single visual according to the Windows screen depth */
713  switch (pScreenInfo->dwDepth)
714    {
715    case 24:
716    case 16:
717    case 15:
718#if defined(XFree86Server)
719      /* Setup the real visual */
720      if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth,
721				     TrueColorMask,
722				     pScreenPriv->dwBitsPerRGB,
723				     -1,
724				     pScreenPriv->dwRedMask,
725				     pScreenPriv->dwGreenMask,
726				     pScreenPriv->dwBlueMask))
727	{
728	  ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks "
729		  "failed\n");
730	  return FALSE;
731	}
732
733#ifdef XWIN_EMULATEPSEUDO
734      if (!pScreenInfo->fEmulatePseudo)
735	break;
736
737      /* Setup a pseudocolor visual */
738      if (!miSetVisualTypesAndMasks (8,
739				     PseudoColorMask,
740				     8,
741				     -1,
742				     0,
743				     0,
744				     0))
745	{
746	  ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks "
747		  "failed for PseudoColor\n");
748	  return FALSE;
749	}
750#endif
751#else /* XFree86Server */
752      /* Setup the real visual */
753      if (!fbSetVisualTypesAndMasks (pScreenInfo->dwDepth,
754				     TrueColorMask,
755				     pScreenPriv->dwBitsPerRGB,
756				     pScreenPriv->dwRedMask,
757				     pScreenPriv->dwGreenMask,
758				     pScreenPriv->dwBlueMask))
759	{
760	  ErrorF ("winInitVisualsShadowGDI - fbSetVisualTypesAndMasks "
761		  "failed for TrueColor\n");
762	  return FALSE;
763	}
764
765#ifdef XWIN_EMULATEPSEUDO
766      if (!pScreenInfo->fEmulatePseudo)
767	break;
768
769      /* Setup a pseudocolor visual */
770      if (!fbSetVisualTypesAndMasks (8,
771				     PseudoColorMask,
772				     8,
773				     0,
774				     0,
775				     0))
776	{
777	  ErrorF ("winInitVisualsShadowGDI - fbSetVisualTypesAndMasks "
778		  "failed for PseudoColor\n");
779	  return FALSE;
780	}
781#endif
782#endif /* XFree86Server */
783      break;
784
785    case 8:
786#if defined(XFree86Server)
787      if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth,
788				     PseudoColorMask,
789				     pScreenPriv->dwBitsPerRGB,
790				     PseudoColor,
791				     pScreenPriv->dwRedMask,
792				     pScreenPriv->dwGreenMask,
793				     pScreenPriv->dwBlueMask))
794	{
795	  ErrorF ("winInitVisualsShadowGDI - miSetVisualTypesAndMasks "
796		  "failed\n");
797	  return FALSE;
798	}
799#else /* XFree86Server */
800      if (!fbSetVisualTypesAndMasks (pScreenInfo->dwDepth,
801				     PseudoColorMask,
802				     pScreenPriv->dwBitsPerRGB,
803				     pScreenPriv->dwRedMask,
804				     pScreenPriv->dwGreenMask,
805				     pScreenPriv->dwBlueMask))
806	{
807	  ErrorF ("winInitVisualsShadowGDI - fbSetVisualTypesAndMasks "
808		  "failed\n");
809	  return FALSE;
810	}
811#endif
812      break;
813
814    default:
815      ErrorF ("winInitVisualsShadowGDI - Unknown screen depth\n");
816      return FALSE;
817    }
818
819#if CYGDEBUG
820  winDebug ("winInitVisualsShadowGDI - Returning\n");
821#endif
822
823  return TRUE;
824}
825
826
827/*
828 * Adjust the proposed video mode
829 */
830
831static Bool
832winAdjustVideoModeShadowGDI (ScreenPtr pScreen)
833{
834  winScreenPriv(pScreen);
835  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
836  HDC			hdc;
837  DWORD			dwBPP;
838
839  hdc = GetDC (NULL);
840
841  /* We're in serious trouble if we can't get a DC */
842  if (hdc == NULL)
843    {
844      ErrorF ("winAdjustVideoModeShadowGDI - GetDC () failed\n");
845      return FALSE;
846    }
847
848  /* Query GDI for current display depth */
849  dwBPP = GetDeviceCaps (hdc, BITSPIXEL);
850
851  /* GDI cannot change the screen depth */
852  if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP)
853    {
854      /* No -depth parameter passed, let the user know the depth being used */
855      ErrorF ("winAdjustVideoModeShadowGDI - Using Windows display "
856	      "depth of %d bits per pixel\n", (int) dwBPP);
857
858      /* Use GDI's depth */
859      pScreenInfo->dwBPP = dwBPP;
860    }
861  else if (dwBPP != pScreenInfo->dwBPP)
862    {
863      /* Warn user if GDI depth is different than -depth parameter */
864      ErrorF ("winAdjustVideoModeShadowGDI - Command line bpp: %d, "\
865	      "using bpp: %d\n", (int) pScreenInfo->dwBPP, (int) dwBPP);
866
867      /* We'll use GDI's depth */
868      pScreenInfo->dwBPP = dwBPP;
869    }
870
871  /* Release our DC */
872  ReleaseDC (NULL, hdc);
873  hdc = NULL;
874
875  return TRUE;
876}
877
878
879/*
880 * Blt exposed regions to the screen
881 */
882
883static Bool
884winBltExposedRegionsShadowGDI (ScreenPtr pScreen)
885{
886  winScreenPriv(pScreen);
887  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
888  winPrivCmapPtr	pCmapPriv = NULL;
889  HDC			hdcUpdate;
890  PAINTSTRUCT		ps;
891
892  /* BeginPaint gives us an hdc that clips to the invalidated region */
893  hdcUpdate = BeginPaint (pScreenPriv->hwndScreen, &ps);
894
895  /* Realize the palette, if we have one */
896  if (pScreenPriv->pcmapInstalled != NULL)
897    {
898      pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled);
899
900      SelectPalette (hdcUpdate, pCmapPriv->hPalette, FALSE);
901      RealizePalette (hdcUpdate);
902    }
903
904  /* Our BitBlt will be clipped to the invalidated region */
905  BitBlt (hdcUpdate,
906	  0, 0,
907	  pScreenInfo->dwWidth, pScreenInfo->dwHeight,
908	  pScreenPriv->hdcShadow,
909	  0, 0,
910	  SRCCOPY);
911
912  /* EndPaint frees the DC */
913  EndPaint (pScreenPriv->hwndScreen, &ps);
914
915#ifdef XWIN_MULTIWINDOW
916  /* Redraw all windows */
917  if (pScreenInfo->fMultiWindow)
918    EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI,
919            (LPARAM)pScreenPriv->hwndScreen);
920#endif
921
922  return TRUE;
923}
924
925
926/*
927 * Do any engine-specific appliation-activation processing
928 */
929
930static Bool
931winActivateAppShadowGDI (ScreenPtr pScreen)
932{
933  winScreenPriv(pScreen);
934  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
935
936  /*
937   * 2004/04/12 - Harold - We perform the restoring or minimizing
938   * manually for ShadowGDI in fullscreen modes so that this engine
939   * will perform just like ShadowDD and ShadowDDNL in fullscreen mode;
940   * if we do not do this then our fullscreen window will appear in the
941   * z-order when it is deactivated and it can be uncovered by resizing
942   * or minimizing another window that is on top of it, which is not how
943   * the DirectDraw engines work.  Therefore we keep this code here to
944   * make sure that all engines work the same in fullscreen mode.
945   */
946
947  /*
948   * Are we active?
949   * Are we fullscreen?
950   */
951  if (pScreenPriv->fActive
952      && pScreenInfo->fFullScreen)
953    {
954      /*
955       * Activating, attempt to bring our window
956       * to the top of the display
957       */
958      ShowWindow (pScreenPriv->hwndScreen, SW_RESTORE);
959    }
960  else if (!pScreenPriv->fActive
961	   && pScreenInfo->fFullScreen)
962    {
963      /*
964       * Deactivating, stuff our window onto the
965       * task bar.
966       */
967      ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE);
968    }
969
970  return TRUE;
971}
972
973
974/*
975 * Reblit the shadow framebuffer to the screen.
976 */
977
978static Bool
979winRedrawScreenShadowGDI (ScreenPtr pScreen)
980{
981  winScreenPriv(pScreen);
982  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
983
984  /* Redraw the whole window, to take account for the new colors */
985  BitBlt (pScreenPriv->hdcScreen,
986	  0, 0,
987	  pScreenInfo->dwWidth, pScreenInfo->dwHeight,
988	  pScreenPriv->hdcShadow,
989	  0, 0,
990	  SRCCOPY);
991
992#ifdef XWIN_MULTIWINDOW
993  /* Redraw all windows */
994  if (pScreenInfo->fMultiWindow)
995    EnumThreadWindows(g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0);
996#endif
997
998  return TRUE;
999}
1000
1001
1002
1003/*
1004 * Realize the currently installed colormap
1005 */
1006
1007static Bool
1008winRealizeInstalledPaletteShadowGDI (ScreenPtr pScreen)
1009{
1010  winScreenPriv(pScreen);
1011  winPrivCmapPtr	pCmapPriv = NULL;
1012
1013#if CYGDEBUG
1014  winDebug ("winRealizeInstalledPaletteShadowGDI\n");
1015#endif
1016
1017  /* Don't do anything if there is not a colormap */
1018  if (pScreenPriv->pcmapInstalled == NULL)
1019    {
1020#if CYGDEBUG
1021      winDebug ("winRealizeInstalledPaletteShadowGDI - No colormap "
1022	      "installed\n");
1023#endif
1024      return TRUE;
1025    }
1026
1027  pCmapPriv = winGetCmapPriv (pScreenPriv->pcmapInstalled);
1028
1029  /* Realize our palette for the screen */
1030  if (RealizePalette (pScreenPriv->hdcScreen) == GDI_ERROR)
1031    {
1032      ErrorF ("winRealizeInstalledPaletteShadowGDI - RealizePalette () "
1033	      "failed\n");
1034      return FALSE;
1035    }
1036
1037  /* Set the DIB color table */
1038  if (SetDIBColorTable (pScreenPriv->hdcShadow,
1039			0,
1040			WIN_NUM_PALETTE_ENTRIES,
1041			pCmapPriv->rgbColors) == 0)
1042    {
1043      ErrorF ("winRealizeInstalledPaletteShadowGDI - SetDIBColorTable () "
1044	      "failed\n");
1045      return FALSE;
1046    }
1047
1048  return TRUE;
1049}
1050
1051
1052/*
1053 * Install the specified colormap
1054 */
1055
1056static Bool
1057winInstallColormapShadowGDI (ColormapPtr pColormap)
1058{
1059  ScreenPtr		pScreen = pColormap->pScreen;
1060  winScreenPriv(pScreen);
1061  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
1062  winCmapPriv(pColormap);
1063
1064  /*
1065   * Tell Windows to install the new colormap
1066   */
1067  if (SelectPalette (pScreenPriv->hdcScreen,
1068		     pCmapPriv->hPalette,
1069		     FALSE) == NULL)
1070    {
1071      ErrorF ("winInstallColormapShadowGDI - SelectPalette () failed\n");
1072      return FALSE;
1073    }
1074
1075  /* Realize the palette */
1076  if (GDI_ERROR == RealizePalette (pScreenPriv->hdcScreen))
1077    {
1078      ErrorF ("winInstallColormapShadowGDI - RealizePalette () failed\n");
1079      return FALSE;
1080    }
1081
1082  /* Set the DIB color table */
1083  if (SetDIBColorTable (pScreenPriv->hdcShadow,
1084			0,
1085			WIN_NUM_PALETTE_ENTRIES,
1086			pCmapPriv->rgbColors) == 0)
1087    {
1088      ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n");
1089      return FALSE;
1090    }
1091
1092  /* Redraw the whole window, to take account for the new colors */
1093  BitBlt (pScreenPriv->hdcScreen,
1094	  0, 0,
1095	  pScreenInfo->dwWidth, pScreenInfo->dwHeight,
1096	  pScreenPriv->hdcShadow,
1097	  0, 0,
1098	  SRCCOPY);
1099
1100  /* Save a pointer to the newly installed colormap */
1101  pScreenPriv->pcmapInstalled = pColormap;
1102
1103#ifdef XWIN_MULTIWINDOW
1104  /* Redraw all windows */
1105  if (pScreenInfo->fMultiWindow)
1106    EnumThreadWindows (g_dwCurrentThreadID, winRedrawAllProcShadowGDI, 0);
1107#endif
1108
1109  return TRUE;
1110}
1111
1112
1113/*
1114 * Store the specified colors in the specified colormap
1115 */
1116
1117static Bool
1118winStoreColorsShadowGDI (ColormapPtr pColormap,
1119			 int ndef,
1120			 xColorItem *pdefs)
1121{
1122  ScreenPtr		pScreen = pColormap->pScreen;
1123  winScreenPriv(pScreen);
1124  winCmapPriv(pColormap);
1125  ColormapPtr curpmap = pScreenPriv->pcmapInstalled;
1126
1127  /* Put the X colormap entries into the Windows logical palette */
1128  if (SetPaletteEntries (pCmapPriv->hPalette,
1129			 pdefs[0].pixel,
1130			 ndef,
1131			 pCmapPriv->peColors + pdefs[0].pixel) == 0)
1132    {
1133      ErrorF ("winStoreColorsShadowGDI - SetPaletteEntries () failed\n");
1134      return FALSE;
1135    }
1136
1137  /* Don't install the Windows palette if the colormap is not installed */
1138  if (pColormap != curpmap)
1139    {
1140      return TRUE;
1141    }
1142
1143  /* Try to install the newly modified colormap */
1144  if (!winInstallColormapShadowGDI (pColormap))
1145    {
1146      ErrorF ("winInstallColormapShadowGDI - winInstallColormapShadowGDI "
1147	      "failed\n");
1148      return FALSE;
1149    }
1150
1151#if 0
1152  /* Tell Windows that the palette has changed */
1153  RealizePalette (pScreenPriv->hdcScreen);
1154
1155  /* Set the DIB color table */
1156  if (SetDIBColorTable (pScreenPriv->hdcShadow,
1157			pdefs[0].pixel,
1158			ndef,
1159			pCmapPriv->rgbColors + pdefs[0].pixel) == 0)
1160    {
1161      ErrorF ("winInstallColormapShadowGDI - SetDIBColorTable () failed\n");
1162      return FALSE;
1163    }
1164
1165  /* Save a pointer to the newly installed colormap */
1166  pScreenPriv->pcmapInstalled = pColormap;
1167#endif
1168
1169  return TRUE;
1170}
1171
1172
1173/*
1174 * Colormap initialization procedure
1175 */
1176
1177static Bool
1178winCreateColormapShadowGDI (ColormapPtr pColormap)
1179{
1180  LPLOGPALETTE		lpPaletteNew = NULL;
1181  DWORD			dwEntriesMax;
1182  VisualPtr		pVisual;
1183  HPALETTE		hpalNew = NULL;
1184  winCmapPriv(pColormap);
1185
1186  /* Get a pointer to the visual that the colormap belongs to */
1187  pVisual = pColormap->pVisual;
1188
1189  /* Get the maximum number of palette entries for this visual */
1190  dwEntriesMax = pVisual->ColormapEntries;
1191
1192  /* Allocate a Windows logical color palette with max entries */
1193  lpPaletteNew = malloc (sizeof (LOGPALETTE)
1194			 + (dwEntriesMax - 1) * sizeof (PALETTEENTRY));
1195  if (lpPaletteNew == NULL)
1196    {
1197      ErrorF ("winCreateColormapShadowGDI - Couldn't allocate palette "
1198	      "with %d entries\n",
1199	      (int) dwEntriesMax);
1200      return FALSE;
1201    }
1202
1203  /* Zero out the colormap */
1204  ZeroMemory (lpPaletteNew, sizeof (LOGPALETTE)
1205	      + (dwEntriesMax - 1) * sizeof (PALETTEENTRY));
1206
1207  /* Set the logical palette structure */
1208  lpPaletteNew->palVersion = 0x0300;
1209  lpPaletteNew->palNumEntries = dwEntriesMax;
1210
1211  /* Tell Windows to create the palette */
1212  hpalNew = CreatePalette (lpPaletteNew);
1213  if (hpalNew == NULL)
1214    {
1215      ErrorF ("winCreateColormapShadowGDI - CreatePalette () failed\n");
1216      free (lpPaletteNew);
1217      return FALSE;
1218    }
1219
1220  /* Save the Windows logical palette handle in the X colormaps' privates */
1221  pCmapPriv->hPalette = hpalNew;
1222
1223  /* Free the palette initialization memory */
1224  free (lpPaletteNew);
1225
1226  return TRUE;
1227}
1228
1229
1230/*
1231 * Colormap destruction procedure
1232 */
1233
1234static Bool
1235winDestroyColormapShadowGDI (ColormapPtr pColormap)
1236{
1237  winScreenPriv(pColormap->pScreen);
1238  winCmapPriv(pColormap);
1239
1240  /*
1241   * Is colormap to be destroyed the default?
1242   *
1243   * Non-default colormaps should have had winUninstallColormap
1244   * called on them before we get here.  The default colormap
1245   * will not have had winUninstallColormap called on it.  Thus,
1246   * we need to handle the default colormap in a special way.
1247   */
1248  if (pColormap->flags & IsDefault)
1249    {
1250#if CYGDEBUG
1251      winDebug ("winDestroyColormapShadowGDI - Destroying default "
1252	      "colormap\n");
1253#endif
1254
1255      /*
1256       * FIXME: Walk the list of all screens, popping the default
1257       * palette out of each screen device context.
1258       */
1259
1260      /* Pop the palette out of the device context */
1261      SelectPalette (pScreenPriv->hdcScreen,
1262		     GetStockObject (DEFAULT_PALETTE),
1263		     FALSE);
1264
1265      /* Clear our private installed colormap pointer */
1266      pScreenPriv->pcmapInstalled = NULL;
1267    }
1268
1269  /* Try to delete the logical palette */
1270  if (DeleteObject (pCmapPriv->hPalette) == 0)
1271    {
1272      ErrorF ("winDestroyColormap - DeleteObject () failed\n");
1273      return FALSE;
1274    }
1275
1276  /* Invalidate the colormap privates */
1277  pCmapPriv->hPalette = NULL;
1278
1279  return TRUE;
1280}
1281
1282
1283/*
1284 * Set engine specific funtions
1285 */
1286
1287Bool
1288winSetEngineFunctionsShadowGDI (ScreenPtr pScreen)
1289{
1290  winScreenPriv(pScreen);
1291  winScreenInfo		*pScreenInfo = pScreenPriv->pScreenInfo;
1292
1293  /* Set our pointers */
1294  pScreenPriv->pwinAllocateFB = winAllocateFBShadowGDI;
1295  pScreenPriv->pwinShadowUpdate = winShadowUpdateGDI;
1296  pScreenPriv->pwinCloseScreen = winCloseScreenShadowGDI;
1297  pScreenPriv->pwinInitVisuals = winInitVisualsShadowGDI;
1298  pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModeShadowGDI;
1299  if (pScreenInfo->fFullScreen)
1300    pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen;
1301  else
1302    pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed;
1303  pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB;
1304  pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI;
1305  pScreenPriv->pwinActivateApp = winActivateAppShadowGDI;
1306  pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI;
1307  pScreenPriv->pwinRealizeInstalledPalette =
1308    winRealizeInstalledPaletteShadowGDI;
1309  pScreenPriv->pwinInstallColormap = winInstallColormapShadowGDI;
1310  pScreenPriv->pwinStoreColors = winStoreColorsShadowGDI;
1311  pScreenPriv->pwinCreateColormap = winCreateColormapShadowGDI;
1312  pScreenPriv->pwinDestroyColormap = winDestroyColormapShadowGDI;
1313  pScreenPriv->pwinHotKeyAltTab = (winHotKeyAltTabProcPtr) (void (*)(void))NoopDDA;
1314  pScreenPriv->pwinCreatePrimarySurface
1315    = (winCreatePrimarySurfaceProcPtr) (void (*)(void))NoopDDA;
1316  pScreenPriv->pwinReleasePrimarySurface
1317    = (winReleasePrimarySurfaceProcPtr) (void (*)(void))NoopDDA;
1318#ifdef XWIN_MULTIWINDOW
1319  pScreenPriv->pwinFinishCreateWindowsWindow =
1320    (winFinishCreateWindowsWindowProcPtr) (void (*)(void))NoopDDA;
1321#endif
1322
1323  return TRUE;
1324}
1325