blob: 30d4677a8bac38da96c79775ab8e7fd2a6939090 [file] [log] [blame]
Alexandre Julliard401710d1993-09-04 10:09:32 +00001/*
2 * Timer functions
3 *
4 * Copyright 1993 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard401710d1993-09-04 10:09:32 +000019 */
20
Steven Edwardscfcc4492003-11-26 22:29:30 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000024#include <stdarg.h>
25
Jeremy Whited3e22d92000-02-10 19:03:02 +000026#include "windef.h"
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000027#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000028#include "wingdi.h"
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000029#include "wine/winuser16.h"
Marcus Meissner61afa331999-02-22 10:16:00 +000030#include "winuser.h"
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000031#include "winerror.h"
32
Alexandre Julliardca22b331996-07-12 19:02:39 +000033#include "winproc.h"
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000034#include "message.h"
Alexandre Julliardf44bbb82001-09-14 00:24:39 +000035#include "win.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000036#include "wine/server.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000037#include "wine/debug.h"
Alexandre Julliard401710d1993-09-04 10:09:32 +000038
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000039WINE_DEFAULT_DEBUG_CHANNEL(timer);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000040
Alexandre Julliard401710d1993-09-04 10:09:32 +000041
Alexandre Julliard5f721f81994-01-04 20:14:34 +000042typedef struct tagTIMER
Alexandre Julliard401710d1993-09-04 10:09:32 +000043{
Alexandre Julliarda3960291999-02-26 11:11:13 +000044 HWND hwnd;
Alexandre Julliardf871f2d2002-10-23 18:56:34 +000045 DWORD thread;
46 UINT msg; /* WM_TIMER or WM_SYSTIMER */
Alexandre Julliarda3960291999-02-26 11:11:13 +000047 UINT id;
48 UINT timeout;
Alexandre Julliard18d02972002-12-03 23:34:52 +000049 WNDPROC proc;
Alexandre Julliard401710d1993-09-04 10:09:32 +000050} TIMER;
51
52#define NB_TIMERS 34
53#define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
54
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000055#define SYS_TIMER_RATE 55 /* min. timer rate in ms (actually 54.925)*/
Uwe Bonnes23cadd31999-09-04 14:32:27 +000056
Alexandre Julliard401710d1993-09-04 10:09:32 +000057static TIMER TimersArray[NB_TIMERS];
58
Alexandre Julliard19b6a492003-08-12 23:50:54 +000059static CRITICAL_SECTION csTimer;
60static CRITICAL_SECTION_DEBUG critsect_debug =
61{
62 0, 0, &csTimer,
63 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
64 0, 0, { 0, (DWORD)(__FILE__ ": csTimer") }
65};
66static CRITICAL_SECTION csTimer = { &critsect_debug, -1, 0, 0, 0, 0 };
Stephane Lussier35ffc5d1999-03-25 13:23:26 +000067
68
69/***********************************************************************
Alexandre Julliardef702d81996-05-28 18:54:58 +000070 * TIMER_ClearTimer
71 *
72 * Clear and remove a timer.
73 */
74static void TIMER_ClearTimer( TIMER * pTimer )
75{
Alexandre Julliardef702d81996-05-28 18:54:58 +000076 pTimer->hwnd = 0;
77 pTimer->msg = 0;
78 pTimer->id = 0;
79 pTimer->timeout = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000080 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
Alexandre Julliardef702d81996-05-28 18:54:58 +000081}
82
83
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000084/***********************************************************************
Alexandre Julliardef702d81996-05-28 18:54:58 +000085 * TIMER_RemoveWindowTimers
86 *
87 * Remove all timers for a given window.
88 */
Alexandre Julliarda3960291999-02-26 11:11:13 +000089void TIMER_RemoveWindowTimers( HWND hwnd )
Alexandre Julliardef702d81996-05-28 18:54:58 +000090{
91 int i;
92 TIMER *pTimer;
93
Stephane Lussier35ffc5d1999-03-25 13:23:26 +000094 EnterCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +000095
Alexandre Julliardef702d81996-05-28 18:54:58 +000096 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
97 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
98 TIMER_ClearTimer( pTimer );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +000099
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000100 LeaveCriticalSection( &csTimer );
Alexandre Julliardef702d81996-05-28 18:54:58 +0000101}
102
103
104/***********************************************************************
Alexandre Julliardf871f2d2002-10-23 18:56:34 +0000105 * TIMER_RemoveThreadTimers
Alexandre Julliardef702d81996-05-28 18:54:58 +0000106 *
Alexandre Julliardf871f2d2002-10-23 18:56:34 +0000107 * Remove all timers for the current thread.
Alexandre Julliardef702d81996-05-28 18:54:58 +0000108 */
Alexandre Julliardf871f2d2002-10-23 18:56:34 +0000109void TIMER_RemoveThreadTimers(void)
Alexandre Julliardef702d81996-05-28 18:54:58 +0000110{
111 int i;
112 TIMER *pTimer;
113
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000114 EnterCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000115
Alexandre Julliardef702d81996-05-28 18:54:58 +0000116 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
Alexandre Julliardf871f2d2002-10-23 18:56:34 +0000117 if ((pTimer->thread == GetCurrentThreadId()) && pTimer->timeout)
Alexandre Julliardef702d81996-05-28 18:54:58 +0000118 TIMER_ClearTimer( pTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000119
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000120 LeaveCriticalSection( &csTimer );
Alexandre Julliardef702d81996-05-28 18:54:58 +0000121}
122
123
Alexandre Julliard5f721f81994-01-04 20:14:34 +0000124/***********************************************************************
Alexandre Julliard401710d1993-09-04 10:09:32 +0000125 * TIMER_SetTimer
126 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000127static UINT_PTR TIMER_SetTimer( HWND hwnd, UINT_PTR id, UINT timeout,
Alexandre Julliard18d02972002-12-03 23:34:52 +0000128 WNDPROC proc, WINDOWPROCTYPE type, BOOL sys )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000129{
130 int i;
131 TIMER * pTimer;
Alexandre Julliard18d02972002-12-03 23:34:52 +0000132 WNDPROC winproc = 0;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000133
Alexandre Julliard8fd26b92001-10-15 17:56:45 +0000134 if (hwnd && !(hwnd = WIN_IsCurrentThread( hwnd )))
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000135 {
136 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
137 return 0;
138 }
Alexandre Julliard5f721f81994-01-04 20:14:34 +0000139
Uwe Bonnes23cadd31999-09-04 14:32:27 +0000140 if (!timeout)
141 { /* timeout==0 is a legal argument UB 990821*/
142 WARN("Timeout== 0 not implemented, using timeout=1\n");
Vincent Béron9a624912002-05-31 23:06:46 +0000143 timeout=1;
Uwe Bonnes23cadd31999-09-04 14:32:27 +0000144 }
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000145
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000146 EnterCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000147
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000148 /* Check if there's already a timer with the same hwnd and id */
149
Alexandre Julliardaca05781994-10-17 18:12:41 +0000150 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
151 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
152 (pTimer->timeout != 0))
153 {
Ulrich Weiganda9238081999-06-22 19:11:33 +0000154 TIMER_ClearTimer( pTimer );
155 break;
Alexandre Julliardaca05781994-10-17 18:12:41 +0000156 }
Alexandre Julliard940d58c1994-09-16 09:24:37 +0000157
Ulrich Weiganda9238081999-06-22 19:11:33 +0000158 if ( i == NB_TIMERS )
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000159 {
Ulrich Weiganda9238081999-06-22 19:11:33 +0000160 /* Find a free timer */
Vincent Béron9a624912002-05-31 23:06:46 +0000161
Ulrich Weiganda9238081999-06-22 19:11:33 +0000162 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
163 if (!pTimer->timeout) break;
164
165 if ( (i >= NB_TIMERS) ||
166 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
167 {
168 LeaveCriticalSection( &csTimer );
169 return 0;
170 }
171 }
172
Alexandre Julliard401710d1993-09-04 10:09:32 +0000173 if (!hwnd) id = i + 1;
Vincent Béron9a624912002-05-31 23:06:46 +0000174
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000175 if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER );
176
177 SERVER_START_REQ( set_win_timer )
178 {
179 req->win = hwnd;
180 req->msg = sys ? WM_SYSTIMER : WM_TIMER;
181 req->id = id;
182 req->rate = max( timeout, SYS_TIMER_RATE );
183 req->lparam = (unsigned int)winproc;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000184 wine_server_call( req );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000185 }
186 SERVER_END_REQ;
187
Alexandre Julliard401710d1993-09-04 10:09:32 +0000188 /* Add the timer */
189
190 pTimer->hwnd = hwnd;
Alexandre Julliardf871f2d2002-10-23 18:56:34 +0000191 pTimer->thread = GetCurrentThreadId();
Alexandre Julliard401710d1993-09-04 10:09:32 +0000192 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
193 pTimer->id = id;
194 pTimer->timeout = timeout;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000195 pTimer->proc = winproc;
Ulrich Weiganda9238081999-06-22 19:11:33 +0000196
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000197 TRACE("Timer added: %p, %p, %04x, %04x, %p\n",
198 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, pTimer->proc );
Ulrich Weiganda9238081999-06-22 19:11:33 +0000199
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000200 LeaveCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000201
Alexandre Julliardca22b331996-07-12 19:02:39 +0000202 if (!id) return TRUE;
203 else return id;
Alexandre Julliard401710d1993-09-04 10:09:32 +0000204}
205
206
207/***********************************************************************
208 * TIMER_KillTimer
209 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000210static BOOL TIMER_KillTimer( HWND hwnd, UINT_PTR id, BOOL sys )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000211{
212 int i;
213 TIMER * pTimer;
Vincent Béron9a624912002-05-31 23:06:46 +0000214
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000215 SERVER_START_REQ( kill_win_timer )
216 {
217 req->win = hwnd;
218 req->msg = sys ? WM_SYSTIMER : WM_TIMER;
219 req->id = id;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000220 wine_server_call( req );
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000221 }
222 SERVER_END_REQ;
223
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000224 EnterCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000225
Alexandre Julliardef702d81996-05-28 18:54:58 +0000226 /* Find the timer */
Vincent Béron9a624912002-05-31 23:06:46 +0000227
Alexandre Julliard401710d1993-09-04 10:09:32 +0000228 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
229 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
230 (pTimer->timeout != 0)) break;
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000231
232 if ( (i >= NB_TIMERS) ||
233 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
234 (!sys && (pTimer->msg != WM_TIMER)) ||
235 (sys && (pTimer->msg != WM_SYSTIMER)) )
236 {
237 LeaveCriticalSection( &csTimer );
238 return FALSE;
239 }
Alexandre Julliard401710d1993-09-04 10:09:32 +0000240
Alexandre Julliardef702d81996-05-28 18:54:58 +0000241 /* Delete the timer */
Alexandre Julliard401710d1993-09-04 10:09:32 +0000242
Alexandre Julliardef702d81996-05-28 18:54:58 +0000243 TIMER_ClearTimer( pTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000244
Stephane Lussier35ffc5d1999-03-25 13:23:26 +0000245 LeaveCriticalSection( &csTimer );
Vincent Béron9a624912002-05-31 23:06:46 +0000246
Alexandre Julliard401710d1993-09-04 10:09:32 +0000247 return TRUE;
248}
249
250
251/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000252 * SetTimer (USER.10)
Alexandre Julliard401710d1993-09-04 10:09:32 +0000253 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000254UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
255 TIMERPROC16 proc )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000256{
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000257 TRACE("%04x %d %d %08lx\n",
Alexandre Julliardca22b331996-07-12 19:02:39 +0000258 hwnd, id, timeout, (LONG)proc );
Alexandre Julliard18d02972002-12-03 23:34:52 +0000259 return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC)proc,
Alexandre Julliardca22b331996-07-12 19:02:39 +0000260 WIN_PROC_16, FALSE );
Alexandre Julliard401710d1993-09-04 10:09:32 +0000261}
262
263
264/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000265 * SetTimer (USER32.@)
Alexandre Julliard401710d1993-09-04 10:09:32 +0000266 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000267UINT_PTR WINAPI SetTimer( HWND hwnd, UINT_PTR id, UINT timeout,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000268 TIMERPROC proc )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000269{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000270 TRACE("%p %d %d %p\n", hwnd, id, timeout, proc );
Alexandre Julliard18d02972002-12-03 23:34:52 +0000271 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC)proc, WIN_PROC_32A, FALSE );
Alexandre Julliard401710d1993-09-04 10:09:32 +0000272}
273
274
275/***********************************************************************
Stephane Lussier6bac4f22000-09-29 00:56:05 +0000276 * TIMER_IsTimerValid
277 */
Alexandre Julliard18d02972002-12-03 23:34:52 +0000278BOOL TIMER_IsTimerValid( HWND hwnd, UINT_PTR id, WNDPROC proc )
Stephane Lussier6bac4f22000-09-29 00:56:05 +0000279{
280 int i;
281 TIMER *pTimer;
282 BOOL ret = FALSE;
283
Alexandre Julliardf44bbb82001-09-14 00:24:39 +0000284 hwnd = WIN_GetFullHandle( hwnd );
Stephane Lussier6bac4f22000-09-29 00:56:05 +0000285 EnterCriticalSection( &csTimer );
Alexandre Julliardf44bbb82001-09-14 00:24:39 +0000286
Stephane Lussier6bac4f22000-09-29 00:56:05 +0000287 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
Alexandre Julliard18d02972002-12-03 23:34:52 +0000288 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) && (pTimer->proc == proc))
Stephane Lussier6bac4f22000-09-29 00:56:05 +0000289 {
290 ret = TRUE;
291 break;
292 }
293
294 LeaveCriticalSection( &csTimer );
295 return ret;
296}
297
298
299/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000300 * SetSystemTimer (USER.11)
Alexandre Julliard401710d1993-09-04 10:09:32 +0000301 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000302UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
303 TIMERPROC16 proc )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000304{
Vincent Béron9a624912002-05-31 23:06:46 +0000305 TRACE("%04x %d %d %08lx\n",
Alexandre Julliardca22b331996-07-12 19:02:39 +0000306 hwnd, id, timeout, (LONG)proc );
Alexandre Julliard18d02972002-12-03 23:34:52 +0000307 return TIMER_SetTimer( WIN_Handle32(hwnd), id, timeout, (WNDPROC)proc, WIN_PROC_16, TRUE );
Alexandre Julliardca22b331996-07-12 19:02:39 +0000308}
309
310
311/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000312 * SetSystemTimer (USER32.@)
Alexandre Julliardca22b331996-07-12 19:02:39 +0000313 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000314UINT_PTR WINAPI SetSystemTimer( HWND hwnd, UINT_PTR id, UINT timeout,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000315 TIMERPROC proc )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000316{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000317 TRACE("%p %d %d %p\n", hwnd, id, timeout, proc );
Alexandre Julliard18d02972002-12-03 23:34:52 +0000318 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC)proc, WIN_PROC_32A, TRUE );
Alexandre Julliardca22b331996-07-12 19:02:39 +0000319}
320
321
322/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000323 * KillTimer (USER32.@)
Alexandre Julliard401710d1993-09-04 10:09:32 +0000324 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000325BOOL WINAPI KillTimer( HWND hwnd, UINT_PTR id )
Alexandre Julliard401710d1993-09-04 10:09:32 +0000326{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000327 TRACE("%p %d\n", hwnd, id );
Alexandre Julliardca22b331996-07-12 19:02:39 +0000328 return TIMER_KillTimer( hwnd, id, FALSE );
329}
330
331
332/***********************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000333 * KillSystemTimer (USER32.@)
Alexandre Julliardca22b331996-07-12 19:02:39 +0000334 */
Dmitry Timoshkov601a3ab2002-10-31 01:04:39 +0000335BOOL WINAPI KillSystemTimer( HWND hwnd, UINT_PTR id )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000336{
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000337 TRACE("%p %d\n", hwnd, id );
Alexandre Julliard401710d1993-09-04 10:09:32 +0000338 return TIMER_KillTimer( hwnd, id, TRUE );
339}