2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window painting function
5 * FILE: subsys/win32k/ntuser/painting.c
6 * PROGRAMER: Filip Navara (xnavara@volny.cz)
8 * 06/06/2001 Created (?)
9 * 18/11/2003 Complete rewrite
12 /* INCLUDES ******************************************************************/
19 /* PRIVATE FUNCTIONS **********************************************************/
22 * @name IntIntersectWithParents
24 * Intersect window rectangle with all parent client rectangles.
27 * Pointer to child window to start intersecting from.
29 * Pointer to rectangle that we want to intersect in screen
30 * coordinates on input and intersected rectangle on output (if TRUE
34 * If any parent is minimized or invisible or the resulting rectangle
35 * is empty then FALSE is returned. Otherwise TRUE is returned.
39 IntIntersectWithParents(PWINDOW_OBJECT Child
, RECTL
*WindowRect
)
41 PWINDOW_OBJECT ParentWindow
;
44 ParentWindow
= Child
->spwndParent
;
45 while (ParentWindow
!= NULL
)
47 ParentWnd
= ParentWindow
->Wnd
;
48 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
49 (ParentWnd
->style
& WS_MINIMIZE
))
54 if (!RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
))
59 /* FIXME: Layered windows. */
61 ParentWindow
= ParentWindow
->spwndParent
;
68 IntValidateParent(PWINDOW_OBJECT Child
, HRGN hValidateRgn
, BOOL Recurse
)
70 PWINDOW_OBJECT ParentWindow
= Child
->spwndParent
;
75 ParentWnd
= ParentWindow
->Wnd
;
76 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
79 if (ParentWindow
->hrgnUpdate
!= 0)
84 IntInvalidateWindows( ParentWindow
,
86 RDW_VALIDATE
| RDW_NOCHILDREN
);
89 ParentWindow
= ParentWindow
->spwndParent
;
96 * @name IntCalcWindowRgn
98 * Get a window or client region.
102 IntCalcWindowRgn(PWINDOW_OBJECT Window
, BOOL Client
)
110 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
112 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
114 if (Window
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
116 NtGdiOffsetRgn(hRgnWindow
,
119 RgnType
= NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Window
->hrgnClip
, RGN_AND
);
120 NtGdiOffsetRgn(hRgnWindow
,
129 * @name IntGetNCUpdateRgn
131 * Get non-client update region of a window and optionally validate it.
134 * Pointer to window to get the NC update region from.
136 * Set to TRUE to force validating the NC update region.
139 * Handle to NC update region. The caller is responsible for deleting
144 IntGetNCUpdateRgn(PWINDOW_OBJECT Window
, BOOL Validate
)
150 if (Window
->hrgnUpdate
!= NULL
&&
151 Window
->hrgnUpdate
!= (HRGN
)1)
153 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
156 * If region creation fails it's safe to fallback to whole
159 if (hRgnNonClient
== NULL
)
164 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
165 if (hRgnWindow
== NULL
)
167 REGION_FreeRgnByHandle(hRgnNonClient
);
171 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
172 hRgnWindow
, RGN_DIFF
);
173 if (RgnType
== ERROR
)
175 REGION_FreeRgnByHandle(hRgnWindow
);
176 REGION_FreeRgnByHandle(hRgnNonClient
);
179 else if (RgnType
== NULLREGION
)
181 REGION_FreeRgnByHandle(hRgnWindow
);
182 REGION_FreeRgnByHandle(hRgnNonClient
);
187 * Remove the nonclient region from the standard update region if
188 * we were asked for it.
193 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
194 hRgnWindow
, RGN_AND
) == NULLREGION
)
196 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
197 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
198 Window
->hrgnUpdate
= NULL
;
199 if (!(Window
->Wnd
->state
& WNDS_INTERNALPAINT
))
200 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
204 REGION_FreeRgnByHandle(hRgnWindow
);
206 return hRgnNonClient
;
210 return Window
->hrgnUpdate
;
217 * Internal function used by IntRedrawWindow.
221 co_IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
, BOOL Recurse
)
224 HWND hWnd
= Window
->hSelf
;
230 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
232 if (Window
->hrgnUpdate
)
234 if (!IntValidateParent(Window
, Window
->hrgnUpdate
, Recurse
))
238 if (Flags
& RDW_UPDATENOW
)
240 if (Window
->hrgnUpdate
!= NULL
||
241 Wnd
->state
& WNDS_INTERNALPAINT
)
243 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
248 if (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
)
250 TempRegion
= IntGetNCUpdateRgn(Window
, TRUE
);
251 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
252 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
253 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
255 if ( (HANDLE
) 1 != TempRegion
&&
258 /* NOTE: The region can already be deleted! */
259 GDIOBJ_FreeObjByHandle(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
263 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
265 if (Window
->hrgnUpdate
)
267 hDC
= UserGetDCEx( Window
,
269 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
271 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
273 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
275 UserReleaseDC(Window
, hDC
, FALSE
);
282 * Check that the window is still valid at this point
284 if (!IntIsWindow(hWnd
))
290 * Paint child windows.
292 if (!(Flags
& RDW_NOCHILDREN
) &&
293 !(Wnd
->style
& WS_MINIMIZE
) &&
294 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
298 if ((List
= IntWinListChildren(Window
)))
300 /* FIXME: Handle WS_EX_TRANSPARENT */
301 for (phWnd
= List
; *phWnd
; ++phWnd
)
303 Window
= UserGetWindowObject(*phWnd
);
305 if (Window
&& (Wnd
->style
& WS_VISIBLE
))
307 USER_REFERENCE_ENTRY Ref
;
308 UserRefObjectCo(Window
, &Ref
);
309 co_IntPaintWindows(Window
, Flags
, TRUE
);
310 UserDerefObjectCo(Window
);
319 * IntInvalidateWindows
321 * Internal function used by IntRedrawWindow.
325 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
329 BOOL HadPaintMessage
, HadNCPaintMessage
;
330 BOOL HasPaintMessage
, HasNCPaintMessage
;
333 DPRINT("IntInvalidateWindows start\n");
335 * If the nonclient is not to be redrawn, clip the region to the client
338 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
342 hRgnClient
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
343 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
344 REGION_FreeRgnByHandle(hRgnClient
);
348 * Clip the given region with window rectangle (or region)
351 if (!Window
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
355 hRgnWindow
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
356 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
357 REGION_FreeRgnByHandle(hRgnWindow
);
361 NtGdiOffsetRgn( hRgn
,
364 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnClip
, RGN_AND
);
365 NtGdiOffsetRgn( hRgn
,
371 * Save current state of pending updates
374 HadPaintMessage
= Window
->hrgnUpdate
!= NULL
||
375 Wnd
->state
& WNDS_INTERNALPAINT
;
376 HadNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
379 * Update the region and flags
382 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
384 if (Window
->hrgnUpdate
== NULL
)
386 Window
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
387 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
390 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
391 hRgn
, RGN_OR
) == NULLREGION
)
393 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
394 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
395 Window
->hrgnUpdate
= NULL
;
398 if (Flags
& RDW_FRAME
)
399 Window
->state
|= WINDOWOBJECT_NEED_NCPAINT
;
400 if (Flags
& RDW_ERASE
)
401 Window
->state
|= WINDOWOBJECT_NEED_ERASEBKGND
;
406 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
408 if (Window
->hrgnUpdate
!= NULL
)
410 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
411 hRgn
, RGN_DIFF
) == NULLREGION
)
413 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
414 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
415 Window
->hrgnUpdate
= NULL
;
419 if (Window
->hrgnUpdate
== NULL
)
420 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
421 if (Flags
& RDW_NOFRAME
)
422 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
423 if (Flags
& RDW_NOERASE
)
424 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
427 if (Flags
& RDW_INTERNALPAINT
)
429 Wnd
->state
|= WNDS_INTERNALPAINT
;
432 if (Flags
& RDW_NOINTERNALPAINT
)
434 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
438 * Process children if needed
441 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
442 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
444 PWINDOW_OBJECT Child
;
446 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
448 if (Child
->Wnd
->style
& WS_VISIBLE
)
451 * Recursive call to update children hrgnUpdate
453 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
454 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
455 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
456 REGION_FreeRgnByHandle(hRgnTemp
);
463 * Fake post paint messages to window message queue if needed
466 HasPaintMessage
= Window
->hrgnUpdate
!= NULL
||
467 Wnd
->state
& WNDS_INTERNALPAINT
;
468 HasNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
470 if (HasPaintMessage
!= HadPaintMessage
)
473 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
475 MsqIncPaintCountQueue(Window
->pti
->MessageQueue
);
478 if (HasNCPaintMessage
!= HadNCPaintMessage
)
480 if (HadNCPaintMessage
)
481 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
483 MsqIncPaintCountQueue(Window
->pti
->MessageQueue
);
485 DPRINT("IntInvalidateWindows exit\n");
489 * IntIsWindowDrawable
492 * Window is drawable when it is visible and all parents are not
497 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
499 PWINDOW_OBJECT WndObject
;
502 for (WndObject
= Window
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
504 Wnd
= WndObject
->Wnd
;
505 if ( Window
->state
& WINDOWSTATUS_DESTROYING
|| // state2
506 Window
->state
& WINDOWSTATUS_DESTROYED
||
508 !(Wnd
->style
& WS_VISIBLE
) ||
509 ((Wnd
->style
& WS_MINIMIZE
) && (WndObject
!= Window
)))
521 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
527 PWINDOW_OBJECT Window
,
528 const RECTL
* UpdateRect
,
533 DPRINT("co_UserRedrawWindow start\n");
537 * Validation of passed parameters.
540 if (!IntIsWindowDrawable(Window
))
542 return TRUE
; // Just do nothing!!!
547 * Transform the parameters UpdateRgn and UpdateRect into
548 * a region hRgn specified in screen coordinates.
551 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
553 if (UpdateRgn
!= NULL
)
555 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
556 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
558 REGION_FreeRgnByHandle(hRgn
);
562 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
564 else if (UpdateRect
!= NULL
)
566 if (!RECTL_bIsEmptyRect(UpdateRect
))
568 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
569 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
572 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
573 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
575 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcWindow
))
576 hRgn
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
580 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcClient
))
581 hRgn
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
587 * Adjust the window update region depending on hRgn and flags.
590 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
593 IntInvalidateWindows(Window
, hRgn
, Flags
);
598 * Repaint and erase windows if needed.
601 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
603 co_IntPaintWindows(Window
, Flags
, FALSE
);
613 REGION_FreeRgnByHandle(hRgn
);
615 DPRINT("co_UserRedrawWindow exit\n");
621 IntIsWindowDirty(PWINDOW_OBJECT Window
)
623 PWND Wnd
= Window
->Wnd
;
624 return (Wnd
->style
& WS_VISIBLE
) &&
625 ((Window
->hrgnUpdate
!= NULL
) ||
626 (Wnd
->state
& WNDS_INTERNALPAINT
) ||
627 (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
));
631 IntFindWindowToRepaint(PWINDOW_OBJECT Window
, PTHREADINFO Thread
)
634 PWINDOW_OBJECT TempWindow
;
637 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
640 if (IntWndBelongsToThread(Window
, Thread
) &&
641 IntIsWindowDirty(Window
))
643 /* Make sure all non-transparent siblings are already drawn. */
644 if (Wnd
->ExStyle
& WS_EX_TRANSPARENT
)
646 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
647 TempWindow
= TempWindow
->spwndNext
)
649 TempWnd
= TempWindow
->Wnd
;
650 if (!(TempWnd
->ExStyle
& WS_EX_TRANSPARENT
) &&
651 IntWndBelongsToThread(TempWindow
, Thread
) &&
652 IntIsWindowDirty(TempWindow
))
654 return TempWindow
->hSelf
;
659 return Window
->hSelf
;
662 if (Window
->spwndChild
)
664 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
675 PWINDOW_OBJECT Window
,
682 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
684 if (!MessageQueue
->PaintCount
)
687 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
688 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
691 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
693 if (Message
->hwnd
== NULL
)
695 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
696 /* Hack to stop spamming the debuglog ! */
697 MessageQueue
->PaintCount
= 0;
701 if (Window
!= NULL
&& Message
->hwnd
!= Window
->hSelf
)
704 Message
->message
= WM_PAINT
;
705 Message
->wParam
= Message
->lParam
= 0;
712 co_IntFixCaret(PWINDOW_OBJECT Window
, RECTL
*lprc
, UINT flags
)
715 PTHRDCARETINFO CaretInfo
;
717 PWINDOW_OBJECT WndCaret
;
719 ASSERT_REFS_CO(Window
);
721 Desktop
= ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->rpdesk
;
722 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
723 hWndCaret
= CaretInfo
->hWnd
;
725 WndCaret
= UserGetWindowObject(hWndCaret
);
727 //fix: check for WndCaret can be null
728 if (WndCaret
== Window
||
729 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
731 POINT pt
, FromOffset
, ToOffset
, Offset
;
734 pt
.x
= CaretInfo
->Pos
.x
;
735 pt
.y
= CaretInfo
->Pos
.y
;
736 IntGetClientOrigin(WndCaret
, &FromOffset
);
737 IntGetClientOrigin(Window
, &ToOffset
);
738 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
739 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
742 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
743 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
744 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
756 /* PUBLIC FUNCTIONS ***********************************************************/
766 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
768 PWINDOW_OBJECT Window
= NULL
;
772 USER_REFERENCE_ENTRY Ref
;
775 DPRINT("Enter NtUserBeginPaint\n");
776 UserEnterExclusive();
778 if (!(Window
= UserGetWindowObject(hWnd
)))
783 UserRefObjectCo(Window
, &Ref
);
787 co_UserHideCaret(Window
);
789 if (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
)
793 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
794 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
795 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
796 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
797 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
799 /* NOTE: The region can already by deleted! */
800 GDIOBJ_FreeObjByHandle(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
804 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
806 Ps
.hdc
= UserGetDCEx( Window
,
808 DCX_INTERSECTRGN
| DCX_USESTYLE
);
814 if (Window
->hrgnUpdate
!= NULL
)
816 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
817 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
818 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
819 /* The region is part of the dc now and belongs to the process! */
820 Window
->hrgnUpdate
= NULL
;
824 if (Wnd
->state
& WNDS_INTERNALPAINT
)
825 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
827 IntGetClientRect(Window
, &Ps
.rcPaint
);
830 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
832 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
834 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
835 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
841 if (Window
->hrgnUpdate
)
843 if (!(Wnd
->style
& WS_CLIPCHILDREN
))
845 PWINDOW_OBJECT Child
;
846 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
848 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
853 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
854 if (! NT_SUCCESS(Status
))
856 SetLastNtError(Status
);
863 if (Window
) UserDerefObjectCo(Window
);
865 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
879 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
881 NTSTATUS Status
= STATUS_SUCCESS
;
882 PWINDOW_OBJECT Window
;
883 DECLARE_RETURN(BOOL
);
884 USER_REFERENCE_ENTRY Ref
;
887 DPRINT("Enter NtUserEndPaint\n");
888 UserEnterExclusive();
890 if (!(Window
= UserGetWindowObject(hWnd
)))
897 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
898 hdc
= pUnsafePs
->hdc
;
900 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
902 Status
= _SEH2_GetExceptionCode();
905 if (!NT_SUCCESS(Status
))
910 UserReleaseDC(Window
, hdc
, TRUE
);
912 UserRefObjectCo(Window
, &Ref
);
913 co_UserShowCaret(Window
);
914 UserDerefObjectCo(Window
);
919 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
926 co_UserGetUpdateRgn(PWINDOW_OBJECT Window
, HRGN hRgn
, BOOL bErase
)
931 ASSERT_REFS_CO(Window
);
933 if (Window
->hrgnUpdate
== NULL
)
935 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
939 Rect
= Window
->Wnd
->rcClient
;
940 IntIntersectWithParents(Window
, &Rect
);
941 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
942 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
943 NtGdiOffsetRgn(hRgn
, -Window
->Wnd
->rcClient
.left
, -Window
->Wnd
->rcClient
.top
);
946 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
948 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
962 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
965 PWINDOW_OBJECT Window
;
967 USER_REFERENCE_ENTRY Ref
;
969 DPRINT("Enter NtUserGetUpdateRgn\n");
970 UserEnterExclusive();
972 if (!(Window
= UserGetWindowObject(hWnd
)))
977 UserRefObjectCo(Window
, &Ref
);
978 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
979 UserDerefObjectCo(Window
);
984 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
990 * NtUserGetUpdateRect
997 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
999 PWINDOW_OBJECT Window
;
1002 PROSRGNDATA RgnData
;
1004 DECLARE_RETURN(BOOL
);
1006 DPRINT("Enter NtUserGetUpdateRect\n");
1007 UserEnterExclusive();
1009 if (!(Window
= UserGetWindowObject(hWnd
)))
1014 if (Window
->hrgnUpdate
== NULL
)
1016 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1020 /* Get the update region bounding box. */
1021 if (Window
->hrgnUpdate
== (HRGN
)1)
1023 Rect
= Window
->Wnd
->rcClient
;
1027 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1028 ASSERT(RgnData
!= NULL
);
1029 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1030 RGNOBJAPI_Unlock(RgnData
);
1032 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1033 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->Wnd
->rcClient
);
1036 if (IntIntersectWithParents(Window
, &Rect
))
1038 RECTL_vOffsetRect(&Rect
,
1039 -Window
->Wnd
->rcClient
.left
,
1040 -Window
->Wnd
->rcClient
.top
);
1043 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1047 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1049 USER_REFERENCE_ENTRY Ref
;
1050 UserRefObjectCo(Window
, &Ref
);
1051 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1052 UserDerefObjectCo(Window
);
1055 if (UnsafeRect
!= NULL
)
1057 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1058 if (!NT_SUCCESS(Status
))
1060 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1065 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1068 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1074 * NtUserRedrawWindow
1083 CONST RECT
*lprcUpdate
,
1087 RECTL SafeUpdateRect
;
1090 USER_REFERENCE_ENTRY Ref
;
1091 NTSTATUS Status
= STATUS_SUCCESS
;
1092 DECLARE_RETURN(BOOL
);
1094 DPRINT("Enter NtUserRedrawWindow\n");
1095 UserEnterExclusive();
1097 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1106 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1107 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1111 Status
= _SEH2_GetExceptionCode();
1114 if (!NT_SUCCESS(Status
))
1116 SetLastWin32Error(RtlNtStatusToDosError(Status
));
1121 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1122 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1123 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1125 /* RedrawWindow fails only in case that flags are invalid */
1126 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1130 UserRefObjectCo(Wnd
, &Ref
);
1132 Ret
= co_UserRedrawWindow( Wnd
,
1133 lprcUpdate
? &SafeUpdateRect
: NULL
,
1137 UserDerefObjectCo(Wnd
);
1142 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1153 const RECTL
*prcScroll
,
1154 const RECTL
*prcClip
,
1159 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1162 GdiGetClipBox(hDC
, &rcClip
);
1166 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1171 rcScroll
= *prcScroll
;
1172 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1180 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1181 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1183 if (!NtGdiBitBlt( hDC
,
1186 rcDst
.right
- rcDst
.left
,
1187 rcDst
.bottom
- rcDst
.top
,
1198 /* Calculate the region that was invalidated by moving or
1199 could not be copied, because it was not visible */
1200 if (hrgnUpdate
|| prcUpdate
)
1202 HRGN hrgnOwn
, hrgnVisible
, hrgnTmp
;
1204 pDC
= DC_LockDc(hDC
);
1209 hrgnVisible
= pDC
->rosdc
.hVisRgn
; // pDC->prgnRao?
1212 /* Begin with the shifted and then clipped scroll rect */
1214 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1215 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1218 hrgnOwn
= hrgnUpdate
;
1219 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1226 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1229 /* Add the source rect */
1230 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1231 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1233 /* Substract the part of the dest that was visible in source */
1234 NtGdiCombineRgn(hrgnTmp
, hrgnTmp
, hrgnVisible
, RGN_AND
);
1235 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1236 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1238 REGION_FreeRgnByHandle(hrgnTmp
);
1242 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1247 REGION_FreeRgnByHandle(hrgnOwn
);
1251 Result
= NULLREGION
;
1267 const RECT
*prcUnsafeScroll
,
1268 const RECT
*prcUnsafeClip
,
1270 LPRECT prcUnsafeUpdate
)
1272 DECLARE_RETURN(DWORD
);
1273 RECTL rcScroll
, rcClip
, rcUpdate
;
1274 NTSTATUS Status
= STATUS_SUCCESS
;
1277 DPRINT("Enter NtUserScrollDC\n");
1278 UserEnterExclusive();
1282 if (prcUnsafeScroll
)
1284 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1285 rcScroll
= *prcUnsafeScroll
;
1289 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1290 rcClip
= *prcUnsafeClip
;
1292 if (prcUnsafeUpdate
)
1294 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1299 Status
= _SEH2_GetExceptionCode();
1302 if (!NT_SUCCESS(Status
))
1304 SetLastNtError(Status
);
1308 Result
= UserScrollDC( hDC
,
1311 prcUnsafeScroll
? &rcScroll
: 0,
1312 prcUnsafeClip
? &rcClip
: 0,
1314 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1317 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1321 if (prcUnsafeUpdate
)
1325 *prcUnsafeUpdate
= rcUpdate
;
1327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1329 Status
= _SEH2_GetExceptionCode();
1332 if (!NT_SUCCESS(Status
))
1334 /* FIXME: SetLastError? */
1335 /* FIXME: correct? We have already scrolled! */
1343 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1349 * NtUserScrollWindowEx
1356 NtUserScrollWindowEx(
1360 const RECT
*prcUnsafeScroll
,
1361 const RECT
*prcUnsafeClip
,
1363 LPRECT prcUnsafeUpdate
,
1366 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1368 PWINDOW_OBJECT Window
= NULL
, CaretWnd
;
1370 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1372 NTSTATUS Status
= STATUS_SUCCESS
;
1373 DECLARE_RETURN(DWORD
);
1374 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1376 DPRINT("Enter NtUserScrollWindowEx\n");
1377 UserEnterExclusive();
1379 Window
= UserGetWindowObject(hWnd
);
1380 if (!Window
|| !IntIsWindowDrawable(Window
))
1382 Window
= NULL
; /* prevent deref at cleanup */
1385 UserRefObjectCo(Window
, &Ref
);
1387 IntGetClientRect(Window
, &rcClip
);
1391 if (prcUnsafeScroll
)
1393 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1394 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1401 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1402 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1407 Status
= _SEH2_GetExceptionCode();
1411 if (!NT_SUCCESS(Status
))
1413 SetLastNtError(Status
);
1417 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1418 (dx
== 0 && dy
== 0))
1424 hrgnOwn
= hrgnUpdate
;
1426 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1428 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1431 /* FIXME: SetLastError? */
1436 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1438 Result
= UserScrollDC( hDC
,
1444 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1446 UserReleaseDC(Window
, hDC
, FALSE
);
1449 * Take into account the fact that some damage may have occurred during
1453 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1454 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1456 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1457 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1458 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1459 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1460 REGION_FreeRgnByHandle(hrgnClip
);
1462 REGION_FreeRgnByHandle(hrgnTemp
);
1464 if (flags
& SW_SCROLLCHILDREN
)
1466 PWINDOW_OBJECT Child
;
1469 USER_REFERENCE_ENTRY WndRef
;
1472 IntGetClientOrigin(Window
, &ClientOrigin
);
1473 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1475 rcChild
= Child
->Wnd
->rcWindow
;
1476 rcChild
.left
-= ClientOrigin
.x
;
1477 rcChild
.top
-= ClientOrigin
.y
;
1478 rcChild
.right
-= ClientOrigin
.x
;
1479 rcChild
.bottom
-= ClientOrigin
.y
;
1481 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1483 UserRefObjectCo(Child
, &WndRef
);
1484 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1485 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1487 UserDerefObjectCo(Child
);
1492 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1494 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1495 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1496 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1499 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1501 UserRefObjectCo(CaretWnd
, &CaretRef
);
1503 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1504 co_UserShowCaret(CaretWnd
);
1506 UserDerefObjectCo(CaretWnd
);
1509 if (prcUnsafeUpdate
)
1513 /* Probe here, to not fail on invalid pointer before scrolling */
1514 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1515 *prcUnsafeUpdate
= rcUpdate
;
1517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1519 Status
= _SEH2_GetExceptionCode();
1523 if (!NT_SUCCESS(Status
))
1525 SetLastNtError(Status
);
1533 if (hrgnOwn
&& !hrgnUpdate
)
1535 REGION_FreeRgnByHandle(hrgnOwn
);
1539 UserDerefObjectCo(Window
);
1541 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1548 UserDrawSysMenuButton(
1549 PWINDOW_OBJECT pWnd
,
1555 PCURICON_OBJECT pIcon
;
1557 ASSERT(pWnd
&& lpRc
);
1559 /* Get the icon to draw. We don't care about WM_GETICON here. */
1561 hIcon
= pWnd
->Wnd
->pcls
->hIconSm
;
1565 DPRINT("Wnd class has no small icon.\n");
1566 hIcon
= pWnd
->Wnd
->pcls
->hIcon
;
1571 DPRINT("Wnd class hasn't any icon.\n");
1572 //FIXME: Draw "winlogo" icon.
1576 if(!(pIcon
= UserGetCurIconObject(hIcon
)))
1578 DPRINT1("UserGetCurIconObject() failed!\n");
1582 return UserDrawIconEx(hDc
, lpRc
->left
, lpRc
->top
, pIcon
,
1583 UserGetSystemMetrics(SM_CXSMICON
),
1584 UserGetSystemMetrics(SM_CYSMICON
),
1585 0, NULL
, DI_NORMAL
);
1589 UserDrawCaptionText(
1591 const PUNICODE_STRING Text
,
1595 HFONT hOldFont
= NULL
, hFont
= NULL
;
1596 COLORREF OldTextColor
;
1597 NONCLIENTMETRICSW nclm
;
1601 DPRINT("%s:", __FUNCTION__
);
1602 for(i
= 0; i
< Text
->Length
/sizeof(WCHAR
); i
++)
1603 DbgPrint("%C", Text
->Buffer
[i
]);
1604 DbgPrint(", %d\n", Text
->Length
/sizeof(WCHAR
));
1607 nclm
.cbSize
= sizeof(nclm
);
1608 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1609 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1611 DPRINT1("%s: UserSystemParametersInfo() failed!\n", __FUNCTION__
);
1615 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1617 if(uFlags
& DC_SMALLCAP
)
1618 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1619 else Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1621 if(!NT_SUCCESS(Status
))
1623 DPRINT1("%s: TextIntCreateFontIndirect() failed! Status: 0x%x\n",
1624 __FUNCTION__
, Status
);
1628 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1631 DPRINT1("%s: SelectFont() failed!\n", __FUNCTION__
);
1632 GreDeleteObject(hFont
);
1636 if(uFlags
& DC_INBUTTON
)
1637 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1638 else OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1639 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1641 //FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1643 GreExtTextOutW(hDc
, lpRc
->left
,
1644 lpRc
->top
, 0, NULL
, Text
->Buffer
,
1645 Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1647 IntGdiSetTextColor(hDc
, OldTextColor
);
1648 NtGdiSelectFont(hDc
, hOldFont
);
1649 GreDeleteObject(hFont
);
1654 BOOL
UserDrawCaption(
1655 PWINDOW_OBJECT pWnd
,
1660 const PUNICODE_STRING str
,
1664 HBITMAP hMemBmp
= NULL
, hOldBmp
= NULL
;
1665 HBRUSH hOldBrush
= NULL
;
1668 UINT VCenter
= 0, Padding
= 0;
1670 LONG ButtonWidth
, IconWidth
;
1674 //ASSERT(pWnd != NULL);
1679 RECTL_vMakeWellOrdered(lpRc
);
1680 hMemBmp
= NtGdiCreateCompatibleBitmap(hDc
,
1681 lpRc
->right
- lpRc
->left
,
1682 lpRc
->bottom
- lpRc
->top
);
1686 DPRINT1("%s: NtGdiCreateCompatibleBitmap() failed!\n", __FUNCTION__
);
1690 hMemDc
= NtGdiCreateCompatibleDC(hDc
);
1693 DPRINT1("%s: NtGdiCreateCompatibleDC() failed!\n", __FUNCTION__
);
1697 hOldBmp
= NtGdiSelectBitmap(hMemDc
, hMemBmp
);
1700 DPRINT1("%s: NtGdiSelectBitmap() failed!\n", __FUNCTION__
);
1704 Height
= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1705 VCenter
= (lpRc
->bottom
- lpRc
->top
) / 2;
1706 Padding
= VCenter
- (Height
/ 2);
1708 if ((!hIcon
) && (Wnd
!= NULL
))
1710 HasIcon
= (uFlags
& DC_ICON
) && (Wnd
->style
& WS_SYSMENU
)
1711 && !(uFlags
& DC_SMALLCAP
) && !(Wnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1712 && !(Wnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1715 HasIcon
= (hIcon
!= 0);
1717 IconWidth
= UserGetSystemMetrics(SM_CXSIZE
) + Padding
;
1720 r
.right
= r
.left
+ (lpRc
->right
- lpRc
->left
);
1722 r
.bottom
= r
.top
+ (Height
/ 2);
1724 // Draw the caption background
1725 if(uFlags
& DC_INBUTTON
)
1727 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1728 IntGetSysColorBrush(COLOR_3DFACE
));
1732 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1736 if(!NtGdiPatBlt(hMemDc
, 0, 0,
1737 lpRc
->right
- lpRc
->left
,
1738 lpRc
->bottom
- lpRc
->top
,
1741 DPRINT1("%s: NtGdiPatBlt() failed!\n", __FUNCTION__
);
1745 if(HasIcon
) r
.left
+=IconWidth
;
1749 r
.right
= (lpRc
->right
- lpRc
->left
);
1750 if(uFlags
& DC_SMALLCAP
)
1751 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1752 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1754 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1755 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1756 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
1760 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1764 if(HasIcon
&& (uFlags
& DC_GRADIENT
))
1766 NtGdiPatBlt(hMemDc
, 0, 0,
1768 lpRc
->bottom
- lpRc
->top
,
1774 NtGdiPatBlt(hMemDc
, 0, 0,
1775 lpRc
->right
- lpRc
->left
,
1776 lpRc
->bottom
- lpRc
->top
,
1780 if(uFlags
& DC_GRADIENT
)
1782 static GRADIENT_RECT gcap
= {0, 1};
1788 if(Wnd
->style
& WS_SYSMENU
)
1790 r
.right
-= 3 + ButtonWidth
;
1791 if(!(uFlags
& DC_SMALLCAP
))
1793 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1794 r
.right
-= 2 + 2 * ButtonWidth
;
1799 //Draw buttons background
1800 if(!NtGdiSelectBrush(hMemDc
,
1801 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1802 COLOR_GRADIENTACTIVECAPTION
:COLOR_GRADIENTINACTIVECAPTION
)))
1804 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1811 lpRc
->right
- lpRc
->left
- r
.right
,
1812 lpRc
->bottom
- lpRc
->top
,
1817 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1818 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1820 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1821 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1825 vert
[0].Red
= (WORD
)Colors
[0]<<8;
1826 vert
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1827 vert
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1830 vert
[1].x
= r
.right
;
1831 vert
[1].y
= lpRc
->bottom
- lpRc
->top
;
1832 vert
[1].Red
= (WORD
)Colors
[1]<<8;
1833 vert
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1834 vert
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1837 if(!GreGradientFill(hMemDc
, vert
, 2, &gcap
,
1838 1, GRADIENT_FILL_RECT_H
))
1840 DPRINT1("%s: IntGdiGradientFill() failed!\n", __FUNCTION__
);
1843 } //if(uFlags & DC_GRADIENT)
1849 r
.left
-= --IconWidth
;
1850 /* FIXME: Draw the Icon when pWnd == NULL but hIcon is valid */
1852 UserDrawSysMenuButton(pWnd
, hMemDc
, &r
, FALSE
);
1854 r
.left
+= IconWidth
;
1861 r
.bottom
= r
.top
+ Height
;
1863 if((uFlags
& DC_TEXT
))
1865 if(!(uFlags
& DC_GRADIENT
))
1867 r
.right
= (lpRc
->right
- lpRc
->left
);
1869 if(uFlags
& DC_SMALLCAP
)
1870 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1871 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1873 if ((Wnd
!= NULL
) && (Wnd
->style
& WS_SYSMENU
))
1875 r
.right
-= 3 + ButtonWidth
;
1876 if(! (uFlags
& DC_SMALLCAP
))
1878 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1879 r
.right
-= 2 + 2 * ButtonWidth
;
1886 /* FIXME: hFont isn't handled */
1888 UserDrawCaptionText(hMemDc
, str
, &r
, uFlags
);
1889 else if (pWnd
!= NULL
)
1891 UNICODE_STRING ustr
;
1892 ustr
.Buffer
= pWnd
->Wnd
->strName
.Buffer
;
1893 ustr
.Length
= pWnd
->Wnd
->strName
.Length
;
1894 ustr
.MaximumLength
= pWnd
->Wnd
->strName
.MaximumLength
;
1895 UserDrawCaptionText(hMemDc
, &ustr
, &r
, uFlags
);
1899 if(!NtGdiBitBlt(hDc
, lpRc
->left
, lpRc
->top
,
1900 lpRc
->right
- lpRc
->left
, lpRc
->bottom
- lpRc
->top
,
1901 hMemDc
, 0, 0, SRCCOPY
, 0, 0))
1903 DPRINT1("%s: NtGdiBitBlt() failed!\n", __FUNCTION__
);
1910 if (hOldBrush
) NtGdiSelectBrush(hMemDc
, hOldBrush
);
1911 if (hOldBmp
) NtGdiSelectBitmap(hMemDc
, hOldBmp
);
1912 if (hMemBmp
) GreDeleteObject(hMemBmp
);
1913 if (hMemDc
) NtGdiDeleteObjectApp(hMemDc
);
1920 UserRealizePalette(HDC hdc
)
1925 Ret
= IntGdiRealizePalette(hdc
);
1926 if (Ret
) // There was a change.
1928 hWnd
= IntWindowFromDC(hdc
);
1929 if (hWnd
) // Send broadcast if dc is associated with a window.
1930 { // FYI: Thread locked in CallOneParam.
1931 co_IntSendMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1939 NtUserDrawCaptionTemp(
1945 const PUNICODE_STRING str
,
1948 PWINDOW_OBJECT pWnd
= NULL
;
1949 UNICODE_STRING SafeStr
= {0};
1950 NTSTATUS Status
= STATUS_SUCCESS
;
1954 UserEnterExclusive();
1958 if(!(pWnd
= UserGetWindowObject(hWnd
)))
1967 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
1968 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
1971 SafeStr
= ProbeForReadUnicodeString(str
);
1972 if (SafeStr
.Length
!= 0)
1974 ProbeForRead( SafeStr
.Buffer
,
1980 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1982 Status
= _SEH2_GetExceptionCode();
1986 if (Status
!= STATUS_SUCCESS
)
1988 SetLastNtError(Status
);
1994 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
1996 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2004 NtUserDrawCaption(HWND hWnd
,
2009 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2014 NtUserInvalidateRect(
2016 CONST RECT
*lpUnsafeRect
,
2019 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2024 NtUserInvalidateRgn(
2029 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2032 /* ValidateRect gets redirected to NtUserValidateRect:
2033 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2042 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2044 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);