Only offset the rect if it's not empty, otherwise we might return negative
[reactos.git] / reactos / subsys / win32k / ntuser / painting.c
index 1513ce1..575dc4e 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-#define DCX_USESTYLE 0x10000
-
 /* PRIVATE FUNCTIONS **********************************************************/
 
+/**
+ * @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)
+{
+   PWINDOW_OBJECT ParentWindow;
+
+   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;
+}
+
 VOID FASTCALL
 IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
 {
@@ -46,27 +88,127 @@ IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
 
    while (ParentWindow)
    {
-      if (!(ParentWindow->Style & WS_CLIPCHILDREN))
+      if (ParentWindow->Style & WS_CLIPCHILDREN)
+         break;      
+
+      if (ParentWindow->UpdateRegion != 0)
       {
-         if (ParentWindow->UpdateRegion != 0)
-         {
-            INT OffsetX, OffsetY;
+         NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
+            ValidRegion, RGN_DIFF);
+         /* FIXME: If the resulting region is empty, remove fake posted paint message */
+      }
 
-            /*
-             * 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);
+      ParentWindow = ParentWindow->Parent;
+   }
+}
+
+/**
+ * @name IntCalcWindowRgn
+ *
+ * Get a window or client region.
+ */
+
+HRGN FASTCALL
+IntCalcWindowRgn(PWINDOW_OBJECT Window, BOOL Client)
+{
+   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;
+}
+
+/**
+ * @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)
+{
+   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);
          }
       }
 
-      ParentWindow = ParentWindow->Parent;
+      NtGdiDeleteObject(hRgnWindow);
+
+      return hRgnNonClient;
+   }
+   else
+   {
+      return Window->UpdateRegion;
    }
 }
 
@@ -85,69 +227,55 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
 
    if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
    {
-      if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
+      if (Window->UpdateRegion)
       {
-         if (Window->NCUpdateRegion)
-         {
-            IntValidateParent(Window, Window->NCUpdateRegion);
-         }
-         TempRegion = Window->NCUpdateRegion;
-         if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
+         IntValidateParent(Window, Window->UpdateRegion);
+      }
+
+      if (Flags & RDW_UPDATENOW)
+      {
+         if (Window->UpdateRegion != NULL ||
+             Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
          {
-            GDIOBJ_SetOwnership(TempRegion, PsGetCurrentProcess());
+            co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
          }
-         Window->NCUpdateRegion = NULL;
-         Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
-         MsqDecPaintCountQueue(Window->MessageQueue);
-         co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
-         if ((HANDLE) 1 != TempRegion && NULL != TempRegion)
+      }
+      else
+      {
+         if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
          {
-            /* NOTE: The region can already be deleted! */
-            GDIOBJ_FreeObj(TempRegion, GDI_OBJECT_TYPE_REGION | GDI_OBJECT_TYPE_SILENT);
+            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)
+         if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
          {
-            /*
-             * This surely wrong! Why we would want to validate the parent?
-             * It breaks quite a few things including dummy WM_ERASEBKGND
-             * implementations that return only TRUE and have corresponding
-             * WM_PAINT that doesn't paint the whole client area.
-             * I left the code here so that no one will readd it again!
-             * - Filip
-             */
-            /* IntValidateParent(Window, Window->UpdateRegion); */
-            hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE |
-                              DCX_INTERSECTUPDATE);
-            if (hDC != NULL)
+            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);
+               UserReleaseDC(Window, hDC, FALSE);
             }
          }
       }
-
-      if (Flags & RDW_UPDATENOW)
-      {
-         if (Window->UpdateRegion != NULL ||
-               Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
-         {
-            co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
-         }
-      }
    }
 
    /*
     * Check that the window is still valid at this point
     */
-
-   if (! IntIsWindow(hWnd))
+   if (!IntIsWindow(hWnd))
    {
       return;
    }
@@ -156,7 +284,7 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
     * Paint child windows.
     */
    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;
 
