892648ce1b73a545bc3e21b5ab2c3a378f2bfc91
[reactos.git] / reactos / subsys / win32k / ntuser / timer.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id$
20 *
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
25 * PROGRAMER: Gunnar
26 * Thomas Weidenmueller (w3seek@users.sourceforge.net)
27 * REVISION HISTORY: 10/04/2003 Implemented System Timers
28 *
29 */
30
31 /* INCLUDES ******************************************************************/
32
33 #include <w32k.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 /* Windows 2000 has room for 32768 window-less timers */
41 #define NUM_WINDOW_LESS_TIMERS 1024
42
43 static FAST_MUTEX Mutex;
44 static RTL_BITMAP WindowLessTimersBitMap;
45 static PVOID WindowLessTimersBitMapBuffer;
46 static ULONG HintIndex = 0;
47
48
49 #define IntLockWindowlessTimerBitmap() \
50 ExAcquireFastMutex(&Mutex)
51
52 #define IntUnlockWindowlessTimerBitmap() \
53 ExReleaseFastMutex(&Mutex)
54
55 /* FUNCTIONS *****************************************************************/
56
57
58 UINT_PTR FASTCALL
59 IntSetTimer(HWND Wnd, UINT_PTR IDEvent, UINT Elapse, TIMERPROC TimerFunc, BOOL SystemTimer)
60 {
61 PWINDOW_OBJECT Window;
62 UINT_PTR Ret = 0;
63 PUSER_MESSAGE_QUEUE MessageQueue;
64
65 DPRINT("IntSetTimer wnd %x id %p elapse %u timerproc %p systemtimer %s\n",
66 Wnd, IDEvent, Elapse, TimerFunc, SystemTimer ? "TRUE" : "FALSE");
67
68 if ((Wnd == NULL) && ! SystemTimer)
69 {
70 DPRINT("Window-less timer\n");
71 /* find a free, window-less timer id */
72 IntLockWindowlessTimerBitmap();
73 IDEvent = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
74
75 if (IDEvent == (UINT_PTR) -1)
76 {
77 IntUnlockWindowlessTimerBitmap();
78 DPRINT1("Unable to find a free window-less timer id\n");
79 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
80 return 0;
81 }
82
83 HintIndex = ++IDEvent;
84 IntUnlockWindowlessTimerBitmap();
85 Ret = IDEvent;
86 MessageQueue = PsGetWin32Thread()->MessageQueue;
87 }
88 else
89 {
90 if (!(Window = UserGetWindowObject(Wnd)))
91 {
92 DPRINT1("Invalid window handle\n");
93 return 0;
94 }
95
96 if (Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
97 {
98 DPRINT1("Trying to set timer for window in another process (shatter attack?)\n");
99 SetLastWin32Error(ERROR_ACCESS_DENIED);
100 return 0;
101 }
102
103 Ret = IDEvent;
104 MessageQueue = Window->MessageQueue;
105 }
106
107 #if 1
108
109 /* Win NT/2k/XP */
110 if (Elapse > 0x7fffffff)
111 {
112 DPRINT("Adjusting uElapse\n");
113 Elapse = 1;
114 }
115
116 #else
117
118 /* Win Server 2003 */
119 if (Elapse > 0x7fffffff)
120 {
121 DPRINT("Adjusting uElapse\n");
122 Elapse = 0x7fffffff;
123 }
124
125 #endif
126
127 /* Win 2k/XP */
128 if (Elapse < 10)
129 {
130 DPRINT("Adjusting uElapse\n");
131 Elapse = 10;
132 }
133
134 if (! MsqSetTimer(MessageQueue, Wnd,
135 IDEvent, Elapse, TimerFunc,
136 SystemTimer ? WM_SYSTIMER : WM_TIMER))
137 {
138 DPRINT1("Failed to set timer in message queue\n");
139 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
140 return 0;
141 }
142
143
144 return Ret;
145 }
146
147
148 BOOL FASTCALL
149 IntKillTimer(HWND Wnd, UINT_PTR IDEvent, BOOL SystemTimer)
150 {
151 DPRINT("IntKillTimer wnd %x id %p systemtimer %s\n",
152 Wnd, IDEvent, SystemTimer ? "TRUE" : "FALSE");
153
154 if (! MsqKillTimer(PsGetWin32Thread()->MessageQueue, Wnd,
155 IDEvent, SystemTimer ? WM_SYSTIMER : WM_TIMER))
156 {
157 DPRINT1("Unable to locate timer in message queue\n");
158 SetLastWin32Error(ERROR_INVALID_PARAMETER);
159 return FALSE;
160 }
161
162 /* window-less timer? */
163 if ((Wnd == NULL) && ! SystemTimer)
164 {
165 /* Release the id */
166 IntLockWindowlessTimerBitmap();
167
168 ASSERT(RtlAreBitsSet(&WindowLessTimersBitMap, IDEvent - 1, 1));
169 RtlClearBits(&WindowLessTimersBitMap, IDEvent - 1, 1);
170
171 IntUnlockWindowlessTimerBitmap();
172 }
173
174 return TRUE;
175 }
176
177 NTSTATUS FASTCALL
178 InitTimerImpl(VOID)
179 {
180 ULONG BitmapBytes;
181
182 ExInitializeFastMutex(&Mutex);
183
184 BitmapBytes = ROUND_UP(NUM_WINDOW_LESS_TIMERS, sizeof(ULONG) * 8) / 8;
185 WindowLessTimersBitMapBuffer = ExAllocatePoolWithTag(PagedPool, BitmapBytes, TAG_TIMERBMP);
186 RtlInitializeBitMap(&WindowLessTimersBitMap,
187 WindowLessTimersBitMapBuffer,
188 BitmapBytes * 8);
189
190 /* yes we need this, since ExAllocatePool isn't supposed to zero out allocated memory */
191 RtlClearAllBits(&WindowLessTimersBitMap);
192
193 return STATUS_SUCCESS;
194 }
195
196
197 UINT_PTR
198 STDCALL
199 NtUserSetTimer
200 (
201 HWND hWnd,
202 UINT_PTR nIDEvent,
203 UINT uElapse,
204 TIMERPROC lpTimerFunc
205 )
206 {
207 DECLARE_RETURN(UINT_PTR);
208
209 DPRINT("Enter NtUserSetTimer\n");
210 UserEnterExclusive();
211
212 RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, FALSE));
213
214 CLEANUP:
215 DPRINT("Leave NtUserSetTimer, ret=%i\n", _ret_);
216 UserLeave();
217 END_CLEANUP;
218 }
219
220
221 BOOL
222 STDCALL
223 NtUserKillTimer
224 (
225 HWND hWnd,
226 UINT_PTR uIDEvent
227 )
228 {
229 DECLARE_RETURN(BOOL);
230
231 DPRINT("Enter NtUserKillTimer\n");
232 UserEnterExclusive();
233
234 RETURN(IntKillTimer(hWnd, uIDEvent, FALSE));
235
236 CLEANUP:
237 DPRINT("Leave NtUserKillTimer, ret=%i\n", _ret_);
238 UserLeave();
239 END_CLEANUP;
240 }
241
242
243 UINT_PTR
244 STDCALL
245 NtUserSetSystemTimer(
246 HWND hWnd,
247 UINT_PTR nIDEvent,
248 UINT uElapse,
249 TIMERPROC lpTimerFunc
250 )
251 {
252 DECLARE_RETURN(UINT_PTR);
253
254 DPRINT("Enter NtUserSetSystemTimer\n");
255 UserEnterExclusive();
256
257 RETURN(IntSetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc, TRUE));
258
259 CLEANUP:
260 DPRINT("Leave NtUserSetSystemTimer, ret=%i\n", _ret_);
261 UserLeave();
262 END_CLEANUP;
263 }
264
265
266 BOOL
267 STDCALL
268 NtUserKillSystemTimer(
269 HWND hWnd,
270 UINT_PTR uIDEvent
271 )
272 {
273 DECLARE_RETURN(BOOL);
274
275 DPRINT("Enter NtUserKillSystemTimer\n");
276 UserEnterExclusive();
277
278 RETURN(IntKillTimer(hWnd, uIDEvent, TRUE));
279
280 CLEANUP:
281 DPRINT("Leave NtUserKillSystemTimer, ret=%i\n", _ret_);
282 UserLeave();
283 END_CLEANUP;
284 }
285
286 /* EOF */