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;
43 /***********************************************************************
46 * Initialize critical section for the timer.
48 BOOL TIMER_Init( void )
50 InitializeCriticalSection( &csTimer );
51 MakeCriticalSectionGlobal( &csTimer );
57 /***********************************************************************
60 * Clear and remove a timer.
62 static void TIMER_ClearTimer( TIMER * pTimer )
64 if ( pTimer->hService != INVALID_HANDLE_VALUE )
66 SERVICE_Delete( pTimer->hService );
67 pTimer->hService = INVALID_HANDLE_VALUE;
70 if ( pTimer->expired )
72 QUEUE_DecTimerCount( pTimer->hq );
73 pTimer->expired = FALSE;
80 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
84 /***********************************************************************
85 * TIMER_RemoveWindowTimers
87 * Remove all timers for a given window.
89 void TIMER_RemoveWindowTimers( HWND hwnd )
94 EnterCriticalSection( &csTimer );
96 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
97 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
98 TIMER_ClearTimer( pTimer );
100 LeaveCriticalSection( &csTimer );
104 /***********************************************************************
105 * TIMER_RemoveQueueTimers
107 * Remove all timers for a given queue.
109 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
114 EnterCriticalSection( &csTimer );
116 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
117 if ((pTimer->hq == hqueue) && pTimer->timeout)
118 TIMER_ClearTimer( pTimer );
120 LeaveCriticalSection( &csTimer );
124 /***********************************************************************
127 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
129 TIMER *pTimer = (TIMER *)timer_ptr;
130 HQUEUE16 wakeQueue = 0;
132 EnterCriticalSection( &csTimer );
134 /* Paranoid check to prevent a race condition ... */
135 if ( !pTimer->timeout )
137 LeaveCriticalSection( &csTimer );
141 if ( !pTimer->expired )
143 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
144 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
146 pTimer->expired = TRUE;
147 wakeQueue = pTimer->hq;
150 LeaveCriticalSection( &csTimer );
152 /* Note: This has to be done outside the csTimer critical section,
153 otherwise we'll get deadlocks. */
156 QUEUE_IncTimerCount( wakeQueue );
160 /***********************************************************************
163 * Build a message for an expired timer.
165 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
166 HQUEUE16 hQueue, BOOL remove )
171 EnterCriticalSection( &csTimer );
173 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
174 if ( pTimer->timeout != 0 && pTimer->expired
175 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
178 if ( i == NB_TIMERS )
180 LeaveCriticalSection( &csTimer );
181 return FALSE; /* No timer */
184 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
185 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
188 pTimer->expired = FALSE;
190 /* Build the message */
191 msg->hwnd = pTimer->hwnd;
192 msg->message = pTimer->msg;
193 msg->wParam = pTimer->id;
194 msg->lParam = (LONG)pTimer->proc;
195 msg->time = GetTickCount();
197 LeaveCriticalSection( &csTimer );
203 /***********************************************************************
206 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
207 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
213 { /* timeout==0 is a legal argument UB 990821*/
214 WARN("Timeout== 0 not implemented, using timeout=1\n");
217 EnterCriticalSection( &csTimer );
219 /* Check if there's already a timer with the same hwnd and id */
221 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
222 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
223 (pTimer->timeout != 0))
225 TIMER_ClearTimer( pTimer );
229 if ( i == NB_TIMERS )
231 /* Find a free timer */
233 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
234 if (!pTimer->timeout) break;
236 if ( (i >= NB_TIMERS) ||
237 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
239 LeaveCriticalSection( &csTimer );
244 if (!hwnd) id = i + 1;
249 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
251 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
253 pTimer->timeout = timeout;
254 pTimer->proc = (HWINDOWPROC)0;
255 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
257 pTimer->expired = FALSE;
258 pTimer->hService = SERVICE_AddTimer( max( timeout * 1000L, SYS_TIMER_RATE ),
259 TIMER_CheckTimer, (ULONG_PTR)pTimer );
261 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
262 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
263 (DWORD)pTimer->proc );
265 LeaveCriticalSection( &csTimer );
267 if (!id) return TRUE;
272 /***********************************************************************
275 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
280 EnterCriticalSection( &csTimer );
284 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
285 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
286 (pTimer->timeout != 0)) break;
288 if ( (i >= NB_TIMERS) ||
289 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
290 (!sys && (pTimer->msg != WM_TIMER)) ||
291 (sys && (pTimer->msg != WM_SYSTIMER)) )
293 LeaveCriticalSection( &csTimer );
297 /* Delete the timer */
299 TIMER_ClearTimer( pTimer );
301 LeaveCriticalSection( &csTimer );
307 /***********************************************************************
308 * SetTimer16 (USER.10)
310 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
313 TRACE("%04x %d %d %08lx\n",
314 hwnd, id, timeout, (LONG)proc );
315 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
316 WIN_PROC_16, FALSE );
320 /***********************************************************************
321 * SetTimer32 (USER32.511)
323 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
326 TRACE("%04x %d %d %08lx\n",
327 hwnd, id, timeout, (LONG)proc );
328 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
329 WIN_PROC_32A, FALSE );
333 /***********************************************************************
334 * SetSystemTimer16 (USER.11)
336 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
339 TRACE("%04x %d %d %08lx\n",
340 hwnd, id, timeout, (LONG)proc );
341 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
346 /***********************************************************************
347 * SetSystemTimer32 (USER32.509)
349 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
352 TRACE("%04x %d %d %08lx\n",
353 hwnd, id, timeout, (LONG)proc );
354 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
355 WIN_PROC_32A, TRUE );
359 /***********************************************************************
360 * KillTimer16 (USER.12)
362 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
364 TRACE("%04x %d\n", hwnd, id );
365 return TIMER_KillTimer( hwnd, id, FALSE );
369 /***********************************************************************
370 * KillTimer32 (USER32.354)
372 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
374 TRACE("%04x %d\n", hwnd, id );
375 return TIMER_KillTimer( hwnd, id, FALSE );
379 /***********************************************************************
380 * KillSystemTimer16 (USER.182)
382 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
384 TRACE("%04x %d\n", hwnd, id );
385 return TIMER_KillTimer( hwnd, id, TRUE );
389 /***********************************************************************
390 * KillSystemTimer32 (USER32.353)
392 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
394 TRACE("%04x %d\n", hwnd, id );
395 return TIMER_KillTimer( hwnd, id, TRUE );