@@ -164,11 +292,13 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
       {
          for (phWnd = List; *phWnd; ++phWnd)
          {
-            Window = IntGetWindowObject(*phWnd);
+            Window = UserGetWindowObject(*phWnd);
             if (Window && (Window->Style & WS_VISIBLE))
             {
+               USER_REFERENCE_ENTRY Ref;
+               UserRefObjectCo(Window, &Ref);
                co_IntPaintWindows(Window, Flags);
-               IntReleaseWindowObject(Window);
+               UserDerefObjectCo(Window);
             }
          }
          ExFreePool(List);
@@ -198,15 +328,18 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
       HRGN hRgnWindow;
 
       hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
-      NtGdiOffsetRgn(hRgnWindow,
-                     -Window->WindowRect.left,
-                     -Window->WindowRect.top);
       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);
    }
 
    /*
@@ -276,60 +409,6 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
       Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
    }
 
-   /*
-    * Split the nonclient update region.
-    */
-
-   if (NULL != Window->UpdateRegion)
-   {
-      HRGN hRgnWindow, hRgnNonClient;
-
-      hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
-      NtGdiOffsetRgn(hRgnWindow,
-                     -Window->WindowRect.left,
-                     -Window->WindowRect.top);
-
-      hRgnNonClient = NtGdiCreateRectRgn(0, 0, 0, 0);
-      if (NtGdiCombineRgn(hRgnNonClient, Window->UpdateRegion,
-                          hRgnWindow, RGN_DIFF) == NULLREGION)
-      {
-         NtGdiDeleteObject(hRgnNonClient);
-         hRgnNonClient = NULL;
-      }
-      else
-      {
-         GDIOBJ_SetOwnership(hRgnNonClient, NULL);
-      }
-
-      /*
-       * Remove the nonclient region from the standard update region.
-       */
-      if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
-                          hRgnWindow, RGN_AND) == NULLREGION)
-      {
-         GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
-         NtGdiDeleteObject(Window->UpdateRegion);
-         Window->UpdateRegion = NULL;
-      }
-
-      if (Window->NCUpdateRegion == NULL)
-      {
-         Window->NCUpdateRegion = hRgnNonClient;
-      }
-      else
-      {
-         if(NULL != hRgnNonClient)
-         {
-            NtGdiCombineRgn(Window->NCUpdateRegion, Window->NCUpdateRegion,
-                            hRgnNonClient, RGN_OR);
-            GDIOBJ_SetOwnership(hRgnNonClient, PsGetCurrentProcess());
-            NtGdiDeleteObject(hRgnNonClient);
-         }
-      }
-
-      NtGdiDeleteObject(hRgnWindow);
-   }
-
    /*
     * Process children if needed
     */
@@ -337,34 +416,21 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
    if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
          ((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);
-               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);
+
       }
    }
 
@@ -405,20 +471,16 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
 BOOL FASTCALL
 IntIsWindowDrawable(PWINDOW_OBJECT Window)
 {
-   PWINDOW_OBJECT Wnd = Window;
+   PWINDOW_OBJECT Wnd;
 
-   do
+   for (Wnd = Window; Wnd != NULL; Wnd = Wnd->Parent)
    {
       if (!(Wnd->Style & WS_VISIBLE) ||
             ((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
       {
          return FALSE;
       }
-
-      Wnd = Wnd->Parent;
-
    }
-   while(Wnd);
 
    return TRUE;
 }
@@ -451,7 +513,7 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
    /*
     * 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))
@@ -459,35 +521,30 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
       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);
+         if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+            NtGdiDeleteObject(hRgn);
+         else
+            NtGdiOffsetRgn(hRgn, Window->ClientRect.left, Window->ClientRect.top);
       }
-      else
-         if (UpdateRect != NULL)
+      else if (UpdateRect != NULL)
+      {
+         if (!IntGdiIsEmptyRect(UpdateRect))
          {
             hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
-            NtGdiOffsetRgn(hRgn,
-                           Window->ClientRect.left - Window->WindowRect.left,
-                           Window->ClientRect.top - Window->WindowRect.top);
+            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);
-            }
-            else
-            {
-               hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
-               NtGdiOffsetRgn(hRgn,
-                              -Window->WindowRect.left,
-                              -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(&Window->WindowRect))
+            hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
+      }
+      else
+      {
+         if (!IntGdiIsEmptyRect(&Window->ClientRect))
+            hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
+      }
    }
 
    /*
@@ -495,7 +552,8 @@ co_UserRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRg
     * Adjust the window update region depending on hRgn and flags.
     */
 
-   if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))
+   if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
+       hRgn != NULL)
    {
       IntInvalidateWindows(Window, hRgn, Flags);
    }
@@ -532,98 +590,74 @@ IntIsWindowDirty(PWINDOW_OBJECT Window)
            (Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
 }
 
