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 /* PRIVATE FUNCTIONS **********************************************************/
41 * @name IntIntersectWithParents
43 * Intersect window rectangle with all parent client rectangles.
46 * Pointer to child window to start intersecting from.
48 * Pointer to rectangle that we want to intersect in screen
49 * coordinates on input and intersected rectangle on output (if TRUE
53 * If any parent is minimized or invisible or the resulting rectangle
54 * is empty then FALSE is returned. Otherwise TRUE is returned.
58 IntIntersectWithParents(PWINDOW_OBJECT Child
, PRECT WindowRect
)
60 PWINDOW_OBJECT ParentWindow
;
62 ParentWindow
= Child
->Parent
;
63 while (ParentWindow
!= NULL
)
65 if (!(ParentWindow
->Style
& WS_VISIBLE
) ||
66 (ParentWindow
->Style
& WS_MINIMIZE
))
71 if (!IntGdiIntersectRect(WindowRect
, WindowRect
, &ParentWindow
->ClientRect
))
76 /* FIXME: Layered windows. */
78 ParentWindow
= ParentWindow
->Parent
;
85 IntValidateParent(PWINDOW_OBJECT Child
, HRGN ValidRegion
)
87 PWINDOW_OBJECT ParentWindow
= Child
->Parent
;
91 if (ParentWindow
->Style
& WS_CLIPCHILDREN
)
94 if (ParentWindow
->UpdateRegion
!= 0)
96 NtGdiCombineRgn(ParentWindow
->UpdateRegion
, ParentWindow
->UpdateRegion
,
97 ValidRegion
, RGN_DIFF
);
98 /* FIXME: If the resulting region is empty, remove fake posted paint message */
101 ParentWindow
= ParentWindow
->Parent
;
106 * @name IntCalcWindowRgn
108 * Get a window or client region.
112 IntCalcWindowRgn(PWINDOW_OBJECT Window
, BOOL Client
)
118 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
120 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
122 if (Window
->WindowRegion
!= NULL
&& !(Window
->Style
& WS_MINIMIZE
))
124 NtGdiOffsetRgn(hRgnWindow
,
125 -Window
->WindowRect
.left
,
126 -Window
->WindowRect
.top
);
127 RgnType
= NtGdiCombineRgn(hRgnWindow
, hRgnWindow
, Window
->WindowRegion
, RGN_AND
);
128 NtGdiOffsetRgn(hRgnWindow
,
129 Window
->WindowRect
.left
,
130 Window
->WindowRect
.top
);
137 * @name IntGetNCUpdateRgn
139 * Get non-client update region of a window and optionally validate it.
142 * Pointer to window to get the NC update region from.
144 * Set to TRUE to force validating the NC update region.
147 * Handle to NC update region. The caller is responsible for deleting
152 IntGetNCUpdateRgn(PWINDOW_OBJECT Window
, BOOL Validate
)
158 if (Window
->UpdateRegion
!= NULL
&&
159 Window
->UpdateRegion
!= (HRGN
)1)
161 hRgnNonClient
= NtGdiCreateRectRgn(0, 0, 0, 0);
162 hRgnWindow
= IntCalcWindowRgn(Window
, TRUE
);
165 * If region creation fails it's safe to fallback to whole
169 if (hRgnNonClient
== NULL
)
174 RgnType
= NtGdiCombineRgn(hRgnNonClient
, Window
->UpdateRegion
,
175 hRgnWindow
, RGN_DIFF
);
176 if (RgnType
== ERROR
)
178 NtGdiDeleteObject(hRgnNonClient
);
181 else if (RgnType
== NULLREGION
)
183 NtGdiDeleteObject(hRgnNonClient
);
188 * Remove the nonclient region from the standard update region if
189 * we were asked for it.
194 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
195 hRgnWindow
, RGN_AND
) == NULLREGION
)
197 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
198 NtGdiDeleteObject(Window
->UpdateRegion
);
199 Window
->UpdateRegion
= NULL
;
200 if (!(Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
))
201 MsqDecPaintCountQueue(Window
->MessageQueue
);
205 NtGdiDeleteObject(hRgnWindow
);
207 return hRgnNonClient
;
211 return Window
->UpdateRegion
;
218 * Internal function used by IntRedrawWindow.
222 co_IntPaintWindows(PWINDOW_OBJECT Window
, ULONG Flags
)
225 HWND hWnd
= Window
->hSelf
;
228 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
230 if (Window
->UpdateRegion
)
232 IntValidateParent(Window
, Window
->UpdateRegion
);
235 if (Flags
& RDW_UPDATENOW
)
237 if (Window
->UpdateRegion
!= NULL
||
238 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
240 co_IntSendMessage(hWnd
, WM_PAINT
, 0, 0);
245 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
247 TempRegion
= IntGetNCUpdateRgn(Window
, TRUE
);
248 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
249 MsqDecPaintCountQueue(Window
->MessageQueue
);
250 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)TempRegion
, 0);
251 if ((HANDLE
) 1 != TempRegion
&& NULL
!= TempRegion
)
253 /* NOTE: The region can already be deleted! */
254 GDIOBJ_FreeObj(TempRegion
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
258 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
260 if (Window
->UpdateRegion
)
262 hDC
= UserGetDCEx(Window
, Window
->UpdateRegion
,
263 DCX_CACHE
| DCX_USESTYLE
|
264 DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
);
265 if (co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)hDC
, 0))
267 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
269 UserReleaseDC(Window
, hDC
, FALSE
);
276 * Check that the window is still valid at this point
278 if (!IntIsWindow(hWnd
))
284 * Paint child windows.
286 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
287 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
291 if ((List
= IntWinListChildren(Window
)))
293 for (phWnd
= List
; *phWnd
; ++phWnd
)
295 Window
= UserGetWindowObject(*phWnd
);
296 if (Window
&& (Window
->Style
& WS_VISIBLE
))
298 USER_REFERENCE_ENTRY Ref
;
299 UserRefObjectCo(Window
, &Ref
);
300 co_IntPaintWindows(Window
, Flags
);
301 UserDerefObjectCo(Window
);
310 * IntInvalidateWindows
312 * Internal function used by IntRedrawWindow.
316 IntInvalidateWindows(PWINDOW_OBJECT Window
, HRGN hRgn
, ULONG Flags
)
319 BOOL HadPaintMessage
, HadNCPaintMessage
;
320 BOOL HasPaintMessage
, HasNCPaintMessage
;
323 * If the nonclient is not to be redrawn, clip the region to the client
326 if (0 != (Flags
& RDW_INVALIDATE
) && 0 == (Flags
& RDW_FRAME
))
330 hRgnClient
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
331 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnClient
, RGN_AND
);
332 NtGdiDeleteObject(hRgnClient
);
336 * Clip the given region with window rectangle (or region)
339 if (!Window
->WindowRegion
|| (Window
->Style
& WS_MINIMIZE
))
343 hRgnWindow
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
344 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, hRgnWindow
, RGN_AND
);
345 NtGdiDeleteObject(hRgnWindow
);
350 -Window
->WindowRect
.left
,
351 -Window
->WindowRect
.top
);
352 RgnType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->WindowRegion
, RGN_AND
);
354 Window
->WindowRect
.left
,
355 Window
->WindowRect
.top
);
359 * Save current state of pending updates
362 HadPaintMessage
= Window
->UpdateRegion
!= NULL
||
363 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
364 HadNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
367 * Update the region and flags
370 if (Flags
& RDW_INVALIDATE
&& RgnType
!= NULLREGION
)
372 if (Window
->UpdateRegion
== NULL
)
374 Window
->UpdateRegion
= NtGdiCreateRectRgn(0, 0, 0, 0);
375 GDIOBJ_SetOwnership(Window
->UpdateRegion
, NULL
);
378 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
379 hRgn
, RGN_OR
) == NULLREGION
)
381 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
382 NtGdiDeleteObject(Window
->UpdateRegion
);
383 Window
->UpdateRegion
= NULL
;
386 if (Flags
& RDW_FRAME
)
387 Window
->Flags
|= WINDOWOBJECT_NEED_NCPAINT
;
388 if (Flags
& RDW_ERASE
)
389 Window
->Flags
|= WINDOWOBJECT_NEED_ERASEBKGND
;
394 if (Flags
& RDW_VALIDATE
&& RgnType
!= NULLREGION
)
396 if (Window
->UpdateRegion
!= NULL
)
398 if (NtGdiCombineRgn(Window
->UpdateRegion
, Window
->UpdateRegion
,
399 hRgn
, RGN_DIFF
) == NULLREGION
)
401 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
402 NtGdiDeleteObject(Window
->UpdateRegion
);
403 Window
->UpdateRegion
= NULL
;
407 if (Window
->UpdateRegion
== NULL
)
408 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
409 if (Flags
& RDW_NOFRAME
)
410 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
411 if (Flags
& RDW_NOERASE
)
412 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
415 if (Flags
& RDW_INTERNALPAINT
)
417 Window
->Flags
|= WINDOWOBJECT_NEED_INTERNALPAINT
;
420 if (Flags
& RDW_NOINTERNALPAINT
)
422 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
426 * Process children if needed
429 if (!(Flags
& RDW_NOCHILDREN
) && !(Window
->Style
& WS_MINIMIZE
) &&
430 ((Flags
& RDW_ALLCHILDREN
) || !(Window
->Style
& WS_CLIPCHILDREN
)))
432 PWINDOW_OBJECT Child
;
434 for (Child
= Window
->FirstChild
; Child
; Child
= Child
->NextSibling
)
436 if (Child
->Style
& WS_VISIBLE
)
439 * Recursive call to update children UpdateRegion
441 HRGN hRgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
442 NtGdiCombineRgn(hRgnTemp
, hRgn
, 0, RGN_COPY
);
443 IntInvalidateWindows(Child
, hRgnTemp
, Flags
);
444 NtGdiDeleteObject(hRgnTemp
);
451 * Fake post paint messages to window message queue if needed
454 HasPaintMessage
= Window
->UpdateRegion
!= NULL
||
455 Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
;
456 HasNCPaintMessage
= Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
;
458 if (HasPaintMessage
!= HadPaintMessage
)
461 MsqDecPaintCountQueue(Window
->MessageQueue
);
463 MsqIncPaintCountQueue(Window
->MessageQueue
);
466 if (HasNCPaintMessage
!= HadNCPaintMessage
)
468 if (HadNCPaintMessage
)
469 MsqDecPaintCountQueue(Window
->MessageQueue
);
471 MsqIncPaintCountQueue(Window
->MessageQueue
);
477 * IntIsWindowDrawable
480 * Window is drawable when it is visible and all parents are not
485 IntIsWindowDrawable(PWINDOW_OBJECT Window
)
489 for (Wnd
= Window
; Wnd
!= NULL
; Wnd
= Wnd
->Parent
)
491 if (!(Wnd
->Style
& WS_VISIBLE
) ||
492 ((Wnd
->Style
& WS_MINIMIZE
) && (Wnd
!= Window
)))
504 * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
509 co_UserRedrawWindow(PWINDOW_OBJECT Window
, const RECT
* UpdateRect
, HRGN UpdateRgn
,
516 * Validation of passed parameters.
519 if (!IntIsWindowDrawable(Window
) ||
520 (Flags
& (RDW_VALIDATE
| RDW_INVALIDATE
)) ==
521 (RDW_VALIDATE
| RDW_INVALIDATE
))
528 * Transform the parameters UpdateRgn and UpdateRect into
529 * a region hRgn specified in screen coordinates.
532 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
))
534 if (UpdateRgn
!= NULL
)
536 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
537 if (NtGdiCombineRgn(hRgn
, UpdateRgn
, NULL
, RGN_COPY
) == NULLREGION
)
538 NtGdiDeleteObject(hRgn
);
540 NtGdiOffsetRgn(hRgn
, Window
->ClientRect
.left
, Window
->ClientRect
.top
);
542 else if (UpdateRect
!= NULL
)
544 if (!IntGdiIsEmptyRect(UpdateRect
))
546 hRgn
= UnsafeIntCreateRectRgnIndirect((RECT
*)UpdateRect
);
547 NtGdiOffsetRgn(hRgn
, Window
->ClientRect
.left
, Window
->ClientRect
.top
);
550 else if ((Flags
& (RDW_INVALIDATE
| RDW_FRAME
)) == (RDW_INVALIDATE
| RDW_FRAME
) ||
551 (Flags
& (RDW_VALIDATE
| RDW_NOFRAME
)) == (RDW_VALIDATE
| RDW_NOFRAME
))
553 if (!IntGdiIsEmptyRect(&Window
->WindowRect
))
554 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->WindowRect
);
558 if (!IntGdiIsEmptyRect(&Window
->ClientRect
))
559 hRgn
= UnsafeIntCreateRectRgnIndirect(&Window
->ClientRect
);
565 * Adjust the window update region depending on hRgn and flags.
568 if (Flags
& (RDW_INVALIDATE
| RDW_VALIDATE
| RDW_INTERNALPAINT
| RDW_NOINTERNALPAINT
) &&
571 IntInvalidateWindows(Window
, hRgn
, Flags
);
576 * Repaint and erase windows if needed.
579 if (Flags
& (RDW_ERASENOW
| RDW_UPDATENOW
))
581 co_IntPaintWindows(Window
, Flags
);
591 NtGdiDeleteObject(hRgn
);
598 IntIsWindowDirty(PWINDOW_OBJECT Window
)
600 return (Window
->Style
& WS_VISIBLE
) &&
601 ((Window
->UpdateRegion
!= NULL
) ||
602 (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
) ||
603 (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
));
607 IntFindWindowToRepaint(PWINDOW_OBJECT Window
, PW32THREAD Thread
)
610 PWINDOW_OBJECT TempWindow
;
612 for (; Window
!= NULL
; Window
= Window
->NextSibling
)
614 if (IntWndBelongsToThread(Window
, Thread
) &&
615 IntIsWindowDirty(Window
))
617 /* Make sure all non-transparent siblings are already drawn. */
618 if (Window
->ExStyle
& WS_EX_TRANSPARENT
)
620 for (TempWindow
= Window
->NextSibling
; TempWindow
!= NULL
;
621 TempWindow
= TempWindow
->NextSibling
)
623 if (!(TempWindow
->ExStyle
& WS_EX_TRANSPARENT
) &&
624 IntWndBelongsToThread(TempWindow
, Thread
) &&
625 IntIsWindowDirty(TempWindow
))
627 return TempWindow
->hSelf
;
632 return Window
->hSelf
;
635 if (Window
->FirstChild
)
637 hChild
= IntFindWindowToRepaint(Window
->FirstChild
, Thread
);
647 IntGetPaintMessage(HWND hWnd
, UINT MsgFilterMin
, UINT MsgFilterMax
,
648 PW32THREAD Thread
, MSG
*Message
, BOOL Remove
)
650 PUSER_MESSAGE_QUEUE MessageQueue
= (PUSER_MESSAGE_QUEUE
)Thread
->MessageQueue
;
652 if (!MessageQueue
->PaintCount
)
655 if ((MsgFilterMin
!= 0 || MsgFilterMax
!= 0) &&
656 (MsgFilterMin
> WM_PAINT
|| MsgFilterMax
< WM_PAINT
))
659 Message
->hwnd
= IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetWin32Thread());
661 if (Message
->hwnd
== NULL
)
663 DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
667 if (hWnd
!= NULL
&& Message
->hwnd
!= hWnd
)
670 Message
->message
= WM_PAINT
;
671 Message
->wParam
= Message
->lParam
= 0;
678 co_IntFixCaret(PWINDOW_OBJECT Window
, LPRECT lprc
, UINT flags
)
680 PDESKTOP_OBJECT Desktop
;
681 PTHRDCARETINFO CaretInfo
;
683 PWINDOW_OBJECT WndCaret
;
685 ASSERT_REFS_CO(Window
);
687 Desktop
= ((PW32THREAD
)PsGetCurrentThread()->Tcb
.Win32Thread
)->Desktop
;
688 CaretInfo
= ((PUSER_MESSAGE_QUEUE
)Desktop
->ActiveMessageQueue
)->CaretInfo
;
689 hWndCaret
= CaretInfo
->hWnd
;
691 WndCaret
= UserGetWindowObject(hWndCaret
);
693 //fix: check for WndCaret can be null
694 if (WndCaret
== Window
||
695 ((flags
& SW_SCROLLCHILDREN
) && IntIsChildWindow(Window
, WndCaret
)))
697 POINT pt
, FromOffset
, ToOffset
, Offset
;
700 pt
.x
= CaretInfo
->Pos
.x
;
701 pt
.y
= CaretInfo
->Pos
.y
;
702 IntGetClientOrigin(WndCaret
, &FromOffset
);
703 IntGetClientOrigin(Window
, &ToOffset
);
704 Offset
.x
= FromOffset
.x
- ToOffset
.x
;
705 Offset
.y
= FromOffset
.y
- ToOffset
.y
;
708 rcCaret
.right
= pt
.x
+ CaretInfo
->Size
.cx
;
709 rcCaret
.bottom
= pt
.y
+ CaretInfo
->Size
.cy
;
710 if (IntGdiIntersectRect(lprc
, lprc
, &rcCaret
))
722 /* PUBLIC FUNCTIONS ***********************************************************/
732 NtUserBeginPaint(HWND hWnd
, PAINTSTRUCT
* UnsafePs
)
734 PWINDOW_OBJECT Window
= NULL
;
739 USER_REFERENCE_ENTRY Ref
;
741 DPRINT("Enter NtUserBeginPaint\n");
742 UserEnterExclusive();
744 if (!(Window
= UserGetWindowObject(hWnd
)))
749 UserRefObjectCo(Window
, &Ref
);
751 co_UserHideCaret(Window
);
753 if (Window
->Flags
& WINDOWOBJECT_NEED_NCPAINT
)
757 hRgn
= IntGetNCUpdateRgn(Window
, FALSE
);
758 Window
->Flags
&= ~WINDOWOBJECT_NEED_NCPAINT
;
759 MsqDecPaintCountQueue(Window
->MessageQueue
);
760 co_IntSendMessage(hWnd
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
761 if (hRgn
!= (HANDLE
)1 && hRgn
!= NULL
)
763 /* NOTE: The region can already by deleted! */
764 GDIOBJ_FreeObj(hRgn
, GDI_OBJECT_TYPE_REGION
| GDI_OBJECT_TYPE_SILENT
);
768 RtlZeroMemory(&Ps
, sizeof(PAINTSTRUCT
));
770 Ps
.hdc
= UserGetDCEx(Window
, Window
->UpdateRegion
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
776 if (Window
->UpdateRegion
!= NULL
)
778 MsqDecPaintCountQueue(Window
->MessageQueue
);
779 Rgn
= RGNDATA_LockRgn(Window
->UpdateRegion
);
782 UnsafeIntGetRgnBox(Rgn
, &Ps
.rcPaint
);
783 RGNDATA_UnlockRgn(Rgn
);
784 IntGdiIntersectRect(&Ps
.rcPaint
, &Ps
.rcPaint
, &Window
->ClientRect
);
785 if (! IntGdiIsEmptyRect(&Ps
.rcPaint
))
787 IntGdiOffsetRect(&Ps
.rcPaint
,
788 -Window
->ClientRect
.left
,
789 -Window
->ClientRect
.top
);
794 IntGetClientRect(Window
, &Ps
.rcPaint
);
796 GDIOBJ_SetOwnership(Window
->UpdateRegion
, PsGetCurrentProcess());
797 Window
->UpdateRegion
= NULL
;
801 if (Window
->Flags
& WINDOWOBJECT_NEED_INTERNALPAINT
)
802 MsqDecPaintCountQueue(Window
->MessageQueue
);
804 IntGetClientRect(Window
, &Ps
.rcPaint
);
807 Window
->Flags
&= ~WINDOWOBJECT_NEED_INTERNALPAINT
;
809 if (Window
->Flags
& WINDOWOBJECT_NEED_ERASEBKGND
)
811 Window
->Flags
&= ~WINDOWOBJECT_NEED_ERASEBKGND
;
812 Ps
.fErase
= !co_IntSendMessage(hWnd
, WM_ERASEBKGND
, (WPARAM
)Ps
.hdc
, 0);
819 Status
= MmCopyToCaller(UnsafePs
, &Ps
, sizeof(PAINTSTRUCT
));
820 if (! NT_SUCCESS(Status
))
822 SetLastNtError(Status
);
829 if (Window
) UserDerefObjectCo(Window
);
831 DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_
);
845 NtUserEndPaint(HWND hWnd
, CONST PAINTSTRUCT
* lPs
)
847 PWINDOW_OBJECT Window
;
848 DECLARE_RETURN(BOOL
);
849 USER_REFERENCE_ENTRY Ref
;
851 DPRINT("Enter NtUserEndPaint\n");
852 UserEnterExclusive();
854 if (!(Window
= UserGetWindowObject(hWnd
)))
859 UserReleaseDC(Window
, lPs
->hdc
, TRUE
);
861 UserRefObjectCo(Window
, &Ref
);
862 co_UserShowCaret(Window
);
863 UserDerefObjectCo(Window
);
868 DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_
);
875 co_UserGetUpdateRgn(PWINDOW_OBJECT Window
, HRGN hRgn
, BOOL bErase
)
880 ASSERT_REFS_CO(Window
);
882 if (Window
->UpdateRegion
== NULL
)
884 RegionType
= (NtGdiSetRectRgn(hRgn
, 0, 0, 0, 0) ? NULLREGION
: ERROR
);
888 Rect
= Window
->ClientRect
;
889 IntIntersectWithParents(Window
, &Rect
);
890 NtGdiSetRectRgn(hRgn
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
891 RegionType
= NtGdiCombineRgn(hRgn
, hRgn
, Window
->UpdateRegion
, RGN_AND
);
892 NtGdiOffsetRgn(hRgn
, -Window
->ClientRect
.left
, -Window
->ClientRect
.top
);
895 if (bErase
&& RegionType
!= NULLREGION
&& RegionType
!= ERROR
)
897 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
911 NtUserGetUpdateRgn(HWND hWnd
, HRGN hRgn
, BOOL bErase
)
914 PWINDOW_OBJECT Window
;
916 USER_REFERENCE_ENTRY Ref
;
918 DPRINT("Enter NtUserGetUpdateRgn\n");
919 UserEnterExclusive();
921 if (!(Window
= UserGetWindowObject(hWnd
)))
926 UserRefObjectCo(Window
, &Ref
);
927 ret
= co_UserGetUpdateRgn(Window
, hRgn
, bErase
);
928 UserDerefObjectCo(Window
);
933 DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_
);
939 * NtUserGetUpdateRect
946 NtUserGetUpdateRect(HWND hWnd
, LPRECT UnsafeRect
, BOOL bErase
)
948 PWINDOW_OBJECT Window
;
953 DECLARE_RETURN(BOOL
);
955 DPRINT("Enter NtUserGetUpdateRect\n");
956 UserEnterExclusive();
958 if (!(Window
= UserGetWindowObject(hWnd
)))
963 if (Window
->UpdateRegion
== NULL
)
965 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
969 /* Get the update region bounding box. */
970 if (Window
->UpdateRegion
== (HRGN
)1)
972 Rect
= Window
->ClientRect
;
976 RgnData
= RGNDATA_LockRgn(Window
->UpdateRegion
);
977 ASSERT(RgnData
!= NULL
);
978 RegionType
= UnsafeIntGetRgnBox(RgnData
, &Rect
);
979 RGNDATA_UnlockRgn(RgnData
);
981 if (RegionType
!= ERROR
&& RegionType
!= NULLREGION
)
982 IntGdiIntersectRect(&Rect
, &Rect
, &Window
->ClientRect
);
985 if (IntIntersectWithParents(Window
, &Rect
))
987 IntGdiOffsetRect(&Rect
,
988 -Window
->ClientRect
.left
,
989 -Window
->ClientRect
.top
);
992 Rect
.left
= Rect
.top
= Rect
.right
= Rect
.bottom
= 0;
996 if (bErase
&& !IntGdiIsEmptyRect(&Rect
))
998 USER_REFERENCE_ENTRY Ref
;
999 UserRefObjectCo(Window
, &Ref
);
1000 co_UserRedrawWindow(Window
, NULL
, NULL
, RDW_ERASENOW
| RDW_NOCHILDREN
);
1001 UserDerefObjectCo(Window
);
1004 if (UnsafeRect
!= NULL
)
1006 Status
= MmCopyToCaller(UnsafeRect
, &Rect
, sizeof(RECT
));
1007 if (!NT_SUCCESS(Status
))
1009 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1014 RETURN(!IntGdiIsEmptyRect(&Rect
));
1017 DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_
);
1023 * NtUserRedrawWindow
1030 NtUserRedrawWindow(HWND hWnd
, CONST RECT
*lprcUpdate
, HRGN hrgnUpdate
,
1033 RECT SafeUpdateRect
;
1036 DECLARE_RETURN(BOOL
);
1037 USER_REFERENCE_ENTRY Ref
;
1039 DPRINT("Enter NtUserRedrawWindow\n");
1040 UserEnterExclusive();
1042 if (!(Wnd
= UserGetWindowObject(hWnd
? hWnd
: IntGetDesktopWindow())))
1047 if (lprcUpdate
!= NULL
)
1049 Status
= MmCopyFromCaller(&SafeUpdateRect
, (PRECT
)lprcUpdate
,
1052 if (!NT_SUCCESS(Status
))
1054 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1059 UserRefObjectCo(Wnd
, &Ref
);
1061 Status
= co_UserRedrawWindow(Wnd
, NULL
== lprcUpdate
? NULL
: &SafeUpdateRect
,
1064 UserDerefObjectCo(Wnd
);
1066 if (!NT_SUCCESS(Status
))
1068 /* IntRedrawWindow fails only in case that flags are invalid */
1069 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1076 DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_
);
1085 UserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1086 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1088 RECT rSrc
, rClipped_src
, rClip
, rDst
, offset
;
1092 * Compute device clipping region (in device coordinates).
1095 DC
= DC_LockDc(hDC
);
1103 IntGdiGetClipBox(hDC
, &rSrc
);
1104 IntLPtoDP(DC
, (LPPOINT
)&rSrc
, 2);
1109 IntGdiGetClipBox(hDC
, &rClip
);
1110 IntLPtoDP(DC
, (LPPOINT
)&rClip
, 2);
1112 IntGdiIntersectRect(&rClipped_src
, &rSrc
, &rClip
);
1114 rDst
= rClipped_src
;
1115 IntGdiSetRect(&offset
, 0, 0, dx
, dy
);
1116 IntLPtoDP(DC
, (LPPOINT
)&offset
, 2);
1117 IntGdiOffsetRect(&rDst
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1118 IntGdiIntersectRect(&rDst
, &rDst
, &rClip
);
1121 * Copy bits, if possible.
1124 if (rDst
.bottom
> rDst
.top
&& rDst
.right
> rDst
.left
)
1126 RECT rDst_lp
= rDst
, rSrc_lp
= rDst
;
1128 IntGdiOffsetRect(&rSrc_lp
, offset
.left
- offset
.right
, offset
.top
- offset
.bottom
);
1129 IntDPtoLP(DC
, (LPPOINT
)&rDst_lp
, 2);
1130 IntDPtoLP(DC
, (LPPOINT
)&rSrc_lp
, 2);
1133 if (!NtGdiBitBlt(hDC
, rDst_lp
.left
, rDst_lp
.top
, rDst_lp
.right
- rDst_lp
.left
,
1134 rDst_lp
.bottom
- rDst_lp
.top
, hDC
, rSrc_lp
.left
, rSrc_lp
.top
,
1144 * Compute update areas. This is the clipped source or'ed with the
1145 * unclipped source translated minus the clipped src translated (rDst)
1146 * all clipped to rClip.
1149 if (hrgnUpdate
|| lprcUpdate
)
1151 HRGN hRgn
= hrgnUpdate
, hRgn2
;
1154 NtGdiSetRectRgn(hRgn
, rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1156 hRgn
= NtGdiCreateRectRgn(rClipped_src
.left
, rClipped_src
.top
, rClipped_src
.right
, rClipped_src
.bottom
);
1158 hRgn2
= UnsafeIntCreateRectRgnIndirect(&rSrc
);
1159 NtGdiOffsetRgn(hRgn2
, offset
.right
- offset
.left
, offset
.bottom
- offset
.top
);
1160 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_OR
);
1162 NtGdiSetRectRgn(hRgn2
, rDst
.left
, rDst
.top
, rDst
.right
, rDst
.bottom
);
1163 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_DIFF
);
1165 NtGdiSetRectRgn(hRgn2
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
1166 NtGdiCombineRgn(hRgn
, hRgn
, hRgn2
, RGN_AND
);
1170 NtGdiGetRgnBox(hRgn
, lprcUpdate
);
1172 /* Put the lprcUpdate in logical coordinate */
1173 NtGdiDPtoLP(hDC
, (LPPOINT
)lprcUpdate
, 2);
1176 NtGdiDeleteObject(hRgn
);
1177 NtGdiDeleteObject(hRgn2
);
1193 NtUserScrollDC(HDC hDC
, INT dx
, INT dy
, const RECT
*lprcScroll
,
1194 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
1196 DECLARE_RETURN(DWORD
);
1198 DPRINT("Enter NtUserScrollDC\n");
1199 UserEnterExclusive();
1201 RETURN( UserScrollDC(hDC
, dx
, dy
, lprcScroll
, lprcClip
, hrgnUpdate
, lprcUpdate
));
1204 DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_
);
1211 * NtUserScrollWindowEx
1218 NtUserScrollWindowEx(HWND hWnd
, INT dx
, INT dy
, const RECT
*UnsafeRect
,
1219 const RECT
*UnsafeClipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
1221 RECT rc
, cliprc
, caretrc
, rect
, clipRect
;
1223 PWINDOW_OBJECT Window
= NULL
, CaretWnd
;
1227 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
1228 BOOL bOwnRgn
= TRUE
;
1230 DECLARE_RETURN(DWORD
);
1231 USER_REFERENCE_ENTRY Ref
, CaretRef
;
1233 DPRINT("Enter NtUserScrollWindowEx\n");
1234 UserEnterExclusive();
1236 Window
= UserGetWindowObject(hWnd
);
1237 if (!Window
|| !IntIsWindowDrawable(Window
))
1239 Window
= NULL
; /* prevent deref at cleanup */
1242 UserRefObjectCo(Window
, &Ref
);
1244 IntGetClientRect(Window
, &rc
);
1246 if (NULL
!= UnsafeRect
)
1248 Status
= MmCopyFromCaller(&rect
, UnsafeRect
, sizeof(RECT
));
1249 if (! NT_SUCCESS(Status
))
1251 SetLastNtError(Status
);
1254 IntGdiIntersectRect(&rc
, &rc
, &rect
);
1257 if (NULL
!= UnsafeClipRect
)
1259 Status
= MmCopyFromCaller(&clipRect
, UnsafeClipRect
, sizeof(RECT
));
1260 if (! NT_SUCCESS(Status
))
1262 SetLastNtError(Status
);
1265 IntGdiIntersectRect(&cliprc
, &rc
, &clipRect
);
1270 if (cliprc
.right
<= cliprc
.left
|| cliprc
.bottom
<= cliprc
.top
||
1271 (dx
== 0 && dy
== 0))
1273 RETURN( NULLREGION
);
1277 hwndCaret
= co_IntFixCaret(Window
, &caretrc
, flags
);
1282 hrgnUpdate
= NtGdiCreateRectRgn(0, 0, 0, 0);
1284 hDC
= UserGetDCEx(Window
, 0, DCX_CACHE
| DCX_USESTYLE
);
1287 UserScrollDC(hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
1288 UserReleaseDC(Window
, hDC
, FALSE
);
1292 * Take into account the fact that some damage may have occurred during
1296 hrgnTemp
= NtGdiCreateRectRgn(0, 0, 0, 0);
1297 Result
= co_UserGetUpdateRgn(Window
, hrgnTemp
, FALSE
);
1298 if (Result
!= NULLREGION
)
1300 HRGN hrgnClip
= UnsafeIntCreateRectRgnIndirect(&cliprc
);
1301 NtGdiOffsetRgn(hrgnTemp
, dx
, dy
);
1302 NtGdiCombineRgn(hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
1303 co_UserRedrawWindow(Window
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
1304 NtGdiDeleteObject(hrgnClip
);
1307 NtGdiDeleteObject(hrgnTemp
);
1309 if (flags
& SW_SCROLLCHILDREN
)
1311 HWND
*List
= IntWinListChildren(Window
);
1318 USER_REFERENCE_ENTRY WndRef
;
1320 IntGetClientOrigin(Window
, &ClientOrigin
);
1321 for (i
= 0; List
[i
]; i
++)
1323 if (!(Wnd
= UserGetWindowObject(List
[i
])))
1326 r
= Wnd
->WindowRect
;
1327 r
.left
-= ClientOrigin
.x
;
1328 r
.top
-= ClientOrigin
.y
;
1329 r
.right
-= ClientOrigin
.x
;
1330 r
.bottom
-= ClientOrigin
.y
;
1332 if (! UnsafeRect
|| IntGdiIntersectRect(&dummy
, &r
, &rc
))
1334 UserRefObjectCo(Wnd
, &WndRef
);
1335 co_WinPosSetWindowPos(Wnd
, 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
1336 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1338 UserDerefObjectCo(Wnd
);
1346 if (flags
& (SW_INVALIDATE
| SW_ERASE
))
1347 co_UserRedrawWindow(Window
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
1348 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
1349 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0));
1351 if (bOwnRgn
&& hrgnUpdate
)
1352 NtGdiDeleteObject(hrgnUpdate
);
1354 if ((CaretWnd
= UserGetWindowObject(hwndCaret
)))
1356 UserRefObjectCo(CaretWnd
, &CaretRef
);
1358 co_IntSetCaretPos(caretrc
.left
+ dx
, caretrc
.top
+ dy
);
1359 co_UserShowCaret(CaretWnd
);
1361 UserDerefObjectCo(CaretWnd
);
1368 UserDerefObjectCo(Window
);
1370 DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_
);