summaryrefslogtreecommitdiffstats
path: root/src/gui_at_sb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui_at_sb.c')
-rw-r--r--src/gui_at_sb.c1192
1 files changed, 1192 insertions, 0 deletions
diff --git a/src/gui_at_sb.c b/src/gui_at_sb.c
new file mode 100644
index 0000000..72dc8c8
--- /dev/null
+++ b/src/gui_at_sb.c
@@ -0,0 +1,1192 @@
+/* vi:set ts=8 sts=4 sw=4 noet: */
+/*
+ * MODIFIED ATHENA SCROLLBAR (USING ARROWHEADS AT ENDS OF TRAVEL)
+ * Modifications Copyright 1992 by Mitch Trachtenberg
+ * Rights, permissions, and disclaimer of warranty are as in the DEC and MIT
+ * notice below.
+ * $XConsortium: Scrollbar.c,v 1.72 94/04/17 20:12:40 kaleb Exp $
+ */
+
+/*
+ * Modified for Vim by Bill Foster and Bram Moolenaar
+ */
+
+/*
+
+Copyright (c) 1987, 1988, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+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 X
+CONSORTIUM 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 X Consortium 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 X Consortium.
+
+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.
+
+*/
+
+/* ScrollBar.c */
+/* created by weissman, Mon Jul 7 13:20:03 1986 */
+/* converted by swick, Thu Aug 27 1987 */
+
+#include "vim.h"
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xaw/XawInit.h>
+#include "gui_at_sb.h"
+
+#include <X11/Xmu/Drawing.h>
+
+/* Private definitions. */
+
+static char defaultTranslations[] =
+ "<Btn1Down>: NotifyScroll()\n\
+ <Btn2Down>: MoveThumb() NotifyThumb()\n\
+ <Btn3Down>: NotifyScroll()\n\
+ <Btn4Down>: ScrollOneLineUp()\n\
+ Shift<Btn4Down>: ScrollPageUp()\n\
+ <Btn5Down>: ScrollOneLineDown()\n\
+ Shift<Btn5Down>: ScrollPageDown()\n\
+ <Btn1Motion>: HandleThumb()\n\
+ <Btn3Motion>: HandleThumb()\n\
+ <Btn2Motion>: MoveThumb() NotifyThumb()\n\
+ <BtnUp>: EndScroll()";
+
+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},
+ {XtNmaxOfThumb, XtCMaxOfThumb, XtRFloat, sizeof(float),
+ Offset(scrollbar.max), XtRFloat, (XtPointer)&floatZero},
+ {XtNminimumThumb, XtCMinimumThumb, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.min_thumb), XtRImmediate, (XtPointer) 7},
+ {XtNshadowWidth, XtCShadowWidth, XtRDimension, sizeof(Dimension),
+ Offset(scrollbar.shadow_width), XtRImmediate, (XtPointer) 1},
+ {XtNtopShadowPixel, XtCTopShadowPixel, XtRPixel, sizeof(Pixel),
+ Offset(scrollbar.top_shadow_pixel), XtRString, XtDefaultBackground},
+ {XtNbottomShadowPixel, XtCBottomShadowPixel, XtRPixel, sizeof(Pixel),
+ Offset(scrollbar.bot_shadow_pixel), XtRString, XtDefaultForeground},
+ {XtNlimitThumb, XtCLimitThumb, XtRBool, sizeof(Bool),
+ Offset(scrollbar.limit_thumb), XtRImmediate, (XtPointer)0}
+};
+#undef Offset
+
+static void ClassInitialize(void);
+static void Initialize(Widget, Widget, ArgList, Cardinal *);
+static void Destroy(Widget);
+static void Realize(Widget, Mask *, XSetWindowAttributes *);
+static void Resize(Widget);
+static void Redisplay(Widget, XEvent *, Region);
+static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
+
+static void HandleThumb(Widget, XEvent *, String *, Cardinal *);
+static void MoveThumb(Widget, XEvent *, String *, Cardinal *);
+static void NotifyThumb(Widget, XEvent *, String *, Cardinal *);
+static void NotifyScroll(Widget, XEvent *, String *, Cardinal *);
+static void EndScroll(Widget, XEvent *, String *, Cardinal *);
+static void ScrollOneLineUp(Widget, XEvent *, String *, Cardinal *);
+static void ScrollOneLineDown(Widget, XEvent *, String *, Cardinal *);
+static void ScrollPageUp(Widget, XEvent *, String *, Cardinal *);
+static void ScrollPageDown(Widget, XEvent *, String *, Cardinal *);
+static void ScrollSome(Widget w, XEvent *event, int call_data);
+static void _Xaw3dDrawShadows(Widget, XEvent *, Region, int);
+static void AllocTopShadowGC(Widget);
+static void AllocBotShadowGC(Widget);
+
+static XtActionsRec actions[] =
+{
+ {"HandleThumb", HandleThumb},
+ {"MoveThumb", MoveThumb},
+ {"NotifyThumb", NotifyThumb},
+ {"NotifyScroll", NotifyScroll},
+ {"EndScroll", EndScroll},
+ {"ScrollOneLineUp", ScrollOneLineUp},
+ {"ScrollOneLineDown", ScrollOneLineDown},
+ {"ScrollPageUp", ScrollPageUp},
+ {"ScrollPageDown", ScrollPageDown}
+};
+
+
+ScrollbarClassRec vim_scrollbarClassRec =
+{
+ { /* core fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Scrollbar",
+ /* size */ sizeof(ScrollbarRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_init */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure*/ TRUE,
+ /* compress_enterleave*/ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ XtInheritChangeSensitive,
+#ifndef OLDXAW
+ /* extension */ NULL
+#endif
+ },
+ { /* scrollbar fields */
+ /* empty */ 0
+ }
+};
+
+WidgetClass vim_scrollbarWidgetClass = (WidgetClass)&vim_scrollbarClassRec;
+
+#define NoButton -1
+#define PICKLENGTH(widget, x, y) \
+ ((widget->scrollbar.orientation == XtorientHorizontal) ? (x) : (y))
+#define AT_MIN(x,y) ((x) < (y) ? (x) : (y))
+#define AT_MAX(x,y) ((x) > (y) ? (x) : (y))
+
+#define LINE_DELAY 300
+#define PAGE_DELAY 300
+#define LINE_REPEAT 50
+#define PAGE_REPEAT 250
+
+ static void
+ClassInitialize(void)
+{
+ XawInitializeWidgetSet();
+ XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
+ (XtConvertArgList)NULL, (Cardinal)0 );
+}
+
+#define MARGIN(sbw) (sbw)->scrollbar.thickness + (sbw)->scrollbar.shadow_width
+
+ static void
+FillArea(
+ ScrollbarWidget sbw,
+ Position top,
+ Position bottom,
+ int fill,
+ int draw_shadow)
+{
+ int tlen = bottom - top; /* length of thumb in pixels */
+ int sw, margin, floor;
+ int lx, ly, lw, lh;
+
+ if (bottom <= 0 || bottom <= top)
+ return;
+ sw = sbw->scrollbar.shadow_width;
+ if (sw < 0)
+ sw = 0;
+ margin = MARGIN (sbw);
+ floor = sbw->scrollbar.length - margin + 2;
+
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ lx = ((top < margin) ? margin : top);
+ ly = sw;
+ lw = (((top + tlen) > floor) ? floor - top : tlen);
+ lh = sbw->core.height - 2 * sw;
+ }
+ else
+ {
+ lx = sw;
+ ly = ((top < margin) ? margin : top);
+ lw = sbw->core.width - 2 * sw;
+ lh = (((top + tlen) > floor) ? floor - top : tlen);
+ }
+ if (lh <= 0 || lw <= 0)
+ return;
+
+ if (draw_shadow)
+ {
+ if (!(sbw->scrollbar.orientation == XtorientHorizontal))
+ {
+ /* Top border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx + lw - 1, ly);
+
+ /* Bottom border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
+ }
+ else
+ {
+ /* Left border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx, ly + lh - 1);
+
+ /* Right border */
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
+ }
+ return;
+ }
+
+ if (fill)
+ {
+ XFillRectangle(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
+ sbw->scrollbar.gc,
+ lx, ly, (unsigned int) lw, (unsigned int) lh);
+
+ if (!(sbw->scrollbar.orientation == XtorientHorizontal))
+ {
+ /* Left border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx, ly + lh - 1);
+
+ /* Right border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx + lw - 1, ly, lx + lw - 1, ly + lh - 1);
+ }
+ else
+ {
+ /* Top border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ lx, ly, lx + lw - 1, ly);
+
+ /* Bottom border */
+ XDrawLine(XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ lx, ly + lh - 1, lx + lw - 1, ly + lh - 1);
+ }
+ }
+ else
+ {
+ XClearArea(XtDisplay((Widget) sbw), XtWindow((Widget) sbw),
+ lx, ly, (unsigned int) lw, (unsigned int) lh, FALSE);
+ }
+}
+
+/* Paint the thumb in the area specified by sbw->top and
+ sbw->shown. The old area is erased. The painting and
+ erasing is done cleverly so that no flickering will occur.
+ */
+
+ static void
+PaintThumb(ScrollbarWidget sbw)
+{
+ Position oldtop, oldbot, newtop, newbot;
+ Dimension margin, tzl;
+
+ margin = MARGIN (sbw);
+ tzl = sbw->scrollbar.length - 2 * margin;
+ newtop = margin + (int)(tzl * sbw->scrollbar.top);
+ newbot = newtop + (int)(tzl * sbw->scrollbar.shown) + 1;
+ if (newbot < newtop + (int)sbw->scrollbar.min_thumb)
+ newbot = newtop + sbw->scrollbar.min_thumb;
+
+ oldtop = sbw->scrollbar.topLoc;
+ oldbot = oldtop + sbw->scrollbar.shownLength;
+ sbw->scrollbar.topLoc = newtop;
+ sbw->scrollbar.shownLength = newbot - newtop;
+ if (XtIsRealized ((Widget) sbw))
+ {
+ if (newtop < oldtop)
+ FillArea(sbw, newtop, AT_MIN(newbot, oldtop+1),1,0);
+ if (newtop > oldtop)
+ FillArea(sbw, oldtop, AT_MIN(newtop, oldbot ),0,0);
+ if (newbot < oldbot)
+ FillArea(sbw, AT_MAX(newbot, oldtop), oldbot, 0,0);
+ if (newbot > oldbot)
+ FillArea(sbw, AT_MAX(newtop, oldbot-1), newbot, 1,0);
+
+ /* Only draw the missing shadows */
+ FillArea(sbw, newtop, newbot, 0, 1);
+ }
+}
+
+ static void
+PaintArrows(ScrollbarWidget sbw)
+{
+ XPoint point[6];
+ Dimension thickness = sbw->scrollbar.thickness - 1;
+ Dimension size;
+ Dimension off;
+
+ if (XtIsRealized((Widget) sbw))
+ {
+ if ((int)thickness * 2 > (int)sbw->scrollbar.length)
+ {
+ size = sbw->scrollbar.length / 2;
+ off = (int)(thickness - size) / 2;
+ }
+ else
+ {
+ size = thickness;
+ off = 0;
+ }
+ point[0].x = off + sbw->scrollbar.shadow_width;
+ point[0].y = size;
+ point[1].x = thickness - off - sbw->scrollbar.shadow_width;
+ point[1].y = size;
+ point[2].x = thickness / 2;
+ point[2].y = sbw->scrollbar.shadow_width;
+
+ point[3].x = off + sbw->scrollbar.shadow_width;
+ point[3].y = sbw->scrollbar.length - size;
+ point[4].x = thickness - off - sbw->scrollbar.shadow_width;
+ point[4].y = sbw->scrollbar.length - size;
+ point[5].x = thickness / 2;
+ point[5].y = sbw->scrollbar.length - sbw->scrollbar.shadow_width - 1;
+
+ /* horizontal arrows require that x and y coordinates be swapped */
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ int n;
+ int swap;
+ for (n = 0; n < 6; n++)
+ {
+ swap = point[n].x;
+ point[n].x = point[n].y;
+ point[n].y = swap;
+ }
+ }
+ /* draw the up/left arrow */
+ XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.gc,
+ point, 3,
+ Convex, CoordModeOrigin);
+ XDrawLines (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ point, 3,
+ CoordModeOrigin);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[0].x, point[0].y,
+ point[2].x, point[2].y);
+ /* draw the down/right arrow */
+ XFillPolygon (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.gc,
+ point+3, 3,
+ Convex, CoordModeOrigin);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[3].x, point[3].y,
+ point[4].x, point[4].y);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.top_shadow_GC,
+ point[3].x, point[3].y,
+ point[5].x, point[5].y);
+ XDrawLine (XtDisplay ((Widget) sbw), XtWindow ((Widget) sbw),
+ sbw->scrollbar.bot_shadow_GC,
+ point[4].x, point[4].y,
+ point[5].x, point[5].y);
+ }
+}
+
+ static void
+Destroy(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ if (sbw->scrollbar.timer_id != (XtIntervalId) 0)
+ XtRemoveTimeOut (sbw->scrollbar.timer_id);
+ XtReleaseGC(w, sbw->scrollbar.gc);
+ XtReleaseGC(w, sbw->scrollbar.top_shadow_GC);
+ XtReleaseGC(w, sbw->scrollbar.bot_shadow_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;
+
+ if (XGetGeometry (XtDisplay(w), sbw->scrollbar.thumb, &root, &x, &y,
+ &width, &height, &bw, &depth) == 0)
+ emsg(_("Scrollbar Widget: Could not get geometry of thumb pixmap."));
+ }
+
+ gcValues.foreground = sbw->scrollbar.foreground;
+ gcValues.background = sbw->core.background_pixel;
+ mask = GCForeground | GCBackground;
+
+ if (sbw->scrollbar.thumb != None)
+ {
+ gcValues.fill_style = FillSolid;
+ mask |= GCFillStyle;
+ }
+ /* the creation should be non-caching, because */
+ /* we now set and clear clip masks on the gc returned */
+ sbw->scrollbar.gc = XtGetGC (w, mask, &gcValues);
+}
+
+ static void
+SetDimensions(ScrollbarWidget sbw)
+{
+ if (sbw->scrollbar.orientation == XtorientVertical)
+ {
+ sbw->scrollbar.length = sbw->core.height;
+ sbw->scrollbar.thickness = sbw->core.width;
+ }
+ else
+ {
+ sbw->scrollbar.length = sbw->core.width;
+ sbw->scrollbar.thickness = sbw->core.height;
+ }
+}
+
+ static void
+Initialize(
+ Widget request UNUSED, /* what the client asked for */
+ Widget new, /* what we're going to give him */
+ ArgList args UNUSED,
+ Cardinal *num_args UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) new;
+
+ CreateGC(new);
+ AllocTopShadowGC(new);
+ AllocBotShadowGC(new);
+
+ if (sbw->core.width == 0)
+ sbw->core.width = (sbw->scrollbar.orientation == XtorientVertical)
+ ? sbw->scrollbar.thickness : sbw->scrollbar.length;
+
+ if (sbw->core.height == 0)
+ sbw->core.height = (sbw->scrollbar.orientation == XtorientHorizontal)
+ ? sbw->scrollbar.thickness : sbw->scrollbar.length;
+
+ SetDimensions(sbw);
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ sbw->scrollbar.timer_id = (XtIntervalId)0;
+ sbw->scrollbar.topLoc = 0;
+ sbw->scrollbar.shownLength = sbw->scrollbar.min_thumb;
+}
+
+ static void
+Realize(
+ Widget w,
+ Mask *valueMask,
+ XSetWindowAttributes *attributes)
+{
+ /* The Simple widget actually stuffs the value in the valuemask. */
+ (*vim_scrollbarWidgetClass->core_class.superclass->core_class.realize)
+ (w, valueMask, attributes);
+}
+
+ static Boolean
+SetValues(
+ Widget current, /* what I am */
+ Widget request UNUSED, /* what he wants me to be */
+ Widget desired, /* what I will become */
+ ArgList args UNUSED,
+ Cardinal *num_args UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) current;
+ ScrollbarWidget dsbw = (ScrollbarWidget) desired;
+ Boolean redraw = FALSE;
+
+/*
+ * If these values are outside the acceptable range ignore them...
+ */
+ if (dsbw->scrollbar.top < 0.0 || dsbw->scrollbar.top > 1.0)
+ dsbw->scrollbar.top = sbw->scrollbar.top;
+
+ if (dsbw->scrollbar.shown < 0.0 || dsbw->scrollbar.shown > 1.0)
+ dsbw->scrollbar.shown = sbw->scrollbar.shown;
+
+/*
+ * Change colors and stuff...
+ */
+ if (XtIsRealized(desired))
+ {
+ if (sbw->scrollbar.foreground != dsbw->scrollbar.foreground ||
+ sbw->core.background_pixel != dsbw->core.background_pixel ||
+ sbw->scrollbar.thumb != dsbw->scrollbar.thumb)
+ {
+ XtReleaseGC(desired, sbw->scrollbar.gc);
+ CreateGC (desired);
+ redraw = TRUE;
+ }
+ if (sbw->scrollbar.top != dsbw->scrollbar.top ||
+ sbw->scrollbar.shown != dsbw->scrollbar.shown)
+ redraw = TRUE;
+ }
+ return redraw;
+}
+
+ static void
+Resize(Widget w)
+{
+ /* ForgetGravity has taken care of background, but thumb may
+ * have to move as a result of the new size. */
+ SetDimensions ((ScrollbarWidget) w);
+ Redisplay(w, (XEvent*) NULL, (Region)NULL);
+}
+
+
+ static void
+Redisplay(Widget w, XEvent *event, Region region)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ int x, y;
+ unsigned int width, height;
+
+ _Xaw3dDrawShadows(w, event, region, FALSE);
+
+ if (sbw->scrollbar.orientation == XtorientHorizontal)
+ {
+ x = sbw->scrollbar.topLoc;
+ y = 1;
+ width = sbw->scrollbar.shownLength;
+ height = sbw->core.height - 2;
+ }
+ else
+ {
+ x = 1;
+ y = sbw->scrollbar.topLoc;
+ width = sbw->core.width - 2;
+ height = sbw->scrollbar.shownLength;
+ }
+ if (region == NULL ||
+ XRectInRegion (region, x, y, width, height) != RectangleOut)
+ {
+ /* Forces entire thumb to be painted. */
+ sbw->scrollbar.topLoc = -(sbw->scrollbar.length + 1);
+ PaintThumb (sbw);
+ }
+ /* we'd like to be region aware here!!!! */
+ PaintArrows(sbw);
+}
+
+
+ static Boolean
+CompareEvents(XEvent *oldEvent, XEvent *newEvent)
+{
+#define Check(field) \
+ do { \
+ if (newEvent->field != oldEvent->field) \
+ return False; \
+ } while (0)
+
+ 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 Boolean
+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);
+
+ return CompareEvents (event, &newEvent);
+}
+
+
+ static void
+ExtractPosition(
+ XEvent *event,
+ Position *x, /* RETURN */
+ Position *y, /* RETURN */
+ unsigned int *state) /* RETURN */
+{
+ switch (event->type)
+ {
+ case MotionNotify:
+ *x = event->xmotion.x;
+ *y = event->xmotion.y;
+ if (state != NULL)
+ *state = event->xmotion.state;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x;
+ *y = event->xbutton.y;
+ if (state != NULL)
+ *state = event->xbutton.state;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x;
+ *y = event->xkey.y;
+ if (state != NULL)
+ *state = event->xkey.state;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x;
+ *y = event->xcrossing.y;
+ if (state != NULL)
+ *state = event->xcrossing.state;
+ break;
+ default:
+ *x = 0; *y = 0;
+ if (state != NULL)
+ *state = 0;
+ }
+}
+
+ static void
+HandleThumb(
+ Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ Position x, y, loc;
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ ExtractPosition(event, &x, &y, (unsigned int *)NULL);
+ loc = PICKLENGTH(sbw, x, y);
+ /* if the motion event puts the pointer in thumb, call Move and Notify */
+ /* also call Move and Notify if we're already in continuous scroll mode */
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT ||
+ (loc >= sbw->scrollbar.topLoc &&
+ loc <= sbw->scrollbar.topLoc + (int)sbw->scrollbar.shownLength))
+ {
+ XtCallActionProc(w, "MoveThumb", event, params, *num_params);
+ XtCallActionProc(w, "NotifyThumb", event, params, *num_params);
+ }
+}
+
+ static void
+RepeatNotify(XtPointer client_data, XtIntervalId *idp UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) client_data;
+ int call_data;
+ char mode = sbw->scrollbar.scroll_mode;
+ unsigned long rep;
+
+ if (mode == SMODE_NONE || mode == SMODE_CONT)
+ {
+ sbw->scrollbar.timer_id = (XtIntervalId)0;
+ return;
+ }
+
+ if (mode == SMODE_LINE_DOWN || mode == SMODE_LINE_UP)
+ {
+ call_data = ONE_LINE_DATA;
+ rep = LINE_REPEAT;
+ }
+ else
+ {
+ call_data = ONE_PAGE_DATA;
+ rep = PAGE_REPEAT;
+ }
+
+ if (mode == SMODE_PAGE_UP || mode == SMODE_LINE_UP)
+ call_data = -call_data;
+
+ XtCallCallbacks((Widget)sbw, XtNscrollProc, (XtPointer)(long_u)call_data);
+
+ sbw->scrollbar.timer_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)sbw),
+ rep,
+ RepeatNotify,
+ client_data);
+}
+
+/*
+ * Same as above, but for floating numbers.
+ */
+ static float
+FloatInRange(float num, float small, float big)
+{
+ return (num < small) ? small : ((num > big) ? big : num);
+}
+
+ static void
+ScrollOneLineUp(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, -ONE_LINE_DATA);
+}
+
+ static void
+ScrollOneLineDown(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, ONE_LINE_DATA);
+}
+
+ static void
+ScrollPageDown(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, ONE_PAGE_DATA);
+}
+
+ static void
+ScrollPageUp(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollSome(w, event, -ONE_PAGE_DATA);
+}
+
+ static void
+ScrollSome(
+ Widget w,
+ XEvent *event,
+ int call_data)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
+ return;
+
+ if (LookAhead(w, event))
+ return;
+
+ sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
+ XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
+}
+
+ static void
+NotifyScroll(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ Position x, y, loc;
+ Dimension arrow_size;
+ unsigned long delay = 0;
+ int call_data = 0;
+ unsigned int state;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if scroll continuous */
+ return;
+
+ if (LookAhead (w, event))
+ return;
+
+ ExtractPosition(event, &x, &y, &state);
+ loc = PICKLENGTH(sbw, x, y);
+
+ if ((int)sbw->scrollbar.thickness * 2 > (int)sbw->scrollbar.length)
+ arrow_size = sbw->scrollbar.length / 2;
+ else
+ arrow_size = sbw->scrollbar.thickness;
+
+ /*
+ * handle CTRL modifier
+ */
+ if (state & ControlMask)
+ {
+ if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
+ call_data = END_PAGE_DATA;
+ else
+ call_data = -END_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ }
+ /*
+ * handle first arrow zone
+ */
+ else if (loc < (Position)arrow_size)
+ {
+ call_data = -ONE_LINE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_LINE_UP;
+ delay = LINE_DELAY;
+ }
+
+ /*
+ * handle last arrow zone
+ */
+ else if (loc > (Position)(sbw->scrollbar.length - arrow_size))
+ {
+ call_data = ONE_LINE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_LINE_DOWN;
+ delay = LINE_DELAY;
+ }
+
+ /*
+ * handle zone "above" the thumb
+ */
+ else if (loc < sbw->scrollbar.topLoc)
+ {
+ call_data = -ONE_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_PAGE_UP;
+ delay = PAGE_DELAY;
+ }
+
+ /*
+ * handle zone "below" the thumb
+ */
+ else if (loc > sbw->scrollbar.topLoc + (Position)sbw->scrollbar.shownLength)
+ {
+ call_data = ONE_PAGE_DATA;
+ sbw->scrollbar.scroll_mode = SMODE_PAGE_DOWN;
+ delay = PAGE_DELAY;
+ }
+
+ if (call_data)
+ XtCallCallbacks(w, XtNscrollProc, (XtPointer)(long_u)call_data);
+
+ /* establish autoscroll */
+ if (delay)
+ sbw->scrollbar.timer_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext(w),
+ delay, RepeatNotify, (XtPointer)w);
+}
+
+ static void
+EndScroll(
+ Widget w,
+ XEvent *event UNUSED,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ sbw->scrollbar.scroll_mode = SMODE_NONE;
+ /* no need to remove any autoscroll timeout; it will no-op */
+ /* because the scroll_mode is SMODE_NONE */
+ /* but be sure to remove timeout in destroy proc */
+}
+
+ static float
+FractionLoc(ScrollbarWidget sbw, int x, int y)
+{
+ int margin;
+ float height, width;
+
+ margin = MARGIN(sbw);
+ x -= margin;
+ y -= margin;
+ height = (float)sbw->core.height - 2 * margin;
+ width = (float)sbw->core.width - 2 * margin;
+ return PICKLENGTH(sbw, x / width, y / height);
+}
+
+ static void
+MoveThumb(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+ Position x, y;
+ float top;
+ char old_mode = sbw->scrollbar.scroll_mode;
+
+ sbw->scrollbar.scroll_mode = SMODE_CONT; /* indicate continuous scroll */
+
+ if (LookAhead(w, event))
+ return;
+
+ if (!event->xmotion.same_screen)
+ return;
+
+ ExtractPosition(event, &x, &y, (unsigned int *)NULL);
+
+ top = FractionLoc(sbw, x, y);
+
+ if (old_mode != SMODE_CONT) /* start dragging: set offset */
+ {
+ if (event->xbutton.button == Button2)
+ sbw->scrollbar.scroll_off = sbw->scrollbar.shown / 2.;
+ else
+ sbw->scrollbar.scroll_off = top - sbw->scrollbar.top;
+ }
+
+ top -= sbw->scrollbar.scroll_off;
+ if (sbw->scrollbar.limit_thumb)
+ top = FloatInRange(top, 0.0,
+ sbw->scrollbar.max - sbw->scrollbar.shown + 0.000001);
+ else
+ top = FloatInRange(top, 0.0, sbw->scrollbar.max);
+
+ sbw->scrollbar.top = top;
+ PaintThumb(sbw);
+ XFlush(XtDisplay(w)); /* re-draw it before Notifying */
+}
+
+
+ static void
+NotifyThumb(
+ Widget w,
+ XEvent *event,
+ String *params UNUSED,
+ Cardinal *num_params UNUSED)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget)w;
+ /* Use a union to avoid a warning for the weird conversion from float to
+ * XtPointer. Comes from Xaw/Scrollbar.c. */
+ union {
+ XtPointer xtp;
+ float xtf;
+ } xtpf;
+
+ if (LookAhead(w, 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 = sbw->scrollbar.top;
+ XtCallCallbacks(w, XtNthumbProc, xtpf.xtp);
+ XtCallCallbacks(w, XtNjumpProc, (XtPointer)&sbw->scrollbar.top);
+}
+
+ static void
+AllocTopShadowGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground;
+ myXGCV.foreground = sbw->scrollbar.top_shadow_pixel;
+ sbw->scrollbar.top_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
+}
+
+ static void
+AllocBotShadowGC(Widget w)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground;
+ myXGCV.foreground = sbw->scrollbar.bot_shadow_pixel;
+ sbw->scrollbar.bot_shadow_GC = XtGetGC(w, valuemask, &myXGCV);
+}
+
+ static void
+_Xaw3dDrawShadows(
+ Widget gw,
+ XEvent *event UNUSED,
+ Region region,
+ int out)
+{
+ XPoint pt[6];
+ ScrollbarWidget sbw = (ScrollbarWidget) gw;
+ Dimension s = sbw->scrollbar.shadow_width;
+ /*
+ * draw the shadows using the core part width and height,
+ * and the scrollbar part shadow_width.
+ *
+ * no point to do anything if the shadow_width is 0 or the
+ * widget has not been realized.
+ */
+ if (s > 0 && XtIsRealized(gw))
+ {
+ Dimension h = sbw->core.height;
+ Dimension w = sbw->core.width;
+ Dimension wms = w - s;
+ Dimension hms = h - s;
+ Display *dpy = XtDisplay (gw);
+ Window win = XtWindow (gw);
+ GC top, bot;
+
+ if (out)
+ {
+ top = sbw->scrollbar.top_shadow_GC;
+ bot = sbw->scrollbar.bot_shadow_GC;
+ }
+ else
+ {
+ top = sbw->scrollbar.bot_shadow_GC;
+ bot = sbw->scrollbar.top_shadow_GC;
+ }
+
+ /* top-left shadow */
+ if ((region == NULL) ||
+ (XRectInRegion (region, 0, 0, w, s) != RectangleOut) ||
+ (XRectInRegion (region, 0, 0, s, h) != RectangleOut))
+ {
+ pt[0].x = 0; pt[0].y = h;
+ pt[1].x = pt[1].y = 0;
+ pt[2].x = w; pt[2].y = 0;
+ pt[3].x = wms; pt[3].y = s;
+ pt[4].x = pt[4].y = s;
+ pt[5].x = s; pt[5].y = hms;
+ XFillPolygon (dpy, win, top, pt, 6, Complex, CoordModeOrigin);
+ }
+
+ /* bottom-right shadow */
+ if ((region == NULL) ||
+ (XRectInRegion (region, 0, hms, w, s) != RectangleOut) ||
+ (XRectInRegion (region, wms, 0, s, h) != RectangleOut))
+ {
+ pt[0].x = 0; pt[0].y = h;
+ pt[1].x = w; pt[1].y = h;
+ pt[2].x = w; pt[2].y = 0;
+ pt[3].x = wms; pt[3].y = s;
+ pt[4].x = wms; pt[4].y = hms;
+ pt[5].x = s; pt[5].y = hms;
+ XFillPolygon (dpy, win, bot, pt, 6, Complex, CoordModeOrigin);
+ }
+ }
+}
+
+
+/*
+ * Set the scroll bar to the given location.
+ */
+ void
+vim_XawScrollbarSetThumb(Widget w, double top, double shown, double max)
+{
+ ScrollbarWidget sbw = (ScrollbarWidget) w;
+
+ if (sbw->scrollbar.scroll_mode == SMODE_CONT) /* if still thumbing */
+ return;
+
+ sbw->scrollbar.max = (max > 1.0) ? 1.0 :
+ (max >= 0.0) ? max : sbw->scrollbar.max;
+
+ sbw->scrollbar.top = (top > sbw->scrollbar.max) ? sbw->scrollbar.max :
+ (top >= 0.0) ? top : sbw->scrollbar.top;
+
+ sbw->scrollbar.shown = (shown > 1.0) ? 1.0 :
+ (shown >= 0.0) ? shown : sbw->scrollbar.shown;
+
+ PaintThumb(sbw);
+}