Owen Wang
[wine.git] / windows / timer.c
blob4da21f1813567170b40cc0bd0831adca086ffbca
1 /*
2 * Timer functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "windef.h"
8 #include "wingdi.h"
9 #include "wine/winuser16.h"
10 #include "winuser.h"
11 #include "queue.h"
12 #include "task.h"
13 #include "winproc.h"
14 #include "services.h"
15 #include "message.h"
16 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(timer)
21 typedef struct tagTIMER
23 HWND hwnd;
24 HQUEUE16 hq;
25 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
26 UINT id;
27 UINT timeout;
28 HANDLE hService;
29 BOOL expired;
30 HWINDOWPROC proc;
31 } TIMER;
33 #define NB_TIMERS 34
34 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
36 #define SYS_TIMER_RATE 54925
38 static TIMER TimersArray[NB_TIMERS];
40 static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT;
43 /***********************************************************************
44 * TIMER_ClearTimer
46 * Clear and remove a timer.
48 static void TIMER_ClearTimer( TIMER * pTimer )
50 if ( pTimer->hService != INVALID_HANDLE_VALUE )
52 SERVICE_Delete( pTimer->hService );
53 pTimer->hService = INVALID_HANDLE_VALUE;
56 if ( pTimer->expired )
58 QUEUE_DecTimerCount( pTimer->hq );
59 pTimer->expired = FALSE;
62 pTimer->hwnd = 0;
63 pTimer->msg = 0;
64 pTimer->id = 0;
65 pTimer->timeout = 0;
66 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
70 /***********************************************************************
71 * TIMER_RemoveWindowTimers
73 * Remove all timers for a given window.
75 void TIMER_RemoveWindowTimers( HWND hwnd )
77 int i;
78 TIMER *pTimer;
80 EnterCriticalSection( &csTimer );
82 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
83 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
84 TIMER_ClearTimer( pTimer );
86 LeaveCriticalSection( &csTimer );
90 /***********************************************************************
91 * TIMER_RemoveQueueTimers
93 * Remove all timers for a given queue.
95 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
97 int i;
98 TIMER *pTimer;
100 EnterCriticalSection( &csTimer );
102 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
103 if ((pTimer->hq == hqueue) && pTimer->timeout)
104 TIMER_ClearTimer( pTimer );
106 LeaveCriticalSection( &csTimer );
110 /***********************************************************************
111 * TIMER_CheckTimer
113 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
115 TIMER *pTimer = (TIMER *)timer_ptr;
116 HQUEUE16 wakeQueue = 0;
118 EnterCriticalSection( &csTimer );
120 /* Paranoid check to prevent a race condition ... */
121 if ( !pTimer->timeout )
123 LeaveCriticalSection( &csTimer );
124 return;
127 if ( !pTimer->expired )
129 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
130 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
132 pTimer->expired = TRUE;
133 wakeQueue = pTimer->hq;
136 LeaveCriticalSection( &csTimer );
138 /* Note: This has to be done outside the csTimer critical section,
139 otherwise we'll get deadlocks. */
141 if ( wakeQueue )
142 QUEUE_IncTimerCount( wakeQueue );
146 /***********************************************************************
147 * TIMER_GetTimerMsg
149 * Build a message for an expired timer.
151 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
152 HQUEUE16 hQueue, BOOL remove )
154 TIMER *pTimer;
155 int i;
157 EnterCriticalSection( &csTimer );
159 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
160 if ( pTimer->timeout != 0 && pTimer->expired
161 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
162 break;
164 if ( i == NB_TIMERS )
166 LeaveCriticalSection( &csTimer );
167 return FALSE; /* No timer */
170 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
171 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
173 if (remove)
174 pTimer->expired = FALSE;
176 /* Build the message */
177 msg->hwnd = pTimer->hwnd;
178 msg->message = pTimer->msg;
179 msg->wParam = pTimer->id;
180 msg->lParam = (LONG)pTimer->proc;
181 msg->time = GetTickCount();
183 LeaveCriticalSection( &csTimer );
185 return TRUE;
189 /***********************************************************************
190 * TIMER_SetTimer
192 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
193 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
195 int i;
196 TIMER * pTimer;
198 if (!timeout)
199 { /* timeout==0 is a legal argument UB 990821*/
200 WARN("Timeout== 0 not implemented, using timeout=1\n");
201 timeout=1;
203 EnterCriticalSection( &csTimer );
205 /* Check if there's already a timer with the same hwnd and id */
207 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
208 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
209 (pTimer->timeout != 0))
211 TIMER_ClearTimer( pTimer );
212 break;
215 if ( i == NB_TIMERS )
217 /* Find a free timer */
219 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
220 if (!pTimer->timeout) break;
222 if ( (i >= NB_TIMERS) ||
223 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
225 LeaveCriticalSection( &csTimer );
226 return 0;
230 if (!hwnd) id = i + 1;
232 /* Add the timer */
234 pTimer->hwnd = hwnd;
235 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
236 : GetFastQueue16( );
237 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
238 pTimer->id = id;
239 pTimer->timeout = timeout;
240 pTimer->proc = (HWINDOWPROC)0;
241 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
243 pTimer->expired = FALSE;
244 pTimer->hService = SERVICE_AddTimer( max( timeout, (SYS_TIMER_RATE+500)/1000 ),
245 TIMER_CheckTimer, (ULONG_PTR)pTimer );
247 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
248 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
249 (DWORD)pTimer->proc );
251 LeaveCriticalSection( &csTimer );
253 if (!id) return TRUE;
254 else return id;
258 /***********************************************************************
259 * TIMER_KillTimer
261 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
263 int i;
264 TIMER * pTimer;
266 EnterCriticalSection( &csTimer );
268 /* Find the timer */
270 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
271 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
272 (pTimer->timeout != 0)) break;
274 if ( (i >= NB_TIMERS) ||
275 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
276 (!sys && (pTimer->msg != WM_TIMER)) ||
277 (sys && (pTimer->msg != WM_SYSTIMER)) )
279 LeaveCriticalSection( &csTimer );
280 return FALSE;
283 /* Delete the timer */
285 TIMER_ClearTimer( pTimer );
287 LeaveCriticalSection( &csTimer );
289 return TRUE;
293 /***********************************************************************
294 * SetTimer16 (USER.10)
296 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
297 TIMERPROC16 proc )
299 TRACE("%04x %d %d %08lx\n",
300 hwnd, id, timeout, (LONG)proc );
301 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
302 WIN_PROC_16, FALSE );
306 /***********************************************************************
307 * SetTimer (USER32.511)
309 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
310 TIMERPROC proc )
312 TRACE("%04x %d %d %08lx\n",
313 hwnd, id, timeout, (LONG)proc );
314 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
315 WIN_PROC_32A, FALSE );
319 /***********************************************************************
320 * SetSystemTimer16 (USER.11)
322 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
323 TIMERPROC16 proc )
325 TRACE("%04x %d %d %08lx\n",
326 hwnd, id, timeout, (LONG)proc );
327 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
328 WIN_PROC_16, TRUE );
332 /***********************************************************************
333 * SetSystemTimer (USER32.509)
335 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
336 TIMERPROC proc )
338 TRACE("%04x %d %d %08lx\n",
339 hwnd, id, timeout, (LONG)proc );
340 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
341 WIN_PROC_32A, TRUE );
345 /***********************************************************************
346 * KillTimer16 (USER.12)
348 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
350 TRACE("%04x %d\n", hwnd, id );
351 return TIMER_KillTimer( hwnd, id, FALSE );
355 /***********************************************************************
356 * KillTimer (USER32.354)
358 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
360 TRACE("%04x %d\n", hwnd, id );
361 return TIMER_KillTimer( hwnd, id, FALSE );
365 /***********************************************************************
366 * KillSystemTimer16 (USER.182)
368 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
370 TRACE("%04x %d\n", hwnd, id );
371 return TIMER_KillTimer( hwnd, id, TRUE );
375 /***********************************************************************
376 * KillSystemTimer (USER32.353)
378 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
380 TRACE("%04x %d\n", hwnd, id );
381 return TIMER_KillTimer( hwnd, id, TRUE );