Check the update rect, not the region. The region might contain only non-client
[reactos.git] / reactos / subsys / win32k / ntuser / painting.c
index 8341227..0f8d1c9 100644 (file)
@@ -16,7 +16,7 @@
  *  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.62 2004/01/17 15:18:25 navaraf Exp $
+ *  $Id$
  *
  *  COPYRIGHT:        See COPYING in the top level directory
  *  PROJECT:          ReactOS kernel
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/safe.h>
-#include <win32k/win32k.h>
-#include <include/object.h>
-#include <include/guicheck.h>
-#include <include/window.h>
-#include <include/desktop.h>
-#include <include/winpos.h>
-#include <include/class.h>
-#include <include/caret.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 <include/intgdi.h>
+#include <w32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* #define FIN_DEBUG */
-
 /* PRIVATE FUNCTIONS **********************************************************/
 
-VOID FASTCALL
-IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
+/**
+ * @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.
+ */
+
+BOOL FASTCALL
+IntIntersectWithParents(PWINDOW_OBJECT Child, PRECT WindowRect)
 {
-   HWND Parent;
    PWINDOW_OBJECT ParentWindow;
 
-#ifdef FIN_DEBUG
+   ParentWindow = Child->Parent;
+   while (ParentWindow != NULL)
    {
-      RECT TempRect;
-      UnsafeIntGetRgnBox(ValidRegion, &TempRect);
-      DPRINT1("IntValidateParent ('%wZ', %d,%d-%d,%d)\n",
-         &Child->WindowName, TempRect.left, TempRect.top, TempRect.right, TempRect.bottom);
+      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;
    }
-#endif
-   Parent = NtUserGetAncestor(Child->Self, GA_PARENT);
-   while (Parent)
+
+   return TRUE;
+}
+
+VOID FASTCALL
+IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
+{
+   PWINDOW_OBJECT ParentWindow = Child->Parent;
+
+   while (ParentWindow)
    {
-      ParentWindow = IntGetWindowObject(Parent);
-      if (ParentWindow && !(ParentWindow->Style & WS_CLIPCHILDREN))
-      {
-         if (ParentWindow->UpdateRegion != 0)
-         {
-            INT OffsetX, OffsetY;
+      if (ParentWindow->Style & WS_CLIPCHILDREN)
+         break;      
 
-            /*
-             * We must offset the child region by the offset of the
-             * child rect in the parent.
-             */
-            OffsetX = Child->WindowRect.left - ParentWindow->WindowRect.left;
-            OffsetY = Child->WindowRect.top - ParentWindow->WindowRect.top;
-            NtGdiOffsetRgn(ValidRegion, OffsetX, OffsetY);
-            NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
-               ValidRegion, RGN_DIFF);
-            /* FIXME: If the resulting region is empty, remove fake posted paint message */
-            NtGdiOffsetRgn(ValidRegion, -OffsetX, -OffsetY);
-         }
+      if (ParentWindow->UpdateRegion != 0)
+      {
+         NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
+            ValidRegion, RGN_DIFF);
+         /* FIXME: If the resulting region is empty, remove fake posted paint message */
       }
-      IntReleaseWindowObject(ParentWindow);
-      Parent = NtUserGetAncestor(Parent, GA_PARENT);
+
+      ParentWindow = ParentWindow->Parent;
    }
 }
 
-/*
- * IntGetNCUpdateRegion
+/**
+ * @name IntCalcWindowRgn
  *
- * Get nonclient part of window update region. 
- * 
- * Return Value
- *    Handle to region that represents invalid nonclient window area. The
- *    caller is responsible for deleting it.
- *
- * Remarks
- *    This function also marks the nonclient update region of window
- *    as valid, clears the WINDOWOBJECT_NEED_NCPAINT flag.
+ * Get a window or client region.
  */
 
 HRGN FASTCALL
-IntGetNCUpdateRegion(PWINDOW_OBJECT Window)
+IntCalcWindowRgn(PWINDOW_OBJECT Window, BOOL Client)
 {
-   HRGN WindowRgn;
-   HRGN NonclientRgn;
+   HRGN hRgnWindow;
+   UINT RgnType;
 
-   /*
-    * Generate the update region.
-    */
+   if (Client)
+      hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
+   else
+      hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
 
-   WindowRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
-   NtGdiOffsetRgn(WindowRgn, 
-      -Window->WindowRect.left,
-      -Window->WindowRect.top);
-   NonclientRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
-   if (NtGdiCombineRgn(NonclientRgn, Window->UpdateRegion,
-       WindowRgn, RGN_DIFF) == NULLREGION)
+   if (Window->WindowRegion != NULL && !(Window->Style & WS_MINIMIZE))
    {
-      NtGdiDeleteObject(NonclientRgn);
-      NonclientRgn = NULL;
+      NtGdiOffsetRgn(hRgnWindow,
+         -Window->WindowRect.left,
+         -Window->WindowRect.top);
+      RgnType = NtGdiCombineRgn(hRgnWindow, hRgnWindow, Window->WindowRegion, RGN_AND);
+      NtGdiOffsetRgn(hRgnWindow,
+         Window->WindowRect.left,
+         Window->WindowRect.top);
    }
 
-   /*
-    * Remove the nonclient region from the standard update region.
-    */
+   return hRgnWindow;
+}
+
+/**
+ * @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.
+ */
 
