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 static TIMER TimersArray[NB_TIMERS];
36 static CRITICAL_SECTION csTimer;
39 /***********************************************************************
42 * Initialize critical section for the timer.
44 BOOL TIMER_Init( void )
46 InitializeCriticalSection( &csTimer );
47 MakeCriticalSectionGlobal( &csTimer );
53 /***********************************************************************
56 * Clear and remove a timer.
58 static void TIMER_ClearTimer( TIMER * pTimer )
60 if ( pTimer->hService != INVALID_HANDLE_VALUE )
62 SERVICE_Delete( pTimer->hService );
63 pTimer->hService = INVALID_HANDLE_VALUE;
66 if ( pTimer->expired )
68 QUEUE_DecTimerCount( pTimer->hq );
69 pTimer->expired = FALSE;
76 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
80 /***********************************************************************
81 * TIMER_RemoveWindowTimers
83 * Remove all timers for a given window.
85 void TIMER_RemoveWindowTimers( HWND hwnd )
90 EnterCriticalSection( &csTimer );
92 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
93 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
94 TIMER_ClearTimer( pTimer );
96 LeaveCriticalSection( &csTimer );
100 /***********************************************************************
101 * TIMER_RemoveQueueTimers
103 * Remove all timers for a given queue.
105 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
110 EnterCriticalSection( &csTimer );
112 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
113 if ((pTimer->hq == hqueue) && pTimer->timeout)
114 TIMER_ClearTimer( pTimer );
116 LeaveCriticalSection( &csTimer );
120 /***********************************************************************
123 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
125 TIMER *pTimer = (TIMER *)timer_ptr;
126 HQUEUE16 wakeQueue = 0;
128 EnterCriticalSection( &csTimer );
130 /* Paranoid check to prevent a race condition ... */
131 if ( !pTimer->timeout )
133 LeaveCriticalSection( &csTimer );
137 if ( !pTimer->expired )
139 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
140 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
142 pTimer->expired = TRUE;
143 wakeQueue = pTimer->hq;
146 LeaveCriticalSection( &csTimer );
148 /* Note: This has to be done outside the csTimer critical section,
149 otherwise we'll get deadlocks. */
152 QUEUE_IncTimerCount( wakeQueue );
156 /***********************************************************************
159 * Build a message for an expired timer.
161 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
162 HQUEUE16 hQueue, BOOL remove )
167 EnterCriticalSection( &csTimer );
169 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
170 if ( pTimer->timeout != 0 && pTimer->expired
171 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
174 if ( i == NB_TIMERS )
176 LeaveCriticalSection( &csTimer );
177 return FALSE; /* No timer */
180 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
181 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
184 pTimer->expired = FALSE;
186 /* Build the message */
187 msg->hwnd = pTimer->hwnd;
188 msg->message = pTimer->msg;
189 msg->wParam = pTimer->id;
190 msg->lParam = (LONG)pTimer->proc;
191 msg->time = GetTickCount();
193 LeaveCriticalSection( &csTimer );
199 /***********************************************************************
202 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
203 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
208 if (!timeout) return 0;
210 EnterCriticalSection( &csTimer );
212 /* Check if there's already a timer with the same hwnd and id */
214 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
215 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
216 (pTimer->timeout != 0))
218 TIMER_ClearTimer( pTimer );
222 if ( i == NB_TIMERS )
224 /* Find a free timer */
226 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
227 if (!pTimer->timeout) break;
229 if ( (i >= NB_TIMERS) ||
230 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
232 LeaveCriticalSection( &csTimer );
237 if (!hwnd) id = i + 1;
242 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
244 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
246 pTimer->timeout = timeout;
247 pTimer->proc = (HWINDOWPROC)0;
248 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
250 pTimer->expired = FALSE;
251 pTimer->hService = SERVICE_AddTimer( timeout * 1000L,
252 TIMER_CheckTimer, (ULONG_PTR)pTimer );
254 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
255 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
256 (DWORD)pTimer->proc );
258 LeaveCriticalSection( &csTimer );
260 if (!id) return TRUE;
265 /***********************************************************************
268 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
273 EnterCriticalSection( &csTimer );
277 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
278 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
279 (pTimer->timeout != 0)) break;
281 if ( (i >= NB_TIMERS) ||
282 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
283 (!sys && (pTimer->msg != WM_TIMER)) ||
284 (sys && (pTimer->msg != WM_SYSTIMER)) )
286 LeaveCriticalSection( &csTimer );
290 /* Delete the timer */
292 TIMER_ClearTimer( pTimer );
294 LeaveCriticalSection( &csTimer );
300 /***********************************************************************
301 * SetTimer16 (USER.10)
303 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
306 TRACE("%04x %d %d %08lx\n",
307 hwnd, id, timeout, (LONG)proc );
308 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
309 WIN_PROC_16, FALSE );
313 /***********************************************************************
314 * SetTimer32 (USER32.511)
316 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
319 TRACE("%04x %d %d %08lx\n",
320 hwnd, id, timeout, (LONG)proc );
321 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
322 WIN_PROC_32A, FALSE );
326 /***********************************************************************
327 * SetSystemTimer16 (USER.11)
329 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
332 TRACE("%04x %d %d %08lx\n",
333 hwnd, id, timeout, (LONG)proc );
334 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
339 /***********************************************************************
340 * SetSystemTimer32 (USER32.509)
342 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
345 TRACE("%04x %d %d %08lx\n",
346 hwnd, id, timeout, (LONG)proc );
347 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
348 WIN_PROC_32A, TRUE );
352 /***********************************************************************
353 * KillTimer16 (USER.12)
355 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
357 TRACE("%04x %d\n", hwnd, id );
358 return TIMER_KillTimer( hwnd, id, FALSE );
362 /***********************************************************************
363 * KillTimer32 (USER32.354)
365 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
367 TRACE("%04x %d\n", hwnd, id );
368 return TIMER_KillTimer( hwnd, id, FALSE );
372 /***********************************************************************
373 * KillSystemTimer16 (USER.182)
375 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
377 TRACE("%04x %d\n", hwnd, id );
378 return TIMER_KillTimer( hwnd, id, TRUE );
382 /***********************************************************************
383 * KillSystemTimer32 (USER32.353)
385 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
387 TRACE("%04x %d\n", hwnd, id );
388 return TIMER_KillTimer( hwnd, id, TRUE );