Scroll cleanup part 4

Andrew M. Johnston johnstonam at logica.com
Tue Oct 8 06:37:46 CDT 2002


Changelog:
            controls.h  - improve the scroll bar nonclient separation
            nonclient.c - remove NC_TrackScrollBar and use scrollbar WINAPI routine
            scrollbar.c - unified drawing code
                        - simpler event processing logic
                        -  minimized drawing
                        - better conformance to windows on LINEUP and LINEDOWN events

The patch was developed without CVS access use patch -p1 from within
the top level wine directory to apply

Requires previous scroll patches

license: X11

Andrew

--- wine-20020804/dlls/user/controls.h	Sun Mar 10 07:44:30 2002
+++ wine/dlls/user/controls.h	Thu Sep 19 18:22:23 2002
@@ -63,10 +63,8 @@
 extern UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget );
 
 /* scrollbar */
-extern void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, BOOL arrows, BOOL interior );
-extern void SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt );
-extern INT SCROLL_SetNCSbState( HWND hwnd, int vMin, int vMax, int vPos,
-                                int hMin, int hMax, int hPos );
+extern void SCROLL_PaintScrollBar(HWND hwnd, INT nBar);
+extern void SCROLL_HandleScrollEvent(HWND hwnd, INT nBar, UINT msg, LPARAM lParam);
 
 /* combo box */