-HWND STDCALL
-IntFindWindowToRepaint(HWND hWnd, PW32THREAD Thread)
+HWND FASTCALL
+IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
 {
-   PWINDOW_OBJECT Window;
-   PWINDOW_OBJECT Child;
-   HWND hFoundWnd = NULL;
-
-   Window = IntGetWindowObject(hWnd);
-   if (Window == NULL)
-      return NULL;
+   HWND hChild;
+   PWINDOW_OBJECT TempWindow;
 
-   if (IntIsWindowDirty(Window) &&
-         IntWndBelongsToThread(Window, Thread))
+   for (; Window != NULL; Window = Window->NextSibling)
    {
-      IntReleaseWindowObject(Window);
-      return hWnd;
-   }
-
-   for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
-   {
-      if (IntIsWindowDirty(Child) &&
-            IntWndBelongsToThread(Child, Thread))
+      if (IntWndBelongsToThread(Window, Thread) &&
+          IntIsWindowDirty(Window))
       {
-         hFoundWnd = Child->hSelf;
-         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;
+               }
+            }
+         }
 
-   if (hFoundWnd == NULL)
-   {
-      HWND *List;
-      INT i;
+         return Window->hSelf;
+      }
 
-      List = IntWinListChildren(Window);
-      if (List != NULL)
+      if (Window->FirstChild)
       {
-         for (i = 0; List[i]; i++)
-         {
-            hFoundWnd = IntFindWindowToRepaint(List[i], Thread);
-            if (hFoundWnd != NULL)
-               break;
-         }
-         ExFreePool(List);
+         hChild = IntFindWindowToRepaint(Window->FirstChild, Thread);
+         if (hChild != NULL)
+            return hChild;
       }
    }
 
-   IntReleaseWindowObject(Window);
-
-   return hFoundWnd;
+   return NULL;
 }
 
 BOOL FASTCALL
 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 ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
          (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
       return FALSE;
 
-   if (hWnd)
-      Message->hwnd = IntFindWindowToRepaint(hWnd, PsGetWin32Thread());
-   else
-      Message->hwnd = IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
+   Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetWin32Thread());
 
    if (Message->hwnd == NULL)
    {
-      if (NULL == hWnd)
-      {
-         DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
-         MessageQueue->PaintPosted = 0;
-         MessageQueue->PaintCount = 0;
-      }
+      DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
       return FALSE;
    }
 
-   Window = IntGetWindowObject(Message->hwnd);
-   if (Window != NULL)
-   {
-      Message->message = WM_PAINT;
-      Message->wParam = Message->lParam = 0;
-      IntReleaseWindowObject(Window);
+   if (hWnd != NULL && Message->hwnd != hWnd)
+      return FALSE;
 
-      return TRUE;
-   }
+   Message->message = WM_PAINT;
+   Message->wParam = Message->lParam = 0;
 
-   return FALSE;
+   return TRUE;
 }
 
 static
@@ -637,14 +671,15 @@ co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
 
    ASSERT_REFS_CO(Window);
 
