[WIN32SS] Don't trigger ProbeForWrite when retrieving caret size from co_IntDrawCaret...
[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: win32ss/user/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 (!GreGetBitmapDimension(CaretInfo->Bitmap, &CaretInfo->Size))
47 {
48 ERR("Failed to get bitmap dimensions\n");
49 goto cleanup;
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 cleanup:
83 if (pWnd->hrgnUpdate)
84 {
85 NtGdiRestoreDC(hdc, -1);
86 }
87
88 UserReleaseDC(pWnd, hdc, FALSE);
89 }
90
91 VOID
92 CALLBACK
93 CaretSystemTimerProc(HWND hwnd,
94 UINT uMsg,
95 UINT_PTR idEvent,
96 DWORD dwTime)
97 {
98 PTHREADINFO pti;
99 PUSER_MESSAGE_QUEUE ThreadQueue;
100 PWND pWnd;
101
102 pti = PsGetCurrentThreadWin32Thread();
103 ThreadQueue = pti->MessageQueue;
104
105 if (ThreadQueue->CaretInfo.hWnd != hwnd)
106 {
107 TRACE("Not the same caret window!\n");
108 return;
109 }
110
111 if (hwnd)
112 {
113 pWnd = UserGetWindowObject(hwnd);
114 if (!pWnd)
115 {
116 ERR("Caret System Timer Proc has invalid window handle! %p Id: %u\n", hwnd, idEvent);
117 return;
118 }
119 }
120 else
121 {
122 TRACE( "Windowless Caret Timer Running!\n" );
123 return;
124 }
125
126 switch (idEvent)
127 {
128 case IDCARETTIMER:
129 {
130 ThreadQueue->CaretInfo.Showing = (ThreadQueue->CaretInfo.Showing ? 0 : 1);
131 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo);
132 }
133 }
134 return;
135 }
136
137 static
138 BOOL FASTCALL
139 co_IntHideCaret(PTHRDCARETINFO CaretInfo)
140 {
141 PWND pWnd;
142 if(CaretInfo->hWnd && CaretInfo->Visible && CaretInfo->Showing)
143 {
144 pWnd = UserGetWindowObject(CaretInfo->hWnd);
145 CaretInfo->Showing = 0;
146
147 co_IntDrawCaret(pWnd, CaretInfo);
148 IntNotifyWinEvent(EVENT_OBJECT_HIDE, pWnd, OBJID_CARET, CHILDID_SELF, 0);
149 return TRUE;
150 }
151 return FALSE;
152 }
153
154 BOOL FASTCALL
155 co_IntDestroyCaret(PTHREADINFO Win32Thread)
156 {
157 PUSER_MESSAGE_QUEUE ThreadQueue;
158 PWND pWnd;
159 ThreadQueue = Win32Thread->MessageQueue;
160
161 if (!ThreadQueue)
162 return FALSE;
163
164 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd);
165 co_IntHideCaret(&ThreadQueue->CaretInfo);
166 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0;
167 ThreadQueue->CaretInfo.hWnd = (HWND)0;
168 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0;
169 ThreadQueue->CaretInfo.Showing = 0;
170 ThreadQueue->CaretInfo.Visible = 0;
171 if (pWnd)
172 {
173 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, pWnd, OBJID_CARET, CHILDID_SELF, 0);
174 }
175 return TRUE;
176 }
177
178 BOOL FASTCALL
179 IntSetCaretBlinkTime(UINT uMSeconds)
180 {
181 /* Don't save the new value to the registry! */
182
183 /* Windows doesn't do this check */
184 if((uMSeconds < MIN_CARETBLINKRATE) || (uMSeconds > MAX_CARETBLINKRATE))
185 {
186 EngSetLastError(ERROR_INVALID_PARAMETER);
187 return FALSE;
188 }
189
190 gpsi->dtCaretBlink = uMSeconds;
191
192 return TRUE;
193 }
194
195 BOOL FASTCALL
196 co_IntSetCaretPos(int X, int Y)
197 {
198 PTHREADINFO pti;
199 PWND pWnd;
200 PUSER_MESSAGE_QUEUE ThreadQueue;
201
202 pti = PsGetCurrentThreadWin32Thread();
203 ThreadQueue = pti->MessageQueue;
204
205 if(ThreadQueue->CaretInfo.hWnd)
206 {
207 pWnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd);
208 if(ThreadQueue->CaretInfo.Pos.x != X || ThreadQueue->CaretInfo.Pos.y != Y)
209 {
210 co_IntHideCaret(&ThreadQueue->CaretInfo);
211 ThreadQueue->CaretInfo.Showing = 1;
212 ThreadQueue->CaretInfo.Pos.x = X;
213 ThreadQueue->CaretInfo.Pos.y = Y;
214 co_IntDrawCaret(pWnd, &ThreadQueue->CaretInfo);
215
216 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM);
217 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_CARET, CHILDID_SELF, 0);
218 }
219 return TRUE;
220 }
221
222 return FALSE;
223 }
224
225 BOOL FASTCALL co_UserHideCaret(PWND Window OPTIONAL)
226 {
227 PTHREADINFO pti;
228 PUSER_MESSAGE_QUEUE ThreadQueue;
229
230 if (Window) ASSERT_REFS_CO(Window);
231
232 if(Window && Window->head.pti->pEThread != PsGetCurrentThread())
233 {
234 EngSetLastError(ERROR_ACCESS_DENIED);
235 return FALSE;
236 }
237
238 pti = PsGetCurrentThreadWin32Thread();
239 ThreadQueue = pti->MessageQueue;
240
241 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h)
242 {
243 EngSetLastError(ERROR_ACCESS_DENIED);
244 return FALSE;
245 }
246
247 if(ThreadQueue->CaretInfo.Visible)
248 {
249 PWND pwnd = UserGetWindowObject(ThreadQueue->CaretInfo.hWnd);
250 IntKillTimer(pwnd, IDCARETTIMER, TRUE);
251
252 co_IntHideCaret(&ThreadQueue->CaretInfo);
253 ThreadQueue->CaretInfo.Visible = 0;
254 ThreadQueue->CaretInfo.Showing = 0;
255 }
256
257 return TRUE;
258 }
259
260 BOOL FASTCALL co_UserShowCaret(PWND Window OPTIONAL)
261 {
262 PTHREADINFO pti;
263 PUSER_MESSAGE_QUEUE ThreadQueue;
264 PWND pWnd = NULL;
265
266 if (Window) ASSERT_REFS_CO(Window);
267
268 if(Window && Window->head.pti->pEThread != PsGetCurrentThread())
269 {
270 EngSetLastError(ERROR_ACCESS_DENIED);
271 return FALSE;
272 }
273
274 pti = PsGetCurrentThreadWin32Thread();
275 ThreadQueue = pti->MessageQueue;
276
277 if(Window && ThreadQueue->CaretInfo.hWnd != Window->head.h)
278 {
279 EngSetLastError(ERROR_ACCESS_DENIED);
280 return FALSE;
281 }
282
283 if (!ThreadQueue->CaretInfo.Visible)
284 {
285 ThreadQueue->CaretInfo.Visible = 1;
286 pWnd = ValidateHwndNoErr(ThreadQueue->CaretInfo.hWnd);
287 if (!ThreadQueue->CaretInfo.Showing && pWnd)
288 {
289 IntNotifyWinEvent(EVENT_OBJECT_SHOW, pWnd, OBJID_CARET, OBJID_CARET, 0);
290 }
291 IntSetTimer(pWnd, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM);
292 }
293 return TRUE;
294 }
295
296 /* SYSCALLS *****************************************************************/
297
298 BOOL
299 APIENTRY
300 NtUserCreateCaret(
301 HWND hWnd,
302 HBITMAP hBitmap,
303 int nWidth,
304 int nHeight)
305 {
306 PWND Window;
307 PTHREADINFO pti;
308 PUSER_MESSAGE_QUEUE ThreadQueue;
309 DECLARE_RETURN(BOOL);
310
311 TRACE("Enter NtUserCreateCaret\n");
312 UserEnterExclusive();
313
314 if(!(Window = UserGetWindowObject(hWnd)))
315 {
316 RETURN(FALSE);
317 }
318
319 if(Window->head.pti->pEThread != PsGetCurrentThread())
320 {
321 EngSetLastError(ERROR_ACCESS_DENIED);
322 RETURN(FALSE);
323 }
324
325 pti = PsGetCurrentThreadWin32Thread();
326 ThreadQueue = pti->MessageQueue;
327
328 if (ThreadQueue->CaretInfo.Visible)
329 {
330 IntKillTimer(Window, IDCARETTIMER, TRUE);
331 co_IntHideCaret(&ThreadQueue->CaretInfo);
332 }
333
334 ThreadQueue->CaretInfo.hWnd = hWnd;
335 if(hBitmap)
336 {
337 ThreadQueue->CaretInfo.Bitmap = hBitmap;
338 ThreadQueue->CaretInfo.Size.cx = ThreadQueue->CaretInfo.Size.cy = 0;
339 }
340 else
341 {
342 if (nWidth == 0)
343 {
344 nWidth = UserGetSystemMetrics(SM_CXBORDER);
345 }
346 if (nHeight == 0)
347 {
348 nHeight = UserGetSystemMetrics(SM_CYBORDER);
349 }
350 ThreadQueue->CaretInfo.Bitmap = (HBITMAP)0;
351 ThreadQueue->CaretInfo.Size.cx = nWidth;
352 ThreadQueue->CaretInfo.Size.cy = nHeight;
353 }
354 ThreadQueue->CaretInfo.Visible = 0;
355 ThreadQueue->CaretInfo.Showing = 0;
356
357 IntSetTimer( Window, IDCARETTIMER, gpsi->dtCaretBlink, CaretSystemTimerProc, TMRF_SYSTEM );
358
359 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_CARET, CHILDID_SELF, 0);
360
361 RETURN(TRUE);
362
363 CLEANUP:
364 TRACE("Leave NtUserCreateCaret, ret=%i\n",_ret_);
365 UserLeave();
366 END_CLEANUP;
367 }
368
369 UINT
370 APIENTRY
371 NtUserGetCaretBlinkTime(VOID)
372 {
373 UINT ret;
374
375 UserEnterShared();
376
377 ret = gpsi->dtCaretBlink;
378
379 UserLeave();
380
381 return ret;
382 }
383
384 BOOL
385 APIENTRY
386 NtUserGetCaretPos(
387 LPPOINT lpPoint)
388 {
389 PTHREADINFO pti;
390 PUSER_MESSAGE_QUEUE ThreadQueue;
391 NTSTATUS Status;
392 DECLARE_RETURN(BOOL);
393
394 TRACE("Enter NtUserGetCaretPos\n");
395 UserEnterShared();
396
397 pti = PsGetCurrentThreadWin32Thread();
398 ThreadQueue = pti->MessageQueue;
399
400 Status = MmCopyToCaller(lpPoint, &ThreadQueue->CaretInfo.Pos, sizeof(POINT));
401 if(!NT_SUCCESS(Status))
402 {
403 SetLastNtError(Status);
404 RETURN(FALSE);
405 }
406
407 RETURN(TRUE);
408
409 CLEANUP:
410 TRACE("Leave NtUserGetCaretPos, ret=%i\n",_ret_);
411 UserLeave();
412 END_CLEANUP;
413 }
414
415 BOOL
416 APIENTRY
417 NtUserShowCaret(HWND hWnd OPTIONAL)
418 {
419 PWND Window = NULL;
420 USER_REFERENCE_ENTRY Ref;
421 DECLARE_RETURN(BOOL);
422 BOOL ret;
423
424 TRACE("Enter NtUserShowCaret\n");
425 UserEnterExclusive();
426
427 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
428 {
429 RETURN(FALSE);
430 }
431
432 if (Window) UserRefObjectCo(Window, &Ref);
433
434 ret = co_UserShowCaret(Window);
435
436 if (Window) UserDerefObjectCo(Window);
437
438 RETURN(ret);
439
440 CLEANUP:
441 TRACE("Leave NtUserShowCaret, ret=%i\n",_ret_);
442 UserLeave();
443 END_CLEANUP;
444 }
445
446 BOOL
447 APIENTRY
448 NtUserHideCaret(HWND hWnd OPTIONAL)
449 {
450 PWND Window = NULL;
451 USER_REFERENCE_ENTRY Ref;
452 DECLARE_RETURN(BOOL);
453 BOOL ret;
454
455 TRACE("Enter NtUserHideCaret\n");
456 UserEnterExclusive();
457
458 if(hWnd && !(Window = UserGetWindowObject(hWnd)))
459 {
460 RETURN(FALSE);
461 }
462
463 if (Window) UserRefObjectCo(Window, &Ref);
464
465 ret = co_UserHideCaret(Window);
466
467 if (Window) UserDerefObjectCo(Window);
468
469 RETURN(ret);
470
471 CLEANUP:
472 TRACE("Leave NtUserHideCaret, ret=%i\n",_ret_);
473 UserLeave();
474 END_CLEANUP;
475 }