-   if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
-       WindowRgn, RGN_AND) == NULLREGION)
+HRGN FASTCALL
+IntGetNCUpdateRgn(PWINDOW_OBJECT Window, BOOL Validate)
+{
+   HRGN hRgnNonClient;
+   HRGN hRgnWindow;
+   UINT RgnType;
+   
+   if (Window->UpdateRegion != NULL &&
+       Window->UpdateRegion != (HRGN)1)
    {
-      NtGdiDeleteObject(Window->UpdateRegion);
-      Window->UpdateRegion = NULL;
-   }
+      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 NonclientRgn;
+      return hRgnNonClient;
+   }
+   else
+   {
+      return Window->UpdateRegion;
+   }
 }
 
 /*
@@ -156,111 +218,92 @@ IntGetNCUpdateRegion(PWINDOW_OBJECT Window)
  * Internal function used by IntRedrawWindow.
  */
 
-VOID FASTCALL
-IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
+STATIC VOID FASTCALL
+co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
 {
-  HDC hDC;
-  HWND hWnd = Window->Self;
+   HDC hDC;
+   HWND hWnd = Window->hSelf;
+   HRGN TempRegion;
 
-  if (! (Window->Style & WS_VISIBLE))
-    {
-      return;
-    }
-
-  if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
-    {
-      if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
-        {
-          IntValidateParent(Window, Window->NCUpdateRegion);
-          IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)Window->NCUpdateRegion, 0);
-          Window->NCUpdateRegion = NULL;
-          Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
-          MsqDecPaintCountQueue(Window->MessageQueue);
-        }
-
-      if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
-        {
-          if (Window->UpdateRegion)
-            {
-#ifdef FIN_DEBUG
-              {
-                 RECT TempRect;
-                 UnsafeIntGetRgnBox(Window->UpdateRegion, &TempRect);
-                 DPRINT1("Sending WM_ERASEBKGND[1]: %d,%d-%d,%d\n",
-                    TempRect.left, TempRect.top, TempRect.right, TempRect.bottom);
-              }
-#endif
-              IntValidateParent(Window, Window->UpdateRegion);
-              hDC = NtUserGetDCEx(hWnd, 0, DCX_CACHE | DCX_USESTYLE |
-                                           DCX_INTERSECTUPDATE);
-              if (hDC != NULL)
-                {
-                  if (IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
-                    {
-                      Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
-                    }
-                  NtUserReleaseDC(hWnd, hDC);
-                }
-            }
-        }
+   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)
+      {
+         if (Window->UpdateRegion != NULL ||
+             Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
+         {
+            co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+         }
+      }
+      else
+      {
+         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)
             {
-#ifdef FIN_DEBUG
-              {
-                 RECT TempRect;
-                 UnsafeIntGetRgnBox(Window->UpdateRegion, &TempRect);
-                 DPRINT1("Sending WM_PAINT[1]: %d,%d-%d,%d\n",
-                    TempRect.left, TempRect.top, TempRect.right, TempRect.bottom);
-              }
-#endif
-              IntSendMessage(hWnd, WM_PAINT, 0, 0);
-              if (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
-                {
-                  Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
-                  if (Window->UpdateRegion == NULL)
-                    {
-                      MsqDecPaintCountQueue(Window->MessageQueue);
-                    }
-                }
+               /* NOTE: The region can already be deleted! */
+               GDIOBJ_FreeObj(TempRegion, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
             }
-        }
-    }
+         }
 
-  /*
-   * Check that the window is still valid at this point
-   */
+         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);
+            }
+         }
+      }
+   }
 
