Annotation of micropolis/src/tk/tkscrbar.c, revision 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.