[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / painting.c
index ddb8bc4..3b1d693 100644 (file)
@@ -56,10 +56,20 @@ IntIntersectWithParents(PWND Child, RECTL *WindowRect)
 }
 
 BOOL FASTCALL
-IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
+IntValidateParent(PWND Child, PREGION ValidateRgn, BOOL Recurse)
 {
-   PWND ParentWnd = Child->spwndParent;
+   PWND ParentWnd = Child;
 
+   if (ParentWnd->style & WS_CHILD)
+   {
+      do
+         ParentWnd = ParentWnd->spwndParent;
+      while (ParentWnd->style & WS_CHILD);
+   }
+// Hax out for drawing issues.
+//   if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
+
+   ParentWnd = Child->spwndParent;
    while (ParentWnd)
    {
       if (ParentWnd->style & WS_CLIPCHILDREN)
@@ -71,7 +81,7 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
             return FALSE;
 
          IntInvalidateWindows( ParentWnd,
-                               hValidateRgn,
+                               ValidateRgn,
                                RDW_VALIDATE | RDW_NOCHILDREN);
       }
 
@@ -81,6 +91,80 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
    return TRUE;
 }
 
+/*
+  Synchronize painting to the top-level windows of other threads.
+*/
+VOID FASTCALL
+IntSendSyncPaint(PWND Wnd, ULONG Flags)
+{
+   PTHREADINFO ptiCur, ptiWnd;
+   PUSER_SENT_MESSAGE Message;
+   PLIST_ENTRY Entry;
+   BOOL bSend = TRUE;
+
+   ptiWnd = Wnd->head.pti;
+   ptiCur = PsGetCurrentThreadWin32Thread();
+   /*
+      Not the current thread, Wnd is in send Nonclient paint also in send erase background and it is visiable.
+   */
+   if ( Wnd->head.pti != ptiCur &&
+        Wnd->state & WNDS_SENDNCPAINT &&
+        Wnd->state & WNDS_SENDERASEBACKGROUND &&
+        Wnd->style & WS_VISIBLE)
+   {
+      // For testing, if you see this, break out the Champagne and have a party!
+      ERR("SendSyncPaint Wnd in State!\n");
+      if (!IsListEmpty(&ptiWnd->SentMessagesListHead))
+      {
+         // Scan sent queue messages to see if we received sync paint messages.
+         Entry = ptiWnd->SentMessagesListHead.Flink;
+         Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+         do
+         {
+            ERR("LOOP it\n");
+            if (Message->Msg.message == WM_SYNCPAINT &&
+                Message->Msg.hwnd == UserHMGetHandle(Wnd))
+            {  // Already received so exit out.
+                ERR("SendSyncPaint Found one in the Sent Msg Queue!\n");
+                bSend = FALSE;
+                break;
+            }
+            Entry = Message->ListEntry.Flink;
+            Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+         }
+         while (Entry != &ptiWnd->SentMessagesListHead);
+      }
+      if (bSend)
+      {
+         ERR("Sending WM_SYNCPAINT\n");
+         // This message has no parameters. But it does! Pass Flags along.
+         co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SYNCPAINT, Flags, 0);
+         Wnd->state |= WNDS_SYNCPAINTPENDING;
+      }
+   }
+
+   // Send to all the children if this is the desktop window.
+   if ( Wnd == UserGetDesktopWindow() )
+   {
+      if ( Flags & RDW_ALLCHILDREN ||
+          ( !(Flags & RDW_NOCHILDREN) && Wnd->style & WS_CLIPCHILDREN))
+      {
+         PWND spwndChild = Wnd->spwndChild;
+         while(spwndChild)
+         {
+            if ( spwndChild->style & WS_CHILD &&
+                 spwndChild->head.pti != ptiCur)
+            {
+               spwndChild = spwndChild->spwndNext;
+               continue;
+            }
+            IntSendSyncPaint( spwndChild, Flags );
+            spwndChild = spwndChild->spwndNext;
+         }
+      }
+   }
+}
+
 /**
  * @name IntCalcWindowRgn
  *
@@ -93,9 +177,21 @@ IntCalcWindowRgn(PWND Wnd, BOOL Client)
    HRGN hRgnWindow;
 
    if (Client)
-      hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
+   {
+      hRgnWindow = NtGdiCreateRectRgn(
+          Wnd->rcClient.left,
+          Wnd->rcClient.top,
+          Wnd->rcClient.right,
+          Wnd->rcClient.bottom);
+   }
    else
-      hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
+   {
+      hRgnWindow = NtGdiCreateRectRgn(
+          Wnd->rcWindow.left,
+          Wnd->rcWindow.top,
+          Wnd->rcWindow.right,
+          Wnd->rcWindow.bottom);
+   }
 
    if (Wnd->hrgnClip != NULL && !(Wnd->style & WS_MINIMIZE))
    {
@@ -166,6 +262,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
       {
          GreDeleteObject(hRgnWindow);
          GreDeleteObject(hRgnNonClient);
+         Window->state &= ~WNDS_UPDATEDIRTY;
          return NULL;
       }
 
@@ -181,9 +278,10 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
          {
             IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
             GreDeleteObject(Window->hrgnUpdate);
+            Window->state &= ~WNDS_UPDATEDIRTY;
             Window->hrgnUpdate = NULL;
             if (!(Window->state & WNDS_INTERNALPAINT))
-               MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+               MsqDecPaintCountQueue(Window->head.pti);
          }
       }
 
@@ -210,31 +308,46 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
    HWND hWnd = Wnd->head.h;
    HRGN TempRegion;
 
+   Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
+
    if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
    {
       if (Wnd->hrgnUpdate)
       {
-         if (!IntValidateParent(Wnd, Wnd->hrgnUpdate, Recurse))
-            return;
+          PREGION RgnUpdate = RGNOBJAPI_Lock(Wnd->hrgnUpdate, NULL);
+          if (RgnUpdate)
+          {
+              if (!IntValidateParent(Wnd, RgnUpdate, Recurse))
+              {
+                  RGNOBJAPI_Unlock(RgnUpdate);
+                  return;
+              }
+              RGNOBJAPI_Unlock(RgnUpdate);
+          }
       }
 
       if (Flags & RDW_UPDATENOW)
       {
-         if (Wnd->hrgnUpdate != NULL ||
-             Wnd->state & WNDS_INTERNALPAINT)
+         if ((Wnd->hrgnUpdate != NULL ||
+              Wnd->state & WNDS_INTERNALPAINT))
          {
+            Wnd->state2 |= WNDS2_WMPAINTSENT;
             co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
          }
       }
-      else
+      else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
       {
          if (Wnd->state & WNDS_SENDNCPAINT)
          {
             TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
             Wnd->state &= ~WNDS_SENDNCPAINT;
-            MsqDecPaintCountQueue(Wnd->head.pti->MessageQueue);
-            co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
-
+            if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
+                !(Wnd->state & WNDS_ACTIVEFRAME))
+            {
+               Wnd->state |= WNDS_ACTIVEFRAME;
+               Wnd->state &= ~WNDS_NONCPAINT;
+            }
+            if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
          }
 
          if (Wnd->state & WNDS_SENDERASEBACKGROUND)
@@ -256,6 +369,10 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
          }
       }
    }
+   else
+   {
+      Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+   }
 
    /*
     * Check that the window is still valid at this point
@@ -288,7 +405,7 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
                UserDerefObjectCo(Wnd);
             }
          }
-         ExFreePool(List);
+         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
       }
    }
 }
@@ -300,24 +417,29 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
  * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
  */
 VOID FASTCALL
-IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
+IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags)
 {
    INT RgnType;
-   BOOL HadPaintMessage, HadNCPaintMessage;
-   BOOL HasPaintMessage, HasNCPaintMessage;
+   BOOL HadPaintMessage;
 
    TRACE("IntInvalidateWindows start\n");
+
+   Wnd->state |= WNDS_PAINTNOTPROCESSED;
+
    /*
     * If the nonclient is not to be redrawn, clip the region to the client
     * rect
     */
    if (0 != (Flags & RDW_INVALIDATE) && 0 == (Flags & RDW_FRAME))
    {
-      HRGN hRgnClient;
+      PREGION RgnClient;
 
-      hRgnClient = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnClient, RGN_AND);
-      GreDeleteObject(hRgnClient);
+      RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
+      if (RgnClient)
+      {
+          RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND);
+          REGION_Delete(RgnClient);
+      }
    }
 
    /*
@@ -326,88 +448,124 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
 
    if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
    {
-      HRGN hRgnWindow;
-
-      hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
-      GreDeleteObject(hRgnWindow);
+      PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
+      if (RgnWindow)
+      {
+          RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND);
+          REGION_Delete(RgnWindow);
+      }
    }
    else
    {
-      NtGdiOffsetRgn( hRgn,
-                     -Wnd->rcWindow.left,
-                     -Wnd->rcWindow.top);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, Wnd->hrgnClip, RGN_AND);
-      NtGdiOffsetRgn( hRgn,
-                      Wnd->rcWindow.left,
-                      Wnd->rcWindow.top);
+       PREGION RgnClip = RGNOBJAPI_Lock(Wnd->hrgnClip, NULL);
+       if (RgnClip)
+       {
+           IntGdiOffsetRgn( Rgn,
+                            -Wnd->rcWindow.left,
+                            -Wnd->rcWindow.top);
+           RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
+           IntGdiOffsetRgn( Rgn,
+                            Wnd->rcWindow.left,
+                            Wnd->rcWindow.top);
+           RGNOBJAPI_Unlock(RgnClip);
+       }
    }
 
    /*
     * Save current state of pending updates
     */
 
-   HadPaintMessage = Wnd->hrgnUpdate != NULL ||
-                     Wnd->state & WNDS_INTERNALPAINT;
-   HadNCPaintMessage = Wnd->state & WNDS_SENDNCPAINT;
+   HadPaintMessage = IntIsWindowDirty(Wnd);
 
    /*
     * Update the region and flags
     */
 
-   if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
+   // The following flags are used to invalidate the window.
+   if (Flags & (RDW_INVALIDATE|RDW_INTERNALPAINT|RDW_ERASE|RDW_FRAME))
    {
-      if (Wnd->hrgnUpdate == NULL)
+      if (Flags & RDW_INTERNALPAINT)
       {
-         Wnd->hrgnUpdate = IntSysCreateRectRgn(0, 0, 0, 0);
-         IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
+         Wnd->state |= WNDS_INTERNALPAINT;
       }
 
-      if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
-                          hRgn, RGN_OR) == NULLREGION)
+      if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
       {
-         IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
-         GreDeleteObject(Wnd->hrgnUpdate);
-         Wnd->hrgnUpdate = NULL;
-      }
+         PREGION RgnUpdate;
 
-      if (Flags & RDW_FRAME)
-         Wnd->state |= WNDS_SENDNCPAINT;
-      if (Flags & RDW_ERASE)
-         Wnd->state |= WNDS_SENDERASEBACKGROUND;
+         Wnd->state &= ~WNDS_NONCPAINT;
 
-      Flags |= RDW_FRAME;
-   }
+         /* If not the same thread set it dirty. */
+         if (Wnd->head.pti != PsGetCurrentThreadWin32Thread())
+         {
+            Wnd->state |= WNDS_UPDATEDIRTY;
+            if (Wnd->state2 & WNDS2_WMPAINTSENT)
+               Wnd->state2 |= WNDS2_ENDPAINTINVALIDATE;
+         }
 
-   if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
-   {
-      if (Wnd->hrgnUpdate != NULL)
-      {
-         if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
-                             hRgn, RGN_DIFF) == NULLREGION)
+         if (Flags & RDW_FRAME)
+            Wnd->state |= WNDS_SENDNCPAINT;
+         if (Flags & RDW_ERASE)
+            Wnd->state |= WNDS_SENDERASEBACKGROUND;
+
+         if (Wnd->hrgnUpdate == NULL)
+         {
+            Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
+            IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
+         }
+
+         RgnUpdate = RGNOBJAPI_Lock(Wnd->hrgnUpdate, NULL);
+         if (RgnUpdate)
          {
-            IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
-            GreDeleteObject(Wnd->hrgnUpdate);
-            Wnd->hrgnUpdate = NULL;
+             RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR);
+             RGNOBJAPI_Unlock(RgnUpdate);
+             if (RgnType == NULLREGION)
+             {
+                IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+                GreDeleteObject(Wnd->hrgnUpdate);
+                Wnd->hrgnUpdate = NULL;
+             }
          }
