Large-scale renaming of all Win32 functions and types to use the
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "winuser.h"
8 #include "queue.h"
9 #include "task.h"
10 #include "winproc.h"
11 #include "debug.h"
12
13
14 typedef struct tagTIMER
15 {
16     HWND           hwnd;
17     HQUEUE16         hq;
18     UINT16           msg;  /* WM_TIMER or WM_SYSTIMER */
19     UINT           id;
20     UINT           timeout;
21     struct tagTIMER *next;
22     DWORD            expires;  /* Next expiration, or 0 if already expired */
23     HWINDOWPROC      proc;
24 } TIMER;
25
26 #define NB_TIMERS            34
27 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
28
29 static TIMER TimersArray[NB_TIMERS];
30
31 static TIMER * pNextTimer = NULL;  /* Next timer to expire */
32
33   /* Duration from 'time' until expiration of the timer */
34 #define EXPIRE_TIME(pTimer,time) \
35           (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
36
37
38 /***********************************************************************
39  *           TIMER_InsertTimer
40  *
41  * Insert the timer at its place in the chain.
42  */
43 static void TIMER_InsertTimer( TIMER * pTimer )
44 {
45     if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
46     {
47         pTimer->next = pNextTimer;
48         pNextTimer = pTimer;
49     }
50     else
51     {
52         TIMER * ptr = pNextTimer;       
53         while (ptr->next && (pTimer->expires >= ptr->next->expires))
54             ptr = ptr->next;
55         pTimer->next = ptr->next;
56         ptr->next = pTimer;
57     }
58 }
59
60
61 /***********************************************************************
62  *           TIMER_RemoveTimer
63  *
64  * Remove the timer from the chain.
65  */
66 static void TIMER_RemoveTimer( TIMER * pTimer )
67 {
68     TIMER **ppTimer = &pNextTimer;
69
70     while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
71     if (*ppTimer) *ppTimer = pTimer->next;
72     pTimer->next = NULL;
73     if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
74 }
75
76
77 /***********************************************************************
78  *           TIMER_ClearTimer
79  *
80  * Clear and remove a timer.
81  */
82 static void TIMER_ClearTimer( TIMER * pTimer )
83 {
84     TIMER_RemoveTimer( pTimer );
85     pTimer->hwnd    = 0;
86     pTimer->msg     = 0;
87     pTimer->id      = 0;
88     pTimer->timeout = 0;
89     WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
90 }
91
92
93 /***********************************************************************
94  *           TIMER_SwitchQueue
95  */
96 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
97 {
98     TIMER * pT = pNextTimer;
99
100     while (pT)
101     {
102         if (pT->hq == old) pT->hq = new;
103         pT = pT->next;
104     }
105 }
106
107
108 /***********************************************************************
109  *           TIMER_RemoveWindowTimers
110  *
111  * Remove all timers for a given window.
112  */
113 void TIMER_RemoveWindowTimers( HWND hwnd )
114 {
115     int i;
116     TIMER *pTimer;
117
118     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
119         if ((pTimer->hwnd == hwnd) && pTimer->timeout)
120             TIMER_ClearTimer( pTimer );
121 }
122
123
124 /***********************************************************************
125  *           TIMER_RemoveQueueTimers
126  *
127  * Remove all timers for a given queue.
128  */
129 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
130 {
131     int i;
132     TIMER *pTimer;
133
134     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
135         if ((pTimer->hq == hqueue) && pTimer->timeout)
136             TIMER_ClearTimer( pTimer );
137 }
138
139
140 /***********************************************************************
141  *           TIMER_RestartTimers
142  *
143  * Restart an expired timer.
144  */
145 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
146 {
147     TIMER_RemoveTimer( pTimer );
148     pTimer->expires = curTime + pTimer->timeout;
149     TIMER_InsertTimer( pTimer );
150 }
151
152                                
153 /***********************************************************************
154  *           TIMER_GetNextExpiration
155  *
156  * Return next timer expiration time, or -1 if none.
157  */
158 LONG TIMER_GetNextExpiration(void)
159 {
160     return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
161 }
162
163
164 /***********************************************************************
165  *           TIMER_ExpireTimers
166  *
167  * Mark expired timers and wake the appropriate queues.
168  */
169 void TIMER_ExpireTimers(void)
170 {
171     TIMER *pTimer = pNextTimer;
172     DWORD curTime = GetTickCount();
173
174     while (pTimer && !pTimer->expires)  /* Skip already expired timers */
175         pTimer = pTimer->next;
176     while (pTimer && (pTimer->expires <= curTime))
177     {
178         pTimer->expires = 0;
179         QUEUE_IncTimerCount( pTimer->hq );
180         pTimer = pTimer->next;
181     }
182 }
183
184
185 /***********************************************************************
186  *           TIMER_GetTimerMsg
187  *
188  * Build a message for an expired timer.
189  */
190 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
191                           HQUEUE16 hQueue, BOOL remove )
192 {
193     TIMER *pTimer = pNextTimer;
194     DWORD curTime = GetTickCount();
195
196     if (hwnd)  /* Find first timer for this window */
197         while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
198     else   /* Find first timer for this queue */
199         while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
200
201     if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
202     if (remove) TIMER_RestartTimer( pTimer, curTime );  /* Restart it */
203
204     TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n", 
205                    pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
206
207       /* Build the message */
208     msg->hwnd    = pTimer->hwnd;
209     msg->message = pTimer->msg;
210     msg->wParam  = pTimer->id;
211     msg->lParam  = (LONG)pTimer->proc;
212     msg->time    = curTime;
213     return TRUE;
214 }
215
216
217 /***********************************************************************
218  *           TIMER_SetTimer
219  */
220 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
221                               WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
222 {
223     int i;
224     TIMER * pTimer;
225
226     if (!timeout) return 0;
227
228       /* Check if there's already a timer with the same hwnd and id */
229
230     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
231         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
232             (pTimer->timeout != 0))
233         {
234               /* Got one: set new values and return */
235             TIMER_RemoveTimer( pTimer );
236             pTimer->timeout = timeout;
237             WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
238             pTimer->proc = (HWINDOWPROC)0;
239             if (proc) WINPROC_SetProc( &pTimer->proc, proc,
240                                        type, WIN_PROC_TIMER );
241             pTimer->expires = GetTickCount() + timeout;
242             TIMER_InsertTimer( pTimer );
243             return id;
244         }
245
246       /* Find a free timer */
247     
248     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
249         if (!pTimer->timeout) break;
250
251     if (i >= NB_TIMERS) return 0;
252     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
253     if (!hwnd) id = i + 1;
254     
255       /* Add the timer */
256
257     pTimer->hwnd    = hwnd;
258     pTimer->hq      = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
259                              : GetFastQueue16( );
260     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
261     pTimer->id      = id;
262     pTimer->timeout = timeout;
263     pTimer->expires = GetTickCount() + timeout;
264     pTimer->proc    = (HWINDOWPROC)0;
265     if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
266     TRACE(timer, "Timer added: %p, %04x, %04x, %04x, %08lx\n", 
267                    pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
268                    (DWORD)pTimer->proc );
269     TIMER_InsertTimer( pTimer );
270     if (!id) return TRUE;
271     else return id;
272 }
273
274
275 /***********************************************************************
276  *           TIMER_KillTimer
277  */
278 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
279 {
280     int i;
281     TIMER * pTimer;
282     
283     /* Find the timer */
284     
285     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
286         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
287             (pTimer->timeout != 0)) break;
288     if (i >= NB_TIMERS) return FALSE;
289     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
290     if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
291     else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;    
292
293     /* Delete the timer */
294
295     TIMER_ClearTimer( pTimer );
296     return TRUE;
297 }
298
299
300 /***********************************************************************
301  *           SetTimer16   (USER.10)
302  */
303 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
304                           TIMERPROC16 proc )
305 {
306     TRACE(timer, "%04x %d %d %08lx\n",
307                    hwnd, id, timeout, (LONG)proc );
308     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
309                            WIN_PROC_16, FALSE );
310 }
311
312
313 /***********************************************************************
314  *           SetTimer32   (USER32.511)
315  */
316 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
317                           TIMERPROC proc )
318 {
319     TRACE(timer, "%04x %d %d %08lx\n",
320                    hwnd, id, timeout, (LONG)proc );
321     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
322                            WIN_PROC_32A, FALSE );
323 }
324
325
326 /***********************************************************************
327  *           SetSystemTimer16   (USER.11)
328  */
329 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
330                                 TIMERPROC16 proc )
331 {
332     TRACE(timer, "%04x %d %d %08lx\n", 
333                    hwnd, id, timeout, (LONG)proc );
334     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
335                            WIN_PROC_16, TRUE );
336 }
337
338
339 /***********************************************************************
340  *           SetSystemTimer32   (USER32.509)
341  */
342 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
343                                 TIMERPROC proc )
344 {
345     TRACE(timer, "%04x %d %d %08lx\n", 
346                    hwnd, id, timeout, (LONG)proc );
347     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
348                            WIN_PROC_32A, TRUE );
349 }
350
351
352 /***********************************************************************
353  *           KillTimer16   (USER.12)
354  */
355 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
356 {
357     TRACE(timer, "%04x %d\n", hwnd, id );
358     return TIMER_KillTimer( hwnd, id, FALSE );
359 }
360
361
362 /***********************************************************************
363  *           KillTimer32   (USER32.354)
364  */
365 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
366 {
367     TRACE(timer, "%04x %d\n", hwnd, id );
368     return TIMER_KillTimer( hwnd, id, FALSE );
369 }
370
371
372 /***********************************************************************
373  *           KillSystemTimer16   (USER.182)
374  */
375 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
376 {
377     TRACE(timer, "%04x %d\n", hwnd, id );
378     return TIMER_KillTimer( hwnd, id, TRUE );
379 }
380
381
382 /***********************************************************************
383  *           KillSystemTimer32   (USER32.353)
384  */
385 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
386 {
387     TRACE(timer, "%04x %d\n", hwnd, id );
388     return TIMER_KillTimer( hwnd, id, TRUE );
389 }