Annotation of micropolis/src/tk/tkcanvas.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkCanvas.c --
        !             3:  *
        !             4:  *     This module implements canvas widgets for the Tk toolkit.
        !             5:  *     A canvas displays a background and a collection of graphical
        !             6:  *     objects such as rectangles, lines, and texts.
        !             7:  *
        !             8:  * Copyright 1991-1992 Regents of the University of California.
        !             9:  * Permission to use, copy, modify, and distribute this
        !            10:  * software and its documentation for any purpose and without
        !            11:  * fee is hereby granted, provided that the above copyright
        !            12:  * notice appear in all copies.  The University of California
        !            13:  * makes no representations about the suitability of this
        !            14:  * software for any purpose.  It is provided "as is" without
        !            15:  * express or implied warranty.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkCanvas.c,v 1.28 92/08/19 08:47:57 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include <stdio.h>
        !            23: #include <stdlib.h>
        !            24: #include <string.h>
        !            25: #include <assert.h>
        !            26: #include "default.h"
        !            27: #include "tkint.h"
        !            28: #include "tkconfig.h"
        !            29: #include "tkcanvas.h"
        !            30: 
        !            31: /*
        !            32:  * See tkCanvas.h for key data structures used to implement canvases.
        !            33:  */
        !            34: 
        !            35: /*
        !            36:  * The structure defined below is used to keep track of a tag search
        !            37:  * in progress.  Only the "prevPtr" field should be accessed by anyone
        !            38:  * other than StartTagSearch and NextItem.
        !            39:  */
        !            40: 
        !            41: typedef struct TagSearch {
        !            42:     Tk_Canvas *canvasPtr;      /* Canvas widget being searched. */
        !            43:     Tk_Uid tag;                        /* Tag to search for.   0 means return
        !            44:                                 * all items. */
        !            45:     Tk_Item *prevPtr;          /* Item just before last one found (or NULL
        !            46:                                 * if last one found was first in the item
        !            47:                                 * list of canvasPtr). */
        !            48:     Tk_Item *currentPtr;       /* Pointer to last item returned. */
        !            49:     int searchOver;            /* Non-zero means NextItem should always
        !            50:                                 * return NULL. */
        !            51: } TagSearch;
        !            52: 
        !            53: /*
        !            54:  * Information used for argv parsing.
        !            55:  */
        !            56: 
        !            57: 
        !            58: static Tk_ConfigSpec configSpecs[] = {
        !            59:     {TK_CONFIG_BORDER, "-background", "background", "Background",
        !            60:        DEF_CANVAS_BG_COLOR, Tk_Offset(Tk_Canvas, bgBorder),
        !            61:        TK_CONFIG_COLOR_ONLY},
        !            62:     {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
        !            63:        (char *) NULL, Tk_Offset(Tk_Canvas, bgColor),
        !            64:        TK_CONFIG_COLOR_ONLY},
        !            65:     {TK_CONFIG_BORDER, "-background", "background", "Background",
        !            66:        DEF_CANVAS_BG_MONO, Tk_Offset(Tk_Canvas, bgBorder),
        !            67:        TK_CONFIG_MONO_ONLY},
        !            68:     {TK_CONFIG_COLOR, (char *) NULL, (char *) NULL, (char *) NULL,
        !            69:        (char *) NULL, Tk_Offset(Tk_Canvas, bgColor),
        !            70:        TK_CONFIG_MONO_ONLY},
        !            71:     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
        !            72:        (char *) NULL, 0, 0},
        !            73:     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
        !            74:        (char *) NULL, 0, 0},
        !            75:     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
        !            76:        DEF_CANVAS_BORDER_WIDTH, Tk_Offset(Tk_Canvas, borderWidth), 0},
        !            77:     {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
        !            78:        DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(Tk_Canvas, closeEnough), 0},
        !            79:     {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
        !            80:        DEF_CANVAS_CONFINE, Tk_Offset(Tk_Canvas, confine), 0},
        !            81:     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
        !            82:        DEF_CANVAS_CURSOR, Tk_Offset(Tk_Canvas, cursor), TK_CONFIG_NULL_OK},
        !            83:     {TK_CONFIG_BORDER, "-cursorbackground", "cursorBackground", "Foreground",
        !            84:        DEF_CANVAS_CURSOR_BG, Tk_Offset(Tk_Canvas, cursorBorder), 0},
        !            85:     {TK_CONFIG_PIXELS, "-cursorborderwidth", "cursorBorderWidth", "BorderWidth",
        !            86:        DEF_CANVAS_CURSOR_BD_COLOR, Tk_Offset(Tk_Canvas, cursorBorderWidth),
        !            87:        TK_CONFIG_COLOR_ONLY},
        !            88:     {TK_CONFIG_PIXELS, "-cursorborderwidth", "cursorBorderWidth", "BorderWidth",
        !            89:        DEF_CANVAS_CURSOR_BD_MONO, Tk_Offset(Tk_Canvas, cursorBorderWidth),
        !            90:        TK_CONFIG_MONO_ONLY},
        !            91:     {TK_CONFIG_INT, "-cursorofftime", "cursorOffTime", "OffTime",
        !            92:        DEF_CANVAS_CURSOR_OFF_TIME, Tk_Offset(Tk_Canvas, cursorOffTime), 0},
        !            93:     {TK_CONFIG_INT, "-cursorontime", "cursorOnTime", "OnTime",
        !            94:        DEF_CANVAS_CURSOR_ON_TIME, Tk_Offset(Tk_Canvas, cursorOnTime), 0},
        !            95:     {TK_CONFIG_PIXELS, "-cursorwidth", "cursorWidth", "CursorWidth",
        !            96:        DEF_CANVAS_CURSOR_WIDTH, Tk_Offset(Tk_Canvas, cursorWidth), 0},
        !            97:     {TK_CONFIG_PIXELS, "-height", "height", "Height",
        !            98:        DEF_CANVAS_HEIGHT, Tk_Offset(Tk_Canvas, height), 0},
        !            99:     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
        !           100:        DEF_CANVAS_RELIEF, Tk_Offset(Tk_Canvas, relief), 0},
        !           101:     {TK_CONFIG_PIXELS, "-scrollincrement", "scrollIncrement", "ScrollIncrement",
        !           102:        DEF_CANVAS_SCROLL_INCREMENT, Tk_Offset(Tk_Canvas, scrollIncrement), 0},
        !           103:     {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
        !           104:        DEF_CANVAS_SCROLL_REGION, Tk_Offset(Tk_Canvas, regionString), 0},
        !           105:     {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
        !           106:        DEF_CANVAS_SELECT_COLOR, Tk_Offset(Tk_Canvas, selBorder),
        !           107:        TK_CONFIG_COLOR_ONLY},
        !           108:     {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
        !           109:        DEF_CANVAS_SELECT_MONO, Tk_Offset(Tk_Canvas, selBorder),
        !           110:        TK_CONFIG_MONO_ONLY},
        !           111:     {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
        !           112:        DEF_CANVAS_SELECT_BD_COLOR, Tk_Offset(Tk_Canvas, selBorderWidth),
        !           113:        TK_CONFIG_COLOR_ONLY},
        !           114:     {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
        !           115:        DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(Tk_Canvas, selBorderWidth),
        !           116:        TK_CONFIG_MONO_ONLY},
        !           117:     {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
        !           118:        DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(Tk_Canvas, selFgColorPtr),
        !           119:        TK_CONFIG_COLOR_ONLY},
        !           120:     {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
        !           121:        DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(Tk_Canvas, selFgColorPtr),
        !           122:        TK_CONFIG_MONO_ONLY},
        !           123:     {TK_CONFIG_PIXELS, "-width", "width", "Width",
        !           124:        DEF_CANVAS_WIDTH, Tk_Offset(Tk_Canvas, width), 0},
        !           125:     {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
        !           126:        DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(Tk_Canvas, xScrollCmd), 0},
        !           127:     {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
        !           128:        DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(Tk_Canvas, yScrollCmd), 0},
        !           129:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
        !           130:        (char *) NULL, 0, 0}
        !           131: };
        !           132: 
        !           133: /*
        !           134:  * List of all the item types known at present:
        !           135:  */
        !           136: 
        !           137: static Tk_ItemType *typeList = NULL;   /* NULL means initialization hasn't
        !           138:                                         * been done yet. */
        !           139: 
        !           140: /*
        !           141:  * Standard item types provided by Tk:
        !           142:  */
        !           143: 
        !           144: extern Tk_ItemType TkArcType, TkBitmapType, TkLineType;
        !           145: extern Tk_ItemType TkOvalType, TkPolygonType;
        !           146: extern Tk_ItemType TkRectangleType, TkTextType, TkWindowType;
        !           147: 
        !           148: /*
        !           149:  * Various Tk_Uid's used by this module (set up during initialization):
        !           150:  */
        !           151: 
        !           152: static Tk_Uid allUid = NULL;
        !           153: static Tk_Uid currentUid = NULL;
        !           154: 
        !           155: /*
        !           156:  * Statistics counters:
        !           157:  */
        !           158: 
        !           159: static int numIdSearches;
        !           160: static int numSlowSearches;
        !           161: 
        !           162: static int CanvasUpdateTime = 200; // Added by Don.
        !           163: 
        !           164: /*
        !           165:  * Prototypes for procedures defined later in this file:
        !           166:  */
        !           167: 
        !           168: static void            CanvasBindProc _ANSI_ARGS_((ClientData clientData,
        !           169:                            XEvent *eventPtr));
        !           170: static void            CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
        !           171: static void            CanvasDoEvent _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           172:                            XEvent *eventPtr));
        !           173: static void            CanvasEventProc _ANSI_ARGS_((ClientData clientData,
        !           174:                            XEvent *eventPtr));
        !           175: static int             CanvasFetchSelection _ANSI_ARGS_((
        !           176:                            ClientData clientData, int offset,
        !           177:                            char *buffer, int maxBytes));
        !           178: static void            CanvasFocusProc _ANSI_ARGS_((ClientData clientData,
        !           179:                            int gotFocus));
        !           180: static void            CanvasLostSelection _ANSI_ARGS_((
        !           181:                            ClientData clientData));
        !           182: static void            CanvasSelectTo _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           183:                            Tk_Item *itemPtr, int index));
        !           184: static void            CanvasSetOrigin _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           185:                            int xOrigin, int yOrigin));
        !           186: static int             CanvasTagsParseProc _ANSI_ARGS_((ClientData clientData,
        !           187:                            Tcl_Interp *interp, Tk_Window tkwin, char *value,
        !           188:                            char *widgRec, int offset));
        !           189: static char *          CanvasTagsPrintProc _ANSI_ARGS_((ClientData clientData,
        !           190:                            Tk_Window tkwin, char *widgRec, int offset,
        !           191:                            Tcl_FreeProc **freeProcPtr));
        !           192: static void            CanvasUpdateScrollbars _ANSI_ARGS_((
        !           193:                            Tk_Canvas *canvasPtr));
        !           194: static int             CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
        !           195:                            Tcl_Interp *interp, int argc, char **argv));
        !           196: static int             ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
        !           197:                            Tk_Canvas *canvasPtr, int argc, char **argv,
        !           198:                            int flags));
        !           199: static void            DestroyCanvas _ANSI_ARGS_((ClientData clientData));
        !           200: static void            DisplayCanvas _ANSI_ARGS_((ClientData clientData));
        !           201: static void            DoItem _ANSI_ARGS_((Tcl_Interp *interp,
        !           202:                            Tk_Item *itemPtr, Tk_Uid tag));
        !           203: static void            EventuallyRedrawArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           204:                            int x1, int y1, int x2, int y2));
        !           205: static int             FindItems _ANSI_ARGS_((Tcl_Interp *interp,
        !           206:                            Tk_Canvas *canvasPtr, int argc, char **argv,
        !           207:                            char *newTag, char *cmdName, char *option));
        !           208: static int             FindArea _ANSI_ARGS_((Tcl_Interp *interp,
        !           209:                            Tk_Canvas *canvasPtr, char **argv, Tk_Uid uid,
        !           210:                            int enclosed));
        !           211: static double          GridAlign _ANSI_ARGS_((double coord, double spacing));
        !           212: static void            InitCanvas _ANSI_ARGS_((void));
        !           213: static Tk_Item *       NextItem _ANSI_ARGS_((TagSearch *searchPtr));
        !           214: static void            PickCurrentItem _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           215:                            XEvent *eventPtr));
        !           216: static void            RelinkItems _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           217:                            char *tag, Tk_Item *prevPtr));
        !           218: #if defined(USE_XPM3)
        !           219: static int             SaveCanvas _ANSI_ARGS_((Tcl_Interp *interp,
        !           220:                            Tk_Canvas *canvasPtr, char *fileName, int x,
        !           221:                            int y, unsigned int width, unsigned int height));
        !           222: #endif
        !           223: static Tk_Item *       StartTagSearch _ANSI_ARGS_((Tk_Canvas *canvasPtr,
        !           224:                            char *tag, TagSearch *searchPtr));
        !           225: 
        !           226: /*
        !           227:  * Custom option for handling "-tags" options for canvas items:
        !           228:  */
        !           229: 
        !           230: Tk_CustomOption tkCanvasTagsOption = {
        !           231:     CanvasTagsParseProc,
        !           232:     CanvasTagsPrintProc,
        !           233:     (ClientData) NULL
        !           234: };
        !           235: 
        !           236: /*
        !           237:  *--------------------------------------------------------------
        !           238:  *
        !           239:  * Tk_CanvasCmd --
        !           240:  *
        !           241:  *     This procedure is invoked to process the "canvas" Tcl
        !           242:  *     command.  See the user documentation for details on what
        !           243:  *     it does.
        !           244:  *
        !           245:  * Results:
        !           246:  *     A standard Tcl result.
        !           247:  *
        !           248:  * Side effects:
        !           249:  *     See the user documentation.
        !           250:  *
        !           251:  *--------------------------------------------------------------
        !           252:  */
        !           253: 
        !           254: int
        !           255: Tk_CanvasCmd(clientData, interp, argc, argv)
        !           256:     ClientData clientData;             /* Main window associated with
        !           257:                                 * interpreter. */
        !           258:     Tcl_Interp *interp;                /* Current interpreter. */
        !           259:     int argc;                  /* Number of arguments. */
        !           260:     char **argv;               /* Argument strings. */
        !           261: {
        !           262:     Tk_Window tkwin = (Tk_Window) clientData;
        !           263:     register Tk_Canvas *canvasPtr;
        !           264:     Tk_Window new;
        !           265: 
        !           266:     if (typeList == NULL) {
        !           267:        InitCanvas();
        !           268:     }
        !           269: 
        !           270:     if (argc < 2) {
        !           271:        Tcl_AppendResult(interp, "wrong # args:  should be \"",
        !           272:                argv[0], " pathName ?options?\"", (char *) NULL);
        !           273:        return TCL_ERROR;
        !           274:     }
        !           275: 
        !           276:     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
        !           277:     if (new == NULL) {
        !           278:        return TCL_ERROR;
        !           279:     }
        !           280: 
        !           281:     /*
        !           282:      * Initialize fields that won't be initialized by ConfigureCanvas,
        !           283:      * or which ConfigureCanvas expects to have reasonable values
        !           284:      * (e.g. resource pointers).
        !           285:      */
        !           286: 
        !           287:     canvasPtr = (Tk_Canvas *) ckalloc(sizeof(Tk_Canvas));
        !           288:     canvasPtr->tkwin = new;
        !           289:     canvasPtr->interp = interp;
        !           290:     canvasPtr->firstItemPtr = NULL;
        !           291:     canvasPtr->lastItemPtr = NULL;
        !           292:     canvasPtr->bgBorder = NULL;
        !           293:     canvasPtr->bgColor = NULL;
        !           294:     canvasPtr->pixmapGC = None;
        !           295:     canvasPtr->selBorder = NULL;
        !           296:     canvasPtr->selFgColorPtr = NULL;
        !           297:     canvasPtr->selItemPtr = NULL;
        !           298:     canvasPtr->selectFirst = -1;
        !           299:     canvasPtr->selectLast = -1;
        !           300:     canvasPtr->cursorBorder = NULL;
        !           301:     canvasPtr->cursorBlinkHandler = (Tk_TimerToken) NULL;
        !           302:     canvasPtr->focusItemPtr = NULL;
        !           303:     canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
        !           304:     canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
        !           305:     canvasPtr->bindingTable = NULL;
        !           306:     canvasPtr->currentItemPtr = NULL;
        !           307:     canvasPtr->pickEvent.type = LeaveNotify;
        !           308:     canvasPtr->xScrollCmd = NULL;
        !           309:     canvasPtr->yScrollCmd = NULL;
        !           310:     canvasPtr->regionString = NULL;
        !           311:     canvasPtr->hotPtr = NULL;
        !           312:     canvasPtr->cursor = None;
        !           313:     canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
        !           314:     canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
        !           315:     canvasPtr->flags = 0;
        !           316:     canvasPtr->nextId = 1;
        !           317:     canvasPtr->updateTimerToken = NULL;
        !           318: 
        !           319:     Tk_SetClass(canvasPtr->tkwin, "Canvas");
        !           320:     Tk_CreateEventHandler(canvasPtr->tkwin, ExposureMask|StructureNotifyMask,
        !           321:            CanvasEventProc, (ClientData) canvasPtr);
        !           322:     Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
        !           323:            |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
        !           324:            |LeaveWindowMask|PointerMotionMask, CanvasBindProc,
        !           325:            (ClientData) canvasPtr);
        !           326:     Tk_CreateSelHandler(canvasPtr->tkwin, XA_STRING, CanvasFetchSelection,
        !           327:            (ClientData) canvasPtr, XA_STRING);
        !           328:     Tcl_CreateCommand(interp, Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
        !           329:            (ClientData) canvasPtr, (void (*)()) NULL);
        !           330:     if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
        !           331:        goto error;
        !           332:     }
        !           333:     Tk_CreateFocusHandler(canvasPtr->tkwin, CanvasFocusProc,
        !           334:            (ClientData) canvasPtr);
        !           335: 
        !           336:     interp->result = Tk_PathName(canvasPtr->tkwin);
        !           337:     return TCL_OK;
        !           338: 
        !           339:     error:
        !           340:     Tk_DestroyWindow(canvasPtr->tkwin);
        !           341:     return TCL_ERROR;
        !           342: }
        !           343: 
        !           344: /*
        !           345:  *--------------------------------------------------------------
        !           346:  *
        !           347:  * CanvasWidgetCmd --
        !           348:  *
        !           349:  *     This procedure is invoked to process the Tcl command
        !           350:  *     that corresponds to a widget managed by this module.
        !           351:  *     See the user documentation for details on what it does.
        !           352:  *
        !           353:  * Results:
        !           354:  *     A standard Tcl result.
        !           355:  *
        !           356:  * Side effects:
        !           357:  *     See the user documentation.
        !           358:  *
        !           359:  *--------------------------------------------------------------
        !           360:  */
        !           361: 
        !           362: static int
        !           363: CanvasWidgetCmd(clientData, interp, argc, argv)
        !           364:     ClientData clientData;             /* Information about canvas
        !           365:                                         * widget. */
        !           366:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           367:     int argc;                          /* Number of arguments. */
        !           368:     char **argv;                       /* Argument strings. */
        !           369: {
        !           370:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !           371:     int length, result;
        !           372:     char c;
        !           373:     Tk_Item *itemPtr = NULL;           /* Initialization needed only to
        !           374:                                         * prevent compiler warning. */
        !           375:     TagSearch search;
        !           376: 
        !           377:     if (argc < 2) {
        !           378:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           379:                argv[0], " option ?arg arg ...?\"", (char *) NULL);
        !           380:        return TCL_ERROR;
        !           381:     }
        !           382:     Tk_Preserve((ClientData) canvasPtr);
        !           383:     result = TCL_OK;
        !           384:     c = argv[1][0];
        !           385:     length = strlen(argv[1]);
        !           386:     if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) {
        !           387:        if (argc < 4) {
        !           388:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           389:                    argv[0], " addtags tag searchCommand ?arg arg ...?\"",
        !           390:                    (char *) NULL);
        !           391:            goto error;
        !           392:        }
        !           393:        result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0],
        !           394:                " addtag tag");
        !           395:     } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)
        !           396:            && (length >= 2)) {
        !           397:        int i, gotAny;
        !           398:        int x1 = 0, y1 = 0, x2 = 0, y2 = 0;     /* Initializations needed
        !           399:                                                 * only to prevent compiler
        !           400:                                                 * warnings. */
        !           401: 
        !           402:        if (argc < 3) {
        !           403:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           404:                    argv[0], " bbox tagOrId ?tagOrId ...?\"",
        !           405:                    (char *) NULL);
        !           406:            goto error;
        !           407:        }
        !           408:        gotAny = 0;
        !           409:        for (i = 2; i < argc; i++) {
        !           410:            for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
        !           411:                    itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           412:                if (!gotAny) {
        !           413:                    x1 = itemPtr->x1;
        !           414:                    y1 = itemPtr->y1;
        !           415:                    x2 = itemPtr->x2;
        !           416:                    y2 = itemPtr->y2;
        !           417:                    gotAny = 1;
        !           418:                } else {
        !           419:                    if (itemPtr->x1 < x1) {
        !           420:                        x1 = itemPtr->x1;
        !           421:                    }
        !           422:                    if (itemPtr->y1 < y1) {
        !           423:                        y1 = itemPtr->y1;
        !           424:                    }
        !           425:                    if (itemPtr->x2 > x2) {
        !           426:                        x2 = itemPtr->x2;
        !           427:                    }
        !           428:                    if (itemPtr->y2 > y2) {
        !           429:                        y2 = itemPtr->y2;
        !           430:                    }
        !           431:                }
        !           432:            }
        !           433:        }
        !           434:        if (gotAny) {
        !           435:            sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2);
        !           436:        }
        !           437:     } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)
        !           438:            && (length >= 2)) {
        !           439:        ClientData object;
        !           440: 
        !           441:        if ((argc < 3) || (argc > 5)) {
        !           442:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           443:                    argv[0], " bind tagOrId ?sequence? ?command?\"",
        !           444:                    (char *) NULL);
        !           445:            goto error;
        !           446:        }
        !           447: 
        !           448:        /*
        !           449:         * Figure out what object to use for the binding (individual
        !           450:         * item vs. tag).
        !           451:         */
        !           452: 
        !           453:        object = 0;
        !           454:        if (isdigit(argv[2][0])) {
        !           455:            int id;
        !           456:            char *end;
        !           457: 
        !           458:            id = strtoul(argv[2], &end, 0);
        !           459:            if (*end != 0) {
        !           460:                goto bindByTag;
        !           461:            }
        !           462:            for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !           463:                    itemPtr = itemPtr->nextPtr) {
        !           464:                if (itemPtr->id == id) {
        !           465:                    object = (ClientData) itemPtr;
        !           466:                    break;
        !           467:                }
        !           468:            }
        !           469:            if (object == 0) {
        !           470:                Tcl_AppendResult(interp, "item \"", argv[2],
        !           471:                        "\" doesn't exist", (char *) NULL);
        !           472:                goto error;
        !           473:            }
        !           474:        } else {
        !           475:            bindByTag:
        !           476:            object = (ClientData) Tk_GetUid(argv[2]);
        !           477:        }
        !           478: 
        !           479:        /*
        !           480:         * Make a binding table if the canvas doesn't already have
        !           481:         * one.
        !           482:         */
        !           483: 
        !           484:        if (canvasPtr->bindingTable == NULL) {
        !           485:            canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
        !           486:        }
        !           487: 
        !           488:        if (argc == 5) {
        !           489:            int append = 0;
        !           490:            unsigned long mask;
        !           491: 
        !           492:            if (argv[4][0] == 0) {
        !           493:                result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
        !           494:                        object, argv[3]);
        !           495:                goto done;
        !           496:            }
        !           497:            if (argv[4][0] == '+') {
        !           498:                argv[4]++;
        !           499:                append = 1;
        !           500:            }
        !           501:            mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
        !           502:                    object, argv[3], argv[4], append);
        !           503:            if (mask == 0) {
        !           504:                goto error;
        !           505:            }
        !           506:            if (mask & ~(ButtonMotionMask|Button1MotionMask|Button2MotionMask
        !           507:                    |Button3MotionMask|Button4MotionMask|Button5MotionMask
        !           508:                    |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
        !           509:                    |LeaveWindowMask|KeyPressMask|KeyReleaseMask
        !           510:                    |PointerMotionMask)) {
        !           511:                Tk_DeleteBinding(interp, canvasPtr->bindingTable,
        !           512:                        object, argv[3]);
        !           513:                Tcl_ResetResult(interp);
        !           514:                Tcl_AppendResult(interp, "requested illegal events; ",
        !           515:                        "only key, button, motion, and enter/leave ",
        !           516:                        "events may be used", (char *) NULL);
        !           517:                goto error;
        !           518:            }
        !           519:        } else if (argc == 4) {
        !           520:            char *command;
        !           521:     
        !           522:            command = Tk_GetBinding(interp, canvasPtr->bindingTable,
        !           523:                    object, argv[3]);
        !           524:            if (command == NULL) {
        !           525:                goto error;
        !           526:            }
        !           527:            interp->result = command;
        !           528:        } else {
        !           529:            Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
        !           530:        }
        !           531:     } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) {
        !           532:        int x;
        !           533:        double grid;
        !           534: 
        !           535:        if ((argc < 3) || (argc > 4)) {
        !           536:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           537:                    argv[0], " canvasx screenx ?gridspacing?\"",
        !           538:                    (char *) NULL);
        !           539:            goto error;
        !           540:        }
        !           541:        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {
        !           542:            goto error;
        !           543:        }
        !           544:        if (argc == 4) {
        !           545:            if (TkGetCanvasCoord(canvasPtr, argv[3], &grid) != TCL_OK) {
        !           546:                goto error;
        !           547:            }
        !           548:        } else {
        !           549:            grid = 0.0;
        !           550:        }
        !           551:        x += canvasPtr->xOrigin;
        !           552:        sprintf(interp->result, "%g", GridAlign((double) x, grid));
        !           553:     } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) {
        !           554:        int y;
        !           555:        double grid;
        !           556: 
        !           557:        if ((argc < 3) || (argc > 4)) {
        !           558:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           559:                    argv[0], " canvasy screeny ?gridspacing?\"",
        !           560:                    (char *) NULL);
        !           561:            goto error;
        !           562:        }
        !           563:        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {
        !           564:            goto error;
        !           565:        }
        !           566:        if (argc == 4) {
        !           567:            if (TkGetCanvasCoord(canvasPtr, argv[3], &grid) != TCL_OK) {
        !           568:                goto error;
        !           569:            }
        !           570:        } else {
        !           571:            grid = 0.0;
        !           572:        }
        !           573:        y += canvasPtr->yOrigin;
        !           574:        sprintf(interp->result, "%g", GridAlign((double) y, grid));
        !           575:     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
        !           576:            && (length >= 3)) {
        !           577:        if (argc == 2) {
        !           578:            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
        !           579:                    (char *) canvasPtr, (char *) NULL, 0);
        !           580:        } else if (argc == 3) {
        !           581:            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
        !           582:                    (char *) canvasPtr, argv[2], 0);
        !           583:        } else {
        !           584:            result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,
        !           585:                    TK_CONFIG_ARGV_ONLY);
        !           586:        }
        !           587:     } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)
        !           588:            && (length >= 3)) {
        !           589:        if (argc < 3) {
        !           590:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           591:                    argv[0], " coords tagOrId ?x y x y ...?\"",
        !           592:                    (char *) NULL);
        !           593:            goto error;
        !           594:        }
        !           595:        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           596:        if (itemPtr != NULL) {
        !           597:            if (argc != 3) {
        !           598:                EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           599:                    itemPtr->x2, itemPtr->y2);
        !           600:            }
        !           601:            if (itemPtr->typePtr->coordProc != NULL) {
        !           602:                result = (*itemPtr->typePtr->coordProc)(canvasPtr, itemPtr,
        !           603:                        argc-3, argv+3);
        !           604:            }
        !           605:            if (argc != 3) {
        !           606:                EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           607:                    itemPtr->x2, itemPtr->y2);
        !           608:            }
        !           609:        }
        !           610:     } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)
        !           611:            && (length >= 2)) {
        !           612:        register Tk_ItemType *typePtr;
        !           613:        Tk_ItemType *matchPtr = NULL;
        !           614:        register Tk_Item *itemPtr;
        !           615: 
        !           616:        if (argc < 3) {
        !           617:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           618:                    argv[0], " create type ?arg arg ...?\"", (char *) NULL);
        !           619:            goto error;
        !           620:        }
        !           621:        c = argv[2][0];
        !           622:        length = strlen(argv[2]);
        !           623:        for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
        !           624:            if ((c == typePtr->name[0])
        !           625:                    && (strncmp(argv[2], typePtr->name, length) == 0)) {
        !           626:                if (matchPtr != NULL) {
        !           627:                    badType:
        !           628:                    Tcl_AppendResult(interp,
        !           629:                            "unknown or ambiguous item type \"",
        !           630:                            argv[2], "\"", (char *) NULL);
        !           631:                    goto error;
        !           632:                }
        !           633:                matchPtr = typePtr;
        !           634:            }
        !           635:        }
        !           636:        if (matchPtr == NULL) {
        !           637:            goto badType;
        !           638:        }
        !           639:        typePtr = matchPtr;
        !           640:        itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
        !           641:        itemPtr->id = canvasPtr->nextId;
        !           642:        canvasPtr->nextId++;
        !           643:        itemPtr->tagPtr = itemPtr->staticTagSpace;
        !           644:        itemPtr->tagSpace = TK_TAG_SPACE;
        !           645:        itemPtr->numTags = 0;
        !           646:        itemPtr->typePtr = typePtr;
        !           647:        if ((*typePtr->createProc)(canvasPtr, itemPtr, argc-3, argv+3)
        !           648:                != TCL_OK) {
        !           649:            ckfree((char *) itemPtr);
        !           650:            goto error;
        !           651:        }
        !           652:        itemPtr->nextPtr = NULL;
        !           653:        canvasPtr->hotPtr = itemPtr;
        !           654:        canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
        !           655:        if (canvasPtr->lastItemPtr == NULL) {
        !           656:            canvasPtr->firstItemPtr = itemPtr;
        !           657:        } else {
        !           658:            canvasPtr->lastItemPtr->nextPtr = itemPtr;
        !           659:        }
        !           660:        canvasPtr->lastItemPtr = itemPtr;
        !           661:        EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           662:                itemPtr->x2, itemPtr->y2);
        !           663:        canvasPtr->flags |= REPICK_NEEDED;
        !           664:        sprintf(interp->result, "%d", itemPtr->id);
        !           665:     } else if ((c == 'c') && (strncmp(argv[1], "cursor", length) == 0)
        !           666:            && (length >= 2)) {
        !           667:        int index;
        !           668: 
        !           669:        if (argc != 4) {
        !           670:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           671:                    argv[0], " cursor tagOrId index\"",
        !           672:                    (char *) NULL);
        !           673:            goto error;
        !           674:        }
        !           675:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           676:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           677:            if ((itemPtr->typePtr->indexProc == NULL)
        !           678:                    || (itemPtr->typePtr->cursorProc == NULL)) {
        !           679:                goto done;
        !           680:            }
        !           681:            if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !           682:                    argv[3], &index) != TCL_OK) {
        !           683:                goto error;
        !           684:            }
        !           685:            (*itemPtr->typePtr->cursorProc)(canvasPtr, itemPtr, index);
        !           686:            if ((itemPtr == canvasPtr->focusItemPtr)
        !           687:                    && (canvasPtr->flags & CURSOR_ON)) {
        !           688:                EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           689:                        itemPtr->x2, itemPtr->y2);
        !           690:            }
        !           691:        }
        !           692:     } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0)
        !           693:            && (length >= 2)) {
        !           694:        int first, last;
        !           695: 
        !           696:        if ((argc != 4) && (argc != 5)) {
        !           697:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           698:                    argv[0], " dchars tagOrId first ?last?\"",
        !           699:                    (char *) NULL);
        !           700:            goto error;
        !           701:        }
        !           702:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           703:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           704:            if ((itemPtr->typePtr->indexProc == NULL)
        !           705:                    || (itemPtr->typePtr->dCharsProc == NULL)) {
        !           706:                continue;
        !           707:            }
        !           708:            if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !           709:                    argv[3], &first) != TCL_OK) {
        !           710:                goto error;
        !           711:            }
        !           712:            if (argc == 5) {
        !           713:                if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !           714:                        argv[4], &last) != TCL_OK) {
        !           715:                    goto error;
        !           716:                }
        !           717:            } else {
        !           718:                last = first;
        !           719:            }
        !           720: 
        !           721:            /*
        !           722:             * Redraw both item's old and new areas:  it's possible
        !           723:             * that a delete could result in a new area larger than
        !           724:             * the old area.
        !           725:             */
        !           726: 
        !           727:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           728:                    itemPtr->x2, itemPtr->y2);
        !           729:            result = (*itemPtr->typePtr->dCharsProc)(canvasPtr, itemPtr,
        !           730:                    first, last);
        !           731:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           732:                    itemPtr->x2, itemPtr->y2);
        !           733:            if (result != TCL_OK) {
        !           734:                goto error;
        !           735:            }
        !           736:        }
        !           737:     } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)
        !           738:            && (length >= 2)) {
        !           739:        if (argc != 3) {
        !           740:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           741:                    argv[0], " delete tagOrId\"",
        !           742:                    (char *) NULL);
        !           743:            goto error;
        !           744:        }
        !           745:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           746:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           747:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           748:                itemPtr->x2, itemPtr->y2);
        !           749:            (*itemPtr->typePtr->deleteProc)(itemPtr);
        !           750:            if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        !           751:                ckfree((char *) itemPtr->tagPtr);
        !           752:            }
        !           753:            if (search.prevPtr == NULL) {
        !           754:                canvasPtr->firstItemPtr = itemPtr->nextPtr;
        !           755:                if (canvasPtr->firstItemPtr == NULL) {
        !           756:                    canvasPtr->lastItemPtr = NULL;
        !           757:                }
        !           758:            } else {
        !           759:                search.prevPtr->nextPtr = itemPtr->nextPtr;
        !           760:            }
        !           761:            if (canvasPtr->lastItemPtr == itemPtr) {
        !           762:                canvasPtr->lastItemPtr = search.prevPtr;
        !           763:            }
        !           764:            ckfree((char *) itemPtr);
        !           765:            if (itemPtr == canvasPtr->currentItemPtr) {
        !           766:                canvasPtr->currentItemPtr = NULL;
        !           767:                canvasPtr->flags |= REPICK_NEEDED;
        !           768:            }
        !           769:            if (itemPtr == canvasPtr->focusItemPtr) {
        !           770:                canvasPtr->focusItemPtr = NULL;
        !           771:            }
        !           772:            if (itemPtr == canvasPtr->selItemPtr) {
        !           773:                canvasPtr->selItemPtr = NULL;
        !           774:            }
        !           775:            if ((itemPtr == canvasPtr->hotPtr)
        !           776:                    || (itemPtr = canvasPtr->hotPrevPtr)) {
        !           777:                canvasPtr->hotPtr = NULL;
        !           778:            }
        !           779:        }
        !           780:     } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0)
        !           781:            && (length >= 2)) {
        !           782:        Tk_Uid tag;
        !           783:        int i;
        !           784: 
        !           785:        if ((argc != 3) && (argc != 4)) {
        !           786:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           787:                    argv[0], " dtag tagOrId ?tagToDelete?\"",
        !           788:                    (char *) NULL);
        !           789:            goto error;
        !           790:        }
        !           791:        if (argc == 4) {
        !           792:            tag = Tk_GetUid(argv[3]);
        !           793:        } else {
        !           794:            tag = Tk_GetUid(argv[2]);
        !           795:        }
        !           796:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           797:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           798:            for (i = itemPtr->numTags-1; i >= 0; i--) {
        !           799:                if (itemPtr->tagPtr[i] == tag) {
        !           800:                    itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
        !           801:                    itemPtr->numTags--;
        !           802:                }
        !           803:            }
        !           804:        }
        !           805:     } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)
        !           806:            && (length >= 2)) {
        !           807:        if (argc < 3) {
        !           808:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           809:                    argv[0], " find searchCommand ?arg arg ...?\"",
        !           810:                    (char *) NULL);
        !           811:            goto error;
        !           812:        }
        !           813:        result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL,
        !           814:                argv[0]," find");
        !           815:     } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0)
        !           816:            && (length >= 2)) {
        !           817:        if (argc > 3) {
        !           818:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           819:                    argv[0], " focus ?tagOrId?\"",
        !           820:                    (char *) NULL);
        !           821:            goto error;
        !           822:        }
        !           823:        itemPtr = canvasPtr->focusItemPtr;
        !           824:        if (argc == 2) {
        !           825:            if (itemPtr != NULL) {
        !           826:                sprintf(interp->result, "%d", itemPtr->id);
        !           827:            }
        !           828:            goto done;
        !           829:        }
        !           830:        if ((itemPtr != NULL) && (canvasPtr->flags & GOT_FOCUS)) {
        !           831:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           832:                    itemPtr->x2, itemPtr->y2);
        !           833:        }
        !           834:        if (argv[2][0] == 0) {
        !           835:            canvasPtr->focusItemPtr = NULL;
        !           836:            goto done;
        !           837:        }
        !           838:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           839:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           840:            if (itemPtr->typePtr->cursorProc != NULL) {
        !           841:                break;
        !           842:            }
        !           843:        }
        !           844:        if (itemPtr == NULL) {
        !           845:            goto done;
        !           846:        }
        !           847:        canvasPtr->focusItemPtr = itemPtr;
        !           848:        if (canvasPtr->flags & GOT_FOCUS) {
        !           849:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           850:                    itemPtr->x2, itemPtr->y2);
        !           851:        }
        !           852:     } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) {
        !           853:        if (argc != 3) {
        !           854:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           855:                    argv[0], " gettags tagOrId\"", (char *) NULL);
        !           856:            goto error;
        !           857:        }
        !           858:        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           859:        if (itemPtr != NULL) {
        !           860:            int i;
        !           861:            for (i = 0; i < itemPtr->numTags; i++) {
        !           862:                Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i], 0);
        !           863:            }
        !           864:        }
        !           865:     } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
        !           866:            && (length >= 3)) {
        !           867:        int index;
        !           868: 
        !           869:        if (argc != 4) {
        !           870:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           871:                    argv[0], " index tagOrId string\"",
        !           872:                    (char *) NULL);
        !           873:            goto error;
        !           874:        }
        !           875:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           876:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           877:            if (itemPtr->typePtr->indexProc != NULL) {
        !           878:                break;
        !           879:            }
        !           880:        }
        !           881:        if (itemPtr == NULL) {
        !           882:            Tcl_AppendResult(interp, "can't find an indexable item \"",
        !           883:                    argv[2], "\"", (char *) NULL);
        !           884:            goto error;
        !           885:        }
        !           886:        if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !           887:                argv[3], &index) != TCL_OK) {
        !           888:            goto error;
        !           889:        }
        !           890:        sprintf(interp->result, "%d", index);
        !           891:     } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
        !           892:            && (length >= 3)) {
        !           893:        int beforeThis;
        !           894: 
        !           895:        if (argc != 5) {
        !           896:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           897:                    argv[0], " insert tagOrId beforeThis string\"",
        !           898:                    (char *) NULL);
        !           899:            goto error;
        !           900:        }
        !           901:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           902:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           903:            if ((itemPtr->typePtr->indexProc == NULL)
        !           904:                    || (itemPtr->typePtr->insertProc == NULL)) {
        !           905:                continue;
        !           906:            }
        !           907:            if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !           908:                    argv[3], &beforeThis) != TCL_OK) {
        !           909:                goto error;
        !           910:            }
        !           911: 
        !           912:            /*
        !           913:             * Redraw both item's old and new areas:  it's possible
        !           914:             * that an insertion could result in a new area either
        !           915:             * larger or smaller than the old area.
        !           916:             */
        !           917: 
        !           918:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           919:                    itemPtr->x2, itemPtr->y2);
        !           920:            result = (*itemPtr->typePtr->insertProc)(canvasPtr, itemPtr,
        !           921:                    beforeThis, argv[4]);
        !           922:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           923:                    itemPtr->x2, itemPtr->y2);
        !           924:            if (result != TCL_OK) {
        !           925:                goto error;
        !           926:            }
        !           927:        }
        !           928:     } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0)
        !           929:            && (length >= 2)) {
        !           930:        if (argc < 3) {
        !           931:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           932:                    argv[0], " itemconfigure tagOrId ?option value ...?\"",
        !           933:                    (char *) NULL);
        !           934:            goto error;
        !           935:        }
        !           936:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !           937:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !           938:            if (argc == 3) {
        !           939:                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
        !           940:                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
        !           941:                        (char *) NULL, 0);
        !           942:            } else if (argc == 4) {
        !           943:                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
        !           944:                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
        !           945:                        argv[3], 0);
        !           946:            } else {
        !           947:                EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           948:                        itemPtr->x2, itemPtr->y2);
        !           949:                result = (*itemPtr->typePtr->configProc)(canvasPtr, itemPtr,
        !           950:                        argc-3, argv+3, TK_CONFIG_ARGV_ONLY);
        !           951:                EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !           952:                        itemPtr->x2, itemPtr->y2);
        !           953:                canvasPtr->flags |= REPICK_NEEDED;
        !           954:            }
        !           955:            if ((result != TCL_OK) || (argc < 5)) {
        !           956:                break;
        !           957:            }
        !           958:        }
        !           959:     } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) {
        !           960:        Tk_Item *prevPtr;
        !           961: 
        !           962:        if ((argc != 3) && (argc != 4)) {
        !           963:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           964:                    argv[0], " lower tagOrId ?belowThis?\"",
        !           965:                    (char *) NULL);
        !           966:            goto error;
        !           967:        }
        !           968: 
        !           969:        /*
        !           970:         * First find the item just after which we'll insert the
        !           971:         * named items.
        !           972:         */
        !           973: 
        !           974:        if (argc == 3) {
        !           975:            prevPtr = NULL;
        !           976:        } else {
        !           977:            prevPtr = StartTagSearch(canvasPtr, argv[3], &search);
        !           978:            if (prevPtr != NULL) {
        !           979:                prevPtr = search.prevPtr;
        !           980:            } else {
        !           981:                Tcl_AppendResult(interp, "tag \"", argv[3],
        !           982:                        "\" doesn't match any items", (char *) NULL);
        !           983:                goto error;
        !           984:            }
        !           985:        }
        !           986:        RelinkItems(canvasPtr, argv[2], prevPtr);
        !           987:     } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) {
        !           988:        double xAmount, yAmount;
        !           989: 
        !           990:        if (argc != 5) {
        !           991:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           992:                    argv[0], " move tagOrId xAmount yAmount\"",
        !           993:                    (char *) NULL);
        !           994:            goto error;
        !           995:        }
        !           996:        if ((TkGetCanvasCoord(canvasPtr, argv[3], &xAmount) != TCL_OK)
        !           997:                || (TkGetCanvasCoord(canvasPtr, argv[4], &yAmount) != TCL_OK)) {
        !           998:            goto error;
        !           999:        }
        !          1000:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !          1001:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          1002:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          1003:                itemPtr->x2, itemPtr->y2);
        !          1004:            (void) (*itemPtr->typePtr->translateProc)(canvasPtr, itemPtr,
        !          1005:                    xAmount, yAmount);
        !          1006:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          1007:                itemPtr->x2, itemPtr->y2);
        !          1008:            canvasPtr->flags |= REPICK_NEEDED;
        !          1009:        }
        !          1010:     } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) {
        !          1011:        Tk_Item *prevPtr;
        !          1012: 
        !          1013:        if ((argc != 3) && (argc != 4)) {
        !          1014:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1015:                    argv[0], " raise tagOrId ?aboveThis?\"",
        !          1016:                    (char *) NULL);
        !          1017:            goto error;
        !          1018:        }
        !          1019: 
        !          1020:        /*
        !          1021:         * First find the item just after which we'll insert the
        !          1022:         * named items.
        !          1023:         */
        !          1024: 
        !          1025:        if (argc == 3) {
        !          1026:            prevPtr = canvasPtr->lastItemPtr;
        !          1027:        } else {
        !          1028:            prevPtr = NULL;
        !          1029:            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
        !          1030:                    itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          1031:                prevPtr = itemPtr;
        !          1032:            }
        !          1033:            if (prevPtr == NULL) {
        !          1034:                Tcl_AppendResult(interp, "tagOrId \"", argv[3],
        !          1035:                        "\" doesn't match any items", (char *) NULL);
        !          1036:                goto error;
        !          1037:            }
        !          1038:        }
        !          1039:        RelinkItems(canvasPtr, argv[2], prevPtr);
        !          1040: #if defined(USE_XPM3)
        !          1041:     } else if ((c == 's') && (strncmp(argv[1], "save", length) == 0)
        !          1042:            && (length >= 3)) {
        !          1043:        if (argc != 3 && argc != 7) {
        !          1044:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1045:                    argv[0], " save fileName ?x y width height?\"",
        !          1046:                    (char *) NULL);
        !          1047:            goto error;
        !          1048:        }
        !          1049:         if (argc == 3) {
        !          1050:            if (SaveCanvas(interp, canvasPtr, argv[2], 0, 0, 0, 0) != TCL_OK) {
        !          1051:                goto error;
        !          1052:            }
        !          1053:         } else {
        !          1054:            if (SaveCanvas(interp, canvasPtr, argv[2], atol(argv[3]),
        !          1055:                    atol(argv[4]), atol(argv[5]), atol(argv[6]))) {
        !          1056:                goto error;
        !          1057:            }
        !          1058:         }
        !          1059: #endif
        !          1060:     } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)
        !          1061:            && (length >= 3)) {
        !          1062:        double xOrigin, yOrigin, xScale, yScale;
        !          1063: 
        !          1064:        if (argc != 7) {
        !          1065:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1066:                    argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"",
        !          1067:                    (char *) NULL);
        !          1068:            goto error;
        !          1069:        }
        !          1070:        if ((TkGetCanvasCoord(canvasPtr, argv[3], &xOrigin) != TCL_OK)
        !          1071:                || (TkGetCanvasCoord(canvasPtr, argv[4], &yOrigin) != TCL_OK)
        !          1072:                || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK)
        !          1073:                || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) {
        !          1074:            goto error;
        !          1075:        }
        !          1076:        if ((xScale <= 0.0) || (yScale <= 0.0)) {
        !          1077:            interp->result = "scale factors must be greater than zero";
        !          1078:            goto error;
        !          1079:        }
        !          1080:        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !          1081:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          1082:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          1083:                itemPtr->x2, itemPtr->y2);
        !          1084:            (void) (*itemPtr->typePtr->scaleProc)(canvasPtr, itemPtr,
        !          1085:                    xOrigin, yOrigin, xScale, yScale);
        !          1086:            EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          1087:                itemPtr->x2, itemPtr->y2);
        !          1088:            canvasPtr->flags |= REPICK_NEEDED;
        !          1089:        }
        !          1090:     } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0)
        !          1091:            && (length >= 3)) {
        !          1092:        int x, y;
        !          1093: 
        !          1094:        if (argc != 5) {
        !          1095:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1096:                    argv[0], " scan mark|dragto x y\"", (char *) NULL);
        !          1097:            goto error;
        !          1098:        }
        !          1099:        if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
        !          1100:                || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
        !          1101:            goto error;
        !          1102:        }
        !          1103:        if ((argv[2][0] == 'm')
        !          1104:                && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
        !          1105:            canvasPtr->scanX = x;
        !          1106:            canvasPtr->scanXOrigin = canvasPtr->xOrigin;
        !          1107:            canvasPtr->scanY = y;
        !          1108:            canvasPtr->scanYOrigin = canvasPtr->yOrigin;
        !          1109:        } else if ((argv[2][0] == 'd')
        !          1110:                && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
        !          1111:            int newXOrigin, newYOrigin, tmp;
        !          1112: 
        !          1113:            /*
        !          1114:             * Compute a new view origin for the canvas, amplifying the
        !          1115:             * mouse motion and rounding to the nearest multiple of the
        !          1116:             * scroll increment.
        !          1117:             */
        !          1118: 
        !          1119:            tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX)
        !          1120:                    - canvasPtr->scrollX1;
        !          1121:            if (tmp >= 0) {
        !          1122:                tmp = (tmp + canvasPtr->scrollIncrement/2)
        !          1123:                        /canvasPtr->scrollIncrement;
        !          1124:            } else {
        !          1125:                tmp = -(((-tmp) + canvasPtr->scrollIncrement/2)
        !          1126:                        /canvasPtr->scrollIncrement);
        !          1127:            }
        !          1128:            newXOrigin = canvasPtr->scrollX1 + tmp*canvasPtr->scrollIncrement;
        !          1129:            tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY)
        !          1130:                    - canvasPtr->scrollY1;
        !          1131:            if (tmp >= 0) {
        !          1132:                tmp = (tmp + canvasPtr->scrollIncrement/2)
        !          1133:                        /canvasPtr->scrollIncrement;
        !          1134:            } else {
        !          1135:                tmp = -(((-tmp) + canvasPtr->scrollIncrement/2)
        !          1136:                        /canvasPtr->scrollIncrement);
        !          1137:            }
        !          1138:            newYOrigin = canvasPtr->scrollY1 + tmp*canvasPtr->scrollIncrement;
        !          1139:            CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
        !          1140:        } else {
        !          1141:            Tcl_AppendResult(interp, "bad scan option \"", argv[2],
        !          1142:                    "\":  must be mark or dragto", (char *) NULL);
        !          1143:            goto error;
        !          1144:        }
        !          1145:     } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0)
        !          1146:            && (length >= 2)) {
        !          1147:        int index;
        !          1148: 
        !          1149:        if (argc < 3) {
        !          1150:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1151:                    argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL);
        !          1152:            goto error;
        !          1153:        }
        !          1154:        if (argc >= 4) {
        !          1155:            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
        !          1156:                    itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          1157:                if ((itemPtr->typePtr->indexProc != NULL)
        !          1158:                        && (itemPtr->typePtr->selectionProc != NULL)){
        !          1159:                    break;
        !          1160:                }
        !          1161:            }
        !          1162:            if (itemPtr == NULL) {
        !          1163:                Tcl_AppendResult(interp,
        !          1164:                        "can't find an indexable and selectable item \"",
        !          1165:                        argv[3], "\"", (char *) NULL);
        !          1166:                goto error;
        !          1167:            }
        !          1168:        }
        !          1169:        if (argc == 5) {
        !          1170:            if ((*itemPtr->typePtr->indexProc)(canvasPtr, itemPtr,
        !          1171:                    argv[4], &index) != TCL_OK) {
        !          1172:                goto error;
        !          1173:            }
        !          1174:        }
        !          1175:        length = strlen(argv[2]);
        !          1176:        c = argv[2][0];
        !          1177:        if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
        !          1178:            if (argc != 5) {
        !          1179:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1180:                        argv[0], " select adjust tagOrId index\"",
        !          1181:                        (char *) NULL);
        !          1182:                goto error;
        !          1183:            }
        !          1184:            if (canvasPtr->selItemPtr == itemPtr) {
        !          1185:                if (index < (canvasPtr->selectFirst
        !          1186:                        + canvasPtr->selectLast)/2) {
        !          1187:                    canvasPtr->selectAnchor = canvasPtr->selectLast + 1;
        !          1188:                } else {
        !          1189:                    canvasPtr->selectAnchor = canvasPtr->selectFirst;
        !          1190:                }
        !          1191:            }
        !          1192:            CanvasSelectTo(canvasPtr, itemPtr, index);
        !          1193:        } else if ((c == 'c') && (argv[2] != NULL)
        !          1194:                && (strncmp(argv[2], "clear", length) == 0)) {
        !          1195:            if (argc != 3) {
        !          1196:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1197:                        argv[0], " select clear\"", (char *) NULL);
        !          1198:                goto error;
        !          1199:            }
        !          1200:            if (canvasPtr->selItemPtr != NULL) {
        !          1201:                EventuallyRedrawArea(canvasPtr, canvasPtr->selItemPtr->x1,
        !          1202:                    canvasPtr->selItemPtr->y1, canvasPtr->selItemPtr->x2,
        !          1203:                    canvasPtr->selItemPtr->y2);
        !          1204:                canvasPtr->selItemPtr = NULL;
        !          1205:            }
        !          1206:            goto done;
        !          1207:        } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
        !          1208:            if (argc != 5) {
        !          1209:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1210:                        argv[0], " select from tagOrId index\"",
        !          1211:                        (char *) NULL);
        !          1212:                goto error;
        !          1213:            }
        !          1214:            canvasPtr->anchorItemPtr = itemPtr;
        !          1215:            canvasPtr->selectAnchor = index;
        !          1216:        } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) {
        !          1217:            if (argc != 3) {
        !          1218:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1219:                        argv[0], " select item\"", (char *) NULL);
        !          1220:                goto error;
        !          1221:            }
        !          1222:            if (canvasPtr->selItemPtr != NULL) {
        !          1223:                sprintf(interp->result, "%d", canvasPtr->selItemPtr->id);
        !          1224:            }
        !          1225:        } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
        !          1226:            if (argc != 5) {
        !          1227:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1228:                        argv[0], " select to tagOrId index\"",
        !          1229:                        (char *) NULL);
        !          1230:                goto error;
        !          1231:            }
        !          1232:            CanvasSelectTo(canvasPtr, itemPtr, index);
        !          1233:        } else {
        !          1234:            Tcl_AppendResult(interp, "bad select option \"", argv[2],
        !          1235:                    "\": must be adjust, clear, from, item, or to",
        !          1236:                    (char *) NULL);
        !          1237:            goto error;
        !          1238:        }
        !          1239:     } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) {
        !          1240:        if (argc != 3) {
        !          1241:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1242:                    argv[0], " type tag\"", (char *) NULL);
        !          1243:            goto error;
        !          1244:        }
        !          1245:        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        !          1246:        if (itemPtr != NULL) {
        !          1247:            interp->result = itemPtr->typePtr->name;
        !          1248:        }
        !          1249:     } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
        !          1250:        int index;
        !          1251: 
        !          1252:        if (argc != 3) {
        !          1253:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1254:                    argv[0], " xview index\"", (char *) NULL);
        !          1255:            goto error;
        !          1256:        }
        !          1257:        if (Tcl_GetInt(canvasPtr->interp, argv[2], &index) != TCL_OK) {
        !          1258:            goto error;
        !          1259:        }
        !          1260:        CanvasSetOrigin(canvasPtr,
        !          1261:                (canvasPtr->scrollX1 + index*canvasPtr->scrollIncrement),
        !          1262:                canvasPtr->yOrigin);
        !          1263:     } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) {
        !          1264:        int index;
        !          1265: 
        !          1266:        if (argc != 3) {
        !          1267:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1268:                    argv[0], " yview index\"", (char *) NULL);
        !          1269:            goto error;
        !          1270:        }
        !          1271:        if (Tcl_GetInt(canvasPtr->interp, argv[2], &index) != TCL_OK) {
        !          1272:            goto error;
        !          1273:        }
        !          1274:        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin,
        !          1275:                (canvasPtr->scrollY1 + index*canvasPtr->scrollIncrement));
        !          1276:     } else {
        !          1277:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !          1278:                "\":  must be addtag, bbox, bind, ",
        !          1279:                "canvasx, canvasy, configure, coords, create, ",
        !          1280:                "cursor, dchars, delete, dtag, find, focus, ",
        !          1281:                "gettags, index, insert, itemconfigure, lower, ",
        !          1282:                "move, raise, scale, scan, select, type, xview, or yview",
        !          1283:                (char *) NULL);  
        !          1284:        goto error;
        !          1285:     }
        !          1286:     done:
        !          1287:     Tk_Release((ClientData) canvasPtr);
        !          1288:     return result;
        !          1289: 
        !          1290:     error:
        !          1291:     Tk_Release((ClientData) canvasPtr);
        !          1292:     return TCL_ERROR;
        !          1293: }
        !          1294: 
        !          1295: /*
        !          1296:  *----------------------------------------------------------------------
        !          1297:  *
        !          1298:  * DestroyCanvas --
        !          1299:  *
        !          1300:  *     This procedure is invoked by Tk_EventuallyFree or Tk_Release
        !          1301:  *     to clean up the internal structure of a canvas at a safe time
        !          1302:  *     (when no-one is using it anymore).
        !          1303:  *
        !          1304:  * Results:
        !          1305:  *     None.
        !          1306:  *
        !          1307:  * Side effects:
        !          1308:  *     Everything associated with the canvas is freed up.
        !          1309:  *
        !          1310:  *----------------------------------------------------------------------
        !          1311:  */
        !          1312: 
        !          1313: static void
        !          1314: DestroyCanvas(clientData)
        !          1315:     ClientData clientData;     /* Info about canvas widget. */
        !          1316: {
        !          1317:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          1318:     register Tk_Item *itemPtr;
        !          1319: 
        !          1320:     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          1321:            itemPtr = canvasPtr->firstItemPtr) {
        !          1322:        canvasPtr->firstItemPtr = itemPtr->nextPtr;
        !          1323:        (*itemPtr->typePtr->deleteProc)(itemPtr);
        !          1324:        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        !          1325:            ckfree((char *) itemPtr->tagPtr);
        !          1326:        }
        !          1327:        ckfree((char *) itemPtr);
        !          1328:     }
        !          1329: 
        !          1330:     if (canvasPtr->bgBorder != NULL) {
        !          1331:        Tk_Free3DBorder(canvasPtr->bgBorder);
        !          1332:     }
        !          1333:     if (canvasPtr->bgColor != NULL) {
        !          1334:        Tk_FreeColor(canvasPtr->bgColor);
        !          1335:     }
        !          1336:     if (canvasPtr->pixmapGC != None) {
        !          1337:        Tk_FreeGC(canvasPtr->pixmapGC);
        !          1338:     }
        !          1339:     if (canvasPtr->selBorder != NULL) {
        !          1340:        Tk_Free3DBorder(canvasPtr->selBorder);
        !          1341:     }
        !          1342:     if (canvasPtr->selFgColorPtr != NULL) {
        !          1343:        Tk_FreeColor(canvasPtr->selFgColorPtr);
        !          1344:     }
        !          1345:     if (canvasPtr->cursorBorder != NULL) {
        !          1346:        Tk_Free3DBorder(canvasPtr->cursorBorder);
        !          1347:     }
        !          1348:     Tk_DeleteTimerHandler(canvasPtr->cursorBlinkHandler);
        !          1349:     if (canvasPtr->bindingTable != NULL) {
        !          1350:        Tk_DeleteBindingTable(canvasPtr->bindingTable);
        !          1351:     }
        !          1352:     if (canvasPtr->xScrollCmd != NULL) {
        !          1353:        ckfree(canvasPtr->xScrollCmd);
        !          1354:     }
        !          1355:     if (canvasPtr->yScrollCmd != NULL) {
        !          1356:        ckfree(canvasPtr->yScrollCmd);
        !          1357:     }
        !          1358:     if (canvasPtr->regionString != NULL) {
        !          1359:        ckfree(canvasPtr->regionString);
        !          1360:     }
        !          1361:     if (canvasPtr->cursor != None) {
        !          1362:        Tk_FreeCursor(canvasPtr->cursor);
        !          1363:     }
        !          1364:     ckfree((char *) canvasPtr);
        !          1365: }
        !          1366: 
        !          1367: /*
        !          1368:  *----------------------------------------------------------------------
        !          1369:  *
        !          1370:  * ConfigureCanvas --
        !          1371:  *
        !          1372:  *     This procedure is called to process an argv/argc list, plus
        !          1373:  *     the Tk option database, in order to configure (or
        !          1374:  *     reconfigure) a canvas widget.
        !          1375:  *
        !          1376:  * Results:
        !          1377:  *     The return value is a standard Tcl result.  If TCL_ERROR is
        !          1378:  *     returned, then interp->result contains an error message.
        !          1379:  *
        !          1380:  * Side effects:
        !          1381:  *     Configuration information, such as colors, border width,
        !          1382:  *     etc. get set for canvasPtr;  old resources get freed,
        !          1383:  *     if there were any.
        !          1384:  *
        !          1385:  *----------------------------------------------------------------------
        !          1386:  */
        !          1387: 
        !          1388: static int
        !          1389: ConfigureCanvas(interp, canvasPtr, argc, argv, flags)
        !          1390:     Tcl_Interp *interp;                /* Used for error reporting. */
        !          1391:     register Tk_Canvas *canvasPtr;     /* Information about widget;  may or may
        !          1392:                                 * not already have values for some fields. */
        !          1393:     int argc;                  /* Number of valid entries in argv. */
        !          1394:     char **argv;               /* Arguments. */
        !          1395:     int flags;                 /* Flags to pass to Tk_ConfigureWidget. */
        !          1396: {
        !          1397:     XGCValues gcValues;
        !          1398:     GC new;
        !          1399: 
        !          1400:     if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
        !          1401:            argc, argv, (char *) canvasPtr, flags) != TCL_OK) {
        !          1402:        return TCL_ERROR;
        !          1403:     }
        !          1404: 
        !          1405:     /*
        !          1406:      * A few options need special processing, such as setting the
        !          1407:      * background from a 3-D border and creating a GC for copying
        !          1408:      * bits to the screen.
        !          1409:      */
        !          1410: 
        !          1411:     Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
        !          1412: 
        !          1413:     gcValues.function = GXcopy;
        !          1414:     gcValues.foreground = canvasPtr->bgColor->pixel;
        !          1415:     gcValues.graphics_exposures = False;
        !          1416:     new = Tk_GetGC(canvasPtr->tkwin,
        !          1417:            GCFunction|GCForeground|GCGraphicsExposures, &gcValues);
        !          1418:     if (canvasPtr->pixmapGC != None) {
        !          1419:        Tk_FreeGC(canvasPtr->pixmapGC);
        !          1420:     }
        !          1421:     canvasPtr->pixmapGC = new;
        !          1422: 
        !          1423:     /*
        !          1424:      * Reset the desired dimensions for the window.
        !          1425:      */
        !          1426: 
        !          1427:     Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width, canvasPtr->height);
        !          1428: 
        !          1429:     /*
        !          1430:      * Restart the cursor timing sequence in case the on-time or off-time
        !          1431:      * just changed.
        !          1432:      */
        !          1433: 
        !          1434:     if (canvasPtr->flags & GOT_FOCUS) {
        !          1435:        CanvasFocusProc((ClientData) canvasPtr, 1);
        !          1436:     }
        !          1437: 
        !          1438:     /*
        !          1439:      * Recompute the scroll region.
        !          1440:      */
        !          1441: 
        !          1442:     canvasPtr->scrollX1 = 0;
        !          1443:     canvasPtr->scrollY1 = 0;
        !          1444:     canvasPtr->scrollX2 = 0;
        !          1445:     canvasPtr->scrollY2 = 0;
        !          1446:     if (canvasPtr->regionString != NULL) {
        !          1447:        int argc2;
        !          1448:        char **argv2;
        !          1449: 
        !          1450:        if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
        !          1451:                &argc2, &argv2) != TCL_OK) {
        !          1452:            return TCL_ERROR;
        !          1453:        }
        !          1454:        if (argc2 != 4) {
        !          1455:            badRegion:
        !          1456:            Tcl_AppendResult(interp, "bad scrollRegion \"",
        !          1457:                    canvasPtr->regionString, "\"", (char *) NULL);
        !          1458:            ckfree(canvasPtr->regionString);
        !          1459:            ckfree((char *) argv2);
        !          1460:            canvasPtr->regionString = NULL;
        !          1461:            return TCL_ERROR;
        !          1462:        }
        !          1463:        if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
        !          1464:                    argv2[0], &canvasPtr->scrollX1) != TCL_OK)
        !          1465:                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
        !          1466:                    argv2[1], &canvasPtr->scrollY1) != TCL_OK)
        !          1467:                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
        !          1468:                    argv2[2], &canvasPtr->scrollX2) != TCL_OK)
        !          1469:                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
        !          1470:                    argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
        !          1471:            goto badRegion;
        !          1472:        }
        !          1473:        ckfree((char *) argv2);
        !          1474:     }
        !          1475: 
        !          1476:     /*
        !          1477:      * Reset the canvases origin (this is a no-op unless confine
        !          1478:      * mode has just been turned on or the scroll region has changed).
        !          1479:      */
        !          1480: 
        !          1481:     CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
        !          1482:     canvasPtr->flags |= UPDATE_SCROLLBARS;
        !          1483:     EventuallyRedrawArea(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin,
        !          1484:            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
        !          1485:            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
        !          1486:     return TCL_OK;
        !          1487: }
        !          1488: 
        !          1489: #if defined(USE_XPM3)
        !          1490: //#include "xpmtk.h"
        !          1491: #include <xpm.h>
        !          1492: /*
        !          1493:  *--------------------------------------------------------------
        !          1494:  *
        !          1495:  * SaveCanvas --
        !          1496:  *
        !          1497:  *     This procedure saves the contents of a canvas window.
        !          1498:  *
        !          1499:  * Results:
        !          1500:  *     The return value is a standard Tcl result.  If TCL_ERROR is
        !          1501:  *     returned, then interp->result contains an error message.
        !          1502:  *
        !          1503:  * Side effects:
        !          1504:  *     A pixmap is written to a file.
        !          1505:  *
        !          1506:  *--------------------------------------------------------------
        !          1507:  */
        !          1508: 
        !          1509: static int
        !          1510: SaveCanvas(interp, canvasPtr, fileName, x, y, width, height)
        !          1511:     Tcl_Interp *interp;                /* Used for error reporting. */
        !          1512:     register Tk_Canvas *canvasPtr;     /* Information about widget */
        !          1513:     char *fileName;             /* the output file name. */
        !          1514:     int x;                      /* upper left x coordinate. */
        !          1515:     int y;                      /* upper left y coordinate. */
        !          1516:     unsigned int width;         /* width of pixmap area to save. */
        !          1517:     unsigned int height;        /* height of pixmap area to save. */
        !          1518: {
        !          1519:     register Tk_Window tkwin = canvasPtr->tkwin;
        !          1520:     register Tk_Item *itemPtr;
        !          1521:     Pixmap pixmap;
        !          1522:     Pixmap savePixmap;
        !          1523:     int screenX1, screenX2, screenY1, screenY2;
        !          1524:     XpmAttributes xpm_attributes;
        !          1525: 
        !          1526:     if (canvasPtr->tkwin == NULL) {
        !          1527:        return TCL_OK;
        !          1528:     }
        !          1529:     if (!Tk_IsMapped(tkwin)) {
        !          1530:        return TCL_OK;
        !          1531:     }
        !          1532:     if (!(fileName && *fileName)) {
        !          1533:        Tcl_ResetResult(interp);
        !          1534:        Tcl_AppendResult(interp, "no filename specified for canvas saving",
        !          1535:                (char *) NULL);
        !          1536:        return TCL_ERROR;
        !          1537:     }
        !          1538: 
        !          1539:     /*
        !          1540:      * Choose a new current item if that is needed (this could cause
        !          1541:      * event handlers to be invoked).
        !          1542:      */
        !          1543: 
        !          1544:     while (canvasPtr->flags & REPICK_NEEDED) {
        !          1545:        Tk_Preserve((ClientData) canvasPtr);
        !          1546:        canvasPtr->flags &= ~REPICK_NEEDED;
        !          1547:        PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
        !          1548:        tkwin = canvasPtr->tkwin;
        !          1549:        Tk_Release((ClientData) canvasPtr);
        !          1550:        if (tkwin == NULL) {
        !          1551:            return TCL_OK;
        !          1552:        }
        !          1553:     }
        !          1554: 
        !          1555:     if(x == 0 && y == 0 && width == 0 && height == 0) {
        !          1556:       screenX1 = 0;
        !          1557:       screenY1 = 0;
        !          1558:       screenX2 = Tk_Width(tkwin);
        !          1559:       screenY2 = Tk_Height(tkwin);
        !          1560:       width = Tk_Width(tkwin);
        !          1561:       height = Tk_Height(tkwin);
        !          1562:     } else {
        !          1563:       if(width != 0 && height != 0) {
        !          1564:         screenX1 = x;
        !          1565:         screenY1 = y;
        !          1566:         screenX2 = x + width;
        !          1567:         screenY2 = y + height;
        !          1568:       } else {
        !          1569:        Tcl_ResetResult(interp);
        !          1570:        Tcl_AppendResult(interp, "no correct size specified for canvas saving",
        !          1571:                (char *) NULL);
        !          1572:         return TCL_ERROR;
        !          1573:       }
        !          1574:     }
        !          1575: 
        !          1576:     /*
        !          1577:      * Saving is done in a temporary pixmap that is allocated
        !          1578:      * here and freed at the end of the procedure.  All drawing
        !          1579:      * is done to the pixmap, and the pixmap is saved to the
        !          1580:      * file at the end of the procedure.
        !          1581:      *
        !          1582:      * Some tricky points about the pixmap:
        !          1583:      *
        !          1584:      * 1. We only allocate a large enough pixmap to hold the
        !          1585:      *    area that has to be saved.  This saves time in
        !          1586:      *    in the X server for large objects that cover much
        !          1587:      *    more than the area being saved:  only the area
        !          1588:      *    of the pixmap will actually have to be saved.
        !          1589:      * 2. The origin of the pixmap is adjusted to an even multiple
        !          1590:      *    of 32 bits.  This is so that stipple patterns with a size
        !          1591:      *    of 8 or 16 or 32 bits will always line up when information
        !          1592:      *    is copied back to the screen.
        !          1593:      * 3. Some X servers (e.g. the one for DECstations) have troubles
        !          1594:      *    with characters that overlap an edge of the pixmap (on the
        !          1595:      *    DEC servers, as of 8/18/92, such characters are drawn one
        !          1596:      *    pixel too far to the right).  To handle this problem,
        !          1597:      *    make the pixmap a bit larger than is absolutely needed
        !          1598:      *    so that for normal-sized fonts the characters that ovelap
        !          1599:      *    the edge of the pixmap will be outside the area we care
        !          1600:      *    about.
        !          1601:      */
        !          1602: 
        !          1603:     canvasPtr->drawableXOrigin = (screenX1 - 30) & ~0x1f;
        !          1604:     canvasPtr->drawableYOrigin = (screenY1 - 30) & ~0x1f;
        !          1605:     pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
        !          1606:        screenX2 + 30 - canvasPtr->drawableXOrigin,
        !          1607:        screenY2 + 30 - canvasPtr->drawableYOrigin,
        !          1608:        Tk_DefaultDepth(Tk_Screen(tkwin)));
        !          1609:     savePixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
        !          1610:        width, height, Tk_DefaultDepth(Tk_Screen(tkwin)));
        !          1611: 
        !          1612:     /*
        !          1613:      * Clear the area to be redrawn.
        !          1614:      */
        !          1615: 
        !          1616:     XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
        !          1617:            screenX1 - canvasPtr->drawableXOrigin,
        !          1618:            screenY1 - canvasPtr->drawableYOrigin,
        !          1619:            (unsigned int) (screenX2 - screenX1),
        !          1620:            (unsigned int) (screenY2 - screenY1));
        !          1621:     XFillRectangle(Tk_Display(tkwin), savePixmap, canvasPtr->pixmapGC,
        !          1622:            0, 0, width, height);
        !          1623: 
        !          1624:     /*
        !          1625:      * Scan through the item list, redrawing those items that need it.
        !          1626:      * An item must be redraw if either (a) it intersects the smaller
        !          1627:      * on-screen area or (b) it intersects the full canvas area and its
        !          1628:      * type requests that it be redrawn always (e.g. so subwindows can
        !          1629:      * be unmapped when they move off-screen).
        !          1630:      */
        !          1631: 
        !          1632:     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          1633:            itemPtr = itemPtr->nextPtr) {
        !          1634:        if ((itemPtr->x1 >= screenX2)
        !          1635:                || (itemPtr->y1 >= screenY2)
        !          1636:                || (itemPtr->x2 < screenX1)
        !          1637:                || (itemPtr->y2 < screenY1)) {
        !          1638:            if (!itemPtr->typePtr->alwaysRedraw
        !          1639:                    || (itemPtr->x1 >= canvasPtr->redrawX2)
        !          1640:                    || (itemPtr->y1 >= canvasPtr->redrawY2)
        !          1641:                    || (itemPtr->x2 < canvasPtr->redrawX1)
        !          1642:                    || (itemPtr->y2 < canvasPtr->redrawY1)) {
        !          1643:                continue;
        !          1644:            }
        !          1645:        }
        !          1646:        (*itemPtr->typePtr->displayProc)(canvasPtr, itemPtr, pixmap);
        !          1647:     }
        !          1648: 
        !          1649:     /*
        !          1650:      * Copy from the temporary pixmap to the save pixmap.
        !          1651:      */
        !          1652: 
        !          1653:     XCopyArea(Tk_Display(tkwin), pixmap, savePixmap,
        !          1654:            canvasPtr->pixmapGC,
        !          1655:            screenX1 - canvasPtr->drawableXOrigin,
        !          1656:            screenY1 - canvasPtr->drawableYOrigin,
        !          1657:            screenX2 - screenX1, screenY2 - screenY1, 0, 0);
        !          1658: 
        !          1659:     /*
        !          1660:      * Save temporary pixmap.
        !          1661:      */
        !          1662: 
        !          1663:     xpm_attributes.width = width;
        !          1664:     xpm_attributes.height = height;
        !          1665:     xpm_attributes.visual = Tk_DefaultVisual(Tk_Screen(tkwin));
        !          1666:     xpm_attributes.colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
        !          1667:     xpm_attributes.valuemask = XpmSize | XpmVisual | XpmColormap;
        !          1668:     if(XpmWriteFileFromPixmap(Tk_Display(tkwin), fileName,
        !          1669:                              savePixmap, (Pixmap) NULL,
        !          1670:                              &xpm_attributes) != XpmSuccess) {
        !          1671:       XFreePixmap(Tk_Display(tkwin), pixmap);
        !          1672:       XFreePixmap(Tk_Display(tkwin), savePixmap);
        !          1673:       Tcl_ResetResult(interp);
        !          1674:       Tcl_AppendResult(interp, "could not save pixmap for canvas",
        !          1675:            (char *) NULL);
        !          1676:       return TCL_ERROR;
        !          1677:     }
        !          1678:     XFreePixmap(Tk_Display(tkwin), pixmap);
        !          1679:     XFreePixmap(Tk_Display(tkwin), savePixmap);
        !          1680: 
        !          1681:     return TCL_OK;
        !          1682: }
        !          1683: #endif
        !          1684: 
        !          1685: /*
        !          1686:  *--------------------------------------------------------------
        !          1687:  *
        !          1688:  * DisplayCanvas --
        !          1689:  *
        !          1690:  *     This procedure redraws the contents of a canvas window.
        !          1691:  *     It is invoked as a do-when-idle handler, so it only runs
        !          1692:  *     when there's nothing else for the application to do.
        !          1693:  *
        !          1694:  * Results:
        !          1695:  *     None.
        !          1696:  *
        !          1697:  * Side effects:
        !          1698:  *     Information appears on the screen.
        !          1699:  *
        !          1700:  *--------------------------------------------------------------
        !          1701:  */
        !          1702: 
        !          1703: static void
        !          1704: DisplayCanvas(clientData)
        !          1705:     ClientData clientData;     /* Information about widget. */
        !          1706: {
        !          1707:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          1708:     register Tk_Window tkwin = canvasPtr->tkwin;
        !          1709:     register Tk_Item *itemPtr;
        !          1710:     Pixmap pixmap;
        !          1711:     int screenX1, screenX2, screenY1, screenY2;
        !          1712: 
        !          1713:     if (canvasPtr->tkwin == NULL) {
        !          1714:        return;
        !          1715:     }
        !          1716:     if (!Tk_IsMapped(tkwin)) {
        !          1717:        goto done;
        !          1718:     }
        !          1719: 
        !          1720:     /*
        !          1721:      * Choose a new current item if that is needed (this could cause
        !          1722:      * event handlers to be invoked).
        !          1723:      */
        !          1724: 
        !          1725:     while (canvasPtr->flags & REPICK_NEEDED) {
        !          1726:        Tk_Preserve((ClientData) canvasPtr);
        !          1727:        canvasPtr->flags &= ~REPICK_NEEDED;
        !          1728:        PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
        !          1729:        tkwin = canvasPtr->tkwin;
        !          1730:        Tk_Release((ClientData) canvasPtr);
        !          1731:        if (tkwin == NULL) {
        !          1732:            return;
        !          1733:        }
        !          1734:     }
        !          1735: 
        !          1736:     /*
        !          1737:      * Compute the intersection between the area that needs redrawing
        !          1738:      * and the area that's visible on the screen.
        !          1739:      */
        !          1740: 
        !          1741:     screenX1 = canvasPtr->xOrigin;
        !          1742:     screenY1 = canvasPtr->yOrigin;
        !          1743:     screenX2 = screenX1 + Tk_Width(tkwin);
        !          1744:     screenY2 = screenY1 + Tk_Height(tkwin);
        !          1745:     if (canvasPtr->redrawX1 > screenX1) {
        !          1746:        screenX1 = canvasPtr->redrawX1;
        !          1747:     }
        !          1748:     if (canvasPtr->redrawY1 > screenY1) {
        !          1749:        screenY1 = canvasPtr->redrawY1;
        !          1750:     }
        !          1751:     if (canvasPtr->redrawX2 < screenX2) {
        !          1752:        screenX2 = canvasPtr->redrawX2;
        !          1753:     }
        !          1754:     if (canvasPtr->redrawY2 < screenY2) {
        !          1755:        screenY2 = canvasPtr->redrawY2;
        !          1756:     }
        !          1757:     if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
        !          1758:        goto done;
        !          1759:     }
        !          1760: 
        !          1761:     /*
        !          1762:      * Redrawing is done in a temporary pixmap that is allocated
        !          1763:      * here and freed at the end of the procedure.  All drawing
        !          1764:      * is done to the pixmap, and the pixmap is copied to the
        !          1765:      * screen at the end of the procedure. The temporary pixmap
        !          1766:      * serves two purposes:
        !          1767:      *
        !          1768:      * 1. It provides a smoother visual effect (no clearing and
        !          1769:      *    gradual redraw will be visible to users).
        !          1770:      * 2. It allows us to redraw only the objects that overlap
        !          1771:      *    the redraw area.  Otherwise incorrect results could
        !          1772:      *   occur from redrawing things that stick outside of
        !          1773:      *   the redraw area (we'd have to redraw everything in
        !          1774:      *    order to make the overlaps look right).
        !          1775:      *
        !          1776:      * Some tricky points about the pixmap:
        !          1777:      *
        !          1778:      * 1. We only allocate a large enough pixmap to hold the
        !          1779:      *    area that has to be redisplayed.  This saves time in
        !          1780:      *    in the X server for large objects that cover much
        !          1781:      *    more than the area being redisplayed:  only the area
        !          1782:      *    of the pixmap will actually have to be redrawn.
        !          1783:      * 2. The origin of the pixmap is adjusted to an even multiple
        !          1784:      *    of 32 bits.  This is so that stipple patterns with a size
        !          1785:      *    of 8 or 16 or 32 bits will always line up when information
        !          1786:      *    is copied back to the screen.
        !          1787:      * 3. Some X servers (e.g. the one for DECstations) have troubles
        !          1788:      *    with characters that overlap an edge of the pixmap (on the
        !          1789:      *    DEC servers, as of 8/18/92, such characters are drawn one
        !          1790:      *    pixel too far to the right).  To handle this problem,
        !          1791:      *    make the pixmap a bit larger than is absolutely needed
        !          1792:      *    so that for normal-sized fonts the characters that ovelap
        !          1793:      *    the edge of the pixmap will be outside the area we care
        !          1794:      *    about.
        !          1795:      */
        !          1796: 
        !          1797:     canvasPtr->drawableXOrigin = (screenX1 - 30) & ~0x1f;
        !          1798:     canvasPtr->drawableYOrigin = (screenY1 - 30) & ~0x1f;
        !          1799:     pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
        !          1800:        screenX2 + 30 - canvasPtr->drawableXOrigin,
        !          1801:        screenY2 + 30 - canvasPtr->drawableYOrigin,
        !          1802:        Tk_DefaultDepth(Tk_Screen(tkwin)));
        !          1803: 
        !          1804:     /*
        !          1805:      * Clear the area to be redrawn.
        !          1806:      */
        !          1807: 
        !          1808:     XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
        !          1809:            screenX1 - canvasPtr->drawableXOrigin,
        !          1810:            screenY1 - canvasPtr->drawableYOrigin,
        !          1811:            (unsigned int) (screenX2 - screenX1),
        !          1812:            (unsigned int) (screenY2 - screenY1));
        !          1813: 
        !          1814:     /*
        !          1815:      * Scan through the item list, redrawing those items that need it.
        !          1816:      * An item must be redraw if either (a) it intersects the smaller
        !          1817:      * on-screen area or (b) it intersects the full canvas area and its
        !          1818:      * type requests that it be redrawn always (e.g. so subwindows can
        !          1819:      * be unmapped when they move off-screen).
        !          1820:      */
        !          1821: 
        !          1822:     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          1823:            itemPtr = itemPtr->nextPtr) {
        !          1824:        if ((itemPtr->x1 >= screenX2)
        !          1825:                || (itemPtr->y1 >= screenY2)
        !          1826:                || (itemPtr->x2 < screenX1)
        !          1827:                || (itemPtr->y2 < screenY1)) {
        !          1828:            if (!itemPtr->typePtr->alwaysRedraw
        !          1829:                    || (itemPtr->x1 >= canvasPtr->redrawX2)
        !          1830:                    || (itemPtr->y1 >= canvasPtr->redrawY2)
        !          1831:                    || (itemPtr->x2 < canvasPtr->redrawX1)
        !          1832:                    || (itemPtr->y2 < canvasPtr->redrawY1)) {
        !          1833:                continue;
        !          1834:            }
        !          1835:        }
        !          1836:        (*itemPtr->typePtr->displayProc)(canvasPtr, itemPtr, pixmap);
        !          1837:     }
        !          1838: 
        !          1839:     /*
        !          1840:      * Draw the window border.
        !          1841:      */
        !          1842: 
        !          1843:     if (canvasPtr->relief != TK_RELIEF_FLAT) {
        !          1844:        Tk_Draw3DRectangle(Tk_Display(tkwin), pixmap,
        !          1845:                canvasPtr->bgBorder,
        !          1846:                canvasPtr->xOrigin - canvasPtr->drawableXOrigin,
        !          1847:                canvasPtr->yOrigin - canvasPtr->drawableYOrigin,
        !          1848:                Tk_Width(tkwin), Tk_Height(tkwin),
        !          1849:                canvasPtr->borderWidth, canvasPtr->relief);
        !          1850:     }
        !          1851: 
        !          1852:     /*
        !          1853:      * Copy from the temporary pixmap to the screen, then free up
        !          1854:      * the temporary pixmap.
        !          1855:      */
        !          1856: 
        !          1857:     XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
        !          1858:            canvasPtr->pixmapGC,
        !          1859:            screenX1 - canvasPtr->drawableXOrigin,
        !          1860:            screenY1 - canvasPtr->drawableYOrigin,
        !          1861:            screenX2 - screenX1, screenY2 - screenY1,
        !          1862:            screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
        !          1863:     XFreePixmap(Tk_Display(tkwin), pixmap);
        !          1864: 
        !          1865:     done:
        !          1866:     canvasPtr->flags &= ~REDRAW_PENDING;
        !          1867:     assert(canvasPtr->updateTimerToken != NULL);
        !          1868:     canvasPtr->updateTimerToken = NULL;
        !          1869:     if (canvasPtr->flags & UPDATE_SCROLLBARS) {
        !          1870:        CanvasUpdateScrollbars(canvasPtr);
        !          1871:     }
        !          1872: }
        !          1873: 
        !          1874: /*
        !          1875:  *--------------------------------------------------------------
        !          1876:  *
        !          1877:  * CanvasEventProc --
        !          1878:  *
        !          1879:  *     This procedure is invoked by the Tk dispatcher for various
        !          1880:  *     events on canvases.
        !          1881:  *
        !          1882:  * Results:
        !          1883:  *     None.
        !          1884:  *
        !          1885:  * Side effects:
        !          1886:  *     When the window gets deleted, internal structures get
        !          1887:  *     cleaned up.  When it gets exposed, it is redisplayed.
        !          1888:  *
        !          1889:  *--------------------------------------------------------------
        !          1890:  */
        !          1891: 
        !          1892: static void
        !          1893: CanvasEventProc(clientData, eventPtr)
        !          1894:     ClientData clientData;     /* Information about window. */
        !          1895:     XEvent *eventPtr;          /* Information about event. */
        !          1896: {
        !          1897:     Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          1898: 
        !          1899:     if (eventPtr->type == Expose) {
        !          1900:        int x, y;
        !          1901: 
        !          1902:        x = eventPtr->xexpose.x + canvasPtr->xOrigin;
        !          1903:        y = eventPtr->xexpose.y + canvasPtr->yOrigin;
        !          1904:        EventuallyRedrawArea(canvasPtr, x, y, x + eventPtr->xexpose.width,
        !          1905:                y + eventPtr->xexpose.height);
        !          1906:     } else if (eventPtr->type == DestroyNotify) {
        !          1907:        Tcl_DeleteCommand(canvasPtr->interp, Tk_PathName(canvasPtr->tkwin));
        !          1908:        canvasPtr->tkwin = NULL;
        !          1909:        if (canvasPtr->flags & REDRAW_PENDING) {
        !          1910:            canvasPtr->flags &= ~REDRAW_PENDING;
        !          1911: //         Tk_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
        !          1912:            assert(canvasPtr->updateTimerToken != NULL);
        !          1913:            if (canvasPtr->updateTimerToken != NULL) {
        !          1914:                Tk_DeleteTimerHandler(canvasPtr->updateTimerToken);
        !          1915:                canvasPtr->updateTimerToken = 0;
        !          1916:            }
        !          1917:        }
        !          1918:        Tk_EventuallyFree((ClientData) canvasPtr, DestroyCanvas);
        !          1919:     } else if (eventPtr->type == ConfigureNotify) {
        !          1920:        canvasPtr->flags |= UPDATE_SCROLLBARS;
        !          1921: 
        !          1922:        /*
        !          1923:         * The call below is needed in order to recenter the canvas if
        !          1924:         * it's confined and its scroll region is smaller than the window.
        !          1925:         */
        !          1926: 
        !          1927:        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
        !          1928:        EventuallyRedrawArea(canvasPtr, 0, 0, Tk_Width(canvasPtr->tkwin),
        !          1929:                Tk_Height(canvasPtr->tkwin));
        !          1930:     }
        !          1931: }
        !          1932: 
        !          1933: /*
        !          1934:  *--------------------------------------------------------------
        !          1935:  *
        !          1936:  * EventuallyRedrawArea --
        !          1937:  *
        !          1938:  *     Arrange for part or all of a canvas widget to redrawn at
        !          1939:  *     the next convenient time in the future.
        !          1940:  *
        !          1941:  * Results:
        !          1942:  *     None.
        !          1943:  *
        !          1944:  * Side effects:
        !          1945:  *     The screen will eventually be refreshed.
        !          1946:  *
        !          1947:  *--------------------------------------------------------------
        !          1948:  */
        !          1949: 
        !          1950: static void
        !          1951: EventuallyRedrawArea(canvasPtr, x1, y1, x2, y2)
        !          1952:     register Tk_Canvas *canvasPtr;     /* Information about widget. */
        !          1953:     int x1, y1;                                /* Upper left corner of area to
        !          1954:                                         * redraw.  Pixels on edge are
        !          1955:                                         * redrawn. */
        !          1956:     int x2, y2;                                /* Lower right corner of area to
        !          1957:                                         * redraw.  Pixels on edge are
        !          1958:                                         * not redrawn. */
        !          1959: {
        !          1960:     if ((canvasPtr->tkwin == NULL) || !Tk_IsMapped(canvasPtr->tkwin)) {
        !          1961:        return;
        !          1962:     }
        !          1963:     if (canvasPtr->flags & REDRAW_PENDING) {
        !          1964:        if (x1 <= canvasPtr->redrawX1) {
        !          1965:            canvasPtr->redrawX1 = x1;
        !          1966:        }
        !          1967:        if (y1 <= canvasPtr->redrawY1) {
        !          1968:            canvasPtr->redrawY1 = y1;
        !          1969:        }
        !          1970:        if (x2 >= canvasPtr->redrawX2) {
        !          1971:            canvasPtr->redrawX2 = x2;
        !          1972:        }
        !          1973:        if (y2 >= canvasPtr->redrawY2) {
        !          1974:            canvasPtr->redrawY2 = y2;
        !          1975:        }
        !          1976:     } else {
        !          1977:        canvasPtr->redrawX1 = x1;
        !          1978:        canvasPtr->redrawY1 = y1;
        !          1979:        canvasPtr->redrawX2 = x2;
        !          1980:        canvasPtr->redrawY2 = y2;
        !          1981: //     Tk_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
        !          1982:        canvasPtr->flags |= REDRAW_PENDING;
        !          1983:        assert(canvasPtr->updateTimerToken == NULL);
        !          1984:        if (canvasPtr->updateTimerToken == 0) {
        !          1985:          canvasPtr->updateTimerToken = 
        !          1986:            Tk_CreateTimerHandler(
        !          1987:              CanvasUpdateTime,
        !          1988:              DisplayCanvas,
        !          1989:              (ClientData) canvasPtr);
        !          1990:        }
        !          1991:     }
        !          1992: }
        !          1993: 
        !          1994: /*
        !          1995:  *--------------------------------------------------------------
        !          1996:  *
        !          1997:  * Tk_CreateItemType --
        !          1998:  *
        !          1999:  *     This procedure may be invoked to add a new kind of canvas
        !          2000:  *     element to the core item types supported by Tk.
        !          2001:  *
        !          2002:  * Results:
        !          2003:  *     None.
        !          2004:  *
        !          2005:  * Side effects:
        !          2006:  *     From now on, the new item type will be useable in canvas
        !          2007:  *     widgets (e.g. typePtr->name can be used as the item type
        !          2008:  *     in "create" widget commands).  If there was already a
        !          2009:  *     type with the same name as in typePtr, it is replaced with
        !          2010:  *     the new type.
        !          2011:  *
        !          2012:  *--------------------------------------------------------------
        !          2013:  */
        !          2014: 
        !          2015: void
        !          2016: Tk_CreateItemType(typePtr)
        !          2017:     Tk_ItemType *typePtr;              /* Information about item type;
        !          2018:                                         * storage must be statically
        !          2019:                                         * allocated (must live forever). */
        !          2020: {
        !          2021:     if (typeList == NULL) {
        !          2022:        InitCanvas();
        !          2023:     }
        !          2024:     typePtr->nextPtr = typeList;
        !          2025:     typeList = typePtr;
        !          2026: }
        !          2027: 
        !          2028: /*
        !          2029:  *--------------------------------------------------------------
        !          2030:  *
        !          2031:  * InitCanvas --
        !          2032:  *
        !          2033:  *     This procedure is invoked to perform once-only-ever
        !          2034:  *     initialization for the module, such as setting up
        !          2035:  *     the type table.
        !          2036:  *
        !          2037:  * Results:
        !          2038:  *     None.
        !          2039:  *
        !          2040:  * Side effects:
        !          2041:  *     None.
        !          2042:  *
        !          2043:  *--------------------------------------------------------------
        !          2044:  */
        !          2045: 
        !          2046: static void
        !          2047: InitCanvas()
        !          2048: {
        !          2049:     if (typeList != NULL) {
        !          2050:        return;
        !          2051:     }
        !          2052:     typeList = &TkRectangleType;
        !          2053:     TkRectangleType.nextPtr = &TkTextType;
        !          2054:     TkTextType.nextPtr = &TkPolygonType;
        !          2055:     TkPolygonType.nextPtr = &TkOvalType;
        !          2056:     TkOvalType.nextPtr = &TkLineType;
        !          2057:     TkLineType.nextPtr = &TkWindowType;
        !          2058:     TkWindowType.nextPtr = &TkBitmapType;
        !          2059:     TkBitmapType.nextPtr = &TkArcType;
        !          2060:     TkArcType.nextPtr = NULL;
        !          2061:     allUid = Tk_GetUid("all");
        !          2062:     currentUid = Tk_GetUid("current");
        !          2063: }
        !          2064: 
        !          2065: /*
        !          2066:  *--------------------------------------------------------------
        !          2067:  *
        !          2068:  * StartTagSearch --
        !          2069:  *
        !          2070:  *     This procedure is called to initiate an enumeration of
        !          2071:  *     all items in a given canvas that contain a given tag.
        !          2072:  *
        !          2073:  * Results:
        !          2074:  *     The return value is a pointer to the first item in
        !          2075:  *     canvasPtr that matches tag, or NULL if there is no
        !          2076:  *     such item.  The information at *searchPtr is initialized
        !          2077:  *     such that successive calls to NextItem will return
        !          2078:  *     successive items that match tag.
        !          2079:  *
        !          2080:  * Side effects:
        !          2081:  *     SearchPtr is linked into a list of searches in progress
        !          2082:  *     on canvasPtr, so that elements can safely be deleted
        !          2083:  *     while the search is in progress.  EndTagSearch must be
        !          2084:  *     called at the end of the search to unlink searchPtr from
        !          2085:  *     this list.
        !          2086:  *
        !          2087:  *--------------------------------------------------------------
        !          2088:  */
        !          2089: 
        !          2090: static Tk_Item *
        !          2091: StartTagSearch(canvasPtr, tag, searchPtr)
        !          2092:     Tk_Canvas *canvasPtr;              /* Canvas whose items are to be
        !          2093:                                         * searched. */
        !          2094:     char *tag;                         /* String giving tag value. */
        !          2095:     TagSearch *searchPtr;              /* Record describing tag search;
        !          2096:                                         * will be initialized here. */
        !          2097: {
        !          2098:     int id;
        !          2099:     register Tk_Item *itemPtr, *prevPtr;
        !          2100:     register Tk_Uid *tagPtr;
        !          2101:     register Tk_Uid uid;
        !          2102:     register int count;
        !          2103: 
        !          2104:     /*
        !          2105:      * Initialize the search.
        !          2106:      */
        !          2107: 
        !          2108:     searchPtr->canvasPtr = canvasPtr;
        !          2109:     searchPtr->searchOver = 0;
        !          2110: 
        !          2111:     /*
        !          2112:      * Find the first matching item in one of several ways. If the tag
        !          2113:      * is a number then it selects the single item with the matching
        !          2114:      * identifier.  In this case see if the item being requested is the
        !          2115:      * hot item, in which case the search can be skipped.
        !          2116:      */
        !          2117: 
        !          2118:     if (isdigit(*tag)) {
        !          2119:        char *end;
        !          2120: 
        !          2121:        numIdSearches++;
        !          2122:        id = strtoul(tag, &end, 0);
        !          2123:        if (*end == 0) {
        !          2124:            itemPtr = canvasPtr->hotPtr;
        !          2125:            prevPtr = canvasPtr->hotPrevPtr;
        !          2126:            if ((itemPtr == NULL) || (itemPtr->id != id) || (prevPtr == NULL)
        !          2127:                    || (prevPtr->nextPtr != itemPtr)) {
        !          2128:                numSlowSearches++;
        !          2129:                for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr;
        !          2130:                        itemPtr != NULL;
        !          2131:                        prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
        !          2132:                    if (itemPtr->id == id) {
        !          2133:                        break;
        !          2134:                    }
        !          2135:                }
        !          2136:            }
        !          2137:            searchPtr->prevPtr = prevPtr;
        !          2138:            searchPtr->searchOver = 1;
        !          2139:            canvasPtr->hotPtr = itemPtr;
        !          2140:            canvasPtr->hotPrevPtr = prevPtr;
        !          2141:            return itemPtr;
        !          2142:        }
        !          2143:     }
        !          2144: 
        !          2145:     searchPtr->tag = uid = Tk_GetUid(tag);
        !          2146:     if (uid == allUid) {
        !          2147: 
        !          2148:        /*
        !          2149:         * All items match.
        !          2150:         */
        !          2151: 
        !          2152:        searchPtr->tag = NULL;
        !          2153:        searchPtr->prevPtr = NULL;
        !          2154:        searchPtr->currentPtr = canvasPtr->firstItemPtr;
        !          2155:        return canvasPtr->firstItemPtr;
        !          2156:     }
        !          2157: 
        !          2158:     /*
        !          2159:      * None of the above.  Search for an item with a matching tag.
        !          2160:      */
        !          2161: 
        !          2162:     for (prevPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          2163:            prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
        !          2164:        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
        !          2165:                count > 0; tagPtr++, count--) {
        !          2166:            if (*tagPtr == uid) {
        !          2167:                searchPtr->prevPtr = prevPtr;
        !          2168:                searchPtr->currentPtr = itemPtr;
        !          2169:                return itemPtr;
        !          2170:            }
        !          2171:        }
        !          2172:     }
        !          2173:     searchPtr->prevPtr = prevPtr;
        !          2174:     searchPtr->searchOver = 1;
        !          2175:     return NULL;
        !          2176: }
        !          2177: 
        !          2178: /*
        !          2179:  *--------------------------------------------------------------
        !          2180:  *
        !          2181:  * NextItem --
        !          2182:  *
        !          2183:  *     This procedure returns successive items that match a given
        !          2184:  *     tag;  it should be called only after StartTagSearch has been
        !          2185:  *     used to begin a search.
        !          2186:  *
        !          2187:  * Results:
        !          2188:  *     The return value is a pointer to the next item that matches
        !          2189:  *     the tag specified to StartTagSearch, or NULL if no such
        !          2190:  *     item exists.  *SearchPtr is updated so that the next call
        !          2191:  *     to this procedure will return the next item.
        !          2192:  *
        !          2193:  * Side effects:
        !          2194:  *     None.
        !          2195:  *
        !          2196:  *--------------------------------------------------------------
        !          2197:  */
        !          2198: 
        !          2199: static Tk_Item *
        !          2200: NextItem(searchPtr)
        !          2201:     TagSearch *searchPtr;              /* Record describing search in
        !          2202:                                         * progress. */
        !          2203: {
        !          2204:     register Tk_Item *itemPtr, *prevPtr;
        !          2205:     register int count;
        !          2206:     register Tk_Uid uid;
        !          2207:     register Tk_Uid *tagPtr;
        !          2208: 
        !          2209:     /*
        !          2210:      * Find next item in list (this may not actually be a suitable
        !          2211:      * one to return), and return if there are no items left.
        !          2212:      */
        !          2213: 
        !          2214:     prevPtr = searchPtr->prevPtr;
        !          2215:     if (prevPtr == NULL) {
        !          2216:        itemPtr = searchPtr->canvasPtr->firstItemPtr;
        !          2217:     } else {
        !          2218:        itemPtr = prevPtr->nextPtr;
        !          2219:     }
        !          2220:     if ((itemPtr == NULL) || (searchPtr->searchOver)) {
        !          2221:        searchPtr->searchOver = 1;
        !          2222:        return NULL;
        !          2223:     }
        !          2224:     if (itemPtr != searchPtr->currentPtr) {
        !          2225:        /*
        !          2226:         * The structure of the list has changed.  Probably the
        !          2227:         * previously-returned item was removed from the list.
        !          2228:         * In this case, don't advance prevPtr;  just return
        !          2229:         * its new successor (i.e. do nothing here).
        !          2230:         */
        !          2231:     } else {
        !          2232:        prevPtr = itemPtr;
        !          2233:        itemPtr = prevPtr->nextPtr;
        !          2234:     }
        !          2235: 
        !          2236:     /*
        !          2237:      * Handle special case of "all" search by returning next item.
        !          2238:      */
        !          2239: 
        !          2240:     uid = searchPtr->tag;
        !          2241:     if (uid == NULL) {
        !          2242:        searchPtr->prevPtr = prevPtr;
        !          2243:        searchPtr->currentPtr = itemPtr;
        !          2244:        return itemPtr;
        !          2245:     }
        !          2246: 
        !          2247:     /*
        !          2248:      * Look for an item with a particular tag.
        !          2249:      */
        !          2250: 
        !          2251:     for ( ; itemPtr != NULL; prevPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
        !          2252:        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
        !          2253:                count > 0; tagPtr++, count--) {
        !          2254:            if (*tagPtr == uid) {
        !          2255:                searchPtr->prevPtr = prevPtr;
        !          2256:                searchPtr->currentPtr = itemPtr;
        !          2257:                return itemPtr;
        !          2258:            }
        !          2259:        }
        !          2260:     }
        !          2261:     searchPtr->prevPtr = prevPtr;
        !          2262:     searchPtr->searchOver = 1;
        !          2263:     return NULL;
        !          2264: }
        !          2265: 
        !          2266: /*
        !          2267:  *--------------------------------------------------------------
        !          2268:  *
        !          2269:  * DoItem --
        !          2270:  *
        !          2271:  *     This is a utility procedure called by FindItems.  It
        !          2272:  *     either adds itemPtr's id to the result forming in interp,
        !          2273:  *     or it adds a new tag to itemPtr, depending on the value
        !          2274:  *     of tag.
        !          2275:  *
        !          2276:  * Results:
        !          2277:  *     None.
        !          2278:  *
        !          2279:  * Side effects:
        !          2280:  *     If tag is NULL then itemPtr's id is added as a list element
        !          2281:  *     to interp->result;  otherwise tag is added to itemPtr's
        !          2282:  *     list of tags.
        !          2283:  *
        !          2284:  *--------------------------------------------------------------
        !          2285:  */
        !          2286: 
        !          2287: static void
        !          2288: DoItem(interp, itemPtr, tag)
        !          2289:     Tcl_Interp *interp;                        /* Interpreter in which to (possibly)
        !          2290:                                         * record item id. */
        !          2291:     register Tk_Item *itemPtr;         /* Item to (possibly) modify. */
        !          2292:     Tk_Uid tag;                                /* Tag to add to those already
        !          2293:                                         * present for item, or NULL. */
        !          2294: {
        !          2295:     register Tk_Uid *tagPtr;
        !          2296:     register int count;
        !          2297: 
        !          2298:     /*
        !          2299:      * Handle the "add-to-result" case and return, if appropriate.
        !          2300:      */
        !          2301: 
        !          2302:     if (tag == NULL) {
        !          2303:        char msg[30];
        !          2304:        sprintf(msg, "%d", itemPtr->id);
        !          2305:        Tcl_AppendElement(interp, msg, 0);
        !          2306:        return;
        !          2307:     }
        !          2308: 
        !          2309:     for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
        !          2310:            count > 0; tagPtr++, count--) {
        !          2311:        if (tag == *tagPtr) {
        !          2312:            return;
        !          2313:        }
        !          2314:     }
        !          2315: 
        !          2316:     /*
        !          2317:      * Grow the tag space if there's no more room left in the current
        !          2318:      * block.
        !          2319:      */
        !          2320: 
        !          2321:     if (itemPtr->tagSpace == itemPtr->numTags) {
        !          2322:        Tk_Uid *newTagPtr;
        !          2323: 
        !          2324:        itemPtr->tagSpace += 5;
        !          2325:        newTagPtr = (Tk_Uid *) ckalloc((unsigned)
        !          2326:                (itemPtr->tagSpace * sizeof(Tk_Uid)));
        !          2327:        memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,
        !          2328:                (itemPtr->numTags * sizeof(Tk_Uid)));
        !          2329:        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        !          2330:            ckfree((char *) itemPtr->tagPtr);
        !          2331:        }
        !          2332:        itemPtr->tagPtr = newTagPtr;
        !          2333:        tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
        !          2334:     }
        !          2335: 
        !          2336:     /*
        !          2337:      * Add in the new tag.
        !          2338:      */
        !          2339: 
        !          2340:     *tagPtr = tag;
        !          2341:     itemPtr->numTags++;
        !          2342: }
        !          2343: 
        !          2344: /*
        !          2345:  *--------------------------------------------------------------
        !          2346:  *
        !          2347:  * FindItems --
        !          2348:  *
        !          2349:  *     This procedure does all the work of implementing the
        !          2350:  *     "find" and "addtag" options of the canvas widget command,
        !          2351:  *     which locate items that have certain features (location,
        !          2352:  *     tags, position in display list, etc.).
        !          2353:  *
        !          2354:  * Results:
        !          2355:  *     A standard Tcl return value.  If newTag is NULL, then a
        !          2356:  *     list of ids from all the items that match argc/argv is
        !          2357:  *     returned in interp->result.  If newTag is NULL, then
        !          2358:  *     the normal interp->result is an empty string.  If an error
        !          2359:  *     occurs, then interp->result will hold an error message.
        !          2360:  *
        !          2361:  * Side effects:
        !          2362:  *     If newTag is non-NULL, then all the items that match the
        !          2363:  *     information in argc/argv have that tag added to their
        !          2364:  *     lists of tags.
        !          2365:  *
        !          2366:  *--------------------------------------------------------------
        !          2367:  */
        !          2368: 
        !          2369: static int
        !          2370: FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option)
        !          2371:     Tcl_Interp *interp;                        /* Interpreter for error reporting. */
        !          2372:     Tk_Canvas *canvasPtr;              /* Canvas whose items are to be
        !          2373:                                         * searched. */
        !          2374:     int argc;                          /* Number of entries in argv.  Must be
        !          2375:                                         * greater than zero. */
        !          2376:     char **argv;                       /* Arguments that describe what items
        !          2377:                                         * to search for (see user doc on
        !          2378:                                         * "find" and "addtag" options). */
        !          2379:     char *newTag;                      /* If non-NULL, gives new tag to set
        !          2380:                                         * on all found items;  if NULL, then
        !          2381:                                         * ids of found items are returned
        !          2382:                                         * in interp->result. */
        !          2383:     char *cmdName;                     /* Name of original Tcl command, for
        !          2384:                                         * use in error messages. */
        !          2385:     char *option;                      /* For error messages:  gives option
        !          2386:                                         * from Tcl command and other stuff
        !          2387:                                         * up to what's in argc/argv. */
        !          2388: {
        !          2389:     char c;
        !          2390:     int length;
        !          2391:     TagSearch search;
        !          2392:     register Tk_Item *itemPtr;
        !          2393:     Tk_Uid uid;
        !          2394: 
        !          2395:     if (newTag != NULL) {
        !          2396:        uid = Tk_GetUid(newTag);
        !          2397:     } else {
        !          2398:        uid = NULL;
        !          2399:     }
        !          2400:     c = argv[0][0];
        !          2401:     length = strlen(argv[0]);
        !          2402:     if ((c == 'a') && (strncmp(argv[0], "above", length) == 0)
        !          2403:            && (length >= 2)) {
        !          2404:        Tk_Item *lastPtr = NULL;
        !          2405:        if (argc != 2) {
        !          2406:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2407:                    cmdName, option, " above tagOrId", (char *) NULL);
        !          2408:            return TCL_ERROR;
        !          2409:        }
        !          2410:        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        !          2411:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          2412:            lastPtr = itemPtr;
        !          2413:        }
        !          2414:        if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
        !          2415:            DoItem(interp, lastPtr->nextPtr, uid);
        !          2416:        }
        !          2417:     } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0)
        !          2418:            && (length >= 2)) {
        !          2419:        if (argc != 1) {
        !          2420:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2421:                    cmdName, option, " all", (char *) NULL);
        !          2422:            return TCL_ERROR;
        !          2423:        }
        !          2424: 
        !          2425:        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          2426:                itemPtr = itemPtr->nextPtr) {
        !          2427:            DoItem(interp, itemPtr, uid);
        !          2428:        }
        !          2429:     } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) {
        !          2430:        if (argc != 2) {
        !          2431:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2432:                    cmdName, option, " below tagOrId", (char *) NULL);
        !          2433:            return TCL_ERROR;
        !          2434:        }
        !          2435:        itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        !          2436:        if (search.prevPtr != NULL) {
        !          2437:            DoItem(interp, search.prevPtr, uid);
        !          2438:        }
        !          2439:     } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) {
        !          2440:        double closestDist;
        !          2441:        Tk_Item *startPtr, *closestPtr;
        !          2442:        double coords[2], halo;
        !          2443:        int x1, y1, x2, y2;
        !          2444: 
        !          2445:        if ((argc < 3) || (argc > 5)) {
        !          2446:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2447:                    cmdName, option, " closest x y ?halo? ?start?",
        !          2448:                    (char *) NULL);
        !          2449:            return TCL_ERROR;
        !          2450:        }
        !          2451:        if ((TkGetCanvasCoord(canvasPtr, argv[1], &coords[0]) != TCL_OK)
        !          2452:                || (TkGetCanvasCoord(canvasPtr, argv[2], &coords[1])
        !          2453:                != TCL_OK)) {
        !          2454:            return TCL_ERROR;
        !          2455:        }
        !          2456:        if (argc > 3) {
        !          2457:            if (TkGetCanvasCoord(canvasPtr, argv[3], &halo) != TCL_OK) {
        !          2458:                return TCL_ERROR;
        !          2459:            }
        !          2460:            if (halo < 0.0) {
        !          2461:                Tcl_AppendResult(interp, "can't have negative halo value \"",
        !          2462:                        argv[3], "\"", (char *) NULL);
        !          2463:                return TCL_ERROR;
        !          2464:            }
        !          2465:        } else {
        !          2466:            halo = 0.0;
        !          2467:        }
        !          2468: 
        !          2469:        /*
        !          2470:         * Find the item at which to start the search.
        !          2471:         */
        !          2472: 
        !          2473:        startPtr = canvasPtr->firstItemPtr;
        !          2474:        if (argc == 5) {
        !          2475:            itemPtr = StartTagSearch(canvasPtr, argv[4], &search);
        !          2476:            if (itemPtr != NULL) {
        !          2477:                startPtr = itemPtr;
        !          2478:            }
        !          2479:        }
        !          2480: 
        !          2481:        /*
        !          2482:         * The code below is optimized so that it can eliminate most
        !          2483:         * items without having to call their item-specific procedures.
        !          2484:         * This is done by keeping a bounding box (x1, y1, x2, y2) that
        !          2485:         * an item's bbox must overlap if the item is to have any
        !          2486:         * chance of being closer than the closest so far.
        !          2487:         */
        !          2488: 
        !          2489:        itemPtr = startPtr;
        !          2490:        if (itemPtr == NULL) {
        !          2491:            return TCL_OK;
        !          2492:        }
        !          2493:        closestDist = (*itemPtr->typePtr->pointProc)(canvasPtr,
        !          2494:                itemPtr, coords) - halo;
        !          2495:        if (closestDist < 0.0) {
        !          2496:            closestDist = 0.0;
        !          2497:        }
        !          2498:        while (1) {
        !          2499:            double newDist;
        !          2500: 
        !          2501:            /*
        !          2502:             * Update the bounding box using itemPtr, which is the
        !          2503:             * new closest item.
        !          2504:             */
        !          2505: 
        !          2506:            x1 = (coords[0] - closestDist - halo - 1);
        !          2507:            y1 = (coords[1] - closestDist - halo - 1);
        !          2508:            x2 = (coords[0] + closestDist + halo + 1);
        !          2509:            y2 = (coords[1] + closestDist + halo + 1);
        !          2510:            closestPtr = itemPtr;
        !          2511: 
        !          2512:            /*
        !          2513:             * Search for an item that beats the current closest one.
        !          2514:             * Work circularly through the canvas's item list until
        !          2515:             * getting back to the starting item.
        !          2516:             */
        !          2517: 
        !          2518:            while (1) {
        !          2519:                itemPtr = itemPtr->nextPtr;
        !          2520:                if (itemPtr == NULL) {
        !          2521:                    itemPtr = canvasPtr->firstItemPtr;
        !          2522:                }
        !          2523:                if (itemPtr == startPtr) {
        !          2524:                    DoItem(interp, closestPtr, uid);
        !          2525:                    return TCL_OK;
        !          2526:                }
        !          2527:                if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
        !          2528:                        || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
        !          2529:                    continue;
        !          2530:                }
        !          2531:                newDist = (*itemPtr->typePtr->pointProc)(canvasPtr,
        !          2532:                        itemPtr, coords) - halo;
        !          2533:                if (newDist < 0.0) {
        !          2534:                    newDist = 0.0;
        !          2535:                }
        !          2536:                if (newDist <= closestDist) {
        !          2537:                    closestDist = newDist;
        !          2538:                    break;
        !          2539:                }
        !          2540:            }
        !          2541:        }
        !          2542:     } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) {
        !          2543:        if (argc != 5) {
        !          2544:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2545:                    cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL);
        !          2546:            return TCL_ERROR;
        !          2547:        }
        !          2548:        return FindArea(interp, canvasPtr, argv+1, uid, 1);
        !          2549:     } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) {
        !          2550:        if (argc != 5) {
        !          2551:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2552:                    cmdName, option, " overlapping x1 y1 x2 y2",
        !          2553:                    (char *) NULL);
        !          2554:            return TCL_ERROR;
        !          2555:        }
        !          2556:        return FindArea(interp, canvasPtr, argv+1, uid, 0);
        !          2557:     } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) {
        !          2558:        if (argc != 2) {
        !          2559:            Tcl_AppendResult(interp, "wrong # args:  must be \"",
        !          2560:                    cmdName, option, " withtag tagOrId", (char *) NULL);
        !          2561:            return TCL_ERROR;
        !          2562:        }
        !          2563:        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        !          2564:                itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          2565:            DoItem(interp, itemPtr, uid);
        !          2566:        }
        !          2567:     } else  {
        !          2568:        Tcl_AppendResult(interp, "bad search command \"", argv[0],
        !          2569:                "\": must be above, all, below, closest, enclosed, ",
        !          2570:                "overlapping, or withtag", (char *) NULL);
        !          2571:        return TCL_ERROR;
        !          2572:     }
        !          2573:     return TCL_OK;
        !          2574: }
        !          2575: 
        !          2576: /*
        !          2577:  *--------------------------------------------------------------
        !          2578:  *
        !          2579:  * FindArea --
        !          2580:  *
        !          2581:  *     This procedure implements area searches for the "find"
        !          2582:  *     and "addtag" options.
        !          2583:  *
        !          2584:  * Results:
        !          2585:  *     A standard Tcl return value.  If newTag is NULL, then a
        !          2586:  *     list of ids from all the items overlapping or enclosed
        !          2587:  *     by the rectangle given by argc is returned in interp->result.
        !          2588:  *     If newTag is NULL, then the normal interp->result is an
        !          2589:  *     empty string.  If an error occurs, then interp->result will
        !          2590:  *     hold an error message.
        !          2591:  *
        !          2592:  * Side effects:
        !          2593:  *     If uid is non-NULL, then all the items overlapping
        !          2594:  *     or enclosed by the area in argv have that tag added to
        !          2595:  *     their lists of tags.
        !          2596:  *
        !          2597:  *--------------------------------------------------------------
        !          2598:  */
        !          2599: 
        !          2600: static int
        !          2601: FindArea(interp, canvasPtr, argv, uid, enclosed)
        !          2602:     Tcl_Interp *interp;                        /* Interpreter for error reporting
        !          2603:                                         * and result storing. */
        !          2604:     Tk_Canvas *canvasPtr;              /* Canvas whose items are to be
        !          2605:                                         * searched. */
        !          2606:     char **argv;                       /* Array of four arguments that
        !          2607:                                         * give the coordinates of the
        !          2608:                                         * rectangular area to search. */
        !          2609:     Tk_Uid uid;                                /* If non-NULL, gives new tag to set
        !          2610:                                         * on all found items;  if NULL, then
        !          2611:                                         * ids of found items are returned
        !          2612:                                         * in interp->result. */
        !          2613:     int enclosed;                      /* 0 means overlapping or enclosed
        !          2614:                                         * items are OK, 1 means only enclosed
        !          2615:                                         * items are OK. */
        !          2616: {
        !          2617:     double rect[4], tmp;
        !          2618:     int x1, y1, x2, y2;
        !          2619:     register Tk_Item *itemPtr;
        !          2620: 
        !          2621:     if ((TkGetCanvasCoord(canvasPtr, argv[0], &rect[0]) != TCL_OK)
        !          2622:            || (TkGetCanvasCoord(canvasPtr, argv[1], &rect[1]) != TCL_OK)
        !          2623:            || (TkGetCanvasCoord(canvasPtr, argv[2], &rect[2]) != TCL_OK)
        !          2624:            || (TkGetCanvasCoord(canvasPtr, argv[3], &rect[3]) != TCL_OK)) {
        !          2625:        return TCL_ERROR;
        !          2626:     }
        !          2627:     if (rect[0] > rect[2]) {
        !          2628:        tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
        !          2629:     }
        !          2630:     if (rect[1] > rect[3]) {
        !          2631:        tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
        !          2632:     }
        !          2633: 
        !          2634:     /*
        !          2635:      * Use an integer bounding box for a quick test, to avoid
        !          2636:      * calling item-specific code except for items that are close.
        !          2637:      */
        !          2638: 
        !          2639:     x1 = (rect[0]-1.0);
        !          2640:     y1 = (rect[1]-1.0);
        !          2641:     x2 = (rect[2]+1.0);
        !          2642:     y2 = (rect[3]+1.0);
        !          2643:     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          2644:            itemPtr = itemPtr->nextPtr) {
        !          2645:        if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
        !          2646:                || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
        !          2647:            continue;
        !          2648:        }
        !          2649:        if ((*itemPtr->typePtr->areaProc)(canvasPtr, itemPtr, rect)
        !          2650:                >= enclosed) {
        !          2651:            DoItem(interp, itemPtr, uid);
        !          2652:        }
        !          2653:     }
        !          2654:     return TCL_OK;
        !          2655: }
        !          2656: 
        !          2657: /*
        !          2658:  *--------------------------------------------------------------
        !          2659:  *
        !          2660:  * RelinkItems --
        !          2661:  *
        !          2662:  *     Move one or more items to a different place in the
        !          2663:  *     display order for a canvas.
        !          2664:  *
        !          2665:  * Results:
        !          2666:  *     None.
        !          2667:  *
        !          2668:  * Side effects:
        !          2669:  *     The items identified by "tag" are moved so that they
        !          2670:  *     are all together in the display list and immediately
        !          2671:  *     after prevPtr.  The order of the moved items relative
        !          2672:  *     to each other is not changed.
        !          2673:  *
        !          2674:  *--------------------------------------------------------------
        !          2675:  */
        !          2676: 
        !          2677: static void
        !          2678: RelinkItems(canvasPtr, tag, prevPtr)
        !          2679:     Tk_Canvas *canvasPtr;      /* Canvas to be modified. */
        !          2680:     char *tag;                 /* Tag identifying items to be moved
        !          2681:                                 * in the redisplay list. */
        !          2682:     Tk_Item *prevPtr;          /* Reposition the items so that they
        !          2683:                                 * go just after this item (NULL means
        !          2684:                                 * put at beginning of list). */
        !          2685: {
        !          2686:     register Tk_Item *itemPtr;
        !          2687:     TagSearch search;
        !          2688:     Tk_Item *firstMovePtr, *lastMovePtr;
        !          2689: 
        !          2690:     /*
        !          2691:      * Find all of the items to be moved and remove them from
        !          2692:      * the list, making an auxiliary list running from firstMovePtr
        !          2693:      * to lastMovePtr.  Record their areas for redisplay.
        !          2694:      */
        !          2695: 
        !          2696:     firstMovePtr = lastMovePtr = NULL;
        !          2697:     for (itemPtr = StartTagSearch(canvasPtr, tag, &search);
        !          2698:            itemPtr != NULL; itemPtr = NextItem(&search)) {
        !          2699:        if (itemPtr == prevPtr) {
        !          2700:            /*
        !          2701:             * Item after which insertion is to occur is being
        !          2702:             * moved!  Switch to insert after its predecessor.
        !          2703:             */
        !          2704: 
        !          2705:            prevPtr = search.prevPtr;
        !          2706:        }
        !          2707:        if (search.prevPtr == NULL) {
        !          2708:            canvasPtr->firstItemPtr = itemPtr->nextPtr;
        !          2709:        } else {
        !          2710:            search.prevPtr->nextPtr = itemPtr->nextPtr;
        !          2711:        }
        !          2712:        if (canvasPtr->lastItemPtr == itemPtr) {
        !          2713:            canvasPtr->lastItemPtr = search.prevPtr;
        !          2714:        }
        !          2715:        if (firstMovePtr == NULL) {
        !          2716:            firstMovePtr = itemPtr;
        !          2717:        } else {
        !          2718:            lastMovePtr->nextPtr = itemPtr;
        !          2719:        }
        !          2720:        lastMovePtr = itemPtr;
        !          2721:        EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          2722:                itemPtr->x2, itemPtr->y2);
        !          2723:        canvasPtr->flags |= REPICK_NEEDED;
        !          2724:     }
        !          2725: 
        !          2726:     /*
        !          2727:      * Insert the list of to-be-moved items back into the canvas's
        !          2728:      * at the desired position.
        !          2729:      */
        !          2730: 
        !          2731:     if (firstMovePtr == NULL) {
        !          2732:        return;
        !          2733:     }
        !          2734:     if (prevPtr == NULL) {
        !          2735:        lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
        !          2736:        canvasPtr->firstItemPtr = firstMovePtr;
        !          2737:     } else {
        !          2738:        lastMovePtr->nextPtr = prevPtr->nextPtr;
        !          2739:        prevPtr->nextPtr = firstMovePtr;
        !          2740:     }
        !          2741:     if (canvasPtr->lastItemPtr == prevPtr) {
        !          2742:        canvasPtr->lastItemPtr = lastMovePtr;
        !          2743:     }
        !          2744: }
        !          2745: 
        !          2746: /*
        !          2747:  *--------------------------------------------------------------
        !          2748:  *
        !          2749:  * CanvasBindProc --
        !          2750:  *
        !          2751:  *     This procedure is invoked by the Tk dispatcher to handle
        !          2752:  *     events associated with bindings on items.
        !          2753:  *
        !          2754:  * Results:
        !          2755:  *     None.
        !          2756:  *
        !          2757:  * Side effects:
        !          2758:  *     Depends on the command invoked as part of the binding
        !          2759:  *     (if there was any).
        !          2760:  *
        !          2761:  *--------------------------------------------------------------
        !          2762:  */
        !          2763: 
        !          2764: static void
        !          2765: CanvasBindProc(clientData, eventPtr)
        !          2766:     ClientData clientData;             /* Pointer to canvas structure. */
        !          2767:     XEvent *eventPtr;                  /* Pointer to X event that just
        !          2768:                                         * happened. */
        !          2769: {
        !          2770:     Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          2771:     int repick  = 0;
        !          2772: 
        !          2773:     Tk_Preserve((ClientData) canvasPtr);
        !          2774: 
        !          2775:     /*
        !          2776:      * This code simulates grabs for mouse buttons by refusing to
        !          2777:      * pick a new current item between the time a mouse button goes
        !          2778:      * down and the time when the last mouse button is released is
        !          2779:      * released again.
        !          2780:      */
        !          2781: 
        !          2782:     if (eventPtr->type == ButtonPress) {
        !          2783:        canvasPtr->flags |= BUTTON_DOWN;
        !          2784:     } else if (eventPtr->type == ButtonRelease) {
        !          2785:        int mask;
        !          2786: 
        !          2787:        switch (eventPtr->xbutton.button) {
        !          2788:            case Button1:
        !          2789:                mask = Button1Mask;
        !          2790:                break;
        !          2791:            case Button2:
        !          2792:                mask = Button2Mask;
        !          2793:                break;
        !          2794:            case Button3:
        !          2795:                mask = Button3Mask;
        !          2796:                break;
        !          2797:            case Button4:
        !          2798:                mask = Button4Mask;
        !          2799:                break;
        !          2800:            case Button5:
        !          2801:                mask = Button5Mask;
        !          2802:                break;
        !          2803:            default:
        !          2804:                mask = 0;
        !          2805:                break;
        !          2806:        }
        !          2807:        if ((eventPtr->xbutton.state & (Button1Mask|Button2Mask
        !          2808:                |Button3Mask|Button4Mask|Button5Mask)) == mask) {
        !          2809:            canvasPtr->flags &= ~BUTTON_DOWN;
        !          2810:            repick = 1;
        !          2811:        }
        !          2812:     } else if ((eventPtr->type == EnterNotify)
        !          2813:            || (eventPtr->type == LeaveNotify)) {
        !          2814:        PickCurrentItem(canvasPtr, eventPtr);
        !          2815:        goto done;
        !          2816:     } else if (eventPtr->type == MotionNotify) {
        !          2817:        PickCurrentItem(canvasPtr, eventPtr);
        !          2818:     }
        !          2819:     CanvasDoEvent(canvasPtr, eventPtr);
        !          2820:     if (repick) {
        !          2821:        unsigned int oldState;
        !          2822: 
        !          2823:        oldState = eventPtr->xbutton.state;
        !          2824:        eventPtr->xbutton.state &= ~(Button1Mask|Button2Mask
        !          2825:                |Button3Mask|Button4Mask|Button5Mask);
        !          2826:        PickCurrentItem(canvasPtr, eventPtr);
        !          2827:        eventPtr->xbutton.state = oldState;
        !          2828:     }
        !          2829: 
        !          2830:     done:
        !          2831:     Tk_Release((ClientData) canvasPtr);
        !          2832: }
        !          2833: 
        !          2834: /*
        !          2835:  *--------------------------------------------------------------
        !          2836:  *
        !          2837:  * PickCurrentItem --
        !          2838:  *
        !          2839:  *     Find the topmost item in a canvas that contains a given
        !          2840:  *     location and mark the the current item.  If the current
        !          2841:  *     item has changed, generate a fake exit event on the old
        !          2842:  *     current item and a fake enter event on the new current
        !          2843:  *     item.
        !          2844:  *
        !          2845:  * Results:
        !          2846:  *     None.
        !          2847:  *
        !          2848:  * Side effects:
        !          2849:  *     The current item for canvasPtr may change.  If it does,
        !          2850:  *     then the commands associated with item entry and exit
        !          2851:  *     could do just about anything.
        !          2852:  *
        !          2853:  *--------------------------------------------------------------
        !          2854:  */
        !          2855: 
        !          2856: static void
        !          2857: PickCurrentItem(canvasPtr, eventPtr)
        !          2858:     register Tk_Canvas *canvasPtr;     /* Canvas pointer in which to select
        !          2859:                                         * current item. */
        !          2860:     XEvent *eventPtr;                  /* Event describing location of
        !          2861:                                         * mouse cursor.  Must be EnterWindow,
        !          2862:                                         * LeaveWindow, ButtonRelease, or
        !          2863:                                         * MotionNotify. */
        !          2864: {
        !          2865:     Tk_Item *closestPtr = NULL;
        !          2866: 
        !          2867:     /*
        !          2868:      * If a button is down, then don't do anything at all;  we'll be
        !          2869:      * called again when all buttons are up, and we can repick then.
        !          2870:      * This implements a form of mouse grabbing for canvases.
        !          2871:      */
        !          2872: 
        !          2873:     if (canvasPtr->flags & BUTTON_DOWN) {
        !          2874:        return;
        !          2875:     }
        !          2876: 
        !          2877:     /*
        !          2878:      * Save information about this event in the canvas.  The event in
        !          2879:      * the canvas is used for two purposes:
        !          2880:      *
        !          2881:      * 1. Event bindings: if the current item changes, fake events are
        !          2882:      *    generated to allow item-enter and item-leave bindings to trigger.
        !          2883:      * 2. Reselection: if the current item gets deleted, can use the
        !          2884:      *    saved event to find a new current item.
        !          2885:      * Translate MotionNotify events into EnterNotify events, since that's
        !          2886:      * what gets reported to item handlers.
        !          2887:      */
        !          2888: 
        !          2889:     if (eventPtr != &canvasPtr->pickEvent) {
        !          2890:        if ((eventPtr->type == MotionNotify)
        !          2891:                || (eventPtr->type == ButtonRelease)) {
        !          2892:            canvasPtr->pickEvent.xcrossing.type = EnterNotify;
        !          2893:            canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
        !          2894:            canvasPtr->pickEvent.xcrossing.send_event
        !          2895:                    = eventPtr->xmotion.send_event;
        !          2896:            canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
        !          2897:            canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
        !          2898:            canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
        !          2899:            canvasPtr->pickEvent.xcrossing.subwindow = None;
        !          2900:            canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
        !          2901:            canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
        !          2902:            canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
        !          2903:            canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
        !          2904:            canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
        !          2905:            canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
        !          2906:            canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
        !          2907:            canvasPtr->pickEvent.xcrossing.same_screen
        !          2908:                    = eventPtr->xmotion.same_screen;
        !          2909:            canvasPtr->pickEvent.xcrossing.focus = False;
        !          2910:            canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
        !          2911:        } else  {
        !          2912:            canvasPtr->pickEvent = *eventPtr;
        !          2913:        }
        !          2914:     }
        !          2915: 
        !          2916:     /*
        !          2917:      * A LeaveNotify event automatically means that there's no current
        !          2918:      * object, so the rest of the code below can be skipped.
        !          2919:      */
        !          2920: 
        !          2921:     if (canvasPtr->pickEvent.type != LeaveNotify) {
        !          2922:        int x1, y1, x2, y2;
        !          2923:        double coords[2];
        !          2924:        register Tk_Item *itemPtr;
        !          2925: 
        !          2926:        coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
        !          2927:        coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
        !          2928:        x1 = coords[0] - canvasPtr->closeEnough;
        !          2929:        y1 = coords[1] - canvasPtr->closeEnough;
        !          2930:        x2 = coords[0] + canvasPtr->closeEnough;
        !          2931:        y2 = coords[1] + canvasPtr->closeEnough;
        !          2932:     
        !          2933:        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        !          2934:                itemPtr = itemPtr->nextPtr) {
        !          2935:            if ((itemPtr->x1 >= x2) || (itemPtr->x2 < x1)
        !          2936:                    || (itemPtr->y1 >= y2) || (itemPtr->y2 < y1)) {
        !          2937:                continue;
        !          2938:            }
        !          2939:            if ((*itemPtr->typePtr->pointProc)(canvasPtr,
        !          2940:                    itemPtr, coords) <= canvasPtr->closeEnough) {
        !          2941:                closestPtr = itemPtr;
        !          2942:            }
        !          2943:        }
        !          2944:     }
        !          2945: 
        !          2946:     /*
        !          2947:      * Simulate a LeaveNotify event on the previous current item and
        !          2948:      * an EnterNotify event on the new current item.  Remove the "current"
        !          2949:      * tag from the previous current item and place it on the new current
        !          2950:      * item.
        !          2951:      */
        !          2952: 
        !          2953:     if (closestPtr == canvasPtr->currentItemPtr) {
        !          2954:        return;
        !          2955:     }
        !          2956:     if (canvasPtr->currentItemPtr != NULL) {
        !          2957:        XEvent event;
        !          2958:        Tk_Item *itemPtr = canvasPtr->currentItemPtr;
        !          2959:        int i;
        !          2960: 
        !          2961:        event = canvasPtr->pickEvent;
        !          2962:        event.type = LeaveNotify;
        !          2963:        CanvasDoEvent(canvasPtr, &event);
        !          2964:        for (i = itemPtr->numTags-1; i >= 0; i--) {
        !          2965:            if (itemPtr->tagPtr[i] == currentUid) {
        !          2966:                itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
        !          2967:                itemPtr->numTags--;
        !          2968:                break;
        !          2969:            }
        !          2970:        }
        !          2971:     }
        !          2972:     canvasPtr->currentItemPtr = closestPtr;
        !          2973:     if (canvasPtr->currentItemPtr != NULL) {
        !          2974:        XEvent event;
        !          2975: 
        !          2976:        DoItem((Tcl_Interp *) NULL, closestPtr, currentUid);
        !          2977:        event = canvasPtr->pickEvent;
        !          2978:        event.type = EnterNotify;
        !          2979:        CanvasDoEvent(canvasPtr, &event);
        !          2980:     }
        !          2981: }
        !          2982: 
        !          2983: /*
        !          2984:  *--------------------------------------------------------------
        !          2985:  *
        !          2986:  * CanvasDoEvent --
        !          2987:  *
        !          2988:  *     This procedure is called to invoke binding processing
        !          2989:  *     for a new event that is associated with the current item
        !          2990:  *     for a canvas.
        !          2991:  *
        !          2992:  * Results:
        !          2993:  *     None.
        !          2994:  *
        !          2995:  * Side effects:
        !          2996:  *     Depends on the bindings for the canvas.
        !          2997:  *
        !          2998:  *--------------------------------------------------------------
        !          2999:  */
        !          3000: 
        !          3001: static void
        !          3002: CanvasDoEvent(canvasPtr, eventPtr)
        !          3003:     Tk_Canvas *canvasPtr;              /* Canvas widget in which event
        !          3004:                                         * occurred. */
        !          3005:     XEvent *eventPtr;                  /* Real or simulated X event that
        !          3006:                                         * is to be processed. */
        !          3007: {
        !          3008: #define NUM_STATIC 3
        !          3009:     ClientData staticObjects[NUM_STATIC];
        !          3010:     ClientData *objectPtr;
        !          3011:     int numObjects, i;
        !          3012:     register Tk_Item *itemPtr;
        !          3013: 
        !          3014:     if (canvasPtr->bindingTable == NULL) {
        !          3015:        return;
        !          3016:     }
        !          3017: 
        !          3018:     itemPtr = canvasPtr->currentItemPtr;
        !          3019:     if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
        !          3020:        itemPtr = canvasPtr->focusItemPtr;
        !          3021:     }
        !          3022:     if (itemPtr == NULL) {
        !          3023:        return;
        !          3024:     }
        !          3025: 
        !          3026:     /*
        !          3027:      * Set up an array with all the relevant objects for processing
        !          3028:      * this event.  The relevant objects are (a) the event's item,
        !          3029:      * (b) the tags associated with the event's item, and (c) the
        !          3030:      * tag "all".  If there are a lot of tags then malloc an array
        !          3031:      * to hold all of the objects.
        !          3032:      */
        !          3033: 
        !          3034:     numObjects = itemPtr->numTags + 2;
        !          3035:     if (numObjects <= NUM_STATIC) {
        !          3036:        objectPtr = staticObjects;
        !          3037:     } else {
        !          3038:        objectPtr = (ClientData *) ckalloc((unsigned)
        !          3039:                (numObjects * sizeof(ClientData)));
        !          3040:     }
        !          3041:     objectPtr[0] = (ClientData) itemPtr;
        !          3042:     for (i = itemPtr->numTags-1; i >= 0; i--) {
        !          3043:        objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
        !          3044:     }
        !          3045:     objectPtr[itemPtr->numTags+1] = (ClientData) allUid;
        !          3046: 
        !          3047:     /*
        !          3048:      * Invoke the binding system, then free up the object array if
        !          3049:      * it was malloc-ed.
        !          3050:      */
        !          3051: 
        !          3052:     Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
        !          3053:            numObjects, objectPtr);
        !          3054:     if (objectPtr != staticObjects) {
        !          3055:        ckfree((char *) objectPtr);
        !          3056:     }
        !          3057: }
        !          3058: 
        !          3059: /*
        !          3060:  *----------------------------------------------------------------------
        !          3061:  *
        !          3062:  * CanvasBlinkProc --
        !          3063:  *
        !          3064:  *     This procedure is called as a timer handler to blink the
        !          3065:  *     insertion cursor off and on.
        !          3066:  *
        !          3067:  * Results:
        !          3068:  *     None.
        !          3069:  *
        !          3070:  * Side effects:
        !          3071:  *     The cursor gets turned on or off, redisplay gets invoked,
        !          3072:  *     and this procedure reschedules itself.
        !          3073:  *
        !          3074:  *----------------------------------------------------------------------
        !          3075:  */
        !          3076: 
        !          3077: static void
        !          3078: CanvasBlinkProc(clientData)
        !          3079:     ClientData clientData;     /* Pointer to record describing entry. */
        !          3080: {
        !          3081:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          3082: 
        !          3083:     if (!(canvasPtr->flags & GOT_FOCUS) || (canvasPtr->cursorOffTime == 0)) {
        !          3084:        return;
        !          3085:     }
        !          3086:     if (canvasPtr->flags & CURSOR_ON) {
        !          3087:        canvasPtr->flags &= ~CURSOR_ON;
        !          3088:        canvasPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          3089:                canvasPtr->cursorOffTime, CanvasBlinkProc,
        !          3090:                (ClientData) canvasPtr);
        !          3091:     } else {
        !          3092:        canvasPtr->flags |= CURSOR_ON;
        !          3093:        canvasPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          3094:                canvasPtr->cursorOnTime, CanvasBlinkProc,
        !          3095:                (ClientData) canvasPtr);
        !          3096:     }
        !          3097:     if (canvasPtr->focusItemPtr != NULL) {
        !          3098:        EventuallyRedrawArea(canvasPtr, canvasPtr->focusItemPtr->x1,
        !          3099:                canvasPtr->focusItemPtr->y1, canvasPtr->focusItemPtr->x2,
        !          3100:                canvasPtr->focusItemPtr->y2);
        !          3101:     }
        !          3102: }
        !          3103: 
        !          3104: /*
        !          3105:  *----------------------------------------------------------------------
        !          3106:  *
        !          3107:  * CanvasFocusProc --
        !          3108:  *
        !          3109:  *     This procedure is called whenever a canvas gets or loses the
        !          3110:  *     input focus.  It's also called whenever the window is
        !          3111:  *     reconfigured while it has the focus.
        !          3112:  *
        !          3113:  * Results:
        !          3114:  *     None.
        !          3115:  *
        !          3116:  * Side effects:
        !          3117:  *     The cursor gets turned on or off.
        !          3118:  *
        !          3119:  *----------------------------------------------------------------------
        !          3120:  */
        !          3121: 
        !          3122: static void
        !          3123: CanvasFocusProc(clientData, gotFocus)
        !          3124:     ClientData clientData;     /* Pointer to structure describing entry. */
        !          3125:     int gotFocus;              /* 1 means window is getting focus, 0 means
        !          3126:                                 * it's losing it. */
        !          3127: {
        !          3128:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          3129: 
        !          3130:     Tk_DeleteTimerHandler(canvasPtr->cursorBlinkHandler);
        !          3131:     if (gotFocus) {
        !          3132:        canvasPtr->flags |= GOT_FOCUS | CURSOR_ON;
        !          3133:        if (canvasPtr->cursorOffTime != 0) {
        !          3134:            canvasPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          3135:                    canvasPtr->cursorOnTime, CanvasBlinkProc,
        !          3136:                    (ClientData) canvasPtr);
        !          3137:        }
        !          3138:     } else {
        !          3139:        canvasPtr->flags &= ~(GOT_FOCUS | CURSOR_ON);
        !          3140:        canvasPtr->cursorBlinkHandler = (Tk_TimerToken) NULL;
        !          3141:     }
        !          3142:     if (canvasPtr->focusItemPtr != NULL) {
        !          3143:        EventuallyRedrawArea(canvasPtr, canvasPtr->focusItemPtr->x1,
        !          3144:                canvasPtr->focusItemPtr->y1, canvasPtr->focusItemPtr->x2,
        !          3145:                canvasPtr->focusItemPtr->y2);
        !          3146:     }
        !          3147: }
        !          3148: 
        !          3149: /*
        !          3150:  *----------------------------------------------------------------------
        !          3151:  *
        !          3152:  * CanvasSelectTo --
        !          3153:  *
        !          3154:  *     Modify the selection by moving its un-anchored end.  This could
        !          3155:  *     make the selection either larger or smaller.
        !          3156:  *
        !          3157:  * Results:
        !          3158:  *     None.
        !          3159:  *
        !          3160:  * Side effects:
        !          3161:  *     The selection changes.
        !          3162:  *
        !          3163:  *----------------------------------------------------------------------
        !          3164:  */
        !          3165: 
        !          3166: static void
        !          3167: CanvasSelectTo(canvasPtr, itemPtr, index)
        !          3168:     register Tk_Canvas *canvasPtr;             /* Information about widget. */
        !          3169:     register Tk_Item *itemPtr;         /* Item that is to hold selection. */
        !          3170:     int index;                         /* Index of element that is to
        !          3171:                                         * become the "other" end of the
        !          3172:                                         * selection. */
        !          3173: {
        !          3174:     int oldFirst, oldLast;
        !          3175:     Tk_Item *oldSelPtr;
        !          3176: 
        !          3177:     oldFirst = canvasPtr->selectFirst;
        !          3178:     oldLast = canvasPtr->selectLast;
        !          3179:     oldSelPtr = canvasPtr->selItemPtr;
        !          3180: 
        !          3181:     /*
        !          3182:      * Grab the selection if we don't own it already.
        !          3183:      */
        !          3184: 
        !          3185:     if (canvasPtr->selItemPtr == NULL) {
        !          3186:        Tk_OwnSelection(canvasPtr->tkwin, CanvasLostSelection,
        !          3187:                (ClientData) canvasPtr);
        !          3188:     } else if (canvasPtr->selItemPtr != itemPtr) {
        !          3189:        EventuallyRedrawArea(canvasPtr, canvasPtr->selItemPtr->x1,
        !          3190:                canvasPtr->selItemPtr->y1, canvasPtr->selItemPtr->x2,
        !          3191:                canvasPtr->selItemPtr->y2);
        !          3192:     }
        !          3193:     canvasPtr->selItemPtr = itemPtr;
        !          3194: 
        !          3195:     if (canvasPtr->anchorItemPtr != itemPtr) {
        !          3196:        canvasPtr->anchorItemPtr = itemPtr;
        !          3197:        canvasPtr->selectAnchor = index;
        !          3198:     }
        !          3199:     if (canvasPtr->selectAnchor <= index) {
        !          3200:        canvasPtr->selectFirst = canvasPtr->selectAnchor;
        !          3201:        canvasPtr->selectLast = index;
        !          3202:     } else {
        !          3203:        canvasPtr->selectFirst = index;
        !          3204:        canvasPtr->selectLast = canvasPtr->selectAnchor - 1;
        !          3205:     }
        !          3206:     if ((canvasPtr->selectFirst != oldFirst)
        !          3207:            || (canvasPtr->selectLast != oldLast)
        !          3208:            || (itemPtr != oldSelPtr)) {
        !          3209:        EventuallyRedrawArea(canvasPtr, itemPtr->x1, itemPtr->y1,
        !          3210:                itemPtr->x2, itemPtr->y2);
        !          3211:     }
        !          3212: }
        !          3213: 
        !          3214: /*
        !          3215:  *--------------------------------------------------------------
        !          3216:  *
        !          3217:  * CanvasFetchSelection --
        !          3218:  *
        !          3219:  *     This procedure is invoked by Tk to return part or all of
        !          3220:  *     the selection, when the selection is in a canvas widget.
        !          3221:  *     This procedure always returns the selection as a STRING.
        !          3222:  *
        !          3223:  * Results:
        !          3224:  *     The return value is the number of non-NULL bytes stored
        !          3225:  *     at buffer.  Buffer is filled (or partially filled) with a
        !          3226:  *     NULL-terminated string containing part or all of the selection,
        !          3227:  *     as given by offset and maxBytes.
        !          3228:  *
        !          3229:  * Side effects:
        !          3230:  *     None.
        !          3231:  *
        !          3232:  *--------------------------------------------------------------
        !          3233:  */
        !          3234: 
        !          3235: static int
        !          3236: CanvasFetchSelection(clientData, offset, buffer, maxBytes)
        !          3237:     ClientData clientData;             /* Information about canvas widget. */
        !          3238:     int offset;                                /* Offset within selection of first
        !          3239:                                         * character to be returned. */
        !          3240:     char *buffer;                      /* Location in which to place
        !          3241:                                         * selection. */
        !          3242:     int maxBytes;                      /* Maximum number of bytes to place
        !          3243:                                         * at buffer, not including terminating
        !          3244:                                         * NULL character. */
        !          3245: {
        !          3246:     register Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          3247: 
        !          3248:     if (canvasPtr->selItemPtr == NULL) {
        !          3249:        return -1;
        !          3250:     }
        !          3251:     if (canvasPtr->selItemPtr->typePtr->selectionProc == NULL) {
        !          3252:        return -1;
        !          3253:     }
        !          3254:     return (*canvasPtr->selItemPtr->typePtr->selectionProc)(
        !          3255:            canvasPtr, canvasPtr->selItemPtr, offset, buffer, maxBytes);
        !          3256: }
        !          3257: 
        !          3258: /*
        !          3259:  *----------------------------------------------------------------------
        !          3260:  *
        !          3261:  * CanvasLostSelection --
        !          3262:  *
        !          3263:  *     This procedure is called back by Tk when the selection is
        !          3264:  *     grabbed away from a canvas widget.
        !          3265:  *
        !          3266:  * Results:
        !          3267:  *     None.
        !          3268:  *
        !          3269:  * Side effects:
        !          3270:  *     The existing selection is unhighlighted, and the window is
        !          3271:  *     marked as not containing a selection.
        !          3272:  *
        !          3273:  *----------------------------------------------------------------------
        !          3274:  */
        !          3275: 
        !          3276: static void
        !          3277: CanvasLostSelection(clientData)
        !          3278:     ClientData clientData;             /* Information about entry widget. */
        !          3279: {
        !          3280:     Tk_Canvas *canvasPtr = (Tk_Canvas *) clientData;
        !          3281: 
        !          3282:     if (canvasPtr->selItemPtr != NULL) {
        !          3283:        EventuallyRedrawArea(canvasPtr, canvasPtr->selItemPtr->x1,
        !          3284:                canvasPtr->selItemPtr->y1, canvasPtr->selItemPtr->x2,
        !          3285:                canvasPtr->selItemPtr->y2);
        !          3286:     }
        !          3287:     canvasPtr->selItemPtr = NULL;
        !          3288: }
        !          3289: 
        !          3290: /*
        !          3291:  *--------------------------------------------------------------
        !          3292:  *
        !          3293:  * TkGetCanvasCoord --
        !          3294:  *
        !          3295:  *     Given a string, returns a floating-point canvas coordinate
        !          3296:  *     corresponding to that string.
        !          3297:  *
        !          3298:  * Results:
        !          3299:  *     The return value is a standard Tcl return result.  If
        !          3300:  *     TCL_OK is returned, then everything went well and the
        !          3301:  *     canvas coordinate is stored at *doublePtr;  otherwise
        !          3302:  *     TCL_ERROR is returned and an error message is left in
        !          3303:  *     canvasPtr->interp->result.
        !          3304:  *
        !          3305:  * Side effects:
        !          3306:  *     None.
        !          3307:  *
        !          3308:  *--------------------------------------------------------------
        !          3309:  */
        !          3310: 
        !          3311: int
        !          3312: TkGetCanvasCoord(canvasPtr, string, doublePtr)
        !          3313:     Tk_Canvas *canvasPtr;      /* Canvas to which coordinate applies. */
        !          3314:     char *string;              /* Describes coordinate (any screen
        !          3315:                                 * coordinate form may be used here). */
        !          3316:     double *doublePtr;         /* Place to store converted coordinate. */
        !          3317: {
        !          3318:     if (Tk_GetScreenMM(canvasPtr->interp, canvasPtr->tkwin, string,
        !          3319:            doublePtr) != TCL_OK) {
        !          3320:        return TCL_ERROR;
        !          3321:     }
        !          3322:     *doublePtr *= canvasPtr->pixelsPerMM;
        !          3323:     return TCL_OK;
        !          3324: }
        !          3325: 
        !          3326: /*
        !          3327:  *--------------------------------------------------------------
        !          3328:  *
        !          3329:  * GridAlign --
        !          3330:  *
        !          3331:  *     Given a coordinate and a grid spacing, this procedure
        !          3332:  *     computes the location of the nearest grid line to the
        !          3333:  *     coordinate.
        !          3334:  *
        !          3335:  * Results:
        !          3336:  *     The return value is the location of the grid line nearest
        !          3337:  *     to coord.
        !          3338:  *
        !          3339:  * Side effects:
        !          3340:  *     None.
        !          3341:  *
        !          3342:  *--------------------------------------------------------------
        !          3343:  */
        !          3344: 
        !          3345: static double
        !          3346: GridAlign(coord, spacing)
        !          3347:     double coord;              /* Coordinate to grid-align. */
        !          3348:     double spacing;            /* Spacing between grid lines.   If <= 0
        !          3349:                                 * then no alignment is done. */
        !          3350: {
        !          3351:     if (spacing <= 0.0) {
        !          3352:        return coord;
        !          3353:     }
        !          3354:     if (coord < 0) {
        !          3355:        return -((int) ((-coord)/spacing + 0.5)) * spacing;
        !          3356:     }
        !          3357:     return ((int) (coord/spacing + 0.5)) * spacing;
        !          3358: }
        !          3359: 
        !          3360: /*
        !          3361:  *--------------------------------------------------------------
        !          3362:  *
        !          3363:  * CanvasUpdateScrollbars --
        !          3364:  *
        !          3365:  *     This procedure is invoked whenever a canvas has changed in
        !          3366:  *     a way that requires scrollbars to be redisplayed (e.g. the
        !          3367:  *     view in the canvas has changed).
        !          3368:  *
        !          3369:  * Results:
        !          3370:  *     None.
        !          3371:  *
        !          3372:  * Side effects:
        !          3373:  *     If there are scrollbars associated with the canvas, then
        !          3374:  *     their scrolling commands are invoked to cause them to
        !          3375:  *     redisplay.  If errors occur, additional Tcl commands may
        !          3376:  *     be invoked to process the errors.
        !          3377:  *
        !          3378:  *--------------------------------------------------------------
        !          3379:  */
        !          3380: 
        !          3381: static void
        !          3382: CanvasUpdateScrollbars(canvasPtr)
        !          3383:     register Tk_Canvas *canvasPtr;             /* Information about canvas. */
        !          3384: {
        !          3385:     int result, size, first, last, page;
        !          3386:     char args[200];
        !          3387: 
        !          3388: #define ROUND(number)                                          \
        !          3389:     if (number >= 0) {                                         \
        !          3390:        number = (number + canvasPtr->scrollIncrement/2)        \
        !          3391:                /canvasPtr->scrollIncrement;                    \
        !          3392:     } else {                                                   \
        !          3393:        number = -(((-number) + canvasPtr->scrollIncrement/2)   \
        !          3394:                /canvasPtr->scrollIncrement);                   \
        !          3395:     }
        !          3396: 
        !          3397:     canvasPtr->flags &= ~UPDATE_SCROLLBARS;
        !          3398:     if (canvasPtr->xScrollCmd != NULL) {
        !          3399:        size = ((canvasPtr->scrollX2 - canvasPtr->scrollX1)
        !          3400:                /canvasPtr->scrollIncrement) + 1;
        !          3401:        first = canvasPtr->xOrigin - canvasPtr->scrollX1;
        !          3402:        ROUND(first);
        !          3403:        last = canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
        !          3404:                - 1 - canvasPtr->scrollX1;
        !          3405:        ROUND(last);
        !          3406:        page = last - first - 1;
        !          3407:        if (page <= 0) {
        !          3408:            page = 1;
        !          3409:        }
        !          3410:        sprintf(args, " %d %d %d %d", size, page, first, last);
        !          3411:        result = Tcl_VarEval(canvasPtr->interp, canvasPtr->xScrollCmd, args,
        !          3412:            (char *) NULL);
        !          3413:        if (result != TCL_OK) {
        !          3414:            TkBindError(canvasPtr->interp);
        !          3415:        }
        !          3416:        Tcl_ResetResult(canvasPtr->interp);
        !          3417:     }
        !          3418: 
        !          3419:     if (canvasPtr->yScrollCmd != NULL) {
        !          3420:        size = ((canvasPtr->scrollY2 - canvasPtr->scrollY1)
        !          3421:                /canvasPtr->scrollIncrement) + 1;
        !          3422:        first = canvasPtr->yOrigin - canvasPtr->scrollY1;
        !          3423:        ROUND(first);
        !          3424:        last = canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
        !          3425:                - 1 - canvasPtr->scrollY1;
        !          3426:        ROUND(last);
        !          3427:        page = last - first - 1;
        !          3428:        if (page <= 0) {
        !          3429:            page = 1;
        !          3430:        }
        !          3431:        sprintf(args, " %d %d %d %d", size, page, first, last);
        !          3432:        result = Tcl_VarEval(canvasPtr->interp, canvasPtr->yScrollCmd, args,
        !          3433:            (char *) NULL);
        !          3434:        if (result != TCL_OK) {
        !          3435:            TkBindError(canvasPtr->interp);
        !          3436:        }
        !          3437:        Tcl_ResetResult(canvasPtr->interp);
        !          3438:     }
        !          3439: }
        !          3440: 
        !          3441: /*
        !          3442:  *--------------------------------------------------------------
        !          3443:  *
        !          3444:  * CanvasSetOrigin --
        !          3445:  *
        !          3446:  *     This procedure is invoked to change the mapping between
        !          3447:  *     canvas coordinates and screen coordinates in the canvas
        !          3448:  *     window.
        !          3449:  *
        !          3450:  * Results:
        !          3451:  *     None.
        !          3452:  *
        !          3453:  * Side effects:
        !          3454:  *     The canvas will be redisplayed to reflect the change in
        !          3455:  *     view.  In addition, scrollbars will be updated if there
        !          3456:  *     are any.
        !          3457:  *
        !          3458:  *--------------------------------------------------------------
        !          3459:  */
        !          3460: 
        !          3461: static void
        !          3462: CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)
        !          3463:     register Tk_Canvas *canvasPtr;     /* Information about canvas. */
        !          3464:     int xOrigin;                       /* New X origin for canvas (canvas
        !          3465:                                         * x-coord corresponding to left edge
        !          3466:                                         * of canvas window). */
        !          3467:     int yOrigin;                       /* New Y origin for canvas (canvas
        !          3468:                                         * y-coord corresponding to top edge
        !          3469:                                         * of canvas window). */
        !          3470: {
        !          3471:     /*
        !          3472:      * Adjust the origin if necessary to keep as much as possible of the
        !          3473:      * canvas in the view.
        !          3474:      */
        !          3475: 
        !          3476:     if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
        !          3477:        int windowWidth, windowHeight, canvasWidth, canvasHeight;
        !          3478: 
        !          3479:        windowWidth = Tk_Width(canvasPtr->tkwin);
        !          3480:        windowHeight = Tk_Height(canvasPtr->tkwin);
        !          3481:        canvasWidth = canvasPtr->scrollX2 - canvasPtr->scrollX1;
        !          3482:        canvasHeight = canvasPtr->scrollY2 - canvasPtr->scrollY1;
        !          3483:        if (canvasWidth < windowWidth) {
        !          3484:            xOrigin = (canvasPtr->scrollX1) - (windowWidth-canvasWidth)/2;
        !          3485:        } else if (xOrigin < canvasPtr->scrollX1) {
        !          3486:            xOrigin = canvasPtr->scrollX1;
        !          3487:        } else if (xOrigin > (canvasPtr->scrollX2 - windowWidth)) {
        !          3488:            xOrigin = canvasPtr->scrollX2 - windowWidth;
        !          3489:        }
        !          3490:        if (canvasHeight < windowHeight) {
        !          3491:            yOrigin = (canvasPtr->scrollY1) - (windowHeight-canvasHeight)/2;
        !          3492:        } else if (yOrigin < canvasPtr->scrollY1) {
        !          3493:            yOrigin = canvasPtr->scrollY1;
        !          3494:        } else if (yOrigin > (canvasPtr->scrollY2 - windowHeight)) {
        !          3495:            yOrigin = canvasPtr->scrollY2 - windowHeight;
        !          3496:        }
        !          3497:     }
        !          3498: 
        !          3499:     if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
        !          3500:        return;
        !          3501:     }
        !          3502: 
        !          3503:     /*
        !          3504:      * Tricky point:  must redisplay not only everything that's visible
        !          3505:      * in the window's final configuration, but also everything that was
        !          3506:      * visible in the initial configuration.  This is needed because some
        !          3507:      * item types, like windows, need to know when they move off-screen
        !          3508:      * so they can explicitly undisplay themselves.
        !          3509:      */
        !          3510: 
        !          3511:     EventuallyRedrawArea(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin,
        !          3512:            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
        !          3513:            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
        !          3514:     canvasPtr->xOrigin = xOrigin;
        !          3515:     canvasPtr->yOrigin = yOrigin;
        !          3516:     canvasPtr->flags |= UPDATE_SCROLLBARS;
        !          3517:     EventuallyRedrawArea(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin,
        !          3518:            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
        !          3519:            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
        !          3520: }
        !          3521: 
        !          3522: /*
        !          3523:  *--------------------------------------------------------------
        !          3524:  *
        !          3525:  * CanvasTagsParseProc --
        !          3526:  *
        !          3527:  *     This procedure is invoked during option processing to handle
        !          3528:  *     "-tags" options for canvas items.
        !          3529:  *
        !          3530:  * Results:
        !          3531:  *     A standard Tcl return value.
        !          3532:  *
        !          3533:  * Side effects:
        !          3534:  *     The tags for a given item get replaced by those indicated
        !          3535:  *     in the value argument.
        !          3536:  *
        !          3537:  *--------------------------------------------------------------
        !          3538:  */
        !          3539: 
        !          3540:        /* ARGSUSED */
        !          3541: static int
        !          3542: CanvasTagsParseProc(clientData, interp, tkwin, value, widgRec, offset)
        !          3543:     ClientData clientData;             /* Not used.*/
        !          3544:     Tcl_Interp *interp;                        /* Used for reporting errors. */
        !          3545:     Tk_Window tkwin;                   /* Window containing canvas widget. */
        !          3546:     char *value;                       /* Value of option (list of tag
        !          3547:                                         * names). */
        !          3548:     char *widgRec;                     /* Pointer to record for item. */
        !          3549:     int offset;                                /* Offset into item (ignored). */
        !          3550: {
        !          3551:     register Tk_Item *itemPtr = (Tk_Item *) widgRec;
        !          3552:     int argc, i;
        !          3553:     char **argv;
        !          3554:     Tk_Uid *newPtr;
        !          3555: 
        !          3556:     /*
        !          3557:      * Break the value up into the individual tag names.
        !          3558:      */
        !          3559: 
        !          3560:     if (Tcl_SplitList(interp, value, &argc, &argv) != TCL_OK) {
        !          3561:        return TCL_ERROR;
        !          3562:     }
        !          3563: 
        !          3564:     /*
        !          3565:      * Make sure that there's enough space in the item to hold the
        !          3566:      * tag names.
        !          3567:      */
        !          3568: 
        !          3569:     if (itemPtr->tagSpace < argc) {
        !          3570:        newPtr = (Tk_Uid *) ckalloc((unsigned) (argc * sizeof(Tk_Uid)));
        !          3571:        for (i = itemPtr->numTags-1; i >= 0; i--) {
        !          3572:            newPtr[i] = itemPtr->tagPtr[i];
        !          3573:        }
        !          3574:        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        !          3575:            ckfree((char *) itemPtr->tagPtr);
        !          3576:        }
        !          3577:        itemPtr->tagPtr = newPtr;
        !          3578:        itemPtr->tagSpace = argc;
        !          3579:     }
        !          3580:     itemPtr->numTags = argc;
        !          3581:     for (i = 0; i < argc; i++) {
        !          3582:        itemPtr->tagPtr[i] = Tk_GetUid(argv[i]);
        !          3583:     }
        !          3584:     ckfree((char *) argv);
        !          3585:     return TCL_OK;
        !          3586: }
        !          3587: 
        !          3588: /*
        !          3589:  *--------------------------------------------------------------
        !          3590:  *
        !          3591:  * CanvasTagsPrintProc --
        !          3592:  *
        !          3593:  *     This procedure is invoked by the Tk configuration code
        !          3594:  *     to produce a printable string for the "-tags" configuration
        !          3595:  *     option for canvas items.
        !          3596:  *
        !          3597:  * Results:
        !          3598:  *     The return value is a string describing all the tags for
        !          3599:  *     the item referred to by "widgRec".  In addition, *freeProcPtr
        !          3600:  *     is filled in with the address of a procedure to call to free
        !          3601:  *     the result string when it's no longer needed (or NULL to
        !          3602:  *     indicate that the string doesn't need to be freed).
        !          3603:  *
        !          3604:  * Side effects:
        !          3605:  *     None.
        !          3606:  *
        !          3607:  *--------------------------------------------------------------
        !          3608:  */
        !          3609: 
        !          3610:        /* ARGSUSED */
        !          3611: static char *
        !          3612: CanvasTagsPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
        !          3613:     ClientData clientData;             /* Ignored. */
        !          3614:     Tk_Window tkwin;                   /* Window containing canvas widget. */
        !          3615:     char *widgRec;                     /* Pointer to record for item. */
        !          3616:     int offset;                                /* Ignored. */
        !          3617:     Tcl_FreeProc **freeProcPtr;                /* Pointer to variable to fill in with
        !          3618:                                         * information about how to reclaim
        !          3619:                                         * storage for return string. */
        !          3620: {
        !          3621:     register Tk_Item *itemPtr = (Tk_Item *) widgRec;
        !          3622: 
        !          3623:     if (itemPtr->numTags == 0) {
        !          3624:        *freeProcPtr = (Tcl_FreeProc *) NULL;
        !          3625:        return "";
        !          3626:     }
        !          3627:     if (itemPtr->numTags == 1) {
        !          3628:        *freeProcPtr = (Tcl_FreeProc *) NULL;
        !          3629:        return (char *) itemPtr->tagPtr[0];
        !          3630:     }
        !          3631:     *freeProcPtr = (Tcl_FreeProc *) free;
        !          3632:     return Tcl_Merge(itemPtr->numTags, (char **) itemPtr->tagPtr);
        !          3633: }

unix.superglobalmegacorp.com

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