2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window painting function
24 * FILE: subsys/win32k/ntuser/painting.c
25 * PROGRAMER: Filip Navara (xnavara@volny.cz)
27 * 06/06/2001 Created (?)
28 * 18/11/2003 Complete rewrite
31 /* INCLUDES ******************************************************************/
38 /* PRIVATE FUNCTIONS **********************************************************/
41 * @name IntIntersectWithParents
43 * Intersect window rectangle with all parent client rectangles.
46 * Pointer to child window to start intersecting from.
48 * Pointer to rectangle that we want to intersect in screen
49 * coordinates on input and intersected rectangle on output (if TRUE
53 * If any parent is minimized or invisible or the resulting rectangle
54 * is empty then FALSE is returned. Otherwise TRUE is returned.
58 IntIntersectWithParents(PWINDOW_OBJECT Child
, PRECT WindowRect
)
60 PWINDOW_OBJECT ParentWindow
;
63 ParentWindow
= Child
->Parent
;
64 while (ParentWindow
!= NULL
)
66 ParentWnd
= ParentWindow
->Wnd
;
67 if (!(ParentWnd
->Style
& WS_VISIBLE
) ||
68 (ParentWnd
->Style
& WS_MINIMIZE
))
73 if (!IntGdiIntersectRect(WindowRect
, WindowRect
, &ParentWnd
->ClientRect
))
78 /* FIXME: Layered windows. */
80 ParentWindow
= ParentWindow
->Parent
;
87 IntValidateParent(PWINDOW_OBJECT Child
, HRGN hValidateRgn
, BOOL Recurse
)
89 PWINDOW_OBJECT ParentWindow
= Child
->Parent
;
94 ParentWnd
= ParentWindow
->Wnd
;
95 if (ParentWnd
->Style
& WS_CLIPCHILDREN
)
98 if (ParentWindow
->UpdateRegion
!= 0)
103 IntInvalidateWindows(ParentWindow
, hValidateRgn
,
104 RDW_VALIDATE
| RDW_NOCHILDREN
);
107 ParentWindow
= ParentWindow
->Parent
;
114 * @name IntCalcWindowRgn
116 * Get a window or client region.
120 IntCalcWindowRgn(PWINDOW_OBJECT Window
, BOOL Client
)
128 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Wnd
->ClientRect
);
130 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Wnd
->WindowRect
);
132 if (Window
->WindowRegion
!= NULL
&& !(Wnd
->Style
& WS_MINIMIZE
))
134 NtGdiOffsetRgn(hRgnWindow
,
135 -Wnd
->WindowRect
.left
,
136 -Wnd
->WindowRect
.top
);
137 RgnType
= NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Window
->WindowRegion
, RGN_AND
);
138 NtGdiOffsetRgn(hRgnWindow
,
139 Wnd
->WindowRect
.left
,
140 Wnd
->WindowRect
.top
);
147 * @name IntGetNCUpdateRgn
149 * Get non-client update region of a window and optionally validate it.
152 * Pointer to window to get the NC update region from.
154 * Set to TRUE to force validating the NC update region.
157 * Handle to NC update region. The caller is responsible for deleting
162 IntGetNCUpdateRgn(PWINDOW_OBJECT Window
, BOOL Validate
)
168 if (Window
->UpdateRegion
!= NULL
&&
169 Window
->UpdateRegion
!= (HRGN
)1)
171 hRgnNonClient
= NtGdiCreateRectRgn(0, 0, 0, 0);
174 * If region creation fails it's safe to fallback to whole
177 if (hRgnNonClient
== NULL
)
182 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
183 if (hRgnWindow
== NULL
)
185 NtGdiDeleteObject(hRgnNonClient
);
189 RgnType
= NtGdiCombineRgn(hRgnNonClient
, Window
->UpdateRegion
,
190 hRgnWindow
, RGN_DIFF
);
191 if (RgnType
== ERROR
)
193 NtGdiDeleteObject(hRgnWindow
);
194 NtGdiDeleteObject(hRgnNonClient
);
197 else if (RgnType
== NULLREGION
)
199 NtGdiDeleteObject(hRgnWindow
);
200 NtGdiDeleteObject(hRgnNonClient
);
205 * Remove the nonclient region from the standard update region if
206 * we were asked for it.
211 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
212 hRgnWindow
, RGN_AND
) == NULLREGION
)
214 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
215 NtGdiDeleteObject(Window
->UpdateRegion
);
216 Window
->UpdateRegion
= NULL
;
217 if (!(Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
218 MsqDecPaintCountQueue(Window
->MessageQueue
);
222 NtGdiDeleteObject(hRgnWindow
);
224 return hRgnNonClient
;
228 return Window
->UpdateRegion
;
235 * Internal function used by IntRedrawWindow.
239 co_IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
, BOOL Recurse
)
242 HWND hWnd
= Window
->hSelf
;
248 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
250 if (Window
->UpdateRegion
)
252 if (!IntValidateParent(Window
, Window
->UpdateRegion
, Recurse
))
256 if (Flags
& RDW_UPDATENOW
)
258 if (Window
->UpdateRegion
!= NULL
||
259 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
261 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
266 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
268 TempRegion
= IntGetNCUpdateRgn(Window
, TRUE
);
269 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
270 MsqDecPaintCountQueue(Window
->MessageQueue
);
271 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
272 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
274 /* NOTE: The region can already be deleted! */
275 GDIOBJ_FreeObjByHandle(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
279 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
281 if (Window
->UpdateRegion
)
283 hDC
= UserGetDCEx(Window
, Window
->UpdateRegion
,
284 DCX_CACHE
| DCX_USESTYLE
|
285 DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
);
286 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
288 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
290 UserReleaseDC(Window
, hDC
, FALSE
);
297 * Check that the window is still valid at this point
299 if (!IntIsWindow(hWnd
))
305 * Paint child windows.
307 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->Style
& WS_MINIMIZE
) &&
308 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->Style
& WS_CLIPCHILDREN
)))
312 if ((List
= IntWinListChildren(Window
)))
314 /* FIXME: Handle WS_EX_TRANSPARENT */
315 for (phWnd
= List
; *phWnd
; ++phWnd
)
317 Window
= UserGetWindowObject(*phWnd
);
319 if (Window
&& (Wnd
->Style
& WS_VISIBLE
))
321 USER_REFERENCE_ENTRY Ref
;
322 UserRefObjectCo(Window
, &Ref
);
323 co_IntPaintWindows(Window
, Flags
, TRUE
);
324 UserDerefObjectCo(Window
);
333 * IntInvalidateWindows
335 * Internal function used by IntRedrawWindow.
339 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
343 BOOL HadPaintMessage
, HadNCPaintMessage
;
344 BOOL HasPaintMessage
, HasNCPaintMessage
;
349 * If the nonclient is not to be redrawn, clip the region to the client
352 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
356 hRgnClient
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->ClientRect
);
357 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
358 NtGdiDeleteObject(hRgnClient
);
362 * Clip the given region with window rectangle (or region)
365 if (!Window
->WindowRegion
|| (Wnd
->Style
& WS_MINIMIZE
))
369 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->WindowRect
);
370 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
371 NtGdiDeleteObject(hRgnWindow
);
376 -Wnd
->WindowRect
.left
,
377 -Wnd
->WindowRect
.top
);
378 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
380 Wnd
->WindowRect
.left
,
381 Wnd
->WindowRect
.top
);
385 * Save current state of pending updates
388 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
389 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
390 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
393 * Update the region and flags
396 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
398 if (Window
->UpdateRegion
== NULL
)
400 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
401 GDIOBJ_SetOwnership(Window
->UpdateRegion
, NULL
);
404 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
405 hRgn
, RGN_OR
) == NULLREGION
)
407 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
408 NtGdiDeleteObject(Window
->UpdateRegion
);
409 Window
->UpdateRegion
= NULL
;
412 if (Flags
& RDW_FRAME
)
413 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
414 if (Flags
& RDW_ERASE
)
415 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
420 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
422 if (Window
->UpdateRegion
!= NULL
)
424 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
425 hRgn
, RGN_DIFF
) == NULLREGION
)
427 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
428 NtGdiDeleteObject(Window
->UpdateRegion
);
429 Window
->UpdateRegion
= NULL
;
433 if (Window
->UpdateRegion
== NULL
)
434 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
435 if (Flags
& RDW_NOFRAME
)
436 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
437 if (Flags
& RDW_NOERASE
)
438 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
441 if (Flags
& RDW_INTERNALPAINT
)
443 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
446 if (Flags
& RDW_NOINTERNALPAINT
)
448 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
452 * Process children if needed
455 if (!(Flags
& RDW_NOCHILDREN
) && !(Wnd
->Style
& WS_MINIMIZE
) &&
456 ((Flags
& RDW_ALLCHILDREN
) || !(Wnd
->Style
& WS_CLIPCHILDREN
)))
458 PWINDOW_OBJECT Child
;
460 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
462 if (Child
->Wnd
->Style
& WS_VISIBLE
)
465 * Recursive call to update children UpdateRegion
467 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
468 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
469 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
470 NtGdiDeleteObject(hRgnTemp
);
477 * Fake post paint messages to window message queue if needed
480 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
481 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
482 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
484 if (HasPaintMessage
!= HadPaintMessage
)
487 MsqDecPaintCountQueue(Window
->MessageQueue
);
489 MsqIncPaintCountQueue(Window
->MessageQueue
);
492 if (HasNCPaintMessage
!= HadNCPaintMessage
)
494 if (HadNCPaintMessage
)
495 MsqDecPaintCountQueue(Window
->MessageQueue
);
497 MsqIncPaintCountQueue(Window
->MessageQueue
);
503 * IntIsWindowDrawable
506 * Window is drawable when it is visible and all parents are not
511 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
513 PWINDOW_OBJECT WndObject
;
516 for (WndObject
= Window
; WndObject
!= NULL
; WndObject
= WndObject
->Parent
)
518 Wnd
= WndObject
->Wnd
;
519 if (!(Wnd
->Style
& WS_VISIBLE
) ||
520 ((Wnd
->Style
& WS_MINIMIZE
) && (WndObject
!= Window
)))
532 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
537 co_UserRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
544 * Validation of passed parameters.
547 if (!IntIsWindowDrawable(Window
) ||
548 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
549 (RDW_VALIDATE
| RDW_INVALIDATE
))
556 * Transform the parameters UpdateRgn and UpdateRect into
557 * a region hRgn specified in screen coordinates.
560 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
562 if (UpdateRgn
!= NULL
)
564 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
565 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
567 NtGdiDeleteObject(hRgn
);
571 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->ClientRect
.left
, Window
->Wnd
->ClientRect
.top
);
573 else if (UpdateRect
!= NULL
)
575 if (!IntGdiIsEmptyRect(UpdateRect
))
577 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
578 NtGdiOffsetRgn(hRgn
, Window
->Wnd
->ClientRect
.left
, Window
->Wnd
->ClientRect
.top
);
581 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
582 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
584 if (!IntGdiIsEmptyRect(&Window
->Wnd
->WindowRect
))
585 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->WindowRect
);
589 if (!IntGdiIsEmptyRect(&Window
->Wnd
->ClientRect
))
590 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->Wnd
->ClientRect
);
596 * Adjust the window update region depending on hRgn and flags.
599 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
602 IntInvalidateWindows(Window
, hRgn
, Flags
);
607 * Repaint and erase windows if needed.
610 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
612 co_IntPaintWindows(Window
, Flags
, FALSE
);
622 NtGdiDeleteObject(hRgn
);
629 IntIsWindowDirty(PWINDOW_OBJECT Window
)
631 PWINDOW Wnd
= Window
->Wnd
;
632 return (Wnd
->Style
& WS_VISIBLE
) &&
633 ((Window
->UpdateRegion
!= NULL
) ||
634 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
) ||
635 (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
));
639 IntFindWindowToRepaint(PWINDOW_OBJECT Window
, PW32THREAD Thread
)
642 PWINDOW_OBJECT TempWindow
;
643 PWINDOW Wnd
, TempWnd
;
645 for (; Window
!= NULL
; Window
= Window
->NextSibling
)
648 if (IntWndBelongsToThread(Window
, Thread
) &&
649 IntIsWindowDirty(Window
))
651 /* Make sure all non-transparent siblings are already drawn. */
652 if (Wnd
->ExStyle
& WS_EX_TRANSPARENT
)
654 for (TempWindow
= Window
->NextSibling
; TempWindow
!= NULL
;
655 TempWindow
= TempWindow
->NextSibling
)
657 TempWnd
= TempWindow
->Wnd
;
658 if (!(TempWnd
->ExStyle
& WS_EX_TRANSPARENT
) &&
659 IntWndBelongsToThread(TempWindow
, Thread
) &&
660 IntIsWindowDirty(TempWindow
))
662 return TempWindow
->hSelf
;
667 return Window
->hSelf
;
670 if (Window
->FirstChild
)
672 hChild
= IntFindWindowToRepaint(Window
->FirstChild
, Thread
);
682 IntGetPaintMessage(HWND hWnd
, UINT MsgFilterMin
, UINT MsgFilterMax
,
683 PW32THREAD Thread
, MSG
*Message
, BOOL Remove
)
685 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
687 if (!MessageQueue
->PaintCount
)
690 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
691 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
694 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
696 if (Message
->hwnd
== NULL
)
698 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
699 /* Hack to stop spamming the debuglog ! */
700 MessageQueue
->PaintCount
= 0;
704 if (hWnd
!= NULL
&& Message
->hwnd
!= hWnd
)
707 Message
->message
= WM_PAINT
;
708 Message
->wParam
= Message
->lParam
= 0;
715 co_IntFixCaret(PWINDOW_OBJECT Window
, LPRECT lprc
, UINT flags
)
717 PDESKTOP_OBJECT Desktop
;
718 PTHRDCARETINFO CaretInfo
;
720 PWINDOW_OBJECT WndCaret
;
722 ASSERT_REFS_CO(Window
);
724 Desktop
= ((PW32THREAD
)PsGetCurrentThread()->Tcb
.Win32Thread
)->Desktop
;
725 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
726 hWndCaret
= CaretInfo
->hWnd
;
728 WndCaret
= UserGetWindowObject(hWndCaret
);
730 //fix: check for WndCaret can be null
731 if (WndCaret
== Window
||
732 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
734 POINT pt
, FromOffset
, ToOffset
, Offset
;
737 pt
.x
= CaretInfo
->Pos
.x
;
738 pt
.y
= CaretInfo
->Pos
.y
;
739 IntGetClientOrigin(WndCaret
, &FromOffset
);
740 IntGetClientOrigin(Window
, &ToOffset
);
741 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
742 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
745 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
746 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
747 if (IntGdiIntersectRect(lprc
, lprc
, &rcCaret
))
759 /* PUBLIC FUNCTIONS ***********************************************************/
769 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
771 PWINDOW_OBJECT Window
= NULL
;
775 USER_REFERENCE_ENTRY Ref
;
778 DPRINT("Enter NtUserBeginPaint\n");
779 UserEnterExclusive();
781 if (!(Window
= UserGetWindowObject(hWnd
)))
786 UserRefObjectCo(Window
, &Ref
);
790 co_UserHideCaret(Window
);
792 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
796 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
797 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
798 MsqDecPaintCountQueue(Window
->MessageQueue
);
799 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
800 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
802 /* NOTE: The region can already by deleted! */
803 GDIOBJ_FreeObjByHandle(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
807 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
809 Ps
.hdc
= UserGetDCEx(Window
, Window
->UpdateRegion
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
815 if (Window
->UpdateRegion
!= NULL
)
817 MsqDecPaintCountQueue(Window
->MessageQueue
);
818 GdiGetClipBox(Ps
.hdc
, &Ps
.rcPaint
);
819 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
820 /* The region is part of the dc now and belongs to the process! */
821 Window
->UpdateRegion
= NULL
;
825 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
826 MsqDecPaintCountQueue(Window
->MessageQueue
);
828 IntGetClientRect(Window
, &Ps
.rcPaint
);
831 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
833 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
835 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
836 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
842 if (Window
->UpdateRegion
)
844 if (!(Wnd
->Style
& WS_CLIPCHILDREN
))
846 PWINDOW_OBJECT Child
;
847 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
849 IntInvalidateWindows(Child
, Window
->UpdateRegion
, RDW_FRAME
| RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
854 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
855 if (! NT_SUCCESS(Status
))
857 SetLastNtError(Status
);
864 if (Window
) UserDerefObjectCo(Window
);
866 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
880 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* pUnsafePs
)
882 NTSTATUS Status
= STATUS_SUCCESS
;
883 PWINDOW_OBJECT Window
;
884 DECLARE_RETURN(BOOL
);
885 USER_REFERENCE_ENTRY Ref
;
888 DPRINT("Enter NtUserEndPaint\n");
889 UserEnterExclusive();
891 if (!(Window
= UserGetWindowObject(hWnd
)))
898 ProbeForRead(pUnsafePs
, sizeof(*pUnsafePs
), 1);
899 hdc
= pUnsafePs
->hdc
;
903 Status
= _SEH_GetExceptionCode();
906 if (!NT_SUCCESS(Status
))
911 UserReleaseDC(Window
, hdc
, TRUE
);
913 UserRefObjectCo(Window
, &Ref
);
914 co_UserShowCaret(Window
);
915 UserDerefObjectCo(Window
);
920 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
927 co_UserGetUpdateRgn(PWINDOW_OBJECT Window
, HRGN hRgn
, BOOL bErase
)
932 ASSERT_REFS_CO(Window
);
934 if (Window
->UpdateRegion
== NULL
)
936 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
940 Rect
= Window
->Wnd
->ClientRect
;
941 IntIntersectWithParents(Window
, &Rect
);
942 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
943 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->UpdateRegion
, RGN_AND
);
944 NtGdiOffsetRgn(hRgn
, -Window
->Wnd
->ClientRect
.left
, -Window
->Wnd
->ClientRect
.top
);
947 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
949 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
963 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
966 PWINDOW_OBJECT Window
;
968 USER_REFERENCE_ENTRY Ref
;
970 DPRINT("Enter NtUserGetUpdateRgn\n");
971 UserEnterExclusive();
973 if (!(Window
= UserGetWindowObject(hWnd
)))
978 UserRefObjectCo(Window
, &Ref
);
979 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
980 UserDerefObjectCo(Window
);
985 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
991 * NtUserGetUpdateRect
998 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
1000 PWINDOW_OBJECT Window
;
1003 PROSRGNDATA RgnData
;
1005 DECLARE_RETURN(BOOL
);
1007 DPRINT("Enter NtUserGetUpdateRect\n");
1008 UserEnterExclusive();
1010 if (!(Window
= UserGetWindowObject(hWnd
)))
1015 if (Window
->UpdateRegion
== NULL
)
1017 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1021 /* Get the update region bounding box. */
1022 if (Window
->UpdateRegion
== (HRGN
)1)
1024 Rect
= Window
->Wnd
->ClientRect
;
1028 RgnData
= REGION_LockRgn(Window
->UpdateRegion
);
1029 ASSERT(RgnData
!= NULL
);
1030 RegionType
= REGION_GetRgnBox(RgnData
, &Rect
);
1031 REGION_UnlockRgn(RgnData
);
1033 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
1034 IntGdiIntersectRect(&Rect
, &Rect
, &Window
->Wnd
->ClientRect
);
1037 if (IntIntersectWithParents(Window
, &Rect
))
1039 IntGdiOffsetRect(&Rect
,
1040 -Window
->Wnd
->ClientRect
.left
,
1041 -Window
->Wnd
->ClientRect
.top
);
1044 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
1048 if (bErase
&& !IntGdiIsEmptyRect(&Rect
))
1050 USER_REFERENCE_ENTRY Ref
;
1051 UserRefObjectCo(Window
, &Ref
);
1052 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1053 UserDerefObjectCo(Window
);
1056 if (UnsafeRect
!= NULL
)
1058 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECT
));
1059 if (!NT_SUCCESS(Status
))
1061 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1066 RETURN(!IntGdiIsEmptyRect(&Rect
));
1069 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1075 * NtUserRedrawWindow
1082 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
1085 RECT SafeUpdateRect
;
1088 DECLARE_RETURN(BOOL
);
1089 USER_REFERENCE_ENTRY Ref
;
1091 DPRINT("Enter NtUserRedrawWindow\n");
1092 UserEnterExclusive();
1094 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1099 if (lprcUpdate
!= NULL
)
1101 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
1104 if (!NT_SUCCESS(Status
))
1106 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1111 UserRefObjectCo(Wnd
, &Ref
);
1113 Status
= co_UserRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
1116 UserDerefObjectCo(Wnd
);
1118 if (!NT_SUCCESS(Status
))
1120 /* IntRedrawWindow fails only in case that flags are invalid */
1121 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1128 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1137 UserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*prcScroll
,
1138 const RECT
*prcClip
, HRGN hrgnUpdate
, LPRECT prcUpdate
)
1141 RECT rcScroll
, rcClip
, rcSrc
, rcDst
;
1144 GdiGetClipBox(hDC
, &rcClip
);
1148 IntGdiIntersectRect(&rcClip
, &rcClip
, prcClip
);
1153 rcScroll
= *prcScroll
;
1154 IntGdiIntersectRect(&rcSrc
, &rcClip
, prcScroll
);
1162 IntGdiOffsetRect(&rcDst
, dx
, dy
);
1163 IntGdiIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1165 if (!NtGdiBitBlt(hDC
, rcDst
.left
, rcDst
.top
,
1166 rcDst
.right
- rcDst
.left
, rcDst
.bottom
- rcDst
.top
,
1167 hDC
, rcDst
.left
- dx
, rcDst
.top
- dy
, SRCCOPY
, 0, 0))
1172 /* Calculate the region that was invalidated by moving or
1173 could not be copied, because it was not visible */
1174 if (hrgnUpdate
|| prcUpdate
)
1176 HRGN hrgnOwn
, hrgnVisible
, hrgnTmp
;
1178 pDC
= DC_LockDc(hDC
);
1183 hrgnVisible
= pDC
->w
.hVisRgn
; // pDC->w.hGCClipRgn?
1186 /* Begin with the shifted and then clipped scroll rect */
1188 IntGdiOffsetRect(&rcDst
, dx
, dy
);
1189 IntGdiIntersectRect(&rcDst
, &rcDst
, &rcClip
);
1192 hrgnOwn
= hrgnUpdate
;
1193 if (!NtGdiSetRectRgn(hrgnOwn
, rcDst
.left
, rcDst
.top
, rcDst
.right
, rcDst
.bottom
))
1200 hrgnOwn
= UnsafeIntCreateRectRgnIndirect(&rcDst
);
1203 /* Add the source rect */
1204 hrgnTmp
= UnsafeIntCreateRectRgnIndirect(&rcSrc
);
1205 NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_OR
);
1207 /* Substract the part of the dest that was visible in source */
1208 NtGdiCombineRgn(hrgnTmp
, hrgnTmp
, hrgnVisible
, RGN_AND
);
1209 NtGdiOffsetRgn(hrgnTmp
, dx
, dy
);
1210 Result
= NtGdiCombineRgn(hrgnOwn
, hrgnOwn
, hrgnTmp
, RGN_DIFF
);
1212 NtGdiDeleteObject(hrgnTmp
);
1216 IntGdiGetRgnBox(hrgnOwn
, prcUpdate
);
1221 NtGdiDeleteObject(hrgnOwn
);
1225 Result
= NULLREGION
;
1241 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*prcUnsafeScroll
,
1242 const RECT
*prcUnsafeClip
, HRGN hrgnUpdate
, LPRECT prcUnsafeUpdate
)
1244 DECLARE_RETURN(DWORD
);
1245 RECT rcScroll
, rcClip
, rcUpdate
;
1246 NTSTATUS Status
= STATUS_SUCCESS
;
1249 DPRINT("Enter NtUserScrollDC\n");
1250 UserEnterExclusive();
1254 if (prcUnsafeScroll
)
1256 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1257 rcScroll
= *prcUnsafeScroll
;
1261 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1262 rcClip
= *prcUnsafeClip
;
1264 if (prcUnsafeUpdate
)
1266 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1271 Status
= _SEH_GetExceptionCode();
1274 if (!NT_SUCCESS(Status
))
1276 SetLastNtError(Status
);
1280 Result
= UserScrollDC(hDC
, dx
, dy
,
1281 prcUnsafeScroll
? &rcScroll
: 0,
1282 prcUnsafeClip
? &rcClip
: 0, hrgnUpdate
,
1283 prcUnsafeUpdate
? &rcUpdate
: NULL
);
1286 /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
1290 if (prcUnsafeUpdate
)
1294 *prcUnsafeUpdate
= rcUpdate
;
1298 Status
= _SEH_GetExceptionCode();
1301 if (!NT_SUCCESS(Status
))
1303 /* FIXME: SetLastError? */
1304 /* FIXME: correct? We have already scrolled! */
1312 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1318 * NtUserScrollWindowEx
1325 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*prcUnsafeScroll
,
1326 const RECT
*prcUnsafeClip
, HRGN hrgnUpdate
, LPRECT prcUnsafeUpdate
, UINT flags
)
1328 RECT rcScroll
, rcClip
, rcCaret
, rcUpdate
;
1330 PWINDOW_OBJECT Window
= NULL
, CaretWnd
;
1332 HRGN hrgnOwn
= NULL
, hrgnTemp
;
1334 NTSTATUS Status
= STATUS_SUCCESS
;
1335 DECLARE_RETURN(DWORD
);
1336 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1338 DPRINT("Enter NtUserScrollWindowEx\n");
1339 UserEnterExclusive();
1341 Window
= UserGetWindowObject(hWnd
);
1342 if (!Window
|| !IntIsWindowDrawable(Window
))
1344 Window
= NULL
; /* prevent deref at cleanup */
1347 UserRefObjectCo(Window
, &Ref
);
1349 IntGetClientRect(Window
, &rcClip
);
1353 if (prcUnsafeScroll
)
1355 ProbeForRead(prcUnsafeScroll
, sizeof(*prcUnsafeScroll
), 1);
1356 IntGdiIntersectRect(&rcScroll
, &rcClip
, prcUnsafeScroll
);
1363 ProbeForRead(prcUnsafeClip
, sizeof(*prcUnsafeClip
), 1);
1364 IntGdiIntersectRect(&rcClip
, &rcClip
, prcUnsafeClip
);
1369 Status
= _SEH_GetExceptionCode();
1373 if (!NT_SUCCESS(Status
))
1375 SetLastNtError(Status
);
1379 if (rcClip
.right
<= rcClip
.left
|| rcClip
.bottom
<= rcClip
.top
||
1380 (dx
== 0 && dy
== 0))
1386 hrgnOwn
= hrgnUpdate
;
1388 hrgnOwn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1390 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1393 /* FIXME: SetLastError? */
1398 hwndCaret
= co_IntFixCaret(Window
, &rcCaret
, flags
);
1400 Result
= UserScrollDC(hDC
, dx
, dy
, &rcScroll
, &rcClip
, hrgnOwn
, prcUnsafeUpdate
? &rcUpdate
: NULL
);
1401 UserReleaseDC(Window
, hDC
, FALSE
);
1404 * Take into account the fact that some damage may have occurred during
1408 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1409 if (co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
) != NULLREGION
)
1411 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&rcClip
);
1412 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1413 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1414 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1415 NtGdiDeleteObject(hrgnClip
);
1417 NtGdiDeleteObject(hrgnTemp
);
1419 if (flags
& SW_SCROLLCHILDREN
)
1421 PWINDOW_OBJECT Child
;
1424 USER_REFERENCE_ENTRY WndRef
;
1427 IntGetClientOrigin(Window
, &ClientOrigin
);
1428 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
1430 rcChild
= Child
->Wnd
->WindowRect
;
1431 rcChild
.left
-= ClientOrigin
.x
;
1432 rcChild
.top
-= ClientOrigin
.y
;
1433 rcChild
.right
-= ClientOrigin
.x
;
1434 rcChild
.bottom
-= ClientOrigin
.y
;
1436 if (! prcUnsafeScroll
|| IntGdiIntersectRect(&rcDummy
, &rcChild
, &rcScroll
))
1438 UserRefObjectCo(Child
, &WndRef
);
1439 co_WinPosSetWindowPos(Child
, 0, rcChild
.left
+ dx
, rcChild
.top
+ dy
, 0, 0,
1440 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1442 UserDerefObjectCo(Child
);
1447 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1449 co_UserRedrawWindow(Window
, NULL
, hrgnOwn
, RDW_INVALIDATE
| RDW_ERASE
|
1450 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1451 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1454 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1456 UserRefObjectCo(CaretWnd
, &CaretRef
);
1458 co_IntSetCaretPos(rcCaret
.left
+ dx
, rcCaret
.top
+ dy
);
1459 co_UserShowCaret(CaretWnd
);
1461 UserDerefObjectCo(CaretWnd
);
1464 if (prcUnsafeUpdate
)
1468 /* Probe here, to not fail on invalid pointer before scrolling */
1469 ProbeForWrite(prcUnsafeUpdate
, sizeof(*prcUnsafeUpdate
), 1);
1470 *prcUnsafeUpdate
= rcUpdate
;
1474 Status
= _SEH_GetExceptionCode();
1478 if (!NT_SUCCESS(Status
))
1480 SetLastNtError(Status
);
1488 if (hrgnOwn
&& !hrgnUpdate
)
1490 NtGdiDeleteObject(hrgnOwn
);
1494 UserDerefObjectCo(Window
);
1496 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);
1503 UserDrawSysMenuButton(
1504 PWINDOW_OBJECT pWnd
,
1510 PCURICON_OBJECT pIcon
;
1512 ASSERT(pWnd
&& lpRc
);
1514 /* Get the icon to draw. We don't care about WM_GETICON here. */
1516 hIcon
= pWnd
->Wnd
->Class
->hIconSm
;
1520 DPRINT("Wnd class has no small icon.\n");
1521 hIcon
= pWnd
->Wnd
->Class
->hIcon
;
1526 DPRINT("Wnd class hasn't any icon.\n");
1527 //FIXME: Draw "winlogo" icon.
1531 if(!(pIcon
= UserGetCurIconObject(hIcon
)))
1533 DPRINT1("UserGetCurIconObject() failed!\n");
1537 return UserDrawIconEx(hDc
, lpRc
->left
, lpRc
->top
, pIcon
,
1538 UserGetSystemMetrics(SM_CXSMICON
),
1539 UserGetSystemMetrics(SM_CYSMICON
),
1540 0, NULL
, DI_NORMAL
);
1544 UserDrawCaptionText(HDC hDc
,
1545 const PUNICODE_STRING Text
,
1549 HFONT hOldFont
= NULL
, hFont
= NULL
;
1550 COLORREF OldTextColor
;
1551 NONCLIENTMETRICSW nclm
;
1555 DPRINT("%s:", __FUNCTION__
);
1556 for(i
= 0; i
< Text
->Length
/sizeof(WCHAR
); i
++)
1557 DbgPrint("%C", Text
->Buffer
[i
]);
1558 DbgPrint(", %d\n", Text
->Length
/sizeof(WCHAR
));
1561 nclm
.cbSize
= sizeof(nclm
);
1562 if(!IntSystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1563 sizeof(NONCLIENTMETRICS
), &nclm
, 0))
1565 DPRINT1("%s: IntSystemParametersInfo() failed!\n", __FUNCTION__
);
1569 IntGdiSetBkMode(hDc
, TRANSPARENT
);
1571 if(uFlags
& DC_SMALLCAP
)
1572 Status
= TextIntCreateFontIndirect(&nclm
.lfSmCaptionFont
, &hFont
);
1573 else Status
= TextIntCreateFontIndirect(&nclm
.lfCaptionFont
, &hFont
);
1575 if(!NT_SUCCESS(Status
))
1577 DPRINT1("%s: TextIntCreateFontIndirect() failed! Status: 0x%x\n",
1578 __FUNCTION__
, Status
);
1582 hOldFont
= NtGdiSelectFont(hDc
, hFont
);
1585 DPRINT1("%s: SelectFont() failed!\n", __FUNCTION__
);
1586 NtGdiDeleteObject(hFont
);
1590 if(uFlags
& DC_INBUTTON
)
1591 OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(COLOR_BTNTEXT
));
1592 else OldTextColor
= IntGdiSetTextColor(hDc
, IntGetSysColor(uFlags
& DC_ACTIVE
1593 ? COLOR_CAPTIONTEXT
: COLOR_INACTIVECAPTIONTEXT
));
1595 //FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
1597 NtGdiExtTextOutW(hDc
, lpRc
->left
,
1598 lpRc
->top
, 0, NULL
, Text
->Buffer
,
1599 Text
->Length
/sizeof(WCHAR
), NULL
, 0);
1601 IntGdiSetTextColor(hDc
, OldTextColor
);
1602 NtGdiSelectFont(hDc
, hOldFont
);
1603 NtGdiDeleteObject(hFont
);
1608 BOOL
UserDrawCaption(
1609 PWINDOW_OBJECT pWnd
,
1614 const PUNICODE_STRING str
,
1618 HBITMAP hMemBmp
= NULL
, hOldBmp
= NULL
;
1619 HBRUSH hOldBrush
= NULL
;
1622 UINT VCenter
= 0, Padding
= 0;
1624 LONG ButtonWidth
, IconWidth
;
1628 //ASSERT(pWnd != NULL);
1633 hMemBmp
= NtGdiCreateCompatibleBitmap(hDc
,
1634 lpRc
->right
- lpRc
->left
,
1635 lpRc
->bottom
- lpRc
->top
);
1639 DPRINT1("%s: NtGdiCreateCompatibleBitmap() failed!\n", __FUNCTION__
);
1643 hMemDc
= NtGdiCreateCompatibleDC(hDc
);
1646 DPRINT1("%s: NtGdiCreateCompatibleDC() failed!\n", __FUNCTION__
);
1650 hOldBmp
= NtGdiSelectBitmap(hMemDc
, hMemBmp
);
1653 DPRINT1("%s: NtGdiSelectBitmap() failed!\n", __FUNCTION__
);
1657 Height
= UserGetSystemMetrics(SM_CYCAPTION
) - 1;
1658 VCenter
= (lpRc
->bottom
- lpRc
->top
) / 2;
1659 Padding
= VCenter
- (Height
/ 2);
1661 if ((!hIcon
) && (Wnd
!= NULL
))
1663 HasIcon
= (uFlags
& DC_ICON
) && (Wnd
->Style
& WS_SYSMENU
)
1664 && !(uFlags
& DC_SMALLCAP
) && !(Wnd
->ExStyle
& WS_EX_DLGMODALFRAME
)
1665 && !(Wnd
->ExStyle
& WS_EX_TOOLWINDOW
);
1668 HasIcon
= (hIcon
!= 0);
1670 IconWidth
= UserGetSystemMetrics(SM_CXSIZE
) + Padding
;
1673 r
.right
= r
.left
+ (lpRc
->right
- lpRc
->left
);
1675 r
.bottom
= r
.top
+ (Height
/ 2);
1677 // Draw the caption background
1678 if(uFlags
& DC_INBUTTON
)
1680 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1681 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1682 COLOR_BTNFACE
: COLOR_BTNSHADOW
));
1686 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1690 if(!NtGdiPatBlt(hMemDc
, 0, 0,
1691 lpRc
->right
- lpRc
->left
,
1692 lpRc
->bottom
- lpRc
->top
,
1695 DPRINT1("%s: NtGdiPatBlt() failed!\n", __FUNCTION__
);
1699 if(HasIcon
) r
.left
+=IconWidth
;
1703 r
.right
= (lpRc
->right
- lpRc
->left
);
1704 if(uFlags
& DC_SMALLCAP
)
1705 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1706 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1708 hOldBrush
= NtGdiSelectBrush(hMemDc
,
1709 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1710 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
));
1714 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1718 if(HasIcon
&& (uFlags
& DC_GRADIENT
))
1720 NtGdiPatBlt(hMemDc
, 0, 0,
1722 lpRc
->bottom
- lpRc
->top
,
1728 NtGdiPatBlt(hMemDc
, 0, 0,
1729 lpRc
->right
- lpRc
->left
,
1730 lpRc
->bottom
- lpRc
->top
,
1734 if(uFlags
& DC_GRADIENT
)
1736 static GRADIENT_RECT gcap
= {0, 1};
1743 if(Wnd
->Style
& WS_SYSMENU
)
1745 r
.right
-= 3 + ButtonWidth
;
1746 if(!(uFlags
& DC_SMALLCAP
))
1748 if(Wnd
->Style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1749 r
.right
-= 2 + 2 * ButtonWidth
;
1754 //Draw buttons background
1755 if(!NtGdiSelectBrush(hMemDc
,
1756 IntGetSysColorBrush(uFlags
& DC_ACTIVE
?
1757 COLOR_GRADIENTACTIVECAPTION
:COLOR_GRADIENTINACTIVECAPTION
)))
1759 DPRINT1("%s: NtGdiSelectBrush() failed!\n", __FUNCTION__
);
1766 lpRc
->right
- lpRc
->left
- r
.right
,
1767 lpRc
->bottom
- lpRc
->top
,
1772 Colors
[0] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1773 COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1775 Colors
[1] = IntGetSysColor((uFlags
& DC_ACTIVE
) ?
1776 COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1780 vert
[0].Red
= (WORD
)Colors
[0]<<8;
1781 vert
[0].Green
= (WORD
)Colors
[0] & 0xFF00;
1782 vert
[0].Blue
= (WORD
)(Colors
[0]>>8) & 0xFF00;
1785 vert
[1].x
= r
.right
;
1786 vert
[1].y
= lpRc
->bottom
- lpRc
->top
;
1787 vert
[1].Red
= (WORD
)Colors
[1]<<8;
1788 vert
[1].Green
= (WORD
)Colors
[1] & 0xFF00;
1789 vert
[1].Blue
= (WORD
)(Colors
[1]>>8) & 0xFF00;
1792 pMemDc
= DC_LockDc(hMemDc
);
1795 DPRINT1("%s: Can't lock dc!\n", __FUNCTION__
);
1799 if(!IntGdiGradientFill(pMemDc
, vert
, 2, &gcap
,
1800 1, GRADIENT_FILL_RECT_H
))
1802 DPRINT1("%s: IntGdiGradientFill() failed!\n", __FUNCTION__
);
1805 DC_UnlockDc(pMemDc
);
1806 } //if(uFlags & DC_GRADIENT)
1812 r
.left
-= --IconWidth
;
1813 /* FIXME: Draw the Icon when pWnd == NULL but hIcon is valid */
1815 UserDrawSysMenuButton(pWnd
, hMemDc
, &r
, FALSE
);
1816 r
.left
+= IconWidth
;
1823 r
.bottom
= r
.top
+ Height
;
1825 if((uFlags
& DC_TEXT
))
1827 if(!(uFlags
& DC_GRADIENT
))
1829 r
.right
= (lpRc
->right
- lpRc
->left
);
1831 if(uFlags
& DC_SMALLCAP
)
1832 ButtonWidth
= UserGetSystemMetrics(SM_CXSMSIZE
) - 2;
1833 else ButtonWidth
= UserGetSystemMetrics(SM_CXSIZE
) - 2;
1835 if ((Wnd
!= NULL
) && (Wnd
->Style
& WS_SYSMENU
))
1837 r
.right
-= 3 + ButtonWidth
;
1838 if(! (uFlags
& DC_SMALLCAP
))
1840 if(Wnd
->Style
& (WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
))
1841 r
.right
-= 2 + 2 * ButtonWidth
;
1848 /* FIXME: hFont isn't handled */
1850 UserDrawCaptionText(hMemDc
, str
, &r
, uFlags
);
1851 else if (pWnd
!= NULL
)
1852 UserDrawCaptionText(hMemDc
, &pWnd
->Wnd
->WindowName
, &r
, uFlags
);
1855 if(!NtGdiBitBlt(hDc
, lpRc
->left
, lpRc
->top
,
1856 lpRc
->right
- lpRc
->left
, lpRc
->bottom
- lpRc
->top
,
1857 hMemDc
, 0, 0, SRCCOPY
, 0, 0))
1859 DPRINT1("%s: NtGdiBitBlt() failed!\n", __FUNCTION__
);
1866 if (hOldBrush
) NtGdiSelectBrush(hMemDc
, hOldBrush
);
1867 if (hOldBmp
) NtGdiSelectBitmap(hMemDc
, hOldBmp
);
1868 if (hMemBmp
) NtGdiDeleteObject(hMemBmp
);
1869 if (hMemDc
) NtGdiDeleteObjectApp(hMemDc
);
1876 UserRealizePalette(HDC hdc
)
1881 Ret
= IntGdiRealizePalette(hdc
);
1882 if (Ret
) // There was a change.
1884 hWnd
= IntWindowFromDC(hdc
);
1885 if (hWnd
) // Send broadcast if dc is associated with a window.
1886 { // FYI: Thread locked in CallOneParam.
1887 co_IntSendMessage((HWND
)HWND_BROADCAST
, WM_PALETTECHANGED
, (WPARAM
)hWnd
, 0);
1895 NtUserDrawCaptionTemp(
1901 const PUNICODE_STRING str
,
1904 PWINDOW_OBJECT pWnd
= NULL
;
1906 UNICODE_STRING SafeStr
= {0};
1909 UserEnterExclusive();
1913 if(!(pWnd
= UserGetWindowObject(hWnd
)))
1922 ProbeForRead(lpRc
, sizeof(RECT
), sizeof(ULONG
));
1923 RtlCopyMemory(&SafeRect
, lpRc
, sizeof(RECT
));
1926 SafeStr
= ProbeForReadUnicodeString(str
);
1927 if (SafeStr
.Length
!= 0)
1929 ProbeForRead(SafeStr
.Buffer
,
1933 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, &SafeStr
, uFlags
);
1936 Ret
= UserDrawCaption(pWnd
, hDC
, &SafeRect
, hFont
, hIcon
, NULL
, uFlags
);
1940 SetLastNtError(_SEH_GetExceptionCode());
1950 NtUserDrawCaption(HWND hWnd
,
1955 return NtUserDrawCaptionTemp(hWnd
, hDC
, lpRc
, 0, 0, NULL
, uFlags
);
1960 NtUserInvalidateRect(
1962 CONST RECT
*lpUnsafeRect
,
1965 return NtUserRedrawWindow(hWnd
, lpUnsafeRect
, NULL
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));
1970 NtUserInvalidateRgn(
1975 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| (bErase
? RDW_ERASE
: 0));