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.59 2004/01/12 00:07:34 navaraf 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>
57 /* #define FIN_DEBUG */
59 /* PRIVATE FUNCTIONS **********************************************************/
62 IntValidateParent(PWINDOW_OBJECT Child
, HRGN ValidRegion
)
65 PWINDOW_OBJECT ParentWindow
;
67 Parent
= NtUserGetAncestor(Child
->Self
, GA_PARENT
);
68 while (Parent
&& Parent
!= IntGetDesktopWindow())
70 ParentWindow
= IntGetWindowObject(Parent
);
71 if (ParentWindow
&& !(ParentWindow
->Style
& WS_CLIPCHILDREN
))
73 if (ParentWindow
->UpdateRegion
!= 0)
78 * We must offset the child region by the offset of the
79 * child rect in the parent.
81 OffsetX
= Child
->WindowRect
.left
- ParentWindow
->WindowRect
.left
;
82 OffsetY
= Child
->WindowRect
.top
- ParentWindow
->WindowRect
.top
;
83 NtGdiOffsetRgn(ValidRegion
, OffsetX
, OffsetY
);
84 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
85 ValidRegion
, RGN_DIFF
);
86 /* FIXME: If the resulting region is empty, remove fake posted paint message */
87 NtGdiOffsetRgn(ValidRegion
, -OffsetX
, -OffsetY
);
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
)
116 * Generate the update region.
119 WindowRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
120 NtGdiOffsetRgn(WindowRgn
,
121 -Window
->WindowRect
.left
,
122 -Window
->WindowRect
.top
);
123 NonclientRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
124 if (NtGdiCombineRgn(NonclientRgn
, Window
->UpdateRegion
,
125 WindowRgn
, RGN_DIFF
) == NULLREGION
)
127 NtGdiDeleteObject(NonclientRgn
);
132 * Remove the nonclient region from the standard update region.
135 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
136 WindowRgn
, RGN_AND
) == NULLREGION
)
138 NtGdiDeleteObject(Window
->UpdateRegion
);
139 Window
->UpdateRegion
= NULL
;
148 * Internal function used by IntRedrawWindow.
152 IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
155 HWND hWnd
= Window
->Self
;
157 if (! (Window
->Style
& WS_VISIBLE
))
162 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
164 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
166 IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)Window
->NCUpdateRegion
, 0);
167 Window
->NCUpdateRegion
= NULL
;
168 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
169 MsqDecPaintCountQueue(Window
->MessageQueue
);
172 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
174 if (Window
->UpdateRegion
)
179 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &TempRect
);
180 DPRINT1("Sending WM_ERASEBKGND[1]: %d,%d-%d,%d\n",
181 TempRect
.left
, TempRect
.top
, TempRect
.right
, TempRect
.bottom
);
184 hDC
= NtUserGetDCEx(hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
|
185 DCX_INTERSECTUPDATE
);
188 if (IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
190 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
192 NtUserReleaseDC(hWnd
, hDC
);
197 if (Flags
& RDW_UPDATENOW
)
199 if (Window
->UpdateRegion
!= NULL
||
200 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
205 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &TempRect
);
206 DPRINT1("Sending WM_PAINT[1]: %d,%d-%d,%d\n",
207 TempRect
.left
, TempRect
.top
, TempRect
.right
, TempRect
.bottom
);
210 IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
211 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
213 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
214 if (Window
->UpdateRegion
== NULL
)
216 MsqDecPaintCountQueue(Window
->MessageQueue
);
224 * Check that the window is still valid at this point
227 if (! IntIsWindow(hWnd
))
233 * Paint child windows.
235 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
236 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)) &&
237 ! IntIsDesktopWindow(Window
))
241 if ((List
= IntWinListChildren(Window
)))
243 for (phWnd
= List
; *phWnd
; ++phWnd
)
245 Window
= IntGetWindowObject(*phWnd
);
248 IntPaintWindows(Window
, Flags
);
249 IntReleaseWindowObject(Window
);
258 * IntInvalidateWindows
260 * Internal function used by IntRedrawWindow.
264 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
,
268 BOOL HadPaintMessage
, HadNCPaintMessage
;
269 BOOL HasPaintMessage
, HasNCPaintMessage
;
273 * Clip the given region with window rectangle (or region)
277 if (!Window
->WindowRegion
)
280 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
281 NtGdiOffsetRgn(hRgnWindow
,
282 -Window
->WindowRect
.left
,
283 -Window
->WindowRect
.top
);
284 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
285 NtGdiDeleteObject(hRgnWindow
);
290 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
295 * Save current state of pending updates
298 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
299 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
300 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
303 * Update the region and flags
306 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
308 if (Window
->UpdateRegion
== NULL
)
310 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
313 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
314 hRgn
, RGN_OR
) == NULLREGION
)
316 NtGdiDeleteObject(Window
->UpdateRegion
);
317 Window
->UpdateRegion
= NULL
;
320 if (Flags
& RDW_FRAME
)
321 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
322 if (Flags
& RDW_ERASE
)
323 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
328 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
330 if (Window
->UpdateRegion
!= NULL
)
332 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
333 hRgn
, RGN_DIFF
) == NULLREGION
)
335 NtGdiDeleteObject(Window
->UpdateRegion
);
336 Window
->UpdateRegion
= NULL
;
340 if (Window
->UpdateRegion
== NULL
)
341 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
342 if (Flags
& RDW_NOFRAME
)
343 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
344 if (Flags
& RDW_NOERASE
)
345 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
348 if (Flags
& RDW_INTERNALPAINT
)
350 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
353 if (Flags
& RDW_NOINTERNALPAINT
)
355 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
359 * Validate parent covered by region
364 IntValidateParent(Window
, Window
->UpdateRegion
);
368 * Split the nonclient update region.
371 if (Window
->NCUpdateRegion
== NULL
)
373 Window
->NCUpdateRegion
= IntGetNCUpdateRegion(Window
);
377 HRGN hRgnNonClient
= IntGetNCUpdateRegion(Window
);
378 NtGdiCombineRgn(Window
->NCUpdateRegion
, Window
->NCUpdateRegion
,
379 hRgnNonClient
, RGN_OR
);
380 NtGdiDeleteObject(hRgnNonClient
);
384 * Process children if needed
387 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
388 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
391 PWINDOW_OBJECT Child
;
393 if ((List
= IntWinListChildren(Window
)))
395 for (phWnd
= List
; *phWnd
; ++phWnd
)
397 Child
= IntGetWindowObject(*phWnd
);
402 if (Child
->Style
& WS_VISIBLE
)
405 * Recursive call to update children UpdateRegion
407 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
408 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
409 NtGdiOffsetRgn(hRgnTemp
,
410 Window
->WindowRect
.left
- Child
->WindowRect
.left
,
411 Window
->WindowRect
.top
- Child
->WindowRect
.top
);
412 IntInvalidateWindows(Child
, hRgnTemp
, Flags
, FALSE
);
415 * WINDOWS REALLY DON'T DO THIS!!!
419 * Update our UpdateRegion depending on children
422 if (Window
->UpdateRegion
!= NULL
)
426 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &TempRect
);
427 NtGdiCombineRgn(hRgnTemp
, Child
->UpdateRegion
, 0, RGN_COPY
);
428 NtGdiCombineRgn(hRgnTemp
, hRgnTemp
, Child
->NCUpdateRegion
, RGN_OR
);
429 NtGdiOffsetRgn(hRgnTemp
,
430 Child
->WindowRect
.left
- Window
->WindowRect
.left
,
431 Child
->WindowRect
.top
- Window
->WindowRect
.top
);
432 UnsafeIntGetRgnBox(hRgnTemp
, &TempRect
);
433 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
434 hRgnTemp
, RGN_DIFF
) == NULLREGION
)
436 NtGdiDeleteObject(Window
->UpdateRegion
);
437 Window
->UpdateRegion
= NULL
;
441 NtGdiDeleteObject(hRgnTemp
);
443 IntReleaseWindowObject(Child
);
450 * Fake post paint messages to window message queue if needed
452 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
453 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
454 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
456 if (HasPaintMessage
!= HadPaintMessage
)
459 MsqDecPaintCountQueue(Window
->MessageQueue
);
461 MsqIncPaintCountQueue(Window
->MessageQueue
);
464 if (HasNCPaintMessage
!= HadNCPaintMessage
)
466 if (HadNCPaintMessage
)
467 MsqDecPaintCountQueue(Window
->MessageQueue
);
469 MsqIncPaintCountQueue(Window
->MessageQueue
);
474 * IntIsWindowDrawable
477 * Window is drawable when it is visible and all parents are not
482 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
484 PWINDOW_OBJECT Wnd
= Window
;
486 for (; Wnd
; Wnd
= Wnd
->Parent
)
488 if (!(Wnd
->Style
& WS_VISIBLE
) ||
489 ((Wnd
->Style
& WS_MINIMIZE
) && (Wnd
!= Window
)))
499 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
504 IntRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
511 * Validation of passed parameters.
514 if (!IntIsWindowDrawable(Window
) ||
515 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
516 (RDW_VALIDATE
| RDW_INVALIDATE
))
523 * Transform the parameters UpdateRgn and UpdateRect into
524 * a region hRgn specified in window coordinates.
527 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
529 if (UpdateRgn
!= NULL
)
531 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
532 NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
);
534 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
535 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
537 if (UpdateRect
!= NULL
)
539 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
541 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
542 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
544 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
545 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
547 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
549 -Window
->WindowRect
.left
,
550 -Window
->WindowRect
.top
);
554 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
556 -Window
->WindowRect
.left
,
557 -Window
->WindowRect
.top
);
563 * Adjust the window update region depending on hRgn and flags.
566 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
))
568 IntInvalidateWindows(Window
, hRgn
, Flags
, TRUE
);
570 if (Window
->UpdateRegion
!= NULL
&& Flags
& RDW_ERASENOW
)
572 /* Validate parent covered by region. */
573 IntValidateParent(Window
, Window
->UpdateRegion
);
578 * Repaint and erase windows if needed.
581 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
583 IntPaintWindows(Window
, Flags
);
593 NtGdiDeleteObject(hRgn
);
600 IntFindWindowToRepaint(HWND hWnd
, PW32THREAD Thread
)
602 PWINDOW_OBJECT Window
;
603 PWINDOW_OBJECT Child
;
604 HWND hFoundWnd
= NULL
;
608 PLIST_ENTRY CurrentEntry
;
610 ExAcquireFastMutex(&Thread
->WindowListLock
);
612 for (CurrentEntry
= Thread
->WindowListHead
.Flink
;
613 CurrentEntry
!= &Thread
->WindowListHead
;
614 CurrentEntry
= CurrentEntry
->Flink
)
616 Window
= CONTAINING_RECORD(CurrentEntry
, WINDOW_OBJECT
, ThreadListEntry
);
617 if (Window
->Parent
!= NULL
&& !IntIsDesktopWindow(Window
->Parent
))
621 if (Window
->Style
& WS_VISIBLE
)
623 hFoundWnd
= IntFindWindowToRepaint(Window
->Self
, Thread
);
624 if (hFoundWnd
!= NULL
)
626 ExReleaseFastMutex(&Thread
->WindowListLock
);
632 ExReleaseFastMutex(&Thread
->WindowListLock
);
637 Window
= IntGetWindowObject(hWnd
);
641 if ((Window
->UpdateRegion
!= NULL
||
642 Window
->Flags
& (WINDOWOBJECT_NEED_INTERNALPAINT
| WINDOWOBJECT_NEED_NCPAINT
)) &&
643 IntWndBelongsToThread(Window
, Thread
))
645 IntReleaseWindowObject(Window
);
649 ExAcquireFastMutex(&Window
->ChildrenListLock
);
651 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
653 if (Child
->Style
& WS_VISIBLE
&&
654 (Child
->UpdateRegion
!= NULL
||
655 Child
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
||
656 Child
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
657 && IntWndBelongsToThread(Child
, Thread
))
659 hFoundWnd
= Child
->Self
;
664 if (hFoundWnd
== NULL
)
666 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
668 if (Child
->Style
& WS_VISIBLE
)
670 hFoundWnd
= IntFindWindowToRepaint(Child
->Self
, Thread
);
671 if (hFoundWnd
!= NULL
)
677 ExReleaseFastMutex(&Window
->ChildrenListLock
);
678 IntReleaseWindowObject(Window
);
685 IntGetPaintMessage(HWND hWnd
, PW32THREAD Thread
, MSG
*Message
,
688 PWINDOW_OBJECT Window
;
689 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
691 if (!MessageQueue
->PaintPosted
)
695 Message
->hwnd
= IntFindWindowToRepaint(hWnd
, PsGetWin32Thread());
697 Message
->hwnd
= IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
699 if (Message
->hwnd
== NULL
)
702 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
704 /* FIXME: Lock the queue! */
705 MessageQueue
->PaintPosted
= 0;
706 MessageQueue
->PaintCount
= 0;
710 Window
= IntGetWindowObject(Message
->hwnd
);
713 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
715 Message
->message
= WM_NCPAINT
;
716 Message
->wParam
= (WPARAM
)Window
->NCUpdateRegion
;
720 Window
->NCUpdateRegion
= NULL
;
721 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
722 MsqDecPaintCountQueue(Window
->MessageQueue
);
729 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &TempRect
);
730 DPRINT1("Sending WM_PAINT[2]: %d,%d-%d,%d\n",
731 TempRect
.left
, TempRect
.top
, TempRect
.right
, TempRect
.bottom
);
734 Message
->message
= WM_PAINT
;
735 Message
->wParam
= Message
->lParam
= 0;
736 if (Remove
&& Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
738 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
739 if (Window
->UpdateRegion
== NULL
)
741 MsqDecPaintCountQueue(Window
->MessageQueue
);
746 IntReleaseWindowObject(Window
);
754 IntFixCaret(HWND hWnd
, LPRECT lprc
, UINT flags
)
758 if (!NtUserGetGUIThreadInfo(0, &info
))
762 if (info
.hwndCaret
== hWnd
||
763 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(hWnd
, info
.hwndCaret
)))
765 POINT pt
, FromOffset
, ToOffset
, Offset
;
767 pt
.x
= info
.rcCaret
.left
;
768 pt
.y
= info
.rcCaret
.top
;
770 IntGetClientOrigin(info
.hwndCaret
, &FromOffset
);
771 IntGetClientOrigin(hWnd
, &ToOffset
);
772 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
773 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
774 info
.rcCaret
.left
+= Offset
.x
;
775 info
.rcCaret
.top
+= Offset
.y
;
776 info
.rcCaret
.right
+= Offset
.x
;
777 info
.rcCaret
.bottom
+= Offset
.y
;
778 if (NtGdiIntersectRect(lprc
, lprc
, &info
.rcCaret
))
783 return info
.hwndCaret
;
790 /* PUBLIC FUNCTIONS ***********************************************************/
800 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* lPs
)
802 PWINDOW_OBJECT Window
;
808 if (!(Window
= IntGetWindowObject(hWnd
)))
810 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
814 NtUserHideCaret(hWnd
);
816 DcxFlags
= DCX_INTERSECTUPDATE
| DCX_WINDOWPAINT
| DCX_USESTYLE
;
818 lPs
->hdc
= NtUserGetDCEx(hWnd
, 0, DcxFlags
);
822 IntReleaseWindowObject(Window
);
826 /* IntRedrawWindow(Window, NULL, 0, RDW_NOINTERNALPAINT | RDW_VALIDATE | RDW_NOCHILDREN);*/
828 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
831 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &TempRect
);
832 DPRINT1("Sending WM_ERASEBKGND[2]: %d,%d-%d,%d\n",
833 TempRect
.left
, TempRect
.top
, TempRect
.right
, TempRect
.bottom
);
837 if (Window
->UpdateRegion
!= NULL
)
839 MsqDecPaintCountQueue(Window
->MessageQueue
);
840 IntValidateParent(Window
, Window
->UpdateRegion
);
841 NtGdiDeleteObject(Window
->UpdateRegion
);
842 Window
->UpdateRegion
= NULL
;
845 IntGetClientRect(Window
, &ClientRect
);
846 IntGdiGetClipBox(lPs
->hdc
, &ClipRect
);
847 DC
= DC_LockDc(lPs
->hdc
);
850 IntReleaseWindowObject(Window
);
853 IntLPtoDP(DC
, (LPPOINT
)&ClipRect
, 2);
854 DC_UnlockDc(lPs
->hdc
);
855 NtGdiIntersectRect(&lPs
->rcPaint
, &ClientRect
, &ClipRect
);
856 NtGdiDPtoLP(lPs
->hdc
, (LPPOINT
)&lPs
->rcPaint
, 2);
858 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
860 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
861 lPs
->fErase
= !IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)lPs
->hdc
, 0);
868 IntReleaseWindowObject(Window
);
881 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
883 NtUserReleaseDC(hWnd
, lPs
->hdc
);
884 NtUserShowCaret(hWnd
);
890 * NtUserInvalidateRect
897 NtUserInvalidateRect(HWND hWnd
, CONST RECT
*Rect
, BOOL Erase
)
899 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
903 * NtUserInvalidateRgn
910 NtUserInvalidateRgn(HWND hWnd
, HRGN Rgn
, BOOL Erase
)
912 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
923 NtUserValidateRgn(HWND hWnd
, HRGN hRgn
)
925 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
936 NtUserUpdateWindow(HWND hWnd
)
938 return NtUserRedrawWindow(hWnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
949 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
951 PWINDOW_OBJECT Window
;
954 if (!(Window
= IntGetWindowObject(hWnd
)))
956 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
960 if (Window
->UpdateRegion
== NULL
)
962 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
966 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
969 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
970 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
973 IntReleaseWindowObject(Window
);
975 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
977 NtUserRedrawWindow(hWnd
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
984 * NtUserGetUpdateRect
991 NtUserGetUpdateRect(HWND hWnd
, LPRECT lpRect
, BOOL fErase
)
993 HRGN hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
997 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1001 NtUserGetUpdateRgn(hWnd
, hRgn
, fErase
);
1002 NtGdiGetRgnBox(hRgn
, lpRect
);
1004 return lpRect
->left
< lpRect
->right
&& lpRect
->top
< lpRect
->bottom
;
1008 * NtUserRedrawWindow
1015 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
1018 RECT SafeUpdateRect
;
1022 if (!(Wnd
= IntGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1024 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1028 if (lprcUpdate
!= NULL
)
1030 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
1033 if (!NT_SUCCESS(Status
))
1035 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1040 Status
= IntRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
1043 if (!NT_SUCCESS(Status
))
1045 /* IntRedrawWindow fails only in case that flags are invalid */
1046 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1061 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1062 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1064 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
1068 * Compute device clipping region (in device coordinates).
1071 DC
= DC_LockDc(hDC
);
1079 IntGdiGetClipBox(hDC
, &rSrc
);
1080 IntLPtoDP(DC
, (LPPOINT
)&rSrc
, 2);
1085 IntGdiGetClipBox(hDC
, &rClip
);
1086 IntLPtoDP(DC
, (LPPOINT
)&rClip
, 2);
1088 NtGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
1090 rDst
= rClipped_src
;
1091 NtGdiSetRect(&offset
, 0, 0, dx
, dy
);
1092 IntLPtoDP(DC
, (LPPOINT
)&offset
, 2);
1093 NtGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1094 NtGdiIntersectRect(&rDst
, &rDst
, &rClip
);
1098 * Copy bits, if possible.
1101 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1103 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1105 NtGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1106 NtGdiDPtoLP(hDC
, (LPPOINT
)&rDst_lp
, 2);
1107 NtGdiDPtoLP(hDC
, (LPPOINT
)&rSrc_lp
, 2);
1109 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1110 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1116 * Compute update areas. This is the clipped source or'ed with the
1117 * unclipped source translated minus the clipped src translated (rDst)
1118 * all clipped to rClip.
1121 if (hrgnUpdate
|| lprcUpdate
)
1123 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1126 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1128 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1130 hRgn2
= NtGdiCreateRectRgnIndirect(&rSrc
);
1131 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1132 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1134 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1135 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1137 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1138 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1142 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1144 /* Put the lprcUpdate in logical coordinate */
1145 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1148 NtGdiDeleteObject(hRgn
);
1149 NtGdiDeleteObject(hRgn2
);
1155 * NtUserScrollWindowEx
1162 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*rect
,
1163 const RECT
*clipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1165 RECT rc
, cliprc
, caretrc
;
1167 PWINDOW_OBJECT Window
;
1171 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1172 BOOL bOwnRgn
= TRUE
;
1174 Window
= IntGetWindowObject(hWnd
);
1175 if (!Window
|| !IntIsWindowDrawable(Window
))
1177 IntReleaseWindowObject(Window
);
1181 IntGetClientRect(Window
, &rc
);
1183 NtGdiIntersectRect(&rc
, &rc
, rect
);
1186 NtGdiIntersectRect(&cliprc
, &rc
, clipRect
);
1190 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1191 (dx
== 0 && dy
== 0))
1197 hwndCaret
= IntFixCaret(hWnd
, &caretrc
, flags
);
1202 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1204 hDC
= NtUserGetDCEx( hWnd
, 0, DCX_CACHE
| DCX_USESTYLE
);
1207 HRGN hRgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
1209 NtUserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1210 NtUserReleaseDC(hWnd
, hDC
);
1212 NtGdiCombineRgn(hrgnUpdate
, hrgnUpdate
, hRgn
, RGN_OR
);
1214 NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_INVALIDATE
| RDW_ERASE
);
1215 NtGdiDeleteObject(hRgn
);
1219 * Take into account the fact that some damage may have occurred during
1223 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1224 Result
= NtUserGetUpdateRgn(hWnd
, hrgnTemp
, FALSE
);
1225 if (Result
!= NULLREGION
)
1227 HRGN hrgnClip
= NtGdiCreateRectRgnIndirect(&cliprc
);
1228 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1229 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1230 NtUserRedrawWindow(hWnd
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1231 NtGdiDeleteObject(hrgnClip
);
1233 NtGdiDeleteObject(hrgnTemp
);
1235 if (flags
& SW_SCROLLCHILDREN
)
1237 HWND
*List
= IntWinListChildren(Window
);
1244 for (i
= 0; List
[i
]; i
++)
1246 NtUserGetWindowRect(List
[i
], &r
);
1247 IntGetClientOrigin(hWnd
, &ClientOrigin
);
1248 r
.left
-= ClientOrigin
.x
;
1249 r
.top
-= ClientOrigin
.y
;
1250 r
.right
-= ClientOrigin
.x
;
1251 r
.bottom
-= ClientOrigin
.y
;
1252 if (!rect
|| NtGdiIntersectRect(&dummy
, &r
, &rc
))
1253 WinPosSetWindowPos(List
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1254 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1261 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1262 NtUserRedrawWindow(hWnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1263 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1264 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1266 if (bOwnRgn
&& hrgnUpdate
)
1267 NtGdiDeleteObject(hrgnUpdate
);
1271 IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1272 NtUserShowCaret(hwndCaret
);
1275 IntReleaseWindowObject(Window
);