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