--- wine-20020804/windows/nonclient.c	Sat Jun  1 07:06:54 2002
+++ wine/windows/nonclient.c	Fri Sep 20 12:22:16 2002
@@ -1459,9 +1459,9 @@
       /* Draw the scroll-bars */
 
     if (dwStyle & WS_VSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
+        SCROLL_PaintScrollBar(hwnd, SB_VERT);
     if (dwStyle & WS_HSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
+        SCROLL_PaintScrollBar(hwnd, SB_HORZ);
 
       /* Draw the "size-box" */
 
@@ -1613,12 +1613,9 @@
 	DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
 
     /* Draw the scroll-bars */
-
-    if (dwStyle & WS_VSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
-    if (dwStyle & WS_HSCROLL)
-        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
-
+    if (dwStyle & WS_VSCROLL) SCROLL_PaintScrollBar(hwnd, SB_VERT);
+    if (dwStyle & WS_HSCROLL) SCROLL_PaintScrollBar(hwnd, SB_HORZ);
+                                           
     /* Draw the "size-box" */
     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
     {
@@ -1649,7 +1646,7 @@
 	    WINPOS_RedrawIconTitle( hwnd );
 	else if (TWEAK_WineLook == WIN31_LOOK)
 	    NC_DoNCPaint( hwnd, clip, FALSE );
-	else
+ 	else
 	    NC_DoNCPaint95( hwnd, clip, FALSE );
     }
     return 0;
@@ -1962,29 +1959,6 @@
 
 
 /***********************************************************************
- *           NC_TrackScrollBar
- *
- * Track a mouse button press on the horizontal or vertical scroll-bar.
- */
-static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
-{
-    INT scrollbar;
-
-    if ((wParam & 0xfff0) == SC_HSCROLL)
-    {
-        if ((wParam & 0x0f) != HTHSCROLL) return;
-	scrollbar = SB_HORZ;
-    }
-    else  /* SC_VSCROLL */
-    {
-        if ((wParam & 0x0f) != HTVSCROLL) return;
-	scrollbar = SB_VERT;
-    }
-    SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
-}
-
-
-/***********************************************************************
  *           NC_HandleNCLButtonDown
  *
  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
@@ -2146,14 +2120,14 @@
 	return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
 
     case SC_VSCROLL:
+    	if ((wParam & 0x0f) == HTVSCROLL)
+    		SCROLL_HandleScrollEvent(hwnd, SB_VERT, WM_LBUTTONDOWN, lParam);
+    	break;
+ 
     case SC_HSCROLL:
-        {
-            POINT pt;
-            pt.x = SLOWORD(lParam);
-            pt.y = SHIWORD(lParam);
-            NC_TrackScrollBar( hwnd, wParam, pt );
-        }
-	break;
+        if ((wParam & 0x0f) == HTHSCROLL)
+        	SCROLL_HandleScrollEvent(hwnd, SB_HORZ, WM_LBUTTONDOWN, lParam);
+       	break;
 
     case SC_MOUSEMENU:
         {


--- wine-20020904/controls/scroll.c	Tue Oct  8 19:22:47 2002
+++ wine/controls/scroll.c	Tue Oct  8 19:13:57 2002
@@ -57,15 +57,72 @@
 	HBITMAP disabled;      /* arrow for disabled state */
 } SCROLL_ARROWS, *LPSCROLL_ARROWS;
 
+
+/*********************************************************************
+ * scrollbar extermity parameters (one arrow)
+ *
+ *  Contains the arrow and its pressed state and the associated
+ *  limiting cordinate
+ */
+typedef struct
+{
+	INT *coord;            /* coordinate of the limiting extremity */
+	INT flags;             /* pressed state of the extermity */
+	LPSCROLL_ARROWS	arrow; /* arrows collection */
+} SCROLL_EXTEMITY, *LPSCROLL_EXTREMITY;
+
+
+/*********************************************************************
+ * scrollbar (display information for drawing a single scroll bar)
+ * 
+ *  Lives as long as a scroll draw operation
+ */
+typedef struct
+{
+	RECT rect;             /* the bounding rectangle of the control */
+	RECT extended;         /* the bounding rectangle thumb movement */
+	UINT hit;              /* windows message for bar position */
+	INT arrow;             /* the arrow size */
+	INT thumb;             /* the thumb size */
+	INT pos;               /* the thumb postion */
+	INT pixels;            /* length of the long dimension of the bar */
+	INT direction;         /* windows message for bar direction */
+	BOOL drawable;         /* scroll bar is a non empty rect */
+	BOOL inside;           /* event was inside scroll bar */
+	BOOL lastInside;       /* last event was inside scroll bar */
+	POINT offset;          /* offset of the scrollbar in the client window */
+	SCROLL_EXTEMITY start; /* the start of the long extent of the bar */
+	SCROLL_EXTEMITY end;   /* the end of the long extent of the bar */
+	LPSCROLLBAR_INFO info; /* the info for the scroll bar */
+} SCROLL_BAR, *LPSCROLL_BAR;
+
 #define SCROLL_MIN_RECT       4	/* Minimum size of rectangle between arrows */
 #define SCROLL_MIN_THUMB      6	/* Minimum size of the thumb in pixels */
 #define SCROLL_FIRST_DELAY  200	/* Delay (in ms) before first repetition */
 #define SCROLL_REPEAT_DELAY  50	/* Delay (in ms) between scroll repetitions */
 #define SCROLL_TIMER          0	/* Scroll timer id */
+#define SCROLL_NO_POS (1 << 30)	/* Dummy value for unkown thumb position */
 
-#define GET_ARROW(arrow, inactive, press) \
-   ((inactive) ? (arrow)->disabled : ((press) ? (arrow)->pressed: (arrow)->normal))
-
+/* Determine if the whole bar is disabled */
+#define SCROLL_DISABLED(info) \
+	((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
+
+/* Determine if the bar has been hit inside and in the given position */
+#define SCROLL_HIT(bar, position) \
+	((bar->inside) && (bar->hit == position))
+
+/* Determine the correct pattern for the fill based on pressed state */
+#define SCROLL_PATTERN(bar, position) \
+	((SCROLL_HIT(bar, position)) ? 0x0f0000 : PATCOPY)
+
+/* Determine if the scroll bar has changed */
+#define SCROLL_CHANGED(bar) ((bar)->inside != (bar)->lastInside)
+
+/* Determine if the arrow should be drawn and call to draw it */
+#define SCROLL_DRAW_ARROW(hdc, bar, arr, current, other) \
+	if (bar->arrow && SCROLL_CHANGED(bar) && \
+		((bar->inside && bar->hit != other) || (bar->hit == current))) \
+			SCROLL_DrawArrow(hdc, &(bar->rect), arr, SCROLL_HIT(bar, current));
 
 /* Determine if the info is valid */
 #define SCROLL_INFO_INVALID(info) \
@@ -73,9 +130,6 @@
 	((info->cbSize != sizeof(*info)) && \
 	(info->cbSize != sizeof(*info) - sizeof(info->nTrackPos))))
 
-  /* Overlap between arrows and thumb */
-#define SCROLL_ARROW_THUMB_OVERLAP ((TWEAK_WineLook == WIN31_LOOK) ? 1 : 0)
-
 /*********************************************************************
  * scrollbar arrow collections (used by Win 31 only)
  */
@@ -84,42 +138,8 @@
 static SCROLL_ARROWS hLeft;  /* Arrow images for left arrow */
 static SCROLL_ARROWS hRight; /* Arrow images for right arrow */
 
+static SCROLL_BAR trackBar; /* The bar structure used during tracking */
 
-  /* Scroll-bar hit testing */
-enum SCROLL_HITTEST
-{
-    SCROLL_NOWHERE,      /* Outside the scroll bar */
-    SCROLL_TOP_ARROW,    /* Top or left arrow */
-    SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
-    SCROLL_THUMB,        /* Thumb rectangle */
-    SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
-    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 HWND SCROLL_TrackingWin = 0;
-static INT  SCROLL_TrackingBar = 0;
-static INT  SCROLL_TrackingPos = 0;
-static INT  SCROLL_TrackingVal = 0;
- /* Hit test code of the last button-down event */
-static enum SCROLL_HITTEST SCROLL_trackHitTest;
-static BOOL SCROLL_trackVertical;
-
- /* Is the moving thumb being displayed? */
-static BOOL SCROLL_MovingThumb = FALSE;
-
- /* Local functions */
-static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
-				    RECT *rect, INT arrowSize,
-				    INT thumbSize, INT thumbPos,
-				    UINT flags, BOOL vertical,
-				    BOOL top_selected, BOOL bottom_selected );
 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
 
 
@@ -221,686 +241,181 @@
 	return info;
 }
 
-/***********************************************************************
- *           SCROLL_GetScrollBarRect
- *
- * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
- * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
- * 'arrowSize' returns the width or height of an arrow (depending on
- * the orientation of the scrollbar), 'thumbSize' returns the size of
- * the thumb, and 'thumbPos' returns the position of the thumb
- * relative to the left or to the top.
- * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
- */
-static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect,
-                                       INT *arrowSize, INT *thumbSize,
-                                       INT *thumbPos )
-{
-    INT pixels;
-    BOOL vertical;
-    WND *wndPtr = WIN_FindWndPtr( hwnd );
-
-    switch(nBar)
-    {
-      case SB_HORZ:
-        lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
-        lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
-        lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
-        lprect->bottom = lprect->top + GetSystemMetrics(SM_CYHSCROLL);
-	if(wndPtr->dwStyle & WS_BORDER) {
-	  lprect->left--;
-	  lprect->right++;
-	} else if(wndPtr->dwStyle & WS_VSCROLL)
-	  lprect->right++;
-        vertical = FALSE;
-	break;
-
-      case SB_VERT:
-        lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
-        lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
-        lprect->right  = lprect->left + GetSystemMetrics(SM_CXVSCROLL);
-        lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
-	if(wndPtr->dwStyle & WS_BORDER) {
-	  lprect->top--;
-	  lprect->bottom++;
-	} else if(wndPtr->dwStyle & WS_HSCROLL)
-	  lprect->bottom++;
-        vertical = TRUE;
-	break;
-
-      case SB_CTL:
-	GetClientRect( hwnd, lprect );
-        vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
-	break;
-
-    default:
-        WIN_ReleaseWndPtr(wndPtr);
-        return FALSE;
-    }
-
-    if (vertical) pixels = lprect->bottom - lprect->top;
-    else pixels = lprect->right - lprect->left;
-
-    if (pixels <= 2*GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
-    {
-        if (pixels > SCROLL_MIN_RECT)
-            *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
-        else
-            *arrowSize = 0;
-        *thumbPos = *thumbSize = 0;
-    }
-    else
-    {
-        SCROLLBAR_INFO *info = SCROLL_GetScrollInfo( hwnd, nBar );
-
-        *arrowSize = GetSystemMetrics(SM_CXVSCROLL);
-        pixels -= (2 * (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP));
-
-        if (info->page)
-        {
-	    *thumbSize = MulDiv(pixels,info->page,(info->maxVal-info->minVal+1));
-            if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
-        }
-        else *thumbSize = GetSystemMetrics(SM_CXVSCROLL);
-
-        if (((pixels -= *thumbSize ) < 0) ||
-            ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
-        {
-            /* Rectangle too small or scrollbar disabled -> no thumb */
-            *thumbPos = *thumbSize = 0;
-        }
-        else
-        {
-            INT max = info->maxVal - max( info->page-1, 0 );
-            if (info->minVal >= max)
-                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-            else
-                *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
-		  + MulDiv(pixels, (info->curVal-info->minVal),(max - info->minVal));
-        }
-    }
-    WIN_ReleaseWndPtr(wndPtr);
-    return vertical;
-}
 
 
 /***********************************************************************
- *           SCROLL_GetThumbVal
+ *           SCROLL_GetThumb
  *
- * Compute the current scroll position based on the thumb position in pixels
- * from the top of the scroll-bar.
- */
-static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect,
-                                  BOOL vertical, INT pos )
-{
-    INT thumbSize;
-    INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
-
-    if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
-        return infoPtr->minVal;
-
-    if (infoPtr->page)
-    {
-        thumbSize = MulDiv(pixels,infoPtr->page,(infoPtr->maxVal-infoPtr->minVal+1));
-        if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
-    }
-    else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
-
-    if ((pixels -= thumbSize) <= 0) return infoPtr->minVal;
-
-    pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
-    if (pos > pixels) pos = pixels;
-
-    if (!infoPtr->page) pos *= infoPtr->maxVal - infoPtr->minVal;
-    else pos *= infoPtr->maxVal - infoPtr->minVal - infoPtr->page + 1;
-    return infoPtr->minVal + ((pos + pixels / 2) / pixels);
-}
-
-/***********************************************************************
- *           SCROLL_PtInRectEx
- */
-static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
-{
-    RECT 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 PtInRect( &rect, pt );
-}
-
-/***********************************************************************
- *           SCROLL_ClipPos
- */
-static POINT SCROLL_ClipPos( LPRECT lpRect, POINT 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;
-}
+ *  Determine the critical sizes and positions of arrows and thumb given
+ *  the bar properties including sizes desired places etc
+ *  
+ * RETURNS
+ *   bar->arrow size the arrow (width or height depending on orientation)
+ *   bar->thumb size of the thumb
+ *   bar->pos position of the thumb (relative to the left or top arrow)
+ * and
+ *   return the proposed new curVal for the scroll bar
+ */
+static UINT SCROLL_GetThumb(
+INT scrollPos /* [in] current or desired scroll position */,
+LPSCROLL_BAR bar /* [in/out] size and position of the bar components */)
+{
+	INT range = bar->info->maxVal - bar->info->minVal;
+	INT pixels = bar->pixels;
+	UINT curVal = 0;
+
+	/* set the default return values */
+	bar->pos = bar->arrow = bar->thumb = 0;
+	 
+	if (pixels > SCROLL_MIN_RECT + GetSystemMetrics(SM_CYHSCROLL) * 2)
+	{
+		/* set bar display properties */
+		bar->arrow = GetSystemMetrics(SM_CYHSCROLL);
 
+		/* using only the non arrow pixels */
+		pixels -= 2 * bar->arrow;
 
-/***********************************************************************
- *           SCROLL_HitTest
- *
- * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
- */
-static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar,
-                                           POINT pt, BOOL bDragging )
-{
-    INT arrowSize, thumbSize, thumbPos;
-    RECT rect;
-
-    BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
-                                           &arrowSize, &thumbSize, &thumbPos );
-
-    if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
-	 (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE;
-
-    if (vertical)
-    {
-        if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
-        if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
-        if (!thumbPos) return SCROLL_TOP_RECT;
-        pt.y -= rect.top;
-        if (pt.y < thumbPos) return SCROLL_TOP_RECT;
-        if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
-    }
-    else  /* horizontal */
-    {
-        if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
-        if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
-        if (!thumbPos) return SCROLL_TOP_RECT;
-        pt.x -= rect.left;
-        if (pt.x < thumbPos) return SCROLL_TOP_RECT;
-        if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
-    }
-    return SCROLL_THUMB;
-}
+		/* set thumb size */       
+		if (bar->info->page)
+			bar->thumb = MulDiv(pixels, bar->info->page, range + 1);
+		else
+			bar->thumb = GetSystemMetrics(SM_CXVSCROLL);
+
+		/* check thumb not too small */
+		if (bar->thumb < SCROLL_MIN_THUMB)
+			bar->thumb = SCROLL_MIN_THUMB;
+
+		/* scroll bar size ok and enabled */
+		range -= bar->info->page - 1;
+		pixels -= bar->thumb;
+
+		/* move thumb */
+		if ((pixels <= 0) || SCROLL_DISABLED(bar->info))
+			 bar->thumb = 0;
+		else if (scrollPos != SCROLL_NO_POS)
+		{
+			/* make the pos reasonable then calculate curVal */
+			if (scrollPos < 0) scrollPos = 0;
+			else if (scrollPos > pixels) scrollPos = pixels;
+			bar->pos = scrollPos;
+			curVal = MulDiv(range, scrollPos, pixels);
+		}
+		else if (range > 0)
+		{
+			/* use curVal to determine bar position */
+			curVal = bar->info->curVal - bar->info->minVal;
+			bar->pos = MulDiv(pixels, curVal, range);
+		}
+	}
+	else if (pixels > SCROLL_MIN_RECT)
+		bar->arrow = (pixels - SCROLL_MIN_RECT) / 2;
 
+	curVal += bar->info->minVal;
+	TRACE("pixels=%d pos=%d thumb=%d curVal=%d range=%d\n",
+		bar->pixels, bar->pos, bar->thumb, curVal, range);
 
-/***********************************************************************
- *           SCROLL_DrawArrows
- *
- * Draw the scroll bar arrows.
- */
-static void SCROLL_DrawArrows_9x( HDC hdc, SCROLLBAR_INFO *infoPtr,
-                                  RECT *rect, INT arrowSize, BOOL vertical,
-                                  BOOL top_pressed, BOOL bottom_pressed )
-{
-  RECT r;
-
-  r = *rect;
-  if( vertical )
-    r.bottom = r.top + arrowSize;
-  else
-    r.right = r.left + arrowSize;
-
-  DrawFrameControl( hdc, &r, DFC_SCROLL,
-		    (vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
-		    | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
-		    | (infoPtr->flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
-
-  r = *rect;
-  if( vertical )
-    r.top = r.bottom-arrowSize;
-  else
-    r.left = r.right-arrowSize;
-
-  DrawFrameControl( hdc, &r, DFC_SCROLL,
-		    (vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
-		    | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
-		    | (infoPtr->flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
-}
-
-static void SCROLL_DrawArrows_31( HDC hdc, SCROLLBAR_INFO *infoPtr,
-				  RECT *rect, INT arrowSize, BOOL vertical,
-				  BOOL top_pressed, BOOL bottom_pressed )
-{
-    HDC hdcMem = CreateCompatibleDC( hdc );
-    HBITMAP hbmpPrev = SelectObject( hdcMem, GET_ARROW(vertical ? &hUp : &hLeft,
-        infoPtr->flags & ESB_DISABLE_UP, top_pressed));
-
-    if (!hUp.normal) SCROLL_LoadBitmaps();
-    SetStretchBltMode( hdc, STRETCH_DELETESCANS );
-    StretchBlt( hdc, rect->left, rect->top,
-                  vertical ? rect->right-rect->left : arrowSize,
-                  vertical ? arrowSize : rect->bottom-rect->top,
-                  hdcMem, 0, 0,
-                  GetSystemMetrics(SM_CXVSCROLL),GetSystemMetrics(SM_CYHSCROLL),
-                  SRCCOPY );
-
-    SelectObject( hdcMem, GET_ARROW(vertical ? &hDown : &hRight,
-         infoPtr->flags & ESB_DISABLE_DOWN, bottom_pressed));
-
-    if (vertical)
-        StretchBlt( hdc, rect->left, rect->bottom - arrowSize,
-                      rect->right - rect->left, arrowSize,
-                      hdcMem, 0, 0,
-                      GetSystemMetrics(SM_CXVSCROLL),GetSystemMetrics(SM_CYHSCROLL),
-                      SRCCOPY );
-    else
-        StretchBlt( hdc, rect->right - arrowSize, rect->top,
-                      arrowSize, rect->bottom - rect->top,
-                      hdcMem, 0, 0,
-                      GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL),
-                      SRCCOPY );
-    SelectObject( hdcMem, hbmpPrev );
-    DeleteDC( hdcMem );
-}
-
-static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr,
-			       RECT *rect, INT arrowSize, BOOL vertical,
-			       BOOL top_pressed, BOOL bottom_pressed )
-{
-  if( TWEAK_WineLook == WIN31_LOOK )
-    SCROLL_DrawArrows_31( hdc, infoPtr, rect, arrowSize,
-			  vertical, top_pressed,bottom_pressed );
-  else
-    SCROLL_DrawArrows_9x( hdc, infoPtr, rect, arrowSize,
-			  vertical, top_pressed,bottom_pressed );
+	return curVal;
 }
 
 
 /***********************************************************************
- *           SCROLL_DrawMovingThumb
+ *           SCROLL_GetScrollBar
  *
- * Draw the moving thumb rectangle.
+ * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
+ * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
+ * 
+ * RETURNS
+ *  The scroll bar structure
  */
-static void SCROLL_DrawMovingThumb_31( HDC hdc, RECT *rect, BOOL vertical,
-				       INT arrowSize, INT thumbSize )
+static BOOL SCROLL_GetScrollBar(
+HWND hwnd /* [in] Handle of window with scrollbar(s) */,
+INT nBar /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */,
+LPSCROLLBAR_INFO info /* [in] The place of the thumb */,
+LPSCROLL_BAR bar /* [out] The bar positions and charactersistics */)
 {
-    RECT r = *rect;
-    if (vertical)
-    {
-        r.top += SCROLL_TrackingPos;
-        if (r.top < rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
-	    r.top = rect->top + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        if (r.top + thumbSize >
-	               rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
-            r.top = rect->bottom - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
-	                                                          - thumbSize;
-        r.bottom = r.top + thumbSize;
-    }
-    else
-    {
-        r.left += SCROLL_TrackingPos;
-        if (r.left < rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
-	    r.left = rect->left + arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        if (r.left + thumbSize >
-	               rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
-            r.left = rect->right - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP)
-	                                                          - thumbSize;
-        r.right = r.left + thumbSize;
-    }
-
-    DrawFocusRect( hdc, &r );
-    SCROLL_MovingThumb = !SCROLL_MovingThumb;
-}
-
-static void SCROLL_DrawMovingThumb_9x( HDC hdc, RECT *rect, BOOL vertical,
-				       INT arrowSize, INT thumbSize )
-{
-  INT pos = SCROLL_TrackingPos;
-  INT max_size;
-
-  if( vertical )
-    max_size = rect->bottom - rect->top;
-  else
-    max_size = rect->right - rect->left;
-
-  max_size -= (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
-
-  if( pos < (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) )
-    pos = (arrowSize-SCROLL_ARROW_THUMB_OVERLAP);
-  else if( pos > max_size )
-    pos = max_size;
-
-  SCROLL_DrawInterior_9x( SCROLL_TrackingWin, hdc, SCROLL_TrackingBar,
-			  rect, arrowSize, thumbSize, pos,
-			  0, vertical, FALSE, FALSE );
-
-  SCROLL_MovingThumb = !SCROLL_MovingThumb;
-}
-
-static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
-				    INT arrowSize, INT thumbSize )
-{
-  if( TWEAK_WineLook == WIN31_LOOK )
-    SCROLL_DrawMovingThumb_31( hdc, rect, vertical, arrowSize, thumbSize );
-  else
-    SCROLL_DrawMovingThumb_9x( hdc, rect, vertical, arrowSize, thumbSize );
-}
-
-/***********************************************************************
- *           SCROLL_DrawInterior
- *
- * Draw the scroll bar interior (everything except the arrows).
- */
-static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
-				    RECT *rect, INT arrowSize,
-				    INT thumbSize, INT thumbPos,
-				    UINT flags, BOOL vertical,
-				    BOOL top_selected, BOOL bottom_selected )
-{
-    RECT r;
-    HPEN hSavePen;
-    HBRUSH hSaveBrush,hBrush;
-
-    /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
-     * The window-owned scrollbars need to call DEFWND_ControlColor
-     * to correctly setup default scrollbar colors
-     */
-    if (nBar == SB_CTL)
-    {
-      hBrush = (HBRUSH)SendMessageA( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
-				     (WPARAM)hdc,(LPARAM)hwnd);
-    }
-    else
-    {
-      hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
-    }
-
-    hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
-    hSaveBrush = SelectObject( hdc, hBrush );
-
-    /* Calculate the scroll rectangle */
-    r = *rect;
-    if (vertical)
-    {
-        r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-    }
-    else
-    {
-        r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-    }
-
-    /* Draw the scroll rectangles and thumb */
-    if (!thumbPos)  /* No thumb to draw */
-    {
-        PatBlt( hdc, r.left, r.top,
-                     r.right - r.left, r.bottom - r.top,
-                     PATCOPY );
-
-        /* cleanup and return */
-        SelectObject( hdc, hSavePen );
-        SelectObject( hdc, hSaveBrush );
-        return;
-    }
-
-    if (vertical)
-    {
-        PatBlt( hdc, r.left, r.top,
-                  r.right - r.left,
-                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
-                  top_selected ? 0x0f0000 : PATCOPY );
-        r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-        PatBlt( hdc, r.left, r.top + thumbSize,
-                  r.right - r.left,
-                  r.bottom - r.top - thumbSize,
-                  bottom_selected ? 0x0f0000 : PATCOPY );
-        r.bottom = r.top + thumbSize;
-    }
-    else  /* horizontal */
-    {
-        PatBlt( hdc, r.left, r.top,
-                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
-                  r.bottom - r.top,
-                  top_selected ? 0x0f0000 : PATCOPY );
-        r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-        PatBlt( hdc, r.left + thumbSize, r.top,
-                  r.right - r.left - thumbSize,
-                  r.bottom - r.top,
-                  bottom_selected ? 0x0f0000 : PATCOPY );
-        r.right = r.left + thumbSize;
-    }
-
-    /* Draw the thumb */
-    DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT | BF_MIDDLE  );
-
-    /* cleanup */
-    SelectObject( hdc, hSavePen );
-    SelectObject( hdc, hSaveBrush );
-}
-
-
-static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
-                                 RECT *rect, INT arrowSize,
-                                 INT thumbSize, INT thumbPos,
-                                 UINT flags, BOOL vertical,
-                                 BOOL top_selected, BOOL bottom_selected )
-{
-    RECT r;
-    HPEN hSavePen;
-    HBRUSH hSaveBrush,hBrush;
-    BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
-
-    if (Save_SCROLL_MovingThumb &&
-        (SCROLL_TrackingWin == hwnd) &&
-        (SCROLL_TrackingBar == nBar))
-        SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
-
-      /* Select the correct brush and pen */
-
-    if (TWEAK_WineLook == WIN31_LOOK && (flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
-    {
-        /* This ought to be the color of the parent window */
-        hBrush = GetSysColorBrush(COLOR_WINDOW);
-    }
-    else
-    {
-        /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
-         * The window-owned scrollbars need to call DEFWND_ControlColor
-         * to correctly setup default scrollbar colors
-         */
-        if (nBar == SB_CTL) {
-            hBrush = (HBRUSH)SendMessageA( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
-                                           (WPARAM)hdc,(LPARAM)hwnd);
-        } else {
-            hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
-        }
-    }
-    hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
-    hSaveBrush = SelectObject( hdc, hBrush );
-
-      /* Calculate the scroll rectangle */
-
-    r = *rect;
-    if (vertical)
-    {
-        r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-    }
-    else
-    {
-        r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
-        r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-    }
-
-      /* Draw the scroll bar frame */
-
-	/* Only draw outline if Win 3.1.  Mar 24, 1999 - Ronald B. Cemer */
-    if (TWEAK_WineLook == WIN31_LOOK)
-	Rectangle( hdc, r.left, r.top, r.right, r.bottom );
-
-      /* Draw the scroll rectangles and thumb */
-
-    if (!thumbPos)  /* No thumb to draw */
-    {
-        INT offset = (TWEAK_WineLook > WIN31_LOOK) ? 0 : 1;
-
-        PatBlt( hdc, r.left+offset, r.top+offset,
-                     r.right - r.left - 2*offset, r.bottom - r.top - 2*offset,
-                     PATCOPY );
-
-        /* cleanup and return */
-        SelectObject( hdc, hSavePen );
-        SelectObject( hdc, hSaveBrush );
-        return;
-    }
-
-    if (vertical)
-    {
-        INT offset = (TWEAK_WineLook == WIN31_LOOK) ? 1 : 0;
-
-        PatBlt( hdc, r.left + offset, r.top + offset,
-                  r.right - r.left - offset*2,
-                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) - offset,
-                  top_selected ? 0x0f0000 : PATCOPY );
-        r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-        PatBlt( hdc, r.left + offset, r.top + thumbSize,
-                  r.right - r.left - offset*2,
-                  r.bottom - r.top - thumbSize - offset,
-                  bottom_selected ? 0x0f0000 : PATCOPY );
-        r.bottom = r.top + thumbSize;
-    }
-    else  /* horizontal */
-    {
-        INT offset = (TWEAK_WineLook == WIN31_LOOK) ? 1 : 0;
-
-        PatBlt( hdc, r.left + offset, r.top + offset,
-                  thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
-                  r.bottom - r.top - offset*2,
-                  top_selected ? 0x0f0000 : PATCOPY );
-        r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
-        PatBlt( hdc, r.left + thumbSize, r.top + offset,
-                  r.right - r.left - thumbSize - offset,
-                  r.bottom - r.top - offset*2,
-                  bottom_selected ? 0x0f0000 : PATCOPY );
-        r.right = r.left + thumbSize;
-    }
-
-      /* Draw the thumb */
-
-    SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
-    if (TWEAK_WineLook == WIN31_LOOK)
-    {
-	Rectangle( hdc, r.left, r.top, r.right, r.bottom );
-	r.top++, r.left++;
-    }
-    else
-    {
-	Rectangle( hdc, r.left+1, r.top+1, r.right-1, r.bottom-1 );
-    }
-    DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
-
-    if (Save_SCROLL_MovingThumb &&
-        (SCROLL_TrackingWin == hwnd) &&
-        (SCROLL_TrackingBar == nBar))
-        SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
-
-    /* cleanup */
-    SelectObject( hdc, hSavePen );
-    SelectObject( hdc, hSaveBrush );
-}
+	INT *from, *to;
+	BOOL vertical = FALSE;
+	WND *wnd = WIN_FindWndPtr(hwnd);
 
+	TRACE("hwnd=%04x nBar=%d info=%p bar=%p\n", hwnd, nBar, info, bar);
 
-/***********************************************************************
- *           SCROLL_DrawScrollBar
- *
- * Redraw the whole scrollbar.
- */
-void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar,
-			   BOOL arrows, BOOL interior )
-{
-    INT arrowSize, thumbSize, thumbPos;
-    RECT rect;
-    BOOL vertical;
-    WND *wndPtr = WIN_FindWndPtr( hwnd );
-    SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
-    BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
-
-    if (!wndPtr || !infoPtr ||
-        ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
-        ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) goto END;
-    if (!WIN_IsWindowDrawable( hwnd, FALSE )) goto END;
-    hwnd = wndPtr->hwndSelf;  /* make it a full handle */
-
-    vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
-                                        &arrowSize, &thumbSize, &thumbPos );
-
-    /* do not draw if the scrollbar rectangle is empty */
-    if(IsRectEmpty(&rect))
-      goto END;
-
-    if (Save_SCROLL_MovingThumb &&
-        (SCROLL_TrackingWin == hwnd) &&
-        (SCROLL_TrackingBar == nBar))
-        SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
-
-      /* Draw the arrows */
-
-    if (arrows && arrowSize)
-    {
-	if( vertical == SCROLL_trackVertical && GetCapture() == hwnd )
-	    SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
-			       (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
-			       (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
+	/* set common state */
+	bar->info = info;
+	bar->inside = TRUE;
+	bar->lastInside = FALSE;
+	bar->hit = SB_THUMBPOSITION;
+	bar->extended = wnd->rectClient;
+	bar->offset.x = bar->offset.y = 0;
+	bar->start.flags = (info->flags & ESB_DISABLE_LTUP) ? DFCS_INACTIVE : 0;
+	bar->end.flags = (info->flags & ESB_DISABLE_RTDN) ? DFCS_INACTIVE : 0;
+
+	/* Set the orientation */
+	if (!wnd) return vertical;
+	vertical = (nBar == SB_VERT) ||
+		((nBar == SB_CTL) && (wnd->dwStyle & SBS_VERT));
+	if (vertical)
+	{
+		/* Fill in the bar properites for vertical scroll bars */
+		bar->drawable = wnd->dwStyle & WS_VSCROLL;
+		bar->direction = WM_VSCROLL;
+		bar->start.coord = &(bar->rect.top);
+		bar->start.flags |= DFCS_SCROLLUP;
+		bar->start.arrow = &hUp;
+		bar->end.coord = &(bar->rect.bottom);
+		bar->end.flags |= DFCS_SCROLLDOWN;
+		bar->end.arrow = &hDown;
+		from = &(bar->extended.left);
+		to = &(bar->extended.right);
+	}
 	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 );
-
-    if (Save_SCROLL_MovingThumb &&
-        (SCROLL_TrackingWin == hwnd) &&
-        (SCROLL_TrackingBar == nBar))
-        SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
-
-    /* if scroll bar has focus, reposition the caret */
-    if(hwnd==GetFocus() && (nBar==SB_CTL))
-    {
-        if (!vertical)
-        {
-            SetCaretPos(thumbPos+1, rect.top+1);
-        }
-        else
-        {
-            SetCaretPos(rect.top+1, thumbPos+1);
-        }
-    }
-
-END:
-    WIN_ReleaseWndPtr(wndPtr);
-}
+	{
+		/* Fill in the bar properites for horizontal scroll bars */
+		bar->drawable = wnd->dwStyle & WS_HSCROLL;
+		bar->direction = WM_HSCROLL;
+		bar->start.coord = &(bar->rect.left);
+		bar->start.flags |= DFCS_SCROLLLEFT;
+		bar->start.arrow = &hLeft;
+		bar->end.coord = &(bar->rect.right);
+		bar->end.flags |= DFCS_SCROLLRIGHT;
+		bar->end.arrow = &hRight;
+		from = &(bar->extended.top);
+		to = &(bar->extended.bottom);
+	}
 
+	/* Get the client rect */
+	if (nBar != SB_CTL)
+	{
+		/* Set the offset used convert tracking to client coordinates */
+		OffsetRect(&(bar->extended), -wnd->rectWindow.left, -wnd->rectWindow.top);
+		bar->offset.x = bar->extended.left;
+		bar->offset.y = bar->extended.top;
+
+		/* Move rectangle to edge */
+		*from = *to;
+		*to += GetSystemMetrics(SM_CXVSCROLL);
+		bar->rect = bar->extended;
+
+		/* Adjust the size based on window style */
+		if (wnd->dwStyle & (WS_BORDER | WS_VSCROLL))
+			(*(bar->end.coord))++;
+		if (wnd->dwStyle & WS_BORDER)
+			(*(bar->start.coord))--;
+	}
+	else
+		bar->rect = bar->extended;
 
-/***********************************************************************
- *           SCROLL_RefreshScrollBar
- *
- * Repaint the scroll bar interior after a SetScrollRange() or
- * SetScrollPos() call.
- */
-static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar,
-				     BOOL arrows, BOOL interior )
-{
-    HDC hdc = GetDCEx( hwnd, 0,
-                           DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
-    if (!hdc) return;
+	/* handle the extended rect used in thumb tracking */
+	/* FIXME: use the correct system metric for win>31 */
+	*from -= GetSystemMetrics(SM_CXVSCROLL);
+	*to += GetSystemMetrics(SM_CXVSCROLL);
+	WIN_ReleasePtr(wnd);
+
+	/* Get the positions of the pieces and update the draw state */
+	bar->drawable = bar->drawable && !(IsRectEmpty(&(bar->rect)));
+	bar->pixels = *(bar->end.coord) - *(bar->start.coord);
+	SCROLL_GetThumb(SCROLL_NO_POS, bar);
 
-    SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
-    ReleaseDC( hwnd, hdc );
+	return vertical;
 }
 
 
@@ -936,286 +451,415 @@
 
 
 /***********************************************************************
- *           SCROLL_HandleScrollEvent
+ *           SCROLL_DrawArrow
  *
- * Handle a mouse or timer event for the scrollbar.
- * 'pt' is the location of the mouse event in client (for SB_CTL) or
- * windows coordinates.
+ * Draw a scroll bar arrow in the needed active and pressed state.
  */
-static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
+static void SCROLL_DrawArrow(
+HDC hdc /* [in] the drawing control */,
+LPRECT rect /* [in] the rectangle to contain the arrow */,
+LPSCROLL_EXTREMITY extremity /* [in] the extremity for the arrow */,
+BOOL pushed /* Indicates is the button is to be shown in its pushed state */)
 {
-      /* Previous mouse position for timer events */
-    static POINT prevPt;
-      /* Thumb position when tracking started. */
-    static UINT trackThumbPos;
-      /* Position in the scroll-bar of the last button-down event. */
-    static INT lastClickPos;
-      /* Position in the scroll-bar of the last mouse event. */
-    static INT lastMousePos;
-
-    enum SCROLL_HITTEST hittest;
-    HWND hwndOwner, hwndCtl;
-    BOOL vertical;
-    INT arrowSize, thumbSize, thumbPos;
-    RECT rect;
-    HDC hdc;
-
-    SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
-    if (!infoPtr) return;
-    if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
-		  return;
-
-    hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
-    vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
-                                        &arrowSize, &thumbSize, &thumbPos );
-    hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
-    hwndCtl   = (nBar == SB_CTL) ? hwnd : 0;
-
-    switch(msg)
-    {
-      case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
-          HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
-          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;
-          prevPt = pt;
-          if (nBar == SB_CTL && (GetWindowLongA(hwnd, GWL_STYLE) & WS_TABSTOP)) SetFocus( hwnd );
-          SetCapture( hwnd );
-          break;
-
-      case WM_MOUSEMOVE:
-          hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
-          prevPt = pt;
-          break;
-
-      case WM_LBUTTONUP:
-          hittest = SCROLL_NOWHERE;
-          ReleaseCapture();
-          /* if scrollbar has focus, show back caret */
-          if (hwnd==GetFocus()) ShowCaret(hwnd);
-          break;
-
-      case WM_SYSTIMER:
-          pt = prevPt;
-          hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
-          break;
-
-      default:
-          return;  /* Should never happen */
-    }
-
-    TRACE("Event: hwnd=%04x bar=%d msg=%s pt=%ld,%ld hit=%d\n",
-          hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
-
-    switch(SCROLL_trackHitTest)
-    {
-    case SCROLL_NOWHERE:  /* No tracking in progress */
-        break;
-
-    case SCROLL_TOP_ARROW:
-        SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
-                           (hittest == SCROLL_trackHitTest), FALSE );
-        if (hittest == SCROLL_trackHitTest)
-        {
-            if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
-            {
-                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                                SB_LINEUP, (LPARAM)hwndCtl );
-	    }
-
-	    SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-			    SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-			    (TIMERPROC)0 );
-        }
-        else KillSystemTimer( hwnd, SCROLL_TIMER );
-        break;
-
-    case SCROLL_TOP_RECT:
-        SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
-                             thumbPos, infoPtr->flags, vertical,
-                             (hittest == SCROLL_trackHitTest), FALSE );
-        if (hittest == SCROLL_trackHitTest)
-        {
-            if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
-            {
-                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                                SB_PAGEUP, (LPARAM)hwndCtl );
-            }
-            SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                              SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                              (TIMERPROC)0 );
-        }
-        else KillSystemTimer( hwnd, SCROLL_TIMER );
-        break;
-
-    case SCROLL_THUMB:
-        if (msg == WM_LBUTTONDOWN)
-        {
-            SCROLL_TrackingWin = hwnd;
-            SCROLL_TrackingBar = nBar;
-            SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
-	    if (!SCROLL_MovingThumb)
-		SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
-        }
-        else if (msg == WM_LBUTTONUP)
-        {
-	    if (SCROLL_MovingThumb)
-		SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
-            SCROLL_TrackingWin = 0;
-            SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
-                                 thumbPos, infoPtr->flags, vertical,
-                                 FALSE, FALSE );
-        }
-        else  /* WM_MOUSEMOVE */
-        {
-            UINT pos;
-
-            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_MovingThumb) )
-            {
-		if (SCROLL_MovingThumb)
-		    SCROLL_DrawMovingThumb( hdc, &rect, vertical,
-                                        arrowSize, thumbSize );
-                lastMousePos = pos;
-                SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
-                SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
-                                                         vertical,
-                                                         SCROLL_TrackingPos );
-                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                                MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
-                                (LPARAM)hwndCtl );
-		if (!SCROLL_MovingThumb)
-		    SCROLL_DrawMovingThumb( hdc, &rect, vertical,
-                                        arrowSize, thumbSize );
-            }
-        }
-        break;
-
-    case SCROLL_BOTTOM_RECT:
-        SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
-                             thumbPos, infoPtr->flags, vertical,
-                             FALSE, (hittest == SCROLL_trackHitTest) );
-        if (hittest == SCROLL_trackHitTest)
-        {
-            if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
-            {
-                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                                SB_PAGEDOWN, (LPARAM)hwndCtl );
-            }
-            SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-                              SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-                              (TIMERPROC)0 );
-        }
-        else KillSystemTimer( hwnd, SCROLL_TIMER );
-        break;
-
-    case SCROLL_BOTTOM_ARROW:
-        SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
-                           FALSE, (hittest == SCROLL_trackHitTest) );
-        if (hittest == SCROLL_trackHitTest)
-        {
-            if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
-            {
-                SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                                SB_LINEDOWN, (LPARAM)hwndCtl );
-	    }
-
-	    SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
-			    SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
-			    (TIMERPROC)0 );
-        }
-        else KillSystemTimer( hwnd, SCROLL_TIMER );
-        break;
-    }
-
-    if (msg == WM_LBUTTONDOWN)
-    {
-
-        if (hittest == SCROLL_THUMB)
-        {
-            UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
-                                 trackThumbPos + lastMousePos - lastClickPos );
-            SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                            MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
-        }
-    }
-
-    if (msg == WM_LBUTTONUP)
-    {
-	hittest = SCROLL_trackHitTest;
-	SCROLL_trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
-
-        if (hittest == SCROLL_THUMB)
-        {
-            UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
-                                 trackThumbPos + lastMousePos - lastClickPos );
-            SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                            MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
-        }
-        SendMessageA( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
-                          SB_ENDSCROLL, (LPARAM)hwndCtl );
-    }
+	if (extremity->flags & DFCS_TRANSPARENT) return;
+
+	TRACE("hdc=%04x rect=%p extremity=%p pushed=%d\n",
+		hdc, rect, extremity, pushed);
+
+	/* clear or set pessed states */
+	if (pushed)
+		extremity->flags |= (DFCS_PUSHED | DFCS_FLAT);
+	else
+		extremity->flags &= ~(DFCS_PUSHED | DFCS_FLAT);
+
+	if (TWEAK_WineLook != WIN31_LOOK)
+		DrawFrameControl(hdc, rect, DFC_SCROLL, extremity->flags);
+	else
+	{
+		HDC hdcMem = CreateCompatibleDC(hdc);
+		HBITMAP hbmpPrev;
+
+		/* load bitmask if not done yet */
+		if (!hUp.normal) SCROLL_LoadBitmaps();
 
-    ReleaseDC( hwnd, hdc );
+		/* draw the arrow from the image */
+		hbmpPrev = SelectObject(hdcMem, 
+			(extremity->flags & DFCS_INACTIVE) ? extremity->arrow->disabled :
+				((extremity->flags & DFCS_PUSHED) ? extremity->arrow->pressed :
+					extremity->arrow->normal));
+		SetStretchBltMode(hdc, STRETCH_DELETESCANS);
+		StretchBlt(hdc, rect->left, rect->top, rect->right - rect->left,
+			rect->bottom - rect->top, hdcMem, 0, 0,
+				GetSystemMetrics(SM_CXVSCROLL),
+					GetSystemMetrics(SM_CYHSCROLL), SRCCOPY);                  
+		SelectObject(hdcMem, hbmpPrev);
+		DeleteDC(hdcMem);
+	}
+}
+
+
+/*************************************************************************
+ *           SCROLL_DrawScrollBar 
+ */
+static void SCROLL_DrawScrollBar(
+HWND hwnd /* [in] Handle of window with scrollbar(s) */,
+INT nBar /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */,
+LPSCROLL_BAR bar /* [in] The place of the thumb */)
+{
+	HPEN hSavePen;
+	HBRUSH hSaveBrush;
+	INT end = *(bar->end.coord);
+	INT start = *(bar->start.coord);
+	HDC hdc = GetDCEx(hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW)); 
+	if (!hdc) return;
+
+	/* select the correct brush and pen */
+	hSavePen = SelectObject(hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
+	if (TWEAK_WineLook == WIN31_LOOK && SCROLL_DISABLED(bar->info))
+		/* this ought to be the color of the parent window */
+		hSaveBrush = SelectObject(hdc, GetSysColorBrush(COLOR_WINDOW));
+	else if (nBar == SB_CTL) 
+		/* only scrollbar controls send WM_CTLCOLORSCROLLBAR. */
+		hSaveBrush = SelectObject(hdc,(HBRUSH)SendMessageA(GetParent(hwnd), 
+			WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)hwnd));
+	else
+		/* the window-owned scrollbars use DEFWND_ControlColor
+		 * (to set default scroll bar colours) */
+		hSaveBrush = SelectObject(hdc,
+			DEFWND_ControlColor(hdc, CTLCOLOR_SCROLLBAR));
+
+	/* draw the end arrow at the end */
+	*(bar->start.coord) = *(bar->end.coord) - bar->arrow;
+	SCROLL_DRAW_ARROW(hdc, bar, &(bar->end), SB_LINEDOWN, SB_LINEUP);
+	*(bar->start.coord) = start;       
+
+	/* draw the start arrow at the start */
+	*(bar->end.coord) = *(bar->start.coord) + bar->arrow;
+	SCROLL_DRAW_ARROW(hdc, bar, &(bar->start), SB_LINEUP, SB_LINEDOWN);
+	*(bar->end.coord) = end;
+
+	/* draw the interior if needed */
+	if (!SCROLL_CHANGED(bar) || (bar->hit != SB_LINEUP && bar->hit != SB_LINEDOWN))
+	{
+		TRACE("hwnd=%04x nBar=%d\n", hwnd, nBar);
+
+		/* resize the arrows out of the scroll rectangle */
+		*(bar->start.coord) += bar->arrow;
+		*(bar->end.coord) -= bar->arrow;
+ 
+		/* draw outline only if Win 3.1.  Mar 24, 1999 - Ronald B. Cemer */
+		if (TWEAK_WineLook == WIN31_LOOK)
+		{
+			Rectangle(hdc, bar->rect.left, bar->rect.top, 
+				bar->rect.right, bar->rect.bottom);
+
+			/* Confine the drawing rect to inside the previous rectangle */
+			bar->rect.top++, bar->rect.left++, (*(bar->start.coord))--;
+			bar->rect.bottom--, bar->rect.right--, (*(bar->end.coord))++;
+		}
+
+		/* draw a first rect and thumb */
+		if (bar->thumb)
+		{
+			INT temp = *(bar->end.coord);
+			HBRUSH hSaveBrushThumb;
+
+			/* draw first rect */
+			*(bar->end.coord) = *(bar->start.coord) + bar->pos;
+			PatBlt(hdc, bar->rect.left, bar->rect.top,
+				bar->rect.right - bar->rect.left, bar->rect.bottom - bar->rect.top,
+					SCROLL_PATTERN(bar, SB_PAGEUP));
+			*(bar->start.coord) = *(bar->end.coord);
+
+			/* draw thumb */
+			*(bar->end.coord) = *(bar->start.coord) + bar->thumb;
+			hSaveBrushThumb = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
+			Rectangle(hdc, bar->rect.left, bar->rect.top,
+				bar->rect.right, bar->rect.bottom);
+			DrawEdge(hdc, &(bar->rect), EDGE_RAISED , BF_RECT); /* | BF_MIDDLE */
+			SelectObject(hdc, hSaveBrushThumb);
+
+			/* if scroll bar has focus, reposition the caret */
+			if ((hwnd == GetFocus()) && (nBar == SB_CTL))
+				SetCaretPos(bar->rect.left + 1, bar->rect.top + 1);
+
+			/* restore rect for next drawing operation */
+			*(bar->start.coord) = *(bar->end.coord);
+			*(bar->end.coord) = temp;
+		} /* thumb to be drawn */
+
+		/* draw last and only rect when no thumb is to be drawn */
+		PatBlt( hdc, bar->rect.left, bar->rect.top,
+			bar->rect.right - bar->rect.left, bar->rect.bottom - bar->rect.top,
+				SCROLL_PATTERN(bar, SB_PAGEDOWN));
+       
+		/* cleanup */
+		if (TWEAK_WineLook == WIN31_LOOK)
+		{
+			bar->rect.top--, bar->rect.left--, (*(bar->start.coord))++;
+			bar->rect.bottom++, bar->rect.right++, (*(bar->end.coord))--;
+		}
+		*(bar->start.coord) = start;
+		*(bar->end.coord) = end;
+	}
+	ReleaseDC(hwnd, hdc);
+	SelectObject(hdc, hSavePen);
+	SelectObject(hdc, hSaveBrush);
+	bar->lastInside = bar->inside;
+}
+
+
+/*************************************************************************
+ *           SCROLL_RefreshScrollBar 
+ */
+static void SCROLL_RefreshScrollBar(
+HWND hwnd /* [in] Handle of window with scrollbar(s) */,
+INT nBar /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */,
+LPSCROLLBAR_INFO info /* [in] The place of the thumb */)
+{
+	TRACE("hwnd=%04x nBar=%d info=%p\n", hwnd, nBar, info);
+
+	/* use the same scroll info structure unless being used by another */
+	if (trackBar.info && trackBar.info == info)
+	{
+		/* currently tracking this bar so use the track structure */
+		SCROLL_GetThumb(trackBar.hit == SB_THUMBPOSITION ? 
+			trackBar.pos : SCROLL_NO_POS, &trackBar);
+		if (trackBar.drawable)
+			SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+	}
+	else if (!(trackBar.info))
+	{
+		/* not tracking but might soon be so use the track structure */
+		SCROLL_GetScrollBar(hwnd, nBar, info, &trackBar);
+		if (trackBar.drawable) 
+			SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+		trackBar.info = 0;
+	}
+	else
+	{
+		/* Event ocurred while tracking a bar so create a bar structure */
+		SCROLL_BAR bar;
+		SCROLL_GetScrollBar(hwnd, nBar, info, &bar);
+		if (bar.drawable) SCROLL_DrawScrollBar(hwnd, nBar, &bar);
+	}
+}
+
+
+/*************************************************************************
+ *           SCROLL_PaintScrollBar 
+ *
+ *  Used by nonclient windows to draw scroll bars in the windows.
+ *  (cleaning up non client would get rid of this)
+ */
+void SCROLL_PaintScrollBar(
+HWND hwnd /* [in] Handle of window with scrollbar(s) */,
+INT nBar /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */)
+{
+	LPSCROLLBAR_INFO info = SCROLL_GetScrollInfo(hwnd, nBar);
+
+	TRACE("hwnd=%04x nBar=%d\n", hwnd, nBar);
+
+	if (info && WIN_IsWindowDrawable(hwnd, FALSE))
+		SCROLL_RefreshScrollBar(hwnd, nBar, info);
+}
+
+
+/***********************************************************************
+ *           SCROLL_GetHit
+ *
+ * Determine in which part of the scroll bar the event happened.
+ */
+static UINT SCROLL_GetHit(
+LONG coord /* [in] The the position of the mouse at the event */,
+LPSCROLL_BAR bar /* [in] The containing bar */)
+{
+	if (coord < 0)
+		return SB_LINEUP;
+	else if (coord >= bar->pixels - bar->arrow * 2)
+		return SB_LINEDOWN;
+	else if (coord < bar->pos)
+		return SB_PAGEUP;
+	else if (coord >= bar->pos + bar->thumb)
+		return SB_PAGEDOWN;
+	else
+		return SB_THUMBPOSITION;
 }
 
 
 /***********************************************************************
- *           SCROLL_TrackScrollBar
+ *           SCROLL_HandleScrollEvent
  *
- * Track a mouse button press on a scroll-bar.
- * pt is in screen-coordinates for non-client scroll bars.
+ * Handle a mouse or timer event for the scrollbar.
  */
