/****************************************************************************/ // ncmapi.c // // RDP Cursor Manager API functions. // // Copyright (C) 1996-2000 Microsoft Corporation /****************************************************************************/ #include #pragma hdrstop #define TRC_FILE "ncmapi" #include #include #include #define DC_INCLUDE_DATA #include #undef DC_INCLUDE_DATA #include #include /****************************************************************************/ /* 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 */