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.

1000 lines
30 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: timers.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the user timer APIs and support routines.
  7. *
  8. * History:
  9. * 12-Nov-1990 DarrinM Created.
  10. * 08-Apr-1992 DarrinM Switched to PM/Win3-like ScanTimers model.
  11. \***************************************************************************/
  12. #define _TIMERS 1 // uses a LARGE_INTEGER
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. /*
  16. * Make sure that if we return a timer id that it is a WORD value. This
  17. * will ensure that WOW doesn't need to handle-translate return values
  18. * from SetTimer().
  19. *
  20. * Start with a large number so that FindTimer() doesn't find a timer we
  21. * calculated with a low cTimerId if the app happens to pass in NULL pwnd
  22. * and a low id (like 1).
  23. */
  24. #define TIMERID_MAX 0x7FFF
  25. #define TIMERID_MIN 0x100
  26. #define ELAPSED_MAX 0x7FFFFFFF
  27. #define SYSRIT_TIMER (TMRF_SYSTEM | TMRF_RIT)
  28. WORD cTimerId = TIMERID_MAX;
  29. /***************************************************************************\
  30. * _SetTimer (API)
  31. *
  32. * This API will start the specified timer.
  33. *
  34. * History:
  35. * 15-Nov-1990 DavidPe Created.
  36. \***************************************************************************/
  37. UINT_PTR _SetTimer(
  38. PWND pwnd,
  39. UINT_PTR nIDEvent,
  40. UINT dwElapse,
  41. TIMERPROC_PWND pTimerFunc)
  42. {
  43. /*
  44. * Prevent apps from setting a Timer with a window proc to another app
  45. */
  46. if (pwnd && (PpiCurrent() != GETPTI(pwnd)->ppi)) {
  47. RIPERR1(ERROR_ACCESS_DENIED,
  48. RIP_WARNING,
  49. "Calling SetTimer with window of another process %lX",
  50. pwnd);
  51. return 0;
  52. }
  53. return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, 0);
  54. }
  55. /***************************************************************************\
  56. * _SetSystemTimer
  57. *
  58. * This API will start start a system timer which will generate WM_SYSTIMER
  59. * messages rather than WM_TIMER
  60. *
  61. * History:
  62. * 15-Nov-1990 DavidPe Created.
  63. * 21-Jan-1991 IanJa Prefix '_' denotes export function (not API)
  64. \***************************************************************************/
  65. UINT_PTR _SetSystemTimer(
  66. PWND pwnd,
  67. UINT_PTR nIDEvent,
  68. DWORD dwElapse,
  69. TIMERPROC_PWND pTimerFunc)
  70. {
  71. /*
  72. * Prevent apps from setting a Timer with a window proc to another app
  73. */
  74. if (pwnd && PpiCurrent() != GETPTI(pwnd)->ppi) {
  75. RIPERR1(ERROR_ACCESS_DENIED,
  76. RIP_WARNING,
  77. "Calling SetSystemTimer with window of another process 0x%p",
  78. pwnd);
  79. return 0;
  80. }
  81. return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, TMRF_SYSTEM);
  82. }
  83. /***************************************************************************\
  84. * FreeTimer
  85. *
  86. * This function does the actual unlinking and freeing of the timer structure.
  87. * I pulled it out of FindTimer() so it could be shared with DestroyQueues-
  88. * Timers.
  89. * Sets *pptmr to point to the next TIMER struct (NULL if none)
  90. *
  91. * History:
  92. * 15-Feb-1991 DarrinM Pulled from FindTimer().
  93. \***************************************************************************/
  94. VOID FreeTimer(
  95. PTIMER ptmr) {
  96. CheckCritIn();
  97. /*
  98. * Mark it for destruction. If it the object is locked it can't
  99. * be freed right now.
  100. */
  101. if (!HMMarkObjectDestroy((PVOID)ptmr))
  102. return;
  103. /*
  104. * If this timer was just about to be processed, decrement
  105. * the ready-count since we're blowing it off.
  106. */
  107. if (ptmr->flags & TMRF_READY)
  108. DecTimerCount(ptmr->pti);
  109. /*
  110. * Unlock the window
  111. */
  112. Unlock(&ptmr->spwnd);
  113. /*
  114. * Unlink this timer
  115. */
  116. if (ptmr->ptmrPrev) {
  117. ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext;
  118. } else {
  119. gptmrFirst = ptmr->ptmrNext;
  120. }
  121. if (ptmr->ptmrNext) {
  122. ptmr->ptmrNext->ptmrPrev = ptmr->ptmrPrev;
  123. }
  124. /*
  125. * Free up the TIMER structure.
  126. */
  127. HMFreeObject((PVOID)ptmr);
  128. }
  129. /***************************************************************************\
  130. * FindTimer
  131. *
  132. * This function will find a timer that matches the parameters. We also
  133. * deal with killing timers here since it's easier to remove items from
  134. * the list while we're scanning it.
  135. *
  136. * History:
  137. * 15-Nov-1990 DavidPe Created.
  138. \***************************************************************************/
  139. PTIMER FindTimer(
  140. PWND pwnd,
  141. UINT_PTR nID,
  142. UINT flags,
  143. BOOL fKill)
  144. {
  145. PTIMER ptmr;
  146. ptmr = gptmrFirst;
  147. while (ptmr != NULL) {
  148. /*
  149. * Is this the timer we're looking for?
  150. */
  151. if ((ptmr->spwnd == pwnd) &&
  152. (ptmr->nID == nID) &&
  153. (ptmr->flags & SYSRIT_TIMER) == (flags & SYSRIT_TIMER)) {
  154. /*
  155. * Are we being called from KillTimer()? If so, destroy the
  156. * timer. return != 0 because *pptmr is gone.
  157. */
  158. if (fKill) {
  159. FreeTimer(ptmr);
  160. return (PTIMER)TRUE;
  161. }
  162. /*
  163. * Found the timer, break out of the loop.
  164. */
  165. break;
  166. }
  167. /*
  168. * No, try the next one.
  169. */
  170. ptmr = ptmr->ptmrNext;
  171. }
  172. return ptmr;
  173. }
  174. /***************************************************************************\
  175. * InternalSetTimer
  176. *
  177. * This is the guts of SetTimer that actually gets things going.
  178. *
  179. * NOTE (darrinm): Technically there is a bit of latency (the time it takes
  180. * between SetTimer's NtSetEvent and when the RIT wakes up and calls ScanTimers)
  181. * between when SetTimer is called and when the counter starts counting down.
  182. * This is uncool but it should be a very short amount of time because the RIT
  183. * is high-priority. If it becomes a problem I know how to fix it.
  184. *
  185. * History:
  186. * 15-Nov-1990 DavidPe Created.
  187. \***************************************************************************/
  188. UINT_PTR InternalSetTimer(
  189. PWND pwnd,
  190. UINT_PTR nIDEvent,
  191. UINT dwElapse,
  192. TIMERPROC_PWND pTimerFunc,
  193. UINT flags)
  194. {
  195. LARGE_INTEGER liT = {1, 0};
  196. PTIMER ptmr;
  197. PTHREADINFO ptiCurrent;
  198. CheckCritIn();
  199. /*
  200. * Assert if someone tries to set a timer after cleanup initiated.
  201. */
  202. if (gbCleanupInitiated) {
  203. RIPMSGF0(RIP_ERROR, "Too late to create a timer.");
  204. return 0;
  205. }
  206. /*
  207. * We need to make sure dwElapse isn't too big. NtUserSetTimer ensures
  208. * that no app passes in zero for the timeout value; let's assert here
  209. * that that remains the case, and that no one internally does this.
  210. */
  211. UserAssert(dwElapse != 0);
  212. if (dwElapse > ELAPSED_MAX) {
  213. RIPMSGF1(RIP_WARNING,
  214. "Timer period (0x%x) is too big",
  215. dwElapse);
  216. dwElapse = ELAPSED_MAX;
  217. }
  218. /*
  219. * Attempt to first locate the timer, then create a new one
  220. * if one isn't found.
  221. */
  222. if ((ptmr = FindTimer(pwnd, nIDEvent, flags, FALSE)) == NULL) {
  223. /*
  224. * Not found. Create a new one.
  225. */
  226. ptmr = (PTIMER)HMAllocObject(NULL, NULL, TYPE_TIMER, sizeof(TIMER));
  227. if (ptmr == NULL) {
  228. return 0;
  229. }
  230. ptmr->spwnd = NULL;
  231. if (pwnd == NULL) {
  232. WORD timerIdInitial = cTimerId;
  233. /*
  234. * Pick a unique, unused timer ID.
  235. */
  236. do {
  237. if (--cTimerId <= TIMERID_MIN) {
  238. cTimerId = TIMERID_MAX;
  239. }
  240. if (cTimerId == timerIdInitial) {
  241. /*
  242. * Flat out of timers bud.
  243. */
  244. HMFreeObject(ptmr);
  245. return 0;
  246. }
  247. } while (FindTimer(NULL, cTimerId, flags, FALSE) != NULL);
  248. ptmr->nID = (UINT)cTimerId;
  249. } else {
  250. ptmr->nID = nIDEvent;
  251. }
  252. /*
  253. * Link the new timer into the front of the list.
  254. * Handily this works even when gptmrFirst is NULL.
  255. */
  256. ptmr->ptmrNext = gptmrFirst;
  257. ptmr->ptmrPrev = NULL;
  258. if (gptmrFirst) {
  259. gptmrFirst->ptmrPrev = ptmr;
  260. }
  261. gptmrFirst = ptmr;
  262. } else {
  263. /*
  264. * If this timer was just about to be processed, decrement
  265. * cTimersReady since we're resetting it.
  266. */
  267. if (ptmr->flags & TMRF_READY) {
  268. DecTimerCount(ptmr->pti);
  269. }
  270. }
  271. /*
  272. * If pwnd is NULL, create a unique id by
  273. * using the timer handle. RIT timers are 'owned' by the RIT pti
  274. * so they are not deleted when the creating pti dies.
  275. *
  276. * We used to record the pti as the pti of the window if one was
  277. * specified. This is not what Win 3.1 does and it broke 10862
  278. * where some merge app was setting the timer on winword's window
  279. * it it still expected to get the messages not winword.
  280. *
  281. * MS Visual C NT was counting on this bug in the NT 3.1 so if
  282. * a thread sets a timer for a window in another thread in the
  283. * same process the timer goes off in the thread of the window.
  284. * You can see this by doing a build in msvcnt and the files being
  285. * compiled do not show up.
  286. */
  287. ptiCurrent = (PTHREADINFO)(W32GetCurrentThread()); /*
  288. * This will be NULL
  289. * for a non-GUI thread.
  290. */
  291. if (pwnd == NULL) {
  292. if (flags & TMRF_RIT) {
  293. ptmr->pti = gptiRit;
  294. } else {
  295. ptmr->pti = ptiCurrent;
  296. UserAssert(ptiCurrent);
  297. }
  298. } else {
  299. /*
  300. * As enforced in the API wrappers. We shouldn't get here
  301. * any other way for an app timer.
  302. *
  303. * Always use pti of the window when TMRF_PTIWINDOW is passed in.
  304. */
  305. if ((ptiCurrent->TIF_flags & TIF_16BIT) && !(flags & TMRF_PTIWINDOW)) {
  306. ptmr->pti = ptiCurrent;
  307. UserAssert(ptiCurrent);
  308. } else {
  309. ptmr->pti = GETPTI(pwnd);
  310. }
  311. }
  312. /*
  313. * Initialize the timer-struct.
  314. *
  315. * NOTE: The ptiOptCreator is used to identify a JOURNAL-timer. We
  316. * want to allow these timers to be destroyed when the creator
  317. * thread goes away. For other threads that create timers across
  318. * threads, we do not want to destroy these timers when the
  319. * creator goes away. Currently, we're only checking for a
  320. * TMRF_RIT. However, in the future we might want to add this
  321. * same check for TMRF_SYSTEM.
  322. */
  323. Lock(&(ptmr->spwnd), pwnd);
  324. ptmr->cmsCountdown = ptmr->cmsRate = dwElapse;
  325. ptmr->flags = flags | TMRF_INIT;
  326. ptmr->pfn = pTimerFunc;
  327. ptmr->ptiOptCreator = (flags & TMRF_RIT ? ptiCurrent : NULL);
  328. /*
  329. * Force the RIT to scan timers.
  330. *
  331. * N.B. The following code sets the raw input thread timer to expire
  332. * at the absolute time 1 which is very far into the past. This
  333. * causes the timer to immediately expire before the set timer
  334. * call returns.
  335. */
  336. if (ptiCurrent == gptiRit) {
  337. /*
  338. * Don't let RIT timer loop reset the master timer - we already have.
  339. */
  340. gbMasterTimerSet = TRUE;
  341. }
  342. UserAssert(gptmrMaster);
  343. KeSetTimer(gptmrMaster, liT, NULL);
  344. /*
  345. * Windows 3.1 returns the timer ID if non-zero, otherwise it returns 1.
  346. */
  347. return (ptmr->nID == 0 ? 1 : ptmr->nID);
  348. }
  349. /***************************************************************************\
  350. * _KillTimer (API)
  351. *
  352. * This API will stop a timer from sending WM_TIMER messages.
  353. *
  354. * History:
  355. * 15-Nov-1990 DavidPe Created.
  356. \***************************************************************************/
  357. BOOL _KillTimer(
  358. PWND pwnd,
  359. UINT_PTR nIDEvent)
  360. {
  361. return KillTimer2(pwnd, nIDEvent, FALSE);
  362. }
  363. /***************************************************************************\
  364. * _KillSystemTimer
  365. *
  366. * This API will stop a system timer from sending WM_SYSTIMER messages.
  367. *
  368. * History:
  369. * 15-Nov-1990 DavidPe Created.
  370. * 21-Jan-1991 IanJa Prefix '_' denotes export function (not API)
  371. \***************************************************************************/
  372. BOOL _KillSystemTimer(
  373. PWND pwnd,
  374. UINT_PTR nIDEvent)
  375. {
  376. return KillTimer2(pwnd, nIDEvent, TRUE);
  377. }
  378. /***************************************************************************\
  379. * KillTimer2
  380. *
  381. * This is the guts of KillTimer that actually kills the timer.
  382. *
  383. * History:
  384. * 15-Nov-1990 DavidPe Created.
  385. \***************************************************************************/
  386. BOOL KillTimer2(
  387. PWND pwnd,
  388. UINT_PTR nIDEvent,
  389. BOOL fSystemTimer)
  390. {
  391. /*
  392. * Call FindTimer() with fKill == TRUE. This will
  393. * basically delete the timer.
  394. */
  395. return (FindTimer(pwnd,
  396. nIDEvent,
  397. (fSystemTimer ? TMRF_SYSTEM : 0),
  398. TRUE) != NULL);
  399. }
  400. /***************************************************************************\
  401. * DestroyQueuesTimers
  402. *
  403. * This function scans through all the timers and destroys any that are
  404. * associated with the specified queue.
  405. *
  406. * History:
  407. * 15-Feb-1991 DarrinM Created.
  408. \***************************************************************************/
  409. VOID DestroyThreadsTimers(
  410. PTHREADINFO pti)
  411. {
  412. PTIMER ptmr;
  413. ptmr = gptmrFirst;
  414. while (ptmr != NULL) {
  415. /*
  416. * Is this one of the timers we're looking for? If so, destroy it.
  417. */
  418. if (ptmr->pti == pti || ptmr->ptiOptCreator == pti) {
  419. PTIMER ptmrNext = ptmr->ptmrNext;
  420. FreeTimer(ptmr);
  421. ptmr = ptmrNext;
  422. } else {
  423. ptmr = ptmr->ptmrNext;
  424. }
  425. }
  426. }
  427. /***************************************************************************\
  428. * DestroyWindowsTimers
  429. *
  430. * This function scans through all the timers and destroys any that are
  431. * associated with the specified window.
  432. *
  433. * History:
  434. * 04-Jun-1991 DarrinM Created.
  435. \***************************************************************************/
  436. VOID DestroyWindowsTimers(
  437. PWND pwnd)
  438. {
  439. PTIMER ptmr;
  440. ptmr = gptmrFirst;
  441. while (ptmr != NULL) {
  442. /*
  443. * Is this one of the timers we're looking for? If so, destroy it.
  444. */
  445. if (ptmr->spwnd == pwnd) {
  446. PTIMER ptmrNext = ptmr->ptmrNext;
  447. FreeTimer(ptmr);
  448. ptmr = ptmrNext;
  449. } else {
  450. ptmr = ptmr->ptmrNext;
  451. }
  452. }
  453. }
  454. /***************************************************************************\
  455. * DoTimer
  456. *
  457. * This function gets called from xxxPeekMessage() if the QS_TIMER bit is
  458. * set. If this timer is okay with the filter specified the appropriate
  459. * WM_*TIMER message will be placed in 'pmsg' and the timer will be reset.
  460. *
  461. * History:
  462. * 15-Nov-1990 DavidPe Created.
  463. * 27-NOv-1991 DavidPe Changed to move 'found' timers to end of list.
  464. \***************************************************************************/
  465. BOOL DoTimer(
  466. PWND pwndFilter)
  467. {
  468. PTHREADINFO pti;
  469. PTIMER ptmr;
  470. PTIMER ptmrNext;
  471. PQMSG pqmsg;
  472. CheckCritIn();
  473. pti = PtiCurrent();
  474. /*
  475. * Search for a timer that belongs to this queue.
  476. */
  477. ptmr = gptmrFirst;
  478. while (ptmr != NULL) {
  479. /*
  480. * Has this timer gone off and is it one we're looking for?
  481. */
  482. if ((ptmr->flags & TMRF_READY) &&
  483. (ptmr->pti == pti) &&
  484. CheckPwndFilter(ptmr->spwnd, pwndFilter)) {
  485. /*
  486. * We found an appropriate timer. Put it in the app's queue and
  487. * return success.
  488. */
  489. if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) {
  490. /*
  491. * Store the message and set the QS_POSTMESSAGE bit so the
  492. * thread knows it has a message.
  493. */
  494. StoreQMessage(pqmsg,
  495. ptmr->spwnd,
  496. (UINT)((ptmr->flags & TMRF_SYSTEM) ?
  497. WM_SYSTIMER : WM_TIMER),
  498. (WPARAM)ptmr->nID,
  499. (LPARAM)ptmr->pfn,
  500. 0, 0, 0);
  501. #ifdef REDIRECTION
  502. StoreQMessagePti(pqmsg, pti);
  503. #endif // REDIRECTION
  504. SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE);
  505. }
  506. /*
  507. * Reset this timer.
  508. */
  509. ptmr->flags &= ~TMRF_READY;
  510. DecTimerCount(ptmr->pti);
  511. /*
  512. * If there are other timers in the system move this timer
  513. * to the end of the list so other timers in for this queue
  514. * get a chance to go off.
  515. */
  516. ptmrNext = ptmr->ptmrNext;
  517. if (ptmrNext != NULL) {
  518. /*
  519. * Remove ptmr from its place in the list.
  520. */
  521. if (ptmr->ptmrPrev) {
  522. ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext;
  523. } else
  524. gptmrFirst = ptmr->ptmrNext;
  525. ptmrNext->ptmrPrev = ptmr->ptmrPrev;
  526. /*
  527. * Move to the last TIMER of the list.
  528. */
  529. while (ptmrNext->ptmrNext != NULL)
  530. ptmrNext = ptmrNext->ptmrNext;
  531. /*
  532. * Insert this timer at the end.
  533. */
  534. ptmrNext->ptmrNext = ptmr;
  535. ptmr->ptmrPrev = ptmrNext;
  536. ptmr->ptmrNext = NULL;
  537. }
  538. return TRUE;
  539. }
  540. ptmr = ptmr->ptmrNext;
  541. }
  542. return FALSE;
  543. }
  544. /***************************************************************************\
  545. * DecTimerCount
  546. *
  547. * This routine decrements cTimersReady and clears QS_TIMER if the count
  548. * goes down to zero.
  549. *
  550. * History:
  551. * 21-Jan-1991 DavidPe Created.
  552. \***************************************************************************/
  553. VOID DecTimerCount(
  554. PTHREADINFO pti)
  555. {
  556. CheckCritIn();
  557. if (--pti->cTimersReady == 0)
  558. pti->pcti->fsWakeBits &= ~QS_TIMER;
  559. }
  560. /***************************************************************************\
  561. * JournalTimer
  562. *
  563. *
  564. * History:
  565. * 04-Mar-1991 DavidPe Created.
  566. \***************************************************************************/
  567. VOID JournalTimer(
  568. PWND pwnd,
  569. UINT message,
  570. UINT_PTR nID,
  571. LPARAM lParam)
  572. {
  573. PTHREADINFO pti;
  574. DBG_UNREFERENCED_PARAMETER(pwnd);
  575. DBG_UNREFERENCED_PARAMETER(message);
  576. DBG_UNREFERENCED_PARAMETER(nID);
  577. /*
  578. * We've already entered the critical section.
  579. */
  580. if (pti = ((PTIMER)lParam)->ptiOptCreator)
  581. WakeSomeone(pti->pq, pti->pq->msgJournal, NULL);
  582. return;
  583. }
  584. /***************************************************************************\
  585. * SetJournalTimer
  586. *
  587. * Sets an NT timer that goes off in 'dt' milliseconds and will wake
  588. * up 'pti' at that time. This is used in journal playback code to
  589. * simulate the timing in which events were originally given to the system.
  590. *
  591. * History:
  592. * 04-Mar-1991 DavidPe Created.
  593. \***************************************************************************/
  594. void SetJournalTimer(
  595. DWORD dt,
  596. UINT msgJournal)
  597. {
  598. static UINT_PTR idJournal = 0;
  599. PtiCurrent()->pq->msgJournal = msgJournal;
  600. /*
  601. * Remember idJournal - because TMRF_ONESHOT timers stay in the timer
  602. * list - by remembering the idJournal, we always reuse the same timer
  603. * rather than creating new ones always.
  604. */
  605. idJournal = InternalSetTimer(NULL,
  606. idJournal,
  607. dt,
  608. JournalTimer,
  609. TMRF_RIT | TMRF_ONESHOT);
  610. }
  611. /***************************************************************************\
  612. * StartTimers
  613. *
  614. * Prime the timer pump by starting the cursor restoration timer.
  615. *
  616. * History:
  617. * 02-Apr-1992 DarrinM Created.
  618. \***************************************************************************/
  619. UINT_PTR StartTimers(VOID)
  620. {
  621. /*
  622. * Let GDI know that it can start settings timers on the RIT.
  623. */
  624. GreStartTimers();
  625. /*
  626. * TMRF_RIT timers are called directly from ScanTimers -- no nasty
  627. * thread switching for these boys.
  628. */
  629. return InternalSetTimer(NULL, 0, 1000, xxxHungAppDemon, TMRF_RIT);
  630. }
  631. /***************************************************************************\
  632. * TimersProc
  633. *
  634. * Deal with the timers. Called from RawInputThread.
  635. *
  636. * History:
  637. * 11-11-1996 CLupu Created.
  638. \***************************************************************************/
  639. VOID TimersProc(
  640. VOID)
  641. {
  642. DWORD dmsSinceLast, cmsCur, dmsNextTimer;
  643. LARGE_INTEGER liT;
  644. PTIMER ptmr;
  645. EnterCrit();
  646. /*
  647. * Calculate how long it was since the last time we processed timers so
  648. * we can subtract that much time from each timer's countdown value.
  649. */
  650. cmsCur = NtGetTickCount();
  651. dmsSinceLast = ComputePastTickDelta(cmsCur, gcmsLastTimer);
  652. gcmsLastTimer = cmsCur;
  653. /*
  654. * dmsNextTimer is the time delta before the next
  655. * timer should go off. As we loop through the
  656. * timers below this will shrink to the smallest
  657. * cmsCountdown value in the list.
  658. */
  659. dmsNextTimer = ELAPSED_MAX;
  660. ptmr = gptmrFirst;
  661. gbMasterTimerSet = FALSE;
  662. while (ptmr != NULL) {
  663. /*
  664. * ONESHOT timers go to a WAITING state after
  665. * they go off. This allows us to leave them
  666. * in the list but keep them from going off
  667. * over and over.
  668. */
  669. if (ptmr->flags & TMRF_WAITING) {
  670. ptmr = ptmr->ptmrNext;
  671. continue;
  672. }
  673. /*
  674. * The first time we encounter a timer we don't
  675. * want to set it off, we just want to use it to
  676. * compute the shortest countdown value.
  677. */
  678. if (ptmr->flags & TMRF_INIT) {
  679. ptmr->flags &= ~TMRF_INIT;
  680. } else {
  681. /*
  682. * If this timer is going off, wake up its
  683. * owner.
  684. */
  685. if (ptmr->cmsCountdown > dmsSinceLast) {
  686. ptmr->cmsCountdown -= dmsSinceLast;
  687. } else {
  688. UserAssert(ptmr->cmsRate <= ELAPSED_MAX);
  689. ptmr->cmsCountdown = ptmr->cmsRate;
  690. /*
  691. * If the timer's owner hasn't handled the
  692. * last time it went off yet, throw this event
  693. * away.
  694. */
  695. if (!(ptmr->flags & TMRF_READY)) {
  696. /*
  697. * A ONESHOT timer goes into a WAITING state
  698. * until SetTimer is called again to reset it.
  699. */
  700. if (ptmr->flags & TMRF_ONESHOT)
  701. ptmr->flags |= TMRF_WAITING;
  702. /*
  703. * RIT timers have the distinction of being
  704. * called directly and executing serially with
  705. * with incoming timer events.
  706. * NOTE: RIT timers get called while we're
  707. * inside the critical section.
  708. */
  709. if (ptmr->flags & TMRF_RIT) {
  710. TL tlTimer;
  711. ThreadLock(ptmr, &tlTimer);
  712. /*
  713. * May set gbMasterTimerSet
  714. */
  715. (ptmr->pfn)(NULL,
  716. WM_SYSTIMER,
  717. ptmr->nID,
  718. (LPARAM)ptmr);
  719. if (HMIsMarkDestroy(ptmr)) {
  720. ptmr = ptmr->ptmrNext;
  721. ThreadUnlock(&tlTimer);
  722. continue;
  723. }
  724. ThreadUnlock(&tlTimer);
  725. } else {
  726. ptmr->flags |= TMRF_READY;
  727. ptmr->pti->cTimersReady++;
  728. SetWakeBit(ptmr->pti, QS_TIMER);
  729. }
  730. }
  731. }
  732. }
  733. /*
  734. * Remember the shortest time left of the timers.
  735. */
  736. if (ptmr->cmsCountdown < dmsNextTimer) {
  737. dmsNextTimer = ptmr->cmsCountdown;
  738. }
  739. /*
  740. * Advance to the next timer structure.
  741. */
  742. ptmr = ptmr->ptmrNext;
  743. }
  744. if (!gbMasterTimerSet) {
  745. /*
  746. * Time in NT should be negative to specify a relative
  747. * time. It's also in hundred nanosecond units so multiply
  748. * by 10000 to get the right value from milliseconds.
  749. */
  750. liT.QuadPart = Int32x32To64(-10000, dmsNextTimer);
  751. KeSetTimer(gptmrMaster, liT, NULL);
  752. }
  753. LeaveCrit();
  754. }
  755. /***************************************************************************\
  756. * xxxSystemTimerProc()
  757. *
  758. * 11/15/96 GerardoB Created
  759. \***************************************************************************/
  760. VOID xxxSystemTimerProc(PWND pwnd, UINT msg, UINT_PTR id, LPARAM lParam)
  761. {
  762. CheckLock(pwnd);
  763. UNREFERENCED_PARAMETER(msg);
  764. UNREFERENCED_PARAMETER(id);
  765. UNREFERENCED_PARAMETER(lParam);
  766. switch (id) {
  767. case IDSYS_LAYER: {
  768. PDCE pdce;
  769. UserAssert(gnVisibleRedirectedCount > 0);
  770. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  771. if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS))
  772. continue;
  773. if ((pdce->DCX_flags & DCX_REDIRECTED) && (pdce->DCX_flags & DCX_INUSE)) {
  774. UpdateRedirectedDC(pdce);
  775. }
  776. }
  777. }
  778. return;
  779. case IDSYS_FADE:
  780. AnimateFade();
  781. return;
  782. case IDSYS_FLASHWND:
  783. xxxFlashWindow(pwnd, FLASHW_TIMERCALL, 0);
  784. return;
  785. case IDSYS_WNDTRACKING: {
  786. /*
  787. * If the active track window hasn't changed,
  788. * it's time to active it.
  789. * spwndTrack can be NULL if it got destroyed but we haven't
  790. * destroyed the timer.yet
  791. */
  792. PTHREADINFO pti = GETPTI(pwnd);
  793. UserAssert(TestUP(ACTIVEWINDOWTRACKING));
  794. if ((pti->rpdesk->spwndTrack != NULL)
  795. && (pwnd == GetActiveTrackPwnd(pti->rpdesk->spwndTrack, NULL))) {
  796. pti->pq->QF_flags |= (QF_ACTIVEWNDTRACKING | QF_MOUSEMOVED);
  797. #ifdef REDIRECTION
  798. /*
  799. * Should we call the hit test hook here ?
  800. */
  801. PushMouseMove(pti->pq, gpsi->ptCursor);
  802. #endif // REDIRECTION
  803. SetWakeBit(pti, QS_MOUSEMOVE);
  804. }
  805. }
  806. break;
  807. case IDSYS_MOUSEHOVER: {
  808. PTHREADINFO pti = GETPTI(pwnd);
  809. PDESKTOP pdesk = pti->rpdesk;
  810. /*
  811. * If hover hasn't been canceled, the mouse is still on
  812. * this window and the point is still on the rect, then
  813. * it's hover time!
  814. */
  815. if ((pdesk->dwDTFlags & DF_TRACKMOUSEHOVER)
  816. && (HWq(pwnd) == HWq(pdesk->spwndTrack)
  817. && PtInRect(&pdesk->rcMouseHover, gpsi->ptCursor))) {
  818. UINT message;
  819. WPARAM wParam;
  820. POINT pt = gpsi->ptCursor;
  821. if (pdesk->htEx == HTCLIENT) {
  822. message = WM_MOUSEHOVER;
  823. wParam = (WPARAM)GetMouseKeyFlags(pti->pq);
  824. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  825. pt.x = pwnd->rcClient.right - pt.x - 1;
  826. } else {
  827. pt.x -= pwnd->rcClient.left;
  828. }
  829. pt.y -= pwnd->rcClient.top;
  830. } else {
  831. message = WM_NCMOUSEHOVER;
  832. /*
  833. * Map the extended hit test code to a public one.
  834. */
  835. wParam = (WPARAM)LOWORD(pdesk->htEx);
  836. if ((wParam >= HTEXMENUFIRST) && (wParam <= HTEXMENULAST)) {
  837. wParam = (WPARAM)HTMENU;
  838. } else if ((wParam >= HTEXSCROLLFIRST) && (wParam <= HTEXSCROLLLAST)) {
  839. wParam = (WPARAM)(HIWORD(pdesk->htEx) ? HTVSCROLL : HTHSCROLL);
  840. }
  841. }
  842. _PostMessage(pwnd, message, wParam, MAKELPARAM(pt.x, pt.y));
  843. pdesk->dwDTFlags &= ~DF_TRACKMOUSEHOVER;
  844. break;
  845. }
  846. }
  847. return;
  848. default:
  849. RIPMSG1(RIP_ERROR, "xxxSystemTimerProc: unexpected id: 0x%x", id);
  850. break;
  851. }
  852. /*
  853. * If we fell through, the timer's got to go.
  854. */
  855. _KillSystemTimer(pwnd, id);
  856. }