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
;
43 /***********************************************************************
46 * Initialize critical section for the timer.
48 BOOL
TIMER_Init( void )
50 InitializeCriticalSection( &csTimer
);
51 MakeCriticalSectionGlobal( &csTimer
);
57 /***********************************************************************
60 * Clear and remove a timer.
62 static void TIMER_ClearTimer( TIMER
* pTimer
)
64 if ( pTimer
->hService
!= INVALID_HANDLE_VALUE
)
66 SERVICE_Delete( pTimer
->hService
);
67 pTimer
->hService
= INVALID_HANDLE_VALUE
;
70 if ( pTimer
->expired
)
72 QUEUE_DecTimerCount( pTimer
->hq
);
73 pTimer
->expired
= FALSE
;
80 WINPROC_FreeProc( pTimer
->proc
, WIN_PROC_TIMER
);
84 /***********************************************************************
85 * TIMER_RemoveWindowTimers
87 * Remove all timers for a given window.
89 void TIMER_RemoveWindowTimers( HWND hwnd
)
94 EnterCriticalSection( &csTimer
);
96 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
97 if ((pTimer
->hwnd
== hwnd
) && pTimer
->timeout
)
98 TIMER_ClearTimer( pTimer
);
100 LeaveCriticalSection( &csTimer
);
104 /***********************************************************************
105 * TIMER_RemoveQueueTimers
107 * Remove all timers for a given queue.
109 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue
)
114 EnterCriticalSection( &csTimer
);
116 for (i
= NB_TIMERS
, pTimer
= TimersArray
; i
> 0; i
--, pTimer
++)
117 if ((pTimer
->hq
== hqueue
) && pTimer
->timeout
)
118 TIMER_ClearTimer( pTimer
);
120 LeaveCriticalSection( &csTimer
);
124 /***********************************************************************
127 static void CALLBACK
TIMER_CheckTimer( ULONG_PTR timer_ptr
)
129 TIMER
*pTimer
= (TIMER
*)timer_ptr
;
130 HQUEUE16 wakeQueue
= 0;
132 EnterCriticalSection( &csTimer
);
134 /* Paranoid check to prevent a race condition ... */
135 if ( !pTimer
->timeout
)
137 LeaveCriticalSection( &csTimer
);
141 if ( !pTimer
->expired
)
143 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
144 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
146 pTimer
->expired
= TRUE
;
147 wakeQueue
= pTimer
->hq
;
150 LeaveCriticalSection( &csTimer
);
152 /* Note: This has to be done outside the csTimer critical section,
153 otherwise we'll get deadlocks. */
156 QUEUE_IncTimerCount( wakeQueue
);
160 /***********************************************************************
163 * Build a message for an expired timer.
165 BOOL
TIMER_GetTimerMsg( MSG
*msg
, HWND hwnd
,
166 HQUEUE16 hQueue
, BOOL remove
)
171 EnterCriticalSection( &csTimer
);
173 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
174 if ( pTimer
->timeout
!= 0 && pTimer
->expired
175 && (hwnd
? (pTimer
->hwnd
== hwnd
) : (pTimer
->hq
== hQueue
)) )
178 if ( i
== NB_TIMERS
)
180 LeaveCriticalSection( &csTimer
);
181 return FALSE
; /* No timer */
184 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
185 pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
, (DWORD
)pTimer
->proc
);
188 pTimer
->expired
= FALSE
;
190 /* Build the message */
191 msg
->hwnd
= pTimer
->hwnd
;
192 msg
->message
= pTimer
->msg
;
193 msg
->wParam
= pTimer
->id
;
194 msg
->lParam
= (LONG
)pTimer
->proc
;
195 msg
->time
= GetTickCount();
197 LeaveCriticalSection( &csTimer
);
203 /***********************************************************************
206 static UINT
TIMER_SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
207 WNDPROC16 proc
, WINDOWPROCTYPE type
, BOOL sys
)
213 { /* timeout==0 is a legal argument UB 990821*/
214 WARN("Timeout== 0 not implemented, using timeout=1\n");
217 EnterCriticalSection( &csTimer
);
219 /* Check if there's already a timer with the same hwnd and id */
221 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
222 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
223 (pTimer
->timeout
!= 0))
225 TIMER_ClearTimer( pTimer
);
229 if ( i
== NB_TIMERS
)
231 /* Find a free timer */
233 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
234 if (!pTimer
->timeout
) break;
236 if ( (i
>= NB_TIMERS
) ||
237 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) )
239 LeaveCriticalSection( &csTimer
);
244 if (!hwnd
) id
= i
+ 1;
249 pTimer
->hq
= (hwnd
) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd
, NULL
) )
251 pTimer
->msg
= sys
? WM_SYSTIMER
: WM_TIMER
;
253 pTimer
->timeout
= timeout
;
254 pTimer
->proc
= (HWINDOWPROC
)0;
255 if (proc
) WINPROC_SetProc( &pTimer
->proc
, proc
, type
, WIN_PROC_TIMER
);
257 pTimer
->expired
= FALSE
;
258 pTimer
->hService
= SERVICE_AddTimer( max( timeout
* 1000L, SYS_TIMER_RATE
),
259 TIMER_CheckTimer
, (ULONG_PTR
)pTimer
);
261 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
262 pTimer
, pTimer
->hwnd
, pTimer
->msg
, pTimer
->id
,
263 (DWORD
)pTimer
->proc
);
265 LeaveCriticalSection( &csTimer
);
267 if (!id
) return TRUE
;
272 /***********************************************************************
275 static BOOL
TIMER_KillTimer( HWND hwnd
, UINT id
, BOOL sys
)
280 EnterCriticalSection( &csTimer
);
284 for (i
= 0, pTimer
= TimersArray
; i
< NB_TIMERS
; i
++, pTimer
++)
285 if ((pTimer
->hwnd
== hwnd
) && (pTimer
->id
== id
) &&
286 (pTimer
->timeout
!= 0)) break;
288 if ( (i
>= NB_TIMERS
) ||
289 (!sys
&& (i
>= NB_TIMERS
-NB_RESERVED_TIMERS
)) ||
290 (!sys
&& (pTimer
->msg
!= WM_TIMER
)) ||
291 (sys
&& (pTimer
->msg
!= WM_SYSTIMER
)) )
293 LeaveCriticalSection( &csTimer
);
297 /* Delete the timer */
299 TIMER_ClearTimer( pTimer
);
301 LeaveCriticalSection( &csTimer
);
307 /***********************************************************************
308 * SetTimer16 (USER.10)
310 UINT16 WINAPI
SetTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
313 TRACE("%04x %d %d %08lx\n",
314 hwnd
, id
, timeout
, (LONG
)proc
);
315 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
316 WIN_PROC_16
, FALSE
);
320 /***********************************************************************
321 * SetTimer32 (USER32.511)
323 UINT WINAPI
SetTimer( HWND hwnd
, UINT id
, UINT timeout
,
326 TRACE("%04x %d %d %08lx\n",
327 hwnd
, id
, timeout
, (LONG
)proc
);
328 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
329 WIN_PROC_32A
, FALSE
);
333 /***********************************************************************
334 * SetSystemTimer16 (USER.11)
336 UINT16 WINAPI
SetSystemTimer16( HWND16 hwnd
, UINT16 id
, UINT16 timeout
,
339 TRACE("%04x %d %d %08lx\n",
340 hwnd
, id
, timeout
, (LONG
)proc
);
341 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
346 /***********************************************************************
347 * SetSystemTimer32 (USER32.509)
349 UINT WINAPI
SetSystemTimer( HWND hwnd
, UINT id
, UINT timeout
,
352 TRACE("%04x %d %d %08lx\n",
353 hwnd
, id
, timeout
, (LONG
)proc
);
354 return TIMER_SetTimer( hwnd
, id
, timeout
, (WNDPROC16
)proc
,
355 WIN_PROC_32A
, TRUE
);
359 /***********************************************************************
360 * KillTimer16 (USER.12)
362 BOOL16 WINAPI
KillTimer16( HWND16 hwnd
, UINT16 id
)
364 TRACE("%04x %d\n", hwnd
, id
);
365 return TIMER_KillTimer( hwnd
, id
, FALSE
);
369 /***********************************************************************
370 * KillTimer32 (USER32.354)
372 BOOL WINAPI
KillTimer( HWND hwnd
, UINT id
)
374 TRACE("%04x %d\n", hwnd
, id
);
375 return TIMER_KillTimer( hwnd
, id
, FALSE
);
379 /***********************************************************************
380 * KillSystemTimer16 (USER.182)
382 BOOL16 WINAPI
KillSystemTimer16( HWND16 hwnd
, UINT16 id
)
384 TRACE("%04x %d\n", hwnd
, id
);
385 return TIMER_KillTimer( hwnd
, id
, TRUE
);
389 /***********************************************************************
390 * KillSystemTimer32 (USER32.353)
392 BOOL WINAPI
KillSystemTimer( HWND hwnd
, UINT id
)
394 TRACE("%04x %d\n", hwnd
, id
);
395 return TIMER_KillTimer( hwnd
, id
, TRUE
);