-  if (! IntIsWindow(hWnd))
-    {
+   /*
+    * 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)))
-    {
+   }
+
+   /*
+    * 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)
+      {
+         for (phWnd = List; *phWnd; ++phWnd)
+         {
+            Window = UserGetWindowObject(*phWnd);
+            if (Window && (Window->Style & WS_VISIBLE))
             {
-              Window = IntGetWindowObject(*phWnd);
-              if (Window)
-                {
-                  IntPaintWindows(Window, Flags);
-                  IntReleaseWindowObject(Window);
-                }
+               USER_REFERENCE_ENTRY Ref;
+               UserRefObjectCo(Window, &Ref);
+               co_IntPaintWindows(Window, Flags);
+               UserDerefObjectCo(Window);
             }
-          ExFreePool(List);
-        }
-    }
+         }
+         ExFreePool(List);
+      }
+   }
 }
 
 /*
@@ -270,42 +313,41 @@ IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
  */
 
 VOID FASTCALL
-IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
-   BOOL ValidateParent)
+IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
 {
    INT RgnType;
    BOOL HadPaintMessage, HadNCPaintMessage;
    BOOL HasPaintMessage, HasNCPaintMessage;
-   HRGN hRgnWindow;
 
    /*
     * Clip the given region with window rectangle (or region)
     */
 
-#ifdef TODO
-   if (!Window->WindowRegion)
-#endif
+   if (!Window->WindowRegion || (Window->Style & WS_MINIMIZE))
    {
+      HRGN hRgnWindow;
+
       hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
-      NtGdiOffsetRgn(hRgnWindow,
-         -Window->WindowRect.left,
-         -Window->WindowRect.top);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);        
+      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
       NtGdiDeleteObject(hRgnWindow);
    }
-#ifdef TODO
    else
    {
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);        
+      NtGdiOffsetRgn(hRgn,
+         -Window->WindowRect.left,
+         -Window->WindowRect.top);
+      RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);
+      NtGdiOffsetRgn(hRgn,
+         Window->WindowRect.left,
+         Window->WindowRect.top);
    }
-#endif
 
    /*
     * Save current state of pending updates
     */
 
    HadPaintMessage = Window->UpdateRegion != NULL ||
-      Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
+                     Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
    HadNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
 
    /*
@@ -317,11 +359,13 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
       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)
+                          hRgn, RGN_OR) == NULLREGION)
       {
+         GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
          NtGdiDeleteObject(Window->UpdateRegion);
          Window->UpdateRegion = NULL;
       }
@@ -339,8 +383,9 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
       if (Window->UpdateRegion != NULL)
       {
          if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
-             hRgn, RGN_DIFF) == NULLREGION)
+                             hRgn, RGN_DIFF) == NULLREGION)
          {
+            GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
             NtGdiDeleteObject(Window->UpdateRegion);
             Window->UpdateRegion = NULL;
          }
@@ -364,74 +409,37 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
       Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
    }
 
-   /*
-    * Validate parent covered by region
-    */
-
-   if (ValidateParent)
-   {
-      IntValidateParent(Window, Window->UpdateRegion);
-   }
-
-   /*
-    * Split the nonclient update region.
-    */
-
-   if (Window->NCUpdateRegion == NULL)
-   {
-      Window->NCUpdateRegion = IntGetNCUpdateRegion(Window);
-   }
-   else
-   {
-      HRGN hRgnNonClient = IntGetNCUpdateRegion(Window);
-      NtGdiCombineRgn(Window->NCUpdateRegion, Window->NCUpdateRegion,
-         hRgnNonClient, RGN_OR);
-      NtGdiDeleteObject(hRgnNonClient);
-   }
-
    /*
     * Process children if needed
     */
 
    if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