-   Desktop = PsGetCurrentThread()->Tcb.Win32Thread->Desktop;
+   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->hSelf, hWndCaret)))
+         ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(WindowWndCaret)))
    {
       POINT pt, FromOffset, ToOffset, Offset;
       RECT rcCaret;
@@ -683,35 +718,30 @@ co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
 HDC STDCALL
 NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
 {
-   PWINDOW_OBJECT Window;
+   PWINDOW_OBJECT Window = NULL;
    PAINTSTRUCT Ps;
    PROSRGNDATA Rgn;
    NTSTATUS Status;
    DECLARE_RETURN(HDC);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserBeginPaint\n");
    UserEnterExclusive();
 
-   if (!(Window = IntGetWindowObject(hWnd)))
+   if (!(Window = UserGetWindowObject(hWnd)))
    {
-      SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
       RETURN( NULL);
    }
 
+   UserRefObjectCo(Window, &Ref);
+   
    co_UserHideCaret(Window);
 
    if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
    {
       HRGN hRgn;
 
-      if (Window->NCUpdateRegion != (HANDLE)1 &&
-            Window->NCUpdateRegion != NULL)
-      {
-         GDIOBJ_SetOwnership(Window->NCUpdateRegion, PsGetCurrentProcess());
-      }
-      hRgn = Window->NCUpdateRegion;
-      IntValidateParent(Window, Window->NCUpdateRegion);
-      Window->NCUpdateRegion = NULL;
+      hRgn = IntGetNCUpdateRgn(Window, FALSE);
       Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
       MsqDecPaintCountQueue(Window->MessageQueue);
       co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
@@ -724,41 +754,43 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
 
    RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
 
-   Ps.hdc = UserGetDCEx(Window, 0, DCX_INTERSECTUPDATE | DCX_WINDOWPAINT | DCX_USESTYLE);
-
+   Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
    if (!Ps.hdc)
    {
-      IntReleaseWindowObject(Window);
-      RETURN( NULL);
+      RETURN(NULL);
    }
 
    if (Window->UpdateRegion != NULL)
    {
       MsqDecPaintCountQueue(Window->MessageQueue);
-      IntValidateParent(Window, Window->UpdateRegion);
       Rgn = RGNDATA_LockRgn(Window->UpdateRegion);
       if (NULL != Rgn)
       {
          UnsafeIntGetRgnBox(Rgn, &Ps.rcPaint);
          RGNDATA_UnlockRgn(Rgn);
-         IntGdiOffsetRect(&Ps.rcPaint,
-                          Window->WindowRect.left - Window->ClientRect.left,
-                          Window->WindowRect.top - Window->ClientRect.top);
+         IntGdiIntersectRect(&Ps.rcPaint, &Ps.rcPaint, &Window->ClientRect);
+         if (! IntGdiIsEmptyRect(&Ps.rcPaint))
+         {
+            IntGdiOffsetRect(&Ps.rcPaint,
+                             -Window->ClientRect.left,
+                             -Window->ClientRect.top);
+         }
       }
       else
       {
          IntGetClientRect(Window, &Ps.rcPaint);
       }
       GDIOBJ_SetOwnership(Window->UpdateRegion, PsGetCurrentProcess());
-      NtGdiDeleteObject(Window->UpdateRegion);
       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)
@@ -771,18 +803,18 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
       Ps.fErase = FALSE;
    }
 
-   IntReleaseWindowObject(Window);
-
    Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
    if (! NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
-      RETURN( NULL);
+      RETURN(NULL);
    }
 
-   RETURN( Ps.hdc);
+   RETURN(Ps.hdc);
 
 CLEANUP:
+   if (Window) UserDerefObjectCo(Window);
+   
    DPRINT("Leave NtUserBeginPaint, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -801,19 +833,21 @@ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
 {
    PWINDOW_OBJECT Window;
    DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserEndPaint\n");
    UserEnterExclusive();
 
-   if (!(Window = IntGetWindowObject(hWnd)))
+   if (!(Window = UserGetWindowObject(hWnd)))
    {
       RETURN(FALSE);
    }
 
-   UserReleaseDC(Window, lPs->hdc);
-   co_UserShowCaret(Window);
+   UserReleaseDC(Window, lPs->hdc, TRUE);
 
-   IntReleaseWindowObject(Window); //temp hack
+   UserRefObjectCo(Window, &Ref);
+   co_UserShowCaret(Window);
+   UserDerefObjectCo(Window);
 
    RETURN(TRUE);
 
@@ -823,74 +857,12 @@ CLEANUP:
    END_CLEANUP;
 }
 
-/*
- * NtUserInvalidateRect
- *
- * Status
- *    @implemented
- */
-
-DWORD STDCALL
-NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
-}
-
-/*
- * NtUserInvalidateRgn
- *
- * Status
- *    @implemented
- */
-
-DWORD STDCALL
-NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
-}
-
-
-
-BOOL FASTCALL
-co_UserValidateRgn(PWINDOW_OBJECT Window, HRGN hRgn)
-{
-   return co_UserRedrawWindow(Window, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
-}
-
-/*
- * NtUserValidateRgn
- *
- * Status
- *    @implemented
- */
-
-BOOL STDCALL
-NtUserValidateRgn(HWND hWnd, HRGN hRgn)
-{
-   return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
-}
-
-/*
- * NtUserUpdateWindow
- *
- * Status
- *    @implemented
- */
-
-BOOL STDCALL
-NtUserUpdateWindow(HWND hWnd)
-{
-   return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
-}
-
-
-
-
 
 INT FASTCALL
 co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
 {
    int RegionType;
+   RECT Rect;
 
    ASSERT_REFS_CO(Window);
 
@@ -900,11 +872,11 @@ co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
    }
    else
    {
-      RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
-      NtGdiOffsetRgn(
-         hRgn,
-         Window->WindowRect.left - Window->ClientRect.left,
-         Window->WindowRect.top - Window->ClientRect.top);
+      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)
@@ -914,6 +886,7 @@ co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
 
    return RegionType;
 }
+
 /*
  * NtUserGetUpdateRgn
  *
@@ -927,6 +900,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
    DECLARE_RETURN(INT);
    PWINDOW_OBJECT Window;
    INT ret;
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserGetUpdateRgn\n");
    UserEnterExclusive();
@@ -936,7 +910,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
       RETURN(ERROR);
    }
 
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
    ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
    UserDerefObjectCo(Window);
 
@@ -962,7 +936,6 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
    RECT Rect;
    INT RegionType;
    PROSRGNDATA RgnData;
-   BOOL AlwaysPaint;
    NTSTATUS Status;
    DECLARE_RETURN(BOOL);
 
@@ -971,7 +944,7 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
 
    if (!(Window = UserGetWindowObject(hWnd)))
    {
-      RETURN( ERROR);
+      RETURN(FALSE);
    }
 
    if (Window->UpdateRegion == NULL)
@@ -980,18 +953,37 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
    }
    else
    {
-      RgnData = RGNDATA_LockRgn(Window->UpdateRegion);
-      ASSERT(RgnData != NULL);
-      RegionType = UnsafeIntGetRgnBox(RgnData, &Rect);
-      ASSERT(RegionType != ERROR);
-      RGNDATA_UnlockRgn(RgnData);
+      /* 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;
+      }
    }
-   AlwaysPaint = (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) ||
-                 (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT);
 
-   if (bErase && Rect.left < Rect.right && Rect.top < Rect.bottom)
+   if (bErase && !IntGdiIsEmptyRect(&Rect))
    {
-      UserRefObjectCo(Window);
+      USER_REFERENCE_ENTRY Ref;
+      UserRefObjectCo(Window, &Ref);
       co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
       UserDerefObjectCo(Window);
    }
@@ -1002,11 +994,11 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
       if (!NT_SUCCESS(Status))
       {
          SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         RETURN( FALSE);
+         RETURN(FALSE);
       }
    }
 
-   RETURN( (Rect.left < Rect.right && Rect.top < Rect.bottom) || AlwaysPaint);
+   RETURN(!IntGdiIsEmptyRect(&Rect));
 
 CLEANUP:
    DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
@@ -1029,6 +1021,7 @@ NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
    NTSTATUS Status;
    PWINDOW_OBJECT Wnd;
    DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserRedrawWindow\n");
    UserEnterExclusive();
@@ -1050,7 +1043,7 @@ NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
       }
    }
 
-   UserRefObjectCo(Wnd);
+   UserRefObjectCo(Wnd, &Ref);
 
    Status = co_UserRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
                                 hrgnUpdate, flags);
@@ -1222,6 +1215,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
    BOOL bOwnRgn = TRUE;
    NTSTATUS Status;
    DECLARE_RETURN(DWORD);
+   USER_REFERENCE_ENTRY Ref, CaretRef;
 
    DPRINT("Enter NtUserScrollWindowEx\n");
    UserEnterExclusive();
@@ -1232,7 +1226,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
       Window = NULL; /* prevent deref at cleanup */
       RETURN( ERROR);
    }
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
 
    IntGetClientRect(Window, &rc);
 
