From d20858433d515a4e54f6ca206f823356dacb2b54 Mon Sep 17 00:00:00 2001
From: Alex Korobka <korobka@ams.sunysb.edu>
Date: Sun, 18 Oct 1998 10:37:46 +0000
Subject: [PATCH] Got rid of flickering scrollbar arrows. MDI scrolling speeded
 up a bit.

---
 controls/scroll.c   | 379 ++++++++++++++++++++++++++++++--------------
 include/scroll.h    |   2 +-
 windows/mdi.c       |  16 +-
 windows/nonclient.c |   8 +-
 4 files changed, 271 insertions(+), 134 deletions(-)

diff --git a/controls/scroll.c b/controls/scroll.c
index 0cade01a66c..fb31e74b755 100644
--- a/controls/scroll.c
+++ b/controls/scroll.c
@@ -69,15 +69,30 @@ enum SCROLL_HITTEST
     SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
 };
 
+ /* What to do after SCROLL_SetScrollInfo() */
+#define SA_SSI_HIDE		0x0001
+#define SA_SSI_SHOW		0x0002
+#define SA_SSI_REFRESH		0x0004
+#define SA_SSI_REPAINT_ARROWS	0x0008
+
  /* Thumb-tracking info */
 static HWND32 SCROLL_TrackingWin = 0;
 static INT32  SCROLL_TrackingBar = 0;
 static INT32  SCROLL_TrackingPos = 0;
 static INT32  SCROLL_TrackingVal = 0;
+ /* Hit test code of the last button-down event */
+static enum SCROLL_HITTEST SCROLL_trackHitTest;
+static BOOL32 SCROLL_trackVertical;
 
-/* Is the moving thumb being displayed? */
+ /* Is the moving thumb being displayed? */
 static BOOL32 SCROLL_MovingThumb = FALSE;
 
+ /* Local functions */
+static BOOL32 SCROLL_ShowScrollBar( HWND32 hwnd, INT32 nBar, 
+				    BOOL32 fShowH, BOOL32 fShowV );
+static INT32 SCROLL_SetScrollInfo( HWND32 hwnd, INT32 nBar, 
+				   const SCROLLINFO *info, INT32 *action );
+
 /***********************************************************************
  *           SCROLL_LoadBitmaps
  */
@@ -273,6 +288,46 @@ static UINT32 SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT32 *rect,
     return infoPtr->MinVal + ((pos + pixels / 2) / pixels);
 }
 
+/***********************************************************************
+ *           SCROLL_PtInRectEx
+ */
+static BOOL32 SCROLL_PtInRectEx( LPRECT32 lpRect, POINT32 pt, BOOL32 vertical )
+{
+    RECT32 rect = *lpRect;
+
+    if (vertical)
+    {
+	rect.left -= lpRect->right - lpRect->left;
+	rect.right += lpRect->right - lpRect->left;
+    }
+    else
+    {
+	rect.top -= lpRect->bottom - lpRect->top;
+	rect.bottom += lpRect->bottom - lpRect->top;
+    }
+    return PtInRect32( &rect, pt );
+}
+
+/***********************************************************************
+ *           SCROLL_ClipPos
+ */
+static POINT32 SCROLL_ClipPos( LPRECT32 lpRect, POINT32 pt )
+{
+    if( pt.x < lpRect->left )
+	pt.x = lpRect->left;
+    else
+    if( pt.x > lpRect->right )
+	pt.x = lpRect->right;
+
+    if( pt.y < lpRect->top )
+	pt.y = lpRect->top;
+    else
+    if( pt.y > lpRect->bottom )
+	pt.y = lpRect->bottom;
+
+    return pt;
+}
+
 
 /***********************************************************************
  *           SCROLL_HitTest
@@ -280,14 +335,16 @@ static UINT32 SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT32 *rect,
  * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
  */
 static enum SCROLL_HITTEST SCROLL_HitTest( HWND32 hwnd, INT32 nBar,
-                                           POINT32 pt )
+                                           POINT32 pt, BOOL32 bDragging )
 {
     INT32 arrowSize, thumbSize, thumbPos;
     RECT32 rect;
 
     BOOL32 vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
                                            &arrowSize, &thumbSize, &thumbPos );
