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