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