-       ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
+         ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
    {
-      HWND *List, *phWnd;
       PWINDOW_OBJECT Child;
 
-      if ((List = IntWinListChildren(Window)))
+      for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
       {
-         for (phWnd = List; *phWnd; ++phWnd)
+         if (Child->Style & WS_VISIBLE)
          {
-            Child = IntGetWindowObject(*phWnd);
-            if(!Child)
-            {
-              continue;
-            }
-            if (Child->Style & WS_VISIBLE)
-            {
-               /*
-                * Recursive call to update children UpdateRegion
-                */
-               HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
-               NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
-               NtGdiOffsetRgn(hRgnTemp,
-                  Window->WindowRect.left - Child->WindowRect.left,
-                  Window->WindowRect.top - Child->WindowRect.top);
-               IntInvalidateWindows(Child, hRgnTemp, Flags, FALSE);
-               NtGdiDeleteObject(hRgnTemp);
-            }
-            IntReleaseWindowObject(Child);
+            /*
+             * 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);
          }
-         ExFreePool(List);
+
       }
    }
 
    /*
     * Fake post paint messages to window message queue if needed
     */
+
    HasPaintMessage = Window->UpdateRegion != NULL ||
-         Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
+                     Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
    HasNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
 
    if (HasPaintMessage != HadPaintMessage)
@@ -449,6 +457,7 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
       else
          MsqIncPaintCountQueue(Window->MessageQueue);
    }
+
 }
 
 /*
@@ -462,13 +471,15 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags,
 BOOL FASTCALL
 IntIsWindowDrawable(PWINDOW_OBJECT Window)
 {
-   PWINDOW_OBJECT Wnd = Window;
-   
-   for (; Wnd; Wnd = Wnd->Parent)
+   PWINDOW_OBJECT Wnd;
+
+   for (Wnd = Window; Wnd != NULL; Wnd = Wnd->Parent)
    {
       if (!(Wnd->Style & WS_VISIBLE) ||
-          ((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
+            ((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
+      {
          return FALSE;
+      }
    }
 
    return TRUE;
@@ -482,8 +493,8 @@ IntIsWindowDrawable(PWINDOW_OBJECT Window)
  */
 
 BOOL FASTCALL
-IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
-   ULONG Flags)
+co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
+                    ULONG Flags)
 {
    HRGN hRgn = NULL;
 
@@ -493,8 +504,8 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
     */
 
    if (!IntIsWindowDrawable(Window) ||
-       (Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
-       (RDW_VALIDATE | RDW_INVALIDATE))
+         (Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
+         (RDW_VALIDATE | RDW_INVALIDATE))
    {
       return FALSE;
    }
@@ -502,7 +513,7 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
    /*
     * Step 2.
     * Transform the parameters UpdateRgn and UpdateRect into
-    * a region hRgn specified in window coordinates.
+    * a region hRgn specified in screen coordinates.
     */
 
    if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
@@ -510,32 +521,29 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
       if (UpdateRgn != NULL)
       {
          hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
-         NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY);
-         NtGdiOffsetRgn(hRgn, 
-            Window->ClientRect.left - Window->WindowRect.left,
-            Window->ClientRect.top - Window->WindowRect.top);
-      } else
-      if (UpdateRect != NULL)
+         if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+            NtGdiDeleteObject(hRgn);
+         else
+            NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
+      }
+      else if (UpdateRect != NULL)
       {
-         hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
-         NtGdiOffsetRgn(hRgn, 
-            Window->ClientRect.left - Window->WindowRect.left,
-            Window->ClientRect.top - Window->WindowRect.top);
-      } else
-      if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
-          (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
+         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))
       {
-         hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
-         NtGdiOffsetRgn(hRgn, 
-            -Window->WindowRect.left,
-            -Window->WindowRect.top);
+         if (!IntGdiIsEmptyRect(&Window->WindowRect))
+            hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
       }
       else
       {
-         hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
-         NtGdiOffsetRgn(hRgn, 
-            -Window->WindowRect.left,
-            -Window->WindowRect.top);
+         if (!IntGdiIsEmptyRect(&Window->ClientRect))
+            hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
       }
    }
 
@@ -544,15 +552,10 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
     * Adjust the window update region depending on hRgn and flags.
     */
 
-   if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))
-   {
-      IntInvalidateWindows(Window, hRgn, Flags, TRUE);
-   } else
-   if (Window->UpdateRegion != NULL && (Flags & (RDW_ERASENOW | RDW_UPDATENOW)))
+   if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
+       hRgn != NULL)
    {
-      /* Validate parent covered by region. */
-      IntValidateParent(Window, Window->UpdateRegion);
-      IntValidateParent(Window, Window->NCUpdateRegion);
+      IntInvalidateWindows(Window, hRgn, Flags);
    }
 
    /*
@@ -562,7 +565,7 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
 
    if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
    {
-      IntPaintWindows(Window, Flags);
+      co_IntPaintWindows(Window, Flags);
    }
 
    /*
@@ -570,7 +573,7 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
     * Cleanup ;-)
     */
 
-   if (NULL != hRgn)
+   if (hRgn != NULL)
    {
       NtGdiDeleteObject(hRgn);
    }
@@ -578,159 +581,125 @@ IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
    return TRUE;
 }
 
