4 * Copyright 1993 Alexandre Julliard
14 typedef struct tagTIMER
18 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
21 struct tagTIMER *next;
22 DWORD expires; /* Next expiration, or 0 if already expired */
27 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
29 static TIMER TimersArray[NB_TIMERS];
31 static TIMER * pNextTimer = NULL; /* Next timer to expire */
33 static CRITICAL_SECTION csTimer;
35 /* Duration from 'time' until expiration of the timer */
36 #define EXPIRE_TIME(pTimer,time) \
37 (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
40 /***********************************************************************
43 * Initialize critical section for the timer.
45 BOOL TIMER_Init( void )
47 InitializeCriticalSection( &csTimer );
48 MakeCriticalSectionGlobal( &csTimer );
54 /***********************************************************************
57 * Insert the timer at its place in the chain.
59 static void TIMER_InsertTimer( TIMER * pTimer )
61 EnterCriticalSection( &csTimer );
63 if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
65 pTimer->next = pNextTimer;
70 TIMER * ptr = pNextTimer;
71 while (ptr->next && (pTimer->expires >= ptr->next->expires))
73 pTimer->next = ptr->next;
77 LeaveCriticalSection( &csTimer );
81 /***********************************************************************
84 * Remove the timer from the chain.
86 static void TIMER_RemoveTimer( TIMER * pTimer )
88 TIMER **ppTimer = &pNextTimer;
90 EnterCriticalSection( &csTimer );
92 while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
93 if (*ppTimer) *ppTimer = pTimer->next;
96 LeaveCriticalSection( &csTimer );
98 if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
102 /***********************************************************************
105 * Clear and remove a timer.
107 static void TIMER_ClearTimer( TIMER * pTimer )
109 TIMER_RemoveTimer( pTimer );
114 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
118 /***********************************************************************
121 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
125 EnterCriticalSection( &csTimer );
130 if (pT->hq == old) pT->hq = new;
134 LeaveCriticalSection( &csTimer );
138 /***********************************************************************
139 * TIMER_RemoveWindowTimers
141 * Remove all timers for a given window.
143 void TIMER_RemoveWindowTimers( HWND hwnd )
148 EnterCriticalSection( &csTimer );
150 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
151 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
152 TIMER_ClearTimer( pTimer );
154 LeaveCriticalSection( &csTimer );
158 /***********************************************************************
159 * TIMER_RemoveQueueTimers
161 * Remove all timers for a given queue.
163 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
168 EnterCriticalSection( &csTimer );
170 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
171 if ((pTimer->hq == hqueue) && pTimer->timeout)
172 TIMER_ClearTimer( pTimer );
174 LeaveCriticalSection( &csTimer );
178 /***********************************************************************
179 * TIMER_RestartTimers
181 * Restart an expired timer.
183 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
185 TIMER_RemoveTimer( pTimer );
186 pTimer->expires = curTime + pTimer->timeout;
187 TIMER_InsertTimer( pTimer );
191 /***********************************************************************
192 * TIMER_GetNextExpiration
194 * Return next timer expiration time, or -1 if none.
196 LONG TIMER_GetNextExpiration(void)
200 EnterCriticalSection( &csTimer );
201 retValue = pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
202 LeaveCriticalSection( &csTimer );
208 /***********************************************************************
211 * Mark expired timers and wake the appropriate queues.
213 void TIMER_ExpireTimers(void)
216 DWORD curTime = GetTickCount();
218 EnterCriticalSection( &csTimer );
222 while (pTimer && !pTimer->expires) /* Skip already expired timers */
223 pTimer = pTimer->next;
224 while (pTimer && (pTimer->expires <= curTime))
227 QUEUE_IncTimerCount( pTimer->hq );
228 pTimer = pTimer->next;
231 LeaveCriticalSection( &csTimer );
235 /***********************************************************************
238 * Build a message for an expired timer.
240 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
241 HQUEUE16 hQueue, BOOL remove )
244 DWORD curTime = GetTickCount();
246 EnterCriticalSection( &csTimer );
250 if (hwnd) /* Find first timer for this window */
251 while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
252 else /* Find first timer for this queue */
253 while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
255 if (!pTimer || (pTimer->expires > curTime))
257 LeaveCriticalSection( &csTimer );
258 return FALSE; /* No timer */
261 if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
263 TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
264 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
266 /* Build the message */
267 msg->hwnd = pTimer->hwnd;
268 msg->message = pTimer->msg;
269 msg->wParam = pTimer->id;
270 msg->lParam = (LONG)pTimer->proc;
273 LeaveCriticalSection( &csTimer );
279 /***********************************************************************
282 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
283 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
288 if (!timeout) return 0;
290 EnterCriticalSection( &csTimer );
292 /* Check if there's already a timer with the same hwnd and id */
294 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
295 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
296 (pTimer->timeout != 0))
298 /* Got one: set new values and return */
299 TIMER_RemoveTimer( pTimer );
300 pTimer->timeout = timeout;
301 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
302 pTimer->proc = (HWINDOWPROC)0;
303 if (proc) WINPROC_SetProc( &pTimer->proc, proc,
304 type, WIN_PROC_TIMER );
305 pTimer->expires = GetTickCount() + timeout;
306 TIMER_InsertTimer( pTimer );
307 LeaveCriticalSection( &csTimer );
311 /* Find a free timer */
313 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
314 if (!pTimer->timeout) break;
316 if ( (i >= NB_TIMERS) ||
317 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
319 LeaveCriticalSection( &csTimer );
323 if (!hwnd) id = i + 1;
328 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
330 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
332 pTimer->timeout = timeout;
333 pTimer->expires = GetTickCount() + timeout;
334 pTimer->proc = (HWINDOWPROC)0;
335 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
336 TRACE(timer, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
337 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
338 (DWORD)pTimer->proc );
339 TIMER_InsertTimer( pTimer );
341 LeaveCriticalSection( &csTimer );
343 if (!id) return TRUE;
348 /***********************************************************************
351 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
356 EnterCriticalSection( &csTimer );
360 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
361 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
362 (pTimer->timeout != 0)) break;
364 if ( (i >= NB_TIMERS) ||
365 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
366 (!sys && (pTimer->msg != WM_TIMER)) ||
367 (sys && (pTimer->msg != WM_SYSTIMER)) )
369 LeaveCriticalSection( &csTimer );
373 /* Delete the timer */
375 TIMER_ClearTimer( pTimer );
377 LeaveCriticalSection( &csTimer );
383 /***********************************************************************
384 * SetTimer16 (USER.10)
386 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
389 TRACE(timer, "%04x %d %d %08lx\n",
390 hwnd, id, timeout, (LONG)proc );
391 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
392 WIN_PROC_16, FALSE );
396 /***********************************************************************
397 * SetTimer32 (USER32.511)
399 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
402 TRACE(timer, "%04x %d %d %08lx\n",
403 hwnd, id, timeout, (LONG)proc );
404 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
405 WIN_PROC_32A, FALSE );
409 /***********************************************************************
410 * SetSystemTimer16 (USER.11)
412 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
415 TRACE(timer, "%04x %d %d %08lx\n",
416 hwnd, id, timeout, (LONG)proc );
417 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
422 /***********************************************************************
423 * SetSystemTimer32 (USER32.509)
425 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
428 TRACE(timer, "%04x %d %d %08lx\n",
429 hwnd, id, timeout, (LONG)proc );
430 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
431 WIN_PROC_32A, TRUE );
435 /***********************************************************************
436 * KillTimer16 (USER.12)
438 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
440 TRACE(timer, "%04x %d\n", hwnd, id );
441 return TIMER_KillTimer( hwnd, id, FALSE );
445 /***********************************************************************
446 * KillTimer32 (USER32.354)
448 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
450 TRACE(timer, "%04x %d\n", hwnd, id );
451 return TIMER_KillTimer( hwnd, id, FALSE );
455 /***********************************************************************
456 * KillSystemTimer16 (USER.182)
458 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
460 TRACE(timer, "%04x %d\n", hwnd, id );
461 return TIMER_KillTimer( hwnd, id, TRUE );
465 /***********************************************************************
466 * KillSystemTimer32 (USER32.353)
468 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
470 TRACE(timer, "%04x %d\n", hwnd, id );
471 return TIMER_KillTimer( hwnd, id, TRUE );