4 * Copyright 1993 Alexandre Julliard
13 typedef struct tagTIMER
17 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
20 struct tagTIMER *next;
21 DWORD expires; /* Next expiration, or 0 if already expired */
26 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
28 static TIMER TimersArray[NB_TIMERS];
30 static TIMER * pNextTimer = NULL; /* Next timer to expire */
32 /* Duration from 'time' until expiration of the timer */
33 #define EXPIRE_TIME(pTimer,time) \
34 (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
37 /***********************************************************************
40 * Insert the timer at its place in the chain.
42 static void TIMER_InsertTimer( TIMER * pTimer )
44 if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
46 pTimer->next = pNextTimer;
51 TIMER * ptr = pNextTimer;
52 while (ptr->next && (pTimer->expires >= ptr->next->expires))
54 pTimer->next = ptr->next;
60 /***********************************************************************
63 * Remove the timer from the chain.
65 static void TIMER_RemoveTimer( TIMER * pTimer )
67 TIMER **ppTimer = &pNextTimer;
69 while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
70 if (*ppTimer) *ppTimer = pTimer->next;
72 if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
76 /***********************************************************************
79 * Clear and remove a timer.
81 static void TIMER_ClearTimer( TIMER * pTimer )
83 TIMER_RemoveTimer( pTimer );
88 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
92 /***********************************************************************
95 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
97 TIMER * pT = pNextTimer;
101 if (pT->hq == old) pT->hq = new;
107 /***********************************************************************
108 * TIMER_RemoveWindowTimers
110 * Remove all timers for a given window.
112 void TIMER_RemoveWindowTimers( HWND32 hwnd )
117 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
118 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
119 TIMER_ClearTimer( pTimer );
123 /***********************************************************************
124 * TIMER_RemoveQueueTimers
126 * Remove all timers for a given queue.
128 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
133 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
134 if ((pTimer->hq == hqueue) && pTimer->timeout)
135 TIMER_ClearTimer( pTimer );
139 /***********************************************************************
140 * TIMER_RestartTimers
142 * Restart an expired timer.
144 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
146 TIMER_RemoveTimer( pTimer );
147 pTimer->expires = curTime + pTimer->timeout;
148 TIMER_InsertTimer( pTimer );
152 /***********************************************************************
153 * TIMER_GetNextExpiration
155 * Return next timer expiration time, or -1 if none.
157 LONG TIMER_GetNextExpiration(void)
159 return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
163 /***********************************************************************
166 * Mark expired timers and wake the appropriate queues.
168 void TIMER_ExpireTimers(void)
170 TIMER *pTimer = pNextTimer;
171 DWORD curTime = GetTickCount();
173 while (pTimer && !pTimer->expires) /* Skip already expired timers */
174 pTimer = pTimer->next;
175 while (pTimer && (pTimer->expires <= curTime))
178 QUEUE_IncTimerCount( pTimer->hq );
179 pTimer = pTimer->next;
184 /***********************************************************************
187 * Build a message for an expired timer.
189 BOOL32 TIMER_GetTimerMsg( MSG16 *msg, HWND32 hwnd,
190 HQUEUE16 hQueue, BOOL32 remove )
192 TIMER *pTimer = pNextTimer;
193 DWORD curTime = GetTickCount();
195 if (hwnd) /* Find first timer for this window */
196 while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
197 else /* Find first timer for this queue */
198 while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
200 if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
201 if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
203 TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
204 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
206 /* Build the message */
207 msg->hwnd = (HWND16)pTimer->hwnd;
208 msg->message = pTimer->msg;
209 msg->wParam = (UINT16)pTimer->id;
210 msg->lParam = (LONG)pTimer->proc;
216 /***********************************************************************
219 static UINT32 TIMER_SetTimer( HWND32 hwnd, UINT32 id, UINT32 timeout,
220 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL32 sys )
225 if (!timeout) return 0;
227 /* Check if there's already a timer with the same hwnd and id */
229 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
230 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
231 (pTimer->timeout != 0))
233 /* Got one: set new values and return */
234 TIMER_RemoveTimer( pTimer );
235 pTimer->timeout = timeout;
236 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
237 pTimer->proc = (HWINDOWPROC)0;
238 if (proc) WINPROC_SetProc( &pTimer->proc, proc,
239 type, WIN_PROC_TIMER );
240 pTimer->expires = GetTickCount() + timeout;
241 TIMER_InsertTimer( pTimer );
245 /* Find a free timer */
247 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
248 if (!pTimer->timeout) break;
250 if (i >= NB_TIMERS) return 0;
251 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
252 if (!hwnd) id = i + 1;
257 pTimer->hq = (hwnd) ? GetTaskQueue( GetWindowTask16( hwnd ) )
259 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
261 pTimer->timeout = timeout;
262 pTimer->expires = GetTickCount() + timeout;
263 pTimer->proc = (HWINDOWPROC)0;
264 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
265 TRACE(timer, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
266 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
267 (DWORD)pTimer->proc );
268 TIMER_InsertTimer( pTimer );
269 if (!id) return TRUE;
274 /***********************************************************************
277 static BOOL32 TIMER_KillTimer( HWND32 hwnd, UINT32 id, BOOL32 sys )
284 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
285 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
286 (pTimer->timeout != 0)) break;
287 if (i >= NB_TIMERS) return FALSE;
288 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
289 if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
290 else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;
292 /* Delete the timer */
294 TIMER_ClearTimer( pTimer );
299 /***********************************************************************
300 * SetTimer16 (USER.10)
302 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
305 TRACE(timer, "%04x %d %d %08lx\n",
306 hwnd, id, timeout, (LONG)proc );
307 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
308 WIN_PROC_16, FALSE );
312 /***********************************************************************
313 * SetTimer32 (USER32.511)
315 UINT32 WINAPI SetTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
318 TRACE(timer, "%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 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
331 TRACE(timer, "%04x %d %d %08lx\n",
332 hwnd, id, timeout, (LONG)proc );
333 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
338 /***********************************************************************
339 * SetSystemTimer32 (USER32.509)
341 UINT32 WINAPI SetSystemTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
344 TRACE(timer, "%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 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
356 TRACE(timer, "%04x %d\n", hwnd, id );
357 return TIMER_KillTimer( hwnd, id, FALSE );
361 /***********************************************************************
362 * KillTimer32 (USER32.354)
364 BOOL32 WINAPI KillTimer32( HWND32 hwnd, UINT32 id )
366 TRACE(timer, "%04x %d\n", hwnd, id );
367 return TIMER_KillTimer( hwnd, id, FALSE );
371 /***********************************************************************
372 * KillSystemTimer16 (USER.182)
374 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
376 TRACE(timer, "%04x %d\n", hwnd, id );
377 return TIMER_KillTimer( hwnd, id, TRUE );
381 /***********************************************************************
382 * KillSystemTimer32 (USER32.353)
384 BOOL32 WINAPI KillSystemTimer32( HWND32 hwnd, UINT32 id )
386 TRACE(timer, "%04x %d\n", hwnd, id );
387 return TIMER_KillTimer( hwnd, id, TRUE );