-HWND STDCALL
-IntFindWindowToRepaint(HWND hWnd, PW32THREAD Thread)
+BOOL FASTCALL
+IntIsWindowDirty(PWINDOW_OBJECT Window)
 {
-   PWINDOW_OBJECT Window;
-   PWINDOW_OBJECT Child;
-   HWND hFoundWnd = NULL;
-
-   Window = IntGetWindowObject(hWnd);
-   if (Window == NULL)
-      return NULL;
-
-   if ((Window->UpdateRegion != NULL ||
-       Window->Flags & (WINDOWOBJECT_NEED_INTERNALPAINT | WINDOWOBJECT_NEED_NCPAINT)) && 
-       IntWndBelongsToThread(Window, Thread))
-   {
-      IntReleaseWindowObject(Window);
-      return hWnd;
-   }
+   return (Window->Style & WS_VISIBLE) &&
+          ((Window->UpdateRegion != NULL) ||
+           (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) ||
+           (Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
+}
 
-   ExAcquireFastMutex(&Window->ChildrenListLock);
+HWND FASTCALL
+IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
+{
+   HWND hChild;
+   PWINDOW_OBJECT TempWindow;
 
-   for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
+   for (; Window != NULL; Window = Window->NextSibling)
    {
-      if (Child->Style & WS_VISIBLE &&
-          (Child->UpdateRegion != NULL ||
-           Child->Flags & WINDOWOBJECT_NEED_INTERNALPAINT ||
-           Child->Flags & WINDOWOBJECT_NEED_NCPAINT)
-          && IntWndBelongsToThread(Child, Thread))
+      if (IntWndBelongsToThread(Window, Thread) &&
+          IntIsWindowDirty(Window))
       {
-         hFoundWnd = Child->Self;
-         break;
+         /* 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 (hFoundWnd == NULL)
-   {
-      for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
+      if (Window->FirstChild)
       {
-         if (Child->Style & WS_VISIBLE)
-         {
-            hFoundWnd = IntFindWindowToRepaint(Child->Self, Thread);
-            if (hFoundWnd != NULL)
-               break;
-         }
+         hChild = IntFindWindowToRepaint(Window->FirstChild, Thread);
+         if (hChild != NULL)
+            return hChild;
       }
    }
 
-   ExReleaseFastMutex(&Window->ChildrenListLock);
-   IntReleaseWindowObject(Window);
-
-   return hFoundWnd;
+   return NULL;
 }
 
 BOOL FASTCALL
-IntGetPaintMessage(HWND hWnd, PW32THREAD Thread, MSG *Message,
-   BOOL Remove)
+IntGetPaintMessage(HWND hWnd, UINT MsgFilterMin, UINT MsgFilterMax,
+                   PW32THREAD Thread, MSG *Message, BOOL Remove)
 {
-   PWINDOW_OBJECT Window;
    PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
 
-   if (!MessageQueue->PaintPosted)
+   if (!MessageQueue->PaintCount)
       return FALSE;
 
-   if (hWnd)
-      Message->hwnd = IntFindWindowToRepaint(hWnd, PsGetWin32Thread());
-   else
-      Message->hwnd = IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
+   if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
+         (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
+      return FALSE;
+
+   Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetWin32Thread());
 
    if (Message->hwnd == NULL)
    {
-#if 0
       DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
-#endif
-      /* FIXME: Lock the queue! */
-      MessageQueue->PaintPosted = 0;
-      MessageQueue->PaintCount = 0;
       return FALSE;
    }
 
-   Window = IntGetWindowObject(Message->hwnd);
-   if (Window != NULL)
-   {
-      if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
-      {
-         Message->message = WM_NCPAINT;
-         Message->wParam = (WPARAM)Window->NCUpdateRegion;
-         Message->lParam = 0;
-         if (Remove)
-         {
-            Window->NCUpdateRegion = NULL;
-            Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
-            MsqDecPaintCountQueue(Window->MessageQueue);
-         }
-      } else
-      {
-#ifdef FIN_DEBUG
-         {
-            RECT TempRect;
-            UnsafeIntGetRgnBox(Window->UpdateRegion, &TempRect);
-            DPRINT1("Sending WM_PAINT[2]: %d,%d-%d,%d\n",
-               TempRect.left, TempRect.top, TempRect.right, TempRect.bottom);
-         }
-#endif
-         Message->message = WM_PAINT;
-         Message->wParam = Message->lParam = 0;
-         if (Remove && Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
-         {
-            Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
-            if (Window->UpdateRegion == NULL)
-            {
-               MsqDecPaintCountQueue(Window->MessageQueue);
-            }
-         }
-      }
+   if (hWnd != NULL && Message->hwnd != hWnd)
+      return FALSE;
 
-      IntReleaseWindowObject(Window);
-      return TRUE;
-   }
+   Message->message = WM_PAINT;
+   Message->wParam = Message->lParam = 0;
 
-   return FALSE;
+   return TRUE;
 }
 
+static
 HWND FASTCALL
-IntFixCaret(HWND hWnd, LPRECT lprc, UINT flags)
+co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
 {
-   GUITHREADINFO info;
-
-   if (!NtUserGetGUIThreadInfo(0, &info))
-      return 0;
-   if (!info.hwndCaret)
-      return 0;
-   if (info.hwndCaret == hWnd ||
-       ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(hWnd, info.hwndCaret)))
+   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;
-      
-      pt.x = info.rcCaret.left;
-      pt.y = info.rcCaret.top;
+      RECT rcCaret;
 
-      IntGetClientOrigin(info.hwndCaret, &FromOffset);
-      IntGetClientOrigin(hWnd, &ToOffset);
+      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;
-      info.rcCaret.left += Offset.x;
-      info.rcCaret.top += Offset.y;
-      info.rcCaret.right += Offset.x;
-      info.rcCaret.bottom += Offset.y;
-      if (NtGdiIntersectRect(lprc, lprc, &info.rcCaret))
+      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))
       {
-         NtUserHideCaret(0);
+         co_UserHideCaret(0);
          lprc->left = pt.x;
          lprc->top = pt.y;
-         return info.hwndCaret;
+         return hWndCaret;
       }
    }
 
@@ -747,76 +716,106 @@ IntFixCaret(HWND hWnd, LPRECT lprc, UINT flags)
  */
 
 HDC STDCALL
-NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
+NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
 {
-   PWINDOW_OBJECT Window;
-   RECT ClientRect;
-   RECT ClipRect;
-   INT DcxFlags;
-   PDC DC;
+   PWINDOW_OBJECT Window = NULL;
+   PAINTSTRUCT Ps;
+   PROSRGNDATA Rgn;
+   NTSTATUS Status;
+   DECLARE_RETURN(HDC);
+   USER_REFERENCE_ENTRY Ref;
 
-   if (!(Window = IntGetWindowObject(hWnd)))
+   DPRINT("Enter NtUserBeginPaint\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
    {
-      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-      return NULL;
+      RETURN( NULL);
    }
 
-   NtUserHideCaret(hWnd);
-
-   DcxFlags = DCX_INTERSECTUPDATE | DCX_WINDOWPAINT | DCX_USESTYLE;
+   UserRefObjectCo(Window, &Ref);
    
-   lPs->hdc = NtUserGetDCEx(hWnd, 0, DcxFlags);
+   co_UserHideCaret(Window);
 
-   if (!lPs->hdc)
+   if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
    {
-      IntReleaseWindowObject(Window);
-      return NULL;
+      HRGN hRgn;
+
+      hRgn = IntGetNCUpdateRgn(Window, FALSE);
+      Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
+      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);
+      }
    }
 
-#ifdef FIN_DEBUG
-   if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
+   RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
+
+   Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
+   if (!Ps.hdc)
    {
-      RECT TempRect;
-      UnsafeIntGetRgnBox(Window->UpdateRegion, &TempRect);
-      DPRINT1("Sending WM_ERASEBKGND[2]: %d,%d-%d,%d\n",
-         TempRect.left, TempRect.top, TempRect.right, TempRect.bottom);
+      RETURN(NULL);
    }
-#endif
-   
+
    if (Window->UpdateRegion != NULL)
    {
       MsqDecPaintCountQueue(Window->MessageQueue);
-      IntValidateParent(Window, Window->UpdateRegion);
-      NtGdiDeleteObject(Window->UpdateRegion);
+      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
+      {
+         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);
+   }
 
-   IntGetClientRect(Window, &ClientRect);
-   IntGdiGetClipBox(lPs->hdc, &ClipRect);
-   DC = DC_LockDc(lPs->hdc);
-   if (NULL == DC)
-     {
-       IntReleaseWindowObject(Window);
-       return NULL;
-     }
-   IntLPtoDP(DC, (LPPOINT)&ClipRect, 2);
-   DC_UnlockDc(lPs->hdc);
-   NtGdiIntersectRect(&lPs->rcPaint, &ClientRect, &ClipRect);
-   NtGdiDPtoLP(lPs->hdc, (LPPOINT)&lPs->rcPaint, 2);
+   Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
 
    if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
    {
       Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
-      lPs->fErase = !IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)lPs->hdc, 0);
+      Ps.fErase = !co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)Ps.hdc, 0);
    }
    else
    {
-      lPs->fErase = FALSE;
+      Ps.fErase = FALSE;
+   }
+
+   Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN(NULL);
    }
 
