[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / painting.c
index 72e6287..a79c130 100644 (file)
@@ -2,13 +2,16 @@
  *  COPYRIGHT:        See COPYING in the top level directory
  *  PROJECT:          ReactOS Win32k subsystem
  *  PURPOSE:          Window painting function
- *  FILE:             subsystems/win32/win32k/ntuser/painting.c
+ *  FILE:             win32ss/user/ntuser/painting.c
  *  PROGRAMER:        Filip Navara (xnavara@volny.cz)
  */
 
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserPainting);
 
+#define RDW_CLIPCHILDREN  4096
+#define RDW_NOUPDATEDIRTY 32768
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 /**
@@ -33,21 +36,21 @@ IntIntersectWithParents(PWND Child, RECTL *WindowRect)
 {
    PWND ParentWnd;
 
+   if (Child->ExStyle & WS_EX_REDIRECTED)
+      return TRUE;
+
    ParentWnd = Child->spwndParent;
    while (ParentWnd != NULL)
    {
-      if (!(ParentWnd->style & WS_VISIBLE) ||
-          (ParentWnd->style & WS_MINIMIZE))
-      {
-         return FALSE;
-      }
-
-      if (!RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient))
+      if (!(ParentWnd->style & WS_VISIBLE)  ||
+           (ParentWnd->style & WS_MINIMIZE) ||
+          !RECTL_bIntersectRect(WindowRect, WindowRect, &ParentWnd->rcClient) )
       {
          return FALSE;
       }
 
-      /* FIXME: Layered windows. */
+      if (ParentWnd->ExStyle & WS_EX_REDIRECTED)
+         return TRUE;
 
       ParentWnd = ParentWnd->spwndParent;
    }
@@ -56,9 +59,12 @@ IntIntersectWithParents(PWND Child, RECTL *WindowRect)
 }
 
 BOOL FASTCALL
-IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
+IntValidateParents(PWND Child, BOOL Recurse)
 {
+   RECTL ParentRect, Rect;
+   BOOL Start, Ret = TRUE;
    PWND ParentWnd = Child;
+   PREGION Rgn = NULL;
 
    if (ParentWnd->style & WS_CHILD)
    {
@@ -66,9 +72,11 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
          ParentWnd = ParentWnd->spwndParent;
       while (ParentWnd->style & WS_CHILD);
    }
-// Hax out for drawing issues.
-//   if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
 
+   // No pending nonclient paints.
+   if (!(ParentWnd->state & WNDS_SYNCPAINTPENDING)) Recurse = FALSE;
+
+   Start = TRUE;
    ParentWnd = Child->spwndParent;
    while (ParentWnd)
    {
@@ -78,17 +86,43 @@ IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse)
       if (ParentWnd->hrgnUpdate != 0)
       {
          if (Recurse)
-            return FALSE;
+         {
+            Ret = FALSE;
+            break;
+         }
+         // Start with child clipping.
+         if (Start)
+         {
+            Start = FALSE;
+
+            Rect = Child->rcWindow;
+
+            if (!IntIntersectWithParents(Child, &Rect)) break;
+
+            Rgn = IntSysCreateRectpRgnIndirect(&Rect);
+
+            if (Child->hrgnClip)
+            {
+               PREGION RgnClip = REGION_LockRgn(Child->hrgnClip);
+               IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
+               REGION_UnlockRgn(RgnClip);
+            }
+         }
+
+         ParentRect = ParentWnd->rcWindow;
+
+         if (!IntIntersectWithParents(ParentWnd, &ParentRect)) break;
 
          IntInvalidateWindows( ParentWnd,
-                               hValidateRgn,
-                               RDW_VALIDATE | RDW_NOCHILDREN);
+                               Rgn,
+                               RDW_VALIDATE | RDW_NOCHILDREN | RDW_NOUPDATEDIRTY);
       }
-
       ParentWnd = ParentWnd->spwndParent;
    }
 
-   return TRUE;
+   if (Rgn) REGION_Delete(Rgn);
+
+   return Ret;
 }
 
 /*
@@ -113,7 +147,7 @@ IntSendSyncPaint(PWND Wnd, ULONG Flags)
         Wnd->style & WS_VISIBLE)
    {
       // For testing, if you see this, break out the Champagne and have a party!
-      ERR("SendSyncPaint Wnd in State!\n");
+      TRACE("SendSyncPaint Wnd in State!\n");
       if (!IsListEmpty(&ptiWnd->SentMessagesListHead))
       {
          // Scan sent queue messages to see if we received sync paint messages.
@@ -136,7 +170,7 @@ IntSendSyncPaint(PWND Wnd, ULONG Flags)
       }
       if (bSend)
       {
-         ERR("Sending WM_SYNCPAINT\n");
+         TRACE("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;
@@ -165,7 +199,7 @@ IntSendSyncPaint(PWND Wnd, ULONG Flags)
    }
 }
 
-/**
+/*
  * @name IntCalcWindowRgn
  *
  * Get a window or client region.
@@ -177,9 +211,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))
    {
@@ -195,7 +241,7 @@ IntCalcWindowRgn(PWND Wnd, BOOL Client)
    return hRgnWindow;
 }
 
-/**
+/*
  * @name IntGetNCUpdateRgn
  *
  * Get non-client update region of a window and optionally validate it.
@@ -215,7 +261,8 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
 {
    HRGN hRgnNonClient;
    HRGN hRgnWindow;
-   UINT RgnType;
+   UINT RgnType, NcType;
+   RECT update;
 
    if (Window->hrgnUpdate != NULL &&
        Window->hrgnUpdate != HRGN_WINDOW)
@@ -238,8 +285,10 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
          return HRGN_WINDOW;
       }
 
-      RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient,
-                                hRgnWindow, RGN_DIFF);
+      NcType = IntGdiGetRgnBox(hRgnNonClient, &update);
+
+      RgnType = NtGdiCombineRgn(hRgnNonClient, hRgnNonClient, hRgnWindow, RGN_DIFF);
+
       if (RgnType == ERROR)
       {
          GreDeleteObject(hRgnWindow);
@@ -261,8 +310,7 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
 
       if (Validate)
       {
-         if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate,
-                             hRgnWindow, RGN_AND) == NULLREGION)
+         if (NtGdiCombineRgn(Window->hrgnUpdate, Window->hrgnUpdate, hRgnWindow, RGN_AND) == NULLREGION)
          {
             IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
             GreDeleteObject(Window->hrgnUpdate);
@@ -273,6 +321,19 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
          }
       }
 
+      /* check if update rgn contains complete nonclient area */
+      if (NcType == SIMPLEREGION)
+      {
+         RECT window;
+         IntGetWindowRect( Window, &window );
+
+         if (IntEqualRect( &window, &update ))
+         {
+            GreDeleteObject(hRgnNonClient);
+            hRgnNonClient = HRGN_WINDOW;
+         }
+      }
+
       GreDeleteObject(hRgnWindow);
 
       return hRgnNonClient;
@@ -283,6 +344,45 @@ IntGetNCUpdateRgn(PWND Window, BOOL Validate)
    }
 }
 
