| /* vi:set ts=8 sts=4 sw=4: */ |
| /* |
| * 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 <X11/IntrinsicP.h> |
| #include <X11/StringDefs.h> |
| |
| #include <X11/Xaw/XawInit.h> |
| #include "vim.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) 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 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); |
| } |