|
|
/****************************************************************************/ // ncmapi.c
//
// RDP Cursor Manager API functions.
//
// Copyright (C) 1996-2000 Microsoft Corporation
/****************************************************************************/
#include <precmpdd.h>
#pragma hdrstop
#define TRC_FILE "ncmapi"
#include <adcg.h>
#include <ncmdisp.h>
#include <nschdisp.h>
#define DC_INCLUDE_DATA
#include <ndddata.c>
#undef DC_INCLUDE_DATA
#include <ncmdata.c>
#include <nchdisp.h>
/****************************************************************************/ /* Name: CM_DDInit */ /* */ /* Purpose: Initialises the display driver component of the cursor */ /* manager. */ /* */ /* Returns: TRUE if successful, FALSE otherwise. */ /* */ /* Params: IN ppDev - pointer to pDev for work bitmap */ /****************************************************************************/ BOOL RDPCALL CM_DDInit(PDD_PDEV ppDev) { BOOL rc = TRUE; SIZEL bitmapSize;
DC_BEGIN_FN("CM_DDInit");
/************************************************************************/ /* 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; cmWorkBitmap24 = EngCreateBitmap(bitmapSize, TS_BYTES_IN_SCANLINE(bitmapSize.cx, 24), BMF_24BPP, BMF_TOPDOWN, NULL);
#ifdef DC_HICOLOR
cmWorkBitmap16 = EngCreateBitmap(bitmapSize, TS_BYTES_IN_SCANLINE(bitmapSize.cx, 16), BMF_16BPP, BMF_TOPDOWN, NULL); if (cmWorkBitmap16 == NULL) { /********************************************************************/ /* We can carry on with reduced function without this one */ /********************************************************************/ TRC_ERR((TB, "Failed to create 16bpp work bitmap")); pddShm->cm.cmSendAnyColor = FALSE; } #endif
if (cmWorkBitmap24 != NULL) { TRC_NRM((TB, "Created work bitmap successfully"));
// Reset the cursor stamp.
cmNextCursorStamp = 0; } else { TRC_ERR((TB, "Failed to create work bitmaps")); rc = FALSE; }
DC_END_FN(); return rc; }
/****************************************************************************/ /* Name: CM_Update */ /* */ /* Purpose: The capabilities may have changed */ /****************************************************************************/ void RDPCALL CM_Update(void) { PCHCACHEDATA pCacheData;
DC_BEGIN_FN("CM_Update");
/************************************************************************/ /* Create the cursor cache. */ /************************************************************************/ if (cmCursorCacheHandle == NULL) { if (pddShm->cm.cmCacheSize) { pCacheData = (PCHCACHEDATA)EngAllocMem(0, CH_CalculateCacheSize(pddShm->cm.cmCacheSize), DD_ALLOC_TAG);
if (pCacheData != NULL) { CH_InitCache(pCacheData, pddShm->cm.cmCacheSize, NULL, FALSE, FALSE, NULL); cmCursorCacheHandle = pCacheData; } else { TRC_ERR((TB, "Failed to create cache: cEntries(%u)", pddShm->cm.cmCacheSize)); } } else { TRC_ERR((TB, "Zero size Cursor Cache")); } }
// Else just clear it for synchonization purposes.
else { CH_ClearCache(cmCursorCacheHandle); }
DC_END_FN(); } /* CM_Update */
/****************************************************************************/ /* Name: CM_DDDisc */ /* */ /* Purpose: Disconnects the display driver component of the cursor */ /* manager. */ /****************************************************************************/ void RDPCALL CM_DDDisc(void) { DC_BEGIN_FN("CM_DDDisc");
/************************************************************************/ /* Free up the cursor cache */ /************************************************************************/ if (cmCursorCacheHandle != 0) { TRC_NRM((TB, "Destroying CM cache")); CH_ClearCache(cmCursorCacheHandle); EngFreeMem(cmCursorCacheHandle); cmCursorCacheHandle = 0; }
DC_END_FN(); } /* CM_DDDisc */
/****************************************************************************/ /* Name: CM_DDTerm */ /* */ /* Purpose: Terminates the display driver component of the cursor */ /* manager. */ /* */ /* Returns: TRUE if successful, FALSE otherwise. */ /****************************************************************************/ void RDPCALL CM_DDTerm(void) { DC_BEGIN_FN("CM_DDTerm");
/************************************************************************/ /* Destroy the work bitmaps. Despite its name, EngDeleteSurface is the */ /* correct function to do this. */ /************************************************************************/ #ifdef DC_HICOLOR
if (cmWorkBitmap24) { if (!EngDeleteSurface((HSURF)cmWorkBitmap24)) { TRC_ERR((TB, "Failed to delete 24bpp work bitmap")); } }
if (cmWorkBitmap16) { if (!EngDeleteSurface((HSURF)cmWorkBitmap16)) { TRC_ERR((TB, "Failed to delete 16bpp work bitmap")); } } #else
if (cmWorkBitmap24 != NULL) { if (!EngDeleteSurface((HSURF)cmWorkBitmap24)) { TRC_ERR((TB, "Failed to delete work bitmap")); } } #endif
/************************************************************************/ /* Free up the cursor cache */ /************************************************************************/ if (cmCursorCacheHandle != 0) { TRC_NRM((TB, "Destroying CM cache")); CH_ClearCache(cmCursorCacheHandle); EngFreeMem(cmCursorCacheHandle); cmCursorCacheHandle = 0; }
TRC_NRM((TB, "CM terminated"));
DC_END_FN(); } /* CM_DDTerm */
/****************************************************************************/ /* CM_InitShm */ /* */ /* Initializes CM Shared Memory. */ /****************************************************************************/ void RDPCALL CM_InitShm(void) { DC_BEGIN_FN("CM_InitShm");
// Set up initial contents of Shm memory, since it is not zeroed on
// init. Don't set up the initially unused cursor shape data.
// NOTE: cmCursorShapeData is specifically placed at the end of
// CM_SHARED_DATA to allow this memset to work. If you change
// the shared mem struct be sure this gets changed.
memset(&pddShm->cm, 0, (unsigned)FIELDOFFSET(CM_SHARED_DATA, cmCursorShapeData.data));
// Set the last known position to something impossible. The IM
// periodic processing will not move the client's mouse until a
// sensible value is found here, ie until the client has sent us a
// mouse position and it has percolated through to the DD. This
// avoids the problem of the mouse leaping to 0,0 on connection.
pddShm->cm.cmCursorPos.x = 0xffffffff;
DC_END_FN(); }
/****************************************************************************/ /* */ /* DrvMovePointer - see NT DDK documentation. */ /* */ /****************************************************************************/ VOID DrvMovePointer(SURFOBJ *pso, LONG x, LONG y, RECTL *prcl) { DC_BEGIN_FN(("DrvMovePointer"));
//
// Win32k hides the hardware cursor by calling the MovePointer
// entry point with (-1,-1). Treat this as a procedural move
// and pass it on to the real worker function
//
// All other paths are handled directly by win32k calling
// DrvMovePointerEx with the right flags
//
if (-1 == x && -1 == y) { DrvMovePointerEx(pso, x, y, MP_PROCEDURAL); }
DC_END_FN(); }
//
// DrvMovePointerEx
//
// Params:
// x,y - new mouse position.
// ulFlags - source of move (see winddits.h).
//
// This function replaces the regular DrvMovePointer entry point
// by also sending us an event source parameter.
//
// This allows us to determine if we should ignore the update (e.g
// if it originates from the primary stack). Or send it down to the
// client in the case of a server initiated move or a shadow move.
//
// We ignore updates from the primary stack because by definition
// those came from the client so it doesn't need feedback from the
// server.
//
BOOL DrvMovePointerEx(SURFOBJ *pso, LONG x, LONG y, ULONG ulFlags) { BOOL fTriggerUpdate = FALSE; PDD_PDEV ppDev = (PDD_PDEV)pso->dhpdev;
DC_BEGIN_FN("CM_DrvMovePointerEx");
if (pddShm != NULL) { if ((ulFlags & MP_TERMSRV_SHADOW) || (ulFlags & MP_PROCEDURAL)) { if (x == -1) { // -1 means hide the pointer.
TRC_NRM((TB, "Hide the pointer")); pddShm->cm.cmHidden = TRUE; } else { // Pointer is not hidden.
if (pddShm->cm.cmHidden) { TRC_NRM((TB, "Unhide the pointer")); } pddShm->cm.cmHidden = FALSE; //
// We always update the position for server initated moves.
//
pddShm->cm.cmCursorPos.x = x; pddShm->cm.cmCursorPos.y = y;
//
// Send an update so we don't need to wait
// for the next output flush.
//
fTriggerUpdate = TRUE;
// Set the cursor moved flag.
pddShm->cm.cmCursorMoved = TRUE; } } else { TRC_ALT((TB,"Discarding move (%d,%d) - src 0x%x", x,y, ulFlags)); }
if (fTriggerUpdate) { //
// Tell the scheduler to send an update
//
SCH_DDOutputAvailable(ppDev, FALSE); } } else { TRC_DBG((TB, "Ignoring move to %d %d as no shr mem yet", x,y)); }
DC_END_FN(); return TRUE; }
/****************************************************************************/ /* */ /* 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; PDD_PDEV ppDev = (PDD_PDEV)pso->dhpdev;
XLATEOBJ workXlo; SURFOBJ *psoToUse;
PCM_CURSOR_SHAPE_DATA pCursorShapeData; RECTL destRectl; POINTL sourcePt; unsigned ii; LONG lineLen; LONG colorLineLen; PBYTE srcPtr; PBYTE dstPtr; #ifdef DC_HICOLOR
unsigned targetBpp; #endif
ULONG palMono[2]; ULONG palBGR[256];
unsigned iCacheEntry; void *UserDefined; CHDataKeyContext CHContext;
DC_BEGIN_FN("DrvSetPointerShape");
/************************************************************************/ // Trace useful info about the cursor
/************************************************************************/ TRC_DBG((TB, "pso %#hlx psoMask %#hlx psoColor %#hlx pxlo %#hlx", pso, psoMask, psoColor, pxlo)); TRC_DBG((TB, "hot spot (%d, %d) x, y (%d, %d)", xHot, yHot, x, y)); TRC_DBG((TB, "Flags %#hlx", fl));
/************************************************************************/ /* check for the shared memory */ /************************************************************************/ if (pddShm != NULL && cmCursorCacheHandle != NULL) { /********************************************************************/ // Check to see if the WD got the last cursor we passed it.
//
// Potentially, we might get called and then called again before the
// WD gets round to sending the first cursor. This doesn't matter
// for a cursor that is already cached - its just a form of spoiling!
// But if it was a cursor definition packet that didn't get sent,
// then later on when we try to use it again, we will send the client
// instructions to use a cache entry for which it doesn't have any
// bits!
/********************************************************************/ if (pddShm->cm.cmBitsWaiting) { TRC_ALT((TB, "WD did not pick up cursor bits - removing entry %d", pddShm->cm.cmCacheEntry));
CH_RemoveCacheEntry(cmCursorCacheHandle, pddShm->cm.cmCacheEntry); }
/************************************************************************/ /* Returning SPS_ACCEPT_NOEXCLUDE means we can ignore prcl. */ /************************************************************************/ DC_IGNORE_PARAMETER(prcl); DC_IGNORE_PARAMETER(x); DC_IGNORE_PARAMETER(y);
/************************************************************************/ /* Set up the position information - in particular, the cursor can be */ /* unhidden via this function */ /************************************************************************/ if (x == -1) { /********************************************************************/ /* -1 means hide the pointer. */ /********************************************************************/ TRC_NRM((TB, "Hide the pointer")); pddShm->cm.cmHidden = TRUE; } else { if (pddShm->cm.cmHidden) { TRC_NRM((TB, "Unhide the pointer")); }
pddShm->cm.cmHidden = FALSE; }
// Set up a local pointer to the cursor shape data.
pCursorShapeData = &(pddShm->cm.cmCursorShapeData);
// Check mask pointer and cursor size. For no mask or too-large pointer,
// we send a null cursor. Note that the bitmap we are passed contains
// TWO masks, one 'above' the other, and so is in fact twice the
// height of the cursor, so we divide cy by 2.
if (psoMask == NULL || (psoMask->sizlBitmap.cx > CM_MAX_CURSOR_WIDTH) || ((psoMask->sizlBitmap.cy / 2) > CM_MAX_CURSOR_HEIGHT)) { // Note that NULL cursor is not the same as hiding the cursor using
// DrvMovePointer(), it is a transparent shape that cannot be
// changed without another DrvSetPointerShape() call.
TRC_NRM((TB, "Transparent or too-large cursor: psoMask=%p, " "width=%u, height=%u", psoMask, (psoMask != NULL ? psoMask->sizlBitmap.cx : 0), (psoMask != NULL ? psoMask->sizlBitmap.cy / 2 : 0))); CM_SET_NULL_CURSOR(pCursorShapeData); pddShm->cm.cmHidden = FALSE; pddShm->cm.cmCacheHit = FALSE; pddShm->cm.cmCursorStamp = cmNextCursorStamp++;
// We set a null cursor. Now tell GDI to simulate it.
// do this if it's alpha or if a mask is specified which
// means the cursor is too big per the test above
if ( fl & SPS_ALPHA || psoMask) { rc = SPS_DECLINE; SCH_DDOutputAvailable(ppDev, TRUE); } DC_QUIT; }
/************************************************************************/ // Now we look to see if the cursor is one we've sent before.
// We have to cache both the mask and any color information as
// potentially we could have the same _shape_ cursor but with different
// colors.
/************************************************************************/ CH_CreateKeyFromFirstData(&CHContext, psoMask->pvBits, psoMask->cjBits); if (psoColor != NULL) CH_CreateKeyFromNextData(&CHContext, psoColor->pvBits, psoColor->cjBits);
/************************************************************************/ /* Now we can look for the cursor in the cache */ /************************************************************************/ if (CH_SearchCache(cmCursorCacheHandle, CHContext.Key1, CHContext.Key2, &UserDefined, &iCacheEntry)) { TRC_NRM((TB, "Found cached cursor %d", iCacheEntry));
/********************************************************************/ /* Flag a cache hit */ /********************************************************************/ pddShm->cm.cmCacheHit = TRUE; pddShm->cm.cmCacheEntry = iCacheEntry; } else { /********************************************************************/ /* If we didn't find it, then let's cache it */ /********************************************************************/ pddShm->cm.cmCacheHit = FALSE; iCacheEntry = CH_CacheKey(cmCursorCacheHandle, CHContext.Key1, CHContext.Key2, NULL); pddShm->cm.cmCacheEntry = iCacheEntry; TRC_NRM((TB, "Cache new cursor: iEntry(%u)", iCacheEntry));
/********************************************************************/ // Tell the WD that there are bits waiting for it.
// We do this here no matter if we DC_QUIT later, to make sure
// we clean up the new cache entry on the next call if the WD has
// not picked up the bits.
/********************************************************************/ pddShm->cm.cmBitsWaiting = TRUE;
/********************************************************************/ /* 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. Note that the bitmap we are passed contains */ /* TWO masks, one 'above' the other, and so is in fact twice the */ /* height of the cursor */ /********************************************************************/ pCursorShapeData->hdr.ptHotSpot.x = xHot; pCursorShapeData->hdr.ptHotSpot.y = yHot;
TRC_NRM((TB, "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;
/********************************************************************/ /* lDelta may be negative for an inverted cursor */ /********************************************************************/ lineLen = (psoMask->lDelta >= 0 ? psoMask->lDelta : -psoMask->lDelta);
/********************************************************************/ /* set up the common parts of the shape header */ /********************************************************************/ pCursorShapeData->hdr.cPlanes = 1; pCursorShapeData->hdr.cbMaskRowWidth = (WORD)(((psoMask->sizlBitmap.cx + 15) & ~15) / 8);
/********************************************************************/ /* Check to see what format we want the cursor in */ /********************************************************************/ if (pddShm->cm.cmNativeColor) { TRC_NRM((TB, "Using native bpp %d", ppDev->cClientBitsPerPel));
/****************************************************************/ /* If we've been passed a mono cursor, we just get the bits as */ /* for the AND mask, flipping as we go */ /****************************************************************/ if (NULL == psoColor) { unsigned targetRowWidth;
TRC_NRM((TB, "Monochrome pointer")); /************************************************************/ /* Get the AND mask - this is always mono. Note that we */ /* have to flip it too */ /************************************************************/ TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask", psoMask->cjBits));
targetRowWidth = ((psoMask->sizlBitmap.cx + 15) & ~15) / 8; dstPtr = pCursorShapeData->data; srcPtr = (BYTE *)psoMask->pvScan0 + psoMask->cjBits / 2 - lineLen; for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, targetRowWidth); srcPtr -= lineLen; dstPtr += targetRowWidth; }
/************************************************************/ /* now the XOR mask */ /************************************************************/ pCursorShapeData->hdr.cBitsPerPel = 1; dstPtr = &(pCursorShapeData->data[targetRowWidth * pCursorShapeData->hdr.cy]); srcPtr = (BYTE *)psoMask->pvScan0 + psoMask->cjBits - lineLen;
pCursorShapeData->hdr.cbColorRowWidth = targetRowWidth;
for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, targetRowWidth); srcPtr -= lineLen; dstPtr += targetRowWidth; } } else { unsigned targetMaskRowWidth; TRC_NRM((TB, "Color pointer"));
/************************************************************/ /* Get the AND mask - this is always mono */ /************************************************************/ TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask", psoMask->cjBits));
targetMaskRowWidth = ((psoMask->sizlBitmap.cx + 15) & ~15) / 8; dstPtr = pCursorShapeData->data; srcPtr = (BYTE *)psoMask->pvScan0; for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, targetMaskRowWidth); srcPtr += lineLen; dstPtr += targetMaskRowWidth; }
/************************************************************/ /* and the XOR mask */ /************************************************************/ #ifndef DC_HICOLOR
pCursorShapeData->hdr.cBitsPerPel = (BYTE)ppDev->cClientBitsPerPel; #endif
colorLineLen = psoColor->lDelta >=0 ? psoColor->lDelta : -psoColor->lDelta;
pCursorShapeData->hdr.cbColorRowWidth = colorLineLen; #ifdef DC_HICOLOR
if (psoColor->iBitmapFormat < BMF_24BPP) { pCursorShapeData->hdr.cBitsPerPel = 1 << psoColor->iBitmapFormat; } else if (psoColor->iBitmapFormat == BMF_24BPP) { pCursorShapeData->hdr.cBitsPerPel = 24; } else if (psoColor->iBitmapFormat == BMF_32BPP) { pCursorShapeData->hdr.cBitsPerPel = 32; } else { TRC_ASSERT((FALSE), (TB, "Bitmap format not supported")); DC_QUIT; }
/********************************************************/ /* We've got a number of options at this point: */ /* */ /* - old clients only understand 8 or 24bpp cursors, so */ /* if the cursor is at 15/16bpp and its an old client, */ /* we need to convert it to 24bpp */ /* */ /* - 8bpp cursors assume the color information is in a */ /* color table; if we're running in hicolor, there */ /* won't be one, so we have to convert the cursor to a */ /* hicolor depth */ /* */ /* - anything else, we can just copy the bytes across */ /* and send them */ /* */ /********************************************************/ if ((!pddShm->cm.cmSendAnyColor && ((pCursorShapeData->hdr.cBitsPerPel == 15) || (pCursorShapeData->hdr.cBitsPerPel == 16))) || ((pCursorShapeData->hdr.cBitsPerPel == 8) && (ppDev->cClientBitsPerPel > 8))) { /****************************************************/ /* if we can send at any old color...
/****************************************************/ if (pddShm->cm.cmSendAnyColor) { /************************************************/ /* ...we'll convert to the client session color */ /* depth */ /************************************************/ targetBpp = ppDev->cClientBitsPerPel; } else { /************************************************/ /* otherwise we'll convert to 24bpp */ /************************************************/ targetBpp = 24; }
TRC_NRM((TB, "Convert %dbpp cursor to %d...", pCursorShapeData->hdr.cBitsPerPel, targetBpp));
/****************************************************/ /* Use the supplied xlate object to convert to the */ /* client bpp */ /****************************************************/ if (targetBpp == 24) { pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap24); pCursorShapeData->hdr.cBitsPerPel = 24; } else { pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap16); pCursorShapeData->hdr.cBitsPerPel = 16; } if (NULL == pWorkSurf) { TRC_ERR((TB, "Failed to lock work surface")); DC_QUIT; } TRC_DBG((TB, "Locked surface"));
/****************************************************/ /* Set up the 'to' rectangle */ /****************************************************/ destRectl.top = 0; destRectl.left = 0; destRectl.right = psoColor->sizlBitmap.cx; destRectl.bottom = psoColor->sizlBitmap.cy;
/****************************************************/ /* and the source start point */ /****************************************************/ 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 */ { TRC_ERR((TB, "Failed to Blt to work bitmap")); EngUnlockSurface(pWorkSurf); DC_QUIT; } TRC_DBG((TB, "Got the bits into the work bitmap"));
/****************************************************/ /* Finally we extract the color AND mask from the */ /* work bitmap */ /****************************************************/ TRC_NRM((TB, "Copy %d bytes of color", pWorkSurf->cjBits)); memcpy(&(pCursorShapeData->data[targetMaskRowWidth * pCursorShapeData->hdr.cy]), pWorkSurf->pvBits, pWorkSurf->cjBits); pCursorShapeData->hdr.cbColorRowWidth = pWorkSurf->lDelta;
EngUnlockSurface(pWorkSurf); } else { #endif
TRC_NRM((TB, "Copy %d bytes of %ubpp AND mask (lDelta %u)", colorLineLen * pCursorShapeData->hdr.cy, pCursorShapeData->hdr.cBitsPerPel, colorLineLen));
dstPtr = &(pCursorShapeData->data[targetMaskRowWidth * pCursorShapeData->hdr.cy]); srcPtr = (BYTE *)psoColor->pvScan0; for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, colorLineLen); srcPtr += psoColor->lDelta; dstPtr += colorLineLen; }
#ifdef DC_HICOLOR
} #endif
// {
// memcpy(dstPtr, srcPtr, lineLen);
// srcPtr += colorLineLen;
// dstPtr += colorLineLen;
// }
} } else { /****************************************************************/ // Now we need to blt the bitmap in to our work bitmap at
// 24bpp and get the bits from there.
/****************************************************************/ TRC_NRM((TB, "Forcing 24bpp")); pCursorShapeData->hdr.cBitsPerPel = 24;
/****************************************************************/ /* Get the AND mask - this is always mono */ /****************************************************************/ TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask", psoMask->cjBits/2))
dstPtr = pCursorShapeData->data; srcPtr = (BYTE *)psoMask->pvScan0; for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--) { memcpy(dstPtr, srcPtr, lineLen); srcPtr += lineLen; dstPtr += lineLen; }
/****************************************************************/ /* If we've been passed a mono cursor, we need to set up our */ /* own translation object, complete with color table */ /****************************************************************/ if (NULL == psoColor) { TRC_NRM((TB, "Monochrome pointer"));
// Row Width should be LONG aligned
pCursorShapeData->hdr.cbColorRowWidth = (psoMask->sizlBitmap.cx * pCursorShapeData->hdr.cBitsPerPel / 8 + 3) & ~3;
palMono[0] = 0; palMono[1] = 0xFFFFFFFF;
workXlo.iUniq = 0; workXlo.flXlate = XO_TABLE; workXlo.iSrcType = PAL_INDEXED; workXlo.iDstType = PAL_RGB; workXlo.cEntries = 2; workXlo.pulXlate = palMono;
/************************************************************/ /* Set up the 'to' rectangle */ /************************************************************/ destRectl.top = 0; destRectl.left = 0; destRectl.right = psoMask->sizlBitmap.cx; destRectl.bottom = psoMask->sizlBitmap.cy / 2;
/************************************************************/ /* the source AND mask is the 'lower' half of the supplied */ /* bitmap */ /************************************************************/ sourcePt.x = 0; sourcePt.y = psoMask->sizlBitmap.cy / 2;
/************************************************************/ /* and set up a pointer to the correct SO to use */ /************************************************************/ psoToUse = psoMask; } else { /************************************************************/ /* check that we're at 8bpp - this won't work if not */ /************************************************************/ TRC_ASSERT( (ppDev->cProtocolBitsPerPel == 8), (TB, "Palette at %d bpp", ppDev->cProtocolBitsPerPel) );
colorLineLen = psoColor->lDelta >= 0 ? psoColor->lDelta : -psoColor->lDelta; pCursorShapeData->hdr.cbColorRowWidth = colorLineLen * pCursorShapeData->hdr.cBitsPerPel / 8;
if (psoColor->iBitmapFormat <= BMF_8BPP) {
/************************************************************/ /* For color cursors, the supplied XLATEOBJ is set up to */ /* convert from the cursor bpp to the screen bpp - which in */ /* most cases for us is a no-op since we will most often be */ /* at 8bpp (the maximum color depth we support). However, */ /* we actually need to convert to 24bpp for the wire */ /* format, which requires a change to the XLATEOBJ. We */ /* can't do this in place, since the XLATEOBJ we are passed */ /* seems to be used elsewhere - not least to display the */ /* desktop icons - so we set up our own */ /************************************************************/ workXlo.iUniq = 0; /* don't cache */ /************************************************************/ /* Set up to use the current palette (which is fortunately */ /* held in the DD_PDEV structure) */ /************************************************************/ workXlo.flXlate = XO_TABLE; /* we provide a lookup table */ /* to do the translation */ workXlo.iSrcType = PAL_INDEXED;/* pel values in the src bmp */ /* are indices into the table*/ workXlo.iDstType = PAL_RGB; /* entries in the table are */ /* RGB values for the dst bmp*/ workXlo.cEntries = 1 << ppDev->cProtocolBitsPerPel; /* which has this many entries */ /************************************************************/ /* Now set up the palette to use in the XLATEOBJ. We have */ /* the current palette stored in the DD_PDEV structure - */ /* unfortunately it is in RGB format and we need BGR... */ /************************************************************/ for (ii = 0 ; ii < workXlo.cEntries; ii++) { palBGR[ii] = (ppDev->Palette[ii].peRed << 16) | (ppDev->Palette[ii].peGreen << 8) | (ppDev->Palette[ii].peBlue); } workXlo.pulXlate = palBGR; /************************************************************/ /* Set up the 'to' rectangle */ /************************************************************/ destRectl.top = 0; destRectl.left = 0; destRectl.right = psoColor->sizlBitmap.cx; destRectl.bottom = psoColor->sizlBitmap.cy; /************************************************************/ /* and the source start point */ /************************************************************/ sourcePt.x = 0; sourcePt.y = 0; /************************************************************/ /* set up a pointer to the correct SO to use */ /************************************************************/ psoToUse = psoColor; } else { // We got a high color cursor to translate to 24bpp workbitmap
// can't easily simulate the XLATEOBJ, since this is TS4 code path
// only, we will just let it fall back to GDI bitmap cursor!
CM_SET_NULL_CURSOR(pCursorShapeData); pddShm->cm.cmHidden = FALSE; pddShm->cm.cmCacheHit = FALSE; pddShm->cm.cmCursorStamp = cmNextCursorStamp++; rc = SPS_DECLINE; SCH_DDOutputAvailable(ppDev, TRUE); DC_QUIT; } }
// Lock the work bitmap to get a surface to pass to EngBitBlt.
pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap24); if (pWorkSurf != NULL) { BOOL RetVal;
TRC_DBG((TB, "Locked surface"));
// Do the blt.
RetVal = EngBitBlt(pWorkSurf, psoToUse, NULL, /* mask surface */ NULL, /* clip object */ &workXlo, /* XLATE object */ &destRectl, &sourcePt, NULL, /* mask origin */ NULL, /* brush */ NULL, /* brush origin */ 0xcccc); /* SRCCPY */
EngUnlockSurface(pWorkSurf); if (RetVal) { TRC_DBG((TB, "Got the bits into the work bitmap")); } else { TRC_ERR((TB, "Failed to Blt to work bitmap")); goto FailBlt; } } else { TRC_ERR((TB, "Failed to lock work surface"));
FailBlt: // Set the cursor bits to all black. On the client,
// this will be seen as the correct mask but a black
// region inside where the cursor color bits would have
// been.
memset(pWorkSurf->pvBits, 0, pWorkSurf->cjBits);
// We do not DC_QUIT here, we want to complete the cursor
// creation even if the output is mostly wrong, since
// we've already cached the bits.
}
/****************************************************************/ /* Finally we extract the color AND mask from the work bitmap */ /****************************************************************/ TRC_NRM((TB, "Copy %d bytes of color", pWorkSurf->cjBits));
memcpy(&(pCursorShapeData->data[psoMask->cjBits / 2]), pWorkSurf->pvBits, pWorkSurf->cjBits); } }
/************************************************************************/ /* Set the cursor stamp */ /************************************************************************/ pddShm->cm.cmCursorStamp = cmNextCursorStamp++;
/************************************************************************/ /* Tell the scheduler that we have some new cursor info */ /************************************************************************/ SCH_DDOutputAvailable(ppDev, FALSE); } else { TRC_ERR((TB, "shared memory is not allocated or invalid cursor handle: " "pddshm=%p, cmCursorCacheHandle=%p", pddShm, cmCursorCacheHandle)); }
DC_EXIT_POINT: DC_END_FN();
return(rc); } /* DrvSetPointerShape */
|