Source code of Windows XP (NT5)
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.

620 lines
15 KiB

  1. #include "precomp.h"
  2. //
  3. // CM.C
  4. // Cursor Manager, display driver side
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. //
  9. //
  10. // CM_DDProcessRequest() - see cm.h
  11. //
  12. //
  13. ULONG CM_DDProcessRequest
  14. (
  15. SURFOBJ* pso,
  16. UINT cjIn,
  17. void * pvIn,
  18. UINT cjOut,
  19. void * pvOut
  20. )
  21. {
  22. BOOL rc;
  23. LPOSI_ESCAPE_HEADER pHeader;
  24. LPOSI_PDEV ppDev = (LPOSI_PDEV)pso->dhpdev;
  25. DebugEntry(CM_DDProcessRequest);
  26. if ((cjIn != sizeof(CM_DRV_XFORM_INFO)) ||
  27. (cjOut != sizeof(CM_DRV_XFORM_INFO)))
  28. {
  29. ERROR_OUT(("CM_DDProcessRequest: Invalid sizes %d, %d for CM_ESC", cjIn, cjOut));
  30. rc = FALSE;
  31. DC_QUIT;
  32. }
  33. //
  34. // Get the request number.
  35. //
  36. pHeader = pvIn;
  37. switch (pHeader->escapeFn)
  38. {
  39. case CM_ESC_XFORM:
  40. {
  41. ASSERT(cjIn == sizeof(CM_DRV_XFORM_INFO));
  42. ASSERT(cjOut == sizeof(CM_DRV_XFORM_INFO));
  43. ((LPCM_DRV_XFORM_INFO)pvOut)->result =
  44. CMDDSetTransform(ppDev, (LPCM_DRV_XFORM_INFO)pvIn);
  45. rc = TRUE;
  46. break;
  47. }
  48. break;
  49. default:
  50. {
  51. ERROR_OUT(("Unrecognised CM_ escape"));
  52. rc = FALSE;
  53. }
  54. break;
  55. }
  56. DC_EXIT_POINT:
  57. DebugExitDWORD(CM_DDProcessRequest, rc);
  58. return((ULONG)rc);
  59. }
  60. // Name: CM_DDInit
  61. //
  62. // Purpose: Allocate a working surface for colour cursors
  63. //
  64. // Returns: TRUE/FALSE
  65. //
  66. // Params: IN ppDev - surface information
  67. //
  68. BOOL CM_DDInit(LPOSI_PDEV ppDev)
  69. {
  70. SIZEL bitmapSize;
  71. BOOL rc = FALSE;
  72. DebugEntry(CM_DDInit);
  73. ASSERT(!g_cmWorkBitmap);
  74. //
  75. // Allocate the work bitmap, at the local device resolution. Note that
  76. // we create it "top down" rather than the default of "bottom up" to
  77. // simplify copying data from the bitmap (we don't have to work out
  78. // offsets into the data - we can copy from the beginning).
  79. //
  80. bitmapSize.cx = CM_MAX_CURSOR_WIDTH;
  81. bitmapSize.cy = CM_MAX_CURSOR_HEIGHT;
  82. g_cmWorkBitmap = EngCreateBitmap(bitmapSize,
  83. BYTES_IN_BITMAP(bitmapSize.cx, 1, ppDev->cBitsPerPel),
  84. ppDev->iBitmapFormat, BMF_TOPDOWN, NULL);
  85. if (!g_cmWorkBitmap)
  86. {
  87. ERROR_OUT(( "Failed to create work bitmap"));
  88. DC_QUIT;
  89. }
  90. rc = TRUE;
  91. DC_EXIT_POINT:
  92. DebugExitBOOL(CM_DDInit, rc);
  93. return(rc);
  94. }
  95. //
  96. //
  97. // CM_DDTerm - see cm.h
  98. //
  99. //
  100. void CM_DDTerm(void)
  101. {
  102. DebugEntry(CM_DDTerm);
  103. //
  104. // Destroy the bitmap. Despite its name, EngDeleteSurface is the
  105. // correct function to do this.
  106. //
  107. if (g_cmWorkBitmap)
  108. {
  109. if (!EngDeleteSurface((HSURF)g_cmWorkBitmap))
  110. {
  111. ERROR_OUT(( "Failed to delete work bitmap"));
  112. }
  113. else
  114. {
  115. TRACE_OUT(( "Deleted work bitmap"));
  116. }
  117. g_cmWorkBitmap = NULL;
  118. }
  119. DebugExitVOID(CM_DDTerm);
  120. }
  121. //
  122. // CM_DDViewing()
  123. //
  124. void CM_DDViewing
  125. (
  126. SURFOBJ * pso,
  127. BOOL fViewers
  128. )
  129. {
  130. DebugEntry(CM_DDViewing);
  131. if (fViewers)
  132. {
  133. //
  134. // Jiggle the cursor so we get the current image.
  135. //
  136. EngSetPointerTag(((LPOSI_PDEV)pso->dhpdev)->hdevEng, NULL, NULL, NULL, 0);
  137. }
  138. DebugExitVOID(CM_DDViewing);
  139. }
  140. //
  141. //
  142. // DrvSetPointerShape - see winddi.h
  143. //
  144. //
  145. ULONG DrvSetPointerShape(SURFOBJ *pso,
  146. SURFOBJ *psoMask,
  147. SURFOBJ *psoColor,
  148. XLATEOBJ *pxlo,
  149. LONG xHot,
  150. LONG yHot,
  151. LONG x,
  152. LONG y,
  153. RECTL *prcl,
  154. FLONG fl)
  155. {
  156. ULONG rc = SPS_ACCEPT_NOEXCLUDE;
  157. SURFOBJ * pWorkSurf = NULL;
  158. LPOSI_PDEV ppDev = (LPOSI_PDEV)pso->dhpdev;
  159. BOOL writingSHM = FALSE;
  160. LPCM_SHAPE_DATA pCursorShapeData;
  161. RECTL destRectl;
  162. POINTL sourcePt;
  163. int ii;
  164. LONG lineLen;
  165. LPBYTE srcPtr;
  166. LPBYTE dstPtr;
  167. LPCM_FAST_DATA lpcmShared;
  168. DebugEntry(DrvSetPointerShape);
  169. //
  170. // Returning SPS_ACCEPT_NOEXCLUDE means we can ignore prcl.
  171. //
  172. //
  173. // Only process the change if we are hosting. (Hosting implies being
  174. // initialized).
  175. //
  176. if (!g_oeViewers)
  177. {
  178. DC_QUIT;
  179. }
  180. //
  181. // Get access to the shared memory.
  182. //
  183. lpcmShared = CM_SHM_START_WRITING;
  184. writingSHM = TRUE;
  185. //
  186. // First of all, let's trace out some useful information.
  187. //
  188. TRACE_OUT(( "pso %#hlx psoMask %#hlx psoColor %#hlx pxlo %#hlx",
  189. pso, psoMask, psoColor, pxlo));
  190. TRACE_OUT(( "hot spot (%d, %d) x, y (%d, %d)", xHot, yHot, x, y));
  191. TRACE_OUT(( "Flags %#hlx", fl));
  192. //
  193. // Set up a local pointer to the cursor shape data.
  194. //
  195. pCursorShapeData = &lpcmShared->cmCursorShapeData;
  196. if (psoMask == NULL)
  197. {
  198. //
  199. // This is a transparent cursor. Send a NULL cursor. Note that
  200. // this is not the same as hiding the cursor using DrvMovePointer -
  201. // as in this case the cursor cannot be unhidden unless
  202. // DrvSetPointerShape is called again.
  203. //
  204. TRACE_OUT(( "Transparent Cursor"));
  205. CM_SET_NULL_CURSOR(pCursorShapeData);
  206. g_asSharedMemory->cmCursorHidden = FALSE;
  207. lpcmShared->cmCursorStamp = g_cmNextCursorStamp++;
  208. DC_QUIT;
  209. }
  210. //
  211. // We've been passed a system cursor. Fill in the header for our local
  212. // cursor. We can get the hot spot position and cursor size and width
  213. // easily.
  214. //
  215. pCursorShapeData->hdr.ptHotSpot.x = xHot;
  216. pCursorShapeData->hdr.ptHotSpot.y = yHot;
  217. TRACE_OUT(( "Pointer mask is %#hlx by %#hlx pixels (lDelta: %#hlx)",
  218. psoMask->sizlBitmap.cx,
  219. psoMask->sizlBitmap.cy,
  220. psoMask->lDelta));
  221. pCursorShapeData->hdr.cx = (WORD)psoMask->sizlBitmap.cx;
  222. pCursorShapeData->hdr.cy = (WORD)psoMask->sizlBitmap.cy / 2;
  223. //
  224. // Check cursor size
  225. //
  226. if ((pCursorShapeData->hdr.cx > CM_MAX_CURSOR_WIDTH) ||
  227. (pCursorShapeData->hdr.cy > CM_MAX_CURSOR_HEIGHT))
  228. {
  229. ERROR_OUT(( "Cursor too big! %d %d",
  230. psoMask->sizlBitmap.cx, psoMask->sizlBitmap.cy));
  231. DC_QUIT;
  232. }
  233. //
  234. // lDelta may be negative for an inverted cursor (which is what we get
  235. // from DC-Share).
  236. //
  237. lineLen = abs(psoMask->lDelta);
  238. //
  239. // At this point we need to know if we are dealing with a color cursor.
  240. //
  241. if (NULL == psoColor)
  242. {
  243. TRACE_OUT(( "Monochrome pointer"));
  244. pCursorShapeData->hdr.cPlanes = 1;
  245. pCursorShapeData->hdr.cBitsPerPel = 1;
  246. pCursorShapeData->hdr.cbRowWidth = (WORD)lineLen;
  247. //
  248. // Copy the 1bpp AND mask and cursor shape (XOR mask) across.
  249. //
  250. TRACE_OUT(( "Copying AND mask across from %#hlx (size: %#hlx)",
  251. psoMask->pvBits,
  252. psoMask->cjBits));
  253. dstPtr = pCursorShapeData->data;
  254. srcPtr = (LPBYTE) psoMask->pvScan0;
  255. for (ii = pCursorShapeData->hdr.cy * 2; ii > 0 ; ii--)
  256. {
  257. memcpy(dstPtr, srcPtr, lineLen);
  258. srcPtr += psoMask->lDelta;
  259. dstPtr += lineLen;
  260. }
  261. //
  262. // Copy black-and-white palette colors
  263. //
  264. TRACE_OUT(( "Copy B+W palette"));
  265. lpcmShared->colorTable[0].peRed = 0;
  266. lpcmShared->colorTable[0].peGreen = 0;
  267. lpcmShared->colorTable[0].peBlue = 0;
  268. lpcmShared->colorTable[0].peFlags = 0;
  269. lpcmShared->colorTable[1].peRed = 255;
  270. lpcmShared->colorTable[1].peGreen = 255;
  271. lpcmShared->colorTable[1].peBlue = 255;
  272. lpcmShared->colorTable[1].peFlags = 0;
  273. //
  274. // That's all we need to do in this case.
  275. //
  276. }
  277. else
  278. {
  279. TRACE_OUT(( "Color pointer - mask of %#hlx by %#hlx (lDelta: %#hlx)",
  280. psoColor->sizlBitmap.cx,
  281. psoColor->sizlBitmap.cy,
  282. psoColor->lDelta));
  283. //
  284. // Note: row width used to calculate AND mask size - and is thus
  285. // for the 1bpp mask.
  286. //
  287. pCursorShapeData->hdr.cbRowWidth = (WORD)lineLen;
  288. pCursorShapeData->hdr.cPlanes = 1;
  289. //
  290. // Note: data at device bpp.
  291. //
  292. TRACE_OUT(( "BPP is %d", pCursorShapeData->hdr.cBitsPerPel));
  293. pCursorShapeData->hdr.cBitsPerPel = (BYTE)ppDev->cBitsPerPel;
  294. //
  295. // Lock the work bitmap to get a surface to pass to EngBitBlt.
  296. //
  297. pWorkSurf = EngLockSurface((HSURF)g_cmWorkBitmap);
  298. if (NULL == pWorkSurf)
  299. {
  300. ERROR_OUT(( "Failed to lock work surface"));
  301. DC_QUIT;
  302. }
  303. TRACE_OUT(( "Locked surface"));
  304. //
  305. // Perform the Blt to our work bitmap so that we can get the bits
  306. // at the native bpp.
  307. //
  308. destRectl.top = 0;
  309. destRectl.left = 0;
  310. destRectl.right = psoColor->sizlBitmap.cx;
  311. destRectl.bottom = psoColor->sizlBitmap.cy;
  312. sourcePt.x = 0;
  313. sourcePt.y = 0;
  314. if (!EngBitBlt(pWorkSurf,
  315. psoColor,
  316. NULL, // mask surface
  317. NULL, // clip object
  318. pxlo, // XLATE object
  319. &destRectl,
  320. &sourcePt,
  321. NULL, // mask origin
  322. NULL, // brush
  323. NULL, // brush origin
  324. 0xcccc)) // SRCCPY
  325. {
  326. ERROR_OUT(( "Failed to Blt to work bitmap"));
  327. DC_QUIT;
  328. }
  329. TRACE_OUT(( "Got the bits at native format into the work bitmap"));
  330. //
  331. // Now copy the bits we want from this work bitmap into the
  332. // DCCURSORSHAPE shared memory.
  333. // First copy the AND bits (but ignore the redundant 1bpp XOR bits)
  334. //
  335. TRACE_OUT(( "Copy %d bytes of 1bpp AND mask", psoMask->cjBits/2));
  336. dstPtr = pCursorShapeData->data;
  337. srcPtr = (LPBYTE) psoMask->pvScan0;
  338. for (ii = pCursorShapeData->hdr.cy; ii > 0 ; ii--)
  339. {
  340. memcpy(dstPtr, srcPtr, lineLen);
  341. srcPtr += psoMask->lDelta;
  342. dstPtr += lineLen;
  343. }
  344. TRACE_OUT(( "Copy %d bytes of color", pWorkSurf->cjBits));
  345. memcpy(&(pCursorShapeData->data[psoMask->cjBits / 2]),
  346. pWorkSurf->pvBits,
  347. pWorkSurf->cjBits);
  348. //
  349. // Now work out the palette and copy into shared memory
  350. //
  351. if (pCursorShapeData->hdr.cBitsPerPel > 8)
  352. {
  353. //
  354. // Need the bitmasks.
  355. //
  356. TRACE_OUT(( "Copy bitmasks"));
  357. lpcmShared->bitmasks[0] = ppDev->flRed;
  358. lpcmShared->bitmasks[1] = ppDev->flGreen;
  359. lpcmShared->bitmasks[2] = ppDev->flBlue;
  360. }
  361. else
  362. {
  363. //
  364. // Need a palette.
  365. //
  366. TRACE_OUT(( "Copy %d palette bytes",
  367. COLORS_FOR_BPP(ppDev->cBitsPerPel) * sizeof(PALETTEENTRY)));
  368. memcpy(lpcmShared->colorTable,
  369. ppDev->pPal,
  370. COLORS_FOR_BPP(ppDev->cBitsPerPel) *
  371. sizeof(PALETTEENTRY));
  372. }
  373. }
  374. //
  375. // Set the cursor stamp, and the cursor hidden state.
  376. //
  377. lpcmShared->cmCursorStamp = g_cmNextCursorStamp++;
  378. g_asSharedMemory->cmCursorHidden = FALSE;
  379. DC_EXIT_POINT:
  380. //
  381. // Free access to the shared memory if we got it earlier.
  382. //
  383. if (writingSHM)
  384. {
  385. CM_SHM_STOP_WRITING;
  386. }
  387. if (pWorkSurf != NULL)
  388. {
  389. //
  390. // Unlock the work bitmap surface.
  391. //
  392. EngUnlockSurface(pWorkSurf);
  393. }
  394. DebugExitDWORD(DrvSetPointerShape, rc);
  395. return(rc);
  396. } // DrvSetPointerShape
  397. //
  398. // DrvMovePointer - see NT DDK documentation.
  399. // We only look at this in order to check for hidden cursors - normal
  400. // pointer moves are ignored.
  401. //
  402. VOID DrvMovePointer(SURFOBJ *pso,
  403. LONG x,
  404. LONG y,
  405. RECTL *prcl)
  406. {
  407. LPOSI_PDEV ppdev = (LPOSI_PDEV) pso->dhpdev;
  408. DebugEntry(DrvMovePointer);
  409. //
  410. // We don't use the exclusion rectangle because we only support
  411. // hardware Pointers. If we were doing our own Pointer simulations we
  412. // would want to update prcl so that the engine would call us to
  413. // exclude our pointer before drawing to the pixels in prcl.
  414. //
  415. //
  416. // Only process the mouse move if we are hosting. (Hosting implies
  417. // being initialized).
  418. //
  419. if (!g_oeViewers)
  420. {
  421. DC_QUIT;
  422. }
  423. if (x == -1)
  424. {
  425. if (!g_cmCursorHidden)
  426. {
  427. //
  428. // Pointer is hidden.
  429. //
  430. TRACE_OUT(("Hide the cursor"));
  431. //
  432. // Set the 'hide cursor' flag.
  433. //
  434. CM_SHM_START_WRITING;
  435. g_asSharedMemory->cmCursorHidden = TRUE;
  436. CM_SHM_STOP_WRITING;
  437. //
  438. // Update our fast-path variable.
  439. //
  440. g_cmCursorHidden = TRUE;
  441. }
  442. }
  443. else
  444. {
  445. if (g_cmCursorHidden)
  446. {
  447. //
  448. // The pointer is unhidden
  449. //
  450. TRACE_OUT(("Show the cursor"));
  451. CM_SHM_START_WRITING;
  452. g_asSharedMemory->cmCursorHidden = FALSE;
  453. CM_SHM_STOP_WRITING;
  454. //
  455. // Update our fast-path variable.
  456. //
  457. g_cmCursorHidden = FALSE;
  458. }
  459. }
  460. DC_EXIT_POINT:
  461. DebugExitVOID(DrvMovePointer);
  462. }
  463. // Name: CMDDSetTransform
  464. //
  465. // Purpose: Set up a cursor transform
  466. //
  467. // Returns: TRUE/FALSE
  468. //
  469. // Params: IN ppDev - device info
  470. // IN pXformInfo - data passed in to DrvEscape
  471. //
  472. BOOL CMDDSetTransform(LPOSI_PDEV ppDev, LPCM_DRV_XFORM_INFO pXformInfo)
  473. {
  474. BOOL rc = FALSE;
  475. LPBYTE pAND = pXformInfo->pANDMask;
  476. SIZEL bitmapSize;
  477. HBITMAP andBitmap;
  478. SURFOBJ * pANDSurf;
  479. DebugEntry(CMDDSetTransform);
  480. if (pAND == NULL)
  481. {
  482. //
  483. // Reset the transform
  484. //
  485. TRACE_OUT(( "Clear transform"));
  486. EngSetPointerTag(ppDev->hdevEng, NULL, NULL, NULL, 0);
  487. rc = TRUE;
  488. DC_QUIT;
  489. }
  490. //
  491. // Transforms are always monochrome
  492. //
  493. //
  494. // Create a 1bpp bitmap, double-height, with the AND bits followed by
  495. // the XOR bits. We are given a top-down DIB, so we need to create
  496. // a top-down bitmap.
  497. //
  498. bitmapSize.cx = pXformInfo->width;
  499. bitmapSize.cy = pXformInfo->height * 2;
  500. andBitmap = EngCreateBitmap(bitmapSize, BYTES_IN_BITMAP(bitmapSize.cx, 1, 1),
  501. BMF_1BPP, BMF_TOPDOWN, NULL);
  502. pANDSurf = EngLockSurface((HSURF)andBitmap);
  503. if (pANDSurf == NULL)
  504. {
  505. ERROR_OUT(( "Failed to lock work surface"));
  506. DC_QUIT;
  507. }
  508. //
  509. // Copy the bits
  510. //
  511. memcpy(pANDSurf->pvBits, pAND, pANDSurf->cjBits);
  512. TRACE_OUT(( "Set the tag"));
  513. EngSetPointerTag(ppDev->hdevEng, pANDSurf, NULL, NULL, 0);
  514. EngUnlockSurface(pANDSurf);
  515. EngDeleteSurface((HSURF)andBitmap);
  516. rc = TRUE;
  517. DC_EXIT_POINT:
  518. DebugExitBOOL(CMDDSetTransform, rc);
  519. return(rc);
  520. } // CMDDSetTransform