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.

831 lines
23 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: cursor.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains code for dealing with cursors.
  7. *
  8. * History:
  9. * 03-Dec-1990 DavidPe Created.
  10. * 01-Feb-1991 MikeKe Added Revalidation code (None)
  11. * 12-Feb-1991 JimA Added access checks
  12. * 21-Jan-1992 IanJa ANSI/Unicode neutralized (null op)
  13. * 02-Aug-1992 DarrinM Added animated cursor code
  14. \***************************************************************************/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. /***************************************************************************\
  18. * zzzSetCursor (API)
  19. *
  20. * This API sets the cursor image for the current thread.
  21. *
  22. * History:
  23. * 12-03-90 DavidPe Created.
  24. \***************************************************************************/
  25. PCURSOR zzzSetCursor(
  26. PCURSOR pcur)
  27. {
  28. PQ pq;
  29. PCURSOR pcurPrev;
  30. PTHREADINFO ptiCurrent = PtiCurrent();
  31. pq = ptiCurrent->pq;
  32. pcurPrev = pq->spcurCurrent;
  33. if (pq->spcurCurrent != pcur) {
  34. /*
  35. * Lock() returns pobjOld - if it is still valid. Don't want to
  36. * return a pcurPrev that is an invalid pointer.
  37. */
  38. pcurPrev = LockQCursor(pq, pcur);
  39. /*
  40. * If no thread 'owns' the cursor, we must be in initialization
  41. * so go ahead and assign it to ourself.
  42. */
  43. if (gpqCursor == NULL)
  44. gpqCursor = pq;
  45. /*
  46. * If we're changing the local-cursor for the thread currently
  47. * representing the global-cursor, update the cursor image now.
  48. */
  49. if (pq == gpqCursor) {
  50. TL tlpcur;
  51. ThreadLockWithPti(ptiCurrent, pcurPrev, &tlpcur);
  52. zzzUpdateCursorImage();
  53. pcurPrev = ThreadUnlock(&tlpcur);
  54. }
  55. }
  56. return pcurPrev;
  57. }
  58. /***************************************************************************\
  59. * zzzSetCursorPos (API)
  60. *
  61. * This API sets the cursor position.
  62. *
  63. * History:
  64. * 03-Dec-1990 DavidPe Created.
  65. * 12-Feb-1991 JimA Added access check
  66. * 16-May-1991 mikeke Changed to return BOOL
  67. \***************************************************************************/
  68. BOOL zzzSetCursorPos(
  69. int x,
  70. int y)
  71. {
  72. /*
  73. * Blow it off if the caller doesn't have the proper access rights
  74. */
  75. if (!CheckWinstaWriteAttributesAccess()) {
  76. return FALSE;
  77. }
  78. zzzInternalSetCursorPos(x, y);
  79. /*
  80. * Save the absolute coordinates in the global array
  81. * for GetMouseMovePointsEx.
  82. */
  83. SAVEPOINT(x, y,
  84. SYSMET(CXVIRTUALSCREEN) - 1,
  85. SYSMET(CYVIRTUALSCREEN) - 1,
  86. NtGetTickCount(), 0);
  87. return TRUE;
  88. }
  89. /***************************************************************************\
  90. * zzzInternalSetCursorPos
  91. *
  92. * This function is used whenever the server needs to set the cursor
  93. * position, regardless of the caller's access rights.
  94. *
  95. * History:
  96. * 12-Feb-1991 JimA Created.
  97. \***************************************************************************/
  98. VOID zzzInternalSetCursorPos(
  99. int x,
  100. int y
  101. )
  102. {
  103. gptCursorAsync.x = x;
  104. gptCursorAsync.y = y;
  105. BoundCursor(&gptCursorAsync);
  106. gpsi->ptCursor = gptCursorAsync;
  107. /*
  108. * Pass MP_PROCEDURAL as the last parameter so that in the
  109. * remote case we send an updated mouse position to the client
  110. */
  111. GreMovePointer(gpDispInfo->hDev, gpsi->ptCursor.x, gpsi->ptCursor.y,
  112. MP_PROCEDURAL);
  113. /*
  114. * Cursor has changed position, so generate a mouse event so the
  115. * window underneath the new location knows it's there and sets the
  116. * shape accordingly.
  117. */
  118. zzzSetFMouseMoved();
  119. }
  120. /***************************************************************************\
  121. * IncCursorLevel
  122. * DecCursorLevel
  123. *
  124. * Keeps track of this thread show/hide cursor level as well as the queue
  125. * it is associated with. Thread levels are done so that when
  126. * AttachThreadInput() is called we can do exact level calculations in the
  127. * new queue.
  128. *
  129. * 15-Jan-1993 ScottLu Created.
  130. \***************************************************************************/
  131. VOID IncCursorLevel(
  132. PTHREADINFO pti)
  133. {
  134. pti->iCursorLevel++;
  135. pti->pq->iCursorLevel++;
  136. }
  137. VOID DecCursorLevel(
  138. PTHREADINFO pti)
  139. {
  140. pti->iCursorLevel--;
  141. pti->pq->iCursorLevel--;
  142. }
  143. /***************************************************************************\
  144. * zzzShowCursor (API)
  145. *
  146. * This API allows the application to hide or show the cursor image.
  147. *
  148. * History:
  149. * 03-Dec-1990 JimA Implemented for fake cursor stuff
  150. \***************************************************************************/
  151. int zzzShowCursor(
  152. BOOL fShow)
  153. {
  154. PTHREADINFO pti = PtiCurrent();
  155. PQ pq;
  156. int iCursorLevel;
  157. pq = pti->pq;
  158. /*
  159. * To preserve pq
  160. */
  161. DeferWinEventNotify();
  162. if (fShow) {
  163. IncCursorLevel(pti);
  164. if ((pq == gpqCursor) && (pq->iCursorLevel == 0))
  165. zzzUpdateCursorImage();
  166. } else {
  167. DecCursorLevel(pti);
  168. if ((pq == gpqCursor) && (pq->iCursorLevel == -1))
  169. zzzUpdateCursorImage();
  170. }
  171. iCursorLevel = pq->iCursorLevel;
  172. zzzEndDeferWinEventNotify();
  173. return iCursorLevel;
  174. }
  175. /***************************************************************************\
  176. * zzzClipCursor (API)
  177. *
  178. * This API sets the cursor clipping rectangle which restricts where the
  179. * cursor can go. If prcClip is NULL, the clipping rectangle will be the
  180. * screen.
  181. *
  182. * History:
  183. * 03-Dec-1990 DavidPe Created.
  184. * 16-May-1991 MikeKe Changed to return BOOL
  185. \***************************************************************************/
  186. BOOL zzzClipCursor(
  187. LPCRECT prcClip)
  188. {
  189. PEPROCESS Process = PsGetCurrentProcess();
  190. /*
  191. * Don't let this happen if it doesn't have access.
  192. */
  193. if (Process != gpepCSRSS && !CheckWinstaWriteAttributesAccess()) {
  194. return FALSE;
  195. }
  196. /*
  197. * The comment from NT 3.51:
  198. * Non-foreground threads can only set the clipping rectangle
  199. * if it was empty, or if they are restoring it to the whole screen.
  200. *
  201. * But the code from NT 3.51 says "IsRectEmpty" instead of
  202. * "!IsRectEmpty", as would follow from the comment. We leave
  203. * the code as it was, as following the comment appears to
  204. * break apps.
  205. *
  206. * CONSIDER: Removing this test altogether after NT4.0 ships.
  207. */
  208. if ( PtiCurrent()->pq != gpqForeground &&
  209. prcClip != NULL &&
  210. IsRectEmpty(&grcCursorClip)) {
  211. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in _ClipCursor");
  212. return FALSE;
  213. }
  214. if (prcClip == NULL) {
  215. grcCursorClip = gpDispInfo->rcScreen;
  216. } else {
  217. /*
  218. * Never let our cursor leave the screen. Can't use IntersectRect()
  219. * because it doesn't allow rects with 0 width or height.
  220. */
  221. grcCursorClip.left = max(gpDispInfo->rcScreen.left , prcClip->left);
  222. grcCursorClip.right = min(gpDispInfo->rcScreen.right , prcClip->right);
  223. grcCursorClip.top = max(gpDispInfo->rcScreen.top , prcClip->top);
  224. grcCursorClip.bottom = min(gpDispInfo->rcScreen.bottom, prcClip->bottom);
  225. /*
  226. * Check for invalid clip rect.
  227. */
  228. if (grcCursorClip.left > grcCursorClip.right ||
  229. grcCursorClip.top > grcCursorClip.bottom) {
  230. grcCursorClip = gpDispInfo->rcScreen;
  231. }
  232. }
  233. /*
  234. * Update the cursor position if it's currently outside the
  235. * cursor clip-rect.
  236. */
  237. if (!PtInRect(&grcCursorClip, gpsi->ptCursor)) {
  238. zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
  239. }
  240. return TRUE;
  241. }
  242. /***************************************************************************\
  243. * BoundCursor
  244. *
  245. * This rountine 'clips' gptCursorAsync to be within rcCursorClip. This
  246. * routine treats rcCursorClip as non-inclusive so the bottom and right sides
  247. * get bound to rcCursorClip.bottom/right - 1.
  248. *
  249. * Is called in OR out of the USER critical section!! IANJA
  250. *
  251. * History:
  252. * 03-Dec-1990 DavidPe Created.
  253. \***************************************************************************/
  254. #ifdef LOCK_MOUSE_CODE
  255. #pragma alloc_text(MOUSE, BoundCursor)
  256. #endif
  257. VOID BoundCursor(
  258. LPPOINT lppt)
  259. {
  260. if (TEST_PUDF(PUDF_VDMBOUNDSACTIVE) && gspwndFullScreen != NULL) {
  261. if (lppt->x < grcVDMCursorBounds.left) {
  262. lppt->x = grcVDMCursorBounds.left;
  263. } else if (lppt->x >= grcVDMCursorBounds.right) {
  264. lppt->x = grcVDMCursorBounds.right - 1;
  265. }
  266. if (lppt->y < grcVDMCursorBounds.top) {
  267. lppt->y = grcVDMCursorBounds.top;
  268. } else if (lppt->y >= grcVDMCursorBounds.bottom) {
  269. lppt->y = grcVDMCursorBounds.bottom - 1;
  270. }
  271. } else {
  272. if (lppt->x < grcCursorClip.left) {
  273. lppt->x = grcCursorClip.left;
  274. } else if (lppt->x >= grcCursorClip.right) {
  275. lppt->x = grcCursorClip.right - 1;
  276. }
  277. if (lppt->y < grcCursorClip.top) {
  278. lppt->y = grcCursorClip.top;
  279. } else if (lppt->y >= grcCursorClip.bottom) {
  280. lppt->y = grcCursorClip.bottom - 1;
  281. }
  282. }
  283. /*
  284. * If we have more than one monitor, then we need to clip the
  285. * cursor to a point on the desktop.
  286. */
  287. if (!gpDispInfo->fDesktopIsRect) {
  288. ClipPointToDesktop(lppt);
  289. }
  290. }
  291. /***************************************************************************\
  292. * SetVDMCursorBounds
  293. *
  294. * This routine is needed so when a vdm is running, the mouse is not bounded
  295. * by the screen. This is so the vdm can correctly virtualize the DOS mouse
  296. * device driver. It can't deal with user always bounding to the screen,
  297. * so it sets wide open bounds.
  298. *
  299. * 20-May-1993 ScottLu Created.
  300. \***************************************************************************/
  301. VOID SetVDMCursorBounds(
  302. LPRECT lprc)
  303. {
  304. if (lprc != NULL) {
  305. /*
  306. * Set grcVDMCursorBounds before TEST_PUDF(PUDF_VDMBOUNDSACTIVE), because
  307. * MoveEvent() calls BoundCursor() from outside the USER CritSect!
  308. */
  309. grcVDMCursorBounds = *lprc;
  310. Win32MemoryBarrier(); // Ensure grcVDMCursorBounds is updated first.
  311. SET_PUDF(PUDF_VDMBOUNDSACTIVE);
  312. } else {
  313. /*
  314. * Turn vdm bounds off.
  315. */
  316. CLEAR_PUDF(PUDF_VDMBOUNDSACTIVE);
  317. }
  318. /*
  319. * Before returning from this function,
  320. * make sure the write instructions are all retired.
  321. */
  322. Win32MemoryBarrier();
  323. }
  324. /***************************************************************************\
  325. * zzzAnimateCursor
  326. *
  327. * When an animated cursor is loaded and the wait cursor is up this routine
  328. * gets called to maintain the cursor animation.
  329. *
  330. * Should only be called by the cursor animation timer.
  331. *
  332. * History:
  333. * 02-Oct-1991 DarrinM Created.
  334. * 03-Aug-1994 SanfordS Calibrated.
  335. \***************************************************************************/
  336. #if defined (_M_IX86) && (_MSC_VER <= 1100)
  337. #pragma optimize("s", off)
  338. #endif
  339. VOID zzzAnimateCursor(
  340. PWND pwndDummy,
  341. UINT message,
  342. UINT_PTR nID,
  343. LPARAM lParam)
  344. {
  345. int iicur;
  346. PACON pacon;
  347. TL tlpacon;
  348. int LostTime;
  349. int tTime;
  350. pacon = (PACON)gpcurLogCurrent;
  351. if (pacon == NULL || !(pacon->CURSORF_flags & CURSORF_ACON)) {
  352. gdwLastAniTick = 0;
  353. return;
  354. }
  355. /*
  356. * Find out actual time loss since last update.
  357. */
  358. if (gdwLastAniTick) {
  359. LostTime = NtGetTickCount() - gdwLastAniTick -
  360. (pacon->ajifRate[pacon->iicur] * 100 / 6);
  361. if (LostTime < 0)
  362. LostTime = 0;
  363. } else {
  364. LostTime = 0;
  365. }
  366. /*
  367. * Increment the animation index.
  368. */
  369. iicur = pacon->iicur + 1;
  370. if (iicur >= pacon->cicur)
  371. iicur = 0;
  372. pacon->iicur = iicur;
  373. /*
  374. * This forces the new cursor to be drawn.
  375. */
  376. ThreadLockAlways(pacon, &tlpacon);
  377. zzzUpdateCursorImage();
  378. tTime = pacon->ajifRate[iicur] * 100 / 6;
  379. while (tTime < LostTime) {
  380. /*
  381. * Animation is outrunning our ability to render it - skip frames
  382. * to catch up.
  383. */
  384. LostTime -= tTime;
  385. /*
  386. * Increment the animation index.
  387. */
  388. iicur = pacon->iicur + 1;
  389. if (iicur >= pacon->cicur)
  390. iicur = 0;
  391. pacon->iicur = iicur;
  392. tTime = pacon->ajifRate[iicur] * 100 / 6;
  393. }
  394. ThreadUnlock(&tlpacon);
  395. gdwLastAniTick = NtGetTickCount() - LostTime;
  396. gidCursorTimer = InternalSetTimer(NULL, gidCursorTimer, tTime - LostTime, zzzAnimateCursor, TMRF_RIT | TMRF_ONESHOT);
  397. return;
  398. DBG_UNREFERENCED_PARAMETER(pwndDummy);
  399. DBG_UNREFERENCED_PARAMETER(message);
  400. DBG_UNREFERENCED_PARAMETER(nID);
  401. DBG_UNREFERENCED_PARAMETER(lParam);
  402. }
  403. /**************************************************************************\
  404. * FCursorShadowed
  405. *
  406. \**************************************************************************/
  407. __inline FCursorShadowed(PCURSINFO pci)
  408. {
  409. return (TestALPHA(CURSORSHADOW) && (pci->CURSORF_flags & CURSORF_SYSTEM));
  410. }
  411. #if defined (_M_IX86) && (_MSC_VER <= 1100)
  412. #pragma optimize("", on)
  413. #endif
  414. /**************************************************************************\
  415. * zzzUpdateCursorImage
  416. *
  417. * History:
  418. * 14-Jan-1992 DavidPe Created.
  419. * 09-Aug-1992 DarrinM Added animated cursor code.
  420. * 01-Oct-2000 JasonSch Added autorun cursor code.
  421. \**************************************************************************/
  422. VOID zzzUpdateCursorImage()
  423. {
  424. PCURSOR pcurLogNew;
  425. PCURSOR pcurPhysNew;
  426. PACON pacon;
  427. PCURSOR pcurPhysOld;
  428. DWORD event;
  429. #ifdef GENERIC_INPUT
  430. /*
  431. * WindowsBug 298252
  432. * Even though the mouse pointer is outside
  433. * the GenericInput aware app, allow it to hide
  434. * the mouse cursor if mouse is captured.
  435. * i.e. use gpqForeground instead of gpqCursor.
  436. */
  437. if (gpqForeground) {
  438. PTHREADINFO ptiMouse = PtiMouseFromQ(gpqForeground);
  439. if (TestRawInputMode(ptiMouse, CaptureMouse)) {
  440. if (gpqForeground->iCursorLevel < 0) {
  441. pcurLogNew = NULL;
  442. goto force_setnull;
  443. }
  444. }
  445. }
  446. #endif
  447. if (gpqCursor == NULL)
  448. return;
  449. if ((gpqCursor->iCursorLevel < 0) || (gpqCursor->spcurCurrent == NULL)) {
  450. pcurLogNew = NULL;
  451. } else {
  452. /*
  453. * Assume we're using the current cursor.
  454. */
  455. pcurLogNew = gpqCursor->spcurCurrent;
  456. /*
  457. * Check to see if we should use the "app starting" or the "autorun"
  458. * cursor.
  459. */
  460. if (gtimeStartCursorHide != 0
  461. #ifdef AUTORUN_CURSOR
  462. || gtmridAutorunCursor != 0
  463. #endif // AUTORUN_CURSOR
  464. ) {
  465. if (gpqCursor->spcurCurrent == SYSCUR(ARROW) ||
  466. #ifdef AUTORUN_CURSOR
  467. gpqCursor->spcurCurrent == SYSCUR(AUTORUN) ||
  468. #endif // AUTORUN_CURSOR
  469. gpqCursor->spcurCurrent == SYSCUR(APPSTARTING)) {
  470. #ifdef AUTORUN_CURSOR
  471. if (gtmridAutorunCursor != 0) {
  472. pcurLogNew = SYSCUR(AUTORUN);
  473. } else {
  474. #endif // AUTORUN_CURSOR
  475. pcurLogNew = SYSCUR(APPSTARTING);
  476. #ifdef AUTORUN_CURSOR
  477. }
  478. #endif // AUTORUN_CURSOR
  479. }
  480. }
  481. }
  482. #ifdef GENERIC_INPUT
  483. force_setnull:
  484. #endif
  485. /*
  486. * If the logical cursor is changing then start/stop the cursor
  487. * animation timer as appropriate.
  488. */
  489. if (pcurLogNew != gpcurLogCurrent) {
  490. /*
  491. * If the old cursor was animating, shut off the animation timer.
  492. */
  493. if (gtmridAniCursor != 0) {
  494. /*
  495. * Disable animation.
  496. */
  497. KILLRITTIMER(NULL, gtmridAniCursor);
  498. gtmridAniCursor = 0;
  499. }
  500. /*
  501. * If the new cursor is animated, start the animation timer.
  502. */
  503. if ((pcurLogNew != NULL) && (pcurLogNew->CURSORF_flags & CURSORF_ACON)) {
  504. /*
  505. * Start the animation over from the beginning.
  506. */
  507. pacon = (PACON)pcurLogNew;
  508. pacon->iicur = 0;
  509. gdwLastAniTick = NtGetTickCount();
  510. /*
  511. * Use the rate table to keep the timer on track.
  512. * 1 Jiffy = 1/60 sec = 100/6 ms
  513. */
  514. gtmridAniCursor = InternalSetTimer(NULL,
  515. gtmridAniCursor,
  516. pacon->ajifRate[0] * 100 / 6,
  517. zzzAnimateCursor,
  518. TMRF_RIT | TMRF_ONESHOT);
  519. }
  520. }
  521. /*
  522. * If this is an animated cursor, find and use the current frame
  523. * of the animation. NOTE: this is done AFTER the AppStarting
  524. * business so the AppStarting cursor itself can be animated.
  525. */
  526. if (pcurLogNew != NULL && pcurLogNew->CURSORF_flags & CURSORF_ACON) {
  527. pcurPhysNew = ((PACON)pcurLogNew)->aspcur[((PACON)pcurLogNew)->
  528. aicur[((PACON)pcurLogNew)->iicur]];
  529. } else {
  530. pcurPhysNew = pcurLogNew;
  531. }
  532. /*
  533. * Remember the new logical cursor.
  534. */
  535. gpcurLogCurrent = pcurLogNew;
  536. /*
  537. * If the physical cursor is changing then update screen.
  538. */
  539. if (pcurPhysNew != gpcurPhysCurrent) {
  540. pcurPhysOld = gpcurPhysCurrent;
  541. gpcurPhysCurrent = pcurPhysNew;
  542. if (pcurPhysNew == NULL) {
  543. SetPointer(FALSE);
  544. } else {
  545. ULONG fl = 0;
  546. if (pcurLogNew->CURSORF_flags & CURSORF_ACON) {
  547. fl |= SPS_ANIMATEUPDATE;
  548. }
  549. if (FCursorShadowed(GETPCI(pcurLogNew))) {
  550. fl |= SPS_ALPHA;
  551. }
  552. GreSetPointer(gpDispInfo->hDev, GETPCI(pcurPhysNew), fl, GETMOUSETRAILS(), MOUSE_TRAILS_FREQ);
  553. }
  554. /*
  555. * Notify anyone who cares about the change
  556. * This can happen on the RIT, so we need to pass on the real
  557. * thread/process ID. Hence we use hwndCursor.
  558. * This comment is from WIn'95 so it may not be true - IanJa.
  559. *
  560. * These are the events we send:
  561. * hcurPhys now NULL -> EVENT_OBJECT_HIDE
  562. * hcurPhys was NULL -> EVENT_OBJECT_SHOW
  563. * hcurPhys changing -> EVENT_OBJECT_NAMECHANGE
  564. * Since we only go through this code if hcurPhys is actually
  565. * changing, these checks are simple.
  566. */
  567. if (!pcurPhysNew) {
  568. event = EVENT_OBJECT_HIDE;
  569. } else if (!pcurPhysOld) {
  570. event = EVENT_OBJECT_SHOW;
  571. } else {
  572. event = EVENT_OBJECT_NAMECHANGE;
  573. }
  574. zzzWindowEvent(event, NULL, OBJID_CURSOR, INDEXID_CONTAINER, WEF_USEPWNDTHREAD);
  575. }
  576. }
  577. #if DBG
  578. /***************************************************************************\
  579. * DbgLockQCursor
  580. *
  581. * Special routine to lock cursors into a queue. Besides a pointer
  582. * to the cursor, the handle is also saved.
  583. * Returns the pointer to the previous current cursor for that queue.
  584. *
  585. * History:
  586. * 26-Jan-1993 JimA Created.
  587. \***************************************************************************/
  588. PCURSOR DbgLockQCursor(
  589. PQ pq,
  590. PCURSOR pcur)
  591. {
  592. /*
  593. * See if the queue is marked for destuction. If so, we should not
  594. * be trying to lock a cursor.
  595. */
  596. UserAssertMsg0(!(pq->QF_flags & QF_INDESTROY),
  597. "LockQCursor: Attempting to lock cursor to freed queue");
  598. return Lock(&pq->spcurCurrent, pcur);
  599. }
  600. #endif // DBG
  601. /***************************************************************************\
  602. * SetPointer
  603. *
  604. * 29-Mar-1998 vadimg created
  605. \***************************************************************************/
  606. void SetPointer(BOOL fSet)
  607. {
  608. if (fSet) {
  609. #ifdef GENERIC_INPUT
  610. if (gpqForeground) {
  611. PTHREADINFO ptiMouse = PtiMouseFromQ(gpqForeground);
  612. if (gpqForeground->iCursorLevel < 0 && TestRawInputMode(ptiMouse, CaptureMouse)) {
  613. return;
  614. }
  615. }
  616. #endif
  617. if (gpqCursor != NULL && gpqCursor->iCursorLevel >= 0 &&
  618. gpqCursor->spcurCurrent != NULL &&
  619. SYSMET(MOUSEPRESENT)) {
  620. PCURSINFO pci = GETPCI(gpqCursor->spcurCurrent);
  621. ULONG fl = FCursorShadowed(pci) ? SPS_ALPHA : 0;
  622. GreSetPointer(gpDispInfo->hDev, pci, fl, GETMOUSETRAILS(), MOUSE_TRAILS_FREQ);
  623. }
  624. } else {
  625. GreSetPointer(gpDispInfo->hDev, NULL, 0, 0, 0);
  626. }
  627. }
  628. /***************************************************************************\
  629. * HideCursorNoCapture
  630. *
  631. * Set the cursor to NULL if the mouse is not captured
  632. *
  633. * 20-May-1998 MCostea created
  634. \***************************************************************************/
  635. VOID zzzHideCursorNoCapture()
  636. {
  637. PTHREADINFO ptiCurrent = PtiCurrentShared();
  638. if (!ptiCurrent->pq->spwndCapture &&
  639. ((GetAppCompatFlags2(VER40) & GACF2_EDITNOMOUSEHIDE) == 0) &&
  640. TestEffectUP(MOUSEVANISH)) {
  641. zzzSetCursor(NULL);
  642. }
  643. }
  644. #ifdef AUTORUN_CURSOR
  645. /***************************************************************************\
  646. * ShowAutorunCursor
  647. *
  648. * Kicks off a system timer that will fire when it's time to hide the autorun
  649. * cursor and calls zzzUpdateCursorImage to change the current cursor to the
  650. * autorun guy.
  651. *
  652. * 02-Oct-2000 JasonSch created
  653. \***************************************************************************/
  654. VOID ShowAutorunCursor(
  655. ULONG ulTimeout)
  656. {
  657. EnterCrit();
  658. /*
  659. * Create/reset the timer. If we're already set it and it hasn't yet gone
  660. * off, this will reset the time to whatever we specify (which is the
  661. * behavior we want).
  662. */
  663. gtmridAutorunCursor = InternalSetTimer(NULL,
  664. gtmridAutorunCursor,
  665. ulTimeout,
  666. HideAutorunCursor,
  667. TMRF_RIT | TMRF_ONESHOT);
  668. LeaveCrit();
  669. }
  670. /***************************************************************************\
  671. * HideAutorunCursor
  672. *
  673. * Destroys the autorun cursor timer and resets the cursor itself.
  674. *
  675. * 02-Oct-2000 JasonSch created
  676. \***************************************************************************/
  677. VOID HideAutorunCursor(
  678. PWND pwnd,
  679. UINT message,
  680. UINT_PTR nID,
  681. LPARAM lParam)
  682. {
  683. CheckCritIn();
  684. /*
  685. * Calling zzzUpdateCursorImage with a NULL gtmridAutorunCursor will cause
  686. * the cursor to change to whatever is should be (e.g., app starting, if
  687. * appropriate).
  688. */
  689. KILLRITTIMER(NULL, gtmridAutorunCursor);
  690. gtmridAutorunCursor = 0;
  691. zzzUpdateCursorImage();
  692. UNREFERENCED_PARAMETER(pwnd);
  693. UNREFERENCED_PARAMETER(message);
  694. UNREFERENCED_PARAMETER(nID);
  695. UNREFERENCED_PARAMETER(lParam);
  696. }
  697. #endif // AUTORUN_CURSOR