-void SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
+void SCROLL_HandleScrollEvent(
+HWND hwnd /* [in] Handle of window with scrollbar(s) */,
+INT nBar /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */,
+UINT msg /* [in] The windows message identifier */,
+LPARAM lParam /* [in] The the position of the mouse at the event */)
 {
-    MSG msg;
-    INT xoffset = 0, yoffset = 0;
-
-    if (scrollbar != SB_CTL)
-    {
-        WND *wndPtr = WIN_GetPtr( hwnd );
-        if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
-        xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
-        yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
-        WIN_ReleasePtr( wndPtr );
-        ScreenToClient( hwnd, &pt );
-        pt.x += xoffset;
-        pt.y += yoffset;
-    }
-
-    SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt );
-
-    do
-    {
-        if (!GetMessageW( &msg, 0, 0, 0 )) break;
-        if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
-        switch(msg.message)
-        {
-        case WM_LBUTTONUP:
-        case WM_MOUSEMOVE:
-        case WM_SYSTIMER:
-            pt.x = LOWORD(msg.lParam) + xoffset;
-            pt.y = HIWORD(msg.lParam) + yoffset;
-            SCROLL_HandleScrollEvent( hwnd, scrollbar, msg.message, pt );
-            break;
-        default:
-            TranslateMessage( &msg );
-            DispatchMessageW( &msg );
-            break;
-        }
-        if (!IsWindow( hwnd ))
-        {
-            ReleaseCapture();
-            break;
-        }
-    } while (msg.message != WM_LBUTTONUP);
+	static UINT clickPos;  /* thumb position when tracking started */
+	static INT clickCoord; /* scroll coordinate of last button-down event */
+	static INT lastCoord;  /* scroll coordinate of last thumb move event */
+
+	/* Initialise the client position offset */
+	MSG mesg;              /* message structure used when tracking */
+	POINT pt;              /* location for event in client coordinates */
+	LONG *coordinate;      /* pointer to relevent coordinate in pt */  
+	LONG coord;            /* coordinate of event interior to arrows */
+	UINT curVal;           /* proposed current value during scrolling */
+	INT oldPos;            /* precious pos when handling moves */
+	BOOL tracking = FALSE; /* inicates if the scrol bar is tracking */
+	LPARAM hwndCtl = (nBar == SB_CTL) ? (LPARAM)hwnd : (LPARAM)0;
+	HWND hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
+
+	/* check scroll bar is enabled */
+	LPSCROLLBAR_INFO info = SCROLL_GetScrollInfo(hwnd, nBar);
+	if (!info || SCROLL_DISABLED(info)) return;
+
+	TRACE("hwnd=%04x nBar=%d\n",hwnd, nBar);
+
+	/* set the appropriate scroll coordinate from pt */
+	if (SCROLL_GetScrollBar(hwnd, nBar, info, &trackBar))
+		coordinate = &(pt.y);
+	else
+		coordinate = &(pt.x);
+
+	/* fill in initial dummy message structure */
+	mesg.message = msg;
+	mesg.lParam = lParam;
+
+	do {
+		/* determine the coordinates in client frame */
+		if (mesg.message == WM_LBUTTONDOWN ||
+			mesg.message == WM_MOUSEMOVE || 
+			mesg.message == WM_LBUTTONUP)
+		{
+			pt.x = LOWORD(mesg.lParam) - trackBar.offset.x;
+			pt.y = HIWORD(mesg.lParam) - trackBar.offset.y;
+		}
+
+		/* mouse down messages are in screen coordinates */
+		if (mesg.message == WM_LBUTTONDOWN && nBar != SB_CTL)
+			ScreenToClient(hwnd, &pt);
+
+		/* determine coordinate in bar after arrow */
+		coord = *coordinate - *(trackBar.start.coord) - trackBar.arrow;
+
+		TRACE("     processing: msg=%s pt=%ld,%ld\n",
+			SPY_GetMsgName(mesg.message, hwnd), pt.x, pt.y);
+
+		/* handle mesage */
+		if (!tracking || !CallMsgFilterW(&mesg, MSGF_SCROLLBAR))
+		switch (mesg.message)
+		{
+		case WM_LBUTTONDOWN:
+			/* handle coords, caret, focus, capture and tracking*/
+			if (GetWindowLongA(hwnd, GWL_STYLE) & WS_TABSTOP) SetFocus(hwnd);
+			SetCapture(hwnd);
+			HideCaret(hwnd);
+			tracking = TRUE;
+
+			/* set the hit and tracking parameters */
+			clickPos = trackBar.pos;
+			lastCoord = clickCoord = coord =
+				*coordinate - *(trackBar.start.coord) - trackBar.arrow;
+
+			/* determine the hit position and draw */
+			trackBar.hit = SCROLL_GetHit(coord, &trackBar);
+			if (trackBar.hit == SB_THUMBPOSITION) break;
+			SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+			/* fall through */
+
+		case WM_SYSTIMER:
+			if (trackBar.inside && trackBar.hit != SB_THUMBPOSITION) 
+			{
+				/* send the hit message to the parent */
+				SendMessageA(hwndOwner, trackBar.direction, trackBar.hit, hwndCtl);
+
+				/* don't repeat when at either the end of the bar */
+				if (!((trackBar.hit == SB_LINEUP && info->curVal == info->minVal) ||
+					(trackBar.hit == SB_LINEDOWN &&
+						info->curVal == info->maxVal - info->page + 1)))
+					SetSystemTimer(hwnd, SCROLL_TIMER, (mesg.message == WM_LBUTTONDOWN) ?
+						SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY, (TIMERPROC)0);
+				else
+					KillSystemTimer(hwnd, SCROLL_TIMER);
+
+				/* handle thumb moving under cursor in page moves */
+				if (!(trackBar.inside = (trackBar.hit == SCROLL_GetHit(coord, &trackBar))))
+					SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+			}
+			break;
+
+		case WM_MOUSEMOVE:
+			/* deterine if inside the bar and update the scroll position */
+			curVal = info->curVal;
+			if (trackBar.hit == SB_LINEUP || trackBar.hit == SB_LINEDOWN)
+				trackBar.inside = PtInRect(&(trackBar.rect), pt)  &&
+					trackBar.hit == SCROLL_GetHit(coord, &trackBar);
+			else if (!trackBar.inside)
+				; /* once outsidebar always outside for non arrow hits */
+			else if (trackBar.hit != SB_THUMBPOSITION)
+				trackBar.inside = PtInRect(&(trackBar.rect), pt) &&
+					trackBar.hit == SCROLL_GetHit(coord, &trackBar);
+			else if (!(trackBar.inside = PtInRect(&(trackBar.extended), pt)))
+				trackBar.hit = SCROLL_NO_POS, curVal = SCROLL_GetThumb(clickPos, &trackBar);
+			else if (coord != lastCoord)
+			{
+				/* if move is relevent find new curVal */
+				lastCoord = coord;
+				oldPos = trackBar.pos;
+				curVal = SCROLL_GetThumb(clickPos + coord - clickCoord, &trackBar);
+				if (trackBar.pos != oldPos) SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+			}
+
+			/* send SB_THUMBTRACK messages to parent if moved */
+			if (info->curVal != curVal)
+				SendMessageA(hwndOwner, trackBar.direction, 
+					MAKEWPARAM(SB_THUMBPOSITION /*SB_THUMBTRACK*/, curVal), hwndCtl);
+
+			/* redraw if needed */
+			if (SCROLL_CHANGED(&trackBar))
+				SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+			break;
+
+		case WM_LBUTTONUP:
+			/* send messages to control */
+			if (trackBar.hit == SB_THUMBPOSITION)
+				SendMessageA(hwndOwner, trackBar.direction,
+					MAKEWPARAM(trackBar.hit, info->curVal), hwndCtl);
+			else if (trackBar.inside)
+			{
+				trackBar.inside = FALSE;
+				SCROLL_DrawScrollBar(hwnd, nBar, &trackBar);
+			}
+			SendMessageA(hwndOwner, trackBar.direction, SB_ENDSCROLL, hwndCtl);
+
+			/* clean up capture and timer */
+			ReleaseCapture();
+			KillSystemTimer(hwnd, SCROLL_TIMER);
+			if (hwnd == GetFocus()) ShowCaret(hwnd);
+			tracking = FALSE;
+			break;
+
+		default:
+			if (tracking)
+			{
+				TranslateMessage(&mesg);
+				DispatchMessageW(&mesg);
+			}
+			else
+				ERR("Illegal message %s\n", SPY_GetMsgName(msg, hwnd));   
+			break;
+		}
+		/*if (tracking && !IsWindow(hwnd)) ReleaseCapture();*/
+	} while (tracking && GetMessageW(&mesg, 0, 0, 0));
+
+	/* Note: failing GetMessageW(&mesg, 0, 0, 0)
+	 * will not clean up capture or scroll timer properly
+	 */ 
+	trackBar.info = 0;
 }
 
 