-    if (!PtInRect32( &rect, pt )) return SCROLL_NOWHERE;
+
+    if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
+	 (!PtInRect32( &rect, pt )) ) return SCROLL_NOWHERE;
 
     if (vertical)
     {
@@ -297,7 +354,6 @@ static enum SCROLL_HITTEST SCROLL_HitTest( HWND32 hwnd, INT32 nBar,
         pt.y -= rect.top;
         if (pt.y < thumbPos) return SCROLL_TOP_RECT;
         if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
-        return SCROLL_THUMB;
     }
     else  /* horizontal */
     {
@@ -307,8 +363,8 @@ static enum SCROLL_HITTEST SCROLL_HitTest( HWND32 hwnd, INT32 nBar,
         pt.x -= rect.left;
         if (pt.x < thumbPos) return SCROLL_TOP_RECT;
         if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
-        return SCROLL_THUMB;
     }
+    return SCROLL_THUMB;
 }
 
 
@@ -325,6 +381,7 @@ static void SCROLL_DrawArrows( HDC32 hdc, SCROLLBAR_INFO *infoPtr,
     HBITMAP32 hbmpPrev = SelectObject32( hdcMem, vertical ?
                                     TOP_ARROW(infoPtr->flags, top_pressed)
                                     : LEFT_ARROW(infoPtr->flags, top_pressed));
+
     SetStretchBltMode32( hdc, STRETCH_DELETESCANS );
     StretchBlt32( hdc, rect->left, rect->top,
                   vertical ? rect->right-rect->left : arrowSize,
@@ -496,7 +553,8 @@ static void SCROLL_DrawInterior( HWND32 hwnd, HDC32 hdc, INT32 nBar,
  *
  * Redraw the whole scrollbar.
  */
-void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar, BOOL32 arrows )
+void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar, 
+			   BOOL32 arrows, BOOL32 interior )
 {
     INT32 arrowSize, thumbSize, thumbPos;
     RECT32 rect;
@@ -513,10 +571,18 @@ void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar, BOOL32 arrows )
 
       /* Draw the arrows */
 
-    if (arrows && arrowSize) SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize,
-                                                vertical, FALSE, FALSE );
-    
-    SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
+    if (arrows && arrowSize)
+    {
+	if( vertical == SCROLL_trackVertical && GetCapture32() == hwnd )
+	    SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
+			       (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
+			       (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
+	else
+	    SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical, 
+							       FALSE, FALSE );
+    }
+    if( interior )
+	SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
                          thumbPos, infoPtr->flags, vertical, FALSE, FALSE );
 }
 
@@ -527,12 +593,14 @@ void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar, BOOL32 arrows )
  * Repaint the scroll bar interior after a SetScrollRange() or
  * SetScrollPos() call.
  */
-static void SCROLL_RefreshScrollBar( HWND32 hwnd, INT32 nBar, BOOL32 arrows )
+static void SCROLL_RefreshScrollBar( HWND32 hwnd, INT32 nBar, 
+				     BOOL32 arrows, BOOL32 interior )
 {
     HDC32 hdc = GetDCEx32( hwnd, 0,
                            DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
     if (!hdc) return;
-    SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows );
+
+    SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
     ReleaseDC32( hwnd, hdc );
 }
 
