Use poll() on the client-side during server waits to implement
[wine.git] / windows / timer.c
blob99935f375e4898ed9c38a3a1cc9667e4add39dc2
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 "winproc.h"
13 #include "services.h"
14 #include "message.h"
15 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(timer);
20 typedef struct tagTIMER
22 HWND hwnd;
23 HQUEUE16 hq;
24 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
25 UINT id;
26 UINT timeout;
27 HANDLE hService;
28 BOOL expired;
29 HWINDOWPROC proc;
30 } TIMER;
32 #define NB_TIMERS 34
33 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
35 #define SYS_TIMER_RATE 54925
37 static TIMER TimersArray[NB_TIMERS];
39 static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT;
42 /***********************************************************************
43 * TIMER_ClearTimer
45 * Clear and remove a timer.
47 static void TIMER_ClearTimer( TIMER * pTimer )
49 if ( pTimer->hService != INVALID_HANDLE_VALUE )
51 SERVICE_Delete( pTimer->hService );
52 pTimer->hService = INVALID_HANDLE_VALUE;
55 if ( pTimer->expired )
57 QUEUE_DecTimerCount( pTimer->hq );
58 pTimer->expired = FALSE;
61 pTimer->hwnd = 0;
62 pTimer->msg = 0;
63 pTimer->id = 0;
64 pTimer->timeout = 0;
65 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
69 /***********************************************************************
70 * TIMER_RemoveWindowTimers
72 * Remove all timers for a given window.
74 void TIMER_RemoveWindowTimers( HWND hwnd )
76 int i;
77 TIMER *pTimer;
79 EnterCriticalSection( &csTimer );
81 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
82 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
83 TIMER_ClearTimer( pTimer );
85 LeaveCriticalSection( &csTimer );
89 /***********************************************************************
90 * TIMER_RemoveQueueTimers
92 * Remove all timers for a given queue.
94 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
96 int i;
97 TIMER *pTimer;
99 EnterCriticalSection( &csTimer );
101 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
102 if ((pTimer->hq == hqueue) && pTimer->timeout)
103 TIMER_ClearTimer( pTimer );
105 LeaveCriticalSection( &csTimer );
109 /***********************************************************************
110 * TIMER_CheckTimer
112 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
114 TIMER *pTimer = (TIMER *)timer_ptr;
115 HQUEUE16 wakeQueue = 0;
117 EnterCriticalSection( &csTimer );
119 /* Paranoid check to prevent a race condition ... */
120 if ( !pTimer->timeout )
122 LeaveCriticalSection( &csTimer );
123 return;
126 if ( !pTimer->expired )
128 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
129 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
131 pTimer->expired = TRUE;
132 wakeQueue = pTimer->hq;
135 LeaveCriticalSection( &csTimer );
137 /* Note: This has to be done outside the csTimer critical section,
138 otherwise we'll get deadlocks. */
140 if ( wakeQueue )
141 QUEUE_IncTimerCount( wakeQueue );
145 /***********************************************************************
146 * TIMER_GetTimerMsg
148 * Build a message for an expired timer.
150 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
151 HQUEUE16 hQueue, BOOL remove )
153 TIMER *pTimer;
154 int i;
156 EnterCriticalSection( &csTimer );
158 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
159 if ( pTimer->timeout != 0 && pTimer->expired
160 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
161 break;
163 if ( i == NB_TIMERS )
165 LeaveCriticalSection( &csTimer );
166 return FALSE; /* No timer */
169 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
170 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
172 if (remove)
173 pTimer->expired = FALSE;
175 /* Build the message */
176 msg->hwnd = pTimer->hwnd;
177 msg->message = pTimer->msg;
178 msg->wParam = pTimer->id;
179 msg->lParam = (LONG)pTimer->proc;
180 msg->time = GetTickCount();
182 LeaveCriticalSection( &csTimer );
184 return TRUE;
188 /***********************************************************************
189 * TIMER_SetTimer
191 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
192 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
194 int i;
195 TIMER * pTimer;
197 if (!timeout)
198 { /* timeout==0 is a legal argument UB 990821*/
199 WARN("Timeout== 0 not implemented, using timeout=1\n");
200 timeout=1;
202 EnterCriticalSection( &csTimer );
204 /* Check if there's already a timer with the same hwnd and id */
206 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
207 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
208 (pTimer->timeout != 0))
210 TIMER_ClearTimer( pTimer );
211 break;
214 if ( i == NB_TIMERS )
216 /* Find a free timer */
218 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
219 if (!pTimer->timeout) break;
221 if ( (i >= NB_TIMERS) ||
222 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
224 LeaveCriticalSection( &csTimer );
225 return 0;
229 if (!hwnd) id = i + 1;
231 /* Add the timer */
233 pTimer->hwnd = hwnd;
234 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
235 : GetFastQueue16( );
236 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
237 pTimer->id = id;
238 pTimer->timeout = timeout;
239 pTimer->proc = (HWINDOWPROC)0;
240 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
242 pTimer->expired = FALSE;
243 pTimer->hService = SERVICE_AddTimer( max( timeout, (SYS_TIMER_RATE+500)/1000 ),
244 TIMER_CheckTimer, (ULONG_PTR)pTimer );
246 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
247 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
248 (DWORD)pTimer->proc );
250 LeaveCriticalSection( &csTimer );
252 if (!id) return TRUE;
253 else return id;
257 /***********************************************************************
258 * TIMER_KillTimer
260 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
262 int i;
263 TIMER * pTimer;
265 EnterCriticalSection( &csTimer );
267 /* Find the timer */
269 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
270 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
271 (pTimer->timeout != 0)) break;
273 if ( (i >= NB_TIMERS) ||
274 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
275 (!sys && (pTimer->msg != WM_TIMER)) ||
276 (sys && (pTimer->msg != WM_SYSTIMER)) )
278 LeaveCriticalSection( &csTimer );
279 return FALSE;
282 /* Delete the timer */
284 TIMER_ClearTimer( pTimer );
286 LeaveCriticalSection( &csTimer );
288 return TRUE;
292 /***********************************************************************
293 * SetTimer (USER.10)
295 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
296 TIMERPROC16 proc )
298 TRACE("%04x %d %d %08lx\n",
299 hwnd, id, timeout, (LONG)proc );
300 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
301 WIN_PROC_16, FALSE );
305 /***********************************************************************
306 * SetTimer (USER32.@)
308 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
309 TIMERPROC proc )
311 TRACE("%04x %d %d %08lx\n",
312 hwnd, id, timeout, (LONG)proc );
313 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
314 WIN_PROC_32A, FALSE );
318 /***********************************************************************
319 * TIMER_IsTimerValid
321 BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc )
323 int i;
324 TIMER *pTimer;
325 BOOL ret = FALSE;
327 EnterCriticalSection( &csTimer );
329 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
330 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
331 (pTimer->proc == hProc))
333 ret = TRUE;
334 break;
337 LeaveCriticalSection( &csTimer );
338 return ret;
342 /***********************************************************************
343 * SetSystemTimer (USER.11)
345 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
346 TIMERPROC16 proc )
348 TRACE("%04x %d %d %08lx\n",
349 hwnd, id, timeout, (LONG)proc );
350 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
351 WIN_PROC_16, TRUE );
355 /***********************************************************************
356 * SetSystemTimer (USER32.@)
358 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
359 TIMERPROC proc )
361 TRACE("%04x %d %d %08lx\n",
362 hwnd, id, timeout, (LONG)proc );
363 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
364 WIN_PROC_32A, TRUE );
368 /***********************************************************************
369 * KillTimer (USER.12)
371 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
373 TRACE("%04x %d\n", hwnd, id );
374 return TIMER_KillTimer( hwnd, id, FALSE );
378 /***********************************************************************
379 * KillTimer (USER32.@)
381 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
383 TRACE("%04x %d\n", hwnd, id );
384 return TIMER_KillTimer( hwnd, id, FALSE );
388 /***********************************************************************
389 * KillSystemTimer (USER.182)
391 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
393 TRACE("%04x %d\n", hwnd, id );
394 return TIMER_KillTimer( hwnd, id, TRUE );
398 /***********************************************************************
399 * KillSystemTimer (USER32.@)
401 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
403 TRACE("%04x %d\n", hwnd, id );
404 return TIMER_KillTimer( hwnd, id, TRUE );