Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

timers.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: timers.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains the user timer APIs and support routines. 00007 * 00008 * History: 00009 * 12-Nov-1990 DarrinM Created. 00010 * 08-Apr-1992 DarrinM Switched to PM/Win3-like ScanTimers model. 00011 \***************************************************************************/ 00012 00013 #define _TIMERS 1 // uses a LARGE_INTEGER 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 00018 /* 00019 * Make sure that if we return a timer id that it is a WORD value. This 00020 * will ensure that WOW doesn't need to handle-translate return values 00021 * from SetTimer(). 00022 * 00023 * Start with a large number so that FindTimer() doesn't find a timer we 00024 * calculated with a low cTimerId if the app happens to pass in NULL pwnd 00025 * and a low id (like 1). 00026 */ 00027 #define TIMERID_MAX 0x7FFF 00028 #define TIMERID_MIN 0x100 00029 00030 #define ELAPSED_MAX 0x7FFFFFFF 00031 00032 #define SYSRIT_TIMER (TMRF_SYSTEM | TMRF_RIT) 00033 00034 WORD cTimerId = TIMERID_MAX; 00035 00036 /***************************************************************************\ 00037 * _SetTimer (API) 00038 * 00039 * This API will start the specified timer. 00040 * 00041 * History: 00042 * 15-Nov-1990 DavidPe Created. 00043 \***************************************************************************/ 00044 00045 UINT_PTR _SetTimer( 00046 PWND pwnd, 00047 UINT_PTR nIDEvent, 00048 UINT dwElapse, 00049 TIMERPROC_PWND pTimerFunc) 00050 { 00051 /* 00052 * Prevent apps from setting a Timer with a window proc to another app 00053 */ 00054 if (pwnd && (PpiCurrent() != GETPTI(pwnd)->ppi)) { 00055 00056 RIPERR1(ERROR_ACCESS_DENIED, 00057 RIP_WARNING, 00058 "Calling SetTimer with window of another process %lX", 00059 pwnd); 00060 00061 return 0; 00062 } 00063 00064 return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, 0); 00065 } 00066 00067 /***************************************************************************\ 00068 * _SetSystemTimer 00069 * 00070 * This API will start start a system timer which will generate WM_SYSTIMER 00071 * messages rather than WM_TIMER 00072 * 00073 * History: 00074 * 15-Nov-1990 DavidPe Created. 00075 * 21-Jan-1991 IanJa Prefix '_' denotes export function (not API) 00076 \***************************************************************************/ 00077 00078 UINT_PTR _SetSystemTimer( 00079 PWND pwnd, 00080 UINT_PTR nIDEvent, 00081 DWORD dwElapse, 00082 TIMERPROC_PWND pTimerFunc) 00083 { 00084 /* 00085 * Prevent apps from setting a Timer with a window proc to another app 00086 */ 00087 if (pwnd && PpiCurrent() != GETPTI(pwnd)->ppi) { 00088 00089 RIPERR1(ERROR_ACCESS_DENIED, 00090 RIP_WARNING, 00091 "Calling SetSystemTimer with window of another process %lX", 00092 pwnd); 00093 00094 return 0; 00095 } 00096 00097 return InternalSetTimer(pwnd, nIDEvent, dwElapse, pTimerFunc, TMRF_SYSTEM); 00098 } 00099 00100 /***************************************************************************\ 00101 * FreeTimer 00102 * 00103 * This function does the actual unlinking and freeing of the timer structure. 00104 * I pulled it out of FindTimer() so it could be shared with DestroyQueues- 00105 * Timers. 00106 * Sets *pptmr to point to the next TIMER struct (NULL if none) 00107 * 00108 * History: 00109 * 15-Feb-1991 DarrinM Pulled from FindTimer(). 00110 \***************************************************************************/ 00111 00112 VOID FreeTimer( 00113 PTIMER ptmr) { 00114 00115 CheckCritIn(); 00116 00117 /* 00118 * Mark it for destruction. If it the object is locked it can't 00119 * be freed right now. 00120 */ 00121 if (!HMMarkObjectDestroy((PVOID)ptmr)) 00122 return; 00123 00124 /* 00125 * If this timer was just about to be processed, decrement 00126 * the ready-count since we're blowing it off. 00127 */ 00128 if (ptmr->flags & TMRF_READY) 00129 DecTimerCount(ptmr->pti); 00130 00131 /* 00132 * Unlock the window 00133 */ 00134 Unlock(&ptmr->spwnd); 00135 00136 /* 00137 * Unlink this timer 00138 */ 00139 if (ptmr->ptmrPrev) { 00140 ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext; 00141 } else { 00142 gptmrFirst = ptmr->ptmrNext; 00143 } 00144 00145 if (ptmr->ptmrNext) { 00146 ptmr->ptmrNext->ptmrPrev = ptmr->ptmrPrev; 00147 } 00148 00149 /* 00150 * Free up the TIMER structure. 00151 */ 00152 HMFreeObject((PVOID)ptmr); 00153 } 00154 00155 00156 /***************************************************************************\ 00157 * FindTimer 00158 * 00159 * This function will find a timer that matches the parameters. We also 00160 * deal with killing timers here since it's easier to remove items from 00161 * the list while we're scanning it. 00162 * 00163 * History: 00164 * 15-Nov-1990 DavidPe Created. 00165 \***************************************************************************/ 00166 00167 PTIMER FindTimer( 00168 PWND pwnd, 00169 UINT_PTR nID, 00170 UINT flags, 00171 BOOL fKill) 00172 { 00173 PTIMER ptmr; 00174 00175 ptmr = gptmrFirst; 00176 00177 while (ptmr != NULL) { 00178 00179 /* 00180 * Is this the timer we're looking for? 00181 */ 00182 if ((ptmr->spwnd == pwnd) && 00183 (ptmr->nID == nID) && 00184 (ptmr->flags & SYSRIT_TIMER) == (flags & SYSRIT_TIMER)) { 00185 00186 /* 00187 * Are we being called from KillTimer()? If so, destroy the 00188 * timer. return != 0 because *pptmr is gone. 00189 */ 00190 if (fKill) { 00191 FreeTimer(ptmr); 00192 return (PTIMER)TRUE; 00193 } 00194 00195 /* 00196 * Found the timer, break out of the loop. 00197 */ 00198 break; 00199 } 00200 00201 /* 00202 * No, try the next one. 00203 */ 00204 ptmr = ptmr->ptmrNext; 00205 } 00206 00207 return ptmr; 00208 } 00209 00210 /***************************************************************************\ 00211 * InternalSetTimer 00212 * 00213 * This is the guts of SetTimer that actually gets things going. 00214 * 00215 * NOTE (darrinm): Technically there is a bit of latency (the time it takes 00216 * between SetTimer's NtSetEvent and when the RIT wakes up and calls ScanTimers) 00217 * between when SetTimer is called and when the counter starts counting down. 00218 * This is uncool but it should be a very short amount of time because the RIT 00219 * is high-priority. If it becomes a problem I know how to fix it. 00220 * 00221 * History: 00222 * 15-Nov-1990 DavidPe Created. 00223 \***************************************************************************/ 00224 00225 UINT_PTR InternalSetTimer( 00226 PWND pwnd, 00227 UINT_PTR nIDEvent, 00228 UINT dwElapse, 00229 TIMERPROC_PWND pTimerFunc, 00230 UINT flags) 00231 { 00232 LARGE_INTEGER liT = {1, 0}; 00233 PTIMER ptmr; 00234 PTHREADINFO ptiCurrent; 00235 00236 CheckCritIn(); 00237 00238 /* 00239 * Assert if someone tries to set a timer after InitiateWin32kCleanup 00240 * killed the RIT. 00241 */ 00242 UserAssert(gptiRit != NULL); 00243 00244 /* 00245 * 1.0 compatibility weirdness. Also, don't allow negative elapse times 00246 * because this'll cause ScanTimers() to generate negative elapse times 00247 * between timers. 00248 */ 00249 if ((dwElapse == 0) || (dwElapse > ELAPSED_MAX)) 00250 dwElapse = 1; 00251 00252 /* 00253 * Attempt to first locate the timer, then create a new one 00254 * if one isn't found. 00255 */ 00256 if ((ptmr = FindTimer(pwnd, nIDEvent, flags, FALSE)) == NULL) { 00257 00258 /* 00259 * Not found. Create a new one. 00260 */ 00261 ptmr = (PTIMER)HMAllocObject(NULL, NULL, TYPE_TIMER, sizeof(TIMER)); 00262 if (ptmr == NULL) { 00263 return 0; 00264 } 00265 00266 ptmr->spwnd = NULL; 00267 00268 if (pwnd == NULL) { 00269 00270 WORD timerIdInitial = cTimerId; 00271 00272 /* 00273 * Pick a unique, unused timer ID. 00274 */ 00275 do { 00276 00277 if (--cTimerId <= TIMERID_MIN) 00278 cTimerId = TIMERID_MAX; 00279 00280 if (cTimerId == timerIdInitial) { 00281 00282 /* 00283 * Flat out of timers bud. 00284 */ 00285 HMFreeObject(ptmr); 00286 return 0; 00287 } 00288 00289 } while (FindTimer(NULL, cTimerId, flags, FALSE) != NULL); 00290 00291 ptmr->nID = (UINT)cTimerId; 00292 00293 } else { 00294 ptmr->nID = nIDEvent; 00295 } 00296 00297 /* 00298 * Link the new timer into the front of the list. 00299 * Handily this works even when gptmrFirst is NULL. 00300 */ 00301 ptmr->ptmrNext = gptmrFirst; 00302 ptmr->ptmrPrev = NULL; 00303 if (gptmrFirst) 00304 gptmrFirst->ptmrPrev = ptmr; 00305 gptmrFirst = ptmr; 00306 00307 } else { 00308 00309 /* 00310 * If this timer was just about to be processed, 00311 * decrement cTimersReady since we're resetting it. 00312 */ 00313 if (ptmr->flags & TMRF_READY) 00314 DecTimerCount(ptmr->pti); 00315 } 00316 00317 /* 00318 * If pwnd is NULL, create a unique id by 00319 * using the timer handle. RIT timers are 'owned' by the RIT pti 00320 * so they are not deleted when the creating pti dies. 00321 * 00322 * We used to record the pti as the pti of the window if one was 00323 * specified. This is not what Win 3.1 does and it broke 10862 00324 * where some merge app was setting the timer on winword's window 00325 * it it still expected to get the messages not winword. 00326 * 00327 * MS Visual C NT was counting on this bug in the NT 3.1 so if 00328 * a thread sets a timer for a window in another thread in the 00329 * same process the timer goes off in the thread of the window. 00330 * You can see this by doing a build in msvcnt and the files being 00331 * compiled do not show up. 00332 */ 00333 ptiCurrent = (PTHREADINFO)(W32GetCurrentThread()); /* 00334 * This will be NULL 00335 * for a non-GUI thread. 00336 */ 00337 00338 if (pwnd == NULL) { 00339 00340 if (flags & TMRF_RIT) { 00341 ptmr->pti = gptiRit; 00342 } else { 00343 ptmr->pti = ptiCurrent; 00344 UserAssert(ptiCurrent); 00345 } 00346 00347 } else { 00348 00349 /* 00350 * As enforced in the API wrappers. We shouldn't get here 00351 * any other way for an app timer. 00352 * 00353 * Always use pti of the window when TMRF_PTIWINDOW is passed in. 00354 */ 00355 if ((ptiCurrent->TIF_flags & TIF_16BIT) && !(flags & TMRF_PTIWINDOW)) { 00356 ptmr->pti = ptiCurrent; 00357 UserAssert(ptiCurrent); 00358 } else { 00359 ptmr->pti = GETPTI(pwnd); 00360 } 00361 } 00362 00363 /* 00364 * Initialize the timer-struct. 00365 * 00366 * NOTE: The ptiOptCreator is used to identify a JOURNAL-timer. We 00367 * want to allow these timers to be destroyed when the creator 00368 * thread goes away. For other threads that create timers across 00369 * threads, we do not want to destroy these timers when the 00370 * creator goes away. Currently, we're only checking for a 00371 * TMRF_RIT. However, in the future we might want to add this 00372 * same check for TMRF_SYSTEM. 00373 */ 00374 Lock(&(ptmr->spwnd), pwnd); 00375 00376 ptmr->cmsCountdown = ptmr->cmsRate = dwElapse; 00377 ptmr->flags = flags | TMRF_INIT; 00378 ptmr->pfn = pTimerFunc; 00379 ptmr->ptiOptCreator = (flags & TMRF_RIT ? ptiCurrent : NULL); 00380 00381 /* 00382 * Force the RIT to scan timers. 00383 * 00384 * N.B. The following code sets the raw input thread timer to expire 00385 * at the absolute time 1 which is very far into the past. This 00386 * causes the timer to immediately expire before the set timer 00387 * call returns. 00388 */ 00389 if (ptiCurrent == gptiRit) { 00390 /* 00391 * Don't let RIT timer loop reset the master timer - we already have. 00392 */ 00393 gbMasterTimerSet = TRUE; 00394 } 00395 00396 UserAssert(gptmrMaster); 00397 KeSetTimer(gptmrMaster, liT, NULL); 00398 00399 /* 00400 * Windows 3.1 returns the timer ID if non-zero, otherwise it returns 1. 00401 */ 00402 return (ptmr->nID == 0 ? 1 : ptmr->nID); 00403 } 00404 00405 /***************************************************************************\ 00406 * _KillTimer (API) 00407 * 00408 * This API will stop a timer from sending WM_TIMER messages. 00409 * 00410 * History: 00411 * 15-Nov-1990 DavidPe Created. 00412 \***************************************************************************/ 00413 00414 BOOL _KillTimer( 00415 PWND pwnd, 00416 UINT_PTR nIDEvent) 00417 { 00418 return KillTimer2(pwnd, nIDEvent, FALSE); 00419 } 00420 00421 /***************************************************************************\ 00422 * _KillSystemTimer 00423 * 00424 * This API will stop a system timer from sending WM_SYSTIMER messages. 00425 * 00426 * History: 00427 * 15-Nov-1990 DavidPe Created. 00428 * 21-Jan-1991 IanJa Prefix '_' denotes export function (not API) 00429 \***************************************************************************/ 00430 00431 BOOL _KillSystemTimer( 00432 PWND pwnd, 00433 UINT_PTR nIDEvent) 00434 { 00435 return KillTimer2(pwnd, nIDEvent, TRUE); 00436 } 00437 00438 /***************************************************************************\ 00439 * KillTimer2 00440 * 00441 * This is the guts of KillTimer that actually kills the timer. 00442 * 00443 * History: 00444 * 15-Nov-1990 DavidPe Created. 00445 \***************************************************************************/ 00446 00447 BOOL KillTimer2( 00448 PWND pwnd, 00449 UINT_PTR nIDEvent, 00450 BOOL fSystemTimer) 00451 { 00452 /* 00453 * Call FindTimer() with fKill == TRUE. This will 00454 * basically delete the timer. 00455 */ 00456 return (FindTimer(pwnd, 00457 nIDEvent, 00458 (fSystemTimer ? TMRF_SYSTEM : 0), 00459 TRUE) != NULL); 00460 } 00461 00462 /***************************************************************************\ 00463 * DestroyQueuesTimers 00464 * 00465 * This function scans through all the timers and destroys any that are 00466 * associated with the specified queue. 00467 * 00468 * History: 00469 * 15-Feb-1991 DarrinM Created. 00470 \***************************************************************************/ 00471 00472 VOID DestroyThreadsTimers( 00473 PTHREADINFO pti) 00474 { 00475 PTIMER ptmr; 00476 00477 ptmr = gptmrFirst; 00478 00479 while (ptmr != NULL) { 00480 00481 /* 00482 * Is this one of the timers we're looking for? If so, destroy it. 00483 */ 00484 if (ptmr->pti == pti || ptmr->ptiOptCreator == pti) { 00485 PTIMER ptmrNext = ptmr->ptmrNext; 00486 FreeTimer(ptmr); 00487 ptmr = ptmrNext; 00488 } else { 00489 ptmr = ptmr->ptmrNext; 00490 } 00491 } 00492 } 00493 00494 /***************************************************************************\ 00495 * DestroyWindowsTimers 00496 * 00497 * This function scans through all the timers and destroys any that are 00498 * associated with the specified window. 00499 * 00500 * History: 00501 * 04-Jun-1991 DarrinM Created. 00502 \***************************************************************************/ 00503 00504 VOID DestroyWindowsTimers( 00505 PWND pwnd) 00506 { 00507 PTIMER ptmr; 00508 00509 ptmr = gptmrFirst; 00510 00511 while (ptmr != NULL) { 00512 00513 /* 00514 * Is this one of the timers we're looking for? If so, destroy it. 00515 */ 00516 if (ptmr->spwnd == pwnd) { 00517 PTIMER ptmrNext = ptmr->ptmrNext; 00518 FreeTimer(ptmr); 00519 ptmr = ptmrNext; 00520 } else { 00521 ptmr = ptmr->ptmrNext; 00522 } 00523 } 00524 } 00525 00526 /***************************************************************************\ 00527 * DoTimer 00528 * 00529 * This function gets called from xxxPeekMessage() if the QS_TIMER bit is 00530 * set. If this timer is okay with the filter specified the appropriate 00531 * WM_*TIMER message will be placed in 'pmsg' and the timer will be reset. 00532 * 00533 * History: 00534 * 15-Nov-1990 DavidPe Created. 00535 * 27-NOv-1991 DavidPe Changed to move 'found' timers to end of list. 00536 \***************************************************************************/ 00537 00538 BOOL DoTimer( 00539 PWND pwndFilter) 00540 { 00541 PTHREADINFO pti; 00542 PTIMER ptmr; 00543 PTIMER ptmrNext; 00544 PQMSG pqmsg; 00545 00546 CheckCritIn(); 00547 00548 pti = PtiCurrent(); 00549 00550 /* 00551 * Search for a timer that belongs to this queue. 00552 */ 00553 ptmr = gptmrFirst; 00554 00555 while (ptmr != NULL) { 00556 00557 /* 00558 * Has this timer gone off and is it one we're looking for? 00559 */ 00560 if ((ptmr->flags & TMRF_READY) && 00561 (ptmr->pti == pti) && 00562 CheckPwndFilter(ptmr->spwnd, pwndFilter)) { 00563 00564 /* 00565 * We found an appropriate timer. Put it in the app's queue and 00566 * return success. 00567 */ 00568 if ((pqmsg = AllocQEntry(&pti->mlPost)) != NULL) { 00569 00570 /* 00571 * Store the message and set the QS_POSTMESSAGE bit so the 00572 * thread knows it has a message. 00573 */ 00574 StoreQMessage(pqmsg, 00575 ptmr->spwnd, 00576 (UINT)((ptmr->flags & TMRF_SYSTEM) ? 00577 WM_SYSTIMER : WM_TIMER), 00578 (WPARAM)ptmr->nID, 00579 (LPARAM)ptmr->pfn, 00580 0, 0, 0); 00581 #ifdef REDIRECTION 00582 StoreQMessagePti(pqmsg, pti); 00583 #endif // REDIRECTION 00584 SetWakeBit(pti, QS_POSTMESSAGE | QS_ALLPOSTMESSAGE); 00585 } 00586 00587 /* 00588 * Reset this timer. 00589 */ 00590 ptmr->flags &= ~TMRF_READY; 00591 DecTimerCount(ptmr->pti); 00592 00593 /* 00594 * If there are other timers in the system move this timer 00595 * to the end of the list so other timers in for this queue 00596 * get a chance to go off. 00597 */ 00598 ptmrNext = ptmr->ptmrNext; 00599 if (ptmrNext != NULL) { 00600 00601 /* 00602 * Remove ptmr from its place in the list. 00603 */ 00604 if (ptmr->ptmrPrev) { 00605 ptmr->ptmrPrev->ptmrNext = ptmr->ptmrNext; 00606 } else 00607 gptmrFirst = ptmr->ptmrNext; 00608 00609 ptmrNext->ptmrPrev = ptmr->ptmrPrev; 00610 00611 /* 00612 * Move to the last TIMER of the list. 00613 */ 00614 while (ptmrNext->ptmrNext != NULL) 00615 ptmrNext = ptmrNext->ptmrNext; 00616 00617 /* 00618 * Insert this timer at the end. 00619 */ 00620 ptmrNext->ptmrNext = ptmr; 00621 ptmr->ptmrPrev = ptmrNext; 00622 ptmr->ptmrNext = NULL; 00623 } 00624 00625 return TRUE; 00626 } 00627 00628 ptmr = ptmr->ptmrNext; 00629 } 00630 00631 return FALSE; 00632 } 00633 00634 /***************************************************************************\ 00635 * DecTimerCount 00636 * 00637 * This routine decrements cTimersReady and clears QS_TIMER if the count 00638 * goes down to zero. 00639 * 00640 * History: 00641 * 21-Jan-1991 DavidPe Created. 00642 \***************************************************************************/ 00643 00644 VOID DecTimerCount( 00645 PTHREADINFO pti) 00646 { 00647 CheckCritIn(); 00648 00649 if (--pti->cTimersReady == 0) 00650 pti->pcti->fsWakeBits &= ~QS_TIMER; 00651 } 00652 00653 /***************************************************************************\ 00654 * JournalTimer 00655 * 00656 * 00657 * History: 00658 * 04-Mar-1991 DavidPe Created. 00659 \***************************************************************************/ 00660 00661 VOID JournalTimer( 00662 PWND pwnd, 00663 UINT message, 00664 UINT_PTR nID, 00665 LPARAM lParam) 00666 { 00667 PTHREADINFO pti; 00668 00669 DBG_UNREFERENCED_PARAMETER(pwnd); 00670 DBG_UNREFERENCED_PARAMETER(message); 00671 DBG_UNREFERENCED_PARAMETER(nID); 00672 00673 /* 00674 * We've already entered the critical section. 00675 */ 00676 if (pti = ((PTIMER)lParam)->ptiOptCreator) 00677 WakeSomeone(pti->pq, pti->pq->msgJournal, NULL); 00678 00679 return; 00680 } 00681 00682 /***************************************************************************\ 00683 * SetJournalTimer 00684 * 00685 * Sets an NT timer that goes off in 'dt' milliseconds and will wake 00686 * up 'pti' at that time. This is used in journal playback code to 00687 * simulate the timing in which events were originally given to the system. 00688 * 00689 * History: 00690 * 04-Mar-1991 DavidPe Created. 00691 \***************************************************************************/ 00692 00693 void SetJournalTimer( 00694 DWORD dt, 00695 UINT msgJournal) 00696 { 00697 static UINT_PTR idJournal = 0; 00698 00699 PtiCurrent()->pq->msgJournal = msgJournal; 00700 00701 /* 00702 * Remember idJournal - because TMRF_ONESHOT timers stay in the timer 00703 * list - by remembering the idJournal, we always reuse the same timer 00704 * rather than creating new ones always. 00705 */ 00706 idJournal = InternalSetTimer(NULL, 00707 idJournal, 00708 dt, 00709 JournalTimer, 00710 TMRF_RIT | TMRF_ONESHOT); 00711 } 00712 00713 /***************************************************************************\ 00714 * StartTimers 00715 * 00716 * Prime the timer pump by starting the cursor restoration timer. 00717 * 00718 * History: 00719 * 02-Apr-1992 DarrinM Created. 00720 \***************************************************************************/ 00721 00722 UINT_PTR StartTimers(VOID) 00723 { 00724 /* 00725 * Let GDI know that it can start settings timers on the RIT. 00726 */ 00727 GreStartTimers(); 00728 00729 /* 00730 * TMRF_RIT timers are called directly from ScanTimers -- no nasty 00731 * thread switching for these boys. 00732 */ 00733 return InternalSetTimer(NULL, 0, 1000, xxxHungAppDemon, TMRF_RIT); 00734 } 00735 00736 00737 /***************************************************************************\ 00738 * TimersProc 00739 * 00740 * Deal with the timers. Called from RawInputThread. 00741 * 00742 * History: 00743 * 11-11-1996 CLupu Created. 00744 \***************************************************************************/ 00745 00746 VOID TimersProc( 00747 VOID) 00748 { 00749 INT dmsSinceLast; 00750 LARGE_INTEGER liT; 00751 PTIMER ptmr; 00752 DWORD cmsCur; 00753 00754 /* 00755 * Calculate how long it was since the last time we 00756 * processed timers so we can subtract that much time 00757 * from each timer's countdown value. 00758 */ 00759 EnterCrit(); 00760 00761 cmsCur = NtGetTickCount(); 00762 dmsSinceLast = ComputePastTickDelta(cmsCur, gcmsLastTimer); 00763 gcmsLastTimer = cmsCur; 00764 00765 /* 00766 * dmsNextTimer is the time delta before the next 00767 * timer should go off. As we loop through the 00768 * timers below this will shrink to the smallest 00769 * cmsCountdown value in the list. 00770 */ 00771 gdmsNextTimer = 0x7FFFFFFF; 00772 ptmr = gptmrFirst; 00773 gbMasterTimerSet = FALSE; 00774 while (ptmr != NULL) { 00775 00776 /* 00777 * ONESHOT timers go to a WAITING state after 00778 * they go off. This allows us to leave them 00779 * in the list but keep them from going off 00780 * over and over. 00781 */ 00782 if (ptmr->flags & TMRF_WAITING) { 00783 ptmr = ptmr->ptmrNext; 00784 continue; 00785 } 00786 00787 /* 00788 * The first time we encounter a timer we don't 00789 * want to set it off, we just want to use it to 00790 * compute the shortest countdown value. 00791 */ 00792 if (ptmr->flags & TMRF_INIT) { 00793 ptmr->flags &= ~TMRF_INIT; 00794 00795 } else { 00796 /* 00797 * If this timer is going off, wake up its 00798 * owner. 00799 */ 00800 ptmr->cmsCountdown -= dmsSinceLast; 00801 if (ptmr->cmsCountdown <= 0) { 00802 ptmr->cmsCountdown = ptmr->cmsRate; 00803 00804 /* 00805 * If the timer's owner hasn't handled the 00806 * last time it went off yet, throw this event 00807 * away. 00808 */ 00809 if (!(ptmr->flags & TMRF_READY)) { 00810 /* 00811 * A ONESHOT timer goes into a WAITING state 00812 * until SetTimer is called again to reset it. 00813 */ 00814 if (ptmr->flags & TMRF_ONESHOT) 00815 ptmr->flags |= TMRF_WAITING; 00816 00817 /* 00818 * RIT timers have the distinction of being 00819 * called directly and executing serially with 00820 * with incoming timer events. 00821 * NOTE: RIT timers get called while we're 00822 * inside the critical section. 00823 */ 00824 if (ptmr->flags & TMRF_RIT) { 00825 TL tlTimer; 00826 00827 ThreadLock(ptmr, &tlTimer); 00828 /* 00829 * May set gbMasterTimerSet 00830 */ 00831 (ptmr->pfn)(NULL, 00832 WM_SYSTIMER, 00833 ptmr->nID, 00834 (LPARAM)ptmr); 00835 00836 if (HMIsMarkDestroy(ptmr)) { 00837 ptmr = ptmr->ptmrNext; 00838 ThreadUnlock(&tlTimer); 00839 continue; 00840 } 00841 ThreadUnlock(&tlTimer); 00842 00843 } else { 00844 ptmr->flags |= TMRF_READY; 00845 ptmr->pti->cTimersReady++; 00846 SetWakeBit(ptmr->pti, QS_TIMER); 00847 } 00848 } 00849 } 00850 } 00851 00852 /* 00853 * Remember the shortest time left of the timers. 00854 */ 00855 if (ptmr->cmsCountdown < gdmsNextTimer) 00856 gdmsNextTimer = ptmr->cmsCountdown; 00857 00858 /* 00859 * Advance to the next timer structure. 00860 */ 00861 ptmr = ptmr->ptmrNext; 00862 } 00863 00864 if (!gbMasterTimerSet) { 00865 /* 00866 * Time in NT should be negative to specify a relative 00867 * time. It's also in hundred nanosecond units so multiply 00868 * by 10000 to get the right value from milliseconds. 00869 */ 00870 liT.QuadPart = Int32x32To64(-10000, gdmsNextTimer); 00871 KeSetTimer(gptmrMaster, liT, NULL); 00872 } 00873 00874 LeaveCrit(); 00875 } 00876 00877 /***************************************************************************\ 00878 * xxxSystemTimerProc() 00879 * 00880 * 11/15/96 GerardoB Created 00881 \***************************************************************************/ 00882 VOID xxxSystemTimerProc(PWND pwnd, UINT msg, UINT_PTR id, LPARAM lParam) 00883 { 00884 CheckLock(pwnd); 00885 UNREFERENCED_PARAMETER(msg); 00886 UNREFERENCED_PARAMETER(id); 00887 UNREFERENCED_PARAMETER(lParam); 00888 00889 switch (id) { 00890 case IDSYS_LAYER: { 00891 PDCE pdce; 00892 00893 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 00894 00895 if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS)) 00896 continue; 00897 00898 if ((pdce->DCX_flags & DCX_LAYERED) && (pdce->DCX_flags & DCX_INUSE)) { 00899 UpdateLayeredSprite(pdce); 00900 } 00901 } 00902 } 00903 return; 00904 00905 case IDSYS_FADE: 00906 AnimateFade(); 00907 return; 00908 00909 case IDSYS_FLASHWND: 00910 xxxFlashWindow(pwnd, FLASHW_TIMERCALL, 0); 00911 return; 00912 00913 case IDSYS_WNDTRACKING: { 00914 /* 00915 * If the active track window hasn't changed, 00916 * it's time to active it. 00917 * spwndTrack can be NULL if it got destroyed but we haven't 00918 * destroyed the timer.yet 00919 */ 00920 PTHREADINFO pti = GETPTI(pwnd); 00921 UserAssert(TestUP(ACTIVEWINDOWTRACKING)); 00922 00923 if ((pti->rpdesk->spwndTrack != NULL) 00924 && (pwnd == GetActiveTrackPwnd(pti->rpdesk->spwndTrack, NULL))) { 00925 00926 pti->pq->QF_flags |= (QF_ACTIVEWNDTRACKING | QF_MOUSEMOVED); 00927 00928 #ifdef REDIRECTION 00929 /* 00930 * Should we call the hit test hook here ? 00931 */ 00932 PushMouseMove(pti->pq, gpsi->ptCursor); 00933 #endif // REDIRECTION 00934 00935 SetWakeBit(pti, QS_MOUSEMOVE); 00936 } 00937 } 00938 break; 00939 00940 case IDSYS_MOUSEHOVER: { 00941 PTHREADINFO pti = GETPTI(pwnd); 00942 PDESKTOP pdesk = pti->rpdesk; 00943 /* 00944 * If hover hasn't been canceled, the mouse is still on 00945 * this window and the point is still on the rect, then 00946 * it's hover time! 00947 */ 00948 if ((pdesk->dwDTFlags & DF_TRACKMOUSEHOVER) 00949 && (HWq(pwnd) == HWq(pdesk->spwndTrack) 00950 && PtInRect(&pdesk->rcMouseHover, gpsi->ptCursor))) { 00951 00952 UINT message; 00953 WPARAM wParam; 00954 POINT pt = gpsi->ptCursor; 00955 00956 if (pdesk->htEx == HTCLIENT) { 00957 message = WM_MOUSEHOVER; 00958 wParam = (WPARAM)GetMouseKeyFlags(pti->pq); 00959 #ifdef USE_MIRRORING 00960 if (TestWF(pwnd, WEFLAYOUTRTL)) { 00961 pt.x = pwnd->rcClient.right - pt.x - 1; 00962 } else 00963 #endif 00964 { 00965 pt.x -= pwnd->rcClient.left; 00966 } 00967 pt.y -= pwnd->rcClient.top; 00968 } else { 00969 message = WM_NCMOUSEHOVER; 00970 /* 00971 * Map the extended hit test code to a public one. 00972 */ 00973 wParam = (WPARAM)LOWORD(pdesk->htEx); 00974 if ((wParam >= HTEXMENUFIRST) && (wParam <= HTEXMENULAST)) { 00975 wParam = (WPARAM)HTMENU; 00976 } else if ((wParam >= HTEXSCROLLFIRST) && (wParam <= HTEXSCROLLLAST)) { 00977 wParam = (WPARAM)(HIWORD(pdesk->htEx) ? HTVSCROLL : HTHSCROLL); 00978 } 00979 } 00980 00981 _PostMessage(pwnd, message, wParam, MAKELPARAM(pt.x, pt.y)); 00982 00983 pdesk->dwDTFlags &= ~DF_TRACKMOUSEHOVER; 00984 break; 00985 } 00986 } 00987 return; 00988 00989 00990 default: 00991 RIPMSG1(RIP_ERROR, "xxxSystemTimerProc: unexpected id:%#lx", id); 00992 break; 00993 } 00994 00995 /* 00996 * if we fell through, the timer got to go 00997 */ 00998 _KillSystemTimer(pwnd, id); 00999 return; 01000 } 01001

Generated on Sat May 15 19:41:59 2004 for test by doxygen 1.3.7