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