|
|
#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
|