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.
19 * $Id: painting.c,v 1.67 2004/02/04 23:01:07 gvg Exp $
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 ******************************************************************/
33 #include <ddk/ntddk.h>
34 #include <internal/safe.h>
35 #include <win32k/win32k.h>
36 #include <include/object.h>
37 #include <include/guicheck.h>
38 #include <include/window.h>
39 #include <include/desktop.h>
40 #include <include/winpos.h>
41 #include <include/class.h>
42 #include <include/caret.h>
43 #include <include/error.h>
44 #include <include/winsta.h>
46 #include <include/painting.h>
47 #include <user32/wininternal.h>
48 #include <include/rect.h>
49 #include <win32k/coord.h>
50 #include <win32k/region.h>
51 #include <include/vis.h>
52 #include <include/intgdi.h>
55 #include <win32k/debug1.h>
57 /* PRIVATE FUNCTIONS **********************************************************/
60 IntValidateParent(PWINDOW_OBJECT Child
, HRGN ValidRegion
)
63 PWINDOW_OBJECT ParentWindow
;
65 Parent
= NtUserGetAncestor(Child
->Self
, GA_PARENT
);
68 ParentWindow
= IntGetWindowObject(Parent
);
69 if (ParentWindow
&& !(ParentWindow
->Style
& WS_CLIPCHILDREN
))
71 ExAcquireFastMutex(&ParentWindow
->UpdateLock
);
72 if (ParentWindow
->UpdateRegion
!= 0)
77 * We must offset the child region by the offset of the
78 * child rect in the parent.
80 OffsetX
= Child
->WindowRect
.left
- ParentWindow
->WindowRect
.left
;
81 OffsetY
= Child
->WindowRect
.top
- ParentWindow
->WindowRect
.top
;
82 NtGdiOffsetRgn(ValidRegion
, OffsetX
, OffsetY
);
83 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
84 ValidRegion
, RGN_DIFF
);
85 /* FIXME: If the resulting region is empty, remove fake posted paint message */
86 NtGdiOffsetRgn(ValidRegion
, -OffsetX
, -OffsetY
);
88 ExReleaseFastMutex(&ParentWindow
->UpdateLock
);
90 IntReleaseWindowObject(ParentWindow
);
91 Parent
= NtUserGetAncestor(Parent
, GA_PARENT
);
96 * IntGetNCUpdateRegion
98 * Get nonclient part of window update region.
101 * Handle to region that represents invalid nonclient window area. The
102 * caller is responsible for deleting it.
105 * This function also marks the nonclient update region of window
106 * as valid, clears the WINDOWOBJECT_NEED_NCPAINT flag.
110 IntGetNCUpdateRegion(PWINDOW_OBJECT Window
)
115 ASSERT(! ExTryToAcquireFastMutex(&Window
->UpdateLock
));
118 * Generate the update region.
121 WindowRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
122 NtGdiOffsetRgn(WindowRgn
,
123 -Window
->WindowRect
.left
,
124 -Window
->WindowRect
.top
);
125 NonclientRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
126 if (NtGdiCombineRgn(NonclientRgn
, Window
->UpdateRegion
,
127 WindowRgn
, RGN_DIFF
) == NULLREGION
)
129 NtGdiDeleteObject(NonclientRgn
);
134 * Remove the nonclient region from the standard update region.
137 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
138 WindowRgn
, RGN_AND
) == NULLREGION
)
140 NtGdiDeleteObject(Window
->UpdateRegion
);
141 Window
->UpdateRegion
= NULL
;
144 NtGdiDeleteObject(WindowRgn
);
152 * Internal function used by IntRedrawWindow.
156 IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
159 HWND hWnd
= Window
->Self
;
161 if (! (Window
->Style
& WS_VISIBLE
))
166 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
168 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
170 ExAcquireFastMutex(&Window
->UpdateLock
);
171 if (Window
->NCUpdateRegion
)
173 IntValidateParent(Window
, Window
->NCUpdateRegion
);
175 IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)Window
->NCUpdateRegion
, 0);
176 Window
->NCUpdateRegion
= NULL
;
177 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
178 MsqDecPaintCountQueue(Window
->MessageQueue
);
179 ExReleaseFastMutex(&Window
->UpdateLock
);
182 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
184 if (Window
->UpdateRegion
)
186 IntValidateParent(Window
, Window
->UpdateRegion
);
187 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
|
188 DCX_INTERSECTUPDATE
);
191 if (IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
193 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
195 NtUserReleaseDC(hWnd
, hDC
);
200 if (Flags
& RDW_UPDATENOW
)
202 if (Window
->UpdateRegion
!= NULL
||
203 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
205 IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
206 ExAcquireFastMutex(&Window
->UpdateLock
);
207 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
209 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
210 if (Window
->UpdateRegion
== NULL
)
212 MsqDecPaintCountQueue(Window
->MessageQueue
);
215 ExReleaseFastMutex(&Window
->UpdateLock
);
221 * Check that the window is still valid at this point
224 if (! IntIsWindow(hWnd
))
230 * Paint child windows.
232 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
233 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
237 if ((List
= IntWinListChildren(Window
)))
239 for (phWnd
= List
; *phWnd
; ++phWnd
)
241 Window
= IntGetWindowObject(*phWnd
);
244 IntPaintWindows(Window
, Flags
);
245 IntReleaseWindowObject(Window
);
254 * IntInvalidateWindows
256 * Internal function used by IntRedrawWindow.
260 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
263 BOOL HadPaintMessage
, HadNCPaintMessage
;
264 BOOL HasPaintMessage
, HasNCPaintMessage
;
268 * Clip the given region with window rectangle (or region)
272 if (!Window
->WindowRegion
)
275 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
276 NtGdiOffsetRgn(hRgnWindow
,
277 -Window
->WindowRect
.left
,
278 -Window
->WindowRect
.top
);
279 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
280 NtGdiDeleteObject(hRgnWindow
);
285 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
290 * Save current state of pending updates
293 ExAcquireFastMutex(&Window
->UpdateLock
);
294 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
295 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
296 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
299 * Update the region and flags
302 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
304 if (Window
->UpdateRegion
== NULL
)
306 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
309 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
310 hRgn
, RGN_OR
) == NULLREGION
)
312 NtGdiDeleteObject(Window
->UpdateRegion
);
313 Window
->UpdateRegion
= NULL
;
316 if (Flags
& RDW_FRAME
)
317 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
318 if (Flags
& RDW_ERASE
)
319 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
324 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
326 if (Window
->UpdateRegion
!= NULL
)
328 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
329 hRgn
, RGN_DIFF
) == NULLREGION
)
331 NtGdiDeleteObject(Window
->UpdateRegion
);
332 Window
->UpdateRegion
= NULL
;
336 if (Window
->UpdateRegion
== NULL
)
337 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
338 if (Flags
& RDW_NOFRAME
)
339 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
340 if (Flags
& RDW_NOERASE
)
341 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
344 if (Flags
& RDW_INTERNALPAINT
)
346 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
349 if (Flags
& RDW_NOINTERNALPAINT
)
351 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
355 * Split the nonclient update region.
358 if (Window
->NCUpdateRegion
== NULL
)
360 Window
->NCUpdateRegion
= IntGetNCUpdateRegion(Window
);
364 HRGN hRgnNonClient
= IntGetNCUpdateRegion(Window
);
365 NtGdiCombineRgn(Window
->NCUpdateRegion
, Window
->NCUpdateRegion
,
366 hRgnNonClient
, RGN_OR
);
367 NtGdiDeleteObject(hRgnNonClient
);
371 * Process children if needed
374 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
375 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
378 PWINDOW_OBJECT Child
;
380 if ((List
= IntWinListChildren(Window
)))
382 for (phWnd
= List
; *phWnd
; ++phWnd
)
384 Child
= IntGetWindowObject(*phWnd
);
389 if (Child
->Style
& WS_VISIBLE
)
392 * Recursive call to update children UpdateRegion
394 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
395 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
396 NtGdiOffsetRgn(hRgnTemp
,
397 Window
->WindowRect
.left
- Child
->WindowRect
.left
,
398 Window
->WindowRect
.top
- Child
->WindowRect
.top
);
399 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
400 NtGdiDeleteObject(hRgnTemp
);
402 IntReleaseWindowObject(Child
);
409 * Fake post paint messages to window message queue if needed
411 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
412 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
413 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
415 if (HasPaintMessage
!= HadPaintMessage
)
418 MsqDecPaintCountQueue(Window
->MessageQueue
);
420 MsqIncPaintCountQueue(Window
->MessageQueue
);
423 if (HasNCPaintMessage
!= HadNCPaintMessage
)
425 if (HadNCPaintMessage
)
426 MsqDecPaintCountQueue(Window
->MessageQueue
);
428 MsqIncPaintCountQueue(Window
->MessageQueue
);
431 ExReleaseFastMutex(&Window
->UpdateLock
);
435 * IntIsWindowDrawable
438 * Window is drawable when it is visible and all parents are not
443 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
445 PWINDOW_OBJECT Wnd
= Window
;
447 for (; Wnd
; Wnd
= Wnd
->Parent
)
449 if (!(Wnd
->Style
& WS_VISIBLE
) ||
450 ((Wnd
->Style
& WS_MINIMIZE
) && (Wnd
!= Window
)))
460 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
465 IntRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
472 * Validation of passed parameters.
475 if (!IntIsWindowDrawable(Window
) ||
476 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
477 (RDW_VALIDATE
| RDW_INVALIDATE
))
484 * Transform the parameters UpdateRgn and UpdateRect into
485 * a region hRgn specified in window coordinates.
488 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
490 if (UpdateRgn
!= NULL
)
492 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
493 NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
);
495 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
496 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
498 if (UpdateRect
!= NULL
)
500 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
502 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
503 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
505 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
506 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
508 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
510 -Window
->WindowRect
.left
,
511 -Window
->WindowRect
.top
);
515 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
517 -Window
->WindowRect
.left
,
518 -Window
->WindowRect
.top
);
524 * Adjust the window update region depending on hRgn and flags.
527 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
))
529 IntInvalidateWindows(Window
, hRgn
, Flags
);
534 * Repaint and erase windows if needed.
537 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
539 IntPaintWindows(Window
, Flags
);
549 NtGdiDeleteObject(hRgn
);
556 IntFindWindowToRepaint(HWND hWnd
, PW32THREAD Thread
)
558 PWINDOW_OBJECT Window
;
559 PWINDOW_OBJECT Child
;
560 HWND hFoundWnd
= NULL
;
562 Window
= IntGetWindowObject(hWnd
);
566 if ((Window
->UpdateRegion
!= NULL
||
567 Window
->Flags
& (WINDOWOBJECT_NEED_INTERNALPAINT
| WINDOWOBJECT_NEED_NCPAINT
)) &&
568 IntWndBelongsToThread(Window
, Thread
))
570 IntReleaseWindowObject(Window
);
574 ExAcquireFastMutex(&Window
->ChildrenListLock
);
576 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
578 if (Child
->Style
& WS_VISIBLE
&&
579 (Child
->UpdateRegion
!= NULL
||
580 Child
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
||
581 Child
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
582 && IntWndBelongsToThread(Child
, Thread
))
584 hFoundWnd
= Child
->Self
;
589 if (hFoundWnd
== NULL
)
591 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
593 if (Child
->Style
& WS_VISIBLE
)
595 hFoundWnd
= IntFindWindowToRepaint(Child
->Self
, Thread
);
596 if (hFoundWnd
!= NULL
)
602 ExReleaseFastMutex(&Window
->ChildrenListLock
);
603 IntReleaseWindowObject(Window
);
609 IntGetPaintMessage(HWND hWnd
, PW32THREAD Thread
, MSG
*Message
,
612 PWINDOW_OBJECT Window
;
613 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
615 if (!MessageQueue
->PaintPosted
)
619 Message
->hwnd
= IntFindWindowToRepaint(hWnd
, PsGetWin32Thread());
621 Message
->hwnd
= IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
623 if (Message
->hwnd
== NULL
)
626 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
628 ExAcquireFastMutex(&MessageQueue
->Lock
);
629 MessageQueue
->PaintPosted
= 0;
630 MessageQueue
->PaintCount
= 0;
631 ExReleaseFastMutex(&MessageQueue
->Lock
);
635 Window
= IntGetWindowObject(Message
->hwnd
);
638 ExAcquireFastMutex(&Window
->UpdateLock
);
639 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
641 Message
->message
= WM_NCPAINT
;
642 Message
->wParam
= (WPARAM
)Window
->NCUpdateRegion
;
646 Window
->NCUpdateRegion
= NULL
;
647 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
648 MsqDecPaintCountQueue(Window
->MessageQueue
);
652 Message
->message
= WM_PAINT
;
653 Message
->wParam
= Message
->lParam
= 0;
654 if (Remove
&& Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
656 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
657 if (Window
->UpdateRegion
== NULL
)
659 MsqDecPaintCountQueue(Window
->MessageQueue
);
663 ExReleaseFastMutex(&Window
->UpdateLock
);
665 IntReleaseWindowObject(Window
);
673 IntFixCaret(HWND hWnd
, LPRECT lprc
, UINT flags
)
675 PDESKTOP_OBJECT Desktop
;
676 PTHRDCARETINFO CaretInfo
;
679 Desktop
= PsGetCurrentThread()->Win32Thread
->Desktop
;
680 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
681 hWndCaret
= CaretInfo
->hWnd
;
682 if (hWndCaret
== hWnd
||
683 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(hWnd
, hWndCaret
)))
685 POINT pt
, FromOffset
, ToOffset
, Offset
;
688 pt
.x
= CaretInfo
->Pos
.x
;
689 pt
.y
= CaretInfo
->Pos
.y
;
690 IntGetClientOrigin(hWndCaret
, &FromOffset
);
691 IntGetClientOrigin(hWnd
, &ToOffset
);
692 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
693 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
696 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
697 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
698 if (NtGdiIntersectRect(lprc
, lprc
, &rcCaret
))
710 /* PUBLIC FUNCTIONS ***********************************************************/
720 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* lPs
)
722 PWINDOW_OBJECT Window
;
724 if (!(Window
= IntGetWindowObject(hWnd
)))
726 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
730 NtUserHideCaret(hWnd
);
732 lPs
->hdc
= NtUserGetDCEx(hWnd
, 0, DCX_INTERSECTUPDATE
| DCX_WINDOWPAINT
|
737 IntReleaseWindowObject(Window
);
741 ExAcquireFastMutex(&Window
->UpdateLock
);
742 if (Window
->UpdateRegion
!= NULL
)
744 MsqDecPaintCountQueue(Window
->MessageQueue
);
745 IntValidateParent(Window
, Window
->UpdateRegion
);
746 NtGdiGetRgnBox(Window
->UpdateRegion
, &lPs
->rcPaint
);
747 NtGdiOffsetRect(&lPs
->rcPaint
,
748 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
749 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
750 NtGdiDeleteObject(Window
->UpdateRegion
);
751 Window
->UpdateRegion
= NULL
;
755 NtUserGetClientRect(Window
, &lPs
->rcPaint
);
757 ExReleaseFastMutex(&Window
->UpdateLock
);
759 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
761 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
762 lPs
->fErase
= !IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)lPs
->hdc
, 0);
769 IntReleaseWindowObject(Window
);
782 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
784 NtUserReleaseDC(hWnd
, lPs
->hdc
);
785 NtUserShowCaret(hWnd
);
791 * NtUserInvalidateRect
798 NtUserInvalidateRect(HWND hWnd
, CONST RECT
*Rect
, BOOL Erase
)
800 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
804 * NtUserInvalidateRgn
811 NtUserInvalidateRgn(HWND hWnd
, HRGN Rgn
, BOOL Erase
)
813 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
824 NtUserValidateRgn(HWND hWnd
, HRGN hRgn
)
826 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
837 NtUserUpdateWindow(HWND hWnd
)
839 return NtUserRedrawWindow(hWnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
850 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
852 PWINDOW_OBJECT Window
;
855 if (!(Window
= IntGetWindowObject(hWnd
)))
857 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
861 if (Window
->UpdateRegion
== NULL
)
863 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
867 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
870 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
871 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
874 IntReleaseWindowObject(Window
);
876 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
878 NtUserRedrawWindow(hWnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
885 * NtUserGetUpdateRect
892 NtUserGetUpdateRect(HWND hWnd
, LPRECT lpRect
, BOOL fErase
)
894 HRGN hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
898 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
902 NtUserGetUpdateRgn(hWnd
, hRgn
, fErase
);
903 NtGdiGetRgnBox(hRgn
, lpRect
);
904 NtGdiDeleteObject(hRgn
);
906 return lpRect
->left
< lpRect
->right
&& lpRect
->top
< lpRect
->bottom
;
917 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
924 if (!(Wnd
= IntGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
926 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
930 if (lprcUpdate
!= NULL
)
932 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
935 if (!NT_SUCCESS(Status
))
937 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
942 Status
= IntRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
945 if (!NT_SUCCESS(Status
))
947 /* IntRedrawWindow fails only in case that flags are invalid */
948 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
963 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
964 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
966 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
970 * Compute device clipping region (in device coordinates).
981 IntGdiGetClipBox(hDC
, &rSrc
);
982 IntLPtoDP(DC
, (LPPOINT
)&rSrc
, 2);
987 IntGdiGetClipBox(hDC
, &rClip
);
988 IntLPtoDP(DC
, (LPPOINT
)&rClip
, 2);
990 NtGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
993 NtGdiSetRect(&offset
, 0, 0, dx
, dy
);
994 IntLPtoDP(DC
, (LPPOINT
)&offset
, 2);
995 NtGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
996 NtGdiIntersectRect(&rDst
, &rDst
, &rClip
);
999 * Copy bits, if possible.
1002 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1004 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1006 NtGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1007 IntDPtoLP(DC
, (LPPOINT
)&rDst_lp
, 2);
1008 IntDPtoLP(DC
, (LPPOINT
)&rSrc_lp
, 2);
1011 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1012 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1022 * Compute update areas. This is the clipped source or'ed with the
1023 * unclipped source translated minus the clipped src translated (rDst)
1024 * all clipped to rClip.
1027 if (hrgnUpdate
|| lprcUpdate
)
1029 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1032 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1034 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1036 hRgn2
= UnsafeIntCreateRectRgnIndirect(&rSrc
);
1037 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1038 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1040 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1041 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1043 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1044 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1048 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1050 /* Put the lprcUpdate in logical coordinate */
1051 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1054 NtGdiDeleteObject(hRgn
);
1055 NtGdiDeleteObject(hRgn2
);
1061 * NtUserScrollWindowEx
1068 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*rect
,
1069 const RECT
*clipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1071 RECT rc
, cliprc
, caretrc
;
1073 PWINDOW_OBJECT Window
;
1077 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1078 BOOL bOwnRgn
= TRUE
;
1080 Window
= IntGetWindowObject(hWnd
);
1081 if (!Window
|| !IntIsWindowDrawable(Window
))
1083 IntReleaseWindowObject(Window
);
1087 IntGetClientRect(Window
, &rc
);
1089 NtGdiIntersectRect(&rc
, &rc
, rect
);
1092 NtGdiIntersectRect(&cliprc
, &rc
, clipRect
);
1096 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1097 (dx
== 0 && dy
== 0))
1103 hwndCaret
= IntFixCaret(hWnd
, &caretrc
, flags
);
1108 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1110 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
);
1113 NtUserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1114 NtUserReleaseDC(hWnd
, hDC
);
1118 * Take into account the fact that some damage may have occurred during
1122 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1123 Result
= NtUserGetUpdateRgn(hWnd
, hrgnTemp
, FALSE
);
1124 if (Result
!= NULLREGION
)
1126 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&cliprc
);
1127 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1128 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1129 NtUserRedrawWindow(hWnd
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1130 NtGdiDeleteObject(hrgnClip
);
1132 NtGdiDeleteObject(hrgnTemp
);
1134 if (flags
& SW_SCROLLCHILDREN
)
1136 HWND
*List
= IntWinListChildren(Window
);
1143 for (i
= 0; List
[i
]; i
++)
1145 NtUserGetWindowRect(List
[i
], &r
);
1146 IntGetClientOrigin(hWnd
, &ClientOrigin
);
1147 r
.left
-= ClientOrigin
.x
;
1148 r
.top
-= ClientOrigin
.y
;
1149 r
.right
-= ClientOrigin
.x
;
1150 r
.bottom
-= ClientOrigin
.y
;
1151 if (!rect
|| NtGdiIntersectRect(&dummy
, &r
, &rc
))
1152 WinPosSetWindowPos(List
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1153 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1160 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1161 NtUserRedrawWindow(hWnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1162 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1163 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1165 if (bOwnRgn
&& hrgnUpdate
)
1166 NtGdiDeleteObject(hrgnUpdate
);
1170 IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1171 NtUserShowCaret(hwndCaret
);
1174 IntReleaseWindowObject(Window
);