diff lwlib/xlwscrollbar.c @ 26:441bb1e64a06 r19-15b96

Import from CVS: tag r19-15b96
author cvs
date Mon, 13 Aug 2007 08:51:32 +0200
parents 9ee227acff29
children 131b0175ea99
line wrap: on
line diff
--- a/lwlib/xlwscrollbar.c	Mon Aug 13 08:51:05 2007 +0200
+++ b/lwlib/xlwscrollbar.c	Mon Aug 13 08:51:32 2007 +0200
@@ -1,5 +1,6 @@
 /* Implements a lightweight scrollbar widget.  
    Copyright (C) 1992, 1993, 1994 Lucid, Inc.
+   Copyright (C) 1997 Sun Microsystems, Inc.
 
 This file is part of the Lucid Widget Library.
 
@@ -19,6 +20,7 @@
 Boston, MA 02111-1307, USA.  */
 
 /* Created by Douglas Keller <dkeller@vnet.ibm.com> */
+/* Lots of hacking by Martin Buchholz */
 
 /*
  * Athena-style scrollbar button bindings added on Sun Dec 24 22:03:57 1995
@@ -61,7 +63,7 @@
  *     XmNtoBottomCallback
  *     XmNdragCallback
  *
- *     XmNknobStyle      - values can be: "plain" or "dimple"
+ *     XmNsliderStyle    - values can be: "plain" or "dimple"
  *     XmNarrowPosition  - values can be: "opposite" or "same"
  *
  */
@@ -86,33 +88,23 @@
 
 #define SS_MIN 8
 
-#define ARROW_UP    0
-#define ARROW_DOWN  1
-#define ARROW_LEFT  2
-#define ARROW_RIGHT 3
-
-#define ARM_NONE   0
-#define ARM_KNOB   1
-#define ARM_UP     2
-#define ARM_DOWN   3
-#define ARM_PAGEUP 4
-#define ARM_PAGEDOWN 5
+typedef enum
+{
+  BUTTON_NONE,
+  BUTTON_SLIDER,
+  BUTTON_UP_ARROW,
+  BUTTON_DOWN_ARROW,
+  BUTTON_TROUGH_ABOVE,
+  BUTTON_TROUGH_BELOW
+} button_where;
 
-#define BUTTON_NONE         0
-#define BUTTON_KNOB         1
-#define BUTTON_UP_ARROW     2
-#define BUTTON_DOWN_ARROW   3
-#define BUTTON_TROUGH_ABOVE 4
-#define BUTTON_TROUGH_BELOW 5
+typedef enum
+{
+  SLIDER_PLAIN,
+  SLIDER_DIMPLE
+} SliderStyle;
 
-#define KNOB_PLAIN  0
-#define KNOB_DIMPLE 1
-
-/************************************************************************
-**
-** Resources
-**
-*/
+/*-------------------------- Resources ----------------------------------*/
 #define offset(field) XtOffset(XlwScrollBarWidget, field)
 
 static XtResource resources[] = {
@@ -189,33 +181,23 @@
     { XmNdragCallback, XmCDragCallback, XtRCallback,
       sizeof(XtPointer), offset(sb.dragCBL), XtRCallback, NULL},
 
+      /* "knob" is obsolete; use "slider" instead. */
+    { XmNsliderStyle, XmCSliderStyle, XtRString, sizeof(char *),
+      offset(sb.sliderStyle), XtRImmediate, NULL},
     { XmNknobStyle, XmCKnobStyle, XtRString, sizeof(char *),
-      offset(sb.knobStyle), XtRImmediate, NULL},
+      offset(sb.sliderStyle), XtRImmediate, NULL},
 
     { XmNarrowPosition, XmCArrowPosition, XtRString,
       sizeof(char *), offset(sb.arrowPosition), XtRImmediate, NULL},
 };
 
-/************************************************************************
-**
-** Prototypes
-**
-*/
+/*-------------------------- Prototypes ---------------------------------*/
 
