xref: /reactos/win32ss/user/ntuser/caret.c (revision 845faec4)
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 }
476