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
)
109 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
111 hRgnWindow
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
113 if (Window
->hrgnClip
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
115 NtGdiOffsetRgn(hRgnWindow
,
118 NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Window
->hrgnClip
, RGN_AND
);
119 NtGdiOffsetRgn(hRgnWindow
,
128 * @name IntGetNCUpdateRgn
130 * Get non-client update region of a window and optionally validate it.
133 * Pointer to window to get the NC update region from.
135 * Set to TRUE to force validating the NC update region.
138 * Handle to NC update region. The caller is responsible for deleting
143 IntGetNCUpdateRgn(PWINDOW_OBJECT Window
, BOOL Validate
)
149 if (Window
->hrgnUpdate
!= NULL
&&
150 Window
->hrgnUpdate
!= (HRGN
)1)
152 hRgnNonClient
= IntCalcWindowRgn(Window
, FALSE
);
155 * If region creation fails it's safe to fallback to whole
158 if (hRgnNonClient
== NULL
)
163 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
164 if (hRgnWindow
== NULL
)
166 REGION_FreeRgnByHandle(hRgnNonClient
);
170 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
171 hRgnWindow
, RGN_DIFF
);
172 if (RgnType
== ERROR
)
174 REGION_FreeRgnByHandle(hRgnWindow
);
175 REGION_FreeRgnByHandle(hRgnNonClient
);
178 else if (RgnType
== NULLREGION
)
180 REGION_FreeRgnByHandle(hRgnWindow
);
181 REGION_FreeRgnByHandle(hRgnNonClient
);
186 * Remove the nonclient region from the standard update region if
187 * we were asked for it.
192 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
193 hRgnWindow
, RGN_AND
) == NULLREGION
)
195 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
196 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
197 Window
->hrgnUpdate
= NULL
;
198 if (!(Window
->Wnd
->state
& WNDS_INTERNALPAINT
))
199 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
203 REGION_FreeRgnByHandle(hRgnWindow
);
205 return hRgnNonClient
;
209 return Window
->hrgnUpdate
;
216 * Internal function used by IntRedrawWindow.
220 co_IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
, BOOL Recurse
)
223 HWND hWnd
= Window
->hSelf
;
229 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
231 if (Window
->hrgnUpdate
)
233 if (!IntValidateParent(Window
, Window
->hrgnUpdate
, Recurse
))
237 if (Flags
& RDW_UPDATENOW
)
239 if (Window
->hrgnUpdate
!= NULL
||
240 Wnd
->state
& WNDS_INTERNALPAINT
)
242 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
247 if (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
)
249 TempRegion
= IntGetNCUpdateRgn(Window
, TRUE
);
250 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
251 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
252 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
254 if ( (HANDLE
) 1 != TempRegion
&&
257 /* NOTE: The region can already be deleted! */
258 GDIOBJ_FreeObjByHandle(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
262 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
264 if (Window
->hrgnUpdate
)
266 hDC
= UserGetDCEx( Window
,
268 DCX_CACHE
|DCX_USESTYLE
|DCX_INTERSECTRGN
|DCX_KEEPCLIPRGN
);
270 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
272 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
274 UserReleaseDC(Window
, hDC
, FALSE
);
281 * Check that the window is still valid at this point
283 if (!IntIsWindow(hWnd
))
289 * Paint child windows.
291 if (!(Flags
& RDW_NOCHILDREN
) &&
292 !(Wnd
->style
& WS_MINIMIZE
) &&
293 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)) )
297 if ((List
= IntWinListChildren(Window
)))
299 /* FIXME: Handle WS_EX_TRANSPARENT */
300 for (phWnd
= List
; *phWnd
; ++phWnd
)
302 Window
= UserGetWindowObject(*phWnd
);
304 if (Window
&& (Wnd
->style
& WS_VISIBLE
))
306 USER_REFERENCE_ENTRY Ref
;
307 UserRefObjectCo(Window
, &Ref
);
308 co_IntPaintWindows(Window
, Flags
, TRUE
);
309 UserDerefObjectCo(Window
);
318 * IntInvalidateWindows
320 * Internal function used by IntRedrawWindow.
324 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
328 BOOL HadPaintMessage
, HadNCPaintMessage
;
329 BOOL HasPaintMessage
, HasNCPaintMessage
;
332 DPRINT("IntInvalidateWindows start\n");
334 * If the nonclient is not to be redrawn, clip the region to the client
337 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
341 hRgnClient
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
342 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
343 REGION_FreeRgnByHandle(hRgnClient
);
347 * Clip the given region with window rectangle (or region)
350 if (!Window
->hrgnClip
|| (Wnd
->style
& WS_MINIMIZE
))
354 hRgnWindow
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
355 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
356 REGION_FreeRgnByHandle(hRgnWindow
);
360 NtGdiOffsetRgn( hRgn
,
363 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnClip
, RGN_AND
);
364 NtGdiOffsetRgn( hRgn
,
370 * Save current state of pending updates
373 HadPaintMessage
= Window
->hrgnUpdate
!= NULL
||
374 Wnd
->state
& WNDS_INTERNALPAINT
;
375 HadNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
378 * Update the region and flags
381 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
383 if (Window
->hrgnUpdate
== NULL
)
385 Window
->hrgnUpdate
= IntSysCreateRectRgn(0, 0, 0, 0);
386 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_PUBLIC
);
389 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
390 hRgn
, RGN_OR
) == NULLREGION
)
392 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
393 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
394 Window
->hrgnUpdate
= NULL
;
397 if (Flags
& RDW_FRAME
)
398 Window
->state
|= WINDOWOBJECT_NEED_NCPAINT
;
399 if (Flags
& RDW_ERASE
)
400 Window
->state
|= WINDOWOBJECT_NEED_ERASEBKGND
;
405 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
407 if (Window
->hrgnUpdate
!= NULL
)
409 if (NtGdiCombineRgn(Window
->hrgnUpdate
, Window
->hrgnUpdate
,
410 hRgn
, RGN_DIFF
) == NULLREGION
)
412 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
413 REGION_FreeRgnByHandle(Window
->hrgnUpdate
);
414 Window
->hrgnUpdate
= NULL
;
418 if (Window
->hrgnUpdate
== NULL
)
419 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
420 if (Flags
& RDW_NOFRAME
)
421 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
422 if (Flags
& RDW_NOERASE
)
423 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
426 if (Flags
& RDW_INTERNALPAINT
)
428 Wnd
->state
|= WNDS_INTERNALPAINT
;
431 if (Flags
& RDW_NOINTERNALPAINT
)
433 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
437 * Process children if needed
440 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
441 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
443 PWINDOW_OBJECT Child
;
445 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
447 if (Child
->Wnd
->style
& WS_VISIBLE
)
450 * Recursive call to update children hrgnUpdate
452 HRGN hRgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
453 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
454 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
455 REGION_FreeRgnByHandle(hRgnTemp
);
462 * Fake post paint messages to window message queue if needed
465 HasPaintMessage
= Window
->hrgnUpdate
!= NULL
||
466 Wnd
->state
& WNDS_INTERNALPAINT
;
467 HasNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
469 if (HasPaintMessage
!= HadPaintMessage
)
472 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
474 MsqIncPaintCountQueue(Window
->pti
->MessageQueue
);
477 if (HasNCPaintMessage
!= HadNCPaintMessage
)
479 if (HadNCPaintMessage
)
480 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
482 MsqIncPaintCountQueue(Window
->pti
->MessageQueue
);
484 DPRINT("IntInvalidateWindows exit\n");
488 * IntIsWindowDrawable
491 * Window is drawable when it is visible and all parents are not
496 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
498 PWINDOW_OBJECT WndObject
;
501 for (WndObject
= Window
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
503 Wnd
= WndObject
->Wnd
;
504 if ( Window
->state
& WINDOWSTATUS_DESTROYING
|| // state2
505 Window
->state
& WINDOWSTATUS_DESTROYED
||
507 !(Wnd
->style
& WS_VISIBLE
) ||
508 ((Wnd
->style
& WS_MINIMIZE
) && (WndObject
!= Window
)))
520 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
526 PWINDOW_OBJECT Window
,
527 const RECTL
* UpdateRect
,
532 DPRINT("co_UserRedrawWindow start\n");
536 * Validation of passed parameters.
539 if (!IntIsWindowDrawable(Window
))
541 return TRUE
; // Just do nothing!!!
546 * Transform the parameters UpdateRgn and UpdateRect into
547 * a region hRgn specified in screen coordinates.
550 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)) // Both are OKAY!
552 if (UpdateRgn
!= NULL
)
554 hRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
555 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
557 REGION_FreeRgnByHandle(hRgn
);
561 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
563 else if (UpdateRect
!= NULL
)
565 if (!RECTL_bIsEmptyRect(UpdateRect
))
567 hRgn
= IntSysCreateRectRgnIndirect((RECTL
*)UpdateRect
);
568 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
571 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
572 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
574 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcWindow
))
575 hRgn
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
579 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcClient
))
580 hRgn
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
586 * Adjust the window update region depending on hRgn and flags.
589 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
592 IntInvalidateWindows(Window
, hRgn
, Flags
);
597 * Repaint and erase windows if needed.
600 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
602 co_IntPaintWindows(Window
, Flags
, FALSE
);
612 REGION_FreeRgnByHandle(hRgn
);
614 DPRINT("co_UserRedrawWindow exit\n");
620 IntIsWindowDirty(PWINDOW_OBJECT Window
)
622 PWND Wnd
= Window
->Wnd
;
623 return (Wnd
->style
& WS_VISIBLE
) &&
624 ((Window
->hrgnUpdate
!= NULL
) ||
625 (Wnd
->state
& WNDS_INTERNALPAINT
) ||
626 (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
));
630 IntFindWindowToRepaint(PWINDOW_OBJECT Window
, PTHREADINFO Thread
)
633 PWINDOW_OBJECT TempWindow
;
636 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
639 if (IntWndBelongsToThread(Window
, Thread
) &&
640 IntIsWindowDirty(Window
))
642 /* Make sure all non-transparent siblings are already drawn. */
643 if (Wnd
->ExStyle
& WS_EX_TRANSPARENT
)
645 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
646 TempWindow
= TempWindow
->spwndNext
)
648 TempWnd
= TempWindow
->Wnd
;
649 if (!(TempWnd
->ExStyle
& WS_EX_TRANSPARENT
) &&
650 IntWndBelongsToThread(TempWindow
, Thread
) &&
651 IntIsWindowDirty(TempWindow
))
653 return TempWindow
->hSelf
;
658 return Window
->hSelf
;
661 if (Window
->spwndChild
)
663 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
674 PWINDOW_OBJECT Window
,
681 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
683 if (!MessageQueue
->PaintCount
)
686 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
687 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
690 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
692 if (Message
->hwnd
== NULL
)
694 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
695 /* Hack to stop spamming the debuglog ! */
696 MessageQueue
->PaintCount
= 0;
700 if (Window
!= NULL
&& Message
->hwnd
!= Window
->hSelf
)
703 Message
->message
= WM_PAINT
;
704 Message
->wParam
= Message
->lParam
= 0;
711 co_IntFixCaret(PWINDOW_OBJECT Window
, RECTL
*lprc
, UINT flags
)
714 PTHRDCARETINFO CaretInfo
;
716 PWINDOW_OBJECT WndCaret
;
718 ASSERT_REFS_CO(Window
);
720 Desktop
= ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->rpdesk
;
721 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
722 hWndCaret
= CaretInfo
->hWnd
;
724 WndCaret
= UserGetWindowObject(hWndCaret
);
726 //fix: check for WndCaret can be null
727 if (WndCaret
== Window
||
728 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
730 POINT pt
, FromOffset
, ToOffset
;
733 pt
.x
= CaretInfo
->Pos
.x
;
734 pt
.y
= CaretInfo
->Pos
.y
;
735 IntGetClientOrigin(WndCaret
, &FromOffset
);
736 IntGetClientOrigin(Window
, &ToOffset
);
739 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
740 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
741 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
756 PWINDOW_OBJECT Window
,
762 INT cx
, cy
, xSrc
, ySrc
;
769 if ( nFlags
& PW_CLIENTONLY
)
771 cx
= pwnd
->rcClient
.right
- pwnd
->rcClient
.left
;
772 cy
= pwnd
->rcClient
.bottom
- pwnd
->rcClient
.top
;
773 xSrc
= pwnd
->rcClient
.left
- pwnd
->rcWindow
.left
;
774 ySrc
= pwnd
->rcClient
.top
- pwnd
->rcWindow
.top
;
778 cx
= pwnd
->rcWindow
.right
- pwnd
->rcWindow
.left
;
779 cy
= pwnd
->rcWindow
.bottom
- pwnd
->rcWindow
.top
;
784 // TODO: Setup Redirection for Print.
787 /* Update the window just incase. */
788 co_IntPaintWindows( Window
, RDW_ERASENOW
|RDW_UPDATENOW
, FALSE
);
790 hdcSrc
= UserGetDCEx( Window
, NULL
, DCX_CACHE
|DCX_WINDOW
);
791 /* Print window to printer context. */
804 UserReleaseDC( Window
, hdcSrc
, FALSE
);
806 // TODO: Release Redirection from Print.
811 /* PUBLIC FUNCTIONS ***********************************************************/
821 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
823 PWINDOW_OBJECT Window
= NULL
;
827 USER_REFERENCE_ENTRY Ref
;
830 DPRINT("Enter NtUserBeginPaint\n");
831 UserEnterExclusive();
833 if (!(Window
= UserGetWindowObject(hWnd
)))
838 UserRefObjectCo(Window
, &Ref
);
842 co_UserHideCaret(Window
);
844 if (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
)
848 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
849 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
850 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
851 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
852 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
854 /* NOTE: The region can already by deleted! */
855 GDIOBJ_FreeObjByHandle(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
859 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
861 Ps
.hdc
= UserGetDCEx( Window
,
863 DCX_INTERSECTRGN
| DCX_USESTYLE
);
869 if (Window
->hrgnUpdate
!= NULL
)
871 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
872 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
873 IntGdiSetRegionOwner(Window
->hrgnUpdate
, GDI_OBJ_HMGR_POWNED
);
874 /* The region is part of the dc now and belongs to the process! */
875 Window
->hrgnUpdate
= NULL
;
879 if (Wnd
->state
& WNDS_INTERNALPAINT
)
880 MsqDecPaintCountQueue(Window
->pti
->MessageQueue
);
882 IntGetClientRect(Window
, &Ps
.rcPaint
);
885 Wnd
->state
&= ~WNDS_INTERNALPAINT
;
887 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
889 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
890 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
896 if (Window
->hrgnUpdate
)
898 if (!(Wnd
->style
& WS_CLIPCHILDREN
))
900 PWINDOW_OBJECT Child
;
901 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
903 IntInvalidateWindows(Child
, Window
->hrgnUpdate
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
908 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
909 if (! NT_SUCCESS(Status
))
911 SetLastNtError(Status
);
918 if (Window
) UserDerefObjectCo(Window
);
920 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
934 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
936 NTSTATUS Status
= STATUS_SUCCESS
;
937 PWINDOW_OBJECT Window
;
938 DECLARE_RETURN(BOOL
);
939 USER_REFERENCE_ENTRY Ref
;
942 DPRINT("Enter NtUserEndPaint\n");
943 UserEnterExclusive();
945 if (!(Window
= UserGetWindowObject(hWnd
)))
952 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
953 hdc
= pUnsafePs
->hdc
;
955 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
957 Status
= _SEH2_GetExceptionCode();
960 if (!NT_SUCCESS(Status
))
965 UserReleaseDC(Window
, hdc
, TRUE
);
967 UserRefObjectCo(Window
, &Ref
);
968 co_UserShowCaret(Window
);
969 UserDerefObjectCo(Window
);
974 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
981 co_UserGetUpdateRgn(PWINDOW_OBJECT Window
, HRGN hRgn
, BOOL bErase
)
986 ASSERT_REFS_CO(Window
);
988 if (Window
->hrgnUpdate
== NULL
)
990 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
994 Rect
= Window
->Wnd
->rcClient
;
995 IntIntersectWithParents(Window
, &Rect
);
996 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
997 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->hrgnUpdate
, RGN_AND
);
998 NtGdiOffsetRgn(hRgn
, -Window
->Wnd
->rcClient
.left
, -Window
->Wnd
->rcClient
.top
);
1001 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
1003 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1010 * NtUserGetUpdateRgn
1017 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
1019 DECLARE_RETURN(INT
);
1020 PWINDOW_OBJECT Window
;
1022 USER_REFERENCE_ENTRY Ref
;
1024 DPRINT("Enter NtUserGetUpdateRgn\n");
1025 UserEnterExclusive();
1027 if (!(Window
= UserGetWindowObject(hWnd
)))
1032 UserRefObjectCo(Window
, &Ref
);
1033 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
1034 UserDerefObjectCo(Window
);
1039 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
1045 * NtUserGetUpdateRect
1052 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1054 PWINDOW_OBJECT Window
;
1057 PROSRGNDATA RgnData
;
1059 DECLARE_RETURN(BOOL
);
1061 DPRINT("Enter NtUserGetUpdateRect\n");
1062 UserEnterExclusive();
1064 if (!(Window
= UserGetWindowObject(hWnd
)))
1069 if (Window
->hrgnUpdate
== NULL
)
1071 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1075 /* Get the update region bounding box. */
1076 if (Window
->hrgnUpdate
== (HRGN
)1)
1078 Rect
= Window
->Wnd
->rcClient
;
1082 RgnData
= RGNOBJAPI_Lock(Window
->hrgnUpdate
, NULL
);
1083 ASSERT(RgnData
!= NULL
);
1084 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1085 RGNOBJAPI_Unlock(RgnData
);
1087 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1088 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->Wnd
->rcClient
);
1091 if (IntIntersectWithParents(Window
, &Rect
))
1093 RECTL_vOffsetRect(&Rect
,
1094 -Window
->Wnd
->rcClient
.left
,
1095 -Window
->Wnd
->rcClient
.top
);
1098 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1102 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1104 USER_REFERENCE_ENTRY Ref
;
1105 UserRefObjectCo(Window
, &Ref
);
1106 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1107 UserDerefObjectCo(Window
);
1110 if (UnsafeRect
!= NULL
)
1112 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1113 if (!NT_SUCCESS(Status
))
1115 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1120 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1123 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1129 * NtUserRedrawWindow
1138 CONST RECT
*lprcUpdate
,
1142 RECTL SafeUpdateRect
;
1145 USER_REFERENCE_ENTRY Ref
;
1146 NTSTATUS Status
= STATUS_SUCCESS
;
1147 DECLARE_RETURN(BOOL
);
1149 DPRINT("Enter NtUserRedrawWindow\n");
1150 UserEnterExclusive();
1152 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1161 ProbeForRead(lprcUpdate
, sizeof(RECTL
), 1);
1162 RtlCopyMemory(&SafeUpdateRect
, lprcUpdate
, sizeof(RECTL
));
1164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1166 Status
= _SEH2_GetExceptionCode();
1169 if (!NT_SUCCESS(Status
))
1171 SetLastWin32Error(RtlNtStatusToDosError(Status
));
1176 if ( flags
& ~(RDW_ERASE
|RDW_FRAME
|RDW_INTERNALPAINT
|RDW_INVALIDATE
|
1177 RDW_NOERASE
|RDW_NOFRAME
|RDW_NOINTERNALPAINT
|RDW_VALIDATE
|
1178 RDW_ERASENOW
|RDW_UPDATENOW
|RDW_ALLCHILDREN
|RDW_NOCHILDREN
) )
1180 /* RedrawWindow fails only in case that flags are invalid */
1181 SetLastWin32Error(ERROR_INVALID_FLAGS
);
1185 UserRefObjectCo(Wnd
, &Ref
);
1187 Ret
= co_UserRedrawWindow( Wnd
,
1188 lprcUpdate
? &SafeUpdateRect
: NULL
,
1192 UserDerefObjectCo(Wnd
);
1197 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1208 const RECTL
*prcScroll
,
1209 const RECTL
*prcClip
,
1214 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1217 GdiGetClipBox(hDC
, &rcClip
);
1221 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1226 rcScroll
= *prcScroll
;
1227 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1235 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1236 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1238 if (!NtGdiBitBlt( hDC
,
1241 rcDst
.right
- rcDst
.left
,
1242 rcDst
.bottom
- rcDst
.top
,
1253 /* Calculate the region that was invalidated by moving or
1254 could not be copied, because it was not visible */
1255 if (hrgnUpdate
|| prcUpdate
)
1257 HRGN hrgnOwn
, hrgnVisible
, hrgnTmp
;
1259 pDC
= DC_LockDc(hDC
);
1264 hrgnVisible
= ((PROSRGNDATA
)pDC
->prgnVis
)->BaseObject
.hHmgr
; // pDC->prgnRao?
1266 /* Begin with the shifted and then clipped scroll rect */
1268 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1269 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1272 hrgnOwn
= hrgnUpdate
;
1273 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1280 hrgnOwn
= IntSysCreateRectRgnIndirect(&rcDst
);
1283 /* Add the source rect */
1284 hrgnTmp
= IntSysCreateRectRgnIndirect(&rcSrc
);
1285 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1287 /* Substract the part of the dest that was visible in source */
1288 NtGdiCombineRgn(hrgnTmp
, hrgnTmp
, hrgnVisible
, RGN_AND
);
1289 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1290 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1292 /* DO NOT Unlock DC while messing with prgnVis! */
1295 REGION_FreeRgnByHandle(hrgnTmp
);
1299 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1304 REGION_FreeRgnByHandle(hrgnOwn
);
1308 Result
= NULLREGION
;
1324 const RECT
*prcUnsafeScroll
,
1325 const RECT
*prcUnsafeClip
,
1327 LPRECT prcUnsafeUpdate
)
1329 DECLARE_RETURN(DWORD
);
1330 RECTL rcScroll
, rcClip
, rcUpdate
;
1331 NTSTATUS Status
= STATUS_SUCCESS
;
1334 DPRINT("Enter NtUserScrollDC\n");
1335 UserEnterExclusive();
1339 if (prcUnsafeScroll
)
1341 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1342 rcScroll
= *prcUnsafeScroll
;
1346 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1347 rcClip
= *prcUnsafeClip
;
1349 if (prcUnsafeUpdate
)
1351 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1354 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1356 Status
= _SEH2_GetExceptionCode();
1359 if (!NT_SUCCESS(Status
))
1361 SetLastNtError(Status
);
1365 Result
= UserScrollDC( hDC
,
1368 prcUnsafeScroll
? &rcScroll
: 0,
1369 prcUnsafeClip
? &rcClip
: 0,
1371 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1374 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1378 if (prcUnsafeUpdate
)
1382 *prcUnsafeUpdate
= rcUpdate
;
1384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1386 Status
= _SEH2_GetExceptionCode();
1389 if (!NT_SUCCESS(Status
))
1391 /* FIXME: SetLastError? */
1392 /* FIXME: correct? We have already scrolled! */
1400 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1406 * NtUserScrollWindowEx
1413 NtUserScrollWindowEx(
1417 const RECT
*prcUnsafeScroll
,
1418 const RECT
*prcUnsafeClip
,
1420 LPRECT prcUnsafeUpdate
,
1423 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1425 PWINDOW_OBJECT Window
= NULL
, CaretWnd
;
1427 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1429 NTSTATUS Status
= STATUS_SUCCESS
;
1430 DECLARE_RETURN(DWORD
);
1431 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1433 DPRINT("Enter NtUserScrollWindowEx\n");
1434 UserEnterExclusive();
1436 Window
= UserGetWindowObject(hWnd
);
1437 if (!Window
|| !IntIsWindowDrawable(Window
))
1439 Window
= NULL
; /* prevent deref at cleanup */
1442 UserRefObjectCo(Window
, &Ref
);
1444 IntGetClientRect(Window
, &rcClip
);
1448 if (prcUnsafeScroll
)
1450 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1451 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1458 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1459 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1464 Status
= _SEH2_GetExceptionCode();
1468 if (!NT_SUCCESS(Status
))
1470 SetLastNtError(Status
);
1474 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1475 (dx
== 0 && dy
== 0))
1481 hrgnOwn
= hrgnUpdate
;
1483 hrgnOwn
= IntSysCreateRectRgn(0, 0, 0, 0);
1485 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1488 /* FIXME: SetLastError? */
1493 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1495 Result
= UserScrollDC( hDC
,
1501 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1503 UserReleaseDC(Window
, hDC
, FALSE
);
1506 * Take into account the fact that some damage may have occurred during
1510 hrgnTemp
= IntSysCreateRectRgn(0, 0, 0, 0);
1511 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1513 HRGN hrgnClip
= IntSysCreateRectRgnIndirect(&rcClip
);
1514 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1515 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1516 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1517 REGION_FreeRgnByHandle(hrgnClip
);
1519 REGION_FreeRgnByHandle(hrgnTemp
);
1521 if (flags
& SW_SCROLLCHILDREN
)
1523 PWINDOW_OBJECT Child
;
1526 USER_REFERENCE_ENTRY WndRef
;
1529 IntGetClientOrigin(Window
, &ClientOrigin
);
1530 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1532 rcChild
= Child
->Wnd
->rcWindow
;
1533 rcChild
.left
-= ClientOrigin
.x
;
1534 rcChild
.top
-= ClientOrigin
.y
;
1535 rcChild
.right
-= ClientOrigin
.x
;
1536 rcChild
.bottom
-= ClientOrigin
.y
;
1538 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1540 UserRefObjectCo(Child
, &WndRef
);
1541 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1542 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1544 UserDerefObjectCo(Child
);
1549 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1551 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1552 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1553 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1556 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1558 UserRefObjectCo(CaretWnd
, &CaretRef
);
1560 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1561 co_UserShowCaret(CaretWnd
);
1563 UserDerefObjectCo(CaretWnd
);
1566 if (prcUnsafeUpdate
)
1570 /* Probe here, to not fail on invalid pointer before scrolling */
1571 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1572 *prcUnsafeUpdate
= rcUpdate
;
1574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1576 Status
= _SEH2_GetExceptionCode();
1580 if (!NT_SUCCESS(Status
))
1582 SetLastNtError(Status
);
1590 if (hrgnOwn
&& !hrgnUpdate
)
1592 REGION_FreeRgnByHandle(hrgnOwn
);
1596 UserDerefObjectCo(Window
);
1598 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1605 UserDrawSysMenuButton(
1606 PWINDOW_OBJECT pWnd
,
1612 PCURICON_OBJECT pIcon
;
1614 ASSERT(pWnd
&& lpRc
);
1616 /* Get the icon to draw. We don't care about WM_GETICON here. */
1618 hIcon
= pWnd
->Wnd
->pcls
->hIconSm
;
1622 DPRINT("Wnd class has no small icon.\n");
1623 hIcon
= pWnd
->Wnd
->pcls
->hIcon
;
1628 DPRINT("Wnd class hasn't any icon.\n");
1629 //FIXME: Draw "winlogo" icon.
1633 if(!(pIcon
= UserGetCurIconObject(hIcon
)))
1635 DPRINT1("UserGetCurIconObject() failed!\n");
1639 return UserDrawIconEx(hDc
, lpRc
->left
, lpRc
->top
, pIcon
,
1640 UserGetSystemMetrics(SM_CXSMICON
),
1641 UserGetSystemMetrics(SM_CYSMICON
),
1642 0, NULL
, DI_NORMAL
);
1646 UserDrawCaptionText(
1648 const PUNICODE_STRING Text
,
1652 HFONT hOldFont
= NULL
, hFont
= NULL
;
1653 COLORREF OldTextColor
;
1654 NONCLIENTMETRICSW nclm
;
1658 DPRINT("%s:", __FUNCTION__
);
1659 for(i
= 0; i
< Text
->Length
/sizeof(WCHAR
); i
++)
1660 DbgPrint("%C", Text
->Buffer
[i
]);
1661 DbgPrint(", %d\n", Text
->Length
/sizeof(WCHAR
));
1664 nclm
.cbSize
= sizeof(nclm
);
1665 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1666 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1668 DPRINT1("%s: UserSystemParametersInfo() failed!\n", __FUNCTION__
);
1672 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1674 if(uFlags
& DC_SMALLCAP
)
1675 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1676 else Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1678 if(!NT_SUCCESS(Status
))
1680 DPRINT1("%s: TextIntCreateFontIndirect() failed! Status: 0x%x\n",
1681 __FUNCTION__
, Status
);
1685 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1688 DPRINT1("%s: SelectFont() failed!\n", __FUNCTION__
);
1689 GreDeleteObject(hFont
);
1693 if(uFlags
& DC_INBUTTON
)
1694 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1695 else OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1696 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1698 //FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1700 GreExtTextOutW(hDc
, lpRc
->left
,
1701 lpRc
->top
, 0, NULL
, Text
->Buffer
,
1702 Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1704 IntGdiSetTextColor(hDc
, OldTextColor
);
1705 NtGdiSelectFont(hDc
, hOldFont
);
1706 GreDeleteObject(hFont
);
1711 BOOL
UserDrawCaption(
1712 PWINDOW_OBJECT pWnd
,
1717 const PUNICODE_STRING str
,
1721 HBITMAP hMemBmp
= NULL
, hOldBmp
= NULL
;
1722 HBRUSH hOldBrush
= NULL
;
1725 UINT VCenter
= 0, Padding
= 0;
1727 LONG ButtonWidth
, IconWidth
;
1731 //ASSERT(pWnd != NULL);
1736 RECTL_vMakeWellOrdered(lpRc
);
1737 hMemBmp
= NtGdiCreateCompatibleBitmap(hDc
,
1738 lpRc
->right
- lpRc
->left
,
1739 lpRc
->bottom
- lpRc
->top
);
1743 DPRINT1("%s: NtGdiCreateCompatibleBitmap() failed!\n", __FUNCTION__
);
1747 hMemDc
= NtGdiCreateCompatibleDC(hDc
);
1750 DPRINT1("%s: NtGdiCreateCompatibleDC() failed!\n", __FUNCTION__
);
1754 hOldBmp
= NtGdiSelectBitmap(hMemDc
, hMemBmp
);
1757 DPRINT1("%s: NtGdiSelectBitmap() failed!\n", __FUNCTION__
);
1761 Height
= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1762 VCenter
= (lpRc
->bottom
- lpRc
->top
) / 2;
1763 Padding
= VCenter
- (Height
/ 2);
1765 if ((!hIcon
) && (Wnd
!= NULL
))
1767 HasIcon
= (uFlags
& DC_ICON
) && (Wnd
->style
& WS_SYSMENU
)
1768 && !(uFlags
& DC_SMALLCAP
) && !(Wnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1769 && !(Wnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1772 HasIcon
= (hIcon
!= 0);
1774 IconWidth
= UserGetSystemMetrics(SM_CXSIZE
) + Padding
;
1777 r
.right
= r
.left
+ (lpRc
->right
- lpRc
->left
);
1779 r
.bottom
= r
.top
+ (Height
/ 2);
1781 // Draw the caption background
1782 if(uFlags
& DC_INBUTTON
)
1784 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1785 IntGetSysColorBrush(COLOR_3DFACE
));
1789 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1793 if(!NtGdiPatBlt(hMemDc
, 0, 0,
1794 lpRc
->right
- lpRc
->left
,
1795 lpRc
->bottom
- lpRc
->top
,
1798 DPRINT1("%s: NtGdiPatBlt() failed!\n", __FUNCTION__
);
1802 if(HasIcon
) r
.left
+=IconWidth
;
1806 r
.right
= (lpRc
->right
- lpRc
->left
);
1807 if(uFlags
& DC_SMALLCAP
)
1808 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1809 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1811 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1812 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1813 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
1817 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1821 if(HasIcon
&& (uFlags
& DC_GRADIENT
))
1823 NtGdiPatBlt(hMemDc
, 0, 0,
1825 lpRc
->bottom
- lpRc
->top
,
1831 NtGdiPatBlt(hMemDc
, 0, 0,
1832 lpRc
->right
- lpRc
->left
,
1833 lpRc
->bottom
- lpRc
->top
,
1837 if(uFlags
& DC_GRADIENT
)
1839 static GRADIENT_RECT gcap
= {0, 1};
1845 if(Wnd
->style
& WS_SYSMENU
)
1847 r
.right
-= 3 + ButtonWidth
;
1848 if(!(uFlags
& DC_SMALLCAP
))
1850 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1851 r
.right
-= 2 + 2 * ButtonWidth
;
1856 //Draw buttons background
1857 if(!NtGdiSelectBrush(hMemDc
,
1858 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1859 COLOR_GRADIENTACTIVECAPTION
:COLOR_GRADIENTINACTIVECAPTION
)))
1861 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1868 lpRc
->right
- lpRc
->left
- r
.right
,
1869 lpRc
->bottom
- lpRc
->top
,
1874 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1875 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1877 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1878 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1882 vert
[0].Red
= (WORD
)Colors
[0]<<8;
1883 vert
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1884 vert
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1887 vert
[1].x
= r
.right
;
1888 vert
[1].y
= lpRc
->bottom
- lpRc
->top
;
1889 vert
[1].Red
= (WORD
)Colors
[1]<<8;
1890 vert
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1891 vert
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1894 if(!GreGradientFill(hMemDc
, vert
, 2, &gcap
,
1895 1, GRADIENT_FILL_RECT_H
))
1897 DPRINT1("%s: IntGdiGradientFill() failed!\n", __FUNCTION__
);
1900 } //if(uFlags & DC_GRADIENT)
1906 r
.left
-= --IconWidth
;
1907 /* FIXME: Draw the Icon when pWnd == NULL but hIcon is valid */
1909 UserDrawSysMenuButton(pWnd
, hMemDc
, &r
, FALSE
);
1911 r
.left
+= IconWidth
;
1918 r
.bottom
= r
.top
+ Height
;
1920 if((uFlags
& DC_TEXT
))
1922 if(!(uFlags
& DC_GRADIENT
))
1924 r
.right
= (lpRc
->right
- lpRc
->left
);
1926 if(uFlags
& DC_SMALLCAP
)
1927 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1928 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1930 if ((Wnd
!= NULL
) && (Wnd
->style
& WS_SYSMENU
))
1932 r
.right
-= 3 + ButtonWidth
;
1933 if(! (uFlags
& DC_SMALLCAP
))
1935 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1936 r
.right
-= 2 + 2 * ButtonWidth
;
1943 /* FIXME: hFont isn't handled */
1945 UserDrawCaptionText(hMemDc
, str
, &r
, uFlags
);
1946 else if (pWnd
!= NULL
)
1948 UNICODE_STRING ustr
;
1949 ustr
.Buffer
= pWnd
->Wnd
->strName
.Buffer
;
1950 ustr
.Length
= pWnd
->Wnd
->strName
.Length
;
1951 ustr
.MaximumLength
= pWnd
->Wnd
->strName
.MaximumLength
;
1952 UserDrawCaptionText(hMemDc
, &ustr
, &r
, uFlags
);
1956 if(!NtGdiBitBlt(hDc
, lpRc
->left
, lpRc
->top
,
1957 lpRc
->right
- lpRc
->left
, lpRc
->bottom
- lpRc
->top
,
1958 hMemDc
, 0, 0, SRCCOPY
, 0, 0))
1960 DPRINT1("%s: NtGdiBitBlt() failed!\n", __FUNCTION__
);
1967 if (hOldBrush
) NtGdiSelectBrush(hMemDc
, hOldBrush
);
1968 if (hOldBmp
) NtGdiSelectBitmap(hMemDc
, hOldBmp
);
1969 if (hMemBmp
) GreDeleteObject(hMemBmp
);
1970 if (hMemDc
) NtGdiDeleteObjectApp(hMemDc
);
1977 UserRealizePalette(HDC hdc
)
1982 Ret
= IntGdiRealizePalette(hdc
);
1983 if (Ret
) // There was a change.
1985 hWnd
= IntWindowFromDC(hdc
);
1986 if (hWnd
) // Send broadcast if dc is associated with a window.
1987 { // FYI: Thread locked in CallOneParam.
1988 co_IntSendMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1996 NtUserDrawCaptionTemp(
2002 const PUNICODE_STRING str
,
2005 PWINDOW_OBJECT pWnd
= NULL
;
2006 UNICODE_STRING SafeStr
= {0};
2007 NTSTATUS Status
= STATUS_SUCCESS
;
2011 UserEnterExclusive();
2015 if(!(pWnd
= UserGetWindowObject(hWnd
)))
2024 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
2025 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
2028 SafeStr
= ProbeForReadUnicodeString(str
);
2029 if (SafeStr
.Length
!= 0)
2031 ProbeForRead( SafeStr
.Buffer
,
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2039 Status
= _SEH2_GetExceptionCode();
2043 if (Status
!= STATUS_SUCCESS
)
2045 SetLastNtError(Status
);
2051 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
2053 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
2061 NtUserDrawCaption(HWND hWnd
,
2066 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
2071 NtUserInvalidateRect(
2073 CONST RECT
*lpUnsafeRect
,
2076 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2081 NtUserInvalidateRgn(
2086 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
2096 PWINDOW_OBJECT Window
;
2099 UserEnterExclusive();
2103 Window
= UserGetWindowObject(hwnd
);
2104 // TODO: Add Desktop and MessageBox check via FNID's.
2107 /* Validate flags and check it as a mask for 0 or 1. */
2108 if ( (nFlags
& PW_CLIENTONLY
) == nFlags
)
2109 Ret
= IntPrintWindow( Window
, hdcBlt
, nFlags
);
2111 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2119 /* ValidateRect gets redirected to NtUserValidateRect:
2120 http://blog.csdn.net/ntdll/archive/2005/10/19/509299.aspx */
2129 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_VALIDATE
);
2131 return NtUserRedrawWindow(hWnd
, lpRect
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ERASENOW
|RDW_ALLCHILDREN
);