+VOID FASTCALL
+IntSendNCPaint(PWND pWnd, HRGN hRgn)
+{
+   pWnd->state &= ~WNDS_SENDNCPAINT;
+
+   if ( pWnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
+       !(pWnd->state & WNDS_ACTIVEFRAME))
+   {
+      pWnd->state |= WNDS_ACTIVEFRAME;
+      pWnd->state &= ~WNDS_NONCPAINT;
+      hRgn = HRGN_WINDOW;
+   }
+
+   if (pWnd->state2 & WNDS2_FORCEFULLNCPAINTCLIPRGN)
+   {
+      pWnd->state2 &= ~WNDS2_FORCEFULLNCPAINTCLIPRGN;
+      hRgn = HRGN_WINDOW;
+   }
+
+   if (hRgn) co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCPAINT, (WPARAM)hRgn, 0);
+}
+
+VOID FASTCALL
+IntSendChildNCPaint(PWND pWnd)
+{
+   pWnd = pWnd->spwndChild;
+   while(pWnd)
+   {
+      if (pWnd->hrgnUpdate == NULL && pWnd->state & WNDS_SENDNCPAINT)
+      {
+         USER_REFERENCE_ENTRY Ref;
+         UserRefObjectCo(pWnd, &Ref);
+         IntSendNCPaint(pWnd, HRGN_WINDOW);
+         UserDerefObjectCo(pWnd);
+      }
+      pWnd = pWnd->spwndNext;
+   }
+}
+
 /*
  * IntPaintWindows
  *
@@ -294,65 +394,67 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
 {
    HDC hDC;
    HWND hWnd = Wnd->head.h;
-   HRGN TempRegion;
+   HRGN TempRegion = NULL;
 
    Wnd->state &= ~WNDS_PAINTNOTPROCESSED;
 
-   if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+   if (Wnd->state & WNDS_SENDNCPAINT ||
+       Wnd->state & WNDS_SENDERASEBACKGROUND)
    {
-      if (Wnd->hrgnUpdate)
+      if (!(Wnd->style & WS_VISIBLE))
       {
-         if (!IntValidateParent(Wnd, Wnd->hrgnUpdate, Recurse))
-            return;
+         Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+         return;
       }
-
-      if (Flags & RDW_UPDATENOW)
+      else
       {
-         if ((Wnd->hrgnUpdate != NULL ||
-              Wnd->state & WNDS_INTERNALPAINT))
+         if (Wnd->hrgnUpdate == NULL)
          {
-            Wnd->state2 |= WNDS2_WMPAINTSENT;
-            co_IntSendMessage(hWnd, WM_PAINT, 0, 0);
+            Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
          }
-      }
-      else if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
-      {
-         if (Wnd->state & WNDS_SENDNCPAINT)
+
+         if (Wnd->head.pti == PsGetCurrentThreadWin32Thread())
          {
-            TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
-            Wnd->state &= ~WNDS_SENDNCPAINT;
-            if ( Wnd == GetW32ThreadInfo()->MessageQueue->spwndActive &&
-                !(Wnd->state & WNDS_ACTIVEFRAME))
+            if (Wnd->state & WNDS_SENDNCPAINT)
             {
-               Wnd->state |= WNDS_ACTIVEFRAME;
-               Wnd->state &= ~WNDS_NONCPAINT;
+               TempRegion = IntGetNCUpdateRgn(Wnd, TRUE);
+
+               IntSendNCPaint(Wnd, TempRegion);
+
+               if (TempRegion > HRGN_WINDOW && GreIsHandleValid(TempRegion))
+               {
+                  /* NOTE: The region can already be deleted! */
+                  GreDeleteObject(TempRegion);
+               }
             }
-            if (TempRegion) co_IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
-         }
 
-         if (Wnd->state & WNDS_SENDERASEBACKGROUND)
-         {
-            if (Wnd->hrgnUpdate)
+            if (Wnd->state & WNDS_SENDERASEBACKGROUND)
             {
-               hDC = UserGetDCEx( Wnd,
-                                  Wnd->hrgnUpdate,
-                                  DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
-
-               Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
-               // Kill the loop, so Clear before we send.
-               if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+               PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+               if (Wnd->hrgnUpdate)
                {
-                  Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+                  hDC = UserGetDCEx( Wnd,
+                                     Wnd->hrgnUpdate,
+                                     DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
+
+                  if (Wnd->head.pti->ppi != pti->ppi)
+                  {
+                     ERR("Sending DC to another Process!!!\n");
+                  }
+
+                  Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+                  // Kill the loop, so Clear before we send.
+                  if (!co_IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
+                  {
+                     Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+                  }
+                  UserReleaseDC(Wnd, hDC, FALSE);
                }
-               UserReleaseDC(Wnd, hDC, FALSE);
             }
          }
+
       }
    }
-   else
-   {
-      Wnd->state &= ~(WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
-   }
 
    /*
     * Check that the window is still valid at this point
@@ -365,19 +467,26 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
    /*
     * Paint child windows.
     */
+
    if (!(Flags & RDW_NOCHILDREN) &&
        !(Wnd->style & WS_MINIMIZE) &&
-        ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)) )
+        ( Flags & RDW_ALLCHILDREN ||
+         (Flags & RDW_CLIPCHILDREN && Wnd->style & WS_CLIPCHILDREN) ) )
    {
       HWND *List, *phWnd;
+      PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
 
       if ((List = IntWinListChildren(Wnd)))
       {
-         /* FIXME: Handle WS_EX_TRANSPARENT */
          for (phWnd = List; *phWnd; ++phWnd)
          {
-            Wnd = UserGetWindowObject(*phWnd);
-            if (Wnd && (Wnd->style & WS_VISIBLE))
+            if ((Wnd = UserGetWindowObject(*phWnd)) == NULL)
+               continue;
+
+            if (Wnd->head.pti != pti && Wnd->style & WS_CHILD)
+               continue;
+
+            if (Wnd->style & WS_VISIBLE)
             {
                USER_REFERENCE_ENTRY Ref;
                UserRefObjectCo(Wnd, &Ref);
@@ -391,55 +500,192 @@ co_IntPaintWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
 }
 
 /*
- * IntInvalidateWindows
+ * IntUpdateWindows
  *
- * Internal function used by IntRedrawWindow, UserRedrawDesktop,
- * co_WinPosSetWindowPos, IntValidateParent, co_UserRedrawWindow.
+ * Internal function used by IntRedrawWindow, simplecall.
  */
+
 VOID FASTCALL
-IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
+co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
 {
-   INT RgnType;
-   BOOL HadPaintMessage;
+   HWND hWnd = Wnd->head.h;
+
+   if ((Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT))
+   {
+      if (Wnd->hrgnUpdate)
+      {
+         if (!IntValidateParents(Wnd, Recurse))
+         {
+            return;
+         }
+      }
+
+      if (Wnd->state & WNDS_INTERNALPAINT)
+      {
+          Wnd->state &= ~WNDS_INTERNALPAINT;
 
-   TRACE("IntInvalidateWindows start\n");
+          if (Wnd->hrgnUpdate == NULL)
+             MsqDecPaintCountQueue(Wnd->head.pti);
+      }
 
-   Wnd->state |= WNDS_PAINTNOTPROCESSED;
+      Wnd->state |= WNDS_PAINTNOTPROCESSED;
+      Wnd->state &= ~WNDS_UPDATEDIRTY;
 
-   /*
-    * If the nonclient is not to be redrawn, clip the region to the client
-    * rect
-    */
-   if (0 != (Flags & RDW_INVALIDATE) && 0 == (Flags & RDW_FRAME))
+      Wnd->state2 |= WNDS2_WMPAINTSENT;
+      co_IntSendMessage(hWnd, WM_PAINT, 0, 0); 
+
+      if (Wnd->state & WNDS_PAINTNOTPROCESSED)
+      {
+         USER_REFERENCE_ENTRY Ref;
+         UserRefObjectCo(Wnd, &Ref);
+         co_IntPaintWindows(Wnd, RDW_NOCHILDREN, FALSE);
+         UserDerefObjectCo(Wnd);
+      }
+   }
+
+   // Force flags as a toggle. Fixes msg:test_paint_messages:WmChildPaintNc.
+   Flags = (Flags & RDW_NOCHILDREN) ? RDW_NOCHILDREN : RDW_ALLCHILDREN; // All children is the default.
+
+  /*
+   * Update child windows.
+   */
+
+   if (!(Flags & RDW_NOCHILDREN) && 
+         Flags & RDW_ALLCHILDREN &&
+         Wnd != UserGetDesktopWindow() )
    {
-      HRGN hRgnClient;
+      PWND Child;
 
-      hRgnClient = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnClient, RGN_AND);
-      GreDeleteObject(hRgnClient);
+      for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
+      {
+         /* transparent window, check for non-transparent sibling to paint first, then skip it */
+         if ( Child->ExStyle & WS_EX_TRANSPARENT &&
+             ( Child->hrgnUpdate != NULL || Child->state & WNDS_INTERNALPAINT ) )
+         {
+            PWND Next = Child->spwndNext;
+            while (Next)
+            {
+               if ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT ) break;
+
+               Next = Next->spwndNext;
+            }
+
+            if (Next) continue;
+         }
+
+         if ( Child->style & WS_VISIBLE)
+         {
+             USER_REFERENCE_ENTRY Ref;
+             UserRefObjectCo(Child, &Ref);
+             co_IntUpdateWindows(Child, Flags, TRUE);
+             UserDerefObjectCo(Child);
+         }
+      }
    }
+}
 
-   /*
-    * Clip the given region with window rectangle (or region)
-    */
+VOID FASTCALL
+UserUpdateWindows(PWND pWnd, ULONG Flags)
+{
+   // If transparent and any sibling windows below needs to be painted, leave.
+   if (pWnd->ExStyle & WS_EX_TRANSPARENT)
+   {
+      PWND Next = pWnd->spwndNext;
+
+      while(Next)
+      {
+         if ( Next->head.pti == pWnd->head.pti &&
+            ( Next->hrgnUpdate != NULL || Next->state & WNDS_INTERNALPAINT) )
+         {
+            return;
+         }
+
+         Next = Next->spwndNext;
+      }
+   }
+   co_IntUpdateWindows(pWnd, Flags, FALSE);
+}
 
-   if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
+VOID FASTCALL
+UserSyncAndPaintWindows(PWND pWnd, ULONG Flags)
+{
+   PWND Parent = pWnd;
+   // Find parent, if it needs to be painted, leave.
+   while(TRUE)
    {
-      HRGN hRgnWindow;
+      if ((Parent = Parent->spwndParent) == NULL) break;
+      if ( Parent->style & WS_CLIPCHILDREN ) break;
+      if ( Parent->hrgnUpdate != NULL || Parent->state & WNDS_INTERNALPAINT ) return;
+   }
 
-      hRgnWindow = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
-      RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
-      GreDeleteObject(hRgnWindow);
+   IntSendSyncPaint(pWnd, Flags);
+   co_IntPaintWindows(pWnd, Flags, FALSE);
+}
+
+/*
+ * IntInvalidateWindows
+ *
+ * Internal function used by IntRedrawWindow, UserRedrawDesktop,
+ * co_WinPosSetWindowPos, co_UserRedrawWindow.
+ */
+VOID FASTCALL
+IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags)
+{
+   INT RgnType = NULLREGION;
+   BOOL HadPaintMessage;
+
+   TRACE("IntInvalidateWindows start Rgn %p\n",Rgn);
+
+   if ( Rgn > PRGN_WINDOW )
+   {
+      /*
+       * If the nonclient is not to be redrawn, clip the region to the client
+       * rect
+       */
+      if ((Flags & RDW_INVALIDATE) != 0 && (Flags & RDW_FRAME) == 0)
+      {
+         PREGION RgnClient;
+
+         RgnClient = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
+         if (RgnClient)
+         {
+             RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClient, RGN_AND);
+             REGION_Delete(RgnClient);
+         }
+      }
+
+      /*
+       * Clip the given region with window rectangle (or region)
+       */
+
+      if (!Wnd->hrgnClip || (Wnd->style & WS_MINIMIZE))
+      {
+         PREGION RgnWindow = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
+         if (RgnWindow)
+         {
+             RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnWindow, RGN_AND);
+             REGION_Delete(RgnWindow);
+         }
+      }
+      else
+      {
+          PREGION RgnClip = REGION_LockRgn(Wnd->hrgnClip);
+          if (RgnClip)
+          {
+              REGION_bOffsetRgn(Rgn,
+                                -Wnd->rcWindow.left,
+                                -Wnd->rcWindow.top);
+              RgnType = IntGdiCombineRgn(Rgn, Rgn, RgnClip, RGN_AND);
+              REGION_bOffsetRgn(Rgn,
+                                Wnd->rcWindow.left,
+                                Wnd->rcWindow.top);
+              REGION_UnlockRgn(RgnClip);
+          }
+      }
    }
    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);
