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
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 ******************************************************************/
38 #define DCX_USESTYLE 0x10000
40 /* PRIVATE FUNCTIONS **********************************************************/
43 IntValidateParent(PWINDOW_OBJECT Child
, HRGN ValidRegion
)
45 PWINDOW_OBJECT ParentWindow
= IntGetParentObject(Child
), OldWindow
;
49 if (!(ParentWindow
->Style
& WS_CLIPCHILDREN
))
51 if (ParentWindow
->UpdateRegion
!= 0)
56 * We must offset the child region by the offset of the
57 * child rect in the parent.
59 OffsetX
= Child
->WindowRect
.left
- ParentWindow
->WindowRect
.left
;
60 OffsetY
= Child
->WindowRect
.top
- ParentWindow
->WindowRect
.top
;
61 NtGdiOffsetRgn(ValidRegion
, OffsetX
, OffsetY
);
62 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
63 ValidRegion
, RGN_DIFF
);
64 /* FIXME: If the resulting region is empty, remove fake posted paint message */
65 NtGdiOffsetRgn(ValidRegion
, -OffsetX
, -OffsetY
);
68 OldWindow
= ParentWindow
;
69 ParentWindow
= IntGetParentObject(ParentWindow
);
70 IntReleaseWindowObject(OldWindow
);
77 * Internal function used by IntRedrawWindow.
81 co_IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
84 HWND hWnd
= Window
->Self
;
87 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
89 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
91 if (Window
->NCUpdateRegion
)
93 IntValidateParent(Window
, Window
->NCUpdateRegion
);
95 TempRegion
= Window
->NCUpdateRegion
;
96 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
98 GDIOBJ_SetOwnership(TempRegion
, PsGetCurrentProcess());
100 Window
->NCUpdateRegion
= NULL
;
101 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
102 MsqDecPaintCountQueue(Window
->MessageQueue
);
103 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
104 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
106 /* NOTE: The region can already be deleted! */
107 GDIOBJ_FreeObj(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
111 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
113 if (Window
->UpdateRegion
)
116 * This surely wrong! Why we would want to validate the parent?
117 * It breaks quite a few things including dummy WM_ERASEBKGND
118 * implementations that return only TRUE and have corresponding
119 * WM_PAINT that doesn't paint the whole client area.
120 * I left the code here so that no one will readd it again!
123 /* IntValidateParent(Window, Window->UpdateRegion); */
124 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
|
125 DCX_INTERSECTUPDATE
);
128 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
130 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
132 UserReleaseDC(Window
, hDC
);
137 if (Flags
& RDW_UPDATENOW
)
139 if (Window
->UpdateRegion
!= NULL
||
140 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
142 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
148 * Check that the window is still valid at this point
151 if (! IntIsWindow(hWnd
))
157 * Paint child windows.
159 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
160 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
164 if ((List
= IntWinListChildren(Window
)))
166 for (phWnd
= List
; *phWnd
; ++phWnd
)
168 Window
= IntGetWindowObject(*phWnd
);
169 if (Window
&& (Window
->Style
& WS_VISIBLE
))
171 co_IntPaintWindows(Window
, Flags
);
172 IntReleaseWindowObject(Window
);
181 * IntInvalidateWindows
183 * Internal function used by IntRedrawWindow.
187 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
190 BOOL HadPaintMessage
, HadNCPaintMessage
;
191 BOOL HasPaintMessage
, HasNCPaintMessage
;
194 * Clip the given region with window rectangle (or region)
197 if (!Window
->WindowRegion
|| (Window
->Style
& WS_MINIMIZE
))
201 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
202 NtGdiOffsetRgn(hRgnWindow
,
203 -Window
->WindowRect
.left
,
204 -Window
->WindowRect
.top
);
205 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
206 NtGdiDeleteObject(hRgnWindow
);
210 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
214 * Save current state of pending updates
217 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
218 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
219 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
222 * Update the region and flags
225 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
227 if (Window
->UpdateRegion
== NULL
)
229 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
230 GDIOBJ_SetOwnership(Window
->UpdateRegion
, NULL
);
233 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
234 hRgn
, RGN_OR
) == NULLREGION
)
236 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
237 NtGdiDeleteObject(Window
->UpdateRegion
);
238 Window
->UpdateRegion
= NULL
;
241 if (Flags
& RDW_FRAME
)
242 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
243 if (Flags
& RDW_ERASE
)
244 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
249 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
251 if (Window
->UpdateRegion
!= NULL
)
253 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
254 hRgn
, RGN_DIFF
) == NULLREGION
)
256 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
257 NtGdiDeleteObject(Window
->UpdateRegion
);
258 Window
->UpdateRegion
= NULL
;
262 if (Window
->UpdateRegion
== NULL
)
263 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
264 if (Flags
& RDW_NOFRAME
)
265 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
266 if (Flags
& RDW_NOERASE
)
267 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
270 if (Flags
& RDW_INTERNALPAINT
)
272 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
275 if (Flags
& RDW_NOINTERNALPAINT
)
277 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
281 * Split the nonclient update region.
284 if (NULL
!= Window
->UpdateRegion
)
286 HRGN hRgnWindow
, hRgnNonClient
;
288 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
289 NtGdiOffsetRgn(hRgnWindow
,
290 -Window
->WindowRect
.left
,
291 -Window
->WindowRect
.top
);
293 hRgnNonClient
= NtGdiCreateRectRgn(0, 0, 0, 0);
294 if (NtGdiCombineRgn(hRgnNonClient
, Window
->UpdateRegion
,
295 hRgnWindow
, RGN_DIFF
) == NULLREGION
)
297 NtGdiDeleteObject(hRgnNonClient
);
298 hRgnNonClient
= NULL
;
302 GDIOBJ_SetOwnership(hRgnNonClient
, NULL
);
306 * Remove the nonclient region from the standard update region.
308 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
309 hRgnWindow
, RGN_AND
) == NULLREGION
)
311 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
312 NtGdiDeleteObject(Window
->UpdateRegion
);
313 Window
->UpdateRegion
= NULL
;
316 if (Window
->NCUpdateRegion
== NULL
)
318 Window
->NCUpdateRegion
= hRgnNonClient
;
322 if(NULL
!= hRgnNonClient
)
324 NtGdiCombineRgn(Window
->NCUpdateRegion
, Window
->NCUpdateRegion
,
325 hRgnNonClient
, RGN_OR
);
326 GDIOBJ_SetOwnership(hRgnNonClient
, PsGetCurrentProcess());
327 NtGdiDeleteObject(hRgnNonClient
);
331 NtGdiDeleteObject(hRgnWindow
);
335 * Process children if needed
338 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
339 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
342 PWINDOW_OBJECT Child
;
344 if ((List
= IntWinListChildren(Window
)))
346 for (phWnd
= List
; *phWnd
; ++phWnd
)
348 Child
= IntGetWindowObject(*phWnd
);
353 if (Child
->Style
& WS_VISIBLE
)
356 * Recursive call to update children UpdateRegion
358 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
359 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
360 NtGdiOffsetRgn(hRgnTemp
,
361 Window
->WindowRect
.left
- Child
->WindowRect
.left
,
362 Window
->WindowRect
.top
- Child
->WindowRect
.top
);
363 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
364 NtGdiDeleteObject(hRgnTemp
);
366 IntReleaseWindowObject(Child
);
373 * Fake post paint messages to window message queue if needed
376 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
377 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
378 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
380 if (HasPaintMessage
!= HadPaintMessage
)
383 MsqDecPaintCountQueue(Window
->MessageQueue
);
385 MsqIncPaintCountQueue(Window
->MessageQueue
);
388 if (HasNCPaintMessage
!= HadNCPaintMessage
)
390 if (HadNCPaintMessage
)
391 MsqDecPaintCountQueue(Window
->MessageQueue
);
393 MsqIncPaintCountQueue(Window
->MessageQueue
);
399 * IntIsWindowDrawable
402 * Window is drawable when it is visible and all parents are not
407 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
409 PWINDOW_OBJECT Old
, Wnd
= Window
;
411 IntReferenceWindowObject(Wnd
);
414 if (!(Wnd
->Style
& WS_VISIBLE
) ||
415 ((Wnd
->Style
& WS_MINIMIZE
) && (Wnd
!= Window
)))
417 IntReleaseWindowObject(Wnd
);
421 Wnd
= IntGetParentObject(Wnd
);
422 IntReleaseWindowObject(Old
);
431 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
436 co_UserRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
443 * Validation of passed parameters.
446 if (!IntIsWindowDrawable(Window
) ||
447 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
448 (RDW_VALIDATE
| RDW_INVALIDATE
))
455 * Transform the parameters UpdateRgn and UpdateRect into
456 * a region hRgn specified in window coordinates.
459 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
461 if (UpdateRgn
!= NULL
)
463 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
464 NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
);
466 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
467 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
469 if (UpdateRect
!= NULL
)
471 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
473 Window
->ClientRect
.left
- Window
->WindowRect
.left
,
474 Window
->ClientRect
.top
- Window
->WindowRect
.top
);
476 if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
477 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
479 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
481 -Window
->WindowRect
.left
,
482 -Window
->WindowRect
.top
);
486 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
488 -Window
->WindowRect
.left
,
489 -Window
->WindowRect
.top
);
495 * Adjust the window update region depending on hRgn and flags.
498 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
))
500 IntInvalidateWindows(Window
, hRgn
, Flags
);
505 * Repaint and erase windows if needed.
508 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
510 co_IntPaintWindows(Window
, Flags
);
520 NtGdiDeleteObject(hRgn
);
527 IntIsWindowDirty(PWINDOW_OBJECT Window
)
529 return (Window
->Style
& WS_VISIBLE
) &&
530 ((Window
->UpdateRegion
!= NULL
) ||
531 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
) ||
532 (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
));
536 IntFindWindowToRepaint(HWND hWnd
, PW32THREAD Thread
)
538 PWINDOW_OBJECT Window
;
539 PWINDOW_OBJECT Child
;
540 HWND hFoundWnd
= NULL
;
542 Window
= IntGetWindowObject(hWnd
);
546 if (IntIsWindowDirty(Window
) &&
547 IntWndBelongsToThread(Window
, Thread
))
549 IntReleaseWindowObject(Window
);
553 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
555 if (IntIsWindowDirty(Child
) &&
556 IntWndBelongsToThread(Child
, Thread
))
558 hFoundWnd
= Child
->Self
;
563 if (hFoundWnd
== NULL
)
568 List
= IntWinListChildren(Window
);
571 for (i
= 0; List
[i
]; i
++)
573 hFoundWnd
= IntFindWindowToRepaint(List
[i
], Thread
);
574 if (hFoundWnd
!= NULL
)
581 IntReleaseWindowObject(Window
);
587 IntGetPaintMessage(HWND hWnd
, UINT MsgFilterMin
, UINT MsgFilterMax
,
588 PW32THREAD Thread
, MSG
*Message
, BOOL Remove
)
590 PWINDOW_OBJECT Window
;
591 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
593 if (!MessageQueue
->PaintPosted
)
596 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
597 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
601 Message
->hwnd
= IntFindWindowToRepaint(hWnd
, PsGetWin32Thread());
603 Message
->hwnd
= IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
605 if (Message
->hwnd
== NULL
)
609 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
610 MessageQueue
->PaintPosted
= 0;
611 MessageQueue
->PaintCount
= 0;
616 Window
= IntGetWindowObject(Message
->hwnd
);
619 Message
->message
= WM_PAINT
;
620 Message
->wParam
= Message
->lParam
= 0;
621 IntReleaseWindowObject(Window
);
631 co_IntFixCaret(HWND hWnd
, LPRECT lprc
, UINT flags
)
633 PDESKTOP_OBJECT Desktop
;
634 PTHRDCARETINFO CaretInfo
;
637 Desktop
= PsGetCurrentThread()->Tcb
.Win32Thread
->Desktop
;
638 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
639 hWndCaret
= CaretInfo
->hWnd
;
640 if (hWndCaret
== hWnd
||
641 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(hWnd
, hWndCaret
)))
643 POINT pt
, FromOffset
, ToOffset
, Offset
;
646 pt
.x
= CaretInfo
->Pos
.x
;
647 pt
.y
= CaretInfo
->Pos
.y
;
648 IntGetClientOrigin(hWndCaret
, &FromOffset
);
649 IntGetClientOrigin(hWnd
, &ToOffset
);
650 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
651 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
654 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
655 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
656 if (IntGdiIntersectRect(lprc
, lprc
, &rcCaret
))
668 /* PUBLIC FUNCTIONS ***********************************************************/
678 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
680 PWINDOW_OBJECT Window
;
686 DPRINT("Enter NtUserBeginPaint\n");
687 UserEnterExclusive();
689 if (!(Window
= IntGetWindowObject(hWnd
)))
691 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
695 co_UserHideCaret(Window
);
697 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
701 if (Window
->NCUpdateRegion
!= (HANDLE
)1 &&
702 Window
->NCUpdateRegion
!= NULL
)
704 GDIOBJ_SetOwnership(Window
->NCUpdateRegion
, PsGetCurrentProcess());
706 hRgn
= Window
->NCUpdateRegion
;
707 IntValidateParent(Window
, Window
->NCUpdateRegion
);
708 Window
->NCUpdateRegion
= NULL
;
709 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
710 MsqDecPaintCountQueue(Window
->MessageQueue
);
711 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
712 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
714 /* NOTE: The region can already by deleted! */
715 GDIOBJ_FreeObj(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
719 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
721 Ps
.hdc
= UserGetDCEx(Window
, 0, DCX_INTERSECTUPDATE
| DCX_WINDOWPAINT
| DCX_USESTYLE
);
725 IntReleaseWindowObject(Window
);
729 if (Window
->UpdateRegion
!= NULL
)
731 MsqDecPaintCountQueue(Window
->MessageQueue
);
732 IntValidateParent(Window
, Window
->UpdateRegion
);
733 Rgn
= RGNDATA_LockRgn(Window
->UpdateRegion
);
736 UnsafeIntGetRgnBox(Rgn
, &Ps
.rcPaint
);
737 RGNDATA_UnlockRgn(Rgn
);
738 IntGdiOffsetRect(&Ps
.rcPaint
,
739 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
740 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
744 IntGetClientRect(Window
, &Ps
.rcPaint
);
746 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
747 NtGdiDeleteObject(Window
->UpdateRegion
);
748 Window
->UpdateRegion
= NULL
;
752 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
753 MsqDecPaintCountQueue(Window
->MessageQueue
);
754 IntGetClientRect(Window
, &Ps
.rcPaint
);
756 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
758 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
760 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
761 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
768 IntReleaseWindowObject(Window
);
770 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
771 if (! NT_SUCCESS(Status
))
773 SetLastNtError(Status
);
780 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
794 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
796 PWINDOW_OBJECT Window
;
797 DECLARE_RETURN(BOOL
);
799 DPRINT("Enter NtUserEndPaint\n");
800 UserEnterExclusive();
802 if (!(Window
= IntGetWindowObject(hWnd
)))
807 UserReleaseDC(Window
, lPs
->hdc
);
808 co_UserShowCaret(Window
);
810 IntReleaseWindowObject(Window
); //temp hack
815 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
821 * NtUserInvalidateRect
828 NtUserInvalidateRect(HWND hWnd
, CONST RECT
*Rect
, BOOL Erase
)
830 return NtUserRedrawWindow(hWnd
, Rect
, 0, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
834 * NtUserInvalidateRgn
841 NtUserInvalidateRgn(HWND hWnd
, HRGN Rgn
, BOOL Erase
)
843 return NtUserRedrawWindow(hWnd
, NULL
, Rgn
, RDW_INVALIDATE
| (Erase
? RDW_ERASE
: 0));
849 UserValidateRgn(HWND hWnd
, HRGN hRgn
)
851 PWINDOW_OBJECT Window
;
854 if (!(Window
= IntGetWindowObject(hWnd
))) return FALSE
;
855 ret
= co_UserRedrawWindow(Window
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
856 IntReleaseWindowObject(Window
);//temp hack
868 NtUserValidateRgn(HWND hWnd
, HRGN hRgn
)
870 return NtUserRedrawWindow(hWnd
, NULL
, hRgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
881 NtUserUpdateWindow(HWND hWnd
)
883 return NtUserRedrawWindow(hWnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
891 co_UserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
893 PWINDOW_OBJECT Window
;
896 if (!(Window
= IntGetWindowObject(hWnd
)))
898 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
902 if (Window
->UpdateRegion
== NULL
)
904 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
908 RegionType
= NtGdiCombineRgn(hRgn
, Window
->UpdateRegion
, hRgn
, RGN_COPY
);
911 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
912 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
915 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
917 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
920 IntReleaseWindowObject(Window
);
932 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
936 DPRINT("Enter NtUserGetUpdateRgn\n");
937 UserEnterExclusive();
939 RETURN(co_UserGetUpdateRgn(hWnd
, hRgn
, bErase
));
942 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
948 * NtUserGetUpdateRect
955 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
957 PWINDOW_OBJECT Window
;
963 DECLARE_RETURN(BOOL
);
965 DPRINT("Enter NtUserGetUpdateRect\n");
966 UserEnterExclusive();
968 if (!(Window
= IntGetWindowObject(hWnd
)))
970 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
974 if (Window
->UpdateRegion
== NULL
)
976 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
980 RgnData
= RGNDATA_LockRgn(Window
->UpdateRegion
);
981 ASSERT(RgnData
!= NULL
);
982 RegionType
= UnsafeIntGetRgnBox(RgnData
, &Rect
);
983 ASSERT(RegionType
!= ERROR
);
984 RGNDATA_UnlockRgn(RgnData
);
986 AlwaysPaint
= (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
) ||
987 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
);
989 if (bErase
&& Rect
.left
< Rect
.right
&& Rect
.top
< Rect
.bottom
)
991 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
994 IntReleaseWindowObject(Window
);
996 if (UnsafeRect
!= NULL
)
998 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECT
));
999 if (!NT_SUCCESS(Status
))
1001 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1006 RETURN( (Rect
.left
< Rect
.right
&& Rect
.top
< Rect
.bottom
) || AlwaysPaint
);
1009 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1015 * NtUserRedrawWindow
1022 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
1025 RECT SafeUpdateRect
;
1028 DECLARE_RETURN(BOOL
);
1030 DPRINT("Enter NtUserRedrawWindow\n");
1031 UserEnterExclusive();
1033 if (!(Wnd
= IntGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1035 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1039 if (lprcUpdate
!= NULL
)
1041 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
1044 if (!NT_SUCCESS(Status
))
1046 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1047 IntReleaseWindowObject(Wnd
);
1052 Status
= co_UserRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
1055 if (!NT_SUCCESS(Status
))
1057 /* IntRedrawWindow fails only in case that flags are invalid */
1058 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1059 IntReleaseWindowObject(Wnd
);
1063 IntReleaseWindowObject(Wnd
);
1067 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1076 UserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1077 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1079 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
1083 * Compute device clipping region (in device coordinates).
1086 DC
= DC_LockDc(hDC
);
1094 IntGdiGetClipBox(hDC
, &rSrc
);
1095 IntLPtoDP(DC
, (LPPOINT
)&rSrc
, 2);
1100 IntGdiGetClipBox(hDC
, &rClip
);
1101 IntLPtoDP(DC
, (LPPOINT
)&rClip
, 2);
1103 IntGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
1105 rDst
= rClipped_src
;
1106 IntGdiSetRect(&offset
, 0, 0, dx
, dy
);
1107 IntLPtoDP(DC
, (LPPOINT
)&offset
, 2);
1108 IntGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1109 IntGdiIntersectRect(&rDst
, &rDst
, &rClip
);
1112 * Copy bits, if possible.
1115 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1117 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1119 IntGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1120 IntDPtoLP(DC
, (LPPOINT
)&rDst_lp
, 2);
1121 IntDPtoLP(DC
, (LPPOINT
)&rSrc_lp
, 2);
1124 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1125 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1135 * Compute update areas. This is the clipped source or'ed with the
1136 * unclipped source translated minus the clipped src translated (rDst)
1137 * all clipped to rClip.
1140 if (hrgnUpdate
|| lprcUpdate
)
1142 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1145 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1147 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1149 hRgn2
= UnsafeIntCreateRectRgnIndirect(&rSrc
);
1150 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1151 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1153 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1154 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1156 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1157 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1161 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1163 /* Put the lprcUpdate in logical coordinate */
1164 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1167 NtGdiDeleteObject(hRgn
);
1168 NtGdiDeleteObject(hRgn2
);
1184 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1185 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1187 DECLARE_RETURN(DWORD
);
1189 DPRINT("Enter NtUserScrollDC\n");
1190 UserEnterExclusive();
1192 RETURN( UserScrollDC(hDC
, dx
, dy
, lprcScroll
, lprcClip
, hrgnUpdate
, lprcUpdate
));
1195 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1202 * NtUserScrollWindowEx
1209 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*UnsafeRect
,
1210 const RECT
*UnsafeClipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1212 RECT rc
, cliprc
, caretrc
, rect
, clipRect
;
1214 PWINDOW_OBJECT Window
, CaretWnd
;
1218 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1219 BOOL bOwnRgn
= TRUE
;
1221 DECLARE_RETURN(DWORD
);
1223 DPRINT("Enter NtUserScrollWindowEx\n");
1224 UserEnterExclusive();
1226 Window
= IntGetWindowObject(hWnd
);
1227 if (!Window
|| !IntIsWindowDrawable(Window
))
1229 IntReleaseWindowObject(Window
);
1233 IntGetClientRect(Window
, &rc
);
1234 if (NULL
!= UnsafeRect
)
1236 Status
= MmCopyFromCaller(&rect
, UnsafeRect
, sizeof(RECT
));
1237 if (! NT_SUCCESS(Status
))
1239 SetLastNtError(Status
);
1242 IntGdiIntersectRect(&rc
, &rc
, &rect
);
1245 if (NULL
!= UnsafeClipRect
)
1247 Status
= MmCopyFromCaller(&clipRect
, UnsafeClipRect
, sizeof(RECT
));
1248 if (! NT_SUCCESS(Status
))
1250 SetLastNtError(Status
);
1253 IntGdiIntersectRect(&cliprc
, &rc
, &clipRect
);
1258 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1259 (dx
== 0 && dy
== 0))
1261 RETURN( NULLREGION
);
1265 hwndCaret
= co_IntFixCaret(hWnd
, &caretrc
, flags
);
1270 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1272 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1275 UserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1276 UserReleaseDC(Window
, hDC
);
1280 * Take into account the fact that some damage may have occurred during
1284 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1285 Result
= co_UserGetUpdateRgn(hWnd
, hrgnTemp
, FALSE
);
1286 if (Result
!= NULLREGION
)
1288 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&cliprc
);
1289 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1290 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1291 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1292 NtGdiDeleteObject(hrgnClip
);
1294 NtGdiDeleteObject(hrgnTemp
);
1296 if (flags
& SW_SCROLLCHILDREN
)
1298 HWND
*List
= IntWinListChildren(Window
);
1304 PWINDOW_OBJECT WindowObject
;
1306 IntGetClientOrigin(hWnd
, &ClientOrigin
);
1307 for (i
= 0; List
[i
]; i
++)
1309 WindowObject
= IntGetWindowObject(List
[i
]);
1310 if (!WindowObject
) continue;
1311 r
= WindowObject
->WindowRect
;
1312 r
.left
-= ClientOrigin
.x
;
1313 r
.top
-= ClientOrigin
.y
;
1314 r
.right
-= ClientOrigin
.x
;
1315 r
.bottom
-= ClientOrigin
.y
;
1316 IntReleaseWindowObject(WindowObject
);
1317 if (! UnsafeRect
|| IntGdiIntersectRect(&dummy
, &r
, &rc
))
1318 co_WinPosSetWindowPos(List
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1319 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1326 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1327 co_UserRedrawWindow(Window
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1328 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1329 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1331 if (bOwnRgn
&& hrgnUpdate
)
1332 NtGdiDeleteObject(hrgnUpdate
);
1334 if ((CaretWnd
= IntGetWindowObject(hwndCaret
)))
1336 co_IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1337 co_UserShowCaret(CaretWnd
);
1338 IntReleaseWindowObject(CaretWnd
);
1341 IntReleaseWindowObject(Window
);
1346 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);