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 #define SYS_TIMER_RATE 54925
36 static TIMER TimersArray
[NB_TIMERS
];
38 static CRITICAL_SECTION csTimer
;
41 /***********************************************************************
44 * Initialize critical section for the timer.
46 BOOL
TIMER_Init( void )
48 InitializeCriticalSection( &csTimer
);
49 MakeCriticalSectionGlobal( &csTimer
);
55 /***********************************************************************
58 * Clear and remove a timer.
60 static void TIMER_ClearTimer( TIMER
* pTimer
)
62 if ( pTimer
->hService
!= INVALID_HANDLE_VALUE
)
64 SERVICE_Delete( pTimer
->hService
);
65 pTimer
->hService
= INVALID_HANDLE_VALUE
;
68 if ( pTimer
->expired
)
70 QUEUE_DecTimerCount( pTimer
->hq
);
71 pTimer
->expired
= FALSE
;
78 WINPROC_FreeProc( pTimer
->proc
, WIN_PROC_TIMER
);
82 /***********************************************************************
83 * TIMER_RemoveWindowTimers
85 * Remove all timers for a given window.
87 void TIMER_RemoveWindowTimers( HWND hwnd
)
92 EnterCriticalSection( &csTimer
);
94 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
95 if ((pTimer
->hwnd
== hwnd
) && pTimer
->timeout
)
96 TIMER_ClearTimer( pTimer
);
98 LeaveCriticalSection( &csTimer
);
102 /***********************************************************************
103 * TIMER_RemoveQueueTimers
105 * Remove all timers for a given queue.
107 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue
)
112 EnterCriticalSection( &csTimer
);
114 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
115 if ((pTimer
->hq
== hqueue
) && pTimer
->timeout
)
116 TIMER_ClearTimer( pTimer
);
118 LeaveCriticalSection( &csTimer
);
122 /***********************************************************************
125 static void CALLBACK
TIMER_CheckTimer( ULONG_PTR timer_ptr
)
127 TIMER
*pTimer
= (TIMER
*)timer_ptr
;
128 HQUEUE16 wakeQueue
= 0;
130 EnterCriticalSection( &csTimer
);
132 /* Paranoid check to prevent a race condition ... */
133 if ( !pTimer
->timeout
)
135 LeaveCriticalSection( &csTimer
);
139 if ( !pTimer
->expired
)
141 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
142 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
144 pTimer
->expired
= TRUE
;
145 wakeQueue
= pTimer
->hq
;
148 LeaveCriticalSection( &csTimer
);
150 /* Note: This has to be done outside the csTimer critical section,
151 otherwise we'll get deadlocks. */
154 QUEUE_IncTimerCount( wakeQueue
);
158 /***********************************************************************
161 * Build a message for an expired timer.
163 BOOL
TIMER_GetTimerMsg( MSG
*msg
, HWND hwnd
,
164 HQUEUE16 hQueue
, BOOL remove
)
169 EnterCriticalSection( &csTimer
);
171 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
172 if ( pTimer
->timeout
!= 0 && pTimer
->expired
173 && (hwnd
? (pTimer
->hwnd
== hwnd
) : (pTimer
->hq
== hQueue
)) )
176 if ( i
== NB_TIMERS
)
178 LeaveCriticalSection( &csTimer
);
179 return FALSE
; /* No timer */
182 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
183 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
186 pTimer
->expired
= FALSE
;
188 /* Build the message */
189 msg
->hwnd
= pTimer
->hwnd
;
190 msg
->message
= pTimer
->msg
;
191 msg
->wParam
= pTimer
->id
;
192 msg
->lParam
= (LONG
)pTimer
->proc
;
193 msg
->time
= GetTickCount();
195 LeaveCriticalSection( &csTimer
);
201 /***********************************************************************
204 static UINT
TIMER_SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
205 WNDPROC16 proc
, WINDOWPROCTYPE type
, BOOL sys
)
211 { /* timeout==0 is a legal argument UB 990821*/
212 WARN("Timeout== 0 not implemented, using timeout=1\n");
215 EnterCriticalSection( &csTimer
);
217 /* Check if there's already a timer with the same hwnd and id */
219 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
220 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
221 (pTimer
->timeout
!= 0))
223 TIMER_ClearTimer( pTimer
);
227 if ( i
== NB_TIMERS
)
229 /* Find a free timer */
231 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
232 if (!pTimer
->timeout
) break;
234 if ( (i
>= NB_TIMERS
) ||
235 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) )
237 LeaveCriticalSection( &csTimer
);
242 if (!hwnd
) id
= i
+ 1;
247 pTimer
->hq
= (hwnd
) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd
, NULL
) )
249 pTimer
->msg
= sys
? WM_SYSTIMER
: WM_TIMER
;
251 pTimer
->timeout
= timeout
;
252 pTimer
->proc
= (HWINDOWPROC
)0;
253 if (proc
) WINPROC_SetProc( &pTimer
->proc
, proc
, type
, WIN_PROC_TIMER
);
255 pTimer
->expired
= FALSE
;
256 pTimer
->hService
= SERVICE_AddTimer( MAX( timeout
* 1000L, SYS_TIMER_RATE
),
257 TIMER_CheckTimer
, (ULONG_PTR
)pTimer
);
259 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
260 pTimer
, pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
,
261 (DWORD
)pTimer
->proc
);
263 LeaveCriticalSection( &csTimer
);
265 if (!id
) return TRUE
;
270 /***********************************************************************
273 static BOOL
TIMER_KillTimer( HWND hwnd
, UINT id
, BOOL sys
)
278 EnterCriticalSection( &csTimer
);
282 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
283 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
284 (pTimer
->timeout
!= 0)) break;
286 if ( (i
>= NB_TIMERS
) ||
287 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) ||
288 (!sys
&& (pTimer
->msg
!= WM_TIMER
)) ||
289 (sys
&& (pTimer
->msg
!= WM_SYSTIMER
)) )
291 LeaveCriticalSection( &csTimer
);
295 /* Delete the timer */
297 TIMER_ClearTimer( pTimer
);
299 LeaveCriticalSection( &csTimer
);
305 /***********************************************************************
306 * SetTimer16 (USER.10)
308 UINT16 WINAPI
SetTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
311 TRACE("%04x %d %d %08lx\n",
312 hwnd
, id
, timeout
, (LONG
)proc
);
313 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
314 WIN_PROC_16
, FALSE
);
318 /***********************************************************************
319 * SetTimer32 (USER32.511)
321 UINT WINAPI
SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
324 TRACE("%04x %d %d %08lx\n",
325 hwnd
, id
, timeout
, (LONG
)proc
);
326 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
327 WIN_PROC_32A
, FALSE
);
331 /***********************************************************************
332 * SetSystemTimer16 (USER.11)
334 UINT16 WINAPI
SetSystemTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
337 TRACE("%04x %d %d %08lx\n",
338 hwnd
, id
, timeout
, (LONG
)proc
);
339 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
344 /***********************************************************************
345 * SetSystemTimer32 (USER32.509)
347 UINT WINAPI
SetSystemTimer( HWND hwnd
, UINT id
, UINT timeout
,
350 TRACE("%04x %d %d %08lx\n",
351 hwnd
, id
, timeout
, (LONG
)proc
);
352 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
353 WIN_PROC_32A
, TRUE
);
357 /***********************************************************************
358 * KillTimer16 (USER.12)
360 BOOL16 WINAPI
KillTimer16( HWND16 hwnd
, UINT16 id
)
362 TRACE("%04x %d\n", hwnd
, id
);
363 return TIMER_KillTimer( hwnd
, id
, FALSE
);
367 /***********************************************************************
368 * KillTimer32 (USER32.354)
370 BOOL WINAPI
KillTimer( HWND hwnd
, UINT id
)
372 TRACE("%04x %d\n", hwnd
, id
);
373 return TIMER_KillTimer( hwnd
, id
, FALSE
);
377 /***********************************************************************
378 * KillSystemTimer16 (USER.182)
380 BOOL16 WINAPI
KillSystemTimer16( HWND16 hwnd
, UINT16 id
)
382 TRACE("%04x %d\n", hwnd
, id
);
383 return TIMER_KillTimer( hwnd
, id
, TRUE
);
387 /***********************************************************************
388 * KillSystemTimer32 (USER32.353)
390 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT id
)
392 TRACE("%04x %d\n", hwnd
, id
);
393 return TIMER_KillTimer( hwnd
, id
, TRUE
);