* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: painting.c,v 1.33 2003/09/11 22:11:44 gvg Exp $
*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * PURPOSE: Painting
- * FILE: subsys/win32k/ntuser/painting.c
- * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
- * REVISION HISTORY:
- * 06-06-2001 CSH Created
+ * $Id$
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Window painting function
+ * FILE: subsys/win32k/ntuser/painting.c
+ * PROGRAMER: Filip Navara (xnavara@volny.cz)
+ * REVISION HISTORY:
+ * 06/06/2001 Created (?)
+ * 18/11/2003 Complete rewrite
*/
+
/* INCLUDES ******************************************************************/
-#include <ddk/ntddk.h>
-#include <win32k/win32k.h>
-#include <include/object.h>
-#include <include/guicheck.h>
-#include <include/window.h>
-#include <include/class.h>
-#include <include/error.h>
-#include <include/winsta.h>
-#include <windows.h>
-#include <include/painting.h>
-#include <user32/wininternal.h>
-#include <include/rect.h>
-#include <win32k/coord.h>
-#include <win32k/region.h>
-#include <include/vis.h>
+#include <w32k.h>
#define NDEBUG
#include <debug.h>
+/* PRIVATE FUNCTIONS **********************************************************/
-/* GLOBALS *******************************************************************/
+/**
+ * @name IntIntersectWithParents
+ *
+ * Intersect window rectangle with all parent client rectangles.
+ *
+ * @param Child
+ * Pointer to child window to start intersecting from.
+ * @param WindowRect
+ * Pointer to rectangle that we want to intersect in screen
+ * coordinates on input and intersected rectangle on output (if TRUE
+ * is returned).
+ *
+ * @return
+ * If any parent is minimized or invisible or the resulting rectangle
+ * is empty then FALSE is returned. Otherwise TRUE is returned.
+ */
-/* client rect in window coordinates */
-#define GETCLIENTRECTW(wnd, r) (r).left = (wnd)->ClientRect.left - (wnd)->WindowRect.left; \
- (r).top = (wnd)->ClientRect.top - (wnd)->WindowRect.top; \
- (r).right = (wnd)->ClientRect.right - (wnd)->WindowRect.left; \
- (r).bottom = (wnd)->ClientRect.bottom - (wnd)->WindowRect.top
+BOOL FASTCALL
+IntIntersectWithParents(PWINDOW_OBJECT Child, PRECT WindowRect)
+{
+ PWINDOW_OBJECT ParentWindow;
-/* FUNCTIONS *****************************************************************/
+ ParentWindow = Child->Parent;
+ while (ParentWindow != NULL)
+ {
+ if (!(ParentWindow->Style & WS_VISIBLE) ||
+ (ParentWindow->Style & WS_MINIMIZE))
+ {
+ return FALSE;
+ }
+
+ if (!IntGdiIntersectRect(WindowRect, WindowRect, &ParentWindow->ClientRect))
+ {
+ return FALSE;
+ }
+
+ /* FIXME: Layered windows. */
+
+ ParentWindow = ParentWindow->Parent;
+ }
+
+ return TRUE;
+}
-HRGN STATIC STDCALL
-PaintDoPaint(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags, ULONG ExFlags)
+VOID FASTCALL
+IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
{
- HDC hDC;
- HWND hWnd = Window->Self;
- BOOL bIcon = (0 != (Window->Style & WS_MINIMIZE)) &&
- (0 != IntGetClassLong(Window, GCL_HICON, FALSE));
-
- if (0 != (ExFlags & RDW_EX_DELAY_NCPAINT) ||
- PaintHaveToDelayNCPaint(Window, 0))
- {
- ExFlags |= RDW_EX_DELAY_NCPAINT;
- }
-
- if (Flags & RDW_UPDATENOW)
- {
- if (NULL != Window->UpdateRegion)
- {
- if (IntIsDesktopWindow(Window))
- {
- VIS_RepaintDesktop(Window->Self, Window->UpdateRegion);
- }
- else
- {
- NtUserSendMessage(hWnd, bIcon ? WM_PAINTICON : WM_PAINT, bIcon, 0);
- }
- }
- }
- else if (Flags & RDW_ERASENOW || ExFlags & RDW_EX_TOPFRAME)
- {
- UINT Dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN |
- DCX_WINDOWPAINT | DCX_CACHE;
- HRGN hRgnRet;
-
- hRgnRet =
- PaintUpdateNCRegion(Window,
- hRgn,
- UNC_REGION | UNC_CHECK |
- ((ExFlags & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
- ((ExFlags & RDW_EX_DELAY_NCPAINT) ?
- UNC_DELAY_NCPAINT : 0));
- if (NULL != hRgnRet)
- {
- if ((HRGN) 1 < hRgnRet)
- {
- hRgn = hRgnRet;
- }
- else
- {
- hRgnRet = NULL;
- }
- if (0 != (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD))
- {
- if (bIcon)
- {
- Dcx |= DCX_WINDOW;
- }
- if (NULL != hRgnRet)
- {
- NtGdiOffsetRgn(hRgnRet,
- Window->WindowRect.left -
- Window->ClientRect.left,
- Window->WindowRect.top -
- Window->ClientRect.top);
- }
- else
- {
- Dcx &= ~DCX_INTERSECTRGN;
- }
- if (NULL != (hDC = NtUserGetDCEx(hWnd, hRgnRet, Dcx)))
- {
- if (IntIsDesktopWindow(Window))
- {
- VIS_RepaintDesktop(Window->Self, Window->UpdateRegion);
- NtGdiDeleteObject(Window->UpdateRegion);
- Window->UpdateRegion = 0;
- }
- else
- {
- if (0 != NtUserSendMessage(hWnd, bIcon ? WM_ICONERASEBKGND :
- WM_ERASEBKGND, (WPARAM)hDC, 0))
- {
- Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
- }
- }
- NtUserReleaseDC(hWnd, hDC);
- }
- }
- }
- }
-
- /* FIXME: Check that the window is still valid at this point. */
-
- ExFlags &= ~RDW_EX_TOPFRAME;
-
- /* FIXME: Paint child windows. */
-
- return(hRgn);
+ PWINDOW_OBJECT ParentWindow = Child->Parent;
+
+ while (ParentWindow)
+ {
+ if (ParentWindow->Style & WS_CLIPCHILDREN)
+ break;
+
+ if (ParentWindow->UpdateRegion != 0)
+ {
+ NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
+ ValidRegion, RGN_DIFF);
+ /* FIXME: If the resulting region is empty, remove fake posted paint message */
+ }
+
+ ParentWindow = ParentWindow->Parent;
+ }
}
-VOID STATIC FASTCALL
-PaintUpdateInternalPaint(PWINDOW_OBJECT Window, ULONG Flags)
+/**
+ * @name IntCalcWindowRgn
+ *
+ * Get a window or client region.
+ */
+
+HRGN FASTCALL
+IntCalcWindowRgn(PWINDOW_OBJECT Window, BOOL Client)
{
- if (Flags & RDW_INTERNALPAINT)
- {
- if (Window->UpdateRegion == NULL &&
- !(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
- {
- MsqIncPaintCountQueue(Window->MessageQueue);
- }
- Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
- }
- else if (Flags & RDW_NOINTERNALPAINT)
- {
- if (Window->UpdateRegion == NULL &&
- (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
- {
- MsqDecPaintCountQueue(Window->MessageQueue);
- }
- Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
- }
+ HRGN hRgnWindow;
+ UINT RgnType;
+
+ if (Client)
+ hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
+ else
+ hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
+
+ if (Window->WindowRegion != NULL && !(Window->Style & WS_MINIMIZE))
+ {
+ NtGdiOffsetRgn(hRgnWindow,
+ -Window->WindowRect.left,
+ -Window->WindowRect.top);
+ RgnType = NtGdiCombineRgn(hRgnWindow, hRgnWindow, Window->WindowRegion, RGN_AND);
+ NtGdiOffsetRgn(hRgnWindow,
+ Window->WindowRect.left,
+ Window->WindowRect.top);
+ }
+
+ return hRgnWindow;
}
-VOID STATIC FASTCALL
-PaintValidateParent(PWINDOW_OBJECT Child)
+/**
+ * @name IntGetNCUpdateRgn
+ *
+ * Get non-client update region of a window and optionally validate it.
+ *
+ * @param Window
+ * Pointer to window to get the NC update region from.
+ * @param Validate
+ * Set to TRUE to force validating the NC update region.
+ *
+ * @return
+ * Handle to NC update region. The caller is responsible for deleting
+ * it.
+ */
+
+HRGN FASTCALL
+IntGetNCUpdateRgn(PWINDOW_OBJECT Window, BOOL Validate)
{
- HWND DesktopHandle = IntGetDesktopWindow();
- PWINDOW_OBJECT Parent = Child->Parent;
- PWINDOW_OBJECT Desktop = IntGetWindowObject(DesktopHandle);
- HRGN hRgn;
-
- if ((HRGN) 1 == Child->UpdateRegion)
- {
- RECT Rect;
-
- Rect.left = Rect.top = 0;
- Rect.right = Child->WindowRect.right - Child->WindowRect.left;
- Rect.bottom = Child->WindowRect.bottom - Child->WindowRect.top;
-
- hRgn = UnsafeIntCreateRectRgnIndirect(&Rect);
- }
- else
- {
- hRgn = Child->UpdateRegion;
- }
-
- while (NULL != Parent && Parent != Desktop)
- {
- if (0 == (Parent->Style & WS_CLIPCHILDREN))
- {
- if (NULL != Parent->UpdateRegion)
- {
- POINT Offset;
-
- if ((HRGN) 1 == Parent->UpdateRegion)
- {
- RECT Rect1;
-
- Rect1.left = Rect1.top = 0;
- Rect1.right = Parent->WindowRect.right -
- Parent->WindowRect.left;
- Rect1.bottom = Parent->WindowRect.bottom -
- Parent->WindowRect.top;
-
- Parent->UpdateRegion =
- UnsafeIntCreateRectRgnIndirect(&Rect1);
- }
- Offset.x = Child->WindowRect.left - Parent->WindowRect.left;
- Offset.y = Child->WindowRect.top - Parent->WindowRect.top;
- NtGdiOffsetRgn(hRgn, Offset.x, Offset.y);
- NtGdiCombineRgn(Parent->UpdateRegion, Parent->UpdateRegion, hRgn,
- RGN_DIFF);
- NtGdiOffsetRgn(hRgn, -Offset.x, -Offset.y);
- }
- }
- Parent = Parent->Parent;
- }
- if (hRgn != Child->UpdateRegion)
- {
- NtGdiDeleteObject(Child->UpdateRegion);
- }
- IntReleaseWindowObject(Desktop);
+ HRGN hRgnNonClient;
+ HRGN hRgnWindow;
+ UINT RgnType;
+
+ if (Window->UpdateRegion != NULL &&
+ Window->UpdateRegion != (HRGN)1)
+ {
+ hRgnNonClient = NtGdiCreateRectRgn(0, 0, 0, 0);
+ hRgnWindow = IntCalcWindowRgn(Window, TRUE);
+
+ /*
+ * If region creation fails it's safe to fallback to whole
+ * window region.
+ */
+
+ if (hRgnNonClient == NULL)
+ {
+ return (HRGN)1;
+ }
+
+ RgnType = NtGdiCombineRgn(hRgnNonClient, Window->UpdateRegion,
+ hRgnWindow, RGN_DIFF);
+ if (RgnType == ERROR)
+ {
+ NtGdiDeleteObject(hRgnNonClient);
+ return (HRGN)1;
+ }
+ else if (RgnType == NULLREGION)
+ {
+ NtGdiDeleteObject(hRgnNonClient);
+ return NULL;
+ }
+
+ /*
+ * Remove the nonclient region from the standard update region if
+ * we were asked for it.
+ */
+
+ if (Validate)
+ {
+ if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
+ hRgnWindow, RGN_AND) == NULLREGION)
+ {
+ GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
+ NtGdiDeleteObject(Window->UpdateRegion);
+ Window->UpdateRegion = NULL;
+ if (!(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ }
+ }
+
+ NtGdiDeleteObject(hRgnWindow);
+
+ return hRgnNonClient;
+ }
+ else
+ {
+ return Window->UpdateRegion;
+ }
}
-VOID STATIC STDCALL
-PaintUpdateRgns(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
- BOOL First)
+/*
+ * IntPaintWindows
+ *
+ * Internal function used by IntRedrawWindow.
+ */
+
+STATIC VOID FASTCALL
+co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
{
- /*
- * Called only when one of the following is set:
- * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
- */
-
- BOOL HadOne = NULL != Window->UpdateRegion && NULL != hRgn;
- BOOL HasChildren = Window->FirstChild &&
- !(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
- ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN));
- RECT Rect;
-
- Rect.left = Rect.top = 0;
- Rect.right = Window->WindowRect.right - Window->WindowRect.left;
- Rect.bottom = Window->WindowRect.bottom - Window->WindowRect.top;
-
- if (Flags & RDW_INVALIDATE)
- {
- if ((HRGN) 1 < hRgn)
- {
- if ((HRGN) 1 != Window->UpdateRegion)
- {
- if ((HRGN) 1 < Window->UpdateRegion)
- {
- NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
- hRgn, RGN_OR);
- }
- Window->UpdateRegion =
- REGION_CropRgn(Window->UpdateRegion,
- Window->UpdateRegion ? Window->UpdateRegion : hRgn,
- &Rect, NULL);
- if (! HadOne)
- {
- UnsafeIntGetRgnBox(Window->UpdateRegion, &Rect);
- if (NtGdiIsEmptyRect(&Rect))
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- Window->UpdateRegion = NULL;
- PaintUpdateInternalPaint(Window, Flags);
- return;
- }
- }
- }
- }
- else if ((HRGN) 1 == hRgn)
- {
- if ((HRGN) 1 < Window->UpdateRegion)
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- }
- Window->UpdateRegion = (HRGN) 1;
- }
+ HDC hDC;
+ HWND hWnd = Window->hSelf;
+ HRGN TempRegion;
+
+ if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ {
+ if (Window->UpdateRegion)
+ {
+ IntValidateParent(Window, Window->UpdateRegion);
+ }
+
+ if (Flags & RDW_UPDATENOW)
+ {
+ if (Window->UpdateRegion != NULL ||
+ Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
+ {
+ co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+ }
+ }
else
- {
- hRgn = Window->UpdateRegion; /* this is a trick that depends on code in PaintRedrawWindow() */
- }
+ {
+ if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
+ {
+ TempRegion = IntGetNCUpdateRgn(Window, TRUE);
+ Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
+ if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
+ {
+ /* NOTE: The region can already be deleted! */
+ GDIOBJ_FreeObj(TempRegion, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
+ }
+ }
+
+ if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
+ {
+ if (Window->UpdateRegion)
+ {
+ hDC = UserGetDCEx(Window, Window->UpdateRegion,
+ DCX_CACHE | DCX_USESTYLE |
+ DCX_INTERSECTRGN | DCX_KEEPCLIPRGN);
+ if (co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+ {
+ Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
+ }
+ UserReleaseDC(Window, hDC, FALSE);
+ }
+ }
+ }
+ }
+
+ /*
+ * Check that the window is still valid at this point
+ */
+ if (!IntIsWindow(hWnd))
+ {
+ return;
+ }
+
+ /*
+ * Paint child windows.
+ */
+ if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
+ ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
+ {
+ HWND *List, *phWnd;
+
+ if ((List = IntWinListChildren(Window)))
+ {
+ for (phWnd = List; *phWnd; ++phWnd)
+ {
+ Window = UserGetWindowObject(*phWnd);
+ if (Window && (Window->Style & WS_VISIBLE))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Window, &Ref);
+ co_IntPaintWindows(Window, Flags);
+ UserDerefObjectCo(Window);
+ }
+ }
+ ExFreePool(List);
+ }
+ }
+}
- if (! HadOne && 0 == (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) &&
- !IntIsDesktopWindow(Window))
- {
- MsqIncPaintCountQueue(Window->MessageQueue);
- }
+/*
+ * IntInvalidateWindows
+ *
+ * Internal function used by IntRedrawWindow.
+ */
+
+VOID FASTCALL
+IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
+{
+ INT RgnType;
+ BOOL HadPaintMessage, HadNCPaintMessage;
+ BOOL HasPaintMessage, HasNCPaintMessage;
+
+ /*
+ * Clip the given region with window rectangle (or region)
+ */
+
+ if (!Window->WindowRegion || (Window->Style & WS_MINIMIZE))
+ {
+ HRGN hRgnWindow;
+
+ hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
+ RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
+ NtGdiDeleteObject(hRgnWindow);
+ }
+ else
+ {
+ NtGdiOffsetRgn(hRgn,
+ -Window->WindowRect.left,
+ -Window->WindowRect.top);
+ RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);
+ NtGdiOffsetRgn(hRgn,
+ Window->WindowRect.left,
+ Window->WindowRect.top);
+ }
+
+ /*
+ * Save current state of pending updates
+ */
+
+ HadPaintMessage = Window->UpdateRegion != NULL ||
+ Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
+ HadNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
+
+ /*
+ * Update the region and flags
+ */
+
+ if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
+ {
+ if (Window->UpdateRegion == NULL)
+ {
+ Window->UpdateRegion = NtGdiCreateRectRgn(0, 0, 0, 0);
+ GDIOBJ_SetOwnership(Window->UpdateRegion, NULL);
+ }
+
+ if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
+ hRgn, RGN_OR) == NULLREGION)
+ {
+ GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
+ NtGdiDeleteObject(Window->UpdateRegion);
+ Window->UpdateRegion = NULL;
+ }
if (Flags & RDW_FRAME)
- {
- Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
- }
+ Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
if (Flags & RDW_ERASE)
- {
- Window->Flags |= WINDOWOBJECT_NEED_ERASEBACKGRD;
- }
+ Window->Flags |= WINDOWOBJECT_NEED_ERASEBKGND;
+
Flags |= RDW_FRAME;
- }
- else if (Flags & RDW_VALIDATE)
- {
- if (NULL != Window->UpdateRegion)
- {
- if ((HRGN) 1 < hRgn)
- {
- if ((HRGN) 1 == Window->UpdateRegion)
- {
- /* If no NCPAINT needed or if we're going to turn it off
- the special value 1 means the whole client rect */
- if (0 == (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) ||
- 0 != (Flags & RDW_NOFRAME))
- {
- Rect.left = Window->ClientRect.left - Window->WindowRect.left;
- Rect.top = Window->ClientRect.top - Window->WindowRect.top;
- Rect.right = Window->ClientRect.right - Window->WindowRect.left;
- Rect.bottom = Window->ClientRect.bottom - Window->WindowRect.top;
- }
- Window->UpdateRegion =
- UnsafeIntCreateRectRgnIndirect(&Rect);
- }
- if (NtGdiCombineRgn(Window->UpdateRegion,
- Window->UpdateRegion, hRgn,
- RGN_DIFF) == NULLREGION)
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- Window->UpdateRegion = NULL;
- }
- }
- else /* validate everything */
- {
- if ((HRGN) 1 < Window->UpdateRegion)
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- }
- Window->UpdateRegion = NULL;
- }
-
- if (NULL != Window->UpdateRegion)
- {
- Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
- if (0 != (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
- {
- MsqDecPaintCountQueue(Window->MessageQueue);
- }
- }
- }
+ }
+
+ if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
+ {
+ if (Window->UpdateRegion != NULL)
+ {
+ if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
+ hRgn, RGN_DIFF) == NULLREGION)
+ {
+ GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
+ NtGdiDeleteObject(Window->UpdateRegion);
+ Window->UpdateRegion = NULL;
+ }
+ }
+ if (Window->UpdateRegion == NULL)
+ Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
if (Flags & RDW_NOFRAME)
- {
- Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
- }
+ Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
if (Flags & RDW_NOERASE)
- {
- Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
- }
- }
-
- if (First && NULL != Window->UpdateRegion && 0 != (Flags & RDW_UPDATENOW))
- {
- PaintValidateParent(Window); /* validate parent covered by region */
- }
-
- /* in/validate child windows that intersect with the region if it
- * is a valid handle. */
-
- if (0 != (Flags & (RDW_INVALIDATE | RDW_VALIDATE)))
- {
- if ((HRGN) 1 < hRgn && HasChildren)
- {
- POINT Total = {0, 0};
- POINT PrevOrign = {0, 0};
- PWINDOW_OBJECT Child;
-
- ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
- Child = Window->FirstChild;
- while (Child)
- {
- if (0 != (Child->Style & WS_VISIBLE))
- {
- POINT Offset;
-
- Rect.left = Child->WindowRect.left - Window->WindowRect.left;
- Rect.top = Child->WindowRect.top - Window->WindowRect.top;
- Rect.right = Child->WindowRect.right - Window->WindowRect.left;
- Rect.bottom = Child->WindowRect.bottom - Window->WindowRect.top;
-
- Offset.x = Rect.left - PrevOrign.x;
- Offset.y = Rect.top - PrevOrign.y;
- NtGdiOffsetRect(&Rect, -Total.x, -Total.y);
-
- if (UnsafeIntRectInRegion(hRgn, &Rect))
- {
- NtGdiOffsetRgn(hRgn, -Offset.x, -Offset.y);
- PaintUpdateRgns(Child, hRgn, Flags, FALSE);
- PrevOrign.x = Rect.left + Total.x;
- PrevOrign.y = Rect.top + Total.y;
- Total.x += Offset.x;
- Total.y += Offset.y;
- }
- }
- Child = Child->NextSibling;
- }
- ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
-
- NtGdiOffsetRgn(hRgn, Total.x, Total.y);
- HasChildren = FALSE;
- }
- }
-
- if (HasChildren)
- {
- PWINDOW_OBJECT Child;
-
- ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
- Child = Window->FirstChild;
- while (Child)
- {
- if (Child->Style & WS_VISIBLE)
+ Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
+ }
+
+ if (Flags & RDW_INTERNALPAINT)
+ {
+ Window->Flags |= WINDOWOBJECT_NEED_INTERNALPAINT;
+ }
+
+ if (Flags & RDW_NOINTERNALPAINT)
+ {
+ Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
+ }
+
+ /*
+ * Process children if needed
+ */
+
+ if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
+ ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
+ {
+ PWINDOW_OBJECT Child;
+
+ for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
{
- PaintUpdateRgns(Child, hRgn, Flags, FALSE);
+ if (Child->Style & WS_VISIBLE)
+ {
+ /*
+ * Recursive call to update children UpdateRegion
+ */
+ HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+ NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
+ IntInvalidateWindows(Child, hRgnTemp, Flags);
+ NtGdiDeleteObject(hRgnTemp);
+ }
+
}
- Child = Child->NextSibling;
- }
- ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
- }
+ }
+
+ /*
+ * Fake post paint messages to window message queue if needed
+ */
+
+ HasPaintMessage = Window->UpdateRegion != NULL ||
+ Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
+ HasNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
+
+ if (HasPaintMessage != HadPaintMessage)
+ {
+ if (HadPaintMessage)
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ else
+ MsqIncPaintCountQueue(Window->MessageQueue);
+ }
+
+ if (HasNCPaintMessage != HadNCPaintMessage)
+ {
+ if (HadNCPaintMessage)
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ else
+ MsqIncPaintCountQueue(Window->MessageQueue);
+ }
- PaintUpdateInternalPaint(Window, Flags);
}
-BOOL STDCALL
-PaintRedrawWindow( PWINDOW_OBJECT Window,
- const RECT* UpdateRect,
- HRGN UpdateRgn,
- ULONG Flags,
- ULONG ExFlags)
-{
- RECT Rect, Rect2;
- POINT Pt;
- HRGN hRgn = NULL;
-
- DPRINT("[win32k.sys:painting] In PaintRedrawWindow()\n");
-
- if ((RDW_INVALIDATE | RDW_FRAME) == (Flags & (RDW_INVALIDATE | RDW_FRAME)) ||
- (RDW_VALIDATE | RDW_NOFRAME) == (Flags & (RDW_VALIDATE | RDW_NOFRAME)))
- {
- Rect = Window->WindowRect;
- }
- else
- {
- Rect = Window->ClientRect;
- }
-
- if (ExFlags & RDW_EX_XYWINDOW)
- {
- Pt.x = Pt.y = 0;
- NtGdiOffsetRect(&Rect, -Window->WindowRect.left, -Window->WindowRect.top);
- }
- else
- {
- Pt.x = Window->ClientRect.left - Window->WindowRect.left;
- Pt.y = Window->ClientRect.top - Window->WindowRect.top;
- NtGdiOffsetRect(&Rect, -Window->ClientRect.left, -Window->ClientRect.top);
- }
-
- if (0 != (Flags & RDW_INVALIDATE)) /* ------------------------- Invalidate */
- {
- if (NULL != UpdateRgn)
- {
- if (NULL != Window->UpdateRegion)
- {
- hRgn = REGION_CropRgn(NULL, UpdateRgn, NULL, &Pt);
- }
- else
- {
- Window->UpdateRegion = REGION_CropRgn(NULL, UpdateRgn, &Rect, &Pt);
- }
- }
- else if (NULL != UpdateRect)
- {
- if (! NtGdiIntersectRect(&Rect2, &Rect, UpdateRect))
- {
-
- if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
- {
- NtGdiDeleteObject(hRgn);
- }
- return TRUE;
- }
- NtGdiOffsetRect(&Rect2, Pt.x, Pt.y);
- if (NULL == Window->UpdateRegion)
- {
- Window->UpdateRegion =
- UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- else
- {
- hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- }
- else /* entire window or client depending on RDW_FRAME */
- {
- if (Flags & RDW_FRAME)
- {
- if (NULL != Window->UpdateRegion)
- {
- hRgn = (HRGN) 1;
- }
- else
- {
- Window->UpdateRegion = (HRGN) 1;
- }
- }
- else
- {
- GETCLIENTRECTW(Window, Rect2);
- if (NULL == Window->UpdateRegion)
- {
- Window->UpdateRegion = UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- else
- {
- hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- }
- }
- }
- else if (Flags & RDW_VALIDATE)
- {
- /* In this we cannot leave with zero hRgn */
- if (NULL != UpdateRgn)
- {
- hRgn = REGION_CropRgn(hRgn, UpdateRgn, &Rect, &Pt);
- UnsafeIntGetRgnBox(hRgn, &Rect2);
- if (NtGdiIsEmptyRect(&Rect2))
- {
-
- if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
- {
- NtGdiDeleteObject(hRgn);
- }
- return TRUE;
- }
- }
- else if (NULL != UpdateRect)
- {
- if (! NtGdiIntersectRect(&Rect2, &Rect, UpdateRect))
- {
-
- if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
- {
- NtGdiDeleteObject(hRgn);
- }
- return TRUE;
- }
- NtGdiOffsetRect(&Rect2, Pt.x, Pt.y);
- hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- else /* entire window or client depending on RDW_NOFRAME */
- {
- if (0 != (Flags & RDW_NOFRAME))
- {
- hRgn = (HRGN) 1;
- }
- else
- {
- GETCLIENTRECTW(Window, Rect2);
- hRgn = UnsafeIntCreateRectRgnIndirect(&Rect2);
- }
- }
- }
+/*
+ * IntIsWindowDrawable
+ *
+ * Remarks
+ * Window is drawable when it is visible and all parents are not
+ * minimized.
+ */
- /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
+BOOL FASTCALL
+IntIsWindowDrawable(PWINDOW_OBJECT Window)
+{
+ PWINDOW_OBJECT Wnd;
- PaintUpdateRgns(Window, hRgn, Flags, TRUE);
+ for (Wnd = Window; Wnd != NULL; Wnd = Wnd->Parent)
+ {
+ if (!(Wnd->Style & WS_VISIBLE) ||
+ ((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
+ {
+ return FALSE;
+ }
+ }
- /* Erase/update windows, from now on hRgn is a scratch region */
+ return TRUE;
+}
- hRgn = PaintDoPaint(Window, (HRGN) 1 == hRgn ? NULL : hRgn, Flags, ExFlags);
+/*
+ * IntRedrawWindow
+ *
+ * Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
+ * first parameter.
+ */
- if ((HRGN) 1 < hRgn && hRgn != UpdateRgn)
- {
+BOOL FASTCALL
+co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
+ ULONG Flags)
+{
+ HRGN hRgn = NULL;
+
+ /*
+ * Step 1.
+ * Validation of passed parameters.
+ */
+
+ if (!IntIsWindowDrawable(Window) ||
+ (Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
+ (RDW_VALIDATE | RDW_INVALIDATE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * Step 2.
+ * Transform the parameters UpdateRgn and UpdateRect into
+ * a region hRgn specified in screen coordinates.
+ */
+
+ if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
+ {
+ if (UpdateRgn != NULL)
+ {
+ hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
+ if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+ NtGdiDeleteObject(hRgn);
+ else
+ NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
+ }
+ else if (UpdateRect != NULL)
+ {
+ if (!IntGdiIsEmptyRect(UpdateRect))
+ {
+ hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
+ NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
+ }
+ }
+ else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
+ (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
+ {
+ if (!IntGdiIsEmptyRect(&Window->WindowRect))
+ hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
+ }
+ else
+ {
+ if (!IntGdiIsEmptyRect(&Window->ClientRect))
+ hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
+ }
+ }
+
+ /*
+ * Step 3.
+ * Adjust the window update region depending on hRgn and flags.
+ */
+
+ if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
+ hRgn != NULL)
+ {
+ IntInvalidateWindows(Window, hRgn, Flags);
+ }
+
+ /*
+ * Step 4.
+ * Repaint and erase windows if needed.
+ */
+
+ if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+ {
+ co_IntPaintWindows(Window, Flags);
+ }
+
+ /*
+ * Step 5.
+ * Cleanup ;-)
+ */
+
+ if (hRgn != NULL)
+ {
NtGdiDeleteObject(hRgn);
- }
+ }
- return TRUE;
+ return TRUE;
}
-BOOL STDCALL
-PaintHaveToDelayNCPaint(PWINDOW_OBJECT Window, ULONG Flags)
+BOOL FASTCALL
+IntIsWindowDirty(PWINDOW_OBJECT Window)
{
- if (Flags & UNC_DELAY_NCPAINT)
- {
- return(TRUE);
- }
-
- if (Flags & UNC_IN_BEGINPAINT)
- {
- return(FALSE);
- }
-
- Window = Window->Parent;
- while (Window != NULL)
- {
- if (Window->Style & WS_CLIPCHILDREN && Window->UpdateRegion != NULL)
- {
- return TRUE;
- }
- Window = Window->Parent;
- }
-
- return FALSE;
+ return (Window->Style & WS_VISIBLE) &&
+ ((Window->UpdateRegion != NULL) ||
+ (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) ||
+ (Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
}
-HWND STDCALL
-PaintingFindWinToRepaint(HWND hWnd, PW32THREAD Thread)
+HWND FASTCALL
+IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
{
- PWINDOW_OBJECT Window;
- PWINDOW_OBJECT BaseWindow;
- PLIST_ENTRY current_entry;
- HWND hFoundWnd = NULL;
-
- if (hWnd == NULL)
- {
- ExAcquireFastMutex(&Thread->WindowListLock);
- current_entry = Thread->WindowListHead.Flink;
- while (current_entry != &Thread->WindowListHead)
- {
- Window = CONTAINING_RECORD(current_entry, WINDOW_OBJECT,
- ThreadListEntry);
- if (Window->Style & WS_VISIBLE)
- {
- hFoundWnd =
- PaintingFindWinToRepaint(Window->Self, Thread);
- if (hFoundWnd != NULL)
- {
- ExReleaseFastMutex(&Thread->WindowListLock);
- return(hFoundWnd);
- }
- }
- current_entry = current_entry->Flink;
- }
- ExReleaseFastMutex(&Thread->WindowListLock);
- return(NULL);
- }
-
- BaseWindow = IntGetWindowObject(hWnd);
- if (BaseWindow == NULL)
- {
- return(NULL);
- }
- if (BaseWindow->UpdateRegion != NULL ||
- BaseWindow->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
- {
- IntReleaseWindowObject(BaseWindow);
- return(hWnd);
- }
-
- ExAcquireFastMutex(&BaseWindow->ChildrenListLock);
- Window = BaseWindow->FirstChild;
- while (Window)
- {
- if (Window->Style & WS_VISIBLE)
- {
- hFoundWnd = PaintingFindWinToRepaint(Window->Self, Thread);
- if (hFoundWnd != NULL)
+ HWND hChild;
+ PWINDOW_OBJECT TempWindow;
+
+ for (; Window != NULL; Window = Window->NextSibling)
+ {
+ if (IntWndBelongsToThread(Window, Thread) &&
+ IntIsWindowDirty(Window))
+ {
+ /* Make sure all non-transparent siblings are already drawn. */
+ if (Window->ExStyle & WS_EX_TRANSPARENT)
+ {
+ for (TempWindow = Window->NextSibling; TempWindow != NULL;
+ TempWindow = TempWindow->NextSibling)
+ {
+ if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
+ IntWndBelongsToThread(TempWindow, Thread) &&
+ IntIsWindowDirty(TempWindow))
+ {
+ return TempWindow->hSelf;
+ }
+ }
+ }
+
+ return Window->hSelf;
+ }
+
+ if (Window->FirstChild)
{
- break;
+ hChild = IntFindWindowToRepaint(Window->FirstChild, Thread);
+ if (hChild != NULL)
+ return hChild;
}
- }
- Window = Window->NextSibling;
- }
- ExReleaseFastMutex(&BaseWindow->ChildrenListLock);
+ }
- IntReleaseWindowObject(BaseWindow);
- return(hFoundWnd);
+ return NULL;
}
-HRGN STDCALL
-PaintUpdateNCRegion(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
+BOOL FASTCALL
+IntGetPaintMessage(HWND hWnd, UINT MsgFilterMin, UINT MsgFilterMax,
+ PW32THREAD Thread, MSG *Message, BOOL Remove)
{
- HRGN hRgnRet;
- RECT ClientRect;
- HRGN hClip = NULL;
+ PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
- /* Desktop has no parent. */
- if (Window->Parent == NULL)
- {
- Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
- if ((HRGN) 1 < Window->UpdateRegion)
- {
- hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
- }
- else
- {
- hRgnRet = Window->UpdateRegion;
- }
- return(hRgnRet);
- }
-
-#if 0 /* NtUserGetFOregroundWindow() not implemented yet */
- if ((Window->Self == NtUserGetForegroundWindow()) &&
- 0 == (Window->Flags & WIN_NCACTIVATED) )
- {
- Window->Flags |= WIN_NCACTIVATED;
- Flags |= UNC_ENTIRE;
- }
-#endif
-
- /*
- * If the window's non-client area needs to be painted,
- */
- if (0 != (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) &&
- ! PaintHaveToDelayNCPaint(Window, Flags))
- {
- RECT UpdateRegionBox;
- RECT Rect;
+ if (!MessageQueue->PaintCount)
+ return FALSE;
+
+ if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
+ (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
+ return FALSE;
+
+ Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetWin32Thread());
+
+ if (Message->hwnd == NULL)
+ {
+ DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
+ return FALSE;
+ }
+
+ if (hWnd != NULL && Message->hwnd != hWnd)
+ return FALSE;
+
+ Message->message = WM_PAINT;
+ Message->wParam = Message->lParam = 0;
+
+ return TRUE;
+}
+
+static
+HWND FASTCALL
+co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
+{
+ PDESKTOP_OBJECT Desktop;
+ PTHRDCARETINFO CaretInfo;
+ HWND hWndCaret;
+ PWINDOW_OBJECT WndCaret;
+
+ ASSERT_REFS_CO(Window);
+
+ Desktop = ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->Desktop;
+ CaretInfo = ((PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue)->CaretInfo;
+ hWndCaret = CaretInfo->hWnd;
+
+ WndCaret = UserGetWindowObject(hWndCaret);
+
+ //fix: check for WndCaret can be null
+ if (WndCaret == Window ||
+ ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(Window, WndCaret)))
+ {
+ POINT pt, FromOffset, ToOffset, Offset;
+ RECT rcCaret;
+
+ pt.x = CaretInfo->Pos.x;
+ pt.y = CaretInfo->Pos.y;
+ IntGetClientOrigin(WndCaret, &FromOffset);
+ IntGetClientOrigin(Window, &ToOffset);
+ Offset.x = FromOffset.x - ToOffset.x;
+ Offset.y = FromOffset.y - ToOffset.y;
+ rcCaret.left = pt.x;
+ rcCaret.top = pt.y;
+ rcCaret.right = pt.x + CaretInfo->Size.cx;
+ rcCaret.bottom = pt.y + CaretInfo->Size.cy;
+ if (IntGdiIntersectRect(lprc, lprc, &rcCaret))
+ {
+ co_UserHideCaret(0);
+ lprc->left = pt.x;
+ lprc->top = pt.y;
+ return hWndCaret;
+ }
+ }
+
+ return 0;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+/*
+ * NtUserBeginPaint
+ *
+ * Status
+ * @implemented
+ */
+
+HDC STDCALL
+NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
+{
+ PWINDOW_OBJECT Window = NULL;
+ PAINTSTRUCT Ps;
+ PROSRGNDATA Rgn;
+ NTSTATUS Status;
+ DECLARE_RETURN(HDC);
+ USER_REFERENCE_ENTRY Ref;
+
+ DPRINT("Enter NtUserBeginPaint\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN( NULL);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+
+ co_UserHideCaret(Window);
+
+ if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
+ {
+ HRGN hRgn;
+
+ hRgn = IntGetNCUpdateRgn(Window, FALSE);
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
- GETCLIENTRECTW(Window, ClientRect);
-
- if ((HRGN) 1 < Window->UpdateRegion)
- {
- UnsafeIntGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
- NtGdiUnionRect(&Rect, &ClientRect, &UpdateRegionBox);
- if (Rect.left != ClientRect.left || Rect.top != ClientRect.top ||
- Rect.right != ClientRect.right || Rect.bottom != ClientRect.bottom)
- {
- hClip = Window->UpdateRegion;
- Window->UpdateRegion = REGION_CropRgn(hRgn, hClip,
- &ClientRect, NULL);
- if (Flags & UNC_REGION)
- {
- hRgnRet = hClip;
- }
- }
-
- if (Flags & UNC_CHECK)
- {
- UnsafeIntGetRgnBox(Window->UpdateRegion, &UpdateRegionBox);
- if (NtGdiIsEmptyRect(&UpdateRegionBox))
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- Window->UpdateRegion = NULL;
- if (0 == (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
- {
- MsqDecPaintCountQueue(Window->MessageQueue);
- }
- Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
- }
- }
-
- if (0 == hClip && 0 != Window->UpdateRegion)
- {
- goto copyrgn;
- }
- }
- else if ((HRGN) 1 == Window->UpdateRegion)
- {
- if (0 != (Flags & UNC_UPDATE))
- {
- Window->UpdateRegion =
- UnsafeIntCreateRectRgnIndirect(&ClientRect);
- }
- if (Flags & UNC_REGION)
- {
- hRgnRet = (HRGN) 1;
- }
- Flags |= UNC_ENTIRE;
- }
- }
- else /* no WM_NCPAINT unless forced */
- {
- if ((HRGN) 1 < Window->UpdateRegion)
- {
-copyrgn:
- if (0 != (Flags & UNC_REGION))
- {
- hRgnRet = REGION_CropRgn(hRgn, Window->UpdateRegion, NULL, NULL);
- }
- }
- else if ((HRGN) 1 == Window->UpdateRegion && 0 != (Flags & UNC_UPDATE))
- {
- GETCLIENTRECTW(Window, ClientRect);
- Window->UpdateRegion =
- UnsafeIntCreateRectRgnIndirect(&ClientRect);
- if (Flags & UNC_REGION)
- {
- hRgnRet = (HRGN) 1;
- }
- }
- }
-
- if (NULL == hClip && 0 != (Flags & UNC_ENTIRE))
- {
- if (RtlCompareMemory(&Window->WindowRect, &Window->ClientRect,
- sizeof(RECT)) != sizeof(RECT))
- {
- hClip = (HRGN) 1;
- }
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
+ if (hRgn != (HANDLE)1 && hRgn != NULL)
+ {
+ /* NOTE: The region can already by deleted! */
+ GDIOBJ_FreeObj(hRgn, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
+ }
+ }
+
+ RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
+
+ Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
+ if (!Ps.hdc)
+ {
+ RETURN(NULL);
+ }
+
+ if (Window->UpdateRegion != NULL)
+ {
+ MsqDecPaintCountQueue(Window->MessageQueue);
+ Rgn = RGNDATA_LockRgn(Window->UpdateRegion);
+ if (NULL != Rgn)
+ {
+ UnsafeIntGetRgnBox(Rgn, &Ps.rcPaint);
+ RGNDATA_UnlockRgn(Rgn);
+ IntGdiIntersectRect(&Ps.rcPaint, &Ps.rcPaint, &Window->ClientRect);
+ IntGdiOffsetRect(&Ps.rcPaint,
+ -Window->ClientRect.left,
+ -Window->ClientRect.top);
+ }
else
- {
- hClip = NULL;
- }
- }
-
- if (NULL != hClip) /* NOTE: WM_NCPAINT allows wParam to be 1 */
- {
- if (hClip == hRgnRet && (HRGN) 1 < hRgnRet)
- {
- hClip = NtGdiCreateRectRgn(0, 0, 0, 0);
- NtGdiCombineRgn(hClip, hRgnRet, 0, RGN_COPY);
- }
-
- NtUserSendMessage(Window->Self, WM_NCPAINT, (WPARAM) hClip, 0);
-
- if ((HRGN) 1 < hClip && hClip != hRgn && hClip != hRgnRet)
- {
- NtGdiDeleteObject(hClip);
- }
-
- /* FIXME: Need to check the window is still valid. */
- }
- return(hRgnRet);
+ {
+ IntGetClientRect(Window, &Ps.rcPaint);
+ }
+ GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
+ Window->UpdateRegion = NULL;
+ }
+ else
+ {
+ if (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
+ MsqDecPaintCountQueue(Window->MessageQueue);
+
+ IntGetClientRect(Window, &Ps.rcPaint);
+ }
+
+ Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
+
+ if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
+ {
+ Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
+ Ps.fErase = !co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)Ps.hdc, 0);
+ }
+ else
+ {
+ Ps.fErase = FALSE;
+ }
+
+ Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN(NULL);
+ }
+
+ RETURN(Ps.hdc);
+
+CLEANUP:
+ if (Window) UserDerefObjectCo(Window);
+
+ DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+
}
+/*
+ * NtUserEndPaint
+ *
+ * Status
+ * @implemented
+ */
+
BOOL STDCALL
NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
{
- NtUserReleaseDC(hWnd, lPs->hdc);
- /* FIXME: Show claret. */
- return(TRUE);
+ PWINDOW_OBJECT Window;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ DPRINT("Enter NtUserEndPaint\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(FALSE);
+ }
+
+ UserReleaseDC(Window, lPs->hdc, TRUE);
+
+ UserRefObjectCo(Window, &Ref);
+ co_UserShowCaret(Window);
+ UserDerefObjectCo(Window);
+
+ RETURN(TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+INT FASTCALL
+co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
+{
+ int RegionType;
+ RECT Rect;
+
+ ASSERT_REFS_CO(Window);
+
+ if (Window->UpdateRegion == NULL)
+ {
+ RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
+ }
+ else
+ {
+ Rect = Window->ClientRect;
+ IntIntersectWithParents(Window, &Rect);
+ NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
+ RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->UpdateRegion, RGN_AND);
+ NtGdiOffsetRgn(hRgn, -Window->ClientRect.left, -Window->ClientRect.top);
+ }
+
+ if (bErase && RegionType != NULLREGION && RegionType != ERROR)
+ {
+ co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+ }
+
+ return RegionType;
}
-static
-HRGN FASTCALL
-GetClientUpdateRegion(PWINDOW_OBJECT Window)
+/*
+ * NtUserGetUpdateRgn
+ *
+ * Status
+ * @implemented
+ */
+
+INT STDCALL
+NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
{
- POINT Offset;
- RECT Rect;
+ DECLARE_RETURN(INT);
+ PWINDOW_OBJECT Window;
+ INT ret;
+ USER_REFERENCE_ENTRY Ref;
- if ((DWORD) Window->UpdateRegion <= 1)
- {
- return Window->UpdateRegion;
- }
+ DPRINT("Enter NtUserGetUpdateRgn\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(ERROR);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+ ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
+ UserDerefObjectCo(Window);
- Offset.x = Window->WindowRect.left - Window->ClientRect.left;
- Offset.y = Window->WindowRect.top - Window->ClientRect.top;
- Rect.left = - Offset.x;
- Rect.top = - Offset.y;
- Rect.right = Rect.left + (Window->ClientRect.right - Window->ClientRect.left);
- Rect.bottom = Rect.top + (Window->ClientRect.bottom - Window->ClientRect.top);
+ RETURN(ret);
- return REGION_CropRgn(NULL, Window->UpdateRegion, &Rect, &Offset);
+CLEANUP:
+ DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
}
-HDC STDCALL
-NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
+/*
+ * NtUserGetUpdateRect
+ *
+ * Status
+ * @implemented
+ */
+
+BOOL STDCALL
+NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
{
- BOOL IsIcon;
- PWINDOW_OBJECT Window;
- HRGN UpdateRegion;
- RECT ClientRect;
- RECT ClipRect;
- //NTSTATUS Status;
- INT DcxFlags;
-
- if (!(Window = IntGetWindowObject(hWnd)))
- {
- SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
- return NULL;
- }
-
- /* Send WM_NCPAINT */
- PaintUpdateNCRegion(Window, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
-
- /* Check ifthe window is still valid. */
- if (!IntGetWindowObject(hWnd))
- {
- return 0;
- }
-
- /* retrieve update region */
- UpdateRegion = GetClientUpdateRegion(Window);
- if (1 < (DWORD) Window->UpdateRegion)
- {
- NtGdiDeleteObject(Window->UpdateRegion);
- }
- Window->UpdateRegion = 0;
- if (UpdateRegion != NULL || (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT))
- {
- MsqDecPaintCountQueue(Window->MessageQueue);
- }
- Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
-
- /* FIXME: Hide caret. */
-
- IsIcon = (Window->Style & WS_MINIMIZE) && IntGetClassLong(Window, GCL_HICON, FALSE);
-
- DcxFlags = DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE;
- if (IsIcon)
- {
- DcxFlags |= DCX_WINDOW;
- }
- if (IntGetClassLong(Window, GCL_STYLE, FALSE) & CS_PARENTDC)
- {
- /* Don't clip the output to the update region for CS_PARENTDC window */
- if ((HRGN) 1 < UpdateRegion)
- {
- NtGdiDeleteObject(UpdateRegion);
- }
- UpdateRegion = NULL;
- DcxFlags &= ~DCX_INTERSECTRGN;
- }
- else
- {
- if (NULL == UpdateRegion) /* empty region, clip everything */
- {
- UpdateRegion = NtGdiCreateRectRgn(0, 0, 0, 0);
- }
- else if ((HRGN) 1 == UpdateRegion) /* whole client area, don't clip */
- {
- UpdateRegion = NULL;
- DcxFlags &= ~DCX_INTERSECTRGN;
- }
- }
- lPs->hdc = NtUserGetDCEx(hWnd, UpdateRegion, DcxFlags);
-
- /* FIXME: Check for DC creation failure. */
-
- IntGetClientRect(Window, &ClientRect);
- NtGdiGetClipBox(lPs->hdc, &ClipRect);
- NtGdiLPtoDP(lPs->hdc, (LPPOINT)&ClipRect, 2);
- NtGdiIntersectRect(&lPs->rcPaint, &ClientRect, &ClipRect);
- NtGdiDPtoLP(lPs->hdc, (LPPOINT)&lPs->rcPaint, 2);
-
- if (Window->Flags & WINDOWOBJECT_NEED_ERASEBACKGRD)
- {
- BOOLEAN Result;
- Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBACKGRD;
- Result = NtUserSendMessage(hWnd,
- IsIcon ? WM_ICONERASEBKGND : WM_ERASEBKGND,
- (WPARAM)lPs->hdc,
- 0);
- lPs->fErase = !Result;
- }
- else
- {
- lPs->fErase = FALSE;
- }
-
- ObmDereferenceObject(Window);
- return(lPs->hdc);
+ PWINDOW_OBJECT Window;
+ RECT Rect;
+ INT RegionType;
+ PROSRGNDATA RgnData;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ DPRINT("Enter NtUserGetUpdateRect\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(FALSE);
+ }
+
+ if (Window->UpdateRegion == NULL)
+ {
+ Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
+ }
+ else
+ {
+ /* Get the update region bounding box. */
+ if (Window->UpdateRegion == (HRGN)1)
+ {
+ Rect = Window->ClientRect;
+ }
+ else
+ {
+ RgnData = RGNDATA_LockRgn(Window->UpdateRegion);
+ ASSERT(RgnData != NULL);
+ RegionType = UnsafeIntGetRgnBox(RgnData, &Rect);
+ RGNDATA_UnlockRgn(RgnData);
+
+ if (RegionType != ERROR && RegionType != NULLREGION)
+ IntGdiIntersectRect(&Rect, &Rect, &Window->ClientRect);
+ }
+
+ if (IntIntersectWithParents(Window, &Rect))
+ {
+ IntGdiOffsetRect(&Rect,
+ -Window->ClientRect.left,
+ -Window->ClientRect.top);
+ } else
+ {
+ Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
+ }
+ }
+
+ if (bErase && !IntGdiIsEmptyRect(&Rect))
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(Window, &Ref);
+ co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+ UserDerefObjectCo(Window);
+ }
+
+ if (UnsafeRect != NULL)
+ {
+ Status = MmCopyToCaller(UnsafeRect, &Rect, sizeof(RECT));
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+ }
+
+ RETURN(Window->UpdateRegion != NULL);
+
+CLEANUP:
+ DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
}
-DWORD
-STDCALL
-NtUserInvalidateRect(
- HWND hWnd,
- CONST RECT *Rect,
- WINBOOL Erase)
+/*
+ * NtUserRedrawWindow
+ *
+ * Status
+ * @implemented
+ */
+
+BOOL STDCALL
+NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
+ UINT flags)
{
- return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
+ RECT SafeUpdateRect;
+ NTSTATUS Status;
+ PWINDOW_OBJECT Wnd;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ DPRINT("Enter NtUserRedrawWindow\n");
+ UserEnterExclusive();
+
+ if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
+ {
+ RETURN( FALSE);
+ }
+
+ if (lprcUpdate != NULL)
+ {
+ Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate,
+ sizeof(RECT));
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN( FALSE);
+ }
+ }
+
+ UserRefObjectCo(Wnd, &Ref);
+
+ Status = co_UserRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
+ hrgnUpdate, flags);
+
+ UserDerefObjectCo(Wnd);
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* IntRedrawWindow fails only in case that flags are invalid */
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ RETURN( FALSE);
+ }
+
+ RETURN( TRUE);
+
+CLEANUP:
+ DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
}
-DWORD
-STDCALL
-NtUserInvalidateRgn(
- HWND hWnd,
- HRGN Rgn,
- WINBOOL Erase)
+
+
+static
+DWORD FASTCALL
+UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
+ const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
{
- return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
+ RECT rSrc, rClipped_src, rClip, rDst, offset;
+ PDC DC;
+
+ /*
+ * Compute device clipping region (in device coordinates).
+ */
+
+ DC = DC_LockDc(hDC);
+ if (NULL == DC)
+ {
+ return FALSE;
+ }
+ if (lprcScroll)
+ rSrc = *lprcScroll;
+ else
+ IntGdiGetClipBox(hDC, &rSrc);
+ IntLPtoDP(DC, (LPPOINT)&rSrc, 2);
+
+ if (lprcClip)
+ rClip = *lprcClip;
+ else
+ IntGdiGetClipBox(hDC, &rClip);
+ IntLPtoDP(DC, (LPPOINT)&rClip, 2);
+
+ IntGdiIntersectRect(&rClipped_src, &rSrc, &rClip);
+
+ rDst = rClipped_src;
+ IntGdiSetRect(&offset, 0, 0, dx, dy);
+ IntLPtoDP(DC, (LPPOINT)&offset, 2);
+ IntGdiOffsetRect(&rDst, offset.right - offset.left, offset.bottom - offset.top);
+ IntGdiIntersectRect(&rDst, &rDst, &rClip);
+
+ /*
+ * Copy bits, if possible.
+ */
+
+ if (rDst.bottom > rDst.top && rDst.right > rDst.left)
+ {
+ RECT rDst_lp = rDst, rSrc_lp = rDst;
+
+ IntGdiOffsetRect(&rSrc_lp, offset.left - offset.right, offset.top - offset.bottom);
+ IntDPtoLP(DC, (LPPOINT)&rDst_lp, 2);
+ IntDPtoLP(DC, (LPPOINT)&rSrc_lp, 2);
+ DC_UnlockDc(DC);
+
+ if (!NtGdiBitBlt(hDC, rDst_lp.left, rDst_lp.top, rDst_lp.right - rDst_lp.left,
+ rDst_lp.bottom - rDst_lp.top, hDC, rSrc_lp.left, rSrc_lp.top,
+ SRCCOPY))
+ return FALSE;
+ }
+ else
+ {
+ DC_UnlockDc(DC);
+ }
+
+ /*
+ * Compute update areas. This is the clipped source or'ed with the
+ * unclipped source translated minus the clipped src translated (rDst)
+ * all clipped to rClip.
+ */
+
+ if (hrgnUpdate || lprcUpdate)
+ {
+ HRGN hRgn = hrgnUpdate, hRgn2;
+
+ if (hRgn)
+ NtGdiSetRectRgn(hRgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
+ else
+ hRgn = NtGdiCreateRectRgn(rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
+
+ hRgn2 = UnsafeIntCreateRectRgnIndirect(&rSrc);
+ NtGdiOffsetRgn(hRgn2, offset.right - offset.left, offset.bottom - offset.top);
+ NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_OR);
+
+ NtGdiSetRectRgn(hRgn2, rDst.left, rDst.top, rDst.right, rDst.bottom);
+ NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_DIFF);
+
+ NtGdiSetRectRgn(hRgn2, rClip.left, rClip.top, rClip.right, rClip.bottom);
+ NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_AND);
+
+ if (lprcUpdate)
+ {
+ NtGdiGetRgnBox(hRgn, lprcUpdate);
+
+ /* Put the lprcUpdate in logical coordinate */
+ NtGdiDPtoLP(hDC, (LPPOINT)lprcUpdate, 2);
+ }
+ if (!hrgnUpdate)
+ NtGdiDeleteObject(hRgn);
+ NtGdiDeleteObject(hRgn2);
+ }
+ return TRUE;
}
-BOOL
-STDCALL
-NtUserValidateRgn(
- HWND hWnd,
- HRGN hRgn)
+
+
+
+/*
+ * NtUserScrollDC
+ *
+ * Status
+ * @implemented
+ */
+
+DWORD STDCALL
+NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
+ const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
{
- return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
+ DECLARE_RETURN(DWORD);
+
+ DPRINT("Enter NtUserScrollDC\n");
+ UserEnterExclusive();
+
+ RETURN( UserScrollDC(hDC, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate));
+
+CLEANUP:
+ DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+
}
-int
-STDCALL
-NtUserGetUpdateRgn(
- HWND hWnd,
- HRGN hRgn,
- WINBOOL bErase)
+/*
+ * NtUserScrollWindowEx
+ *
+ * Status
+ * @implemented
+ */
+
+DWORD STDCALL
+NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
+ const RECT *UnsafeClipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags)
{
- PWINDOW_OBJECT Window;
- int RegionType;
-
- if (!(Window = IntGetWindowObject(hWnd)))
- {
- SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
- return ERROR;
- }
-
- if (NULL == Window->UpdateRegion)
- {
- RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
- }
- else if ((HRGN) 1 == Window->UpdateRegion)
- {
- RegionType = (NtGdiSetRectRgn(hRgn,
- 0, 0,
- Window->ClientRect.right - Window->ClientRect.left,
- Window->ClientRect.bottom - Window->ClientRect.top) ?
- SIMPLEREGION : ERROR);
- }
- else
- {
- RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
- NtGdiOffsetRgn(hRgn, Window->WindowRect.left - Window->ClientRect.left,
- Window->WindowRect.top - Window->ClientRect.top );
- }
-
- if (bErase &&
- (SIMPLEREGION == RegionType || COMPLEXREGION == RegionType))
- {
- PaintRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN, 0);
- }
-
- IntReleaseWindowObject(Window);
-
- return RegionType;
+ RECT rc, cliprc, caretrc, rect, clipRect;
+ INT Result;
+ PWINDOW_OBJECT Window = NULL, CaretWnd;
+ HDC hDC;
+ HRGN hrgnTemp;
+ HWND hwndCaret;
+ BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
+ BOOL bOwnRgn = TRUE;
+ NTSTATUS Status;
+ DECLARE_RETURN(DWORD);
+ USER_REFERENCE_ENTRY Ref, CaretRef;
+
+ DPRINT("Enter NtUserScrollWindowEx\n");
+ UserEnterExclusive();
+
+ Window = UserGetWindowObject(hWnd);
+ if (!Window || !IntIsWindowDrawable(Window))
+ {
+ Window = NULL; /* prevent deref at cleanup */
+ RETURN( ERROR);
+ }
+ UserRefObjectCo(Window, &Ref);
+
+ IntGetClientRect(Window, &rc);
+
+ if (NULL != UnsafeRect)
+ {
+ Status = MmCopyFromCaller(&rect, UnsafeRect, sizeof(RECT));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( ERROR);
+ }
+ IntGdiIntersectRect(&rc, &rc, &rect);
+ }
+
+ if (NULL != UnsafeClipRect)
+ {
+ Status = MmCopyFromCaller(&clipRect, UnsafeClipRect, sizeof(RECT));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( ERROR);
+ }
+ IntGdiIntersectRect(&cliprc, &rc, &clipRect);
+ }
+ else
+ cliprc = rc;
+
+ if (cliprc.right <= cliprc.left || cliprc.bottom <= cliprc.top ||
+ (dx == 0 && dy == 0))
+ {
+ RETURN( NULLREGION);
+ }
+
+ caretrc = rc;
+ hwndCaret = co_IntFixCaret(Window, &caretrc, flags);
+
+ if (hrgnUpdate)
+ bOwnRgn = FALSE;
+ else if (bUpdate)
+ hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
+
+ hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE);
+ if (hDC)
+ {
+ UserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
+ UserReleaseDC(Window, hDC, FALSE);
+ }
+
+ /*
+ * Take into account the fact that some damage may have occurred during
+ * the scroll.
+ */
+
+ hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+ Result = co_UserGetUpdateRgn(Window, hrgnTemp, FALSE);
+ if (Result != NULLREGION)
+ {
+ HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&cliprc);
+ NtGdiOffsetRgn(hrgnTemp, dx, dy);
+ NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
+ co_UserRedrawWindow(Window, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
+ NtGdiDeleteObject(hrgnClip);
+ }
+
+ NtGdiDeleteObject(hrgnTemp);
+
+ if (flags & SW_SCROLLCHILDREN)
+ {
+ HWND *List = IntWinListChildren(Window);
+ if (List)
+ {
+ int i;
+ RECT r, dummy;
+ POINT ClientOrigin;
+ PWINDOW_OBJECT Wnd;
+ USER_REFERENCE_ENTRY WndRef;
+
+ IntGetClientOrigin(Window, &ClientOrigin);
+ for (i = 0; List[i]; i++)
+ {
+ if (!(Wnd = UserGetWindowObject(List[i])))
+ continue;
+
+ r = Wnd->WindowRect;
+ r.left -= ClientOrigin.x;
+ r.top -= ClientOrigin.y;
+ r.right -= ClientOrigin.x;
+ r.bottom -= ClientOrigin.y;
+
+ if (! UnsafeRect || IntGdiIntersectRect(&dummy, &r, &rc))
+ {
+ UserRefObjectCo(Wnd, &WndRef);
+ co_WinPosSetWindowPos(Wnd, 0, r.left + dx, r.top + dy, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
+ SWP_NOREDRAW);
+ UserDerefObjectCo(Wnd);
+ }
+
+ }
+ ExFreePool(List);
+ }
+ }
+
+ if (flags & (SW_INVALIDATE | SW_ERASE))
+ co_UserRedrawWindow(Window, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
+ ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
+ ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
+
+ if (bOwnRgn && hrgnUpdate)
+ NtGdiDeleteObject(hrgnUpdate);
+
+ if ((CaretWnd = UserGetWindowObject(hwndCaret)))
+ {
+ UserRefObjectCo(CaretWnd, &CaretRef);
+
+ co_IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
+ co_UserShowCaret(CaretWnd);
+
+ UserDerefObjectCo(CaretWnd);
+ }
+
+ RETURN(Result);
+
+CLEANUP:
+ if (Window)
+ UserDerefObjectCo(Window);
+
+ DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
}
/* EOF */