Release 940201
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include "windows.h"
10 #include "message.h"
11
12
13 typedef struct tagTIMER
14 {
15     HWND             hwnd;
16     WORD             msg;  /* WM_TIMER or WM_SYSTIMER */
17     WORD             id;
18     WORD             timeout;
19     struct tagTIMER *next;
20     DWORD            expires;
21     FARPROC          proc;
22 } TIMER;
23
24 #define NB_TIMERS            34
25 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
26
27 static TIMER TimersArray[NB_TIMERS];
28
29 static TIMER * pNextTimer = NULL;  /* Next timer to expire */
30
31
32 /***********************************************************************
33  *           TIMER_InsertTimer
34  *
35  * Insert the timer at its place in the chain.
36  */
37 static void TIMER_InsertTimer( TIMER * pTimer )
38 {
39     if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
40     {
41         pTimer->next = pNextTimer;
42         pNextTimer = pTimer;
43     }
44     else
45     {
46         TIMER * ptr = pNextTimer;       
47         while (ptr->next && (pTimer->expires >= ptr->next->expires))
48             ptr = ptr->next;
49         pTimer->next = ptr;
50         ptr->next = pTimer;
51     }
52 }
53
54
55 /***********************************************************************
56  *           TIMER_RemoveTimer
57  *
58  * Remove the timer from the chain.
59  */
60 static void TIMER_RemoveTimer( TIMER * pTimer )
61 {
62     if (pTimer == pNextTimer) pNextTimer = pTimer->next;
63     else
64     {
65         TIMER * ptr = pNextTimer;
66         while (ptr && (ptr->next != pTimer)) ptr = ptr->next;
67         if (ptr) ptr->next = pTimer->next;
68     }
69     pTimer->next = NULL;
70 }
71
72
73 /***********************************************************************
74  *           TIMER_NextExpire
75  *
76  * Return time until next timer expiration (-1 if none).
77  */
78 static DWORD TIMER_NextExpire( DWORD curTime )
79 {
80     if (!pNextTimer) return -1;
81     if (pNextTimer->expires <= curTime) return 0;
82     return pNextTimer->expires - curTime;
83 }
84
85
86 /***********************************************************************
87  *           TIMER_CheckTimer
88  *
89  * Check whether a timer has expired, and post a message if necessary.
90  * Return TRUE if msg posted, and return time until next expiration in 'next'.
91  */
92 BOOL TIMER_CheckTimer( DWORD *next )
93 {
94     TIMER * pTimer = pNextTimer;
95     DWORD curTime = GetTickCount();
96     
97     if ((*next = TIMER_NextExpire( curTime )) != 0) return FALSE;
98
99     PostMessage( pTimer->hwnd, pTimer->msg, pTimer->id, (LONG)pTimer->proc );
100     TIMER_RemoveTimer( pTimer );
101
102       /* If timeout == 0, the timer has been removed by KillTimer */
103     if (pTimer->timeout)
104     {
105           /* Restart the timer */
106         pTimer->expires = curTime + pTimer->timeout;
107         TIMER_InsertTimer( pTimer );
108     }
109     *next = TIMER_NextExpire( curTime );
110     return TRUE;
111 }
112
113
114 /***********************************************************************
115  *           TIMER_SetTimer
116  */
117 static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout,
118                             FARPROC proc, BOOL sys )
119 {
120     int i;
121     TIMER * pTimer;
122
123     if (!timeout) return 0;
124     if (!hwnd && !proc) return 0;
125     
126       /* Find a free timer */
127     
128     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
129         if (!pTimer->timeout) break;
130
131     if (i >= NB_TIMERS) return 0;
132     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
133     if (!hwnd) id = i + 1;
134     
135       /* Add the timer */
136
137     pTimer->hwnd    = hwnd;
138     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
139     pTimer->id      = id;
140     pTimer->timeout = timeout;
141     pTimer->expires = GetTickCount() + timeout;
142     pTimer->proc    = proc;
143     TIMER_InsertTimer( pTimer );
144     MSG_IncTimerCount( GetTaskQueue(0) );
145     if (!id)
146         return TRUE;
147     else
148         return id;
149 }
150
151
152 /***********************************************************************
153  *           TIMER_KillTimer
154  */
155 static BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys )
156 {
157     int i;
158     TIMER * pTimer;
159     
160       /* Find the timer */
161     
162     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
163         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
164             (pTimer->timeout != 0)) break;
165     if (i >= NB_TIMERS) return FALSE;
166     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
167     if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
168     else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;    
169
170       /* Delete the timer */
171
172     pTimer->hwnd    = 0;
173     pTimer->msg     = 0;
174     pTimer->id      = 0;
175     pTimer->timeout = 0;
176     pTimer->proc    = 0;
177     TIMER_RemoveTimer( pTimer );
178     MSG_DecTimerCount( GetTaskQueue(0) );
179     return TRUE;
180 }
181
182
183 /***********************************************************************
184  *           SetTimer   (USER.10)
185  */
186 WORD SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
187 {
188 #ifdef DEBUG_TIMER    
189     printf( "SetTimer: %d %d %d %p\n", hwnd, id, timeout, proc );
190 #endif
191     return TIMER_SetTimer( hwnd, id, timeout, proc, FALSE );
192 }
193
194
195 /***********************************************************************
196  *           SetSystemTimer   (USER.11)
197  */
198 WORD SetSystemTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
199 {
200 #ifdef DEBUG_TIMER    
201     printf( "SetSystemTimer: %d %d %d %p\n", hwnd, id, timeout, proc );
202 #endif
203     return TIMER_SetTimer( hwnd, id, timeout, proc, TRUE );
204 }
205
206
207 /***********************************************************************
208  *           KillTimer   (USER.12)
209  */
210 BOOL KillTimer( HWND hwnd, WORD id )
211 {
212 #ifdef DEBUG_TIMER
213     printf( "KillTimer: %d %d\n", hwnd, id );
214 #endif
215     return TIMER_KillTimer( hwnd, id, FALSE );
216 }
217
218
219 /***********************************************************************
220  *           KillSystemTimer   (USER.182)
221  */
222 BOOL KillSystemTimer( HWND hwnd, WORD id )
223 {
224 #ifdef DEBUG_TIMER
225     printf( "KillSystemTimer: %d %d\n", hwnd, id );
226 #endif
227     return TIMER_KillTimer( hwnd, id, TRUE );
228 }