+         Flags |= RDW_FRAME; // For children.
       }
+   }    // The following flags are used to validate the window.
+   else if (Flags & (RDW_VALIDATE|RDW_NOINTERNALPAINT|RDW_NOERASE|RDW_NOFRAME))
+   {
+      /* FIXME: Handle WNDS_UPDATEDIRTY */
 
-      if (Wnd->hrgnUpdate == NULL)
-         Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
-      if (Flags & RDW_NOFRAME)
-         Wnd->state &= ~WNDS_SENDNCPAINT;
-      if (Flags & RDW_NOERASE)
-         Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
-   }
+      if (Flags & RDW_NOINTERNALPAINT)
+      {
+         Wnd->state &= ~WNDS_INTERNALPAINT;
+      }
 
-   if (Flags & RDW_INTERNALPAINT)
-   {
-      Wnd->state |= WNDS_INTERNALPAINT;
-   }
+      if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
+      {
+         if (Flags & RDW_NOFRAME)
+            Wnd->state &= ~WNDS_SENDNCPAINT;
+         if (Flags & RDW_NOERASE)
+            Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
 
-   if (Flags & RDW_NOINTERNALPAINT)
-   {
-      Wnd->state &= ~WNDS_INTERNALPAINT;
+         if (Wnd->hrgnUpdate != NULL)
+         {
+             PREGION RgnUpdate = RGNOBJAPI_Lock(Wnd->hrgnUpdate, NULL);
+
+             if (RgnUpdate)
+             {
+                 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF);
+                 RGNOBJAPI_Unlock(RgnUpdate);
+
+                 if(RgnType == NULLREGION)
+                 {
+                     IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+                     GreDeleteObject(Wnd->hrgnUpdate);
+                     Wnd->hrgnUpdate = NULL;
+                 }
+             }
+         }
+
+         if (Wnd->hrgnUpdate == NULL)
+            Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+      }
    }
 
    /*
@@ -426,12 +584,14 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
             /*
              * Recursive call to update children hrgnUpdate
              */
-            HRGN hRgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
-            NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
-            IntInvalidateWindows(Child, hRgnTemp, Flags);
-            GreDeleteObject(hRgnTemp);
+            PREGION RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+            if (RgnTemp)
+            {
+                IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY);
+                IntInvalidateWindows(Child, RgnTemp, Flags);
+                REGION_Delete(RgnTemp);
+            }
          }
-
       }
    }
 
@@ -439,24 +599,12 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
     * Fake post paint messages to window message queue if needed
     */
 
-   HasPaintMessage = Wnd->hrgnUpdate != NULL ||
-                     Wnd->state & WNDS_INTERNALPAINT;
-   HasNCPaintMessage = Wnd->state & WNDS_SENDNCPAINT;
-
-   if (HasPaintMessage != HadPaintMessage)
+   if (HadPaintMessage != IntIsWindowDirty(Wnd))
    {
       if (HadPaintMessage)
-         MsqDecPaintCountQueue(Wnd->head.pti->MessageQueue);
-      else
-         MsqIncPaintCountQueue(Wnd->head.pti->MessageQueue);
-   }
-
-   if (HasNCPaintMessage != HadNCPaintMessage)
-   {
-      if (HadNCPaintMessage)
-         MsqDecPaintCountQueue(Wnd->head.pti->MessageQueue);
+         MsqDecPaintCountQueue(Wnd->head.pti);
       else
-         MsqIncPaintCountQueue(Wnd->head.pti->MessageQueue);
+         MsqIncPaintCountQueue(Wnd->head.pti);
    }
    TRACE("IntInvalidateWindows exit\n");
 }
@@ -500,10 +648,10 @@ BOOL FASTCALL
 co_UserRedrawWindow(
    PWND Window,
    const RECTL* UpdateRect,
-   HRGN UpdateRgn,
+   PREGION UpdateRgn,
    ULONG Flags)
 {
-   HRGN hRgn = NULL;
+   PREGION TmpRgn = NULL;
    TRACE("co_UserRedrawWindow start\n");
 
    /*
@@ -524,35 +672,37 @@ co_UserRedrawWindow(
 
    if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY!
    {
-      if (UpdateRgn != NULL)
+      if (UpdateRgn)
       {
-         hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
-         if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
-         {
-            GreDeleteObject(hRgn);
-            hRgn = NULL;
-         }
-         else
-            NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
+          TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
+          if (IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+          {
+              REGION_Delete(TmpRgn);
+              TmpRgn = NULL;
+          }
+          else
+          {
+              IntGdiOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top);
+          }
       }
       else if (UpdateRect != NULL)
       {
          if (!RECTL_bIsEmptyRect(UpdateRect))
          {
-            hRgn = IntSysCreateRectRgnIndirect((RECTL *)UpdateRect);
-            NtGdiOffsetRgn(hRgn, Window->rcClient.left, Window->rcClient.top);
+            TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect);
+            IntGdiOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top);
          }
       }
       else if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
                (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
       {
          if (!RECTL_bIsEmptyRect(&Window->rcWindow))
-            hRgn = IntSysCreateRectRgnIndirect(&Window->rcWindow);
+            TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow);
       }
       else
       {
          if (!RECTL_bIsEmptyRect(&Window->rcClient))
-            hRgn = IntSysCreateRectRgnIndirect(&Window->rcClient);
+            TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient);
       }
    }
 
@@ -562,9 +712,9 @@ co_UserRedrawWindow(
     */
 
    if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT) &&
-       hRgn != NULL)
+       TmpRgn != NULL)
    {
-      IntInvalidateWindows(Window, hRgn, Flags);
+      IntInvalidateWindows(Window, TmpRgn, Flags);
    }
 
    /*
@@ -574,6 +724,7 @@ co_UserRedrawWindow(
 
    if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
    {
+      if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
       co_IntPaintWindows(Window, Flags, FALSE);
    }
 
@@ -582,9 +733,9 @@ co_UserRedrawWindow(
     * Cleanup ;-)
     */
 
-   if (hRgn != NULL)
+   if (TmpRgn != NULL)
    {
-      GreDeleteObject(hRgn);
+      REGION_Delete(TmpRgn);
    }
    TRACE("co_UserRedrawWindow exit\n");
 
