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.33 2003/09/11 22:11:44 gvg Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/painting.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/guicheck.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
40 #include <include/painting.h>
41 #include <user32/wininternal.h>
42 #include <include/rect.h>
43 #include <win32k/coord.h>
44 #include <win32k/region.h>
45 #include <include/vis.h>
51 /* GLOBALS *******************************************************************/
53 /* client rect in window coordinates */
54 #define GETCLIENTRECTW(wnd, r) (r).left = (wnd)->ClientRect.left - (wnd)->WindowRect.left; \
55 (r).top = (wnd)->ClientRect.top - (wnd)->WindowRect.top; \
56 (r).right = (wnd)->ClientRect.right - (wnd)->WindowRect.left; \
57 (r).bottom = (wnd)->ClientRect.bottom - (wnd)->WindowRect.top
59 /* FUNCTIONS *****************************************************************/
62 PaintDoPaint(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
, ULONG ExFlags
)
65 HWND hWnd
= Window
->Self
;
66 BOOL bIcon
= (0 != (Window
->Style
& WS_MINIMIZE
)) &&
67 (0 != IntGetClassLong(Window
, GCL_HICON
, FALSE
));
69 if (0 != (ExFlags
& RDW_EX_DELAY_NCPAINT
) ||
70 PaintHaveToDelayNCPaint(Window
, 0))
72 ExFlags
|= RDW_EX_DELAY_NCPAINT
;
75 if (Flags
& RDW_UPDATENOW
)
77 if (NULL
!= Window
->UpdateRegion
)
79 if (IntIsDesktopWindow(Window
))
81 VIS_RepaintDesktop(Window
->Self
, Window
->UpdateRegion
);
85 NtUserSendMessage(hWnd
, bIcon
? WM_PAINTICON
: WM_PAINT
, bIcon
, 0);
89 else if (Flags
& RDW_ERASENOW
|| ExFlags
& RDW_EX_TOPFRAME
)
91 UINT Dcx
= DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
|
92 DCX_WINDOWPAINT
| DCX_CACHE
;
96 PaintUpdateNCRegion(Window
,
98 UNC_REGION
| UNC_CHECK
|
99 ((ExFlags
& RDW_EX_TOPFRAME
) ? UNC_ENTIRE
: 0) |
100 ((ExFlags
& RDW_EX_DELAY_NCPAINT
) ?
101 UNC_DELAY_NCPAINT
: 0));
104 if ((HRGN
) 1 < hRgnRet
)
112 if (0 != (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBACKGRD
))
120 NtGdiOffsetRgn(hRgnRet
,
121 Window
->WindowRect
.left
-
122 Window
->ClientRect
.left
,
123 Window
->WindowRect
.top
-
124 Window
->ClientRect
.top
);
128 Dcx
&= ~DCX_INTERSECTRGN
;
130 if (NULL
!= (hDC
= NtUserGetDCEx(hWnd
, hRgnRet
, Dcx
)))
132 if (IntIsDesktopWindow(Window
))
134 VIS_RepaintDesktop(Window
->Self
, Window
->UpdateRegion
);
135 NtGdiDeleteObject(Window
->UpdateRegion
);
136 Window
->UpdateRegion
= 0;
140 if (0 != NtUserSendMessage(hWnd
, bIcon
? WM_ICONERASEBKGND
:
141 WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
143 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBACKGRD
;
146 NtUserReleaseDC(hWnd
, hDC
);
152 /* FIXME: Check that the window is still valid at this point. */
154 ExFlags
&= ~RDW_EX_TOPFRAME
;
156 /* FIXME: Paint child windows. */
162 PaintUpdateInternalPaint(PWINDOW_OBJECT Window
, ULONG Flags
)
164 if (Flags
& RDW_INTERNALPAINT
)
166 if (Window
->UpdateRegion
== NULL
&&
167 !(Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
169 MsqIncPaintCountQueue(Window
->MessageQueue
);
171 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
173 else if (Flags
& RDW_NOINTERNALPAINT
)
175 if (Window
->UpdateRegion
== NULL
&&
176 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
178 MsqDecPaintCountQueue(Window
->MessageQueue
);
180 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
185 PaintValidateParent(PWINDOW_OBJECT Child
)
187 HWND DesktopHandle
= IntGetDesktopWindow();
188 PWINDOW_OBJECT Parent
= Child
->Parent
;
189 PWINDOW_OBJECT Desktop
= IntGetWindowObject(DesktopHandle
);
192 if ((HRGN
) 1 == Child
->UpdateRegion
)
196 Rect
.left
= Rect
.top
= 0;
197 Rect
.right
= Child
->WindowRect
.right
- Child
->WindowRect
.left
;
198 Rect
.bottom
= Child
->WindowRect
.bottom
- Child
->WindowRect
.top
;
200 hRgn
= UnsafeIntCreateRectRgnIndirect(&Rect
);
204 hRgn
= Child
->UpdateRegion
;
207 while (NULL
!= Parent
&& Parent
!= Desktop
)
209 if (0 == (Parent
->Style
& WS_CLIPCHILDREN
))
211 if (NULL
!= Parent
->UpdateRegion
)
215 if ((HRGN
) 1 == Parent
->UpdateRegion
)
219 Rect1
.left
= Rect1
.top
= 0;
220 Rect1
.right
= Parent
->WindowRect
.right
-
221 Parent
->WindowRect
.left
;
222 Rect1
.bottom
= Parent
->WindowRect
.bottom
-
223 Parent
->WindowRect
.top
;
225 Parent
->UpdateRegion
=
226 UnsafeIntCreateRectRgnIndirect(&Rect1
);
228 Offset
.x
= Child
->WindowRect
.left
- Parent
->WindowRect
.left
;
229 Offset
.y
= Child
->WindowRect
.top
- Parent
->WindowRect
.top
;
230 NtGdiOffsetRgn(hRgn
, Offset
.x
, Offset
.y
);
231 NtGdiCombineRgn(Parent
->UpdateRegion
, Parent
->UpdateRegion
, hRgn
,
233 NtGdiOffsetRgn(hRgn
, -Offset
.x
, -Offset
.y
);
236 Parent
= Parent
->Parent
;
238 if (hRgn
!= Child
->UpdateRegion
)
240 NtGdiDeleteObject(Child
->UpdateRegion
);
242 IntReleaseWindowObject(Desktop
);
246 PaintUpdateRgns(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
,
250 * Called only when one of the following is set:
251 * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
254 BOOL HadOne
= NULL
!= Window
->UpdateRegion
&& NULL
!= hRgn
;
255 BOOL HasChildren
= Window
->FirstChild
&&
256 !(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
257 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
));
260 Rect
.left
= Rect
.top
= 0;
261 Rect
.right
= Window
->WindowRect
.right
- Window
->WindowRect
.left
;
262 Rect
.bottom
= Window
->WindowRect
.bottom
- Window
->WindowRect
.top
;
264 if (Flags
& RDW_INVALIDATE
)
268 if ((HRGN
) 1 != Window
->UpdateRegion
)
270 if ((HRGN
) 1 < Window
->UpdateRegion
)
272 NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
275 Window
->UpdateRegion
=
276 REGION_CropRgn(Window
->UpdateRegion
,
277 Window
->UpdateRegion
? Window
->UpdateRegion
: hRgn
,
281 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &Rect
);
282 if (NtGdiIsEmptyRect(&Rect
))
284 NtGdiDeleteObject(Window
->UpdateRegion
);
285 Window
->UpdateRegion
= NULL
;
286 PaintUpdateInternalPaint(Window
, Flags
);
292 else if ((HRGN
) 1 == hRgn
)
294 if ((HRGN
) 1 < Window
->UpdateRegion
)
296 NtGdiDeleteObject(Window
->UpdateRegion
);
298 Window
->UpdateRegion
= (HRGN
) 1;
302 hRgn
= Window
->UpdateRegion
; /* this is a trick that depends on code in PaintRedrawWindow() */
305 if (! HadOne
&& 0 == (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
) &&
306 !IntIsDesktopWindow(Window
))
308 MsqIncPaintCountQueue(Window
->MessageQueue
);
311 if (Flags
& RDW_FRAME
)
313 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
315 if (Flags
& RDW_ERASE
)
317 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBACKGRD
;
321 else if (Flags
& RDW_VALIDATE
)
323 if (NULL
!= Window
->UpdateRegion
)
327 if ((HRGN
) 1 == Window
->UpdateRegion
)
329 /* If no NCPAINT needed or if we're going to turn it off
330 the special value 1 means the whole client rect */
331 if (0 == (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
) ||
332 0 != (Flags
& RDW_NOFRAME
))
334 Rect
.left
= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
335 Rect
.top
= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
336 Rect
.right
= Window
->ClientRect
.right
- Window
->WindowRect
.left
;
337 Rect
.bottom
= Window
->ClientRect
.bottom
- Window
->WindowRect
.top
;
339 Window
->UpdateRegion
=
340 UnsafeIntCreateRectRgnIndirect(&Rect
);
342 if (NtGdiCombineRgn(Window
->UpdateRegion
,
343 Window
->UpdateRegion
, hRgn
,
344 RGN_DIFF
) == NULLREGION
)
346 NtGdiDeleteObject(Window
->UpdateRegion
);
347 Window
->UpdateRegion
= NULL
;
350 else /* validate everything */
352 if ((HRGN
) 1 < Window
->UpdateRegion
)
354 NtGdiDeleteObject(Window
->UpdateRegion
);
356 Window
->UpdateRegion
= NULL
;
359 if (NULL
!= Window
->UpdateRegion
)
361 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBACKGRD
;
362 if (0 != (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
364 MsqDecPaintCountQueue(Window
->MessageQueue
);
369 if (Flags
& RDW_NOFRAME
)
371 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
373 if (Flags
& RDW_NOERASE
)
375 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBACKGRD
;
379 if (First
&& NULL
!= Window
->UpdateRegion
&& 0 != (Flags
& RDW_UPDATENOW
))
381 PaintValidateParent(Window
); /* validate parent covered by region */
384 /* in/validate child windows that intersect with the region if it
385 * is a valid handle. */
387 if (0 != (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
)))
389 if ((HRGN
) 1 < hRgn
&& HasChildren
)
391 POINT Total
= {0, 0};
392 POINT PrevOrign
= {0, 0};
393 PWINDOW_OBJECT Child
;
395 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
396 Child
= Window
->FirstChild
;
399 if (0 != (Child
->Style
& WS_VISIBLE
))
403 Rect
.left
= Child
->WindowRect
.left
- Window
->WindowRect
.left
;
404 Rect
.top
= Child
->WindowRect
.top
- Window
->WindowRect
.top
;
405 Rect
.right
= Child
->WindowRect
.right
- Window
->WindowRect
.left
;
406 Rect
.bottom
= Child
->WindowRect
.bottom
- Window
->WindowRect
.top
;
408 Offset
.x
= Rect
.left
- PrevOrign
.x
;
409 Offset
.y
= Rect
.top
- PrevOrign
.y
;
410 NtGdiOffsetRect(&Rect
, -Total
.x
, -Total
.y
);
412 if (UnsafeIntRectInRegion(hRgn
, &Rect
))
414 NtGdiOffsetRgn(hRgn
, -Offset
.x
, -Offset
.y
);
415 PaintUpdateRgns(Child
, hRgn
, Flags
, FALSE
);
416 PrevOrign
.x
= Rect
.left
+ Total
.x
;
417 PrevOrign
.y
= Rect
.top
+ Total
.y
;
422 Child
= Child
->NextSibling
;
424 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
426 NtGdiOffsetRgn(hRgn
, Total
.x
, Total
.y
);
433 PWINDOW_OBJECT Child
;
435 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
436 Child
= Window
->FirstChild
;
439 if (Child
->Style
& WS_VISIBLE
)
441 PaintUpdateRgns(Child
, hRgn
, Flags
, FALSE
);
443 Child
= Child
->NextSibling
;
445 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
448 PaintUpdateInternalPaint(Window
, Flags
);
452 PaintRedrawWindow( PWINDOW_OBJECT Window
,
453 const RECT
* UpdateRect
,
462 DPRINT("[win32k.sys:painting] In PaintRedrawWindow()\n");
464 if ((RDW_INVALIDATE
| RDW_FRAME
) == (Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) ||
465 (RDW_VALIDATE
| RDW_NOFRAME
) == (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)))
467 Rect
= Window
->WindowRect
;
471 Rect
= Window
->ClientRect
;
474 if (ExFlags
& RDW_EX_XYWINDOW
)
477 NtGdiOffsetRect(&Rect
, -Window
->WindowRect
.left
, -Window
->WindowRect
.top
);
481 Pt
.x
= Window
->ClientRect
.left
- Window
->WindowRect
.left
;
482 Pt
.y
= Window
->ClientRect
.top
- Window
->WindowRect
.top
;
483 NtGdiOffsetRect(&Rect
, -Window
->ClientRect
.left
, -Window
->ClientRect
.top
);
486 if (0 != (Flags
& RDW_INVALIDATE
)) /* ------------------------- Invalidate */
488 if (NULL
!= UpdateRgn
)
490 if (NULL
!= Window
->UpdateRegion
)
492 hRgn
= REGION_CropRgn(NULL
, UpdateRgn
, NULL
, &Pt
);
496 Window
->UpdateRegion
= REGION_CropRgn(NULL
, UpdateRgn
, &Rect
, &Pt
);
499 else if (NULL
!= UpdateRect
)
501 if (! NtGdiIntersectRect(&Rect2
, &Rect
, UpdateRect
))
504 if ((HRGN
) 1 < hRgn
&& hRgn
!= UpdateRgn
)
506 NtGdiDeleteObject(hRgn
);
510 NtGdiOffsetRect(&Rect2
, Pt
.x
, Pt
.y
);
511 if (NULL
== Window
->UpdateRegion
)
513 Window
->UpdateRegion
=
514 UnsafeIntCreateRectRgnIndirect(&Rect2
);
518 hRgn
= UnsafeIntCreateRectRgnIndirect(&Rect2
);
521 else /* entire window or client depending on RDW_FRAME */
523 if (Flags
& RDW_FRAME
)
525 if (NULL
!= Window
->UpdateRegion
)
531 Window
->UpdateRegion
= (HRGN
) 1;
536 GETCLIENTRECTW(Window
, Rect2
);
537 if (NULL
== Window
->UpdateRegion
)
539 Window
->UpdateRegion
= UnsafeIntCreateRectRgnIndirect(&Rect2
);
543 hRgn
= UnsafeIntCreateRectRgnIndirect(&Rect2
);
548 else if (Flags
& RDW_VALIDATE
)
550 /* In this we cannot leave with zero hRgn */
551 if (NULL
!= UpdateRgn
)
553 hRgn
= REGION_CropRgn(hRgn
, UpdateRgn
, &Rect
, &Pt
);
554 UnsafeIntGetRgnBox(hRgn
, &Rect2
);
555 if (NtGdiIsEmptyRect(&Rect2
))
558 if ((HRGN
) 1 < hRgn
&& hRgn
!= UpdateRgn
)
560 NtGdiDeleteObject(hRgn
);
565 else if (NULL
!= UpdateRect
)
567 if (! NtGdiIntersectRect(&Rect2
, &Rect
, UpdateRect
))
570 if ((HRGN
) 1 < hRgn
&& hRgn
!= UpdateRgn
)
572 NtGdiDeleteObject(hRgn
);
576 NtGdiOffsetRect(&Rect2
, Pt
.x
, Pt
.y
);
577 hRgn
= UnsafeIntCreateRectRgnIndirect(&Rect2
);
579 else /* entire window or client depending on RDW_NOFRAME */
581 if (0 != (Flags
& RDW_NOFRAME
))
587 GETCLIENTRECTW(Window
, Rect2
);
588 hRgn
= UnsafeIntCreateRectRgnIndirect(&Rect2
);
593 /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
595 PaintUpdateRgns(Window
, hRgn
, Flags
, TRUE
);
597 /* Erase/update windows, from now on hRgn is a scratch region */
599 hRgn
= PaintDoPaint(Window
, (HRGN
) 1 == hRgn
? NULL
: hRgn
, Flags
, ExFlags
);
601 if ((HRGN
) 1 < hRgn
&& hRgn
!= UpdateRgn
)
603 NtGdiDeleteObject(hRgn
);
610 PaintHaveToDelayNCPaint(PWINDOW_OBJECT Window
, ULONG Flags
)
612 if (Flags
& UNC_DELAY_NCPAINT
)
617 if (Flags
& UNC_IN_BEGINPAINT
)
622 Window
= Window
->Parent
;
623 while (Window
!= NULL
)
625 if (Window
->Style
& WS_CLIPCHILDREN
&& Window
->UpdateRegion
!= NULL
)
629 Window
= Window
->Parent
;
636 PaintingFindWinToRepaint(HWND hWnd
, PW32THREAD Thread
)
638 PWINDOW_OBJECT Window
;
639 PWINDOW_OBJECT BaseWindow
;
640 PLIST_ENTRY current_entry
;
641 HWND hFoundWnd
= NULL
;
645 ExAcquireFastMutex(&Thread
->WindowListLock
);
646 current_entry
= Thread
->WindowListHead
.Flink
;
647 while (current_entry
!= &Thread
->WindowListHead
)
649 Window
= CONTAINING_RECORD(current_entry
, WINDOW_OBJECT
,
651 if (Window
->Style
& WS_VISIBLE
)
654 PaintingFindWinToRepaint(Window
->Self
, Thread
);
655 if (hFoundWnd
!= NULL
)
657 ExReleaseFastMutex(&Thread
->WindowListLock
);
661 current_entry
= current_entry
->Flink
;
663 ExReleaseFastMutex(&Thread
->WindowListLock
);
667 BaseWindow
= IntGetWindowObject(hWnd
);
668 if (BaseWindow
== NULL
)
672 if (BaseWindow
->UpdateRegion
!= NULL
||
673 BaseWindow
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
675 IntReleaseWindowObject(BaseWindow
);
679 ExAcquireFastMutex(&BaseWindow
->ChildrenListLock
);
680 Window
= BaseWindow
->FirstChild
;
683 if (Window
->Style
& WS_VISIBLE
)
685 hFoundWnd
= PaintingFindWinToRepaint(Window
->Self
, Thread
);
686 if (hFoundWnd
!= NULL
)
691 Window
= Window
->NextSibling
;
693 ExReleaseFastMutex(&BaseWindow
->ChildrenListLock
);
695 IntReleaseWindowObject(BaseWindow
);
700 PaintUpdateNCRegion(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
706 /* Desktop has no parent. */
707 if (Window
->Parent
== NULL
)
709 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
710 if ((HRGN
) 1 < Window
->UpdateRegion
)
712 hRgnRet
= REGION_CropRgn(hRgn
, Window
->UpdateRegion
, NULL
, NULL
);
716 hRgnRet
= Window
->UpdateRegion
;
721 #if 0 /* NtUserGetFOregroundWindow() not implemented yet */
722 if ((Window
->Self
== NtUserGetForegroundWindow()) &&
723 0 == (Window
->Flags
& WIN_NCACTIVATED
) )
725 Window
->Flags
|= WIN_NCACTIVATED
;
731 * If the window's non-client area needs to be painted,
733 if (0 != (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
) &&
734 ! PaintHaveToDelayNCPaint(Window
, Flags
))
736 RECT UpdateRegionBox
;
739 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
740 GETCLIENTRECTW(Window
, ClientRect
);
742 if ((HRGN
) 1 < Window
->UpdateRegion
)
744 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &UpdateRegionBox
);
745 NtGdiUnionRect(&Rect
, &ClientRect
, &UpdateRegionBox
);
746 if (Rect
.left
!= ClientRect
.left
|| Rect
.top
!= ClientRect
.top
||
747 Rect
.right
!= ClientRect
.right
|| Rect
.bottom
!= ClientRect
.bottom
)
749 hClip
= Window
->UpdateRegion
;
750 Window
->UpdateRegion
= REGION_CropRgn(hRgn
, hClip
,
752 if (Flags
& UNC_REGION
)
758 if (Flags
& UNC_CHECK
)
760 UnsafeIntGetRgnBox(Window
->UpdateRegion
, &UpdateRegionBox
);
761 if (NtGdiIsEmptyRect(&UpdateRegionBox
))
763 NtGdiDeleteObject(Window
->UpdateRegion
);
764 Window
->UpdateRegion
= NULL
;
765 if (0 == (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
767 MsqDecPaintCountQueue(Window
->MessageQueue
);
769 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBACKGRD
;
773 if (0 == hClip
&& 0 != Window
->UpdateRegion
)
778 else if ((HRGN
) 1 == Window
->UpdateRegion
)
780 if (0 != (Flags
& UNC_UPDATE
))
782 Window
->UpdateRegion
=
783 UnsafeIntCreateRectRgnIndirect(&ClientRect
);
785 if (Flags
& UNC_REGION
)
792 else /* no WM_NCPAINT unless forced */
794 if ((HRGN
) 1 < Window
->UpdateRegion
)
797 if (0 != (Flags
& UNC_REGION
))
799 hRgnRet
= REGION_CropRgn(hRgn
, Window
->UpdateRegion
, NULL
, NULL
);
802 else if ((HRGN
) 1 == Window
->UpdateRegion
&& 0 != (Flags
& UNC_UPDATE
))
804 GETCLIENTRECTW(Window
, ClientRect
);
805 Window
->UpdateRegion
=
806 UnsafeIntCreateRectRgnIndirect(&ClientRect
);
807 if (Flags
& UNC_REGION
)
814 if (NULL
== hClip
&& 0 != (Flags
& UNC_ENTIRE
))
816 if (RtlCompareMemory(&Window
->WindowRect
, &Window
->ClientRect
,
817 sizeof(RECT
)) != sizeof(RECT
))
827 if (NULL
!= hClip
) /* NOTE: WM_NCPAINT allows wParam to be 1 */
829 if (hClip
== hRgnRet
&& (HRGN
) 1 < hRgnRet
)
831 hClip
= NtGdiCreateRectRgn(0, 0, 0, 0);
832 NtGdiCombineRgn(hClip
, hRgnRet
, 0, RGN_COPY
);
835 NtUserSendMessage(Window
->Self
, WM_NCPAINT
, (WPARAM
) hClip
, 0);
837 if ((HRGN
) 1 < hClip
&& hClip
!= hRgn
&& hClip
!= hRgnRet
)
839 NtGdiDeleteObject(hClip
);
842 /* FIXME: Need to check the window is still valid. */
848 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
850 NtUserReleaseDC(hWnd
, lPs
->hdc
);
851 /* FIXME: Show claret. */
857 GetClientUpdateRegion(PWINDOW_OBJECT Window
)
862 if ((DWORD
) Window
->UpdateRegion
<= 1)
864 return Window
->UpdateRegion
;
867 Offset
.x
= Window
->WindowRect
.left
- Window
->ClientRect
.left
;
868 Offset
.y
= Window
->WindowRect
.top
- Window
->ClientRect
.top
;
869 Rect
.left
= - Offset
.x
;
870 Rect
.top
= - Offset
.y
;
871 Rect
.right
= Rect
.left
+ (Window
->ClientRect
.right
- Window
->ClientRect
.left
);
872 Rect
.bottom
= Rect
.top
+ (Window
->ClientRect
.bottom
- Window
->ClientRect
.top
);
874 return REGION_CropRgn(NULL
, Window
->UpdateRegion
, &Rect
, &Offset
);
878 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* lPs
)
881 PWINDOW_OBJECT Window
;
888 if (!(Window
= IntGetWindowObject(hWnd
)))
890 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
894 /* Send WM_NCPAINT */
895 PaintUpdateNCRegion(Window
, 0, UNC_UPDATE
| UNC_IN_BEGINPAINT
);
897 /* Check ifthe window is still valid. */
898 if (!IntGetWindowObject(hWnd
))
903 /* retrieve update region */
904 UpdateRegion
= GetClientUpdateRegion(Window
);
905 if (1 < (DWORD
) Window
->UpdateRegion
)
907 NtGdiDeleteObject(Window
->UpdateRegion
);
909 Window
->UpdateRegion
= 0;
910 if (UpdateRegion
!= NULL
|| (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
912 MsqDecPaintCountQueue(Window
->MessageQueue
);
914 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
916 /* FIXME: Hide caret. */
918 IsIcon
= (Window
->Style
& WS_MINIMIZE
) && IntGetClassLong(Window
, GCL_HICON
, FALSE
);
920 DcxFlags
= DCX_INTERSECTRGN
| DCX_WINDOWPAINT
| DCX_USESTYLE
;
923 DcxFlags
|= DCX_WINDOW
;
925 if (IntGetClassLong(Window
, GCL_STYLE
, FALSE
) & CS_PARENTDC
)
927 /* Don't clip the output to the update region for CS_PARENTDC window */
928 if ((HRGN
) 1 < UpdateRegion
)
930 NtGdiDeleteObject(UpdateRegion
);
933 DcxFlags
&= ~DCX_INTERSECTRGN
;
937 if (NULL
== UpdateRegion
) /* empty region, clip everything */
939 UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
941 else if ((HRGN
) 1 == UpdateRegion
) /* whole client area, don't clip */
944 DcxFlags
&= ~DCX_INTERSECTRGN
;
947 lPs
->hdc
= NtUserGetDCEx(hWnd
, UpdateRegion
, DcxFlags
);
949 /* FIXME: Check for DC creation failure. */
951 IntGetClientRect(Window
, &ClientRect
);
952 NtGdiGetClipBox(lPs
->hdc
, &ClipRect
);
953 NtGdiLPtoDP(lPs
->hdc
, (LPPOINT
)&ClipRect
, 2);
954 NtGdiIntersectRect(&lPs
->rcPaint
, &ClientRect
, &ClipRect
);
955 NtGdiDPtoLP(lPs
->hdc
, (LPPOINT
)&lPs
->rcPaint
, 2);
957 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBACKGRD
)
960 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBACKGRD
;
961 Result
= NtUserSendMessage(hWnd
,
962 IsIcon
? WM_ICONERASEBKGND
: WM_ERASEBKGND
,
965 lPs
->fErase
= !Result
;
972 ObmDereferenceObject(Window
);
978 NtUserInvalidateRect(
983 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
993 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
1002 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
1012 PWINDOW_OBJECT Window
;
1015 if (!(Window
= IntGetWindowObject(hWnd
)))
1017 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1021 if (NULL
== Window
->UpdateRegion
)
1023 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
1025 else if ((HRGN
) 1 == Window
->UpdateRegion
)
1027 RegionType
= (NtGdiSetRectRgn(hRgn
,
1029 Window
->ClientRect
.right
- Window
->ClientRect
.left
,
1030 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
) ?
1031 SIMPLEREGION
: ERROR
);
1035 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
1036 NtGdiOffsetRgn(hRgn
, Window
->WindowRect
.left
- Window
->ClientRect
.left
,
1037 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
1041 (SIMPLEREGION
== RegionType
|| COMPLEXREGION
== RegionType
))
1043 PaintRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
, 0);
1046 IntReleaseWindowObject(Window
);