4 * Copyright 1993 Alexandre Julliard
14 DEFAULT_DEBUG_CHANNEL(timer)
17 typedef struct tagTIMER
21 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
30 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
32 static TIMER TimersArray[NB_TIMERS];
34 static CRITICAL_SECTION csTimer;
37 /***********************************************************************
40 * Initialize critical section for the timer.
42 BOOL TIMER_Init( void )
44 InitializeCriticalSection( &csTimer );
45 MakeCriticalSectionGlobal( &csTimer );
51 /***********************************************************************
54 * Clear and remove a timer.
56 static void TIMER_ClearTimer( TIMER * pTimer )
58 if ( pTimer->hService != INVALID_HANDLE_VALUE )
60 SERVICE_Delete( pTimer->hService );
61 pTimer->hService = INVALID_HANDLE_VALUE;
64 if ( pTimer->expired )
66 QUEUE_DecTimerCount( pTimer->hq );
67 pTimer->expired = FALSE;
74 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
78 /***********************************************************************
79 * TIMER_RemoveWindowTimers
81 * Remove all timers for a given window.
83 void TIMER_RemoveWindowTimers( HWND hwnd )
88 EnterCriticalSection( &csTimer );
90 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
91 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
92 TIMER_ClearTimer( pTimer );
94 LeaveCriticalSection( &csTimer );
98 /***********************************************************************
99 * TIMER_RemoveQueueTimers
101 * Remove all timers for a given queue.
103 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
108 EnterCriticalSection( &csTimer );
110 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
111 if ((pTimer->hq == hqueue) && pTimer->timeout)
112 TIMER_ClearTimer( pTimer );
114 LeaveCriticalSection( &csTimer );
118 /***********************************************************************
121 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
123 TIMER *pTimer = (TIMER *)timer_ptr;
124 HQUEUE16 wakeQueue = 0;
126 EnterCriticalSection( &csTimer );
128 /* Paranoid check to prevent a race condition ... */
129 if ( !pTimer->timeout )
131 LeaveCriticalSection( &csTimer );
135 if ( !pTimer->expired )
137 TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
138 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
140 pTimer->expired = TRUE;
141 wakeQueue = pTimer->hq;
144 LeaveCriticalSection( &csTimer );
146 /* Note: This has to be done outside the csTimer critical section,
147 otherwise we'll get deadlocks. */
150 QUEUE_IncTimerCount( wakeQueue );
154 /***********************************************************************
157 * Build a message for an expired timer.
159 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
160 HQUEUE16 hQueue, BOOL remove )
165 EnterCriticalSection( &csTimer );
167 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
168 if ( pTimer->timeout != 0 && pTimer->expired
169 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
172 if ( i == NB_TIMERS )
174 LeaveCriticalSection( &csTimer );
175 return FALSE; /* No timer */
178 TRACE(timer, "Timer got message: %04x, %04x, %04x, %08lx\n",
179 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
182 pTimer->expired = FALSE;
184 /* Build the message */
185 msg->hwnd = pTimer->hwnd;
186 msg->message = pTimer->msg;
187 msg->wParam = pTimer->id;
188 msg->lParam = (LONG)pTimer->proc;
189 msg->time = GetTickCount();
191 LeaveCriticalSection( &csTimer );
197 /***********************************************************************
200 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
201 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
206 if (!timeout) return 0;
208 EnterCriticalSection( &csTimer );
210 /* Check if there's already a timer with the same hwnd and id */
212 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
213 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
214 (pTimer->timeout != 0))
216 TIMER_ClearTimer( pTimer );
220 if ( i == NB_TIMERS )
222 /* Find a free timer */
224 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
225 if (!pTimer->timeout) break;
227 if ( (i >= NB_TIMERS) ||
228 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
230 LeaveCriticalSection( &csTimer );
235 if (!hwnd) id = i + 1;
240 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
242 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
244 pTimer->timeout = timeout;
245 pTimer->proc = (HWINDOWPROC)0;
246 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
248 pTimer->expired = FALSE;
249 pTimer->hService = SERVICE_AddTimer( timeout * 1000L,
250 TIMER_CheckTimer, (ULONG_PTR)pTimer );
252 TRACE(timer, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
253 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
254 (DWORD)pTimer->proc );
256 LeaveCriticalSection( &csTimer );
258 if (!id) return TRUE;
263 /***********************************************************************
266 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
271 EnterCriticalSection( &csTimer );
275 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
276 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
277 (pTimer->timeout != 0)) break;
279 if ( (i >= NB_TIMERS) ||
280 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
281 (!sys && (pTimer->msg != WM_TIMER)) ||
282 (sys && (pTimer->msg != WM_SYSTIMER)) )
284 LeaveCriticalSection( &csTimer );
288 /* Delete the timer */
290 TIMER_ClearTimer( pTimer );
292 LeaveCriticalSection( &csTimer );
298 /***********************************************************************
299 * SetTimer16 (USER.10)
301 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
304 TRACE(timer, "%04x %d %d %08lx\n",
305 hwnd, id, timeout, (LONG)proc );
306 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
307 WIN_PROC_16, FALSE );
311 /***********************************************************************
312 * SetTimer32 (USER32.511)
314 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
317 TRACE(timer, "%04x %d %d %08lx\n",
318 hwnd, id, timeout, (LONG)proc );
319 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
320 WIN_PROC_32A, FALSE );
324 /***********************************************************************
325 * SetSystemTimer16 (USER.11)
327 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
330 TRACE(timer, "%04x %d %d %08lx\n",
331 hwnd, id, timeout, (LONG)proc );
332 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
337 /***********************************************************************
338 * SetSystemTimer32 (USER32.509)
340 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
343 TRACE(timer, "%04x %d %d %08lx\n",
344 hwnd, id, timeout, (LONG)proc );
345 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
346 WIN_PROC_32A, TRUE );
350 /***********************************************************************
351 * KillTimer16 (USER.12)
353 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
355 TRACE(timer, "%04x %d\n", hwnd, id );
356 return TIMER_KillTimer( hwnd, id, FALSE );
360 /***********************************************************************
361 * KillTimer32 (USER32.354)
363 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
365 TRACE(timer, "%04x %d\n", hwnd, id );
366 return TIMER_KillTimer( hwnd, id, FALSE );
370 /***********************************************************************
371 * KillSystemTimer16 (USER.182)
373 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
375 TRACE(timer, "%04x %d\n", hwnd, id );
376 return TIMER_KillTimer( hwnd, id, TRUE );
380 /***********************************************************************
381 * KillSystemTimer32 (USER32.353)
383 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
385 TRACE(timer, "%04x %d\n", hwnd, id );
386 return TIMER_KillTimer( hwnd, id, TRUE );