@@ -575,8 +643,6 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
 {
       /* Previous mouse position for timer events */
     static POINT32 prevPt;
-      /* Hit test code of the last button-down event */
-    static enum SCROLL_HITTEST trackHitTest;
       /* Thumb position when tracking started. */
     static UINT32 trackThumbPos;
       /* Position in the scroll-bar of the last button-down event. */
@@ -593,7 +659,8 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
 
     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
     if (!infoPtr) return;
-    if ((trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) return;
+    if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) 
+		  return;
 
     hdc = GetDCEx32( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
@@ -604,7 +671,8 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
     switch(msg)
     {
       case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
-          trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt );
+	  SCROLL_trackVertical = vertical;
+          SCROLL_trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
           lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
           lastMousePos  = lastClickPos;
           trackThumbPos = thumbPos;
@@ -614,7 +682,7 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
           break;
 
       case WM_MOUSEMOVE:
-          hittest = SCROLL_HitTest( hwnd, nBar, pt );
+          hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
           prevPt = pt;
           break;
 
@@ -625,7 +693,7 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
 
       case WM_SYSTIMER:
           pt = prevPt;
-          hittest = SCROLL_HitTest( hwnd, nBar, pt );
+          hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
           break;
 
       default:
@@ -635,15 +703,15 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
     TRACE(scroll, "Event: hwnd=%04x bar=%d msg=%x pt=%d,%d hit=%d\n",
 		 hwnd, nBar, msg, pt.x, pt.y, hittest );
 
-    switch(trackHitTest)
+    switch(SCROLL_trackHitTest)
     {
     case SCROLL_NOWHERE:  /* No tracking in progress */
         break;
 
     case SCROLL_TOP_ARROW:
         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
-                           (hittest == trackHitTest), FALSE );
-        if (hittest == trackHitTest)
+                           (hittest == SCROLL_trackHitTest), FALSE );
+        if (hittest == SCROLL_trackHitTest)
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
@@ -660,8 +728,8 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
     case SCROLL_TOP_RECT:
         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
                              thumbPos, infoPtr->flags, vertical,
-                             (hittest == trackHitTest), FALSE );
-        if (hittest == trackHitTest)
+                             (hittest == SCROLL_trackHitTest), FALSE );
+        if (hittest == SCROLL_trackHitTest)
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
@@ -695,8 +763,12 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
         {
             UINT32 pos;
 
-            if (!PtInRect32( &rect, pt )) pos = lastClickPos;
-            else pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
+            if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos;
+            else
+	    {
+		pt = SCROLL_ClipPos( &rect, pt );
+		pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
+	    }
             if (pos != lastMousePos)
             {
                 SCROLL_DrawMovingThumb( hdc, &rect, vertical,
@@ -718,8 +790,8 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
     case SCROLL_BOTTOM_RECT:
         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
                              thumbPos, infoPtr->flags, vertical,
-                             FALSE, (hittest == trackHitTest) );
-        if (hittest == trackHitTest)
+                             FALSE, (hittest == SCROLL_trackHitTest) );
+        if (hittest == SCROLL_trackHitTest)
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
@@ -735,8 +807,8 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
         
     case SCROLL_BOTTOM_ARROW:
         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
-                           FALSE, (hittest == trackHitTest) );
-        if (hittest == trackHitTest)
+                           FALSE, (hittest == SCROLL_trackHitTest) );
+        if (hittest == SCROLL_trackHitTest)
         {
             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
             {
@@ -753,7 +825,10 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
 
     if (msg == WM_LBUTTONUP)
     {
-        if (trackHitTest == SCROLL_THUMB)
+	hittest = SCROLL_trackHitTest;
+	SCROLL_trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
+
+        if (hittest == SCROLL_THUMB)
         {
             UINT32 val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
                                  trackThumbPos + lastMousePos - lastClickPos );
@@ -763,7 +838,6 @@ void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar, UINT32 msg, POINT32 pt)
         else
             SendMessage32A( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
                             SB_ENDSCROLL, hwndCtl );
-        trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
     }
 
     ReleaseDC32( hwnd, hdc );
@@ -839,7 +913,7 @@ LRESULT WINAPI ScrollBarWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
         {
             PAINTSTRUCT32 ps;
             HDC32 hdc = BeginPaint32( hwnd, &ps );
-            SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE );
+            SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE, TRUE );
             EndPaint32( hwnd, &ps );
         }
         break;
