Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1031 lines
47 KiB

  1. /****************************************************************************/
  2. // ncmapi.c
  3. //
  4. // RDP Cursor Manager API functions.
  5. //
  6. // Copyright (C) 1996-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #pragma hdrstop
  10. #define TRC_FILE "ncmapi"
  11. #include <adcg.h>
  12. #include <ncmdisp.h>
  13. #include <nschdisp.h>
  14. #define DC_INCLUDE_DATA
  15. #include <ndddata.c>
  16. #undef DC_INCLUDE_DATA
  17. #include <ncmdata.c>
  18. #include <nchdisp.h>
  19. /****************************************************************************/
  20. /* Name: CM_DDInit */
  21. /* */
  22. /* Purpose: Initialises the display driver component of the cursor */
  23. /* manager. */
  24. /* */
  25. /* Returns: TRUE if successful, FALSE otherwise. */
  26. /* */
  27. /* Params: IN ppDev - pointer to pDev for work bitmap */
  28. /****************************************************************************/
  29. BOOL RDPCALL CM_DDInit(PDD_PDEV ppDev)
  30. {
  31. BOOL rc = TRUE;
  32. SIZEL bitmapSize;
  33. DC_BEGIN_FN("CM_DDInit");
  34. /************************************************************************/
  35. /* Allocate the work bitmap, at the local device resolution. Note that */
  36. /* we create it "top down" rather than the default of "bottom up" to */
  37. /* simplify copying data from the bitmap (we don't have to work out */
  38. /* offsets into the data - we can copy from the beginning). */
  39. /************************************************************************/
  40. bitmapSize.cx = CM_MAX_CURSOR_WIDTH;
  41. bitmapSize.cy = CM_MAX_CURSOR_HEIGHT;
  42. cmWorkBitmap24 = EngCreateBitmap(bitmapSize,
  43. TS_BYTES_IN_SCANLINE(bitmapSize.cx, 24), BMF_24BPP, BMF_TOPDOWN,
  44. NULL);
  45. #ifdef DC_HICOLOR
  46. cmWorkBitmap16 = EngCreateBitmap(bitmapSize,
  47. TS_BYTES_IN_SCANLINE(bitmapSize.cx, 16), BMF_16BPP, BMF_TOPDOWN,
  48. NULL);
  49. if (cmWorkBitmap16 == NULL)
  50. {
  51. /********************************************************************/
  52. /* We can carry on with reduced function without this one */
  53. /********************************************************************/
  54. TRC_ERR((TB, "Failed to create 16bpp work bitmap"));
  55. pddShm->cm.cmSendAnyColor = FALSE;
  56. }
  57. #endif
  58. if (cmWorkBitmap24 != NULL) {
  59. TRC_NRM((TB, "Created work bitmap successfully"));
  60. // Reset the cursor stamp.
  61. cmNextCursorStamp = 0;
  62. }
  63. else {
  64. TRC_ERR((TB, "Failed to create work bitmaps"));
  65. rc = FALSE;
  66. }
  67. DC_END_FN();
  68. return rc;
  69. }
  70. /****************************************************************************/
  71. /* Name: CM_Update */
  72. /* */
  73. /* Purpose: The capabilities may have changed */
  74. /****************************************************************************/
  75. void RDPCALL CM_Update(void)
  76. {
  77. PCHCACHEDATA pCacheData;
  78. DC_BEGIN_FN("CM_Update");
  79. /************************************************************************/
  80. /* Create the cursor cache. */
  81. /************************************************************************/
  82. if (cmCursorCacheHandle == NULL) {
  83. if (pddShm->cm.cmCacheSize) {
  84. pCacheData = (PCHCACHEDATA)EngAllocMem(0,
  85. CH_CalculateCacheSize(pddShm->cm.cmCacheSize),
  86. DD_ALLOC_TAG);
  87. if (pCacheData != NULL) {
  88. CH_InitCache(pCacheData, pddShm->cm.cmCacheSize, NULL,
  89. FALSE, FALSE, NULL);
  90. cmCursorCacheHandle = pCacheData;
  91. }
  92. else {
  93. TRC_ERR((TB, "Failed to create cache: cEntries(%u)",
  94. pddShm->cm.cmCacheSize));
  95. }
  96. }
  97. else {
  98. TRC_ERR((TB, "Zero size Cursor Cache"));
  99. }
  100. }
  101. // Else just clear it for synchonization purposes.
  102. else {
  103. CH_ClearCache(cmCursorCacheHandle);
  104. }
  105. DC_END_FN();
  106. } /* CM_Update */
  107. /****************************************************************************/
  108. /* Name: CM_DDDisc */
  109. /* */
  110. /* Purpose: Disconnects the display driver component of the cursor */
  111. /* manager. */
  112. /****************************************************************************/
  113. void RDPCALL CM_DDDisc(void)
  114. {
  115. DC_BEGIN_FN("CM_DDDisc");
  116. /************************************************************************/
  117. /* Free up the cursor cache */
  118. /************************************************************************/
  119. if (cmCursorCacheHandle != 0) {
  120. TRC_NRM((TB, "Destroying CM cache"));
  121. CH_ClearCache(cmCursorCacheHandle);
  122. EngFreeMem(cmCursorCacheHandle);
  123. cmCursorCacheHandle = 0;
  124. }
  125. DC_END_FN();
  126. } /* CM_DDDisc */
  127. /****************************************************************************/
  128. /* Name: CM_DDTerm */
  129. /* */
  130. /* Purpose: Terminates the display driver component of the cursor */
  131. /* manager. */
  132. /* */
  133. /* Returns: TRUE if successful, FALSE otherwise. */
  134. /****************************************************************************/
  135. void RDPCALL CM_DDTerm(void)
  136. {
  137. DC_BEGIN_FN("CM_DDTerm");
  138. /************************************************************************/
  139. /* Destroy the work bitmaps. Despite its name, EngDeleteSurface is the */
  140. /* correct function to do this. */
  141. /************************************************************************/
  142. #ifdef DC_HICOLOR
  143. if (cmWorkBitmap24)
  144. {
  145. if (!EngDeleteSurface((HSURF)cmWorkBitmap24))
  146. {
  147. TRC_ERR((TB, "Failed to delete 24bpp work bitmap"));
  148. }
  149. }
  150. if (cmWorkBitmap16)
  151. {
  152. if (!EngDeleteSurface((HSURF)cmWorkBitmap16))
  153. {
  154. TRC_ERR((TB, "Failed to delete 16bpp work bitmap"));
  155. }
  156. }
  157. #else
  158. if (cmWorkBitmap24 != NULL) {
  159. if (!EngDeleteSurface((HSURF)cmWorkBitmap24)) {
  160. TRC_ERR((TB, "Failed to delete work bitmap"));
  161. }
  162. }
  163. #endif
  164. /************************************************************************/
  165. /* Free up the cursor cache */
  166. /************************************************************************/
  167. if (cmCursorCacheHandle != 0) {
  168. TRC_NRM((TB, "Destroying CM cache"));
  169. CH_ClearCache(cmCursorCacheHandle);
  170. EngFreeMem(cmCursorCacheHandle);
  171. cmCursorCacheHandle = 0;
  172. }
  173. TRC_NRM((TB, "CM terminated"));
  174. DC_END_FN();
  175. } /* CM_DDTerm */
  176. /****************************************************************************/
  177. /* CM_InitShm */
  178. /* */
  179. /* Initializes CM Shared Memory. */
  180. /****************************************************************************/
  181. void RDPCALL CM_InitShm(void)
  182. {
  183. DC_BEGIN_FN("CM_InitShm");
  184. // Set up initial contents of Shm memory, since it is not zeroed on
  185. // init. Don't set up the initially unused cursor shape data.
  186. // NOTE: cmCursorShapeData is specifically placed at the end of
  187. // CM_SHARED_DATA to allow this memset to work. If you change
  188. // the shared mem struct be sure this gets changed.
  189. memset(&pddShm->cm, 0, (unsigned)FIELDOFFSET(CM_SHARED_DATA,
  190. cmCursorShapeData.data));
  191. // Set the last known position to something impossible. The IM
  192. // periodic processing will not move the client's mouse until a
  193. // sensible value is found here, ie until the client has sent us a
  194. // mouse position and it has percolated through to the DD. This
  195. // avoids the problem of the mouse leaping to 0,0 on connection.
  196. pddShm->cm.cmCursorPos.x = 0xffffffff;
  197. DC_END_FN();
  198. }
  199. /****************************************************************************/
  200. /* */
  201. /* DrvMovePointer - see NT DDK documentation. */
  202. /* */
  203. /****************************************************************************/
  204. VOID DrvMovePointer(SURFOBJ *pso, LONG x, LONG y, RECTL *prcl)
  205. {
  206. DC_BEGIN_FN(("DrvMovePointer"));
  207. //
  208. // Win32k hides the hardware cursor by calling the MovePointer
  209. // entry point with (-1,-1). Treat this as a procedural move
  210. // and pass it on to the real worker function
  211. //
  212. // All other paths are handled directly by win32k calling
  213. // DrvMovePointerEx with the right flags
  214. //
  215. if (-1 == x && -1 == y) {
  216. DrvMovePointerEx(pso, x, y, MP_PROCEDURAL);
  217. }
  218. DC_END_FN();
  219. }
  220. //
  221. // DrvMovePointerEx
  222. //
  223. // Params:
  224. // x,y - new mouse position.
  225. // ulFlags - source of move (see winddits.h).
  226. //
  227. // This function replaces the regular DrvMovePointer entry point
  228. // by also sending us an event source parameter.
  229. //
  230. // This allows us to determine if we should ignore the update (e.g
  231. // if it originates from the primary stack). Or send it down to the
  232. // client in the case of a server initiated move or a shadow move.
  233. //
  234. // We ignore updates from the primary stack because by definition
  235. // those came from the client so it doesn't need feedback from the
  236. // server.
  237. //
  238. BOOL DrvMovePointerEx(SURFOBJ *pso, LONG x, LONG y, ULONG ulFlags)
  239. {
  240. BOOL fTriggerUpdate = FALSE;
  241. PDD_PDEV ppDev = (PDD_PDEV)pso->dhpdev;
  242. DC_BEGIN_FN("CM_DrvMovePointerEx");
  243. if (pddShm != NULL) {
  244. if ((ulFlags & MP_TERMSRV_SHADOW) ||
  245. (ulFlags & MP_PROCEDURAL))
  246. {
  247. if (x == -1) {
  248. // -1 means hide the pointer.
  249. TRC_NRM((TB, "Hide the pointer"));
  250. pddShm->cm.cmHidden = TRUE;
  251. }
  252. else {
  253. // Pointer is not hidden.
  254. if (pddShm->cm.cmHidden) {
  255. TRC_NRM((TB, "Unhide the pointer"));
  256. }
  257. pddShm->cm.cmHidden = FALSE;
  258. //
  259. // We always update the position for server initated moves.
  260. //
  261. pddShm->cm.cmCursorPos.x = x;
  262. pddShm->cm.cmCursorPos.y = y;
  263. //
  264. // Send an update so we don't need to wait
  265. // for the next output flush.
  266. //
  267. fTriggerUpdate = TRUE;
  268. // Set the cursor moved flag.
  269. pddShm->cm.cmCursorMoved = TRUE;
  270. }
  271. }
  272. else
  273. {
  274. TRC_ALT((TB,"Discarding move (%d,%d) - src 0x%x",
  275. x,y, ulFlags));
  276. }
  277. if (fTriggerUpdate)
  278. {
  279. //
  280. // Tell the scheduler to send an update
  281. //
  282. SCH_DDOutputAvailable(ppDev, FALSE);
  283. }
  284. }
  285. else {
  286. TRC_DBG((TB, "Ignoring move to %d %d as no shr mem yet", x,y));
  287. }
  288. DC_END_FN();
  289. return TRUE;
  290. }
  291. /****************************************************************************/
  292. /* */
  293. /* DrvSetPointerShape - see winddi.h */
  294. /* */
  295. /****************************************************************************/
  296. ULONG DrvSetPointerShape(SURFOBJ *pso,
  297. SURFOBJ *psoMask,
  298. SURFOBJ *psoColor,
  299. XLATEOBJ *pxlo,
  300. LONG xHot,
  301. LONG yHot,
  302. LONG x,
  303. LONG y,
  304. RECTL *prcl,
  305. FLONG fl)
  306. {
  307. ULONG rc = SPS_ACCEPT_NOEXCLUDE;
  308. SURFOBJ *pWorkSurf;
  309. PDD_PDEV ppDev = (PDD_PDEV)pso->dhpdev;
  310. XLATEOBJ workXlo;
  311. SURFOBJ *psoToUse;
  312. PCM_CURSOR_SHAPE_DATA pCursorShapeData;
  313. RECTL destRectl;
  314. POINTL sourcePt;
  315. unsigned ii;
  316. LONG lineLen;
  317. LONG colorLineLen;
  318. PBYTE srcPtr;
  319. PBYTE dstPtr;
  320. #ifdef DC_HICOLOR
  321. unsigned targetBpp;
  322. #endif
  323. ULONG palMono[2];
  324. ULONG palBGR[256];
  325. unsigned iCacheEntry;
  326. void *UserDefined;
  327. CHDataKeyContext CHContext;
  328. DC_BEGIN_FN("DrvSetPointerShape");
  329. /************************************************************************/
  330. // Trace useful info about the cursor
  331. /************************************************************************/
  332. TRC_DBG((TB, "pso %#hlx psoMask %#hlx psoColor %#hlx pxlo %#hlx",
  333. pso, psoMask, psoColor, pxlo));
  334. TRC_DBG((TB, "hot spot (%d, %d) x, y (%d, %d)", xHot, yHot, x, y));
  335. TRC_DBG((TB, "Flags %#hlx", fl));
  336. /************************************************************************/
  337. /* check for the shared memory */
  338. /************************************************************************/
  339. if (pddShm != NULL && cmCursorCacheHandle != NULL)
  340. {
  341. /********************************************************************/
  342. // Check to see if the WD got the last cursor we passed it.
  343. //
  344. // Potentially, we might get called and then called again before the
  345. // WD gets round to sending the first cursor. This doesn't matter
  346. // for a cursor that is already cached - its just a form of spoiling!
  347. // But if it was a cursor definition packet that didn't get sent,
  348. // then later on when we try to use it again, we will send the client
  349. // instructions to use a cache entry for which it doesn't have any
  350. // bits!
  351. /********************************************************************/
  352. if (pddShm->cm.cmBitsWaiting)
  353. {
  354. TRC_ALT((TB, "WD did not pick up cursor bits - removing entry %d",
  355. pddShm->cm.cmCacheEntry));
  356. CH_RemoveCacheEntry(cmCursorCacheHandle,
  357. pddShm->cm.cmCacheEntry);
  358. }
  359. /************************************************************************/
  360. /* Returning SPS_ACCEPT_NOEXCLUDE means we can ignore prcl. */
  361. /************************************************************************/
  362. DC_IGNORE_PARAMETER(prcl);
  363. DC_IGNORE_PARAMETER(x);
  364. DC_IGNORE_PARAMETER(y);
  365. /************************************************************************/
  366. /* Set up the position information - in particular, the cursor can be */
  367. /* unhidden via this function */
  368. /************************************************************************/
  369. if (x == -1) {
  370. /********************************************************************/
  371. /* -1 means hide the pointer. */
  372. /********************************************************************/
  373. TRC_NRM((TB, "Hide the pointer"));
  374. pddShm->cm.cmHidden = TRUE;
  375. }
  376. else {
  377. if (pddShm->cm.cmHidden) {
  378. TRC_NRM((TB, "Unhide the pointer"));
  379. }
  380. pddShm->cm.cmHidden = FALSE;
  381. }
  382. // Set up a local pointer to the cursor shape data.
  383. pCursorShapeData = &(pddShm->cm.cmCursorShapeData);
  384. // Check mask pointer and cursor size. For no mask or too-large pointer,
  385. // we send a null cursor. Note that the bitmap we are passed contains
  386. // TWO masks, one 'above' the other, and so is in fact twice the
  387. // height of the cursor, so we divide cy by 2.
  388. if (psoMask == NULL ||
  389. (psoMask->sizlBitmap.cx > CM_MAX_CURSOR_WIDTH) ||
  390. ((psoMask->sizlBitmap.cy / 2) > CM_MAX_CURSOR_HEIGHT)) {
  391. // Note that NULL cursor is not the same as hiding the cursor using
  392. // DrvMovePointer(), it is a transparent shape that cannot be
  393. // changed without another DrvSetPointerShape() call.
  394. TRC_NRM((TB, "Transparent or too-large cursor: psoMask=%p, "
  395. "width=%u, height=%u", psoMask,
  396. (psoMask != NULL ? psoMask->sizlBitmap.cx : 0),
  397. (psoMask != NULL ? psoMask->sizlBitmap.cy / 2 : 0)));
  398. CM_SET_NULL_CURSOR(pCursorShapeData);
  399. pddShm->cm.cmHidden = FALSE;
  400. pddShm->cm.cmCacheHit = FALSE;
  401. pddShm->cm.cmCursorStamp = cmNextCursorStamp++;
  402. // We set a null cursor. Now tell GDI to simulate it.
  403. // do this if it's alpha or if a mask is specified which
  404. // means the cursor is too big per the test above
  405. if ( fl & SPS_ALPHA || psoMask) {
  406. rc = SPS_DECLINE;
  407. SCH_DDOutputAvailable(ppDev, TRUE);
  408. }
  409. DC_QUIT;
  410. }
  411. /************************************************************************/
  412. // Now we look to see if the cursor is one we've sent before.
  413. // We have to cache both the mask and any color information as
  414. // potentially we could have the same _shape_ cursor but with different
  415. // colors.
  416. /************************************************************************/
  417. CH_CreateKeyFromFirstData(&CHContext, psoMask->pvBits, psoMask->cjBits);
  418. if (psoColor != NULL)
  419. CH_CreateKeyFromNextData(&CHContext, psoColor->pvBits,
  420. psoColor->cjBits);
  421. /************************************************************************/
  422. /* Now we can look for the cursor in the cache */
  423. /************************************************************************/
  424. if (CH_SearchCache(cmCursorCacheHandle, CHContext.Key1, CHContext.Key2,
  425. &UserDefined, &iCacheEntry))
  426. {
  427. TRC_NRM((TB, "Found cached cursor %d", iCacheEntry));
  428. /********************************************************************/
  429. /* Flag a cache hit */
  430. /********************************************************************/
  431. pddShm->cm.cmCacheHit = TRUE;
  432. pddShm->cm.cmCacheEntry = iCacheEntry;
  433. }
  434. else
  435. {
  436. /********************************************************************/
  437. /* If we didn't find it, then let's cache it */
  438. /********************************************************************/
  439. pddShm->cm.cmCacheHit = FALSE;
  440. iCacheEntry = CH_CacheKey(cmCursorCacheHandle, CHContext.Key1,
  441. CHContext.Key2, NULL);
  442. pddShm->cm.cmCacheEntry = iCacheEntry;
  443. TRC_NRM((TB, "Cache new cursor: iEntry(%u)", iCacheEntry));
  444. /********************************************************************/
  445. // Tell the WD that there are bits waiting for it.
  446. // We do this here no matter if we DC_QUIT later, to make sure
  447. // we clean up the new cache entry on the next call if the WD has
  448. // not picked up the bits.
  449. /********************************************************************/
  450. pddShm->cm.cmBitsWaiting = TRUE;
  451. /********************************************************************/
  452. /* We've been passed a system cursor. Fill in the header for our */
  453. /* local cursor. We can get the hot spot position and cursor size */
  454. /* and width easily. Note that the bitmap we are passed contains */
  455. /* TWO masks, one 'above' the other, and so is in fact twice the */
  456. /* height of the cursor */
  457. /********************************************************************/
  458. pCursorShapeData->hdr.ptHotSpot.x = xHot;
  459. pCursorShapeData->hdr.ptHotSpot.y = yHot;
  460. TRC_NRM((TB, "Pointer mask is %#hlx by %#hlx pixels (lDelta: %#hlx)",
  461. psoMask->sizlBitmap.cx,
  462. psoMask->sizlBitmap.cy,
  463. psoMask->lDelta));
  464. pCursorShapeData->hdr.cx = (WORD)psoMask->sizlBitmap.cx;
  465. pCursorShapeData->hdr.cy = (WORD)psoMask->sizlBitmap.cy / 2;
  466. /********************************************************************/
  467. /* lDelta may be negative for an inverted cursor */
  468. /********************************************************************/
  469. lineLen = (psoMask->lDelta >= 0 ? psoMask->lDelta : -psoMask->lDelta);
  470. /********************************************************************/
  471. /* set up the common parts of the shape header */
  472. /********************************************************************/
  473. pCursorShapeData->hdr.cPlanes = 1;
  474. pCursorShapeData->hdr.cbMaskRowWidth =
  475. (WORD)(((psoMask->sizlBitmap.cx + 15) & ~15) / 8);
  476. /********************************************************************/
  477. /* Check to see what format we want the cursor in */
  478. /********************************************************************/
  479. if (pddShm->cm.cmNativeColor)
  480. {
  481. TRC_NRM((TB, "Using native bpp %d", ppDev->cClientBitsPerPel));
  482. /****************************************************************/
  483. /* If we've been passed a mono cursor, we just get the bits as */
  484. /* for the AND mask, flipping as we go */
  485. /****************************************************************/
  486. if (NULL == psoColor)
  487. {
  488. unsigned targetRowWidth;
  489. TRC_NRM((TB, "Monochrome pointer"));
  490. /************************************************************/
  491. /* Get the AND mask - this is always mono. Note that we */
  492. /* have to flip it too */
  493. /************************************************************/
  494. TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask",
  495. psoMask->cjBits));
  496. targetRowWidth = ((psoMask->sizlBitmap.cx + 15) & ~15) / 8;
  497. dstPtr = pCursorShapeData->data;
  498. srcPtr = (BYTE *)psoMask->pvScan0
  499. + psoMask->cjBits / 2
  500. - lineLen;
  501. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  502. {
  503. memcpy(dstPtr, srcPtr, targetRowWidth);
  504. srcPtr -= lineLen;
  505. dstPtr += targetRowWidth;
  506. }
  507. /************************************************************/
  508. /* now the XOR mask */
  509. /************************************************************/
  510. pCursorShapeData->hdr.cBitsPerPel = 1;
  511. dstPtr = &(pCursorShapeData->data[targetRowWidth *
  512. pCursorShapeData->hdr.cy]);
  513. srcPtr = (BYTE *)psoMask->pvScan0
  514. + psoMask->cjBits - lineLen;
  515. pCursorShapeData->hdr.cbColorRowWidth = targetRowWidth;
  516. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  517. {
  518. memcpy(dstPtr, srcPtr, targetRowWidth);
  519. srcPtr -= lineLen;
  520. dstPtr += targetRowWidth;
  521. }
  522. }
  523. else
  524. {
  525. unsigned targetMaskRowWidth;
  526. TRC_NRM((TB, "Color pointer"));
  527. /************************************************************/
  528. /* Get the AND mask - this is always mono */
  529. /************************************************************/
  530. TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask",
  531. psoMask->cjBits));
  532. targetMaskRowWidth = ((psoMask->sizlBitmap.cx + 15) & ~15) / 8;
  533. dstPtr = pCursorShapeData->data;
  534. srcPtr = (BYTE *)psoMask->pvScan0;
  535. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  536. {
  537. memcpy(dstPtr, srcPtr, targetMaskRowWidth);
  538. srcPtr += lineLen;
  539. dstPtr += targetMaskRowWidth;
  540. }
  541. /************************************************************/
  542. /* and the XOR mask */
  543. /************************************************************/
  544. #ifndef DC_HICOLOR
  545. pCursorShapeData->hdr.cBitsPerPel =
  546. (BYTE)ppDev->cClientBitsPerPel;
  547. #endif
  548. colorLineLen = psoColor->lDelta >=0 ? psoColor->lDelta :
  549. -psoColor->lDelta;
  550. pCursorShapeData->hdr.cbColorRowWidth = colorLineLen;
  551. #ifdef DC_HICOLOR
  552. if (psoColor->iBitmapFormat < BMF_24BPP) {
  553. pCursorShapeData->hdr.cBitsPerPel = 1 << psoColor->iBitmapFormat;
  554. }
  555. else if (psoColor->iBitmapFormat == BMF_24BPP) {
  556. pCursorShapeData->hdr.cBitsPerPel = 24;
  557. }
  558. else if (psoColor->iBitmapFormat == BMF_32BPP) {
  559. pCursorShapeData->hdr.cBitsPerPel = 32;
  560. }
  561. else {
  562. TRC_ASSERT((FALSE), (TB, "Bitmap format not supported"));
  563. DC_QUIT;
  564. }
  565. /********************************************************/
  566. /* We've got a number of options at this point: */
  567. /* */
  568. /* - old clients only understand 8 or 24bpp cursors, so */
  569. /* if the cursor is at 15/16bpp and its an old client, */
  570. /* we need to convert it to 24bpp */
  571. /* */
  572. /* - 8bpp cursors assume the color information is in a */
  573. /* color table; if we're running in hicolor, there */
  574. /* won't be one, so we have to convert the cursor to a */
  575. /* hicolor depth */
  576. /* */
  577. /* - anything else, we can just copy the bytes across */
  578. /* and send them */
  579. /* */
  580. /********************************************************/
  581. if ((!pddShm->cm.cmSendAnyColor &&
  582. ((pCursorShapeData->hdr.cBitsPerPel == 15) ||
  583. (pCursorShapeData->hdr.cBitsPerPel == 16)))
  584. || ((pCursorShapeData->hdr.cBitsPerPel == 8) &&
  585. (ppDev->cClientBitsPerPel > 8)))
  586. {
  587. /****************************************************/
  588. /* if we can send at any old color...
  589. /****************************************************/
  590. if (pddShm->cm.cmSendAnyColor)
  591. {
  592. /************************************************/
  593. /* ...we'll convert to the client session color */
  594. /* depth */
  595. /************************************************/
  596. targetBpp = ppDev->cClientBitsPerPel;
  597. }
  598. else
  599. {
  600. /************************************************/
  601. /* otherwise we'll convert to 24bpp */
  602. /************************************************/
  603. targetBpp = 24;
  604. }
  605. TRC_NRM((TB, "Convert %dbpp cursor to %d...",
  606. pCursorShapeData->hdr.cBitsPerPel, targetBpp));
  607. /****************************************************/
  608. /* Use the supplied xlate object to convert to the */
  609. /* client bpp */
  610. /****************************************************/
  611. if (targetBpp == 24)
  612. {
  613. pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap24);
  614. pCursorShapeData->hdr.cBitsPerPel = 24;
  615. }
  616. else
  617. {
  618. pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap16);
  619. pCursorShapeData->hdr.cBitsPerPel = 16;
  620. }
  621. if (NULL == pWorkSurf)
  622. {
  623. TRC_ERR((TB, "Failed to lock work surface"));
  624. DC_QUIT;
  625. }
  626. TRC_DBG((TB, "Locked surface"));
  627. /****************************************************/
  628. /* Set up the 'to' rectangle */
  629. /****************************************************/
  630. destRectl.top = 0;
  631. destRectl.left = 0;
  632. destRectl.right = psoColor->sizlBitmap.cx;
  633. destRectl.bottom = psoColor->sizlBitmap.cy;
  634. /****************************************************/
  635. /* and the source start point */
  636. /****************************************************/
  637. sourcePt.x = 0;
  638. sourcePt.y = 0;
  639. if (!EngBitBlt(pWorkSurf,
  640. psoColor,
  641. NULL, /* mask surface */
  642. NULL, /* clip object */
  643. pxlo, /* XLATE object */
  644. &destRectl,
  645. &sourcePt,
  646. NULL, /* mask origin */
  647. NULL, /* brush */
  648. NULL, /* brush origin */
  649. 0xcccc)) /* SRCCPY */
  650. {
  651. TRC_ERR((TB, "Failed to Blt to work bitmap"));
  652. EngUnlockSurface(pWorkSurf);
  653. DC_QUIT;
  654. }
  655. TRC_DBG((TB, "Got the bits into the work bitmap"));
  656. /****************************************************/
  657. /* Finally we extract the color AND mask from the */
  658. /* work bitmap */
  659. /****************************************************/
  660. TRC_NRM((TB, "Copy %d bytes of color",
  661. pWorkSurf->cjBits));
  662. memcpy(&(pCursorShapeData->data[targetMaskRowWidth *
  663. pCursorShapeData->hdr.cy]),
  664. pWorkSurf->pvBits,
  665. pWorkSurf->cjBits);
  666. pCursorShapeData->hdr.cbColorRowWidth = pWorkSurf->lDelta;
  667. EngUnlockSurface(pWorkSurf);
  668. }
  669. else
  670. {
  671. #endif
  672. TRC_NRM((TB, "Copy %d bytes of %ubpp AND mask (lDelta %u)",
  673. colorLineLen * pCursorShapeData->hdr.cy,
  674. pCursorShapeData->hdr.cBitsPerPel,
  675. colorLineLen));
  676. dstPtr = &(pCursorShapeData->data[targetMaskRowWidth *
  677. pCursorShapeData->hdr.cy]);
  678. srcPtr = (BYTE *)psoColor->pvScan0;
  679. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  680. {
  681. memcpy(dstPtr, srcPtr, colorLineLen);
  682. srcPtr += psoColor->lDelta;
  683. dstPtr += colorLineLen;
  684. }
  685. #ifdef DC_HICOLOR
  686. }
  687. #endif
  688. // {
  689. // memcpy(dstPtr, srcPtr, lineLen);
  690. // srcPtr += colorLineLen;
  691. // dstPtr += colorLineLen;
  692. // }
  693. }
  694. }
  695. else
  696. {
  697. /****************************************************************/
  698. // Now we need to blt the bitmap in to our work bitmap at
  699. // 24bpp and get the bits from there.
  700. /****************************************************************/
  701. TRC_NRM((TB, "Forcing 24bpp"));
  702. pCursorShapeData->hdr.cBitsPerPel = 24;
  703. /****************************************************************/
  704. /* Get the AND mask - this is always mono */
  705. /****************************************************************/
  706. TRC_NRM((TB, "Copy %d bytes of 1bpp AND mask", psoMask->cjBits/2))
  707. dstPtr = pCursorShapeData->data;
  708. srcPtr = (BYTE *)psoMask->pvScan0;
  709. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  710. {
  711. memcpy(dstPtr, srcPtr, lineLen);
  712. srcPtr += lineLen;
  713. dstPtr += lineLen;
  714. }
  715. /****************************************************************/
  716. /* If we've been passed a mono cursor, we need to set up our */
  717. /* own translation object, complete with color table */
  718. /****************************************************************/
  719. if (NULL == psoColor)
  720. {
  721. TRC_NRM((TB, "Monochrome pointer"));
  722. // Row Width should be LONG aligned
  723. pCursorShapeData->hdr.cbColorRowWidth =
  724. (psoMask->sizlBitmap.cx *
  725. pCursorShapeData->hdr.cBitsPerPel / 8 + 3) & ~3;
  726. palMono[0] = 0;
  727. palMono[1] = 0xFFFFFFFF;
  728. workXlo.iUniq = 0;
  729. workXlo.flXlate = XO_TABLE;
  730. workXlo.iSrcType = PAL_INDEXED;
  731. workXlo.iDstType = PAL_RGB;
  732. workXlo.cEntries = 2;
  733. workXlo.pulXlate = palMono;
  734. /************************************************************/
  735. /* Set up the 'to' rectangle */
  736. /************************************************************/
  737. destRectl.top = 0;
  738. destRectl.left = 0;
  739. destRectl.right = psoMask->sizlBitmap.cx;
  740. destRectl.bottom = psoMask->sizlBitmap.cy / 2;
  741. /************************************************************/
  742. /* the source AND mask is the 'lower' half of the supplied */
  743. /* bitmap */
  744. /************************************************************/
  745. sourcePt.x = 0;
  746. sourcePt.y = psoMask->sizlBitmap.cy / 2;
  747. /************************************************************/
  748. /* and set up a pointer to the correct SO to use */
  749. /************************************************************/
  750. psoToUse = psoMask;
  751. }
  752. else
  753. {
  754. /************************************************************/
  755. /* check that we're at 8bpp - this won't work if not */
  756. /************************************************************/
  757. TRC_ASSERT( (ppDev->cProtocolBitsPerPel == 8),
  758. (TB, "Palette at %d bpp",
  759. ppDev->cProtocolBitsPerPel) );
  760. colorLineLen = psoColor->lDelta >= 0 ? psoColor->lDelta :
  761. -psoColor->lDelta;
  762. pCursorShapeData->hdr.cbColorRowWidth = colorLineLen *
  763. pCursorShapeData->hdr.cBitsPerPel / 8;
  764. if (psoColor->iBitmapFormat <= BMF_8BPP) {
  765. /************************************************************/
  766. /* For color cursors, the supplied XLATEOBJ is set up to */
  767. /* convert from the cursor bpp to the screen bpp - which in */
  768. /* most cases for us is a no-op since we will most often be */
  769. /* at 8bpp (the maximum color depth we support). However, */
  770. /* we actually need to convert to 24bpp for the wire */
  771. /* format, which requires a change to the XLATEOBJ. We */
  772. /* can't do this in place, since the XLATEOBJ we are passed */
  773. /* seems to be used elsewhere - not least to display the */
  774. /* desktop icons - so we set up our own */
  775. /************************************************************/
  776. workXlo.iUniq = 0; /* don't cache */
  777. /************************************************************/
  778. /* Set up to use the current palette (which is fortunately */
  779. /* held in the DD_PDEV structure) */
  780. /************************************************************/
  781. workXlo.flXlate = XO_TABLE; /* we provide a lookup table */
  782. /* to do the translation */
  783. workXlo.iSrcType = PAL_INDEXED;/* pel values in the src bmp */
  784. /* are indices into the table*/
  785. workXlo.iDstType = PAL_RGB; /* entries in the table are */
  786. /* RGB values for the dst bmp*/
  787. workXlo.cEntries = 1 << ppDev->cProtocolBitsPerPel;
  788. /* which has this many entries */
  789. /************************************************************/
  790. /* Now set up the palette to use in the XLATEOBJ. We have */
  791. /* the current palette stored in the DD_PDEV structure - */
  792. /* unfortunately it is in RGB format and we need BGR... */
  793. /************************************************************/
  794. for (ii = 0 ; ii < workXlo.cEntries; ii++)
  795. {
  796. palBGR[ii] = (ppDev->Palette[ii].peRed << 16)
  797. | (ppDev->Palette[ii].peGreen << 8)
  798. | (ppDev->Palette[ii].peBlue);
  799. }
  800. workXlo.pulXlate = palBGR;
  801. /************************************************************/
  802. /* Set up the 'to' rectangle */
  803. /************************************************************/
  804. destRectl.top = 0;
  805. destRectl.left = 0;
  806. destRectl.right = psoColor->sizlBitmap.cx;
  807. destRectl.bottom = psoColor->sizlBitmap.cy;
  808. /************************************************************/
  809. /* and the source start point */
  810. /************************************************************/
  811. sourcePt.x = 0;
  812. sourcePt.y = 0;
  813. /************************************************************/
  814. /* set up a pointer to the correct SO to use */
  815. /************************************************************/
  816. psoToUse = psoColor;
  817. }
  818. else {
  819. // We got a high color cursor to translate to 24bpp workbitmap
  820. // can't easily simulate the XLATEOBJ, since this is TS4 code path
  821. // only, we will just let it fall back to GDI bitmap cursor!
  822. CM_SET_NULL_CURSOR(pCursorShapeData);
  823. pddShm->cm.cmHidden = FALSE;
  824. pddShm->cm.cmCacheHit = FALSE;
  825. pddShm->cm.cmCursorStamp = cmNextCursorStamp++;
  826. rc = SPS_DECLINE;
  827. SCH_DDOutputAvailable(ppDev, TRUE);
  828. DC_QUIT;
  829. }
  830. }
  831. // Lock the work bitmap to get a surface to pass to EngBitBlt.
  832. pWorkSurf = EngLockSurface((HSURF)cmWorkBitmap24);
  833. if (pWorkSurf != NULL) {
  834. BOOL RetVal;
  835. TRC_DBG((TB, "Locked surface"));
  836. // Do the blt.
  837. RetVal = EngBitBlt(pWorkSurf,
  838. psoToUse,
  839. NULL, /* mask surface */
  840. NULL, /* clip object */
  841. &workXlo, /* XLATE object */
  842. &destRectl,
  843. &sourcePt,
  844. NULL, /* mask origin */
  845. NULL, /* brush */
  846. NULL, /* brush origin */
  847. 0xcccc); /* SRCCPY */
  848. EngUnlockSurface(pWorkSurf);
  849. if (RetVal) {
  850. TRC_DBG((TB, "Got the bits into the work bitmap"));
  851. }
  852. else {
  853. TRC_ERR((TB, "Failed to Blt to work bitmap"));
  854. goto FailBlt;
  855. }
  856. }
  857. else {
  858. TRC_ERR((TB, "Failed to lock work surface"));
  859. FailBlt:
  860. // Set the cursor bits to all black. On the client,
  861. // this will be seen as the correct mask but a black
  862. // region inside where the cursor color bits would have
  863. // been.
  864. memset(pWorkSurf->pvBits, 0, pWorkSurf->cjBits);
  865. // We do not DC_QUIT here, we want to complete the cursor
  866. // creation even if the output is mostly wrong, since
  867. // we've already cached the bits.
  868. }
  869. /****************************************************************/
  870. /* Finally we extract the color AND mask from the work bitmap */
  871. /****************************************************************/
  872. TRC_NRM((TB, "Copy %d bytes of color", pWorkSurf->cjBits));
  873. memcpy(&(pCursorShapeData->data[psoMask->cjBits / 2]),
  874. pWorkSurf->pvBits,
  875. pWorkSurf->cjBits);
  876. }
  877. }
  878. /************************************************************************/
  879. /* Set the cursor stamp */
  880. /************************************************************************/
  881. pddShm->cm.cmCursorStamp = cmNextCursorStamp++;
  882. /************************************************************************/
  883. /* Tell the scheduler that we have some new cursor info */
  884. /************************************************************************/
  885. SCH_DDOutputAvailable(ppDev, FALSE);
  886. }
  887. else {
  888. TRC_ERR((TB, "shared memory is not allocated or invalid cursor handle: "
  889. "pddshm=%p, cmCursorCacheHandle=%p", pddShm, cmCursorCacheHandle));
  890. }
  891. DC_EXIT_POINT:
  892. DC_END_FN();
  893. return(rc);
  894. } /* DrvSetPointerShape */