4 * Copyright 1993 Alexandre Julliard
7 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
12 /* #define DEBUG_TIMER */
16 typedef struct tagTIMER
20 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
23 struct tagTIMER *next;
24 DWORD expires; /* Next expiration, or 0 if already expired */
29 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
31 static TIMER TimersArray[NB_TIMERS];
33 static TIMER * pNextTimer = NULL; /* Next timer to expire */
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 * Insert the timer at its place in the chain.
45 static void TIMER_InsertTimer( TIMER * pTimer )
47 if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
49 pTimer->next = pNextTimer;
54 TIMER * ptr = pNextTimer;
55 while (ptr->next && (pTimer->expires >= ptr->next->expires))
57 pTimer->next = ptr->next;
63 /***********************************************************************
66 * Remove the timer from the chain.
68 static void TIMER_RemoveTimer( TIMER * pTimer )
70 TIMER **ppTimer = &pNextTimer;
72 while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
73 if (*ppTimer) *ppTimer = pTimer->next;
75 if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
79 /***********************************************************************
82 * Clear and remove a timer.
84 static void TIMER_ClearTimer( TIMER * pTimer )
86 TIMER_RemoveTimer( pTimer );
91 WINPROC_FreeProc( pTimer->proc );
95 /***********************************************************************
98 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
100 TIMER * pT = pNextTimer;
104 if (pT->hq == old) pT->hq = new;
110 /***********************************************************************
111 * TIMER_RemoveWindowTimers
113 * Remove all timers for a given window.
115 void TIMER_RemoveWindowTimers( HWND32 hwnd )
120 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
121 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
122 TIMER_ClearTimer( pTimer );
126 /***********************************************************************
127 * TIMER_RemoveQueueTimers
129 * Remove all timers for a given queue.
131 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
136 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
137 if ((pTimer->hq == hqueue) && pTimer->timeout)
138 TIMER_ClearTimer( pTimer );
142 /***********************************************************************
143 * TIMER_RestartTimers
145 * Restart an expired timer.
147 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
149 TIMER_RemoveTimer( pTimer );
150 pTimer->expires = curTime + pTimer->timeout;
151 TIMER_InsertTimer( pTimer );
155 /***********************************************************************
156 * TIMER_GetNextExpiration
158 * Return next timer expiration time, or -1 if none.
160 LONG TIMER_GetNextExpiration(void)
162 return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
166 /***********************************************************************
169 * Mark expired timers and wake the appropriate queues.
171 void TIMER_ExpireTimers(void)
173 TIMER *pTimer = pNextTimer;
174 DWORD curTime = GetTickCount();
176 while (pTimer && !pTimer->expires) /* Skip already expired timers */
177 pTimer = pTimer->next;
178 while (pTimer && (pTimer->expires <= curTime))
181 QUEUE_IncTimerCount( pTimer->hq );
182 pTimer = pTimer->next;
187 /***********************************************************************
190 * Build a message for an expired timer.
192 BOOL32 TIMER_GetTimerMsg( MSG16 *msg, HWND32 hwnd,
193 HQUEUE16 hQueue, BOOL32 remove )
195 TIMER *pTimer = pNextTimer;
196 DWORD curTime = GetTickCount();
198 if (hwnd) /* Find first timer for this window */
199 while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
200 else /* Find first timer for this queue */
201 while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
203 if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
204 if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
206 dprintf_timer( stddeb, "Timer expired: %04x, %04x, %04x, %08lx\n",
207 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
209 /* Build the message */
210 msg->hwnd = (HWND16)pTimer->hwnd;
211 msg->message = pTimer->msg;
212 msg->wParam = (UINT16)pTimer->id;
213 msg->lParam = (LONG)pTimer->proc;
219 /***********************************************************************
222 static UINT32 TIMER_SetTimer( HWND32 hwnd, UINT32 id, UINT32 timeout,
223 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL32 sys )
228 if (!timeout) return 0;
230 /* Check if there's already a timer with the same hwnd and id */
232 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
233 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
234 (pTimer->timeout != 0))
236 /* Got one: set new values and return */
237 TIMER_RemoveTimer( pTimer );
238 pTimer->timeout = timeout;
239 WINPROC_FreeProc( pTimer->proc );
240 pTimer->proc = (HWINDOWPROC)0;
241 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type );
242 pTimer->expires = GetTickCount() + timeout;
243 TIMER_InsertTimer( pTimer );
247 /* Find a free timer */
249 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
250 if (!pTimer->timeout) break;
252 if (i >= NB_TIMERS) return 0;
253 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
254 if (!hwnd) id = i + 1;
259 pTimer->hq = (hwnd) ? GetTaskQueue( GetWindowTask16( hwnd ) )
261 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
263 pTimer->timeout = timeout;
264 pTimer->expires = GetTickCount() + timeout;
265 pTimer->proc = (HWINDOWPROC)0;
266 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type );
267 dprintf_timer( stddeb, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
268 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
269 (DWORD)pTimer->proc );
270 TIMER_InsertTimer( pTimer );
271 if (!id) return TRUE;
276 /***********************************************************************
279 static BOOL32 TIMER_KillTimer( HWND32 hwnd, UINT32 id, BOOL32 sys )
286 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
287 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
288 (pTimer->timeout != 0)) break;
289 if (i >= NB_TIMERS) return FALSE;
290 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
291 if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
292 else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;
294 /* Delete the timer */
296 TIMER_ClearTimer( pTimer );
301 /***********************************************************************
302 * SetTimer16 (USER.10)
304 UINT16 SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout, TIMERPROC16 proc )
306 dprintf_timer( stddeb, "SetTimer16: %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.510)
316 UINT32 SetTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout, TIMERPROC32 proc )
318 dprintf_timer( stddeb, "SetTimer32: %04x %d %d %08lx\n",
319 hwnd, id, timeout, (LONG)proc );
320 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
321 WIN_PROC_32A, FALSE );
325 /***********************************************************************
326 * SetSystemTimer16 (USER.11)
328 UINT16 SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
331 dprintf_timer( stddeb, "SetSystemTimer16: %04x %d %d %08lx\n",
332 hwnd, id, timeout, (LONG)proc );
333 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
338 /***********************************************************************
339 * SetSystemTimer32 (USER32.508)
341 UINT32 SetSystemTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
344 dprintf_timer( stddeb, "SetSystemTimer32: %04x %d %d %08lx\n",
345 hwnd, id, timeout, (LONG)proc );
346 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
347 WIN_PROC_32A, TRUE );
351 /***********************************************************************
352 * KillTimer16 (USER.12)
354 BOOL16 KillTimer16( HWND16 hwnd, UINT16 id )
356 dprintf_timer(stddeb, "KillTimer16: %04x %d\n", hwnd, id );
357 return TIMER_KillTimer( hwnd, id, FALSE );
361 /***********************************************************************
362 * KillTimer32 (USER32.353)
364 BOOL32 KillTimer32( HWND32 hwnd, UINT32 id )
366 dprintf_timer(stddeb, "KillTimer32: %04x %d\n", hwnd, id );
367 return TIMER_KillTimer( hwnd, id, FALSE );
371 /***********************************************************************
372 * KillSystemTimer16 (USER.182)
374 BOOL16 KillSystemTimer16( HWND16 hwnd, UINT16 id )
376 dprintf_timer( stddeb, "KillSystemTimer16: %04x %d\n", hwnd, id );
377 return TIMER_KillTimer( hwnd, id, TRUE );
381 /***********************************************************************
382 * KillSystemTimer32 (USER32.352)
384 BOOL32 KillSystemTimer32( HWND32 hwnd, UINT32 id )
386 dprintf_timer( stddeb, "KillSystemTimer32: %04x %d\n", hwnd, id );
387 return TIMER_KillTimer( hwnd, id, TRUE );