+      RgnType == NULLREGION;
    }
 
    /*
@@ -460,8 +706,10 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
          Wnd->state |= WNDS_INTERNALPAINT;
       }
 
-      if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
+      if (Flags & RDW_INVALIDATE )
       {
+         PREGION RgnUpdate;
+
          Wnd->state &= ~WNDS_NONCPAINT;
 
          /* If not the same thread set it dirty. */
@@ -474,54 +722,90 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
 
          if (Flags & RDW_FRAME)
             Wnd->state |= WNDS_SENDNCPAINT;
+
          if (Flags & RDW_ERASE)
             Wnd->state |= WNDS_SENDERASEBACKGROUND;
 
-         if (Wnd->hrgnUpdate == NULL)
+         if (RgnType != NULLREGION && Rgn > PRGN_WINDOW)
          {
-            Wnd->hrgnUpdate = IntSysCreateRectRgn(0, 0, 0, 0);
-            IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
-         }
+            if (Wnd->hrgnUpdate == NULL)
+            {
+               Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
+               IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
+            }
 
-         if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
-                             hRgn, RGN_OR) == NULLREGION)
-         {
-            IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
-            GreDeleteObject(Wnd->hrgnUpdate);
-            Wnd->hrgnUpdate = NULL;
+            if (Wnd->hrgnUpdate != HRGN_WINDOW)
+            {
+               RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
+               if (RgnUpdate)
+               {
+                  RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_OR);
+                  REGION_UnlockRgn(RgnUpdate);
+                  if (RgnType == NULLREGION)
+                  {
+                     IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+                     GreDeleteObject(Wnd->hrgnUpdate);
+                     Wnd->hrgnUpdate = NULL;
+                  }
+               }
+            }
          }
-         Flags |= RDW_FRAME; // For children.
+
+         Flags |= RDW_ERASE|RDW_FRAME; // For children.
+
+      }
+
+      if (!HadPaintMessage && IntIsWindowDirty(Wnd))
+      {
+         MsqIncPaintCountQueue(Wnd->head.pti);
       }
+
    }    // 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->state & WNDS_UPDATEDIRTY && !(Flags & RDW_NOUPDATEDIRTY))
+         return;
 
       if (Flags & RDW_NOINTERNALPAINT)
       {
          Wnd->state &= ~WNDS_INTERNALPAINT;
       }
 
-      if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
+      if (Flags & RDW_VALIDATE)
       {
          if (Flags & RDW_NOFRAME)
             Wnd->state &= ~WNDS_SENDNCPAINT;
+
          if (Flags & RDW_NOERASE)
             Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
 
-         if (Wnd->hrgnUpdate != NULL)
+         if (Wnd->hrgnUpdate > HRGN_WINDOW && RgnType != NULLREGION && Rgn > PRGN_WINDOW)
          {
-            if (NtGdiCombineRgn(Wnd->hrgnUpdate, Wnd->hrgnUpdate,
-                                hRgn, RGN_DIFF) == NULLREGION)
-            {
-               IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
-               GreDeleteObject(Wnd->hrgnUpdate);
-               Wnd->hrgnUpdate = NULL;
-            }
+             PREGION RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
+
+             if (RgnUpdate)
+             {
+                 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, Rgn, RGN_DIFF);
+                 REGION_UnlockRgn(RgnUpdate);
+
+                 if (RgnType == NULLREGION)
+                 {
+                     IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
+                     GreDeleteObject(Wnd->hrgnUpdate);
+                     Wnd->hrgnUpdate = NULL;
+                 }
+             }
          }
-
+         // If update is null, do not erase.
          if (Wnd->hrgnUpdate == NULL)
+         {
             Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+         }
+      }
+
+      if (HadPaintMessage && !IntIsWindowDirty(Wnd))
+      {
+         MsqDecPaintCountQueue(Wnd->head.pti);
       }
    }
 
@@ -529,9 +813,10 @@ IntInvalidateWindows(PWND Wnd, HRGN hRgn, ULONG Flags)
     * Process children if needed
     */
 
-   if (!(Flags & RDW_NOCHILDREN) && !(Wnd->style & WS_MINIMIZE) &&
+   if (!(Flags & RDW_NOCHILDREN) &&
+       !(Wnd->style & WS_MINIMIZE) &&
          ((Flags & RDW_ALLCHILDREN) || !(Wnd->style & WS_CLIPCHILDREN)))
-   {
+   { 
       PWND Child;
 
       for (Child = Wnd->spwndChild; Child; Child = Child->spwndNext)
@@ -541,25 +826,16 @@ 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)
+            {
+                if (Rgn > PRGN_WINDOW) IntGdiCombineRgn(RgnTemp, Rgn, 0, RGN_COPY);
+                IntInvalidateWindows(Child, ((Rgn > PRGN_WINDOW)?RgnTemp:Rgn), Flags);
+                REGION_Delete(RgnTemp);
+            }
          }
       }
    }
-
-   /*
-    * Fake post paint messages to window message queue if needed
-    */
-
-   if (HadPaintMessage != IntIsWindowDirty(Wnd))
-   {
-      if (HadPaintMessage)
-         MsqDecPaintCountQueue(Wnd->head.pti);
-      else
-         MsqIncPaintCountQueue(Wnd->head.pti);
-   }
    TRACE("IntInvalidateWindows exit\n");
 }
 