@@ -1278,7 +1272,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
    if (hDC)
    {
       UserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
-      UserReleaseDC(Window, hDC);
+      UserReleaseDC(Window, hDC, FALSE);
    }
 
    /*
@@ -1308,6 +1302,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
          RECT r, dummy;
          POINT ClientOrigin;
          PWINDOW_OBJECT Wnd;
+         USER_REFERENCE_ENTRY WndRef;
 
          IntGetClientOrigin(Window, &ClientOrigin);
          for (i = 0; List[i]; i++)
@@ -1323,7 +1318,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
 
             if (! UnsafeRect || IntGdiIntersectRect(&dummy, &r, &rc))
             {
-               UserRefObjectCo(Wnd);
+               UserRefObjectCo(Wnd, &WndRef);
                co_WinPosSetWindowPos(Wnd, 0, r.left + dx, r.top + dy, 0, 0,
                                      SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
                                      SWP_NOREDRAW);
@@ -1345,7 +1340,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
 
    if ((CaretWnd = UserGetWindowObject(hwndCaret)))
    {
-      UserRefObjectCo(CaretWnd);
+      UserRefObjectCo(CaretWnd, &CaretRef);
 
       co_IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
       co_UserShowCaret(CaretWnd);
@@ -1353,7 +1348,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
       UserDerefObjectCo(CaretWnd);
    }
 
-   RETURN( Result);
+   RETURN(Result);
 
 CLEANUP:
    if (Window)