2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window painting function
5 * FILE: subsystems/win32/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(PWND Child
, RECTL
*WindowRect
)
43 ParentWnd
= Child
->spwndParent
;
44 while (ParentWnd
!= NULL
)
46 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
47 (ParentWnd
->style
& WS_MINIMIZE
))
52 if (!RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
))
57 /* FIXME: Layered windows. */
59 ParentWnd
= ParentWnd
->spwndParent
;
66 IntValidateParent(PWND Child
, HRGN hValidateRgn
, BOOL Recurse
)
68 PWND ParentWnd
= Child
->spwndParent
;
72 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
75 if (ParentWnd
->hrgnUpdate
!= 0)
80 IntInvalidateWindows( ParentWnd
,
82 RDW_VALIDATE
| RDW_NOCHILDREN
);
85 ParentWnd
= ParentWnd
->spwndParent
;
92 * @name IntCalcWindowRgn
94 * Get a window or client region.
98 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
103 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
105 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
107 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
109 NtGdiOffsetRgn(hRgnWindow
,
112 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
113 NtGdiOffsetRgn(hRgnWindow
,
122 * @name IntGetNCUpdateRgn
124 * Get non-client update region of a window and optionally validate it.
127 * Pointer to window to get the NC update region from.
129 * Set to TRUE to force validating the NC update region.
132 * Handle to NC update region. The caller is responsible for deleting
137 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
143 if (Window
->hrgnUpdate
!= NULL
&&
144 Window
->hrgnUpdate
!= HRGN_WINDOW
)
146 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
149 * If region creation fails it's safe to fallback to whole
152 if (hRgnNonClient
== NULL
)
157 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
158 if (hRgnWindow
== NULL
)
160 REGION_FreeRgnByHandle(hRgnNonClient
);
164 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
165 hRgnWindow
, RGN_DIFF
);
166 if (RgnType
== ERROR
)
168 REGION_FreeRgnByHandle(hRgnWindow
);
169 REGION_FreeRgnByHandle(hRgnNonClient
);
172 else if (RgnType
== NULLREGION
)
174 REGION_FreeRgnByHandle(hRgnWindow
);
175 REGION_FreeRgnByHandle(hRgnNonClient
);
180 * Remove the nonclient region from the standard update region if
181 * we were asked for it.
186 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
187 hRgnWindow
, RGN_AND
) == NULLREGION
)
189 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
190 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
191 Window
->hrgnUpdate
= NULL
;
192 if (!(Window
->state
& WNDS_INTERNALPAINT
))
193 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
197 REGION_FreeRgnByHandle(hRgnWindow
);
199 return hRgnNonClient
;
203 return Window
->hrgnUpdate
;
210 * Internal function used by IntRedrawWindow.
214 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
217 HWND hWnd
= Wnd
->head
.h
;
220 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
224 if (!IntValidateParent(Wnd
, Wnd
->hrgnUpdate
, Recurse
))
228 if (Flags
& RDW_UPDATENOW
)
230 if (Wnd
->hrgnUpdate
!= NULL
||
231 Wnd
->state
& WNDS_INTERNALPAINT
)
233 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
238 if (Wnd
->state
& WNDS_SENDNCPAINT
)
240 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
241 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
242 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
243 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
245 if ( (HANDLE
) 1 != TempRegion
&&
248 /* NOTE: The region can already be deleted! */
249 GDIOBJ_FreeObjByHandle(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
253 if (Wnd
->state
& WNDS_ERASEBACKGROUND
)
257 hDC
= UserGetDCEx( Wnd
,
259 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
261 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
263 Wnd
->state
&= ~WNDS_ERASEBACKGROUND
;
265 UserReleaseDC(Wnd
, hDC
, FALSE
);
272 * Check that the window is still valid at this point
274 if (!IntIsWindow(hWnd
))
280 * Paint child windows.
282 if (!(Flags
& RDW_NOCHILDREN
) &&
283 !(Wnd
->style
& WS_MINIMIZE
) &&
284 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
288 if ((List
= IntWinListChildren(Wnd
)))
290 /* FIXME: Handle WS_EX_TRANSPARENT */
291 for (phWnd
= List
; *phWnd
; ++phWnd
)
293 Wnd
= UserGetWindowObject(*phWnd
);
294 if (Wnd
&& (Wnd
->style
& WS_VISIBLE
))
296 USER_REFERENCE_ENTRY Ref
;
297 UserRefObjectCo(Wnd
, &Ref
);
298 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
299 UserDerefObjectCo(Wnd
);
308 * IntInvalidateWindows
310 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
311 * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
314 IntInvalidateWindows(PWND Wnd
, HRGN hRgn
, ULONG Flags
)
317 BOOL HadPaintMessage
, HadNCPaintMessage
;
318 BOOL HasPaintMessage
, HasNCPaintMessage
;
320 DPRINT("IntInvalidateWindows start\n");
322 * If the nonclient is not to be redrawn, clip the region to the client
325 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
329 hRgnClient
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
330 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
331 REGION_FreeRgnByHandle(hRgnClient
);
335 * Clip the given region with window rectangle (or region)
338 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
342 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
343 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
344 REGION_FreeRgnByHandle(hRgnWindow
);
348 NtGdiOffsetRgn( hRgn
,
351 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Wnd
->hrgnClip
, RGN_AND
);
352 NtGdiOffsetRgn( hRgn
,
358 * Save current state of pending updates
361 HadPaintMessage
= Wnd
->hrgnUpdate
!= NULL
||
362 Wnd
->state
& WNDS_INTERNALPAINT
;
363 HadNCPaintMessage
= Wnd
->state
& WNDS_SENDNCPAINT
;
366 * Update the region and flags
369 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
371 if (Wnd
->hrgnUpdate
== NULL
)
373 Wnd
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
374 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
377 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
378 hRgn
, RGN_OR
) == NULLREGION
)
380 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
381 REGION_FreeRgnByHandle(Wnd
->hrgnUpdate
);
382 Wnd
->hrgnUpdate
= NULL
;
385 if (Flags
& RDW_FRAME
)
386 Wnd
->state
|= WNDS_SENDNCPAINT
;
387 if (Flags
& RDW_ERASE
)
388 Wnd
->state
|= WNDS_ERASEBACKGROUND
;
393 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
395 if (Wnd
->hrgnUpdate
!= NULL
)
397 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
398 hRgn
, RGN_DIFF
) == NULLREGION
)
400 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
401 REGION_FreeRgnByHandle(Wnd
->hrgnUpdate
);
402 Wnd
->hrgnUpdate
= NULL
;
406 if (Wnd
->hrgnUpdate
== NULL
)
407 Wnd
->state
&= ~WNDS_ERASEBACKGROUND
;
408 if (Flags
& RDW_NOFRAME
)
409 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
410 if (Flags
& RDW_NOERASE
)
411 Wnd
->state
&= ~WNDS_ERASEBACKGROUND
;
414 if (Flags
& RDW_INTERNALPAINT
)
416 Wnd
->state
|= WNDS_INTERNALPAINT
;
419 if (Flags
& RDW_NOINTERNALPAINT
)
421 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
425 * Process children if needed
428 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
429 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
433 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
435 if (Child
->style
& WS_VISIBLE
)
438 * Recursive call to update children hrgnUpdate
440 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
441 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
442 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
443 REGION_FreeRgnByHandle(hRgnTemp
);
450 * Fake post paint messages to window message queue if needed
453 HasPaintMessage
= Wnd
->hrgnUpdate
!= NULL
||
454 Wnd
->state
& WNDS_INTERNALPAINT
;
455 HasNCPaintMessage
= Wnd
->state
& WNDS_SENDNCPAINT
;
457 if (HasPaintMessage
!= HadPaintMessage
)
460 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
462 MsqIncPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
465 if (HasNCPaintMessage
!= HadNCPaintMessage
)
467 if (HadNCPaintMessage
)
468 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
470 MsqIncPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
472 DPRINT("IntInvalidateWindows exit\n");
476 * IntIsWindowDrawable
479 * Window is drawable when it is visible and all parents are not
484 IntIsWindowDrawable(PWND Wnd
)
488 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
490 if ( WndObject
->state2
& WNDS2_INDESTROY
||
491 WndObject
->state
& WNDS_DESTROYED
||
493 !(WndObject
->style
& WS_VISIBLE
) ||
494 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
506 * Internal version of NtUserRedrawWindow that takes WND as
513 const RECTL
* UpdateRect
,
518 DPRINT("co_UserRedrawWindow start\n");
522 * Validation of passed parameters.
525 if (!IntIsWindowDrawable(Window
))
527 return TRUE
; // Just do nothing!!!
532 * Transform the parameters UpdateRgn and UpdateRect into
533 * a region hRgn specified in screen coordinates.
536 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
538 if (UpdateRgn
!= NULL
)
540 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
541 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
543 REGION_FreeRgnByHandle(hRgn
);
547 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
549 else if (UpdateRect
!= NULL
)
551 if (!RECTL_bIsEmptyRect(UpdateRect
))
553 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
554 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
557 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
558 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
560 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
561 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
565 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
566 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcClient
);
572 * Adjust the window update region depending on hRgn and flags.
575 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
578 IntInvalidateWindows(Window
, hRgn
, Flags
);
583 * Repaint and erase windows if needed.
586 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
588 co_IntPaintWindows(Window
, Flags
, FALSE
);
598 REGION_FreeRgnByHandle(hRgn
);
600 DPRINT("co_UserRedrawWindow exit\n");
606 IntIsWindowDirty(PWND Wnd
)
608 return (Wnd
->style
& WS_VISIBLE
) &&
609 ((Wnd
->hrgnUpdate
!= NULL
) ||
610 (Wnd
->state
& WNDS_INTERNALPAINT
) ||
611 (Wnd
->state
& WNDS_SENDNCPAINT
));
615 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
620 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
622 if (IntWndBelongsToThread(Window
, Thread
) &&
623 IntIsWindowDirty(Window
))
625 /* Make sure all non-transparent siblings are already drawn. */
626 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
628 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
629 TempWindow
= TempWindow
->spwndNext
)
631 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
632 IntWndBelongsToThread(TempWindow
, Thread
) &&
633 IntIsWindowDirty(TempWindow
))
635 return TempWindow
->head
.h
;
640 return Window
->head
.h
;
643 if (Window
->spwndChild
)
645 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
663 if (!Thread
->cPaintsReady
)
666 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
667 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
670 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
672 if (Message
->hwnd
== NULL
)
674 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread
->cPaintsReady
);
675 /* Hack to stop spamming the debuglog ! */
676 Thread
->cPaintsReady
= 0;
680 if (Window
!= NULL
&& Message
->hwnd
!= Window
->head
.h
)
683 Message
->message
= WM_PAINT
;
684 Message
->wParam
= Message
->lParam
= 0;
691 co_IntFixCaret(PWND Window
, RECTL
*lprc
, UINT flags
)
694 PTHRDCARETINFO CaretInfo
;
696 PUSER_MESSAGE_QUEUE ActiveMessageQueue
;
700 ASSERT_REFS_CO(Window
);
702 pti
= PsGetCurrentThreadWin32Thread();
703 Desktop
= pti
->rpdesk
;
704 ActiveMessageQueue
= Desktop
->ActiveMessageQueue
;
705 if (!ActiveMessageQueue
) return 0;
706 CaretInfo
= ActiveMessageQueue
->CaretInfo
;
707 hWndCaret
= CaretInfo
->hWnd
;
709 WndCaret
= UserGetWindowObject(hWndCaret
);
711 //fix: check for WndCaret can be null
712 if (WndCaret
== Window
||
713 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
715 POINT pt
, FromOffset
, ToOffset
;
718 pt
.x
= CaretInfo
->Pos
.x
;
719 pt
.y
= CaretInfo
->Pos
.y
;
720 IntGetClientOrigin(WndCaret
, &FromOffset
);
721 IntGetClientOrigin(Window
, &ToOffset
);
724 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
725 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
726 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
746 INT cx
, cy
, xSrc
, ySrc
;
748 if ( nFlags
& PW_CLIENTONLY
)
750 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
751 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
752 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
753 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
757 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
758 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
763 // TODO: Setup Redirection for Print.
766 /* Update the window just incase. */
767 co_IntPaintWindows( pwnd
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
769 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
770 /* Print window to printer context. */
783 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
785 // TODO: Release Redirection from Print.
790 /* PUBLIC FUNCTIONS ***********************************************************/
800 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
806 USER_REFERENCE_ENTRY Ref
;
808 DPRINT("Enter NtUserBeginPaint\n");
809 UserEnterExclusive();
811 if (!(Window
= UserGetWindowObject(hWnd
)))
816 UserRefObjectCo(Window
, &Ref
);
818 co_UserHideCaret(Window
);
820 if (Window
->state
& WNDS_SENDNCPAINT
)
824 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
825 Window
->state
&= ~WNDS_SENDNCPAINT
;
826 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
827 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
828 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
830 /* NOTE: The region can already by deleted! */
831 GDIOBJ_FreeObjByHandle(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
835 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
837 Ps
.hdc
= UserGetDCEx( Window
,
839 DCX_INTERSECTRGN
| DCX_USESTYLE
);
845 if (Window
->hrgnUpdate
!= NULL
)
847 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
848 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
849 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
850 /* The region is part of the dc now and belongs to the process! */
851 Window
->hrgnUpdate
= NULL
;
855 if (Window
->state
& WNDS_INTERNALPAINT
)
856 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
858 IntGetClientRect(Window
, &Ps
.rcPaint
);
861 Window
->state
&= ~WNDS_INTERNALPAINT
;
863 if (Window
->state
& WNDS_ERASEBACKGROUND
)
865 Window
->state
&= ~WNDS_ERASEBACKGROUND
;
866 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
872 if (Window
->hrgnUpdate
)
874 if (!(Window
->style
& WS_CLIPCHILDREN
))
877 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
879 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
884 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
885 if (! NT_SUCCESS(Status
))
887 SetLastNtError(Status
);
894 if (Window
) UserDerefObjectCo(Window
);
896 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
910 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
912 NTSTATUS Status
= STATUS_SUCCESS
;
914 DECLARE_RETURN(BOOL
);
915 USER_REFERENCE_ENTRY Ref
;
918 DPRINT("Enter NtUserEndPaint\n");
919 UserEnterExclusive();
921 if (!(Window
= UserGetWindowObject(hWnd
)))
928 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
929 hdc
= pUnsafePs
->hdc
;
931 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
933 Status
= _SEH2_GetExceptionCode();
936 if (!NT_SUCCESS(Status
))
941 UserReleaseDC(Window
, hdc
, TRUE
);
943 UserRefObjectCo(Window
, &Ref
);
944 co_UserShowCaret(Window
);
945 UserDerefObjectCo(Window
);
950 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
957 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
962 ASSERT_REFS_CO(Window
);
964 if (Window
->hrgnUpdate
== NULL
)
966 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
970 Rect
= Window
->rcClient
;
971 IntIntersectWithParents(Window
, &Rect
);
972 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
973 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
974 NtGdiOffsetRgn(hRgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
977 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
979 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
993 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
998 USER_REFERENCE_ENTRY Ref
;
1000 DPRINT("Enter NtUserGetUpdateRgn\n");
1001 UserEnterExclusive();
1003 if (!(Window
= UserGetWindowObject(hWnd
)))
1008 UserRefObjectCo(Window
, &Ref
);
1009 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1010 UserDerefObjectCo(Window
);
1015 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1021 * NtUserGetUpdateRect
1028 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1033 PROSRGNDATA RgnData
;
1035 DECLARE_RETURN(BOOL
);
1037 DPRINT("Enter NtUserGetUpdateRect\n");
1038 UserEnterExclusive();
1040 if (!(Window
= UserGetWindowObject(hWnd
)))
1045 if (Window
->hrgnUpdate
== NULL
)
1047 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1051 /* Get the update region bounding box. */
1052 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1054 Rect
= Window
->rcClient
;
1058 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1059 ASSERT(RgnData
!= NULL
);
1060 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1061 RGNOBJAPI_Unlock(RgnData
);
1063 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1064 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1067 if (IntIntersectWithParents(Window
, &Rect
))
1069 RECTL_vOffsetRect(&Rect
,
1070 -Window
->rcClient
.left
,
1071 -Window
->rcClient
.top
);
1074 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1078 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1080 USER_REFERENCE_ENTRY Ref
;
1081 UserRefObjectCo(Window
, &Ref
);
1082 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1083 UserDerefObjectCo(Window
);
1086 if (UnsafeRect
!= NULL
)
1088 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1089 if (!NT_SUCCESS(Status
))
1091 EngSetLastError(ERROR_INVALID_PARAMETER
);
1096 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1099 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1105 * NtUserRedrawWindow
1114 CONST RECT
*lprcUpdate
,
1118 RECTL SafeUpdateRect
;
1121 USER_REFERENCE_ENTRY Ref
;
1122 NTSTATUS Status
= STATUS_SUCCESS
;
1123 DECLARE_RETURN(BOOL
);
1125 DPRINT("Enter NtUserRedrawWindow\n");
1126 UserEnterExclusive();
1128 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1137 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1138 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1140 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1142 Status
= _SEH2_GetExceptionCode();
1145 if (!NT_SUCCESS(Status
))
1147 EngSetLastError(RtlNtStatusToDosError(Status
));
1152 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1153 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1154 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1156 /* RedrawWindow fails only in case that flags are invalid */
1157 EngSetLastError(ERROR_INVALID_FLAGS
);
1161 UserRefObjectCo(Wnd
, &Ref
);
1163 Ret
= co_UserRedrawWindow( Wnd
,
1164 lprcUpdate
? &SafeUpdateRect
: NULL
,
1168 UserDerefObjectCo(Wnd
);
1173 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1184 const RECTL
*prcScroll
,
1185 const RECTL
*prcClip
,
1190 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1193 GdiGetClipBox(hDC
, &rcClip
);
1197 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1202 rcScroll
= *prcScroll
;
1203 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1211 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1212 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1214 if (!NtGdiBitBlt( hDC
,
1217 rcDst
.right
- rcDst
.left
,
1218 rcDst
.bottom
- rcDst
.top
,
1229 /* Calculate the region that was invalidated by moving or
1230 could not be copied, because it was not visible */
1231 if (hrgnUpdate
|| prcUpdate
)
1233 HRGN hrgnOwn
, hrgnVisible
, hrgnTmp
;
1235 pDC
= DC_LockDc(hDC
);
1240 hrgnVisible
= ((PROSRGNDATA
)pDC
->prgnVis
)->BaseObject
.hHmgr
; // pDC->prgnRao?
1242 /* Begin with the shifted and then clipped scroll rect */
1244 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1245 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1248 hrgnOwn
= hrgnUpdate
;
1249 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1256 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1259 /* Add the source rect */
1260 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1261 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1263 /* Substract the part of the dest that was visible in source */
1264 NtGdiCombineRgn(hrgnTmp
, hrgnTmp
, hrgnVisible
, RGN_AND
);
1265 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1266 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1268 /* DO NOT Unlock DC while messing with prgnVis! */
1271 REGION_FreeRgnByHandle(hrgnTmp
);
1275 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1280 REGION_FreeRgnByHandle(hrgnOwn
);
1284 Result
= NULLREGION
;
1300 const RECT
*prcUnsafeScroll
,
1301 const RECT
*prcUnsafeClip
,
1303 LPRECT prcUnsafeUpdate
)
1305 DECLARE_RETURN(DWORD
);
1306 RECTL rcScroll
, rcClip
, rcUpdate
;
1307 NTSTATUS Status
= STATUS_SUCCESS
;
1310 DPRINT("Enter NtUserScrollDC\n");
1311 UserEnterExclusive();
1315 if (prcUnsafeScroll
)
1317 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1318 rcScroll
= *prcUnsafeScroll
;
1322 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1323 rcClip
= *prcUnsafeClip
;
1325 if (prcUnsafeUpdate
)
1327 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1332 Status
= _SEH2_GetExceptionCode();
1335 if (!NT_SUCCESS(Status
))
1337 SetLastNtError(Status
);
1341 Result
= UserScrollDC( hDC
,
1344 prcUnsafeScroll
? &rcScroll
: 0,
1345 prcUnsafeClip
? &rcClip
: 0,
1347 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1350 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1354 if (prcUnsafeUpdate
)
1358 *prcUnsafeUpdate
= rcUpdate
;
1360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1362 Status
= _SEH2_GetExceptionCode();
1365 if (!NT_SUCCESS(Status
))
1367 /* FIXME: SetLastError? */
1368 /* FIXME: correct? We have already scrolled! */
1376 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1382 * NtUserScrollWindowEx
1389 NtUserScrollWindowEx(
1393 const RECT
*prcUnsafeScroll
,
1394 const RECT
*prcUnsafeClip
,
1396 LPRECT prcUnsafeUpdate
,
1399 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1401 PWND Window
= NULL
, CaretWnd
;
1403 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1405 NTSTATUS Status
= STATUS_SUCCESS
;
1406 DECLARE_RETURN(DWORD
);
1407 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1409 DPRINT("Enter NtUserScrollWindowEx\n");
1410 UserEnterExclusive();
1412 Window
= UserGetWindowObject(hWnd
);
1413 if (!Window
|| !IntIsWindowDrawable(Window
))
1415 Window
= NULL
; /* prevent deref at cleanup */
1418 UserRefObjectCo(Window
, &Ref
);
1420 IntGetClientRect(Window
, &rcClip
);
1424 if (prcUnsafeScroll
)
1426 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1427 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1434 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1435 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1440 Status
= _SEH2_GetExceptionCode();
1444 if (!NT_SUCCESS(Status
))
1446 SetLastNtError(Status
);
1450 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1451 (dx
== 0 && dy
== 0))
1457 hrgnOwn
= hrgnUpdate
;
1459 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1461 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1464 /* FIXME: SetLastError? */
1469 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1471 Result
= UserScrollDC( hDC
,
1477 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1479 UserReleaseDC(Window
, hDC
, FALSE
);
1482 * Take into account the fact that some damage may have occurred during
1486 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1487 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1489 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1490 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1491 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1492 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1493 REGION_FreeRgnByHandle(hrgnClip
);
1495 REGION_FreeRgnByHandle(hrgnTemp
);
1497 if (flags
& SW_SCROLLCHILDREN
)
1502 USER_REFERENCE_ENTRY WndRef
;
1505 IntGetClientOrigin(Window
, &ClientOrigin
);
1506 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1508 rcChild
= Child
->rcWindow
;
1509 rcChild
.left
-= ClientOrigin
.x
;
1510 rcChild
.top
-= ClientOrigin
.y
;
1511 rcChild
.right
-= ClientOrigin
.x
;
1512 rcChild
.bottom
-= ClientOrigin
.y
;
1514 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1516 UserRefObjectCo(Child
, &WndRef
);
1517 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1518 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1520 UserDerefObjectCo(Child
);
1525 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1527 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1528 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1529 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1532 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1534 UserRefObjectCo(CaretWnd
, &CaretRef
);
1536 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1537 co_UserShowCaret(CaretWnd
);
1539 UserDerefObjectCo(CaretWnd
);
1542 if (prcUnsafeUpdate
)
1546 /* Probe here, to not fail on invalid pointer before scrolling */
1547 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1548 *prcUnsafeUpdate
= rcUpdate
;
1550 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1552 Status
= _SEH2_GetExceptionCode();
1556 if (!NT_SUCCESS(Status
))
1558 SetLastNtError(Status
);
1566 if (hrgnOwn
&& !hrgnUpdate
)
1568 REGION_FreeRgnByHandle(hrgnOwn
);
1572 UserDerefObjectCo(Window
);
1574 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1581 UserDrawSysMenuButton(
1588 PCURICON_OBJECT pIcon
;
1590 ASSERT(pWnd
&& lpRc
);
1592 /* Get the icon to draw. We don't care about WM_GETICON here. */
1594 hIcon
= pWnd
->pcls
->hIconSm
;
1598 DPRINT("Wnd class has no small icon.\n");
1599 hIcon
= pWnd
->pcls
->hIcon
;
1604 DPRINT("Wnd class hasn't any icon.\n");
1605 //FIXME: Draw "winlogo" icon.
1609 if(!(pIcon
= UserGetCurIconObject(hIcon
)))
1611 DPRINT1("UserGetCurIconObject() failed!\n");
1615 return UserDrawIconEx(hDc
, lpRc
->left
, lpRc
->top
, pIcon
,
1616 UserGetSystemMetrics(SM_CXSMICON
),
1617 UserGetSystemMetrics(SM_CYSMICON
),
1618 0, NULL
, DI_NORMAL
);
1622 UserDrawCaptionText(
1624 const PUNICODE_STRING Text
,
1628 HFONT hOldFont
= NULL
, hFont
= NULL
;
1629 COLORREF OldTextColor
;
1630 NONCLIENTMETRICSW nclm
;
1634 DPRINT("%s:", __FUNCTION__
);
1635 for(i
= 0; i
< Text
->Length
/sizeof(WCHAR
); i
++)
1636 DbgPrint("%C", Text
->Buffer
[i
]);
1637 DbgPrint(", %d\n", Text
->Length
/sizeof(WCHAR
));
1640 nclm
.cbSize
= sizeof(nclm
);
1641 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1642 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1644 DPRINT1("%s: UserSystemParametersInfo() failed!\n", __FUNCTION__
);
1648 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1650 if(uFlags
& DC_SMALLCAP
)
1651 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1652 else Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1654 if(!NT_SUCCESS(Status
))
1656 DPRINT1("%s: TextIntCreateFontIndirect() failed! Status: 0x%x\n",
1657 __FUNCTION__
, Status
);
1661 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1664 DPRINT1("%s: SelectFont() failed!\n", __FUNCTION__
);
1665 GreDeleteObject(hFont
);
1669 if(uFlags
& DC_INBUTTON
)
1670 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1671 else OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1672 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1674 //FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1676 GreExtTextOutW(hDc
, lpRc
->left
,
1677 lpRc
->top
, 0, NULL
, Text
->Buffer
,
1678 Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1680 IntGdiSetTextColor(hDc
, OldTextColor
);
1681 NtGdiSelectFont(hDc
, hOldFont
);
1682 GreDeleteObject(hFont
);
1687 BOOL
UserDrawCaption(
1693 const PUNICODE_STRING str
,
1697 HBITMAP hMemBmp
= NULL
, hOldBmp
= NULL
;
1698 HBRUSH hOldBrush
= NULL
;
1701 UINT VCenter
= 0, Padding
= 0;
1703 LONG ButtonWidth
, IconWidth
;
1706 //ASSERT(pWnd != NULL);
1708 RECTL_vMakeWellOrdered(lpRc
);
1709 hMemBmp
= NtGdiCreateCompatibleBitmap(hDc
,
1710 lpRc
->right
- lpRc
->left
,
1711 lpRc
->bottom
- lpRc
->top
);
1715 DPRINT1("%s: NtGdiCreateCompatibleBitmap() failed!\n", __FUNCTION__
);
1719 hMemDc
= NtGdiCreateCompatibleDC(hDc
);
1722 DPRINT1("%s: NtGdiCreateCompatibleDC() failed!\n", __FUNCTION__
);
1726 hOldBmp
= NtGdiSelectBitmap(hMemDc
, hMemBmp
);
1729 DPRINT1("%s: NtGdiSelectBitmap() failed!\n", __FUNCTION__
);
1733 Height
= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1734 VCenter
= (lpRc
->bottom
- lpRc
->top
) / 2;
1735 Padding
= VCenter
- (Height
/ 2);
1737 if ((!hIcon
) && (pWnd
!= NULL
))
1739 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
1740 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1741 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1744 HasIcon
= (hIcon
!= 0);
1746 IconWidth
= UserGetSystemMetrics(SM_CXSIZE
) + Padding
;
1749 r
.right
= r
.left
+ (lpRc
->right
- lpRc
->left
);
1751 r
.bottom
= r
.top
+ (Height
/ 2);
1753 // Draw the caption background
1754 if(uFlags
& DC_INBUTTON
)
1756 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1757 IntGetSysColorBrush(COLOR_3DFACE
));
1761 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1765 if(!NtGdiPatBlt(hMemDc
, 0, 0,
1766 lpRc
->right
- lpRc
->left
,
1767 lpRc
->bottom
- lpRc
->top
,
1770 DPRINT1("%s: NtGdiPatBlt() failed!\n", __FUNCTION__
);
1774 if(HasIcon
) r
.left
+=IconWidth
;
1778 r
.right
= (lpRc
->right
- lpRc
->left
);
1779 if(uFlags
& DC_SMALLCAP
)
1780 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1781 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1783 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1784 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1785 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
1789 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1793 if(HasIcon
&& (uFlags
& DC_GRADIENT
))
1795 NtGdiPatBlt(hMemDc
, 0, 0,
1797 lpRc
->bottom
- lpRc
->top
,
1803 NtGdiPatBlt(hMemDc
, 0, 0,
1804 lpRc
->right
- lpRc
->left
,
1805 lpRc
->bottom
- lpRc
->top
,
1809 if(uFlags
& DC_GRADIENT
)
1811 static GRADIENT_RECT gcap
= {0, 1};
1817 if(pWnd
->style
& WS_SYSMENU
)
1819 r
.right
-= 3 + ButtonWidth
;
1820 if(!(uFlags
& DC_SMALLCAP
))
1822 if(pWnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1823 r
.right
-= 2 + 2 * ButtonWidth
;
1828 //Draw buttons background
1829 if(!NtGdiSelectBrush(hMemDc
,
1830 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1831 COLOR_GRADIENTACTIVECAPTION
:COLOR_GRADIENTINACTIVECAPTION
)))
1833 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1840 lpRc
->right
- lpRc
->left
- r
.right
,
1841 lpRc
->bottom
- lpRc
->top
,
1846 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1847 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1849 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1850 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1854 vert
[0].Red
= (WORD
)Colors
[0]<<8;
1855 vert
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1856 vert
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1859 vert
[1].x
= r
.right
;
1860 vert
[1].y
= lpRc
->bottom
- lpRc
->top
;
1861 vert
[1].Red
= (WORD
)Colors
[1]<<8;
1862 vert
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1863 vert
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1866 if(!GreGradientFill(hMemDc
, vert
, 2, &gcap
,
1867 1, GRADIENT_FILL_RECT_H
))
1869 DPRINT1("%s: IntGdiGradientFill() failed!\n", __FUNCTION__
);
1872 } //if(uFlags & DC_GRADIENT)
1878 r
.left
-= --IconWidth
;
1879 /* FIXME: Draw the Icon when pWnd == NULL but hIcon is valid */
1881 UserDrawSysMenuButton(pWnd
, hMemDc
, &r
, FALSE
);
1883 r
.left
+= IconWidth
;
1890 r
.bottom
= r
.top
+ Height
;
1892 if((uFlags
& DC_TEXT
))
1894 if(!(uFlags
& DC_GRADIENT
))
1896 r
.right
= (lpRc
->right
- lpRc
->left
);
1898 if(uFlags
& DC_SMALLCAP
)
1899 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1900 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1902 if ((pWnd
!= NULL
) && (pWnd
->style
& WS_SYSMENU
))
1904 r
.right
-= 3 + ButtonWidth
;
1905 if(! (uFlags
& DC_SMALLCAP
))
1907 if(pWnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1908 r
.right
-= 2 + 2 * ButtonWidth
;
1915 /* FIXME: hFont isn't handled */
1917 UserDrawCaptionText(hMemDc
, str
, &r
, uFlags
);
1918 else if (pWnd
!= NULL
)
1920 UNICODE_STRING ustr
;
1921 ustr
.Buffer
= pWnd
->strName
.Buffer
;
1922 ustr
.Length
= pWnd
->strName
.Length
;
1923 ustr
.MaximumLength
= pWnd
->strName
.MaximumLength
;
1924 UserDrawCaptionText(hMemDc
, &ustr
, &r
, uFlags
);
1928 if(!NtGdiBitBlt(hDc
, lpRc
->left
, lpRc
->top
,
1929 lpRc
->right
- lpRc
->left
, lpRc
->bottom
- lpRc
->top
,
1930 hMemDc
, 0, 0, SRCCOPY
, 0, 0))
1932 DPRINT1("%s: NtGdiBitBlt() failed!\n", __FUNCTION__
);
1939 if (hOldBrush
) NtGdiSelectBrush(hMemDc
, hOldBrush
);
1940 if (hOldBmp
) NtGdiSelectBitmap(hMemDc
, hOldBmp
);
1941 if (hMemBmp
) GreDeleteObject(hMemBmp
);
1942 if (hMemDc
) NtGdiDeleteObjectApp(hMemDc
);
1949 UserRealizePalette(HDC hdc
)
1954 Ret
= IntGdiRealizePalette(hdc
);
1955 if (Ret
) // There was a change.
1957 hWnd
= IntWindowFromDC(hdc
);
1958 if (hWnd
) // Send broadcast if dc is associated with a window.
1959 { // FYI: Thread locked in CallOneParam.
1960 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1968 NtUserDrawCaptionTemp(
1974 const PUNICODE_STRING str
,
1978 UNICODE_STRING SafeStr
= {0};
1979 NTSTATUS Status
= STATUS_SUCCESS
;
1983 UserEnterExclusive();
1987 if(!(pWnd
= UserGetWindowObject(hWnd
)))
1996 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
1997 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2000 SafeStr
= ProbeForReadUnicodeString(str
);
2001 if (SafeStr
.Length
!= 0)
2003 ProbeForRead( SafeStr
.Buffer
,
2009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2011 Status
= _SEH2_GetExceptionCode();
2015 if (Status
!= STATUS_SUCCESS
)
2017 SetLastNtError(Status
);
2023 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2025 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2033 NtUserDrawCaption(HWND hWnd
,
2038 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2043 NtUserInvalidateRect(
2045 CONST RECT
*lpUnsafeRect
,
2048 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2053 NtUserInvalidateRgn(
2058 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2071 UserEnterExclusive();
2075 Window
= UserGetWindowObject(hwnd
);
2076 // TODO: Add Desktop and MessageBox check via FNID's.
2079 /* Validate flags and check it as a mask for 0 or 1. */
2080 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2081 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2083 EngSetLastError(ERROR_INVALID_PARAMETER
);
2091 /* ValidateRect gets redirected to NtUserValidateRect:
2092 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2101 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2103 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);