4 * Copyright 1993 Alexandre Julliard
9 #include "wine/winuser16.h"
15 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(timer
);
20 typedef struct tagTIMER
24 UINT16 msg
; /* WM_TIMER or WM_SYSTIMER */
33 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
35 #define SYS_TIMER_RATE 54925
37 static TIMER TimersArray
[NB_TIMERS
];
39 static CRITICAL_SECTION csTimer
= CRITICAL_SECTION_INIT
;
42 /***********************************************************************
45 * Clear and remove a timer.
47 static void TIMER_ClearTimer( TIMER
* pTimer
)
49 if ( pTimer
->hService
!= INVALID_HANDLE_VALUE
)
51 SERVICE_Delete( pTimer
->hService
);
52 pTimer
->hService
= INVALID_HANDLE_VALUE
;
55 if ( pTimer
->expired
)
57 QUEUE_DecTimerCount( pTimer
->hq
);
58 pTimer
->expired
= FALSE
;
65 WINPROC_FreeProc( pTimer
->proc
, WIN_PROC_TIMER
);
69 /***********************************************************************
70 * TIMER_RemoveWindowTimers
72 * Remove all timers for a given window.
74 void TIMER_RemoveWindowTimers( HWND hwnd
)
79 EnterCriticalSection( &csTimer
);
81 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
82 if ((pTimer
->hwnd
== hwnd
) && pTimer
->timeout
)
83 TIMER_ClearTimer( pTimer
);
85 LeaveCriticalSection( &csTimer
);
89 /***********************************************************************
90 * TIMER_RemoveQueueTimers
92 * Remove all timers for a given queue.
94 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue
)
99 EnterCriticalSection( &csTimer
);
101 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
102 if ((pTimer
->hq
== hqueue
) && pTimer
->timeout
)
103 TIMER_ClearTimer( pTimer
);
105 LeaveCriticalSection( &csTimer
);
109 /***********************************************************************
112 static void CALLBACK
TIMER_CheckTimer( ULONG_PTR timer_ptr
)
114 TIMER
*pTimer
= (TIMER
*)timer_ptr
;
115 HQUEUE16 wakeQueue
= 0;
117 EnterCriticalSection( &csTimer
);
119 /* Paranoid check to prevent a race condition ... */
120 if ( !pTimer
->timeout
)
122 LeaveCriticalSection( &csTimer
);
126 if ( !pTimer
->expired
)
128 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
129 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
131 pTimer
->expired
= TRUE
;
132 wakeQueue
= pTimer
->hq
;
135 LeaveCriticalSection( &csTimer
);
137 /* Note: This has to be done outside the csTimer critical section,
138 otherwise we'll get deadlocks. */
141 QUEUE_IncTimerCount( wakeQueue
);
145 /***********************************************************************
148 * Build a message for an expired timer.
150 BOOL
TIMER_GetTimerMsg( MSG
*msg
, HWND hwnd
,
151 HQUEUE16 hQueue
, BOOL remove
)
156 EnterCriticalSection( &csTimer
);
158 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
159 if ( pTimer
->timeout
!= 0 && pTimer
->expired
160 && (hwnd
? (pTimer
->hwnd
== hwnd
) : (pTimer
->hq
== hQueue
)) )
163 if ( i
== NB_TIMERS
)
165 LeaveCriticalSection( &csTimer
);
166 return FALSE
; /* No timer */
169 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
170 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
173 pTimer
->expired
= FALSE
;
175 /* Build the message */
176 msg
->hwnd
= pTimer
->hwnd
;
177 msg
->message
= pTimer
->msg
;
178 msg
->wParam
= pTimer
->id
;
179 msg
->lParam
= (LONG
)pTimer
->proc
;
180 msg
->time
= GetTickCount();
182 LeaveCriticalSection( &csTimer
);
188 /***********************************************************************
191 static UINT
TIMER_SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
192 WNDPROC16 proc
, WINDOWPROCTYPE type
, BOOL sys
)
198 { /* timeout==0 is a legal argument UB 990821*/
199 WARN("Timeout== 0 not implemented, using timeout=1\n");
202 EnterCriticalSection( &csTimer
);
204 /* Check if there's already a timer with the same hwnd and id */
206 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
207 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
208 (pTimer
->timeout
!= 0))
210 TIMER_ClearTimer( pTimer
);
214 if ( i
== NB_TIMERS
)
216 /* Find a free timer */
218 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
219 if (!pTimer
->timeout
) break;
221 if ( (i
>= NB_TIMERS
) ||
222 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) )
224 LeaveCriticalSection( &csTimer
);
229 if (!hwnd
) id
= i
+ 1;
234 pTimer
->hq
= (hwnd
) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd
, NULL
) )
236 pTimer
->msg
= sys
? WM_SYSTIMER
: WM_TIMER
;
238 pTimer
->timeout
= timeout
;
239 pTimer
->proc
= (HWINDOWPROC
)0;
240 if (proc
) WINPROC_SetProc( &pTimer
->proc
, proc
, type
, WIN_PROC_TIMER
);
242 pTimer
->expired
= FALSE
;
243 pTimer
->hService
= SERVICE_AddTimer( max( timeout
, (SYS_TIMER_RATE
+500)/1000 ),
244 TIMER_CheckTimer
, (ULONG_PTR
)pTimer
);
246 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
247 pTimer
, pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
,
248 (DWORD
)pTimer
->proc
);
250 LeaveCriticalSection( &csTimer
);
252 if (!id
) return TRUE
;
257 /***********************************************************************
260 static BOOL
TIMER_KillTimer( HWND hwnd
, UINT id
, BOOL sys
)
265 EnterCriticalSection( &csTimer
);
269 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
270 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
271 (pTimer
->timeout
!= 0)) break;
273 if ( (i
>= NB_TIMERS
) ||
274 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) ||
275 (!sys
&& (pTimer
->msg
!= WM_TIMER
)) ||
276 (sys
&& (pTimer
->msg
!= WM_SYSTIMER
)) )
278 LeaveCriticalSection( &csTimer
);
282 /* Delete the timer */
284 TIMER_ClearTimer( pTimer
);
286 LeaveCriticalSection( &csTimer
);
292 /***********************************************************************
295 UINT16 WINAPI
SetTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
298 TRACE("%04x %d %d %08lx\n",
299 hwnd
, id
, timeout
, (LONG
)proc
);
300 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
301 WIN_PROC_16
, FALSE
);
305 /***********************************************************************
306 * SetTimer (USER32.@)
308 UINT WINAPI
SetTimer( HWND hwnd
, UINT id
, UINT 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_32A
, FALSE
);
318 /***********************************************************************
321 BOOL
TIMER_IsTimerValid( HWND hwnd
, UINT id
, HWINDOWPROC hProc
)
327 EnterCriticalSection( &csTimer
);
329 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
330 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
331 (pTimer
->proc
== hProc
))
337 LeaveCriticalSection( &csTimer
);
342 /***********************************************************************
343 * SetSystemTimer (USER.11)
345 UINT16 WINAPI
SetSystemTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
348 TRACE("%04x %d %d %08lx\n",
349 hwnd
, id
, timeout
, (LONG
)proc
);
350 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
355 /***********************************************************************
356 * SetSystemTimer (USER32.@)
358 UINT WINAPI
SetSystemTimer( HWND hwnd
, UINT id
, UINT timeout
,
361 TRACE("%04x %d %d %08lx\n",
362 hwnd
, id
, timeout
, (LONG
)proc
);
363 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
364 WIN_PROC_32A
, TRUE
);
368 /***********************************************************************
369 * KillTimer (USER.12)
371 BOOL16 WINAPI
KillTimer16( HWND16 hwnd
, UINT16 id
)
373 TRACE("%04x %d\n", hwnd
, id
);
374 return TIMER_KillTimer( hwnd
, id
, FALSE
);
378 /***********************************************************************
379 * KillTimer (USER32.@)
381 BOOL WINAPI
KillTimer( HWND hwnd
, UINT id
)
383 TRACE("%04x %d\n", hwnd
, id
);
384 return TIMER_KillTimer( hwnd
, id
, FALSE
);
388 /***********************************************************************
389 * KillSystemTimer (USER.182)
391 BOOL16 WINAPI
KillSystemTimer16( HWND16 hwnd
, UINT16 id
)
393 TRACE("%04x %d\n", hwnd
, id
);
394 return TIMER_KillTimer( hwnd
, id
, TRUE
);
398 /***********************************************************************
399 * KillSystemTimer (USER32.@)
401 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT id
)
403 TRACE("%04x %d\n", hwnd
, id
);
404 return TIMER_KillTimer( hwnd
, id
, TRUE
);