Release 970305
[wine/multimedia.git] / windows / timer.c
blob93f856307ebcde008a7e63def452122c125a59e6
1 /*
2 * Timer functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "windows.h"
8 #include "queue.h"
9 #include "winproc.h"
10 #include "stddebug.h"
11 /* #define DEBUG_TIMER */
12 #include "debug.h"
15 typedef struct tagTIMER
17 HWND32 hwnd;
18 HQUEUE16 hq;
19 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
20 UINT32 id;
21 UINT32 timeout;
22 struct tagTIMER *next;
23 DWORD expires; /* Next expiration, or 0 if already expired */
24 HWINDOWPROC proc;
25 } TIMER;
27 #define NB_TIMERS 34
28 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
30 static TIMER TimersArray[NB_TIMERS];
32 static TIMER * pNextTimer = NULL; /* Next timer to expire */
34 /* Duration from 'time' until expiration of the timer */
35 #define EXPIRE_TIME(pTimer,time) \
36 (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
39 /***********************************************************************
40 * TIMER_InsertTimer
42 * Insert the timer at its place in the chain.
44 static void TIMER_InsertTimer( TIMER * pTimer )
46 if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
48 pTimer->next = pNextTimer;
49 pNextTimer = pTimer;
51 else
53 TIMER * ptr = pNextTimer;
54 while (ptr->next && (pTimer->expires >= ptr->next->expires))
55 ptr = ptr->next;
56 pTimer->next = ptr->next;
57 ptr->next = pTimer;
62 /***********************************************************************
63 * TIMER_RemoveTimer
65 * Remove the timer from the chain.
67 static void TIMER_RemoveTimer( TIMER * pTimer )
69 TIMER **ppTimer = &pNextTimer;
71 while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
72 if (*ppTimer) *ppTimer = pTimer->next;
73 pTimer->next = NULL;
74 if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
78 /***********************************************************************
79 * TIMER_ClearTimer
81 * Clear and remove a timer.
83 static void TIMER_ClearTimer( TIMER * pTimer )
85 TIMER_RemoveTimer( pTimer );
86 pTimer->hwnd = 0;
87 pTimer->msg = 0;
88 pTimer->id = 0;
89 pTimer->timeout = 0;
90 WINPROC_FreeProc( pTimer->proc );
94 /***********************************************************************
95 * TIMER_SwitchQueue
97 void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
99 TIMER * pT = pNextTimer;
101 while (pT)
103 if (pT->hq == old) pT->hq = new;
104 pT = pT->next;
109 /***********************************************************************
110 * TIMER_RemoveWindowTimers
112 * Remove all timers for a given window.
114 void TIMER_RemoveWindowTimers( HWND32 hwnd )
116 int i;
117 TIMER *pTimer;
119 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
120 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
121 TIMER_ClearTimer( pTimer );
125 /***********************************************************************
126 * TIMER_RemoveQueueTimers
128 * Remove all timers for a given queue.
130 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
132 int i;
133 TIMER *pTimer;
135 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
136 if ((pTimer->hq == hqueue) && pTimer->timeout)
137 TIMER_ClearTimer( pTimer );
141 /***********************************************************************
142 * TIMER_RestartTimers
144 * Restart an expired timer.
146 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
148 TIMER_RemoveTimer( pTimer );
149 pTimer->expires = curTime + pTimer->timeout;
150 TIMER_InsertTimer( pTimer );
154 /***********************************************************************
155 * TIMER_GetNextExpiration
157 * Return next timer expiration time, or -1 if none.
159 LONG TIMER_GetNextExpiration(void)
161 return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
165 /***********************************************************************
166 * TIMER_ExpireTimers
168 * Mark expired timers and wake the appropriate queues.
170 void TIMER_ExpireTimers(void)
172 TIMER *pTimer = pNextTimer;
173 DWORD curTime = GetTickCount();
175 while (pTimer && !pTimer->expires) /* Skip already expired timers */
176 pTimer = pTimer->next;
177 while (pTimer && (pTimer->expires <= curTime))
179 pTimer->expires = 0;
180 QUEUE_IncTimerCount( pTimer->hq );
181 pTimer = pTimer->next;
186 /***********************************************************************
187 * TIMER_GetTimerMsg
189 * Build a message for an expired timer.
191 BOOL32 TIMER_GetTimerMsg( MSG16 *msg, HWND32 hwnd,
192 HQUEUE16 hQueue, BOOL32 remove )
194 TIMER *pTimer = pNextTimer;
195 DWORD curTime = GetTickCount();
197 if (hwnd) /* Find first timer for this window */
198 while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
199 else /* Find first timer for this queue */
200 while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
202 if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
203 if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
205 dprintf_timer( stddeb, "Timer expired: %04x, %04x, %04x, %08lx\n",
206 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
208 /* Build the message */
209 msg->hwnd = (HWND16)pTimer->hwnd;
210 msg->message = pTimer->msg;
211 msg->wParam = (UINT16)pTimer->id;
212 msg->lParam = (LONG)pTimer->proc;
213 msg->time = curTime;
214 return TRUE;
218 /***********************************************************************
219 * TIMER_SetTimer
221 static UINT32 TIMER_SetTimer( HWND32 hwnd, UINT32 id, UINT32 timeout,
222 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL32 sys )
224 int i;
225 TIMER * pTimer;
227 if (!timeout) return 0;
229 /* Check if there's already a timer with the same hwnd and id */
231 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
232 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
233 (pTimer->timeout != 0))
235 /* Got one: set new values and return */
236 TIMER_RemoveTimer( pTimer );
237 pTimer->timeout = timeout;
238 WINPROC_FreeProc( pTimer->proc );
239 pTimer->proc = (HWINDOWPROC)0;
240 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type );
241 pTimer->expires = GetTickCount() + timeout;
242 TIMER_InsertTimer( pTimer );
243 return id;
246 /* Find a free timer */
248 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
249 if (!pTimer->timeout) break;
251 if (i >= NB_TIMERS) return 0;
252 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
253 if (!hwnd) id = i + 1;
255 /* Add the timer */
257 pTimer->hwnd = hwnd;
258 pTimer->hq = (hwnd) ? GetTaskQueue( GetWindowTask16( hwnd ) )
259 : GetTaskQueue( 0 );
260 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
261 pTimer->id = id;
262 pTimer->timeout = timeout;
263 pTimer->expires = GetTickCount() + timeout;
264 pTimer->proc = (HWINDOWPROC)0;
265 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type );
266 dprintf_timer( stddeb, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
267 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
268 (DWORD)pTimer->proc );
269 TIMER_InsertTimer( pTimer );
270 if (!id) return TRUE;
271 else return id;
275 /***********************************************************************
276 * TIMER_KillTimer
278 static BOOL32 TIMER_KillTimer( HWND32 hwnd, UINT32 id, BOOL32 sys )
280 int i;
281 TIMER * pTimer;
283 /* Find the timer */
285 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
286 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
287 (pTimer->timeout != 0)) break;
288 if (i >= NB_TIMERS) return FALSE;
289 if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
290 if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
291 else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;
293 /* Delete the timer */
295 TIMER_ClearTimer( pTimer );
296 return TRUE;
300 /***********************************************************************
301 * SetTimer16 (USER.10)
303 UINT16 SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout, TIMERPROC16 proc )
305 dprintf_timer( stddeb, "SetTimer16: %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.510)
315 UINT32 SetTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout, TIMERPROC32 proc )
317 dprintf_timer( stddeb, "SetTimer32: %04x %d %d %08lx\n",
318 hwnd, id, timeout, (LONG)proc );
319 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
320 WIN_PROC_32A, FALSE );
324 /***********************************************************************
325 * SetSystemTimer16 (USER.11)
327 UINT16 SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
328 TIMERPROC16 proc )
330 dprintf_timer( stddeb, "SetSystemTimer16: %04x %d %d %08lx\n",
331 hwnd, id, timeout, (LONG)proc );
332 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
333 WIN_PROC_16, TRUE );
337 /***********************************************************************
338 * SetSystemTimer32 (USER32.508)
340 UINT32 SetSystemTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
341 TIMERPROC32 proc )
343 dprintf_timer( stddeb, "SetSystemTimer32: %04x %d %d %08lx\n",
344 hwnd, id, timeout, (LONG)proc );
345 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
346 WIN_PROC_32A, TRUE );
350 /***********************************************************************
351 * KillTimer16 (USER.12)
353 BOOL16 KillTimer16( HWND16 hwnd, UINT16 id )
355 dprintf_timer(stddeb, "KillTimer16: %04x %d\n", hwnd, id );
356 return TIMER_KillTimer( hwnd, id, FALSE );
360 /***********************************************************************
361 * KillTimer32 (USER32.353)
363 BOOL32 KillTimer32( HWND32 hwnd, UINT32 id )
365 dprintf_timer(stddeb, "KillTimer32: %04x %d\n", hwnd, id );
366 return TIMER_KillTimer( hwnd, id, FALSE );
370 /***********************************************************************
371 * KillSystemTimer16 (USER.182)
373 BOOL16 KillSystemTimer16( HWND16 hwnd, UINT16 id )
375 dprintf_timer( stddeb, "KillSystemTimer16: %04x %d\n", hwnd, id );
376 return TIMER_KillTimer( hwnd, id, TRUE );
380 /***********************************************************************
381 * KillSystemTimer32 (USER32.352)
383 BOOL32 KillSystemTimer32( HWND32 hwnd, UINT32 id )
385 dprintf_timer( stddeb, "KillSystemTimer32: %04x %d\n", hwnd, id );
386 return TIMER_KillTimer( hwnd, id, TRUE );