4 * Copyright 1993 Alexandre Julliard
9 #include "wine/winuser16.h"
15 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(timer);
20 typedef struct tagTIMER
24 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
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 /***********************************************************************
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;
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 )
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 )
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 /***********************************************************************
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 );
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. */
141 QUEUE_IncTimerCount( wakeQueue );
145 /***********************************************************************
148 * Build a message for an expired timer.
150 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
151 HQUEUE16 hQueue, BOOL remove )
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)) )
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);
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 );
188 /***********************************************************************
191 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
192 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
198 { /* timeout==0 is a legal argument UB 990821*/
199 WARN("Timeout== 0 not implemented, using timeout=1\n");
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 );
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 );
229 if (!hwnd) id = i + 1;
234 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
236 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
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;
257 /***********************************************************************
260 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
265 EnterCriticalSection( &csTimer );
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 );
282 /* Delete the timer */
284 TIMER_ClearTimer( pTimer );
286 LeaveCriticalSection( &csTimer );
292 /***********************************************************************
295 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
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,
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 /***********************************************************************
321 BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc )
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))
337 LeaveCriticalSection( &csTimer );
342 /***********************************************************************
343 * SetSystemTimer (USER.11)
345 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
348 TRACE("%04x %d %d %08lx\n",
349 hwnd, id, timeout, (LONG)proc );
350 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
355 /***********************************************************************
356 * SetSystemTimer (USER32.@)
358 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
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 );