4 * Copyright 1993 Alexandre Julliard
7 #include "wine/winuser16.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(timer)
19 typedef struct tagTIMER
23 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
32 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
34 #define SYS_TIMER_RATE 54925
36 static TIMER TimersArray[NB_TIMERS];
38 static CRITICAL_SECTION csTimer;
41 /***********************************************************************
44 * Initialize critical section for the timer.
46 BOOL TIMER_Init( void )
48 InitializeCriticalSection( &csTimer );
49 MakeCriticalSectionGlobal( &csTimer );
55 /***********************************************************************
58 * Clear and remove a timer.
60 static void TIMER_ClearTimer( TIMER * pTimer )
62 if ( pTimer->hService != INVALID_HANDLE_VALUE )
64 SERVICE_Delete( pTimer->hService );
65 pTimer->hService = INVALID_HANDLE_VALUE;
68 if ( pTimer->expired )
70 QUEUE_DecTimerCount( pTimer->hq );
71 pTimer->expired = FALSE;
78 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
82 /***********************************************************************
83 * TIMER_RemoveWindowTimers
85 * Remove all timers for a given window.
87 void TIMER_RemoveWindowTimers( HWND hwnd )
92 EnterCriticalSection( &csTimer );
94 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
95 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
96 TIMER_ClearTimer( pTimer );
98 LeaveCriticalSection( &csTimer );
102 /***********************************************************************
103 * TIMER_RemoveQueueTimers
105 * Remove all timers for a given queue.
107 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
112 EnterCriticalSection( &csTimer );
114 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
115 if ((pTimer->hq == hqueue) && pTimer->timeout)
116 TIMER_ClearTimer( pTimer );
118 LeaveCriticalSection( &csTimer );
122 /***********************************************************************
125 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
127 TIMER *pTimer = (TIMER *)timer_ptr;
128 HQUEUE16 wakeQueue = 0;
130 EnterCriticalSection( &csTimer );
132 /* Paranoid check to prevent a race condition ... */
133 if ( !pTimer->timeout )
135 LeaveCriticalSection( &csTimer );
139 if ( !pTimer->expired )
141 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
142 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
144 pTimer->expired = TRUE;
145 wakeQueue = pTimer->hq;
148 LeaveCriticalSection( &csTimer );
150 /* Note: This has to be done outside the csTimer critical section,
151 otherwise we'll get deadlocks. */
154 QUEUE_IncTimerCount( wakeQueue );
158 /***********************************************************************
161 * Build a message for an expired timer.
163 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
164 HQUEUE16 hQueue, BOOL remove )
169 EnterCriticalSection( &csTimer );
171 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
172 if ( pTimer->timeout != 0 && pTimer->expired
173 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
176 if ( i == NB_TIMERS )
178 LeaveCriticalSection( &csTimer );
179 return FALSE; /* No timer */
182 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
183 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
186 pTimer->expired = FALSE;
188 /* Build the message */
189 msg->hwnd = pTimer->hwnd;
190 msg->message = pTimer->msg;
191 msg->wParam = pTimer->id;
192 msg->lParam = (LONG)pTimer->proc;
193 msg->time = GetTickCount();
195 LeaveCriticalSection( &csTimer );
201 /***********************************************************************
204 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
205 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
211 { /* timeout==0 is a legal argument UB 990821*/
212 WARN("Timeout== 0 not implemented, using timeout=1\n");
215 EnterCriticalSection( &csTimer );
217 /* Check if there's already a timer with the same hwnd and id */
219 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
220 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
221 (pTimer->timeout != 0))
223 TIMER_ClearTimer( pTimer );
227 if ( i == NB_TIMERS )
229 /* Find a free timer */
231 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
232 if (!pTimer->timeout) break;
234 if ( (i >= NB_TIMERS) ||
235 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
237 LeaveCriticalSection( &csTimer );
242 if (!hwnd) id = i + 1;
247 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
249 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
251 pTimer->timeout = timeout;
252 pTimer->proc = (HWINDOWPROC)0;
253 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
255 pTimer->expired = FALSE;
256 pTimer->hService = SERVICE_AddTimer( MAX( timeout * 1000L, SYS_TIMER_RATE ),
257 TIMER_CheckTimer, (ULONG_PTR)pTimer );
259 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
260 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
261 (DWORD)pTimer->proc );
263 LeaveCriticalSection( &csTimer );
265 if (!id) return TRUE;
270 /***********************************************************************
273 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
278 EnterCriticalSection( &csTimer );
282 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
283 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
284 (pTimer->timeout != 0)) break;
286 if ( (i >= NB_TIMERS) ||
287 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
288 (!sys && (pTimer->msg != WM_TIMER)) ||
289 (sys && (pTimer->msg != WM_SYSTIMER)) )
291 LeaveCriticalSection( &csTimer );
295 /* Delete the timer */
297 TIMER_ClearTimer( pTimer );
299 LeaveCriticalSection( &csTimer );
305 /***********************************************************************
306 * SetTimer16 (USER.10)
308 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 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_16, FALSE );
318 /***********************************************************************
319 * SetTimer32 (USER32.511)
321 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
324 TRACE("%04x %d %d %08lx\n",
325 hwnd, id, timeout, (LONG)proc );
326 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
327 WIN_PROC_32A, FALSE );
331 /***********************************************************************
332 * SetSystemTimer16 (USER.11)
334 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
337 TRACE("%04x %d %d %08lx\n",
338 hwnd, id, timeout, (LONG)proc );
339 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
344 /***********************************************************************
345 * SetSystemTimer32 (USER32.509)
347 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
350 TRACE("%04x %d %d %08lx\n",
351 hwnd, id, timeout, (LONG)proc );
352 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
353 WIN_PROC_32A, TRUE );
357 /***********************************************************************
358 * KillTimer16 (USER.12)
360 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
362 TRACE("%04x %d\n", hwnd, id );
363 return TIMER_KillTimer( hwnd, id, FALSE );
367 /***********************************************************************
368 * KillTimer32 (USER32.354)
370 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
372 TRACE("%04x %d\n", hwnd, id );
373 return TIMER_KillTimer( hwnd, id, FALSE );
377 /***********************************************************************
378 * KillSystemTimer16 (USER.182)
380 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
382 TRACE("%04x %d\n", hwnd, id );
383 return TIMER_KillTimer( hwnd, id, TRUE );
387 /***********************************************************************
388 * KillSystemTimer32 (USER32.353)
390 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
392 TRACE("%04x %d\n", hwnd, id );
393 return TIMER_KillTimer( hwnd, id, TRUE );