@@ -1227,20 +871,22 @@
 static void WINAPI SCROLL_SetFocus(
 HWND hwnd /* [in] Handle of window with scrollbar(s) */)
 {
-	/* Create a caret when a ScrollBar get focus */
-	RECT rect;
-	int arrowSize, thumbSize, thumbPos, vertical;
-	vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,
-		&arrowSize, &thumbSize, &thumbPos );
-	if (!vertical)
+	SCROLL_BAR bar;
+	LPSCROLLBAR_INFO info = SCROLL_GetScrollInfo(hwnd, SB_CTL);
+	if (!info) return;
+
+	TRACE("hwnd=%04x", hwnd);
+
+	/* Create a caret when a ScrollBar gets focus */
+	if (SCROLL_GetScrollBar(hwnd, SB_CTL, info, &bar))
 	{
-		CreateCaret(hwnd,1, thumbSize-2, rect.bottom-rect.top-2);
-		SetCaretPos(thumbPos+1, rect.top+1);
+		CreateCaret(hwnd, 1, GetSystemMetrics(SM_CXVSCROLL) - 2, bar.thumb - 2);
+		SetCaretPos(bar.rect.top + 1, bar.pos + 1);
 	}
 	else
 	{
-		CreateCaret(hwnd,1, rect.right-rect.left-2,thumbSize-2);
-		SetCaretPos(rect.top+1, thumbPos+1);
+		CreateCaret(hwnd, 1, bar.thumb - 2,  GetSystemMetrics(SM_CYHSCROLL) - 2);
+		SetCaretPos(bar.pos + 1, bar.rect.top + 1);
 	}
 	ShowCaret(hwnd);
 }