@@ -935,11 +1009,38 @@ INT32 nBar /* [I] One of SB_HORZ, SB_VERT, or SB_CTL */,
 const SCROLLINFO *info /* [I] Specifies what to change and new values */,
 BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
 {
+    INT32 action;
+    INT32 retVal = SCROLL_SetScrollInfo( hwnd, nBar, info, &action );
+
+    if( action & SA_SSI_HIDE )
+	SCROLL_ShowScrollBar( hwnd, nBar, FALSE, FALSE );
+    else
+    {
+	if( action & SA_SSI_SHOW )
+	    if( SCROLL_ShowScrollBar( hwnd, nBar, TRUE, TRUE ) )
+		return retVal; /* SetWindowPos() already did the painting */
+
+	if( bRedraw && (action & SA_SSI_REFRESH))
+	    SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
+	else if( action & SA_SSI_REPAINT_ARROWS )
+	    SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, FALSE );
+    }
+    return retVal;
+}
+
+INT32 SCROLL_SetScrollInfo( HWND32 hwnd, INT32 nBar, 
+			    const SCROLLINFO *info, INT32 *action  )
+{
+    /* Update the scrollbar state and set action flags according to 
+     * what has to be done graphics wise. */
+
     SCROLLBAR_INFO *infoPtr;
     UINT32 new_flags;
-    BOOL32 repaint_arrows = FALSE;
+
     dbg_decl_str(scroll, 256);
 
+   *action = 0;
+
     if (!(infoPtr = SCROLL_GetScrollInfo(hwnd, nBar))) return 0;
     if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
     if ((info->cbSize != sizeof(*info)) &&
@@ -950,7 +1051,11 @@ BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
     if (info->fMask & SIF_PAGE)
     {
         dsprintf(scroll, " page=%d", info->nPage );
-        infoPtr->Page = info->nPage;
+	if( infoPtr->Page != info->nPage )
+	{
+            infoPtr->Page = info->nPage;
+	   *action |= SA_SSI_REFRESH;
+	}
     }
 
     /* Set the scroll pos */
@@ -958,7 +1063,11 @@ BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
     if (info->fMask & SIF_POS)
     {
         dsprintf(scroll, " pos=%d", info->nPos );
-        infoPtr->CurVal = info->nPos;
+	if( infoPtr->CurVal != info->nPos )
+	{
+	    infoPtr->CurVal = info->nPos;
+	   *action |= SA_SSI_REFRESH;
+	}
     }
 
     /* Set the scroll range */
@@ -976,8 +1085,13 @@ BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
         }
         else
         {
-            infoPtr->MinVal = info->nMin;
-            infoPtr->MaxVal = info->nMax;
+	    if( infoPtr->MinVal != info->nMin ||
+		infoPtr->MaxVal != info->nMax )
+	    {
+	       *action |= SA_SSI_REFRESH;
+                infoPtr->MinVal = info->nMin;
+                infoPtr->MaxVal = info->nMax;
+	    }
         }
     }
 
@@ -1010,29 +1124,31 @@ BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
         {
             /* Hide or disable scroll-bar */
             if (info->fMask & SIF_DISABLENOSCROLL)
+	    {
                 new_flags = ESB_DISABLE_BOTH;
+	       *action |= SA_SSI_REFRESH;
+	    }
             else if (nBar != SB_CTL)
-            {
-                ShowScrollBar32( hwnd, nBar, FALSE );
-                bRedraw = FALSE;  /* No need to repaint anything */
+	    {
+		*action = SA_SSI_HIDE;
+		goto done;
             }
         }
         else  /* Show and enable scroll-bar */
         {
-            new_flags = 0;
-            if (nBar != SB_CTL) ShowScrollBar32( hwnd, nBar, TRUE );
+	    new_flags = 0;
+            if (nBar != SB_CTL)
+		*action |= SA_SSI_SHOW;
         }
 
-        if (infoPtr->flags != new_flags)
+        if (infoPtr->flags != new_flags) /* check arrow flags */
         {
             infoPtr->flags = new_flags;
-            repaint_arrows = TRUE;
+           *action |= SA_SSI_REPAINT_ARROWS;
         }
     }
 
-    if (bRedraw || repaint_arrows)
-        SCROLL_RefreshScrollBar( hwnd, nBar, repaint_arrows );
-
+done:
     /* Return current position */
 
     return infoPtr->CurVal;
@@ -1190,34 +1306,34 @@ BOOL32 bRedraw /* [I] Should scrollbar be redrawn afterwards ? */)
 /*************************************************************************
  *	     SCROLL_SetNCSbState
  *
- * This is for CalcChildScroll in windows/mdi.c
+ * Updates both scrollbars at the same time. Used by MDI CalcChildScroll().
  */
