Annotation of micropolis/src/tk/tkscrbar.c, revision 1.1.1.1

1.1       root        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 1990-1992 Regents of the University of California.
                     10:  * Permission to use, copy, modify, and distribute this
                     11:  * software and its documentation for any purpose and without
                     12:  * fee is hereby granted, provided that the above copyright
                     13:  * notice appear in all copies.  The University of California
                     14:  * makes no representations about the suitability of this
                     15:  * software for any purpose.  It is provided "as is" without
                     16:  * express or implied warranty.
                     17:  */
                     18: 
                     19: #ifndef lint
                     20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkScrollbar.c,v 1.35 92/05/22 16:57:27 ouster Exp $ SPRITE (Berkeley)";
                     21: #endif
                     22: 
                     23: #include "tkconfig.h"
                     24: #include "default.h"
                     25: #include "tkint.h"
                     26: 
                     27: /*
                     28:  * A data structure of the following type is kept for each scrollbar
                     29:  * widget managed by this file:
                     30:  */
                     31: 
                     32: typedef struct {
                     33:     Tk_Window tkwin;           /* Window that embodies the scrollbar.  NULL
                     34:                                 * means that the window has been destroyed
                     35:                                 * but the data structures haven't yet been
                     36:                                 * cleaned up.*/
                     37:     Tcl_Interp *interp;                /* Interpreter associated with scrollbar. */
                     38:     Tk_Uid orientUid;          /* Orientation for window ("vertical" or
                     39:                                 * "horizontal"). */
                     40:     int vertical;              /* Non-zero means vertical orientation
                     41:                                 * requested, zero means horizontal. */
                     42:     int width;                 /* Desired narrow dimension of scrollbar,
                     43:                                 * in pixels. */
                     44:     char *command;             /* Command prefix to use when invoking
                     45:                                 * scrolling commands.  NULL means don't
                     46:                                 * invoke commands.  Malloc'ed. */
                     47:     int commandSize;           /* Number of non-NULL bytes in command. */
                     48:     int repeatDelay;           /* How long to wait before auto-repeating
                     49:                                 * on scrolling actions (in ms). */
                     50:     int repeatInterval;                /* Interval between autorepeats (in ms). */
                     51: 
                     52:     /*
                     53:      * Information used when displaying widget:
                     54:      */
                     55: 
                     56:     int borderWidth;           /* Width of 3-D borders. */
                     57:     Tk_3DBorder bgBorder;      /* Used for drawing background. */
                     58:     Tk_3DBorder fgBorder;      /* For drawing foreground shapes. */
                     59:     Tk_3DBorder activeBorder;  /* For drawing foreground shapes when
                     60:                                 * active (i.e. when mouse is positioned
                     61:                                 * over element).  NULL means use fgBorder. */
                     62:     GC copyGC;                 /* Used for copying from pixmap onto screen. */
                     63:     int relief;                        /* Indicates whether window as a whole is
                     64:                                 * raised, sunken, or flat. */
                     65:     int offset;                        /* Zero if relief is TK_RELIEF_FLAT,
                     66:                                 * borderWidth otherwise.   Indicates how
                     67:                                 * much interior stuff must be offset from
                     68:                                 * outside edges to leave room for border. */
                     69:     int arrowLength;           /* Length of arrows along long dimension of
                     70:                                 * scrollbar.  Recomputed on window size
                     71:                                 * changes. */
                     72:     int sliderFirst;           /* Pixel coordinate of top or left edge
                     73:                                 * of slider area, including border. */
                     74:     int sliderLast;            /* Coordinate of pixel just after bottom
                     75:                                 * or right edge of slider area, including
                     76:                                 * border. */
                     77:     int mouseField;            /* Indicates which scrollbar element is
                     78:                                 * under mouse (e.g. TOP_ARROW;  see below
                     79:                                 * for possible values). */
                     80:     int pressField;            /* Field in which button was pressed, or -1
                     81:                                 * if no button is down. */
                     82:     int pressPos;              /* Position of mouse when button was
                     83:                                 * pressed (y for vertical scrollbar, x
                     84:                                 * for horizontal). */
                     85:     int pressFirstUnit;                /* Value of "firstUnit" when mouse button
                     86:                                 * was pressed. */
                     87: 
                     88:     /*
                     89:      * Information describing the application related to the scrollbar.
                     90:      * This information is provided by the application by invoking the
                     91:      * "set" widget command.
                     92:      */
                     93: 
                     94:     int totalUnits;            /* Total dimension of application, in
                     95:                                 * units. */
                     96:     int windowUnits;           /* Maximum number of units that can
                     97:                                 * be displayed in the window at
                     98:                                 * once. */
                     99:     int firstUnit;             /* Number of last unit visible in
                    100:                                 * application's window. */
                    101:     int lastUnit;              /* Index of last unit visible in window. */
                    102: 
                    103:     /*
                    104:      * Miscellaneous information:
                    105:      */
                    106: 
                    107:     Cursor cursor;             /* Current cursor for window, or None. */
                    108:     Tk_TimerToken autoRepeat;  /* Token for auto-repeat that's
                    109:                                 * currently in progress.  NULL means no
                    110:                                 * auto-repeat in progress. */
                    111:     int flags;                 /* Various flags;  see below for
                    112:                                 * definitions. */
                    113: } Scrollbar;
                    114: 
                    115: /*
                    116:  * Legal values for "mouseField" field of Scrollbar structures.  These
                    117:  * are also the return values from the ScrollbarPosition procedure.
                    118:  */
                    119: 
                    120: #define TOP_ARROW      1
                    121: #define TOP_GAP                2
                    122: #define SLIDER         3
                    123: #define BOTTOM_GAP     4
                    124: #define BOTTOM_ARROW   5
                    125: #define OUTSIDE                6
                    126: 
                    127: /*
                    128:  * Flag bits for scrollbars:
                    129:  * 
                    130:  * REDRAW_PENDING:             Non-zero means a DoWhenIdle handler
                    131:  *                             has already been queued to redraw
                    132:  *                             this window.
                    133:  */
                    134: 
                    135: #define REDRAW_PENDING         1
                    136: 
                    137: /*
                    138:  * Information used for argv parsing.
                    139:  */
                    140: 
                    141: 
                    142: static Tk_ConfigSpec configSpecs[] = {
                    143:     {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background",
                    144:        DEF_SCROLLBAR_ACTIVE_FG_COLOR, Tk_Offset(Scrollbar, activeBorder),
                    145:        TK_CONFIG_COLOR_ONLY},
                    146:     {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background",
                    147:        DEF_SCROLLBAR_ACTIVE_FG_MONO, Tk_Offset(Scrollbar, activeBorder),
                    148:        TK_CONFIG_MONO_ONLY},
                    149:     {TK_CONFIG_BORDER, "-background", "background", "Background",
                    150:        DEF_SCROLLBAR_BG_COLOR, Tk_Offset(Scrollbar, bgBorder),
                    151:        TK_CONFIG_COLOR_ONLY},
                    152:     {TK_CONFIG_BORDER, "-background", "background", "Background",
                    153:        DEF_SCROLLBAR_BG_MONO, Tk_Offset(Scrollbar, bgBorder),
                    154:        TK_CONFIG_MONO_ONLY},
                    155:     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
                    156:        (char *) NULL, 0, 0},
                    157:     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
                    158:        (char *) NULL, 0, 0},
                    159:     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
                    160:        DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(Scrollbar, borderWidth), 0},
                    161:     {TK_CONFIG_STRING, "-command", "command", "Command",
                    162:        DEF_SCROLLBAR_COMMAND, Tk_Offset(Scrollbar, command), 0},
                    163:     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
                    164:        DEF_SCROLLBAR_CURSOR, Tk_Offset(Scrollbar, cursor), TK_CONFIG_NULL_OK},
                    165:     {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
                    166:        (char *) NULL, 0, 0},
                    167:     {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
                    168:        DEF_SCROLLBAR_FG_COLOR, Tk_Offset(Scrollbar, fgBorder),
                    169:        TK_CONFIG_COLOR_ONLY},
                    170:     {TK_CONFIG_BORDER, "-foreground", "foreground", "Foreground",
                    171:        DEF_SCROLLBAR_FG_MONO, Tk_Offset(Scrollbar, fgBorder),
                    172:        TK_CONFIG_MONO_ONLY},
                    173:     {TK_CONFIG_UID, "-orient", "orient", "Orient",
                    174:        DEF_SCROLLBAR_ORIENT, Tk_Offset(Scrollbar, orientUid), 0},
                    175:     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
                    176:        DEF_SCROLLBAR_RELIEF, Tk_Offset(Scrollbar, relief), 0},
                    177:     {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
                    178:        DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(Scrollbar, repeatDelay), 0},
                    179:     {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
                    180:        DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(Scrollbar, repeatInterval), 0},
                    181:     {TK_CONFIG_PIXELS, "-width", "width", "Width",
                    182:        DEF_SCROLLBAR_WIDTH, Tk_Offset(Scrollbar, width), 0},
                    183:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
                    184:        (char *) NULL, 0, 0}
                    185: };
                    186: 
                    187: /*
                    188:  * Forward declarations for procedures defined later in this file:
                    189:  */
                    190: 
                    191: static void            ComputeScrollbarGeometry _ANSI_ARGS_((
                    192:                            Scrollbar *scrollPtr));
                    193: static int             ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp,
                    194:                            Scrollbar *scrollPtr, int argc, char **argv,
                    195:                            int flags));
                    196: static void            DestroyScrollbar _ANSI_ARGS_((ClientData clientData));
                    197: static void            DisplayScrollbar _ANSI_ARGS_((ClientData clientData));
                    198: static void            EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr));
                    199: static void            ScrollbarEventProc _ANSI_ARGS_((ClientData clientData,
                    200:                            XEvent *eventPtr));
                    201: static void            ScrollbarMouseProc _ANSI_ARGS_((ClientData clientData,
                    202:                            XEvent *eventPtr));
                    203: static void            ScrollbarNewField _ANSI_ARGS_((Scrollbar *scrollPtr,
                    204:                            int field));
                    205: static int             ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr,
                    206:                            int x, int y));
                    207: static void            ScrollbarTimerProc _ANSI_ARGS_((
                    208:                            ClientData clientData));
                    209: static int             ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData,
                    210:                            Tcl_Interp *, int argc, char **argv));
                    211: static void            ScrollCmd _ANSI_ARGS_((Scrollbar *scrollPtr,
                    212:                            int unit));
                    213: 
                    214: /*
                    215:  *--------------------------------------------------------------
                    216:  *
                    217:  * Tk_ScrollbarCmd --
                    218:  *
                    219:  *     This procedure is invoked to process the "scrollbar" Tcl
                    220:  *     command.  See the user documentation for details on what
                    221:  *     it does.
                    222:  *
                    223:  * Results:
                    224:  *     A standard Tcl result.
                    225:  *
                    226:  * Side effects:
                    227:  *     See the user documentation.
                    228:  *
                    229:  *--------------------------------------------------------------
                    230:  */
                    231: 
                    232: int
                    233: Tk_ScrollbarCmd(clientData, interp, argc, argv)
                    234:     ClientData clientData;     /* Main window associated with
                    235:                                 * interpreter. */
                    236:     Tcl_Interp *interp;                /* Current interpreter. */
                    237:     int argc;                  /* Number of arguments. */
                    238:     char **argv;               /* Argument strings. */
                    239: {
                    240:     Tk_Window tkwin = (Tk_Window) clientData;
                    241:     register Scrollbar *scrollPtr;
                    242:     Tk_Window new;
                    243: 
                    244:     if (argc < 2) {
                    245:        Tcl_AppendResult(interp, "wrong # args:  should be \"",
                    246:                argv[0], " pathName ?options?\"", (char *) NULL);
                    247:        return TCL_ERROR;
                    248:     }
                    249: 
                    250:     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
                    251:     if (new == NULL) {
                    252:        return TCL_ERROR;
                    253:     }
                    254: 
                    255:     /*
                    256:      * Initialize fields that won't be initialized by ConfigureScrollbar,
                    257:      * or which ConfigureScrollbar expects to have reasonable values
                    258:      * (e.g. resource pointers).
                    259:      */
                    260: 
                    261:     scrollPtr = (Scrollbar *) ckalloc(sizeof(Scrollbar));
                    262:     scrollPtr->tkwin = new;
                    263:     scrollPtr->interp = interp;
                    264:     scrollPtr->command = NULL;
                    265:     scrollPtr->bgBorder = NULL;
                    266:     scrollPtr->fgBorder = NULL;
                    267:     scrollPtr->activeBorder = NULL;
                    268:     scrollPtr->copyGC = None;
                    269:     scrollPtr->mouseField = OUTSIDE;
                    270:     scrollPtr->pressField = -1;
                    271:     scrollPtr->totalUnits = 0;
                    272:     scrollPtr->windowUnits = 0;
                    273:     scrollPtr->firstUnit = 0;
                    274:     scrollPtr->lastUnit = 0;
                    275:     scrollPtr->cursor = None;
                    276:     scrollPtr->autoRepeat = NULL;
                    277:     scrollPtr->flags = 0;
                    278: 
                    279:     Tk_SetClass(scrollPtr->tkwin, "Scrollbar");
                    280:     Tk_CreateEventHandler(scrollPtr->tkwin, ExposureMask|StructureNotifyMask,
                    281:            ScrollbarEventProc, (ClientData) scrollPtr);
                    282:     Tk_CreateEventHandler(scrollPtr->tkwin, EnterWindowMask|LeaveWindowMask
                    283:            |PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
                    284:            ScrollbarMouseProc, (ClientData) scrollPtr);
                    285:     Tcl_CreateCommand(interp, Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd,
                    286:            (ClientData) scrollPtr, (void (*)()) NULL);
                    287:     if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) {
                    288:        goto error;
                    289:     }
                    290: 
                    291:     interp->result = Tk_PathName(scrollPtr->tkwin);
                    292:     return TCL_OK;
                    293: 
                    294:     error:
                    295:     Tk_DestroyWindow(scrollPtr->tkwin);
                    296:     return TCL_ERROR;
                    297: }
                    298: 
                    299: /*
                    300:  *--------------------------------------------------------------
                    301:  *
                    302:  * ScrollbarWidgetCmd --
                    303:  *
                    304:  *     This procedure is invoked to process the Tcl command
                    305:  *     that corresponds to a widget managed by this module.
                    306:  *     See the user documentation for details on what it does.
                    307:  *
                    308:  * Results:
                    309:  *     A standard Tcl result.
                    310:  *
                    311:  * Side effects:
                    312:  *     See the user documentation.
                    313:  *
                    314:  *--------------------------------------------------------------
                    315:  */
                    316: 
                    317: static int
                    318: ScrollbarWidgetCmd(clientData, interp, argc, argv)
                    319:     ClientData clientData;     /* Information about scrollbar
                    320:                                         * widget. */
                    321:     Tcl_Interp *interp;                        /* Current interpreter. */
                    322:     int argc;                          /* Number of arguments. */
                    323:     char **argv;                       /* Argument strings. */
                    324: {
                    325:     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
                    326:     int result = TCL_OK;
                    327:     int length;
                    328:     char c;
                    329: 
                    330:     if (argc < 2) {
                    331:        Tcl_AppendResult(interp, "wrong # args: should be \"",
                    332:                argv[0], " option ?arg arg ...?\"", (char *) NULL);
                    333:        return TCL_ERROR;
                    334:     }
                    335:     Tk_Preserve((ClientData) scrollPtr);
                    336:     c = argv[1][0];
                    337:     length = strlen(argv[1]);
                    338:     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
                    339:        if (argc == 2) {
                    340:            result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs,
                    341:                    (char *) scrollPtr, (char *) NULL, 0);
                    342:        } else if (argc == 3) {
                    343:            result = Tk_ConfigureInfo(interp, scrollPtr->tkwin, configSpecs,
                    344:                    (char *) scrollPtr, argv[2], 0);
                    345:        } else {
                    346:            result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2,
                    347:                    TK_CONFIG_ARGV_ONLY);
                    348:        }
                    349:     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
                    350:        if (argc != 2) {
                    351:            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    352:                    argv[0], " get\"", (char *) NULL);
                    353:            goto error;
                    354:        }
                    355:        sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits,
                    356:                scrollPtr->windowUnits, scrollPtr->firstUnit,
                    357:                scrollPtr->lastUnit);
                    358:     } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) {
                    359:        int totalUnits, windowUnits, firstUnit, lastUnit;
                    360: 
                    361:        if (argc != 6) {
                    362:            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    363:                    argv[0],
                    364:                    " set totalUnits windowUnits firstUnit lastUnit\"",
                    365:                    (char *) NULL);
                    366:            goto error;
                    367:        }
                    368:        if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) {
                    369:            goto error;
                    370:        }
                    371:        if (totalUnits < 0) {
                    372:            sprintf(interp->result, "illegal totalUnits %d", totalUnits);
                    373:            goto error;
                    374:        }
                    375:        if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) {
                    376:            goto error;
                    377:        }
                    378:        if (windowUnits < 0) {
                    379:            sprintf(interp->result, "illegal windowUnits %d", windowUnits);
                    380:            goto error;
                    381:        }
                    382:        if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) {
                    383:            goto error;
                    384:        }
                    385:        if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) {
                    386:            goto error;
                    387:        }
                    388:        if (totalUnits > 0) {
                    389:            if (lastUnit < firstUnit) {
                    390:                sprintf(interp->result, "illegal lastUnit %d", lastUnit);
                    391:                goto error;
                    392:            }
                    393:        } else {
                    394:            firstUnit = lastUnit = 0;
                    395:        }
                    396:        scrollPtr->totalUnits = totalUnits;
                    397:        scrollPtr->windowUnits = windowUnits;
                    398:        scrollPtr->firstUnit = firstUnit;
                    399:        scrollPtr->lastUnit = lastUnit;
                    400:        ComputeScrollbarGeometry(scrollPtr);
                    401:        EventuallyRedraw(scrollPtr);
                    402:     } else {
                    403:        Tcl_AppendResult(interp, "bad option \"", argv[1],
                    404:                "\":  must be configure, get, or set", (char *) NULL);
                    405:        goto error;
                    406:     }
                    407:     Tk_Release((ClientData) scrollPtr);
                    408:     return result;
                    409: 
                    410:     error:
                    411:     Tk_Release((ClientData) scrollPtr);
                    412:     return TCL_ERROR;
                    413: }
                    414: 
                    415: /*
                    416:  *----------------------------------------------------------------------
                    417:  *
                    418:  * DestroyScrollbar --
                    419:  *
                    420:  *     This procedure is invoked by Tk_EventuallyFree or Tk_Release
                    421:  *     to clean up the internal structure of a scrollbar at a safe time
                    422:  *     (when no-one is using it anymore).
                    423:  *
                    424:  * Results:
                    425:  *     None.
                    426:  *
                    427:  * Side effects:
                    428:  *     Everything associated with the scrollbar is freed up.
                    429:  *
                    430:  *----------------------------------------------------------------------
                    431:  */
                    432: 
                    433: static void
                    434: DestroyScrollbar(clientData)
                    435:     ClientData clientData;     /* Info about scrollbar widget. */
                    436: {
                    437:     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
                    438: 
                    439:     if (scrollPtr->command != NULL) {
                    440:        ckfree(scrollPtr->command);
                    441:     }
                    442:     if (scrollPtr->bgBorder != NULL) {
                    443:        Tk_Free3DBorder(scrollPtr->bgBorder);
                    444:     }
                    445:     if (scrollPtr->fgBorder != NULL) {
                    446:        Tk_Free3DBorder(scrollPtr->fgBorder);
                    447:     }
                    448:     if (scrollPtr->activeBorder != NULL) {
                    449:        Tk_Free3DBorder(scrollPtr->activeBorder);
                    450:     }
                    451:     if (scrollPtr->copyGC != None) {
                    452:        Tk_FreeGC(scrollPtr->copyGC);
                    453:     }
                    454:     if (scrollPtr->cursor != None) {
                    455:        Tk_FreeCursor(scrollPtr->cursor);
                    456:     }
                    457:     ckfree((char *) scrollPtr);
                    458: }
                    459: 
                    460: /*
                    461:  *----------------------------------------------------------------------
                    462:  *
                    463:  * ConfigureScrollbar --
                    464:  *
                    465:  *     This procedure is called to process an argv/argc list, plus
                    466:  *     the Tk option database, in order to configure (or
                    467:  *     reconfigure) a scrollbar widget.
                    468:  *
                    469:  * Results:
                    470:  *     The return value is a standard Tcl result.  If TCL_ERROR is
                    471:  *     returned, then interp->result contains an error message.
                    472:  *
                    473:  * Side effects:
                    474:  *     Configuration information, such as colors, border width,
                    475:  *     etc. get set for scrollPtr;  old resources get freed,
                    476:  *     if there were any.
                    477:  *
                    478:  *----------------------------------------------------------------------
                    479:  */
                    480: 
                    481: static int
                    482: ConfigureScrollbar(interp, scrollPtr, argc, argv, flags)
                    483:     Tcl_Interp *interp;                        /* Used for error reporting. */
                    484:     register Scrollbar *scrollPtr;     /* Information about widget;  may or
                    485:                                         * may not already have values for
                    486:                                         * some fields. */
                    487:     int argc;                          /* Number of valid entries in argv. */
                    488:     char **argv;                       /* Arguments. */
                    489:     int flags;                         /* Flags to pass to
                    490:                                         * Tk_ConfigureWidget. */
                    491: {
                    492:     int length;
                    493:     XGCValues gcValues;
                    494: 
                    495:     if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, configSpecs,
                    496:            argc, argv, (char *) scrollPtr, flags) != TCL_OK) {
                    497:        return TCL_ERROR;
                    498:     }
                    499: 
                    500:     /*
                    501:      * A few options need special processing, such as parsing the
                    502:      * orientation or setting the background from a 3-D border.
                    503:      */
                    504: 
                    505:     length = strlen(scrollPtr->orientUid);
                    506:     if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) {
                    507:        scrollPtr->vertical = 1;
                    508:     } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) {
                    509:        scrollPtr->vertical = 0;
                    510:     } else {
                    511:        Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid,
                    512:                "\": must be vertical or horizontal", (char *) NULL);
                    513:        return TCL_ERROR;
                    514:     }
                    515: 
                    516:     if (scrollPtr->command != NULL) {
                    517:        scrollPtr->commandSize = strlen(scrollPtr->command);
                    518:     } else {
                    519:        scrollPtr->commandSize = 0;
                    520:     }
                    521: 
                    522:     Tk_SetBackgroundFromBorder(scrollPtr->tkwin, scrollPtr->bgBorder);
                    523: 
                    524:     if (scrollPtr->copyGC == None) {
                    525:        gcValues.graphics_exposures = False;
                    526:        scrollPtr->copyGC = Tk_GetGC(scrollPtr->tkwin, GCGraphicsExposures,
                    527:            &gcValues);
                    528:     }
                    529: 
                    530:     /*
                    531:      * Register the desired geometry for the window (leave enough space
                    532:      * for the two arrows plus a minimum-size slider, plus border around
                    533:      * the whole window, if any).  Then arrange for the window to be
                    534:      * redisplayed.
                    535:      */
                    536: 
                    537:     ComputeScrollbarGeometry(scrollPtr);
                    538:     EventuallyRedraw(scrollPtr);
                    539:     return TCL_OK;
                    540: }
                    541: 
                    542: /*
                    543:  *--------------------------------------------------------------
                    544:  *
                    545:  * DisplayScrollbar --
                    546:  *
                    547:  *     This procedure redraws the contents of a scrollbar window.
                    548:  *     It is invoked as a do-when-idle handler, so it only runs
                    549:  *     when there's nothing else for the application to do.
                    550:  *
                    551:  * Results:
                    552:  *     None.
                    553:  *
                    554:  * Side effects:
                    555:  *     Information appears on the screen.
                    556:  *
                    557:  *--------------------------------------------------------------
                    558:  */
                    559: 
                    560: static void
                    561: DisplayScrollbar(clientData)
                    562:     ClientData clientData;     /* Information about window. */
                    563: {
                    564:     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
                    565:     register Tk_Window tkwin = scrollPtr->tkwin;
                    566:     XPoint points[7];
                    567:     Tk_3DBorder border;
                    568:     int relief, width, fieldLength;
                    569:     Pixmap pixmap;
                    570: 
                    571:     if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
                    572:        goto done;
                    573:     }
                    574: 
                    575:     if (scrollPtr->vertical) {
                    576:        width = Tk_Width(tkwin) - 2*scrollPtr->offset;
                    577:     } else {
                    578:        width = Tk_Height(tkwin) - 2*scrollPtr->offset;
                    579:     }
                    580: 
                    581:     /*
                    582:      * In order to avoid screen flashes, this procedure redraws
                    583:      * the scrollbar in a pixmap, then copies the pixmap to the
                    584:      * screen in a single operation.  This means that there's no
                    585:      * point in time where the on-sreen image has been cleared.
                    586:      */
                    587: 
                    588:     pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
                    589:            Tk_Width(tkwin), Tk_Height(tkwin),
                    590:            Tk_DefaultDepth(Tk_Screen(tkwin)));
                    591:     Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, scrollPtr->bgBorder,
                    592:            0, 0, Tk_Width(tkwin), Tk_Height(tkwin),
                    593:            scrollPtr->borderWidth, scrollPtr->relief);
                    594: 
                    595:     /*
                    596:      * Draw the top or left arrow.  The coordinates of the polygon
                    597:      * points probably seem odd, but they were carefully chosen with
                    598:      * respect to X's rules for filling polygons.  These point choices
                    599:      * cause the arrows to just fill the narrow dimension of the
                    600:      * scrollbar and be properly centered.
                    601:      */
                    602: 
                    603:     if (scrollPtr->mouseField == TOP_ARROW) {
                    604:        border = scrollPtr->activeBorder;
                    605:        relief = scrollPtr->pressField == TOP_ARROW ? TK_RELIEF_SUNKEN
                    606:                : TK_RELIEF_RAISED;
                    607:     } else {
                    608:        border = scrollPtr->fgBorder;
                    609:        relief = TK_RELIEF_RAISED;
                    610:     }
                    611:     if (scrollPtr->vertical) {
                    612:        points[0].x = scrollPtr->offset - 1;
                    613:        points[0].y = scrollPtr->arrowLength + scrollPtr->offset;
                    614:        points[1].x = width + scrollPtr->offset;
                    615:        points[1].y = points[0].y;
                    616:        points[2].x = width/2 + scrollPtr->offset;
                    617:        points[2].y = scrollPtr->offset - 1;
                    618:        Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border,
                    619:                points, 3, scrollPtr->borderWidth, relief);
                    620:     } else {
                    621:        points[0].x = scrollPtr->arrowLength + scrollPtr->offset;
                    622:        points[0].y = scrollPtr->offset - 1;
                    623:        points[1].x = scrollPtr->offset;
                    624:        points[1].y = width/2 + scrollPtr->offset;
                    625:        points[2].x = points[0].x;
                    626:        points[2].y = width + scrollPtr->offset;
                    627:        Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border,
                    628:                points, 3, scrollPtr->borderWidth, relief);
                    629:     }
                    630: 
                    631:     /*
                    632:      * Display the bottom or right arrow.
                    633:      */
                    634: 
                    635:     if (scrollPtr->mouseField == BOTTOM_ARROW) {
                    636:        border = scrollPtr->activeBorder;
                    637:        relief = scrollPtr->pressField == BOTTOM_ARROW ? TK_RELIEF_SUNKEN
                    638:                : TK_RELIEF_RAISED;
                    639:     } else {
                    640:        border = scrollPtr->fgBorder;
                    641:        relief = TK_RELIEF_RAISED;
                    642:     }
                    643:     if (scrollPtr->vertical) {
                    644:        points[0].x = scrollPtr->offset;
                    645:        points[0].y = Tk_Height(tkwin) - scrollPtr->arrowLength
                    646:                - scrollPtr->offset;
                    647:        points[1].x = width/2 + scrollPtr->offset;
                    648:        points[1].y = Tk_Height(tkwin) - scrollPtr->offset;
                    649:        points[2].x = width + scrollPtr->offset;
                    650:        points[2].y = points[0].y;
                    651:        Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border,
                    652:                points, 3, scrollPtr->borderWidth, relief);
                    653:     } else {
                    654:        points[0].x = Tk_Width(tkwin) - scrollPtr->arrowLength
                    655:                - scrollPtr->offset;
                    656:        points[0].y = scrollPtr->offset - 1;
                    657:        points[1].x = points[0].x;
                    658:        points[1].y = width + scrollPtr->offset;
                    659:        points[2].x = Tk_Width(tkwin) - scrollPtr->offset;
                    660:        points[2].y = width/2 + scrollPtr->offset;
                    661:        Tk_Fill3DPolygon(Tk_Display(tkwin), pixmap, border,
                    662:                points, 3, scrollPtr->borderWidth, relief);
                    663:     }
                    664: 
                    665:     /*
                    666:      * Display the slider.
                    667:      */
                    668: 
                    669:     if (scrollPtr->mouseField == SLIDER) {
                    670:        border = scrollPtr->activeBorder;
                    671:        relief = scrollPtr->pressField == SLIDER ? TK_RELIEF_SUNKEN
                    672:                : TK_RELIEF_RAISED;
                    673:     } else {
                    674:        border = scrollPtr->fgBorder;
                    675:        relief = TK_RELIEF_RAISED;
                    676:     }
                    677:     fieldLength = (scrollPtr->vertical ? Tk_Height(tkwin) : Tk_Width(tkwin))
                    678:            - 2*(scrollPtr->arrowLength + scrollPtr->offset);
                    679:     if (fieldLength < 0) {
                    680:        fieldLength = 0;
                    681:     }
                    682:     if (scrollPtr->vertical) {
                    683:        Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, border,
                    684:                1 + scrollPtr->offset, scrollPtr->sliderFirst,
                    685:                width-2, scrollPtr->sliderLast - scrollPtr->sliderFirst,
                    686:                scrollPtr->borderWidth, relief);
                    687:     } else {
                    688:        Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, border,
                    689:                scrollPtr->sliderFirst, 1 + scrollPtr->offset,
                    690:                scrollPtr->sliderLast - scrollPtr->sliderFirst, width-2,
                    691:                scrollPtr->borderWidth, relief);
                    692:     }
                    693: 
                    694:     /*
                    695:      * Copy the information from the off-screen pixmap onto the screen,
                    696:      * then delete the pixmap.
                    697:      */
                    698: 
                    699:     XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
                    700:        scrollPtr->copyGC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, 0);
                    701:     XFreePixmap(Tk_Display(tkwin), pixmap);
                    702: 
                    703:     done:
                    704:     scrollPtr->flags &= ~REDRAW_PENDING;
                    705: }
                    706: 
                    707: /*
                    708:  *--------------------------------------------------------------
                    709:  *
                    710:  * ScrollbarEventProc --
                    711:  *
                    712:  *     This procedure is invoked by the Tk dispatcher for various
                    713:  *     events on scrollbars.
                    714:  *
                    715:  * Results:
                    716:  *     None.
                    717:  *
                    718:  * Side effects:
                    719:  *     When the window gets deleted, internal structures get
                    720:  *     cleaned up.  When it gets exposed, it is redisplayed.
                    721:  *
                    722:  *--------------------------------------------------------------
                    723:  */
                    724: 
                    725: static void
                    726: ScrollbarEventProc(clientData, eventPtr)
                    727:     ClientData clientData;     /* Information about window. */
                    728:     XEvent *eventPtr;          /* Information about event. */
                    729: {
                    730:     Scrollbar *scrollPtr = (Scrollbar *) clientData;
                    731: 
                    732:     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
                    733:        EventuallyRedraw(scrollPtr);
                    734:     } else if (eventPtr->type == DestroyNotify) {
                    735:        Tcl_DeleteCommand(scrollPtr->interp, Tk_PathName(scrollPtr->tkwin));
                    736:        scrollPtr->tkwin = NULL;
                    737:        if (scrollPtr->flags & REDRAW_PENDING) {
                    738:            Tk_CancelIdleCall(DisplayScrollbar, (ClientData) scrollPtr);
                    739:        }
                    740:        Tk_EventuallyFree((ClientData) scrollPtr, DestroyScrollbar);
                    741:     } else if (eventPtr->type == ConfigureNotify) {
                    742:        ComputeScrollbarGeometry(scrollPtr);
                    743:     }
                    744: }
                    745: 
                    746: /*
                    747:  *----------------------------------------------------------------------
                    748:  *
                    749:  * ComputeScrollbarGeometry --
                    750:  *
                    751:  *     After changes in a scrollbar's size or configuration, this
                    752:  *     procedure recomputes various geometry information used in
                    753:  *     displaying the scrollbar.
                    754:  *
                    755:  * Results:
                    756:  *     None.
                    757:  *
                    758:  * Side effects:
                    759:  *     The scrollbar will be displayed differently.
                    760:  *
                    761:  *----------------------------------------------------------------------
                    762:  */
                    763: 
                    764: static void
                    765: ComputeScrollbarGeometry(scrollPtr)
                    766:     register Scrollbar *scrollPtr;     /* Scrollbar whose geometry may
                    767:                                         * have changed. */
                    768: {
                    769:     int width, fieldLength;
                    770: 
                    771:     if (scrollPtr->relief == TK_RELIEF_FLAT) {
                    772:        scrollPtr->offset = 0;
                    773:     } else {
                    774:        scrollPtr->offset = scrollPtr->borderWidth;
                    775:     }
                    776:     width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin)
                    777:            : Tk_Height(scrollPtr->tkwin);
                    778:     scrollPtr->arrowLength =
                    779:                (((width - 2*scrollPtr->offset)*173) + 100) / 200;
                    780:     fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
                    781:            : Tk_Width(scrollPtr->tkwin))
                    782:            - 2*(scrollPtr->arrowLength + scrollPtr->offset);
                    783:     if (fieldLength < 0) {
                    784:        fieldLength = 0;
                    785:     }
                    786:     if (scrollPtr->totalUnits <= 0) {
                    787:        scrollPtr->sliderFirst = 0;
                    788:        scrollPtr->sliderLast = fieldLength;
                    789:     } else {
                    790:        scrollPtr->sliderFirst = (fieldLength*scrollPtr->firstUnit
                    791:                + scrollPtr->totalUnits/2)/scrollPtr->totalUnits;
                    792:        scrollPtr->sliderLast = (fieldLength*(scrollPtr->lastUnit+1)
                    793:                + scrollPtr->totalUnits/2)/scrollPtr->totalUnits;
                    794: 
                    795:        /*
                    796:         * Adjust the slider so that some piece of it is always
                    797:         * displayed in the scrollbar and so that it has at least
                    798:         * a minimal width (so it can be grabbed with the mouse).
                    799:         */
                    800: 
                    801:        if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) {
                    802:            scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth;
                    803:        }
                    804:        if (scrollPtr->sliderFirst < 0) {
                    805:            scrollPtr->sliderFirst = 0;
                    806:        }
                    807:        if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
                    808:                + 2*scrollPtr->borderWidth)) {
                    809:            scrollPtr->sliderLast = scrollPtr->sliderFirst
                    810:                    + 2*scrollPtr->borderWidth;
                    811:        }
                    812:        if (scrollPtr->sliderLast > fieldLength) {
                    813:            scrollPtr->sliderLast = fieldLength;
                    814:        }
                    815:     }
                    816:     scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->offset;
                    817:     scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->offset;
                    818: 
                    819:     /*
                    820:      * Register the desired geometry for the window (leave enough space
                    821:      * for the two arrows plus a minimum-size slider, plus border around
                    822:      * the whole window, if any).  Then arrange for the window to be
                    823:      * redisplayed.
                    824:      */
                    825: 
                    826:     if (scrollPtr->vertical) {
                    827:        Tk_GeometryRequest(scrollPtr->tkwin,
                    828:                scrollPtr->width + 2*scrollPtr->offset,
                    829:                2*(scrollPtr->arrowLength + scrollPtr->borderWidth
                    830:                + scrollPtr->offset));
                    831:     } else {
                    832:        Tk_GeometryRequest(scrollPtr->tkwin,
                    833:                2*(scrollPtr->arrowLength + scrollPtr->borderWidth
                    834:                + scrollPtr->offset), scrollPtr->width + 2*scrollPtr->offset);
                    835:     }
                    836:     Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->borderWidth);
                    837: 
                    838: }
                    839: 
                    840: /*
                    841:  *--------------------------------------------------------------
                    842:  *
                    843:  * ScrollbarPosition --
                    844:  *
                    845:  *     Determine the scrollbar element corresponding to a
                    846:  *     given position.
                    847:  *
                    848:  * Results:
                    849:  *     One of TOP_ARROW, TOP_GAP, etc., indicating which element
                    850:  *     of the scrollbar covers the position given by (x, y).  If
                    851:  *     (x,y) is outside the scrollbar entirely, then OUTSIDE is
                    852:  *     returned.
                    853:  *
                    854:  * Side effects:
                    855:  *     None.
                    856:  *
                    857:  *--------------------------------------------------------------
                    858:  */
                    859: 
                    860: static int
                    861: ScrollbarPosition(scrollPtr, x, y)
                    862:     register Scrollbar *scrollPtr;     /* Scrollbar widget record. */
                    863:     int x, y;                          /* Coordinates within scrollPtr's
                    864:                                         * window. */
                    865: {
                    866:     int length, width, tmp;
                    867: 
                    868:     if (scrollPtr->vertical) {
                    869:        length = Tk_Height(scrollPtr->tkwin);
                    870:        width = Tk_Width(scrollPtr->tkwin);
                    871:     } else {
                    872:        tmp = x;
                    873:        x = y;
                    874:        y = tmp;
                    875:        length = Tk_Width(scrollPtr->tkwin);
                    876:        width = Tk_Height(scrollPtr->tkwin);
                    877:     }
                    878: 
                    879:     if ((x < 0) || (x > width) || (y < 0)) {
                    880:        return OUTSIDE;
                    881:     }
                    882: 
                    883:     /*
                    884:      * All of the calculations in this procedure mirror those in
                    885:      * DisplayScrollbar.  Be sure to keep the two consistent.
                    886:      */
                    887: 
                    888:     if (y < (scrollPtr->offset + scrollPtr->arrowLength)) {
                    889:        return TOP_ARROW;
                    890:     }
                    891:     if (y < scrollPtr->sliderFirst) {
                    892:        return TOP_GAP;
                    893:     }
                    894:     if (y < scrollPtr->sliderLast) {
                    895:        return SLIDER;
                    896:     }
                    897:     if (y >= (length - (scrollPtr->arrowLength + scrollPtr->offset))) {
                    898:        return BOTTOM_ARROW;
                    899:     }
                    900:     return BOTTOM_GAP;
                    901: }
                    902: 
                    903: /*
                    904:  *--------------------------------------------------------------
                    905:  *
                    906:  * ScrollbarMouseProc --
                    907:  *
                    908:  *     This procedure is called back by Tk in response to
                    909:  *     mouse events such as window entry, window exit, mouse
                    910:  *     motion, and button presses.
                    911:  *
                    912:  * Results:
                    913:  *     None.
                    914:  *
                    915:  * Side effects:
                    916:  *     This procedure implements the "feel" of the scrollbar
                    917:  *     by issuing scrolling commands in response to button presses
                    918:  *     and mouse motion.
                    919:  *
                    920:  *--------------------------------------------------------------
                    921:  */
                    922: 
                    923: static void
                    924: ScrollbarMouseProc(clientData, eventPtr)
                    925:     ClientData clientData;             /* Information about window. */
                    926:     register XEvent *eventPtr;         /* Information about event. */
                    927: {
                    928:     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
                    929: 
                    930:     Tk_Preserve((ClientData) scrollPtr);
                    931:     if (eventPtr->type == EnterNotify) {
                    932:        if (scrollPtr->pressField == -1) {
                    933:            ScrollbarNewField(scrollPtr,
                    934:                    ScrollbarPosition(scrollPtr, eventPtr->xcrossing.x,
                    935:                    eventPtr->xcrossing.y));
                    936:        }
                    937:     } else if (eventPtr->type == LeaveNotify) {
                    938:        if (scrollPtr->pressField == -1) {
                    939:            ScrollbarNewField(scrollPtr, OUTSIDE);
                    940:        }
                    941:     } else if (eventPtr->type == MotionNotify) {
                    942:        if (scrollPtr->pressField == SLIDER) {
                    943:            int delta, length, newFirst;
                    944: 
                    945:            if (scrollPtr->vertical) {
                    946:                delta = eventPtr->xmotion.y - scrollPtr->pressPos;
                    947:                length = Tk_Height(scrollPtr->tkwin)
                    948:                        - 2*(scrollPtr->arrowLength + scrollPtr->offset);
                    949:            } else {
                    950:                delta = eventPtr->xmotion.x - scrollPtr->pressPos;
                    951:                length = Tk_Width(scrollPtr->tkwin)
                    952:                        - 2*(scrollPtr->arrowLength + scrollPtr->offset);
                    953:            }
                    954: 
                    955:            /*
                    956:             * Do the division with positive numbers to avoid
                    957:             * differences in negative-number truncation on different
                    958:             * machines.
                    959:             */
                    960: 
                    961:            if (delta >= 0) {
                    962:                newFirst = scrollPtr->pressFirstUnit
                    963:                        + ((delta * scrollPtr->totalUnits) + (length/2))
                    964:                        / length;
                    965:            } else {
                    966:                newFirst = scrollPtr->pressFirstUnit
                    967:                        - (((-delta) * scrollPtr->totalUnits) + (length/2))
                    968:                        / length;
                    969:            }
                    970:            ScrollCmd(scrollPtr, newFirst);
                    971:        } else if (scrollPtr->pressField == -1) {
                    972:            ScrollbarNewField(scrollPtr,
                    973:                    ScrollbarPosition(scrollPtr, eventPtr->xmotion.x,
                    974:                    eventPtr->xmotion.y));
                    975:        }
                    976:     } else if ((eventPtr->type == ButtonPress)
                    977:            && (eventPtr->xbutton.state == 0)) {
                    978:        scrollPtr->pressField = scrollPtr->mouseField;
                    979:        if (scrollPtr->pressField != SLIDER) {
                    980:            scrollPtr->autoRepeat = Tk_CreateTimerHandler(
                    981:                    scrollPtr->repeatDelay,
                    982:                    ScrollbarTimerProc, (ClientData) scrollPtr);
                    983:        }
                    984:        if (scrollPtr->vertical) {
                    985:            scrollPtr->pressPos = eventPtr->xbutton.y;
                    986:        } else {
                    987:            scrollPtr->pressPos = eventPtr->xbutton.x;
                    988:        }
                    989:        scrollPtr->pressFirstUnit = scrollPtr->firstUnit;
                    990:        if (scrollPtr->pressFirstUnit <= -scrollPtr->windowUnits) {
                    991:            scrollPtr->pressFirstUnit = 1-scrollPtr->windowUnits;
                    992:        }
                    993:        if (scrollPtr->pressFirstUnit >= scrollPtr->totalUnits) {
                    994:            scrollPtr->pressFirstUnit = scrollPtr->totalUnits-1;
                    995:        }
                    996:        EventuallyRedraw(scrollPtr);
                    997:     } else if (eventPtr->type == ButtonRelease) {
                    998:        if (scrollPtr->pressField == scrollPtr->mouseField) {
                    999:            switch (scrollPtr->pressField) {
                   1000:                case TOP_ARROW:
                   1001:                    ScrollCmd(scrollPtr, scrollPtr->firstUnit-1);
                   1002:                    break;
                   1003:                case TOP_GAP:
                   1004:                    if (scrollPtr->windowUnits <= 1) {
                   1005:                        ScrollCmd(scrollPtr, scrollPtr->firstUnit - 1);
                   1006:                    } else {
                   1007:                        ScrollCmd(scrollPtr, scrollPtr->firstUnit
                   1008:                                - (scrollPtr->windowUnits-1));
                   1009:                    }
                   1010:                    break;
                   1011:                case BOTTOM_GAP: {
                   1012:                    if (scrollPtr->windowUnits <= 1) {
                   1013:                        ScrollCmd(scrollPtr, scrollPtr->firstUnit + 1);
                   1014:                    } else {
                   1015:                        ScrollCmd(scrollPtr, scrollPtr->firstUnit
                   1016:                                + (scrollPtr->windowUnits-1));
                   1017:                    }
                   1018:                    break;
                   1019:                }
                   1020:                case BOTTOM_ARROW:
                   1021:                    ScrollCmd(scrollPtr, scrollPtr->firstUnit+1);
                   1022:                    break;
                   1023:            }
                   1024:        }
                   1025:        if (scrollPtr->autoRepeat != NULL) {
                   1026:            Tk_DeleteTimerHandler(scrollPtr->autoRepeat);
                   1027:            scrollPtr->autoRepeat = NULL;
                   1028:        }
                   1029:        EventuallyRedraw(scrollPtr);
                   1030:        scrollPtr->pressField = -1;
                   1031:        ScrollbarNewField(scrollPtr,
                   1032:                ScrollbarPosition(scrollPtr, eventPtr->xbutton.x,
                   1033:                eventPtr->xbutton.y));
                   1034:     }
                   1035:     Tk_Release((ClientData) scrollPtr);
                   1036: }
                   1037: 
                   1038: /*
                   1039:  *--------------------------------------------------------------
                   1040:  *
                   1041:  * ScrollCmd --
                   1042:  *
                   1043:  *     This procedure takes care of invoking a scrolling Tcl
                   1044:  *     command and reporting any error that occurs in it.
                   1045:  *
                   1046:  * Results:
                   1047:  *     None.
                   1048:  *
                   1049:  * Side effects:
                   1050:  *     A Tcl command is invoked, and an additional error-processing
                   1051:  *     command may also be invoked.
                   1052:  *
                   1053:  *--------------------------------------------------------------
                   1054:  */
                   1055: 
                   1056: static void
                   1057: ScrollCmd(scrollPtr, unit)
                   1058:     register Scrollbar *scrollPtr;     /* Scrollbar from which to issue
                   1059:                                         * command. */
                   1060:     int unit;                          /* Unit position within thing being
                   1061:                                         * being displayed that should appear
                   1062:                                         * at top or right of screen. */
                   1063: {
                   1064:     char string[20];
                   1065:     int result;
                   1066: 
                   1067:     if ((unit == scrollPtr->firstUnit) || (scrollPtr->command == NULL)) {
                   1068:        return;
                   1069:     }
                   1070:     sprintf(string, " %d", unit);
                   1071:     result = Tcl_VarEval(scrollPtr->interp, scrollPtr->command, string,
                   1072:            (char *) NULL);
                   1073:     if (result != TCL_OK) {
                   1074:        TkBindError(scrollPtr->interp);
                   1075:     }
                   1076: }
                   1077: 
                   1078: /*
                   1079:  *--------------------------------------------------------------
                   1080:  *
                   1081:  * EventuallyRedraw --
                   1082:  *
                   1083:  *     Arrange for one or more of the fields of a scrollbar
                   1084:  *     to be redrawn.
                   1085:  *
                   1086:  * Results:
                   1087:  *     None.
                   1088:  *
                   1089:  * Side effects:
                   1090:  *     None.
                   1091:  *
                   1092:  *--------------------------------------------------------------
                   1093:  */
                   1094: 
                   1095: static void
                   1096: EventuallyRedraw(scrollPtr)
                   1097:     register Scrollbar *scrollPtr;     /* Information about widget. */
                   1098: {
                   1099:     if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) {
                   1100:        return;
                   1101:     }
                   1102:     if ((scrollPtr->flags & REDRAW_PENDING) == 0) {
                   1103:        Tk_DoWhenIdle(DisplayScrollbar, (ClientData) scrollPtr);
                   1104:        scrollPtr->flags |= REDRAW_PENDING;
                   1105:     }
                   1106: }
                   1107: 
                   1108: /*
                   1109:  *--------------------------------------------------------------
                   1110:  *
                   1111:  * ScrollbarNewField --
                   1112:  *
                   1113:  *     This procedure is called to declare that the mouse is in
                   1114:  *     a particular field of the scrollbar (e.g. top arrow), so
                   1115:  *     that the field can be highlighed and the previous field
                   1116:  *     can be returned to normal display.
                   1117:  *
                   1118:  * Results:
                   1119:  *     None.
                   1120:  *
                   1121:  * Side effects:
                   1122:  *     Fields may be redisplayed.
                   1123:  *
                   1124:  *--------------------------------------------------------------
                   1125:  */
                   1126: 
                   1127: static void
                   1128: ScrollbarNewField(scrollPtr, field)
                   1129:     register Scrollbar *scrollPtr;     /* Information about widget. */
                   1130:     int field;                         /* Identifies field under mouse,
                   1131:                                         * e.g. TOP_ARROW. */
                   1132: {
                   1133:     if (field == scrollPtr->mouseField) {
                   1134:        return;
                   1135:     }
                   1136:     EventuallyRedraw(scrollPtr);
                   1137:     scrollPtr->mouseField = field;
                   1138: }
                   1139: 
                   1140: /*
                   1141:  *--------------------------------------------------------------
                   1142:  *
                   1143:  * ScrollbarTimerProc --
                   1144:  *
                   1145:  *     This procedure is invoked as a Tk timer handler for actions
                   1146:  *     that auto-repeat (mouse presses in an arrow or gap).  It
                   1147:  *     performs the auto-repeat action.
                   1148:  *
                   1149:  * Results:
                   1150:  *     None.
                   1151:  *
                   1152:  * Side effects:
                   1153:  *     Whatever action corresponds to the current mouse button
                   1154:  *     is repeated, and this procedure is rescheduled to execute
                   1155:  *     again later.
                   1156:  *
                   1157:  *--------------------------------------------------------------
                   1158:  */
                   1159: 
                   1160: static void
                   1161: ScrollbarTimerProc(clientData)
                   1162:     ClientData clientData;     /* Information about widget. */
                   1163: {
                   1164:     register Scrollbar *scrollPtr = (Scrollbar *) clientData;
                   1165: 
                   1166:     Tk_Preserve((ClientData) scrollPtr);
                   1167:     switch(scrollPtr->pressField) {
                   1168:        case TOP_ARROW:
                   1169:            ScrollCmd(scrollPtr, scrollPtr->firstUnit-1);
                   1170:            break;
                   1171:        case TOP_GAP:
                   1172:            ScrollCmd(scrollPtr, scrollPtr->firstUnit
                   1173:                    - (scrollPtr->windowUnits-1));
                   1174:            break;
                   1175:        case BOTTOM_GAP: {
                   1176:            ScrollCmd(scrollPtr, scrollPtr->firstUnit
                   1177:                    + (scrollPtr->windowUnits-1));
                   1178:            break;
                   1179:        }
                   1180:        case BOTTOM_ARROW:
                   1181:            ScrollCmd(scrollPtr, scrollPtr->firstUnit+1);
                   1182:            break;
                   1183:     }
                   1184:     if (scrollPtr->tkwin != NULL) {
                   1185:        scrollPtr->autoRepeat = Tk_CreateTimerHandler(
                   1186:                scrollPtr->repeatInterval, ScrollbarTimerProc,
                   1187:                (ClientData) scrollPtr);
                   1188:     }
                   1189:     Tk_Release((ClientData) scrollPtr);
                   1190: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.