Handle non-hardware X events correctly with native USER
[wine/multimedia.git] / windows / timer.c
blob488b4304d51285599579daa764cf97d98e8cbc40
1 /*
2 * Timer functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "windows.h"
8 #include "queue.h"
9 #include "winproc.h"
10 #include "debug.h"
13 typedef struct tagTIMER
15 HWND32 hwnd;
16 HQUEUE16 hq;
17 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
18 UINT32 id;
19 UINT32 timeout;
20 struct tagTIMER *next;
21 DWORD expires; /* Next expiration, or 0 if already expired */
22 HWINDOWPROC proc;
23 } TIMER;
25 #define NB_TIMERS 34
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 /***********************************************************************
38 * TIMER_InsertTimer
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;
47 pNextTimer = pTimer;
49 else
51 TIMER * ptr = pNextTimer;
52 while (ptr->next && (pTimer->expires >= ptr->next->expires))
53 ptr = ptr->next;
54 pTimer->next = ptr->next;
55 ptr->next = pTimer;
60 /***********************************************************************
61 * TIMER_RemoveTimer
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;
71 pTimer->next = NULL;
72 if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
76 /***********************************************************************
77 * TIMER_ClearTimer
79 * Clear and remove a timer.
81 static void TIMER_ClearTimer( TIMER * pTimer )
83 TIMER_RemoveTimer( pTimer );
84 pTimer->hwnd = 0;
85 pTimer->msg = 0;
86 pTimer->id = 0;
87 pTimer->timeout = 0;
88 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
92 /***********************************************************************
93 * TIMER_SwitchQueue
95 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
97 TIMER * pT = pNextTimer;
99 while (pT)
101 if (pT->hq == old) pT->hq = new;
102 pT = pT->next;
107 /***********************************************************************
108 * TIMER_RemoveWindowTimers
110 * Remove all timers for a given window.
112 void TIMER_RemoveWindowTimers( HWND32 hwnd )
114 int i;
115 TIMER *pTimer;
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 )
130 int i;
131 TIMER *pTimer;
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 /***********************************************************************
164 * TIMER_ExpireTimers
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))
177 pTimer->expires = 0;
178 QUEUE_IncTimerCount( pTimer->hq );
179 pTimer = pTimer->next;
184 /***********************************************************************
185 * TIMER_GetTimerMsg
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;
211 msg->time = curTime;
212 return TRUE;
216 /***********************************************************************
217 * TIMER_SetTimer
219 static UINT32 TIMER_SetTimer( HWND32 hwnd, UINT32 id, UINT32 timeout,
220 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL32 sys )
222 int i;
223 TIMER * pTimer;
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 );
242 return id;
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;
254 /* Add the timer */
256 pTimer->hwnd = hwnd;
257 pTimer->hq = (hwnd) ? GetTaskQueue( GetWindowTask16( hwnd ) )
258 : GetTaskQueue( 0 );
259 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
260 pTimer->id = id;
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;
270 else return id;
274 /***********************************************************************
275 * TIMER_KillTimer
277 static BOOL32 TIMER_KillTimer( HWND32 hwnd, UINT32 id, BOOL32 sys )
279 int i;
280 TIMER * pTimer;
282 /* Find the timer */
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 );
295 return TRUE;
299 /***********************************************************************
300 * SetTimer16 (USER.10)
302 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
303 TIMERPROC16 proc )
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,
316 TIMERPROC32 proc )
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,
329 TIMERPROC16 proc )
331 TRACE(timer, "%04x %d %d %08lx\n",
332 hwnd, id, timeout, (LONG)proc );
333 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
334 WIN_PROC_16, TRUE );
338 /***********************************************************************
339 * SetSystemTimer32 (USER32.509)
341 UINT32 WINAPI SetSystemTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
342 TIMERPROC32 proc )
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 );