-DWORD SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos,
+INT32 SCROLL_SetNCSbState(WND* wndPtr, int vMin, int vMax, int vPos,
 				       int hMin, int hMax, int hPos)
 {
-  SCROLLBAR_INFO  *infoPtr = SCROLL_GetPtrScrollInfo(wndPtr, SB_VERT);
+    INT32 vA, hA;
+    SCROLLINFO vInfo, hInfo;
  
-  wndPtr->dwStyle |= (WS_VSCROLL | WS_HSCROLL);
-
-  if( vMin >= vMax ) 
-    { vMin = vMax;
-      wndPtr->dwStyle &= ~WS_VSCROLL; }
-  if( vPos > vMax ) vPos = vMax; else if( vPos < vMin ) vPos = vMin;
-  infoPtr->MinVal = vMin;
-  infoPtr->MaxVal = vMax;
-  infoPtr->CurVal = vPos;
-
-  infoPtr = SCROLL_GetPtrScrollInfo(wndPtr, SB_HORZ);
-
-  if( hMin >= hMax )
-    { hMin = hMax;
-      wndPtr->dwStyle &= ~WS_HSCROLL; }
-  if( hPos > hMax ) hPos = hMax; else if( hPos < hMin ) hPos = hMin;
-  infoPtr->MinVal = hMin;
-  infoPtr->MaxVal = hMax;
-  infoPtr->CurVal = hPos;
-
-  return wndPtr->dwStyle & (WS_VSCROLL | WS_HSCROLL);
+    vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
+    vInfo.nMin   = vMin;	 hInfo.nMin   = hMin;
+    vInfo.nMax   = vMax;	 hInfo.nMax   = hMax;
+    vInfo.nPos   = vPos;	 hInfo.nPos   = hPos;
+    vInfo.fMask  = hInfo.fMask = SIF_RANGE | SIF_POS;
+
+    SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_VERT, &vInfo, &vA );
+    SCROLL_SetScrollInfo( wndPtr->hwndSelf, SB_HORZ, &hInfo, &hA );
+
+    if( !SCROLL_ShowScrollBar( wndPtr->hwndSelf, SB_BOTH,
+			      (hA & SA_SSI_SHOW),(vA & SA_SSI_SHOW) ) )
+    {
+	/* SetWindowPos() wasn't called, just redraw the scrollbars if needed */
+	if( vA & SA_SSI_REFRESH )
+	    SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_VERT, FALSE, TRUE );
+
+	if( hA & SA_SSI_REFRESH )
+	    SCROLL_RefreshScrollBar( wndPtr->hwndSelf, SB_HORZ, FALSE, TRUE );
+    }
+    return 0;
 }
 
 
@@ -1261,82 +1377,91 @@ LPINT32 lpMax /* [O] Where to store maximum value */)
 
 
 /*************************************************************************
- *           ShowScrollBar16   (USER.267)
- */
-void WINAPI ShowScrollBar16( HWND16 hwnd, INT16 nBar, BOOL16 fShow )
-{
-    ShowScrollBar32( hwnd, nBar, fShow );
-}
-
-
-/*************************************************************************
- *           ShowScrollBar32   (USER32.532)
+ *           SCROLL_ShowScrollBar()
  *
- * RETURNS STD
+ * Back-end for ShowScrollBar(). Returns FALSE if no action was taken.
+ * NOTE: fShowV/fShowH must be zero when nBar is SB_HORZ/SB_VERT.
  */