@@ -602,11 +878,11 @@ BOOL FASTCALL
 co_UserRedrawWindow(
    PWND Window,
    const RECTL* UpdateRect,
-   HRGN UpdateRgn,
+   PREGION UpdateRgn,
    ULONG Flags)
 {
-   HRGN hRgn = NULL;
-   TRACE("co_UserRedrawWindow start\n");
+   PREGION TmpRgn = NULL;
+   TRACE("co_UserRedrawWindow start Rgn %p\n",UpdateRgn);
 
    /*
     * Step 1.
@@ -618,6 +894,11 @@ co_UserRedrawWindow(
       return TRUE; // Just do nothing!!!
    }
 
+   if (Window == NULL)
+   {
+      Window = UserGetDesktopWindow();
+   }
+
    /*
     * Step 2.
     * Transform the parameters UpdateRgn and UpdateRect into
@@ -626,36 +907,59 @@ co_UserRedrawWindow(
 
    if (Flags & (RDW_INVALIDATE | RDW_VALIDATE)) // Both are OKAY!
    {
-      if (UpdateRgn != NULL)
+      /* We can't hold lock on GDI objects while doing roundtrips to user mode,
+       * so use a copy instead */
+      if (UpdateRgn)
+      {
+          TmpRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
+
+          if (UpdateRgn > PRGN_WINDOW)
+          {
+             IntGdiCombineRgn(TmpRgn, UpdateRgn, NULL, RGN_COPY);
+          }
+
+          if (Window != UserGetDesktopWindow())
+          {
+             REGION_bOffsetRgn(TmpRgn, Window->rcClient.left, Window->rcClient.top);
+          }
+      }
+      else
       {
-         hRgn = IntSysCreateRectRgn(0, 0, 0, 0);
-         if (NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY) == NULLREGION)
+         if (UpdateRect != NULL)
          {
-            GreDeleteObject(hRgn);
-            hRgn = NULL;
+            if (Window == UserGetDesktopWindow())
+            {
+               TmpRgn = IntSysCreateRectpRgnIndirect(UpdateRect);
+            }          
+            else
+            {
+               TmpRgn = IntSysCreateRectpRgn(Window->rcClient.left + UpdateRect->left,
+                                             Window->rcClient.top  + UpdateRect->top,
+                                             Window->rcClient.left + UpdateRect->right,
+                                             Window->rcClient.top  + UpdateRect->bottom);
+            }
          }
          else
-            NtGdiOffsetRgn(hRgn, 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);
+            if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
+                (Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
+            {
+               if (!RECTL_bIsEmptyRect(&Window->rcWindow))
+                   TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcWindow);
+            }
+            else
+            {
+               if (!RECTL_bIsEmptyRect(&Window->rcClient))
+                   TmpRgn = IntSysCreateRectpRgnIndirect(&Window->rcClient);
+            }
          }
       }
-      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);
-      }
-      else
-      {
-         if (!RECTL_bIsEmptyRect(&Window->rcClient))
-            hRgn = IntSysCreateRectRgnIndirect(&Window->rcClient);
-      }
+   }
+
+   /* Fixes test RDW_INTERNALPAINT behavior */
+   if (TmpRgn == NULL)
+   {
+      TmpRgn = PRGN_WINDOW; // Need a region so the bits can be set!!!
    }
 
    /*
@@ -664,9 +968,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);
    }
 
    /*
@@ -674,10 +978,16 @@ co_UserRedrawWindow(
     * Repaint and erase windows if needed.
     */
 
-   if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
+   if (Flags & RDW_UPDATENOW)
+   {
+      UserUpdateWindows(Window, Flags);
+   }
+   else if (Flags & RDW_ERASENOW)
    {
-      if (Flags & RDW_ERASENOW) IntSendSyncPaint(Window, Flags);
-      co_IntPaintWindows(Window, Flags, FALSE);
+      if ((Flags & (RDW_NOCHILDREN|RDW_ALLCHILDREN)) == 0)
+         Flags |= RDW_CLIPCHILDREN;
+
+      UserSyncAndPaintWindows(Window, Flags);
    }
 
    /*
@@ -685,9 +995,9 @@ co_UserRedrawWindow(
     * Cleanup ;-)
     */
 
-   if (hRgn != NULL)
+   if (TmpRgn > PRGN_WINDOW)
    {
-      GreDeleteObject(hRgn);
+      REGION_Delete(TmpRgn);
    }
    TRACE("co_UserRedrawWindow exit\n");
 
@@ -702,6 +1012,14 @@ IntIsWindowDirty(PWND Wnd)
              Wnd->state & WNDS_INTERNALPAINT ) );
 }
 
+/*
+   Conditions to paint any window:
+
+   1. Update region is not null.
+   2. Internal paint flag is set.
+   3. Paint count is not zero.
+
+ */
 PWND FASTCALL
 IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
 {
@@ -710,27 +1028,28 @@ IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
 
    for (; Window != NULL; Window = Window->spwndNext)
    {
-      if (IntWndBelongsToThread(Window, Thread) &&
-          IntIsWindowDirty(Window))
+      if (IntWndBelongsToThread(Window, Thread))
       {
-         /* Make sure all non-transparent siblings are already drawn. */
-         if (Window->ExStyle & WS_EX_TRANSPARENT)
+         if (IntIsWindowDirty(Window))
          {
-            for (TempWindow = Window->spwndNext; TempWindow != NULL;
-                 TempWindow = TempWindow->spwndNext)
+            /* Make sure all non-transparent siblings are already drawn. */
+            if (Window->ExStyle & WS_EX_TRANSPARENT)
             {
-               if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
-                   IntWndBelongsToThread(TempWindow, Thread) &&
-                   IntIsWindowDirty(TempWindow))
+               for (TempWindow = Window->spwndNext; TempWindow != NULL;
+                    TempWindow = TempWindow->spwndNext)
                {
-                  return TempWindow;
+                  if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
+                       IntWndBelongsToThread(TempWindow, Thread) &&
+                       IntIsWindowDirty(TempWindow))
+                  {
+                     return TempWindow;
+                  }
                }
             }
+            return Window;
          }
-
-         return Window;
       }