@@ -1254,21 +900,21 @@
 static void SCROLL_KillFocus(
 HWND hwnd /* [in] Handle of window with scrollbar(s) */)
 {
-	RECT rect;
-	int arrowSize, thumbSize, thumbPos, vertical;
-	vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,&arrowSize, &thumbSize, &thumbPos );
-	if (!vertical)
-	{
-		rect.left=thumbPos+1;
-		rect.right=rect.left+thumbSize;
-	}
-	else
-	{
-		rect.top=thumbPos+1;
-		rect.bottom=rect.top+thumbSize;
-	}
+	SCROLL_BAR bar;
+	LPSCROLLBAR_INFO info = SCROLL_GetScrollInfo(hwnd, SB_CTL);
+	if (!info) return;
+
+	TRACE("hwnd=%04x", hwnd);
+
+	SCROLL_GetScrollBar(hwnd, SB_CTL, info, &bar); 
+
+	/* move the bar rect */
+	*(bar.start.coord)  = bar.pos + 1;
+	*(bar.end.coord) = *(bar.start.coord) + bar.thumb;
+
+	/* Handle the caret display */
 	HideCaret(hwnd);
-	InvalidateRect(hwnd,&rect,0);
+	InvalidateRect(hwnd, &(bar.rect), 0);
 	DestroyCaret();
 }
 
