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.45 2003/12/12 18:18:21 weiden 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>
56 /* PRIVATE FUNCTIONS **********************************************************/
59 IntValidateParent(PWINDOW_OBJECT Child
)
62 PWINDOW_OBJECT ParentWindow
;
64 Parent
= NtUserGetAncestor(Child
->Self
, GA_PARENT
);
65 while (Parent
&& Parent
!= IntGetDesktopWindow())
67 ParentWindow
= IntGetWindowObject(Parent
);
68 if (ParentWindow
&& !(ParentWindow
->Style
& WS_CLIPCHILDREN
))
70 if (ParentWindow
->UpdateRegion
!= 0)
75 * We must offset the child region by the offset of the
76 * child rect in the parent.
78 OffsetX
= Child
->WindowRect
.left
- ParentWindow
->WindowRect
.left
;
79 OffsetY
= Child
->WindowRect
.top
- ParentWindow
->WindowRect
.top
;
80 NtGdiOffsetRgn(Child
->UpdateRegion
, OffsetX
, OffsetY
);
81 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
82 Child
->UpdateRegion
, RGN_DIFF
);
83 /* FIXME: If the resulting region is empty, remove fake posted paint message */
84 NtGdiOffsetRgn(Child
->UpdateRegion
, -OffsetX
, -OffsetY
);
87 IntReleaseWindowObject(ParentWindow
);
88 Parent
= NtUserGetAncestor(Parent
, GA_PARENT
);
93 * IntGetNCUpdateRegion
95 * Get nonclient part of window update region.
98 * Handle to region that represents invalid nonclient window area. The
99 * caller is responsible for deleting it.
102 * This function also marks the nonclient update region of window
103 * as valid, clears the WINDOWOBJECT_NEED_NCPAINT flag and removes
104 * the fake paint message from message queue if the Remove is set
109 IntGetNCUpdateRegion(PWINDOW_OBJECT Window
, BOOL Remove
)
114 WindowRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
115 NtGdiOffsetRgn(WindowRgn
,
116 -Window
->WindowRect
.left
,
117 -Window
->WindowRect
.top
);
118 NonclientRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
119 if (NtGdiCombineRgn(NonclientRgn
, Window
->UpdateRegion
,
120 WindowRgn
, RGN_DIFF
) == NULLREGION
)
122 NtGdiDeleteObject(NonclientRgn
);
127 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
128 WindowRgn
, RGN_AND
) == NULLREGION
)
130 NtGdiDeleteObject(Window
->UpdateRegion
);
131 Window
->UpdateRegion
= NULL
;
133 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
134 MsqDecPaintCountQueue(Window
->MessageQueue
);
143 * Internal function used by IntRedrawWindow.
147 IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
150 HWND hWnd
= Window
->Self
;
152 if (! (Window
->Style
& WS_VISIBLE
))
157 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
159 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
161 NtUserSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)IntGetNCUpdateRegion(Window
, TRUE
), 0);
164 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
166 if (Window
->UpdateRegion
)
168 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
|
169 DCX_INTERSECTUPDATE
);
172 if (NtUserSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
174 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
176 NtUserReleaseDC(hWnd
, hDC
);
181 if (Flags
& RDW_UPDATENOW
)
183 if (Window
->UpdateRegion
!= NULL
||
184 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
186 NtUserSendMessage(hWnd
, WM_PAINT
, 0, 0);
187 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
189 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
190 if (Window
->UpdateRegion
== NULL
)
192 MsqDecPaintCountQueue(Window
->MessageQueue
);
200 * Check that the window is still valid at this point
203 if (! IntIsWindow(hWnd
))
209 * Paint child windows.
211 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
212 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)) &&
213 ! IntIsDesktopWindow(Window
))
217 if ((List
= IntWinListChildren(Window
)))
219 for (phWnd
= List
; *phWnd
; ++phWnd
)
221 Window
= IntGetWindowObject(*phWnd
);
224 IntPaintWindows(Window
, Flags
);
225 IntReleaseWindowObject(Window
);
234 * IntInvalidateWindows
236 * Internal function used by IntRedrawWindow.
240 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
,
244 BOOL HadPaintMessage
, HadNCPaintMessage
;
245 BOOL HasPaintMessage
, HasNCPaintMessage
;
249 * Clip the given region with window rectangle (or region)
253 if (!Window
->WindowRegion
)
256 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
257 NtGdiOffsetRgn(hRgnWindow
,
258 -Window
->WindowRect
.left
,
259 -Window
->WindowRect
.top
);
260 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
261 NtGdiDeleteObject(hRgnWindow
);
266 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
271 * Save current state of pending updates
274 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
275 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
276 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
279 * Update the region and flags
282 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
284 if (Window
->UpdateRegion
== NULL
)
286 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
289 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
290 hRgn
, RGN_OR
) == NULLREGION
)
292 NtGdiDeleteObject(Window
->UpdateRegion
);
293 Window
->UpdateRegion
= NULL
;
296 if (Flags
& RDW_FRAME
)
297 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
298 if (Flags
& RDW_ERASE
)
299 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
304 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
306 if (Window
->UpdateRegion
!= NULL
)
308 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
309 hRgn
, RGN_DIFF
) == NULLREGION
)
311 NtGdiDeleteObject(Window
->UpdateRegion
);
312 Window
->UpdateRegion
= NULL
;
316 if (Window
->UpdateRegion
== NULL
)
317 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
318 if (Flags
& RDW_NOFRAME
)
319 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
320 if (Flags
& RDW_NOERASE
)
321 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
324 if (Flags
& RDW_INTERNALPAINT
)
326 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
329 if (Flags
& RDW_NOINTERNALPAINT
)
331 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
335 * Validate parent covered by region
340 IntValidateParent(Window
);
344 * Process children if needed
347 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
348 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
351 PWINDOW_OBJECT Child
;
353 if ((List
= IntWinListChildren(Window
)))
355 for (phWnd
= List
; *phWnd
; ++phWnd
)
357 Child
= IntGetWindowObject(*phWnd
);
358 if ((Child
->Style
& (WS_VISIBLE
| WS_MINIMIZE
)) == WS_VISIBLE
)
361 * Recursive call to update children UpdateRegion
363 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
364 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
365 NtGdiOffsetRgn(hRgnTemp
,
366 Window
->WindowRect
.left
- Child
->WindowRect
.left
,
367 Window
->WindowRect
.top
- Child
->WindowRect
.top
);
368 IntInvalidateWindows(Child
, hRgnTemp
, Flags
, FALSE
);
371 * Update our UpdateRegion depending on children
373 NtGdiCombineRgn(hRgnTemp
, Child
->UpdateRegion
, 0, RGN_COPY
);
374 NtGdiOffsetRgn(hRgnTemp
,
375 Child
->WindowRect
.left
- Window
->WindowRect
.left
,
376 Child
->WindowRect
.top
- Window
->WindowRect
.top
);
377 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
378 NtGdiOffsetRgn(hRgnWindow
,
379 -Window
->WindowRect
.left
,
380 -Window
->WindowRect
.top
);
381 NtGdiCombineRgn(hRgnTemp
, hRgnTemp
, hRgnWindow
, RGN_AND
);
382 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
383 hRgnTemp
, RGN_DIFF
) == NULLREGION
)
385 NtGdiDeleteObject(Window
->UpdateRegion
);
386 Window
->UpdateRegion
= NULL
;
388 NtGdiDeleteObject(hRgnTemp
);
390 IntReleaseWindowObject(Child
);
397 * Fake post paint messages to window message queue if needed
399 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
400 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
401 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
403 if (HasPaintMessage
!= HadPaintMessage
)
406 MsqDecPaintCountQueue(Window
->MessageQueue
);
408 MsqIncPaintCountQueue(Window
->MessageQueue
);
411 if (HasNCPaintMessage
!= HadNCPaintMessage
)
413 if (HadNCPaintMessage
)
414 MsqDecPaintCountQueue(Window
->MessageQueue
);
416 MsqIncPaintCountQueue(Window
->MessageQueue
);
421 * IntIsWindowDrawable
424 * Window is drawable when it is visible, all parents are not
425 * minimized, and it is itself not minimized.
429 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
431 for (; Window
; Window
= Window
->Parent
)
433 if ((Window
->Style
& (WS_VISIBLE
| WS_MINIMIZE
)) != WS_VISIBLE
)
443 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
448 IntRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
455 * Validation of passed parameters.
458 if (!IntIsWindowDrawable(Window
) ||
459 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
460 (RDW_VALIDATE
| RDW_INVALIDATE
))
467 * Transform the parameters UpdateRgn and UpdateRect into
468 * a region hRgn specified in window coordinates.
471 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
473 if (UpdateRgn
!= NULL
)
475 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
476 NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
);
478 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
479 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
481 if (UpdateRect
!= NULL
)
483 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
485 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
486 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
488 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
489 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
491 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
493 -Window
->WindowRect
.left
,
494 -Window
->WindowRect
.top
);
498 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
500 -Window
->WindowRect
.left
,
501 -Window
->WindowRect
.top
);
507 * Adjust the window update region depending on hRgn and flags.
510 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
))
512 IntInvalidateWindows(Window
, hRgn
, Flags
, TRUE
);
514 if (Window
->UpdateRegion
!= NULL
&& Flags
& RDW_ERASENOW
)
516 /* Validate parent covered by region. */
517 IntValidateParent(Window
);
522 * Repaint and erase windows if needed.
525 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
527 IntPaintWindows(Window
, Flags
);
537 NtGdiDeleteObject(hRgn
);
544 IntFindWindowToRepaint(HWND hWnd
, PW32THREAD Thread
)
546 PWINDOW_OBJECT Window
;
547 PWINDOW_OBJECT Child
;
548 HWND hFoundWnd
= NULL
;
552 PLIST_ENTRY CurrentEntry
;
554 ExAcquireFastMutex(&Thread
->WindowListLock
);
556 for (CurrentEntry
= Thread
->WindowListHead
.Flink
;
557 CurrentEntry
!= &Thread
->WindowListHead
;
558 CurrentEntry
= CurrentEntry
->Flink
)
560 Window
= CONTAINING_RECORD(CurrentEntry
, WINDOW_OBJECT
, ThreadListEntry
);
561 if (Window
->Parent
!= NULL
&& !IntIsDesktopWindow(Window
->Parent
))
565 if (Window
->Style
& WS_VISIBLE
)
567 hFoundWnd
= IntFindWindowToRepaint(Window
->Self
, Thread
);
568 if (hFoundWnd
!= NULL
)
570 ExReleaseFastMutex(&Thread
->WindowListLock
);
576 ExReleaseFastMutex(&Thread
->WindowListLock
);
581 Window
= IntGetWindowObject(hWnd
);
585 if (Window
->UpdateRegion
!= NULL
||
586 Window
->Flags
& (WINDOWOBJECT_NEED_INTERNALPAINT
| WINDOWOBJECT_NEED_NCPAINT
))
588 IntReleaseWindowObject(Window
);
592 ExAcquireFastMutex(&Window
->ChildrenListLock
);
594 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
596 if (Child
->Style
& WS_VISIBLE
&&
597 (Child
->UpdateRegion
!= NULL
||
598 Child
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
||
599 Child
->Flags
& WINDOWOBJECT_NEED_NCPAINT
))
601 hFoundWnd
= Child
->Self
;
606 if (hFoundWnd
== NULL
)
608 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
610 if (Child
->Style
& WS_VISIBLE
)
612 hFoundWnd
= IntFindWindowToRepaint(Child
->Self
, Thread
);
613 if (hFoundWnd
!= NULL
)
619 ExReleaseFastMutex(&Window
->ChildrenListLock
);
620 IntReleaseWindowObject(Window
);
627 IntGetPaintMessage(HWND hWnd
, PW32THREAD Thread
, MSG
*Message
,
630 PWINDOW_OBJECT Window
;
631 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
633 if (!MessageQueue
->PaintPosted
)
637 Message
->hwnd
= IntFindWindowToRepaint(hWnd
, PsGetWin32Thread());
639 Message
->hwnd
= IntFindWindowToRepaint(NULL
, PsGetWin32Thread());
641 if (Message
->hwnd
== NULL
)
644 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
645 /* FIXME: Lock the queue! */
646 MessageQueue
->PaintPosted
= 0;
647 MessageQueue
->PaintCount
= 0;
652 Window
= IntGetWindowObject(Message
->hwnd
);
655 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
657 Message
->message
= WM_NCPAINT
;
658 Message
->wParam
= (WPARAM
)IntGetNCUpdateRegion(Window
, Remove
);
662 Message
->message
= WM_PAINT
;
663 Message
->wParam
= Message
->lParam
= 0;
664 if (Remove
&& Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
666 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
667 if (Window
->UpdateRegion
== NULL
)
669 MsqDecPaintCountQueue(Window
->MessageQueue
);
674 IntReleaseWindowObject(Window
);
682 IntFixCaret(HWND hWnd
, LPRECT lprc
, UINT flags
)
686 if (!NtUserGetGUIThreadInfo(0, &info
))
690 if (info
.hwndCaret
== hWnd
||
691 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(hWnd
, info
.hwndCaret
)))
693 POINT pt
, FromOffset
, ToOffset
, Offset
;
695 pt
.x
= info
.rcCaret
.left
;
696 pt
.y
= info
.rcCaret
.top
;
698 NtUserGetClientOrigin(info
.hwndCaret
, &FromOffset
);
699 NtUserGetClientOrigin(hWnd
, &ToOffset
);
700 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
701 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
702 info
.rcCaret
.left
+= Offset
.x
;
703 info
.rcCaret
.top
+= Offset
.y
;
704 info
.rcCaret
.right
+= Offset
.x
;
705 info
.rcCaret
.bottom
+= Offset
.y
;
706 if (NtGdiIntersectRect(lprc
, lprc
, &info
.rcCaret
))
711 return info
.hwndCaret
;
718 /* PUBLIC FUNCTIONS ***********************************************************/
728 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* lPs
)
730 PWINDOW_OBJECT Window
;
735 if (!(Window
= IntGetWindowObject(hWnd
)))
737 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
741 NtUserHideCaret(hWnd
);
743 DcxFlags
= DCX_INTERSECTUPDATE
| DCX_WINDOWPAINT
| DCX_USESTYLE
;
744 if (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_PARENTDC
)
746 /* FIXME: Is this correct? */
747 /* Don't clip the output to the update region for CS_PARENTDC window */
748 DcxFlags
&= ~DCX_INTERSECTUPDATE
;
751 lPs
->hdc
= NtUserGetDCEx(hWnd
, 0, DcxFlags
);
755 IntReleaseWindowObject(Window
);
759 /* IntRedrawWindow(Window, NULL, 0, RDW_NOINTERNALPAINT | RDW_VALIDATE | RDW_NOCHILDREN);*/
760 if (Window
->UpdateRegion
!= NULL
)
762 MsqDecPaintCountQueue(Window
->MessageQueue
);
763 IntValidateParent(Window
);
764 NtGdiDeleteObject(Window
->UpdateRegion
);
765 Window
->UpdateRegion
= NULL
;
768 IntGetClientRect(Window
, &ClientRect
);
769 NtGdiGetClipBox(lPs
->hdc
, &ClipRect
);
770 NtGdiLPtoDP(lPs
->hdc
, (LPPOINT
)&ClipRect
, 2);
771 NtGdiIntersectRect(&lPs
->rcPaint
, &ClientRect
, &ClipRect
);
772 NtGdiDPtoLP(lPs
->hdc
, (LPPOINT
)&lPs
->rcPaint
, 2);
774 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
776 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
777 lPs
->fErase
= !NtUserSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)lPs
->hdc
, 0);
784 IntReleaseWindowObject(Window
);
797 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
799 NtUserReleaseDC(hWnd
, lPs
->hdc
);
800 NtUserShowCaret(hWnd
);
806 * NtUserInvalidateRect
813 NtUserInvalidateRect(HWND hWnd
, CONST RECT
*Rect
, BOOL Erase
)
815 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
819 * NtUserInvalidateRgn
826 NtUserInvalidateRgn(HWND hWnd
, HRGN Rgn
, BOOL Erase
)
828 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
839 NtUserValidateRgn(HWND hWnd
, HRGN hRgn
)
841 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
852 NtUserUpdateWindow(HWND hWnd
)
854 return NtUserRedrawWindow(hWnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
865 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
867 PWINDOW_OBJECT Window
;
870 if (!(Window
= IntGetWindowObject(hWnd
)))
872 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
876 if (Window
->UpdateRegion
== NULL
)
878 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
882 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
885 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
886 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
889 IntReleaseWindowObject(Window
);
891 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
893 NtUserRedrawWindow(hWnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
900 * NtUserGetUpdateRect
907 NtUserGetUpdateRect(HWND hWnd
, LPRECT lpRect
, BOOL fErase
)
909 HRGN hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
913 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
917 NtUserGetUpdateRgn(hWnd
, hRgn
, fErase
);
918 NtGdiGetRgnBox(hRgn
, lpRect
);
920 return lpRect
->left
< lpRect
->right
&& lpRect
->top
< lpRect
->bottom
;
931 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
938 if (!(Wnd
= IntGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
940 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
944 if (lprcUpdate
!= NULL
)
946 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
949 if (!NT_SUCCESS(Status
))
951 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
956 Status
= IntRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
959 if (!NT_SUCCESS(Status
))
961 /* IntRedrawWindow fails only in case that flags are invalid */
962 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
977 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
978 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
980 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
983 * Compute device clipping region (in device coordinates).
989 NtGdiGetClipBox(hDC
, &rSrc
);
990 NtGdiLPtoDP(hDC
, (LPPOINT
)&rSrc
, 2);
995 NtGdiGetClipBox(hDC
, &rClip
);
996 NtGdiLPtoDP(hDC
, (LPPOINT
)&rClip
, 2);
998 NtGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
1000 rDst
= rClipped_src
;
1001 NtGdiSetRect(&offset
, 0, 0, dx
, dy
);
1002 NtGdiLPtoDP(hDC
, (LPPOINT
)&offset
, 2);
1003 NtGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1004 NtGdiIntersectRect(&rDst
, &rDst
, &rClip
);
1007 * Copy bits, if possible.
1010 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1012 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1014 NtGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1015 NtGdiDPtoLP(hDC
, (LPPOINT
)&rDst_lp
, 2);
1016 NtGdiDPtoLP(hDC
, (LPPOINT
)&rSrc_lp
, 2);
1018 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1019 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1025 * Compute update areas. This is the clipped source or'ed with the
1026 * unclipped source translated minus the clipped src translated (rDst)
1027 * all clipped to rClip.
1030 if (hrgnUpdate
|| lprcUpdate
)
1032 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1035 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1037 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1039 hRgn2
= NtGdiCreateRectRgnIndirect(&rSrc
);
1040 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1041 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1043 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1044 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1046 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1047 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1051 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1053 /* Put the lprcUpdate in logical coordinate */
1054 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1057 NtGdiDeleteObject(hRgn
);
1058 NtGdiDeleteObject(hRgn2
);
1064 * NtUserScrollWindowEx
1071 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*rect
,
1072 const RECT
*clipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1074 RECT rc
, cliprc
, caretrc
;
1076 PWINDOW_OBJECT Window
;
1080 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1081 BOOL bOwnRgn
= TRUE
;
1083 Window
= IntGetWindowObject(hWnd
);
1084 if (!Window
|| !IntIsWindowDrawable(Window
))
1086 IntReleaseWindowObject(Window
);
1090 IntGetClientRect(Window
, &rc
);
1092 NtGdiIntersectRect(&rc
, &rc
, rect
);
1095 NtGdiIntersectRect(&cliprc
, &rc
, clipRect
);
1099 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1100 (dx
== 0 && dy
== 0))
1106 hwndCaret
= IntFixCaret(hWnd
, &caretrc
, flags
);
1111 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1113 hDC
= NtUserGetDCEx( hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
);
1116 HRGN hRgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
1118 NtUserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1119 NtUserReleaseDC(hWnd
, hDC
);
1121 NtGdiCombineRgn(hrgnUpdate
, hrgnUpdate
, hRgn
, RGN_OR
);
1123 NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| RDW_ERASE
);
1124 NtGdiDeleteObject(hRgn
);
1128 * Take into account the fact that some damage may have occurred during
1132 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1133 Result
= NtUserGetUpdateRgn(hWnd
, hrgnTemp
, FALSE
);
1134 if (Result
!= NULLREGION
)
1136 HRGN hrgnClip
= NtGdiCreateRectRgnIndirect(&cliprc
);
1137 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1138 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1139 NtUserRedrawWindow(hWnd
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1140 NtGdiDeleteObject(hrgnClip
);
1142 NtGdiDeleteObject(hrgnTemp
);
1144 if (flags
& SW_SCROLLCHILDREN
)
1146 HWND
*List
= IntWinListChildren(Window
);
1153 for (i
= 0; List
[i
]; i
++)
1155 NtUserGetWindowRect(List
[i
], &r
);
1156 NtUserGetClientOrigin(hWnd
, &ClientOrigin
);
1157 r
.left
-= ClientOrigin
.x
;
1158 r
.top
-= ClientOrigin
.y
;
1159 r
.right
-= ClientOrigin
.x
;
1160 r
.bottom
-= ClientOrigin
.y
;
1161 if (!rect
|| NtGdiIntersectRect(&dummy
, &r
, &rc
))
1162 WinPosSetWindowPos(List
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1163 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1170 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1171 NtUserRedrawWindow(hWnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1172 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1173 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1175 if (bOwnRgn
&& hrgnUpdate
)
1176 NtGdiDeleteObject(hrgnUpdate
);
1180 IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1181 NtUserShowCaret(hwndCaret
);
1184 IntReleaseWindowObject(Window
);