@@ -594,16 +745,15 @@ co_UserRedrawWindow(
 BOOL FASTCALL
 IntIsWindowDirty(PWND Wnd)
 {
-   return (Wnd->style & WS_VISIBLE) &&
-          ((Wnd->hrgnUpdate != NULL) ||
-           (Wnd->state & WNDS_INTERNALPAINT) ||
-           (Wnd->state & WNDS_SENDNCPAINT));
+   return ( Wnd->style & WS_VISIBLE &&
+           ( Wnd->hrgnUpdate != NULL ||
+             Wnd->state & WNDS_INTERNALPAINT ) );
 }
 
-HWND FASTCALL
+PWND FASTCALL
 IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
 {
-   HWND hChild;
+   PWND hChild;
    PWND TempWindow;
 
    for (; Window != NULL; Window = Window->spwndNext)
@@ -621,12 +771,12 @@ IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
                    IntWndBelongsToThread(TempWindow, Thread) &&
                    IntIsWindowDirty(TempWindow))
                {
-                  return TempWindow->head.h;
+                  return TempWindow;
                }
             }
          }
 
-         return Window->head.h;
+         return Window;
       }
 
       if (Window->spwndChild)
@@ -636,8 +786,7 @@ IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
             return hChild;
       }
    }
-
-   return NULL;
+   return Window;
 }
 
 BOOL FASTCALL
@@ -649,29 +798,42 @@ IntGetPaintMessage(
    MSG *Message,
    BOOL Remove)
 {
-   if (!Thread->cPaintsReady)
-      return FALSE;
+   PWND PaintWnd;
 
    if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
          (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
       return FALSE;
 
-   Message->hwnd = IntFindWindowToRepaint(UserGetDesktopWindow(), PsGetCurrentThreadWin32Thread());
+   if (Thread->TIF_flags & TIF_SYSTEMTHREAD )
+   {
+      ERR("WM_PAINT is in a System Thread!\n");
+   }
+
+   PaintWnd = IntFindWindowToRepaint(UserGetDesktopWindow(), Thread);
+
+   Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
 
    if (Message->hwnd == NULL)
    {
-      ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %d\n",Thread->cPaintsReady);
+      ERR("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady);
       /* Hack to stop spamming the debuglog ! */
       Thread->cPaintsReady = 0;
       return FALSE;
    }
 
-   if (Window != NULL && Message->hwnd != Window->head.h)
+   if (Window != NULL && PaintWnd != Window)
       return FALSE;
 
-   Message->message = WM_PAINT;
+   if (PaintWnd->state & WNDS_INTERNALPAINT)
+   {
+      PaintWnd->state &= ~WNDS_INTERNALPAINT;
+      if (!PaintWnd->hrgnUpdate)
+         MsqDecPaintCountQueue(Thread);
+   }
+   PaintWnd->state2 &= ~WNDS2_WMPAINTSENT;
+   PaintWnd->state &= ~WNDS_UPDATEDIRTY;
    Message->wParam = Message->lParam = 0;
-
+   Message->message = WM_PAINT;
    return TRUE;
 }
 
@@ -695,7 +857,7 @@ co_IntFixCaret(PWND Window, RECTL *lprc, UINT flags)
    CaretInfo = ActiveMessageQueue->CaretInfo;
    hWndCaret = CaretInfo->hWnd;
 
-   WndCaret = UserGetWindowObject(hWndCaret);
+   WndCaret = ValidateHwndNoErr(hWndCaret);
 
    // FIXME: Check for WndCaret can be NULL
    if (WndCaret == Window ||
@@ -801,65 +963,47 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
    return Ret;
 }
 
-/* PUBLIC FUNCTIONS ***********************************************************/
-
-/*
- * NtUserBeginPaint
- *
- * Status
- *    @implemented
- */
-
-HDC APIENTRY
-NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
+HDC FASTCALL
+IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
 {
-   PWND Window = NULL;
-   PAINTSTRUCT Ps;
-   NTSTATUS Status;
-   DECLARE_RETURN(HDC);
-   USER_REFERENCE_ENTRY Ref;
-
-   TRACE("Enter NtUserBeginPaint\n");
-   UserEnterExclusive();
-
-   if (!(Window = UserGetWindowObject(hWnd)))
-   {
-      RETURN( NULL);
-   }
-
-   UserRefObjectCo(Window, &Ref);
-
    co_UserHideCaret(Window);
 
+   Window->state2 |= WNDS2_STARTPAINT;
+   Window->state &= ~WNDS_PAINTNOTPROCESSED;
+
    if (Window->state & WNDS_SENDNCPAINT)
    {
       HRGN hRgn;
 
+      Window->state &= ~WNDS_UPDATEDIRTY;
       hRgn = IntGetNCUpdateRgn(Window, FALSE);
       Window->state &= ~WNDS_SENDNCPAINT;
-      MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
-      co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)hRgn, 0);
+      co_IntSendMessage(UserHMGetHandle(Window), WM_NCPAINT, (WPARAM)hRgn, 0);
       if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
       {
-         /* NOTE: The region can already by deleted! */
+         /* NOTE: The region can already be deleted! */
          GreDeleteObject(hRgn);
       }
    }
+   else
+   {
+      Window->state &= ~WNDS_UPDATEDIRTY;
+   }
 
-   RtlZeroMemory(&Ps, sizeof(PAINTSTRUCT));
+   RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
 
-   Ps.hdc = UserGetDCEx( Window,
+   Ps->hdc = UserGetDCEx( Window,
                          Window->hrgnUpdate,
                          DCX_INTERSECTRGN | DCX_USESTYLE);
-   if (!Ps.hdc)
+   if (!Ps->hdc)
    {
-      RETURN(NULL);
+      return NULL;
    }
 
    if (Window->hrgnUpdate != NULL)
    {
-      MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
-      GdiGetClipBox(Ps.hdc, &Ps.rcPaint);
+      MsqDecPaintCountQueue(Window->head.pti);
+      GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
       IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
       /* The region is part of the dc now and belongs to the process! */
       Window->hrgnUpdate = NULL;
@@ -867,9 +1011,9 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
    else
    {
       if (Window->state & WNDS_INTERNALPAINT)
-         MsqDecPaintCountQueue(Window->head.pti->MessageQueue);
+         MsqDecPaintCountQueue(Window->head.pti);
 
-      IntGetClientRect(Window, &Ps.rcPaint);
+      IntGetClientRect(Window, &Ps->rcPaint);
    }
 
    Window->state &= ~WNDS_INTERNALPAINT;
@@ -877,15 +1021,15 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
    if (Window->state & WNDS_SENDERASEBACKGROUND)
    {
       Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
-      Ps.fErase = !co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)Ps.hdc, 0);
-      if ( Ps.fErase )
+      Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0);
+      if ( Ps->fErase )
       {
          Window->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
       }
    }
    else
    {
-      Ps.fErase = FALSE;
+      Ps->fErase = FALSE;
    }
    if (Window->hrgnUpdate)
    {
@@ -894,10 +1038,60 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
          PWND Child;
          for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
          {
-            IntInvalidateWindows(Child, Window->hrgnUpdate, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
+            if (Child->hrgnUpdate == NULL && Child->state & WNDS_SENDNCPAINT) // Helped fixing test_redrawnow.
+            IntInvalidateWindows(Child, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
          }
       }
    }
+   return Ps->hdc;
+}
+
+BOOL FASTCALL
+IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps)
+{
+   HDC hdc = NULL;
+
+   hdc = Ps->hdc;
+
+   UserReleaseDC(Wnd, hdc, TRUE);
+
+   Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
+
+   co_UserShowCaret(Wnd);
+
+   return TRUE;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * NtUserBeginPaint
+ *
+ * Status
+ *    @implemented
+ */
+
+HDC APIENTRY
+NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
+{
+   PWND Window = NULL;
+   PAINTSTRUCT Ps;
+   NTSTATUS Status;
+   HDC hDC;
+   USER_REFERENCE_ENTRY Ref;
+   DECLARE_RETURN(HDC);
+
+   TRACE("Enter NtUserBeginPaint\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN( NULL);
+   }
+
+   UserRefObjectCo(Window, &Ref);
+
+   hDC = IntBeginPaint(Window, &Ps);
 
    Status = MmCopyToCaller(UnsafePs, &Ps, sizeof(PAINTSTRUCT));
    if (! NT_SUCCESS(Status))
@@ -906,12 +1100,12 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
       RETURN(NULL);
    }
 
-   RETURN(Ps.hdc);
+   RETURN(hDC);
 
 CLEANUP:
    if (Window) UserDerefObjectCo(Window);
 
-   TRACE("Leave NtUserBeginPaint, ret=%i\n",_ret_);
+   TRACE("Leave NtUserBeginPaint, ret=%p\n",_ret_);
    UserLeave();
    END_CLEANUP;
 
@@ -928,10 +1122,10 @@ BOOL APIENTRY
 NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
 {
    NTSTATUS Status = STATUS_SUCCESS;
-   PWND Window;
-   DECLARE_RETURN(BOOL);
+   PWND Window = NULL;
+   PAINTSTRUCT Ps;
    USER_REFERENCE_ENTRY Ref;
-   HDC hdc = NULL;
+   DECLARE_RETURN(BOOL);
 
    TRACE("Enter NtUserEndPaint\n");
    UserEnterExclusive();
@@ -941,10 +1135,12 @@ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
       RETURN(FALSE);
    }
 
+   UserRefObjectCo(Window, &Ref); // Here for the exception.
+
    _SEH2_TRY
    {
       ProbeForRead(pUnsafePs, sizeof(*pUnsafePs), 1);
-      hdc = pUnsafePs->hdc;
+      RtlCopyMemory(&Ps, pUnsafePs, sizeof(PAINTSTRUCT));
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
@@ -956,15 +1152,11 @@ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* pUnsafePs)
       RETURN(FALSE);
    }
 
