[Win32k]
[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 <win32k.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->rpdesk->rpwinstaParent;
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 gpsi->dtCaretBlink = uMSeconds;
77
78 return TRUE;
79 }
80
81 static
82 UINT FASTCALL
83 IntQueryCaretBlinkRate(VOID)
84 {
85 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(CARET_REGKEY);
86 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(CARET_VALUENAME);
87 NTSTATUS Status;
88 HANDLE KeyHandle = NULL;
89 OBJECT_ATTRIBUTES KeyAttributes;
90 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
91 ULONG Length = 0;
92 ULONG ResLength = 0;
93 ULONG Val = 0;
94
95 InitializeObjectAttributes(&KeyAttributes, &KeyName, OBJ_CASE_INSENSITIVE,
96 NULL, NULL);
97
98 Status = ZwOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
99 if(!NT_SUCCESS(Status))
100 {
101 return 0;
102 }
103
104 Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
105 0, 0, &ResLength);
106 if((Status != STATUS_BUFFER_TOO_SMALL))
107 {
108 NtClose(KeyHandle);
109 return 0;
110 }
111
112 ResLength += sizeof(KEY_VALUE_PARTIAL_INFORMATION);
113 KeyValuePartialInfo = ExAllocatePoolWithTag(PagedPool, ResLength, TAG_STRING);
114 Length = ResLength;
115
116 if(!KeyValuePartialInfo)
117 {
118 NtClose(KeyHandle);
119 return 0;
120 }
121
122 Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation,
123 (PVOID)KeyValuePartialInfo, Length, &ResLength);
124 if(!NT_SUCCESS(Status) || (KeyValuePartialInfo->Type != REG_SZ))
125 {
126 NtClose(KeyHandle);
127 ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
128 return 0;
129 }
130
131 ValueName.Length = KeyValuePartialInfo->DataLength;
132 ValueName.MaximumLength = KeyValuePartialInfo->DataLength;
133 ValueName.Buffer = (PWSTR)KeyValuePartialInfo->Data;
134
135 Status = RtlUnicodeStringToInteger(&ValueName, 0, &Val);
136 if(!NT_SUCCESS(Status))
137 {
138 Val = 0;
139 }
140
141 ExFreePoolWithTag(KeyValuePartialInfo, TAG_STRING);
142 NtClose(KeyHandle);
143
144 return (UINT)Val;
145 }
146
147 static
148 UINT FASTCALL
149 IntGetCaretBlinkTime(VOID)
150 {
151 PTHREADINFO pti;
152 PWINSTATION_OBJECT WinStaObject;
153 UINT Ret;
154
155 pti = PsGetCurrentThreadWin32Thread();
156 WinStaObject = pti->rpdesk->rpwinstaParent;
157
158 Ret = WinStaObject->CaretBlinkRate;
159 if(!Ret)
160 {
161 /* load it from the registry the first call only! */
162 Ret = WinStaObject->CaretBlinkRate = IntQueryCaretBlinkRate();
163 }
164
165 /* windows doesn't do this check */
166 if((Ret < MIN_CARETBLINKRATE) || (Ret > MAX_CARETBLINKRATE))
167 {
168 Ret = DEFAULT_CARETBLINKRATE;
169 }
170
171 return Ret;
172 }
173
174
175 BOOL FASTCALL
176 co_IntSetCaretPos(int X, int Y)
177 {
178 PTHREADINFO pti;
179 PUSER_MESSAGE_QUEUE ThreadQueue;
180
181 pti = PsGetCurrentThreadWin32Thread();
182 ThreadQueue = pti->MessageQueue;
183
184 if(ThreadQueue->CaretInfo->hWnd)
185 {
186 if(ThreadQueue->CaretInfo->Pos.x != X || ThreadQueue->CaretInfo->Pos.y != Y)
187 {
188 co_IntHideCaret(ThreadQueue->CaretInfo);
189 ThreadQueue->CaretInfo->Showing = 0;
190 ThreadQueue->CaretInfo->Pos.x = X;
191 ThreadQueue->CaretInfo->Pos.y = Y;
192 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
193 IntSetTimer(UserGetWindowObject(ThreadQueue->CaretInfo->hWnd), IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TMRF_SYSTEM);
194 }
195 return TRUE;
196 }
197
198 return FALSE;
199 }
200
201 BOOL FASTCALL
202 IntSwitchCaretShowing(PVOID Info)
203 {
204 PTHREADINFO pti;
205 PUSER_MESSAGE_QUEUE ThreadQueue;
206
207 pti = PsGetCurrentThreadWin32Thread();
208 ThreadQueue = pti->MessageQueue;
209
210 if(ThreadQueue->CaretInfo->hWnd)
211 {
212 ThreadQueue->CaretInfo->Showing = (ThreadQueue->CaretInfo->Showing ? 0 : 1);
213 MmCopyToCaller(Info, ThreadQueue->CaretInfo, sizeof(THRDCARETINFO));
214 return TRUE;
215 }
216
217 return FALSE;
218 }
219
220 #if 0 //unused
221 static
222 VOID FASTCALL
223 co_IntDrawCaret(HWND hWnd)
224 {
225 PTHREADINFO pti;
226 PUSER_MESSAGE_QUEUE ThreadQueue;
227
228 pti = PsGetCurrentThreadWin32Thread();
229 ThreadQueue = pti->MessageQueue;
230
231 if(ThreadQueue->CaretInfo->hWnd && ThreadQueue->CaretInfo->Visible &&
232 ThreadQueue->CaretInfo->Showing)
233 {
234 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
235 ThreadQueue->CaretInfo->Showing = 1;
236 }
237 }
238 #endif
239
240
241
242 BOOL FASTCALL co_UserHideCaret(PWINDOW_OBJECT Window OPTIONAL)
243 {
244 PTHREADINFO pti;
245 PUSER_MESSAGE_QUEUE ThreadQueue;
246
247 if (Window) ASSERT_REFS_CO(Window);
248
249 if(Window && Window->pti->pEThread != PsGetCurrentThread())
250 {
251 SetLastWin32Error(ERROR_ACCESS_DENIED);
252 return FALSE;
253 }
254
255 pti = PsGetCurrentThreadWin32Thread();
256 ThreadQueue = pti->MessageQueue;
257
258 if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
259 {
260 SetLastWin32Error(ERROR_ACCESS_DENIED);
261 return FALSE;
262 }
263
264 if(ThreadQueue->CaretInfo->Visible)
265 {
266 IntKillTimer(ThreadQueue->CaretInfo->hWnd, IDCARETTIMER, TRUE);
267
268 co_IntHideCaret(ThreadQueue->CaretInfo);
269 ThreadQueue->CaretInfo->Visible = 0;
270 ThreadQueue->CaretInfo->Showing = 0;
271 }
272
273 return TRUE;
274 }
275
276
277 BOOL FASTCALL co_UserShowCaret(PWINDOW_OBJECT Window OPTIONAL)
278 {
279 PTHREADINFO pti;
280 PUSER_MESSAGE_QUEUE ThreadQueue;
281
282 if (Window) ASSERT_REFS_CO(Window);
283
284 if(Window && Window->pti->pEThread != PsGetCurrentThread())
285 {
286 SetLastWin32Error(ERROR_ACCESS_DENIED);
287 return FALSE;
288 }
289
290 pti = PsGetCurrentThreadWin32Thread();
291 ThreadQueue = pti->MessageQueue;
292
293 if(Window && ThreadQueue->CaretInfo->hWnd != Window->hSelf)
294 {
295 SetLastWin32Error(ERROR_ACCESS_DENIED);
296 return FALSE;
297 }
298
299 if(!ThreadQueue->CaretInfo->Visible)
300 {
301 ThreadQueue->CaretInfo->Visible = 1;
302 if(!ThreadQueue->CaretInfo->Showing)
303 {
304 co_IntSendMessage(ThreadQueue->CaretInfo->hWnd, WM_SYSTIMER, IDCARETTIMER, 0);
305 }
306 IntSetTimer(UserGetWindowObject(ThreadQueue->CaretInfo->hWnd), IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TMRF_SYSTEM);
307 }
308
309 return TRUE;
310 }
311
312
313 /* SYSCALLS *****************************************************************/
314
315 BOOL
316 APIENTRY
317 NtUserCreateCaret(
318 HWND hWnd,
319 HBITMAP hBitmap,
320 int nWidth,
321 int nHeight)
322 {
323 PWINDOW_OBJECT Window;
324 PTHREADINFO pti;
325 PUSER_MESSAGE_QUEUE ThreadQueue;
326 DECLARE_RETURN(BOOL);
327
328 DPRINT("Enter NtUserCreateCaret\n");
329 UserEnterExclusive();
330
331 if(!(Window = UserGetWindowObject(hWnd)))
332 {
333 RETURN(FALSE);
334 }
335
336 if(Window->pti->pEThread != PsGetCurrentThread())
337 {
338 SetLastWin32Error(ERROR_ACCESS_DENIED);
339 RETURN(FALSE);
340 }
341
342 pti = PsGetCurrentThreadWin32Thread();
343 ThreadQueue = pti->MessageQueue;
344
345 if (ThreadQueue->CaretInfo->Visible)
346 {
347 IntKillTimer(hWnd, IDCARETTIMER, TRUE);
348 co_IntHideCaret(ThreadQueue->CaretInfo);
349 }
350
351 ThreadQueue->CaretInfo->hWnd = hWnd;
352 if(hBitmap)
353 {
354 ThreadQueue->CaretInfo->Bitmap = hBitmap;
355 ThreadQueue->CaretInfo->Size.cx = ThreadQueue->CaretInfo->Size.cy = 0;
356 }
357 else
358 {
359 if (nWidth == 0)
360 {
361 nWidth = UserGetSystemMetrics(SM_CXBORDER);
362 }
363 if (nHeight == 0)
364 {
365 nHeight = UserGetSystemMetrics(SM_CYBORDER);
366 }
367 ThreadQueue->CaretInfo->Bitmap = (HBITMAP)0;
368 ThreadQueue->CaretInfo->Size.cx = nWidth;
369 ThreadQueue->CaretInfo->Size.cy = nHeight;
370 }
371 ThreadQueue->CaretInfo->Visible = 0;
372 ThreadQueue->CaretInfo->Showing = 0;
373
374 RETURN(TRUE);
375
376 CLEANUP:
377 DPRINT("Leave NtUserCreateCaret, ret=%i\n",_ret_);
378 UserLeave();
379 END_CLEANUP;
380 }
381
382 UINT
383 APIENTRY
384 NtUserGetCaretBlinkTime(VOID)
385 {
386 DECLARE_RETURN(UINT);
387
388 DPRINT("Enter NtUserGetCaretBlinkTime\n");
389 UserEnterShared();
390
391 RETURN(IntGetCaretBlinkTime());
392
393 CLEANUP:
394 DPRINT("Leave NtUserGetCaretBlinkTime, ret=%i\n",_ret_);
395 UserLeave();
396 END_CLEANUP;
397 }
398
399 BOOL
400 APIENTRY
401 NtUserGetCaretPos(
402 LPPOINT lpPoint)
403 {
404 PTHREADINFO pti;
405 PUSER_MESSAGE_QUEUE ThreadQueue;
406 NTSTATUS Status;
407 DECLARE_RETURN(BOOL);
408
409 DPRINT("Enter NtUserGetCaretPos\n");
410 UserEnterShared();
411
412 pti = PsGetCurrentThreadWin32Thread();
413 ThreadQueue = pti->MessageQueue;
414
415 Status = MmCopyToCaller(lpPoint, &(ThreadQueue->CaretInfo->Pos), sizeof(POINT));
416 if(!NT_SUCCESS(Status))
417 {
418 SetLastNtError(Status);
419 RETURN(FALSE);
420 }
421
422 RETURN(TRUE);
423
424 CLEANUP:
425 DPRINT("Leave NtUserGetCaretPos, ret=%i\n",_ret_);
426 UserLeave();
427 END_CLEANUP;
428 }
429
430 BOOL
431 APIENTRY
432 NtUserShowCaret(HWND hWnd OPTIONAL)
433 {
434 PWINDOW_OBJECT Window = NULL;
435 USER_REFERENCE_ENTRY Ref;
436 DECLARE_RETURN(BOOL);
437 BOOL ret;
438
439 DPRINT("Enter NtUserShowCaret\n");
440 UserEnterExclusive();
441
442 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
443 {
444 RETURN(FALSE);
445 }
446
447 if (Window) UserRefObjectCo(Window, &Ref);
448
449 ret = co_UserShowCaret(Window);
450
451 if (Window) UserDerefObjectCo(Window);
452
453 RETURN(ret);
454
455 CLEANUP:
456 DPRINT("Leave NtUserShowCaret, ret=%i\n",_ret_);
457 UserLeave();
458 END_CLEANUP;
459 }
460
461 BOOL
462 APIENTRY
463 NtUserHideCaret(HWND hWnd OPTIONAL)
464 {
465 PWINDOW_OBJECT Window = NULL;
466 USER_REFERENCE_ENTRY Ref;
467 DECLARE_RETURN(BOOL);
468 BOOL ret;
469
470 DPRINT("Enter NtUserHideCaret\n");
471 UserEnterExclusive();
472
473 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
474 {
475 RETURN(FALSE);
476 }
477
478 if (Window) UserRefObjectCo(Window, &Ref);
479
480 ret = co_UserHideCaret(Window);
481
482 if (Window) UserDerefObjectCo(Window);
483
484 RETURN(ret);
485
486 CLEANUP:
487 DPRINT("Leave NtUserHideCaret, ret=%i\n",_ret_);
488 UserLeave();
489 END_CLEANUP;
490 }