aboutsummaryrefslogtreecommitdiff
path: root/libXaw/src/Scrollbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'libXaw/src/Scrollbar.c')
-rw-r--r--libXaw/src/Scrollbar.c1764
1 files changed, 882 insertions, 882 deletions
diff --git a/libXaw/src/Scrollbar.c b/libXaw/src/Scrollbar.c
index 777043063..6413f0bf6 100644
--- a/libXaw/src/Scrollbar.c
+++ b/libXaw/src/Scrollbar.c
@@ -1,882 +1,882 @@
-/***********************************************************
-
-Copyright 1987, 1988, 1994, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-
-Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Digital not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-******************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/Xmu/Drawing.h>
-#include <X11/Xaw/ScrollbarP.h>
-#include <X11/Xaw/XawInit.h>
-#include "Private.h"
-
-#define NoButton -1
-#define PICKLENGTH(widget, x, y) \
-(((widget)->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
-
-/*
- * Class Methods
- */
-static void XawScrollbarClassInitialize(void);
-static void XawScrollbarDestroy(Widget);
-static void XawScrollbarInitialize(Widget, Widget, ArgList, Cardinal*_args);
-static void XawScrollbarRealize(Widget, Mask*, XSetWindowAttributes*);
-static void XawScrollbarRedisplay(Widget, XEvent*, Region);
-static void XawScrollbarResize(Widget);
-static Boolean XawScrollbarSetValues(Widget, Widget, Widget,
- ArgList, Cardinal*);
-
-/*
- * Prototypes
- */
-static Boolean CompareEvents(XEvent*, XEvent*);
-static void CreateGC(Widget);
-static float FloatInRange(float, float, float);
-static float FractionLoc(ScrollbarWidget, int, int);
-static void ExtractPosition(XEvent*, Position*, Position*);
-static int InRange(int, int, int);
-static void FillArea(ScrollbarWidget, int, int, int);
-static Bool LookAhead(Widget, XEvent*);
-static void PaintThumb(ScrollbarWidget);
-static Bool PeekNotifyEvent(Display*, XEvent*, char*);
-static void SetDimensions(ScrollbarWidget);
-
-/*
- * Actions
- */
-static void EndScroll(Widget, XEvent*, String*, Cardinal*);
-static void MoveThumb(Widget, XEvent*, String*, Cardinal*);
-static void NotifyScroll(Widget, XEvent*, String*, Cardinal*);
-static void NotifyThumb(Widget, XEvent*, String*, Cardinal*);
-static void StartScroll(Widget, XEvent*, String*, Cardinal*);
-
-/*
- * Initialization
- */
-static char defaultTranslations[] =
-"<Btn1Down>:" "StartScroll(Forward)\n"
-"<Btn2Down>:" "StartScroll(Continuous) MoveThumb() NotifyThumb()\n"
-"<Btn3Down>:" "StartScroll(Backward)\n"
-"<Btn2Motion>:" "MoveThumb() NotifyThumb()\n"
-"<BtnUp>:" "NotifyScroll(Proportional) EndScroll()\n";
-
-static float floatZero = 0.0;
-
-#define Offset(field) XtOffsetOf(ScrollbarRec, field)
-
-static XtResource resources[] = {
- {
- XtNlength,
- XtCLength,
- XtRDimension,
- sizeof(Dimension),
- Offset(scrollbar.length),
- XtRImmediate,
- (XtPointer)1
- },
- {
- XtNthickness,
- XtCThickness,
- XtRDimension,
- sizeof(Dimension),
- Offset(scrollbar.thickness),
- XtRImmediate,
- (XtPointer)14
- },
- {
- XtNorientation,
- XtCOrientation,
- XtROrientation,
- sizeof(XtOrientation),
- Offset(scrollbar.orientation),
- XtRImmediate,
- (XtPointer)XtorientVertical
- },
- {
- XtNscrollProc,
- XtCCallback,
- XtRCallback,
- sizeof(XtPointer),
- Offset(scrollbar.scrollProc),
- XtRCallback,
- NULL
- },
- {
- XtNthumbProc,
- XtCCallback,
- XtRCallback,
- sizeof(XtPointer),
- Offset(scrollbar.thumbProc),
- XtRCallback,
- NULL
- },
- {
- XtNjumpProc,
- XtCCallback,
- XtRCallback,
- sizeof(XtPointer),
- Offset(scrollbar.jumpProc),
- XtRCallback,
- NULL
- },
- {
- XtNthumb,
- XtCThumb,
- XtRBitmap,
- sizeof(Pixmap),
- Offset(scrollbar.thumb),
- XtRImmediate,
- (XtPointer)XtUnspecifiedPixmap
- },
- {
- XtNforeground,
- XtCForeground,
- XtRPixel,
- sizeof(Pixel),
- Offset(scrollbar.foreground),
- XtRString,
- XtDefaultForeground
- },
- {
- XtNshown,
- XtCShown,
- XtRFloat,
- sizeof(float),
- Offset(scrollbar.shown),
- XtRFloat,
- (XtPointer)&floatZero
- },
- {
- XtNtopOfThumb,
- XtCTopOfThumb,
- XtRFloat,
- sizeof(float),
- Offset(scrollbar.top),
- XtRFloat,
- (XtPointer)&floatZero
- },
- {
- XtNscrollVCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.verCursor),
- XtRString,
- "sb_v_double_arrow"
- },
- {
- XtNscrollHCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.horCursor),
- XtRString,
- "sb_h_double_arrow"
- },
- {
- XtNscrollUCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.upCursor),
- XtRString,
- "sb_up_arrow"
- },
- {
- XtNscrollDCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.downCursor),
- XtRString,
- "sb_down_arrow"
- },
- {
- XtNscrollLCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.leftCursor),
- XtRString,
- "sb_left_arrow"
- },
- {
- XtNscrollRCursor,
- XtCCursor,
- XtRCursor,
- sizeof(Cursor),
- Offset(scrollbar.rightCursor),
- XtRString,
- "sb_right_arrow"
- },
- {
- XtNminimumThumb,
- XtCMinimumThumb,
- XtRDimension,
- sizeof(Dimension),
- Offset(scrollbar.min_thumb),
- XtRImmediate,
- (XtPointer)7
- },
-};
-#undef Offset
-
-static XtActionsRec actions[] = {
- {"StartScroll", StartScroll},
- {"MoveThumb", MoveThumb},
- {"NotifyThumb", NotifyThumb},
- {"NotifyScroll", NotifyScroll},
- {"EndScroll", EndScroll},
-};
-
-#define Superclass (&simpleClassRec)
-ScrollbarClassRec scrollbarClassRec = {
- /* core */
- {
- (WidgetClass)&simpleClassRec, /* superclass */
- "Scrollbar", /* class_name */
- sizeof(ScrollbarRec), /* widget_size */
- XawScrollbarClassInitialize, /* class_initialize */
- NULL, /* class_part_init */
- False, /* class_inited */
- XawScrollbarInitialize, /* initialize */
- NULL, /* initialize_hook */
- XawScrollbarRealize, /* realize */
- actions, /* actions */
- XtNumber(actions), /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- True, /* compress_motion */
- True, /* compress_exposure */
- True, /* compress_enterleave */
- False, /* visible_interest */
- XawScrollbarDestroy, /* destroy */
- XawScrollbarResize, /* resize */
- XawScrollbarRedisplay, /* expose */
- XawScrollbarSetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- defaultTranslations, /* tm_table */
- XtInheritQueryGeometry, /* query_geometry */
- XtInheritDisplayAccelerator, /* display_accelerator */
- NULL, /* extension */
- },
- /* simple */
- {
- XtInheritChangeSensitive, /* change_sensitive */
- },
- /* scrollbar */
- {
- NULL, /* extension */
- },
-};
-
-WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
-
-/*
- * Implementation
- */
-static void
-XawScrollbarClassInitialize(void)
-{
- XawInitializeWidgetSet();
- XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
- NULL, 0);
- XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString,
- NULL, 0, XtCacheNone, NULL);
-}
-
-/*
- * Make sure the first number is within the range specified by the other
- * two numbers.
- */
-static int
-InRange(int num, int small, int big)
-{
- return ((num < small) ? small : ((num > big) ? big : num));
-}
-
-/*
- * Same as above, but for floating numbers
- */
-static float
-FloatInRange(float num, float small, float big)
-{
- return ((num < small) ? small : ((num > big) ? big : num));
-}
-
-/* Fill the area specified by top and bottom with the given pattern */
-static float
-FractionLoc(ScrollbarWidget w, int x, int y)
-{
- float result;
-
- result = PICKLENGTH(w, x / (float)XtWidth(w), y / (float)XtHeight(w));
-
- return (FloatInRange(result, 0.0, 1.0));
-}
-
-static void
-FillArea(ScrollbarWidget w, int top, int bottom, int thumb)
-{
- Dimension length;
-
- top = XawMax(1, top);
- if (w->scrollbar.orientation == XtorientHorizontal)
- bottom = XawMin(bottom, XtWidth(w) - 1);
- else
- bottom = XawMin(bottom, XtHeight(w) - 1);
-
- if (bottom <= top)
- return;
-
- length = bottom - top;
-
- switch(thumb) {
- /* Fill the new Thumb location */
- case 1:
- if (w->scrollbar.orientation == XtorientHorizontal)
- XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
- top, 1, length, XtHeight(w) - 2);
- else
- XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
- 1, top, XtWidth(w) - 2, length);
- break;
- /* Clear the old Thumb location */
- case 0:
- if (w->scrollbar.orientation == XtorientHorizontal)
- XClearArea(XtDisplay(w), XtWindow(w),
- top, 1, length, XtHeight(w) - 2, False);
- else
- XClearArea(XtDisplay(w), XtWindow(w),
- 1, top, XtWidth(w) - 2, length, False);
- break;
- }
-}
-
-
-/* Paint the thumb in the area specified by w->top and
- w->shown. The old area is erased. The painting and
- erasing is done cleverly so that no flickering will occur. */
-static void
-PaintThumb(ScrollbarWidget w)
-{
- Position oldtop, oldbot, newtop, newbot;
-
- oldtop = w->scrollbar.topLoc;
- oldbot = oldtop + w->scrollbar.shownLength;
- newtop = w->scrollbar.length * w->scrollbar.top;
- newbot = newtop + (int)(w->scrollbar.length * w->scrollbar.shown);
- if (newbot < newtop + (int)w->scrollbar.min_thumb)
- newbot = newtop + w->scrollbar.min_thumb;
- w->scrollbar.topLoc = newtop;
- w->scrollbar.shownLength = newbot - newtop;
-
- if (XtIsRealized((Widget)w)) {
- if (newtop < oldtop)
- FillArea(w, newtop, XawMin(newbot, oldtop), 1);
- if (newtop > oldtop)
- FillArea(w, oldtop, XawMin(newtop, oldbot), 0);
- if (newbot < oldbot)
- FillArea(w, XawMax(newbot, oldtop), oldbot, 0);
- if (newbot > oldbot)
- FillArea(w, XawMax(newtop, oldbot), newbot, 1);
- }
-}
-
-static void
-SetDimensions(ScrollbarWidget w)
-{
- if (w->scrollbar.orientation == XtorientVertical) {
- w->scrollbar.length = XtHeight(w);
- w->scrollbar.thickness = XtWidth(w);
- }
- else {
- w->scrollbar.length = XtWidth(w);
- w->scrollbar.thickness = XtHeight(w);
- }
-}
-
-static void
-XawScrollbarDestroy(Widget w)
-{
- ScrollbarWidget sbw = (ScrollbarWidget)w;
-
- XtReleaseGC(w, sbw->scrollbar.gc);
-}
-
-static void
-CreateGC(Widget w)
-{
- ScrollbarWidget sbw = (ScrollbarWidget)w;
- XGCValues gcValues;
- XtGCMask mask;
- unsigned int depth = 1;
-
- if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
- sbw->scrollbar.thumb = XmuCreateStippledPixmap(XtScreen(w),
- (Pixel)1, (Pixel)0,
- depth);
- else if (sbw->scrollbar.thumb != None) {
- Window root;
- int x, y;
- unsigned int width, height, bw;
-
- XGetGeometry(XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
- &width, &height, &bw, &depth);
- }
-
- gcValues.foreground = sbw->scrollbar.foreground;
- gcValues.background = sbw->core.background_pixel;
- mask = GCForeground | GCBackground;
-
- if (sbw->scrollbar.thumb != None) {
- if (depth == 1) {
- gcValues.fill_style = FillOpaqueStippled;
- gcValues.stipple = sbw->scrollbar.thumb;
- mask |= GCFillStyle | GCStipple;
- }
- else {
- gcValues.fill_style = FillTiled;
- gcValues.tile = sbw->scrollbar.thumb;
- mask |= GCFillStyle | GCTile;
- }
- }
- sbw->scrollbar.gc = XtGetGC(w, mask, &gcValues);
-}
-
-/* ARGSUSED */
-static void
-XawScrollbarInitialize(Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- ScrollbarWidget w = (ScrollbarWidget)cnew;
-
- CreateGC(cnew);
-
- if (XtWidth(w) == 0)
- XtWidth(w) = w->scrollbar.orientation == XtorientVertical ?
- w->scrollbar.thickness : w->scrollbar.length;
-
- if (XtHeight(w) == 0)
- XtHeight(w) = w->scrollbar.orientation == XtorientHorizontal ?
- w->scrollbar.thickness : w->scrollbar.length;
-
- SetDimensions(w);
- w->scrollbar.direction = 0;
- w->scrollbar.topLoc = 0;
- w->scrollbar.shownLength = w->scrollbar.min_thumb;
-}
-
-static void
-XawScrollbarRealize(Widget gw, Mask *valueMask,
- XSetWindowAttributes *attributes)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
-
- w->scrollbar.inactiveCursor = w->scrollbar.orientation == XtorientVertical ?
- w->scrollbar.verCursor : w->scrollbar.horCursor;
-
- XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
-
- /*
- * The Simple widget actually stuffs the value in the valuemask
- */
- (*scrollbarWidgetClass->core_class.superclass->core_class.realize)
- (gw, valueMask, attributes);
-}
-
-/*ARGSUSED*/
-static Boolean
-XawScrollbarSetValues(Widget current, Widget request, Widget desired,
- ArgList args, Cardinal *num_args)
-{
- ScrollbarWidget w = (ScrollbarWidget)current;
- ScrollbarWidget dw = (ScrollbarWidget)desired;
- Boolean redraw = False;
-
- /*
- * If these values are outside the acceptable range ignore them...
- */
- if (dw->scrollbar.top < 0.0 || dw->scrollbar.top > 1.0)
- dw->scrollbar.top = w->scrollbar.top;
-
- if (dw->scrollbar.shown < 0.0 || dw->scrollbar.shown > 1.0)
- dw->scrollbar.shown = w->scrollbar.shown;
-
- if (XtIsRealized (desired)) {
- if (w->scrollbar.foreground != dw->scrollbar.foreground ||
- w->core.background_pixel != dw->core.background_pixel ||
- w->scrollbar.thumb != dw->scrollbar.thumb) {
- XtReleaseGC((Widget)dw, w->scrollbar.gc);
- CreateGC((Widget)dw);
- redraw = True;
- }
- if (w->scrollbar.top != dw->scrollbar.top ||
- w->scrollbar.shown != dw->scrollbar.shown)
- redraw = True;
- }
-
- return (redraw);
-}
-
-static void
-XawScrollbarResize(Widget gw)
-{
- /* ForgetGravity has taken care of background, but thumb may
- * have to move as a result of the new size. */
- SetDimensions((ScrollbarWidget)gw);
- XawScrollbarRedisplay(gw, NULL, NULL);
-}
-
-/*ARGSUSED*/
-static void
-XawScrollbarRedisplay(Widget gw, XEvent *event, Region region)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
- int x, y;
- unsigned int width, height;
-
- if (Superclass->core_class.expose)
- (*Superclass->core_class.expose)(gw, event, region);
-
- if (w->scrollbar.orientation == XtorientHorizontal) {
- x = w->scrollbar.topLoc;
- y = 1;
- width = w->scrollbar.shownLength;
- height = XtHeight(w) - 2;
- }
- else {
- x = 1;
- y = w->scrollbar.topLoc;
- width = XtWidth(w) - 2;
- height = w->scrollbar.shownLength;
- }
-
- if (region == NULL ||
- XRectInRegion(region, x, y, width, height) != RectangleOut) {
- /* Forces entire thumb to be painted */
- w->scrollbar.topLoc = -(w->scrollbar.length + 1);
- PaintThumb(w);
- }
-}
-
-/*ARGSUSED*/
-static void
-StartScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
- Cursor cursor;
- char direction;
-
- if (w->scrollbar.direction != 0) /* if we're already scrolling */
- return;
- if (*num_params > 0)
- direction = *params[0];
- else
- direction = 'C';
-
- w->scrollbar.direction = direction;
-
- switch(direction) {
- case 'B':
- case 'b':
- cursor = w->scrollbar.orientation == XtorientVertical ?
- w->scrollbar.downCursor : w->scrollbar.rightCursor;
- break;
- case 'F':
- case 'f':
- cursor = w->scrollbar.orientation == XtorientVertical ?
- w->scrollbar.upCursor : w->scrollbar.leftCursor;
- break;
- case 'C':
- case 'c':
- cursor = w->scrollbar.orientation == XtorientVertical ?
- w->scrollbar.rightCursor : w->scrollbar.upCursor;
- break;
- default:
- return; /* invalid invocation */
- }
-
- XtVaSetValues(gw, XtNcursor, cursor, NULL);
-
- XFlush(XtDisplay(w));
-}
-
-static Boolean
-CompareEvents(XEvent *oldEvent, XEvent *newEvent)
-{
-#define Check(field) if (newEvent->field != oldEvent->field) return (False)
-
- Check(xany.display);
- Check(xany.type);
- Check(xany.window);
-
- switch(newEvent->type) {
- case MotionNotify:
- Check(xmotion.state);
- break;
- case ButtonPress:
- case ButtonRelease:
- Check(xbutton.state);
- Check(xbutton.button);
- break;
- case KeyPress:
- case KeyRelease:
- Check(xkey.state);
- Check(xkey.keycode);
- break;
- case EnterNotify:
- case LeaveNotify:
- Check(xcrossing.mode);
- Check(xcrossing.detail);
- Check(xcrossing.state);
- break;
- }
-#undef Check
-
- return (True);
-}
-
-struct EventData {
- XEvent *oldEvent;
- int count;
-};
-
-static Bool
-PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
-{
- struct EventData *eventData = (struct EventData*)args;
-
- return (++eventData->count == QLength(dpy) /* since PeekIf blocks */
- || CompareEvents(event, eventData->oldEvent));
-}
-
-static Bool
-LookAhead(Widget w, XEvent *event)
-{
- XEvent newEvent;
- struct EventData eventData;
-
- if (QLength(XtDisplay(w)) == 0)
- return (False);
-
- eventData.count = 0;
- eventData.oldEvent = event;
-
- XPeekIfEvent(XtDisplay(w), &newEvent, PeekNotifyEvent, (char*)&eventData);
-
- if (CompareEvents(event, &newEvent))
- return (True);
-
- return (False);
-}
-
-static void
-ExtractPosition(XEvent *event, Position *x, Position *y)
-{
- switch(event->type) {
- case MotionNotify:
- *x = event->xmotion.x;
- *y = event->xmotion.y;
- break;
- case ButtonPress:
- case ButtonRelease:
- *x = event->xbutton.x;
- *y = event->xbutton.y;
- break;
- case KeyPress:
- case KeyRelease:
- *x = event->xkey.x;
- *y = event->xkey.y;
- break;
- case EnterNotify:
- case LeaveNotify:
- *x = event->xcrossing.x;
- *y = event->xcrossing.y;
- break;
- default:
- *x = 0;
- *y = 0;
- break;
- }
-}
-
-static void
-NotifyScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
- long call_data = 0;
- char style;
- Position x, y;
-
- if (w->scrollbar.direction == 0) /* if no StartScroll */
- return;
-
- if (LookAhead(gw, event))
- return;
-
- if (*num_params > 0)
- style = *params[0];
- else
- style = 'P';
-
- switch(style) {
- case 'P': /* Proportional */
- case 'p':
- ExtractPosition(event, &x, &y);
- call_data = InRange(PICKLENGTH(w, x, y), 0, (int)w->scrollbar.length);
- break;
- case 'F': /* FullLength */
- case 'f':
- call_data = w->scrollbar.length;
- break;
- }
-
- switch(w->scrollbar.direction) {
- case 'B':
- case 'b':
- call_data = -call_data;
- /*FALLTHROUGH*/
- case 'F':
- case 'f':
- XtCallCallbacks(gw, XtNscrollProc, (XtPointer)call_data);
- break;
- case 'C':
- case 'c': /* NotifyThumb has already called the thumbProc(s) */
- break;
- }
-}
-
-/*ARGSUSED*/
-static void
-EndScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
-
- XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
- XFlush(XtDisplay(w)); /* make sure it get propogated */
-
- w->scrollbar.direction = 0;
-}
-
-/*ARGSUSED*/
-static void
-MoveThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
- Position x, y;
-
- if (w->scrollbar.direction == 0) /* if no StartScroll */
- return;
-
- if (LookAhead(gw, event))
- return;
-
- if (!event->xmotion.same_screen)
- return;
-
- ExtractPosition(event, &x, &y);
- w->scrollbar.top = FractionLoc(w, x, y);
-}
-
-/*ARGSUSED*/
-static void
-NotifyThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
- union {
- XtPointer xtp;
- float xtf;
- } xtpf;
-
- if (w->scrollbar.direction == 0) /* if no StartScroll */
- return;
-
- if (LookAhead(gw, event))
- return;
-
- /* thumbProc is not pretty, but is necessary for backwards
- compatibility on those architectures for which it work{s,ed};
- the intent is to pass a (truncated) float by value. */
- xtpf.xtf = w->scrollbar.top;
- XtCallCallbacks(gw, XtNthumbProc, xtpf.xtp);
- XtCallCallbacks(gw, XtNjumpProc, (XtPointer)&w->scrollbar.top);
-
- PaintThumb(w);
-}
-
-/*
- * Public routines
- */
-/* Set the scroll bar to the given location. */
-void
-XawScrollbarSetThumb(Widget gw,
-#if NeedWidePrototypes
- double top, double shown
-#else
- float top, float shown
-#endif
- )
-{
- ScrollbarWidget w = (ScrollbarWidget)gw;
-
- if (w->scrollbar.direction == 'c') /* if still thumbing */
- return;
-
- w->scrollbar.top = top > 1.0 ? 1.0 : top >= 0.0 ? top : w->scrollbar.top;
-
- w->scrollbar.shown = shown > 1.0 ? 1.0 : shown >= 0.0 ?
- shown : w->scrollbar.shown;
- PaintThumb(w);
-}
+/***********************************************************
+
+Copyright 1987, 1988, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Drawing.h>
+#include <X11/Xaw/ScrollbarP.h>
+#include <X11/Xaw/XawInit.h>
+#include "Private.h"
+
+#define NoButton -1
+#define PICKLENGTH(widget, x, y) \
+(((widget)->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
+
+/*
+ * Class Methods
+ */
+static void XawScrollbarClassInitialize(void);
+static void XawScrollbarDestroy(Widget);
+static void XawScrollbarInitialize(Widget, Widget, ArgList, Cardinal*_args);
+static void XawScrollbarRealize(Widget, Mask*, XSetWindowAttributes*);
+static void XawScrollbarRedisplay(Widget, XEvent*, Region);
+static void XawScrollbarResize(Widget);
+static Boolean XawScrollbarSetValues(Widget, Widget, Widget,
+ ArgList, Cardinal*);
+
+/*
+ * Prototypes
+ */
+static Boolean CompareEvents(XEvent*, XEvent*);
+static void CreateGC(Widget);
+static float FloatInRange(float, float, float);
+static float FractionLoc(ScrollbarWidget, int, int);
+static void ExtractPosition(XEvent*, Position*, Position*);
+static int InRange(int, int, int);
+static void FillArea(ScrollbarWidget, int, int, int);
+static Bool LookAhead(Widget, XEvent*);
+static void PaintThumb(ScrollbarWidget);
+static Bool PeekNotifyEvent(Display*, XEvent*, char*);
+static void SetDimensions(ScrollbarWidget);
+
+/*
+ * Actions
+ */
+static void EndScroll(Widget, XEvent*, String*, Cardinal*);
+static void MoveThumb(Widget, XEvent*, String*, Cardinal*);
+static void NotifyScroll(Widget, XEvent*, String*, Cardinal*);
+static void NotifyThumb(Widget, XEvent*, String*, Cardinal*);
+static void StartScroll(Widget, XEvent*, String*, Cardinal*);
+
+/*
+ * Initialization
+ */
+static char defaultTranslations[] =
+"<Btn1Down>:" "StartScroll(Forward)\n"
+"<Btn2Down>:" "StartScroll(Continuous) MoveThumb() NotifyThumb()\n"
+"<Btn3Down>:" "StartScroll(Backward)\n"
+"<Btn2Motion>:" "MoveThumb() NotifyThumb()\n"
+"<BtnUp>:" "NotifyScroll(Proportional) EndScroll()\n";
+
+static float floatZero = 0.0;
+
+#define Offset(field) XtOffsetOf(ScrollbarRec, field)
+
+static XtResource resources[] = {
+ {
+ XtNlength,
+ XtCLength,
+ XtRDimension,
+ sizeof(Dimension),
+ Offset(scrollbar.length),
+ XtRImmediate,
+ (XtPointer)1
+ },
+ {
+ XtNthickness,
+ XtCThickness,
+ XtRDimension,
+ sizeof(Dimension),
+ Offset(scrollbar.thickness),
+ XtRImmediate,
+ (XtPointer)14
+ },
+ {
+ XtNorientation,
+ XtCOrientation,
+ XtROrientation,
+ sizeof(XtOrientation),
+ Offset(scrollbar.orientation),
+ XtRImmediate,
+ (XtPointer)XtorientVertical
+ },
+ {
+ XtNscrollProc,
+ XtCCallback,
+ XtRCallback,
+ sizeof(XtPointer),
+ Offset(scrollbar.scrollProc),
+ XtRCallback,
+ NULL
+ },
+ {
+ XtNthumbProc,
+ XtCCallback,
+ XtRCallback,
+ sizeof(XtPointer),
+ Offset(scrollbar.thumbProc),
+ XtRCallback,
+ NULL
+ },
+ {
+ XtNjumpProc,
+ XtCCallback,
+ XtRCallback,
+ sizeof(XtPointer),
+ Offset(scrollbar.jumpProc),
+ XtRCallback,
+ NULL
+ },
+ {
+ XtNthumb,
+ XtCThumb,
+ XtRBitmap,
+ sizeof(Pixmap),
+ Offset(scrollbar.thumb),
+ XtRImmediate,
+ (XtPointer)XtUnspecifiedPixmap
+ },
+ {
+ XtNforeground,
+ XtCForeground,
+ XtRPixel,
+ sizeof(Pixel),
+ Offset(scrollbar.foreground),
+ XtRString,
+ XtDefaultForeground
+ },
+ {
+ XtNshown,
+ XtCShown,
+ XtRFloat,
+ sizeof(float),
+ Offset(scrollbar.shown),
+ XtRFloat,
+ (XtPointer)&floatZero
+ },
+ {
+ XtNtopOfThumb,
+ XtCTopOfThumb,
+ XtRFloat,
+ sizeof(float),
+ Offset(scrollbar.top),
+ XtRFloat,
+ (XtPointer)&floatZero
+ },
+ {
+ XtNscrollVCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.verCursor),
+ XtRString,
+ "sb_v_double_arrow"
+ },
+ {
+ XtNscrollHCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.horCursor),
+ XtRString,
+ "sb_h_double_arrow"
+ },
+ {
+ XtNscrollUCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.upCursor),
+ XtRString,
+ "sb_up_arrow"
+ },
+ {
+ XtNscrollDCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.downCursor),
+ XtRString,
+ "sb_down_arrow"
+ },
+ {
+ XtNscrollLCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.leftCursor),
+ XtRString,
+ "sb_left_arrow"
+ },
+ {
+ XtNscrollRCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ Offset(scrollbar.rightCursor),
+ XtRString,
+ "sb_right_arrow"
+ },
+ {
+ XtNminimumThumb,
+ XtCMinimumThumb,
+ XtRDimension,
+ sizeof(Dimension),
+ Offset(scrollbar.min_thumb),
+ XtRImmediate,
+ (XtPointer)7
+ },
+};
+#undef Offset
+
+static XtActionsRec actions[] = {
+ {"StartScroll", StartScroll},
+ {"MoveThumb", MoveThumb},
+ {"NotifyThumb", NotifyThumb},
+ {"NotifyScroll", NotifyScroll},
+ {"EndScroll", EndScroll},
+};
+
+#define Superclass (&simpleClassRec)
+ScrollbarClassRec scrollbarClassRec = {
+ /* core */
+ {
+ (WidgetClass)&simpleClassRec, /* superclass */
+ "Scrollbar", /* class_name */
+ sizeof(ScrollbarRec), /* widget_size */
+ XawScrollbarClassInitialize, /* class_initialize */
+ NULL, /* class_part_init */
+ False, /* class_inited */
+ XawScrollbarInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XawScrollbarRealize, /* realize */
+ actions, /* actions */
+ XtNumber(actions), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ True, /* compress_motion */
+ True, /* compress_exposure */
+ True, /* compress_enterleave */
+ False, /* visible_interest */
+ XawScrollbarDestroy, /* destroy */
+ XawScrollbarResize, /* resize */
+ XawScrollbarRedisplay, /* expose */
+ XawScrollbarSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL, /* extension */
+ },
+ /* simple */
+ {
+ XtInheritChangeSensitive, /* change_sensitive */
+ },
+ /* scrollbar */
+ {
+ NULL, /* extension */
+ },
+};
+
+WidgetClass scrollbarWidgetClass = (WidgetClass)&scrollbarClassRec;
+
+/*
+ * Implementation
+ */
+static void
+XawScrollbarClassInitialize(void)
+{
+ XawInitializeWidgetSet();
+ XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
+ NULL, 0);
+ XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+
+/*
+ * Make sure the first number is within the range specified by the other
+ * two numbers.
+ */
+static int
+InRange(int num, int small, int big)
+{
+ return ((num < small) ? small : ((num > big) ? big : num));
+}
+
+/*
+ * Same as above, but for floating numbers
+ */
+static float
+FloatInRange(float num, float small, float big)
+{
+ return ((num < small) ? small : ((num > big) ? big : num));
+}
+
+/* Fill the area specified by top and bottom with the given pattern */
+static float
+FractionLoc(ScrollbarWidget w, int x, int y)
+{
+ float result;
+
+ result = PICKLENGTH(w, x / (float)XtWidth(w), y / (float)XtHeight(w));
+
+ return (FloatInRange(result, 0.0, 1.0));
+}
+
+static void
+FillArea(ScrollbarWidget w, int top, int bottom, int thumb)
+{
+ Dimension length;
+
+ top = XawMax(1, top);
+ if (w->scrollbar.orientation == XtorientHorizontal)
+ bottom = XawMin(bottom, XtWidth(w) - 1);
+ else
+ bottom = XawMin(bottom, XtHeight(w) - 1);
+
+ if (bottom <= top)
+ return;
+
+ length = bottom - top;
+
+ switch(thumb) {
+ /* Fill the new Thumb location */
+ case 1:
+ if (w->scrollbar.orientation == XtorientHorizontal)
+ XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
+ top, 1, length, XtHeight(w) - 2);
+ else
+ XFillRectangle(XtDisplay(w), XtWindow(w), w->scrollbar.gc,
+ 1, top, XtWidth(w) - 2, length);
+ break;
+ /* Clear the old Thumb location */
+ case 0:
+ if (w->scrollbar.orientation == XtorientHorizontal)
+ XClearArea(XtDisplay(w), XtWindow(w),
+ top, 1, length, XtHeight(w) - 2, False);
+ else
+ XClearArea(XtDisplay(w), XtWindow(w),
+ 1, top, XtWidth(w) - 2, length, False);
+ break;
+ }
+}
+
+
+/* Paint the thumb in the area specified by w->top and
+ w->shown. The old area is erased. The painting and
+ erasing is done cleverly so that no flickering will occur. */
+static void
+PaintThumb(ScrollbarWidget w)
+{
+ Position oldtop, oldbot, newtop, newbot;
+
+ oldtop = w->scrollbar.topLoc;
+ oldbot = oldtop + w->scrollbar.shownLength;
+ newtop = w->scrollbar.length * w->scrollbar.top;
+ newbot = newtop + (int)(w->scrollbar.length * w->scrollbar.shown);
+ if (newbot < newtop + (int)w->scrollbar.min_thumb)
+ newbot = newtop + w->scrollbar.min_thumb;
+ w->scrollbar.topLoc = newtop;
+ w->scrollbar.shownLength = newbot - newtop;
+
+ if (XtIsRealized((Widget)w)) {
+ if (newtop < oldtop)
+ FillArea(w, newtop, XawMin(newbot, oldtop), 1);
+ if (newtop > oldtop)
+ FillArea(w, oldtop, XawMin(newtop, oldbot), 0);
+ if (newbot < oldbot)
+ FillArea(w, XawMax(newbot, oldtop), oldbot, 0);
+ if (newbot > oldbot)
+ FillArea(w, XawMax(newtop, oldbot), newbot, 1);
+ }
+}
+
+static void
+SetDimensions(ScrollbarWidget w)
+{
+ if (w->scrollbar.orientation == XtorientVertical) {
+ w->scrollbar.length = XtHeight(w);
+ w->scrollbar.thickness = XtWidth(w);
+ }
+ else {
+ w->scrollbar.length = XtWidth(w);
+ w->scrollbar.thickness = XtHeight(w);
+ }
+}
+
+static void
+XawScrollbarDestroy(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+
+ XtReleaseGC(w, sbw->scrollbar.gc);
+}
+
+static void
+CreateGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+ XGCValues gcValues;
+ XtGCMask mask;
+ unsigned int depth = 1;
+
+ if (sbw->scrollbar.thumb == XtUnspecifiedPixmap)
+ sbw->scrollbar.thumb = XmuCreateStippledPixmap(XtScreen(w),
+ (Pixel)1, (Pixel)0,
+ depth);
+ else if (sbw->scrollbar.thumb != None) {
+ Window root;
+ int x, y;
+ unsigned int width, height, bw;
+
+ XGetGeometry(XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
+ &width, &height, &bw, &depth);
+ }
+
+ gcValues.foreground = sbw->scrollbar.foreground;
+ gcValues.background = sbw->core.background_pixel;
+ mask = GCForeground | GCBackground;
+
+ if (sbw->scrollbar.thumb != None) {
+ if (depth == 1) {
+ gcValues.fill_style = FillOpaqueStippled;
+ gcValues.stipple = sbw->scrollbar.thumb;
+ mask |= GCFillStyle | GCStipple;
+ }
+ else {
+ gcValues.fill_style = FillTiled;
+ gcValues.tile = sbw->scrollbar.thumb;
+ mask |= GCFillStyle | GCTile;
+ }
+ }
+ sbw->scrollbar.gc = XtGetGC(w, mask, &gcValues);
+}
+
+/* ARGSUSED */
+static void
+XawScrollbarInitialize(Widget request, Widget cnew,
+ ArgList args, Cardinal *num_args)
+{
+ ScrollbarWidget w = (ScrollbarWidget)cnew;
+
+ CreateGC(cnew);
+
+ if (XtWidth(w) == 0)
+ XtWidth(w) = w->scrollbar.orientation == XtorientVertical ?
+ w->scrollbar.thickness : w->scrollbar.length;
+
+ if (XtHeight(w) == 0)
+ XtHeight(w) = w->scrollbar.orientation == XtorientHorizontal ?
+ w->scrollbar.thickness : w->scrollbar.length;
+
+ SetDimensions(w);
+ w->scrollbar.direction = 0;
+ w->scrollbar.topLoc = 0;
+ w->scrollbar.shownLength = w->scrollbar.min_thumb;
+}
+
+static void
+XawScrollbarRealize(Widget gw, Mask *valueMask,
+ XSetWindowAttributes *attributes)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+
+ w->scrollbar.inactiveCursor = w->scrollbar.orientation == XtorientVertical ?
+ w->scrollbar.verCursor : w->scrollbar.horCursor;
+
+ XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
+
+ /*
+ * The Simple widget actually stuffs the value in the valuemask
+ */
+ (*scrollbarWidgetClass->core_class.superclass->core_class.realize)
+ (gw, valueMask, attributes);
+}
+
+/*ARGSUSED*/
+static Boolean
+XawScrollbarSetValues(Widget current, Widget request, Widget desired,
+ ArgList args, Cardinal *num_args)
+{
+ ScrollbarWidget w = (ScrollbarWidget)current;
+ ScrollbarWidget dw = (ScrollbarWidget)desired;
+ Boolean redraw = False;
+
+ /*
+ * If these values are outside the acceptable range ignore them...
+ */
+ if (dw->scrollbar.top < 0.0 || dw->scrollbar.top > 1.0)
+ dw->scrollbar.top = w->scrollbar.top;
+
+ if (dw->scrollbar.shown < 0.0 || dw->scrollbar.shown > 1.0)
+ dw->scrollbar.shown = w->scrollbar.shown;
+
+ if (XtIsRealized (desired)) {
+ if (w->scrollbar.foreground != dw->scrollbar.foreground ||
+ w->core.background_pixel != dw->core.background_pixel ||
+ w->scrollbar.thumb != dw->scrollbar.thumb) {
+ XtReleaseGC((Widget)dw, w->scrollbar.gc);
+ CreateGC((Widget)dw);
+ redraw = True;
+ }
+ if (w->scrollbar.top != dw->scrollbar.top ||
+ w->scrollbar.shown != dw->scrollbar.shown)
+ redraw = True;
+ }
+
+ return (redraw);
+}
+
+static void
+XawScrollbarResize(Widget gw)
+{
+ /* ForgetGravity has taken care of background, but thumb may
+ * have to move as a result of the new size. */
+ SetDimensions((ScrollbarWidget)gw);
+ XawScrollbarRedisplay(gw, NULL, NULL);
+}
+
+/*ARGSUSED*/
+static void
+XawScrollbarRedisplay(Widget gw, XEvent *event, Region region)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+ int x, y;
+ unsigned int width, height;
+
+ if (Superclass->core_class.expose)
+ (*Superclass->core_class.expose)(gw, event, region);
+
+ if (w->scrollbar.orientation == XtorientHorizontal) {
+ x = w->scrollbar.topLoc;
+ y = 1;
+ width = w->scrollbar.shownLength;
+ height = XtHeight(w) - 2;
+ }
+ else {
+ x = 1;
+ y = w->scrollbar.topLoc;
+ width = XtWidth(w) - 2;
+ height = w->scrollbar.shownLength;
+ }
+
+ if (region == NULL ||
+ XRectInRegion(region, x, y, width, height) != RectangleOut) {
+ /* Forces entire thumb to be painted */
+ w->scrollbar.topLoc = -(w->scrollbar.length + 1);
+ PaintThumb(w);
+ }
+}
+
+/*ARGSUSED*/
+static void
+StartScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+ Cursor cursor;
+ char direction;
+
+ if (w->scrollbar.direction != 0) /* if we're already scrolling */
+ return;
+ if (*num_params > 0)
+ direction = *params[0];
+ else
+ direction = 'C';
+
+ w->scrollbar.direction = direction;
+
+ switch(direction) {
+ case 'B':
+ case 'b':
+ cursor = w->scrollbar.orientation == XtorientVertical ?
+ w->scrollbar.downCursor : w->scrollbar.rightCursor;
+ break;
+ case 'F':
+ case 'f':
+ cursor = w->scrollbar.orientation == XtorientVertical ?
+ w->scrollbar.upCursor : w->scrollbar.leftCursor;
+ break;
+ case 'C':
+ case 'c':
+ cursor = w->scrollbar.orientation == XtorientVertical ?
+ w->scrollbar.rightCursor : w->scrollbar.upCursor;
+ break;
+ default:
+ return; /* invalid invocation */
+ }
+
+ XtVaSetValues(gw, XtNcursor, cursor, NULL);
+
+ XFlush(XtDisplay(w));
+}
+
+static Boolean
+CompareEvents(XEvent *oldEvent, XEvent *newEvent)
+{
+#define Check(field) if (newEvent->field != oldEvent->field) return (False)
+
+ Check(xany.display);
+ Check(xany.type);
+ Check(xany.window);
+
+ switch(newEvent->type) {
+ case MotionNotify:
+ Check(xmotion.state);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ Check(xbutton.state);
+ Check(xbutton.button);
+ break;
+ case KeyPress:
+ case KeyRelease:
+ Check(xkey.state);
+ Check(xkey.keycode);
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ Check(xcrossing.mode);
+ Check(xcrossing.detail);
+ Check(xcrossing.state);
+ break;
+ }
+#undef Check
+
+ return (True);
+}
+
+struct EventData {
+ XEvent *oldEvent;
+ int count;
+};
+
+static Bool
+PeekNotifyEvent(Display *dpy, XEvent *event, char *args)
+{
+ struct EventData *eventData = (struct EventData*)args;
+
+ return (++eventData->count == QLength(dpy) /* since PeekIf blocks */
+ || CompareEvents(event, eventData->oldEvent));
+}
+
+static Bool
+LookAhead(Widget w, XEvent *event)
+{
+ XEvent newEvent;
+ struct EventData eventData;
+
+ if (QLength(XtDisplay(w)) == 0)
+ return (False);
+
+ eventData.count = 0;
+ eventData.oldEvent = event;
+
+ XPeekIfEvent(XtDisplay(w), &newEvent, PeekNotifyEvent, (char*)&eventData);
+
+ if (CompareEvents(event, &newEvent))
+ return (True);
+
+ return (False);
+}
+
+static void
+ExtractPosition(XEvent *event, Position *x, Position *y)
+{
+ switch(event->type) {
+ case MotionNotify:
+ *x = event->xmotion.x;
+ *y = event->xmotion.y;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x;
+ *y = event->xbutton.y;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x;
+ *y = event->xkey.y;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x;
+ *y = event->xcrossing.y;
+ break;
+ default:
+ *x = 0;
+ *y = 0;
+ break;
+ }
+}
+
+static void
+NotifyScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+ long call_data = 0;
+ char style;
+ Position x, y;
+
+ if (w->scrollbar.direction == 0) /* if no StartScroll */
+ return;
+
+ if (LookAhead(gw, event))
+ return;
+
+ if (*num_params > 0)
+ style = *params[0];
+ else
+ style = 'P';
+
+ switch(style) {
+ case 'P': /* Proportional */
+ case 'p':
+ ExtractPosition(event, &x, &y);
+ call_data = InRange(PICKLENGTH(w, x, y), 0, (int)w->scrollbar.length);
+ break;
+ case 'F': /* FullLength */
+ case 'f':
+ call_data = w->scrollbar.length;
+ break;
+ }
+
+ switch(w->scrollbar.direction) {
+ case 'B':
+ case 'b':
+ call_data = -call_data;
+ /*FALLTHROUGH*/
+ case 'F':
+ case 'f':
+ XtCallCallbacks(gw, XtNscrollProc, (XtPointer)call_data);
+ break;
+ case 'C':
+ case 'c': /* NotifyThumb has already called the thumbProc(s) */
+ break;
+ }
+}
+
+/*ARGSUSED*/
+static void
+EndScroll(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+
+ XtVaSetValues(gw, XtNcursor, w->scrollbar.inactiveCursor, NULL);
+ XFlush(XtDisplay(w)); /* make sure it get propogated */
+
+ w->scrollbar.direction = 0;
+}
+
+/*ARGSUSED*/
+static void
+MoveThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+ Position x, y;
+
+ if (w->scrollbar.direction == 0) /* if no StartScroll */
+ return;
+
+ if (LookAhead(gw, event))
+ return;
+
+ if (!event->xmotion.same_screen)
+ return;
+
+ ExtractPosition(event, &x, &y);
+ w->scrollbar.top = FractionLoc(w, x, y);
+}
+
+/*ARGSUSED*/
+static void
+NotifyThumb(Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+ union {
+ XtPointer xtp;
+ float xtf;
+ } xtpf;
+
+ if (w->scrollbar.direction == 0) /* if no StartScroll */
+ return;
+
+ if (LookAhead(gw, event))
+ return;
+
+ /* thumbProc is not pretty, but is necessary for backwards
+ compatibility on those architectures for which it work{s,ed};
+ the intent is to pass a (truncated) float by value. */
+ xtpf.xtf = w->scrollbar.top;
+ XtCallCallbacks(gw, XtNthumbProc, xtpf.xtp);
+ XtCallCallbacks(gw, XtNjumpProc, (XtPointer)&w->scrollbar.top);
+
+ PaintThumb(w);
+}
+
+/*
+ * Public routines
+ */
+/* Set the scroll bar to the given location. */
+void
+XawScrollbarSetThumb(Widget gw,
+#if NeedWidePrototypes
+ double top, double shown
+#else
+ float top, float shown
+#endif
+ )
+{
+ ScrollbarWidget w = (ScrollbarWidget)gw;
+
+ if (w->scrollbar.direction == 'c') /* if still thumbing */
+ return;
+
+ w->scrollbar.top = top > 1.0 ? 1.0 : top >= 0.0 ? top : w->scrollbar.top;
+
+ w->scrollbar.shown = shown > 1.0 ? 1.0 : shown >= 0.0 ?
+ shown : w->scrollbar.shown;
+ PaintThumb(w);
+}