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

Last change on this file since 264 was 264, checked in by pr, 21 years ago

Fix spelling errors.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 26.1 KB
Line 
1
2/*
3 *@@sourcefile timer.c:
4 * XTimers, which can be used to avoid excessive PM
5 * timer usage.
6 *
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.
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 *
20 * XTimers are used excessively by the default widgets
21 * of XWorkplace's XCenter.
22 *
23 * There are a few limitations with the XTimers though:
24 *
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.
31 *
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 *
36 * -- Queue timers (with HWND == NULLHANDLE) are not
37 * supported.
38 *
39 * -- When a window is destroyed, its timers are not
40 * automatically cleaned up. tmrTimerTick does
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.
45 *
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 *
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/*
70 * Copyright (C) 2000-2001 Ulrich M”ller.
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
92#define INCL_DOSMISC
93#define INCL_DOSERRORS
94
95#define INCL_WINWINDOWMGR
96#define INCL_WINMESSAGEMGR
97#define INCL_WINTIMER
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"
108#include "helpers\math.h"
109#include "helpers\standards.h"
110#include "helpers\threads.h"
111#include "helpers\timer.h"
112
113// #define DEBUG_XTIMERS
114
115/*
116 *@@category: Helpers\PM helpers\Timer replacements
117 * see timer.c.
118 */
119
120/* ******************************************************************
121 *
122 * Private declarations
123 *
124 ********************************************************************/
125
126/*
127 *@@ XTIMER:
128 * one of these represents an XTimer.
129 * These are stored in a linked list in
130 * an _XTIMERSET.
131 */
132
133typedef struct _XTIMER
134{
135 USHORT usTimerID; // timer ID, as passed to tmrStartXTimer
136 HWND hwndTarget; // target window, as passed to tmrStartXTimer
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
147HMTX G_hmtxTimers = NULLHANDLE; // timers lock mutex
148
149/* ******************************************************************
150 *
151 * Private functions
152 *
153 ********************************************************************/
154
155/*
156 *@@ LockTimers:
157 *
158 *@@added V0.9.12 (2001-05-12) [umoeller]
159 */
160
161STATIC BOOL LockTimers(VOID)
162{
163 if (!G_hmtxTimers)
164 return (!DosCreateMutexSem(NULL,
165 &G_hmtxTimers,
166 0,
167 TRUE)); // request!
168 else
169 return !DosRequestMutexSem(G_hmtxTimers, SEM_INDEFINITE_WAIT);
170}
171
172/*
173 *@@ UnlockTimers:
174 *
175 *@@added V0.9.12 (2001-05-12) [umoeller]
176 */
177
178STATIC VOID UnlockTimers(VOID)
179{
180 DosReleaseMutexSem(G_hmtxTimers);
181}
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 *
189 * Internal function. Caller must hold the mutex.
190 */
191
192STATIC PXTIMER FindTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
193 HWND hwnd, // in: timer target window
194 USHORT usTimerID) // in: timer ID
195{
196 PLINKLIST pllXTimers;
197 if ( (pSet)
198 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
199 )
200 {
201 PLISTNODE pNode = lstQueryFirstNode(pllXTimers);
202 while (pNode)
203 {
204 PXTIMER pTimer = (PXTIMER)pNode->pItemData;
205 if ( (pTimer->usTimerID == usTimerID)
206 && (pTimer->hwndTarget == hwnd)
207 )
208 {
209 return (pTimer);
210 }
211
212 pNode = pNode->pNext;
213 }
214 }
215
216 return NULL;
217}
218
219/*
220 *@@ RemoveTimer:
221 * removes the specified XTIMER structure from
222 * the global linked list of running timers.
223 *
224 * Internal function. Caller must hold the mutex.
225 */
226
227STATIC VOID RemoveTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
228 PXTIMER pTimer) // in: timer to remove
229{
230 PLINKLIST pllXTimers;
231 if ( (pSet)
232 && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
233 )
234 {
235 #ifdef DEBUG_XTIMERS
236 _Pmpf((__FUNCTION__ ": removing timer %d", pTimer->usTimerID));
237 #endif
238 lstRemoveItem(pllXTimers,
239 pTimer); // auto-free!
240 }
241}
242
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]
251 *@@changed V0.9.14 (2001-07-07) [umoeller]: added GCD optimizations
252 */
253
254STATIC VOID AdjustPMTimer(PXTIMERSET pSet)
255{
256 PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
257 ULONG cTimers = lstCountItems(pllXTimers);
258
259 #ifdef DEBUG_XTIMERS
260 _Pmpf((__FUNCTION__ ": entering"));
261 #endif
262
263 if (!cTimers)
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:
281
282 ULONG ulOldPMTimeout = pSet->ulPMTimeout;
283
284 PLISTNODE pNode = lstQueryFirstNode(pllXTimers);
285 PXTIMER pTimer1 = (PXTIMER)pNode->pItemData;
286
287 if (cTimers == 1)
288 {
289 // only one timer:
290 // that's easy
291 #ifdef DEBUG_XTIMERS
292 _Pmpf((" got 1 timer"));
293 #endif
294
295 pSet->ulPMTimeout = pTimer1->ulTimeout;
296 }
297 else if (cTimers == 2)
298 {
299 // exactly two timers:
300 // find the greatest common denominator
301 PXTIMER pTimer2 = (PXTIMER)pNode->pNext->pItemData;
302 #ifdef DEBUG_XTIMERS
303 _Pmpf((" got 2 timers"));
304 #endif
305
306 pSet->ulPMTimeout = mathGCD(pTimer1->ulTimeout,
307 pTimer2->ulTimeout);
308 }
309 else
310 {
311 // more than two timers:
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
317 #ifdef DEBUG_XTIMERS
318 _Pmpf((" got %d timers", cTimers));
319 #endif
320
321 // fill an array of integers with the
322 // timer frequencies
323 while (pNode)
324 {
325 pTimer1 = (PXTIMER)pNode->pItemData;
326
327 #ifdef DEBUG_XTIMERS
328 _Pmpf((" timeout %d is %d", i, pTimer1->ulTimeout));
329 #endif
330
331 paInts[i++] = pTimer1->ulTimeout;
332
333 pNode = pNode->pNext;
334 }
335
336 pSet->ulPMTimeout = mathGCDMulti(paInts,
337 cTimers);
338 }
339
340 #ifdef DEBUG_XTIMERS
341 _Pmpf(("--> GCD is %d", pSet->ulPMTimeout));
342 #endif
343
344 if ( (!pSet->idPMTimerRunning) // timer not running?
345 || (pSet->ulPMTimeout != ulOldPMTimeout) // timeout changed?
346 )
347 {
348 // start or restart PM timer
349 pSet->idPMTimerRunning = WinStartTimer(pSet->hab,
350 pSet->hwndOwner,
351 pSet->idPMTimer,
352 pSet->ulPMTimeout);
353 }
354 }
355}
356
357/* ******************************************************************
358 *
359 * Exported functions
360 *
361 ********************************************************************/
362
363/*
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 *
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 *
376 * Use tmrDestroySet to free all resources again.
377 *
378 *@@added V0.9.9 (2001-02-28) [umoeller]
379 */
380
381PXTIMERSET tmrCreateSet(HWND hwndOwner, // in: owner window
382 USHORT usPMTimerID)
383{
384 PXTIMERSET pSet = NEW(XTIMERSET);
385 if (pSet)
386 {
387 pSet->hab = WinQueryAnchorBlock(hwndOwner);
388 pSet->hwndOwner = hwndOwner;
389 pSet->idPMTimer = usPMTimerID;
390 pSet->idPMTimerRunning = 0;
391 pSet->ulPMTimeout = 0;
392
393 pSet->pvllXTimers = (PVOID)lstCreate(TRUE);
394 }
395
396 return (pSet);
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]
408 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
409 */
410
411VOID tmrDestroySet(PXTIMERSET pSet) // in: timer set (from tmrCreateSet)
412{
413 if (LockTimers())
414 {
415 if (pSet)
416 {
417 PLINKLIST pllXTimers;
418 if (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
419 {
420 PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
421 while (pTimerNode)
422 {
423 PLISTNODE pNext = pTimerNode->pNext;
424 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
425 RemoveTimer(pSet, pTimer);
426 pTimerNode = pNext;
427 }
428
429 lstFree(&pllXTimers);
430 pSet->pvllXTimers = NULL;
431 }
432
433 if (pSet->idPMTimerRunning)
434 {
435 WinStopTimer(pSet->hab,
436 pSet->hwndOwner,
437 pSet->idPMTimer);
438 pSet->idPMTimerRunning = 0;
439 }
440
441 free(pSet);
442 }
443
444 UnlockTimers();
445 }
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]
460 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
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
463 *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed "half frequency" regression caused by frequency optimizations
464 *@@changed V0.9.16 (2001-12-18) [umoeller]: now using WinDispatchMsg to avoid crashes during win destruction
465 *@@changed V0.9.19 (2002-05-04) [umoeller]: added excpt handling to avoid hanging all timers on the mutex
466 */
467
468VOID tmrTimerTick(PXTIMERSET pSet) // in: timer set (from tmrCreateSet)
469{
470 BOOL fLocked = FALSE;
471
472 TRY_LOUD(excpt1)
473 {
474 if (fLocked = LockTimers())
475 {
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;
485
486 if (!(pTimerNode = lstQueryFirstNode(pllXTimers)))
487 {
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;
500 }
501 else
502 {
503 // we have timers:
504 BOOL fFoundInvalid = FALSE;
505
506 // get current time
507 ULONG ulTimeNow = 0;
508 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
509 &ulTimeNow, sizeof(ulTimeNow));
510
511 #ifdef DEBUG_XTIMERS
512 _Pmpf((__FUNCTION__ ": ulTimeNow = %d", ulTimeNow));
513 #endif
514
515 while (pTimerNode)
516 {
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;
521
522 PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
523
524 #ifdef DEBUG_XTIMERS
525 _Pmpf((" timer %d: ulNextFire = %d",
526 lstIndexFromItem(pllXTimers, pTimer),
527 pTimer->ulNextFire));
528 #endif
529
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 )
541 {
542 // this timer has elapsed:
543 // fire!
544
545 #ifdef DEBUG_XTIMERS
546 _Pmpf((" --> fire!"));
547 #endif
548
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);
557
558 // moved this up V0.9.14 (2001-08-01) [umoeller]
559 pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
560
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); */
575
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
587
588 // V0.9.14 (2001-08-01) [umoeller]
589
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
601
602 fFoundInvalid = TRUE;
603 }
604
605 } // end if (pTimer->ulNextFire < ulTimeNow)
606
607 // next timer
608 pTimerNode = pNext; // V0.9.12 (2001-05-24) [umoeller]
609 } // end while (pTimerNode)
610
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)
622 UnlockTimers();
623}
624
625/*
626 *@@ tmrStartXTimer:
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 *
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.
637 *
638 * Returns 0 if an error occurred. It is thus
639 * invalid to specify a timer ID of 0.
640 *
641 * The timer is _not_ stopped automatically
642 * when the window is destroyed.
643 *
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 *
660 *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
661 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
662 *@@changed V0.9.14 (2001-07-12) [umoeller]: now rounding freq's to multiples of 25
663 */
664
665USHORT XWPENTRY tmrStartXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
666 HWND hwnd, // in: target window for XTimer
667 USHORT usTimerID, // in: timer ID for XTimer's WM_TIMER (must be > 0)
668 ULONG ulTimeout) // in: XTimer's timeout
669{
670 USHORT usrc = 0;
671
672 // _Pmpf((__FUNCTION__ ": entering"));
673
674 if (LockTimers())
675 {
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 )
683 {
684 PXTIMER pTimer;
685 ULONG ulTimeNow;
686
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;
695
696 DosQuerySysInfo(QSV_MS_COUNT,
697 QSV_MS_COUNT,
698 &ulTimeNow,
699 sizeof(ulTimeNow));
700
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))
714 {
715 pTimer->usTimerID = usTimerID;
716 pTimer->hwndTarget = hwnd;
717 pTimer->ulTimeout = ulTimeout;
718 pTimer->ulNextFire = ulTimeNow + ulTimeout;
719
720 lstAppendItem(pllXTimers,
721 pTimer);
722 usrc = usTimerID;
723 }
724 }
725
726 if (usrc)
727 // timer created or reset:
728 AdjustPMTimer(pSet);
729
730 } // if ((hwnd) && (ulTimeout))
731
732 UnlockTimers();
733 }
734
735 return (usrc);
736}
737
738/*
739 *@@ tmrStopXTimer:
740 * similar to WinStopTimer, this stops the
741 * specified timer (which must have been
742 * started with the same hwnd and usTimerID
743 * using tmrStartXTimer).
744 *
745 * Returns TRUE if the timer was stopped.
746 *
747 *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
748 */
749
750BOOL XWPENTRY tmrStopXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
751 HWND hwnd,
752 USHORT usTimerID)
753{
754 BOOL brc = FALSE;
755 if (LockTimers())
756 {
757 PXTIMER pTimer;
758 #ifdef DEBUG_XTIMERS
759 _Pmpf((__FUNCTION__ ": finding timer %d", usTimerID));
760 #endif
761 if (pTimer = FindTimer(pSet,
762 hwnd,
763 usTimerID))
764 // FindTimer checks the params
765 {
766 RemoveTimer(pSet, pTimer);
767 // recalculate
768 AdjustPMTimer(pSet);
769 brc = TRUE;
770 }
771
772 UnlockTimers();
773 }
774
775 return brc;
776}
777
778
Note: See TracBrowser for help on using the repository browser.