2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window timers messages
24 * FILE: subsys/win32k/ntuser/timer.c
26 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
27 * REVISION HISTORY: 10/04/2003 Implemented System Timers
31 /* INCLUDES ******************************************************************/
38 /* GLOBALS *******************************************************************/
40 /* Windows 2000 has room for 32768 window-less timers */
41 #define NUM_WINDOW_LESS_TIMERS 1024
43 static FAST_MUTEX Mutex
;
44 static RTL_BITMAP WindowLessTimersBitMap
;
45 static PVOID WindowLessTimersBitMapBuffer
;
46 static ULONG HintIndex
= 0;
49 #define IntLockWindowlessTimerBitmap() \
50 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Mutex)
52 #define IntUnlockWindowlessTimerBitmap() \
53 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Mutex)
55 /* FUNCTIONS *****************************************************************/
59 IntSetTimer(HWND Wnd
, UINT_PTR IDEvent
, UINT Elapse
, TIMERPROC TimerFunc
, BOOL SystemTimer
)
61 PWINDOW_OBJECT Window
;
63 PUSER_MESSAGE_QUEUE MessageQueue
;
65 DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
66 Wnd
, IDEvent
, Elapse
, TimerFunc
, SystemTimer
? "TRUE" : "FALSE");
68 if ((Wnd
== NULL
) && ! SystemTimer
)
70 DPRINT("Window-less timer\n");
71 /* find a free, window-less timer id */
72 IntLockWindowlessTimerBitmap();
73 IDEvent
= RtlFindClearBitsAndSet(&WindowLessTimersBitMap
, 1, HintIndex
);
75 if (IDEvent
== (UINT_PTR
) -1)
77 IntUnlockWindowlessTimerBitmap();
78 DPRINT1("Unable to find a free window-less timer id\n");
79 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES
);
83 HintIndex
= ++IDEvent
;
84 IntUnlockWindowlessTimerBitmap();
86 MessageQueue
= PsGetWin32Thread()->MessageQueue
;
90 if (!(Window
= UserGetWindowObject(Wnd
)))
92 DPRINT1("Invalid window handle\n");
96 if (Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
98 DPRINT1("Trying to set timer for window in another process (shatter attack?)\n");
99 SetLastWin32Error(ERROR_ACCESS_DENIED
);
104 MessageQueue
= Window
->MessageQueue
;
110 if (Elapse
> 0x7fffffff)
112 DPRINT("Adjusting uElapse\n");
118 /* Win Server 2003 */
119 if (Elapse
> 0x7fffffff)
121 DPRINT("Adjusting uElapse\n");
130 DPRINT("Adjusting uElapse\n");
134 if (! MsqSetTimer(MessageQueue
, Wnd
,
135 IDEvent
, Elapse
, TimerFunc
,
136 SystemTimer
? WM_SYSTIMER
: WM_TIMER
))
138 DPRINT1("Failed to set timer in message queue\n");
139 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES
);
149 IntKillTimer(HWND Wnd
, UINT_PTR IDEvent
, BOOL SystemTimer
)
151 DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
152 Wnd
, IDEvent
, SystemTimer
? "TRUE" : "FALSE");
154 if (! MsqKillTimer(PsGetWin32Thread()->MessageQueue
, Wnd
,
155 IDEvent
, SystemTimer
? WM_SYSTIMER
: WM_TIMER
))
157 DPRINT1("Unable to locate timer in message queue\n");
158 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
162 /* window-less timer? */
163 if ((Wnd
== NULL
) && ! SystemTimer
)
166 IntLockWindowlessTimerBitmap();
168 ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap
, IDEvent
- 1, 1));
169 RtlClearBits(&WindowLessTimersBitMap
, IDEvent
- 1, 1);
171 IntUnlockWindowlessTimerBitmap();
182 ExInitializeFastMutex(&Mutex
);
184 BitmapBytes
= ROUND_UP(NUM_WINDOW_LESS_TIMERS
, sizeof(ULONG
) * 8) / 8;
185 WindowLessTimersBitMapBuffer
= ExAllocatePoolWithTag(PagedPool
, BitmapBytes
, TAG_TIMERBMP
);
186 if (WindowLessTimersBitMapBuffer
== NULL
)
188 return STATUS_UNSUCCESSFUL
;
191 RtlInitializeBitMap(&WindowLessTimersBitMap
,
192 WindowLessTimersBitMapBuffer
,
195 /* yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory */
196 RtlClearAllBits(&WindowLessTimersBitMap
);
198 return STATUS_SUCCESS
;
209 TIMERPROC lpTimerFunc
212 DECLARE_RETURN(UINT_PTR
);
214 DPRINT("Enter NtUserSetTimer\n");
215 UserEnterExclusive();
217 RETURN(IntSetTimer(hWnd
, nIDEvent
, uElapse
, lpTimerFunc
, FALSE
));
220 DPRINT("Leave NtUserSetTimer, ret=%i\n", _ret_
);
234 DECLARE_RETURN(BOOL
);
236 DPRINT("Enter NtUserKillTimer\n");
237 UserEnterExclusive();
239 RETURN(IntKillTimer(hWnd
, uIDEvent
, FALSE
));
242 DPRINT("Leave NtUserKillTimer, ret=%i\n", _ret_
);
250 NtUserSetSystemTimer(
254 TIMERPROC lpTimerFunc
257 DECLARE_RETURN(UINT_PTR
);
259 DPRINT("Enter NtUserSetSystemTimer\n");
260 UserEnterExclusive();
262 RETURN(IntSetTimer(hWnd
, nIDEvent
, uElapse
, lpTimerFunc
, TRUE
));
265 DPRINT("Leave NtUserSetSystemTimer, ret=%i\n", _ret_
);
273 NtUserKillSystemTimer(
278 DECLARE_RETURN(BOOL
);
280 DPRINT("Enter NtUserKillSystemTimer\n");
281 UserEnterExclusive();
283 RETURN(IntKillTimer(hWnd
, uIDEvent
, TRUE
));
286 DPRINT("Leave NtUserKillSystemTimer, ret=%i\n", _ret_
);