4 * Copyright 1993 Alexandre Julliard
9 #include "wine/winuser16.h"
16 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(timer)
21 typedef struct tagTIMER
25 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
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 /***********************************************************************
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;
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 )
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 )
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 /***********************************************************************
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 );
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. */
142 QUEUE_IncTimerCount( wakeQueue );
146 /***********************************************************************
149 * Build a message for an expired timer.
151 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
152 HQUEUE16 hQueue, BOOL remove )
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)) )
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);
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 );
189 /***********************************************************************
192 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
193 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
199 { /* timeout==0 is a legal argument UB 990821*/
200 WARN("Timeout== 0 not implemented, using timeout=1\n");
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 );
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 );
230 if (!hwnd) id = i + 1;
235 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
237 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
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;
258 /***********************************************************************
261 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
266 EnterCriticalSection( &csTimer );
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 );
283 /* Delete the timer */
285 TIMER_ClearTimer( pTimer );
287 LeaveCriticalSection( &csTimer );
293 /***********************************************************************
294 * SetTimer16 (USER.10)
296 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
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,
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,
325 TRACE("%04x %d %d %08lx\n",
326 hwnd, id, timeout, (LONG)proc );
327 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
332 /***********************************************************************
333 * SetSystemTimer (USER32.509)
335 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
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 );