2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
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);