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 #define DCX_USESTYLE 0x10000
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IntValidateParent(PWINDOW_OBJECT Child
, HRGN ValidRegion
)
45 PWINDOW_OBJECT ParentWindow
= IntGetParentObject(Child
), OldWindow
;
49 if (!(ParentWindow
->Style
& WS_CLIPCHILDREN
))
51 IntLockWindowUpdate(ParentWindow
);
52 if (ParentWindow
->UpdateRegion
!= 0)
57 * We must offset the child region by the offset of the
58 * child rect in the parent.
60 OffsetX
= Child
->WindowRect
.left
- ParentWindow
->WindowRect
.left
;
61 OffsetY
= Child
->WindowRect
.top
- ParentWindow
->WindowRect
.top
;
62 NtGdiOffsetRgn(ValidRegion
, OffsetX
, OffsetY
);
63 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
64 ValidRegion
, RGN_DIFF
);
65 /* FIXME: If the resulting region is empty, remove fake posted paint message */
66 NtGdiOffsetRgn(ValidRegion
, -OffsetX
, -OffsetY
);
68 IntUnLockWindowUpdate(ParentWindow
);
70 OldWindow
= ParentWindow
;
71 ParentWindow
= IntGetParentObject(ParentWindow
);
72 IntReleaseWindowObject(OldWindow
);
79 * Internal function used by IntRedrawWindow.
83 IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
86 HWND hWnd
= Window
->Self
;
89 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
91 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
93 IntLockWindowUpdate(Window
);
94 if (Window
->NCUpdateRegion
)
96 IntValidateParent(Window
, Window
->NCUpdateRegion
);
98 TempRegion
= Window
->NCUpdateRegion
;
99 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
101 GDIOBJ_SetOwnership(TempRegion
, PsGetCurrentProcess());
103 Window
->NCUpdateRegion
= NULL
;
104 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
105 MsqDecPaintCountQueue(Window
->MessageQueue
);
106 IntUnLockWindowUpdate(Window
);
107 IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
108 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
110 /* NOTE: The region can already be deleted! */
111 GDIOBJ_FreeObj(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
115 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
117 if (Window
->UpdateRegion
)
120 * This surely wrong! Why we would want to validate the parent?
121 * It breaks quite a few things including dummy WM_ERASEBKGND
122 * implementations that return only TRUE and have corresponding
123 * WM_PAINT that doesn't paint the whole client area.
124 * I left the code here so that no one will readd it again!
127 /* IntValidateParent(Window, Window->UpdateRegion); */
128 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
|
129 DCX_INTERSECTUPDATE
);
132 if (IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
134 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
136 NtUserReleaseDC(hWnd
, hDC
);
141 if (Flags
& RDW_UPDATENOW
)
143 if (Window
->UpdateRegion
!= NULL
||
144 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
146 IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
152 * Check that the window is still valid at this point
155 if (! IntIsWindow(hWnd
))
161 * Paint child windows.
163 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
164 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
168 if ((List
= IntWinListChildren(Window
)))
170 for (phWnd
= List
; *phWnd
; ++phWnd
)
172 Window
= IntGetWindowObject(*phWnd
);
173 if (Window
&& (Window
->Style
& WS_VISIBLE
))
175 IntPaintWindows(Window
, Flags
);
176 IntReleaseWindowObject(Window
);
185 * IntInvalidateWindows
187 * Internal function used by IntRedrawWindow.
191 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
194 BOOL HadPaintMessage
, HadNCPaintMessage
;
195 BOOL HasPaintMessage
, HasNCPaintMessage
;
198 * Clip the given region with window rectangle (or region)
201 IntLockWindowUpdate(Window
);
202 if (!Window
->WindowRegion
|| (Window
->Style
& WS_MINIMIZE
))
206 IntUnLockWindowUpdate(Window
);
207 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
208 NtGdiOffsetRgn(hRgnWindow
,
209 -Window
->WindowRect
.left
,
210 -Window
->WindowRect
.top
);
211 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
212 NtGdiDeleteObject(hRgnWindow
);
216 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
217 IntUnLockWindowUpdate(Window
);
221 * Save current state of pending updates
224 IntLockWindowUpdate(Window
);
225 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
226 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
227 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
230 * Update the region and flags
233 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
235 if (Window
->UpdateRegion
== NULL
)
237 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
238 GDIOBJ_SetOwnership(Window
->UpdateRegion
, NULL
);
241 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
242 hRgn
, RGN_OR
) == NULLREGION
)
244 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
245 NtGdiDeleteObject(Window
->UpdateRegion
);
246 Window
->UpdateRegion
= NULL
;
249 if (Flags
& RDW_FRAME
)
250 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
251 if (Flags
& RDW_ERASE
)
252 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
257 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
259 if (Window
->UpdateRegion
!= NULL
)
261 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
262 hRgn
, RGN_DIFF
) == NULLREGION
)
264 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
265 NtGdiDeleteObject(Window
->UpdateRegion
);
266 Window
->UpdateRegion
= NULL
;
270 if (Window
->UpdateRegion
== NULL
)
271 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
272 if (Flags
& RDW_NOFRAME
)
273 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
274 if (Flags
& RDW_NOERASE
)
275 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
278 if (Flags
& RDW_INTERNALPAINT
)
280 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
283 if (Flags
& RDW_NOINTERNALPAINT
)
285 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
289 * Split the nonclient update region.
292 if (NULL
!= Window
->UpdateRegion
)
294 HRGN hRgnWindow
, hRgnNonClient
;
296 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
297 NtGdiOffsetRgn(hRgnWindow
,
298 -Window
->WindowRect
.left
,
299 -Window
->WindowRect
.top
);
301 hRgnNonClient
= NtGdiCreateRectRgn(0, 0, 0, 0);
302 if (NtGdiCombineRgn(hRgnNonClient
, Window
->UpdateRegion
,
303 hRgnWindow
, RGN_DIFF
) == NULLREGION
)
305 NtGdiDeleteObject(hRgnNonClient
);
306 hRgnNonClient
= NULL
;
310 GDIOBJ_SetOwnership(hRgnNonClient
, NULL
);
314 * Remove the nonclient region from the standard update region.
316 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
317 hRgnWindow
, RGN_AND
) == NULLREGION
)
319 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
320 NtGdiDeleteObject(Window
->UpdateRegion
);
321 Window
->UpdateRegion
= NULL
;
324 if (Window
->NCUpdateRegion
== NULL
)
326 Window
->NCUpdateRegion
= hRgnNonClient
;
330 if(NULL
!= hRgnNonClient
)
332 NtGdiCombineRgn(Window
->NCUpdateRegion
, Window
->NCUpdateRegion
,
333 hRgnNonClient
, RGN_OR
);
334 GDIOBJ_SetOwnership(hRgnNonClient
, PsGetCurrentProcess());
335 NtGdiDeleteObject(hRgnNonClient
);
339 NtGdiDeleteObject(hRgnWindow
);
343 * Process children if needed
346 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
347 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
350 PWINDOW_OBJECT Child
;
352 if ((List
= IntWinListChildren(Window
)))
354 for (phWnd
= List
; *phWnd
; ++phWnd
)
356 Child
= IntGetWindowObject(*phWnd
);
361 if (Child
->Style
& WS_VISIBLE
)
364 * Recursive call to update children UpdateRegion
366 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
367 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
368 NtGdiOffsetRgn(hRgnTemp
,
369 Window
->WindowRect
.left
- Child
->WindowRect
.left
,
370 Window
->WindowRect
.top
- Child
->WindowRect
.top
);
371 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
372 NtGdiDeleteObject(hRgnTemp
);
374 IntReleaseWindowObject(Child
);
381 * Fake post paint messages to window message queue if needed
384 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
385 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
386 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
388 if (HasPaintMessage
!= HadPaintMessage
)
391 MsqDecPaintCountQueue(Window
->MessageQueue
);
393 MsqIncPaintCountQueue(Window
->MessageQueue
);
396 if (HasNCPaintMessage
!= HadNCPaintMessage
)
398 if (HadNCPaintMessage
)
399 MsqDecPaintCountQueue(Window
->MessageQueue
);
401 MsqIncPaintCountQueue(Window
->MessageQueue
);
404 IntUnLockWindowUpdate(Window
);
408 * IntIsWindowDrawable
411 * Window is drawable when it is visible and all parents are not
416 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
418 PWINDOW_OBJECT Old
, Wnd
= Window
;
420 IntReferenceWindowObject(Wnd
);
423 if (!(Wnd
->Style
& WS_VISIBLE
) ||
424 ((Wnd
->Style
& WS_MINIMIZE
) && (Wnd
!= Window
)))
426 IntReleaseWindowObject(Wnd
);
430 Wnd
= IntGetParentObject(Wnd
);
431 IntReleaseWindowObject(Old
);
440 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
445 IntRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
452 * Validation of passed parameters.
455 if (!IntIsWindowDrawable(Window
) ||
456 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
457 (RDW_VALIDATE
| RDW_INVALIDATE
))
464 * Transform the parameters UpdateRgn and UpdateRect into
465 * a region hRgn specified in window coordinates.
468 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
470 if (UpdateRgn
!= NULL
)
472 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
473 NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
);
475 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
476 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
478 if (UpdateRect
!= NULL
)
480 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
482 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
483 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
485 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
486 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
488 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
490 -Window
->WindowRect
.left
,
491 -Window
->WindowRect
.top
);
495 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
497 -Window
->WindowRect
.left
,
498 -Window
->WindowRect
.top
);
504 * Adjust the window update region depending on hRgn and flags.
507 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
))
509 IntInvalidateWindows(Window
, hRgn
, Flags
);
514 * Repaint and erase windows if needed.
517 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
519 IntPaintWindows(Window
, Flags
);
529 NtGdiDeleteObject(hRgn
);
536 IntIsWindowDirty(PWINDOW_OBJECT Window
)
538 return (Window
->Style
& WS_VISIBLE
) &&
539 ((Window
->UpdateRegion
!= NULL
) ||
540 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
) ||
541 (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
));
545 IntFindWindowToRepaint(HWND hWnd
, PW32THREAD Thread
)
547 PWINDOW_OBJECT Window
;
548 PWINDOW_OBJECT Child
;
549 HWND hFoundWnd
= NULL
;
551 Window
= IntGetWindowObject(hWnd
);
555 if (IntIsWindowDirty(Window
) &&
556 IntWndBelongsToThread(Window
, Thread
))
558 IntReleaseWindowObject(Window
);
562 IntLockRelatives(Window
);
563 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
565 if (IntIsWindowDirty(Child
) &&
566 IntWndBelongsToThread(Child
, Thread
))
568 hFoundWnd
= Child
->Self
;
572 IntUnLockRelatives(Window
);
574 if (hFoundWnd
== NULL
)
579 List
= IntWinListChildren(Window
);
582 for (i
= 0; List
[i
]; i
++)
584 hFoundWnd
= IntFindWindowToRepaint(List
[i
], Thread
);
585 if (hFoundWnd
!= NULL
)
592 IntReleaseWindowObject(Window
);
598 IntGetPaintMessage(HWND hWnd
, UINT MsgFilterMin
, UINT MsgFilterMax
,
599 PW32THREAD Thread
, MSG
*Message
, BOOL Remove
)
601 PWINDOW_OBJECT Window
;
602 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
604 if (!MessageQueue
->PaintPosted
)
607 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
608 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
612 Message
->hwnd
= IntFindWindowToRepaint(hWnd
, PsGetWin32Thread());
614 Message
->hwnd
= IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
616 if (Message
->hwnd
== NULL
)
620 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
621 IntLockMessageQueue(MessageQueue
);
622 MessageQueue
->PaintPosted
= 0;
623 MessageQueue
->PaintCount
= 0;
624 IntUnLockMessageQueue(MessageQueue
);
629 Window
= IntGetWindowObject(Message
->hwnd
);
632 Message
->message
= WM_PAINT
;
633 Message
->wParam
= Message
->lParam
= 0;
634 IntReleaseWindowObject(Window
);
643 IntFixCaret(HWND hWnd
, LPRECT lprc
, UINT flags
)
645 PDESKTOP_OBJECT Desktop
;
646 PTHRDCARETINFO CaretInfo
;
649 Desktop
= PsGetCurrentThread()->Tcb
.Win32Thread
->Desktop
;
650 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
651 hWndCaret
= CaretInfo
->hWnd
;
652 if (hWndCaret
== hWnd
||
653 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(hWnd
, hWndCaret
)))
655 POINT pt
, FromOffset
, ToOffset
, Offset
;
658 pt
.x
= CaretInfo
->Pos
.x
;
659 pt
.y
= CaretInfo
->Pos
.y
;
660 IntGetClientOrigin(hWndCaret
, &FromOffset
);
661 IntGetClientOrigin(hWnd
, &ToOffset
);
662 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
663 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
666 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
667 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
668 if (IntGdiIntersectRect(lprc
, lprc
, &rcCaret
))
680 /* PUBLIC FUNCTIONS ***********************************************************/
690 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
692 PWINDOW_OBJECT Window
;
697 if (!(Window
= IntGetWindowObject(hWnd
)))
699 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
703 NtUserHideCaret(hWnd
);
705 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
709 if (Window
->NCUpdateRegion
!= (HANDLE
)1 &&
710 Window
->NCUpdateRegion
!= NULL
)
712 GDIOBJ_SetOwnership(Window
->NCUpdateRegion
, PsGetCurrentProcess());
714 hRgn
= Window
->NCUpdateRegion
;
715 IntValidateParent(Window
, Window
->NCUpdateRegion
);
716 Window
->NCUpdateRegion
= NULL
;
717 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
718 MsqDecPaintCountQueue(Window
->MessageQueue
);
719 IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
720 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
722 /* NOTE: The region can already by deleted! */
723 GDIOBJ_FreeObj(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
727 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
728 Ps
.hdc
= NtUserGetDCEx(hWnd
, 0, DCX_INTERSECTUPDATE
| DCX_WINDOWPAINT
|
733 IntReleaseWindowObject(Window
);
737 IntLockWindowUpdate(Window
);
738 if (Window
->UpdateRegion
!= NULL
)
740 MsqDecPaintCountQueue(Window
->MessageQueue
);
741 IntValidateParent(Window
, Window
->UpdateRegion
);
742 Rgn
= RGNDATA_LockRgn(Window
->UpdateRegion
);
745 UnsafeIntGetRgnBox(Rgn
, &Ps
.rcPaint
);
746 RGNDATA_UnlockRgn(Rgn
);
747 IntGdiOffsetRect(&Ps
.rcPaint
,
748 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
749 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
753 IntGetClientRect(Window
, &Ps
.rcPaint
);
755 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
756 NtGdiDeleteObject(Window
->UpdateRegion
);
757 Window
->UpdateRegion
= NULL
;
761 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
762 MsqDecPaintCountQueue(Window
->MessageQueue
);
763 IntGetClientRect(Window
, &Ps
.rcPaint
);
765 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
766 IntUnLockWindowUpdate(Window
);
768 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
770 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
771 Ps
.fErase
= !IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
778 IntReleaseWindowObject(Window
);
780 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
781 if (! NT_SUCCESS(Status
))
783 SetLastNtError(Status
);
798 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
800 NtUserReleaseDC(hWnd
, lPs
->hdc
);
801 NtUserShowCaret(hWnd
);
807 * NtUserInvalidateRect
814 NtUserInvalidateRect(HWND hWnd
, CONST RECT
*Rect
, BOOL Erase
)
816 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
820 * NtUserInvalidateRgn
827 NtUserInvalidateRgn(HWND hWnd
, HRGN Rgn
, BOOL Erase
)
829 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
840 NtUserValidateRgn(HWND hWnd
, HRGN hRgn
)
842 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
853 NtUserUpdateWindow(HWND hWnd
)
855 return NtUserRedrawWindow(hWnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
866 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
868 PWINDOW_OBJECT Window
;
871 if (!(Window
= IntGetWindowObject(hWnd
)))
873 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
877 IntLockWindowUpdate(Window
);
878 if (Window
->UpdateRegion
== NULL
)
880 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
884 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
887 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
888 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
890 IntUnLockWindowUpdate(Window
);
892 IntReleaseWindowObject(Window
);
894 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
896 NtUserRedrawWindow(hWnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
903 * NtUserGetUpdateRect
910 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
912 PWINDOW_OBJECT Window
;
919 if (!(Window
= IntGetWindowObject(hWnd
)))
921 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
925 IntLockWindowUpdate(Window
);
926 if (Window
->UpdateRegion
== NULL
)
928 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
932 RgnData
= RGNDATA_LockRgn(Window
->UpdateRegion
);
933 ASSERT(RgnData
!= NULL
);
934 RegionType
= UnsafeIntGetRgnBox(RgnData
, &Rect
);
935 ASSERT(RegionType
!= ERROR
);
936 RGNDATA_UnlockRgn(RgnData
);
938 AlwaysPaint
= (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
) ||
939 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
);
940 IntUnLockWindowUpdate(Window
);
942 IntReleaseWindowObject(Window
);
944 if (bErase
&& Rect
.left
< Rect
.right
&& Rect
.top
< Rect
.bottom
)
946 NtUserRedrawWindow(hWnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
949 if (UnsafeRect
!= NULL
)
951 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECT
));
952 if (!NT_SUCCESS(Status
))
954 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
959 return (Rect
.left
< Rect
.right
&& Rect
.top
< Rect
.bottom
) || AlwaysPaint
;
970 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
977 if (!(Wnd
= IntGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
979 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
983 if (lprcUpdate
!= NULL
)
985 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
988 if (!NT_SUCCESS(Status
))
990 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
991 IntReleaseWindowObject(Wnd
);
996 Status
= IntRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
999 if (!NT_SUCCESS(Status
))
1001 /* IntRedrawWindow fails only in case that flags are invalid */
1002 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1003 IntReleaseWindowObject(Wnd
);
1007 IntReleaseWindowObject(Wnd
);
1019 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1020 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1022 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
1026 * Compute device clipping region (in device coordinates).
1029 DC
= DC_LockDc(hDC
);
1037 IntGdiGetClipBox(hDC
, &rSrc
);
1038 IntLPtoDP(DC
, (LPPOINT
)&rSrc
, 2);
1043 IntGdiGetClipBox(hDC
, &rClip
);
1044 IntLPtoDP(DC
, (LPPOINT
)&rClip
, 2);
1046 IntGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
1048 rDst
= rClipped_src
;
1049 IntGdiSetRect(&offset
, 0, 0, dx
, dy
);
1050 IntLPtoDP(DC
, (LPPOINT
)&offset
, 2);
1051 IntGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1052 IntGdiIntersectRect(&rDst
, &rDst
, &rClip
);
1055 * Copy bits, if possible.
1058 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1060 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1062 IntGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1063 IntDPtoLP(DC
, (LPPOINT
)&rDst_lp
, 2);
1064 IntDPtoLP(DC
, (LPPOINT
)&rSrc_lp
, 2);
1067 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1068 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1078 * Compute update areas. This is the clipped source or'ed with the
1079 * unclipped source translated minus the clipped src translated (rDst)
1080 * all clipped to rClip.
1083 if (hrgnUpdate
|| lprcUpdate
)
1085 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1088 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1090 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1092 hRgn2
= UnsafeIntCreateRectRgnIndirect(&rSrc
);
1093 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1094 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1096 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1097 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1099 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1100 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1104 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1106 /* Put the lprcUpdate in logical coordinate */
1107 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1110 NtGdiDeleteObject(hRgn
);
1111 NtGdiDeleteObject(hRgn2
);
1117 * NtUserScrollWindowEx
1124 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*UnsafeRect
,
1125 const RECT
*UnsafeClipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1127 RECT rc
, cliprc
, caretrc
, rect
, clipRect
;
1129 PWINDOW_OBJECT Window
;
1133 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1134 BOOL bOwnRgn
= TRUE
;
1137 Window
= IntGetWindowObject(hWnd
);
1138 if (!Window
|| !IntIsWindowDrawable(Window
))
1140 IntReleaseWindowObject(Window
);
1144 IntGetClientRect(Window
, &rc
);
1145 if (NULL
!= UnsafeRect
)
1147 Status
= MmCopyFromCaller(&rect
, UnsafeRect
, sizeof(RECT
));
1148 if (! NT_SUCCESS(Status
))
1150 SetLastNtError(Status
);
1153 IntGdiIntersectRect(&rc
, &rc
, &rect
);
1156 if (NULL
!= UnsafeClipRect
)
1158 Status
= MmCopyFromCaller(&clipRect
, UnsafeClipRect
, sizeof(RECT
));
1159 if (! NT_SUCCESS(Status
))
1161 SetLastNtError(Status
);
1164 IntGdiIntersectRect(&cliprc
, &rc
, &clipRect
);
1169 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1170 (dx
== 0 && dy
== 0))
1176 hwndCaret
= IntFixCaret(hWnd
, &caretrc
, flags
);
1181 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1183 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
);
1186 NtUserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1187 NtUserReleaseDC(hWnd
, hDC
);
1191 * Take into account the fact that some damage may have occurred during
1195 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1196 Result
= NtUserGetUpdateRgn(hWnd
, hrgnTemp
, FALSE
);
1197 if (Result
!= NULLREGION
)
1199 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&cliprc
);
1200 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1201 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1202 NtUserRedrawWindow(hWnd
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1203 NtGdiDeleteObject(hrgnClip
);
1205 NtGdiDeleteObject(hrgnTemp
);
1207 if (flags
& SW_SCROLLCHILDREN
)
1209 HWND
*List
= IntWinListChildren(Window
);
1215 PWINDOW_OBJECT WindowObject
;
1217 IntGetClientOrigin(hWnd
, &ClientOrigin
);
1218 for (i
= 0; List
[i
]; i
++)
1220 WindowObject
= IntGetWindowObject(List
[i
]);
1221 if (!WindowObject
) continue;
1222 r
= WindowObject
->WindowRect
;
1223 r
.left
-= ClientOrigin
.x
;
1224 r
.top
-= ClientOrigin
.y
;
1225 r
.right
-= ClientOrigin
.x
;
1226 r
.bottom
-= ClientOrigin
.y
;
1227 IntReleaseWindowObject(WindowObject
);
1228 if (! UnsafeRect
|| IntGdiIntersectRect(&dummy
, &r
, &rc
))
1229 WinPosSetWindowPos(List
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1230 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1237 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1238 NtUserRedrawWindow(hWnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1239 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1240 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1242 if (bOwnRgn
&& hrgnUpdate
)
1243 NtGdiDeleteObject(hrgnUpdate
);
1247 IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1248 NtUserShowCaret(hwndCaret
);
1251 IntReleaseWindowObject(Window
);