-   IntReleaseWindowObject(Window);
+   RETURN(Ps.hdc);
+
+CLEANUP:
+   if (Window) UserDerefObjectCo(Window);
+   
+   DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 
-   return lPs->hdc;
 }
 
 /*
@@ -829,62 +828,60 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
 BOOL STDCALL
 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
 {
-   NtUserReleaseDC(hWnd, lPs->hdc);
-   NtUserShowCaret(hWnd);
+   PWINDOW_OBJECT Window;
+   DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
 
-   return TRUE;
-}
+   DPRINT("Enter NtUserEndPaint\n");
+   UserEnterExclusive();
 
-/*
- * NtUserInvalidateRect
- *
- * Status
- *    @implemented
- */
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(FALSE);
+   }
 
-DWORD STDCALL
-NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
-}
+   UserReleaseDC(Window, lPs->hdc, TRUE);
 
-/*
- * NtUserInvalidateRgn
- *
- * Status
- *    @implemented
- */
+   UserRefObjectCo(Window, &Ref);
+   co_UserShowCaret(Window);
+   UserDerefObjectCo(Window);
 
-DWORD STDCALL
-NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
+   RETURN(TRUE);
+
+CLEANUP:
+   DPRINT("Leave NtUserEndPaint, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
-/*
- * NtUserValidateRgn
- *
- * Status
- *    @implemented
- */
 
-BOOL STDCALL
-NtUserValidateRgn(HWND hWnd, HRGN hRgn)
+INT FASTCALL
+co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
 {
-   return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
-}
+   int RegionType;
+   RECT Rect;
 
-/*
- * NtUserUpdateWindow
- *
- * Status
- *    @implemented
- */
-BOOL STDCALL
-NtUserUpdateWindow(HWND hWnd)
-{
-   return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
+   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;
 }
 
 /*
@@ -897,36 +894,29 @@ NtUserUpdateWindow(HWND hWnd)
 INT STDCALL
 NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
 {
+   DECLARE_RETURN(INT);
    PWINDOW_OBJECT Window;
-   int RegionType;
+   INT ret;
+   USER_REFERENCE_ENTRY Ref;
 
-   if (!(Window = IntGetWindowObject(hWnd)))
-   {
-      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-      return ERROR;
-   }
-    
-   if (Window->UpdateRegion == NULL)
-   {
-      RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
-   }
-   else
+   DPRINT("Enter NtUserGetUpdateRgn\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
    {
-      RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
-      NtGdiOffsetRgn(
-         hRgn,
-         Window->WindowRect.left - Window->ClientRect.left,
-         Window->WindowRect.top - Window->ClientRect.top);
+      RETURN(ERROR);
    }
 
-   IntReleaseWindowObject(Window);
+   UserRefObjectCo(Window, &Ref);
+   ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
+   UserDerefObjectCo(Window);
 
-   if (bErase && RegionType != NULLREGION && RegionType != ERROR)
-   {
-      NtUserRedrawWindow(hWnd, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
-   }
-  
-   return RegionType;
+   RETURN(ret);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 /*
@@ -937,20 +927,80 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
  */
 
 BOOL STDCALL
-NtUserGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL fErase)
+NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
 {
-   HRGN hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
+   PWINDOW_OBJECT Window;
+   RECT Rect;
+   INT RegionType;
+   PROSRGNDATA RgnData;
+   NTSTATUS Status;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserGetUpdateRect\n");
+   UserEnterExclusive();
 
-   if (!lpRect)
+   if (!(Window = UserGetWindowObject(hWnd)))
    {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      return FALSE;
+      RETURN(FALSE);
    }
 
-   NtUserGetUpdateRgn(hWnd, hRgn, fErase);
-   NtGdiGetRgnBox(hRgn, lpRect);
+   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);
 
