Authors: Guy Albertelli <guy@codeweavers.com>, Mike McCormack <mike_mccormack@start...
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "windef.h"
8 #include "wingdi.h"
9 #include "wine/winuser16.h"
10 #include "winuser.h"
11 #include "winerror.h"
12
13 #include "winproc.h"
14 #include "message.h"
15 #include "win.h"
16 #include "wine/server.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(timer);
20
21
22 typedef struct tagTIMER
23 {
24     HWND           hwnd;
25     HQUEUE16       hq;
26     UINT16         msg;  /* WM_TIMER or WM_SYSTIMER */
27     UINT           id;
28     UINT           timeout;
29     HWINDOWPROC    proc;
30 } TIMER;
31
32 #define NB_TIMERS            34
33 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
34
35 #define SYS_TIMER_RATE  55   /* min. timer rate in ms (actually 54.925)*/
36
37 static TIMER TimersArray[NB_TIMERS];
38
39 static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT("csTimer");
40
41
42 /***********************************************************************
43  *           TIMER_ClearTimer
44  *
45  * Clear and remove a timer.
46  */
47 static void TIMER_ClearTimer( TIMER * pTimer )
48 {
49     pTimer->hwnd    = 0;
50     pTimer->msg     = 0;
51     pTimer->id      = 0;
52     pTimer->timeout = 0;
53     WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
54 }
55
56
57 /***********************************************************************
58  *           TIMER_RemoveWindowTimers
59  *
60  * Remove all timers for a given window.
61  */
62 void TIMER_RemoveWindowTimers( HWND hwnd )
63 {
64     int i;
65     TIMER *pTimer;
66
67     EnterCriticalSection( &csTimer );
68     
69     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
70         if ((pTimer->hwnd == hwnd) && pTimer->timeout)
71             TIMER_ClearTimer( pTimer );
72
73     LeaveCriticalSection( &csTimer );
74 }
75
76
77 /***********************************************************************
78  *           TIMER_RemoveQueueTimers
79  *
80  * Remove all timers for a given queue.
81  */
82 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
83 {
84     int i;
85     TIMER *pTimer;
86
87     EnterCriticalSection( &csTimer );
88     
89     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
90         if ((pTimer->hq == hqueue) && pTimer->timeout)
91             TIMER_ClearTimer( pTimer );
92     
93     LeaveCriticalSection( &csTimer );
94 }
95
96
97 /***********************************************************************
98  *           TIMER_SetTimer
99  */
100 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
101                               WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
102 {
103     int i;
104     TIMER * pTimer;
105     HWINDOWPROC winproc = 0;
106
107     if (hwnd && !(hwnd = WIN_IsCurrentThread( hwnd )))
108     {
109         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
110         return 0;
111     }
112
113     if (!timeout)
114       {       /* timeout==0 is a legal argument  UB 990821*/
115        WARN("Timeout== 0 not implemented, using timeout=1\n");
116         timeout=1; 
117       }
118
119     EnterCriticalSection( &csTimer );
120     
121       /* Check if there's already a timer with the same hwnd and id */
122
123     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
124         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
125             (pTimer->timeout != 0))
126         {
127             TIMER_ClearTimer( pTimer );
128             break;
129         }
130
131     if ( i == NB_TIMERS )
132     {
133           /* Find a free timer */
134     
135         for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
136             if (!pTimer->timeout) break;
137
138         if ( (i >= NB_TIMERS) ||
139              (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
140         {
141             LeaveCriticalSection( &csTimer );
142             return 0;
143         }
144     }
145
146     if (!hwnd) id = i + 1;
147     
148     if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER );
149
150     SERVER_START_REQ( set_win_timer )
151     {
152         req->win    = hwnd;
153         req->msg    = sys ? WM_SYSTIMER : WM_TIMER;
154         req->id     = id;
155         req->rate   = max( timeout, SYS_TIMER_RATE );
156         req->lparam = (unsigned int)winproc;
157         wine_server_call( req );
158     }
159     SERVER_END_REQ;
160
161       /* Add the timer */
162
163     pTimer->hwnd    = hwnd;
164     pTimer->hq      = InitThreadInput16( 0, 0 );
165     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
166     pTimer->id      = id;
167     pTimer->timeout = timeout;
168     pTimer->proc    = winproc;
169
170     TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n", 
171                    pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
172                    (DWORD)pTimer->proc );
173
174     LeaveCriticalSection( &csTimer );
175     
176     if (!id) return TRUE;
177     else return id;
178 }
179
180
181 /***********************************************************************
182  *           TIMER_KillTimer
183  */
184 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
185 {
186     int i;
187     TIMER * pTimer;
188     
189     SERVER_START_REQ( kill_win_timer )
190     {
191         req->win = hwnd;
192         req->msg = sys ? WM_SYSTIMER : WM_TIMER;
193         req->id  = id;
194         wine_server_call( req );
195     }
196     SERVER_END_REQ;
197
198     EnterCriticalSection( &csTimer );
199     
200     /* Find the timer */
201     
202     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
203         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
204             (pTimer->timeout != 0)) break;
205
206     if ( (i >= NB_TIMERS) ||
207          (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
208          (!sys && (pTimer->msg != WM_TIMER)) ||
209          (sys && (pTimer->msg != WM_SYSTIMER)) )
210     {
211         LeaveCriticalSection( &csTimer );
212         return FALSE;
213     }
214
215     /* Delete the timer */
216
217     TIMER_ClearTimer( pTimer );
218     
219     LeaveCriticalSection( &csTimer );
220     
221     return TRUE;
222 }
223
224
225 /***********************************************************************
226  *              SetTimer (USER.10)
227  */
228 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
229                           TIMERPROC16 proc )
230 {
231     TRACE("%04x %d %d %08lx\n",
232                    hwnd, id, timeout, (LONG)proc );
233     return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC16)proc,
234                            WIN_PROC_16, FALSE );
235 }
236
237
238 /***********************************************************************
239  *              SetTimer (USER32.@)
240  */
241 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
242                           TIMERPROC proc )
243 {
244     TRACE("%04x %d %d %08lx\n",
245                    hwnd, id, timeout, (LONG)proc );
246     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc, WIN_PROC_32A, FALSE );
247 }
248
249
250 /***********************************************************************
251  *           TIMER_IsTimerValid
252  */
253 BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc )
254 {
255     int i;
256     TIMER *pTimer;
257     BOOL ret = FALSE;
258
259     hwnd = WIN_GetFullHandle( hwnd );
260     EnterCriticalSection( &csTimer );
261
262     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
263         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
264             (pTimer->proc == hProc))
265         {
266             ret = TRUE;
267             break;
268         }
269
270    LeaveCriticalSection( &csTimer );
271    return ret;
272 }
273
274
275 /***********************************************************************
276  *              SetSystemTimer (USER.11)
277  */
278 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
279                                 TIMERPROC16 proc )
280 {
281     TRACE("%04x %d %d %08lx\n", 
282                    hwnd, id, timeout, (LONG)proc );
283     return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC16)proc,
284                            WIN_PROC_16, TRUE );
285 }
286
287
288 /***********************************************************************
289  *              SetSystemTimer (USER32.@)
290  */
291 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
292                                 TIMERPROC proc )
293 {
294     TRACE("%04x %d %d %08lx\n", 
295                    hwnd, id, timeout, (LONG)proc );
296     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc, WIN_PROC_32A, TRUE );
297 }
298
299
300 /***********************************************************************
301  *              KillTimer (USER32.@)
302  */
303 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
304 {
305     TRACE("%04x %d\n", hwnd, id );
306     return TIMER_KillTimer( hwnd, id, FALSE );
307 }
308
309
310 /***********************************************************************
311  *              KillSystemTimer (USER32.@)
312  */
313 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
314 {
315     TRACE("%04x %d\n", hwnd, id );
316     return TIMER_KillTimer( hwnd, id, TRUE );
317 }