#include "precomp.h" // // CM.C // Cursor Manager, display driver side // // Copyright(c) Microsoft 1997- // // // // CM_DDProcessRequest() - see cm.h // // ULONG CM_DDProcessRequest ( SURFOBJ* pso, UINT cjIn, void * pvIn, UINT cjOut, void * pvOut ) { BOOL rc; LPOSI_ESCAPE_HEADER pHeader; LPOSI_PDEV ppDev = (LPOSI_PDEV)pso->dhpdev; DebugEntry(CM_DDProcessRequest); if ((cjIn != sizeof(CM_DRV_XFORM_INFO)) || (cjOut != sizeof(CM_DRV_XFORM_INFO))) { ERROR_OUT(("CM_DDProcessRequest: Invalid sizes %d, %d for CM_ESC", cjIn, cjOut)); rc = FALSE; DC_QUIT; } // // Get the request number. // pHeader = pvIn; switch (pHeader->escapeFn) { case CM_ESC_XFORM: { ASSERT(cjIn == sizeof(CM_DRV_XFORM_INFO)); ASSERT(cjOut == sizeof(CM_DRV_XFORM_INFO)); ((LPCM_DRV_XFORM_INFO)pvOut)->result = CMDDSetTransform(ppDev, (LPCM_DRV_XFORM_INFO)pvIn); rc = TRUE; break; } break; default: { ERROR_OUT(("Unrecognised CM_ escape")); rc = FALSE; } break; } DC_EXIT_POINT: DebugExitDWORD(CM_DDProcessRequest, rc); return((ULONG)rc); } // Name: CM_DDInit // // Purpose: Allocate a working surface for colour cursors // // Returns: TRUE/FALSE // // Params: IN ppDev - surface information // BOOL CM_DDInit(LPOSI_PDEV ppDev) { SIZEL bitmapSize; BOOL rc = FALSE; DebugEntry(CM_DDInit); ASSERT(!g_cmWorkBitmap); // // Allocate the work bitmap, at the local device resolution. Note that // we create it "top down" rather than the default of "bottom up" to // simplify copying data from the bitmap (we don't have to work out // offsets into the data - we can copy from the beginning). // bitmapSize.cx = CM_MAX_CURSOR_WIDTH; bitmapSize.cy = CM_MAX_CURSOR_HEIGHT; g_cmWorkBitmap = EngCreateBitmap(bitmapSize, BYTES_IN_BITMAP(bitmapSize.cx, 1, ppDev->cBitsPerPel), ppDev->iBitmapFormat, BMF_TOPDOWN, NULL); if (!g_cmWorkBitmap) { ERROR_OUT(( "Failed to create work bitmap")); DC_QUIT; } rc = TRUE; DC_EXIT_POINT: DebugExitBOOL(CM_DDInit, rc); return(rc); } // // // CM_DDTerm - see cm.h // // void CM_DDTerm(void) { DebugEntry(CM_DDTerm); // // Destroy the bitmap. Despite its name, EngDeleteSurface is the // correct function to do this. // if (g_cmWorkBitmap) { if (!EngDeleteSurface((HSURF)g_cmWorkBitmap)) { ERROR_OUT(( "Failed to delete work bitmap")); } else { TRACE_OUT(( "Deleted work bitmap")); } g_cmWorkBitmap = NULL; } DebugExitVOID(CM_DDTerm); } // // CM_DDViewing() // void CM_DDViewing ( SURFOBJ * pso, BOOL fViewers ) { DebugEntry(CM_DDViewing); if (fViewers) { // // Jiggle the cursor so we get the current image. // EngSetPointerTag(((LPOSI_PDEV)pso->dhpdev)->hdevEng, NULL, NULL, NULL, 0); } DebugExitVOID(CM_DDViewing); } // // // DrvSetPointerShape - see winddi.h // // ULONG DrvSetPointerShape(SURFOBJ *pso, SURFOBJ *psoMask, SURFOBJ *psoColor, XLATEOBJ *pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL *prcl, FLONG fl) { ULONG rc = SPS_ACCEPT_NOEXCLUDE; SURFOBJ * pWorkSurf = NULL; LPOSI_PDEV ppDev = (LPOSI_PDEV)pso->dhpdev; BOOL writingSHM = FALSE; LPCM_SHAPE_DATA pCursorShapeData; RECTL destRectl; POINTL sourcePt; int ii; LONG lineLen; LPBYTE srcPtr; LPBYTE dstPtr; LPCM_FAST_DATA lpcmShared; DebugEntry(DrvSetPointerShape); // // Returning SPS_ACCEPT_NOEXCLUDE means we can ignore prcl. // // // Only process the change if we are hosting. (Hosting implies being // initialized). // if (!g_oeViewers) { DC_QUIT; } // // Get access to the shared memory. // lpcmShared = CM_SHM_START_WRITING; writingSHM = TRUE; // // First of all, let's trace out some useful information. // TRACE_OUT(( "pso %#hlx psoMask %#hlx psoColor %#hlx pxlo %#hlx", pso, psoMask, psoColor, pxlo)); TRACE_OUT(( "hot spot (%d, %d) x, y (%d, %d)", xHot, yHot, x, y)); TRACE_OUT(( "Flags %#hlx", fl)); // // Set up a local pointer to the cursor shape data. // pCursorShapeData = &lpcmShared->cmCursorShapeData; if (psoMask == NULL) { // // This is a transparent cursor. Send a NULL cursor. Note that // this is not the same as hiding the cursor using DrvMovePointer - // as in this case the cursor cannot be unhidden unless // DrvSetPointerShape is called again. // TRACE_OUT(( "Transparent Cursor")); CM_SET_NULL_CURSOR(pCursorShapeData); g_asSharedMemory->cmCursorHidden = FALSE; lpcmShared->cmCursorStamp = g_cmNextCursorStamp++; DC_QUIT; } // // We've been passed a system cursor. Fill in the header for our local // cursor. We can get the hot spot position and cursor size and width // easily. // pCursorShapeData->hdr.ptHotSpot.x = xHot; pCursorShapeData->hdr.ptHotSpot.y = yHot; TRACE_OUT(( "Pointer mask is %#hlx by %#hlx pixels (lDelta: %#hlx)", psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy, psoMask->lDelta)); pCursorShapeData->hdr.cx = (WORD)psoMask->sizlBitmap.cx; pCursorShapeData->hdr.cy = (WORD)psoMask->sizlBitmap.cy / 2; // // Check cursor size // if ((pCursorShapeData->hdr.cx > CM_MAX_CURSOR_WIDTH) || (pCursorShapeData->hdr.cy > CM_MAX_CURSOR_HEIGHT)) { ERROR_OUT(( "Cursor too big! %d %d", psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy)); DC_QUIT; } // // lDelta may be negative for an inverted cursor (which is what we get // from DC-Share). // lineLen = abs(psoMask->lDelta); // // At this point we need to know if we are dealing with a color cursor. // if (NULL == psoColor) { TRACE_OUT(( "Monochrome pointer")); pCursorShapeData->hdr.cPlanes = 1; pCursorShapeData->hdr.cBitsPerPel = 1; pCursorShapeData->hdr.cbRowWidth = (WORD)lineLen; // // Copy the 1bpp AND mask and cursor shape (XOR mask) across. // TRACE_OUT(( "Copying AND mask across from %#hlx (size: %#hlx)", psoMask->pvBits, psoMask->cjBits)); dstPtr = pCursorShapeData->data; srcPtr = (LPBYTE) psoMask->pvScan0; for (ii = pCursorShapeData->hdr.cy * 2; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, lineLen); srcPtr += psoMask->lDelta; dstPtr += lineLen; } // // Copy black-and-white palette colors // TRACE_OUT(( "Copy B+W palette")); lpcmShared->colorTable[0].peRed = 0; lpcmShared->colorTable[0].peGreen = 0; lpcmShared->colorTable[0].peBlue = 0; lpcmShared->colorTable[0].peFlags = 0; lpcmShared->colorTable[1].peRed = 255; lpcmShared->colorTable[1].peGreen = 255; lpcmShared->colorTable[1].peBlue = 255; lpcmShared->colorTable[1].peFlags = 0; // // That's all we need to do in this case. // } else { TRACE_OUT(( "Color pointer - mask of %#hlx by %#hlx (lDelta: %#hlx)", psoColor->sizlBitmap.cx, psoColor->sizlBitmap.cy, psoColor->lDelta)); // // Note: row width used to calculate AND mask size - and is thus // for the 1bpp mask. // pCursorShapeData->hdr.cbRowWidth = (WORD)lineLen; pCursorShapeData->hdr.cPlanes = 1; // // Note: data at device bpp. // TRACE_OUT(( "BPP is %d", pCursorShapeData->hdr.cBitsPerPel)); pCursorShapeData->hdr.cBitsPerPel = (BYTE)ppDev->cBitsPerPel; // // Lock the work bitmap to get a surface to pass to EngBitBlt. // pWorkSurf = EngLockSurface((HSURF)g_cmWorkBitmap); if (NULL == pWorkSurf) { ERROR_OUT(( "Failed to lock work surface")); DC_QUIT; } TRACE_OUT(( "Locked surface")); // // Perform the Blt to our work bitmap so that we can get the bits // at the native bpp. // destRectl.top = 0; destRectl.left = 0; destRectl.right = psoColor->sizlBitmap.cx; destRectl.bottom = psoColor->sizlBitmap.cy; sourcePt.x = 0; sourcePt.y = 0; if (!EngBitBlt(pWorkSurf, psoColor, NULL, // mask surface NULL, // clip object pxlo, // XLATE object &destRectl, &sourcePt, NULL, // mask origin NULL, // brush NULL, // brush origin 0xcccc)) // SRCCPY { ERROR_OUT(( "Failed to Blt to work bitmap")); DC_QUIT; } TRACE_OUT(( "Got the bits at native format into the work bitmap")); // // Now copy the bits we want from this work bitmap into the // DCCURSORSHAPE shared memory. // First copy the AND bits (but ignore the redundant 1bpp XOR bits) // TRACE_OUT(( "Copy %d bytes of 1bpp AND mask", psoMask->cjBits/2)); dstPtr = pCursorShapeData->data; srcPtr = (LPBYTE) psoMask->pvScan0; for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, lineLen); srcPtr += psoMask->lDelta; dstPtr += lineLen; } TRACE_OUT(( "Copy %d bytes of color", pWorkSurf->cjBits)); memcpy(&(pCursorShapeData->data[psoMask->cjBits / 2]), pWorkSurf->pvBits, pWorkSurf->cjBits); // // Now work out the palette and copy into shared memory // if (pCursorShapeData->hdr.cBitsPerPel > 8) { // // Need the bitmasks. // TRACE_OUT(( "Copy bitmasks")); lpcmShared->bitmasks[0] = ppDev->flRed; lpcmShared->bitmasks[1] = ppDev->flGreen; lpcmShared->bitmasks[2] = ppDev->flBlue; } else { // // Need a palette. // TRACE_OUT(( "Copy %d palette bytes", COLORS_FOR_BPP(ppDev->cBitsPerPel) * sizeof(PALETTEENTRY))); memcpy(lpcmShared->colorTable, ppDev->pPal, COLORS_FOR_BPP(ppDev->cBitsPerPel) * sizeof(PALETTEENTRY)); } } // // Set the cursor stamp, and the cursor hidden state. // lpcmShared->cmCursorStamp = g_cmNextCursorStamp++; g_asSharedMemory->cmCursorHidden = FALSE; DC_EXIT_POINT: // // Free access to the shared memory if we got it earlier. // if (writingSHM) { CM_SHM_STOP_WRITING; } if (pWorkSurf != NULL) { // // Unlock the work bitmap surface. // EngUnlockSurface(pWorkSurf); } DebugExitDWORD(DrvSetPointerShape, rc); return(rc); } // DrvSetPointerShape // // DrvMovePointer - see NT DDK documentation. // We only look at this in order to check for hidden cursors - normal // pointer moves are ignored. // VOID DrvMovePointer(SURFOBJ *pso, LONG x, LONG y, RECTL *prcl) { LPOSI_PDEV ppdev = (LPOSI_PDEV) pso->dhpdev; DebugEntry(DrvMovePointer); // // We don't use the exclusion rectangle because we only support // hardware Pointers. If we were doing our own Pointer simulations we // would want to update prcl so that the engine would call us to // exclude our pointer before drawing to the pixels in prcl. // // // Only process the mouse move if we are hosting. (Hosting implies // being initialized). // if (!g_oeViewers) { DC_QUIT; } if (x == -1) { if (!g_cmCursorHidden) { // // Pointer is hidden. // TRACE_OUT(("Hide the cursor")); // // Set the 'hide cursor' flag. // CM_SHM_START_WRITING; g_asSharedMemory->cmCursorHidden = TRUE; CM_SHM_STOP_WRITING; // // Update our fast-path variable. // g_cmCursorHidden = TRUE; } } else { if (g_cmCursorHidden) { // // The pointer is unhidden // TRACE_OUT(("Show the cursor")); CM_SHM_START_WRITING; g_asSharedMemory->cmCursorHidden = FALSE; CM_SHM_STOP_WRITING; // // Update our fast-path variable. // g_cmCursorHidden = FALSE; } } DC_EXIT_POINT: DebugExitVOID(DrvMovePointer); } // Name: CMDDSetTransform // // Purpose: Set up a cursor transform // // Returns: TRUE/FALSE // // Params: IN ppDev - device info // IN pXformInfo - data passed in to DrvEscape // BOOL CMDDSetTransform(LPOSI_PDEV ppDev, LPCM_DRV_XFORM_INFO pXformInfo) { BOOL rc = FALSE; LPBYTE pAND = pXformInfo->pANDMask; SIZEL bitmapSize; HBITMAP andBitmap; SURFOBJ * pANDSurf; DebugEntry(CMDDSetTransform); if (pAND == NULL) { // // Reset the transform // TRACE_OUT(( "Clear transform")); EngSetPointerTag(ppDev->hdevEng, NULL, NULL, NULL, 0); rc = TRUE; DC_QUIT; } // // Transforms are always monochrome // // // Create a 1bpp bitmap, double-height, with the AND bits followed by // the XOR bits. We are given a top-down DIB, so we need to create // a top-down bitmap. // bitmapSize.cx = pXformInfo->width; bitmapSize.cy = pXformInfo->height * 2; andBitmap = EngCreateBitmap(bitmapSize, BYTES_IN_BITMAP(bitmapSize.cx, 1, 1), BMF_1BPP, BMF_TOPDOWN, NULL); pANDSurf = EngLockSurface((HSURF)andBitmap); if (pANDSurf == NULL) { ERROR_OUT(( "Failed to lock work surface")); DC_QUIT; } // // Copy the bits // memcpy(pANDSurf->pvBits, pAND, pANDSurf->cjBits); TRACE_OUT(( "Set the tag")); EngSetPointerTag(ppDev->hdevEng, pANDSurf, NULL, NULL, 0); EngUnlockSurface(pANDSurf); EngDeleteSurface((HSURF)andBitmap); rc = TRUE; DC_EXIT_POINT: DebugExitBOOL(CMDDSetTransform, rc); return(rc); } // CMDDSetTransform