-/*
-** Actions
-*/
-static void Select(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void PageUpOrLeft(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void PageDownOrRight(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void Drag(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void Release(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void Jump(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
-static void Abort(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
+/* Actions */
+typedef void Action(Widget w, XEvent *event, String *parms, Cardinal *num_parms);
+static Action Select, PageUpOrLeft, PageDownOrRight, Drag, Release, Jump, Abort;
 
-/*
-** Methods
-*/
+/* Methods */
 static void Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num_args);
 static Boolean SetValues(Widget current, Widget request, Widget nw, ArgList args, Cardinal *num_args);
 static void Destroy(Widget widget);
@@ -223,46 +205,32 @@
 static void Resize(Widget widget);
 static void Realize(Widget widget, XtValueMask *valuemask, XSetWindowAttributes *attr);
 
-/*
-** Private
-*/
-
+/* Private */
 
-/************************************************************************
-**
-** Actions Table
-**
-*/
-static XtActionsRec actions[] = {
-    {"Select",		Select},
-    {"PageDownOrRight",	PageDownOrRight},
-    {"PageUpOrLeft",	PageUpOrLeft},
-    {"Drag",		Drag},
-    {"Release",		Release},
-    {"Jump",		Jump},
-    {"Abort",		Abort},
+/*-------------------------- Actions Table ------------------------------*/
+static XtActionsRec actions[] =
+{
+  {"Select",		Select},
+  {"PageDownOrRight",	PageDownOrRight},
+  {"PageUpOrLeft",	PageUpOrLeft},
+  {"Drag",		Drag},
+  {"Release",		Release},
+  {"Jump",		Jump},
+  {"Abort",		Abort},
 };
 
-/************************************************************************
-**
-** Default Translation Table
-**
-*/
+/*--------------------- Default Translation Table -----------------------*/
 static char default_translations[] =
-    "<Btn1Down>:    Select()\n"
-    "<Btn1Motion>:  Drag()\n"
-    "<Btn1Up>:      Release()\n"
-    "<Btn2Down>:    Jump()\n"
-    "<Btn2Motion>:  Drag()\n"
-    "<Btn2Up>:      Release()\n"
-    "<Key>Delete:   Abort()"
+  "<Btn1Down>:    Select()\n"
+  "<Btn1Motion>:  Drag()\n"
+  "<Btn1Up>:      Release()\n"
+  "<Btn2Down>:    Jump()\n"
+  "<Btn2Motion>:  Drag()\n"
+  "<Btn2Up>:      Release()\n"
+  "<Key>Delete:   Abort()"
 ;
 
-/************************************************************************
-**
-** Class record initalization
-**
-*/
+/*------------------- Class record initialization -----------------------*/
 XlwScrollBarClassRec xlwScrollBarClassRec = {
     /* core_class fields */
     {
@@ -305,11 +273,7 @@
 
 WidgetClass xlwScrollBarWidgetClass = (WidgetClass) &xlwScrollBarClassRec;
 
-/************************************************************************
-**
-** Debug functions
-**
-*/
+/*-------------------------- Debug Functions ----------------------------*/
 
 #ifdef SHOW_CLEAR
 static void
@@ -329,15 +293,13 @@
 static void
 check(XlwScrollBarWidget w)
 {
-  int height;
-  
-  height= widget_h (w);
-  if (w->sb.showArrows) height -= (2 * arrow_h (w));
+  int height = widget_h (w);
+  if (w->sb.showArrows)
+    height -= (2 * arrow_h (w));
 
   if ((w->sb.above + w->sb.ss + w->sb.below > height) ||
       (w->sb.value < w->sb.minimum) ||
-      (w->sb.value > w->sb.maximum - w->sb.sliderSize)
-      )
+      (w->sb.value > w->sb.maximum - w->sb.sliderSize))
     {
       printf("above=%d ss=%d below=%d height=%d\n", 
 	     w->sb.above, w->sb.ss, w->sb.below, height);
@@ -353,11 +315,7 @@
 #  define CHECK(w)
 #endif
 
-/************************************************************************
-**
-** Static functions
-**
-*/
+/*-------------------------- Static functions ---------------------------*/
 
 static void
 call_callbacks (XlwScrollBarWidget w, int reason,
@@ -437,9 +395,8 @@
     }
 }
 
-/*
-** Widget sizes minus the shadow and highlight area
-*/
+/* Widget sizes minus the shadow and highlight area */
+
 static int
 widget_x (XlwScrollBarWidget w)
 {
@@ -455,41 +412,26 @@
 static int
 widget_w (XlwScrollBarWidget w)
 {
-  int width, x = w->sb.shadowThickness;
-
-  width = VERT (w) ? w->core.width : w->core.height;
-
-  if (width <= (2 * x))
-    return 1;
-  else
-    return width - (2 * x);
+  int x = w->sb.shadowThickness;
+  int width = (VERT (w) ? w->core.width : w->core.height) - (2 * x);
+  return width > 1 ? width : 1;
 }
 
 static int
 widget_h (XlwScrollBarWidget w)
 {
-  int height, y = w->sb.shadowThickness;
-
-  height = VERT (w) ? w->core.height : w->core.width;
+  int y = w->sb.shadowThickness;
+  int height = (VERT (w) ? w->core.height : w->core.width) - (2 * y);
 
-  if (height <= (2 * y))
-    return 1;
-  else
-    return height - (2 * y);
+  return height > 1 ? height : 1;
 }
 
 static int
 arrow_h (XlwScrollBarWidget w)
 {
-  int width, height;
-
-  width = widget_w (w);
-  height= widget_h (w);
-
-  if (width > ((height / 2) - (SS_MIN / 2) - 1))
-    return     (height / 2) - (SS_MIN / 2) - 1 ;
-  else
-    return width;
+  int width = widget_w (w);
+  int minimum_size = ((widget_h (w) - SS_MIN) / 2) - 1;
+  return minimum_size < width ? minimum_size : width;
 }
 
 static int
@@ -504,29 +446,29 @@
   return VERT (w) ? event->xbutton.y : event->xbutton.x;
 }
 
-/*
-** Safe addition and subtraction
-*/
-static int
-safe_add (int a, int b)
+/* Safe addition and subtraction */
+static void
+increment_value (XlwScrollBarWidget w, int diff)
 {
-  if (a > 0 && INT_MAX - a < b) return INT_MAX;
-  else return a + b;
+  w->sb.value = w->sb.maximum - diff < w->sb.value ?
+    w->sb.maximum :
+    w->sb.value + diff;
 }
 
-static int
-safe_subtract (int a, int b)
+static void
+decrement_value (XlwScrollBarWidget w, int diff)
 {
-  if (a < 0 && -(INT_MIN - a) < b) return INT_MIN;
-  else return a - b;
+  w->sb.value = w->sb.minimum + diff > w->sb.value ?
+    w->sb.minimum :
+    w->sb.value - diff;
 }
 
-static int
-knob_style (XlwScrollBarWidget w)
+static SliderStyle
+slider_style (XlwScrollBarWidget w)
 {
-  return w->sb.knobStyle && w->sb.knobStyle[0] == 'd' ?
-    KNOB_DIMPLE :
-    KNOB_PLAIN;
+  return w->sb.sliderStyle && w->sb.sliderStyle[0] == 'd' ?
+    SLIDER_DIMPLE :
+    SLIDER_PLAIN;
 }
 
 static Boolean
@@ -535,9 +477,7 @@
   return w->sb.arrowPosition && w->sb.arrowPosition[0] == 's' ? True : False;
 }
 
-/*
-** GC and Pixel allocation
-*/
+/*-------------------------- GC and Pixel allocation --------------------*/
 static GC
 get_gc (XlwScrollBarWidget w, Pixel fg, Pixel bg, Pixmap pm)
 {
@@ -559,8 +499,8 @@
   values.background = bg;
   values.fill_style = FillOpaqueStippled;
   values.stipple    = pm;
-  mask              = GCForeground | GCBackground |
-     (pm == None ? 0 : GCStipple | GCFillStyle);
+  mask = GCForeground | GCBackground |
+    (pm == None ? 0 : GCStipple | GCFillStyle);
   return XtGetGC((Widget) w, mask, &values);
 }
 
@@ -716,7 +656,7 @@
        * really in color but just short on color cells -- We want the 
        * following behavior, which has been empirically determined to
        * work well for all fg/bg combinations in mono: If the trough
-       * and thumb are BOTH black, then use a white top shadow and a
+       * and slider are BOTH black, then use a white top shadow and a
        * grey bottom shadow, otherwise use a grey top shadow and a
        * black bottom shadow.
        */
@@ -724,7 +664,7 @@
       Pixel white = WhitePixelOfScreen (DefaultScreenOfDisplay (XtDisplay (w)));
       Pixel black = BlackPixelOfScreen (DefaultScreenOfDisplay (XtDisplay (w)));
 
-      /* Note: core.background_pixel is the color of the thumb ... */
+      /* Note: core.background_pixel is the color of the slider ... */
 
       if (w->core.background_pixel == black &&
 	  w->sb.troughColor == black)
@@ -759,9 +699,7 @@
     }
 }
 
-/*
-** Draw 3d border
-*/
+/*-------------------------- Draw 3D Border -----------------------------*/
 static void
 draw_shadows (Display *dpy, Drawable d, GC shine_gc, GC shadow_gc,
 	      int x, int y, int width, int height, int shadowT)
@@ -798,20 +736,18 @@
   XDrawSegments (dpy, d, shadow_gc, shadow, shadowT * 2);
 }
 
-/*
-** Draw 3d arrows, left, up, down, and right
-*/
+/*------------------ Draw 3D Arrows: left, up, down, right --------------*/
 static int
 make_vert_seg (XSegment *seg, int x1, int y1, int x2, int y2, int shadowT)
 {
   int i;
 
-  for (i=0; i<shadowT; i++)
+  for (i=0; i<shadowT; i++, seg++)
     {
-      seg[i].x1 = x1;
-      seg[i].y1 = y1 + i;
-      seg[i].x2 = x2;
-      seg[i].y2 = y2 + i;
+      seg->x1 = x1;
+      seg->y1 = y1++;
+      seg->x2 = x2;
+      seg->y2 = y2++;
     }
   return shadowT;
 }
@@ -821,12 +757,12 @@
 {
   int i;
 
-  for (i=0; i<shadowT; i++)
+  for (i=0; i<shadowT; i++, seg++)
     {
-      seg[i].x1 = x1 + i;
-      seg[i].y1 = y1;
-      seg[i].x2 = x2 + i;
-      seg[i].y2 = y2;
+      seg->x1 = x1++;
+      seg->y1 = y1;
+      seg->x2 = x2++;
+      seg->y2 = y2;
     }
   return shadowT;
 }
@@ -843,18 +779,18 @@
 
   if (shadowT > (width  / 2)) shadowT = (width  / 2);
   if (shadowT > (height / 2)) shadowT = (height / 2);
-  if (shadowT <= 0) shadowT = 0;
+  if (shadowT < 0) shadowT = 0;
 
   /*  /  */
   make_vert_seg (shine,
-		 x,       y + height - shadowT - 1,
+		 x, y + height - shadowT - 1,
 		 x + mid, y, shadowT);
   /*  _\  */
   make_vert_seg (shadow,
-		 x,             y + height - shadowT - 1,
+		 x, y + height - shadowT - 1,
 		 x + width - 1, y + height - shadowT - 1, shadowT);
   make_vert_seg (shadow + shadowT,
-		 x + mid,       y,
+		 x + mid, y,
 		 x + width - 1, y + height - shadowT - 1, shadowT);
 
   triangle[0].x = x;
@@ -876,21 +812,20 @@
 {
   XSegment shine[10], shadow[10];
   XPoint triangle[3];
-  int mid;
 
-  mid = width / 2;
+  int mid = width / 2;
 
   if (shadowT > (width  / 2)) shadowT = (width  / 2);
   if (shadowT > (height / 2)) shadowT = (height / 2);
-  if (shadowT <= 0) shadowT = 0;
+  if (shadowT < 0) shadowT = 0;
 
   /*  /  */
   make_hor_seg (shine,
-		x,         y + mid,
+		x, y + mid,
 		x + width - shadowT - 1, y, shadowT);
   /*  \|  */
   make_hor_seg (shadow,
-		x,         y + mid,
+		x, y + mid,
 		x + width - shadowT - 1, y + height - 1, shadowT);
   make_hor_seg (shadow + shadowT,
 		x + width - shadowT - 1, y,
@@ -921,19 +856,19 @@
 
   if (shadowT > (width  / 2)) shadowT = (width  / 2);
   if (shadowT > (height / 2)) shadowT = (height / 2);
-  if (shadowT <= 0) shadowT = 0;
+  if (shadowT < 0) shadowT = 0;
       
   /*  \-  */
   make_vert_seg (shine,
-		 x,       y,
+		 x, y,
 		 x + mid, y + height - shadowT - 1, shadowT);
   make_vert_seg (shine + shadowT,
-		 x,             y,
+		 x, y,
 		 x + width - 1, y, shadowT);
   /*  /  */
   make_vert_seg (shadow,
 		 x + width - 1, y,
-		 x + mid,       y + height - shadowT - 1, shadowT);
+		 x + mid, y + height - shadowT - 1, shadowT);
 
   triangle[0].x = x;
   triangle[0].y = y;
@@ -960,23 +895,23 @@
 
   if (shadowT > (width  / 2)) shadowT = (width  / 2);
   if (shadowT > (height / 2)) shadowT = (height / 2);
-  if (shadowT <= 0) shadowT = 0;
+  if (shadowT < 0) shadowT = 0;
       
   /*  |\  */
   make_hor_seg (shine,
-		x,       y,
+		x, y,
 		x + width - shadowT - 1, y + mid, shadowT);
   make_hor_seg (shine + shadowT,
 		x, y,
-		x, y + height -1, shadowT);
+		x, y + height - 1, shadowT);
   /*  /  */
   make_hor_seg (shadow,
-		x, y + height -1,
+		x, y + height - 1,
 		x + width - shadowT - 1, y + mid, shadowT);
 
   triangle[0].x = x + 1;
   triangle[0].y = y + height - 1;
-  triangle[1].x = x + width - 1;
+  triangle[1].x = x + width  - 1;
   triangle[1].y = y + mid;
   triangle[2].x = x + 1;
   triangle[2].y = y;
@@ -995,9 +930,7 @@
   XDrawArc (dpy, win, shadow, x, y, width, height, 45*64, -179*64);
 }
 
-/*
-** Scrollbar values -> pixels, pixels -> scrollbar values
-*/
+/*------- Scrollbar values -> pixels, pixels -> scrollbar values --------*/
 
 static void
 seg_pixel_sizes (XlwScrollBarWidget w, int *above_return,
@@ -1019,14 +952,14 @@
   above = ((height * value + fuz) / total);
   below = ((height) - (ss + above));
 
-  /* Dont' let knob get smaller than SS_MIN */
+  /* Don't let slider get smaller than SS_MIN */
   if (ss < SS_MIN)
     {
       /* add a percent amount for integer rounding */
       float tmp = ((((float) (SS_MIN - ss) * (float) value)) / total) + 0.5;
 
       above -= (int) tmp;
-      ss     = SS_MIN;
+      ss = SS_MIN;
       below = ((height) - (ss + above));
 
       if (above < 0)
@@ -1071,8 +1004,11 @@
   if (w->sb.value < w->sb.minimum)
       w->sb.value = w->sb.minimum;
 
-  if (w->sb.value > w->sb.maximum - w->sb.sliderSize)
-      w->sb.value = w->sb.maximum - w->sb.sliderSize;
+  if (w->sb.value > w->sb.maximum)
+      w->sb.value = w->sb.maximum;
+
+  if (w->sb.sliderSize > w->sb.maximum - w->sb.value)
+      w->sb.sliderSize = w->sb.maximum - w->sb.value;
 }
 
 static int
@@ -1081,8 +1017,9 @@
   float total, height, fuz;
   int value, ss;
 
-  height= widget_h (w);
-  if (w->sb.showArrows) height -= (2 * arrow_h (w));
+  height = widget_h (w);
+  if (w->sb.showArrows)
+    height -= (2 * arrow_h (w));
 
   total = w->sb.maximum - w->sb.minimum;
   fuz = height / 2;
@@ -1114,23 +1051,13 @@
 redraw_dimple (XlwScrollBarWidget w, Display *dpy, Window win,
 	       int x, int y, int width, int height)
 {
-  GC shine, shadow;
-  int shadowT, size;
-
-  if (KNOB_DIMPLE == knob_style (w))
+  if (SLIDER_DIMPLE == slider_style (w))
     {
-      if (w->sb.armed == ARM_KNOB)
-	{
-	  shine  = w->sb.bottomShadowGC;
-	  shadow = w->sb.topShadowGC;
-	}
-      else
-	{
-	  shine  = w->sb.topShadowGC;
-	  shadow = w->sb.bottomShadowGC;
-	}
-
-      shadowT = w->sb.shadowThickness;
+      int size;
+      int slider_p = (w->sb.armed == ARM_SLIDER);
+      GC shine  = slider_p ? w->sb.bottomShadowGC : w->sb.topShadowGC;
+      GC shadow = slider_p ? w->sb.topShadowGC    : w->sb.bottomShadowGC;
+      int shadowT = w->sb.shadowThickness;
 
       x += shadowT;
       y += shadowT;
@@ -1153,59 +1080,58 @@
 }
 
 static void
-draw_knob (XlwScrollBarWidget w, int above, int ss, int below)
+draw_slider (XlwScrollBarWidget w, int above, int ss, int below)
 {
   Display *dpy = XtDisplay ((Widget) w);
   Window   win = XtWindow  ((Widget) w);
-  int x, y, width, height;
-  int shadowT;
 
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
-
-  shadowT = w->sb.shadowThickness;
+  int x       = widget_x (w);
+  int y       = widget_y (w);
+  int width   = widget_w (w);
+  int height  = widget_h (w);
+  int shadowT = w->sb.shadowThickness;
+  int vert_p  = VERT (w);
 
   if (shadowT > (width  / 2)) shadowT = (width  / 2);
   if (shadowT > (height / 2)) shadowT = (height / 2);
-  if (shadowT <= 0) return;
+  if (shadowT < 0)            shadowT = 0;
 
-  if (w->sb.showArrows && !arrow_same_end (w)) y += arrow_h (w);
+  if (w->sb.showArrows && !arrow_same_end (w))
+    y += arrow_h (w);
 
-  /* trough above knob */
+  /* trough above slider */
   if (above > 0)
     {
-      if (VERT (w))
+      if (vert_p)
 	XClearArea (dpy, win, x, y, width, above, False);
       else
 	XClearArea (dpy, win, y, x, above, width, False);
     }
 
-  /* knob */
-  if (VERT (w))
+  /* slider */
+  if (vert_p)
     {
       draw_shadows (dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC,
 		    x, y + above, width, ss, shadowT);
-      XFillRectangle (dpy, win,
-		      w->sb.backgroundGC,
-		      x+shadowT, y + above + shadowT, width-2*shadowT, ss-2*shadowT);
+      XFillRectangle (dpy, win, w->sb.backgroundGC,
+		      x+shadowT, y + above + shadowT,
+		      width-2*shadowT, ss-2*shadowT);
       redraw_dimple (w, dpy, win, x, y + above, width, ss);
     }
   else
     {
       draw_shadows (dpy, win, w->sb.topShadowGC, w->sb.bottomShadowGC,
 		    y + above, x, ss, width, shadowT);
-      XFillRectangle (dpy, win,
-		      w->sb.backgroundGC,
-		      y + above + shadowT, x+shadowT, ss-2*shadowT, width-2*shadowT);
+      XFillRectangle (dpy, win, w->sb.backgroundGC,
+		      y + above + shadowT, x+shadowT,
+		      ss-2*shadowT, width-2*shadowT);
       redraw_dimple (w, dpy, win, y + above, x, ss, width);
     }
 
-  /* trough below knob */
+  /* trough below slider */
   if (below > 0)
     {
-      if (VERT (w))
+      if (vert_p)
 	XClearArea (dpy, win, x, y + above + ss, width, below, False);
       else
 	XClearArea (dpy, win, y + above + ss, x, below, width, False);
@@ -1219,35 +1145,22 @@
 {
   Display *dpy = XtDisplay ((Widget) w);
   Window   win = XtWindow  ((Widget) w);
-  GC bg, shine, shadow;
-  int x, y, width, height, arrow_height, shadowT;
-
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
-  arrow_height = arrow_h (w);
 
-  shadowT = w->sb.shadowThickness;
-  bg      = w->sb.backgroundGC;
+  int x       = widget_x (w);
+  int y       = widget_y (w);
+  int width   = widget_w (w);
+  int height  = widget_h (w);
+  int shadowT = w->sb.shadowThickness;
+  int arrow_height = arrow_h (w);
 
-  if (armed)
-    {
-      shine   = w->sb.bottomShadowGC;
-      shadow  = w->sb.topShadowGC;
-    }
-  else
-    {
-      shine   = w->sb.topShadowGC;
-      shadow  = w->sb.bottomShadowGC;
-    }
+  GC bg     = w->sb.backgroundGC;
+  GC shine  = armed ? w->sb.bottomShadowGC : w->sb.topShadowGC;
+  GC shadow = armed ? w->sb.topShadowGC    : w->sb.bottomShadowGC;
 
   if (VERT (w))
     {
       if (arrow_same_end (w))
-	{
-	  y += height - 2 * arrow_h (w) + 2;
-	}
+	y += height - 2 * arrow_height;
       if (clear_behind)
 	XClearArea (dpy, win, x, y, width, arrow_height + 1, False);
       draw_arrow_up (dpy, win, bg, shine, shadow,
@@ -1257,9 +1170,7 @@
   else
     {
       if (arrow_same_end (w))
-	{
-	  y += height - 2 * arrow_h (w);
-	}
+	y += height - 2 * arrow_height;
       if (clear_behind)
 	XClearArea (dpy, win, y, x, arrow_height + 1, height, False);
       draw_arrow_left (dpy, win, bg, shine, shadow,
@@ -1273,28 +1184,17 @@
 {
   Display *dpy = XtDisplay ((Widget) w);
   Window   win = XtWindow  ((Widget) w);
-  GC bg, shine, shadow;
-  int x, y, width, height, arrow_height, shadowT;
-
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
-  arrow_height = arrow_h (w);
 
-  shadowT = w->sb.shadowThickness;
-  bg      = w->sb.backgroundGC;
+  int x       = widget_x (w);
+  int y       = widget_y (w);
+  int width   = widget_w (w);
+  int height  = widget_h (w);
+  int shadowT = w->sb.shadowThickness;
+  int arrow_height = arrow_h (w);
 
-  if (armed)
-    {
-      shine  = w->sb.bottomShadowGC;
-      shadow = w->sb.topShadowGC;
-    }
-  else
-    {
-      shine  = w->sb.topShadowGC;
-      shadow = w->sb.bottomShadowGC;
-    }
+  GC bg     = w->sb.backgroundGC;
+  GC shine  = armed ? w->sb.bottomShadowGC : w->sb.topShadowGC;
+  GC shadow = armed ? w->sb.topShadowGC    : w->sb.bottomShadowGC;
 
   if (VERT (w))
     {
@@ -1323,48 +1223,49 @@
 {
   Display *dpy = XtDisplay ((Widget) w);
   Window   win = XtWindow  ((Widget) w);
-  int x, y, width, height, shadowT, tmp;
-
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
-  shadowT = w->sb.shadowThickness;
 
   if (w->sb.showArrows)
     {
-      if (region == NULL || XRectInRegion (region, x, y, width, width))
+      if (region == NULL)
 	{
-	  redraw_up_arrow (w, False, behind_arrows);
-	}
-      if (VERT (w))
-	{
-	  y = y + height - width + 1;
+	  redraw_up_arrow   (w, False, behind_arrows);
+	  redraw_down_arrow (w, False, behind_arrows);
 	}
       else
 	{
-	  tmp = y;
-	  y = x;
-	  x = tmp + height - width + 1;
-	}
-      if (region == NULL || XRectInRegion (region, x, y, width, width))
-	{
-	  redraw_down_arrow (w, False, behind_arrows);
+	  int x        = widget_x (w);
+	  int y        = widget_y (w);
+	  int width    = widget_w (w);
+	  int height   = widget_h (w);
+	  int arrow_height = arrow_h (w);
+	  int ax = x, ay = y;
+
+	  if (arrow_same_end (w))
+	    {
+	      if (VERT (w))
+		ay = y + height - arrow_height - arrow_height;
+	      else
+		ax = x + height - arrow_height - arrow_height;
+	    }
+	  if (XRectInRegion (region, ax, ay, width, width))
+	    redraw_up_arrow (w, False, behind_arrows);
+
+	  if (VERT (w))
+	    ay = y + height - arrow_height;
+	  else
+	    ax = x + height - arrow_height;
+	  if (XRectInRegion (region, ax, ay, width, width))
+	    redraw_down_arrow (w, False, behind_arrows);
 	}
     }
 
-  draw_shadows (dpy, win, w->sb.bottomShadowGC, w->sb.topShadowGC,
-		0, 0, w->core.width, w->core.height, shadowT);
+  draw_shadows (dpy, win, w->sb.bottomShadowGC, w->sb.topShadowGC, 0, 0,
+		w->core.width, w->core.height, w->sb.shadowThickness);
 
-  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
-
+  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 }
 
-/************************************************************************
-**
-** Method functions
-**
-*/
+/*-------------------------- Method Functions ---------------------------*/
 
 static void
 Initialize (Widget treq, Widget tnew, ArgList args, Cardinal *num_args)
@@ -1374,8 +1275,6 @@
   Display *dpy = XtDisplay ((Widget) w);
   Window win = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
 
-  DBUG (fprintf (stderr, "Initialize\n"));
-
   if (request->core.width  == 0) w->core.width  += (VERT (w) ? 12 : 25);
   if (request->core.height == 0) w->core.height += (VERT (w) ? 25 : 12);
 
@@ -1386,6 +1285,7 @@
   w->sb.ss    = 0;
   w->sb.below = 0;
   w->sb.armed = ARM_NONE;
+  w->sb.forced_scroll = FORCED_SCROLL_NONE;
 
   if (w->sb.shadowThickness > 5) w->sb.shadowThickness = 5;
 
@@ -1417,8 +1317,6 @@
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
   Display *dpy = XtDisplay ((Widget) w);
 
-  DBUG (fprintf (stderr, "Destroy\n"));
-
   XtReleaseGC (widget, w->sb.bottomShadowGC);
   XtReleaseGC (widget, w->sb.topShadowGC);
   XtReleaseGC (widget, w->sb.backgroundGC);
@@ -1426,7 +1324,10 @@
   XFreePixmap (dpy, w->sb.grayPixmap);
 
   if (w->sb.timerActive)
-    XtRemoveTimeOut (w->sb.timerId);
+    {
+      XtRemoveTimeOut (w->sb.timerId);
+      w->sb.timerActive = False; /* Should be a no-op, but you never know */
+    }
 }
 
 static void
@@ -1437,8 +1338,6 @@
   Window win;
   XSetWindowAttributes win_attr;
 
-  DBUG (fprintf (stderr, "Realize\n"));
-
   (*coreClassRec.core_class.realize)(widget, valuemask, attr);
 
   win = XtWindow ((Widget) w);
@@ -1448,7 +1347,7 @@
   XSetWindowBackground (dpy, win, w->sb.troughColor);
 
   /* Change bit gravity so widget is not cleared on resize */
-  win_attr.bit_gravity   = NorthWestGravity;
+  win_attr.bit_gravity = NorthWestGravity;
   XChangeWindowAttributes (dpy, win, CWBitGravity , &win_attr);
 
 }
@@ -1466,11 +1365,17 @@
 
       seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
 
-      /*redraw_everything(w, NULL, True);*/
+      /* redraw_everything (w, NULL, True); */
 
       w->sb.fullRedrawNext = True;
       /* Force expose event */
-      XClearArea (dpy, win, widget_x(w), widget_y(w), 1, 1, True);
+      XClearArea (dpy, win, widget_x (w), widget_y (w), 1, 1, True);
+    }
+
+  if (w->sb.timerActive)
+    {
+      XtRemoveTimeOut (w->sb.timerId);
+      w->sb.timerActive = False;
     }
 }
 
@@ -1484,13 +1389,9 @@
   if (XtIsRealized (widget))
     {
       if (w->sb.fullRedrawNext)
-	{
-	  redraw_everything (w, NULL, True);
-	}
+	redraw_everything (w, NULL, True);
       else
-	{
-	  redraw_everything (w, region, False);
-	}
+	redraw_everything (w, region, False);
       w->sb.fullRedrawNext = False;
     }
 }
@@ -1542,9 +1443,7 @@
     }
 
   if (cur->sb.orientation != w->sb.orientation)
-    {
-      do_redisplay = True;
-    }
+    do_redisplay = True;
 
 
   if (cur->sb.minimum       != w->sb.minimum       ||
@@ -1558,7 +1457,7 @@
       if (XtIsRealized ((Widget) w))
 	{
 	  seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+	  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 	}
     }
 
@@ -1587,7 +1486,6 @@
 		       int increment, int pageIncrement, Boolean notify)
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
-  int last_value;
 
   if (w && XtClass ((Widget) w) == xlwScrollBarWidgetClass &&
       (w->sb.value         != value         ||
@@ -1595,6 +1493,8 @@
        w->sb.increment     != increment     ||
        w->sb.pageIncrement != pageIncrement))
     {
+      int last_value = w->sb.value;
+      
       w->sb.value         = value;
       w->sb.sliderSize    = sliderSize;
       w->sb.increment     = increment;
@@ -1605,55 +1505,43 @@
       if (XtIsRealized (widget))
 	{
 	  seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
-
-	  last_value  = w->sb.value;
-	  w->sb.value = value_from_pixel (w, w->sb.above);
-	  verify_values (w);
+	  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 
 	  if (w->sb.value != last_value && notify)
-	    {
-	      call_callbacks (w, XmCR_VALUE_CHANGED, w->sb.value, 0, NULL);
-	    }
+	    call_callbacks (w, XmCR_VALUE_CHANGED, w->sb.value, 0, NULL);
 	}
     }
 }
 
-/************************************************************************
-**
-** Action functions
-**
-*/
+/*-------------------------- Action Functions ---------------------------*/
 
 static void
 timer (XtPointer data, XtIntervalId *id)
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) data;
-  int reason, last_value;
-  
   w->sb.timerActive = False;
 
   if (w->sb.armed != ARM_NONE)
     {
-      last_value = w->sb.value;
-      reason     = XmCR_NONE;
+      int last_value = w->sb.value;
+      int reason     = XmCR_NONE;
 
       switch (w->sb.armed)
 	{
 	case ARM_PAGEUP:
-	  w->sb.value = safe_subtract (w->sb.value, w->sb.pageIncrement);
+	  decrement_value (w, w->sb.pageIncrement);
 	  reason = XmCR_PAGE_DECREMENT;
 	  break;
 	case ARM_PAGEDOWN:
-	  w->sb.value = safe_add (w->sb.value, w->sb.pageIncrement);
+	  increment_value (w, w->sb.pageIncrement);
 	  reason = XmCR_PAGE_INCREMENT;
 	  break;
 	case ARM_UP:
-	  w->sb.value = safe_subtract (w->sb.value, w->sb.increment);
+	  decrement_value (w, w->sb.increment);
 	  reason = XmCR_DECREMENT;
 	  break;
 	case ARM_DOWN:
-	  w->sb.value = safe_add (w->sb.value, w->sb.increment);
+	  increment_value (w, w->sb.increment);
 	  reason = XmCR_INCREMENT;
 	  break;
 	}
@@ -1663,7 +1551,7 @@
       if (last_value != w->sb.value)
 	{
 	  seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+	  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 
 	  call_callbacks (w, reason, w->sb.value, 0, NULL);
 
@@ -1676,180 +1564,97 @@
     }
 }
 
-static int
+static button_where
 what_button (XlwScrollBarWidget w, int mouse_x, int mouse_y)
 {
-  int x, y, width, height, arrow_height_top, arrow_height_bottom;
-  int where;
+  int width   = widget_w (w);
+  int height  = widget_h (w);
+  int arrow_height = arrow_h (w);
 
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
+  mouse_x -= widget_x (w);
+  mouse_y -= widget_y (w);
 
-#if 0
-  arrow_height = w->sb.showArrows ? arrow_h (w) : 0;
-#endif
+  if (mouse_x < 0 || mouse_x >= width ||
+      mouse_y < 0 || mouse_y >= height)
+    return BUTTON_NONE;
+
   if (w->sb.showArrows)
     {
+      if (mouse_y >= (height -= arrow_height))
+	return BUTTON_DOWN_ARROW;
+      
       if (arrow_same_end (w))
 	{
-	  arrow_height_top = 0;
-	  arrow_height_bottom = 2 * arrow_h (w);
+	  if (mouse_y >= (height -= arrow_height))
+	    return BUTTON_UP_ARROW;
 	}
       else
-	{
-	  arrow_height_top = arrow_height_bottom = arrow_h (w);
-	}
+	if ( (mouse_y -= arrow_height) < 0)
+	  return BUTTON_UP_ARROW;
     }
-  else
-    {
-      arrow_height_top = arrow_height_bottom = 0;
-    }
-
-  where = BUTTON_NONE;
+  
+  if ( (mouse_y -= w->sb.above) < 0)
+    return BUTTON_TROUGH_ABOVE;
 
-  if (mouse_x > x && mouse_x < (x + width))
-    {
-      if (mouse_y > (y + arrow_height_top) &&
-	  mouse_y < (y + height - arrow_height_bottom))
-	{
-	  if (mouse_y < (y + w->sb.above + arrow_height_top))
-	    {
-	      where = BUTTON_TROUGH_ABOVE;
-	    }
-	  else if (mouse_y > (y + w->sb.above + w->sb.ss + arrow_height_top))
-	    {
-	      where = BUTTON_TROUGH_BELOW;
-	    }
-	  else
-	    {
-	      where = BUTTON_KNOB;
-	    }
-	}
-      else if (arrow_same_end (w))
-	{
-	  if (mouse_y > (y + height - arrow_height_bottom + 1) &&
-	      mouse_y < (y + height))
-	    {
-	      if (mouse_y < (y + height - arrow_height_bottom/2))
-		{
-		  where = BUTTON_UP_ARROW;
-		}
-	      else
-		{
-		  where = BUTTON_DOWN_ARROW;
-		}
-	    }
-	}
-      else
-	{
-	  if (mouse_y > y && mouse_y < (y + arrow_height_top))
-	    {
-	      where = BUTTON_UP_ARROW;
-	    }
-	  else if (mouse_y > (y + height - arrow_height_bottom + 1) &&
-		   mouse_y < (y + height))
-	    {
-	      where = BUTTON_DOWN_ARROW;
-	    }
-	}
-    }
-#if 0
-  if (mouse_x > x && mouse_x < (x + width))
-    {
-      if (mouse_y > (y + arrow_height) && mouse_y < (y + height - arrow_height))
-	{
-	  if (mouse_y < (y+w->sb.above+arrow_height))
-	    {
-	      where = BUTTON_TROUGH_ABOVE;
-	    }
-	  else if (mouse_y > (y + w->sb.above + w->sb.ss + arrow_height))
-	    {
-	      where = BUTTON_TROUGH_BELOW;
-	    }
-	  else
-	    {
-	      where = BUTTON_KNOB;
-	    }
-	}
-      else if (mouse_y > y && mouse_y < (y + arrow_height))
-	{
-	  where = BUTTON_UP_ARROW;
-	}
-      else if (mouse_y > (y + height - arrow_height + 1) &&
-	       mouse_y < (y + height))
-	{
-	  where = BUTTON_DOWN_ARROW;
-	}
-    }
-#endif
-  return where;
+  if ( (mouse_y -= w->sb.ss) < 0)
+    return BUTTON_SLIDER;
+
+  return BUTTON_TROUGH_BELOW;
 }
 
-#define FORCED_SCROLL_NONE	0
-#define FORCED_SCROLL_DOWNRIGHT	1
-#define FORCED_SCROLL_UPLEFT	2
-
-int forced_scroll_flag = FORCED_SCROLL_NONE;
-
 static void
 PageDownOrRight (Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
 {
-  forced_scroll_flag = FORCED_SCROLL_DOWNRIGHT;
+  XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
+  w->sb.forced_scroll = FORCED_SCROLL_DOWNRIGHT;
   Select (widget, event, parms, num_parms);
-  forced_scroll_flag = FORCED_SCROLL_NONE;
+  w->sb.forced_scroll = FORCED_SCROLL_NONE;
 }
 
 static void
 PageUpOrLeft (Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
 {
-  forced_scroll_flag = FORCED_SCROLL_UPLEFT;
+  XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
+  w->sb.forced_scroll = FORCED_SCROLL_UPLEFT;
   Select (widget, event, parms, num_parms);
-  forced_scroll_flag = FORCED_SCROLL_NONE;
+  w->sb.forced_scroll = FORCED_SCROLL_NONE;
 }
 
 static void
 Select (Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
-  int mouse_x, mouse_y;
-  int reason, last_value;
-  int sb_button;
-
-  DBUG (fprintf (stderr, "Select:\n"));
+  button_where sb_button;
 
-  mouse_x = event_x (w, event);
-  mouse_y = event_y (w, event);
+  int mouse_x = event_x (w, event);
+  int mouse_y = event_y (w, event);
 
-  w->sb.savedValue = w->sb.value;
-
-  last_value = w->sb.value;
-  reason     = XmCR_NONE;
+  int last_value = w->sb.savedValue = w->sb.value;
+  int reason     = XmCR_NONE;
 
   XtGrabKeyboard ((Widget) w, False, GrabModeAsync, GrabModeAsync,
 		  event->xbutton.time);
 
   sb_button = what_button (w, mouse_x, mouse_y);
 
-  if (forced_scroll_flag != FORCED_SCROLL_NONE)
+  if (w->sb.forced_scroll != FORCED_SCROLL_NONE)
     {
-      switch  (sb_button)
+      switch (sb_button)
 	{
 	case BUTTON_TROUGH_ABOVE:
 	case BUTTON_TROUGH_BELOW:
-	case BUTTON_KNOB:
+	case BUTTON_SLIDER:
 	  sb_button= BUTTON_NONE; /* cause next switch to fall through */
-	  if (forced_scroll_flag == FORCED_SCROLL_UPLEFT)
+	  if (w->sb.forced_scroll == FORCED_SCROLL_UPLEFT)
 	    {
-	      w->sb.value = safe_subtract (w->sb.value, w->sb.pageIncrement);
+	      decrement_value (w, w->sb.pageIncrement);
 	      w->sb.armed = ARM_PAGEUP;
 	      reason      = XmCR_PAGE_DECREMENT;
 	      break;
 	    }
-	  else if (forced_scroll_flag == FORCED_SCROLL_DOWNRIGHT)
+	  else if (w->sb.forced_scroll == FORCED_SCROLL_DOWNRIGHT)
 	    {
-	      w->sb.value = safe_add (w->sb.value, w->sb.pageIncrement);
+	      increment_value (w, w->sb.pageIncrement);
 	      w->sb.armed = ARM_PAGEDOWN;
 	      reason      = XmCR_PAGE_INCREMENT;
 	      break;
@@ -1861,48 +1666,46 @@
   switch (sb_button)
     {
     case BUTTON_TROUGH_ABOVE:
-      w->sb.value = safe_subtract (w->sb.value, w->sb.pageIncrement);
+      decrement_value (w, w->sb.pageIncrement);
       w->sb.armed = ARM_PAGEUP;
       reason      = XmCR_PAGE_DECREMENT;
       break;
     case BUTTON_TROUGH_BELOW:
-      w->sb.value = safe_add (w->sb.value, w->sb.pageIncrement);
+      increment_value (w, w->sb.pageIncrement);
       w->sb.armed = ARM_PAGEDOWN;
       reason      = XmCR_PAGE_INCREMENT;
       break;
-    case BUTTON_KNOB:
+    case BUTTON_SLIDER:
       w->sb.lastY = mouse_y;
-      w->sb.armed = ARM_KNOB;
-      draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+      w->sb.armed = ARM_SLIDER;
+      draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
       break;
     case BUTTON_UP_ARROW:
       if (event->xbutton.state & ControlMask)
 	{
-	  w->sb.value = INT_MIN;
-	  w->sb.armed = ARM_UP;
+	  w->sb.value = w->sb.minimum;
 	  reason      = XmCR_TO_TOP;
 	}
       else
 	{
-	  w->sb.value = safe_subtract (w->sb.value, w->sb.increment);
-	  w->sb.armed = ARM_UP;
+	  decrement_value (w, w->sb.increment);
 	  reason      = XmCR_DECREMENT;
 	}
+      w->sb.armed = ARM_UP;
       redraw_up_arrow (w, True, False);
       break;
     case BUTTON_DOWN_ARROW:
       if (event->xbutton.state & ControlMask)
 	{
-	  w->sb.value = INT_MAX;
-	  w->sb.armed = ARM_DOWN;
+	  w->sb.value = w->sb.maximum;
 	  reason      = XmCR_TO_BOTTOM;
 	}
       else
 	{
-	  w->sb.value = safe_add (w->sb.value, w->sb.increment);
-	  w->sb.armed = ARM_DOWN;
+	  increment_value (w, w->sb.increment);
 	  reason      = XmCR_INCREMENT;
 	}
+      w->sb.armed = ARM_DOWN;
       redraw_down_arrow (w, True, False);
       break;
     }
@@ -1912,7 +1715,7 @@
   if (last_value != w->sb.value)
     {
       seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
-      draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+      draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 	  
       call_callbacks (w, reason, w->sb.value, mouse_y, event);
 
@@ -1933,56 +1736,29 @@
 Drag (Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
-  int diff;
-  int height, mouse_y;
-  int last_value, last_above;
 
-  DBUG (fprintf (stderr, "Drag:\n"));
-
-  if (w->sb.armed == ARM_KNOB)
+  if (w->sb.armed == ARM_SLIDER)
     {
-      height  = widget_h (w);
-      if (w->sb.showArrows) height -= (2 * arrow_h (w));
-
-      mouse_y = event_y (w, event);
+      int mouse_y = event_y (w, event);
+      int diff    = mouse_y - w->sb.lastY;
 
-      diff = mouse_y - w->sb.lastY;
-
-      last_above = w->sb.above;
-      last_value = w->sb.value;
-
-      if (diff < 0)
+      if (diff < -(w->sb.above)) /* up */
 	{
-	  /* up */
-	  w->sb.above -= (-diff);
-	  if (w->sb.above < 0)
-	    {
-	      mouse_y = (mouse_y - w->sb.above);
-	      w->sb.above = 0;
-	      diff = 0;
-	      w->sb.below = height - w->sb.ss;
-	    }
-	  w->sb.below -= diff;
-	  CHECK (w);
+	  mouse_y -= (diff + w->sb.above);
+	  diff = -(w->sb.above);
 	}
-      else if (diff > 0)
+      else if (diff > w->sb.below) /* down */
 	{
-	  /* down */
-	  w->sb.above += diff;
-	  if (w->sb.above + w->sb.ss > height)
-	    {
-	      mouse_y = height + (mouse_y - (w->sb.above + w->sb.ss));
-	      w->sb.above = height - w->sb.ss;
-	      diff = 0;
-	      w->sb.below = 0;
-	    }
-	  w->sb.below -= diff;
-	  CHECK (w);
+	  mouse_y -= (diff - w->sb.below);
+	  diff = w->sb.below;
 	}
 
-      if (last_above != w->sb.above)
+      if (diff)
 	{
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+	  w->sb.above += diff;
+	  w->sb.below -= diff;
+
+	  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 
 	  w->sb.lastY = mouse_y;
 
@@ -1990,8 +1766,7 @@
 	  verify_values (w);
 	  CHECK (w);
 
-	  if (w->sb.value != last_value)
-	    call_callbacks (w, XmCR_DRAG, w->sb.value, event_y (w, event), event);
+	  call_callbacks (w, XmCR_DRAG, w->sb.value, event_y (w, event), event);
 	}
     }
   CHECK (w);
@@ -2002,14 +1777,12 @@
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
 
-  DBUG (fprintf (stderr, "EndDrag:\n"));
-
   switch (w->sb.armed)
     {
-    case ARM_KNOB:
+    case ARM_SLIDER:
       call_callbacks (w, XmCR_VALUE_CHANGED, w->sb.value, event_y (w, event), event);
       w->sb.armed = ARM_NONE;
-      draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+      draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
       break;
     case ARM_UP:
       redraw_up_arrow (w, False, False);
@@ -2028,21 +1801,21 @@
 Jump (Widget widget, XEvent *event, String *parms, Cardinal *num_parms)
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
-  int x, y, width, height, mouse_x, mouse_y;
-  int arrow_height;
-  int last_above, last_value;
+  int last_value;
 
-  DBUG (fprintf (stderr, "Jump:\n"));
+  int mouse_x = event_x (w, event);
+  int mouse_y = event_y (w, event);
 
-  x       = widget_x (w);
-  y       = widget_y (w);
-  width   = widget_w (w);
-  height  = widget_h (w);
+  int scroll_region_y = widget_y (w);
+  int scroll_region_h = widget_h (w);
   
-  mouse_x = event_x (w, event);
-  mouse_y = event_y (w, event);
-
-  arrow_height = w->sb.showArrows ? arrow_h (w) : 0;
+  if (w->sb.showArrows)
+    {
+      int arrow_height = arrow_h (w);
+      scroll_region_h -= 2 * arrow_height;
+      if (!arrow_same_end (w))
+	scroll_region_y += arrow_height;
+    }
 
   XtGrabKeyboard ((Widget) w, False, GrabModeAsync, GrabModeAsync,
 		  event->xbutton.time);
@@ -2051,45 +1824,31 @@
     {
     case BUTTON_TROUGH_ABOVE:
     case BUTTON_TROUGH_BELOW:
-    case BUTTON_KNOB:
+    case BUTTON_SLIDER:
       w->sb.savedValue = w->sb.value;
 
-      height -= (2*arrow_height);
-      y      += arrow_height;
-
-      last_above = w->sb.above;
       last_value = w->sb.value;
 
-      w->sb.armed = ARM_KNOB;
-      draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
-
-      w->sb.above = mouse_y - (w->sb.ss / 2) - arrow_height;
+      w->sb.above = mouse_y - (w->sb.ss / 2) - scroll_region_y;
       if (w->sb.above < 0)
-	{
-	  w->sb.above = 0;
-	}
-      else if (w->sb.above + w->sb.ss > height)
-	{
-	  w->sb.above = height - w->sb.ss;
-	}
-      w->sb.below = (height - (w->sb.ss + w->sb.above));
+	w->sb.above = 0;
+      else if (w->sb.above + w->sb.ss > scroll_region_h) 
+	w->sb.above = scroll_region_h - w->sb.ss;
+
+      w->sb.below = scroll_region_h - w->sb.ss - w->sb.above;
 
-      if (last_above != w->sb.above)
-	{
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
-
-	  w->sb.value = value_from_pixel (w, w->sb.above);
-	  verify_values (w);
-	  CHECK (w);
+      w->sb.armed = ARM_SLIDER;
+      draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 
-	  w->sb.lastY = mouse_y;
-	  w->sb.lastY = w->sb.above + arrow_height + (w->sb.ss / 2);
+      w->sb.value = value_from_pixel (w, w->sb.above);
+      verify_values (w);
+      CHECK (w);
 
-	  if (w->sb.value != last_value)
-	    {
-	      call_callbacks (w, XmCR_DRAG, w->sb.value, event_y (w, event), event);
-	    }
-	}
+      w->sb.lastY = mouse_y;
+
+      if (w->sb.value != last_value)
+	call_callbacks (w, XmCR_DRAG, w->sb.value, mouse_y, event);
+      
       break;
     }
   CHECK (w);
@@ -2100,8 +1859,6 @@
 {
   XlwScrollBarWidget w = (XlwScrollBarWidget) widget;
 
-  DBUG (fprintf (stderr, "Abort:\n"));
-
   if (w->sb.armed != ARM_NONE)
     {
       if (w->sb.value != w->sb.savedValue)
@@ -2109,7 +1866,7 @@
 	  w->sb.value = w->sb.savedValue;
 
 	  seg_pixel_sizes (w, &w->sb.above, &w->sb.ss, &w->sb.below);
-	  draw_knob (w, w->sb.above, w->sb.ss, w->sb.below);
+	  draw_slider (w, w->sb.above, w->sb.ss, w->sb.below);
 
 	  call_callbacks (w, XmCR_VALUE_CHANGED, w->sb.value,
 			  event_y (w, event), event);