418ddb5323b0bea4ab933a453fd01ad2d015a519
[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
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->rpdesk->rpwinstaParent;
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(UserGetWindowObject(ThreadQueue->CaretInfo->hWnd), IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TMRF_SYSTEM);
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->pti->pEThread != 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->pti->pEThread != 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(UserGetWindowObject(ThreadQueue->CaretInfo->hWnd), IDCARETTIMER, IntGetCaretBlinkTime(), NULL, TMRF_SYSTEM);
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->pti->pEThread != 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 if (nWidth == 0)
359 {
360 nWidth = UserGetSystemMetrics(SM_CXBORDER);
361 }
362 if (nHeight == 0)
363 {
364 nHeight = UserGetSystemMetrics(SM_CYBORDER);
365 }
366 ThreadQueue->CaretInfo->Bitmap = (HBITMAP)0;
367 ThreadQueue->CaretInfo->Size.cx = nWidth;
368 ThreadQueue->CaretInfo->Size.cy = nHeight;
369 }
370 ThreadQueue->CaretInfo->Visible = 0;
371 ThreadQueue->CaretInfo->Showing = 0;
372
373 RETURN(TRUE);
374
375 CLEANUP:
376 DPRINT("Leave NtUserCreateCaret, ret=%i\n",_ret_);
377 UserLeave();
378 END_CLEANUP;
379 }
380
381 UINT
382 APIENTRY
383 NtUserGetCaretBlinkTime(VOID)
384 {
385 DECLARE_RETURN(UINT);
386
387 DPRINT("Enter NtUserGetCaretBlinkTime\n");
388 UserEnterShared();
389
390 RETURN(IntGetCaretBlinkTime());
391
392 CLEANUP:
393 DPRINT("Leave NtUserGetCaretBlinkTime, ret=%i\n",_ret_);
394 UserLeave();
395 END_CLEANUP;
396 }
397
398 BOOL
399 APIENTRY
400 NtUserGetCaretPos(
401 LPPOINT lpPoint)
402 {
403 PTHREADINFO pti;
404 PUSER_MESSAGE_QUEUE ThreadQueue;
405 NTSTATUS Status;
406 DECLARE_RETURN(BOOL);
407
408 DPRINT("Enter NtUserGetCaretPos\n");
409 UserEnterShared();
410
411 pti = PsGetCurrentThreadWin32Thread();
412 ThreadQueue = pti->MessageQueue;
413
414 Status = MmCopyToCaller(lpPoint, &(ThreadQueue->CaretInfo->Pos), sizeof(POINT));
415 if(!NT_SUCCESS(Status))
416 {
417 SetLastNtError(Status);
418 RETURN(FALSE);
419 }
420
421 RETURN(TRUE);
422
423 CLEANUP:
424 DPRINT("Leave NtUserGetCaretPos, ret=%i\n",_ret_);
425 UserLeave();
426 END_CLEANUP;
427 }
428
429 BOOL
430 APIENTRY
431 NtUserShowCaret(HWND hWnd OPTIONAL)
432 {
433 PWINDOW_OBJECT Window = NULL;
434 USER_REFERENCE_ENTRY Ref;
435 DECLARE_RETURN(BOOL);
436 BOOL ret;
437
438 DPRINT("Enter NtUserShowCaret\n");
439 UserEnterExclusive();
440
441 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
442 {
443 RETURN(FALSE);
444 }
445
446 if (Window) UserRefObjectCo(Window, &Ref);
447
448 ret = co_UserShowCaret(Window);
449
450 if (Window) UserDerefObjectCo(Window);
451
452 RETURN(ret);
453
454 CLEANUP:
455 DPRINT("Leave NtUserShowCaret, ret=%i\n",_ret_);
456 UserLeave();
457 END_CLEANUP;
458 }
459
460 BOOL
461 APIENTRY
462 NtUserHideCaret(HWND hWnd OPTIONAL)
463 {
464 PWINDOW_OBJECT Window = NULL;
465 USER_REFERENCE_ENTRY Ref;
466 DECLARE_RETURN(BOOL);
467 BOOL ret;
468
469 DPRINT("Enter NtUserHideCaret\n");
470 UserEnterExclusive();
471
472 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
473 {
474 RETURN(FALSE);
475 }
476
477 if (Window) UserRefObjectCo(Window, &Ref);
478
479 ret = co_UserHideCaret(Window);
480
481 if (Window) UserDerefObjectCo(Window);
482
483 RETURN(ret);
484
485 CLEANUP:
486 DPRINT("Leave NtUserHideCaret, ret=%i\n",_ret_);
487 UserLeave();
488 END_CLEANUP;
489 }