-BOOL32 WINAPI ShowScrollBar32( 
-HWND32 hwnd, /* [I] Handle of window whose scrollbar(s) will be affected   */
-INT32 nBar, /* [I] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
-BOOL32 fShow /* [I] TRUE = show, FALSE = hide  */)
+BOOL32 SCROLL_ShowScrollBar( HWND32 hwnd, INT32 nBar, 
+			     BOOL32 fShowH, BOOL32 fShowV )
 {
     WND *wndPtr = WIN_FindWndPtr( hwnd );
 
     if (!wndPtr) return FALSE;
-    TRACE(scroll, "hwnd=%04x bar=%d on=%d\n",
-                    hwnd, nBar, fShow );
+    TRACE(scroll, "hwnd=%04x bar=%d horz=%d, vert=%d\n",
+                    hwnd, nBar, fShowH, fShowV );
 
     switch(nBar)
     {
     case SB_CTL:
-        ShowWindow32( hwnd, fShow ? SW_SHOW : SW_HIDE );
+        ShowWindow32( hwnd, fShowH ? SW_SHOW : SW_HIDE );
         return TRUE;
 
+    case SB_BOTH:
     case SB_HORZ:
-        if (fShow)
+        if (fShowH)
         {
-            if (wndPtr->dwStyle & WS_HSCROLL) return TRUE;
+            fShowH = !(wndPtr->dwStyle & WS_HSCROLL);
             wndPtr->dwStyle |= WS_HSCROLL;
         }
         else  /* hide it */
         {
-            if (!(wndPtr->dwStyle & WS_HSCROLL)) return TRUE;
+            fShowH = (wndPtr->dwStyle & WS_HSCROLL);
             wndPtr->dwStyle &= ~WS_HSCROLL;
         }
-        break;
+        if( nBar == SB_HORZ ) break; 
+	/* fall through */
 
     case SB_VERT:
-        if (fShow)
+        if (fShowV)
         {
-            if (wndPtr->dwStyle & WS_VSCROLL) return TRUE;
+            fShowV = !(wndPtr->dwStyle & WS_VSCROLL);
             wndPtr->dwStyle |= WS_VSCROLL;
         }
-        else  /* hide it */
+	else  /* hide it */
         {
-            if (!(wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
+            fShowV = (wndPtr->dwStyle & WS_VSCROLL);
             wndPtr->dwStyle &= ~WS_VSCROLL;
         }
         break;
 
-    case SB_BOTH:
-        if (fShow)
-        {
-            if ((wndPtr->dwStyle & WS_HSCROLL)
-                && (wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
-            wndPtr->dwStyle |= WS_HSCROLL | WS_VSCROLL;
-        }
-        else  /* hide it */
-        {
-            if (!(wndPtr->dwStyle & WS_HSCROLL)
-                && !(wndPtr->dwStyle & WS_VSCROLL)) return TRUE;
-            wndPtr->dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
-        }
-        break;
-
     default:
-        return TRUE;  /* Nothing to do! */
+        return FALSE;  /* Nothing to do! */
     }
-    SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
+
+    if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */
+    {
+	SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
                     | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
+        return TRUE;
+    }
+
+    return FALSE; /* no frame changes */
+}
+
+
+/*************************************************************************
+ *           ShowScrollBar16   (USER.267)
+ */
+void WINAPI ShowScrollBar16( HWND16 hwnd, INT16 nBar, BOOL16 fShow )
+{
+    SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow,
+				      (nBar == SB_HORZ) ? 0 : fShow );
+}
+
+
+/*************************************************************************
+ *           ShowScrollBar32   (USER32.532)
+ *
+ * RETURNS STD
+ */
+BOOL32 WINAPI ShowScrollBar32(
+HWND32 hwnd, /* [I] Handle of window whose scrollbar(s) will be affected   */
+INT32 nBar, /* [I] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
+BOOL32 fShow /* [I] TRUE = show, FALSE = hide  */)
+{
+    SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow,
+                                      (nBar == SB_HORZ) ? 0 : fShow );
     return TRUE;
 }
 
@@ -1355,16 +1480,30 @@ BOOL16 WINAPI EnableScrollBar16( HWND16 hwnd, INT16 nBar, UINT16 flags )
  */
 BOOL32 WINAPI EnableScrollBar32( HWND32 hwnd, INT32 nBar, UINT32 flags )
 {
+    BOOL32 bFineWithMe;
     SCROLLBAR_INFO *infoPtr;
 
-    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
-    TRACE(scroll, "%04x %d %d\n",
-                    hwnd, nBar, flags );
+    TRACE(scroll, "%04x %d %d\n", hwnd, nBar, flags );
+
     flags &= ESB_DISABLE_BOTH;
-    if (infoPtr->flags == flags) return FALSE;
+
+    if (nBar == SB_BOTH)
+    {
+	if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, SB_VERT ))) return FALSE;
+	if (!(bFineWithMe = (infoPtr->flags == flags)) )
+	{
+	    infoPtr->flags = flags;
+	    SCROLL_RefreshScrollBar( hwnd, SB_VERT, TRUE, TRUE );
+	}
+	nBar = SB_HORZ;
+    }
+    else
+	bFineWithMe = TRUE;
+   
+    if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
+    if (bFineWithMe && infoPtr->flags == flags) return FALSE;
     infoPtr->flags = flags;
 
