[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / caret.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Caret functions
5 * FILE: subsystems/win32/win32k/ntuser/caret.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserCaret);
11
12 /* DEFINES *****************************************************************/
13
14 #define MIN_CARETBLINKRATE 100
15 #define MAX_CARETBLINKRATE 10000
16
17 /* FUNCTIONS *****************************************************************/
18
19 VOID FASTCALL
20 co_IntDrawCaret(PWND pWnd, PTHRDCARETINFO CaretInfo)
21 {
22 HDC hdc, hdcMem;
23 HBITMAP hbmOld;
24 BOOL bDone = FALSE;
25
26 if (pWnd == NULL)
27 {
28 TRACE("Null Window!\n");
29 return;
30 }
31
32 hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE | DCX_WINDOW);
33 if (!hdc)
34 {
35 ERR("GetDC failed\n");
36 return;
37 }
38
39 if (pWnd->hrgnUpdate)
40 {
41 NtGdiSaveDC(hdc);
42 }
43
44 if (CaretInfo->Bitmap)
45 {
46 if (!NtGdiGetBitmapDimension(CaretInfo->Bitmap, &CaretInfo->Size))
47 {
48 ERR("Failed to get bitmap dimensions\n");
49 return;
50 }
51
52 hdcMem = NtGdiCreateCompatibleDC(hdc);
53 if (hdcMem)
54 {
55 hbmOld = NtGdiSelectBitmap(hdcMem, CaretInfo->Bitmap);
56 bDone = NtGdiBitBlt(hdc,
57 CaretInfo->Pos.x,
58 CaretInfo->Pos.y,
59 CaretInfo->Size.cx,
60 CaretInfo->Size.cy,
61 hdcMem,
62 0,
63 0,
64 SRCINVERT,
65 0,
66 0);
67 NtGdiSelectBitmap(hdcMem, hbmOld);
68 GreDeleteObject(hdcMem);
69 }
70 }
71
72 if (!bDone)
73 {
74 NtGdiPatBlt(hdc,
75 CaretInfo->Pos.x,
76 CaretInfo->Pos.y,
77 CaretInfo->Size.cx,
78 CaretInfo->Size.cy,
79 DSTINVERT);
80 }
81
82 if (pWnd->hrgnUpdate)
83 {
84 NtGdiRestoreDC(hdc, -1);
85 }
86
87 UserReleaseDC(pWnd, hdc, FALSE);
88 }
89
90 VOID
91 CALLBACK
92 CaretSystemTimerProc(HWND hwnd,
93 UINT uMsg,
94 UINT_PTR idEvent,
95 DWORD dwTime)
96 {
97 PTHREADINFO pti;
98 PUSER_MESSAGE_QUEUE ThreadQueue;
99 PWND pWnd;
100
101 pti = PsGetCurrentThreadWin32Thread();
102 ThreadQueue = pti->MessageQueue;
103
104 if (ThreadQueue->CaretInfo.hWnd != hwnd)
105 {
106 TRACE("Not the same caret window!\n");
107 return;
108 }
109
110 if (hwnd)
111 {
112 pWnd = UserGetWindowObject(hwnd);
113 if (!pWnd)
114 {
115 ERR("Caret System Timer Proc has invalid window handle! %p Id: %u\n", hwnd, idEvent);
116 return;
117 }
118 }
119 else
120 {
121 TRACE( "Windowless Caret Timer Running!\n" );
122 return;
123 }
124
125 switch (idEvent)
126 {
127 case IDCARETTIMER:
128 {
129 ThreadQueue->CaretInfo.Showing = (ThreadQueue->CaretInfo.Showing ? 0 : 1);
130 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo);
131 }
132 }
133 return;
134 }
135
136 static
137 BOOL FASTCALL
138 co_IntHideCaret(PTHRDCARETINFO CaretInfo)
139 {
140 PWND pWnd;
141 if(CaretInfo->hWnd && CaretInfo->Visible && CaretInfo->Showing)
142 {
143 pWnd = UserGetWindowObject(CaretInfo->hWnd);
144 CaretInfo->Showing = 0;
145
146 co_IntDrawCaret(pWnd, CaretInfo);
147 IntNotifyWinEvent(EVENT_OBJECT_HIDE, pWnd, OBJID_CARET, CHILDID_SELF, 0);
148 return TRUE;
149 }
150 return FALSE;
151 }
152
153 BOOL FASTCALL
154 co_IntDestroyCaret(PTHREADINFO Win32Thread)
155 {
156 PUSER_MESSAGE_QUEUE ThreadQueue;
157 PWND pWnd;
158 ThreadQueue = Win32Thread->MessageQueue;
159
160 if (!ThreadQueue)
161 return FALSE;
162
163 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd);
164 co_IntHideCaret(&ThreadQueue->CaretInfo);
165 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0;
166 ThreadQueue->CaretInfo.hWnd = (HWND)0;
167 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0;
168 ThreadQueue->CaretInfo.Showing = 0;
169 ThreadQueue->CaretInfo.Visible = 0;
170 if (pWnd)
171 {
172 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, pWnd, OBJID_CARET, CHILDID_SELF, 0);
173 }
174 return TRUE;
175 }
176
177 BOOL FASTCALL
178 IntSetCaretBlinkTime(UINT uMSeconds)
179 {
180 /* Don't save the new value to the registry! */
181
182 /* Windows doesn't do this check */
183 if((uMSeconds < MIN_CARETBLINKRATE) || (uMSeconds > MAX_CARETBLINKRATE))
184 {
185 EngSetLastError(ERROR_INVALID_PARAMETER);
186 return FALSE;
187 }
188
189 gpsi->dtCaretBlink = uMSeconds;
190
191 return TRUE;
192 }
193
194 BOOL FASTCALL
195 co_IntSetCaretPos(int X, int Y)
196 {
197 PTHREADINFO pti;
198 PWND pWnd;
199 PUSER_MESSAGE_QUEUE ThreadQueue;
200
201 pti = PsGetCurrentThreadWin32Thread();
202 ThreadQueue = pti->MessageQueue;
203
204 if(ThreadQueue->CaretInfo.hWnd)
205 {
206 pWnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd);
207 if(ThreadQueue->CaretInfo.Pos.x != X || ThreadQueue->CaretInfo.Pos.y != Y)
208 {
209 co_IntHideCaret(&ThreadQueue->CaretInfo);
210 ThreadQueue->CaretInfo.Showing = 1;
211 ThreadQueue->CaretInfo.Pos.x = X;
212 ThreadQueue->CaretInfo.Pos.y = Y;
213 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo);
214
215 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM);
216 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_CARET, CHILDID_SELF, 0);
217 }
218 return TRUE;
219 }
220
221 return FALSE;
222 }
223
224 BOOL FASTCALL co_UserHideCaret(PWND Window OPTIONAL)
225 {
226 PTHREADINFO pti;
227 PUSER_MESSAGE_QUEUE ThreadQueue;
228
229 if (Window) ASSERT_REFS_CO(Window);
230
231 if(Window && Window->head.pti->pEThread != PsGetCurrentThread())
232 {
233 EngSetLastError(ERROR_ACCESS_DENIED);
234 return FALSE;
235 }
236
237 pti = PsGetCurrentThreadWin32Thread();
238 ThreadQueue = pti->MessageQueue;
239
240 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h)
241 {
242 EngSetLastError(ERROR_ACCESS_DENIED);
243 return FALSE;
244 }
245
246 if(ThreadQueue->CaretInfo.Visible)
247 {
248 PWND pwnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd);
249 IntKillTimer(pwnd, IDCARETTIMER, TRUE);
250
251 co_IntHideCaret(&ThreadQueue->CaretInfo);
252 ThreadQueue->CaretInfo.Visible = 0;
253 ThreadQueue->CaretInfo.Showing = 0;
254 }
255
256 return TRUE;
257 }
258
259 BOOL FASTCALL co_UserShowCaret(PWND Window OPTIONAL)
260 {
261 PTHREADINFO pti;
262 PUSER_MESSAGE_QUEUE ThreadQueue;
263 PWND pWnd = NULL;
264
265 if (Window) ASSERT_REFS_CO(Window);
266
267 if(Window && Window->head.pti->pEThread != PsGetCurrentThread())
268 {
269 EngSetLastError(ERROR_ACCESS_DENIED);
270 return FALSE;
271 }
272
273 pti = PsGetCurrentThreadWin32Thread();
274 ThreadQueue = pti->MessageQueue;
275
276 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h)
277 {
278 EngSetLastError(ERROR_ACCESS_DENIED);
279 return FALSE;
280 }
281
282 if (!ThreadQueue->CaretInfo.Visible)
283 {
284 ThreadQueue->CaretInfo.Visible = 1;
285 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd);
286 if (!ThreadQueue->CaretInfo.Showing && pWnd)
287 {
288 IntNotifyWinEvent(EVENT_OBJECT_SHOW, pWnd, OBJID_CARET, OBJID_CARET, 0);
289 }
290 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM);
291 }
292 return TRUE;
293 }
294
295 /* SYSCALLS *****************************************************************/
296
297 BOOL
298 APIENTRY
299 NtUserCreateCaret(
300 HWND hWnd,
301 HBITMAP hBitmap,
302 int nWidth,
303 int nHeight)
304 {
305 PWND Window;
306 PTHREADINFO pti;
307 PUSER_MESSAGE_QUEUE ThreadQueue;
308 DECLARE_RETURN(BOOL);
309
310 TRACE("Enter NtUserCreateCaret\n");
311 UserEnterExclusive();
312
313 if(!(Window = UserGetWindowObject(hWnd)))
314 {
315 RETURN(FALSE);
316 }
317
318 if(Window->head.pti->pEThread != PsGetCurrentThread())
319 {
320 EngSetLastError(ERROR_ACCESS_DENIED);
321 RETURN(FALSE);
322 }
323
324 pti = PsGetCurrentThreadWin32Thread();
325 ThreadQueue = pti->MessageQueue;
326
327 if (ThreadQueue->CaretInfo.Visible)
328 {
329 IntKillTimer(Window, IDCARETTIMER, TRUE);
330 co_IntHideCaret(&ThreadQueue->CaretInfo);
331 }
332
333 ThreadQueue->CaretInfo.hWnd = hWnd;
334 if(hBitmap)
335 {
336 ThreadQueue->CaretInfo.Bitmap = hBitmap;
337 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0;
338 }
339 else
340 {
341 if (nWidth == 0)
342 {
343 nWidth = UserGetSystemMetrics(SM_CXBORDER);
344 }
345 if (nHeight == 0)
346 {
347 nHeight = UserGetSystemMetrics(SM_CYBORDER);
348 }
349 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0;
350 ThreadQueue->CaretInfo.Size.cx = nWidth;
351 ThreadQueue->CaretInfo.Size.cy = nHeight;
352 }
353 ThreadQueue->CaretInfo.Visible = 0;
354 ThreadQueue->CaretInfo.Showing = 0;
355
356 IntSetTimer( Window, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM );
357
358 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_CARET, CHILDID_SELF, 0);
359
360 RETURN(TRUE);
361
362 CLEANUP:
363 TRACE("Leave NtUserCreateCaret, ret=%i\n",_ret_);
364 UserLeave();
365 END_CLEANUP;
366 }
367
368 UINT
369 APIENTRY
370 NtUserGetCaretBlinkTime(VOID)
371 {
372 UINT ret;
373
374 UserEnterShared();
375
376 ret = gpsi->dtCaretBlink;
377
378 UserLeave();
379
380 return ret;
381 }
382
383 BOOL
384 APIENTRY
385 NtUserGetCaretPos(
386 LPPOINT lpPoint)
387 {
388 PTHREADINFO pti;
389 PUSER_MESSAGE_QUEUE ThreadQueue;
390 NTSTATUS Status;
391 DECLARE_RETURN(BOOL);
392
393 TRACE("Enter NtUserGetCaretPos\n");
394 UserEnterShared();
395
396 pti = PsGetCurrentThreadWin32Thread();
397 ThreadQueue = pti->MessageQueue;
398
399 Status = MmCopyToCaller(lpPoint, &ThreadQueue->CaretInfo.Pos, sizeof(POINT));
400 if(!NT_SUCCESS(Status))
401 {
402 SetLastNtError(Status);
403 RETURN(FALSE);
404 }
405
406 RETURN(TRUE);
407
408 CLEANUP:
409 TRACE("Leave NtUserGetCaretPos, ret=%i\n",_ret_);
410 UserLeave();
411 END_CLEANUP;
412 }
413
414 BOOL
415 APIENTRY
416 NtUserShowCaret(HWND hWnd OPTIONAL)
417 {
418 PWND Window = NULL;
419 USER_REFERENCE_ENTRY Ref;
420 DECLARE_RETURN(BOOL);
421 BOOL ret;
422
423 TRACE("Enter NtUserShowCaret\n");
424 UserEnterExclusive();
425
426 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
427 {
428 RETURN(FALSE);
429 }
430
431 if (Window) UserRefObjectCo(Window, &Ref);
432
433 ret = co_UserShowCaret(Window);
434
435 if (Window) UserDerefObjectCo(Window);
436
437 RETURN(ret);
438
439 CLEANUP:
440 TRACE("Leave NtUserShowCaret, ret=%i\n",_ret_);
441 UserLeave();
442 END_CLEANUP;
443 }
444
445 BOOL
446 APIENTRY
447 NtUserHideCaret(HWND hWnd OPTIONAL)
448 {
449 PWND Window = NULL;
450 USER_REFERENCE_ENTRY Ref;
451 DECLARE_RETURN(BOOL);
452 BOOL ret;
453
454 TRACE("Enter NtUserHideCaret\n");
455 UserEnterExclusive();
456
457 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
458 {
459 RETURN(FALSE);
460 }
461
462 if (Window) UserRefObjectCo(Window, &Ref);
463
464 ret = co_UserHideCaret(Window);
465
466 if (Window) UserDerefObjectCo(Window);
467
468 RETURN(ret);
469
470 CLEANUP:
471 TRACE("Leave NtUserHideCaret, ret=%i\n",_ret_);
472 UserLeave();
473 END_CLEANUP;
474 }