-
+      /* find a child of the specified window that needs repainting */
       if (Window->spwndChild)
       {
          hChild = IntFindWindowToRepaint(Window->spwndChild, Thread);
@@ -750,7 +1069,7 @@ IntGetPaintMessage(
    MSG *Message,
    BOOL Remove)
 {
-   PWND PaintWnd;
+   PWND PaintWnd, StartWnd;
 
    if ((MsgFilterMin != 0 || MsgFilterMax != 0) &&
          (MsgFilterMin > WM_PAINT || MsgFilterMax < WM_PAINT))
@@ -761,19 +1080,26 @@ IntGetPaintMessage(
       ERR("WM_PAINT is in a System Thread!\n");
    }
 
-   PaintWnd = IntFindWindowToRepaint(UserGetDesktopWindow(), Thread);
+   StartWnd = UserGetDesktopWindow();
+   PaintWnd = IntFindWindowToRepaint(StartWnd, Thread);
 
    Message->hwnd = PaintWnd ? UserHMGetHandle(PaintWnd) : NULL;
 
-   if (Message->hwnd == NULL)
+   if (Message->hwnd == NULL && 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 ! */
+      // Find note in window.c:"PAINTING BUG".
+      ERR("WARNING SOMETHING HAS GONE WRONG: Thread marked as containing dirty windows, but no dirty windows found! Counts %u\n",Thread->cPaintsReady);
+      /* Hack to stop spamming the debug log ! */
       Thread->cPaintsReady = 0;
       return FALSE;
    }
 
-   if (Window != NULL && PaintWnd != Window)
+   if (Message->hwnd == NULL)
+      return FALSE;
+
+   if (!(Window == NULL ||
+         PaintWnd == Window ||
+         IntIsChildWindow(Window, PaintWnd))) /* check that it is a child of the specified parent */
       return FALSE;
 
    if (PaintWnd->state & WNDS_INTERNALPAINT)
@@ -782,60 +1108,23 @@ IntGetPaintMessage(
       if (!PaintWnd->hrgnUpdate)
          MsqDecPaintCountQueue(Thread);
    }
-   PaintWnd->state2 &= ~WNDS2_WMPAINTSENT;
+   PaintWnd->state2 &= ~WNDS2_STARTPAINT;
    PaintWnd->state &= ~WNDS_UPDATEDIRTY;
-   Message->wParam = Message->lParam = 0;
-   Message->message = WM_PAINT;
-   return TRUE;
-}
-
-static
-HWND FASTCALL
-co_IntFixCaret(PWND Window, RECTL *lprc, UINT flags)
-{
-   PDESKTOP Desktop;
-   PTHRDCARETINFO CaretInfo;
-   PTHREADINFO pti;
-   PUSER_MESSAGE_QUEUE ActiveMessageQueue;
-   HWND hWndCaret;
-   PWND WndCaret;
-
-   ASSERT_REFS_CO(Window);
-
-   pti = PsGetCurrentThreadWin32Thread();
-   Desktop = pti->rpdesk;
-   ActiveMessageQueue = Desktop->ActiveMessageQueue;
-   if (!ActiveMessageQueue) return 0;
-   CaretInfo = ActiveMessageQueue->CaretInfo;
-   hWndCaret = CaretInfo->hWnd;
 
-   WndCaret = ValidateHwndNoErr(hWndCaret);
-
-   // FIXME: Check for WndCaret can be NULL
-   if (WndCaret == Window ||
-         ((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(Window, WndCaret)))
+   Window = PaintWnd;
+   while( Window && Window != UserGetDesktopWindow())
    {
-      POINT pt, FromOffset, ToOffset;
-      RECTL rcCaret;
-
-      pt.x = CaretInfo->Pos.x;
-      pt.y = CaretInfo->Pos.y;
-      IntGetClientOrigin(WndCaret, &FromOffset);
-      IntGetClientOrigin(Window, &ToOffset);
-      rcCaret.left = pt.x;
-      rcCaret.top = pt.y;
-      rcCaret.right = pt.x + CaretInfo->Size.cx;
-      rcCaret.bottom = pt.y + CaretInfo->Size.cy;
-      if (RECTL_bIntersectRect(lprc, lprc, &rcCaret))
+      // Role back and check for clip children, do not set if any.
+      if (Window->spwndParent && !(Window->spwndParent->style & WS_CLIPCHILDREN))
       {
-         co_UserHideCaret(0);
-         lprc->left = pt.x;
-         lprc->top = pt.y;
-         return hWndCaret;
+         PaintWnd->state2 |= WNDS2_WMPAINTSENT;
       }
+      Window = Window->spwndParent;
    }
 
-   return 0;
+   Message->wParam = Message->lParam = 0;
+   Message->message = WM_PAINT;
+   return TRUE;
 }
 
 BOOL
@@ -867,7 +1156,7 @@ IntPrintWindow(
     return FALSE;
 
     /* Update the window just incase. */
-    co_IntPaintWindows( pwnd, RDW_ERASENOW|RDW_UPDATENOW, FALSE);
+    co_IntUpdateWindows( pwnd, RDW_ALLCHILDREN, FALSE);
 
     hdcSrc = UserGetDCEx( pwnd, NULL, DCX_CACHE|DCX_WINDOW);
     /* Print window to printer context. */
@@ -894,23 +1183,129 @@ BOOL
 FASTCALL
 IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
 {
-   PPROPERTY pprop;
    DWORD FlashState;
-   BOOL Ret = FALSE;
+   UINT uCount = pfwi->uCount;
+   BOOL Activate = FALSE, Ret = FALSE;
+
+   ASSERT(pfwi);
 
-   pprop = IntGetProp(pWnd, AtomFlashWndState);
-   if (!pprop)
+   FlashState = (DWORD)UserGetProp(pWnd, AtomFlashWndState);
+
+   if (FlashState == FLASHW_FINISHED)
    {
-      FlashState = pfwi->dwFlags;
-      IntSetProp(pWnd, AtomFlashWndState, (HANDLE) FlashState);
-      return TRUE;
+      // Cycle has finished, kill timer and set this to Stop.
+      FlashState |= FLASHW_KILLSYSTIMER;
+      pfwi->dwFlags = FLASHW_STOP;
+   }
+   else
+   {
+      if (FlashState)
+      {
+         if (pfwi->dwFlags == FLASHW_SYSTIMER)
+         {
+             // Called from system timer, restore flags, counts and state.
+             pfwi->dwFlags = LOWORD(FlashState);
+             uCount = HIWORD(FlashState);
+             FlashState = MAKELONG(LOWORD(FlashState),0);
+         }
+         else
+         {
+             // Clean out the trash! Fix SeaMonkey crash after restart.
+             FlashState = 0;
+         }
+      }
+
+      if (FlashState == 0)
+      {  // First time in cycle, setup flash state.
+         if ( pWnd->state & WNDS_ACTIVEFRAME ||
+             (pfwi->dwFlags & FLASHW_CAPTION && pWnd->style & (WS_BORDER|WS_DLGFRAME)))
+         {
+             FlashState = FLASHW_STARTED|FLASHW_ACTIVE;
+         }
+      }
+
+      // Set previous window state.
+      Ret = !!(FlashState & FLASHW_ACTIVE);
+
+      if ( pfwi->dwFlags & FLASHW_TIMERNOFG &&
+           gpqForeground == pWnd->head.pti->MessageQueue )
+      {
+          // Flashing until foreground, set this to Stop.
+          pfwi->dwFlags = FLASHW_STOP;
+      }
    }
 
-   FlashState = (DWORD)pprop->Data;
+   // Toggle activate flag.
    if ( pfwi->dwFlags == FLASHW_STOP )
    {
+      if (gpqForeground && gpqForeground->spwndActive == pWnd)
+         Activate = TRUE;
+      else
+         Activate = FALSE;
+   }
+   else
+   {
+      Activate = (FlashState & FLASHW_ACTIVE) == 0;
+   }
+
+   if ( pfwi->dwFlags == FLASHW_STOP || pfwi->dwFlags & FLASHW_CAPTION )
+   {
+      co_IntSendMessage(UserHMGetHandle(pWnd), WM_NCACTIVATE, Activate, 0);
+   }
+
+   // FIXME: Check for a Stop Sign here.
+   if ( pfwi->dwFlags & FLASHW_TRAY )
+   {
+      // Need some shell work here too.
+      TRACE("FIXME: Flash window no Tray support!\n");
+   }
+
+   if ( pfwi->dwFlags == FLASHW_STOP )
+   {
+      if (FlashState & FLASHW_KILLSYSTIMER)
+      {
+         IntKillTimer(pWnd, ID_EVENT_SYSTIMER_FLASHWIN, TRUE);
+      }
+
       IntRemoveProp(pWnd, AtomFlashWndState);
-      Ret = TRUE;
+   }
+   else
+   {  // Have a count and started, set timer.
+      if ( uCount )
+      {
+         FlashState |= FLASHW_COUNT;
+
+         if (!(Activate ^ !!(FlashState & FLASHW_STARTED)))
+             uCount--;
+
+         if (!(FlashState & FLASHW_KILLSYSTIMER))
+             pfwi->dwFlags |= FLASHW_TIMER;
+      }
+
+      if (pfwi->dwFlags & FLASHW_TIMER)
+      {
+         FlashState |= FLASHW_KILLSYSTIMER;
+
+         IntSetTimer( pWnd,
+                      ID_EVENT_SYSTIMER_FLASHWIN,
+                      pfwi->dwTimeout ? pfwi->dwTimeout : gpsi->dtCaretBlink,
+                      SystemTimerProc,
+                      TMRF_SYSTEM );
+      }
+
+      if (FlashState & FLASHW_COUNT && uCount == 0)
+      {
+         // Keep spinning? Nothing else to do.
+         FlashState = FLASHW_FINISHED;
+      }
+      else
+      {
+         // Save state and flags so this can be restored next time through.
+         FlashState ^= (FlashState ^ -!!(Activate)) & FLASHW_ACTIVE;
+         FlashState ^= (FlashState ^ pfwi->dwFlags) & (FLASHW_MASK & ~FLASHW_TIMER);
+      }
+      FlashState = MAKELONG(LOWORD(FlashState),uCount);
+      IntSetProp(pWnd, AtomFlashWndState, (HANDLE) FlashState);
    }
    return Ret;
 }
@@ -918,6 +1313,10 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
 HDC FASTCALL
 IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
 {
+   RECT Rect;
+   INT type;
+   BOOL Erase = FALSE;
+
    co_UserHideCaret(Window);
 
    Window->state2 |= WNDS2_STARTPAINT;
@@ -926,16 +1325,19 @@ IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
    if (Window->state & WNDS_SENDNCPAINT)
    {
       HRGN hRgn;
-
-      Window->state &= ~WNDS_UPDATEDIRTY;
-      hRgn = IntGetNCUpdateRgn(Window, FALSE);
-      Window->state &= ~WNDS_SENDNCPAINT;
-      co_IntSendMessage(UserHMGetHandle(Window), WM_NCPAINT, (WPARAM)hRgn, 0);
-      if (hRgn != HRGN_WINDOW && hRgn != NULL && GreIsHandleValid(hRgn))
+      // Application can keep update dirty.
+      do
       {
-         /* NOTE: The region can already be deleted! */
-         GreDeleteObject(hRgn);
+         Window->state &= ~WNDS_UPDATEDIRTY;
+         hRgn = IntGetNCUpdateRgn(Window, FALSE);
+         IntSendNCPaint(Window, hRgn);
+         if (hRgn > HRGN_WINDOW && GreIsHandleValid(hRgn))
+         {
+            /* NOTE: The region can already be deleted! */
+            GreDeleteObject(hRgn);
+         }
       }
+      while(Window->state & WNDS_UPDATEDIRTY);
    }
    else
    {
@@ -944,18 +1346,29 @@ IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
 
    RtlZeroMemory(Ps, sizeof(PAINTSTRUCT));
 
+   if (Window->state2 & WNDS2_ENDPAINTINVALIDATE)
+   {
+      ERR("BP: Another thread invalidated this window\n");
+   }
+
    Ps->hdc = UserGetDCEx( Window,
-                         Window->hrgnUpdate,
-                         DCX_INTERSECTRGN | DCX_USESTYLE);
+                          Window->hrgnUpdate,
+                          DCX_INTERSECTRGN | DCX_USESTYLE);
    if (!Ps->hdc)
    {
       return NULL;
    }
 
+   // If set, always clear flags out due to the conditions later on for sending the message.
+   if (Window->state & WNDS_SENDERASEBACKGROUND)
+   {
+      Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
+      Erase = TRUE;
+   }
+
    if (Window->hrgnUpdate != NULL)
    {
       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;
@@ -964,15 +1377,19 @@ IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
    {
       if (Window->state & WNDS_INTERNALPAINT)
          MsqDecPaintCountQueue(Window->head.pti);
-
-      IntGetClientRect(Window, &Ps->rcPaint);
    }
 
+   type = GdiGetClipBox(Ps->hdc, &Ps->rcPaint);
+
+   IntGetClientRect(Window, &Rect);
+
    Window->state &= ~WNDS_INTERNALPAINT;
 
-   if (Window->state & WNDS_SENDERASEBACKGROUND)
+   if ( Erase &&               // Set to erase,
+        type != NULLREGION &&  // don't erase if the clip box is empty,
+        (!(Window->pcls->style & CS_PARENTDC) || // not parent dc or
+         RECTL_bIntersectRect( &Rect, &Rect, &Ps->rcPaint) ) ) // intersecting.
    {
-      Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
       Ps->fErase = !co_IntSendMessage(UserHMGetHandle(Window), WM_ERASEBKGND, (WPARAM)Ps->hdc, 0);
       if ( Ps->fErase )
       {
@@ -983,18 +1400,9 @@ IntBeginPaint(PWND Window, PPAINTSTRUCT Ps)
    {
       Ps->fErase = FALSE;
    }
-   if (Window->hrgnUpdate)
-   {
-      if (!(Window->style & WS_CLIPCHILDREN))
-      {
-         PWND Child;
-         for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
-         {
-            if (Child->hrgnUpdate == NULL && Child->state & WNDS_SENDNCPAINT) // Helped fixing test_redrawnow.
-            IntInvalidateWindows(Child, Window->hrgnUpdate, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
-         }
-      }
-   }
+
+   IntSendChildNCPaint(Window);
+
    return Ps->hdc;
 }
 
@@ -1007,6 +1415,12 @@ IntEndPaint(PWND Wnd, PPAINTSTRUCT Ps)
 
    UserReleaseDC(Wnd, hdc, TRUE);
 
+   if (Wnd->state2 & WNDS2_ENDPAINTINVALIDATE)
+   {
+      ERR("EP: Another thread invalidated this window\n");
+      Wnd->state2 &= ~WNDS2_ENDPAINTINVALIDATE;
+   }
+
    Wnd->state2 &= ~(WNDS2_WMPAINTSENT|WNDS2_STARTPAINT);
 
    co_UserShowCaret(Wnd);
@@ -1156,35 +1570,130 @@ Exit:
    return Ret;
 }
 
+/*
+    GetUpdateRgn, this fails the same as the old one.
+ */
 INT FASTCALL
 co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
 {
    int RegionType;
+   BOOL Type;
    RECTL Rect;
 
    ASSERT_REFS_CO(Window);
 
+   if (bErase)
+   {
+      USER_REFERENCE_ENTRY Ref;
+      UserRefObjectCo(Window, &Ref);
+      co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
+      UserDerefObjectCo(Window);
+   }
+
    Window->state &= ~WNDS_UPDATEDIRTY;
 
    if (Window->hrgnUpdate == NULL)
    {
-      RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
+       NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+       return NULLREGION;
+   }
+
+   Rect = Window->rcClient;
+   Type = IntIntersectWithParents(Window, &Rect);
+
+   if (Window->hrgnUpdate == HRGN_WINDOW)
+   {
+      // Trap it out.
+      ERR("GURn: Caller is passing Window Region 1\n");
+      if (!Type)
+      {
+         NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+         return NULLREGION;
+      }
+
+      RegionType = SIMPLEREGION;
+
+      if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
+      {
+         RECTL_vOffsetRect(&Rect,
+                          -Window->rcClient.left,
+                          -Window->rcClient.top);
+      }
+      GreSetRectRgnIndirect(hRgn, &Rect);
    }
    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);
+      HRGN hrgnTemp = GreCreateRectRgnIndirect(&Rect);
+
+      RegionType = NtGdiCombineRgn(hRgn, hrgnTemp, Window->hrgnUpdate, RGN_AND);
+
+      if (RegionType == ERROR || RegionType == NULLREGION)
+      {
+         if (hrgnTemp) GreDeleteObject(hrgnTemp);
+         NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
+         return NULLREGION;
+      }
+
+      if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
+      {
+         NtGdiOffsetRgn(hRgn,
+                       -Window->rcClient.left,
+                       -Window->rcClient.top);
+      }
+      if (hrgnTemp) GreDeleteObject(hrgnTemp);
    }
+   return RegionType;
+}
+
+BOOL FASTCALL
+co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase)
+{
+   INT RegionType;
+   BOOL Ret = TRUE;
 
-   if (bErase && RegionType != NULLREGION && RegionType != ERROR)
+   if (bErase)
    {
-      co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
+      USER_REFERENCE_ENTRY Ref;
+      UserRefObjectCo(Window, &Ref);
+      co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
+      UserDerefObjectCo(Window);
    }
 
-   return RegionType;
+   Window->state &= ~WNDS_UPDATEDIRTY;
+
+   if (Window->hrgnUpdate == NULL)
+   {
+      pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
+      Ret = FALSE;
+   }
+   else
+   {
+      /* Get the update region bounding box. */
+      if (Window->hrgnUpdate == HRGN_WINDOW)
+      {
+         *pRect = Window->rcClient;
+         ERR("GURt: Caller is retrieving Window Region 1\n");
+      }
+      else
+      {
+         RegionType = IntGdiGetRgnBox(Window->hrgnUpdate, pRect);
+
+         if (RegionType != ERROR && RegionType != NULLREGION)
+            RECTL_bIntersectRect(pRect, pRect, &Window->rcClient);
+      }
+
+      if (IntIntersectWithParents(Window, pRect))
+      {
+         RECTL_vOffsetRect(pRect,
+                          -Window->rcClient.left,
+                          -Window->rcClient.top);
+      }
+      else
+      {
+         pRect->left = pRect->top = pRect->right = pRect->bottom = 0;
+      }
+   }
+   return Ret;
 }
 
 /*
@@ -1200,7 +1709,6 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
    DECLARE_RETURN(INT);
    PWND Window;
    INT ret;
-   USER_REFERENCE_ENTRY Ref;
 
    TRACE("Enter NtUserGetUpdateRgn\n");
    UserEnterExclusive();
@@ -1210,9 +1718,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
       RETURN(ERROR);
    }
 
-   UserRefObjectCo(Window, &Ref);
    ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
-   UserDerefObjectCo(Window);
 
    RETURN(ret);
 
@@ -1234,9 +1740,8 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
 {
    PWND Window;
    RECTL Rect;
-   INT RegionType;
-   PROSRGNDATA RgnData;
    NTSTATUS Status;
+   BOOL Ret;
    DECLARE_RETURN(BOOL);
 
    TRACE("Enter NtUserGetUpdateRect\n");
@@ -1247,48 +1752,7 @@ 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;
-   }
-   else
-   {
-      /* Get the update region bounding box. */
-      if (Window->hrgnUpdate == HRGN_WINDOW)
-      {
-         Rect = Window->rcClient;
-      }
-      else
-      {
-         RgnData = RGNOBJAPI_Lock(Window->hrgnUpdate, NULL);
-         ASSERT(RgnData != NULL);
-         RegionType = REGION_GetRgnBox(RgnData, &Rect);
-         RGNOBJAPI_Unlock(RgnData);
-
-         if (RegionType != ERROR && RegionType != NULLREGION)
-            RECTL_bIntersectRect(&Rect, &Rect, &Window->rcClient);
-      }
-
-      if (IntIntersectWithParents(Window, &Rect))
-      {
-         RECTL_vOffsetRect(&Rect,
-                          -Window->rcClient.left,
-                          -Window->rcClient.top);
-      } else
-      {
-         Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
-      }
-   }
-
-   if (bErase && !RECTL_bIsEmptyRect(&Rect))
-   {
-      USER_REFERENCE_ENTRY Ref;
-      UserRefObjectCo(Window, &Ref);
-      co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
-      UserDerefObjectCo(Window);
-   }
+   Ret = co_UserGetUpdateRect(Window, &Rect, bErase);
 
    if (UnsafeRect != NULL)
    {
@@ -1300,7 +1764,7 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
       }
    }
 
-   RETURN(!RECTL_bIsEmptyRect(&Rect));
+   RETURN(Ret);
 
 CLEANUP:
    TRACE("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
@@ -1327,6 +1791,7 @@ NtUserRedrawWindow(
    BOOL Ret;
    USER_REFERENCE_ENTRY Ref;
    NTSTATUS Status = STATUS_SUCCESS;
+   PREGION RgnUpdate = NULL;
    DECLARE_RETURN(BOOL);
 
    TRACE("Enter NtUserRedrawWindow\n");
@@ -1365,11 +1830,29 @@ NtUserRedrawWindow(
       RETURN( FALSE);
    }
 
+   /* We can't hold lock on GDI objects while doing roundtrips to user mode,
+    * so it will be copied.
+    */
+   if (hrgnUpdate > HRGN_WINDOW)
+   {
+       RgnUpdate = REGION_LockRgn(hrgnUpdate);
+       if (!RgnUpdate)
+       {
+           EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+           RETURN(FALSE);
+       }
+       REGION_UnlockRgn(RgnUpdate);
+   }
+   else if (hrgnUpdate == HRGN_WINDOW) // Trap it out.
+   {
+       ERR("NTRW: Caller is passing Window Region 1\n");
+   }
+
    UserRefObjectCo(Wnd, &Ref);
 
    Ret = co_UserRedrawWindow( Wnd,
                               lprcUpdate ? &SafeUpdateRect : NULL,
-                              hrgnUpdate,
+                              RgnUpdate,
                               flags);
 
    UserDerefObjectCo(Wnd);
@@ -1382,450 +1865,11 @@ CLEANUP:
    END_CLEANUP;
 }
 
-static
-INT FASTCALL
-UserScrollDC(
-   HDC hDC,
-   INT dx,
-   INT dy,
-   const RECTL *prcScroll,
-   const RECTL *prcClip,
-   HRGN hrgnUpdate,
-   RECTL *prcUpdate)
-{
-   PDC pDC;
-   RECTL rcScroll, rcClip, rcSrc, rcDst;
-   INT Result;
-
-   GdiGetClipBox(hDC, &rcClip);
-   rcScroll = rcClip;
-   if (prcClip)
-   {
-      RECTL_bIntersectRect(&rcClip, &rcClip, prcClip);
-   }
-
-   if (prcScroll)
-   {
-      rcScroll = *prcScroll;
-      RECTL_bIntersectRect(&rcSrc, &rcClip, prcScroll);
-   }
-   else
-   {
-      rcSrc = rcClip;
-   }
-
-   rcDst = rcSrc;
-   RECTL_vOffsetRect(&rcDst, dx, dy);
-   RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
-
-   if (!NtGdiBitBlt( hDC,
-                     rcDst.left,
-                     rcDst.top,
-                     rcDst.right - rcDst.left,
-                     rcDst.bottom - rcDst.top,
-                     hDC,
-                     rcDst.left - dx,
-                     rcDst.top - dy,
-                     SRCCOPY,
-                     0,
-                     0))
-   {
-      return ERROR;
-   }
-
-   /* Calculate the region that was invalidated by moving or
-      could not be copied, because it was not visible */
-   if (hrgnUpdate || prcUpdate)
-   {
-      HRGN hrgnOwn, hrgnTmp;
-      PREGION prgnTmp;
-
-      pDC = DC_LockDc(hDC);
-      if (!pDC)
-      {
-         return FALSE;
-      }
-
-      /* Begin with the shifted and then clipped scroll rect */
-      rcDst = rcScroll;
-      RECTL_vOffsetRect(&rcDst, dx, dy);
-      RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
-      if (hrgnUpdate)
-      {
-         hrgnOwn = hrgnUpdate;
-         if (!NtGdiSetRectRgn(hrgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom))
-         {
-            DC_UnlockDc(pDC);
-            return ERROR;
-         }
-      }
-      else
-      {
-         hrgnOwn = IntSysCreateRectRgnIndirect(&rcDst);
-      }
-
-      /* Add the source rect */
-      hrgnTmp = IntSysCreateRectRgnIndirect(&rcSrc);
-      NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnTmp, 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);
-
-      /* DO NOT Unlock DC while messing with prgnVis! */
-      DC_UnlockDc(pDC);
-
-      GreDeleteObject(hrgnTmp);
-
-      if (prcUpdate)
-      {
-         IntGdiGetRgnBox(hrgnOwn, prcUpdate);
-      }
-
-      if (!hrgnUpdate)
-      {
-         GreDeleteObject(hrgnOwn);
-      }
-   }
-   else
-      Result = NULLREGION;
-
-   return Result;
-}
-
-/*
- * NtUserScrollDC
- *
- * Status
- *    @implemented
- */
-BOOL APIENTRY
-NtUserScrollDC(
-   HDC hDC,
-   INT dx,
-   INT dy,
-   const RECT *prcUnsafeScroll,
-   const RECT *prcUnsafeClip,
-   HRGN hrgnUpdate,
-   LPRECT prcUnsafeUpdate)
-{
-   DECLARE_RETURN(DWORD);
-   RECTL rcScroll, rcClip, rcUpdate;
-   NTSTATUS Status = STATUS_SUCCESS;
-   DWORD Result;
-
-   TRACE("Enter NtUserScrollDC\n");
-   UserEnterExclusive();
-
-   _SEH2_TRY
-   {
-      if (prcUnsafeScroll)
-      {
-         ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
-         rcScroll = *prcUnsafeScroll;
-      }
-      if (prcUnsafeClip)
-      {
-         ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
-         rcClip = *prcUnsafeClip;
-      }
-      if (prcUnsafeUpdate)
-      {
-         ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
-      }
-   }
-   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-   {
-      Status = _SEH2_GetExceptionCode();
-   }
-   _SEH2_END
-   if (!NT_SUCCESS(Status))
-   {
-      SetLastNtError(Status);
-      RETURN(FALSE);
-   }
-
-   Result = UserScrollDC( hDC,
-                          dx,
-                          dy,
-                          prcUnsafeScroll? &rcScroll : 0,
-                          prcUnsafeClip? &rcClip : 0,
-                          hrgnUpdate,
-                          prcUnsafeUpdate? &rcUpdate : NULL);
-   if(Result == ERROR)
-   {
-         /* FIXME: Only if hRgnUpdate is invalid we should SetLastError(ERROR_INVALID_HANDLE) */
-      RETURN(FALSE);
-   }
-
-   if (prcUnsafeUpdate)
-   {
-      _SEH2_TRY
-      {
-         *prcUnsafeUpdate = rcUpdate;
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-         Status = _SEH2_GetExceptionCode();
-      }
-      _SEH2_END
-      if (!NT_SUCCESS(Status))
-      {
-         /* FIXME: SetLastError? */
-         /* FIXME: correct? We have already scrolled! */
-         RETURN(FALSE);
-      }
-   }
-
-   RETURN(TRUE);
-
-CLEANUP:
-   TRACE("Leave NtUserScrollDC, ret=%lu\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
-}
-
-/*
- * NtUserScrollWindowEx
- *
- * Status
- *    @implemented
- */
-
-DWORD APIENTRY
-NtUserScrollWindowEx(
-   HWND hWnd,
-   INT dx,
-   INT dy,
-   const RECT *prcUnsafeScroll,
-   const RECT *prcUnsafeClip,
-   HRGN hrgnUpdate,
-   LPRECT prcUnsafeUpdate,
-   UINT flags)
-{
-   RECTL rcScroll, rcClip, rcCaret, rcUpdate;
-   INT Result;
-   PWND Window = NULL, CaretWnd;
-   HDC hDC;
-   HRGN hrgnOwn = NULL, hrgnTemp, hrgnWinupd = NULL;
-   HWND hwndCaret;
-   DWORD dcxflags = 0;
-   int rdw_flags;
-   BOOL bOwnRgn = TRUE;
-   NTSTATUS Status = STATUS_SUCCESS;
-   DECLARE_RETURN(DWORD);
-   USER_REFERENCE_ENTRY Ref, CaretRef;
-
-   TRACE("Enter NtUserScrollWindowEx\n");
-   UserEnterExclusive();
-
-   Window = UserGetWindowObject(hWnd);
-   if (!Window || !IntIsWindowDrawable(Window))
-   {
-      Window = NULL; /* prevent deref at cleanup */
-      RETURN( ERROR);
-   }
-   UserRefObjectCo(Window, &Ref);
-
-   IntGetClientRect(Window, &rcClip);
-
-   _SEH2_TRY
-   {
-      if (prcUnsafeScroll)
-      {
-         ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
-         RECTL_bIntersectRect(&rcScroll, &rcClip, prcUnsafeScroll);
-      }
-      else
-         rcScroll = rcClip;
-
-      if (prcUnsafeClip)
-      {
-         ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
-         RECTL_bIntersectRect(&rcClip, &rcClip, prcUnsafeClip);
-      }
-   }
-   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-   {
-      Status = _SEH2_GetExceptionCode();
-   }
-   _SEH2_END
-
-   if (!NT_SUCCESS(Status))
-   {
-      SetLastNtError(Status);
-      RETURN(ERROR);
-   }
-
-   if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
-         (dx == 0 && dy == 0))
-   {
-      RETURN(NULLREGION);
-   }
-
-   if (hrgnUpdate)
-   {
-      hrgnOwn = hrgnUpdate;
-      bOwnRgn = FALSE;
-   }
-   else
-      hrgnOwn = IntSysCreateRectRgn(0, 0, 0, 0);
-
-   /* 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
-   {
-       /* So in this case ScrollWindowEx uses Cache DC. */
-       dcxflags = DCX_CACHE|DCX_USESTYLE;
-       if (flags & SW_SCROLLCHILDREN) dcxflags |= DCX_NOCLIPCHILDREN;
-   }
-
-   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,
-                          prcUnsafeUpdate? &rcUpdate : NULL);
-
-   UserReleaseDC(Window, hDC, FALSE);
-
-   /*
-    * Take into account the fact that some damage may have occurred during
-    * 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)
-   {
-      HRGN hrgnClip = IntSysCreateRectRgnIndirect(&rcClip);
-      if (!bOwnRgn)
-      {
-         hrgnWinupd = IntSysCreateRectRgn( 0, 0, 0, 0);
-         NtGdiCombineRgn( hrgnWinupd, hrgnTemp, 0, RGN_COPY);
-      }
-      NtGdiOffsetRgn(hrgnTemp, dx, dy);
-      NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
-      if (!bOwnRgn) NtGdiCombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR );
-      co_UserRedrawWindow(Window, NULL, hrgnTemp, rdw_flags );
-      GreDeleteObject(hrgnClip);
-   }
-   GreDeleteObject(hrgnTemp);
-
-   if (flags & SW_SCROLLCHILDREN)
-   {
-      PWND Child;
-      RECTL rcChild;
-      POINT ClientOrigin;
-      USER_REFERENCE_ENTRY WndRef;
-      RECTL rcDummy;
-
-      IntGetClientOrigin(Window, &ClientOrigin);
-      for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
-      {
-         rcChild = Child->rcWindow;
-         rcChild.left -= ClientOrigin.x;
-         rcChild.top -= ClientOrigin.y;
-         rcChild.right -= ClientOrigin.x;
-         rcChild.bottom -= ClientOrigin.y;
-
-         if (! prcUnsafeScroll || RECTL_bIntersectRect(&rcDummy, &rcChild, &rcScroll))
-         {
-            UserRefObjectCo(Child, &WndRef);
-            co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0,
-                                  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
-                                  SWP_NOREDRAW | SWP_DEFERERASE);
-            UserDerefObjectCo(Child);
-         }
-      }
-   }
-
-   if (flags & (SW_INVALIDATE | SW_ERASE))
-   {
-      co_UserRedrawWindow(Window, NULL, hrgnOwn, rdw_flags |
-                          ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
-                          ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
-   }
-
-   if (hwndCaret && (CaretWnd = UserGetWindowObject(hwndCaret)))
-   {
-      UserRefObjectCo(CaretWnd, &CaretRef);
-
-      co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
-      co_UserShowCaret(CaretWnd);
-
-      UserDerefObjectCo(CaretWnd);
-   }
-
-   if (prcUnsafeUpdate)
-   {
-      _SEH2_TRY
-      {
-         /* Probe here, to not fail on invalid pointer before scrolling */
-         ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
-         *prcUnsafeUpdate = rcUpdate;
-      }
-      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-      {
-         Status = _SEH2_GetExceptionCode();
-      }
-      _SEH2_END
-
-      if (!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         RETURN(ERROR);
-      }
-   }
-
-   RETURN(Result);
-
-CLEANUP:
-   if (hrgnWinupd && !bOwnRgn)
-   {
-      NtGdiCombineRgn( hrgnOwn, hrgnOwn, hrgnWinupd, RGN_OR);
-      GreDeleteObject(hrgnWinupd);
-   }
-
-   if (hrgnOwn && !hrgnUpdate)
-   {
-      GreDeleteObject(hrgnOwn);
-   }
-
-   if (Window)
-      UserDerefObjectCo(Window);
-
-   TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
-}
+static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
 
 BOOL
 UserDrawCaptionText(
+   PWND pWnd,
    HDC hDc,
    const PUNICODE_STRING Text,
    const RECTL *lpRc,
@@ -1838,12 +1882,14 @@ UserDrawCaptionText(
    NTSTATUS Status;
    BOOLEAN bDeleteFont = FALSE;
    SIZE Size;
+   ULONG fit = 0, Length;
+   WCHAR szText[128];
+   RECTL r = *lpRc;
 
    TRACE("UserDrawCaptionText: %wZ\n", Text);
 
    nclm.cbSize = sizeof(nclm);
-   if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS,
-      sizeof(NONCLIENTMETRICS), &nclm, 0))
+   if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nclm, 0))
    {
       ERR("UserSystemParametersInfo() failed!\n");
       return FALSE;
@@ -1868,27 +1914,51 @@ UserDrawCaptionText(
    IntGdiSetBkMode(hDc, TRANSPARENT);
 
    hOldFont = NtGdiSelectFont(hDc, hFont);
-   if(!hOldFont)
-   {
-      ERR("SelectFont() failed!\n");
-      /* Don't fail */
-   }
 
    if(uFlags & DC_INBUTTON)
       OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(COLOR_BTNTEXT));
    else
-      OldTextColor = IntGdiSetTextColor(hDc, IntGetSysColor(uFlags & DC_ACTIVE
-         ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
+      OldTextColor = IntGdiSetTextColor(hDc,
+                                        IntGetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
+
+   // Adjust for system menu.
+   if (pWnd && pWnd->style & WS_SYSMENU)
+   {
+      r.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
+      if ((pWnd->style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW))
+      {
+         r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+         r.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
+      }
+   }
+
+   GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 0);
 
-   // FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
-   GreGetTextExtentW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), &Size, 0);
-   GreExtTextOutW(hDc,
-                  lpRc->left, (lpRc->top + lpRc->bottom)/2 - Size.cy/2,
-                  0, NULL, Text->Buffer, Text->Length/sizeof(WCHAR), NULL, 0);
+   Length = (Text->Length/sizeof(WCHAR) == fit ? fit : fit+1);
+   
+   RtlZeroMemory(&szText, sizeof(szText));
+   RtlCopyMemory(&szText, Text->Buffer, Text->Length);
+
+   if (Text->Length/sizeof(WCHAR) > Length && Length > 3)
+   {
+      RtlCopyMemory(&szText[Length-3], ELLIPSISW, sizeof(ELLIPSISW));
+   }
+
+   GreExtTextOutW( hDc,
+                   lpRc->left,
+                   lpRc->top + (lpRc->bottom - lpRc->top) / 2 - Size.cy / 2, // DT_SINGLELINE && DT_VCENTER
+                   ETO_CLIPPED,
+                  (RECTL *)lpRc,
+                  (LPWSTR)&szText,
+                   Length,
+                   NULL,
+                   0 );
 
    IntGdiSetTextColor(hDc, OldTextColor);
+
    if (hOldFont)
       NtGdiSelectFont(hDc, hOldFont);
+
    if (bDeleteFont)
       GreDeleteObject(hFont);
 
@@ -1985,13 +2055,17 @@ BOOL UserDrawCaption(
    {
       PCURICON_OBJECT pIcon = NULL;
 
-      if (!hIcon && pWnd)
+      if (hIcon)
       {
-          hIcon = NC_IconForWindow( pWnd );
+          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)
       {
@@ -2002,9 +2076,13 @@ BOOL UserDrawCaption(
          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))
@@ -2012,14 +2090,14 @@ BOOL UserDrawCaption(
       Rect.left += 2;
 
       if (Str)
-         UserDrawCaptionText(hDc, Str, &Rect, uFlags, hFont);
+         UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont);
       else if (pWnd != NULL) // FIXME: Windows does not do that
       {
          UNICODE_STRING ustr;
          ustr.Buffer = pWnd->strName.Buffer; // FIXME: LARGE_STRING truncated!
          ustr.Length = (USHORT)min(pWnd->strName.Length, MAXUSHORT);
          ustr.MaximumLength = (USHORT)min(pWnd->strName.MaximumLength, MAXUSHORT);
-         UserDrawCaptionText(hDc, &ustr, &Rect, uFlags, hFont);
+         UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont);
       }
    }
 
@@ -2141,7 +2219,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
@@ -2151,6 +2235,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));
 }
 
@@ -2197,11 +2286,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 */