@@ -1371,20 +1017,10 @@
 			wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
 
 	case WM_LBUTTONDOWN:
-		{
-			POINT pt; pt.x = SLOWORD(lParam); pt.y = SHIWORD(lParam);
-			SCROLL_TrackScrollBar( hwnd, SB_CTL, pt );
-		}
-		break;
-
 	case WM_LBUTTONUP:
 	case WM_MOUSEMOVE:
 	case WM_SYSTIMER:
-		{
-			POINT pt; pt.x = SLOWORD(lParam); pt.y = SHIWORD(lParam);
-			SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, pt );
-		}
-		break;
+		SCROLL_HandleScrollEvent(hwnd, SB_CTL, message, lParam); break;
 
 	case WM_KEYDOWN:
 		SCROLL_HandleKbdEvent(hwnd, wParam, lParam); break;
@@ -1406,7 +1042,7 @@
 
 	case WM_PAINT:
 		/* FIXME: needs to handle all types of bars */
-		SCROLL_RefreshScrollBar(hwnd, SB_CTL, TRUE, TRUE); break;
+		SCROLL_PaintScrollBar(hwnd, SB_CTL); break;
 
 	case SBM_SETPOS16:
 	case SBM_SETPOS:
@@ -1631,7 +1267,7 @@
 	if (WIN_IsWindowDrawable(hwnd, FALSE) &&
 		((infoPtr->flags != oldFlags) ||
 			(bRedraw && changed && (infoPtr->minVal < gap))))
-				SCROLL_RefreshScrollBar(hwnd, nBar, TRUE, TRUE);
+				SCROLL_RefreshScrollBar(hwnd, nBar, infoPtr);
 
 	return infoPtr->curVal;
 }
@@ -1810,7 +1446,7 @@
 	{
 		info->flags = flags;
 		if (WIN_IsWindowDrawable(hwnd, FALSE))
-			SCROLL_RefreshScrollBar(hwnd, nBar, TRUE, TRUE);
+			SCROLL_RefreshScrollBar(hwnd, nBar, info);
 	}
 
 	return ret;





More information about the wine-patches mailing list