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