source: branches/branch-1-0/src/helpers/timer.c

Last change on this file was 297, checked in by pr, 20 years ago

Update functions using exception handlers to force non-register variables

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 26.1 KB
RevLine 
[14]1
2/*
3 *@@sourcefile timer.c:
[41]4 * XTimers, which can be used to avoid excessive PM
5 * timer usage.
[14]6 *
[44]7 * The functions here allow you to share a single PM
8 * timer for many windows on the same thread. Basically,
9 * these start a "master PM timer", to whose WM_TIMER
10 * message your window procedure must respond by calling
11 * tmrTimerTick, which will "distribute" the timer tick
12 * to those XTimers which have elapsed.
[14]13 *
14 * The main advantage of the XTimers is that these
15 * are not a limited resource (as opposed to PM timers).
16 * I don't know how many PM timers exist on the system,
17 * but PMREF says that the no. of remaining timers can
18 * be queried with WinQuerySysValue(SV_CTIMERS).
19 *
[127]20 * XTimers are used excessively by the default widgets
21 * of XWorkplace's XCenter.
22 *
[14]23 * There are a few limitations with the XTimers though:
24 *
[44]25 * -- tmrTimerTick (which you must call when the
26 * "master" WM_TIMER comes in) does not post WM_TIMER
27 * messages to the windows specified in the subtimers,
28 * but calls the window procedure of the target window
29 * directly. This makes sure that timers work even if
30 * some thread is hogging the SIQ.
[14]31 *
[44]32 * This however requires that all XTimers must run on
33 * the same thread as the owner window of the master
34 * timer which was specified with tmrCreateSet.
35 *
[14]36 * -- Queue timers (with HWND == NULLHANDLE) are not
37 * supported.
38 *
[44]39 * -- When a window is destroyed, its timers are not
40 * automatically cleaned up. tmrTimerTick does
[19]41 * detect invalid windows and removes them from the
42 * timers list before posting, but to be on the safe
43 * side, always call tmrStopAllTimers when WM_DESTROY
44 * comes into a window which has used timers.
[14]45 *
[127]46 * So to use XTimers, do the following:
47 *
48 * 1. Create a timer set with tmrCreateSet. Specify
49 * an owner window and the timer ID of the master
50 * PM timer.
51 *
52 * 2. You can then start and stop XTimers for windows
53 * on the same thread by calling tmrStartXTimer and
54 * tmrStopXTimer, respectively.
55 *
56 * 3. In the window proc of the owner window, respond
57 * to WM_TIMER for the master PM timer by calling
58 * tmrTimerTick. This will call the window procs
59 * of those windows with WM_TIMER messages directly
60 * whose XTimers have elapsed.
61 *
[14]62 * Function prefixes:
63 * -- tmr* timer functions
64 *
65 *@@header "helpers\timer.h"
66 *@@added V0.9.7 (2000-12-04) [umoeller]
67 */
68
69/*
[297]70 * Copyright (C) 2000-2005 Ulrich M”ller.
[14]71 * This file is part of the "XWorkplace helpers" source package.
72 * This is free software; you can redistribute it and/or modify
73 * it under the terms of the GNU General Public License as published
74 * by the Free Software Foundation, in version 2 as it comes in the
75 * "COPYING" file of the XWorkplace main distribution.
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU General Public License for more details.
80 */
81
82// OS2 includes
83
84#define OS2EMX_PLAIN_CHAR
85 // this is needed for "os2emx.h"; if this is defined,
86 // emx will define PSZ as _signed_ char, otherwise
87 // as unsigned char
88
89#define INCL_DOSEXCEPTIONS
90#define INCL_DOSPROCESS
91#define INCL_DOSSEMAPHORES
[15]92#define INCL_DOSMISC
[14]93#define INCL_DOSERRORS
[17]94
[41]95#define INCL_WINWINDOWMGR
[17]96#define INCL_WINMESSAGEMGR
[41]97#define INCL_WINTIMER
[14]98#include <os2.h>
99
100#include <stdio.h>
101#include <setjmp.h>
102
103#include "setup.h" // code generation and debugging options
104
105#include "helpers\datetime.h"
106#include "helpers\except.h"
107#include "helpers\linklist.h"
[86]108#include "helpers\math.h"
[91]109#include "helpers\standards.h"
[14]110#include "helpers\threads.h"
111#include "helpers\timer.h"
112
[164]113// #define DEBUG_XTIMERS
[163]114
[14]115/*
116 *@@category: Helpers\PM helpers\Timer replacements
[21]117 * see timer.c.
[14]118 */
119
120/* ******************************************************************
121 *
122 * Private declarations
123 *
124 ********************************************************************/
125
126/*
127 *@@ XTIMER:
128 * one of these represents an XTimer.
[44]129 * These are stored in a linked list in
130 * an _XTIMERSET.
[14]131 */
132
133typedef struct _XTIMER
134{
[41]135 USHORT usTimerID; // timer ID, as passed to tmrStartXTimer
136 HWND hwndTarget; // target window, as passed to tmrStartXTimer
[14]137 ULONG ulTimeout; // timer's timeout (in ms)
138 ULONG ulNextFire; // next time scalar (from dtGetULongTime) to fire at
139} XTIMER, *PXTIMER;
140
141/* ******************************************************************
142 *
143 * Global variables
144 *
145 ********************************************************************/
146
[68]147HMTX G_hmtxTimers = NULLHANDLE; // timers lock mutex
[14]148
[68]149/* ******************************************************************
150 *
151 * Private functions
152 *
153 ********************************************************************/
154
[14]155/*
[68]156 *@@ LockTimers:
[14]157 *
[68]158 *@@added V0.9.12 (2001-05-12) [umoeller]
[14]159 */
160
[222]161STATIC BOOL LockTimers(VOID)
[14]162{
[68]163 if (!G_hmtxTimers)
[297]164 return !DosCreateMutexSem(NULL,
165 &G_hmtxTimers,
166 0,
167 TRUE); // request!
168
169 return !DosRequestMutexSem(G_hmtxTimers, SEM_INDEFINITE_WAIT);
[68]170}
[14]171
[68]172/*
173 *@@ UnlockTimers:
174 *
175 *@@added V0.9.12 (2001-05-12) [umoeller]
176 */
[14]177
[222]178STATIC VOID UnlockTimers(VOID)
[68]179{
180 DosReleaseMutexSem(G_hmtxTimers);
181}
[14]182
183/*
184 *@@ FindTimer:
185 * returns the XTIMER structure from the global
186 * linked list which matches the given window
187 * _and_ timer ID.
188 *
[68]189 * Internal function. Caller must hold the mutex.
[14]190 */
191
[222]192STATIC PXTIMER FindTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
[142]193 HWND hwnd, // in: timer target window
194 USHORT usTimerID) // in: timer ID
[14]195{
[127]196 PLINKLIST pllXTimers;
197 if ( (pSet)
198 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
199 )
[14]200 {
[41]201 PLISTNODE pNode = lstQueryFirstNode(pllXTimers);
202 while (pNode)
[14]203 {
[41]204 PXTIMER pTimer = (PXTIMER)pNode->pItemData;
205 if ( (pTimer->usTimerID == usTimerID)
206 && (pTimer->hwndTarget == hwnd)
207 )
208 {
[297]209 return pTimer;
[41]210 }
211
212 pNode = pNode->pNext;
[14]213 }
[41]214 }
[14]215
[169]216 return NULL;
[14]217}
218
219/*
220 *@@ RemoveTimer:
221 * removes the specified XTIMER structure from
222 * the global linked list of running timers.
223 *
[68]224 * Internal function. Caller must hold the mutex.
[14]225 */
226
[222]227STATIC VOID RemoveTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
[163]228 PXTIMER pTimer) // in: timer to remove
[14]229{
[127]230 PLINKLIST pllXTimers;
231 if ( (pSet)
232 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
233 )
[41]234 {
[163]235 #ifdef DEBUG_XTIMERS
236 _Pmpf((__FUNCTION__ ": removing timer %d", pTimer->usTimerID));
237 #endif
[41]238 lstRemoveItem(pllXTimers,
239 pTimer); // auto-free!
240 }
[14]241}
242
[74]243/*
244 *@@ AdjustPMTimer:
245 * goes thru all XTimers in the sets and starts
246 * or stops the PM timer with a decent frequency.
247 *
248 * Internal function. Caller must hold the mutex.
249 *
250 *@@added V0.9.9 (2001-03-07) [umoeller]
[86]251 *@@changed V0.9.14 (2001-07-07) [umoeller]: added GCD optimizations
[74]252 */
253
[222]254STATIC VOID AdjustPMTimer(PXTIMERSET pSet)
[74]255{
256 PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
[91]257 ULONG cTimers = lstCountItems(pllXTimers);
[93]258
259 #ifdef DEBUG_XTIMERS
260 _Pmpf((__FUNCTION__ ": entering"));
261 #endif
262
[91]263 if (!cTimers)
[74]264 {
265 // no XTimers running:
266 if (pSet->idPMTimerRunning)
267 {
268 // but PM timer running:
269 // stop it
270 WinStopTimer(pSet->hab,
271 pSet->hwndOwner,
272 pSet->idPMTimer);
273 pSet->idPMTimerRunning = 0;
274 }
275
276 pSet->ulPMTimeout = 0;
277 }
278 else
279 {
280 // we have timers:
[86]281
[91]282 ULONG ulOldPMTimeout = pSet->ulPMTimeout;
[74]283
[91]284 PLISTNODE pNode = lstQueryFirstNode(pllXTimers);
285 PXTIMER pTimer1 = (PXTIMER)pNode->pItemData;
286
287 if (cTimers == 1)
[74]288 {
[86]289 // only one timer:
290 // that's easy
[93]291 #ifdef DEBUG_XTIMERS
292 _Pmpf((" got 1 timer"));
293 #endif
294
[91]295 pSet->ulPMTimeout = pTimer1->ulTimeout;
[86]296 }
[91]297 else if (cTimers == 2)
[86]298 {
299 // exactly two timers:
300 // find the greatest common denominator
[91]301 PXTIMER pTimer2 = (PXTIMER)pNode->pNext->pItemData;
[93]302 #ifdef DEBUG_XTIMERS
303 _Pmpf((" got 2 timers"));
304 #endif
[74]305
[86]306 pSet->ulPMTimeout = mathGCD(pTimer1->ulTimeout,
307 pTimer2->ulTimeout);
308 }
309 else
310 {
[91]311 // more than two timers:
[86]312 // run through all timers and find the greatest
313 // common denominator of all frequencies...
314 int *paInts = (int*)_alloca(sizeof(int) * cTimers),
315 i = 0;
316
[93]317 #ifdef DEBUG_XTIMERS
318 _Pmpf((" got %d timers", cTimers));
319 #endif
[86]320
321 // fill an array of integers with the
322 // timer frequencies
323 while (pNode)
324 {
[91]325 pTimer1 = (PXTIMER)pNode->pItemData;
[86]326
[93]327 #ifdef DEBUG_XTIMERS
328 _Pmpf((" timeout %d is %d", i, pTimer1->ulTimeout));
329 #endif
[86]330
[91]331 paInts[i++] = pTimer1->ulTimeout;
[86]332
333 pNode = pNode->pNext;
334 }
335
336 pSet->ulPMTimeout = mathGCDMulti(paInts,
337 cTimers);
[74]338 }
339
[93]340 #ifdef DEBUG_XTIMERS
341 _Pmpf(("--> GCD is %d", pSet->ulPMTimeout));
342 #endif
343
[91]344 if ( (!pSet->idPMTimerRunning) // timer not running?
[74]345 || (pSet->ulPMTimeout != ulOldPMTimeout) // timeout changed?
346 )
[93]347 {
[74]348 // start or restart PM timer
349 pSet->idPMTimerRunning = WinStartTimer(pSet->hab,
350 pSet->hwndOwner,
351 pSet->idPMTimer,
352 pSet->ulPMTimeout);
[93]353 }
[74]354 }
355}
356
[41]357/* ******************************************************************
358 *
359 * Exported functions
360 *
361 ********************************************************************/
362
[14]363/*
[41]364 *@@ tmrCreateSet:
365 * creates a "timer set" for use with the XTimer functions.
366 * This is the first step if you want to use the XTimers.
367 *
[44]368 * hwndOwner must specify the "owner window", the target
369 * window for the master PM timer. This window must respond
370 * to a WM_TIMER message with the specified usPMTimerID and
371 * invoke tmrTimerTick then.
372 *
373 * Note that the master timer is not started until an XTimer
374 * is started.
375 *
[41]376 * Use tmrDestroySet to free all resources again.
377 *
378 *@@added V0.9.9 (2001-02-28) [umoeller]
379 */
380
[44]381PXTIMERSET tmrCreateSet(HWND hwndOwner, // in: owner window
[41]382 USHORT usPMTimerID)
383{
[91]384 PXTIMERSET pSet = NEW(XTIMERSET);
[41]385 if (pSet)
386 {
387 pSet->hab = WinQueryAnchorBlock(hwndOwner);
388 pSet->hwndOwner = hwndOwner;
389 pSet->idPMTimer = usPMTimerID;
390 pSet->idPMTimerRunning = 0;
[44]391 pSet->ulPMTimeout = 0;
[41]392
393 pSet->pvllXTimers = (PVOID)lstCreate(TRUE);
394 }
395
[297]396 return pSet;
[41]397}
398
399/*
400 *@@ tmrDestroySet:
401 * destroys a timer set previously created using
402 * tmrCreateSet.
403 *
404 * Of course, this will stop all XTimers which
405 * might still be running with this set.
406 *
407 *@@added V0.9.9 (2001-02-28) [umoeller]
[68]408 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
[41]409 */
410
[44]411VOID tmrDestroySet(PXTIMERSET pSet) // in: timer set (from tmrCreateSet)
[41]412{
[74]413 if (LockTimers())
[41]414 {
[74]415 if (pSet)
[41]416 {
[127]417 PLINKLIST pllXTimers;
418 if (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
[68]419 {
[74]420 PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
421 while (pTimerNode)
[68]422 {
[74]423 PLISTNODE pNext = pTimerNode->pNext;
[68]424 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
425 RemoveTimer(pSet, pTimer);
[74]426 pTimerNode = pNext;
[68]427 }
428
[74]429 lstFree(&pllXTimers);
430 pSet->pvllXTimers = NULL;
[41]431 }
432
[127]433 if (pSet->idPMTimerRunning)
434 {
435 WinStopTimer(pSet->hab,
436 pSet->hwndOwner,
437 pSet->idPMTimer);
438 pSet->idPMTimerRunning = 0;
439 }
440
441 free(pSet);
[44]442 }
443
[74]444 UnlockTimers();
[44]445 }
[41]446}
447
448/*
449 *@@ tmrTimerTick:
450 * implements a PM timer tick.
451 *
452 * When your window procs receives WM_TIMER for the
453 * one PM timer which is supposed to trigger all the
454 * XTimers, it must call this function. This will
455 * evaluate all XTimers on the list and "fire" them
456 * by calling the window procs directly with the
457 * WM_TIMER message.
458 *
459 *@@added V0.9.9 (2001-02-28) [umoeller]
[68]460 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
[91]461 *@@changed V0.9.12 (2001-05-24) [umoeller]: fixed crash if this got called during tmrTimerTick
462 *@@changed V0.9.14 (2001-08-01) [umoeller]: fixed mem overwrite which might have caused crashes if this got called during tmrTimerTick
[93]463 *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed "half frequency" regression caused by frequency optimizations
[127]464 *@@changed V0.9.16 (2001-12-18) [umoeller]: now using WinDispatchMsg to avoid crashes during win destruction
[163]465 *@@changed V0.9.19 (2002-05-04) [umoeller]: added excpt handling to avoid hanging all timers on the mutex
[41]466 */
467
[44]468VOID tmrTimerTick(PXTIMERSET pSet) // in: timer set (from tmrCreateSet)
[41]469{
[297]470 volatile BOOL fLocked = FALSE; // XWP V1.0.4 (2005-10-09) [pr]
[163]471
472 TRY_LOUD(excpt1)
[41]473 {
[163]474 if (fLocked = LockTimers())
[68]475 {
[163]476 PLINKLIST pllXTimers;
477 if ( (pSet)
478 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
479 )
480 {
481 // go thru all XTimers and see which one
482 // has elapsed; for all of these, post WM_TIMER
483 // to the target window proc
484 PLISTNODE pTimerNode;
[127]485
[163]486 if (!(pTimerNode = lstQueryFirstNode(pllXTimers)))
[68]487 {
[163]488 // no timers left:
489 if (pSet->idPMTimerRunning)
490 {
491 // but PM timer running:
492 // stop it
493 WinStopTimer(pSet->hab,
494 pSet->hwndOwner,
495 pSet->idPMTimer);
496 pSet->idPMTimerRunning = 0;
497 }
498
499 pSet->ulPMTimeout = 0;
[127]500 }
[163]501 else
[74]502 {
[163]503 // we have timers:
504 BOOL fFoundInvalid = FALSE;
[68]505
[163]506 // get current time
507 ULONG ulTimeNow = 0;
508 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
509 &ulTimeNow, sizeof(ulTimeNow));
[41]510
[93]511 #ifdef DEBUG_XTIMERS
[163]512 _Pmpf((__FUNCTION__ ": ulTimeNow = %d", ulTimeNow));
[93]513 #endif
514
[163]515 while (pTimerNode)
[74]516 {
[163]517 // get next node first because the
518 // list can get modified while processing
519 // V0.9.12 (2001-05-24) [umoeller]
520 PLISTNODE pNext = pTimerNode->pNext;
[41]521
[163]522 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
523
[93]524 #ifdef DEBUG_XTIMERS
[163]525 _Pmpf((" timer %d: ulNextFire = %d",
526 lstIndexFromItem(pllXTimers, pTimer),
527 pTimer->ulNextFire));
[93]528 #endif
529
[163]530 if ( (pTimer)
531 // && (pTimer->ulNextFire < ulTimeNow)
532 // V0.9.14 (2001-08-01) [umoeller]
533 // use <= because otherwise we'll get
534 // only half the frequency...
535 // we get here frequently where the
536 // two values are EXACTLY equal due
537 // to the above optimization (DosQuerySysInfo
538 // called once only for the entire loop)
539 && (pTimer->ulNextFire <= ulTimeNow)
540 )
[74]541 {
[163]542 // this timer has elapsed:
543 // fire!
[93]544
[163]545 #ifdef DEBUG_XTIMERS
546 _Pmpf((" --> fire!"));
547 #endif
[93]548
[163]549 if (WinIsWindow(pSet->hab,
550 pTimer->hwndTarget))
551 {
552 // window still valid:
553 // get the window's window proc
554 QMSG qmsg;
555 PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
556 QWP_PFNWP);
[91]557
[163]558 // moved this up V0.9.14 (2001-08-01) [umoeller]
559 pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
[91]560
[163]561 // call the window proc DIRECTLY
562 // V0.9.16 (2001-12-18) [umoeller]:
563 // now using WinDispatchMsg to avoid crashes
564 // while hwndTarget is being destroyed
565 /* qmsg.hwnd = pTimer->hwndTarget;
566 qmsg.msg = WM_TIMER;
567 qmsg.mp1 = (MPARAM)pTimer->usTimerID;
568 qmsg.mp2 = (MPARAM)0;
569 qmsg.time = 0;
570 qmsg.ptl.x = 0;
571 qmsg.ptl.y = 0;
572 qmsg.reserved = 0;
573 WinDispatchMsg(pSet->hab,
574 &qmsg); */
[41]575
[163]576 pfnwp(pTimer->hwndTarget,
577 WM_TIMER,
578 (MPARAM)pTimer->usTimerID,
579 0);
580 // V0.9.12 (2001-05-24) [umoeller]
581 // if the winproc chooses to start or
582 // stop a timer, pNext still points
583 // to a valid node...
584 // -- if a timer is removed, that's OK
585 // -- if a timer is added, it is added to
586 // the list, so we'll see it in this loop
[91]587
[163]588 // V0.9.14 (2001-08-01) [umoeller]
[41]589
[163]590 // DO NOT REFERENCE pTimer AFTER THIS CODE;
591 // the winproc might have removed the timer,
592 // and since the list is auto-free, pTimer
593 // might have been freed!!
594 }
595 else
596 {
597 // window has been destroyed:
598 lstRemoveNode(pllXTimers,
599 pTimerNode);
600 // pNext is still valid
[41]601
[163]602 fFoundInvalid = TRUE;
603 }
[68]604
[163]605 } // end if (pTimer->ulNextFire < ulTimeNow)
[41]606
[163]607 // next timer
608 pTimerNode = pNext; // V0.9.12 (2001-05-24) [umoeller]
609 } // end while (pTimerNode)
[41]610
[163]611 // destroy invalid timers, if any
612 if (fFoundInvalid)
613 AdjustPMTimer(pSet);
614
615 } // end else if (!pTimerNode)
616 } // end if (pllXTimers)
617 } // end if (LockTimers())
618 }
619 CATCH(excpt1) {} END_CATCH();
620
621 if (fLocked)
[74]622 UnlockTimers();
[41]623}
624
625/*
626 *@@ tmrStartXTimer:
[14]627 * starts an XTimer.
628 *
629 * Any window can request an XTimer using
630 * this function. This operates similar to
631 * WinStartTimer, except that the number of
632 * XTimers is not limited.
633 *
[127]634 * Returns the ID of a new timer or resets an
635 * existing timer (if usTimerID is already used
636 * with hwnd). Use tmrStopXTimer to stop the timer.
[14]637 *
[264]638 * Returns 0 if an error occurred. It is thus
[127]639 * invalid to specify a timer ID of 0.
640 *
[14]641 * The timer is _not_ stopped automatically
[15]642 * when the window is destroyed.
[14]643 *
[86]644 * Note: Unless you own the timer set that
645 * your timer runs on, it is strongly recommended
646 * that your timer frequency is set to a multiple
647 * of 125. The PM master timer behind the timer
648 * set will be set to the greatest common divisor
649 * of all frequencies, and if you set one timer
650 * to 2000 and the other one to 2001, you will
651 * cause quite a lot of overhead. This applies
652 * especially to timers started by XCenter widgets.
653 *
654 * For security, all timer frequencies will be
655 * rounded to multiples of 25 anyway. Still,
656 * running two timers at 1000 and 1025 will cause
657 * the master timer to be set to 25, which is
658 * overkill.
659 *
[15]660 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
[68]661 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
[86]662 *@@changed V0.9.14 (2001-07-12) [umoeller]: now rounding freq's to multiples of 25
[14]663 */
664
[44]665USHORT XWPENTRY tmrStartXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
666 HWND hwnd, // in: target window for XTimer
[127]667 USHORT usTimerID, // in: timer ID for XTimer's WM_TIMER (must be > 0)
[44]668 ULONG ulTimeout) // in: XTimer's timeout
[14]669{
670 USHORT usrc = 0;
671
[41]672 // _Pmpf((__FUNCTION__ ": entering"));
673
[74]674 if (LockTimers())
[14]675 {
[127]676 PLINKLIST pllXTimers;
677 if ( (pSet)
678 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
679 && (hwnd)
680 && (ulTimeout)
681 && (usTimerID) // V0.9.16 (2001-12-18) [umoeller]
682 )
[14]683 {
[127]684 PXTIMER pTimer;
685 ULONG ulTimeNow;
[41]686
[127]687 // fix the timeout... we allow only multiples of
688 // 25, and it must be at least 25 (otherwise our
689 // internal master timer calculations will fail)
690 // V0.9.14 (2001-07-07) [umoeller]
691 if (ulTimeout < 25)
692 ulTimeout = 25;
693 else
694 ulTimeout = (ulTimeout + 10) / 25 * 25;
[68]695
[127]696 DosQuerySysInfo(QSV_MS_COUNT,
697 QSV_MS_COUNT,
698 &ulTimeNow,
699 sizeof(ulTimeNow));
[86]700
[127]701 // check if this timer exists already
702 if (pTimer = FindTimer(pSet,
703 hwnd,
704 usTimerID))
705 {
706 // exists already: reset only
707 pTimer->ulNextFire = ulTimeNow + ulTimeout;
708 usrc = usTimerID;
709 }
710 else
711 {
712 // new timer needed:
713 if (pTimer = NEW(XTIMER))
[14]714 {
[127]715 pTimer->usTimerID = usTimerID;
716 pTimer->hwndTarget = hwnd;
717 pTimer->ulTimeout = ulTimeout;
[15]718 pTimer->ulNextFire = ulTimeNow + ulTimeout;
[127]719
720 lstAppendItem(pllXTimers,
721 pTimer);
[91]722 usrc = usTimerID;
[14]723 }
[127]724 }
[14]725
[127]726 if (usrc)
727 // timer created or reset:
728 AdjustPMTimer(pSet);
[68]729
[127]730 } // if ((hwnd) && (ulTimeout))
[74]731
732 UnlockTimers();
[41]733 }
[14]734
[297]735 return usrc;
[14]736}
737
738/*
[41]739 *@@ tmrStopXTimer:
[14]740 * similar to WinStopTimer, this stops the
741 * specified timer (which must have been
742 * started with the same hwnd and usTimerID
[41]743 * using tmrStartXTimer).
[14]744 *
745 * Returns TRUE if the timer was stopped.
[68]746 *
747 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
[14]748 */
749
[44]750BOOL XWPENTRY tmrStopXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
[41]751 HWND hwnd,
752 USHORT usTimerID)
[14]753{
754 BOOL brc = FALSE;
[74]755 if (LockTimers())
[41]756 {
[127]757 PXTIMER pTimer;
[163]758 #ifdef DEBUG_XTIMERS
759 _Pmpf((__FUNCTION__ ": finding timer %d", usTimerID));
760 #endif
[127]761 if (pTimer = FindTimer(pSet,
762 hwnd,
763 usTimerID))
764 // FindTimer checks the params
[68]765 {
[127]766 RemoveTimer(pSet, pTimer);
767 // recalculate
768 AdjustPMTimer(pSet);
769 brc = TRUE;
[74]770 }
[68]771
[74]772 UnlockTimers();
[14]773 }
774
[167]775 return brc;
[14]776}
777
778
Note: See TracBrowser for help on using the repository browser.