diff options
Diffstat (limited to 'libXaw/src/Scrollbar.c')
-rw-r--r-- | libXaw/src/Scrollbar.c | 1764 |
1 files changed, 882 insertions, 882 deletions
diff --git a/libXaw/src/Scrollbar.c b/libXaw/src/Scrollbar.c index 6413f0bf6..777043063 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);
+}
|