2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window painting function
5 * FILE: subsystems/win32/win32k/ntuser/painting.c
6 * PROGRAMER: Filip Navara (xnavara@volny.cz)
10 DBG_DEFAULT_CHANNEL(UserPainting
);
12 /* PRIVATE FUNCTIONS **********************************************************/
15 * @name IntIntersectWithParents
17 * Intersect window rectangle with all parent client rectangles.
20 * Pointer to child window to start intersecting from.
22 * Pointer to rectangle that we want to intersect in screen
23 * coordinates on input and intersected rectangle on output (if TRUE
27 * If any parent is minimized or invisible or the resulting rectangle
28 * is empty then FALSE is returned. Otherwise TRUE is returned.
32 IntIntersectWithParents(PWND Child
, RECTL
*WindowRect
)
36 ParentWnd
= Child
->spwndParent
;
37 while (ParentWnd
!= NULL
)
39 if (!(ParentWnd
->style
& WS_VISIBLE
) ||
40 (ParentWnd
->style
& WS_MINIMIZE
))
45 if (!RECTL_bIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->rcClient
))
50 /* FIXME: Layered windows. */
52 ParentWnd
= ParentWnd
->spwndParent
;
59 IntValidateParent(PWND Child
, HRGN hValidateRgn
, BOOL Recurse
)
61 PWND ParentWnd
= Child
->spwndParent
;
65 if (ParentWnd
->style
& WS_CLIPCHILDREN
)
68 if (ParentWnd
->hrgnUpdate
!= 0)
73 IntInvalidateWindows( ParentWnd
,
75 RDW_VALIDATE
| RDW_NOCHILDREN
);
78 ParentWnd
= ParentWnd
->spwndParent
;
85 * @name IntCalcWindowRgn
87 * Get a window or client region.
91 IntCalcWindowRgn(PWND Wnd
, BOOL Client
)
96 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
98 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
100 if (Wnd
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
102 NtGdiOffsetRgn(hRgnWindow
,
105 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Wnd
->hrgnClip
, RGN_AND
);
106 NtGdiOffsetRgn(hRgnWindow
,
115 * @name IntGetNCUpdateRgn
117 * Get non-client update region of a window and optionally validate it.
120 * Pointer to window to get the NC update region from.
122 * Set to TRUE to force validating the NC update region.
125 * Handle to NC update region. The caller is responsible for deleting
130 IntGetNCUpdateRgn(PWND Window
, BOOL Validate
)
136 if (Window
->hrgnUpdate
!= NULL
&&
137 Window
->hrgnUpdate
!= HRGN_WINDOW
)
139 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
142 * If region creation fails it's safe to fallback to whole
145 if (hRgnNonClient
== NULL
)
150 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
151 if (hRgnWindow
== NULL
)
153 GreDeleteObject(hRgnNonClient
);
157 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
158 hRgnWindow
, RGN_DIFF
);
159 if (RgnType
== ERROR
)
161 GreDeleteObject(hRgnWindow
);
162 GreDeleteObject(hRgnNonClient
);
165 else if (RgnType
== NULLREGION
)
167 GreDeleteObject(hRgnWindow
);
168 GreDeleteObject(hRgnNonClient
);
173 * Remove the nonclient region from the standard update region if
174 * we were asked for it.
179 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
180 hRgnWindow
, RGN_AND
) == NULLREGION
)
182 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
183 GreDeleteObject(Window
->hrgnUpdate
);
184 Window
->hrgnUpdate
= NULL
;
185 if (!(Window
->state
& WNDS_INTERNALPAINT
))
186 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
190 GreDeleteObject(hRgnWindow
);
192 return hRgnNonClient
;
196 return Window
->hrgnUpdate
;
203 * Internal function used by IntRedrawWindow.
207 co_IntPaintWindows(PWND Wnd
, ULONG Flags
, BOOL Recurse
)
210 HWND hWnd
= Wnd
->head
.h
;
213 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
217 if (!IntValidateParent(Wnd
, Wnd
->hrgnUpdate
, Recurse
))
221 if (Flags
& RDW_UPDATENOW
)
223 if (Wnd
->hrgnUpdate
!= NULL
||
224 Wnd
->state
& WNDS_INTERNALPAINT
)
226 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
231 if (Wnd
->state
& WNDS_SENDNCPAINT
)
233 TempRegion
= IntGetNCUpdateRgn(Wnd
, TRUE
);
234 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
235 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
236 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
240 if (Wnd
->state
& WNDS_SENDERASEBACKGROUND
)
244 hDC
= UserGetDCEx( Wnd
,
246 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
248 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
249 // Kill the loop, so Clear before we send.
250 if (!co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
252 Wnd
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
254 UserReleaseDC(Wnd
, hDC
, FALSE
);
261 * Check that the window is still valid at this point
263 if (!IntIsWindow(hWnd
))
269 * Paint child windows.
271 if (!(Flags
& RDW_NOCHILDREN
) &&
272 !(Wnd
->style
& WS_MINIMIZE
) &&
273 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
277 if ((List
= IntWinListChildren(Wnd
)))
279 /* FIXME: Handle WS_EX_TRANSPARENT */
280 for (phWnd
= List
; *phWnd
; ++phWnd
)
282 Wnd
= UserGetWindowObject(*phWnd
);
283 if (Wnd
&& (Wnd
->style
& WS_VISIBLE
))
285 USER_REFERENCE_ENTRY Ref
;
286 UserRefObjectCo(Wnd
, &Ref
);
287 co_IntPaintWindows(Wnd
, Flags
, TRUE
);
288 UserDerefObjectCo(Wnd
);
297 * IntInvalidateWindows
299 * Internal function used by IntRedrawWindow, UserRedrawDesktop,
300 * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
303 IntInvalidateWindows(PWND Wnd
, HRGN hRgn
, ULONG Flags
)
306 BOOL HadPaintMessage
, HadNCPaintMessage
;
307 BOOL HasPaintMessage
, HasNCPaintMessage
;
309 TRACE("IntInvalidateWindows start\n");
311 * If the nonclient is not to be redrawn, clip the region to the client
314 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
318 hRgnClient
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
319 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
320 GreDeleteObject(hRgnClient
);
324 * Clip the given region with window rectangle (or region)
327 if (!Wnd
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
331 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
332 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
333 GreDeleteObject(hRgnWindow
);
337 NtGdiOffsetRgn( hRgn
,
340 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Wnd
->hrgnClip
, RGN_AND
);
341 NtGdiOffsetRgn( hRgn
,
347 * Save current state of pending updates
350 HadPaintMessage
= Wnd
->hrgnUpdate
!= NULL
||
351 Wnd
->state
& WNDS_INTERNALPAINT
;
352 HadNCPaintMessage
= Wnd
->state
& WNDS_SENDNCPAINT
;
355 * Update the region and flags
358 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
360 if (Wnd
->hrgnUpdate
== NULL
)
362 Wnd
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
363 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
366 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
367 hRgn
, RGN_OR
) == NULLREGION
)
369 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
370 GreDeleteObject(Wnd
->hrgnUpdate
);
371 Wnd
->hrgnUpdate
= NULL
;
374 if (Flags
& RDW_FRAME
)
375 Wnd
->state
|= WNDS_SENDNCPAINT
;
376 if (Flags
& RDW_ERASE
)
377 Wnd
->state
|= WNDS_SENDERASEBACKGROUND
;
382 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
384 if (Wnd
->hrgnUpdate
!= NULL
)
386 if (NtGdiCombineRgn(Wnd
->hrgnUpdate
, Wnd
->hrgnUpdate
,
387 hRgn
, RGN_DIFF
) == NULLREGION
)
389 IntGdiSetRegionOwner(Wnd
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
390 GreDeleteObject(Wnd
->hrgnUpdate
);
391 Wnd
->hrgnUpdate
= NULL
;
395 if (Wnd
->hrgnUpdate
== NULL
)
396 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
397 if (Flags
& RDW_NOFRAME
)
398 Wnd
->state
&= ~WNDS_SENDNCPAINT
;
399 if (Flags
& RDW_NOERASE
)
400 Wnd
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
403 if (Flags
& RDW_INTERNALPAINT
)
405 Wnd
->state
|= WNDS_INTERNALPAINT
;
408 if (Flags
& RDW_NOINTERNALPAINT
)
410 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
414 * Process children if needed
417 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
418 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
422 for (Child
= Wnd
->spwndChild
; Child
; Child
= Child
->spwndNext
)
424 if (Child
->style
& WS_VISIBLE
)
427 * Recursive call to update children hrgnUpdate
429 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
430 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
431 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
432 GreDeleteObject(hRgnTemp
);
439 * Fake post paint messages to window message queue if needed
442 HasPaintMessage
= Wnd
->hrgnUpdate
!= NULL
||
443 Wnd
->state
& WNDS_INTERNALPAINT
;
444 HasNCPaintMessage
= Wnd
->state
& WNDS_SENDNCPAINT
;
446 if (HasPaintMessage
!= HadPaintMessage
)
449 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
451 MsqIncPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
454 if (HasNCPaintMessage
!= HadNCPaintMessage
)
456 if (HadNCPaintMessage
)
457 MsqDecPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
459 MsqIncPaintCountQueue(Wnd
->head
.pti
->MessageQueue
);
461 TRACE("IntInvalidateWindows exit\n");
465 * IntIsWindowDrawable
468 * Window is drawable when it is visible and all parents are not
473 IntIsWindowDrawable(PWND Wnd
)
477 for (WndObject
= Wnd
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
479 if ( WndObject
->state2
& WNDS2_INDESTROY
||
480 WndObject
->state
& WNDS_DESTROYED
||
482 !(WndObject
->style
& WS_VISIBLE
) ||
483 ((WndObject
->style
& WS_MINIMIZE
) && (WndObject
!= Wnd
)))
495 * Internal version of NtUserRedrawWindow that takes WND as
502 const RECTL
* UpdateRect
,
507 TRACE("co_UserRedrawWindow start\n");
511 * Validation of passed parameters.
514 if (!IntIsWindowDrawable(Window
))
516 return TRUE
; // Just do nothing!!!
521 * Transform the parameters UpdateRgn and UpdateRect into
522 * a region hRgn specified in screen coordinates.
525 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
527 if (UpdateRgn
!= NULL
)
529 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
530 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
532 GreDeleteObject(hRgn
);
536 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
538 else if (UpdateRect
!= NULL
)
540 if (!RECTL_bIsEmptyRect(UpdateRect
))
542 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
543 NtGdiOffsetRgn(hRgn
, Window
->rcClient
.left
, Window
->rcClient
.top
);
546 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
547 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
549 if (!RECTL_bIsEmptyRect(&Window
->rcWindow
))
550 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
554 if (!RECTL_bIsEmptyRect(&Window
->rcClient
))
555 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcClient
);
561 * Adjust the window update region depending on hRgn and flags.
564 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
567 IntInvalidateWindows(Window
, hRgn
, Flags
);
572 * Repaint and erase windows if needed.
575 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
577 co_IntPaintWindows(Window
, Flags
, FALSE
);
587 GreDeleteObject(hRgn
);
589 TRACE("co_UserRedrawWindow exit\n");
595 IntIsWindowDirty(PWND Wnd
)
597 return (Wnd
->style
& WS_VISIBLE
) &&
598 ((Wnd
->hrgnUpdate
!= NULL
) ||
599 (Wnd
->state
& WNDS_INTERNALPAINT
) ||
600 (Wnd
->state
& WNDS_SENDNCPAINT
));
604 IntFindWindowToRepaint(PWND Window
, PTHREADINFO Thread
)
609 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
611 if (IntWndBelongsToThread(Window
, Thread
) &&
612 IntIsWindowDirty(Window
))
614 /* Make sure all non-transparent siblings are already drawn. */
615 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
617 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
618 TempWindow
= TempWindow
->spwndNext
)
620 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
621 IntWndBelongsToThread(TempWindow
, Thread
) &&
622 IntIsWindowDirty(TempWindow
))
624 return TempWindow
->head
.h
;
629 return Window
->head
.h
;
632 if (Window
->spwndChild
)
634 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
652 if (!Thread
->cPaintsReady
)
655 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
656 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
659 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
661 if (Message
->hwnd
== NULL
)
663 ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread
->cPaintsReady
);
664 /* Hack to stop spamming the debuglog ! */
665 Thread
->cPaintsReady
= 0;
669 if (Window
!= NULL
&& Message
->hwnd
!= Window
->head
.h
)
672 Message
->message
= WM_PAINT
;
673 Message
->wParam
= Message
->lParam
= 0;
680 co_IntFixCaret(PWND Window
, RECTL
*lprc
, UINT flags
)
683 PTHRDCARETINFO CaretInfo
;
685 PUSER_MESSAGE_QUEUE ActiveMessageQueue
;
689 ASSERT_REFS_CO(Window
);
691 pti
= PsGetCurrentThreadWin32Thread();
692 Desktop
= pti
->rpdesk
;
693 ActiveMessageQueue
= Desktop
->ActiveMessageQueue
;
694 if (!ActiveMessageQueue
) return 0;
695 CaretInfo
= ActiveMessageQueue
->CaretInfo
;
696 hWndCaret
= CaretInfo
->hWnd
;
698 WndCaret
= UserGetWindowObject(hWndCaret
);
700 // FIXME: Check for WndCaret can be NULL
701 if (WndCaret
== Window
||
702 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
704 POINT pt
, FromOffset
, ToOffset
;
707 pt
.x
= CaretInfo
->Pos
.x
;
708 pt
.y
= CaretInfo
->Pos
.y
;
709 IntGetClientOrigin(WndCaret
, &FromOffset
);
710 IntGetClientOrigin(Window
, &ToOffset
);
713 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
714 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
715 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
735 INT cx
, cy
, xSrc
, ySrc
;
737 if ( nFlags
& PW_CLIENTONLY
)
739 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
740 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
741 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
742 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
746 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
747 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
752 // TODO: Setup Redirection for Print.
755 /* Update the window just incase. */
756 co_IntPaintWindows( pwnd
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
758 hdcSrc
= UserGetDCEx( pwnd
, NULL
, DCX_CACHE
|DCX_WINDOW
);
759 /* Print window to printer context. */
772 UserReleaseDC( pwnd
, hdcSrc
, FALSE
);
774 // TODO: Release Redirection from Print.
781 IntFlashWindowEx(PWND pWnd
, PFLASHWINFO pfwi
)
787 pprop
= IntGetProp(pWnd
, AtomFlashWndState
);
790 FlashState
= pfwi
->dwFlags
;
791 IntSetProp(pWnd
, AtomFlashWndState
, (HANDLE
) FlashState
);
795 FlashState
= (DWORD
)pprop
->Data
;
796 if ( pfwi
->dwFlags
== FLASHW_STOP
)
798 IntRemoveProp(pWnd
, AtomFlashWndState
);
804 /* PUBLIC FUNCTIONS ***********************************************************/
814 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
820 USER_REFERENCE_ENTRY Ref
;
822 TRACE("Enter NtUserBeginPaint\n");
823 UserEnterExclusive();
825 if (!(Window
= UserGetWindowObject(hWnd
)))
830 UserRefObjectCo(Window
, &Ref
);
832 co_UserHideCaret(Window
);
834 if (Window
->state
& WNDS_SENDNCPAINT
)
838 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
839 Window
->state
&= ~WNDS_SENDNCPAINT
;
840 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
841 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
842 if (hRgn
!= HRGN_WINDOW
&& hRgn
!= NULL
&& GreIsHandleValid(hRgn
))
844 /* NOTE: The region can already by deleted! */
845 GreDeleteObject(hRgn
);
849 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
851 Ps
.hdc
= UserGetDCEx( Window
,
853 DCX_INTERSECTRGN
| DCX_USESTYLE
);
859 if (Window
->hrgnUpdate
!= NULL
)
861 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
862 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
863 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
864 /* The region is part of the dc now and belongs to the process! */
865 Window
->hrgnUpdate
= NULL
;
869 if (Window
->state
& WNDS_INTERNALPAINT
)
870 MsqDecPaintCountQueue(Window
->head
.pti
->MessageQueue
);
872 IntGetClientRect(Window
, &Ps
.rcPaint
);
875 Window
->state
&= ~WNDS_INTERNALPAINT
;
877 if (Window
->state
& WNDS_SENDERASEBACKGROUND
)
879 Window
->state
&= ~(WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
880 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
883 Window
->state
|= (WNDS_SENDERASEBACKGROUND
|WNDS_ERASEBACKGROUND
);
890 if (Window
->hrgnUpdate
)
892 if (!(Window
->style
& WS_CLIPCHILDREN
))
895 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
897 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
902 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
903 if (! NT_SUCCESS(Status
))
905 SetLastNtError(Status
);
912 if (Window
) UserDerefObjectCo(Window
);
914 TRACE("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
928 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
930 NTSTATUS Status
= STATUS_SUCCESS
;
932 DECLARE_RETURN(BOOL
);
933 USER_REFERENCE_ENTRY Ref
;
936 TRACE("Enter NtUserEndPaint\n");
937 UserEnterExclusive();
939 if (!(Window
= UserGetWindowObject(hWnd
)))
946 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
947 hdc
= pUnsafePs
->hdc
;
949 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
951 Status
= _SEH2_GetExceptionCode();
954 if (!NT_SUCCESS(Status
))
959 UserReleaseDC(Window
, hdc
, TRUE
);
961 UserRefObjectCo(Window
, &Ref
);
962 co_UserShowCaret(Window
);
963 UserDerefObjectCo(Window
);
968 TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_
);
977 NtUserFlashWindowEx(IN PFLASHWINFO pfwi
)
980 FLASHWINFO finfo
= {0};
983 UserEnterExclusive();
987 ProbeForRead(pfwi
, sizeof(FLASHWINFO
), sizeof(ULONG
));
988 RtlCopyMemory(&finfo
, pfwi
, sizeof(FLASHWINFO
));
990 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
992 SetLastNtError(_SEH2_GetExceptionCode());
999 if (!( pWnd
= (PWND
)UserGetObject(gHandleTable
, finfo
.hwnd
, otWindow
)) ||
1000 finfo
.cbSize
!= sizeof(FLASHWINFO
) ||
1001 finfo
.dwFlags
& ~(FLASHW_ALL
|FLASHW_TIMER
|FLASHW_TIMERNOFG
) )
1003 EngSetLastError(ERROR_INVALID_PARAMETER
);
1008 Ret
= IntFlashWindowEx(pWnd
, &finfo
);
1016 co_UserGetUpdateRgn(PWND Window
, HRGN hRgn
, BOOL bErase
)
1021 ASSERT_REFS_CO(Window
);
1023 if (Window
->hrgnUpdate
== NULL
)
1025 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
1029 Rect
= Window
->rcClient
;
1030 IntIntersectWithParents(Window
, &Rect
);
1031 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
1032 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
1033 NtGdiOffsetRgn(hRgn
, -Window
->rcClient
.left
, -Window
->rcClient
.top
);
1036 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1038 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1045 * NtUserGetUpdateRgn
1052 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1054 DECLARE_RETURN(INT
);
1057 USER_REFERENCE_ENTRY Ref
;
1059 TRACE("Enter NtUserGetUpdateRgn\n");
1060 UserEnterExclusive();
1062 if (!(Window
= UserGetWindowObject(hWnd
)))
1067 UserRefObjectCo(Window
, &Ref
);
1068 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1069 UserDerefObjectCo(Window
);
1074 TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1080 * NtUserGetUpdateRect
1087 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1092 PROSRGNDATA RgnData
;
1094 DECLARE_RETURN(BOOL
);
1096 TRACE("Enter NtUserGetUpdateRect\n");
1097 UserEnterExclusive();
1099 if (!(Window
= UserGetWindowObject(hWnd
)))
1104 if (Window
->hrgnUpdate
== NULL
)
1106 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1110 /* Get the update region bounding box. */
1111 if (Window
->hrgnUpdate
== HRGN_WINDOW
)
1113 Rect
= Window
->rcClient
;
1117 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1118 ASSERT(RgnData
!= NULL
);
1119 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1120 RGNOBJAPI_Unlock(RgnData
);
1122 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1123 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->rcClient
);
1126 if (IntIntersectWithParents(Window
, &Rect
))
1128 RECTL_vOffsetRect(&Rect
,
1129 -Window
->rcClient
.left
,
1130 -Window
->rcClient
.top
);
1133 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1137 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1139 USER_REFERENCE_ENTRY Ref
;
1140 UserRefObjectCo(Window
, &Ref
);
1141 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1142 UserDerefObjectCo(Window
);
1145 if (UnsafeRect
!= NULL
)
1147 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1148 if (!NT_SUCCESS(Status
))
1150 EngSetLastError(ERROR_INVALID_PARAMETER
);
1155 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1158 TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1164 * NtUserRedrawWindow
1173 CONST RECT
*lprcUpdate
,
1177 RECTL SafeUpdateRect
;
1180 USER_REFERENCE_ENTRY Ref
;
1181 NTSTATUS Status
= STATUS_SUCCESS
;
1182 DECLARE_RETURN(BOOL
);
1184 TRACE("Enter NtUserRedrawWindow\n");
1185 UserEnterExclusive();
1187 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1196 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1197 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1201 Status
= _SEH2_GetExceptionCode();
1204 if (!NT_SUCCESS(Status
))
1206 EngSetLastError(RtlNtStatusToDosError(Status
));
1211 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1212 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1213 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1215 /* RedrawWindow fails only in case that flags are invalid */
1216 EngSetLastError(ERROR_INVALID_FLAGS
);
1220 UserRefObjectCo(Wnd
, &Ref
);
1222 Ret
= co_UserRedrawWindow( Wnd
,
1223 lprcUpdate
? &SafeUpdateRect
: NULL
,
1227 UserDerefObjectCo(Wnd
);
1232 TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1243 const RECTL
*prcScroll
,
1244 const RECTL
*prcClip
,
1249 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1252 GdiGetClipBox(hDC
, &rcClip
);
1256 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1261 rcScroll
= *prcScroll
;
1262 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1270 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1271 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1273 if (!NtGdiBitBlt( hDC
,
1276 rcDst
.right
- rcDst
.left
,
1277 rcDst
.bottom
- rcDst
.top
,
1288 /* Calculate the region that was invalidated by moving or
1289 could not be copied, because it was not visible */
1290 if (hrgnUpdate
|| prcUpdate
)
1292 HRGN hrgnOwn
, hrgnTmp
;
1295 pDC
= DC_LockDc(hDC
);
1301 /* Begin with the shifted and then clipped scroll rect */
1303 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1304 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1307 hrgnOwn
= hrgnUpdate
;
1308 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1316 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1319 /* Add the source rect */
1320 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1321 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1323 /* Substract the part of the dest that was visible in source */
1324 prgnTmp
= RGNOBJAPI_Lock(hrgnTmp
, NULL
);
1325 IntGdiCombineRgn(prgnTmp
, prgnTmp
, pDC
->prgnVis
, RGN_AND
);
1326 RGNOBJAPI_Unlock(prgnTmp
);
1327 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1328 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1330 /* DO NOT Unlock DC while messing with prgnVis! */
1333 GreDeleteObject(hrgnTmp
);
1337 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1342 GreDeleteObject(hrgnOwn
);
1346 Result
= NULLREGION
;
1362 const RECT
*prcUnsafeScroll
,
1363 const RECT
*prcUnsafeClip
,
1365 LPRECT prcUnsafeUpdate
)
1367 DECLARE_RETURN(DWORD
);
1368 RECTL rcScroll
, rcClip
, rcUpdate
;
1369 NTSTATUS Status
= STATUS_SUCCESS
;
1372 TRACE("Enter NtUserScrollDC\n");
1373 UserEnterExclusive();
1377 if (prcUnsafeScroll
)
1379 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1380 rcScroll
= *prcUnsafeScroll
;
1384 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1385 rcClip
= *prcUnsafeClip
;
1387 if (prcUnsafeUpdate
)
1389 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1394 Status
= _SEH2_GetExceptionCode();
1397 if (!NT_SUCCESS(Status
))
1399 SetLastNtError(Status
);
1403 Result
= UserScrollDC( hDC
,
1406 prcUnsafeScroll
? &rcScroll
: 0,
1407 prcUnsafeClip
? &rcClip
: 0,
1409 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1412 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1416 if (prcUnsafeUpdate
)
1420 *prcUnsafeUpdate
= rcUpdate
;
1422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1424 Status
= _SEH2_GetExceptionCode();
1427 if (!NT_SUCCESS(Status
))
1429 /* FIXME: SetLastError? */
1430 /* FIXME: correct? We have already scrolled! */
1438 TRACE("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1444 * NtUserScrollWindowEx
1451 NtUserScrollWindowEx(
1455 const RECT
*prcUnsafeScroll
,
1456 const RECT
*prcUnsafeClip
,
1458 LPRECT prcUnsafeUpdate
,
1461 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1463 PWND Window
= NULL
, CaretWnd
;
1465 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1467 NTSTATUS Status
= STATUS_SUCCESS
;
1468 DECLARE_RETURN(DWORD
);
1469 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1471 TRACE("Enter NtUserScrollWindowEx\n");
1472 UserEnterExclusive();
1474 Window
= UserGetWindowObject(hWnd
);
1475 if (!Window
|| !IntIsWindowDrawable(Window
))
1477 Window
= NULL
; /* prevent deref at cleanup */
1480 UserRefObjectCo(Window
, &Ref
);
1482 IntGetClientRect(Window
, &rcClip
);
1486 if (prcUnsafeScroll
)
1488 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1489 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1496 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1497 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1502 Status
= _SEH2_GetExceptionCode();
1506 if (!NT_SUCCESS(Status
))
1508 SetLastNtError(Status
);
1512 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1513 (dx
== 0 && dy
== 0))
1519 hrgnOwn
= hrgnUpdate
;
1521 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1523 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1526 /* FIXME: SetLastError? */
1531 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1533 Result
= UserScrollDC( hDC
,
1539 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1541 UserReleaseDC(Window
, hDC
, FALSE
);
1544 * Take into account the fact that some damage may have occurred during
1548 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1549 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1551 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1552 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1553 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1554 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1555 GreDeleteObject(hrgnClip
);
1557 GreDeleteObject(hrgnTemp
);
1559 if (flags
& SW_SCROLLCHILDREN
)
1564 USER_REFERENCE_ENTRY WndRef
;
1567 IntGetClientOrigin(Window
, &ClientOrigin
);
1568 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1570 rcChild
= Child
->rcWindow
;
1571 rcChild
.left
-= ClientOrigin
.x
;
1572 rcChild
.top
-= ClientOrigin
.y
;
1573 rcChild
.right
-= ClientOrigin
.x
;
1574 rcChild
.bottom
-= ClientOrigin
.y
;
1576 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1578 UserRefObjectCo(Child
, &WndRef
);
1579 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1580 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1582 UserDerefObjectCo(Child
);
1587 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1589 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1590 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1591 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1594 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1596 UserRefObjectCo(CaretWnd
, &CaretRef
);
1598 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1599 co_UserShowCaret(CaretWnd
);
1601 UserDerefObjectCo(CaretWnd
);
1604 if (prcUnsafeUpdate
)
1608 /* Probe here, to not fail on invalid pointer before scrolling */
1609 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1610 *prcUnsafeUpdate
= rcUpdate
;
1612 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1614 Status
= _SEH2_GetExceptionCode();
1618 if (!NT_SUCCESS(Status
))
1620 SetLastNtError(Status
);
1628 if (hrgnOwn
&& !hrgnUpdate
)
1630 GreDeleteObject(hrgnOwn
);
1634 UserDerefObjectCo(Window
);
1636 TRACE("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1642 UserDrawCaptionText(
1644 const PUNICODE_STRING Text
,
1649 HFONT hOldFont
= NULL
;
1650 COLORREF OldTextColor
;
1651 NONCLIENTMETRICSW nclm
;
1653 BOOLEAN bDeleteFont
= FALSE
;
1656 TRACE("UserDrawCaptionText: %wZ\n", Text
);
1658 nclm
.cbSize
= sizeof(nclm
);
1659 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1660 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1662 ERR("UserSystemParametersInfo() failed!\n");
1668 if(uFlags
& DC_SMALLCAP
)
1669 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1671 Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1673 if(!NT_SUCCESS(Status
))
1675 ERR("TextIntCreateFontIndirect() failed! Status: 0x%x\n", Status
);
1682 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1684 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1687 ERR("SelectFont() failed!\n");
1691 if(uFlags
& DC_INBUTTON
)
1692 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1694 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1695 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1697 // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1698 GreGetTextExtentW(hDc
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), &Size
, 0);
1700 lpRc
->left
, (lpRc
->top
+ lpRc
->bottom
)/2 - Size
.cy
/2,
1701 0, NULL
, Text
->Buffer
, Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1703 IntGdiSetTextColor(hDc
, OldTextColor
);
1705 NtGdiSelectFont(hDc
, hOldFont
);
1707 GreDeleteObject(hFont
);
1712 BOOL
UserDrawCaption(
1718 const PUNICODE_STRING Str
,
1722 HBRUSH hBgBrush
, hOldBrush
= NULL
;
1726 RECTL_vMakeWellOrdered(lpRc
);
1728 if (!hIcon
&& pWnd
!= NULL
)
1730 HasIcon
= (uFlags
& DC_ICON
) && (pWnd
->style
& WS_SYSMENU
)
1731 && !(uFlags
& DC_SMALLCAP
) && !(pWnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1732 && !(pWnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1735 HasIcon
= (hIcon
!= 0);
1737 // Draw the caption background
1738 if((uFlags
& DC_GRADIENT
) && !(uFlags
& DC_INBUTTON
))
1740 static GRADIENT_RECT gcap
= {0, 1};
1741 TRIVERTEX Vertices
[2];
1744 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1745 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1747 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1748 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1750 Vertices
[0].x
= Rect
.left
;
1751 Vertices
[0].y
= Rect
.top
;
1752 Vertices
[0].Red
= (WORD
)Colors
[0]<<8;
1753 Vertices
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1754 Vertices
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1755 Vertices
[0].Alpha
= 0;
1757 Vertices
[1].x
= Rect
.right
;
1758 Vertices
[1].y
= Rect
.bottom
;
1759 Vertices
[1].Red
= (WORD
)Colors
[1]<<8;
1760 Vertices
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1761 Vertices
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1762 Vertices
[1].Alpha
= 0;
1764 if(!GreGradientFill(hDc
, Vertices
, 2, &gcap
, 1, GRADIENT_FILL_RECT_H
))
1766 ERR("GreGradientFill() failed!\n");
1772 if(uFlags
& DC_INBUTTON
)
1773 hBgBrush
= IntGetSysColorBrush(COLOR_3DFACE
);
1774 else if(uFlags
& DC_ACTIVE
)
1775 hBgBrush
= IntGetSysColorBrush(COLOR_ACTIVECAPTION
);
1777 hBgBrush
= IntGetSysColorBrush(COLOR_INACTIVECAPTION
);
1779 hOldBrush
= NtGdiSelectBrush(hDc
, hBgBrush
);
1783 ERR("NtGdiSelectBrush() failed!\n");
1787 if(!NtGdiPatBlt(hDc
, Rect
.left
, Rect
.top
,
1788 Rect
.right
- Rect
.left
,
1789 Rect
.bottom
- Rect
.top
,
1792 ERR("NtGdiPatBlt() failed!\n");
1800 PCURICON_OBJECT pIcon
= NULL
;
1804 hIcon
= pWnd
->pcls
->hIconSm
; // FIXME: Windows does not do that
1806 hIcon
= pWnd
->pcls
->hIcon
;
1810 pIcon
= UserGetCurIconObject(hIcon
);
1814 LONG cx
= UserGetSystemMetrics(SM_CXSMICON
);
1815 LONG cy
= UserGetSystemMetrics(SM_CYSMICON
);
1816 LONG x
= Rect
.left
- cx
/2 + 1 + (Rect
.bottom
- Rect
.top
)/2; // this is really what Window does
1817 LONG y
= (Rect
.top
+ Rect
.bottom
)/2 - cy
/2; // center
1818 UserDrawIconEx(hDc
, x
, y
, pIcon
, cx
, cy
, 0, NULL
, DI_NORMAL
);
1823 Rect
.left
+= Rect
.bottom
- Rect
.top
;
1825 if((uFlags
& DC_TEXT
))
1830 UserDrawCaptionText(hDc
, Str
, &Rect
, uFlags
, hFont
);
1831 else if (pWnd
!= NULL
) // FIXME: Windows does not do that
1833 UNICODE_STRING ustr
;
1834 ustr
.Buffer
= pWnd
->strName
.Buffer
; // FIXME: LARGE_STRING truncated!
1835 ustr
.Length
= (USHORT
)min(pWnd
->strName
.Length
, MAXUSHORT
);
1836 ustr
.MaximumLength
= (USHORT
)min(pWnd
->strName
.MaximumLength
, MAXUSHORT
);
1837 UserDrawCaptionText(hDc
, &ustr
, &Rect
, uFlags
, hFont
);
1844 if (hOldBrush
) NtGdiSelectBrush(hDc
, hOldBrush
);
1851 UserRealizePalette(HDC hdc
)
1856 Ret
= IntGdiRealizePalette(hdc
);
1857 if (Ret
) // There was a change.
1859 hWnd
= IntWindowFromDC(hdc
);
1860 if (hWnd
) // Send broadcast if dc is associated with a window.
1861 { // FYI: Thread locked in CallOneParam.
1862 UserSendNotifyMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1870 NtUserDrawCaptionTemp(
1876 const PUNICODE_STRING str
,
1880 UNICODE_STRING SafeStr
= {0};
1881 NTSTATUS Status
= STATUS_SUCCESS
;
1885 UserEnterExclusive();
1889 if(!(pWnd
= UserGetWindowObject(hWnd
)))
1898 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
1899 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
1902 SafeStr
= ProbeForReadUnicodeString(str
);
1903 if (SafeStr
.Length
!= 0)
1905 ProbeForRead( SafeStr
.Buffer
,
1911 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1913 Status
= _SEH2_GetExceptionCode();
1917 if (Status
!= STATUS_SUCCESS
)
1919 SetLastNtError(Status
);
1925 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
1927 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
1935 NtUserDrawCaption(HWND hWnd
,
1940 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
1945 NtUserInvalidateRect(
1947 CONST RECT
*lpUnsafeRect
,
1950 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
1955 NtUserInvalidateRgn(
1960 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
1973 UserEnterExclusive();
1977 Window
= UserGetWindowObject(hwnd
);
1978 // TODO: Add Desktop and MessageBox check via FNID's.
1981 /* Validate flags and check it as a mask for 0 or 1. */
1982 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
1983 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
1985 EngSetLastError(ERROR_INVALID_PARAMETER
);
1993 /* ValidateRect gets redirected to NtUserValidateRect:
1994 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2003 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2005 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);