-   return lpRect->left < lpRect->right && lpRect->top < lpRect->bottom;
+         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(!IntGdiIsEmptyRect(&Rect));
+
+CLEANUP:
+   DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 /*
@@ -962,53 +1012,62 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL fErase)
 
 BOOL STDCALL
 NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
-   UINT flags)
+                   UINT flags)
 {
    RECT SafeUpdateRect;
    NTSTATUS Status;
    PWINDOW_OBJECT Wnd;
+   DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
+
+   DPRINT("Enter NtUserRedrawWindow\n");
+   UserEnterExclusive();
 
-   if (!(Wnd = IntGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
+   if (!(Wnd = UserGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
    {
-      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-      return FALSE;
+      RETURN( FALSE);
    }
 
    if (lprcUpdate != NULL)
    {
       Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate,
-         sizeof(RECT));
+                                sizeof(RECT));
 
       if (!NT_SUCCESS(Status))
       {
          SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         return FALSE;
+         RETURN( FALSE);
       }
    }
 
-   Status = IntRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
-      hrgnUpdate, flags);
+   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( FALSE);
    }
-   return TRUE;
+
+   RETURN( TRUE);
+
+CLEANUP:
+   DPRINT("Leave NtUserRedrawWindow, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
-/*
- * NtUserScrollDC
- *
- * Status
- *    @implemented
- */
 
