sync to trunk head (37853) (except rbuild changes)
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / caret.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Caret functions
6 * FILE: subsys/win32k/ntuser/caret.c
7 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
8 * REVISION HISTORY:
9 * 10/15/2003 Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <w32k.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* DEFINES *****************************************************************/
20
21 #define MIN_CARETBLINKRATE 100
22 #define MAX_CARETBLINKRATE 10000
23 #define DEFAULT_CARETBLINKRATE 530
24 #define CARET_REGKEY L"\\Registry\\User\\.Default\\Control Panel\\Desktop"
25 #define CARET_VALUENAME L"CursorBlinkRate"
26
27 /* FUNCTIONS *****************************************************************/
28
29 static
30 BOOL FASTCALL
31 co_IntHideCaret(PTHRDCARETINFO CaretInfo)
32 {
33 if(CaretInfo->hWnd && CaretInfo->Visible && CaretInfo->Showing)
34 {
35 co_IntSendMessage(CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
36 CaretInfo->Showing = 0;
37 return TRUE;
38 }
39 return FALSE;
40 }
41
42 BOOL FASTCALL
43 co_IntDestroyCaret(PTHREADINFO Win32Thread)
44 {
45 PUSER_MESSAGE_QUEUE ThreadQueue;
46 ThreadQueue = (PUSER_MESSAGE_QUEUE)Win32Thread->MessageQueue;
47
48 if(!ThreadQueue || !ThreadQueue->CaretInfo)
49 return FALSE;
50
51 co_IntHideCaret(ThreadQueue->CaretInfo);
52 ThreadQueue->CaretInfo->Bitmap = (HBITMAP)0;
53 ThreadQueue->CaretInfo->hWnd = (HWND)0;
54 ThreadQueue->CaretInfo->Size.cx = ThreadQueue->CaretInfo->Size.cy = 0;
55 ThreadQueue->CaretInfo->Showing = 0;
56 ThreadQueue->CaretInfo->Visible = 0;
57 return TRUE;
58 }
59
60 BOOL FASTCALL
61 IntSetCaretBlinkTime(UINT uMSeconds)
62 {
63 /* Don't save the new value to the registry! */
64 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
65 PWINSTATION_OBJECT WinStaObject = pti->Desktop->WindowStation;
66
67 /* windows doesn't do this check */
68 if((uMSeconds < MIN_CARETBLINKRATE) || (uMSeconds > MAX_CARETBLINKRATE))
69 {
70 SetLastWin32Error(ERROR_INVALID_PARAMETER);
71 ObDereferenceObject(WinStaObject);
72 return FALSE;
73 }
74
75 WinStaObject->CaretBlinkRate = uMSeconds;
76
77 return TRUE;
78 }
79
80 static
81 UINT FASTCALL
82 IntQueryCaretBlinkRate(VOID)
83 {
84 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(CARET_REGKEY);
85 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(CARET_VALUENAME);
86 NTSTATUS Status;
87 HANDLE KeyHandle = NULL;
88 OBJECT_ATTRIBUTES KeyAttributes;
89 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
90 ULONG Length = 0;
91 ULONG ResLength = 0;
92 ULONG Val = 0;
93
94 InitializeObjectAttributes(&KeyAttributes, &KeyName, OBJ_CASE_INSENSITIVE,
95 NULL, NULL);
96
97 Status = ZwOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
98 if(!NT_SUCCESS(Status))
99 {
100 return 0;
101 }
102
103 Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
104 0, 0, &ResLength);
105 if((Status != STATUS_BUFFER_TOO_SMALL))
106 {
107 NtClose(KeyHandle);
108 return 0;
109 }
110
111 ResLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
112 KeyValuePartialInfo = ExAllocatePoolWithTag(PagedPool, ResLength, TAG_STRING);
113 Length = ResLength;
114
115 if(!KeyValuePartialInfo)
116 {
117 NtClose(KeyHandle);
118 return 0;
119 }
120
121 Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
122 (PVOID)KeyValuePartialInfo, Length, &ResLength);
123 if(!NT_SUCCESS(Status) || (KeyValuePartialInfo->Type != REG_SZ))
124 {
125 NtClose(KeyHandle);
126 ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
127 return 0;
128 }
129
130 ValueName.Length = KeyValuePartialInfo->DataLength;
131 ValueName.MaximumLength = KeyValuePartialInfo->DataLength;
132 ValueName.Buffer = (PWSTR)KeyValuePartialInfo->Data;
133
134 Status = RtlUnicodeStringToInteger(&ValueName, 0, &Val);
135 if(!NT_SUCCESS(Status))
136 {
137 Val = 0;
138 }
139
140 ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
141 NtClose(KeyHandle);
142
143 return (UINT)Val;
144 }
145
146 static
147 UINT FASTCALL
148 IntGetCaretBlinkTime(VOID)
149 {
150 PTHREADINFO pti;
151 PWINSTATION_OBJECT WinStaObject;
152 UINT Ret;
153
154 pti = PsGetCurrentThreadWin32Thread();
155 WinStaObject = pti->Desktop->WindowStation;
156
157 Ret = WinStaObject->CaretBlinkRate;
158 if(!Ret)
159 {
160 /* load it from the registry the first call only! */
161 Ret = WinStaObject->CaretBlinkRate = IntQueryCaretBlinkRate();
162 }
163
164 /* windows doesn't do this check */
165 if((Ret < MIN_CARETBLINKRATE) || (Ret > MAX_CARETBLINKRATE))
166 {
167 Ret = DEFAULT_CARETBLINKRATE;
168 }
169
170 return Ret;
171 }
172
173
174 BOOL FASTCALL
175 co_IntSetCaretPos(int X, int Y)
176 {
177 PTHREADINFO pti;
178 PUSER_MESSAGE_QUEUE ThreadQueue;
179
180 pti = PsGetCurrentThreadWin32Thread();
181 ThreadQueue = pti->MessageQueue;
182
183 if(ThreadQueue->CaretInfo->hWnd)
184 {
185 if(ThreadQueue->CaretInfo->Pos.x != X || ThreadQueue->CaretInfo->Pos.y != Y)
186 {
187 co_IntHideCaret(ThreadQueue->CaretInfo);
188 ThreadQueue->CaretInfo->Showing = 0;
189 ThreadQueue->CaretInfo->Pos.x = X;
190 ThreadQueue->CaretInfo->Pos.y = Y;
191 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
192 IntSetTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TRUE);
193 }
194 return TRUE;
195 }
196
197 return FALSE;
198 }
199
200 BOOL FASTCALL
201 IntSwitchCaretShowing(PVOID Info)
202 {
203 PTHREADINFO pti;
204 PUSER_MESSAGE_QUEUE ThreadQueue;
205
206 pti = PsGetCurrentThreadWin32Thread();
207 ThreadQueue = pti->MessageQueue;
208
209 if(ThreadQueue->CaretInfo->hWnd)
210 {
211 ThreadQueue->CaretInfo->Showing = (ThreadQueue->CaretInfo->Showing ? 0 : 1);
212 MmCopyToCaller(Info, ThreadQueue->CaretInfo, sizeof(THRDCARETINFO));
213 return TRUE;
214 }
215
216 return FALSE;
217 }
218
219 #if 0 //unused
220 static
221 VOID FASTCALL
222 co_IntDrawCaret(HWND hWnd)
223 {
224 PTHREADINFO pti;
225 PUSER_MESSAGE_QUEUE ThreadQueue;
226
227 pti = PsGetCurrentThreadWin32Thread();
228 ThreadQueue = pti->MessageQueue;
229
230 if(ThreadQueue->CaretInfo->hWnd && ThreadQueue->CaretInfo->Visible &&
231 ThreadQueue->CaretInfo->Showing)
232 {
233 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
234 ThreadQueue->CaretInfo->Showing = 1;
235 }
236 }
237 #endif
238
239
240
241 BOOL FASTCALL co_UserHideCaret(PWINDOW_OBJECT Window OPTIONAL)
242 {
243 PTHREADINFO pti;
244 PUSER_MESSAGE_QUEUE ThreadQueue;
245
246 if (Window) ASSERT_REFS_CO(Window);
247
248 if(Window && Window->OwnerThread != PsGetCurrentThread())
249 {
250 SetLastWin32Error(ERROR_ACCESS_DENIED);
251 return FALSE;
252 }
253
254 pti = PsGetCurrentThreadWin32Thread();
255 ThreadQueue = pti->MessageQueue;
256
257 if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
258 {
259 SetLastWin32Error(ERROR_ACCESS_DENIED);
260 return FALSE;
261 }
262
263 if(ThreadQueue->CaretInfo->Visible)
264 {
265 IntKillTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, TRUE);
266
267 co_IntHideCaret(ThreadQueue->CaretInfo);
268 ThreadQueue->CaretInfo->Visible = 0;
269 ThreadQueue->CaretInfo->Showing = 0;
270 }
271
272 return TRUE;
273 }
274
275
276 BOOL FASTCALL co_UserShowCaret(PWINDOW_OBJECT Window OPTIONAL)
277 {
278 PTHREADINFO pti;
279 PUSER_MESSAGE_QUEUE ThreadQueue;
280
281 if (Window) ASSERT_REFS_CO(Window);
282
283 if(Window && Window->OwnerThread != PsGetCurrentThread())
284 {
285 SetLastWin32Error(ERROR_ACCESS_DENIED);
286 return FALSE;
287 }
288
289 pti = PsGetCurrentThreadWin32Thread();
290 ThreadQueue = pti->MessageQueue;
291
292 if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
293 {
294 SetLastWin32Error(ERROR_ACCESS_DENIED);
295 return FALSE;
296 }
297
298 if(!ThreadQueue->CaretInfo->Visible)
299 {
300 ThreadQueue->CaretInfo->Visible = 1;
301 if(!ThreadQueue->CaretInfo->Showing)
302 {
303 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
304 }
305 IntSetTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TRUE);
306 }
307
308 return TRUE;
309 }
310
311
312 /* SYSCALLS *****************************************************************/
313
314 BOOL
315 APIENTRY
316 NtUserCreateCaret(
317 HWND hWnd,
318 HBITMAP hBitmap,
319 int nWidth,
320 int nHeight)
321 {
322 PWINDOW_OBJECT Window;
323 PTHREADINFO pti;
324 PUSER_MESSAGE_QUEUE ThreadQueue;
325 DECLARE_RETURN(BOOL);
326
327 DPRINT("Enter NtUserCreateCaret\n");
328 UserEnterExclusive();
329
330 if(!(Window = UserGetWindowObject(hWnd)))
331 {
332 RETURN(FALSE);
333 }
334
335 if(Window->OwnerThread != PsGetCurrentThread())
336 {
337 SetLastWin32Error(ERROR_ACCESS_DENIED);
338 RETURN(FALSE);
339 }
340
341 pti = PsGetCurrentThreadWin32Thread();
342 ThreadQueue = pti->MessageQueue;
343
344 if (ThreadQueue->CaretInfo->Visible)
345 {
346 IntKillTimer(hWnd, IDCARETTIMER, TRUE);
347 co_IntHideCaret(ThreadQueue->CaretInfo);
348 }
349
350 ThreadQueue->CaretInfo->hWnd = hWnd;
351 if(hBitmap)
352 {
353 ThreadQueue->CaretInfo->Bitmap = hBitmap;
354 ThreadQueue->CaretInfo->Size.cx = ThreadQueue->CaretInfo->Size.cy = 0;
355 }
356 else
357 {
358 ThreadQueue->CaretInfo->Bitmap = (HBITMAP)0;
359 ThreadQueue->CaretInfo->Size.cx = nWidth;
360 ThreadQueue->CaretInfo->Size.cy = nHeight;
361 }
362 ThreadQueue->CaretInfo->Visible = 0;
363 ThreadQueue->CaretInfo->Showing = 0;
364
365 RETURN(TRUE);
366
367 CLEANUP:
368 DPRINT("Leave NtUserCreateCaret, ret=%i\n",_ret_);
369 UserLeave();
370 END_CLEANUP;
371 }
372
373 UINT
374 APIENTRY
375 NtUserGetCaretBlinkTime(VOID)
376 {
377 DECLARE_RETURN(UINT);
378
379 DPRINT("Enter NtUserGetCaretBlinkTime\n");
380 UserEnterShared();
381
382 RETURN(IntGetCaretBlinkTime());
383
384 CLEANUP:
385 DPRINT("Leave NtUserGetCaretBlinkTime, ret=%i\n",_ret_);
386 UserLeave();
387 END_CLEANUP;
388 }
389
390 BOOL
391 APIENTRY
392 NtUserGetCaretPos(
393 LPPOINT lpPoint)
394 {
395 PTHREADINFO pti;
396 PUSER_MESSAGE_QUEUE ThreadQueue;
397 NTSTATUS Status;
398 DECLARE_RETURN(BOOL);
399
400 DPRINT("Enter NtUserGetCaretPos\n");
401 UserEnterShared();
402
403 pti = PsGetCurrentThreadWin32Thread();
404 ThreadQueue = pti->MessageQueue;
405
406 Status = MmCopyToCaller(lpPoint, &(ThreadQueue->CaretInfo->Pos), sizeof(POINT));
407 if(!NT_SUCCESS(Status))
408 {
409 SetLastNtError(Status);
410 RETURN(FALSE);
411 }
412
413 RETURN(TRUE);
414
415 CLEANUP:
416 DPRINT("Leave NtUserGetCaretPos, ret=%i\n",_ret_);
417 UserLeave();
418 END_CLEANUP;
419 }
420
421 BOOL
422 APIENTRY
423 NtUserShowCaret(HWND hWnd OPTIONAL)
424 {
425 PWINDOW_OBJECT Window = NULL;
426 USER_REFERENCE_ENTRY Ref;
427 DECLARE_RETURN(BOOL);
428 BOOL ret;
429
430 DPRINT("Enter NtUserShowCaret\n");
431 UserEnterExclusive();
432
433 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
434 {
435 RETURN(FALSE);
436 }
437
438 if (Window) UserRefObjectCo(Window, &Ref);
439
440 ret = co_UserShowCaret(Window);
441
442 if (Window) UserDerefObjectCo(Window);
443
444 RETURN(ret);
445
446 CLEANUP:
447 DPRINT("Leave NtUserShowCaret, ret=%i\n",_ret_);
448 UserLeave();
449 END_CLEANUP;
450 }
451
452 BOOL
453 APIENTRY
454 NtUserHideCaret(HWND hWnd OPTIONAL)
455 {
456 PWINDOW_OBJECT Window = NULL;
457 USER_REFERENCE_ENTRY Ref;
458 DECLARE_RETURN(BOOL);
459 BOOL ret;
460
461 DPRINT("Enter NtUserHideCaret\n");
462 UserEnterExclusive();
463
464 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
465 {
466 RETURN(FALSE);
467 }
468
469 if (Window) UserRefObjectCo(Window, &Ref);
470
471 ret = co_UserHideCaret(Window);
472
473 if (Window) UserDerefObjectCo(Window);
474
475 RETURN(ret);
476
477 CLEANUP:
478 DPRINT("Leave NtUserHideCaret, ret=%i\n",_ret_);
479 UserLeave();
480 END_CLEANUP;
481 }