Start using the exported TEB structure from winternl.h where
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "windef.h"
22 #include "wingdi.h"
23 #include "wine/winuser16.h"
24 #include "winuser.h"
25 #include "winerror.h"
26
27 #include "winproc.h"
28 #include "message.h"
29 #include "win.h"
30 #include "wine/server.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(timer);
34
35
36 typedef struct tagTIMER
37 {
38     HWND           hwnd;
39     DWORD          thread;
40     UINT           msg;  /* WM_TIMER or WM_SYSTIMER */
41     UINT           id;
42     UINT           timeout;
43     WNDPROC        proc;
44 } TIMER;
45
46 #define NB_TIMERS            34
47 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
48
49 #define SYS_TIMER_RATE  55   /* min. timer rate in ms (actually 54.925)*/
50
51 static TIMER TimersArray[NB_TIMERS];
52
53 static CRITICAL_SECTION csTimer;
54 static CRITICAL_SECTION_DEBUG critsect_debug =
55 {
56     0, 0, &csTimer,
57     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
58       0, 0, { 0, (DWORD)(__FILE__ ": csTimer") }
59 };
60 static CRITICAL_SECTION csTimer = { &critsect_debug, -1, 0, 0, 0, 0 };
61
62
63 /***********************************************************************
64  *           TIMER_ClearTimer
65  *
66  * Clear and remove a timer.
67  */
68 static void TIMER_ClearTimer( TIMER * pTimer )
69 {
70     pTimer->hwnd    = 0;
71     pTimer->msg     = 0;
72     pTimer->id      = 0;
73     pTimer->timeout = 0;
74     WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
75 }
76
77
78 /***********************************************************************
79  *           TIMER_RemoveWindowTimers
80  *
81  * Remove all timers for a given window.
82  */
83 void TIMER_RemoveWindowTimers( HWND hwnd )
84 {
85     int i;
86     TIMER *pTimer;
87
88     EnterCriticalSection( &csTimer );
89
90     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
91         if ((pTimer->hwnd == hwnd) && pTimer->timeout)
92             TIMER_ClearTimer( pTimer );
93
94     LeaveCriticalSection( &csTimer );
95 }
96
97
98 /***********************************************************************
99  *           TIMER_RemoveThreadTimers
100  *
101  * Remove all timers for the current thread.
102  */
103 void TIMER_RemoveThreadTimers(void)
104 {
105     int i;
106     TIMER *pTimer;
107
108     EnterCriticalSection( &csTimer );
109
110     for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
111         if ((pTimer->thread == GetCurrentThreadId()) && pTimer->timeout)
112             TIMER_ClearTimer( pTimer );
113
114     LeaveCriticalSection( &csTimer );
115 }
116
117
118 /***********************************************************************
119  *           TIMER_SetTimer
120  */
121 static UINT_PTR TIMER_SetTimer( HWND hwnd, UINT_PTR id, UINT timeout,
122                                 WNDPROC proc, WINDOWPROCTYPE type, BOOL sys )
123 {
124     int i;
125     TIMER * pTimer;
126     WNDPROC winproc = 0;
127
128     if (hwnd && !(hwnd = WIN_IsCurrentThread( hwnd )))
129     {
130         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
131         return 0;
132     }
133
134     if (!timeout)
135       {       /* timeout==0 is a legal argument  UB 990821*/
136        WARN("Timeout== 0 not implemented, using timeout=1\n");
137         timeout=1;
138       }
139
140     EnterCriticalSection( &csTimer );
141
142       /* Check if there's already a timer with the same hwnd and id */
143
144     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
145         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
146             (pTimer->timeout != 0))
147         {
148             TIMER_ClearTimer( pTimer );
149             break;
150         }
151
152     if ( i == NB_TIMERS )
153     {
154           /* Find a free timer */
155
156         for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
157             if (!pTimer->timeout) break;
158
159         if ( (i >= NB_TIMERS) ||
160              (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
161         {
162             LeaveCriticalSection( &csTimer );
163             return 0;
164         }
165     }
166
167     if (!hwnd) id = i + 1;
168
169     if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER );
170
171     SERVER_START_REQ( set_win_timer )
172     {
173         req->win    = hwnd;
174         req->msg    = sys ? WM_SYSTIMER : WM_TIMER;
175         req->id     = id;
176         req->rate   = max( timeout, SYS_TIMER_RATE );
177         req->lparam = (unsigned int)winproc;
178         wine_server_call( req );
179     }
180     SERVER_END_REQ;
181
182       /* Add the timer */
183
184     pTimer->hwnd    = hwnd;
185     pTimer->thread  = GetCurrentThreadId();
186     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
187     pTimer->id      = id;
188     pTimer->timeout = timeout;
189     pTimer->proc    = winproc;
190
191     TRACE("Timer added: %p, %p, %04x, %04x, %p\n",
192           pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, pTimer->proc );
193
194     LeaveCriticalSection( &csTimer );
195
196     if (!id) return TRUE;
197     else return id;
198 }
199
200
201 /***********************************************************************
202  *           TIMER_KillTimer
203  */
204 static BOOL TIMER_KillTimer( HWND hwnd, UINT_PTR id, BOOL sys )
205 {
206     int i;
207     TIMER * pTimer;
208
209     SERVER_START_REQ( kill_win_timer )
210     {
211         req->win = hwnd;
212         req->msg = sys ? WM_SYSTIMER : WM_TIMER;
213         req->id  = id;
214         wine_server_call( req );
215     }
216     SERVER_END_REQ;
217
218     EnterCriticalSection( &csTimer );
219
220     /* Find the timer */
221
222     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
223         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
224             (pTimer->timeout != 0)) break;
225
226     if ( (i >= NB_TIMERS) ||
227          (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
228          (!sys && (pTimer->msg != WM_TIMER)) ||
229          (sys && (pTimer->msg != WM_SYSTIMER)) )
230     {
231         LeaveCriticalSection( &csTimer );
232         return FALSE;
233     }
234
235     /* Delete the timer */
236
237     TIMER_ClearTimer( pTimer );
238
239     LeaveCriticalSection( &csTimer );
240
241     return TRUE;
242 }
243
244
245 /***********************************************************************
246  *              SetTimer (USER.10)
247  */
248 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
249                           TIMERPROC16 proc )
250 {
251     TRACE("%04x %d %d %08lx\n",
252                    hwnd, id, timeout, (LONG)proc );
253     return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC)proc,
254                            WIN_PROC_16, FALSE );
255 }
256
257
258 /***********************************************************************
259  *              SetTimer (USER32.@)
260  */
261 UINT_PTR WINAPI SetTimer( HWND hwnd, UINT_PTR id, UINT timeout,
262                           TIMERPROC proc )
263 {
264     TRACE("%p %d %d %p\n", hwnd, id, timeout, proc );
265     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC)proc, WIN_PROC_32A, FALSE );
266 }
267
268
269 /***********************************************************************
270  *           TIMER_IsTimerValid
271  */
272 BOOL TIMER_IsTimerValid( HWND hwnd, UINT_PTR id, WNDPROC proc )
273 {
274     int i;
275     TIMER *pTimer;
276     BOOL ret = FALSE;
277
278     hwnd = WIN_GetFullHandle( hwnd );
279     EnterCriticalSection( &csTimer );
280
281     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
282         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) && (pTimer->proc == proc))
283         {
284             ret = TRUE;
285             break;
286         }
287
288    LeaveCriticalSection( &csTimer );
289    return ret;
290 }
291
292
293 /***********************************************************************
294  *              SetSystemTimer (USER.11)
295  */
296 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
297                                 TIMERPROC16 proc )
298 {
299     TRACE("%04x %d %d %08lx\n",
300                    hwnd, id, timeout, (LONG)proc );
301     return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC)proc, WIN_PROC_16, TRUE );
302 }
303
304
305 /***********************************************************************
306  *              SetSystemTimer (USER32.@)
307  */
308 UINT_PTR WINAPI SetSystemTimer( HWND hwnd, UINT_PTR id, UINT timeout,
309                                 TIMERPROC proc )
310 {
311     TRACE("%p %d %d %p\n", hwnd, id, timeout, proc );
312     return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC)proc, WIN_PROC_32A, TRUE );
313 }
314
315
316 /***********************************************************************
317  *              KillTimer (USER32.@)
318  */
319 BOOL WINAPI KillTimer( HWND hwnd, UINT_PTR id )
320 {
321     TRACE("%p %d\n", hwnd, id );
322     return TIMER_KillTimer( hwnd, id, FALSE );
323 }
324
325
326 /***********************************************************************
327  *              KillSystemTimer (USER32.@)
328  */
329 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT_PTR id )
330 {
331     TRACE("%p %d\n", hwnd, id );
332     return TIMER_KillTimer( hwnd, id, TRUE );
333 }