4 * Copyright 1993 Alexandre Julliard
9 #include "wine/winuser16.h"
16 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(timer
)
21 typedef struct tagTIMER
25 UINT16 msg
; /* WM_TIMER or WM_SYSTIMER */
34 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
36 #define SYS_TIMER_RATE 54925
38 static TIMER TimersArray
[NB_TIMERS
];
40 static CRITICAL_SECTION csTimer
= CRITICAL_SECTION_INIT
;
43 /***********************************************************************
46 * Clear and remove a timer.
48 static void TIMER_ClearTimer( TIMER
* pTimer
)
50 if ( pTimer
->hService
!= INVALID_HANDLE_VALUE
)
52 SERVICE_Delete( pTimer
->hService
);
53 pTimer
->hService
= INVALID_HANDLE_VALUE
;
56 if ( pTimer
->expired
)
58 QUEUE_DecTimerCount( pTimer
->hq
);
59 pTimer
->expired
= FALSE
;
66 WINPROC_FreeProc( pTimer
->proc
, WIN_PROC_TIMER
);
70 /***********************************************************************
71 * TIMER_RemoveWindowTimers
73 * Remove all timers for a given window.
75 void TIMER_RemoveWindowTimers( HWND hwnd
)
80 EnterCriticalSection( &csTimer
);
82 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
83 if ((pTimer
->hwnd
== hwnd
) && pTimer
->timeout
)
84 TIMER_ClearTimer( pTimer
);
86 LeaveCriticalSection( &csTimer
);
90 /***********************************************************************
91 * TIMER_RemoveQueueTimers
93 * Remove all timers for a given queue.
95 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue
)
100 EnterCriticalSection( &csTimer
);
102 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
103 if ((pTimer
->hq
== hqueue
) && pTimer
->timeout
)
104 TIMER_ClearTimer( pTimer
);
106 LeaveCriticalSection( &csTimer
);
110 /***********************************************************************
113 static void CALLBACK
TIMER_CheckTimer( ULONG_PTR timer_ptr
)
115 TIMER
*pTimer
= (TIMER
*)timer_ptr
;
116 HQUEUE16 wakeQueue
= 0;
118 EnterCriticalSection( &csTimer
);
120 /* Paranoid check to prevent a race condition ... */
121 if ( !pTimer
->timeout
)
123 LeaveCriticalSection( &csTimer
);
127 if ( !pTimer
->expired
)
129 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
130 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
132 pTimer
->expired
= TRUE
;
133 wakeQueue
= pTimer
->hq
;
136 LeaveCriticalSection( &csTimer
);
138 /* Note: This has to be done outside the csTimer critical section,
139 otherwise we'll get deadlocks. */
142 QUEUE_IncTimerCount( wakeQueue
);
146 /***********************************************************************
149 * Build a message for an expired timer.
151 BOOL
TIMER_GetTimerMsg( MSG
*msg
, HWND hwnd
,
152 HQUEUE16 hQueue
, BOOL remove
)
157 EnterCriticalSection( &csTimer
);
159 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
160 if ( pTimer
->timeout
!= 0 && pTimer
->expired
161 && (hwnd
? (pTimer
->hwnd
== hwnd
) : (pTimer
->hq
== hQueue
)) )
164 if ( i
== NB_TIMERS
)
166 LeaveCriticalSection( &csTimer
);
167 return FALSE
; /* No timer */
170 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
171 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
174 pTimer
->expired
= FALSE
;
176 /* Build the message */
177 msg
->hwnd
= pTimer
->hwnd
;
178 msg
->message
= pTimer
->msg
;
179 msg
->wParam
= pTimer
->id
;
180 msg
->lParam
= (LONG
)pTimer
->proc
;
181 msg
->time
= GetTickCount();
183 LeaveCriticalSection( &csTimer
);
189 /***********************************************************************
192 static UINT
TIMER_SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
193 WNDPROC16 proc
, WINDOWPROCTYPE type
, BOOL sys
)
199 { /* timeout==0 is a legal argument UB 990821*/
200 WARN("Timeout== 0 not implemented, using timeout=1\n");
203 EnterCriticalSection( &csTimer
);
205 /* Check if there's already a timer with the same hwnd and id */
207 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
208 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
209 (pTimer
->timeout
!= 0))
211 TIMER_ClearTimer( pTimer
);
215 if ( i
== NB_TIMERS
)
217 /* Find a free timer */
219 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
220 if (!pTimer
->timeout
) break;
222 if ( (i
>= NB_TIMERS
) ||
223 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) )
225 LeaveCriticalSection( &csTimer
);
230 if (!hwnd
) id
= i
+ 1;
235 pTimer
->hq
= (hwnd
) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd
, NULL
) )
237 pTimer
->msg
= sys
? WM_SYSTIMER
: WM_TIMER
;
239 pTimer
->timeout
= timeout
;
240 pTimer
->proc
= (HWINDOWPROC
)0;
241 if (proc
) WINPROC_SetProc( &pTimer
->proc
, proc
, type
, WIN_PROC_TIMER
);
243 pTimer
->expired
= FALSE
;
244 pTimer
->hService
= SERVICE_AddTimer( max( timeout
, (SYS_TIMER_RATE
+500)/1000 ),
245 TIMER_CheckTimer
, (ULONG_PTR
)pTimer
);
247 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
248 pTimer
, pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
,
249 (DWORD
)pTimer
->proc
);
251 LeaveCriticalSection( &csTimer
);
253 if (!id
) return TRUE
;
258 /***********************************************************************
261 static BOOL
TIMER_KillTimer( HWND hwnd
, UINT id
, BOOL sys
)
266 EnterCriticalSection( &csTimer
);
270 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
271 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
272 (pTimer
->timeout
!= 0)) break;
274 if ( (i
>= NB_TIMERS
) ||
275 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) ||
276 (!sys
&& (pTimer
->msg
!= WM_TIMER
)) ||
277 (sys
&& (pTimer
->msg
!= WM_SYSTIMER
)) )
279 LeaveCriticalSection( &csTimer
);
283 /* Delete the timer */
285 TIMER_ClearTimer( pTimer
);
287 LeaveCriticalSection( &csTimer
);
293 /***********************************************************************
294 * SetTimer16 (USER.10)
296 UINT16 WINAPI
SetTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
299 TRACE("%04x %d %d %08lx\n",
300 hwnd
, id
, timeout
, (LONG
)proc
);
301 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
302 WIN_PROC_16
, FALSE
);
306 /***********************************************************************
307 * SetTimer (USER32.511)
309 UINT WINAPI
SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
312 TRACE("%04x %d %d %08lx\n",
313 hwnd
, id
, timeout
, (LONG
)proc
);
314 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
315 WIN_PROC_32A
, FALSE
);
319 /***********************************************************************
320 * SetSystemTimer16 (USER.11)
322 UINT16 WINAPI
SetSystemTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
325 TRACE("%04x %d %d %08lx\n",
326 hwnd
, id
, timeout
, (LONG
)proc
);
327 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
332 /***********************************************************************
333 * SetSystemTimer (USER32.509)
335 UINT WINAPI
SetSystemTimer( HWND hwnd
, UINT id
, UINT timeout
,
338 TRACE("%04x %d %d %08lx\n",
339 hwnd
, id
, timeout
, (LONG
)proc
);
340 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
341 WIN_PROC_32A
, TRUE
);
345 /***********************************************************************
346 * KillTimer16 (USER.12)
348 BOOL16 WINAPI
KillTimer16( HWND16 hwnd
, UINT16 id
)
350 TRACE("%04x %d\n", hwnd
, id
);
351 return TIMER_KillTimer( hwnd
, id
, FALSE
);
355 /***********************************************************************
356 * KillTimer (USER32.354)
358 BOOL WINAPI
KillTimer( HWND hwnd
, UINT id
)
360 TRACE("%04x %d\n", hwnd
, id
);
361 return TIMER_KillTimer( hwnd
, id
, FALSE
);
365 /***********************************************************************
366 * KillSystemTimer16 (USER.182)
368 BOOL16 WINAPI
KillSystemTimer16( HWND16 hwnd
, UINT16 id
)
370 TRACE("%04x %d\n", hwnd
, id
);
371 return TIMER_KillTimer( hwnd
, id
, TRUE
);
375 /***********************************************************************
376 * KillSystemTimer (USER32.353)
378 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT id
)
380 TRACE("%04x %d\n", hwnd
, id
);
381 return TIMER_KillTimer( hwnd
, id
, TRUE
);