/* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * *Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the *"Software"), to deal in the Software without restriction, including *without limitation the rights to use, copy, modify, merge, publish, *distribute, sublicense, and/or sell copies of the Software, and to *permit persons to whom the Software is furnished to do so, subject to *the following conditions: * *The above copyright notice and this permission notice shall be *included in all copies or substantial portions of the Software. * *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *Except as contained in this notice, the name of the XFree86 Project *shall not be used in advertising or otherwise to promote the sale, use *or other dealings in this Software without prior written authorization *from the XFree86 Project. * * Authors: Dakshinamurthy Karra * Suhaib M Siddiqi * Peter Busch * Harold L Hunt II */ #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif #include "win.h" /* * Local function prototypes */ static Bool winAllocateFBPrimaryDD(ScreenPtr pScreen); static Bool winCloseScreenPrimaryDD(int nIndex, ScreenPtr pScreen); static Bool winInitVisualsPrimaryDD(ScreenPtr pScreen); static Bool winAdjustVideoModePrimaryDD(ScreenPtr pScreen); static Bool winActivateAppPrimaryDD(ScreenPtr pScreen); static Bool winHotKeyAltTabPrimaryDD(ScreenPtr pScreen); /* * Create a DirectDraw primary surface */ static Bool winAllocateFBPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; HRESULT ddrval = DD_OK; DDSURFACEDESC ddsd; DDSURFACEDESC *pddsdPrimary = NULL; DDSURFACEDESC *pddsdOffscreen = NULL; RECT rcClient; winDebug ("winAllocateFBPrimaryDD\n"); /* Get client area location in screen coords */ GetClientRect(pScreenPriv->hwndScreen, &rcClient); MapWindowPoints(pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT) & rcClient, 2); /* Create a DirectDraw object, store the address at lpdd */ ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); if (ddrval != DD_OK) FatalError("winAllocateFBPrimaryDD - Could not start DirectDraw\n"); /* Get a DirectDraw2 interface pointer */ ddrval = IDirectDraw_QueryInterface(pScreenPriv->pdd, &IID_IDirectDraw2, (LPVOID *) & pScreenPriv->pdd2); if (FAILED(ddrval)) { ErrorF("winAllocateFBShadowDD - Failed DD2 query: %08x\n", (unsigned int) ddrval); return FALSE; } winDebug ("winAllocateFBPrimaryDD - Created and initialized DD\n"); /* Are we windowed or fullscreen? */ if (pScreenInfo->fFullScreen) { /* Full screen mode */ ddrval = IDirectDraw2_SetCooperativeLevel(pScreenPriv->pdd2, pScreenPriv->hwndScreen, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); if (FAILED(ddrval)) FatalError("winAllocateFBPrimaryDD - Could not set " "cooperative level\n"); /* Change the video mode to the mode requested */ ddrval = IDirectDraw2_SetDisplayMode(pScreenPriv->pdd2, pScreenInfo->dwWidth, pScreenInfo->dwHeight, pScreenInfo->dwBPP, pScreenInfo->dwRefreshRate, 0); if (FAILED(ddrval)) FatalError("winAllocateFBPrimaryDD - Could not set " "full screen display mode\n"); } else { /* Windowed mode */ ddrval = IDirectDraw2_SetCooperativeLevel(pScreenPriv->pdd2, pScreenPriv->hwndScreen, DDSCL_NORMAL); if (FAILED(ddrval)) FatalError("winAllocateFBPrimaryDD - Could not set " "cooperative level\n"); } /* Describe the primary surface */ ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; /* Create the primary surface */ ddrval = IDirectDraw2_CreateSurface(pScreenPriv->pdd2, &ddsd, &pScreenPriv->pddsPrimary, NULL); if (FAILED(ddrval)) FatalError("winAllocateFBPrimaryDD - Could not create primary " "surface %08x\n", (unsigned int) ddrval); winDebug ("winAllocateFBPrimaryDD - Created primary\n"); /* Allocate a DD surface description for our screen privates */ pddsdPrimary = pScreenPriv->pddsdPrimary = malloc(sizeof(DDSURFACEDESC)); if (pddsdPrimary == NULL) FatalError("winAllocateFBPrimaryDD - Could not allocate surface " "description memory\n"); ZeroMemory(pddsdPrimary, sizeof(*pddsdPrimary)); pddsdPrimary->dwSize = sizeof(*pddsdPrimary); /* Describe the offscreen surface to be created */ /* * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, * as drawing, locking, and unlocking take forever * with video memory surfaces. In addition, * video memory is a somewhat scarce resource, * so you shouldn't be allocating video memory when * you have the option of using system memory instead. */ ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwHeight = pScreenInfo->dwHeight; ddsd.dwWidth = pScreenInfo->dwWidth; /* Create the shadow surface */ ddrval = IDirectDraw2_CreateSurface(pScreenPriv->pdd2, &ddsd, &pScreenPriv->pddsOffscreen, NULL); if (ddrval != DD_OK) FatalError("winAllocateFBPrimaryDD - Could not create shadow " "surface\n"); winDebug ("winAllocateFBPrimaryDD - Created offscreen\n"); /* Allocate a DD surface description for our screen privates */ pddsdOffscreen = pScreenPriv->pddsdOffscreen = malloc(sizeof(DDSURFACEDESC)); if (pddsdOffscreen == NULL) FatalError("winAllocateFBPrimaryDD - Could not allocate surface " "description memory\n"); ZeroMemory(pddsdOffscreen, sizeof(*pddsdOffscreen)); pddsdOffscreen->dwSize = sizeof(*pddsdOffscreen); winDebug ("winAllocateFBPrimaryDD - Locking primary\n"); /* Lock the primary surface */ ddrval = IDirectDrawSurface2_Lock(pScreenPriv->pddsPrimary, pScreenInfo-> fFullScreen ? NULL : &rcClient, pddsdPrimary, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pddsdPrimary->lpSurface == NULL) FatalError("winAllocateFBPrimaryDD - Could not lock " "primary surface\n"); winDebug ("winAllocateFBPrimaryDD - Locked primary\n"); /* We don't know how to deal with anything other than RGB */ if (!(pddsdPrimary->ddpfPixelFormat.dwFlags & DDPF_RGB)) FatalError("winAllocateFBPrimaryDD - Color format other than RGB\n"); /* Grab the pitch from the surface desc */ pScreenInfo->dwStride = (pddsdPrimary->u1.lPitch * 8) / pScreenInfo->dwBPP; /* Save the pointer to our surface memory */ pScreenInfo->pfb = pddsdPrimary->lpSurface; /* Grab the color depth and masks from the surface description */ pScreenPriv->dwRedMask = pddsdPrimary->ddpfPixelFormat.u2.dwRBitMask; pScreenPriv->dwGreenMask = pddsdPrimary->ddpfPixelFormat.u3.dwGBitMask; pScreenPriv->dwBlueMask = pddsdPrimary->ddpfPixelFormat.u4.dwBBitMask; winDebug ("winAllocateFBPrimaryDD - Returning\n"); return TRUE; } static void winFreeFBPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; /* Free the offscreen surface, if there is one */ if (pScreenPriv->pddsOffscreen) { IDirectDrawSurface2_Unlock(pScreenPriv->pddsOffscreen, NULL); IDirectDrawSurface2_Release(pScreenPriv->pddsOffscreen); pScreenPriv->pddsOffscreen = NULL; } /* Release the primary surface, if there is one */ if (pScreenPriv->pddsPrimary) { IDirectDrawSurface2_Unlock(pScreenPriv->pddsPrimary, NULL); IDirectDrawSurface2_Release(pScreenPriv->pddsPrimary); pScreenPriv->pddsPrimary = NULL; } /* Free the DirectDraw object, if there is one */ if (pScreenPriv->pdd) { IDirectDraw2_RestoreDisplayMode(pScreenPriv->pdd); IDirectDraw2_Release(pScreenPriv->pdd); pScreenPriv->pdd = NULL; } /* Invalidate the ScreenInfo's fb pointer */ pScreenInfo->pfb = NULL; } static Bool winInitScreenPrimaryDD(ScreenPtr pScreen) { return winAllocateFBPrimaryDD(pScreen); } /* * Call the wrapped CloseScreen function. * * Free our resources and private structures. */ static Bool winCloseScreenPrimaryDD(int nIndex, ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; Bool fReturn; ErrorF("winCloseScreenPrimaryDD - Freeing screen resources\n"); /* Flag that the screen is closed */ pScreenPriv->fClosed = TRUE; pScreenPriv->fActive = FALSE; /* Call the wrapped CloseScreen procedure */ WIN_UNWRAP(CloseScreen); if (pScreen->CloseScreen) fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); /* Delete the window property */ RemoveProp(pScreenPriv->hwndScreen, WIN_SCR_PROP); winFreeFBPrimaryDD(pScreen); /* Delete tray icon, if we have one */ if (!pScreenInfo->fNoTrayIcon) winDeleteNotifyIcon(pScreenPriv); /* Free the exit confirmation dialog box, if it exists */ if (g_hDlgExit != NULL) { DestroyWindow(g_hDlgExit); g_hDlgExit = NULL; } /* Kill our window */ if (pScreenPriv->hwndScreen) { DestroyWindow(pScreenPriv->hwndScreen); pScreenPriv->hwndScreen = NULL; } /* Kill our screeninfo's pointer to the screen */ pScreenInfo->pScreen = NULL; /* Free the screen privates for this screen */ free((pointer) pScreenPriv); return fReturn; } /* * Tell mi what sort of visuals we need. * * Generally we only need one visual, as our screen can only * handle one format at a time, I believe. You may want * to verify that last sentence. */ static Bool winInitVisualsPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; DWORD dwRedBits, dwGreenBits, dwBlueBits; /* Count the number of ones in each color mask */ dwRedBits = winCountBits(pScreenPriv->dwRedMask); dwGreenBits = winCountBits(pScreenPriv->dwGreenMask); dwBlueBits = winCountBits(pScreenPriv->dwBlueMask); /* Store the maximum number of ones in a color mask as the bitsPerRGB */ if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) pScreenPriv->dwBitsPerRGB = dwRedBits; else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) pScreenPriv->dwBitsPerRGB = dwGreenBits; else pScreenPriv->dwBitsPerRGB = dwBlueBits; winDebug ("winInitVisualsPrimaryDD - Masks: %08x %08x %08x bpRGB: %d\n", (unsigned int) pScreenPriv->dwRedMask, (unsigned int) pScreenPriv->dwGreenMask, (unsigned int) pScreenPriv->dwBlueMask, (int) pScreenPriv->dwBitsPerRGB); /* Create a single visual according to the Windows screen depth */ switch (pScreenInfo->dwDepth) { case 24: case 16: case 15: if (!miSetVisualTypesAndMasks(pScreenInfo->dwDepth, TrueColorMask, pScreenPriv->dwBitsPerRGB, TrueColor, pScreenPriv->dwRedMask, pScreenPriv->dwGreenMask, pScreenPriv->dwBlueMask)) { ErrorF("winInitVisualsPrimaryDD - " "miSetVisualTypesAndMasks failed\n"); return FALSE; } break; case 8: winDebug("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); if (!miSetVisualTypesAndMasks(pScreenInfo->dwDepth, PseudoColorMask, pScreenPriv->dwBitsPerRGB, PseudoColor, pScreenPriv->dwRedMask, pScreenPriv->dwGreenMask, pScreenPriv->dwBlueMask)) { ErrorF("winInitVisualsPrimaryDD - " "miSetVisualTypesAndMasks failed\n"); return FALSE; } winDebug("winInitVisualsPrimaryDD - Returned from " "miSetVisualTypesAndMasks\n"); break; default: ErrorF("winInitVisualsPrimaryDD - Unknown screen depth\n"); return FALSE; } winDebug ("winInitVisualsPrimaryDD - Returning\n"); return TRUE; } static Bool winAdjustVideoModePrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; HDC hdc = NULL; DWORD dwBPP; /* We're in serious trouble if we can't get a DC */ hdc = GetDC(NULL); if (hdc == NULL) { ErrorF("winAdjustVideoModePrimaryDD - GetDC failed\n"); return FALSE; } /* Query GDI for current display depth */ dwBPP = GetDeviceCaps(hdc, BITSPIXEL); /* DirectDraw can only change the depth in fullscreen mode */ if (!(pScreenInfo->fFullScreen && (pScreenInfo->dwBPP != WIN_DEFAULT_BPP))) { /* Otherwise, We'll use GDI's depth */ pScreenInfo->dwBPP = dwBPP; } /* Release our DC */ ReleaseDC(NULL, hdc); return TRUE; } /* * We need to blit our offscreen fb to * the screen when we are activated, and we need to point * the fb code back to the primary surface memory. */ static Bool winActivateAppPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); RECT rcSrc, rcClient; HRESULT ddrval = DD_OK; /* Check for errors */ if (pScreenPriv == NULL || pScreenPriv->pScreenInfo == NULL || pScreenPriv->pddsPrimary == NULL || pScreenPriv->pddsOffscreen == NULL) return FALSE; /* Check for do-nothing */ if (!pScreenPriv->fActive) return TRUE; /* We are activating */ ddrval = IDirectDrawSurface2_IsLost(pScreenPriv->pddsOffscreen); if (ddrval == DD_OK) { IDirectDrawSurface2_Unlock(pScreenPriv->pddsOffscreen, NULL); /* * We don't check for an error from Unlock, because it * doesn't matter if the Unlock failed. */ } /* Restore both surfaces, just cause I like it that way */ IDirectDrawSurface2_Restore(pScreenPriv->pddsOffscreen); IDirectDrawSurface2_Restore(pScreenPriv->pddsPrimary); /* Get client area in screen coords */ GetClientRect(pScreenPriv->hwndScreen, &rcClient); MapWindowPoints(pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT) & rcClient, 2); /* Setup a source rectangle */ rcSrc.left = 0; rcSrc.top = 0; rcSrc.right = pScreenPriv->pScreenInfo->dwWidth; rcSrc.bottom = pScreenPriv->pScreenInfo->dwHeight; ddrval = IDirectDrawSurface2_Blt(pScreenPriv->pddsPrimary, &rcClient, pScreenPriv->pddsOffscreen, &rcSrc, DDBLT_WAIT, NULL); if (ddrval != DD_OK) FatalError("winActivateAppPrimaryDD () - Failed blitting offscreen " "surface to primary surface %08x\n", (unsigned int) ddrval); /* Lock the primary surface */ ddrval = IDirectDrawSurface2_Lock(pScreenPriv->pddsPrimary, &rcClient, pScreenPriv->pddsdPrimary, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pScreenPriv->pddsdPrimary->lpSurface == NULL) FatalError("winActivateAppPrimaryDD () - Could not lock " "primary surface\n"); /* Notify FB of the new memory pointer */ winUpdateFBPointer(pScreen, pScreenPriv->pddsdPrimary->lpSurface); /* * Register the Alt-Tab combo as a hotkey so we can copy * the primary framebuffer before the display mode changes */ RegisterHotKey(pScreenPriv->hwndScreen, 1, MOD_ALT, 9); return TRUE; } /* * Handle the Alt+Tab hotkey. * * We need to save the primary fb to an offscreen fb when * we get deactivated, and point the fb code at the offscreen * fb for the duration of the deactivation. */ static Bool winHotKeyAltTabPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; RECT rcClient, rcSrc; HRESULT ddrval = DD_OK; winDebug ("\nwinHotKeyAltTabPrimaryDD\n\n"); /* Alt+Tab was pressed, we will lose focus very soon */ pScreenPriv->fActive = FALSE; /* Check for error conditions */ if (pScreenPriv->pddsPrimary == NULL || pScreenPriv->pddsOffscreen == NULL) return FALSE; /* Get client area in screen coords */ GetClientRect(pScreenPriv->hwndScreen, &rcClient); MapWindowPoints(pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT) & rcClient, 2); /* Did we loose the primary surface? */ ddrval = IDirectDrawSurface2_IsLost(pScreenPriv->pddsPrimary); if (ddrval == DD_OK) { ddrval = IDirectDrawSurface2_Unlock(pScreenPriv->pddsPrimary, NULL); if (FAILED(ddrval)) FatalError("winHotKeyAltTabPrimaryDD - Failed unlocking primary " "surface\n"); } /* Setup a source rectangle */ rcSrc.left = 0; rcSrc.top = 0; rcSrc.right = pScreenInfo->dwWidth; rcSrc.bottom = pScreenInfo->dwHeight; /* Blit the primary surface to the offscreen surface */ ddrval = IDirectDrawSurface2_Blt(pScreenPriv->pddsOffscreen, NULL, /* should be rcDest */ pScreenPriv->pddsPrimary, NULL, DDBLT_WAIT, NULL); if (ddrval == DDERR_SURFACELOST) { IDirectDrawSurface2_Restore(pScreenPriv->pddsOffscreen); IDirectDrawSurface2_Restore(pScreenPriv->pddsPrimary); /* Blit the primary surface to the offscreen surface */ ddrval = IDirectDrawSurface2_Blt(pScreenPriv->pddsOffscreen, NULL, pScreenPriv->pddsPrimary, NULL, DDBLT_WAIT, NULL); if (FAILED(ddrval)) FatalError("winHotKeyAltTabPrimaryDD - Failed blitting primary " "surface to offscreen surface: %08x\n", (unsigned int) ddrval); } else { FatalError("winHotKeyAltTabPrimaryDD - Unknown error from " "Blt: %08dx\n", (unsigned int) ddrval); } /* Lock the offscreen surface */ ddrval = IDirectDrawSurface2_Lock(pScreenPriv->pddsOffscreen, NULL, pScreenPriv->pddsdOffscreen, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pScreenPriv->pddsdPrimary->lpSurface == NULL) FatalError("winHotKeyAltTabPrimaryDD - Could not lock " "offscreen surface\n"); /* Notify FB of the new memory pointer */ winUpdateFBPointer(pScreen, pScreenPriv->pddsdOffscreen->lpSurface); /* Unregister our hotkey */ UnregisterHotKey(pScreenPriv->hwndScreen, 1); return TRUE; } /* Set engine specific functions */ Bool winSetEngineFunctionsPrimaryDD(ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; /* Set our pointers */ pScreenPriv->pwinAllocateFB = winAllocateFBPrimaryDD; pScreenPriv->pwinFreeFB = winFreeFBPrimaryDD; pScreenPriv->pwinShadowUpdate = (winShadowUpdateProcPtr) (void (*)(void)) NoopDDA; pScreenPriv->pwinInitScreen = winInitScreenPrimaryDD; pScreenPriv->pwinCloseScreen = winCloseScreenPrimaryDD; pScreenPriv->pwinInitVisuals = winInitVisualsPrimaryDD; pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModePrimaryDD; if (pScreenInfo->fFullScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; else pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = (winBltExposedRegionsProcPtr) (void (*)(void)) NoopDDA; pScreenPriv->pwinActivateApp = winActivateAppPrimaryDD; pScreenPriv->pwinRedrawScreen = NULL; pScreenPriv->pwinRealizeInstalledPalette = NULL; pScreenPriv->pwinInstallColormap = NULL; pScreenPriv->pwinStoreColors = NULL; pScreenPriv->pwinCreateColormap = NULL; pScreenPriv->pwinDestroyColormap = NULL; pScreenPriv->pwinHotKeyAltTab = winHotKeyAltTabPrimaryDD; pScreenPriv->pwinCreatePrimarySurface = (winCreatePrimarySurfaceProcPtr) (void (*)(void)) NoopDDA; pScreenPriv->pwinReleasePrimarySurface = (winReleasePrimarySurfaceProcPtr) (void (*)(void)) NoopDDA; #ifdef XWIN_MULTIWINDOW pScreenPriv->pwinFinishCreateWindowsWindow = (winFinishCreateWindowsWindowProcPtr) (void (*)(void)) NoopDDA; #endif return TRUE; }