Converted to the new debug interface, using script written by Patrik
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "wine/winuser16.h"
8 #include "winuser.h"
9 #include "queue.h"
10 #include "task.h"
11 #include "winproc.h"
12 #include "services.h"
13 #include "message.h"
14 #include "debugtools.h"
15
16 DEFAULT_DEBUG_CHANNEL(timer)
17
18
19 typedef struct tagTIMER
20 {
21     HWND           hwnd;
22     HQUEUE16       hq;
23     UINT16         msg;  /* WM_TIMER or WM_SYSTIMER */
24     UINT           id;
25     UINT           timeout;
26     HANDLE         hService;
27     BOOL           expired;
28     HWINDOWPROC    proc;
29 } TIMER;
30
31 #define NB_TIMERS            34
32 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
33
34 static TIMER TimersArray[NB_TIMERS];
35
36 static CRITICAL_SECTION csTimer;
37
38
39 /***********************************************************************
40  *           TIMER_Init
41  *
42  * Initialize critical section for the timer.
43  */
44 BOOL TIMER_Init( void )
45 {
46     InitializeCriticalSection( &csTimer );
47     MakeCriticalSectionGlobal( &csTimer );
48
49     return TRUE;
50 }
51
52
53 /***********************************************************************
54  *           TIMER_ClearTimer
55  *
56  * Clear and remove a timer.
57  */
58 static void TIMER_ClearTimer( TIMER * pTimer )
59 {
60     if ( pTimer->hService != INVALID_HANDLE_VALUE ) 
61     {
62         SERVICE_Delete( pTimer->hService );
63         pTimer->hService = INVALID_HANDLE_VALUE;
64     }
65
66     if ( pTimer->expired ) 
67     {
68         QUEUE_DecTimerCount( pTimer->hq );
69         pTimer->expired = FALSE;
70     }
71
72     pTimer->hwnd    = 0;
73     pTimer->msg     = 0;
74     pTimer->id      = 0;
75     pTimer->timeout = 0;
76     WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
77 }
78
79
80 /***********************************************************************
81  *           TIMER_RemoveWindowTimers
82  *
83  * Remove all timers for a given window.
84  */
85 void TIMER_RemoveWindowTimers( HWND hwnd )
86 {
87     int i;
88     TIMER *pTimer;
89
90     EnterCriticalSection( &csTimer );
91     
92     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
93         if ((pTimer->hwnd == hwnd) && pTimer->timeout)
94             TIMER_ClearTimer( pTimer );
95     
96     LeaveCriticalSection( &csTimer );
97 }
98
99
100 /***********************************************************************
101  *           TIMER_RemoveQueueTimers
102  *
103  * Remove all timers for a given queue.
104  */
105 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
106 {
107     int i;
108     TIMER *pTimer;
109
110     EnterCriticalSection( &csTimer );
111     
112     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
113         if ((pTimer->hq == hqueue) && pTimer->timeout)
114             TIMER_ClearTimer( pTimer );
115     
116     LeaveCriticalSection( &csTimer );
117 }
118
119
120 /***********************************************************************
121  *           TIMER_CheckTimer
122  */
123 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
124 {
125     TIMER *pTimer = (TIMER *)timer_ptr;
126     HQUEUE16 wakeQueue = 0;
127
128     EnterCriticalSection( &csTimer );
129
130     /* Paranoid check to prevent a race condition ... */
131     if ( !pTimer->timeout )
132     {
133         LeaveCriticalSection( &csTimer );
134         return;
135     }
136
137     if ( !pTimer->expired )
138     {
139         TRACE("Timer expired: %04x, %04x, %04x, %08lx\n", 
140                      pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
141
142         pTimer->expired = TRUE;
143         wakeQueue = pTimer->hq;
144     }
145
146     LeaveCriticalSection( &csTimer );
147
148     /* Note: This has to be done outside the csTimer critical section,
149              otherwise we'll get deadlocks. */
150
151     if ( wakeQueue )
152         QUEUE_IncTimerCount( wakeQueue );
153 }
154
155
156 /***********************************************************************
157  *           TIMER_GetTimerMsg
158  *
159  * Build a message for an expired timer.
160  */
161 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
162                           HQUEUE16 hQueue, BOOL remove )
163 {
164     TIMER *pTimer;
165     int i;
166
167     EnterCriticalSection( &csTimer );
168
169     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
170         if (    pTimer->timeout != 0 && pTimer->expired
171              && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
172             break;
173
174     if ( i == NB_TIMERS )
175     {
176         LeaveCriticalSection( &csTimer );
177         return FALSE; /* No timer */
178     }
179     
180     TRACE("Timer got message: %04x, %04x, %04x, %08lx\n", 
181                    pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
182
183     if (remove) 
184         pTimer->expired = FALSE;
185
186       /* Build the message */
187     msg->hwnd    = pTimer->hwnd;
188     msg->message = pTimer->msg;
189     msg->wParam  = pTimer->id;
190     msg->lParam  = (LONG)pTimer->proc;
191     msg->time    = GetTickCount();
192
193     LeaveCriticalSection( &csTimer );
194     
195     return TRUE;
196 }
197
198
199 /***********************************************************************
200  *           TIMER_SetTimer
201  */
202 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
203                               WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
204 {
205     int i;
206     TIMER * pTimer;
207
208     if (!timeout) return 0;
209
210     EnterCriticalSection( &csTimer );
211     
212       /* Check if there's already a timer with the same hwnd and id */
213
214     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
215         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
216             (pTimer->timeout != 0))
217         {
218             TIMER_ClearTimer( pTimer );
219             break;
220         }
221
222     if ( i == NB_TIMERS )
223     {
224           /* Find a free timer */
225     
226         for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
227             if (!pTimer->timeout) break;
228
229         if ( (i >= NB_TIMERS) ||
230              (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
231         {
232             LeaveCriticalSection( &csTimer );
233             return 0;
234         }
235     }
236
237     if (!hwnd) id = i + 1;
238     
239       /* Add the timer */
240
241     pTimer->hwnd    = hwnd;
242     pTimer->hq      = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
243                              : GetFastQueue16( );
244     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
245     pTimer->id      = id;
246     pTimer->timeout = timeout;
247     pTimer->proc    = (HWINDOWPROC)0;
248     if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
249
250     pTimer->expired  = FALSE;
251     pTimer->hService = SERVICE_AddTimer( timeout * 1000L, 
252                                          TIMER_CheckTimer, (ULONG_PTR)pTimer );
253
254     TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n", 
255                    pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
256                    (DWORD)pTimer->proc );
257
258     LeaveCriticalSection( &csTimer );
259     
260     if (!id) return TRUE;
261     else return id;
262 }
263
264
265 /***********************************************************************
266  *           TIMER_KillTimer
267  */
268 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
269 {
270     int i;
271     TIMER * pTimer;
272     
273     EnterCriticalSection( &csTimer );
274     
275     /* Find the timer */
276     
277     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
278         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
279             (pTimer->timeout != 0)) break;
280
281     if ( (i >= NB_TIMERS) ||
282          (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
283          (!sys && (pTimer->msg != WM_TIMER)) ||
284          (sys && (pTimer->msg != WM_SYSTIMER)) )
285     {
286         LeaveCriticalSection( &csTimer );
287         return FALSE;
288     }
289
290     /* Delete the timer */
291
292     TIMER_ClearTimer( pTimer );
293     
294     LeaveCriticalSection( &csTimer );
295     
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("%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("%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("%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("%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("%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("%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("%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("%04x %d\n", hwnd, id );
388     return TIMER_KillTimer( hwnd, id, TRUE );
389 }