home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / tkstep0.3b3 / tkstep0 / tkstep / tkScrollbar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-08  |  49.2 KB  |  1,585 lines

  1. /* 
  2.  * tkScrollbar.c --
  3.  *
  4.  *    This module implements a scrollbar widgets for the Tk
  5.  *    toolkit.  A scrollbar displays a slider and two arrows;
  6.  *    mouse clicks on features within the scrollbar cause
  7.  *    scrolling commands to be invoked.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) tkScrollbar.c 1.79 96/02/15 18:52:40
  16.  */
  17. /*
  18.  * TkSTEP modifications Copyright
  19.  * by Alfredo K. Kojima 
  20.  */ 
  21.  
  22. #include "tkPort.h"
  23. #include "default.h"
  24. #include "tkInt.h"
  25.  
  26. /*
  27.  * A data structure of the following type is kept for each scrollbar
  28.  * widget managed by this file:
  29.  */
  30.  
  31. typedef struct {
  32.     Tk_Window tkwin;        /* Window that embodies the scrollbar.  NULL
  33.                  * means that the window has been destroyed
  34.                  * but the data structures haven't yet been
  35.                  * cleaned up.*/
  36.     Display *display;        /* Display containing widget.  Used, among
  37.                  * other things, so that resources can be
  38.                  * freed even after tkwin has gone away. */
  39.     Tcl_Interp *interp;        /* Interpreter associated with scrollbar. */
  40.     Tcl_Command widgetCmd;    /* Token for scrollbar's widget command. */
  41.     Tk_Uid orientUid;        /* Orientation for window ("vertical" or
  42.                  * "horizontal"). */
  43.     int vertical;        /* Non-zero means vertical orientation
  44.                  * requested, zero means horizontal. */
  45.     int width;            /* Desired narrow dimension of scrollbar,
  46.                  * in pixels. */
  47.     char *command;        /* Command prefix to use when invoking
  48.                  * scrolling commands.  NULL means don't
  49.                  * invoke commands.  Malloc'ed. */
  50.     int commandSize;        /* Number of non-NULL bytes in command. */
  51.     int repeatDelay;        /* How long to wait before auto-repeating
  52.                  * on scrolling actions (in ms). */
  53.     int repeatInterval;        /* Interval between autorepeats (in ms). */
  54.     int jump;            /* Value of -jump option. */
  55.  
  56.     /*
  57.      * Information used when displaying widget:
  58.      */
  59.  
  60.     int borderWidth;        /* Width of 3-D borders. */
  61.     Tk_3DBorder bgBorder;    /* Used for drawing background (all flat
  62.                  * surfaces except for trough). */
  63.     Tk_3DBorder activeBorder;    /* For drawing backgrounds when active (i.e.
  64.                  * when mouse is positioned over element). */
  65.     XColor *troughColorPtr;    /* Color for drawing trough. */
  66.     XColor *darkPtr;        /* Color for background stipple */    
  67.     GC troughGC;        /* For drawing trough's stippled part. */
  68.     GC troughBackGC;        /* For drawing trough */
  69.     GC copyGC;            /* Used for copying from pixmap onto screen. */
  70.     int relief;            /* Indicates whether window as a whole is
  71.                  * raised, sunken, or flat. */
  72.     int highlightWidth;        /* Width in pixels of highlight to draw
  73.                  * around widget when it has the focus.
  74.                  * <= 0 means don't draw a highlight. */
  75.     XColor *highlightBgColorPtr;
  76.                 /* Color for drawing traversal highlight
  77.                  * area when highlight is off. */
  78.     XColor *highlightColorPtr;    /* Color for drawing traversal highlight. */
  79.     Pixmap stipple;        /* trough base pattern */
  80.     Pixmap bump;        /* bump in the slider */
  81.     int inset;            /* Total width of all borders, including
  82.                  * traversal highlight and 3-D border.
  83.                  * Indicates how much interior stuff must
  84.                  * be offset from outside edges to leave
  85.                  * room for borders. */
  86.     int elementBorderWidth;    /* Width of border to draw around elements
  87.                  * inside scrollbar (arrows and slider).
  88.                  * -1 means use borderWidth. */
  89.     int arrowLength;        /* Length of arrows along long dimension of
  90.                  * scrollbar, including space for a small gap
  91.                  * between the arrow and the slider.
  92.                  * Recomputed on window size changes. */
  93.     int sliderFirst;        /* Pixel coordinate of top or left edge
  94.                  * of slider area, including border. */
  95.     int sliderLast;        /* Coordinate of pixel just after bottom
  96.                  * or right edge of slider area, including
  97.                  * border. */
  98.     int activeField;        /* Names field to be displayed in active
  99.                  * colors, such as TOP_ARROW, or 0 for
  100.                  * no field. */
  101.     int activeRelief;        /* Value of -activeRelief option: relief
  102.                  * to use for active element. */
  103.  
  104.     /*
  105.      * Information describing the application related to the scrollbar.
  106.      * This information is provided by the application by invoking the
  107.      * "set" widget command.  This information can now be provided in
  108.      * two ways:  the "old" form (totalUnits, windowUnits, firstUnit,
  109.      * and lastUnit), or the "new" form (firstFraction and lastFraction).
  110.      * FirstFraction and lastFraction will always be valid, but
  111.      * the old-style information is only valid if the NEW_STYLE_COMMANDS
  112.      * flag is 0.
  113.      */
  114.  
  115.     int totalUnits;        /* Total dimension of application, in
  116.                  * units.  Valid only if the NEW_STYLE_COMMANDS
  117.                  * flag isn't set. */
  118.     int windowUnits;        /* Maximum number of units that can be
  119.                  * displayed in the window at once.  Valid
  120.                  * only if the NEW_STYLE_COMMANDS flag isn't
  121.                  * set. */
  122.     int firstUnit;        /* Number of last unit visible in
  123.                  * application's window.  Valid only if the
  124.                  * NEW_STYLE_COMMANDS flag isn't set. */
  125.     int lastUnit;        /* Index of last unit visible in window.
  126.                  * Valid only if the NEW_STYLE_COMMANDS
  127.                  * flag isn't set. */
  128.     double firstFraction;    /* Position of first visible thing in window,
  129.                  * specified as a fraction between 0 and
  130.                  * 1.0. */
  131.     double lastFraction;    /* Position of last visible thing in window,
  132.                  * specified as a fraction between 0 and
  133.                  * 1.0. */
  134.  
  135.     /*
  136.      * Miscellaneous information:
  137.      */
  138.  
  139.     Tk_Cursor cursor;        /* Current cursor for window, or None. */
  140.     char *takeFocus;        /* Value of -takefocus option;  not used in
  141.                  * the C code, but used by keyboard traversal
  142.                  * scripts.  Malloc'ed, but may be NULL. */
  143.     int flags;            /* Various flags;  see below for
  144.                  * definitions. */
  145. } Scrollbar;
  146.  
  147. /*
  148.  * Legal values for "activeField" field of Scrollbar structures.  These
  149.  * are also the return values from the ScrollbarPosition procedure.
  150.  */
  151.  
  152. #define OUTSIDE        0
  153. #define TOP_ARROW    1
  154. #define TOP_GAP        2
  155. #define SLIDER        3
  156. #define BOTTOM_GAP    4
  157. #define BOTTOM_ARROW    5
  158.  
  159. /*
  160.  * Flag bits for scrollbars:
  161.  * 
  162.  * REDRAW_PENDING:        Non-zero means a DoWhenIdle handler
  163.  *                has already been queued to redraw
  164.  *                this window.
  165.  * NEW_STYLE_COMMANDS:        Non-zero means the new style of commands
  166.  *                should be used to communicate with the
  167.  *                widget:  ".t yview scroll 2 lines", instead
  168.  *                of ".t yview 40", for example.
  169.  * GOT_FOCUS:            Non-zero means this window has the input
  170.  *                focus.
  171.  */
  172.  
  173. #define REDRAW_PENDING        1
  174. #define NEW_STYLE_COMMANDS    2
  175. #define GOT_FOCUS        4
  176.  
  177. #define RECONFIGURE        256
  178. /*
  179.  * Minimum slider length, in pixels (designed to make sure that the slider
  180.  * is always easy to grab with the mouse).
  181.  */
  182.  
  183. #define MIN_SLIDER_LENGTH    5
  184.  
  185. /*
  186.  * If you want to make Tk ignore attribute settings that may be violating
  187.  * NEXTSTEP(tm) styles leave DISABLE_FORCE_STEP undef'ed, otherwise define it
  188.  * somewhere
  189.  */
  190. #ifndef DISABLE_FORCE_STEP
  191. #  define DISABLE_CHANGE    TK_CONFIG_DONT_CHANGE_DEFAULT
  192. #else
  193. #  define DISABLE_CHANGE    0
  194. #endif
  195.  
  196. /*
  197.  * Information used for argv parsing.
  198.  */
  199.  
  200. static Tk_ConfigSpec configSpecs[] = {
  201.     {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
  202.     DEF_SCROLLBAR_ACTIVE_BG_COLOR, Tk_Offset(Scrollbar, activeBorder),
  203.     TK_CONFIG_COLOR_ONLY|DISABLE_CHANGE},
  204.     {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
  205.     DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(Scrollbar, activeBorder),
  206.     TK_CONFIG_MONO_ONLY|DISABLE_CHANGE},
  207.     {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief",
  208.     DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(Scrollbar, activeRelief), 
  209.         0},
  210.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  211.     DEF_SCROLLBAR_BG_COLOR, Tk_Offset(Scrollbar, bgBorder),
  212.     TK_CONFIG_COLOR_ONLY|DISABLE_CHANGE},
  213.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  214.     DEF_SCROLLBAR_BG_MONO, Tk_Offset(Scrollbar, bgBorder),
  215.     TK_CONFIG_MONO_ONLY|DISABLE_CHANGE},
  216.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  217.     (char *) NULL, 0, 0},
  218.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  219.     (char *) NULL, 0, 0},
  220.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  221.     DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(Scrollbar, borderWidth), 
  222.         DISABLE_CHANGE},
  223.     {TK_CONFIG_STRING, "-command", "command", "Command",
  224.     DEF_SCROLLBAR_COMMAND, Tk_Offset(Scrollbar, command),
  225.     TK_CONFIG_NULL_OK},
  226.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  227.     DEF_SCROLLBAR_CURSOR, Tk_Offset(Scrollbar, cursor), TK_CONFIG_NULL_OK},
  228.     {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth",
  229.     "BorderWidth", DEF_SCROLLBAR_EL_BORDER_WIDTH,
  230.     Tk_Offset(Scrollbar, elementBorderWidth), 0},
  231.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  232.     "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG,
  233.     Tk_Offset(Scrollbar, highlightBgColorPtr), 
  234.         DISABLE_CHANGE},
  235.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  236.     DEF_SCROLLBAR_HIGHLIGHT,
  237.     Tk_Offset(Scrollbar, highlightColorPtr), 
  238.         DISABLE_CHANGE},
  239.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  240.     "HighlightThickness",
  241.     DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(Scrollbar, highlightWidth), 
  242.         DISABLE_CHANGE},
  243.     {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump",
  244.     DEF_SCROLLBAR_JUMP, Tk_Offset(Scrollbar, jump), 0},
  245.     {TK_CONFIG_UID, "-orient", "orient", "Orient",
  246.     DEF_SCROLLBAR_ORIENT, Tk_Offset(Scrollbar, orientUid), 0},
  247.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  248.     DEF_SCROLLBAR_RELIEF, Tk_Offset(Scrollbar, relief), 
  249.         DISABLE_CHANGE},
  250.     {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
  251.     DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(Scrollbar, repeatDelay), 0},
  252.     {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
  253.     DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(Scrollbar, repeatInterval), 0},
  254.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  255.     DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(Scrollbar, takeFocus),
  256.     TK_CONFIG_NULL_OK},
  257.     {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background",
  258.     DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(Scrollbar, troughColorPtr),
  259.     TK_CONFIG_COLOR_ONLY|DISABLE_CHANGE},
  260.     {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background",
  261.     DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(Scrollbar, troughColorPtr),
  262.     TK_CONFIG_MONO_ONLY|DISABLE_CHANGE},
  263.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  264.     DEF_SCROLLBAR_WIDTH, Tk_Offset(Scrollbar, width), 
  265.         DISABLE_CHANGE},
  266.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  267.     (char *) NULL, 0, 0}
  268. };
  269.  
  270.  
  271.  
  272. #define SB_BUMP_WIDTH  6
  273. #define SB_BUMP_HEIGHT 6
  274. static char scrollbar_bump[] = {
  275. " dbbb "\
  276. "dbdddd"\
  277. "bdd   "\
  278. "bd  ww"\
  279. "bd www"\
  280. " d ww "
  281. };
  282.  
  283.  
  284. static unsigned char scrollbar_bump_bmp[] = {
  285.    0x1e, 0x21, 0x39, 0x35, 0x3d, 0x1e};
  286.  
  287.  
  288. /*
  289.  * Forward declarations for procedures defined later in this file:
  290.  */
  291.  
  292. static void        ComputeScrollbarGeometry _ANSI_ARGS_((
  293.                 Scrollbar *scrollPtr));
  294. static int        ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp,
  295.                 Scrollbar *scrollPtr, int argc, char **argv,
  296.                 int flags));
  297. static void        DestroyScrollbar _ANSI_ARGS_((char *memPtr));
  298. static void        DisplayScrollbar _ANSI_ARGS_((ClientData clientData));
  299. static void        EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr));
  300. static void        ScrollbarCmdDeletedProc _ANSI_ARGS_((
  301.                 ClientData clientData));
  302. static void        ScrollbarEventProc _ANSI_ARGS_((ClientData clientData,
  303.                 XEvent *eventPtr));
  304. static int        ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr,
  305.                 int x, int y));
  306. static int        ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData,
  307.                 Tcl_Interp *, int argc, char **argv));
  308.  
  309.  
  310. /*
  311.  *--------------------------------------------------------
  312.  * PaintPixmap -
  313.  *    Dirty routine to draw pixmaps from char data
  314.  *    
  315.  * gotta find a better way to do this...
  316.  *--------------------------------------------------------
  317.  */
  318. static void PaintPixmap(clientData, d, data, width, height)
  319.     ClientData clientData;
  320.     Drawable d;
  321.     char *data;
  322.     int width, height;
  323. {
  324.     int x, y, ofs=0;
  325.     Scrollbar *scrollPtr = (Scrollbar *)clientData;
  326.     Display *display = scrollPtr->display;
  327.     GC lightGC, backGC, darkGC, dark2GC;
  328.  
  329.  
  330.     backGC = Tk_3DBorderGC( scrollPtr->tkwin, scrollPtr->bgBorder, 
  331.                TK_3D_FLAT_GC);
  332.     lightGC = Tk_3DBorderGC( scrollPtr->tkwin, scrollPtr->bgBorder, 
  333.               TK_3D_LIGHT_GC);
  334.     darkGC = Tk_3DBorderGC( scrollPtr->tkwin, scrollPtr->bgBorder, 
  335.                TK_3D_DARK_GC);
  336.     dark2GC = Tk_3DBorderGC( scrollPtr->tkwin, scrollPtr->bgBorder, 
  337.                TK_3D_DARK2_GC);
  338.     for(y = 0; y < height; y++) {
  339.     for(x = 0; x < width; x++) {
  340.         switch (data[ofs++]) {
  341.          case 'b': /* black */
  342.         XDrawPoint( scrollPtr->display, d, dark2GC, x, y);
  343.         break;
  344.          case 'd': /* dark */
  345.         XDrawPoint( scrollPtr->display, d, darkGC, x, y);
  346.         break;
  347.          case 'w': /* white */
  348.         XDrawPoint( scrollPtr->display, d, lightGC, x, y);
  349.         break;
  350.          default:
  351.         XDrawPoint( scrollPtr->display, d, backGC, x, y);
  352.         }
  353.     }
  354.     }
  355. }
  356.  
  357.  
  358. /*
  359.  *---------------------------------------------
  360.  *  
  361.  * MakePixmaps
  362.  *   Make pixmaps needed by scrollbar with 
  363.  * PaintPixmap
  364.  *
  365.  *---------------------------------------------
  366.  */
  367. static void MakePixmaps(clientData)
  368.     ClientData clientData;
  369. {
  370.     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
  371.  
  372.     if (Tk_Depth(scrollPtr->tkwin) > 1) {
  373.     scrollPtr->bump = Tk_GetPixmap( scrollPtr->display, 
  374.         Tk_WindowId(scrollPtr->tkwin),
  375.         SB_BUMP_WIDTH, SB_BUMP_HEIGHT, Tk_Depth(scrollPtr->tkwin) );
  376.     PaintPixmap(clientData, scrollPtr->bump, scrollbar_bump,
  377.             SB_BUMP_WIDTH, SB_BUMP_HEIGHT);
  378.     
  379.     } else { /* monochrome display */
  380.     scrollPtr->bump = XCreateBitmapFromData( scrollPtr->display,
  381.         Tk_WindowId(scrollPtr->tkwin), scrollbar_bump_bmp,
  382.         SB_BUMP_WIDTH, SB_BUMP_HEIGHT);
  383.     }
  384. }
  385.  
  386. /*
  387.  *--------------------------------------------------------------
  388.  *
  389.  * Tk_ScrollbarCmd --
  390.  *
  391.  *    This procedure is invoked to process the "scrollbar" Tcl
  392.  *    command.  See the user documentation for details on what
  393.  *    it does.
  394.  *
  395.  * Results:
  396.  *    A standard Tcl result.
  397.  *
  398.  * Side effects:
  399.  *    See the user documentation.
  400.  *
  401.  *--------------------------------------------------------------
  402.  */
  403.  
  404. int
  405. Tk_ScrollbarCmd(clientData, interp, argc, argv)
  406.     ClientData clientData;    /* Main window associated with
  407.                  * interpreter. */
  408.     Tcl_Interp *interp;        /* Current interpreter. */
  409.     int argc;            /* Number of arguments. */
  410.     char **argv;        /* Argument strings. */
  411. {
  412.     Tk_Window tkwin = (Tk_Window) clientData;
  413.     register Scrollbar *scrollPtr;
  414.     Tk_Window new;
  415.  
  416.     if (argc < 2) {
  417.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  418.         argv[0], " pathName ?options?\"", (char *) NULL);
  419.     return TCL_ERROR;
  420.     }
  421.  
  422.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
  423.     if (new == NULL) {
  424.     return TCL_ERROR;
  425.     }
  426.  
  427.     /*
  428.      * Initialize fields that won't be initialized by ConfigureScrollbar,
  429.      * or which ConfigureScrollbar expects to have reasonable values
  430.      * (e.g. resource pointers).
  431.      */
  432.  
  433.     scrollPtr = (Scrollbar *) ckalloc(sizeof(Scrollbar));
  434.     scrollPtr->tkwin = new;
  435.     scrollPtr->display = Tk_Display(new);
  436.     scrollPtr->interp = interp;
  437.     scrollPtr->widgetCmd = Tcl_CreateCommand(interp,
  438.         Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd,
  439.         (ClientData) scrollPtr, ScrollbarCmdDeletedProc);
  440.     scrollPtr->orientUid = NULL;
  441.     scrollPtr->vertical = 0;
  442.     scrollPtr->width = 0;
  443.     scrollPtr->command = NULL;
  444.     scrollPtr->commandSize = 0;
  445.     scrollPtr->repeatDelay = 0;
  446.     scrollPtr->repeatInterval = 0;
  447.     scrollPtr->borderWidth = 0;
  448.     scrollPtr->bgBorder = NULL;
  449.     scrollPtr->activeBorder = NULL;
  450.     scrollPtr->troughColorPtr = NULL;
  451.     scrollPtr->darkPtr = NULL;
  452.     scrollPtr->troughBackGC = None;
  453.     scrollPtr->bump = None;
  454.     scrollPtr->stipple = None;    
  455.     scrollPtr->troughGC = None;
  456.     scrollPtr->copyGC = None;
  457.     scrollPtr->relief = TK_RELIEF_FLAT;
  458.     scrollPtr->highlightWidth = 0;
  459.     scrollPtr->highlightBgColorPtr = NULL;
  460.     scrollPtr->highlightColorPtr = NULL;
  461.     scrollPtr->inset = 0;
  462.     scrollPtr->elementBorderWidth = -1;
  463.     scrollPtr->arrowLength = 0;
  464.     scrollPtr->sliderFirst = 0;
  465.     scrollPtr->sliderLast = 0;
  466.     scrollPtr->activeField = 0;
  467.     scrollPtr->activeRelief = TK_RELIEF_RAISED;
  468.     scrollPtr->totalUnits = 0;
  469.     scrollPtr->windowUnits = 0;
  470.     scrollPtr->firstUnit = 0;
  471.     scrollPtr->lastUnit = 0;
  472.     scrollPtr->firstFraction = 0.0;
  473.     scrollPtr->lastFraction = 0.0;
  474.     scrollPtr->cursor = None;
  475.     scrollPtr->takeFocus = NULL;
  476.     scrollPtr->flags = 0;
  477.  
  478.     Tk_SetClass(scrollPtr->tkwin, "Scrollbar");
  479.     Tk_CreateEventHandler(scrollPtr->tkwin,
  480.         ExposureMask|StructureNotifyMask|FocusChangeMask,
  481.         ScrollbarEventProc, (ClientData) scrollPtr);
  482.     if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) {
  483.     goto error;
  484.     }
  485.  
  486.     interp->result = Tk_PathName(scrollPtr->tkwin);
  487.     return TCL_OK;
  488.  
  489.     error:
  490.     Tk_DestroyWindow(scrollPtr->tkwin);
  491.     return TCL_ERROR;
  492. }
  493.  
  494. /*
  495.  *--------------------------------------------------------------
  496.  *
  497.  * ScrollbarWidgetCmd --
  498.  *
  499.  *    This procedure is invoked to process the Tcl command
  500.  *    that corresponds to a widget managed by this module.
  501.  *    See the user documentation for details on what it does.
  502.  *
  503.  * Results:
  504.  *    A standard Tcl result.
  505.  *
  506.  * Side effects:
  507.  *    See the user documentation.
  508.  *
  509.  *--------------------------------------------------------------
  510.  */
  511.  
  512. static int
  513. ScrollbarWidgetCmd(clientData, interp, argc, argv)
  514.     ClientData clientData;    /* Information about scrollbar
  515.                      * widget. */
  516.     Tcl_Interp *interp;            /* Current interpreter. */
  517.     int argc;                /* Number of arguments. */
  518.     char **argv;            /* Argument strings. */
  519. {
  520.     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
  521.     int result = TCL_OK;
  522.     size_t length;
  523.     int c;
  524.  
  525.     if (argc < 2) {
  526.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  527.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  528.     return TCL_ERROR;
  529.     }
  530.     Tcl_Preserve((ClientData) scrollPtr);
  531.     c = argv[1][0];
  532.     length = strlen(argv[1]);
  533.     if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) {
  534.     if (argc == 2) {
  535.         switch (scrollPtr->activeField) {
  536.         case TOP_ARROW:        interp->result = "arrow1";    break;
  537.         case SLIDER:        interp->result = "slider";    break;
  538.         case BOTTOM_ARROW:    interp->result = "arrow2";    break;
  539.         }
  540.         goto done;
  541.     }
  542.     if (argc != 3) {
  543.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  544.             argv[0], " activate element\"", (char *) NULL);
  545.         goto error;
  546.     }
  547.     c = argv[2][0];
  548.     length = strlen(argv[2]);
  549.     if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) {
  550.         scrollPtr->activeField = TOP_ARROW;
  551.     } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) {
  552.         scrollPtr->activeField = BOTTOM_ARROW;
  553.     } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) {
  554.         scrollPtr->activeField = SLIDER;
  555.     } else {
  556.         scrollPtr->activeField = OUTSIDE;
  557.     }
  558.     EventuallyRedraw(scrollPtr);
  559.     } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  560.         && (length >= 2)) {
  561.     if (argc != 3) {
  562.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  563.             argv[0], " cget option\"",
  564.             (char *) NULL);
  565.         goto error;
  566.     }
  567.     result = Tk_ConfigureValue(interp, scrollPtr->tkwin, configSpecs,
  568.         (char *) scrollPtr, argv[2], 0);
  569.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  570.         && (length >= 2)) {
  571.     /* make sure that fg colors will be changed */    
  572.     scrollPtr->flags|=RECONFIGURE;
  573.     if (argc == 2) {
  574.         result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs,
  575.             (char *) scrollPtr, (char *) NULL, 0);
  576.     } else if (argc == 3) {
  577.         result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs,
  578.             (char *) scrollPtr, argv[2], 0);
  579.     } else {
  580.         result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2,
  581.             TK_CONFIG_ARGV_ONLY);
  582.     }
  583.     } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) {
  584.     int xDelta, yDelta, pixels, length;
  585.     double fraction;
  586.  
  587.     if (argc != 4) {
  588.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  589.             argv[0], " delta xDelta yDelta\"", (char *) NULL);
  590.         goto error;
  591.     }
  592.     if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK)
  593.         || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) {
  594.         goto error;
  595.     }
  596.     if (scrollPtr->vertical) {
  597.         pixels = yDelta;
  598.         length = Tk_Height(scrollPtr->tkwin) - 1
  599.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  600.     } else {
  601.         pixels = xDelta;
  602.         length = Tk_Width(scrollPtr->tkwin) - 1
  603.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  604.     }
  605.     if (length == 0) {
  606.         fraction = 0.0;
  607.     } else {
  608.         fraction = ((double) pixels / (double) length);
  609.     }
  610.     sprintf(interp->result, "%g", fraction);
  611.     } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) {
  612.     int x, y, pos, length;
  613.     double fraction;
  614.  
  615.     if (argc != 4) {
  616.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  617.             argv[0], " fraction x y\"", (char *) NULL);
  618.         goto error;
  619.     }
  620.     if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
  621.         || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
  622.         goto error;
  623.     }
  624.     if (scrollPtr->vertical) {
  625.         pos = y - (scrollPtr->arrowLength + scrollPtr->inset);
  626.         length = Tk_Height(scrollPtr->tkwin) - 1
  627.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  628.     } else {
  629.         pos = x - (scrollPtr->arrowLength + scrollPtr->inset);
  630.         length = Tk_Width(scrollPtr->tkwin) - 1
  631.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  632.     }
  633.     if (length == 0) {
  634.         fraction = 0.0;
  635.     } else {
  636.         fraction = ((double) pos / (double) length);
  637.     }
  638.     if (fraction < 0) {
  639.         fraction = 0;
  640.     } else if (fraction > 1.0) {
  641.         fraction = 1.0;
  642.     }
  643.     sprintf(interp->result, "%g", fraction);
  644.     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
  645.     if (argc != 2) {
  646.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  647.             argv[0], " get\"", (char *) NULL);
  648.         goto error;
  649.     }
  650.     if (scrollPtr->flags & NEW_STYLE_COMMANDS) {
  651.         char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE];
  652.  
  653.         Tcl_PrintDouble(interp, scrollPtr->firstFraction, first);
  654.         Tcl_PrintDouble(interp, scrollPtr->lastFraction, last);
  655.         Tcl_AppendResult(interp, first, " ", last, (char *) NULL);
  656.     } else {
  657.         sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits,
  658.             scrollPtr->windowUnits, scrollPtr->firstUnit,
  659.             scrollPtr->lastUnit);
  660.     }
  661.     } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) {
  662.     int x, y, thing;
  663.  
  664.     if (argc != 4) {
  665.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  666.             argv[0], " identify x y\"", (char *) NULL);
  667.         goto error;
  668.     }
  669.     if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
  670.         || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
  671.         goto error;
  672.     }
  673.     thing = ScrollbarPosition(scrollPtr, x,y);
  674.     switch (thing) {
  675.         case TOP_ARROW:    interp->result = "arrow1";    break;
  676.         case TOP_GAP:    interp->result = "trough1";    break;
  677.         case SLIDER:    interp->result = "slider";    break;
  678.         case BOTTOM_GAP:    interp->result = "trough2";    break;
  679.         case BOTTOM_ARROW:    interp->result = "arrow2";    break;
  680.     }
  681.     } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) {
  682.     int totalUnits, windowUnits, firstUnit, lastUnit;
  683.  
  684.     if (argc == 4) {
  685.         double first, last;
  686.  
  687.         if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) {
  688.         goto error;
  689.         }
  690.         if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) {
  691.         goto error;
  692.         }
  693.         if (first < 0) {
  694.         scrollPtr->firstFraction = 0;
  695.         } else if (first > 1.0) {
  696.         scrollPtr->firstFraction = 1.0;
  697.         } else {
  698.         scrollPtr->firstFraction = first;
  699.         }
  700.         if (last < scrollPtr->firstFraction) {
  701.         scrollPtr->lastFraction = scrollPtr->firstFraction;
  702.         } else if (last > 1.0) {
  703.         scrollPtr->lastFraction = 1.0;
  704.         } else {
  705.         scrollPtr->lastFraction = last;
  706.         }
  707.         scrollPtr->flags |= NEW_STYLE_COMMANDS;
  708.     } else if (argc == 6) {
  709.         if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) {
  710.         goto error;
  711.         }
  712.         if (totalUnits < 0) {
  713.         totalUnits = 0;
  714.         }
  715.         if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) {
  716.         goto error;
  717.         }
  718.         if (windowUnits < 0) {
  719.         windowUnits = 0;
  720.         }
  721.         if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) {
  722.         goto error;
  723.         }
  724.         if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) {
  725.         goto error;
  726.         }
  727.         if (totalUnits > 0) {
  728.         if (lastUnit < firstUnit) {
  729.             lastUnit = firstUnit;
  730.         }
  731.         } else {
  732.         firstUnit = lastUnit = 0;
  733.         }
  734.         scrollPtr->totalUnits = totalUnits;
  735.         scrollPtr->windowUnits = windowUnits;
  736.         scrollPtr->firstUnit = firstUnit;
  737.         scrollPtr->lastUnit = lastUnit;
  738.         if (scrollPtr->totalUnits == 0) {
  739.         scrollPtr->firstFraction = 0.0;
  740.         scrollPtr->lastFraction = 1.0;
  741.         } else {
  742.         scrollPtr->firstFraction = ((double) firstUnit)/totalUnits;
  743.         scrollPtr->lastFraction = ((double) (lastUnit+1))/totalUnits;
  744.         }
  745.         scrollPtr->flags &= ~NEW_STYLE_COMMANDS;
  746.     } else {
  747.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  748.             argv[0], " set firstFraction lastFraction\" or \"",
  749.             argv[0],
  750.             " set totalUnits windowUnits firstUnit lastUnit\"",
  751.             (char *) NULL);
  752.         goto error;
  753.     }
  754.     ComputeScrollbarGeometry(scrollPtr);
  755.     EventuallyRedraw(scrollPtr);
  756.     } else {
  757.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  758.         "\": must be activate, cget, configure, delta, fraction, ",
  759.         "get, identify, or set", (char *) NULL);
  760.     goto error;
  761.     }
  762.     done:
  763.     Tcl_Release((ClientData) scrollPtr);
  764.     return result;
  765.  
  766.     error:
  767.     Tcl_Release((ClientData) scrollPtr);
  768.     return TCL_ERROR;
  769. }
  770.  
  771. /*
  772.  *----------------------------------------------------------------------
  773.  *
  774.  * DestroyScrollbar --
  775.  *
  776.  *    This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  777.  *    to clean up the internal structure of a scrollbar at a safe time
  778.  *    (when no-one is using it anymore).
  779.  *
  780.  * Results:
  781.  *    None.
  782.  *
  783.  * Side effects:
  784.  *    Everything associated with the scrollbar is freed up.
  785.  *
  786.  *----------------------------------------------------------------------
  787.  */
  788.  
  789. static void
  790. DestroyScrollbar(memPtr)
  791.     char *memPtr;    /* Info about scrollbar widget. */
  792. {
  793.     register Scrollbar *scrollPtr = (Scrollbar *) memPtr;
  794.  
  795.     /*
  796.      * Free up all the stuff that requires special handling, then
  797.      * let Tk_FreeOptions handle all the standard option-related
  798.      * stuff.
  799.      */
  800.  
  801.     if (scrollPtr->troughGC != None) {
  802.     Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC);
  803.     }
  804.     if (scrollPtr->copyGC != None) {
  805.     Tk_FreeGC(scrollPtr->display, scrollPtr->copyGC);
  806.     }
  807.     if (scrollPtr->troughBackGC != None) {
  808.     Tk_FreeGC(scrollPtr->display, scrollPtr->troughBackGC);
  809.     }
  810.     if (scrollPtr->bump != None) {
  811.     Tk_FreePixmap(scrollPtr->display, scrollPtr->bump);
  812.     }
  813.     if (scrollPtr->stipple != None) {
  814.     Tk_FreeBitmap(scrollPtr->display, scrollPtr->stipple);
  815.     }    
  816.     if (scrollPtr->darkPtr != NULL) {
  817.     Tk_FreeColor(scrollPtr->darkPtr);
  818.     }    
  819.     Tk_FreeOptions(configSpecs, (char *) scrollPtr, scrollPtr->display, 0);
  820.     ckfree((char *) scrollPtr);
  821. }
  822.  
  823. /*
  824.  *----------------------------------------------------------------------
  825.  *
  826.  * ConfigureScrollbar --
  827.  *
  828.  *    This procedure is called to process an argv/argc list, plus
  829.  *    the Tk option database, in order to configure (or
  830.  *    reconfigure) a scrollbar widget.
  831.  *
  832.  * Results:
  833.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  834.  *    returned, then interp->result contains an error message.
  835.  *
  836.  * Side effects:
  837.  *    Configuration information, such as colors, border width,
  838.  *    etc. get set for scrollPtr;  old resources get freed,
  839.  *    if there were any.
  840.  *
  841.  *----------------------------------------------------------------------
  842.  */
  843. static int
  844. ConfigureScrollbar(interp, scrollPtr, argc, argv, flags)
  845.     Tcl_Interp *interp;            /* Used for error reporting. */
  846.     register Scrollbar *scrollPtr;    /* Information about widget;  may or
  847.                      * may not already have values for
  848.                      * some fields. */
  849.     int argc;                /* Number of valid entries in argv. */
  850.     char **argv;            /* Arguments. */
  851.     int flags;                /* Flags to pass to
  852.                      * Tk_ConfigureWidget. */
  853. {
  854.     size_t length;
  855.     XGCValues gcValues;
  856.     XColor newcolor;
  857.     GC new;
  858.  
  859.     if (Tk_StrictMotif(scrollPtr->tkwin)) {
  860.     flags|=TK_CONFIG_CHECK_MY_FLAG;
  861.     } 
  862.     if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, configSpecs,
  863.         argc, argv, (char *) scrollPtr, flags) != TCL_OK) {
  864.     return TCL_ERROR;
  865.     }
  866.     /*
  867.      * A few options need special processing, such as parsing the
  868.      * orientation or setting the background from a 3-D border.
  869.      */
  870.  
  871.     length = strlen(scrollPtr->orientUid);
  872.     if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) {
  873.     scrollPtr->vertical = 1;
  874.     } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) {
  875.     scrollPtr->vertical = 0;
  876.     } else {
  877.     Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid,
  878.         "\": must be vertical or horizontal", (char *) NULL);
  879.     return TCL_ERROR;
  880.     }
  881.  
  882.     if (scrollPtr->command != NULL) {
  883.     scrollPtr->commandSize = strlen(scrollPtr->command);
  884.     } else {
  885.     scrollPtr->commandSize = 0;
  886.     }
  887.  
  888.     if (scrollPtr->stipple==None) {
  889.     scrollPtr->stipple = Tk_GetBitmap((Tcl_Interp *)NULL, scrollPtr->tkwin,
  890.         Tk_GetUid("gray50"));
  891.     if (scrollPtr->stipple == None) {
  892.         panic("ScrollBar couldn't allocate bitmap for trough");
  893.     }
  894.     }
  895.     
  896.     Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder);    
  897.     /* alloc color for trough base stipple */
  898.     newcolor.red = (60 * (int) scrollPtr->troughColorPtr->red)/100;
  899.     newcolor.green =(60 * (int) scrollPtr->troughColorPtr->green)/100;
  900.     newcolor.blue = (60 * (int) scrollPtr->troughColorPtr->blue)/100;
  901.     
  902.     if (scrollPtr->darkPtr != NULL) {
  903.     Tk_FreeColor(scrollPtr->darkPtr);
  904.     }    
  905.     scrollPtr->darkPtr = Tk_GetColorByValue(scrollPtr->tkwin,
  906.     &newcolor);
  907.  
  908.     gcValues.background = scrollPtr->troughColorPtr->pixel;
  909.     gcValues.foreground = scrollPtr->darkPtr->pixel;   
  910.     gcValues.stipple = scrollPtr->stipple;
  911.     gcValues.fill_style = FillOpaqueStippled;
  912.  
  913.     new = Tk_GetGC(scrollPtr->tkwin, GCForeground|GCBackground|GCStipple|
  914.     GCFillStyle, &gcValues);
  915.     if (scrollPtr->troughGC != None) {
  916.     Tk_FreeGC(scrollPtr->display, scrollPtr->troughGC);
  917.     }
  918.     scrollPtr->troughGC = new;
  919.     gcValues.foreground = scrollPtr->troughColorPtr->pixel;
  920.     new = Tk_GetGC(scrollPtr->tkwin, GCForeground, &gcValues);
  921.     if (scrollPtr->troughBackGC != None) {
  922.     Tk_FreeGC(scrollPtr->display, scrollPtr->troughBackGC);
  923.     }
  924.     scrollPtr->troughBackGC = new;
  925.     
  926.     if (scrollPtr->copyGC == None) {
  927.     gcValues.graphics_exposures = False;
  928.     scrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures,
  929.         &gcValues);
  930.     }
  931.  
  932.     if (Tk_IsMapped(scrollPtr->tkwin)&&(scrollPtr->flags & RECONFIGURE)) {
  933.     scrollPtr->flags &= ~RECONFIGURE;
  934.     if (scrollPtr->bump != None) {
  935.         Tk_FreePixmap(scrollPtr->display, scrollPtr->bump);
  936.     }
  937.     MakePixmaps(scrollPtr);
  938.     }
  939.     /*
  940.      * Register the desired geometry for the window (leave enough space
  941.      * for the two arrows plus a minimum-size slider, plus border around
  942.      * the whole window, if any).  Then arrange for the window to be
  943.      * redisplayed.
  944.      */
  945.  
  946.     ComputeScrollbarGeometry(scrollPtr);
  947.     EventuallyRedraw(scrollPtr);
  948.  
  949.     return TCL_OK;
  950. }
  951.  
  952. #define ARROW_UP    0
  953. #define ARROW_DOWN    1
  954. #define ARROW_LEFT    2
  955. #define ARROW_RIGHT    3
  956. /*
  957.  * DrawArrow --
  958.  *       Draws an antialiased arrow with direction dir and size w x h. 
  959.  *      It's coordinates are relative to the center of the arrow. 
  960.  */
  961. static void DrawArrow(scrollPtr, drawable, x, y, w, h, dir)
  962.     Scrollbar   *scrollPtr;
  963.     Drawable    drawable;
  964.     int     x, y;    /* position relative to middle of arrow */
  965.     int     w, h;
  966.     char    dir;
  967. {
  968.     int i, hw;
  969.     float d, s;
  970.     GC     core, border;
  971.  
  972.     core = Tk_3DBorderGC(scrollPtr->tkwin,scrollPtr->bgBorder,TK_3D_DARK2_GC);
  973.     border = Tk_3DBorderGC(scrollPtr->tkwin,scrollPtr->bgBorder,TK_3D_DARK_GC);
  974.  
  975.     if (h<3) h=3;
  976.     if (w<3) w=3;
  977.     if (dir<2) { /* vertical */
  978.     hw = w/2;
  979.     d = ((float)w/2)/(float)h;
  980.     y -= h/2;    
  981.     } else {
  982.     hw = h/2;
  983.     d = ((float)h/2)/(float)w;
  984.     x -= w/2;
  985.     }    
  986.     s=0;
  987.     switch (dir) {
  988.      case ARROW_DOWN:
  989.     s=h*d+0.5;
  990.     d=-d;
  991.      case ARROW_UP:
  992.     for(i = 0; i < h; i++) {
  993.         s += d;    
  994.         XDrawLine(scrollPtr->display, drawable, core,
  995.               (unsigned)(x-(int)(s-0.5)), y+i,
  996.               (unsigned)(x+(int)(s-0.5)), y+i);
  997.         /* anti-aliasing */    
  998.         if ((int)(s+0.5)!=(int)s) {
  999.         XDrawPoint(scrollPtr->display, drawable, 
  1000.                border, (unsigned)(x+(int)s), y+i);
  1001.         XDrawPoint(scrollPtr->display, drawable,
  1002.                border, (unsigned)(x-(int)s), y+i);
  1003.         }
  1004.     }
  1005.     break;
  1006.      case ARROW_RIGHT:
  1007.     s=h*d+0.5;
  1008.     d=-d;
  1009.      case ARROW_LEFT:
  1010.     for(i = 0; i < h; i++) {
  1011.         s += d;    
  1012.         XDrawLine(scrollPtr->display, drawable,
  1013.               core, x+i,(unsigned)(y-(int)(s-0.5)),
  1014.               x+i,(unsigned)(y+(int)(s-0.5)));
  1015.         /* anti-aliasing */    
  1016.         if ((int)(s+0.5)!=(int)s) {
  1017.         XDrawPoint(scrollPtr->display, drawable,
  1018.                border, x+i,(unsigned)(y+(int)s));
  1019.         XDrawPoint(scrollPtr->display, drawable,
  1020.                border, x+i,(unsigned)(y-(int)s));
  1021.         }
  1022.     }
  1023.     break;
  1024.     }
  1025. }
  1026.  
  1027.  
  1028. /*
  1029.  *--------------------------------------------------------------
  1030.  *
  1031.  * DisplayScrollbar --
  1032.  *
  1033.  *    This procedure redraws the contents of a scrollbar window.
  1034.  *    It is invoked as a do-when-idle handler, so it only runs
  1035.  *    when there's nothing else for the application to do.
  1036.  *
  1037.  * Results:
  1038.  *    None.
  1039.  *
  1040.  * Side effects:
  1041.  *    Information appears on the screen.
  1042.  *
  1043.  *--------------------------------------------------------------
  1044.  */
  1045.  
  1046. static void
  1047. DisplayScrollbar(clientData)
  1048.     ClientData clientData;    /* Information about window. */
  1049. {
  1050.     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
  1051.     register Tk_Window tkwin = scrollPtr->tkwin;
  1052.     Tk_3DBorder border;
  1053.     int relief, width, elementBorderWidth, sliderSize, delta;
  1054.     int arrowl = scrollPtr->arrowLength;
  1055.     Pixmap pixmap;
  1056.     int empty=0;    
  1057.  
  1058.  
  1059.     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  1060.     goto done;
  1061.     }
  1062.  
  1063.     if ((scrollPtr->firstFraction<=0.0) && (scrollPtr->lastFraction>=1.0)) {
  1064.     empty=1;
  1065.     }
  1066.     
  1067.     if (scrollPtr->vertical) {
  1068.     width = Tk_Width(tkwin) - 2*scrollPtr->inset;
  1069.     } else {
  1070.     width = Tk_Height(tkwin) - 2*scrollPtr->inset;
  1071.     }
  1072.     elementBorderWidth = scrollPtr->elementBorderWidth;
  1073.     if (elementBorderWidth < 0) {
  1074.     elementBorderWidth = scrollPtr->borderWidth;
  1075.     }
  1076.  
  1077.     if (scrollPtr->bump == None) {
  1078.     MakePixmaps((ClientData)scrollPtr);
  1079.     }
  1080.  
  1081.     /*
  1082.      * In order to avoid screen flashes, this procedure redraws
  1083.      * the scrollbar in a pixmap, then copies the pixmap to the
  1084.      * screen in a single operation.  This means that there's no
  1085.      * point in time where the on-sreen image has been cleared.
  1086.      */
  1087.  
  1088.     pixmap = Tk_GetPixmap(scrollPtr->display, Tk_WindowId(tkwin),
  1089.         Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  1090.  
  1091.     sliderSize = scrollPtr->sliderLast - scrollPtr->sliderFirst + 1;
  1092.     if (scrollPtr->highlightWidth != 0) {
  1093.     GC gc;
  1094.  
  1095.     if (scrollPtr->flags & GOT_FOCUS) {
  1096.         gc = Tk_GCForColor(scrollPtr->highlightColorPtr, pixmap);
  1097.     } else {
  1098.         gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, pixmap);
  1099.     }
  1100.     Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, pixmap);
  1101.     }
  1102.     /*
  1103.      * Tk_Draw3DRectangle(tkwin, pixmap, scrollPtr->bgBorder,
  1104.         scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  1105.         Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  1106.         Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
  1107.         scrollPtr->borderWidth, scrollPtr->relief);
  1108.      */
  1109.     XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughBackGC,
  1110.     scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  1111.      Tk_Width(tkwin) - 2*scrollPtr->highlightWidth,
  1112.       Tk_Height(tkwin) - 2*scrollPtr->highlightWidth);
  1113.     
  1114.     XDrawRectangle(scrollPtr->display, pixmap, 
  1115.     Tk_3DBorderGC(scrollPtr->tkwin,scrollPtr->bgBorder,TK_3D_DARK2_GC),
  1116.      scrollPtr->highlightWidth, scrollPtr->highlightWidth,
  1117.      Tk_Width(tkwin) - 2*scrollPtr->highlightWidth-1,
  1118.      Tk_Height(tkwin) - 2*scrollPtr->highlightWidth-1);
  1119.  
  1120.     if (scrollPtr->vertical) {
  1121.     if (!empty) {
  1122.         XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC,
  1123.            scrollPtr->inset, scrollPtr->inset,
  1124.            (unsigned) (Tk_Width(tkwin) - 2*scrollPtr->inset),
  1125.            (unsigned) (Tk_Height(tkwin) + 1 -
  1126.            (scrollPtr->arrowLength + scrollPtr->inset)*2));
  1127.     } else {
  1128.         XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC,
  1129.            scrollPtr->inset, scrollPtr->inset,
  1130.            (unsigned) (Tk_Width(tkwin) - 2*scrollPtr->inset),
  1131.            (unsigned) (Tk_Height(tkwin) - 2*scrollPtr->inset));
  1132.     }
  1133.     } else {
  1134.     if (!empty) {
  1135.         XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC,
  1136.            scrollPtr->arrowLength * 2+2,
  1137.            scrollPtr->inset,
  1138.            (unsigned) (Tk_Width(tkwin) -
  1139.            (scrollPtr->arrowLength*2 + scrollPtr->inset*2)),
  1140.            (unsigned) (Tk_Height(tkwin) - 2*scrollPtr->inset));
  1141.     } else {
  1142.         XFillRectangle(scrollPtr->display, pixmap, scrollPtr->troughGC,
  1143.            scrollPtr->inset, scrollPtr->inset,
  1144.            (unsigned) (Tk_Width(tkwin) - 2*scrollPtr->inset),
  1145.            (unsigned) (Tk_Height(tkwin) - 2*scrollPtr->inset));
  1146.     }
  1147.     }
  1148.     
  1149.     /* 
  1150.      * don't draw slider/arrows if everything is visible
  1151.      */
  1152.     if (empty) {
  1153.     goto docopy;
  1154.     }    
  1155.     
  1156.     /*
  1157.      * Draw the top or left arrow.  The coordinates of the polygon
  1158.      * points probably seem odd, but they were carefully chosen with
  1159.      * respect to X's rules for filling polygons.  These point choices
  1160.      * cause the arrows to just fill the narrow dimension of the
  1161.      * scrollbar and be properly centered.
  1162.      */
  1163.     if (scrollPtr->activeField == TOP_ARROW) {
  1164.     border = scrollPtr->activeBorder;
  1165.     relief = scrollPtr->activeField == TOP_ARROW ? scrollPtr->activeRelief
  1166.         : TK_RELIEF_RAISED;
  1167.     delta = (relief == TK_RELIEF_SUNKEN) ? scrollPtr->borderWidth/2+1 : 0;
  1168.     } else {
  1169.     border = scrollPtr->bgBorder;
  1170.     relief = TK_RELIEF_RAISED;
  1171.     delta = 0;
  1172.     }
  1173.     
  1174.     if (scrollPtr->vertical) {
  1175.     Tk_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->inset,
  1176.          Tk_Height(tkwin) - scrollPtr->arrowLength*2,
  1177.         scrollPtr->width, scrollPtr->width,
  1178.         elementBorderWidth, relief);
  1179.     if (width >= 5) {
  1180.         DrawArrow(scrollPtr, pixmap, scrollPtr->inset+arrowl/2+delta
  1181.               -(2-(arrowl&1)),
  1182.               Tk_Height(tkwin) - (2-(arrowl&1)) + scrollPtr->inset/2 -
  1183.               arrowl*2 + (arrowl-scrollPtr->inset)/2+delta,
  1184.               arrowl-2*scrollPtr->inset-3, arrowl-2*scrollPtr->inset-3,
  1185.               ARROW_UP);
  1186.     }    
  1187.     } else {
  1188.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  1189.          scrollPtr->inset, scrollPtr->inset,
  1190.         scrollPtr->width, scrollPtr->width,
  1191.         elementBorderWidth, relief);
  1192.     if (width >= 5) {
  1193.         DrawArrow(scrollPtr, pixmap, 3*scrollPtr->inset/2 - (arrowl&1) +
  1194.               (arrowl-scrollPtr->inset)/2+delta,
  1195.               scrollPtr->inset+ arrowl/2-(arrowl&1)+delta,
  1196.               arrowl-2*scrollPtr->inset-3, arrowl-2*scrollPtr->inset-3,
  1197.               ARROW_LEFT);
  1198.     }
  1199.     }
  1200.  
  1201.     /*
  1202.      * Display the bottom or right arrow.
  1203.      */
  1204.  
  1205.     if (scrollPtr->activeField == BOTTOM_ARROW) {
  1206.     border = scrollPtr->activeBorder;
  1207.     relief = scrollPtr->activeField == BOTTOM_ARROW
  1208.         ? scrollPtr->activeRelief : TK_RELIEF_RAISED;
  1209.     delta = (relief == TK_RELIEF_SUNKEN) ? scrollPtr->borderWidth/2+1 : 0;
  1210.     } else {
  1211.     border = scrollPtr->bgBorder;
  1212.     relief = TK_RELIEF_RAISED;
  1213.     delta = 0;
  1214.     }
  1215.     if (scrollPtr->vertical) {
  1216.     Tk_Fill3DRectangle(tkwin, pixmap, border, scrollPtr->inset,
  1217.          Tk_Height(tkwin) - scrollPtr->arrowLength,
  1218.         scrollPtr->width, scrollPtr->width,
  1219.         elementBorderWidth, relief);
  1220.     if (width >= 5 ) {
  1221.         DrawArrow(scrollPtr, pixmap, scrollPtr->inset+arrowl/2-
  1222.               (2-(arrowl&1))+delta,
  1223.               scrollPtr->inset/2+Tk_Height(tkwin) - (1-(arrowl&1)) -
  1224.               arrowl + (arrowl-scrollPtr->inset)/2+delta,
  1225.               arrowl-2*scrollPtr->inset-3, arrowl-2*scrollPtr->inset-3,
  1226.               ARROW_DOWN);        
  1227.     }    
  1228.     } else {
  1229.     Tk_Fill3DRectangle(tkwin, pixmap, border, 
  1230.          scrollPtr->inset + scrollPtr->arrowLength,
  1231.         scrollPtr->inset, scrollPtr->width, scrollPtr->width,
  1232.         elementBorderWidth, relief);
  1233.     if (width >= 5) {
  1234.         DrawArrow(scrollPtr, pixmap, 3*scrollPtr->inset/2+delta-
  1235.               (arrowl&1) + arrowl + (arrowl-scrollPtr->inset)/2,
  1236.               scrollPtr->inset+arrowl/2-(arrowl&1)+delta,
  1237.               arrowl-2*scrollPtr->inset-3, arrowl-2*scrollPtr->inset-3,
  1238.               ARROW_RIGHT);
  1239.     }
  1240.     }
  1241.  
  1242.  
  1243.     /*
  1244.      * Display the slider.
  1245.      */
  1246.  
  1247.     if (scrollPtr->activeField == SLIDER) {
  1248.     border = scrollPtr->activeBorder;
  1249.     relief = /*scrollPtr->activeField == SLIDER ? scrollPtr->activeRelief
  1250.         :*/ TK_RELIEF_RAISED;
  1251.     } else {
  1252.     border = scrollPtr->bgBorder;
  1253.     relief = TK_RELIEF_RAISED;
  1254.     }
  1255.     if (scrollPtr->vertical) {
  1256.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  1257.         scrollPtr->inset, scrollPtr->sliderFirst,
  1258.         width, sliderSize,
  1259.         elementBorderWidth, relief);
  1260.     if ((sliderSize > SB_BUMP_HEIGHT*2) && (width > SB_BUMP_WIDTH)) {
  1261.         XCopyArea(scrollPtr->display, scrollPtr->bump, pixmap,
  1262.         scrollPtr->copyGC, 0, 0, SB_BUMP_WIDTH, SB_BUMP_HEIGHT,
  1263.         scrollPtr->inset + (width - SB_BUMP_WIDTH)/2-1, 
  1264.         scrollPtr->sliderFirst - 1  + (sliderSize - SB_BUMP_HEIGHT)/2);
  1265.     }
  1266.     } else {
  1267.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  1268.         scrollPtr->sliderFirst, scrollPtr->inset,
  1269.         sliderSize-1, width,
  1270.         elementBorderWidth, relief);
  1271.     if ((sliderSize > SB_BUMP_HEIGHT*2) && (width > SB_BUMP_HEIGHT)) {
  1272.         XCopyArea(scrollPtr->display, scrollPtr->bump, pixmap,
  1273.         scrollPtr->copyGC, 0, 0, SB_BUMP_WIDTH, SB_BUMP_HEIGHT,
  1274.         scrollPtr->sliderFirst + (sliderSize - SB_BUMP_HEIGHT)/2-1, 
  1275.         scrollPtr->inset - 1 + (width - SB_BUMP_WIDTH)/2);
  1276.     }
  1277.     }
  1278.  
  1279.     /*
  1280.      * Copy the information from the off-screen pixmap onto the screen,
  1281.      * then delete the pixmap.
  1282.      */
  1283.     docopy:
  1284.     XCopyArea(scrollPtr->display, pixmap, Tk_WindowId(tkwin),
  1285.         scrollPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin),
  1286.         (unsigned) Tk_Height(tkwin), 0, 0);
  1287.     Tk_FreePixmap(scrollPtr->display, pixmap);
  1288.  
  1289.     done:
  1290.     scrollPtr->flags &= ~REDRAW_PENDING;
  1291. }
  1292.  
  1293. /*
  1294.  *--------------------------------------------------------------
  1295.  *
  1296.  * ScrollbarEventProc --
  1297.  *
  1298.  *    This procedure is invoked by the Tk dispatcher for various
  1299.  *    events on scrollbars.
  1300.  *
  1301.  * Results:
  1302.  *    None.
  1303.  *
  1304.  * Side effects:
  1305.  *    When the window gets deleted, internal structures get
  1306.  *    cleaned up.  When it gets exposed, it is redisplayed.
  1307.  *
  1308.  *--------------------------------------------------------------
  1309.  */
  1310.  
  1311. static void
  1312. ScrollbarEventProc(clientData, eventPtr)
  1313.     ClientData clientData;    /* Information about window. */
  1314.     XEvent *eventPtr;        /* Information about event. */
  1315. {
  1316.     Scrollbar *scrollPtr = (Scrollbar *) clientData;
  1317.  
  1318.     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
  1319.     EventuallyRedraw(scrollPtr);
  1320.     } else if (eventPtr->type == DestroyNotify) {
  1321.     if (scrollPtr->tkwin != NULL) {
  1322.         scrollPtr->tkwin = NULL;
  1323.         Tcl_DeleteCommand(scrollPtr->interp,
  1324.             Tcl_GetCommandName(scrollPtr->interp,
  1325.             scrollPtr->widgetCmd));
  1326.     }
  1327.     if (scrollPtr->flags & REDRAW_PENDING) {
  1328.         Tcl_CancelIdleCall(DisplayScrollbar, (ClientData) scrollPtr);
  1329.     }
  1330.     Tcl_EventuallyFree((ClientData) scrollPtr, DestroyScrollbar);
  1331.     } else if (eventPtr->type == ConfigureNotify) {
  1332.     ComputeScrollbarGeometry(scrollPtr);
  1333.     EventuallyRedraw(scrollPtr);
  1334.     } else if (eventPtr->type == FocusIn) {
  1335.     if (eventPtr->xfocus.detail != NotifyInferior) {
  1336.         scrollPtr->flags |= GOT_FOCUS;
  1337.         if (scrollPtr->highlightWidth > 0) {
  1338.         EventuallyRedraw(scrollPtr);
  1339.         }
  1340.     }
  1341.     } else if (eventPtr->type == FocusOut) {
  1342.     if (eventPtr->xfocus.detail != NotifyInferior) {
  1343.         scrollPtr->flags &= ~GOT_FOCUS;
  1344.         if (scrollPtr->highlightWidth > 0) {
  1345.         EventuallyRedraw(scrollPtr);
  1346.         }
  1347.     }
  1348.     }
  1349. }
  1350.  
  1351. /*
  1352.  *----------------------------------------------------------------------
  1353.  *
  1354.  * ScrollbarCmdDeletedProc --
  1355.  *
  1356.  *    This procedure is invoked when a widget command is deleted.  If
  1357.  *    the widget isn't already in the process of being destroyed,
  1358.  *    this command destroys it.
  1359.  *
  1360.  * Results:
  1361.  *    None.
  1362.  *
  1363.  * Side effects:
  1364.  *    The widget is destroyed.
  1365.  *
  1366.  *----------------------------------------------------------------------
  1367.  */
  1368.  
  1369. static void
  1370. ScrollbarCmdDeletedProc(clientData)
  1371.     ClientData clientData;    /* Pointer to widget record for widget. */
  1372. {
  1373.     Scrollbar *scrollPtr = (Scrollbar *) clientData;
  1374.     Tk_Window tkwin = scrollPtr->tkwin;
  1375.  
  1376.     /*
  1377.      * This procedure could be invoked either because the window was
  1378.      * destroyed and the command was then deleted (in which case tkwin
  1379.      * is NULL) or because the command was deleted, and then this procedure
  1380.      * destroys the widget.
  1381.      */
  1382.  
  1383.     if (tkwin != NULL) {
  1384.     scrollPtr->tkwin = NULL;
  1385.     Tk_DestroyWindow(tkwin);
  1386.     }
  1387. }
  1388.  
  1389. /*
  1390.  *----------------------------------------------------------------------
  1391.  *
  1392.  * ComputeScrollbarGeometry --
  1393.  *
  1394.  *    After changes in a scrollbar's size or configuration, this
  1395.  *    procedure recomputes various geometry information used in
  1396.  *    displaying the scrollbar.
  1397.  *
  1398.  * Results:
  1399.  *    None.
  1400.  *
  1401.  * Side effects:
  1402.  *    The scrollbar will be displayed differently.
  1403.  *
  1404.  *----------------------------------------------------------------------
  1405.  */
  1406.  
  1407. static void
  1408. ComputeScrollbarGeometry(scrollPtr)
  1409.     register Scrollbar *scrollPtr;    /* Scrollbar whose geometry may
  1410.                      * have changed. */
  1411. {
  1412.     int width, fieldLength;
  1413.  
  1414.     if (scrollPtr->highlightWidth < 0) {
  1415.     scrollPtr->highlightWidth = 0;
  1416.     }
  1417.     scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
  1418.     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
  1419.         : Tk_Height(scrollPtr->tkwin);
  1420.     scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1;
  1421.     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
  1422.         : Tk_Width(scrollPtr->tkwin))
  1423.         - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  1424.     if (fieldLength < 0) {
  1425.     fieldLength = 0;
  1426.     }
  1427.     scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
  1428.     scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction;
  1429.  
  1430.     /*
  1431.      * Adjust the slider so that some piece of it is always
  1432.      * displayed in the scrollbar and so that it has at least
  1433.      * a minimal width (so it can be grabbed with the mouse).
  1434.      */
  1435.  
  1436.     if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
  1437.     scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
  1438.     }
  1439.     if (scrollPtr->sliderFirst < 0) {
  1440.     scrollPtr->sliderFirst = 0;
  1441.     }
  1442.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  1443.         + MIN_SLIDER_LENGTH)) {
  1444.     scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
  1445.     }
  1446.     if (scrollPtr->sliderLast > fieldLength) {
  1447.     scrollPtr->sliderLast = fieldLength;
  1448.     }
  1449.     if (scrollPtr->vertical) {    
  1450.     scrollPtr->sliderFirst += scrollPtr->inset;
  1451.     scrollPtr->sliderLast += scrollPtr->inset;
  1452.     } else {
  1453.     scrollPtr->sliderFirst += scrollPtr->arrowLength*2 + scrollPtr->inset;
  1454.     scrollPtr->sliderLast += scrollPtr->arrowLength*2 +scrollPtr->inset;
  1455.     }        
  1456.  
  1457.     /*
  1458.      * Register the desired geometry for the window (leave enough space
  1459.      * for the two arrows plus a minimum-size slider, plus border around
  1460.      * the whole window, if any).  Then arrange for the window to be
  1461.      * redisplayed.
  1462.      */
  1463.  
  1464.     if (scrollPtr->vertical) {
  1465.     Tk_GeometryRequest(scrollPtr->tkwin,
  1466.         scrollPtr->width + 2*scrollPtr->inset,
  1467.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  1468.         + scrollPtr->inset));
  1469.     } else {
  1470.     Tk_GeometryRequest(scrollPtr->tkwin,
  1471.         2*(scrollPtr->arrowLength + scrollPtr->borderWidth
  1472.         + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset);
  1473.     }
  1474.     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset);
  1475. }
  1476.  
  1477. /*
  1478.  *--------------------------------------------------------------
  1479.  *
  1480.  * ScrollbarPosition --
  1481.  *
  1482.  *    Determine the scrollbar element corresponding to a
  1483.  *    given position.
  1484.  *
  1485.  * Results:
  1486.  *    One of TOP_ARROW, TOP_GAP, etc., indicating which element
  1487.  *    of the scrollbar covers the position given by (x, y).  If
  1488.  *    (x,y) is outside the scrollbar entirely, then OUTSIDE is
  1489.  *    returned.
  1490.  *
  1491.  * Side effects:
  1492.  *    None.
  1493.  *
  1494.  *--------------------------------------------------------------
  1495.  */
  1496.  
  1497. static int
  1498. ScrollbarPosition(scrollPtr, x, y)
  1499.     register Scrollbar *scrollPtr;    /* Scrollbar widget record. */
  1500.     int x, y;                /* Coordinates within scrollPtr's
  1501.                      * window. */
  1502. {
  1503.     int length, width, tmp;
  1504.  
  1505.     if (scrollPtr->vertical) {
  1506.     length = Tk_Height(scrollPtr->tkwin);
  1507.     width = Tk_Width(scrollPtr->tkwin);
  1508.     } else {
  1509.     tmp = x;
  1510.     x = y;
  1511.     y = tmp;
  1512.     length = Tk_Width(scrollPtr->tkwin);
  1513.     width = Tk_Height(scrollPtr->tkwin);
  1514.     }
  1515.  
  1516.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  1517.         || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  1518.     return OUTSIDE;
  1519.     }
  1520.  
  1521.     /*
  1522.      * All of the calculations in this procedure mirror those in
  1523.      * DisplayScrollbar.  Be sure to keep the two consistent.
  1524.      */
  1525.     if (scrollPtr->vertical) {    
  1526.     if (y < scrollPtr->sliderFirst) {
  1527.         return TOP_GAP;
  1528.     }
  1529.     if (y < scrollPtr->sliderLast) {        
  1530.         return SLIDER;
  1531.     }
  1532.     if (y < (length - (scrollPtr->arrowLength*2 + scrollPtr->inset + 1))) {
  1533.         return BOTTOM_GAP;
  1534.     }
  1535.     if (y < (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
  1536.         return TOP_ARROW;
  1537.     }
  1538.     return BOTTOM_ARROW;
  1539.     } else {
  1540.     if (y < (scrollPtr->arrowLength + scrollPtr->inset)) {
  1541.         return TOP_ARROW;
  1542.     }
  1543.     if (y < (scrollPtr->arrowLength*2 + scrollPtr->inset + 1)) {
  1544.         return BOTTOM_ARROW;
  1545.     }
  1546.     if (y < (scrollPtr->sliderFirst)) {
  1547.         return TOP_GAP;
  1548.     }
  1549.     if (y < (scrollPtr->sliderLast)) {
  1550.         return SLIDER;
  1551.     }
  1552.     return BOTTOM_GAP;
  1553.     }
  1554. }
  1555.  
  1556. /*
  1557.  *--------------------------------------------------------------
  1558.  *
  1559.  * EventuallyRedraw --
  1560.  *
  1561.  *    Arrange for one or more of the fields of a scrollbar
  1562.  *    to be redrawn.
  1563.  *
  1564.  * Results:
  1565.  *    None.
  1566.  *
  1567.  * Side effects:
  1568.  *    None.
  1569.  *
  1570.  *--------------------------------------------------------------
  1571.  */
  1572.  
  1573. static void
  1574. EventuallyRedraw(scrollPtr)
  1575.     register Scrollbar *scrollPtr;    /* Information about widget. */
  1576. {
  1577.     if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) {
  1578.     return;
  1579.     }
  1580.     if ((scrollPtr->flags & REDRAW_PENDING) == 0) {
  1581.     Tcl_DoWhenIdle(DisplayScrollbar, (ClientData) scrollPtr);
  1582.     scrollPtr->flags |= REDRAW_PENDING;
  1583.     }
  1584. }
  1585.