4 * Copyright 1993 Alexandre Julliard
7 #include "wine/winuser16.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(timer
)
19 typedef struct tagTIMER
23 UINT16 msg
; /* WM_TIMER or WM_SYSTIMER */
32 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
34 static TIMER TimersArray
[NB_TIMERS
];
36 static CRITICAL_SECTION csTimer
;
39 /***********************************************************************
42 * Initialize critical section for the timer.
44 BOOL
TIMER_Init( void )
46 InitializeCriticalSection( &csTimer
);
47 MakeCriticalSectionGlobal( &csTimer
);
53 /***********************************************************************
56 * Clear and remove a timer.
58 static void TIMER_ClearTimer( TIMER
* pTimer
)
60 if ( pTimer
->hService
!= INVALID_HANDLE_VALUE
)
62 SERVICE_Delete( pTimer
->hService
);
63 pTimer
->hService
= INVALID_HANDLE_VALUE
;
66 if ( pTimer
->expired
)
68 QUEUE_DecTimerCount( pTimer
->hq
);
69 pTimer
->expired
= FALSE
;
76 WINPROC_FreeProc( pTimer
->proc
, WIN_PROC_TIMER
);
80 /***********************************************************************
81 * TIMER_RemoveWindowTimers
83 * Remove all timers for a given window.
85 void TIMER_RemoveWindowTimers( HWND hwnd
)
90 EnterCriticalSection( &csTimer
);
92 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
93 if ((pTimer
->hwnd
== hwnd
) && pTimer
->timeout
)
94 TIMER_ClearTimer( pTimer
);
96 LeaveCriticalSection( &csTimer
);
100 /***********************************************************************
101 * TIMER_RemoveQueueTimers
103 * Remove all timers for a given queue.
105 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue
)
110 EnterCriticalSection( &csTimer
);
112 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
113 if ((pTimer
->hq
== hqueue
) && pTimer
->timeout
)
114 TIMER_ClearTimer( pTimer
);
116 LeaveCriticalSection( &csTimer
);
120 /***********************************************************************
123 static void CALLBACK
TIMER_CheckTimer( ULONG_PTR timer_ptr
)
125 TIMER
*pTimer
= (TIMER
*)timer_ptr
;
126 HQUEUE16 wakeQueue
= 0;
128 EnterCriticalSection( &csTimer
);
130 /* Paranoid check to prevent a race condition ... */
131 if ( !pTimer
->timeout
)
133 LeaveCriticalSection( &csTimer
);
137 if ( !pTimer
->expired
)
139 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
140 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
142 pTimer
->expired
= TRUE
;
143 wakeQueue
= pTimer
->hq
;
146 LeaveCriticalSection( &csTimer
);
148 /* Note: This has to be done outside the csTimer critical section,
149 otherwise we'll get deadlocks. */
152 QUEUE_IncTimerCount( wakeQueue
);
156 /***********************************************************************
159 * Build a message for an expired timer.
161 BOOL
TIMER_GetTimerMsg( MSG
*msg
, HWND hwnd
,
162 HQUEUE16 hQueue
, BOOL remove
)
167 EnterCriticalSection( &csTimer
);
169 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
170 if ( pTimer
->timeout
!= 0 && pTimer
->expired
171 && (hwnd
? (pTimer
->hwnd
== hwnd
) : (pTimer
->hq
== hQueue
)) )
174 if ( i
== NB_TIMERS
)
176 LeaveCriticalSection( &csTimer
);
177 return FALSE
; /* No timer */
180 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
181 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
184 pTimer
->expired
= FALSE
;
186 /* Build the message */
187 msg
->hwnd
= pTimer
->hwnd
;
188 msg
->message
= pTimer
->msg
;
189 msg
->wParam
= pTimer
->id
;
190 msg
->lParam
= (LONG
)pTimer
->proc
;
191 msg
->time
= GetTickCount();
193 LeaveCriticalSection( &csTimer
);
199 /***********************************************************************
202 static UINT
TIMER_SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
203 WNDPROC16 proc
, WINDOWPROCTYPE type
, BOOL sys
)
208 if (!timeout
) return 0;
210 EnterCriticalSection( &csTimer
);
212 /* Check if there's already a timer with the same hwnd and id */
214 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
215 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
216 (pTimer
->timeout
!= 0))
218 TIMER_ClearTimer( pTimer
);
222 if ( i
== NB_TIMERS
)
224 /* Find a free timer */
226 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
227 if (!pTimer
->timeout
) break;
229 if ( (i
>= NB_TIMERS
) ||
230 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) )
232 LeaveCriticalSection( &csTimer
);
237 if (!hwnd
) id
= i
+ 1;
242 pTimer
->hq
= (hwnd
) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd
, NULL
) )
244 pTimer
->msg
= sys
? WM_SYSTIMER
: WM_TIMER
;
246 pTimer
->timeout
= timeout
;
247 pTimer
->proc
= (HWINDOWPROC
)0;
248 if (proc
) WINPROC_SetProc( &pTimer
->proc
, proc
, type
, WIN_PROC_TIMER
);
250 pTimer
->expired
= FALSE
;
251 pTimer
->hService
= SERVICE_AddTimer( timeout
* 1000L,
252 TIMER_CheckTimer
, (ULONG_PTR
)pTimer
);
254 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
255 pTimer
, pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
,
256 (DWORD
)pTimer
->proc
);
258 LeaveCriticalSection( &csTimer
);
260 if (!id
) return TRUE
;
265 /***********************************************************************
268 static BOOL
TIMER_KillTimer( HWND hwnd
, UINT id
, BOOL sys
)
273 EnterCriticalSection( &csTimer
);
277 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
278 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
279 (pTimer
->timeout
!= 0)) break;
281 if ( (i
>= NB_TIMERS
) ||
282 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) ||
283 (!sys
&& (pTimer
->msg
!= WM_TIMER
)) ||
284 (sys
&& (pTimer
->msg
!= WM_SYSTIMER
)) )
286 LeaveCriticalSection( &csTimer
);
290 /* Delete the timer */
292 TIMER_ClearTimer( pTimer
);
294 LeaveCriticalSection( &csTimer
);
300 /***********************************************************************
301 * SetTimer16 (USER.10)
303 UINT16 WINAPI
SetTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
306 TRACE("%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.511)
316 UINT WINAPI
SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
319 TRACE("%04x %d %d %08lx\n",
320 hwnd
, id
, timeout
, (LONG
)proc
);
321 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
322 WIN_PROC_32A
, FALSE
);
326 /***********************************************************************
327 * SetSystemTimer16 (USER.11)
329 UINT16 WINAPI
SetSystemTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
332 TRACE("%04x %d %d %08lx\n",
333 hwnd
, id
, timeout
, (LONG
)proc
);
334 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
339 /***********************************************************************
340 * SetSystemTimer32 (USER32.509)
342 UINT WINAPI
SetSystemTimer( HWND hwnd
, UINT id
, UINT timeout
,
345 TRACE("%04x %d %d %08lx\n",
346 hwnd
, id
, timeout
, (LONG
)proc
);
347 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
348 WIN_PROC_32A
, TRUE
);
352 /***********************************************************************
353 * KillTimer16 (USER.12)
355 BOOL16 WINAPI
KillTimer16( HWND16 hwnd
, UINT16 id
)
357 TRACE("%04x %d\n", hwnd
, id
);
358 return TIMER_KillTimer( hwnd
, id
, FALSE
);
362 /***********************************************************************
363 * KillTimer32 (USER32.354)
365 BOOL WINAPI
KillTimer( HWND hwnd
, UINT id
)
367 TRACE("%04x %d\n", hwnd
, id
);
368 return TIMER_KillTimer( hwnd
, id
, FALSE
);
372 /***********************************************************************
373 * KillSystemTimer16 (USER.182)
375 BOOL16 WINAPI
KillSystemTimer16( HWND16 hwnd
, UINT16 id
)
377 TRACE("%04x %d\n", hwnd
, id
);
378 return TIMER_KillTimer( hwnd
, id
, TRUE
);
382 /***********************************************************************
383 * KillSystemTimer32 (USER32.353)
385 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT id
)
387 TRACE("%04x %d\n", hwnd
, id
);
388 return TIMER_KillTimer( hwnd
, id
, TRUE
);