[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / painting.c
index 7f86ccd..43e8d88 100644 (file)
@@ -9,9 +9,6 @@
 #include <win32k.h>
 DBG_DEFAULT_CHANNEL(UserPainting);
 
-#define RDW_CLIPCHILDREN  4096
-#define RDW_NOUPDATEDIRTY 32768
-
 /* PRIVATE FUNCTIONS **********************************************************/
 
 /**
@@ -510,7 +507,7 @@ co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
 {
    HWND hWnd = Wnd->head.h;
 
-   if ((Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT))
+   if ( Wnd->hrgnUpdate != NULL || Wnd->state & WNDS_INTERNALPAINT )
    {
       if (Wnd->hrgnUpdate)
       {
@@ -573,7 +570,7 @@ co_IntUpdateWindows(PWND Wnd, ULONG Flags, BOOL Recurse)
             if (Next) continue;
          }
 
-         if ( Child->style & WS_VISIBLE)
+         if (Child->style & WS_VISIBLE)
          {
              USER_REFERENCE_ENTRY Ref;
              UserRefObjectCo(Child, &Ref);
@@ -685,7 +682,7 @@ IntInvalidateWindows(PWND Wnd, PREGION Rgn, ULONG Flags)
    }
    else
    {
-      RgnType == NULLREGION;
+      RgnType = NULLREGION;
    }
 
    /*
@@ -1004,6 +1001,106 @@ co_UserRedrawWindow(
    return TRUE;
 }
 
+VOID FASTCALL
+PaintSuspendedWindow(PWND pwnd, HRGN hrgnOrig)
+{
+   if (pwnd->hrgnUpdate)
+   {
+      HDC hDC;
+      INT Flags = DC_NC|DC_NOSENDMSG;
+      HRGN hrgnTemp;
+      RECT Rect;
+      INT type;
+      PREGION prgn;
+
+      if (pwnd->hrgnUpdate > HRGN_WINDOW)
+      {
+         hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+         type = NtGdiCombineRgn( hrgnTemp, pwnd->hrgnUpdate, 0, RGN_COPY);
+         if (type == ERROR)
+         {
+            GreDeleteObject(hrgnTemp);
+            hrgnTemp = HRGN_WINDOW;
+         }
+      }
+      else
+      {
+         hrgnTemp = GreCreateRectRgnIndirect(&pwnd->rcWindow);
+      }
+
+      if ( hrgnOrig &&
+           hrgnTemp > HRGN_WINDOW &&
+           NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnOrig, RGN_AND) == NULLREGION)
+      {
+         GreDeleteObject(hrgnTemp);
+         return;
+      }
+
+      hDC = UserGetDCEx(pwnd, hrgnTemp, DCX_WINDOW|DCX_INTERSECTRGN|DCX_USESTYLE|DCX_KEEPCLIPRGN);
+
+      Rect = pwnd->rcWindow;
+      RECTL_vOffsetRect(&Rect, -pwnd->rcWindow.left, -pwnd->rcWindow.top);
+
+      // Clear out client area!
+      FillRect(hDC, &Rect, IntGetSysColorBrush(COLOR_WINDOW));
+
+      NC_DoNCPaint(pwnd, hDC, Flags); // Redraw without MENUs.
+
+      UserReleaseDC(pwnd, hDC, FALSE);
+
+      prgn = REGION_LockRgn(hrgnTemp);
+      IntInvalidateWindows(pwnd, prgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
+      REGION_UnlockRgn(prgn);
+
+      // Set updates for this window.
+      pwnd->state |= WNDS_SENDNCPAINT|WNDS_SENDERASEBACKGROUND|WNDS_UPDATEDIRTY;
+
+      // DCX_KEEPCLIPRGN is set. Check it anyway.
+      if (hrgnTemp > HRGN_WINDOW && GreIsHandleValid(hrgnTemp)) GreDeleteObject(hrgnTemp);
+   }
+}
+
+VOID FASTCALL
+UpdateTheadChildren(PWND pWnd, HRGN hRgn)
+{
+   PaintSuspendedWindow( pWnd, hRgn );
+
+   if (!(pWnd->style & WS_CLIPCHILDREN))
+      return;
+
+   pWnd = pWnd->spwndChild; // invalidate children if any.
+   while (pWnd)
+   {
+      UpdateTheadChildren( pWnd, hRgn );
+      pWnd = pWnd->spwndNext;
+   }
+}
+
+VOID FASTCALL
+UpdateThreadWindows(PWND pWnd, PTHREADINFO pti, HRGN hRgn)
+{
+   PWND pwndTemp;
+
+   for ( pwndTemp = pWnd;
+         pwndTemp;
+         pwndTemp = pwndTemp->spwndNext )
+   {
+      if (pwndTemp->head.pti == pti)
+      {
+          UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
+      }
+      else
+      {
+          if (IsThreadSuspended(pwndTemp->head.pti))
+          {
+             UpdateTheadChildren(pwndTemp, hRgn);
+          }
+          else
+             UserUpdateWindows(pwndTemp, RDW_ALLCHILDREN);
+      }
+   }
+}
+
 BOOL FASTCALL
 IntIsWindowDirty(PWND Wnd)
 {
@@ -1060,6 +1157,16 @@ IntFindWindowToRepaint(PWND Window, PTHREADINFO Thread)
    return Window;
 }
 
+//
+// Internal painting of windows.
+//
+VOID FASTCALL
+IntPaintWindow( PWND Window )
+{
+   // Handle normal painting.
+   co_IntPaintWindows( Window, RDW_NOCHILDREN, FALSE );
+}
+
 BOOL FASTCALL
 IntGetPaintMessage(
    PWND Window,
@@ -1127,55 +1234,6 @@ IntGetPaintMessage(
    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)))
-   {
-      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))
-      {
-         co_UserHideCaret(0);
-         lprc->left = pt.x;
-         lprc->top = pt.y;
-         return hWndCaret;
-      }
-   }
-
-   return 0;
-}
-
 BOOL
 FASTCALL
 IntPrintWindow(
@@ -1238,7 +1296,7 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
 
    ASSERT(pfwi);
 
-   FlashState = (DWORD)UserGetProp(pWnd, AtomFlashWndState);
+   FlashState = (DWORD)UserGetProp(pWnd, AtomFlashWndState, TRUE);
 
    if (FlashState == FLASHW_FINISHED)
    {
@@ -1276,7 +1334,7 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
       // Set previous window state.
       Ret = !!(FlashState & FLASHW_ACTIVE);
 
-      if ( pfwi->dwFlags & FLASHW_TIMERNOFG &&
+      if ( (pfwi->dwFlags & FLASHW_TIMERNOFG) == FLASHW_TIMERNOFG &&
            gpqForeground == pWnd->head.pti->MessageQueue )
       {
           // Flashing until foreground, set this to Stop.
@@ -1316,7 +1374,7 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
          IntKillTimer(pWnd, ID_EVENT_SYSTIMER_FLASHWIN, TRUE);
       }
 
-      IntRemoveProp(pWnd, AtomFlashWndState);
+      UserRemoveProp(pWnd, AtomFlashWndState, TRUE);
    }
    else
    {  // Have a count and started, set timer.
@@ -1354,7 +1412,7 @@ IntFlashWindowEx(PWND pWnd, PFLASHWINFO pfwi)
          FlashState ^= (FlashState ^ pfwi->dwFlags) & (FLASHW_MASK & ~FLASHW_TIMER);
       }
       FlashState = MAKELONG(LOWORD(FlashState),uCount);
-      IntSetProp(pWnd, AtomFlashWndState, (HANDLE) FlashState);
+      UserSetProp(pWnd, AtomFlashWndState, (HANDLE)FlashState, TRUE);
    }
    return Ret;
 }
@@ -1585,30 +1643,27 @@ NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
 {
    PWND pWnd;
    FLASHWINFO finfo = {0};
-   BOOL Ret = TRUE;
+   BOOL Ret = FALSE;
 
    UserEnterExclusive();
 
    _SEH2_TRY
    {
-      ProbeForRead(pfwi, sizeof(FLASHWINFO), sizeof(ULONG));
+      ProbeForRead(pfwi, sizeof(FLASHWINFO), 1);
       RtlCopyMemory(&finfo, pfwi, sizeof(FLASHWINFO));
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
       SetLastNtError(_SEH2_GetExceptionCode());
-      Ret = FALSE;
+      _SEH2_YIELD(goto Exit);
    }
    _SEH2_END
 
-   if (!Ret) goto Exit;
-
-   if (!( pWnd = (PWND)UserGetObject(gHandleTable, finfo.hwnd, TYPE_WINDOW)) ||
+   if (!( pWnd = ValidateHwndNoErr(finfo.hwnd)) ||
         finfo.cbSize != sizeof(FLASHWINFO) ||
         finfo.dwFlags & ~(FLASHW_ALL|FLASHW_TIMER|FLASHW_TIMERNOFG) )
    {
       EngSetLastError(ERROR_INVALID_PARAMETER);
-      Ret = FALSE;
       goto Exit;
    }
 
@@ -1680,7 +1735,7 @@ co_UserGetUpdateRgn(PWND Window, HRGN hRgn, BOOL bErase)
       {
          if (hrgnTemp) GreDeleteObject(hrgnTemp);
          NtGdiSetRectRgn(hRgn, 0, 0, 0, 0);
-         return NULLREGION;
+         return RegionType;
       }
 
       if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
@@ -1733,9 +1788,23 @@ co_UserGetUpdateRect(PWND Window, PRECT pRect, BOOL bErase)
 
       if (IntIntersectWithParents(Window, pRect))
       {
-         RECTL_vOffsetRect(pRect,
-                          -Window->rcClient.left,
-                          -Window->rcClient.top);
+         if (Window != UserGetDesktopWindow()) // Window->fnid == FNID_DESKTOP
+         {
+            RECTL_vOffsetRect(pRect,
+                              -Window->rcClient.left,
+                              -Window->rcClient.top);
+         }
+         if (Window->pcls->style & CS_OWNDC)
+         {
+            HDC hdc;
+            //DWORD layout;
+            hdc = UserGetDCEx(Window, NULL, DCX_USESTYLE);
+            //layout = NtGdiSetLayout(hdc, -1, 0);
+            //IntMapWindowPoints( 0, Window, (LPPOINT)pRect, 2 );
+            GreDPtoLP( hdc, (LPPOINT)pRect, 2 );
+            //NtGdiSetLayout(hdc, -1, layout);
+            UserReleaseDC(Window, hdc, FALSE);
+         }
       }
       else
       {
@@ -1914,555 +1983,6 @@ CLEANUP:
    END_CLEANUP;
 }
 
-/*
-    Old GetUpdateRgn, for scrolls, see above note.
- */
-INT FASTCALL
-co_IntGetUpdateRgn(PWND Window, PREGION Rgn, BOOL bErase)
-{
-    int RegionType;
-    RECTL Rect;
-    PREGION UpdateRgn;
-
-    ASSERT_REFS_CO(Window);
-
-    if (bErase)
-    {
-       co_IntPaintWindows(Window, RDW_NOCHILDREN, FALSE);
-    }
-
-    Window->state &= ~WNDS_UPDATEDIRTY;
-
-    if (Window->hrgnUpdate == NULL)
-    {
-        REGION_SetRectRgn(Rgn, 0, 0, 0, 0);
-        return NULLREGION;
-    }
-
-    UpdateRgn = REGION_LockRgn(Window->hrgnUpdate);
-    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);
-    REGION_bOffsetRgn(Rgn, -Window->rcClient.left, -Window->rcClient.top);
-    REGION_UnlockRgn(UpdateRgn);
-
-    return RegionType;
-}
-
-static
-INT FASTCALL
-UserScrollDC(
-   HDC hDC,
-   INT dx,
-   INT dy,
-   const RECTL *prcScroll,
-   const RECTL *prcClip,
-   HRGN hrgnUpdate,
-   PREGION RgnUpdate,
-   RECTL *prcUpdate)
-{
-   PDC pDC;
-   RECTL rcScroll, rcClip, rcSrc, rcDst;
-   INT Result;
-
-   if (GdiGetClipBox(hDC, &rcClip) == ERROR)
-   {
-       ERR("GdiGetClipBox failed for HDC %p\n", hDC);
-       return ERROR;
-   }
-
-   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 (RgnUpdate || hrgnUpdate || prcUpdate)
-   {
-      PREGION RgnOwn, RgnTmp;
-
-      pDC = DC_LockDc(hDC);
-      if (!pDC)
-      {
-         return ERROR;
-      }
-
-       if (hrgnUpdate)
-       {
-           NT_ASSERT(RgnUpdate == NULL);
-           RgnUpdate = REGION_LockRgn(hrgnUpdate);
-           if (!RgnUpdate)
-           {
-               DC_UnlockDc(pDC);
-               return ERROR;
-           }
-       }
-
-      /* Begin with the shifted and then clipped scroll rect */
-      rcDst = rcScroll;
-      RECTL_vOffsetRect(&rcDst, dx, dy);
-      RECTL_bIntersectRect(&rcDst, &rcDst, &rcClip);
-      if (RgnUpdate)
-      {
-         RgnOwn = RgnUpdate;
-         REGION_SetRectRgn(RgnOwn, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom);
-      }
-      else
-      {
-         RgnOwn = IntSysCreateRectpRgnIndirect(&rcDst);
-      }
-
-      /* Add the source rect */
-      RgnTmp = IntSysCreateRectpRgnIndirect(&rcSrc);
-      IntGdiCombineRgn(RgnOwn, RgnOwn, RgnTmp, RGN_OR);
-
-      /* Substract the part of the dest that was visible in source */
-      IntGdiCombineRgn(RgnTmp, RgnTmp, pDC->prgnVis, RGN_AND);
-      REGION_bOffsetRgn(RgnTmp, dx, dy);
-      Result = IntGdiCombineRgn(RgnOwn, RgnOwn, RgnTmp, RGN_DIFF);
-
-      /* DO NOT Unlock DC while messing with prgnVis! */
-      DC_UnlockDc(pDC);
-
-      REGION_Delete(RgnTmp);
-
-      if (prcUpdate)
-      {
-         REGION_GetRgnBox(RgnOwn, prcUpdate);
-      }
-
-      if (hrgnUpdate)
-      {
-         REGION_UnlockRgn(RgnUpdate);
-      }
-      else if (!RgnUpdate)
-      {
-         REGION_Delete(RgnOwn);
-      }
-   }
-   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,
-                          NULL,
-                          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;
-   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;
-
-   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);
-   }
-
-   /* 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)
-   {
-       RgnTemp = REGION_LockRgn(hrgnUpdate);
-       if (!RgnTemp)
-       {
-           EngSetLastError(ERROR_INVALID_HANDLE);
-           RETURN(ERROR);
-       }
-       IntGdiCombineRgn(RgnUpdate, RgnTemp, NULL, RGN_COPY);
-       REGION_UnlockRgn(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
-   {
-       /* 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,
-                          NULL,
-                          RgnUpdate,
-                          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.
-    */
-
-   RgnTemp = IntSysCreateRectpRgn(0, 0, 0, 0);
-   if (!RgnTemp)
-   {
-       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-       RETURN(ERROR);
-   }
-
-   if (co_IntGetUpdateRgn(Window, RgnTemp, FALSE) != NULLREGION)
-   {
-      PREGION RgnClip = IntSysCreateRectpRgnIndirect(&rcClip);
-      if (RgnClip)
-      {
-          if (hrgnUpdate)
-          {
-             RgnWinupd = IntSysCreateRectpRgn( 0, 0, 0, 0);
-             IntGdiCombineRgn( RgnWinupd, RgnTemp, 0, RGN_COPY);
-          }
-
-          REGION_bOffsetRgn(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)
-   {
-      PWND Child;
-      RECTL rcChild;
-      POINT ClientOrigin;
-      USER_REFERENCE_ENTRY WndRef;
-      RECTL rcDummy;
-      LPARAM lParam;
-
-      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);
-
-            if (Window->spwndParent == UserGetDesktopWindow()) // Window->spwndParent->fnid == FNID_DESKTOP )
-               lParam = MAKELONG(Child->rcClient.left, Child->rcClient.top);
-            else
-               lParam = MAKELONG(rcChild.left + dx, rcChild.top + dy);
-
-            /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
-            /* windows sometimes a WM_MOVE */                  
-            co_IntSendMessage(UserHMGetHandle(Child), WM_MOVE, 0, lParam);
-            
-            UserDerefObjectCo(Child);
-         }
-      }
-   }
-
-   if (flags & (SW_INVALIDATE | SW_ERASE))
-   {
-      co_UserRedrawWindow( Window,
-                           NULL,
-                           RgnUpdate,
-                           rdw_flags |                                    /*    HACK    */
-                          ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : RDW_NOCHILDREN) );
-   }
-
-   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 (hrgnUpdate && (_ret_ != ERROR))
-   {
-       /* Give everything back to the caller */
-       RgnTemp = REGION_LockRgn(hrgnUpdate);
-       /* The handle should still be valid */
-       ASSERT(RgnTemp);
-       if (RgnWinupd)
-           IntGdiCombineRgn(RgnTemp, RgnUpdate, RgnWinupd, RGN_OR);
-       else
-           IntGdiCombineRgn(RgnTemp, RgnUpdate, NULL, RGN_COPY);
-       REGION_UnlockRgn(RgnTemp);
-   }
-
-   if (RgnWinupd)
-   {
-       REGION_Delete(RgnWinupd);
-   }
-
-   if (RgnUpdate)
-   {
-      REGION_Delete(RgnUpdate);
-   }
-
-   if (Window)
-      UserDerefObjectCo(Window);
-
-   TRACE("Leave NtUserScrollWindowEx, ret=%lu\n",_ret_);
-   UserLeave();
-   END_CLEANUP;
-}
-
-static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
-
 BOOL
 UserDrawCaptionText(
    PWND pWnd,
@@ -2478,14 +1998,14 @@ UserDrawCaptionText(
    NTSTATUS Status;
    BOOLEAN bDeleteFont = FALSE;
    SIZE Size;
+   BOOL Ret = TRUE;
    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, nclm.cbSize, &nclm, 0))
    {
       ERR("UserSystemParametersInfo() failed!\n");
       return FALSE;
@@ -2531,25 +2051,33 @@ UserDrawCaptionText(
    GreGetTextExtentExW(hDc, Text->Buffer, Text->Length/sizeof(WCHAR), r.right - r.left, &fit, 0, &Size, 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)
+   if (Text->Length/sizeof(WCHAR) > Length)
    {
-      RtlCopyMemory(&szText[Length-3], ELLIPSISW, sizeof(ELLIPSISW));
+      Ret = FALSE;
    }
 
-   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 );
-
+   if (Ret)
+   {  // Faster while in setup.
+      GreExtTextOutW( hDc,
+                      lpRc->left,
+                      lpRc->top + (lpRc->bottom - lpRc->top) / 2 - Size.cy / 2, // DT_SINGLELINE && DT_VCENTER
+                      ETO_CLIPPED,
+                     (RECTL *)lpRc,
+                      Text->Buffer,
+                      Length,
+                      NULL,
+                      0 );
+   }
+   else
+   {
+      DrawTextW( hDc,
+                 Text->Buffer,
+                 Text->Length/sizeof(WCHAR),
+                (RECTL *)&r,
+                 DT_END_ELLIPSIS|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_LEFT);
+   }
    IntGdiSetTextColor(hDc, OldTextColor);
 
    if (hOldFont)
@@ -2558,9 +2086,12 @@ UserDrawCaptionText(
    if (bDeleteFont)
       GreDeleteObject(hFont);
 
-   return TRUE;
+   return Ret;
 }
 
+//
+// This draws Buttons, Icons and Text...
+//
 BOOL UserDrawCaption(
    PWND pWnd,
    HDC hDc,
@@ -2577,14 +2108,14 @@ BOOL UserDrawCaption(
 
    RECTL_vMakeWellOrdered(lpRc);
 
+   /* Determine whether the icon needs to be displayed */
    if (!hIcon && pWnd != NULL)
    {
-     HasIcon = (uFlags & DC_ICON) && (pWnd->style & WS_SYSMENU)
-        && !(uFlags & DC_SMALLCAP) && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME)
-        && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
+     HasIcon = (uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP) &&
+               (pWnd->style & WS_SYSMENU) && !(pWnd->ExStyle & WS_EX_TOOLWINDOW);
    }
    else
-     HasIcon = (hIcon != 0);
+     HasIcon = (hIcon != NULL);
 
    // Draw the caption background
    if((uFlags & DC_GRADIENT) && !(uFlags & DC_INBUTTON))
@@ -2668,7 +2199,7 @@ BOOL UserDrawCaption(
          LONG cx = UserGetSystemMetrics(SM_CXSMICON);
          LONG cy = UserGetSystemMetrics(SM_CYSMICON);
          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
+         LONG y = (Rect.top + Rect.bottom - cy)/2; // center
          UserDrawIconEx(hDc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
          UserDereferenceObject(pIcon);
       }
@@ -2683,17 +2214,25 @@ BOOL UserDrawCaption(
 
    if((uFlags & DC_TEXT))
    {
+      BOOL Set = FALSE;
       Rect.left += 2;
 
       if (Str)
-         UserDrawCaptionText(pWnd, hDc, Str, &Rect, uFlags, hFont);
+         Set = 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(pWnd, hDc, &ustr, &Rect, uFlags, hFont);
+         Set = UserDrawCaptionText(pWnd, hDc, &ustr, &Rect, uFlags, hFont);
+      }
+      if (pWnd)
+      {
+         if (Set)
+            pWnd->state2 &= ~WNDS2_CAPTIONTEXTTRUNCATED;
+         else
+            pWnd->state2 |= WNDS2_CAPTIONTEXTTRUNCATED;
       }
    }
 
@@ -2792,8 +2331,26 @@ NtUserDrawCaptionTemp(
    if (str != NULL)
       Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, &SafeStr, uFlags);
    else
+   {
+      if ( RECTL_bIsEmptyRect(&SafeRect) && hFont == 0 && hIcon == 0 )
+      {
+         Ret = TRUE;
+         if (uFlags & DC_DRAWCAPTIONMD)
+         {
+            ERR("NC Caption Mode\n");
+            UserDrawCaptionBar(pWnd, hDC, uFlags);
+            goto Exit;
+         }
+         else if (uFlags & DC_DRAWFRAMEMD)
+         {
+            ERR("NC Paint Mode\n");
+            NC_DoNCPaint(pWnd, hDC, uFlags); // Update Menus too!
+            goto Exit;
+         }
+      }
       Ret = UserDrawCaption(pWnd, hDC, &SafeRect, hFont, hIcon, NULL, uFlags);
-
+   }
+Exit:
    UserLeave();
    return Ret;
 }
@@ -2805,7 +2362,7 @@ NtUserDrawCaption(HWND hWnd,
    LPCRECT lpRc,
    UINT uFlags)
 {
-       return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
+   return NtUserDrawCaptionTemp(hWnd, hDC, lpRc, 0, 0, NULL, uFlags);
 }
 
 BOOL