-   UserReleaseDC(Window, hdc, TRUE);
-
-   UserRefObjectCo(Window, &Ref);
-   co_UserShowCaret(Window);
-   UserDerefObjectCo(Window);
-
-   RETURN(TRUE);
+   RETURN(IntEndPaint(Window, &Ps));
 
 CLEANUP:
+   if (Window) UserDerefObjectCo(Window);
+
    TRACE("Leave NtUserEndPaint, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -996,7 +1188,7 @@ NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
 
    if (!Ret) goto Exit;
 
-   if (!( pWnd = (PWND)UserGetObject(gHandleTable, finfo.hwnd, otWindow)) ||
+   if (!( pWnd = (PWND)UserGetObject(gHandleTable, finfo.hwnd, TYPE_WINDOW)) ||
         finfo.cbSize != sizeof(FLASHWINFO) ||
         finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) )
    {
@@ -1013,25 +1205,32 @@ Exit:
 }
 
 INT FASTCALL
-co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
+co_UserGetUpdateRgn(PWND Window, PREGION Rgn, BOOL bErase)
 {
-   int RegionType;
-   RECTL Rect;
+    int RegionType;
+    RECTL Rect;
+    PREGION UpdateRgn;
 
-   ASSERT_REFS_CO(Window);
+    ASSERT_REFS_CO(Window);
 
-   if (Window->hrgnUpdate == NULL)
-   {
-      RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
-   }
-   else
-   {
-      Rect = Window->rcClient;
-      IntIntersectWithParents(Window, &Rect);
-      NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
-      RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->hrgnUpdate, RGN_AND);
-      NtGdiOffsetRgn(hRgn, -Window->rcClient.left, -Window->rcClient.top);
-   }
+    Window->state &= ~WNDS_UPDATEDIRTY;
+
+    if (Window->hrgnUpdate == NULL)
+    {
+        REGION_SetRectRgn(Rgn, 0, 0, 0, 0);
+        return NULLREGION;
+    }
+
+    UpdateRgn = RGNOBJAPI_Lock(Window->hrgnUpdate, NULL);
+    if (!UpdateRgn)
+       return ERROR;
+
+    Rect = Window->rcClient;
+    IntIntersectWithParents(Window, &Rect);
+    REGION_SetRectRgn(Rgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
+    RegionType = IntGdiCombineRgn(Rgn, Rgn, UpdateRgn, RGN_AND);
+    IntGdiOffsetRgn(Rgn, -Window->rcClient.left, -Window->rcClient.top);
+    RGNOBJAPI_Unlock(UpdateRgn);
 
    if (bErase && RegionType != NULLREGION && RegionType != ERROR)
    {
@@ -1055,6 +1254,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
    PWND Window;
    INT ret;
    USER_REFERENCE_ENTRY Ref;
+   PREGION Rgn = NULL;
 
    TRACE("Enter NtUserGetUpdateRgn\n");
    UserEnterExclusive();
@@ -1064,13 +1264,33 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
       RETURN(ERROR);
    }
 
+   /* Use a system region, we can't hold GDI locks when doing roundtrips to user mode */
+   Rgn = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if (!Rgn)
+       RETURN(ERROR);
+
    UserRefObjectCo(Window, &Ref);
-   ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
+   ret = co_UserGetUpdateRgn(Window, Rgn, bErase);
    UserDerefObjectCo(Window);
 
    RETURN(ret);
 
 CLEANUP:
+   if (Rgn && (_ret_ != ERROR))
+   {
+       PREGION TheRgn = RGNOBJAPI_Lock(hRgn, NULL);
+       if (!TheRgn)
+       {
+           EngSetLastError(ERROR_INVALID_HANDLE);
+           _ret_ = ERROR;
+       }
+       IntGdiCombineRgn(TheRgn, Rgn, NULL, RGN_COPY);
+       RGNOBJAPI_Unlock(TheRgn);
+   }
+
+   if (Rgn)
+       REGION_Delete(Rgn);
+
    TRACE("Leave NtUserGetUpdateRgn, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -1101,6 +1321,8 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
       RETURN(FALSE);
    }
 
+   Window->state &= ~WNDS_UPDATEDIRTY;
+
    if (Window->hrgnUpdate == NULL)
    {
       Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
@@ -1179,6 +1401,7 @@ NtUserRedrawWindow(
    BOOL Ret;
    USER_REFERENCE_ENTRY Ref;
    NTSTATUS Status = STATUS_SUCCESS;
+   PREGION RgnUpdate = NULL;
    DECLARE_RETURN(BOOL);
 
    TRACE("Enter NtUserRedrawWindow\n");
@@ -1217,11 +1440,34 @@ NtUserRedrawWindow(
       RETURN( FALSE);
    }
 
+   /* We can't hold lock on GDI obects while doing roundtrips to user mode,
+    * so use a copy instead */
+   if (hrgnUpdate)
+   {
+       PREGION RgnTemp;
+
+       RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0);
+       if (!RgnUpdate)
+       {
+           EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+           RETURN(FALSE);
+       }
+
+       RgnTemp = RGNOBJAPI_Lock(hrgnUpdate, NULL);
+       if (!RgnTemp)
+       {
+           EngSetLastError(ERROR_INVALID_HANDLE);
+           RETURN(FALSE);
+       }
+       IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
+       RGNOBJAPI_Unlock(RgnTemp);
+   }
+
    UserRefObjectCo(Wnd, &Ref);
 
    Ret = co_UserRedrawWindow( Wnd,
                               lprcUpdate ? &SafeUpdateRect : NULL,
-                              hrgnUpdate,
+                              RgnUpdate,
                               flags);
 
    UserDerefObjectCo(Wnd);
@@ -1229,6 +1475,8 @@ NtUserRedrawWindow(
    RETURN( Ret);
 
 CLEANUP:
+    if (RgnUpdate)
+        REGION_Delete(RgnUpdate);
    TRACE("Leave NtUserRedrawWindow, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
@@ -1242,7 +1490,7 @@ UserScrollDC(
    INT dy,
    const RECTL *prcScroll,
    const RECTL *prcClip,
-   HRGN hrgnUpdate,
+   PREGION RgnUpdate,
    RECTL *prcUpdate)
 {
    PDC pDC;
@@ -1287,10 +1535,9 @@ UserScrollDC(
 
    /* Calculate the region that was invalidated by moving or
       could not be copied, because it was not visible */
-   if (hrgnUpdate || prcUpdate)
+   if (RgnUpdate || prcUpdate)
    {
-      HRGN hrgnOwn, hrgnTmp;
-      PREGION prgnTmp;
+      PREGION RgnOwn, RgnTmp;
 
       pDC = DC_LockDc(hDC);
       if (!pDC)
@@ -1302,44 +1549,38 @@ UserScrollDC(
       rcDst = rcScroll;
       RECTL_vOffsetRect(&rcDst, dx, dy);
       RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
-      if (hrgnUpdate)
+      if (RgnUpdate)
       {
-         hrgnOwn = hrgnUpdate;
-         if (!NtGdiSetRectRgn(hrgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom))
-         {
-            DC_UnlockDc(pDC);
-            return ERROR;
-         }
+         RgnOwn = RgnUpdate;
+         REGION_SetRectRgn(RgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom);
       }
       else
       {
-         hrgnOwn = IntSysCreateRectRgnIndirect(&rcDst);
+         RgnOwn = IntSysCreateRectpRgnIndirect(&rcDst);
       }
 
       /* Add the source rect */
-      hrgnTmp = IntSysCreateRectRgnIndirect(&rcSrc);
-      NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_OR);
+      RgnTmp = IntSysCreateRectpRgnIndirect(&rcSrc);
+      IntGdiCombineRgn(RgnOwn, RgnOwn, RgnTmp, RGN_OR);
 
       /* Substract the part of the dest that was visible in source */
-      prgnTmp = RGNOBJAPI_Lock(hrgnTmp, NULL);
-      IntGdiCombineRgn(prgnTmp, prgnTmp, pDC->prgnVis, RGN_AND);
-      RGNOBJAPI_Unlock(prgnTmp);
-      NtGdiOffsetRgn(hrgnTmp, dx, dy);
-      Result = NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, RGN_DIFF);
+      IntGdiCombineRgn(RgnTmp, RgnTmp, pDC->prgnVis, RGN_AND);
+      IntGdiOffsetRgn(RgnTmp, dx, dy);
+      Result = IntGdiCombineRgn(RgnOwn, RgnOwn, RgnTmp, RGN_DIFF);
 
       /* DO NOT Unlock DC while messing with prgnVis! */
       DC_UnlockDc(pDC);
 
-      GreDeleteObject(hrgnTmp);
+      REGION_Delete(RgnTmp);
 
       if (prcUpdate)
       {
-         IntGdiGetRgnBox(hrgnOwn, prcUpdate);
+         REGION_GetRgnBox(RgnOwn, prcUpdate);
       }
 
-      if (!hrgnUpdate)
+      if (!RgnUpdate)
       {
-         GreDeleteObject(hrgnOwn);
+         REGION_Delete(RgnOwn);
       }
    }
    else
@@ -1368,6 +1609,7 @@ NtUserScrollDC(
    RECTL rcScroll, rcClip, rcUpdate;
    NTSTATUS Status = STATUS_SUCCESS;
    DWORD Result;
+   PREGION RgnUpdate = NULL;
 
    TRACE("Enter NtUserScrollDC\n");
    UserEnterExclusive();
@@ -1400,12 +1642,19 @@ NtUserScrollDC(
       RETURN(FALSE);
    }
 
+   if (hrgnUpdate)
+   {
+       RgnUpdate = RGNOBJAPI_Lock(hrgnUpdate, NULL);
+       if (!RgnUpdate)
+           RETURN(FALSE);
+   }
+
    Result = UserScrollDC( hDC,
                           dx,
                           dy,
                           prcUnsafeScroll? &rcScroll : 0,
                           prcUnsafeClip? &rcClip : 0,
-                          hrgnUpdate,
+                          RgnUpdate,
                           prcUnsafeUpdate? &rcUpdate : NULL);
    if(Result == ERROR)
    {
@@ -1435,7 +1684,9 @@ NtUserScrollDC(
    RETURN(TRUE);
 
 CLEANUP:
-   TRACE("Leave NtUserScrollDC, ret=%i\n",_ret_);
+   if (RgnUpdate)
+       RGNOBJAPI_Unlock(RgnUpdate);
+   TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_);
    UserLeave();
    END_CLEANUP;
 }
@@ -1462,8 +1713,10 @@ NtUserScrollWindowEx(
    INT Result;
    PWND Window = NULL, CaretWnd;
    HDC hDC;
-   HRGN hrgnOwn = NULL, hrgnTemp;
+   PREGION RgnUpdate = NULL, RgnTemp, RgnWinupd = NULL;
    HWND hwndCaret;
+   DWORD dcxflags = 0;
+   int rdw_flags;
    NTSTATUS Status = STATUS_SUCCESS;
    DECLARE_RETURN(DWORD);
    USER_REFERENCE_ENTRY Ref, CaretRef;
@@ -1515,46 +1768,98 @@ NtUserScrollWindowEx(
       RETURN(NULLREGION);
    }
 
+   /* We must use a copy of the region, as we can't hold an exclusive lock
+    * on it while doing callouts to user-mode */
+   RgnUpdate = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if(!RgnUpdate)
+   {
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       RETURN(ERROR);
+   }
+
    if (hrgnUpdate)
-      hrgnOwn = hrgnUpdate;
+   {
+       RgnTemp = RGNOBJAPI_Lock(hrgnUpdate, NULL);
+       if (!RgnTemp)
+       {
+           EngSetLastError(ERROR_INVALID_HANDLE);
+           RETURN(ERROR);
+       }
+       IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
+       RGNOBJAPI_Unlock(RgnTemp);
+   }
+
+   /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
+   if (flags & SW_SCROLLWNDDCE)
+   {
+      dcxflags = DCX_USESTYLE;
+
+      if (!(Window->pcls->style & (CS_OWNDC|CS_CLASSDC)))
+         dcxflags |= DCX_CACHE; // AH??? wine~ If not Powned or with Class go Cheap!
+
+      if (flags & SW_SCROLLCHILDREN && Window->style & WS_CLIPCHILDREN)
+         dcxflags |= DCX_CACHE|DCX_NOCLIPCHILDREN;
+   }
    else
-      hrgnOwn = IntSysCreateRectRgn(0, 0, 0, 0);
+   {
+       /* So in this case ScrollWindowEx uses Cache DC. */
+       dcxflags = DCX_CACHE|DCX_USESTYLE;
+       if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
+   }
 
-   hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE);
+   hDC = UserGetDCEx(Window, 0, dcxflags);
    if (!hDC)
    {
       /* FIXME: SetLastError? */
       RETURN(ERROR);
    }
 
+   rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? RDW_INVALIDATE | RDW_ERASE  : RDW_INVALIDATE ;
+
    rcCaret = rcScroll;
    hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
 
    Result = UserScrollDC( hDC,
                           dx,
                           dy,
-                         &rcScroll,
-                         &rcClip,
-                          hrgnOwn,
+                          &rcScroll,
+                          &rcClip,
+                          RgnUpdate,
                           prcUnsafeUpdate? &rcUpdate : NULL);
 
    UserReleaseDC(Window, hDC, FALSE);
 
    /*
     * Take into account the fact that some damage may have occurred during
-    * the scroll.
+    * the scroll. Keep a copy in hrgnWinupd to be added to hrngUpdate at the end.
     */
 
-   hrgnTemp = IntSysCreateRectRgn(0, 0, 0, 0);
-   if (co_UserGetUpdateRgn(Window, hrgnTemp, FALSE) != NULLREGION)
+   RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
+   if (!RgnTemp)
    {
-      HRGN hrgnClip = IntSysCreateRectRgnIndirect(&rcClip);
-      NtGdiOffsetRgn(hrgnTemp, dx, dy);
-      NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
-      co_UserRedrawWindow(Window, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
-      GreDeleteObject(hrgnClip);
+       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       RETURN(ERROR);
    }
-   GreDeleteObject(hrgnTemp);
+
+   if (co_UserGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION)
+   {
+      PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip);
+      if (RgnClip)
+      {
+          if (hrgnUpdate)
+          {
+             RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0);
+             IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY);
+          }
+          IntGdiOffsetRgn(RgnTemp, dx, dy);
+          IntGdiCombineRgn(RgnTemp, RgnTemp, RgnClip, RGN_AND);
+          if (hrgnUpdate)
+              IntGdiCombineRgn( RgnWinupd, RgnWinupd, RgnTemp, RGN_OR );
+          co_UserRedrawWindow(Window, NULL, RgnTemp, rdw_flags );
+          REGION_Delete(RgnClip);
+      }
+   }
+   REGION_Delete(RgnTemp);
 
    if (flags & SW_SCROLLCHILDREN)
    {
@@ -1578,7 +1883,7 @@ NtUserScrollWindowEx(
             UserRefObjectCo(Child, &WndRef);
             co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0,
                                   SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
-                                  SWP_NOREDRAW);
+                                  SWP_NOREDRAW | SWP_DEFERERASE);
             UserDerefObjectCo(Child);
          }
       }
@@ -1586,12 +1891,12 @@ NtUserScrollWindowEx(
 
    if (flags & (SW_INVALIDATE | SW_ERASE))
    {
-      co_UserRedrawWindow(Window, NULL, hrgnOwn, RDW_INVALIDATE | RDW_ERASE |
+      co_UserRedrawWindow(Window, NULL, RgnUpdate, rdw_flags |
                           ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
                           ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
    }
 
-   if ((CaretWnd = UserGetWindowObject(hwndCaret)))
+   if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
    {
       UserRefObjectCo(CaretWnd, &CaretRef);
 
@@ -1625,15 +1930,33 @@ NtUserScrollWindowEx(
    RETURN(Result);
 
 CLEANUP:
-   if (hrgnOwn && !hrgnUpdate)
+   if (hrgnUpdate && (_ret_ != ERROR))
    {
-      GreDeleteObject(hrgnOwn);
+       /* Give everything back to the caller */
+       RgnTemp = RGNOBJAPI_Lock(hrgnUpdate, NULL);
+       /* The handle should still be valid */
+       ASSERT(RgnTemp);
+       if (RgnWinupd)
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, RgnWinupd, RGN_OR);
+       else
+           IntGdiCombineRgn(RgnTemp, RgnUpdate, NULL, RGN_COPY);
+       RGNOBJAPI_Unlock(RgnTemp);
+   }
+
+   if (RgnWinupd)
+   {
+       REGION_Delete(RgnWinupd);
+   }
+
+   if (RgnUpdate)
+   {
+      REGION_Delete(RgnUpdate);
    }
 
    if (Window)
       UserDerefObjectCo(Window);
 
-   TRACE("Leave NtUserScrollWindowEx, ret=%i\n",_ret_);
+   TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_);
    UserLeave();
    END_CLEANUP;
 }
@@ -1799,15 +2122,17 @@ BOOL UserDrawCaption(
    {
       PCURICON_OBJECT pIcon = NULL;
 
-      if (!hIcon && pWnd)
+      if (hIcon)
       {
-          hIcon = pWnd->pcls->hIconSm; // FIXME: Windows does not do that
-          if(!hIcon)
-             hIcon = pWnd->pcls->hIcon;
+          pIcon = UserGetCurIconObject(hIcon);
+      }
+      else if (pWnd)
+      {
+          pIcon = NC_IconForWindow(pWnd);
+          // FIXME: NC_IconForWindow should reference it for us */
+          if (pIcon)
+              UserReferenceObject(pIcon);
       }
-
-      if (hIcon)
-         pIcon = UserGetCurIconObject(hIcon);
 
       if (pIcon)
       {
@@ -1816,10 +2141,15 @@ BOOL UserDrawCaption(
          LONG x = Rect.left - cx/2 + 1 + (Rect.bottom - Rect.top)/2; // this is really what Window does
          LONG y = (Rect.top + Rect.bottom)/2 - cy/2; // center
          UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
+         UserDereferenceObject(pIcon);
+      }
+      else
+      {
+          HasIcon = FALSE;
       }
    }
 
-   if (hIcon)
+   if (HasIcon)
       Rect.left += Rect.bottom - Rect.top;
 
    if((uFlags & DC_TEXT))
@@ -1850,7 +2180,7 @@ INT
 FASTCALL
 UserRealizePalette(HDC hdc)
 {
-  HWND hWnd;
+  HWND hWnd, hWndDesktop;
   DWORD Ret;
 
   Ret = IntGdiRealizePalette(hdc);
@@ -1859,6 +2189,15 @@ UserRealizePalette(HDC hdc)
       hWnd = IntWindowFromDC(hdc);
       if (hWnd) // Send broadcast if dc is associated with a window.
       {  // FYI: Thread locked in CallOneParam.
+         hWndDesktop = IntGetDesktopWindow();
+         if ( hWndDesktop != hWnd )
+         {
+            PWND pWnd = UserGetWindowObject(hWndDesktop);
+            ERR("RealizePalette Desktop.");
+            hdc = UserGetWindowDC(pWnd);
+            IntPaintDesktop(hdc);
+            UserReleaseDC(pWnd,hdc,FALSE);
+         }
          UserSendNotifyMessage((HWND)HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)hWnd, 0);
       }
   }
@@ -1947,7 +2286,13 @@ NtUserInvalidateRect(
     CONST RECT *lpUnsafeRect,
     BOOL bErase)
 {
-    return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
+    UINT flags = RDW_INVALIDATE | (bErase ? RDW_ERASE : 0);
+    if (!hWnd)
+    {
+       flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
+       lpUnsafeRect = NULL;
+    }
+    return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, flags);
 }
 
 BOOL
@@ -1957,6 +2302,11 @@ NtUserInvalidateRgn(
     HRGN hRgn,
     BOOL bErase)
 {
+    if (!hWnd)
+    {
+       EngSetLastError( ERROR_INVALID_WINDOW_HANDLE );
+       return FALSE;
+    }
     return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
 }
 
@@ -1974,8 +2324,13 @@ NtUserPrintWindow(
 
     if (hwnd)
     {
-       Window = UserGetWindowObject(hwnd);
-       // TODO: Add Desktop and MessageBox check via FNID's.
+       if (!(Window = UserGetWindowObject(hwnd)) || // FIXME:
+             Window == UserGetDesktopWindow() ||    // pWnd->fnid == FNID_DESKTOP
+             Window == UserGetMessageWindow() )     // pWnd->fnid == FNID_MESSAGEWND
+       {
+          goto Exit;
+       }
+
        if ( Window )
        {
           /* Validate flags and check it as a mask for 0 or 1. */
@@ -1985,7 +2340,7 @@ NtUserPrintWindow(
              EngSetLastError(ERROR_INVALID_PARAMETER);
        }
     }
-
+Exit:
     UserLeave();
     return Ret;
 }
@@ -1998,11 +2353,13 @@ NtUserValidateRect(
     HWND hWnd,
     const RECT *lpRect)
 {
-    if (hWnd)
+    UINT flags = RDW_VALIDATE;
+    if (!hWnd)
     {
-       return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_VALIDATE );
+       flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
+       lpRect = NULL;
     }
-    return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ERASENOW|RDW_ALLCHILDREN);
+    return NtUserRedrawWindow(hWnd, lpRect, NULL, flags);
 }
 
 /* EOF */