-DWORD STDCALL
-NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
-   const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
+
+static
+DWORD FASTCALL
+UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
+             const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
 {
    RECT rSrc, rClipped_src, rClip, rDst, offset;
    PDC DC;
@@ -1019,9 +1078,9 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
 
    DC = DC_LockDc(hDC);
    if (NULL == DC)
-     {
-       return FALSE;
-     }
+   {
+      return FALSE;
+   }
    if (lprcScroll)
       rSrc = *lprcScroll;
    else
@@ -1034,14 +1093,13 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
       IntGdiGetClipBox(hDC, &rClip);
    IntLPtoDP(DC, (LPPOINT)&rClip, 2);
 
-   NtGdiIntersectRect(&rClipped_src, &rSrc, &rClip);
+   IntGdiIntersectRect(&rClipped_src, &rSrc, &rClip);
 
    rDst = rClipped_src;
-   NtGdiSetRect(&offset, 0, 0, dx, dy);
+   IntGdiSetRect(&offset, 0, 0, dx, dy);
    IntLPtoDP(DC, (LPPOINT)&offset, 2);
-   NtGdiOffsetRect(&rDst, offset.right - offset.left,  offset.bottom - offset.top);
-   NtGdiIntersectRect(&rDst, &rDst, &rClip);
-   DC_UnlockDc(hDC);
+   IntGdiOffsetRect(&rDst, offset.right - offset.left,  offset.bottom - offset.top);
+   IntGdiIntersectRect(&rDst, &rDst, &rClip);
 
    /*
     * Copy bits, if possible.
@@ -1051,15 +1109,20 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
    {
       RECT rDst_lp = rDst, rSrc_lp = rDst;
 
-      NtGdiOffsetRect(&rSrc_lp, offset.left - offset.right, offset.top - offset.bottom);
-      NtGdiDPtoLP(hDC, (LPPOINT)&rDst_lp, 2);
-      NtGdiDPtoLP(hDC, (LPPOINT)&rSrc_lp, 2);
+      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
@@ -1076,13 +1139,13 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
       else
          hRgn = NtGdiCreateRectRgn(rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
 
-      hRgn2 = NtGdiCreateRectRgnIndirect(&rSrc);
+      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);
 
@@ -1100,6 +1163,34 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
    return TRUE;
 }
 
+
+
+
+/*
+ * NtUserScrollDC
+ *
+ * Status
+ *    @implemented
+ */
+
+DWORD STDCALL
+NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
+               const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
+{
+   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;
+
+}
+
 /*
  * NtUserScrollWindowEx
  *
@@ -1108,77 +1199,95 @@ NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
  */
 
 DWORD STDCALL
-NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *rect,
-   const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags)
+NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
+                     const RECT *UnsafeClipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags)
 {
-   RECT rc, cliprc, caretrc;
+   RECT rc, cliprc, caretrc, rect, clipRect;
    INT Result;
-   PWINDOW_OBJECT Window;
+   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 = IntGetWindowObject(hWnd);
+   Window = UserGetWindowObject(hWnd);
    if (!Window || !IntIsWindowDrawable(Window))
    {
-      IntReleaseWindowObject(Window);
-      return ERROR;
+      Window = NULL; /* prevent deref at cleanup */
+      RETURN( ERROR);
    }
+   UserRefObjectCo(Window, &Ref);
 
    IntGetClientRect(Window, &rc);
-   if (rect)
-      NtGdiIntersectRect(&rc, &rc, rect);
 
-   if (clipRect)
-      NtGdiIntersectRect(&cliprc, &rc, clipRect);
+   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;
+         (dx == 0 && dy == 0))
+   {
+      RETURN( NULLREGION);
    }
 
    caretrc = rc;
-   hwndCaret = IntFixCaret(hWnd, &caretrc, flags);
+   hwndCaret = co_IntFixCaret(Window, &caretrc, flags);
 
    if (hrgnUpdate)
       bOwnRgn = FALSE;
    else if (bUpdate)
       hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
 
-   hDC = NtUserGetDCEx( hWnd, 0, DCX_CACHE | DCX_USESTYLE );
+   hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE);
    if (hDC)
    {
-      HRGN hRgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
-
-      NtUserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
-      NtUserReleaseDC(hWnd, hDC);
-      if (bUpdate)
-         NtGdiCombineRgn(hrgnUpdate, hrgnUpdate, hRgn, RGN_OR);
-      else
-         NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | RDW_ERASE);
-      NtGdiDeleteObject(hRgn);
+      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 = NtUserGetUpdateRgn(hWnd, hrgnTemp, FALSE);
+   Result = co_UserGetUpdateRgn(Window, hrgnTemp, FALSE);
    if (Result != NULLREGION)
    {
-      HRGN hrgnClip = NtGdiCreateRectRgnIndirect(&cliprc);
+      HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&cliprc);
       NtGdiOffsetRgn(hrgnTemp, dx, dy);
       NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
-      NtUserRedrawWindow(hWnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
+      co_UserRedrawWindow(Window, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
       NtGdiDeleteObject(hrgnClip);
    }
+
    NtGdiDeleteObject(hrgnTemp);
 
    if (flags & SW_SCROLLCHILDREN)
@@ -1189,41 +1298,62 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *rect,
          int i;
          RECT r, dummy;
          POINT ClientOrigin;
+         PWINDOW_OBJECT Wnd;
+         USER_REFERENCE_ENTRY WndRef;
 
+         IntGetClientOrigin(Window, &ClientOrigin);
          for (i = 0; List[i]; i++)
          {
-            NtUserGetWindowRect(List[i], &r);
-            IntGetClientOrigin(hWnd, &ClientOrigin);
+            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 (!rect || NtGdiIntersectRect(&dummy, &r, &rc))
-               WinPosSetWindowPos(List[i], 0, r.left + dx, r.top + dy, 0, 0,
-                                  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
-                                  SWP_NOREDRAW);
+
+            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))
-      NtUserRedrawWindow(hWnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
-                         ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
-                         ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
+      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 (hwndCaret)
+
+   if ((CaretWnd = UserGetWindowObject(hwndCaret)))
    {
-      IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
-      NtUserShowCaret(hwndCaret);
+      UserRefObjectCo(CaretWnd, &CaretRef);
+
+      co_IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
+      co_UserShowCaret(CaretWnd);
+
+      UserDerefObjectCo(CaretWnd);
    }
 
-   IntReleaseWindowObject(Window);
-    
-   return Result;
+   RETURN(Result);
+
+CLEANUP:
+   if (Window)
+      UserDerefObjectCo(Window);
+
+   DPRINT("Leave NtUserScrollWindowEx, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 /* EOF */