-    /* Redraw the whole scroll bar */
-    SCROLL_RefreshScrollBar( hwnd, nBar, TRUE );
+    SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
     return TRUE;
 }
diff --git a/include/scroll.h b/include/scroll.h
index 0a70a6c5621..2b8df751601 100644
--- a/include/scroll.h
+++ b/include/scroll.h
@@ -22,7 +22,7 @@ typedef struct
 extern LRESULT WINAPI ScrollBarWndProc( HWND32 hwnd, UINT32 uMsg,
                                         WPARAM32 wParam, LPARAM lParam );
 extern void SCROLL_DrawScrollBar( HWND32 hwnd, HDC32 hdc, INT32 nBar,
-                                  BOOL32 arrows );
+                                  BOOL32 arrows, BOOL32 interior );
 extern void SCROLL_HandleScrollEvent( HWND32 hwnd, INT32 nBar,
                                       UINT32 msg, POINT32 pt );
 
diff --git a/windows/mdi.c b/windows/mdi.c
index f38c164c095..83a88498ada 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -32,7 +32,7 @@
 static HBITMAP16 hBmpClose   = 0;
 static HBITMAP16 hBmpRestore = 0;
 
-DWORD SCROLL_SetNCSbState(WND*,int,int,int,int,int,int);
+INT32 SCROLL_SetNCSbState(WND*,int,int,int,int,int,int);
 
 /* ----------------- declarations ----------------- */
 static void MDI_UpdateFrameText(WND *, HWND32, BOOL32, LPCSTR);
@@ -259,7 +259,7 @@ static LRESULT MDIRefreshMenu( HWND32 hwnd, HMENU32 hmenuFrame,
     TRACE(mdi, "%04x %04x %04x\n",
                 hwnd, hmenuFrame, hmenuWindow);
 
-    FIXME(mdi,"partial function stub\n");
+    FIXME(mdi,"partially function stub");
 
     return oldFrameMenu;
 }
@@ -1598,6 +1598,7 @@ BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
  */
 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
 {
+    SCROLLINFO info;
     RECT32 childRect, clientRect;
     INT32  vmin, vmax, hmin, hmax, vpos, hpos;
     WND *pWnd, *Wnd;
@@ -1617,9 +1618,6 @@ void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
     } 
     UnionRect32( &childRect, &clientRect, &childRect );
 
-    /* jump through the hoops to prevent excessive flashing 
-     */
-
     hmin = childRect.left; hmax = childRect.right - clientRect.right;
     hpos = clientRect.left - childRect.left;
     vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
@@ -1630,14 +1628,14 @@ void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
 	case SB_HORZ:
 			vpos = hpos; vmin = hmin; vmax = hmax;
 	case SB_VERT:
-			SetScrollPos32(hwnd, scroll, vpos, FALSE);
-			SetScrollRange32(hwnd, scroll, vmin, vmax, TRUE);
+			info.cbSize = sizeof(info);
+			info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
+			info.fMask = SIF_POS | SIF_RANGE;
+			SetScrollInfo32(hwnd, scroll, &info, TRUE);
 			break;
 	case SB_BOTH:
 			SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
 						  hmin, hmax, hpos);
-			SetWindowPos32(hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
-                                       | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
     }    
 }
 
diff --git a/windows/nonclient.c b/windows/nonclient.c
index 572a9528682..ff43659b08d 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -1559,9 +1559,9 @@ void NC_DoNCPaint( WND* wndPtr, HRGN32 clip, BOOL32 suppress_menupaint )
       /* Draw the scroll-bars */
 
     if (wndPtr->dwStyle & WS_VSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE );
+        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
     if (wndPtr->dwStyle & WS_HSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE );
+        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
 
       /* Draw the "size-box" */
 
@@ -1689,9 +1689,9 @@ void  NC_DoNCPaint95(
     /* Draw the scroll-bars */
 
     if (wndPtr->dwStyle & WS_VSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE );
+        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
     if (wndPtr->dwStyle & WS_HSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE );
+        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
 
     /* Draw the "size-box" */
     if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL))
-- 
GitLab