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