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
->UpdateRegion
!= 0)
84 IntInvalidateWindows(ParentWindow
, hValidateRgn
,
85 RDW_VALIDATE
| RDW_NOCHILDREN
);
88 ParentWindow
= ParentWindow
->spwndParent
;
95 * @name IntCalcWindowRgn
97 * Get a window or client region.
101 IntCalcWindowRgn(PWINDOW_OBJECT Window
, BOOL Client
)
109 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Wnd
->rcClient
);
111 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Wnd
->rcWindow
);
113 if (Window
->WindowRegion
!= NULL
&& !(Wnd
->style
& WS_MINIMIZE
))
115 NtGdiOffsetRgn(hRgnWindow
,
118 RgnType
= NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Window
->WindowRegion
, 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
->UpdateRegion
!= NULL
&&
150 Window
->UpdateRegion
!= (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 GreDeleteObject(hRgnNonClient
);
170 RgnType
= NtGdiCombineRgn(hRgnNonClient
, hRgnNonClient
,
171 hRgnWindow
, RGN_DIFF
);
172 if (RgnType
== ERROR
)
174 GreDeleteObject(hRgnWindow
);
175 GreDeleteObject(hRgnNonClient
);
178 else if (RgnType
== NULLREGION
)
180 GreDeleteObject(hRgnWindow
);
181 GreDeleteObject(hRgnNonClient
);
186 * Remove the nonclient region from the standard update region if
187 * we were asked for it.
192 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
193 hRgnWindow
, RGN_AND
) == NULLREGION
)
195 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
196 GreDeleteObject(Window
->UpdateRegion
);
197 Window
->UpdateRegion
= NULL
;
198 if (!(Window
->state
& WINDOWOBJECT_NEED_INTERNALPAINT
))
199 MsqDecPaintCountQueue(Window
->MessageQueue
);
203 GreDeleteObject(hRgnWindow
);
205 return hRgnNonClient
;
209 return Window
->UpdateRegion
;
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
->UpdateRegion
)
233 if (!IntValidateParent(Window
, Window
->UpdateRegion
, Recurse
))
237 if (Flags
& RDW_UPDATENOW
)
239 if (Window
->UpdateRegion
!= NULL
||
240 Window
->state
& WINDOWOBJECT_NEED_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
->MessageQueue
);
252 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
253 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
255 /* NOTE: The region can already be deleted! */
256 GDIOBJ_FreeObjByHandle(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
260 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
262 if (Window
->UpdateRegion
)
264 hDC
= UserGetDCEx(Window
, Window
->UpdateRegion
,
265 DCX_CACHE
| DCX_USESTYLE
|
266 DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
);
267 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
269 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
271 UserReleaseDC(Window
, hDC
, FALSE
);
278 * Check that the window is still valid at this point
280 if (!IntIsWindow(hWnd
))
286 * Paint child windows.
288 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
289 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
293 if ((List
= IntWinListChildren(Window
)))
295 /* FIXME: Handle WS_EX_TRANSPARENT */
296 for (phWnd
= List
; *phWnd
; ++phWnd
)
298 Window
= UserGetWindowObject(*phWnd
);
300 if (Window
&& (Wnd
->style
& WS_VISIBLE
))
302 USER_REFERENCE_ENTRY Ref
;
303 UserRefObjectCo(Window
, &Ref
);
304 co_IntPaintWindows(Window
, Flags
, TRUE
);
305 UserDerefObjectCo(Window
);
314 * IntInvalidateWindows
316 * Internal function used by IntRedrawWindow.
320 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
324 BOOL HadPaintMessage
, HadNCPaintMessage
;
325 BOOL HasPaintMessage
, HasNCPaintMessage
;
330 * If the nonclient is not to be redrawn, clip the region to the client
333 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
337 hRgnClient
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
338 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
339 GreDeleteObject(hRgnClient
);
343 * Clip the given region with window rectangle (or region)
346 if (!Window
->WindowRegion
|| (Wnd
->style
& WS_MINIMIZE
))
350 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
351 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
352 GreDeleteObject(hRgnWindow
);
359 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
366 * Save current state of pending updates
369 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
370 Window
->state
& WINDOWOBJECT_NEED_INTERNALPAINT
;
371 HadNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
374 * Update the region and flags
377 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
379 if (Window
->UpdateRegion
== NULL
)
381 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
382 GDIOBJ_SetOwnership(Window
->UpdateRegion
, NULL
);
385 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
386 hRgn
, RGN_OR
) == NULLREGION
)
388 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
389 GreDeleteObject(Window
->UpdateRegion
);
390 Window
->UpdateRegion
= NULL
;
393 if (Flags
& RDW_FRAME
)
394 Window
->state
|= WINDOWOBJECT_NEED_NCPAINT
;
395 if (Flags
& RDW_ERASE
)
396 Window
->state
|= WINDOWOBJECT_NEED_ERASEBKGND
;
401 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
403 if (Window
->UpdateRegion
!= NULL
)
405 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
406 hRgn
, RGN_DIFF
) == NULLREGION
)
408 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
409 GreDeleteObject(Window
->UpdateRegion
);
410 Window
->UpdateRegion
= NULL
;
414 if (Window
->UpdateRegion
== NULL
)
415 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
416 if (Flags
& RDW_NOFRAME
)
417 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
418 if (Flags
& RDW_NOERASE
)
419 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
422 if (Flags
& RDW_INTERNALPAINT
)
424 Window
->state
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
427 if (Flags
& RDW_NOINTERNALPAINT
)
429 Window
->state
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
433 * Process children if needed
436 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->style
& WS_MINIMIZE
) &&
437 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->style
& WS_CLIPCHILDREN
)))
439 PWINDOW_OBJECT Child
;
441 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
443 if (Child
->Wnd
->style
& WS_VISIBLE
)
446 * Recursive call to update children UpdateRegion
448 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
449 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
450 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
451 GreDeleteObject(hRgnTemp
);
458 * Fake post paint messages to window message queue if needed
461 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
462 Window
->state
& WINDOWOBJECT_NEED_INTERNALPAINT
;
463 HasNCPaintMessage
= Window
->state
& WINDOWOBJECT_NEED_NCPAINT
;
465 if (HasPaintMessage
!= HadPaintMessage
)
468 MsqDecPaintCountQueue(Window
->MessageQueue
);
470 MsqIncPaintCountQueue(Window
->MessageQueue
);
473 if (HasNCPaintMessage
!= HadNCPaintMessage
)
475 if (HadNCPaintMessage
)
476 MsqDecPaintCountQueue(Window
->MessageQueue
);
478 MsqIncPaintCountQueue(Window
->MessageQueue
);
484 * IntIsWindowDrawable
487 * Window is drawable when it is visible and all parents are not
492 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
494 PWINDOW_OBJECT WndObject
;
497 for (WndObject
= Window
; WndObject
!= NULL
; WndObject
= WndObject
->spwndParent
)
499 Wnd
= WndObject
->Wnd
;
500 if (!(Wnd
->style
& WS_VISIBLE
) ||
501 ((Wnd
->style
& WS_MINIMIZE
) && (WndObject
!= Window
)))
513 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
518 co_UserRedrawWindow(PWINDOW_OBJECT Window
, const RECTL
* UpdateRect
, HRGN UpdateRgn
,
525 * Validation of passed parameters.
528 if (!IntIsWindowDrawable(Window
) ||
529 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
530 (RDW_VALIDATE
| RDW_INVALIDATE
))
537 * Transform the parameters UpdateRgn and UpdateRect into
538 * a region hRgn specified in screen coordinates.
541 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
543 if (UpdateRgn
!= NULL
)
545 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
546 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
548 GreDeleteObject(hRgn
);
552 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
554 else if (UpdateRect
!= NULL
)
556 if (!RECTL_bIsEmptyRect(UpdateRect
))
558 hRgn
= UnsafeIntCreateRectRgnIndirect((RECTL
*)UpdateRect
);
559 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->rcClient
.left
, Window
->Wnd
->rcClient
.top
);
562 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
563 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
565 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcWindow
))
566 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
570 if (!RECTL_bIsEmptyRect(&Window
->Wnd
->rcClient
))
571 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
577 * Adjust the window update region depending on hRgn and flags.
580 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
583 IntInvalidateWindows(Window
, hRgn
, Flags
);
588 * Repaint and erase windows if needed.
591 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
593 co_IntPaintWindows(Window
, Flags
, FALSE
);
603 GreDeleteObject(hRgn
);
610 IntIsWindowDirty(PWINDOW_OBJECT Window
)
612 PWND Wnd
= Window
->Wnd
;
613 return (Wnd
->style
& WS_VISIBLE
) &&
614 ((Window
->UpdateRegion
!= NULL
) ||
615 (Window
->state
& WINDOWOBJECT_NEED_INTERNALPAINT
) ||
616 (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
));
620 IntFindWindowToRepaint(PWINDOW_OBJECT Window
, PTHREADINFO Thread
)
623 PWINDOW_OBJECT TempWindow
;
626 for (; Window
!= NULL
; Window
= Window
->spwndNext
)
629 if (IntWndBelongsToThread(Window
, Thread
) &&
630 IntIsWindowDirty(Window
))
632 /* Make sure all non-transparent siblings are already drawn. */
633 if (Wnd
->ExStyle
& WS_EX_TRANSPARENT
)
635 for (TempWindow
= Window
->spwndNext
; TempWindow
!= NULL
;
636 TempWindow
= TempWindow
->spwndNext
)
638 TempWnd
= TempWindow
->Wnd
;
639 if (!(TempWnd
->ExStyle
& WS_EX_TRANSPARENT
) &&
640 IntWndBelongsToThread(TempWindow
, Thread
) &&
641 IntIsWindowDirty(TempWindow
))
643 return TempWindow
->hSelf
;
648 return Window
->hSelf
;
651 if (Window
->spwndChild
)
653 hChild
= IntFindWindowToRepaint(Window
->spwndChild
, Thread
);
663 IntGetPaintMessage(PWINDOW_OBJECT Window
, UINT MsgFilterMin
, UINT MsgFilterMax
,
664 PTHREADINFO Thread
, MSG
*Message
, BOOL Remove
)
666 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
668 if (!MessageQueue
->PaintCount
)
671 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
672 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
675 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
677 if (Message
->hwnd
== NULL
)
679 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
680 /* Hack to stop spamming the debuglog ! */
681 MessageQueue
->PaintCount
= 0;
685 if (Window
!= NULL
&& Message
->hwnd
!= Window
->hSelf
)
688 Message
->message
= WM_PAINT
;
689 Message
->wParam
= Message
->lParam
= 0;
696 co_IntFixCaret(PWINDOW_OBJECT Window
, RECTL
*lprc
, UINT flags
)
699 PTHRDCARETINFO CaretInfo
;
701 PWINDOW_OBJECT WndCaret
;
703 ASSERT_REFS_CO(Window
);
705 Desktop
= ((PTHREADINFO
)PsGetCurrentThread()->Tcb
.Win32Thread
)->Desktop
;
706 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->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
, Offset
;
718 pt
.x
= CaretInfo
->Pos
.x
;
719 pt
.y
= CaretInfo
->Pos
.y
;
720 IntGetClientOrigin(WndCaret
, &FromOffset
);
721 IntGetClientOrigin(Window
, &ToOffset
);
722 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
723 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
726 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
727 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
728 if (RECTL_bIntersectRect(lprc
, lprc
, &rcCaret
))
740 /* PUBLIC FUNCTIONS ***********************************************************/
750 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
752 PWINDOW_OBJECT Window
= NULL
;
756 USER_REFERENCE_ENTRY Ref
;
759 DPRINT("Enter NtUserBeginPaint\n");
760 UserEnterExclusive();
762 if (!(Window
= UserGetWindowObject(hWnd
)))
767 UserRefObjectCo(Window
, &Ref
);
771 co_UserHideCaret(Window
);
773 if (Window
->state
& WINDOWOBJECT_NEED_NCPAINT
)
777 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
778 Window
->state
&= ~WINDOWOBJECT_NEED_NCPAINT
;
779 MsqDecPaintCountQueue(Window
->MessageQueue
);
780 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
781 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
783 /* NOTE: The region can already by deleted! */
784 GDIOBJ_FreeObjByHandle(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
788 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
790 Ps
.hdc
= UserGetDCEx(Window
, Window
->UpdateRegion
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
796 if (Window
->UpdateRegion
!= NULL
)
798 MsqDecPaintCountQueue(Window
->MessageQueue
);
799 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
800 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
801 /* The region is part of the dc now and belongs to the process! */
802 Window
->UpdateRegion
= NULL
;
806 if (Window
->state
& WINDOWOBJECT_NEED_INTERNALPAINT
)
807 MsqDecPaintCountQueue(Window
->MessageQueue
);
809 IntGetClientRect(Window
, &Ps
.rcPaint
);
812 Window
->state
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
814 if (Window
->state
& WINDOWOBJECT_NEED_ERASEBKGND
)
816 Window
->state
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
817 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
823 if (Window
->UpdateRegion
)
825 if (!(Wnd
->style
& WS_CLIPCHILDREN
))
827 PWINDOW_OBJECT Child
;
828 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
830 IntInvalidateWindows(Child
, Window
->UpdateRegion
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
835 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
836 if (! NT_SUCCESS(Status
))
838 SetLastNtError(Status
);
845 if (Window
) UserDerefObjectCo(Window
);
847 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
861 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
863 NTSTATUS Status
= STATUS_SUCCESS
;
864 PWINDOW_OBJECT Window
;
865 DECLARE_RETURN(BOOL
);
866 USER_REFERENCE_ENTRY Ref
;
869 DPRINT("Enter NtUserEndPaint\n");
870 UserEnterExclusive();
872 if (!(Window
= UserGetWindowObject(hWnd
)))
879 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
880 hdc
= pUnsafePs
->hdc
;
882 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
884 Status
= _SEH2_GetExceptionCode();
887 if (!NT_SUCCESS(Status
))
892 UserReleaseDC(Window
, hdc
, TRUE
);
894 UserRefObjectCo(Window
, &Ref
);
895 co_UserShowCaret(Window
);
896 UserDerefObjectCo(Window
);
901 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
908 co_UserGetUpdateRgn(PWINDOW_OBJECT Window
, HRGN hRgn
, BOOL bErase
)
913 ASSERT_REFS_CO(Window
);
915 if (Window
->UpdateRegion
== NULL
)
917 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
921 Rect
= Window
->Wnd
->rcClient
;
922 IntIntersectWithParents(Window
, &Rect
);
923 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
924 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->UpdateRegion
, RGN_AND
);
925 NtGdiOffsetRgn(hRgn
, -Window
->Wnd
->rcClient
.left
, -Window
->Wnd
->rcClient
.top
);
928 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
930 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
944 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
947 PWINDOW_OBJECT Window
;
949 USER_REFERENCE_ENTRY Ref
;
951 DPRINT("Enter NtUserGetUpdateRgn\n");
952 UserEnterExclusive();
954 if (!(Window
= UserGetWindowObject(hWnd
)))
959 UserRefObjectCo(Window
, &Ref
);
960 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
961 UserDerefObjectCo(Window
);
966 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
972 * NtUserGetUpdateRect
979 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
981 PWINDOW_OBJECT Window
;
986 DECLARE_RETURN(BOOL
);
988 DPRINT("Enter NtUserGetUpdateRect\n");
989 UserEnterExclusive();
991 if (!(Window
= UserGetWindowObject(hWnd
)))
996 if (Window
->UpdateRegion
== NULL
)
998 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1002 /* Get the update region bounding box. */
1003 if (Window
->UpdateRegion
== (HRGN
)1)
1005 Rect
= Window
->Wnd
->rcClient
;
1009 RgnData
= REGION_LockRgn(Window
->UpdateRegion
);
1010 ASSERT(RgnData
!= NULL
);
1011 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1012 REGION_UnlockRgn(RgnData
);
1014 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1015 RECTL_bIntersectRect(&Rect
, &Rect
, &Window
->Wnd
->rcClient
);
1018 if (IntIntersectWithParents(Window
, &Rect
))
1020 RECTL_vOffsetRect(&Rect
,
1021 -Window
->Wnd
->rcClient
.left
,
1022 -Window
->Wnd
->rcClient
.top
);
1025 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1029 if (bErase
&& !RECTL_bIsEmptyRect(&Rect
))
1031 USER_REFERENCE_ENTRY Ref
;
1032 UserRefObjectCo(Window
, &Ref
);
1033 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1034 UserDerefObjectCo(Window
);
1037 if (UnsafeRect
!= NULL
)
1039 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECTL
));
1040 if (!NT_SUCCESS(Status
))
1042 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1047 RETURN(!RECTL_bIsEmptyRect(&Rect
));
1050 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1056 * NtUserRedrawWindow
1063 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
1066 RECTL SafeUpdateRect
;
1069 DECLARE_RETURN(BOOL
);
1070 USER_REFERENCE_ENTRY Ref
;
1072 DPRINT("Enter NtUserRedrawWindow\n");
1073 UserEnterExclusive();
1075 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1080 if (lprcUpdate
!= NULL
)
1082 Status
= MmCopyFromCaller(&SafeUpdateRect
, lprcUpdate
,
1085 if (!NT_SUCCESS(Status
))
1087 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1092 UserRefObjectCo(Wnd
, &Ref
);
1094 Status
= co_UserRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
1097 UserDerefObjectCo(Wnd
);
1099 if (!NT_SUCCESS(Status
))
1101 /* IntRedrawWindow fails only in case that flags are invalid */
1102 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1109 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1118 UserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECTL
*prcScroll
,
1119 const RECTL
*prcClip
, HRGN hrgnUpdate
, RECTL
*prcUpdate
)
1122 RECTL rcScroll
, rcClip
, rcSrc
, rcDst
;
1125 GdiGetClipBox(hDC
, &rcClip
);
1129 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcClip
);
1134 rcScroll
= *prcScroll
;
1135 RECTL_bIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1143 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1144 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1146 if (!NtGdiBitBlt(hDC
, rcDst
.left
, rcDst
.top
,
1147 rcDst
.right
- rcDst
.left
, rcDst
.bottom
- rcDst
.top
,
1148 hDC
, rcDst
.left
- dx
, rcDst
.top
- dy
, SRCCOPY
, 0, 0))
1153 /* Calculate the region that was invalidated by moving or
1154 could not be copied, because it was not visible */
1155 if (hrgnUpdate
|| prcUpdate
)
1157 HRGN hrgnOwn
, hrgnVisible
, hrgnTmp
;
1159 pDC
= DC_LockDc(hDC
);
1164 hrgnVisible
= pDC
->rosdc
.hVisRgn
; // pDC->w.hGCClipRgn?
1167 /* Begin with the shifted and then clipped scroll rect */
1169 RECTL_vOffsetRect(&rcDst
, dx
, dy
);
1170 RECTL_bIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1173 hrgnOwn
= hrgnUpdate
;
1174 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1181 hrgnOwn
= UnsafeIntCreateRectRgnIndirect(&rcDst
);
1184 /* Add the source rect */
1185 hrgnTmp
= UnsafeIntCreateRectRgnIndirect(&rcSrc
);
1186 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1188 /* Substract the part of the dest that was visible in source */
1189 NtGdiCombineRgn(hrgnTmp
, hrgnTmp
, hrgnVisible
, RGN_AND
);
1190 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1191 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1193 GreDeleteObject(hrgnTmp
);
1197 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1202 GreDeleteObject(hrgnOwn
);
1206 Result
= NULLREGION
;
1222 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*prcUnsafeScroll
,
1223 const RECT
*prcUnsafeClip
, HRGN hrgnUpdate
, LPRECT prcUnsafeUpdate
)
1225 DECLARE_RETURN(DWORD
);
1226 RECTL rcScroll
, rcClip
, rcUpdate
;
1227 NTSTATUS Status
= STATUS_SUCCESS
;
1230 DPRINT("Enter NtUserScrollDC\n");
1231 UserEnterExclusive();
1235 if (prcUnsafeScroll
)
1237 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1238 rcScroll
= *prcUnsafeScroll
;
1242 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1243 rcClip
= *prcUnsafeClip
;
1245 if (prcUnsafeUpdate
)
1247 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1252 Status
= _SEH2_GetExceptionCode();
1255 if (!NT_SUCCESS(Status
))
1257 SetLastNtError(Status
);
1261 Result
= UserScrollDC(hDC
, dx
, dy
,
1262 prcUnsafeScroll
? &rcScroll
: 0,
1263 prcUnsafeClip
? &rcClip
: 0, hrgnUpdate
,
1264 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1267 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1271 if (prcUnsafeUpdate
)
1275 *prcUnsafeUpdate
= rcUpdate
;
1277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1279 Status
= _SEH2_GetExceptionCode();
1282 if (!NT_SUCCESS(Status
))
1284 /* FIXME: SetLastError? */
1285 /* FIXME: correct? We have already scrolled! */
1293 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1299 * NtUserScrollWindowEx
1306 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*prcUnsafeScroll
,
1307 const RECT
*prcUnsafeClip
, HRGN hrgnUpdate
, LPRECT prcUnsafeUpdate
, UINT flags
)
1309 RECTL rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1311 PWINDOW_OBJECT Window
= NULL
, CaretWnd
;
1313 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1315 NTSTATUS Status
= STATUS_SUCCESS
;
1316 DECLARE_RETURN(DWORD
);
1317 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1319 DPRINT("Enter NtUserScrollWindowEx\n");
1320 UserEnterExclusive();
1322 Window
= UserGetWindowObject(hWnd
);
1323 if (!Window
|| !IntIsWindowDrawable(Window
))
1325 Window
= NULL
; /* prevent deref at cleanup */
1328 UserRefObjectCo(Window
, &Ref
);
1330 IntGetClientRect(Window
, &rcClip
);
1334 if (prcUnsafeScroll
)
1336 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1337 RECTL_bIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1344 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1345 RECTL_bIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1348 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1350 Status
= _SEH2_GetExceptionCode();
1354 if (!NT_SUCCESS(Status
))
1356 SetLastNtError(Status
);
1360 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1361 (dx
== 0 && dy
== 0))
1367 hrgnOwn
= hrgnUpdate
;
1369 hrgnOwn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1371 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1374 /* FIXME: SetLastError? */
1379 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1381 Result
= UserScrollDC(hDC
, dx
, dy
, &rcScroll
, &rcClip
, hrgnOwn
, prcUnsafeUpdate
? &rcUpdate
: NULL
);
1382 UserReleaseDC(Window
, hDC
, FALSE
);
1385 * Take into account the fact that some damage may have occurred during
1389 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1390 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1392 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&rcClip
);
1393 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1394 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1395 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1396 GreDeleteObject(hrgnClip
);
1398 GreDeleteObject(hrgnTemp
);
1400 if (flags
& SW_SCROLLCHILDREN
)
1402 PWINDOW_OBJECT Child
;
1405 USER_REFERENCE_ENTRY WndRef
;
1408 IntGetClientOrigin(Window
, &ClientOrigin
);
1409 for (Child
= Window
->spwndChild
; Child
; Child
= Child
->spwndNext
)
1411 rcChild
= Child
->Wnd
->rcWindow
;
1412 rcChild
.left
-= ClientOrigin
.x
;
1413 rcChild
.top
-= ClientOrigin
.y
;
1414 rcChild
.right
-= ClientOrigin
.x
;
1415 rcChild
.bottom
-= ClientOrigin
.y
;
1417 if (! prcUnsafeScroll
|| RECTL_bIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1419 UserRefObjectCo(Child
, &WndRef
);
1420 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1421 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1423 UserDerefObjectCo(Child
);
1428 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1430 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1431 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1432 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1435 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1437 UserRefObjectCo(CaretWnd
, &CaretRef
);
1439 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1440 co_UserShowCaret(CaretWnd
);
1442 UserDerefObjectCo(CaretWnd
);
1445 if (prcUnsafeUpdate
)
1449 /* Probe here, to not fail on invalid pointer before scrolling */
1450 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1451 *prcUnsafeUpdate
= rcUpdate
;
1453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1455 Status
= _SEH2_GetExceptionCode();
1459 if (!NT_SUCCESS(Status
))
1461 SetLastNtError(Status
);
1469 if (hrgnOwn
&& !hrgnUpdate
)
1471 GreDeleteObject(hrgnOwn
);
1475 UserDerefObjectCo(Window
);
1477 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1484 UserDrawSysMenuButton(
1485 PWINDOW_OBJECT pWnd
,
1491 PCURICON_OBJECT pIcon
;
1493 ASSERT(pWnd
&& lpRc
);
1495 /* Get the icon to draw. We don't care about WM_GETICON here. */
1497 hIcon
= pWnd
->Wnd
->pcls
->hIconSm
;
1501 DPRINT("Wnd class has no small icon.\n");
1502 hIcon
= pWnd
->Wnd
->pcls
->hIcon
;
1507 DPRINT("Wnd class hasn't any icon.\n");
1508 //FIXME: Draw "winlogo" icon.
1512 if(!(pIcon
= UserGetCurIconObject(hIcon
)))
1514 DPRINT1("UserGetCurIconObject() failed!\n");
1518 return UserDrawIconEx(hDc
, lpRc
->left
, lpRc
->top
, pIcon
,
1519 UserGetSystemMetrics(SM_CXSMICON
),
1520 UserGetSystemMetrics(SM_CYSMICON
),
1521 0, NULL
, DI_NORMAL
);
1525 UserDrawCaptionText(HDC hDc
,
1526 const PUNICODE_STRING Text
,
1530 HFONT hOldFont
= NULL
, hFont
= NULL
;
1531 COLORREF OldTextColor
;
1532 NONCLIENTMETRICSW nclm
;
1536 DPRINT("%s:", __FUNCTION__
);
1537 for(i
= 0; i
< Text
->Length
/sizeof(WCHAR
); i
++)
1538 DbgPrint("%C", Text
->Buffer
[i
]);
1539 DbgPrint(", %d\n", Text
->Length
/sizeof(WCHAR
));
1542 nclm
.cbSize
= sizeof(nclm
);
1543 if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1544 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1546 DPRINT1("%s: UserSystemParametersInfo() failed!\n", __FUNCTION__
);
1550 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1552 if(uFlags
& DC_SMALLCAP
)
1553 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1554 else Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1556 if(!NT_SUCCESS(Status
))
1558 DPRINT1("%s: TextIntCreateFontIndirect() failed! Status: 0x%x\n",
1559 __FUNCTION__
, Status
);
1563 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1566 DPRINT1("%s: SelectFont() failed!\n", __FUNCTION__
);
1567 GreDeleteObject(hFont
);
1571 if(uFlags
& DC_INBUTTON
)
1572 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1573 else OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1574 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1576 //FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1578 GreExtTextOutW(hDc
, lpRc
->left
,
1579 lpRc
->top
, 0, NULL
, Text
->Buffer
,
1580 Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1582 IntGdiSetTextColor(hDc
, OldTextColor
);
1583 NtGdiSelectFont(hDc
, hOldFont
);
1584 GreDeleteObject(hFont
);
1589 BOOL
UserDrawCaption(
1590 PWINDOW_OBJECT pWnd
,
1595 const PUNICODE_STRING str
,
1599 HBITMAP hMemBmp
= NULL
, hOldBmp
= NULL
;
1600 HBRUSH hOldBrush
= NULL
;
1603 UINT VCenter
= 0, Padding
= 0;
1605 LONG ButtonWidth
, IconWidth
;
1609 //ASSERT(pWnd != NULL);
1614 RECTL_vMakeWellOrdered(lpRc
);
1615 hMemBmp
= NtGdiCreateCompatibleBitmap(hDc
,
1616 lpRc
->right
- lpRc
->left
,
1617 lpRc
->bottom
- lpRc
->top
);
1621 DPRINT1("%s: NtGdiCreateCompatibleBitmap() failed!\n", __FUNCTION__
);
1625 hMemDc
= NtGdiCreateCompatibleDC(hDc
);
1628 DPRINT1("%s: NtGdiCreateCompatibleDC() failed!\n", __FUNCTION__
);
1632 hOldBmp
= NtGdiSelectBitmap(hMemDc
, hMemBmp
);
1635 DPRINT1("%s: NtGdiSelectBitmap() failed!\n", __FUNCTION__
);
1639 Height
= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1640 VCenter
= (lpRc
->bottom
- lpRc
->top
) / 2;
1641 Padding
= VCenter
- (Height
/ 2);
1643 if ((!hIcon
) && (Wnd
!= NULL
))
1645 HasIcon
= (uFlags
& DC_ICON
) && (Wnd
->style
& WS_SYSMENU
)
1646 && !(uFlags
& DC_SMALLCAP
) && !(Wnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1647 && !(Wnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1650 HasIcon
= (hIcon
!= 0);
1652 IconWidth
= UserGetSystemMetrics(SM_CXSIZE
) + Padding
;
1655 r
.right
= r
.left
+ (lpRc
->right
- lpRc
->left
);
1657 r
.bottom
= r
.top
+ (Height
/ 2);
1659 // Draw the caption background
1660 if(uFlags
& DC_INBUTTON
)
1662 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1663 IntGetSysColorBrush(COLOR_3DFACE
));
1667 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1671 if(!NtGdiPatBlt(hMemDc
, 0, 0,
1672 lpRc
->right
- lpRc
->left
,
1673 lpRc
->bottom
- lpRc
->top
,
1676 DPRINT1("%s: NtGdiPatBlt() failed!\n", __FUNCTION__
);
1680 if(HasIcon
) r
.left
+=IconWidth
;
1684 r
.right
= (lpRc
->right
- lpRc
->left
);
1685 if(uFlags
& DC_SMALLCAP
)
1686 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1687 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1689 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1690 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1691 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
1695 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1699 if(HasIcon
&& (uFlags
& DC_GRADIENT
))
1701 NtGdiPatBlt(hMemDc
, 0, 0,
1703 lpRc
->bottom
- lpRc
->top
,
1709 NtGdiPatBlt(hMemDc
, 0, 0,
1710 lpRc
->right
- lpRc
->left
,
1711 lpRc
->bottom
- lpRc
->top
,
1715 if(uFlags
& DC_GRADIENT
)
1717 static GRADIENT_RECT gcap
= {0, 1};
1724 if(Wnd
->style
& WS_SYSMENU
)
1726 r
.right
-= 3 + ButtonWidth
;
1727 if(!(uFlags
& DC_SMALLCAP
))
1729 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1730 r
.right
-= 2 + 2 * ButtonWidth
;
1735 //Draw buttons background
1736 if(!NtGdiSelectBrush(hMemDc
,
1737 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1738 COLOR_GRADIENTACTIVECAPTION
:COLOR_GRADIENTINACTIVECAPTION
)))
1740 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1747 lpRc
->right
- lpRc
->left
- r
.right
,
1748 lpRc
->bottom
- lpRc
->top
,
1753 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1754 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1756 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1757 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1761 vert
[0].Red
= (WORD
)Colors
[0]<<8;
1762 vert
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1763 vert
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1766 vert
[1].x
= r
.right
;
1767 vert
[1].y
= lpRc
->bottom
- lpRc
->top
;
1768 vert
[1].Red
= (WORD
)Colors
[1]<<8;
1769 vert
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1770 vert
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1773 pMemDc
= DC_LockDc(hMemDc
);
1776 DPRINT1("%s: Can't lock dc!\n", __FUNCTION__
);
1780 if(!IntGdiGradientFill(pMemDc
, vert
, 2, &gcap
,
1781 1, GRADIENT_FILL_RECT_H
))
1783 DPRINT1("%s: IntGdiGradientFill() failed!\n", __FUNCTION__
);
1786 DC_UnlockDc(pMemDc
);
1787 } //if(uFlags & DC_GRADIENT)
1793 r
.left
-= --IconWidth
;
1794 /* FIXME: Draw the Icon when pWnd == NULL but hIcon is valid */
1796 UserDrawSysMenuButton(pWnd
, hMemDc
, &r
, FALSE
);
1798 r
.left
+= IconWidth
;
1805 r
.bottom
= r
.top
+ Height
;
1807 if((uFlags
& DC_TEXT
))
1809 if(!(uFlags
& DC_GRADIENT
))
1811 r
.right
= (lpRc
->right
- lpRc
->left
);
1813 if(uFlags
& DC_SMALLCAP
)
1814 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1815 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1817 if ((Wnd
!= NULL
) && (Wnd
->style
& WS_SYSMENU
))
1819 r
.right
-= 3 + ButtonWidth
;
1820 if(! (uFlags
& DC_SMALLCAP
))
1822 if(Wnd
->style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1823 r
.right
-= 2 + 2 * ButtonWidth
;
1830 /* FIXME: hFont isn't handled */
1832 UserDrawCaptionText(hMemDc
, str
, &r
, uFlags
);
1833 else if (pWnd
!= NULL
)
1834 UserDrawCaptionText(hMemDc
, &pWnd
->Wnd
->strName
, &r
, uFlags
);
1837 if(!NtGdiBitBlt(hDc
, lpRc
->left
, lpRc
->top
,
1838 lpRc
->right
- lpRc
->left
, lpRc
->bottom
- lpRc
->top
,
1839 hMemDc
, 0, 0, SRCCOPY
, 0, 0))
1841 DPRINT1("%s: NtGdiBitBlt() failed!\n", __FUNCTION__
);
1848 if (hOldBrush
) NtGdiSelectBrush(hMemDc
, hOldBrush
);
1849 if (hOldBmp
) NtGdiSelectBitmap(hMemDc
, hOldBmp
);
1850 if (hMemBmp
) GreDeleteObject(hMemBmp
);
1851 if (hMemDc
) NtGdiDeleteObjectApp(hMemDc
);
1858 UserRealizePalette(HDC hdc
)
1863 Ret
= IntGdiRealizePalette(hdc
);
1864 if (Ret
) // There was a change.
1866 hWnd
= IntWindowFromDC(hdc
);
1867 if (hWnd
) // Send broadcast if dc is associated with a window.
1868 { // FYI: Thread locked in CallOneParam.
1869 co_IntSendMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1877 NtUserDrawCaptionTemp(
1883 const PUNICODE_STRING str
,
1886 PWINDOW_OBJECT pWnd
= NULL
;
1887 UNICODE_STRING SafeStr
= {0};
1888 NTSTATUS Status
= STATUS_SUCCESS
;
1892 UserEnterExclusive();
1896 if(!(pWnd
= UserGetWindowObject(hWnd
)))
1905 ProbeForRead(lpRc
, sizeof(RECTL
), sizeof(ULONG
));
1906 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECTL
));
1909 SafeStr
= ProbeForReadUnicodeString(str
);
1910 if (SafeStr
.Length
!= 0)
1912 ProbeForRead( SafeStr
.Buffer
,
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1920 Status
= _SEH2_GetExceptionCode();
1924 if (Status
!= STATUS_SUCCESS
)
1926 SetLastNtError(Status
);
1932 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
1934 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
1942 NtUserDrawCaption(HWND hWnd
,
1947 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
1952 NtUserInvalidateRect(
1954 CONST RECT
*lpUnsafeRect
,
1957 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
1962 NtUserInvalidateRgn(
1967 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));