OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkCanvas.c] - Diff between revs 579 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 579 Rev 1765
/*
/*
 * tkCanvas.c --
 * tkCanvas.c --
 *
 *
 *      This module implements canvas widgets for the Tk toolkit.
 *      This module implements canvas widgets for the Tk toolkit.
 *      A canvas displays a background and a collection of graphical
 *      A canvas displays a background and a collection of graphical
 *      objects such as rectangles, lines, and texts.
 *      objects such as rectangles, lines, and texts.
 *
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
 * Copyright (c) 1998 by Scriptics Corporation.
 * Copyright (c) 1998 by Scriptics Corporation.
 *
 *
 * See the file "license.terms" for information on usage and redistribution
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 *
 * RCS: @(#) $Id: tkCanvas.c,v 1.1.1.1 2002-01-16 10:25:51 markom Exp $
 * RCS: @(#) $Id: tkCanvas.c,v 1.1.1.1 2002-01-16 10:25:51 markom Exp $
 */
 */
 
 
#include "default.h"
#include "default.h"
#include "tkInt.h"
#include "tkInt.h"
#include "tkPort.h"
#include "tkPort.h"
#include "tkCanvas.h"
#include "tkCanvas.h"
 
 
/*
/*
 * See tkCanvas.h for key data structures used to implement canvases.
 * See tkCanvas.h for key data structures used to implement canvases.
 */
 */
 
 
/*
/*
 * The structure defined below is used to keep track of a tag search
 * The structure defined below is used to keep track of a tag search
 * in progress.  No field should be accessed by anyone other than
 * in progress.  No field should be accessed by anyone other than
 * StartTagSearch and NextItem.
 * StartTagSearch and NextItem.
 */
 */
 
 
typedef struct TagSearch {
typedef struct TagSearch {
    TkCanvas *canvasPtr;        /* Canvas widget being searched. */
    TkCanvas *canvasPtr;        /* Canvas widget being searched. */
    Tk_Uid tag;                 /* Tag to search for.   0 means return
    Tk_Uid tag;                 /* Tag to search for.   0 means return
                                 * all items. */
                                 * all items. */
    Tk_Item *currentPtr;        /* Pointer to last item returned. */
    Tk_Item *currentPtr;        /* Pointer to last item returned. */
    Tk_Item *lastPtr;           /* The item right before the currentPtr
    Tk_Item *lastPtr;           /* The item right before the currentPtr
                                 * is tracked so if the currentPtr is
                                 * is tracked so if the currentPtr is
                                 * deleted we don't have to start from the
                                 * deleted we don't have to start from the
                                 * beginning. */
                                 * beginning. */
    int searchOver;             /* Non-zero means NextItem should always
    int searchOver;             /* Non-zero means NextItem should always
                                 * return NULL. */
                                 * return NULL. */
} TagSearch;
} TagSearch;
 
 
/*
/*
 * Information used for argv parsing.
 * Information used for argv parsing.
 */
 */
 
 
static Tk_ConfigSpec configSpecs[] = {
static Tk_ConfigSpec configSpecs[] = {
    {TK_CONFIG_BORDER, "-background", "background", "Background",
    {TK_CONFIG_BORDER, "-background", "background", "Background",
        DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
        DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
        TK_CONFIG_COLOR_ONLY},
        TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_BORDER, "-background", "background", "Background",
    {TK_CONFIG_BORDER, "-background", "background", "Background",
        DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
        DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
        TK_CONFIG_MONO_ONLY},
        TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
        (char *) NULL, 0, 0},
        (char *) NULL, 0, 0},
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
        (char *) NULL, 0, 0},
        (char *) NULL, 0, 0},
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
        DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},
        DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},
    {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
    {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
        DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},
        DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},
    {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
    {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
        DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},
        DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
        DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},
        DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},
    {TK_CONFIG_PIXELS, "-height", "height", "Height",
    {TK_CONFIG_PIXELS, "-height", "height", "Height",
        DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},
        DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},
    {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
    {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
        "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
        "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
        Tk_Offset(TkCanvas, highlightBgColorPtr), 0},
        Tk_Offset(TkCanvas, highlightBgColorPtr), 0},
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
        DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},
        DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
        "HighlightThickness",
        "HighlightThickness",
        DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},
        DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},
    {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
    {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
        DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},
        DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
        DEF_CANVAS_INSERT_BD_COLOR,
        DEF_CANVAS_INSERT_BD_COLOR,
        Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},
        Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
        DEF_CANVAS_INSERT_BD_MONO,
        DEF_CANVAS_INSERT_BD_MONO,
        Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},
        Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
    {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
        DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},
        DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},
    {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
    {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
        DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0},
        DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0},
    {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
    {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
        DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0},
        DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0},
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
        DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},
        DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},
    {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
    {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
        DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
        DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
        TK_CONFIG_NULL_OK},
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
        DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
        DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
        TK_CONFIG_COLOR_ONLY},
        TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
        DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
        DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
        TK_CONFIG_MONO_ONLY},
        TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
        DEF_CANVAS_SELECT_BD_COLOR,
        DEF_CANVAS_SELECT_BD_COLOR,
        Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},
        Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
        DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
        DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
        TK_CONFIG_MONO_ONLY},
        TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
        DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
        DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
        TK_CONFIG_COLOR_ONLY},
        TK_CONFIG_COLOR_ONLY},
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
        DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
        DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
        TK_CONFIG_MONO_ONLY},
        TK_CONFIG_MONO_ONLY},
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
        DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
        DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
        TK_CONFIG_NULL_OK},
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_PIXELS, "-width", "width", "Width",
    {TK_CONFIG_PIXELS, "-width", "width", "Width",
        DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},
        DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},
    {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
    {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
        DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
        DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
        TK_CONFIG_NULL_OK},
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
    {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
        "ScrollIncrement",
        "ScrollIncrement",
        DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
        DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
        0},
        0},
    {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
    {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
        DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
        DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
        TK_CONFIG_NULL_OK},
        TK_CONFIG_NULL_OK},
    {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
    {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
        "ScrollIncrement",
        "ScrollIncrement",
        DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
        DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
        0},
        0},
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
        (char *) NULL, 0, 0}
        (char *) NULL, 0, 0}
};
};
 
 
/*
/*
 * List of all the item types known at present:
 * List of all the item types known at present:
 */
 */
 
 
static Tk_ItemType *typeList = NULL;    /* NULL means initialization hasn't
static Tk_ItemType *typeList = NULL;    /* NULL means initialization hasn't
                                         * been done yet. */
                                         * been done yet. */
 
 
/*
/*
 * Standard item types provided by Tk:
 * Standard item types provided by Tk:
 */
 */
 
 
extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;
extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;
extern Tk_ItemType tkOvalType, tkPolygonType;
extern Tk_ItemType tkOvalType, tkPolygonType;
extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
 
 
/*
/*
 * Various Tk_Uid's used by this module (set up during initialization):
 * Various Tk_Uid's used by this module (set up during initialization):
 */
 */
 
 
static Tk_Uid allUid = NULL;
static Tk_Uid allUid = NULL;
static Tk_Uid currentUid = NULL;
static Tk_Uid currentUid = NULL;
 
 
/*
/*
 * Statistics counters:
 * Statistics counters:
 */
 */
 
 
static int numIdSearches;
static int numIdSearches;
static int numSlowSearches;
static int numSlowSearches;
 
 
/*
/*
 * Prototypes for procedures defined later in this file:
 * Prototypes for procedures defined later in this file:
 */
 */
 
 
static void             CanvasBindProc _ANSI_ARGS_((ClientData clientData,
static void             CanvasBindProc _ANSI_ARGS_((ClientData clientData,
                            XEvent *eventPtr));
                            XEvent *eventPtr));
static void             CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
static void             CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
static void             CanvasCmdDeletedProc _ANSI_ARGS_((
static void             CanvasCmdDeletedProc _ANSI_ARGS_((
                            ClientData clientData));
                            ClientData clientData));
static void             CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,
                            XEvent *eventPtr));
                            XEvent *eventPtr));
static void             CanvasEventProc _ANSI_ARGS_((ClientData clientData,
static void             CanvasEventProc _ANSI_ARGS_((ClientData clientData,
                            XEvent *eventPtr));
                            XEvent *eventPtr));
static int              CanvasFetchSelection _ANSI_ARGS_((
static int              CanvasFetchSelection _ANSI_ARGS_((
                            ClientData clientData, int offset,
                            ClientData clientData, int offset,
                            char *buffer, int maxBytes));
                            char *buffer, int maxBytes));
static Tk_Item *        CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,
static Tk_Item *        CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,
                            double coords[2]));
                            double coords[2]));
static void             CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,
                            int gotFocus));
                            int gotFocus));
static void             CanvasLostSelection _ANSI_ARGS_((
static void             CanvasLostSelection _ANSI_ARGS_((
                            ClientData clientData));
                            ClientData clientData));
static void             CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,
                            Tk_Item *itemPtr, int index));
                            Tk_Item *itemPtr, int index));
static void             CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,
                            int xOrigin, int yOrigin));
                            int xOrigin, int yOrigin));
static void             CanvasUpdateScrollbars _ANSI_ARGS_((
static void             CanvasUpdateScrollbars _ANSI_ARGS_((
                            TkCanvas *canvasPtr));
                            TkCanvas *canvasPtr));
static int              CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
static int              CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
                            Tcl_Interp *interp, int argc, char **argv));
                            Tcl_Interp *interp, int argc, char **argv));
static void             CanvasWorldChanged _ANSI_ARGS_((
static void             CanvasWorldChanged _ANSI_ARGS_((
                            ClientData instanceData));
                            ClientData instanceData));
static int              ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
static int              ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
                            TkCanvas *canvasPtr, int argc, char **argv,
                            TkCanvas *canvasPtr, int argc, char **argv,
                            int flags));
                            int flags));
static void             DestroyCanvas _ANSI_ARGS_((char *memPtr));
static void             DestroyCanvas _ANSI_ARGS_((char *memPtr));
static void             DisplayCanvas _ANSI_ARGS_((ClientData clientData));
static void             DisplayCanvas _ANSI_ARGS_((ClientData clientData));
static void             DoItem _ANSI_ARGS_((Tcl_Interp *interp,
static void             DoItem _ANSI_ARGS_((Tcl_Interp *interp,
                            Tk_Item *itemPtr, Tk_Uid tag));
                            Tk_Item *itemPtr, Tk_Uid tag));
static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,
static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,
                            TkCanvas *canvasPtr, int argc, char **argv,
                            TkCanvas *canvasPtr, int argc, char **argv,
                            char *newTag, char *cmdName, char *option));
                            char *newTag, char *cmdName, char *option));
static int              FindArea _ANSI_ARGS_((Tcl_Interp *interp,
static int              FindArea _ANSI_ARGS_((Tcl_Interp *interp,
                            TkCanvas *canvasPtr, char **argv, Tk_Uid uid,
                            TkCanvas *canvasPtr, char **argv, Tk_Uid uid,
                            int enclosed));
                            int enclosed));
static double           GridAlign _ANSI_ARGS_((double coord, double spacing));
static double           GridAlign _ANSI_ARGS_((double coord, double spacing));
static void             InitCanvas _ANSI_ARGS_((void));
static void             InitCanvas _ANSI_ARGS_((void));
static Tk_Item *        NextItem _ANSI_ARGS_((TagSearch *searchPtr));
static Tk_Item *        NextItem _ANSI_ARGS_((TagSearch *searchPtr));
static void             PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,
                            XEvent *eventPtr));
                            XEvent *eventPtr));
static void             PrintScrollFractions _ANSI_ARGS_((int screen1,
static void             PrintScrollFractions _ANSI_ARGS_((int screen1,
                            int screen2, int object1, int object2,
                            int screen2, int object1, int object2,
                            char *string));
                            char *string));
static void             RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
static void             RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
                            char *tag, Tk_Item *prevPtr));
                            char *tag, Tk_Item *prevPtr));
static Tk_Item *        StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
static Tk_Item *        StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
                            char *tag, TagSearch *searchPtr));
                            char *tag, TagSearch *searchPtr));
 
 
/*
/*
 * The structure below defines canvas class behavior by means of procedures
 * The structure below defines canvas class behavior by means of procedures
 * that can be invoked from generic window code.
 * that can be invoked from generic window code.
 */
 */
 
 
static TkClassProcs canvasClass = {
static TkClassProcs canvasClass = {
    NULL,                       /* createProc. */
    NULL,                       /* createProc. */
    CanvasWorldChanged,         /* geometryProc. */
    CanvasWorldChanged,         /* geometryProc. */
    NULL                        /* modalProc. */
    NULL                        /* modalProc. */
};
};
 
 


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * Tk_CanvasCmd --
 * Tk_CanvasCmd --
 *
 *
 *      This procedure is invoked to process the "canvas" Tcl
 *      This procedure is invoked to process the "canvas" Tcl
 *      command.  See the user documentation for details on what
 *      command.  See the user documentation for details on what
 *      it does.
 *      it does.
 *
 *
 * Results:
 * Results:
 *      A standard Tcl result.
 *      A standard Tcl result.
 *
 *
 * Side effects:
 * Side effects:
 *      See the user documentation.
 *      See the user documentation.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
int
int
Tk_CanvasCmd(clientData, interp, argc, argv)
Tk_CanvasCmd(clientData, interp, argc, argv)
    ClientData clientData;              /* Main window associated with
    ClientData clientData;              /* Main window associated with
                                 * interpreter. */
                                 * interpreter. */
    Tcl_Interp *interp;         /* Current interpreter. */
    Tcl_Interp *interp;         /* Current interpreter. */
    int argc;                   /* Number of arguments. */
    int argc;                   /* Number of arguments. */
    char **argv;                /* Argument strings. */
    char **argv;                /* Argument strings. */
{
{
    Tk_Window tkwin = (Tk_Window) clientData;
    Tk_Window tkwin = (Tk_Window) clientData;
    TkCanvas *canvasPtr;
    TkCanvas *canvasPtr;
    Tk_Window new;
    Tk_Window new;
 
 
    if (typeList == NULL) {
    if (typeList == NULL) {
        InitCanvas();
        InitCanvas();
    }
    }
 
 
    if (argc < 2) {
    if (argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_AppendResult(interp, "wrong # args: should be \"",
                argv[0], " pathName ?options?\"", (char *) NULL);
                argv[0], " pathName ?options?\"", (char *) NULL);
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
 
 
    new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
    new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
    if (new == NULL) {
    if (new == NULL) {
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
 
 
    /*
    /*
     * Initialize fields that won't be initialized by ConfigureCanvas,
     * Initialize fields that won't be initialized by ConfigureCanvas,
     * or which ConfigureCanvas expects to have reasonable values
     * or which ConfigureCanvas expects to have reasonable values
     * (e.g. resource pointers).
     * (e.g. resource pointers).
     */
     */
 
 
    canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));
    canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));
    canvasPtr->tkwin = new;
    canvasPtr->tkwin = new;
    canvasPtr->display = Tk_Display(new);
    canvasPtr->display = Tk_Display(new);
    canvasPtr->interp = interp;
    canvasPtr->interp = interp;
    canvasPtr->widgetCmd = Tcl_CreateCommand(interp,
    canvasPtr->widgetCmd = Tcl_CreateCommand(interp,
            Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
            Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
            (ClientData) canvasPtr, CanvasCmdDeletedProc);
            (ClientData) canvasPtr, CanvasCmdDeletedProc);
    canvasPtr->firstItemPtr = NULL;
    canvasPtr->firstItemPtr = NULL;
    canvasPtr->lastItemPtr = NULL;
    canvasPtr->lastItemPtr = NULL;
    canvasPtr->borderWidth = 0;
    canvasPtr->borderWidth = 0;
    canvasPtr->bgBorder = NULL;
    canvasPtr->bgBorder = NULL;
    canvasPtr->relief = TK_RELIEF_FLAT;
    canvasPtr->relief = TK_RELIEF_FLAT;
    canvasPtr->highlightWidth = 0;
    canvasPtr->highlightWidth = 0;
    canvasPtr->highlightBgColorPtr = NULL;
    canvasPtr->highlightBgColorPtr = NULL;
    canvasPtr->highlightColorPtr = NULL;
    canvasPtr->highlightColorPtr = NULL;
    canvasPtr->inset = 0;
    canvasPtr->inset = 0;
    canvasPtr->pixmapGC = None;
    canvasPtr->pixmapGC = None;
    canvasPtr->width = None;
    canvasPtr->width = None;
    canvasPtr->height = None;
    canvasPtr->height = None;
    canvasPtr->confine = 0;
    canvasPtr->confine = 0;
    canvasPtr->textInfo.selBorder = NULL;
    canvasPtr->textInfo.selBorder = NULL;
    canvasPtr->textInfo.selBorderWidth = 0;
    canvasPtr->textInfo.selBorderWidth = 0;
    canvasPtr->textInfo.selFgColorPtr = NULL;
    canvasPtr->textInfo.selFgColorPtr = NULL;
    canvasPtr->textInfo.selItemPtr = NULL;
    canvasPtr->textInfo.selItemPtr = NULL;
    canvasPtr->textInfo.selectFirst = -1;
    canvasPtr->textInfo.selectFirst = -1;
    canvasPtr->textInfo.selectLast = -1;
    canvasPtr->textInfo.selectLast = -1;
    canvasPtr->textInfo.anchorItemPtr = NULL;
    canvasPtr->textInfo.anchorItemPtr = NULL;
    canvasPtr->textInfo.selectAnchor = 0;
    canvasPtr->textInfo.selectAnchor = 0;
    canvasPtr->textInfo.insertBorder = NULL;
    canvasPtr->textInfo.insertBorder = NULL;
    canvasPtr->textInfo.insertWidth = 0;
    canvasPtr->textInfo.insertWidth = 0;
    canvasPtr->textInfo.insertBorderWidth = 0;
    canvasPtr->textInfo.insertBorderWidth = 0;
    canvasPtr->textInfo.focusItemPtr = NULL;
    canvasPtr->textInfo.focusItemPtr = NULL;
    canvasPtr->textInfo.gotFocus = 0;
    canvasPtr->textInfo.gotFocus = 0;
    canvasPtr->textInfo.cursorOn = 0;
    canvasPtr->textInfo.cursorOn = 0;
    canvasPtr->insertOnTime = 0;
    canvasPtr->insertOnTime = 0;
    canvasPtr->insertOffTime = 0;
    canvasPtr->insertOffTime = 0;
    canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
    canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
    canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
    canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
    canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
    canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
    canvasPtr->bindingTable = NULL;
    canvasPtr->bindingTable = NULL;
    canvasPtr->currentItemPtr = NULL;
    canvasPtr->currentItemPtr = NULL;
    canvasPtr->newCurrentPtr = NULL;
    canvasPtr->newCurrentPtr = NULL;
    canvasPtr->closeEnough = 0.0;
    canvasPtr->closeEnough = 0.0;
    canvasPtr->pickEvent.type = LeaveNotify;
    canvasPtr->pickEvent.type = LeaveNotify;
    canvasPtr->pickEvent.xcrossing.x = 0;
    canvasPtr->pickEvent.xcrossing.x = 0;
    canvasPtr->pickEvent.xcrossing.y = 0;
    canvasPtr->pickEvent.xcrossing.y = 0;
    canvasPtr->state = 0;
    canvasPtr->state = 0;
    canvasPtr->xScrollCmd = NULL;
    canvasPtr->xScrollCmd = NULL;
    canvasPtr->yScrollCmd = NULL;
    canvasPtr->yScrollCmd = NULL;
    canvasPtr->scrollX1 = 0;
    canvasPtr->scrollX1 = 0;
    canvasPtr->scrollY1 = 0;
    canvasPtr->scrollY1 = 0;
    canvasPtr->scrollX2 = 0;
    canvasPtr->scrollX2 = 0;
    canvasPtr->scrollY2 = 0;
    canvasPtr->scrollY2 = 0;
    canvasPtr->regionString = NULL;
    canvasPtr->regionString = NULL;
    canvasPtr->xScrollIncrement = 0;
    canvasPtr->xScrollIncrement = 0;
    canvasPtr->yScrollIncrement = 0;
    canvasPtr->yScrollIncrement = 0;
    canvasPtr->scanX = 0;
    canvasPtr->scanX = 0;
    canvasPtr->scanXOrigin = 0;
    canvasPtr->scanXOrigin = 0;
    canvasPtr->scanY = 0;
    canvasPtr->scanY = 0;
    canvasPtr->scanYOrigin = 0;
    canvasPtr->scanYOrigin = 0;
    canvasPtr->hotPtr = NULL;
    canvasPtr->hotPtr = NULL;
    canvasPtr->hotPrevPtr = NULL;
    canvasPtr->hotPrevPtr = NULL;
    canvasPtr->cursor = None;
    canvasPtr->cursor = None;
    canvasPtr->takeFocus = NULL;
    canvasPtr->takeFocus = NULL;
    canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
    canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
    canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
    canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
    canvasPtr->flags = 0;
    canvasPtr->flags = 0;
    canvasPtr->nextId = 1;
    canvasPtr->nextId = 1;
    canvasPtr->psInfoPtr = NULL;
    canvasPtr->psInfoPtr = NULL;
    Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);
    Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);
 
 
    Tk_SetClass(canvasPtr->tkwin, "Canvas");
    Tk_SetClass(canvasPtr->tkwin, "Canvas");
    TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr);
    TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr);
    Tk_CreateEventHandler(canvasPtr->tkwin,
    Tk_CreateEventHandler(canvasPtr->tkwin,
            ExposureMask|StructureNotifyMask|FocusChangeMask,
            ExposureMask|StructureNotifyMask|FocusChangeMask,
            CanvasEventProc, (ClientData) canvasPtr);
            CanvasEventProc, (ClientData) canvasPtr);
    Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
    Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
            |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
            |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
            |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
            |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
            CanvasBindProc, (ClientData) canvasPtr);
            CanvasBindProc, (ClientData) canvasPtr);
    Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
    Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
            CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
            CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
    if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
    if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
        goto error;
        goto error;
    }
    }
 
 
    interp->result = Tk_PathName(canvasPtr->tkwin);
    interp->result = Tk_PathName(canvasPtr->tkwin);
    return TCL_OK;
    return TCL_OK;
 
 
    error:
    error:
    Tk_DestroyWindow(canvasPtr->tkwin);
    Tk_DestroyWindow(canvasPtr->tkwin);
    return TCL_ERROR;
    return TCL_ERROR;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasWidgetCmd --
 * CanvasWidgetCmd --
 *
 *
 *      This procedure is invoked to process the Tcl command
 *      This procedure is invoked to process the Tcl command
 *      that corresponds to a widget managed by this module.
 *      that corresponds to a widget managed by this module.
 *      See the user documentation for details on what it does.
 *      See the user documentation for details on what it does.
 *
 *
 * Results:
 * Results:
 *      A standard Tcl result.
 *      A standard Tcl result.
 *
 *
 * Side effects:
 * Side effects:
 *      See the user documentation.
 *      See the user documentation.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static int
static int
CanvasWidgetCmd(clientData, interp, argc, argv)
CanvasWidgetCmd(clientData, interp, argc, argv)
    ClientData clientData;              /* Information about canvas
    ClientData clientData;              /* Information about canvas
                                         * widget. */
                                         * widget. */
    Tcl_Interp *interp;                 /* Current interpreter. */
    Tcl_Interp *interp;                 /* Current interpreter. */
    int argc;                           /* Number of arguments. */
    int argc;                           /* Number of arguments. */
    char **argv;                        /* Argument strings. */
    char **argv;                        /* Argument strings. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    size_t length;
    size_t length;
    int c, result;
    int c, result;
    Tk_Item *itemPtr = NULL;            /* Initialization needed only to
    Tk_Item *itemPtr = NULL;            /* Initialization needed only to
                                         * prevent compiler warning. */
                                         * prevent compiler warning. */
    TagSearch search;
    TagSearch search;
 
 
    if (argc < 2) {
    if (argc < 2) {
        Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_AppendResult(interp, "wrong # args: should be \"",
                argv[0], " option ?arg arg ...?\"", (char *) NULL);
                argv[0], " option ?arg arg ...?\"", (char *) NULL);
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
    Tcl_Preserve((ClientData) canvasPtr);
    Tcl_Preserve((ClientData) canvasPtr);
    result = TCL_OK;
    result = TCL_OK;
    c = argv[1][0];
    c = argv[1][0];
    length = strlen(argv[1]);
    length = strlen(argv[1]);
    if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) {
    if ((c == 'a') && (strncmp(argv[1], "addtag", length) == 0)) {
        if (argc < 4) {
        if (argc < 4) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " addtags tag searchCommand ?arg arg ...?\"",
                    argv[0], " addtags tag searchCommand ?arg arg ...?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0],
        result = FindItems(interp, canvasPtr, argc-3, argv+3, argv[2], argv[0],
                " addtag tag");
                " addtag tag");
    } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)
    } else if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        int i, gotAny;
        int i, gotAny;
        int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed
        int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed
                                                 * only to prevent compiler
                                                 * only to prevent compiler
                                                 * warnings. */
                                                 * warnings. */
 
 
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " bbox tagOrId ?tagOrId ...?\"",
                    argv[0], " bbox tagOrId ?tagOrId ...?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        gotAny = 0;
        gotAny = 0;
        for (i = 2; i < argc; i++) {
        for (i = 2; i < argc; i++) {
            for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
            for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                if ((itemPtr->x1 >= itemPtr->x2)
                if ((itemPtr->x1 >= itemPtr->x2)
                        || (itemPtr->y1 >= itemPtr->y2)) {
                        || (itemPtr->y1 >= itemPtr->y2)) {
                    continue;
                    continue;
                }
                }
                if (!gotAny) {
                if (!gotAny) {
                    x1 = itemPtr->x1;
                    x1 = itemPtr->x1;
                    y1 = itemPtr->y1;
                    y1 = itemPtr->y1;
                    x2 = itemPtr->x2;
                    x2 = itemPtr->x2;
                    y2 = itemPtr->y2;
                    y2 = itemPtr->y2;
                    gotAny = 1;
                    gotAny = 1;
                } else {
                } else {
                    if (itemPtr->x1 < x1) {
                    if (itemPtr->x1 < x1) {
                        x1 = itemPtr->x1;
                        x1 = itemPtr->x1;
                    }
                    }
                    if (itemPtr->y1 < y1) {
                    if (itemPtr->y1 < y1) {
                        y1 = itemPtr->y1;
                        y1 = itemPtr->y1;
                    }
                    }
                    if (itemPtr->x2 > x2) {
                    if (itemPtr->x2 > x2) {
                        x2 = itemPtr->x2;
                        x2 = itemPtr->x2;
                    }
                    }
                    if (itemPtr->y2 > y2) {
                    if (itemPtr->y2 > y2) {
                        y2 = itemPtr->y2;
                        y2 = itemPtr->y2;
                    }
                    }
                }
                }
            }
            }
        }
        }
        if (gotAny) {
        if (gotAny) {
            sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2);
            sprintf(interp->result, "%d %d %d %d", x1, y1, x2, y2);
        }
        }
    } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)
    } else if ((c == 'b') && (strncmp(argv[1], "bind", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        ClientData object;
        ClientData object;
 
 
        if ((argc < 3) || (argc > 5)) {
        if ((argc < 3) || (argc > 5)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " bind tagOrId ?sequence? ?command?\"",
                    argv[0], " bind tagOrId ?sequence? ?command?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
 
 
        /*
        /*
         * Figure out what object to use for the binding (individual
         * Figure out what object to use for the binding (individual
         * item vs. tag).
         * item vs. tag).
         */
         */
 
 
        object = 0;
        object = 0;
        if (isdigit(UCHAR(argv[2][0]))) {
        if (isdigit(UCHAR(argv[2][0]))) {
            int id;
            int id;
            char *end;
            char *end;
            Tcl_HashEntry *entryPtr;
            Tcl_HashEntry *entryPtr;
 
 
            id = strtoul(argv[2], &end, 0);
            id = strtoul(argv[2], &end, 0);
            if (*end != 0) {
            if (*end != 0) {
                goto bindByTag;
                goto bindByTag;
            }
            }
            entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
            entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
            if (entryPtr != NULL) {
            if (entryPtr != NULL) {
                itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
                itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
                object = (ClientData) itemPtr;
                object = (ClientData) itemPtr;
            }
            }
 
 
            if (object == 0) {
            if (object == 0) {
                Tcl_AppendResult(interp, "item \"", argv[2],
                Tcl_AppendResult(interp, "item \"", argv[2],
                        "\" doesn't exist", (char *) NULL);
                        "\" doesn't exist", (char *) NULL);
                goto error;
                goto error;
            }
            }
        } else {
        } else {
            bindByTag:
            bindByTag:
            object = (ClientData) Tk_GetUid(argv[2]);
            object = (ClientData) Tk_GetUid(argv[2]);
        }
        }
 
 
        /*
        /*
         * Make a binding table if the canvas doesn't already have
         * Make a binding table if the canvas doesn't already have
         * one.
         * one.
         */
         */
 
 
        if (canvasPtr->bindingTable == NULL) {
        if (canvasPtr->bindingTable == NULL) {
            canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
            canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
        }
        }
 
 
        if (argc == 5) {
        if (argc == 5) {
            int append = 0;
            int append = 0;
            unsigned long mask;
            unsigned long mask;
 
 
            if (argv[4][0] == 0) {
            if (argv[4][0] == 0) {
                result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
                result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
                        object, argv[3]);
                        object, argv[3]);
                goto done;
                goto done;
            }
            }
            if (argv[4][0] == '+') {
            if (argv[4][0] == '+') {
                argv[4]++;
                argv[4]++;
                append = 1;
                append = 1;
            }
            }
            mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
            mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
                    object, argv[3], argv[4], append);
                    object, argv[3], argv[4], append);
            if (mask == 0) {
            if (mask == 0) {
                goto error;
                goto error;
            }
            }
            if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
            if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
                    |Button2MotionMask|Button3MotionMask|Button4MotionMask
                    |Button2MotionMask|Button3MotionMask|Button4MotionMask
                    |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
                    |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
                    |EnterWindowMask|LeaveWindowMask|KeyPressMask
                    |EnterWindowMask|LeaveWindowMask|KeyPressMask
                    |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
                    |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
                Tk_DeleteBinding(interp, canvasPtr->bindingTable,
                Tk_DeleteBinding(interp, canvasPtr->bindingTable,
                        object, argv[3]);
                        object, argv[3]);
                Tcl_ResetResult(interp);
                Tcl_ResetResult(interp);
                Tcl_AppendResult(interp, "requested illegal events; ",
                Tcl_AppendResult(interp, "requested illegal events; ",
                        "only key, button, motion, enter, leave, and virtual ",
                        "only key, button, motion, enter, leave, and virtual ",
                        "events may be used", (char *) NULL);
                        "events may be used", (char *) NULL);
                goto error;
                goto error;
            }
            }
        } else if (argc == 4) {
        } else if (argc == 4) {
            char *command;
            char *command;
 
 
            command = Tk_GetBinding(interp, canvasPtr->bindingTable,
            command = Tk_GetBinding(interp, canvasPtr->bindingTable,
                    object, argv[3]);
                    object, argv[3]);
            if (command == NULL) {
            if (command == NULL) {
                goto error;
                goto error;
            }
            }
            interp->result = command;
            interp->result = command;
        } else {
        } else {
            Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
            Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
        }
        }
    } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) {
    } else if ((c == 'c') && (strcmp(argv[1], "canvasx") == 0)) {
        int x;
        int x;
        double grid;
        double grid;
 
 
        if ((argc < 3) || (argc > 4)) {
        if ((argc < 3) || (argc > 4)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " canvasx screenx ?gridspacing?\"",
                    argv[0], " canvasx screenx ?gridspacing?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {
        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {
            goto error;
            goto error;
        }
        }
        if (argc == 4) {
        if (argc == 4) {
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
                    &grid) != TCL_OK) {
                    &grid) != TCL_OK) {
                goto error;
                goto error;
            }
            }
        } else {
        } else {
            grid = 0.0;
            grid = 0.0;
        }
        }
        x += canvasPtr->xOrigin;
        x += canvasPtr->xOrigin;
        Tcl_PrintDouble(interp, GridAlign((double) x, grid), interp->result);
        Tcl_PrintDouble(interp, GridAlign((double) x, grid), interp->result);
    } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) {
    } else if ((c == 'c') && (strcmp(argv[1], "canvasy") == 0)) {
        int y;
        int y;
        double grid;
        double grid;
 
 
        if ((argc < 3) || (argc > 4)) {
        if ((argc < 3) || (argc > 4)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " canvasy screeny ?gridspacing?\"",
                    argv[0], " canvasy screeny ?gridspacing?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {
        if (Tk_GetPixels(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {
            goto error;
            goto error;
        }
        }
        if (argc == 4) {
        if (argc == 4) {
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
                    argv[3], &grid) != TCL_OK) {
                    argv[3], &grid) != TCL_OK) {
                goto error;
                goto error;
            }
            }
        } else {
        } else {
            grid = 0.0;
            grid = 0.0;
        }
        }
        y += canvasPtr->yOrigin;
        y += canvasPtr->yOrigin;
        Tcl_PrintDouble(interp, GridAlign((double) y, grid), interp->result);
        Tcl_PrintDouble(interp, GridAlign((double) y, grid), interp->result);
    } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
    } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        if (argc != 3) {
        if (argc != 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " cget option\"",
                    argv[0], " cget option\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
        result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
                (char *) canvasPtr, argv[2], 0);
                (char *) canvasPtr, argv[2], 0);
    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        if (argc == 2) {
        if (argc == 2) {
            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
                    (char *) canvasPtr, (char *) NULL, 0);
                    (char *) canvasPtr, (char *) NULL, 0);
        } else if (argc == 3) {
        } else if (argc == 3) {
            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
            result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
                    (char *) canvasPtr, argv[2], 0);
                    (char *) canvasPtr, argv[2], 0);
        } else {
        } else {
            result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,
            result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,
                    TK_CONFIG_ARGV_ONLY);
                    TK_CONFIG_ARGV_ONLY);
        }
        }
    } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)
    } else if ((c == 'c') && (strncmp(argv[1], "coords", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " coords tagOrId ?x y x y ...?\"",
                    argv[0], " coords tagOrId ?x y x y ...?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr != NULL) {
        if (itemPtr != NULL) {
            if (argc != 3) {
            if (argc != 3) {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
            }
            if (itemPtr->typePtr->coordProc != NULL) {
            if (itemPtr->typePtr->coordProc != NULL) {
                result = (*itemPtr->typePtr->coordProc)(interp,
                result = (*itemPtr->typePtr->coordProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
            }
            }
            if (argc != 3) {
            if (argc != 3) {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
            }
        }
        }
    } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)
    } else if ((c == 'c') && (strncmp(argv[1], "create", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        Tk_ItemType *typePtr;
        Tk_ItemType *typePtr;
        Tk_ItemType *matchPtr = NULL;
        Tk_ItemType *matchPtr = NULL;
        Tk_Item *itemPtr;
        Tk_Item *itemPtr;
        int isNew = 0;
        int isNew = 0;
        Tcl_HashEntry *entryPtr;
        Tcl_HashEntry *entryPtr;
 
 
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " create type ?arg arg ...?\"", (char *) NULL);
                    argv[0], " create type ?arg arg ...?\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        c = argv[2][0];
        c = argv[2][0];
        length = strlen(argv[2]);
        length = strlen(argv[2]);
        for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
        for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
            if ((c == typePtr->name[0])
            if ((c == typePtr->name[0])
                    && (strncmp(argv[2], typePtr->name, length) == 0)) {
                    && (strncmp(argv[2], typePtr->name, length) == 0)) {
                if (matchPtr != NULL) {
                if (matchPtr != NULL) {
                    badType:
                    badType:
                    Tcl_AppendResult(interp,
                    Tcl_AppendResult(interp,
                            "unknown or ambiguous item type \"",
                            "unknown or ambiguous item type \"",
                            argv[2], "\"", (char *) NULL);
                            argv[2], "\"", (char *) NULL);
                    goto error;
                    goto error;
                }
                }
                matchPtr = typePtr;
                matchPtr = typePtr;
            }
            }
        }
        }
        if (matchPtr == NULL) {
        if (matchPtr == NULL) {
            goto badType;
            goto badType;
        }
        }
        typePtr = matchPtr;
        typePtr = matchPtr;
        itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
        itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
        itemPtr->id = canvasPtr->nextId;
        itemPtr->id = canvasPtr->nextId;
        canvasPtr->nextId++;
        canvasPtr->nextId++;
        itemPtr->tagPtr = itemPtr->staticTagSpace;
        itemPtr->tagPtr = itemPtr->staticTagSpace;
        itemPtr->tagSpace = TK_TAG_SPACE;
        itemPtr->tagSpace = TK_TAG_SPACE;
        itemPtr->numTags = 0;
        itemPtr->numTags = 0;
        itemPtr->typePtr = typePtr;
        itemPtr->typePtr = typePtr;
        if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
        if ((*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
                itemPtr, argc-3, argv+3) != TCL_OK) {
                itemPtr, argc-3, argv+3) != TCL_OK) {
            ckfree((char *) itemPtr);
            ckfree((char *) itemPtr);
            goto error;
            goto error;
        }
        }
        itemPtr->nextPtr = NULL;
        itemPtr->nextPtr = NULL;
        entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,
        entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,
                (char *) itemPtr->id, &isNew);
                (char *) itemPtr->id, &isNew);
        Tcl_SetHashValue(entryPtr, itemPtr);
        Tcl_SetHashValue(entryPtr, itemPtr);
        itemPtr->prevPtr = canvasPtr->lastItemPtr;
        itemPtr->prevPtr = canvasPtr->lastItemPtr;
        canvasPtr->hotPtr = itemPtr;
        canvasPtr->hotPtr = itemPtr;
        canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
        canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
        if (canvasPtr->lastItemPtr == NULL) {
        if (canvasPtr->lastItemPtr == NULL) {
            canvasPtr->firstItemPtr = itemPtr;
            canvasPtr->firstItemPtr = itemPtr;
        } else {
        } else {
            canvasPtr->lastItemPtr->nextPtr = itemPtr;
            canvasPtr->lastItemPtr->nextPtr = itemPtr;
        }
        }
        canvasPtr->lastItemPtr = itemPtr;
        canvasPtr->lastItemPtr = itemPtr;
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        canvasPtr->flags |= REPICK_NEEDED;
        canvasPtr->flags |= REPICK_NEEDED;
        sprintf(interp->result, "%d", itemPtr->id);
        sprintf(interp->result, "%d", itemPtr->id);
    } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0)
    } else if ((c == 'd') && (strncmp(argv[1], "dchars", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        int first, last;
        int first, last;
 
 
        if ((argc != 4) && (argc != 5)) {
        if ((argc != 4) && (argc != 5)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " dchars tagOrId first ?last?\"",
                    argv[0], " dchars tagOrId first ?last?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if ((itemPtr->typePtr->indexProc == NULL)
            if ((itemPtr->typePtr->indexProc == NULL)
                    || (itemPtr->typePtr->dCharsProc == NULL)) {
                    || (itemPtr->typePtr->dCharsProc == NULL)) {
                continue;
                continue;
            }
            }
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
                    itemPtr, argv[3], &first) != TCL_OK) {
                    itemPtr, argv[3], &first) != TCL_OK) {
                goto error;
                goto error;
            }
            }
            if (argc == 5) {
            if (argc == 5) {
                if ((*itemPtr->typePtr->indexProc)(interp,
                if ((*itemPtr->typePtr->indexProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argv[4], &last)
                        (Tk_Canvas) canvasPtr, itemPtr, argv[4], &last)
                        != TCL_OK) {
                        != TCL_OK) {
                    goto error;
                    goto error;
                }
                }
            } else {
            } else {
                last = first;
                last = first;
            }
            }
 
 
            /*
            /*
             * Redraw both item's old and new areas:  it's possible
             * Redraw both item's old and new areas:  it's possible
             * that a delete could result in a new area larger than
             * that a delete could result in a new area larger than
             * the old area.
             * the old area.
             */
             */
 
 
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
            (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
                    itemPtr, first, last);
                    itemPtr, first, last);
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
        }
    } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)
    } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        int i;
        int i;
        Tcl_HashEntry *entryPtr;
        Tcl_HashEntry *entryPtr;
 
 
        for (i = 2; i < argc; i++) {
        for (i = 2; i < argc; i++) {
            for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
            for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                if (canvasPtr->bindingTable != NULL) {
                if (canvasPtr->bindingTable != NULL) {
                    Tk_DeleteAllBindings(canvasPtr->bindingTable,
                    Tk_DeleteAllBindings(canvasPtr->bindingTable,
                            (ClientData) itemPtr);
                            (ClientData) itemPtr);
                }
                }
                (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
                (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
                        canvasPtr->display);
                        canvasPtr->display);
                if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
                if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
                    ckfree((char *) itemPtr->tagPtr);
                    ckfree((char *) itemPtr->tagPtr);
                }
                }
                entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
                entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
                        (char *) itemPtr->id);
                        (char *) itemPtr->id);
                Tcl_DeleteHashEntry(entryPtr);
                Tcl_DeleteHashEntry(entryPtr);
                if (itemPtr->nextPtr != NULL) {
                if (itemPtr->nextPtr != NULL) {
                    itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
                    itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
                }
                }
                if (itemPtr->prevPtr != NULL) {
                if (itemPtr->prevPtr != NULL) {
                    itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
                    itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
                }
                }
                if (canvasPtr->firstItemPtr == itemPtr) {
                if (canvasPtr->firstItemPtr == itemPtr) {
                    canvasPtr->firstItemPtr = itemPtr->nextPtr;
                    canvasPtr->firstItemPtr = itemPtr->nextPtr;
                    if (canvasPtr->firstItemPtr == NULL) {
                    if (canvasPtr->firstItemPtr == NULL) {
                        canvasPtr->lastItemPtr = NULL;
                        canvasPtr->lastItemPtr = NULL;
                    }
                    }
                }
                }
                if (canvasPtr->lastItemPtr == itemPtr) {
                if (canvasPtr->lastItemPtr == itemPtr) {
                    canvasPtr->lastItemPtr = itemPtr->prevPtr;
                    canvasPtr->lastItemPtr = itemPtr->prevPtr;
                }
                }
                ckfree((char *) itemPtr);
                ckfree((char *) itemPtr);
                if (itemPtr == canvasPtr->currentItemPtr) {
                if (itemPtr == canvasPtr->currentItemPtr) {
                    canvasPtr->currentItemPtr = NULL;
                    canvasPtr->currentItemPtr = NULL;
                    canvasPtr->flags |= REPICK_NEEDED;
                    canvasPtr->flags |= REPICK_NEEDED;
                }
                }
                if (itemPtr == canvasPtr->newCurrentPtr) {
                if (itemPtr == canvasPtr->newCurrentPtr) {
                    canvasPtr->newCurrentPtr = NULL;
                    canvasPtr->newCurrentPtr = NULL;
                    canvasPtr->flags |= REPICK_NEEDED;
                    canvasPtr->flags |= REPICK_NEEDED;
                }
                }
                if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
                if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
                    canvasPtr->textInfo.focusItemPtr = NULL;
                    canvasPtr->textInfo.focusItemPtr = NULL;
                }
                }
                if (itemPtr == canvasPtr->textInfo.selItemPtr) {
                if (itemPtr == canvasPtr->textInfo.selItemPtr) {
                    canvasPtr->textInfo.selItemPtr = NULL;
                    canvasPtr->textInfo.selItemPtr = NULL;
                }
                }
                if ((itemPtr == canvasPtr->hotPtr)
                if ((itemPtr == canvasPtr->hotPtr)
                        || (itemPtr == canvasPtr->hotPrevPtr)) {
                        || (itemPtr == canvasPtr->hotPrevPtr)) {
                    canvasPtr->hotPtr = NULL;
                    canvasPtr->hotPtr = NULL;
                }
                }
            }
            }
        }
        }
    } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0)
    } else if ((c == 'd') && (strncmp(argv[1], "dtag", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        Tk_Uid tag;
        Tk_Uid tag;
        int i;
        int i;
 
 
        if ((argc != 3) && (argc != 4)) {
        if ((argc != 3) && (argc != 4)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " dtag tagOrId ?tagToDelete?\"",
                    argv[0], " dtag tagOrId ?tagToDelete?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        if (argc == 4) {
        if (argc == 4) {
            tag = Tk_GetUid(argv[3]);
            tag = Tk_GetUid(argv[3]);
        } else {
        } else {
            tag = Tk_GetUid(argv[2]);
            tag = Tk_GetUid(argv[2]);
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            for (i = itemPtr->numTags-1; i >= 0; i--) {
            for (i = itemPtr->numTags-1; i >= 0; i--) {
                if (itemPtr->tagPtr[i] == tag) {
                if (itemPtr->tagPtr[i] == tag) {
                    itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
                    itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
                    itemPtr->numTags--;
                    itemPtr->numTags--;
                }
                }
            }
            }
        }
        }
    } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)
    } else if ((c == 'f') && (strncmp(argv[1], "find", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " find searchCommand ?arg arg ...?\"",
                    argv[0], " find searchCommand ?arg arg ...?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL,
        result = FindItems(interp, canvasPtr, argc-2, argv+2, (char *) NULL,
                argv[0]," find");
                argv[0]," find");
    } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0)
    } else if ((c == 'f') && (strncmp(argv[1], "focus", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        if (argc > 3) {
        if (argc > 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " focus ?tagOrId?\"",
                    argv[0], " focus ?tagOrId?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        itemPtr = canvasPtr->textInfo.focusItemPtr;
        itemPtr = canvasPtr->textInfo.focusItemPtr;
        if (argc == 2) {
        if (argc == 2) {
            if (itemPtr != NULL) {
            if (itemPtr != NULL) {
                sprintf(interp->result, "%d", itemPtr->id);
                sprintf(interp->result, "%d", itemPtr->id);
            }
            }
            goto done;
            goto done;
        }
        }
        if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {
        if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
        }
        if (argv[2][0] == 0) {
        if (argv[2][0] == 0) {
            canvasPtr->textInfo.focusItemPtr = NULL;
            canvasPtr->textInfo.focusItemPtr = NULL;
            goto done;
            goto done;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if (itemPtr->typePtr->icursorProc != NULL) {
            if (itemPtr->typePtr->icursorProc != NULL) {
                break;
                break;
            }
            }
        }
        }
        if (itemPtr == NULL) {
        if (itemPtr == NULL) {
            goto done;
            goto done;
        }
        }
        canvasPtr->textInfo.focusItemPtr = itemPtr;
        canvasPtr->textInfo.focusItemPtr = itemPtr;
        if (canvasPtr->textInfo.gotFocus) {
        if (canvasPtr->textInfo.gotFocus) {
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
        }
    } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) {
    } else if ((c == 'g') && (strncmp(argv[1], "gettags", length) == 0)) {
        if (argc != 3) {
        if (argc != 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " gettags tagOrId\"", (char *) NULL);
                    argv[0], " gettags tagOrId\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr != NULL) {
        if (itemPtr != NULL) {
            int i;
            int i;
            for (i = 0; i < itemPtr->numTags; i++) {
            for (i = 0; i < itemPtr->numTags; i++) {
                Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]);
                Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]);
            }
            }
        }
        }
    } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
    } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        int index;
        int index;
 
 
        if (argc != 4) {
        if (argc != 4) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " icursor tagOrId index\"",
                    argv[0], " icursor tagOrId index\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if ((itemPtr->typePtr->indexProc == NULL)
            if ((itemPtr->typePtr->indexProc == NULL)
                    || (itemPtr->typePtr->icursorProc == NULL)) {
                    || (itemPtr->typePtr->icursorProc == NULL)) {
                goto done;
                goto done;
            }
            }
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
                    itemPtr, argv[3], &index) != TCL_OK) {
                    itemPtr, argv[3], &index) != TCL_OK) {
                goto error;
                goto error;
            }
            }
            (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr,
            (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr,
                    index);
                    index);
            if ((itemPtr == canvasPtr->textInfo.focusItemPtr)
            if ((itemPtr == canvasPtr->textInfo.focusItemPtr)
                    && (canvasPtr->textInfo.cursorOn)) {
                    && (canvasPtr->textInfo.cursorOn)) {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            }
            }
        }
        }
    } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
    } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        int index;
        int index;
 
 
        if (argc != 4) {
        if (argc != 4) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " index tagOrId string\"",
                    argv[0], " index tagOrId string\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if (itemPtr->typePtr->indexProc != NULL) {
            if (itemPtr->typePtr->indexProc != NULL) {
                break;
                break;
            }
            }
        }
        }
        if (itemPtr == NULL) {
        if (itemPtr == NULL) {
            Tcl_AppendResult(interp, "can't find an indexable item \"",
            Tcl_AppendResult(interp, "can't find an indexable item \"",
                    argv[2], "\"", (char *) NULL);
                    argv[2], "\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
        if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
                itemPtr, argv[3], &index) != TCL_OK) {
                itemPtr, argv[3], &index) != TCL_OK) {
            goto error;
            goto error;
        }
        }
        sprintf(interp->result, "%d", index);
        sprintf(interp->result, "%d", index);
    } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
    } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        int beforeThis;
        int beforeThis;
 
 
        if (argc != 5) {
        if (argc != 5) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " insert tagOrId beforeThis string\"",
                    argv[0], " insert tagOrId beforeThis string\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if ((itemPtr->typePtr->indexProc == NULL)
            if ((itemPtr->typePtr->indexProc == NULL)
                    || (itemPtr->typePtr->insertProc == NULL)) {
                    || (itemPtr->typePtr->insertProc == NULL)) {
                continue;
                continue;
            }
            }
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
                    itemPtr, argv[3], &beforeThis) != TCL_OK) {
                    itemPtr, argv[3], &beforeThis) != TCL_OK) {
                goto error;
                goto error;
            }
            }
 
 
            /*
            /*
             * Redraw both item's old and new areas:  it's possible
             * Redraw both item's old and new areas:  it's possible
             * that an insertion could result in a new area either
             * that an insertion could result in a new area either
             * larger or smaller than the old area.
             * larger or smaller than the old area.
             */
             */
 
 
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
            (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
                    itemPtr, beforeThis, argv[4]);
                    itemPtr, beforeThis, argv[4]);
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1,
                    itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->y1, itemPtr->x2, itemPtr->y2);
        }
        }
    } else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0)
    } else if ((c == 'i') && (strncmp(argv[1], "itemcget", length) == 0)
            && (length >= 6)) {
            && (length >= 6)) {
        if (argc != 4) {
        if (argc != 4) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " itemcget tagOrId option\"",
                    argv[0], " itemcget tagOrId option\"",
                    (char *) NULL);
                    (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr != NULL) {
        if (itemPtr != NULL) {
            result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
            result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
                    itemPtr->typePtr->configSpecs, (char *) itemPtr,
                    itemPtr->typePtr->configSpecs, (char *) itemPtr,
                    argv[3], 0);
                    argv[3], 0);
        }
        }
    } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0)
    } else if ((c == 'i') && (strncmp(argv[1], "itemconfigure", length) == 0)
            && (length >= 6)) {
            && (length >= 6)) {
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " itemconfigure tagOrId ?option value ...?\"",
                    argv[0], " itemconfigure tagOrId ?option value ...?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            if (argc == 3) {
            if (argc == 3) {
                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        (char *) NULL, 0);
                        (char *) NULL, 0);
            } else if (argc == 4) {
            } else if (argc == 4) {
                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
                result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        itemPtr->typePtr->configSpecs, (char *) itemPtr,
                        argv[3], 0);
                        argv[3], 0);
            } else {
            } else {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                result = (*itemPtr->typePtr->configProc)(interp,
                result = (*itemPtr->typePtr->configProc)(interp,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,
                        (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,
                        TK_CONFIG_ARGV_ONLY);
                        TK_CONFIG_ARGV_ONLY);
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                        itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                canvasPtr->flags |= REPICK_NEEDED;
                canvasPtr->flags |= REPICK_NEEDED;
            }
            }
            if ((result != TCL_OK) || (argc < 5)) {
            if ((result != TCL_OK) || (argc < 5)) {
                break;
                break;
            }
            }
        }
        }
    } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) {
    } else if ((c == 'l') && (strncmp(argv[1], "lower", length) == 0)) {
        Tk_Item *itemPtr;
        Tk_Item *itemPtr;
 
 
        if ((argc != 3) && (argc != 4)) {
        if ((argc != 3) && (argc != 4)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " lower tagOrId ?belowThis?\"",
                    argv[0], " lower tagOrId ?belowThis?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
 
 
        /*
        /*
         * First find the item just after which we'll insert the
         * First find the item just after which we'll insert the
         * named items.
         * named items.
         */
         */
 
 
        if (argc == 3) {
        if (argc == 3) {
            itemPtr = NULL;
            itemPtr = NULL;
        } else {
        } else {
            itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
            itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
            if (itemPtr == NULL) {
            if (itemPtr == NULL) {
                Tcl_AppendResult(interp, "tag \"", argv[3],
                Tcl_AppendResult(interp, "tag \"", argv[3],
                        "\" doesn't match any items", (char *) NULL);
                        "\" doesn't match any items", (char *) NULL);
                goto error;
                goto error;
            }
            }
            itemPtr = itemPtr->prevPtr;
            itemPtr = itemPtr->prevPtr;
        }
        }
        RelinkItems(canvasPtr, argv[2], itemPtr);
        RelinkItems(canvasPtr, argv[2], itemPtr);
    } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) {
    } else if ((c == 'm') && (strncmp(argv[1], "move", length) == 0)) {
        double xAmount, yAmount;
        double xAmount, yAmount;
 
 
        if (argc != 5) {
        if (argc != 5) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " move tagOrId xAmount yAmount\"",
                    argv[0], " move tagOrId xAmount yAmount\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
                &xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp,
                &xAmount) != TCL_OK) || (Tk_CanvasGetCoord(interp,
                (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) {
                (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) {
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
            (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
                    itemPtr,  xAmount, yAmount);
                    itemPtr,  xAmount, yAmount);
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            canvasPtr->flags |= REPICK_NEEDED;
            canvasPtr->flags |= REPICK_NEEDED;
        }
        }
    } else if ((c == 'p') && (strncmp(argv[1], "postscript", length) == 0)) {
    } else if ((c == 'p') && (strncmp(argv[1], "postscript", length) == 0)) {
        result = TkCanvPostscriptCmd(canvasPtr, interp, argc, argv);
        result = TkCanvPostscriptCmd(canvasPtr, interp, argc, argv);
    } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) {
    } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) {
        Tk_Item *prevPtr;
        Tk_Item *prevPtr;
 
 
        if ((argc != 3) && (argc != 4)) {
        if ((argc != 3) && (argc != 4)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " raise tagOrId ?aboveThis?\"",
                    argv[0], " raise tagOrId ?aboveThis?\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
 
 
        /*
        /*
         * First find the item just after which we'll insert the
         * First find the item just after which we'll insert the
         * named items.
         * named items.
         */
         */
 
 
        if (argc == 3) {
        if (argc == 3) {
            prevPtr = canvasPtr->lastItemPtr;
            prevPtr = canvasPtr->lastItemPtr;
        } else {
        } else {
            prevPtr = NULL;
            prevPtr = NULL;
            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                prevPtr = itemPtr;
                prevPtr = itemPtr;
            }
            }
            if (prevPtr == NULL) {
            if (prevPtr == NULL) {
                Tcl_AppendResult(interp, "tagOrId \"", argv[3],
                Tcl_AppendResult(interp, "tagOrId \"", argv[3],
                        "\" doesn't match any items", (char *) NULL);
                        "\" doesn't match any items", (char *) NULL);
                goto error;
                goto error;
            }
            }
        }
        }
        RelinkItems(canvasPtr, argv[2], prevPtr);
        RelinkItems(canvasPtr, argv[2], prevPtr);
    } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)
    } else if ((c == 's') && (strncmp(argv[1], "scale", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        double xOrigin, yOrigin, xScale, yScale;
        double xOrigin, yOrigin, xScale, yScale;
 
 
        if (argc != 7) {
        if (argc != 7) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"",
                    argv[0], " scale tagOrId xOrigin yOrigin xScale yScale\"",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
                    argv[3], &xOrigin) != TCL_OK)
                    argv[3], &xOrigin) != TCL_OK)
                || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
                || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr,
                    argv[4], &yOrigin) != TCL_OK)
                    argv[4], &yOrigin) != TCL_OK)
                || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK)
                || (Tcl_GetDouble(interp, argv[5], &xScale) != TCL_OK)
                || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) {
                || (Tcl_GetDouble(interp, argv[6], &yScale) != TCL_OK)) {
            goto error;
            goto error;
        }
        }
        if ((xScale == 0.0) || (yScale == 0.0)) {
        if ((xScale == 0.0) || (yScale == 0.0)) {
            interp->result = "scale factor cannot be zero";
            interp->result = "scale factor cannot be zero";
            goto error;
            goto error;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
            (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
                    itemPtr, xOrigin, yOrigin, xScale, yScale);
                    itemPtr, xOrigin, yOrigin, xScale, yScale);
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                    itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
            canvasPtr->flags |= REPICK_NEEDED;
            canvasPtr->flags |= REPICK_NEEDED;
        }
        }
    } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0)
    } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0)
            && (length >= 3)) {
            && (length >= 3)) {
        int x, y;
        int x, y;
 
 
        if (argc != 5) {
        if (argc != 5) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " scan mark|dragto x y\"", (char *) NULL);
                    argv[0], " scan mark|dragto x y\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
        if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
                || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
                || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
            goto error;
            goto error;
        }
        }
        if ((argv[2][0] == 'm')
        if ((argv[2][0] == 'm')
                && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
                && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
            canvasPtr->scanX = x;
            canvasPtr->scanX = x;
            canvasPtr->scanXOrigin = canvasPtr->xOrigin;
            canvasPtr->scanXOrigin = canvasPtr->xOrigin;
            canvasPtr->scanY = y;
            canvasPtr->scanY = y;
            canvasPtr->scanYOrigin = canvasPtr->yOrigin;
            canvasPtr->scanYOrigin = canvasPtr->yOrigin;
        } else if ((argv[2][0] == 'd')
        } else if ((argv[2][0] == 'd')
                && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
                && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
            int newXOrigin, newYOrigin, tmp;
            int newXOrigin, newYOrigin, tmp;
 
 
            /*
            /*
             * Compute a new view origin for the canvas, amplifying the
             * Compute a new view origin for the canvas, amplifying the
             * mouse motion.
             * mouse motion.
             */
             */
 
 
            tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX)
            tmp = canvasPtr->scanXOrigin - 10*(x - canvasPtr->scanX)
                    - canvasPtr->scrollX1;
                    - canvasPtr->scrollX1;
            newXOrigin = canvasPtr->scrollX1 + tmp;
            newXOrigin = canvasPtr->scrollX1 + tmp;
            tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY)
            tmp = canvasPtr->scanYOrigin - 10*(y - canvasPtr->scanY)
                    - canvasPtr->scrollY1;
                    - canvasPtr->scrollY1;
            newYOrigin = canvasPtr->scrollY1 + tmp;
            newYOrigin = canvasPtr->scrollY1 + tmp;
            CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
            CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
        } else {
        } else {
            Tcl_AppendResult(interp, "bad scan option \"", argv[2],
            Tcl_AppendResult(interp, "bad scan option \"", argv[2],
                    "\": must be mark or dragto", (char *) NULL);
                    "\": must be mark or dragto", (char *) NULL);
            goto error;
            goto error;
        }
        }
    } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0)
    } else if ((c == 's') && (strncmp(argv[1], "select", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        int index;
        int index;
 
 
        if (argc < 3) {
        if (argc < 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL);
                    argv[0], " select option ?tagOrId? ?arg?\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        if (argc >= 4) {
        if (argc >= 4) {
            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
            for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                    itemPtr != NULL; itemPtr = NextItem(&search)) {
                if ((itemPtr->typePtr->indexProc != NULL)
                if ((itemPtr->typePtr->indexProc != NULL)
                        && (itemPtr->typePtr->selectionProc != NULL)){
                        && (itemPtr->typePtr->selectionProc != NULL)){
                    break;
                    break;
                }
                }
            }
            }
            if (itemPtr == NULL) {
            if (itemPtr == NULL) {
                Tcl_AppendResult(interp,
                Tcl_AppendResult(interp,
                        "can't find an indexable and selectable item \"",
                        "can't find an indexable and selectable item \"",
                        argv[3], "\"", (char *) NULL);
                        argv[3], "\"", (char *) NULL);
                goto error;
                goto error;
            }
            }
        }
        }
        if (argc == 5) {
        if (argc == 5) {
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
            if ((*itemPtr->typePtr->indexProc)(interp, (Tk_Canvas) canvasPtr,
                    itemPtr, argv[4], &index) != TCL_OK) {
                    itemPtr, argv[4], &index) != TCL_OK) {
                goto error;
                goto error;
            }
            }
        }
        }
        length = strlen(argv[2]);
        length = strlen(argv[2]);
        c = argv[2][0];
        c = argv[2][0];
        if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
        if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
            if (argc != 5) {
            if (argc != 5) {
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                        argv[0], " select adjust tagOrId index\"",
                        argv[0], " select adjust tagOrId index\"",
                        (char *) NULL);
                        (char *) NULL);
                goto error;
                goto error;
            }
            }
            if (canvasPtr->textInfo.selItemPtr == itemPtr) {
            if (canvasPtr->textInfo.selItemPtr == itemPtr) {
                if (index < (canvasPtr->textInfo.selectFirst
                if (index < (canvasPtr->textInfo.selectFirst
                        + canvasPtr->textInfo.selectLast)/2) {
                        + canvasPtr->textInfo.selectLast)/2) {
                    canvasPtr->textInfo.selectAnchor =
                    canvasPtr->textInfo.selectAnchor =
                            canvasPtr->textInfo.selectLast + 1;
                            canvasPtr->textInfo.selectLast + 1;
                } else {
                } else {
                    canvasPtr->textInfo.selectAnchor =
                    canvasPtr->textInfo.selectAnchor =
                            canvasPtr->textInfo.selectFirst;
                            canvasPtr->textInfo.selectFirst;
                }
                }
            }
            }
            CanvasSelectTo(canvasPtr, itemPtr, index);
            CanvasSelectTo(canvasPtr, itemPtr, index);
        } else if ((c == 'c') && (argv[2] != NULL)
        } else if ((c == 'c') && (argv[2] != NULL)
                && (strncmp(argv[2], "clear", length) == 0)) {
                && (strncmp(argv[2], "clear", length) == 0)) {
            if (argc != 3) {
            if (argc != 3) {
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                        argv[0], " select clear\"", (char *) NULL);
                        argv[0], " select clear\"", (char *) NULL);
                goto error;
                goto error;
            }
            }
            if (canvasPtr->textInfo.selItemPtr != NULL) {
            if (canvasPtr->textInfo.selItemPtr != NULL) {
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                        canvasPtr->textInfo.selItemPtr->x1,
                        canvasPtr->textInfo.selItemPtr->x1,
                        canvasPtr->textInfo.selItemPtr->y1,
                        canvasPtr->textInfo.selItemPtr->y1,
                        canvasPtr->textInfo.selItemPtr->x2,
                        canvasPtr->textInfo.selItemPtr->x2,
                        canvasPtr->textInfo.selItemPtr->y2);
                        canvasPtr->textInfo.selItemPtr->y2);
                canvasPtr->textInfo.selItemPtr = NULL;
                canvasPtr->textInfo.selItemPtr = NULL;
            }
            }
            goto done;
            goto done;
        } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
        } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
            if (argc != 5) {
            if (argc != 5) {
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                        argv[0], " select from tagOrId index\"",
                        argv[0], " select from tagOrId index\"",
                        (char *) NULL);
                        (char *) NULL);
                goto error;
                goto error;
            }
            }
            canvasPtr->textInfo.anchorItemPtr = itemPtr;
            canvasPtr->textInfo.anchorItemPtr = itemPtr;
            canvasPtr->textInfo.selectAnchor = index;
            canvasPtr->textInfo.selectAnchor = index;
        } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) {
        } else if ((c == 'i') && (strncmp(argv[2], "item", length) == 0)) {
            if (argc != 3) {
            if (argc != 3) {
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                        argv[0], " select item\"", (char *) NULL);
                        argv[0], " select item\"", (char *) NULL);
                goto error;
                goto error;
            }
            }
            if (canvasPtr->textInfo.selItemPtr != NULL) {
            if (canvasPtr->textInfo.selItemPtr != NULL) {
                sprintf(interp->result, "%d",
                sprintf(interp->result, "%d",
                        canvasPtr->textInfo.selItemPtr->id);
                        canvasPtr->textInfo.selItemPtr->id);
            }
            }
        } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
        } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
            if (argc != 5) {
            if (argc != 5) {
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                Tcl_AppendResult(interp, "wrong # args: should be \"",
                        argv[0], " select to tagOrId index\"",
                        argv[0], " select to tagOrId index\"",
                        (char *) NULL);
                        (char *) NULL);
                goto error;
                goto error;
            }
            }
            CanvasSelectTo(canvasPtr, itemPtr, index);
            CanvasSelectTo(canvasPtr, itemPtr, index);
        } else {
        } else {
            Tcl_AppendResult(interp, "bad select option \"", argv[2],
            Tcl_AppendResult(interp, "bad select option \"", argv[2],
                    "\": must be adjust, clear, from, item, or to",
                    "\": must be adjust, clear, from, item, or to",
                    (char *) NULL);
                    (char *) NULL);
            goto error;
            goto error;
        }
        }
    } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) {
    } else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) {
        if (argc != 3) {
        if (argc != 3) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    argv[0], " type tag\"", (char *) NULL);
                    argv[0], " type tag\"", (char *) NULL);
            goto error;
            goto error;
        }
        }
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
        if (itemPtr != NULL) {
        if (itemPtr != NULL) {
            interp->result = itemPtr->typePtr->name;
            interp->result = itemPtr->typePtr->name;
        }
        }
    } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
    } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
        int count, type;
        int count, type;
        int newX = 0;            /* Initialization needed only to prevent
        int newX = 0;            /* Initialization needed only to prevent
                                 * gcc warnings. */
                                 * gcc warnings. */
        double fraction;
        double fraction;
 
 
        if (argc == 2) {
        if (argc == 2) {
            PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset,
            PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset,
                    canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
                    canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
                    - canvasPtr->inset, canvasPtr->scrollX1,
                    - canvasPtr->inset, canvasPtr->scrollX1,
                    canvasPtr->scrollX2, interp->result);
                    canvasPtr->scrollX2, interp->result);
        } else {
        } else {
            type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
            type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
            switch (type) {
            switch (type) {
                case TK_SCROLL_ERROR:
                case TK_SCROLL_ERROR:
                    goto error;
                    goto error;
                case TK_SCROLL_MOVETO:
                case TK_SCROLL_MOVETO:
                    newX = canvasPtr->scrollX1 - canvasPtr->inset
                    newX = canvasPtr->scrollX1 - canvasPtr->inset
                            + (int) (fraction * (canvasPtr->scrollX2
                            + (int) (fraction * (canvasPtr->scrollX2
                            - canvasPtr->scrollX1) + 0.5);
                            - canvasPtr->scrollX1) + 0.5);
                    break;
                    break;
                case TK_SCROLL_PAGES:
                case TK_SCROLL_PAGES:
                    newX = (int) (canvasPtr->xOrigin + count * .9
                    newX = (int) (canvasPtr->xOrigin + count * .9
                            * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
                            * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
                    break;
                    break;
                case TK_SCROLL_UNITS:
                case TK_SCROLL_UNITS:
                    if (canvasPtr->xScrollIncrement > 0) {
                    if (canvasPtr->xScrollIncrement > 0) {
                        newX = canvasPtr->xOrigin
                        newX = canvasPtr->xOrigin
                                + count*canvasPtr->xScrollIncrement;
                                + count*canvasPtr->xScrollIncrement;
                    } else {
                    } else {
                        newX = (int) (canvasPtr->xOrigin + count * .1
                        newX = (int) (canvasPtr->xOrigin + count * .1
                                * (Tk_Width(canvasPtr->tkwin)
                                * (Tk_Width(canvasPtr->tkwin)
                                - 2*canvasPtr->inset));
                                - 2*canvasPtr->inset));
                    }
                    }
                    break;
                    break;
            }
            }
            CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
            CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
        }
        }
    } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) {
    } else if ((c == 'y') && (strncmp(argv[1], "yview", length) == 0)) {
        int count, type;
        int count, type;
        int newY = 0;            /* Initialization needed only to prevent
        int newY = 0;            /* Initialization needed only to prevent
                                 * gcc warnings. */
                                 * gcc warnings. */
        double fraction;
        double fraction;
 
 
        if (argc == 2) {
        if (argc == 2) {
            PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset,
            PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset,
                    canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
                    canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
                    - canvasPtr->inset, canvasPtr->scrollY1,
                    - canvasPtr->inset, canvasPtr->scrollY1,
                    canvasPtr->scrollY2, interp->result);
                    canvasPtr->scrollY2, interp->result);
        } else {
        } else {
            type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
            type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
            switch (type) {
            switch (type) {
                case TK_SCROLL_ERROR:
                case TK_SCROLL_ERROR:
                    goto error;
                    goto error;
                case TK_SCROLL_MOVETO:
                case TK_SCROLL_MOVETO:
                    newY = canvasPtr->scrollY1 - canvasPtr->inset
                    newY = canvasPtr->scrollY1 - canvasPtr->inset
                            + (int) (fraction*(canvasPtr->scrollY2
                            + (int) (fraction*(canvasPtr->scrollY2
                            - canvasPtr->scrollY1) + 0.5);
                            - canvasPtr->scrollY1) + 0.5);
                    break;
                    break;
                case TK_SCROLL_PAGES:
                case TK_SCROLL_PAGES:
                    newY = (int) (canvasPtr->yOrigin + count * .9
                    newY = (int) (canvasPtr->yOrigin + count * .9
                            * (Tk_Height(canvasPtr->tkwin)
                            * (Tk_Height(canvasPtr->tkwin)
                            - 2*canvasPtr->inset));
                            - 2*canvasPtr->inset));
                    break;
                    break;
                case TK_SCROLL_UNITS:
                case TK_SCROLL_UNITS:
                    if (canvasPtr->yScrollIncrement > 0) {
                    if (canvasPtr->yScrollIncrement > 0) {
                        newY = canvasPtr->yOrigin
                        newY = canvasPtr->yOrigin
                                + count*canvasPtr->yScrollIncrement;
                                + count*canvasPtr->yScrollIncrement;
                    } else {
                    } else {
                        newY = (int) (canvasPtr->yOrigin + count * .1
                        newY = (int) (canvasPtr->yOrigin + count * .1
                                * (Tk_Height(canvasPtr->tkwin)
                                * (Tk_Height(canvasPtr->tkwin)
                                - 2*canvasPtr->inset));
                                - 2*canvasPtr->inset));
                    }
                    }
                    break;
                    break;
            }
            }
            CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
            CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
        }
        }
    } else {
    } else {
        Tcl_AppendResult(interp, "bad option \"", argv[1],
        Tcl_AppendResult(interp, "bad option \"", argv[1],
                "\": must be addtag, bbox, bind, ",
                "\": must be addtag, bbox, bind, ",
                "canvasx, canvasy, cget, configure, coords, create, ",
                "canvasx, canvasy, cget, configure, coords, create, ",
                "dchars, delete, dtag, find, focus, ",
                "dchars, delete, dtag, find, focus, ",
                "gettags, icursor, index, insert, itemcget, itemconfigure, ",
                "gettags, icursor, index, insert, itemcget, itemconfigure, ",
                "lower, move, postscript, raise, scale, scan, ",
                "lower, move, postscript, raise, scale, scan, ",
                "select, type, xview, or yview",
                "select, type, xview, or yview",
                (char *) NULL);
                (char *) NULL);
        goto error;
        goto error;
    }
    }
    done:
    done:
    Tcl_Release((ClientData) canvasPtr);
    Tcl_Release((ClientData) canvasPtr);
    return result;
    return result;
 
 
    error:
    error:
    Tcl_Release((ClientData) canvasPtr);
    Tcl_Release((ClientData) canvasPtr);
    return TCL_ERROR;
    return TCL_ERROR;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * DestroyCanvas --
 * DestroyCanvas --
 *
 *
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
 *      to clean up the internal structure of a canvas at a safe time
 *      to clean up the internal structure of a canvas at a safe time
 *      (when no-one is using it anymore).
 *      (when no-one is using it anymore).
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Everything associated with the canvas is freed up.
 *      Everything associated with the canvas is freed up.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
DestroyCanvas(memPtr)
DestroyCanvas(memPtr)
    char *memPtr;               /* Info about canvas widget. */
    char *memPtr;               /* Info about canvas widget. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) memPtr;
    TkCanvas *canvasPtr = (TkCanvas *) memPtr;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
 
 
    /*
    /*
     * Free up all of the items in the canvas.
     * Free up all of the items in the canvas.
     */
     */
 
 
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
            itemPtr = canvasPtr->firstItemPtr) {
            itemPtr = canvasPtr->firstItemPtr) {
        canvasPtr->firstItemPtr = itemPtr->nextPtr;
        canvasPtr->firstItemPtr = itemPtr->nextPtr;
        (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
        (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
                canvasPtr->display);
                canvasPtr->display);
        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
            ckfree((char *) itemPtr->tagPtr);
            ckfree((char *) itemPtr->tagPtr);
        }
        }
        ckfree((char *) itemPtr);
        ckfree((char *) itemPtr);
    }
    }
 
 
    /*
    /*
     * Free up all the stuff that requires special handling,
     * Free up all the stuff that requires special handling,
     * then let Tk_FreeOptions handle all the standard option-related
     * then let Tk_FreeOptions handle all the standard option-related
     * stuff.
     * stuff.
     */
     */
 
 
    Tcl_DeleteHashTable(&canvasPtr->idTable);
    Tcl_DeleteHashTable(&canvasPtr->idTable);
    if (canvasPtr->pixmapGC != None) {
    if (canvasPtr->pixmapGC != None) {
        Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
        Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
    }
    }
    Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
    Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
    if (canvasPtr->bindingTable != NULL) {
    if (canvasPtr->bindingTable != NULL) {
        Tk_DeleteBindingTable(canvasPtr->bindingTable);
        Tk_DeleteBindingTable(canvasPtr->bindingTable);
    }
    }
    Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
    Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
    ckfree((char *) canvasPtr);
    ckfree((char *) canvasPtr);
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * ConfigureCanvas --
 * ConfigureCanvas --
 *
 *
 *      This procedure is called to process an argv/argc list, plus
 *      This procedure is called to process an argv/argc list, plus
 *      the Tk option database, in order to configure (or
 *      the Tk option database, in order to configure (or
 *      reconfigure) a canvas widget.
 *      reconfigure) a canvas widget.
 *
 *
 * Results:
 * Results:
 *      The return value is a standard Tcl result.  If TCL_ERROR is
 *      The return value is a standard Tcl result.  If TCL_ERROR is
 *      returned, then interp->result contains an error message.
 *      returned, then interp->result contains an error message.
 *
 *
 * Side effects:
 * Side effects:
 *      Configuration information, such as colors, border width,
 *      Configuration information, such as colors, border width,
 *      etc. get set for canvasPtr;  old resources get freed,
 *      etc. get set for canvasPtr;  old resources get freed,
 *      if there were any.
 *      if there were any.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static int
static int
ConfigureCanvas(interp, canvasPtr, argc, argv, flags)
ConfigureCanvas(interp, canvasPtr, argc, argv, flags)
    Tcl_Interp *interp;         /* Used for error reporting. */
    Tcl_Interp *interp;         /* Used for error reporting. */
    TkCanvas *canvasPtr;        /* Information about widget;  may or may
    TkCanvas *canvasPtr;        /* Information about widget;  may or may
                                 * not already have values for some fields. */
                                 * not already have values for some fields. */
    int argc;                   /* Number of valid entries in argv. */
    int argc;                   /* Number of valid entries in argv. */
    char **argv;                /* Arguments. */
    char **argv;                /* Arguments. */
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
{
{
    XGCValues gcValues;
    XGCValues gcValues;
    GC new;
    GC new;
 
 
    if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
    if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
            argc, argv, (char *) canvasPtr, flags) != TCL_OK) {
            argc, argv, (char *) canvasPtr, flags) != TCL_OK) {
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
 
 
    /*
    /*
     * A few options need special processing, such as setting the
     * A few options need special processing, such as setting the
     * background from a 3-D border and creating a GC for copying
     * background from a 3-D border and creating a GC for copying
     * bits to the screen.
     * bits to the screen.
     */
     */
 
 
    Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
    Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
 
 
    if (canvasPtr->highlightWidth < 0) {
    if (canvasPtr->highlightWidth < 0) {
        canvasPtr->highlightWidth = 0;
        canvasPtr->highlightWidth = 0;
    }
    }
    canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
    canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
 
 
    gcValues.function = GXcopy;
    gcValues.function = GXcopy;
    gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
    gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
    gcValues.graphics_exposures = False;
    gcValues.graphics_exposures = False;
    new = Tk_GetGCColor(canvasPtr->tkwin,
    new = Tk_GetGCColor(canvasPtr->tkwin,
            GCFunction|GCForeground|GCGraphicsExposures, &gcValues,
            GCFunction|GCForeground|GCGraphicsExposures, &gcValues,
            Tk_3DBorderColor(canvasPtr->bgBorder), NULL);
            Tk_3DBorderColor(canvasPtr->bgBorder), NULL);
    if (canvasPtr->pixmapGC != None) {
    if (canvasPtr->pixmapGC != None) {
        Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
        Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
    }
    }
    canvasPtr->pixmapGC = new;
    canvasPtr->pixmapGC = new;
 
 
    /*
    /*
     * Reset the desired dimensions for the window.
     * Reset the desired dimensions for the window.
     */
     */
 
 
    Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
    Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
            canvasPtr->height + 2*canvasPtr->inset);
            canvasPtr->height + 2*canvasPtr->inset);
 
 
    /*
    /*
     * Restart the cursor timing sequence in case the on-time or off-time
     * Restart the cursor timing sequence in case the on-time or off-time
     * just changed.
     * just changed.
     */
     */
 
 
    if (canvasPtr->textInfo.gotFocus) {
    if (canvasPtr->textInfo.gotFocus) {
        CanvasFocusProc(canvasPtr, 1);
        CanvasFocusProc(canvasPtr, 1);
    }
    }
 
 
    /*
    /*
     * Recompute the scroll region.
     * Recompute the scroll region.
     */
     */
 
 
    canvasPtr->scrollX1 = 0;
    canvasPtr->scrollX1 = 0;
    canvasPtr->scrollY1 = 0;
    canvasPtr->scrollY1 = 0;
    canvasPtr->scrollX2 = 0;
    canvasPtr->scrollX2 = 0;
    canvasPtr->scrollY2 = 0;
    canvasPtr->scrollY2 = 0;
    if (canvasPtr->regionString != NULL) {
    if (canvasPtr->regionString != NULL) {
        int argc2;
        int argc2;
        char **argv2;
        char **argv2;
 
 
        if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
        if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
                &argc2, &argv2) != TCL_OK) {
                &argc2, &argv2) != TCL_OK) {
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        if (argc2 != 4) {
        if (argc2 != 4) {
            Tcl_AppendResult(interp, "bad scrollRegion \"",
            Tcl_AppendResult(interp, "bad scrollRegion \"",
                    canvasPtr->regionString, "\"", (char *) NULL);
                    canvasPtr->regionString, "\"", (char *) NULL);
            badRegion:
            badRegion:
            ckfree(canvasPtr->regionString);
            ckfree(canvasPtr->regionString);
            ckfree((char *) argv2);
            ckfree((char *) argv2);
            canvasPtr->regionString = NULL;
            canvasPtr->regionString = NULL;
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
        if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                    argv2[0], &canvasPtr->scrollX1) != TCL_OK)
                    argv2[0], &canvasPtr->scrollX1) != TCL_OK)
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                    argv2[1], &canvasPtr->scrollY1) != TCL_OK)
                    argv2[1], &canvasPtr->scrollY1) != TCL_OK)
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                    argv2[2], &canvasPtr->scrollX2) != TCL_OK)
                    argv2[2], &canvasPtr->scrollX2) != TCL_OK)
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
                    argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
                    argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
            goto badRegion;
            goto badRegion;
        }
        }
        ckfree((char *) argv2);
        ckfree((char *) argv2);
    }
    }
 
 
    /*
    /*
     * Reset the canvas's origin (this is a no-op unless confine
     * Reset the canvas's origin (this is a no-op unless confine
     * mode has just been turned on or the scroll region has changed).
     * mode has just been turned on or the scroll region has changed).
     */
     */
 
 
    CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
    CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
    canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
    canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
    return TCL_OK;
    return TCL_OK;
}
}


/*
/*
 *---------------------------------------------------------------------------
 *---------------------------------------------------------------------------
 *
 *
 * CanvasWorldChanged --
 * CanvasWorldChanged --
 *
 *
 *      This procedure is called when the world has changed in some
 *      This procedure is called when the world has changed in some
 *      way and the widget needs to recompute all its graphics contexts
 *      way and the widget needs to recompute all its graphics contexts
 *      and determine its new geometry.
 *      and determine its new geometry.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Configures all items in the canvas with a empty argc/argv, for
 *      Configures all items in the canvas with a empty argc/argv, for
 *      the side effect of causing all the items to recompute their
 *      the side effect of causing all the items to recompute their
 *      geometry and to be redisplayed.
 *      geometry and to be redisplayed.
 *
 *
 *---------------------------------------------------------------------------
 *---------------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasWorldChanged(instanceData)
CanvasWorldChanged(instanceData)
    ClientData instanceData;    /* Information about widget. */
    ClientData instanceData;    /* Information about widget. */
{
{
    TkCanvas *canvasPtr;
    TkCanvas *canvasPtr;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
    int result;
    int result;
 
 
    canvasPtr = (TkCanvas *) instanceData;
    canvasPtr = (TkCanvas *) instanceData;
    itemPtr = canvasPtr->firstItemPtr;
    itemPtr = canvasPtr->firstItemPtr;
    for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
    for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
        result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,
        result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,
                (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
                (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
                TK_CONFIG_ARGV_ONLY);
                TK_CONFIG_ARGV_ONLY);
        if (result != TCL_OK) {
        if (result != TCL_OK) {
            Tcl_ResetResult(canvasPtr->interp);
            Tcl_ResetResult(canvasPtr->interp);
        }
        }
    }
    }
    canvasPtr->flags |= REPICK_NEEDED;
    canvasPtr->flags |= REPICK_NEEDED;
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * DisplayCanvas --
 * DisplayCanvas --
 *
 *
 *      This procedure redraws the contents of a canvas window.
 *      This procedure redraws the contents of a canvas window.
 *      It is invoked as a do-when-idle handler, so it only runs
 *      It is invoked as a do-when-idle handler, so it only runs
 *      when there's nothing else for the application to do.
 *      when there's nothing else for the application to do.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Information appears on the screen.
 *      Information appears on the screen.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
DisplayCanvas(clientData)
DisplayCanvas(clientData)
    ClientData clientData;      /* Information about widget. */
    ClientData clientData;      /* Information about widget. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    Tk_Window tkwin = canvasPtr->tkwin;
    Tk_Window tkwin = canvasPtr->tkwin;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
    Pixmap pixmap;
    Pixmap pixmap;
    int screenX1, screenX2, screenY1, screenY2, width, height;
    int screenX1, screenX2, screenY1, screenY2, width, height;
 
 
    if (canvasPtr->tkwin == NULL) {
    if (canvasPtr->tkwin == NULL) {
        return;
        return;
    }
    }
    if (!Tk_IsMapped(tkwin)) {
    if (!Tk_IsMapped(tkwin)) {
        goto done;
        goto done;
    }
    }
 
 
    /*
    /*
     * Choose a new current item if that is needed (this could cause
     * Choose a new current item if that is needed (this could cause
     * event handlers to be invoked).
     * event handlers to be invoked).
     */
     */
 
 
    while (canvasPtr->flags & REPICK_NEEDED) {
    while (canvasPtr->flags & REPICK_NEEDED) {
        Tcl_Preserve((ClientData) canvasPtr);
        Tcl_Preserve((ClientData) canvasPtr);
        canvasPtr->flags &= ~REPICK_NEEDED;
        canvasPtr->flags &= ~REPICK_NEEDED;
        PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
        PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
        tkwin = canvasPtr->tkwin;
        tkwin = canvasPtr->tkwin;
        Tcl_Release((ClientData) canvasPtr);
        Tcl_Release((ClientData) canvasPtr);
        if (tkwin == NULL) {
        if (tkwin == NULL) {
            return;
            return;
        }
        }
    }
    }
 
 
    /*
    /*
     * Compute the intersection between the area that needs redrawing
     * Compute the intersection between the area that needs redrawing
     * and the area that's visible on the screen.
     * and the area that's visible on the screen.
     */
     */
 
 
    if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
    if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
            && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
            && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
        screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
        screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
        screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
        screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
        screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
        screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
        screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
        screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
        if (canvasPtr->redrawX1 > screenX1) {
        if (canvasPtr->redrawX1 > screenX1) {
            screenX1 = canvasPtr->redrawX1;
            screenX1 = canvasPtr->redrawX1;
        }
        }
        if (canvasPtr->redrawY1 > screenY1) {
        if (canvasPtr->redrawY1 > screenY1) {
            screenY1 = canvasPtr->redrawY1;
            screenY1 = canvasPtr->redrawY1;
        }
        }
        if (canvasPtr->redrawX2 < screenX2) {
        if (canvasPtr->redrawX2 < screenX2) {
            screenX2 = canvasPtr->redrawX2;
            screenX2 = canvasPtr->redrawX2;
        }
        }
        if (canvasPtr->redrawY2 < screenY2) {
        if (canvasPtr->redrawY2 < screenY2) {
            screenY2 = canvasPtr->redrawY2;
            screenY2 = canvasPtr->redrawY2;
        }
        }
        if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
        if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
            goto borders;
            goto borders;
        }
        }
 
 
        /*
        /*
         * Redrawing is done in a temporary pixmap that is allocated
         * Redrawing is done in a temporary pixmap that is allocated
         * here and freed at the end of the procedure.  All drawing
         * here and freed at the end of the procedure.  All drawing
         * is done to the pixmap, and the pixmap is copied to the
         * is done to the pixmap, and the pixmap is copied to the
         * screen at the end of the procedure. The temporary pixmap
         * screen at the end of the procedure. The temporary pixmap
         * serves two purposes:
         * serves two purposes:
         *
         *
         * 1. It provides a smoother visual effect (no clearing and
         * 1. It provides a smoother visual effect (no clearing and
         *    gradual redraw will be visible to users).
         *    gradual redraw will be visible to users).
         * 2. It allows us to redraw only the objects that overlap
         * 2. It allows us to redraw only the objects that overlap
         *    the redraw area.  Otherwise incorrect results could
         *    the redraw area.  Otherwise incorrect results could
         *        occur from redrawing things that stick outside of
         *        occur from redrawing things that stick outside of
         *        the redraw area (we'd have to redraw everything in
         *        the redraw area (we'd have to redraw everything in
         *    order to make the overlaps look right).
         *    order to make the overlaps look right).
         *
         *
         * Some tricky points about the pixmap:
         * Some tricky points about the pixmap:
         *
         *
         * 1. We only allocate a large enough pixmap to hold the
         * 1. We only allocate a large enough pixmap to hold the
         *    area that has to be redisplayed.  This saves time in
         *    area that has to be redisplayed.  This saves time in
         *    in the X server for large objects that cover much
         *    in the X server for large objects that cover much
         *    more than the area being redisplayed:  only the area
         *    more than the area being redisplayed:  only the area
         *    of the pixmap will actually have to be redrawn.
         *    of the pixmap will actually have to be redrawn.
         * 2. Some X servers (e.g. the one for DECstations) have troubles
         * 2. Some X servers (e.g. the one for DECstations) have troubles
         *    with characters that overlap an edge of the pixmap (on the
         *    with characters that overlap an edge of the pixmap (on the
         *    DEC servers, as of 8/18/92, such characters are drawn one
         *    DEC servers, as of 8/18/92, such characters are drawn one
         *    pixel too far to the right).  To handle this problem,
         *    pixel too far to the right).  To handle this problem,
         *    make the pixmap a bit larger than is absolutely needed
         *    make the pixmap a bit larger than is absolutely needed
         *    so that for normal-sized fonts the characters that overlap
         *    so that for normal-sized fonts the characters that overlap
         *    the edge of the pixmap will be outside the area we care
         *    the edge of the pixmap will be outside the area we care
         *    about.
         *    about.
         */
         */
 
 
        canvasPtr->drawableXOrigin = screenX1 - 30;
        canvasPtr->drawableXOrigin = screenX1 - 30;
        canvasPtr->drawableYOrigin = screenY1 - 30;
        canvasPtr->drawableYOrigin = screenY1 - 30;
        pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
        pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
            (screenX2 + 30 - canvasPtr->drawableXOrigin),
            (screenX2 + 30 - canvasPtr->drawableXOrigin),
            (screenY2 + 30 - canvasPtr->drawableYOrigin),
            (screenY2 + 30 - canvasPtr->drawableYOrigin),
            Tk_Depth(tkwin));
            Tk_Depth(tkwin));
 
 
        /*
        /*
         * Clear the area to be redrawn.
         * Clear the area to be redrawn.
         */
         */
 
 
        width = screenX2 - screenX1;
        width = screenX2 - screenX1;
        height = screenY2 - screenY1;
        height = screenY2 - screenY1;
 
 
        XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
        XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
                screenX1 - canvasPtr->drawableXOrigin,
                screenX1 - canvasPtr->drawableXOrigin,
                screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
                screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
                (unsigned int) height);
                (unsigned int) height);
 
 
        /*
        /*
         * Scan through the item list, redrawing those items that need it.
         * Scan through the item list, redrawing those items that need it.
         * An item must be redraw if either (a) it intersects the smaller
         * An item must be redraw if either (a) it intersects the smaller
         * on-screen area or (b) it intersects the full canvas area and its
         * on-screen area or (b) it intersects the full canvas area and its
         * type requests that it be redrawn always (e.g. so subwindows can
         * type requests that it be redrawn always (e.g. so subwindows can
         * be unmapped when they move off-screen).
         * be unmapped when they move off-screen).
         */
         */
 
 
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
                itemPtr = itemPtr->nextPtr) {
                itemPtr = itemPtr->nextPtr) {
            if ((itemPtr->x1 >= screenX2)
            if ((itemPtr->x1 >= screenX2)
                    || (itemPtr->y1 >= screenY2)
                    || (itemPtr->y1 >= screenY2)
                    || (itemPtr->x2 < screenX1)
                    || (itemPtr->x2 < screenX1)
                    || (itemPtr->y2 < screenY1)) {
                    || (itemPtr->y2 < screenY1)) {
                if (!itemPtr->typePtr->alwaysRedraw
                if (!itemPtr->typePtr->alwaysRedraw
                        || (itemPtr->x1 >= canvasPtr->redrawX2)
                        || (itemPtr->x1 >= canvasPtr->redrawX2)
                        || (itemPtr->y1 >= canvasPtr->redrawY2)
                        || (itemPtr->y1 >= canvasPtr->redrawY2)
                        || (itemPtr->x2 < canvasPtr->redrawX1)
                        || (itemPtr->x2 < canvasPtr->redrawX1)
                        || (itemPtr->y2 < canvasPtr->redrawY1)) {
                        || (itemPtr->y2 < canvasPtr->redrawY1)) {
                    continue;
                    continue;
                }
                }
            }
            }
            (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
            (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
                    canvasPtr->display, pixmap, screenX1, screenY1, width,
                    canvasPtr->display, pixmap, screenX1, screenY1, width,
                    height);
                    height);
        }
        }
 
 
        /*
        /*
         * Copy from the temporary pixmap to the screen, then free up
         * Copy from the temporary pixmap to the screen, then free up
         * the temporary pixmap.
         * the temporary pixmap.
         */
         */
 
 
        XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
        XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
                canvasPtr->pixmapGC,
                canvasPtr->pixmapGC,
                screenX1 - canvasPtr->drawableXOrigin,
                screenX1 - canvasPtr->drawableXOrigin,
                screenY1 - canvasPtr->drawableYOrigin,
                screenY1 - canvasPtr->drawableYOrigin,
                (unsigned) (screenX2 - screenX1),
                (unsigned) (screenX2 - screenX1),
                (unsigned) (screenY2 - screenY1),
                (unsigned) (screenY2 - screenY1),
                screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
                screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
        Tk_FreePixmap(Tk_Display(tkwin), pixmap);
        Tk_FreePixmap(Tk_Display(tkwin), pixmap);
    }
    }
 
 
    /*
    /*
     * Draw the window borders, if needed.
     * Draw the window borders, if needed.
     */
     */
 
 
    borders:
    borders:
    if (canvasPtr->flags & REDRAW_BORDERS) {
    if (canvasPtr->flags & REDRAW_BORDERS) {
        canvasPtr->flags &= ~REDRAW_BORDERS;
        canvasPtr->flags &= ~REDRAW_BORDERS;
        if (canvasPtr->borderWidth > 0) {
        if (canvasPtr->borderWidth > 0) {
            Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
            Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
                    canvasPtr->bgBorder, canvasPtr->highlightWidth,
                    canvasPtr->bgBorder, canvasPtr->highlightWidth,
                    canvasPtr->highlightWidth,
                    canvasPtr->highlightWidth,
                    Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
                    Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
                    Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
                    Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
                    canvasPtr->borderWidth, canvasPtr->relief);
                    canvasPtr->borderWidth, canvasPtr->relief);
        }
        }
        if (canvasPtr->highlightWidth != 0) {
        if (canvasPtr->highlightWidth != 0) {
            GC gc;
            GC gc;
 
 
            if (canvasPtr->textInfo.gotFocus) {
            if (canvasPtr->textInfo.gotFocus) {
                gc = Tk_GCForColor(canvasPtr->highlightColorPtr,
                gc = Tk_GCForColor(canvasPtr->highlightColorPtr,
                        Tk_WindowId(tkwin));
                        Tk_WindowId(tkwin));
            } else {
            } else {
                gc = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
                gc = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
                        Tk_WindowId(tkwin));
                        Tk_WindowId(tkwin));
            }
            }
            Tk_DrawFocusHighlight(tkwin, gc, canvasPtr->highlightWidth,
            Tk_DrawFocusHighlight(tkwin, gc, canvasPtr->highlightWidth,
                    Tk_WindowId(tkwin));
                    Tk_WindowId(tkwin));
        }
        }
    }
    }
 
 
    done:
    done:
    canvasPtr->flags &= ~REDRAW_PENDING;
    canvasPtr->flags &= ~REDRAW_PENDING;
    canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
    canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
    canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
    canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
    if (canvasPtr->flags & UPDATE_SCROLLBARS) {
    if (canvasPtr->flags & UPDATE_SCROLLBARS) {
        CanvasUpdateScrollbars(canvasPtr);
        CanvasUpdateScrollbars(canvasPtr);
    }
    }
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasEventProc --
 * CanvasEventProc --
 *
 *
 *      This procedure is invoked by the Tk dispatcher for various
 *      This procedure is invoked by the Tk dispatcher for various
 *      events on canvases.
 *      events on canvases.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      When the window gets deleted, internal structures get
 *      When the window gets deleted, internal structures get
 *      cleaned up.  When it gets exposed, it is redisplayed.
 *      cleaned up.  When it gets exposed, it is redisplayed.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasEventProc(clientData, eventPtr)
CanvasEventProc(clientData, eventPtr)
    ClientData clientData;      /* Information about window. */
    ClientData clientData;      /* Information about window. */
    XEvent *eventPtr;           /* Information about event. */
    XEvent *eventPtr;           /* Information about event. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
 
 
    if (eventPtr->type == Expose) {
    if (eventPtr->type == Expose) {
        int x, y;
        int x, y;
 
 
        x = eventPtr->xexpose.x + canvasPtr->xOrigin;
        x = eventPtr->xexpose.x + canvasPtr->xOrigin;
        y = eventPtr->xexpose.y + canvasPtr->yOrigin;
        y = eventPtr->xexpose.y + canvasPtr->yOrigin;
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
                x + eventPtr->xexpose.width,
                x + eventPtr->xexpose.width,
                y + eventPtr->xexpose.height);
                y + eventPtr->xexpose.height);
        if ((eventPtr->xexpose.x < canvasPtr->inset)
        if ((eventPtr->xexpose.x < canvasPtr->inset)
                || (eventPtr->xexpose.y < canvasPtr->inset)
                || (eventPtr->xexpose.y < canvasPtr->inset)
                || ((eventPtr->xexpose.x + eventPtr->xexpose.width)
                || ((eventPtr->xexpose.x + eventPtr->xexpose.width)
                    > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
                    > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
                || ((eventPtr->xexpose.y + eventPtr->xexpose.height)
                || ((eventPtr->xexpose.y + eventPtr->xexpose.height)
                    > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
                    > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
            canvasPtr->flags |= REDRAW_BORDERS;
            canvasPtr->flags |= REDRAW_BORDERS;
        }
        }
    } else if (eventPtr->type == DestroyNotify) {
    } else if (eventPtr->type == DestroyNotify) {
        if (canvasPtr->tkwin != NULL) {
        if (canvasPtr->tkwin != NULL) {
            canvasPtr->tkwin = NULL;
            canvasPtr->tkwin = NULL;
            Tcl_DeleteCommandFromToken(canvasPtr->interp,
            Tcl_DeleteCommandFromToken(canvasPtr->interp,
                    canvasPtr->widgetCmd);
                    canvasPtr->widgetCmd);
        }
        }
        if (canvasPtr->flags & REDRAW_PENDING) {
        if (canvasPtr->flags & REDRAW_PENDING) {
            Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
            Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
        }
        }
        Tcl_EventuallyFree((ClientData) canvasPtr, DestroyCanvas);
        Tcl_EventuallyFree((ClientData) canvasPtr, DestroyCanvas);
    } else if (eventPtr->type == ConfigureNotify) {
    } else if (eventPtr->type == ConfigureNotify) {
        canvasPtr->flags |= UPDATE_SCROLLBARS;
        canvasPtr->flags |= UPDATE_SCROLLBARS;
 
 
        /*
        /*
         * The call below is needed in order to recenter the canvas if
         * The call below is needed in order to recenter the canvas if
         * it's confined and its scroll region is smaller than the window.
         * it's confined and its scroll region is smaller than the window.
         */
         */
 
 
        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
        CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
                canvasPtr->yOrigin,
                canvasPtr->yOrigin,
                canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
                canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
                canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
                canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
        canvasPtr->flags |= REDRAW_BORDERS;
        canvasPtr->flags |= REDRAW_BORDERS;
    } else if (eventPtr->type == FocusIn) {
    } else if (eventPtr->type == FocusIn) {
        if (eventPtr->xfocus.detail != NotifyInferior) {
        if (eventPtr->xfocus.detail != NotifyInferior) {
            CanvasFocusProc(canvasPtr, 1);
            CanvasFocusProc(canvasPtr, 1);
        }
        }
    } else if (eventPtr->type == FocusOut) {
    } else if (eventPtr->type == FocusOut) {
        if (eventPtr->xfocus.detail != NotifyInferior) {
        if (eventPtr->xfocus.detail != NotifyInferior) {
            CanvasFocusProc(canvasPtr, 0);
            CanvasFocusProc(canvasPtr, 0);
        }
        }
    } else if (eventPtr->type == UnmapNotify) {
    } else if (eventPtr->type == UnmapNotify) {
        Tk_Item *itemPtr;
        Tk_Item *itemPtr;
 
 
        /*
        /*
         * Special hack:  if the canvas is unmapped, then must notify
         * Special hack:  if the canvas is unmapped, then must notify
         * all items with "alwaysRedraw" set, so that they know that
         * all items with "alwaysRedraw" set, so that they know that
         * they are no longer displayed.
         * they are no longer displayed.
         */
         */
 
 
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
                itemPtr = itemPtr->nextPtr) {
                itemPtr = itemPtr->nextPtr) {
            if (itemPtr->typePtr->alwaysRedraw) {
            if (itemPtr->typePtr->alwaysRedraw) {
                (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,
                (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,
                        itemPtr, canvasPtr->display, None, 0, 0, 0, 0);
                        itemPtr, canvasPtr->display, None, 0, 0, 0, 0);
            }
            }
        }
        }
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasCmdDeletedProc --
 * CanvasCmdDeletedProc --
 *
 *
 *      This procedure is invoked when a widget command is deleted.  If
 *      This procedure is invoked when a widget command is deleted.  If
 *      the widget isn't already in the process of being destroyed,
 *      the widget isn't already in the process of being destroyed,
 *      this command destroys it.
 *      this command destroys it.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The widget is destroyed.
 *      The widget is destroyed.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasCmdDeletedProc(clientData)
CanvasCmdDeletedProc(clientData)
    ClientData clientData;      /* Pointer to widget record for widget. */
    ClientData clientData;      /* Pointer to widget record for widget. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    Tk_Window tkwin = canvasPtr->tkwin;
    Tk_Window tkwin = canvasPtr->tkwin;
 
 
    /*
    /*
     * This procedure could be invoked either because the window was
     * This procedure could be invoked either because the window was
     * destroyed and the command was then deleted (in which case tkwin
     * destroyed and the command was then deleted (in which case tkwin
     * is NULL) or because the command was deleted, and then this procedure
     * is NULL) or because the command was deleted, and then this procedure
     * destroys the widget.
     * destroys the widget.
     */
     */
 
 
    if (tkwin != NULL) {
    if (tkwin != NULL) {
        canvasPtr->tkwin = NULL;
        canvasPtr->tkwin = NULL;
        Tk_DestroyWindow(tkwin);
        Tk_DestroyWindow(tkwin);
    }
    }
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * Tk_CanvasEventuallyRedraw --
 * Tk_CanvasEventuallyRedraw --
 *
 *
 *      Arrange for part or all of a canvas widget to redrawn at
 *      Arrange for part or all of a canvas widget to redrawn at
 *      some convenient time in the future.
 *      some convenient time in the future.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The screen will eventually be refreshed.
 *      The screen will eventually be refreshed.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
void
void
Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
    Tk_Canvas canvas;           /* Information about widget. */
    Tk_Canvas canvas;           /* Information about widget. */
    int x1, y1;                 /* Upper left corner of area to redraw.
    int x1, y1;                 /* Upper left corner of area to redraw.
                                 * Pixels on edge are redrawn. */
                                 * Pixels on edge are redrawn. */
    int x2, y2;                 /* Lower right corner of area to redraw.
    int x2, y2;                 /* Lower right corner of area to redraw.
                                 * Pixels on edge are not redrawn. */
                                 * Pixels on edge are not redrawn. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) canvas;
    TkCanvas *canvasPtr = (TkCanvas *) canvas;
    if ((x1 == x2) || (y1 == y2)) {
    if ((x1 == x2) || (y1 == y2)) {
        return;
        return;
    }
    }
    if (canvasPtr->flags & REDRAW_PENDING) {
    if (canvasPtr->flags & REDRAW_PENDING) {
        if (x1 <= canvasPtr->redrawX1) {
        if (x1 <= canvasPtr->redrawX1) {
            canvasPtr->redrawX1 = x1;
            canvasPtr->redrawX1 = x1;
        }
        }
        if (y1 <= canvasPtr->redrawY1) {
        if (y1 <= canvasPtr->redrawY1) {
            canvasPtr->redrawY1 = y1;
            canvasPtr->redrawY1 = y1;
        }
        }
        if (x2 >= canvasPtr->redrawX2) {
        if (x2 >= canvasPtr->redrawX2) {
            canvasPtr->redrawX2 = x2;
            canvasPtr->redrawX2 = x2;
        }
        }
        if (y2 >= canvasPtr->redrawY2) {
        if (y2 >= canvasPtr->redrawY2) {
            canvasPtr->redrawY2 = y2;
            canvasPtr->redrawY2 = y2;
        }
        }
    } else {
    } else {
        canvasPtr->redrawX1 = x1;
        canvasPtr->redrawX1 = x1;
        canvasPtr->redrawY1 = y1;
        canvasPtr->redrawY1 = y1;
        canvasPtr->redrawX2 = x2;
        canvasPtr->redrawX2 = x2;
        canvasPtr->redrawY2 = y2;
        canvasPtr->redrawY2 = y2;
        Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
        Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
        canvasPtr->flags |= REDRAW_PENDING;
        canvasPtr->flags |= REDRAW_PENDING;
    }
    }
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * Tk_CreateItemType --
 * Tk_CreateItemType --
 *
 *
 *      This procedure may be invoked to add a new kind of canvas
 *      This procedure may be invoked to add a new kind of canvas
 *      element to the core item types supported by Tk.
 *      element to the core item types supported by Tk.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      From now on, the new item type will be useable in canvas
 *      From now on, the new item type will be useable in canvas
 *      widgets (e.g. typePtr->name can be used as the item type
 *      widgets (e.g. typePtr->name can be used as the item type
 *      in "create" widget commands).  If there was already a
 *      in "create" widget commands).  If there was already a
 *      type with the same name as in typePtr, it is replaced with
 *      type with the same name as in typePtr, it is replaced with
 *      the new type.
 *      the new type.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
void
void
Tk_CreateItemType(typePtr)
Tk_CreateItemType(typePtr)
    Tk_ItemType *typePtr;               /* Information about item type;
    Tk_ItemType *typePtr;               /* Information about item type;
                                         * storage must be statically
                                         * storage must be statically
                                         * allocated (must live forever). */
                                         * allocated (must live forever). */
{
{
    Tk_ItemType *typePtr2, *prevPtr;
    Tk_ItemType *typePtr2, *prevPtr;
 
 
    if (typeList == NULL) {
    if (typeList == NULL) {
        InitCanvas();
        InitCanvas();
    }
    }
 
 
    /*
    /*
     * If there's already an item type with the given name, remove it.
     * If there's already an item type with the given name, remove it.
     */
     */
 
 
    for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
    for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
            prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
            prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
        if (strcmp(typePtr2->name, typePtr->name) == 0) {
        if (strcmp(typePtr2->name, typePtr->name) == 0) {
            if (prevPtr == NULL) {
            if (prevPtr == NULL) {
                typeList = typePtr2->nextPtr;
                typeList = typePtr2->nextPtr;
            } else {
            } else {
                prevPtr->nextPtr = typePtr2->nextPtr;
                prevPtr->nextPtr = typePtr2->nextPtr;
            }
            }
            break;
            break;
        }
        }
    }
    }
    typePtr->nextPtr = typeList;
    typePtr->nextPtr = typeList;
    typeList = typePtr;
    typeList = typePtr;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * Tk_GetItemTypes --
 * Tk_GetItemTypes --
 *
 *
 *      This procedure returns a pointer to the list of all item
 *      This procedure returns a pointer to the list of all item
 *      types.
 *      types.
 *
 *
 * Results:
 * Results:
 *      The return value is a pointer to the first in the list
 *      The return value is a pointer to the first in the list
 *      of item types currently supported by canvases.
 *      of item types currently supported by canvases.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
Tk_ItemType *
Tk_ItemType *
Tk_GetItemTypes()
Tk_GetItemTypes()
{
{
    if (typeList == NULL) {
    if (typeList == NULL) {
        InitCanvas();
        InitCanvas();
    }
    }
    return typeList;
    return typeList;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * InitCanvas --
 * InitCanvas --
 *
 *
 *      This procedure is invoked to perform once-only-ever
 *      This procedure is invoked to perform once-only-ever
 *      initialization for the module, such as setting up
 *      initialization for the module, such as setting up
 *      the type table.
 *      the type table.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
InitCanvas()
InitCanvas()
{
{
    if (typeList != NULL) {
    if (typeList != NULL) {
        return;
        return;
    }
    }
    typeList = &tkRectangleType;
    typeList = &tkRectangleType;
    tkRectangleType.nextPtr = &tkTextType;
    tkRectangleType.nextPtr = &tkTextType;
    tkTextType.nextPtr = &tkLineType;
    tkTextType.nextPtr = &tkLineType;
    tkLineType.nextPtr = &tkPolygonType;
    tkLineType.nextPtr = &tkPolygonType;
    tkPolygonType.nextPtr = &tkImageType;
    tkPolygonType.nextPtr = &tkImageType;
    tkImageType.nextPtr = &tkOvalType;
    tkImageType.nextPtr = &tkOvalType;
    tkOvalType.nextPtr = &tkBitmapType;
    tkOvalType.nextPtr = &tkBitmapType;
    tkBitmapType.nextPtr = &tkArcType;
    tkBitmapType.nextPtr = &tkArcType;
    tkArcType.nextPtr = &tkWindowType;
    tkArcType.nextPtr = &tkWindowType;
    tkWindowType.nextPtr = NULL;
    tkWindowType.nextPtr = NULL;
    allUid = Tk_GetUid("all");
    allUid = Tk_GetUid("all");
    currentUid = Tk_GetUid("current");
    currentUid = Tk_GetUid("current");
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * StartTagSearch --
 * StartTagSearch --
 *
 *
 *      This procedure is called to initiate an enumeration of
 *      This procedure is called to initiate an enumeration of
 *      all items in a given canvas that contain a given tag.
 *      all items in a given canvas that contain a given tag.
 *
 *
 * Results:
 * Results:
 *      The return value is a pointer to the first item in
 *      The return value is a pointer to the first item in
 *      canvasPtr that matches tag, or NULL if there is no
 *      canvasPtr that matches tag, or NULL if there is no
 *      such item.  The information at *searchPtr is initialized
 *      such item.  The information at *searchPtr is initialized
 *      such that successive calls to NextItem will return
 *      such that successive calls to NextItem will return
 *      successive items that match tag.
 *      successive items that match tag.
 *
 *
 * Side effects:
 * Side effects:
 *      SearchPtr is linked into a list of searches in progress
 *      SearchPtr is linked into a list of searches in progress
 *      on canvasPtr, so that elements can safely be deleted
 *      on canvasPtr, so that elements can safely be deleted
 *      while the search is in progress.  EndTagSearch must be
 *      while the search is in progress.  EndTagSearch must be
 *      called at the end of the search to unlink searchPtr from
 *      called at the end of the search to unlink searchPtr from
 *      this list.
 *      this list.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static Tk_Item *
static Tk_Item *
StartTagSearch(canvasPtr, tag, searchPtr)
StartTagSearch(canvasPtr, tag, searchPtr)
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
                                         * searched. */
                                         * searched. */
    char *tag;                          /* String giving tag value. */
    char *tag;                          /* String giving tag value. */
    TagSearch *searchPtr;               /* Record describing tag search;
    TagSearch *searchPtr;               /* Record describing tag search;
                                         * will be initialized here. */
                                         * will be initialized here. */
{
{
    int id;
    int id;
    Tk_Item *itemPtr, *lastPtr;
    Tk_Item *itemPtr, *lastPtr;
    Tk_Uid *tagPtr;
    Tk_Uid *tagPtr;
    Tk_Uid uid;
    Tk_Uid uid;
    int count;
    int count;
 
 
    /*
    /*
     * Initialize the search.
     * Initialize the search.
     */
     */
 
 
    searchPtr->canvasPtr = canvasPtr;
    searchPtr->canvasPtr = canvasPtr;
    searchPtr->searchOver = 0;
    searchPtr->searchOver = 0;
 
 
    /*
    /*
     * Find the first matching item in one of several ways. If the tag
     * Find the first matching item in one of several ways. If the tag
     * is a number then it selects the single item with the matching
     * is a number then it selects the single item with the matching
     * identifier.  In this case see if the item being requested is the
     * identifier.  In this case see if the item being requested is the
     * hot item, in which case the search can be skipped.
     * hot item, in which case the search can be skipped.
     */
     */
 
 
    if (isdigit(UCHAR(*tag))) {
    if (isdigit(UCHAR(*tag))) {
        char *end;
        char *end;
        Tcl_HashEntry *entryPtr;
        Tcl_HashEntry *entryPtr;
 
 
        numIdSearches++;
        numIdSearches++;
        id = strtoul(tag, &end, 0);
        id = strtoul(tag, &end, 0);
        if (*end == 0) {
        if (*end == 0) {
            itemPtr = canvasPtr->hotPtr;
            itemPtr = canvasPtr->hotPtr;
            lastPtr = canvasPtr->hotPrevPtr;
            lastPtr = canvasPtr->hotPrevPtr;
            if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)
            if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)
                    || (lastPtr->nextPtr != itemPtr)) {
                    || (lastPtr->nextPtr != itemPtr)) {
                numSlowSearches++;
                numSlowSearches++;
                entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
                entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
                if (entryPtr != NULL) {
                if (entryPtr != NULL) {
                    itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);
                    itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);
                    lastPtr = itemPtr->prevPtr;
                    lastPtr = itemPtr->prevPtr;
                } else {
                } else {
                    lastPtr = itemPtr = NULL;
                    lastPtr = itemPtr = NULL;
                }
                }
            }
            }
            searchPtr->lastPtr = lastPtr;
            searchPtr->lastPtr = lastPtr;
            searchPtr->searchOver = 1;
            searchPtr->searchOver = 1;
            canvasPtr->hotPtr = itemPtr;
            canvasPtr->hotPtr = itemPtr;
            canvasPtr->hotPrevPtr = lastPtr;
            canvasPtr->hotPrevPtr = lastPtr;
            return itemPtr;
            return itemPtr;
        }
        }
    }
    }
 
 
    searchPtr->tag = uid = Tk_GetUid(tag);
    searchPtr->tag = uid = Tk_GetUid(tag);
    if (uid == allUid) {
    if (uid == allUid) {
 
 
        /*
        /*
         * All items match.
         * All items match.
         */
         */
 
 
        searchPtr->tag = NULL;
        searchPtr->tag = NULL;
        searchPtr->lastPtr = NULL;
        searchPtr->lastPtr = NULL;
        searchPtr->currentPtr = canvasPtr->firstItemPtr;
        searchPtr->currentPtr = canvasPtr->firstItemPtr;
        return canvasPtr->firstItemPtr;
        return canvasPtr->firstItemPtr;
    }
    }
 
 
    /*
    /*
     * None of the above.  Search for an item with a matching tag.
     * None of the above.  Search for an item with a matching tag.
     */
     */
 
 
    for (lastPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
    for (lastPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
            lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
            lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
                count > 0; tagPtr++, count--) {
                count > 0; tagPtr++, count--) {
            if (*tagPtr == uid) {
            if (*tagPtr == uid) {
                searchPtr->lastPtr = lastPtr;
                searchPtr->lastPtr = lastPtr;
                searchPtr->currentPtr = itemPtr;
                searchPtr->currentPtr = itemPtr;
                return itemPtr;
                return itemPtr;
            }
            }
        }
        }
    }
    }
    searchPtr->lastPtr = lastPtr;
    searchPtr->lastPtr = lastPtr;
    searchPtr->searchOver = 1;
    searchPtr->searchOver = 1;
    return NULL;
    return NULL;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * NextItem --
 * NextItem --
 *
 *
 *      This procedure returns successive items that match a given
 *      This procedure returns successive items that match a given
 *      tag;  it should be called only after StartTagSearch has been
 *      tag;  it should be called only after StartTagSearch has been
 *      used to begin a search.
 *      used to begin a search.
 *
 *
 * Results:
 * Results:
 *      The return value is a pointer to the next item that matches
 *      The return value is a pointer to the next item that matches
 *      the tag specified to StartTagSearch, or NULL if no such
 *      the tag specified to StartTagSearch, or NULL if no such
 *      item exists.  *SearchPtr is updated so that the next call
 *      item exists.  *SearchPtr is updated so that the next call
 *      to this procedure will return the next item.
 *      to this procedure will return the next item.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static Tk_Item *
static Tk_Item *
NextItem(searchPtr)
NextItem(searchPtr)
    TagSearch *searchPtr;               /* Record describing search in
    TagSearch *searchPtr;               /* Record describing search in
                                         * progress. */
                                         * progress. */
{
{
    Tk_Item *itemPtr, *lastPtr;
    Tk_Item *itemPtr, *lastPtr;
    int count;
    int count;
    Tk_Uid uid;
    Tk_Uid uid;
    Tk_Uid *tagPtr;
    Tk_Uid *tagPtr;
 
 
    /*
    /*
     * Find next item in list (this may not actually be a suitable
     * Find next item in list (this may not actually be a suitable
     * one to return), and return if there are no items left.
     * one to return), and return if there are no items left.
     */
     */
 
 
    lastPtr = searchPtr->lastPtr;
    lastPtr = searchPtr->lastPtr;
    if (lastPtr == NULL) {
    if (lastPtr == NULL) {
        itemPtr = searchPtr->canvasPtr->firstItemPtr;
        itemPtr = searchPtr->canvasPtr->firstItemPtr;
    } else {
    } else {
        itemPtr = lastPtr->nextPtr;
        itemPtr = lastPtr->nextPtr;
    }
    }
    if ((itemPtr == NULL) || (searchPtr->searchOver)) {
    if ((itemPtr == NULL) || (searchPtr->searchOver)) {
        searchPtr->searchOver = 1;
        searchPtr->searchOver = 1;
        return NULL;
        return NULL;
    }
    }
    if (itemPtr != searchPtr->currentPtr) {
    if (itemPtr != searchPtr->currentPtr) {
        /*
        /*
         * The structure of the list has changed.  Probably the
         * The structure of the list has changed.  Probably the
         * previously-returned item was removed from the list.
         * previously-returned item was removed from the list.
         * In this case, don't advance lastPtr;  just return
         * In this case, don't advance lastPtr;  just return
         * its new successor (i.e. do nothing here).
         * its new successor (i.e. do nothing here).
         */
         */
    } else {
    } else {
        lastPtr = itemPtr;
        lastPtr = itemPtr;
        itemPtr = lastPtr->nextPtr;
        itemPtr = lastPtr->nextPtr;
    }
    }
 
 
    /*
    /*
     * Handle special case of "all" search by returning next item.
     * Handle special case of "all" search by returning next item.
     */
     */
 
 
    uid = searchPtr->tag;
    uid = searchPtr->tag;
    if (uid == NULL) {
    if (uid == NULL) {
        searchPtr->lastPtr = lastPtr;
        searchPtr->lastPtr = lastPtr;
        searchPtr->currentPtr = itemPtr;
        searchPtr->currentPtr = itemPtr;
        return itemPtr;
        return itemPtr;
    }
    }
 
 
    /*
    /*
     * Look for an item with a particular tag.
     * Look for an item with a particular tag.
     */
     */
 
 
    for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
    for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
        for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
                count > 0; tagPtr++, count--) {
                count > 0; tagPtr++, count--) {
            if (*tagPtr == uid) {
            if (*tagPtr == uid) {
                searchPtr->lastPtr = lastPtr;
                searchPtr->lastPtr = lastPtr;
                searchPtr->currentPtr = itemPtr;
                searchPtr->currentPtr = itemPtr;
                return itemPtr;
                return itemPtr;
            }
            }
        }
        }
    }
    }
    searchPtr->lastPtr = lastPtr;
    searchPtr->lastPtr = lastPtr;
    searchPtr->searchOver = 1;
    searchPtr->searchOver = 1;
    return NULL;
    return NULL;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * DoItem --
 * DoItem --
 *
 *
 *      This is a utility procedure called by FindItems.  It
 *      This is a utility procedure called by FindItems.  It
 *      either adds itemPtr's id to the result forming in interp,
 *      either adds itemPtr's id to the result forming in interp,
 *      or it adds a new tag to itemPtr, depending on the value
 *      or it adds a new tag to itemPtr, depending on the value
 *      of tag.
 *      of tag.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      If tag is NULL then itemPtr's id is added as a list element
 *      If tag is NULL then itemPtr's id is added as a list element
 *      to interp->result;  otherwise tag is added to itemPtr's
 *      to interp->result;  otherwise tag is added to itemPtr's
 *      list of tags.
 *      list of tags.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
DoItem(interp, itemPtr, tag)
DoItem(interp, itemPtr, tag)
    Tcl_Interp *interp;                 /* Interpreter in which to (possibly)
    Tcl_Interp *interp;                 /* Interpreter in which to (possibly)
                                         * record item id. */
                                         * record item id. */
    Tk_Item *itemPtr;                   /* Item to (possibly) modify. */
    Tk_Item *itemPtr;                   /* Item to (possibly) modify. */
    Tk_Uid tag;                         /* Tag to add to those already
    Tk_Uid tag;                         /* Tag to add to those already
                                         * present for item, or NULL. */
                                         * present for item, or NULL. */
{
{
    Tk_Uid *tagPtr;
    Tk_Uid *tagPtr;
    int count;
    int count;
 
 
    /*
    /*
     * Handle the "add-to-result" case and return, if appropriate.
     * Handle the "add-to-result" case and return, if appropriate.
     */
     */
 
 
    if (tag == NULL) {
    if (tag == NULL) {
        char msg[30];
        char msg[30];
        sprintf(msg, "%d", itemPtr->id);
        sprintf(msg, "%d", itemPtr->id);
        Tcl_AppendElement(interp, msg);
        Tcl_AppendElement(interp, msg);
        return;
        return;
    }
    }
 
 
    for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
    for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
            count > 0; tagPtr++, count--) {
            count > 0; tagPtr++, count--) {
        if (tag == *tagPtr) {
        if (tag == *tagPtr) {
            return;
            return;
        }
        }
    }
    }
 
 
    /*
    /*
     * Grow the tag space if there's no more room left in the current
     * Grow the tag space if there's no more room left in the current
     * block.
     * block.
     */
     */
 
 
    if (itemPtr->tagSpace == itemPtr->numTags) {
    if (itemPtr->tagSpace == itemPtr->numTags) {
        Tk_Uid *newTagPtr;
        Tk_Uid *newTagPtr;
 
 
        itemPtr->tagSpace += 5;
        itemPtr->tagSpace += 5;
        newTagPtr = (Tk_Uid *) ckalloc((unsigned)
        newTagPtr = (Tk_Uid *) ckalloc((unsigned)
                (itemPtr->tagSpace * sizeof(Tk_Uid)));
                (itemPtr->tagSpace * sizeof(Tk_Uid)));
        memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,
        memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,
                (itemPtr->numTags * sizeof(Tk_Uid)));
                (itemPtr->numTags * sizeof(Tk_Uid)));
        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
        if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
            ckfree((char *) itemPtr->tagPtr);
            ckfree((char *) itemPtr->tagPtr);
        }
        }
        itemPtr->tagPtr = newTagPtr;
        itemPtr->tagPtr = newTagPtr;
        tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
        tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
    }
    }
 
 
    /*
    /*
     * Add in the new tag.
     * Add in the new tag.
     */
     */
 
 
    *tagPtr = tag;
    *tagPtr = tag;
    itemPtr->numTags++;
    itemPtr->numTags++;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * FindItems --
 * FindItems --
 *
 *
 *      This procedure does all the work of implementing the
 *      This procedure does all the work of implementing the
 *      "find" and "addtag" options of the canvas widget command,
 *      "find" and "addtag" options of the canvas widget command,
 *      which locate items that have certain features (location,
 *      which locate items that have certain features (location,
 *      tags, position in display list, etc.).
 *      tags, position in display list, etc.).
 *
 *
 * Results:
 * Results:
 *      A standard Tcl return value.  If newTag is NULL, then a
 *      A standard Tcl return value.  If newTag is NULL, then a
 *      list of ids from all the items that match argc/argv is
 *      list of ids from all the items that match argc/argv is
 *      returned in interp->result.  If newTag is NULL, then
 *      returned in interp->result.  If newTag is NULL, then
 *      the normal interp->result is an empty string.  If an error
 *      the normal interp->result is an empty string.  If an error
 *      occurs, then interp->result will hold an error message.
 *      occurs, then interp->result will hold an error message.
 *
 *
 * Side effects:
 * Side effects:
 *      If newTag is non-NULL, then all the items that match the
 *      If newTag is non-NULL, then all the items that match the
 *      information in argc/argv have that tag added to their
 *      information in argc/argv have that tag added to their
 *      lists of tags.
 *      lists of tags.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static int
static int
FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option)
FindItems(interp, canvasPtr, argc, argv, newTag, cmdName, option)
    Tcl_Interp *interp;                 /* Interpreter for error reporting. */
    Tcl_Interp *interp;                 /* Interpreter for error reporting. */
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
                                         * searched. */
                                         * searched. */
    int argc;                           /* Number of entries in argv.  Must be
    int argc;                           /* Number of entries in argv.  Must be
                                         * greater than zero. */
                                         * greater than zero. */
    char **argv;                        /* Arguments that describe what items
    char **argv;                        /* Arguments that describe what items
                                         * to search for (see user doc on
                                         * to search for (see user doc on
                                         * "find" and "addtag" options). */
                                         * "find" and "addtag" options). */
    char *newTag;                       /* If non-NULL, gives new tag to set
    char *newTag;                       /* If non-NULL, gives new tag to set
                                         * on all found items;  if NULL, then
                                         * on all found items;  if NULL, then
                                         * ids of found items are returned
                                         * ids of found items are returned
                                         * in interp->result. */
                                         * in interp->result. */
    char *cmdName;                      /* Name of original Tcl command, for
    char *cmdName;                      /* Name of original Tcl command, for
                                         * use in error messages. */
                                         * use in error messages. */
    char *option;                       /* For error messages:  gives option
    char *option;                       /* For error messages:  gives option
                                         * from Tcl command and other stuff
                                         * from Tcl command and other stuff
                                         * up to what's in argc/argv. */
                                         * up to what's in argc/argv. */
{
{
    int c;
    int c;
    size_t length;
    size_t length;
    TagSearch search;
    TagSearch search;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
    Tk_Uid uid;
    Tk_Uid uid;
 
 
    if (newTag != NULL) {
    if (newTag != NULL) {
        uid = Tk_GetUid(newTag);
        uid = Tk_GetUid(newTag);
    } else {
    } else {
        uid = NULL;
        uid = NULL;
    }
    }
    c = argv[0][0];
    c = argv[0][0];
    length = strlen(argv[0]);
    length = strlen(argv[0]);
    if ((c == 'a') && (strncmp(argv[0], "above", length) == 0)
    if ((c == 'a') && (strncmp(argv[0], "above", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        Tk_Item *lastPtr = NULL;
        Tk_Item *lastPtr = NULL;
        if (argc != 2) {
        if (argc != 2) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " above tagOrId", (char *) NULL);
                    cmdName, option, " above tagOrId", (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            lastPtr = itemPtr;
            lastPtr = itemPtr;
        }
        }
        if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
        if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
            DoItem(interp, lastPtr->nextPtr, uid);
            DoItem(interp, lastPtr->nextPtr, uid);
        }
        }
    } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0)
    } else if ((c == 'a') && (strncmp(argv[0], "all", length) == 0)
            && (length >= 2)) {
            && (length >= 2)) {
        if (argc != 1) {
        if (argc != 1) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " all", (char *) NULL);
                    cmdName, option, " all", (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
 
 
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
        for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
                itemPtr = itemPtr->nextPtr) {
                itemPtr = itemPtr->nextPtr) {
            DoItem(interp, itemPtr, uid);
            DoItem(interp, itemPtr, uid);
        }
        }
    } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) {
    } else if ((c == 'b') && (strncmp(argv[0], "below", length) == 0)) {
        Tk_Item *itemPtr;
        Tk_Item *itemPtr;
 
 
        if (argc != 2) {
        if (argc != 2) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " below tagOrId", (char *) NULL);
                    cmdName, option, " below tagOrId", (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        if (itemPtr->prevPtr != NULL) {
        if (itemPtr->prevPtr != NULL) {
            DoItem(interp, itemPtr->prevPtr, uid);
            DoItem(interp, itemPtr->prevPtr, uid);
        }
        }
    } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) {
    } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) {
        double closestDist;
        double closestDist;
        Tk_Item *startPtr, *closestPtr;
        Tk_Item *startPtr, *closestPtr;
        double coords[2], halo;
        double coords[2], halo;
        int x1, y1, x2, y2;
        int x1, y1, x2, y2;
 
 
        if ((argc < 3) || (argc > 5)) {
        if ((argc < 3) || (argc > 5)) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " closest x y ?halo? ?start?",
                    cmdName, option, " closest x y ?halo? ?start?",
                    (char *) NULL);
                    (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1],
        if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1],
                &coords[0]) != TCL_OK) || (Tk_CanvasGetCoord(interp,
                &coords[0]) != TCL_OK) || (Tk_CanvasGetCoord(interp,
                (Tk_Canvas) canvasPtr, argv[2], &coords[1]) != TCL_OK)) {
                (Tk_Canvas) canvasPtr, argv[2], &coords[1]) != TCL_OK)) {
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        if (argc > 3) {
        if (argc > 3) {
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
            if (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
                    &halo) != TCL_OK) {
                    &halo) != TCL_OK) {
                return TCL_ERROR;
                return TCL_ERROR;
            }
            }
            if (halo < 0.0) {
            if (halo < 0.0) {
                Tcl_AppendResult(interp, "can't have negative halo value \"",
                Tcl_AppendResult(interp, "can't have negative halo value \"",
                        argv[3], "\"", (char *) NULL);
                        argv[3], "\"", (char *) NULL);
                return TCL_ERROR;
                return TCL_ERROR;
            }
            }
        } else {
        } else {
            halo = 0.0;
            halo = 0.0;
        }
        }
 
 
        /*
        /*
         * Find the item at which to start the search.
         * Find the item at which to start the search.
         */
         */
 
 
        startPtr = canvasPtr->firstItemPtr;
        startPtr = canvasPtr->firstItemPtr;
        if (argc == 5) {
        if (argc == 5) {
            itemPtr = StartTagSearch(canvasPtr, argv[4], &search);
            itemPtr = StartTagSearch(canvasPtr, argv[4], &search);
            if (itemPtr != NULL) {
            if (itemPtr != NULL) {
                startPtr = itemPtr;
                startPtr = itemPtr;
            }
            }
        }
        }
 
 
        /*
        /*
         * The code below is optimized so that it can eliminate most
         * The code below is optimized so that it can eliminate most
         * items without having to call their item-specific procedures.
         * items without having to call their item-specific procedures.
         * This is done by keeping a bounding box (x1, y1, x2, y2) that
         * This is done by keeping a bounding box (x1, y1, x2, y2) that
         * an item's bbox must overlap if the item is to have any
         * an item's bbox must overlap if the item is to have any
         * chance of being closer than the closest so far.
         * chance of being closer than the closest so far.
         */
         */
 
 
        itemPtr = startPtr;
        itemPtr = startPtr;
        if (itemPtr == NULL) {
        if (itemPtr == NULL) {
            return TCL_OK;
            return TCL_OK;
        }
        }
        closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
        closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
                itemPtr, coords) - halo;
                itemPtr, coords) - halo;
        if (closestDist < 0.0) {
        if (closestDist < 0.0) {
            closestDist = 0.0;
            closestDist = 0.0;
        }
        }
        while (1) {
        while (1) {
            double newDist;
            double newDist;
 
 
            /*
            /*
             * Update the bounding box using itemPtr, which is the
             * Update the bounding box using itemPtr, which is the
             * new closest item.
             * new closest item.
             */
             */
 
 
            x1 = (int) (coords[0] - closestDist - halo - 1);
            x1 = (int) (coords[0] - closestDist - halo - 1);
            y1 = (int) (coords[1] - closestDist - halo - 1);
            y1 = (int) (coords[1] - closestDist - halo - 1);
            x2 = (int) (coords[0] + closestDist + halo + 1);
            x2 = (int) (coords[0] + closestDist + halo + 1);
            y2 = (int) (coords[1] + closestDist + halo + 1);
            y2 = (int) (coords[1] + closestDist + halo + 1);
            closestPtr = itemPtr;
            closestPtr = itemPtr;
 
 
            /*
            /*
             * Search for an item that beats the current closest one.
             * Search for an item that beats the current closest one.
             * Work circularly through the canvas's item list until
             * Work circularly through the canvas's item list until
             * getting back to the starting item.
             * getting back to the starting item.
             */
             */
 
 
            while (1) {
            while (1) {
                itemPtr = itemPtr->nextPtr;
                itemPtr = itemPtr->nextPtr;
                if (itemPtr == NULL) {
                if (itemPtr == NULL) {
                    itemPtr = canvasPtr->firstItemPtr;
                    itemPtr = canvasPtr->firstItemPtr;
                }
                }
                if (itemPtr == startPtr) {
                if (itemPtr == startPtr) {
                    DoItem(interp, closestPtr, uid);
                    DoItem(interp, closestPtr, uid);
                    return TCL_OK;
                    return TCL_OK;
                }
                }
                if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
                if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
                        || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
                        || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
                    continue;
                    continue;
                }
                }
                newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
                newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
                        itemPtr, coords) - halo;
                        itemPtr, coords) - halo;
                if (newDist < 0.0) {
                if (newDist < 0.0) {
                    newDist = 0.0;
                    newDist = 0.0;
                }
                }
                if (newDist <= closestDist) {
                if (newDist <= closestDist) {
                    closestDist = newDist;
                    closestDist = newDist;
                    break;
                    break;
                }
                }
            }
            }
        }
        }
    } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) {
    } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) {
        if (argc != 5) {
        if (argc != 5) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL);
                    cmdName, option, " enclosed x1 y1 x2 y2", (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        return FindArea(interp, canvasPtr, argv+1, uid, 1);
        return FindArea(interp, canvasPtr, argv+1, uid, 1);
    } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) {
    } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) {
        if (argc != 5) {
        if (argc != 5) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " overlapping x1 y1 x2 y2",
                    cmdName, option, " overlapping x1 y1 x2 y2",
                    (char *) NULL);
                    (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        return FindArea(interp, canvasPtr, argv+1, uid, 0);
        return FindArea(interp, canvasPtr, argv+1, uid, 0);
    } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) {
    } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) {
                if (argc != 2) {
                if (argc != 2) {
            Tcl_AppendResult(interp, "wrong # args: should be \"",
            Tcl_AppendResult(interp, "wrong # args: should be \"",
                    cmdName, option, " withtag tagOrId", (char *) NULL);
                    cmdName, option, " withtag tagOrId", (char *) NULL);
            return TCL_ERROR;
            return TCL_ERROR;
        }
        }
        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
        for (itemPtr = StartTagSearch(canvasPtr, argv[1], &search);
                itemPtr != NULL; itemPtr = NextItem(&search)) {
                itemPtr != NULL; itemPtr = NextItem(&search)) {
            DoItem(interp, itemPtr, uid);
            DoItem(interp, itemPtr, uid);
        }
        }
    } else  {
    } else  {
        Tcl_AppendResult(interp, "bad search command \"", argv[0],
        Tcl_AppendResult(interp, "bad search command \"", argv[0],
                "\": must be above, all, below, closest, enclosed, ",
                "\": must be above, all, below, closest, enclosed, ",
                "overlapping, or withtag", (char *) NULL);
                "overlapping, or withtag", (char *) NULL);
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
    return TCL_OK;
    return TCL_OK;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * FindArea --
 * FindArea --
 *
 *
 *      This procedure implements area searches for the "find"
 *      This procedure implements area searches for the "find"
 *      and "addtag" options.
 *      and "addtag" options.
 *
 *
 * Results:
 * Results:
 *      A standard Tcl return value.  If newTag is NULL, then a
 *      A standard Tcl return value.  If newTag is NULL, then a
 *      list of ids from all the items overlapping or enclosed
 *      list of ids from all the items overlapping or enclosed
 *      by the rectangle given by argc is returned in interp->result.
 *      by the rectangle given by argc is returned in interp->result.
 *      If newTag is NULL, then the normal interp->result is an
 *      If newTag is NULL, then the normal interp->result is an
 *      empty string.  If an error occurs, then interp->result will
 *      empty string.  If an error occurs, then interp->result will
 *      hold an error message.
 *      hold an error message.
 *
 *
 * Side effects:
 * Side effects:
 *      If uid is non-NULL, then all the items overlapping
 *      If uid is non-NULL, then all the items overlapping
 *      or enclosed by the area in argv have that tag added to
 *      or enclosed by the area in argv have that tag added to
 *      their lists of tags.
 *      their lists of tags.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static int
static int
FindArea(interp, canvasPtr, argv, uid, enclosed)
FindArea(interp, canvasPtr, argv, uid, enclosed)
    Tcl_Interp *interp;                 /* Interpreter for error reporting
    Tcl_Interp *interp;                 /* Interpreter for error reporting
                                         * and result storing. */
                                         * and result storing. */
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
    TkCanvas *canvasPtr;                /* Canvas whose items are to be
                                         * searched. */
                                         * searched. */
    char **argv;                        /* Array of four arguments that
    char **argv;                        /* Array of four arguments that
                                         * give the coordinates of the
                                         * give the coordinates of the
                                         * rectangular area to search. */
                                         * rectangular area to search. */
    Tk_Uid uid;                         /* If non-NULL, gives new tag to set
    Tk_Uid uid;                         /* If non-NULL, gives new tag to set
                                         * on all found items;  if NULL, then
                                         * on all found items;  if NULL, then
                                         * ids of found items are returned
                                         * ids of found items are returned
                                         * in interp->result. */
                                         * in interp->result. */
    int enclosed;                       /* 0 means overlapping or enclosed
    int enclosed;                       /* 0 means overlapping or enclosed
                                         * items are OK, 1 means only enclosed
                                         * items are OK, 1 means only enclosed
                                         * items are OK. */
                                         * items are OK. */
{
{
    double rect[4], tmp;
    double rect[4], tmp;
    int x1, y1, x2, y2;
    int x1, y1, x2, y2;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
 
 
    if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0],
    if ((Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[0],
                &rect[0]) != TCL_OK)
                &rect[0]) != TCL_OK)
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1],
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[1],
                &rect[1]) != TCL_OK)
                &rect[1]) != TCL_OK)
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2],
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[2],
                &rect[2]) != TCL_OK)
                &rect[2]) != TCL_OK)
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
            || (Tk_CanvasGetCoord(interp, (Tk_Canvas) canvasPtr, argv[3],
                &rect[3]) != TCL_OK)) {
                &rect[3]) != TCL_OK)) {
        return TCL_ERROR;
        return TCL_ERROR;
    }
    }
    if (rect[0] > rect[2]) {
    if (rect[0] > rect[2]) {
        tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
        tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
    }
    }
    if (rect[1] > rect[3]) {
    if (rect[1] > rect[3]) {
        tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
        tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
    }
    }
 
 
    /*
    /*
     * Use an integer bounding box for a quick test, to avoid
     * Use an integer bounding box for a quick test, to avoid
     * calling item-specific code except for items that are close.
     * calling item-specific code except for items that are close.
     */
     */
 
 
    x1 = (int) (rect[0]-1.0);
    x1 = (int) (rect[0]-1.0);
    y1 = (int) (rect[1]-1.0);
    y1 = (int) (rect[1]-1.0);
    x2 = (int) (rect[2]+1.0);
    x2 = (int) (rect[2]+1.0);
    y2 = (int) (rect[3]+1.0);
    y2 = (int) (rect[3]+1.0);
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
            itemPtr = itemPtr->nextPtr) {
            itemPtr = itemPtr->nextPtr) {
        if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
        if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
                || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
                || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
            continue;
            continue;
        }
        }
        if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect)
        if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect)
                >= enclosed) {
                >= enclosed) {
            DoItem(interp, itemPtr, uid);
            DoItem(interp, itemPtr, uid);
        }
        }
    }
    }
    return TCL_OK;
    return TCL_OK;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * RelinkItems --
 * RelinkItems --
 *
 *
 *      Move one or more items to a different place in the
 *      Move one or more items to a different place in the
 *      display order for a canvas.
 *      display order for a canvas.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The items identified by "tag" are moved so that they
 *      The items identified by "tag" are moved so that they
 *      are all together in the display list and immediately
 *      are all together in the display list and immediately
 *      after prevPtr.  The order of the moved items relative
 *      after prevPtr.  The order of the moved items relative
 *      to each other is not changed.
 *      to each other is not changed.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
RelinkItems(canvasPtr, tag, prevPtr)
RelinkItems(canvasPtr, tag, prevPtr)
    TkCanvas *canvasPtr;        /* Canvas to be modified. */
    TkCanvas *canvasPtr;        /* Canvas to be modified. */
    char *tag;                  /* Tag identifying items to be moved
    char *tag;                  /* Tag identifying items to be moved
                                 * in the redisplay list. */
                                 * in the redisplay list. */
    Tk_Item *prevPtr;           /* Reposition the items so that they
    Tk_Item *prevPtr;           /* Reposition the items so that they
                                 * go just after this item (NULL means
                                 * go just after this item (NULL means
                                 * put at beginning of list). */
                                 * put at beginning of list). */
{
{
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
    TagSearch search;
    TagSearch search;
    Tk_Item *firstMovePtr, *lastMovePtr;
    Tk_Item *firstMovePtr, *lastMovePtr;
 
 
    /*
    /*
     * Find all of the items to be moved and remove them from
     * Find all of the items to be moved and remove them from
     * the list, making an auxiliary list running from firstMovePtr
     * the list, making an auxiliary list running from firstMovePtr
     * to lastMovePtr.  Record their areas for redisplay.
     * to lastMovePtr.  Record their areas for redisplay.
     */
     */
 
 
    firstMovePtr = lastMovePtr = NULL;
    firstMovePtr = lastMovePtr = NULL;
    for (itemPtr = StartTagSearch(canvasPtr, tag, &search);
    for (itemPtr = StartTagSearch(canvasPtr, tag, &search);
            itemPtr != NULL; itemPtr = NextItem(&search)) {
            itemPtr != NULL; itemPtr = NextItem(&search)) {
        if (itemPtr == prevPtr) {
        if (itemPtr == prevPtr) {
            /*
            /*
             * Item after which insertion is to occur is being
             * Item after which insertion is to occur is being
             * moved!  Switch to insert after its predecessor.
             * moved!  Switch to insert after its predecessor.
             */
             */
 
 
            prevPtr = prevPtr->prevPtr;
            prevPtr = prevPtr->prevPtr;
        }
        }
        if (itemPtr->prevPtr == NULL) {
        if (itemPtr->prevPtr == NULL) {
            if (itemPtr->nextPtr != NULL) {
            if (itemPtr->nextPtr != NULL) {
                itemPtr->nextPtr->prevPtr = NULL;
                itemPtr->nextPtr->prevPtr = NULL;
            }
            }
            canvasPtr->firstItemPtr = itemPtr->nextPtr;
            canvasPtr->firstItemPtr = itemPtr->nextPtr;
        } else {
        } else {
            if (itemPtr->nextPtr != NULL) {
            if (itemPtr->nextPtr != NULL) {
                itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
                itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
            }
            }
            itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
            itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
        }
        }
        if (canvasPtr->lastItemPtr == itemPtr) {
        if (canvasPtr->lastItemPtr == itemPtr) {
            canvasPtr->lastItemPtr = itemPtr->prevPtr;
            canvasPtr->lastItemPtr = itemPtr->prevPtr;
        }
        }
        if (firstMovePtr == NULL) {
        if (firstMovePtr == NULL) {
            itemPtr->prevPtr = NULL;
            itemPtr->prevPtr = NULL;
            firstMovePtr = itemPtr;
            firstMovePtr = itemPtr;
        } else {
        } else {
            itemPtr->prevPtr = lastMovePtr;
            itemPtr->prevPtr = lastMovePtr;
            lastMovePtr->nextPtr = itemPtr;
            lastMovePtr->nextPtr = itemPtr;
        }
        }
        lastMovePtr = itemPtr;
        lastMovePtr = itemPtr;
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, itemPtr->x1, itemPtr->y1,
                itemPtr->x2, itemPtr->y2);
                itemPtr->x2, itemPtr->y2);
        canvasPtr->flags |= REPICK_NEEDED;
        canvasPtr->flags |= REPICK_NEEDED;
    }
    }
 
 
    /*
    /*
     * Insert the list of to-be-moved items back into the canvas's
     * Insert the list of to-be-moved items back into the canvas's
     * at the desired position.
     * at the desired position.
     */
     */
 
 
    if (firstMovePtr == NULL) {
    if (firstMovePtr == NULL) {
        return;
        return;
    }
    }
    if (prevPtr == NULL) {
    if (prevPtr == NULL) {
        if (canvasPtr->firstItemPtr != NULL) {
        if (canvasPtr->firstItemPtr != NULL) {
            canvasPtr->firstItemPtr->prevPtr = lastMovePtr;
            canvasPtr->firstItemPtr->prevPtr = lastMovePtr;
        }
        }
        lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
        lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
        canvasPtr->firstItemPtr = firstMovePtr;
        canvasPtr->firstItemPtr = firstMovePtr;
    } else {
    } else {
        if (prevPtr->nextPtr != NULL) {
        if (prevPtr->nextPtr != NULL) {
            prevPtr->nextPtr->prevPtr = lastMovePtr;
            prevPtr->nextPtr->prevPtr = lastMovePtr;
        }
        }
        lastMovePtr->nextPtr = prevPtr->nextPtr;
        lastMovePtr->nextPtr = prevPtr->nextPtr;
        if (firstMovePtr != NULL) {
        if (firstMovePtr != NULL) {
            firstMovePtr->prevPtr = prevPtr;
            firstMovePtr->prevPtr = prevPtr;
        }
        }
        prevPtr->nextPtr = firstMovePtr;
        prevPtr->nextPtr = firstMovePtr;
    }
    }
    if (canvasPtr->lastItemPtr == prevPtr) {
    if (canvasPtr->lastItemPtr == prevPtr) {
        canvasPtr->lastItemPtr = lastMovePtr;
        canvasPtr->lastItemPtr = lastMovePtr;
    }
    }
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasBindProc --
 * CanvasBindProc --
 *
 *
 *      This procedure is invoked by the Tk dispatcher to handle
 *      This procedure is invoked by the Tk dispatcher to handle
 *      events associated with bindings on items.
 *      events associated with bindings on items.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Depends on the command invoked as part of the binding
 *      Depends on the command invoked as part of the binding
 *      (if there was any).
 *      (if there was any).
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasBindProc(clientData, eventPtr)
CanvasBindProc(clientData, eventPtr)
    ClientData clientData;              /* Pointer to canvas structure. */
    ClientData clientData;              /* Pointer to canvas structure. */
    XEvent *eventPtr;                   /* Pointer to X event that just
    XEvent *eventPtr;                   /* Pointer to X event that just
                                         * happened. */
                                         * happened. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
 
 
    Tcl_Preserve((ClientData) canvasPtr);
    Tcl_Preserve((ClientData) canvasPtr);
 
 
    /*
    /*
     * This code below keeps track of the current modifier state in
     * This code below keeps track of the current modifier state in
     * canvasPtr>state.  This information is used to defer repicks of
     * canvasPtr>state.  This information is used to defer repicks of
     * the current item while buttons are down.
     * the current item while buttons are down.
     */
     */
 
 
    if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
    if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
        int mask;
        int mask;
 
 
        switch (eventPtr->xbutton.button) {
        switch (eventPtr->xbutton.button) {
            case Button1:
            case Button1:
                mask = Button1Mask;
                mask = Button1Mask;
                break;
                break;
            case Button2:
            case Button2:
                mask = Button2Mask;
                mask = Button2Mask;
                break;
                break;
            case Button3:
            case Button3:
                mask = Button3Mask;
                mask = Button3Mask;
                break;
                break;
            case Button4:
            case Button4:
                mask = Button4Mask;
                mask = Button4Mask;
                break;
                break;
            case Button5:
            case Button5:
                mask = Button5Mask;
                mask = Button5Mask;
                break;
                break;
            default:
            default:
                mask = 0;
                mask = 0;
                break;
                break;
        }
        }
 
 
        /*
        /*
         * For button press events, repick the current item using the
         * For button press events, repick the current item using the
         * button state before the event, then process the event.  For
         * button state before the event, then process the event.  For
         * button release events, first process the event, then repick
         * button release events, first process the event, then repick
         * the current item using the button state *after* the event
         * the current item using the button state *after* the event
         * (the button has logically gone up before we change the
         * (the button has logically gone up before we change the
         * current item).
         * current item).
         */
         */
 
 
        if (eventPtr->type == ButtonPress) {
        if (eventPtr->type == ButtonPress) {
            /*
            /*
             * On a button press, first repick the current item using
             * On a button press, first repick the current item using
             * the button state before the event, the process the event.
             * the button state before the event, the process the event.
             */
             */
 
 
            canvasPtr->state = eventPtr->xbutton.state;
            canvasPtr->state = eventPtr->xbutton.state;
            PickCurrentItem(canvasPtr, eventPtr);
            PickCurrentItem(canvasPtr, eventPtr);
            canvasPtr->state ^= mask;
            canvasPtr->state ^= mask;
            CanvasDoEvent(canvasPtr, eventPtr);
            CanvasDoEvent(canvasPtr, eventPtr);
        } else {
        } else {
            /*
            /*
             * Button release: first process the event, with the button
             * Button release: first process the event, with the button
             * still considered to be down.  Then repick the current
             * still considered to be down.  Then repick the current
             * item under the assumption that the button is no longer down.
             * item under the assumption that the button is no longer down.
             */
             */
 
 
            canvasPtr->state = eventPtr->xbutton.state;
            canvasPtr->state = eventPtr->xbutton.state;
            CanvasDoEvent(canvasPtr, eventPtr);
            CanvasDoEvent(canvasPtr, eventPtr);
            eventPtr->xbutton.state ^= mask;
            eventPtr->xbutton.state ^= mask;
            canvasPtr->state = eventPtr->xbutton.state;
            canvasPtr->state = eventPtr->xbutton.state;
            PickCurrentItem(canvasPtr, eventPtr);
            PickCurrentItem(canvasPtr, eventPtr);
            eventPtr->xbutton.state ^= mask;
            eventPtr->xbutton.state ^= mask;
        }
        }
        goto done;
        goto done;
    } else if ((eventPtr->type == EnterNotify)
    } else if ((eventPtr->type == EnterNotify)
            || (eventPtr->type == LeaveNotify)) {
            || (eventPtr->type == LeaveNotify)) {
        canvasPtr->state = eventPtr->xcrossing.state;
        canvasPtr->state = eventPtr->xcrossing.state;
        PickCurrentItem(canvasPtr, eventPtr);
        PickCurrentItem(canvasPtr, eventPtr);
        goto done;
        goto done;
    } else if (eventPtr->type == MotionNotify) {
    } else if (eventPtr->type == MotionNotify) {
        canvasPtr->state = eventPtr->xmotion.state;
        canvasPtr->state = eventPtr->xmotion.state;
        PickCurrentItem(canvasPtr, eventPtr);
        PickCurrentItem(canvasPtr, eventPtr);
    }
    }
    CanvasDoEvent(canvasPtr, eventPtr);
    CanvasDoEvent(canvasPtr, eventPtr);
 
 
    done:
    done:
    Tcl_Release((ClientData) canvasPtr);
    Tcl_Release((ClientData) canvasPtr);
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * PickCurrentItem --
 * PickCurrentItem --
 *
 *
 *      Find the topmost item in a canvas that contains a given
 *      Find the topmost item in a canvas that contains a given
 *      location and mark the the current item.  If the current
 *      location and mark the the current item.  If the current
 *      item has changed, generate a fake exit event on the old
 *      item has changed, generate a fake exit event on the old
 *      current item and a fake enter event on the new current
 *      current item and a fake enter event on the new current
 *      item.
 *      item.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The current item for canvasPtr may change.  If it does,
 *      The current item for canvasPtr may change.  If it does,
 *      then the commands associated with item entry and exit
 *      then the commands associated with item entry and exit
 *      could do just about anything.  A binding script could
 *      could do just about anything.  A binding script could
 *      delete the canvas, so callers should protect themselves
 *      delete the canvas, so callers should protect themselves
 *      with Tcl_Preserve and Tcl_Release.
 *      with Tcl_Preserve and Tcl_Release.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
PickCurrentItem(canvasPtr, eventPtr)
PickCurrentItem(canvasPtr, eventPtr)
    TkCanvas *canvasPtr;                /* Canvas widget in which to select
    TkCanvas *canvasPtr;                /* Canvas widget in which to select
                                         * current item. */
                                         * current item. */
    XEvent *eventPtr;                   /* Event describing location of
    XEvent *eventPtr;                   /* Event describing location of
                                         * mouse cursor.  Must be EnterWindow,
                                         * mouse cursor.  Must be EnterWindow,
                                         * LeaveWindow, ButtonRelease, or
                                         * LeaveWindow, ButtonRelease, or
                                         * MotionNotify. */
                                         * MotionNotify. */
{
{
    double coords[2];
    double coords[2];
    int buttonDown;
    int buttonDown;
 
 
    /*
    /*
     * Check whether or not a button is down.  If so, we'll log entry
     * Check whether or not a button is down.  If so, we'll log entry
     * and exit into and out of the current item, but not entry into
     * and exit into and out of the current item, but not entry into
     * any other item.  This implements a form of grabbing equivalent
     * any other item.  This implements a form of grabbing equivalent
     * to what the X server does for windows.
     * to what the X server does for windows.
     */
     */
 
 
    buttonDown = canvasPtr->state
    buttonDown = canvasPtr->state
            & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
            & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
    if (!buttonDown) {
    if (!buttonDown) {
        canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
        canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
    }
    }
 
 
    /*
    /*
     * Save information about this event in the canvas.  The event in
     * Save information about this event in the canvas.  The event in
     * the canvas is used for two purposes:
     * the canvas is used for two purposes:
     *
     *
     * 1. Event bindings: if the current item changes, fake events are
     * 1. Event bindings: if the current item changes, fake events are
     *    generated to allow item-enter and item-leave bindings to trigger.
     *    generated to allow item-enter and item-leave bindings to trigger.
     * 2. Reselection: if the current item gets deleted, can use the
     * 2. Reselection: if the current item gets deleted, can use the
     *    saved event to find a new current item.
     *    saved event to find a new current item.
     * Translate MotionNotify events into EnterNotify events, since that's
     * Translate MotionNotify events into EnterNotify events, since that's
     * what gets reported to item handlers.
     * what gets reported to item handlers.
     */
     */
 
 
    if (eventPtr != &canvasPtr->pickEvent) {
    if (eventPtr != &canvasPtr->pickEvent) {
        if ((eventPtr->type == MotionNotify)
        if ((eventPtr->type == MotionNotify)
                || (eventPtr->type == ButtonRelease)) {
                || (eventPtr->type == ButtonRelease)) {
            canvasPtr->pickEvent.xcrossing.type = EnterNotify;
            canvasPtr->pickEvent.xcrossing.type = EnterNotify;
            canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
            canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
            canvasPtr->pickEvent.xcrossing.send_event
            canvasPtr->pickEvent.xcrossing.send_event
                    = eventPtr->xmotion.send_event;
                    = eventPtr->xmotion.send_event;
            canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
            canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
            canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
            canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
            canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
            canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
            canvasPtr->pickEvent.xcrossing.subwindow = None;
            canvasPtr->pickEvent.xcrossing.subwindow = None;
            canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
            canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
            canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
            canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
            canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
            canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
            canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
            canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
            canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
            canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
            canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
            canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
            canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
            canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
            canvasPtr->pickEvent.xcrossing.same_screen
            canvasPtr->pickEvent.xcrossing.same_screen
                    = eventPtr->xmotion.same_screen;
                    = eventPtr->xmotion.same_screen;
            canvasPtr->pickEvent.xcrossing.focus = False;
            canvasPtr->pickEvent.xcrossing.focus = False;
            canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
            canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
        } else  {
        } else  {
            canvasPtr->pickEvent = *eventPtr;
            canvasPtr->pickEvent = *eventPtr;
        }
        }
    }
    }
 
 
    /*
    /*
     * If this is a recursive call (there's already a partially completed
     * If this is a recursive call (there's already a partially completed
     * call pending on the stack;  it's in the middle of processing a
     * call pending on the stack;  it's in the middle of processing a
     * Leave event handler for the old current item) then just return;
     * Leave event handler for the old current item) then just return;
     * the pending call will do everything that's needed.
     * the pending call will do everything that's needed.
     */
     */
 
 
    if (canvasPtr->flags & REPICK_IN_PROGRESS) {
    if (canvasPtr->flags & REPICK_IN_PROGRESS) {
        return;
        return;
    }
    }
 
 
    /*
    /*
     * A LeaveNotify event automatically means that there's no current
     * A LeaveNotify event automatically means that there's no current
     * object, so the check for closest item can be skipped.
     * object, so the check for closest item can be skipped.
     */
     */
 
 
    coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
    coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
    coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
    coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
    if (canvasPtr->pickEvent.type != LeaveNotify) {
    if (canvasPtr->pickEvent.type != LeaveNotify) {
        canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);
        canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);
    } else {
    } else {
        canvasPtr->newCurrentPtr = NULL;
        canvasPtr->newCurrentPtr = NULL;
    }
    }
 
 
    if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)
    if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)
            && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
            && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
        /*
        /*
         * Nothing to do:  the current item hasn't changed.
         * Nothing to do:  the current item hasn't changed.
         */
         */
 
 
        return;
        return;
    }
    }
 
 
    /*
    /*
     * Simulate a LeaveNotify event on the previous current item and
     * Simulate a LeaveNotify event on the previous current item and
     * an EnterNotify event on the new current item.  Remove the "current"
     * an EnterNotify event on the new current item.  Remove the "current"
     * tag from the previous current item and place it on the new current
     * tag from the previous current item and place it on the new current
     * item.
     * item.
     */
     */
 
 
    if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)
    if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)
            && (canvasPtr->currentItemPtr != NULL)
            && (canvasPtr->currentItemPtr != NULL)
            && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
            && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
        XEvent event;
        XEvent event;
        Tk_Item *itemPtr = canvasPtr->currentItemPtr;
        Tk_Item *itemPtr = canvasPtr->currentItemPtr;
        int i;
        int i;
 
 
        event = canvasPtr->pickEvent;
        event = canvasPtr->pickEvent;
        event.type = LeaveNotify;
        event.type = LeaveNotify;
 
 
        /*
        /*
         * If the event's detail happens to be NotifyInferior the
         * If the event's detail happens to be NotifyInferior the
         * binding mechanism will discard the event.  To be consistent,
         * binding mechanism will discard the event.  To be consistent,
         * always use NotifyAncestor.
         * always use NotifyAncestor.
         */
         */
 
 
        event.xcrossing.detail = NotifyAncestor;
        event.xcrossing.detail = NotifyAncestor;
        canvasPtr->flags |= REPICK_IN_PROGRESS;
        canvasPtr->flags |= REPICK_IN_PROGRESS;
        CanvasDoEvent(canvasPtr, &event);
        CanvasDoEvent(canvasPtr, &event);
        canvasPtr->flags &= ~REPICK_IN_PROGRESS;
        canvasPtr->flags &= ~REPICK_IN_PROGRESS;
 
 
        /*
        /*
         * The check below is needed because there could be an event
         * The check below is needed because there could be an event
         * handler for <LeaveNotify> that deletes the current item.
         * handler for <LeaveNotify> that deletes the current item.
         */
         */
 
 
        if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {
        if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {
            for (i = itemPtr->numTags-1; i >= 0; i--) {
            for (i = itemPtr->numTags-1; i >= 0; i--) {
                if (itemPtr->tagPtr[i] == currentUid) {
                if (itemPtr->tagPtr[i] == currentUid) {
                    itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
                    itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
                    itemPtr->numTags--;
                    itemPtr->numTags--;
                    break;
                    break;
                }
                }
            }
            }
        }
        }
 
 
        /*
        /*
         * Note:  during CanvasDoEvent above, it's possible that
         * Note:  during CanvasDoEvent above, it's possible that
         * canvasPtr->newCurrentPtr got reset to NULL because the
         * canvasPtr->newCurrentPtr got reset to NULL because the
         * item was deleted.
         * item was deleted.
         */
         */
    }
    }
    if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) {
    if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) {
        canvasPtr->flags |= LEFT_GRABBED_ITEM;
        canvasPtr->flags |= LEFT_GRABBED_ITEM;
        return;
        return;
    }
    }
 
 
    /*
    /*
     * Special note:  it's possible that canvasPtr->newCurrentPtr ==
     * Special note:  it's possible that canvasPtr->newCurrentPtr ==
     * canvasPtr->currentItemPtr here.  This can happen, for example,
     * canvasPtr->currentItemPtr here.  This can happen, for example,
     * if LEFT_GRABBED_ITEM was set.
     * if LEFT_GRABBED_ITEM was set.
     */
     */
 
 
    canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
    canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
    canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;
    canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;
    if (canvasPtr->currentItemPtr != NULL) {
    if (canvasPtr->currentItemPtr != NULL) {
        XEvent event;
        XEvent event;
 
 
        DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid);
        DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid);
        event = canvasPtr->pickEvent;
        event = canvasPtr->pickEvent;
        event.type = EnterNotify;
        event.type = EnterNotify;
        event.xcrossing.detail = NotifyAncestor;
        event.xcrossing.detail = NotifyAncestor;
        CanvasDoEvent(canvasPtr, &event);
        CanvasDoEvent(canvasPtr, &event);
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasFindClosest --
 * CanvasFindClosest --
 *
 *
 *      Given x and y coordinates, find the topmost canvas item that
 *      Given x and y coordinates, find the topmost canvas item that
 *      is "close" to the coordinates.
 *      is "close" to the coordinates.
 *
 *
 * Results:
 * Results:
 *      The return value is a pointer to the topmost item that is
 *      The return value is a pointer to the topmost item that is
 *      close to (x,y), or NULL if no item is close.
 *      close to (x,y), or NULL if no item is close.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static Tk_Item *
static Tk_Item *
CanvasFindClosest(canvasPtr, coords)
CanvasFindClosest(canvasPtr, coords)
    TkCanvas *canvasPtr;                /* Canvas widget to search. */
    TkCanvas *canvasPtr;                /* Canvas widget to search. */
    double coords[2];                   /* Desired x,y position in canvas,
    double coords[2];                   /* Desired x,y position in canvas,
                                         * not screen, coordinates.) */
                                         * not screen, coordinates.) */
{
{
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
    Tk_Item *bestPtr;
    Tk_Item *bestPtr;
    int x1, y1, x2, y2;
    int x1, y1, x2, y2;
 
 
    x1 = (int) (coords[0] - canvasPtr->closeEnough);
    x1 = (int) (coords[0] - canvasPtr->closeEnough);
    y1 = (int) (coords[1] - canvasPtr->closeEnough);
    y1 = (int) (coords[1] - canvasPtr->closeEnough);
    x2 = (int) (coords[0] + canvasPtr->closeEnough);
    x2 = (int) (coords[0] + canvasPtr->closeEnough);
    y2 = (int) (coords[1] + canvasPtr->closeEnough);
    y2 = (int) (coords[1] + canvasPtr->closeEnough);
 
 
    bestPtr = NULL;
    bestPtr = NULL;
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
    for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
            itemPtr = itemPtr->nextPtr) {
            itemPtr = itemPtr->nextPtr) {
        if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)
        if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)
                || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {
                || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {
            continue;
            continue;
        }
        }
        if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
        if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
                itemPtr, coords) <= canvasPtr->closeEnough) {
                itemPtr, coords) <= canvasPtr->closeEnough) {
            bestPtr = itemPtr;
            bestPtr = itemPtr;
        }
        }
    }
    }
    return bestPtr;
    return bestPtr;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasDoEvent --
 * CanvasDoEvent --
 *
 *
 *      This procedure is called to invoke binding processing
 *      This procedure is called to invoke binding processing
 *      for a new event that is associated with the current item
 *      for a new event that is associated with the current item
 *      for a canvas.
 *      for a canvas.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      Depends on the bindings for the canvas.  A binding script
 *      Depends on the bindings for the canvas.  A binding script
 *      could delete the canvas, so callers should protect themselves
 *      could delete the canvas, so callers should protect themselves
 *      with Tcl_Preserve and Tcl_Release.
 *      with Tcl_Preserve and Tcl_Release.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasDoEvent(canvasPtr, eventPtr)
CanvasDoEvent(canvasPtr, eventPtr)
    TkCanvas *canvasPtr;                /* Canvas widget in which event
    TkCanvas *canvasPtr;                /* Canvas widget in which event
                                         * occurred. */
                                         * occurred. */
    XEvent *eventPtr;                   /* Real or simulated X event that
    XEvent *eventPtr;                   /* Real or simulated X event that
                                         * is to be processed. */
                                         * is to be processed. */
{
{
#define NUM_STATIC 3
#define NUM_STATIC 3
    ClientData staticObjects[NUM_STATIC];
    ClientData staticObjects[NUM_STATIC];
    ClientData *objectPtr;
    ClientData *objectPtr;
    int numObjects, i;
    int numObjects, i;
    Tk_Item *itemPtr;
    Tk_Item *itemPtr;
 
 
    if (canvasPtr->bindingTable == NULL) {
    if (canvasPtr->bindingTable == NULL) {
        return;
        return;
    }
    }
 
 
    itemPtr = canvasPtr->currentItemPtr;
    itemPtr = canvasPtr->currentItemPtr;
    if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
    if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
        itemPtr = canvasPtr->textInfo.focusItemPtr;
        itemPtr = canvasPtr->textInfo.focusItemPtr;
    }
    }
    if (itemPtr == NULL) {
    if (itemPtr == NULL) {
        return;
        return;
    }
    }
 
 
    /*
    /*
     * Set up an array with all the relevant objects for processing
     * Set up an array with all the relevant objects for processing
     * this event.  The relevant objects are (a) the event's item,
     * this event.  The relevant objects are (a) the event's item,
     * (b) the tags associated with the event's item, and (c) the
     * (b) the tags associated with the event's item, and (c) the
     * tag "all".  If there are a lot of tags then malloc an array
     * tag "all".  If there are a lot of tags then malloc an array
     * to hold all of the objects.
     * to hold all of the objects.
     */
     */
 
 
    numObjects = itemPtr->numTags + 2;
    numObjects = itemPtr->numTags + 2;
    if (numObjects <= NUM_STATIC) {
    if (numObjects <= NUM_STATIC) {
        objectPtr = staticObjects;
        objectPtr = staticObjects;
    } else {
    } else {
        objectPtr = (ClientData *) ckalloc((unsigned)
        objectPtr = (ClientData *) ckalloc((unsigned)
                (numObjects * sizeof(ClientData)));
                (numObjects * sizeof(ClientData)));
    }
    }
    objectPtr[0] = (ClientData) allUid;
    objectPtr[0] = (ClientData) allUid;
    for (i = itemPtr->numTags-1; i >= 0; i--) {
    for (i = itemPtr->numTags-1; i >= 0; i--) {
        objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
        objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
    }
    }
    objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr;
    objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr;
 
 
    /*
    /*
     * Invoke the binding system, then free up the object array if
     * Invoke the binding system, then free up the object array if
     * it was malloc-ed.
     * it was malloc-ed.
     */
     */
 
 
    if (canvasPtr->tkwin != NULL) {
    if (canvasPtr->tkwin != NULL) {
        Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
        Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
                numObjects, objectPtr);
                numObjects, objectPtr);
    }
    }
    if (objectPtr != staticObjects) {
    if (objectPtr != staticObjects) {
        ckfree((char *) objectPtr);
        ckfree((char *) objectPtr);
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasBlinkProc --
 * CanvasBlinkProc --
 *
 *
 *      This procedure is called as a timer handler to blink the
 *      This procedure is called as a timer handler to blink the
 *      insertion cursor off and on.
 *      insertion cursor off and on.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The cursor gets turned on or off, redisplay gets invoked,
 *      The cursor gets turned on or off, redisplay gets invoked,
 *      and this procedure reschedules itself.
 *      and this procedure reschedules itself.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasBlinkProc(clientData)
CanvasBlinkProc(clientData)
    ClientData clientData;      /* Pointer to record describing entry. */
    ClientData clientData;      /* Pointer to record describing entry. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
 
 
    if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {
    if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {
        return;
        return;
    }
    }
    if (canvasPtr->textInfo.cursorOn) {
    if (canvasPtr->textInfo.cursorOn) {
        canvasPtr->textInfo.cursorOn = 0;
        canvasPtr->textInfo.cursorOn = 0;
        canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
        canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
                canvasPtr->insertOffTime, CanvasBlinkProc,
                canvasPtr->insertOffTime, CanvasBlinkProc,
                (ClientData) canvasPtr);
                (ClientData) canvasPtr);
    } else {
    } else {
        canvasPtr->textInfo.cursorOn = 1;
        canvasPtr->textInfo.cursorOn = 1;
        canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
        canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
                canvasPtr->insertOnTime, CanvasBlinkProc,
                canvasPtr->insertOnTime, CanvasBlinkProc,
                (ClientData) canvasPtr);
                (ClientData) canvasPtr);
    }
    }
    if (canvasPtr->textInfo.focusItemPtr != NULL) {
    if (canvasPtr->textInfo.focusItemPtr != NULL) {
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                canvasPtr->textInfo.focusItemPtr->x1,
                canvasPtr->textInfo.focusItemPtr->x1,
                canvasPtr->textInfo.focusItemPtr->y1,
                canvasPtr->textInfo.focusItemPtr->y1,
                canvasPtr->textInfo.focusItemPtr->x2,
                canvasPtr->textInfo.focusItemPtr->x2,
                canvasPtr->textInfo.focusItemPtr->y2);
                canvasPtr->textInfo.focusItemPtr->y2);
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasFocusProc --
 * CanvasFocusProc --
 *
 *
 *      This procedure is called whenever a canvas gets or loses the
 *      This procedure is called whenever a canvas gets or loses the
 *      input focus.  It's also called whenever the window is
 *      input focus.  It's also called whenever the window is
 *      reconfigured while it has the focus.
 *      reconfigured while it has the focus.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The cursor gets turned on or off.
 *      The cursor gets turned on or off.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasFocusProc(canvasPtr, gotFocus)
CanvasFocusProc(canvasPtr, gotFocus)
    TkCanvas *canvasPtr;        /* Canvas that just got or lost focus. */
    TkCanvas *canvasPtr;        /* Canvas that just got or lost focus. */
    int gotFocus;               /* 1 means window is getting focus, 0 means
    int gotFocus;               /* 1 means window is getting focus, 0 means
                                 * it's losing it. */
                                 * it's losing it. */
{
{
    Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
    Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
    if (gotFocus) {
    if (gotFocus) {
        canvasPtr->textInfo.gotFocus = 1;
        canvasPtr->textInfo.gotFocus = 1;
        canvasPtr->textInfo.cursorOn = 1;
        canvasPtr->textInfo.cursorOn = 1;
        if (canvasPtr->insertOffTime != 0) {
        if (canvasPtr->insertOffTime != 0) {
            canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
            canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
                    canvasPtr->insertOffTime, CanvasBlinkProc,
                    canvasPtr->insertOffTime, CanvasBlinkProc,
                    (ClientData) canvasPtr);
                    (ClientData) canvasPtr);
        }
        }
    } else {
    } else {
        canvasPtr->textInfo.gotFocus = 0;
        canvasPtr->textInfo.gotFocus = 0;
        canvasPtr->textInfo.cursorOn = 0;
        canvasPtr->textInfo.cursorOn = 0;
        canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
        canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
    }
    }
    if (canvasPtr->textInfo.focusItemPtr != NULL) {
    if (canvasPtr->textInfo.focusItemPtr != NULL) {
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                canvasPtr->textInfo.focusItemPtr->x1,
                canvasPtr->textInfo.focusItemPtr->x1,
                canvasPtr->textInfo.focusItemPtr->y1,
                canvasPtr->textInfo.focusItemPtr->y1,
                canvasPtr->textInfo.focusItemPtr->x2,
                canvasPtr->textInfo.focusItemPtr->x2,
                canvasPtr->textInfo.focusItemPtr->y2);
                canvasPtr->textInfo.focusItemPtr->y2);
    }
    }
    if (canvasPtr->highlightWidth > 0) {
    if (canvasPtr->highlightWidth > 0) {
        canvasPtr->flags |= REDRAW_BORDERS;
        canvasPtr->flags |= REDRAW_BORDERS;
        if (!(canvasPtr->flags & REDRAW_PENDING)) {
        if (!(canvasPtr->flags & REDRAW_PENDING)) {
            Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
            Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
            canvasPtr->flags |= REDRAW_PENDING;
            canvasPtr->flags |= REDRAW_PENDING;
        }
        }
    }
    }
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasSelectTo --
 * CanvasSelectTo --
 *
 *
 *      Modify the selection by moving its un-anchored end.  This could
 *      Modify the selection by moving its un-anchored end.  This could
 *      make the selection either larger or smaller.
 *      make the selection either larger or smaller.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The selection changes.
 *      The selection changes.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasSelectTo(canvasPtr, itemPtr, index)
CanvasSelectTo(canvasPtr, itemPtr, index)
    TkCanvas *canvasPtr;        /* Information about widget. */
    TkCanvas *canvasPtr;        /* Information about widget. */
    Tk_Item *itemPtr;           /* Item that is to hold selection. */
    Tk_Item *itemPtr;           /* Item that is to hold selection. */
    int index;                  /* Index of element that is to become the
    int index;                  /* Index of element that is to become the
                                 * "other" end of the selection. */
                                 * "other" end of the selection. */
{
{
    int oldFirst, oldLast;
    int oldFirst, oldLast;
    Tk_Item *oldSelPtr;
    Tk_Item *oldSelPtr;
 
 
    oldFirst = canvasPtr->textInfo.selectFirst;
    oldFirst = canvasPtr->textInfo.selectFirst;
    oldLast = canvasPtr->textInfo.selectLast;
    oldLast = canvasPtr->textInfo.selectLast;
    oldSelPtr = canvasPtr->textInfo.selItemPtr;
    oldSelPtr = canvasPtr->textInfo.selItemPtr;
 
 
    /*
    /*
     * Grab the selection if we don't own it already.
     * Grab the selection if we don't own it already.
     */
     */
 
 
    if (canvasPtr->textInfo.selItemPtr == NULL) {
    if (canvasPtr->textInfo.selItemPtr == NULL) {
        Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
        Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
                (ClientData) canvasPtr);
                (ClientData) canvasPtr);
    } else if (canvasPtr->textInfo.selItemPtr != itemPtr) {
    } else if (canvasPtr->textInfo.selItemPtr != itemPtr) {
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                canvasPtr->textInfo.selItemPtr->x1,
                canvasPtr->textInfo.selItemPtr->x1,
                canvasPtr->textInfo.selItemPtr->y1,
                canvasPtr->textInfo.selItemPtr->y1,
                canvasPtr->textInfo.selItemPtr->x2,
                canvasPtr->textInfo.selItemPtr->x2,
                canvasPtr->textInfo.selItemPtr->y2);
                canvasPtr->textInfo.selItemPtr->y2);
    }
    }
    canvasPtr->textInfo.selItemPtr = itemPtr;
    canvasPtr->textInfo.selItemPtr = itemPtr;
 
 
    if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {
    if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {
        canvasPtr->textInfo.anchorItemPtr = itemPtr;
        canvasPtr->textInfo.anchorItemPtr = itemPtr;
        canvasPtr->textInfo.selectAnchor = index;
        canvasPtr->textInfo.selectAnchor = index;
    }
    }
    if (canvasPtr->textInfo.selectAnchor <= index) {
    if (canvasPtr->textInfo.selectAnchor <= index) {
        canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;
        canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;
        canvasPtr->textInfo.selectLast = index;
        canvasPtr->textInfo.selectLast = index;
    } else {
    } else {
        canvasPtr->textInfo.selectFirst = index;
        canvasPtr->textInfo.selectFirst = index;
        canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;
        canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;
    }
    }
    if ((canvasPtr->textInfo.selectFirst != oldFirst)
    if ((canvasPtr->textInfo.selectFirst != oldFirst)
            || (canvasPtr->textInfo.selectLast != oldLast)
            || (canvasPtr->textInfo.selectLast != oldLast)
            || (itemPtr != oldSelPtr)) {
            || (itemPtr != oldSelPtr)) {
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
                itemPtr->x1, itemPtr->y1, itemPtr->x2, itemPtr->y2);
    }
    }
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasFetchSelection --
 * CanvasFetchSelection --
 *
 *
 *      This procedure is invoked by Tk to return part or all of
 *      This procedure is invoked by Tk to return part or all of
 *      the selection, when the selection is in a canvas widget.
 *      the selection, when the selection is in a canvas widget.
 *      This procedure always returns the selection as a STRING.
 *      This procedure always returns the selection as a STRING.
 *
 *
 * Results:
 * Results:
 *      The return value is the number of non-NULL bytes stored
 *      The return value is the number of non-NULL bytes stored
 *      at buffer.  Buffer is filled (or partially filled) with a
 *      at buffer.  Buffer is filled (or partially filled) with a
 *      NULL-terminated string containing part or all of the selection,
 *      NULL-terminated string containing part or all of the selection,
 *      as given by offset and maxBytes.
 *      as given by offset and maxBytes.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static int
static int
CanvasFetchSelection(clientData, offset, buffer, maxBytes)
CanvasFetchSelection(clientData, offset, buffer, maxBytes)
    ClientData clientData;              /* Information about canvas widget. */
    ClientData clientData;              /* Information about canvas widget. */
    int offset;                         /* Offset within selection of first
    int offset;                         /* Offset within selection of first
                                         * character to be returned. */
                                         * character to be returned. */
    char *buffer;                       /* Location in which to place
    char *buffer;                       /* Location in which to place
                                         * selection. */
                                         * selection. */
    int maxBytes;                       /* Maximum number of bytes to place
    int maxBytes;                       /* Maximum number of bytes to place
                                         * at buffer, not including terminating
                                         * at buffer, not including terminating
                                         * NULL character. */
                                         * NULL character. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
 
 
    if (canvasPtr->textInfo.selItemPtr == NULL) {
    if (canvasPtr->textInfo.selItemPtr == NULL) {
        return -1;
        return -1;
    }
    }
    if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) {
    if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) {
        return -1;
        return -1;
    }
    }
    return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)(
    return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)(
            (Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset,
            (Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset,
            buffer, maxBytes);
            buffer, maxBytes);
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * CanvasLostSelection --
 * CanvasLostSelection --
 *
 *
 *      This procedure is called back by Tk when the selection is
 *      This procedure is called back by Tk when the selection is
 *      grabbed away from a canvas widget.
 *      grabbed away from a canvas widget.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The existing selection is unhighlighted, and the window is
 *      The existing selection is unhighlighted, and the window is
 *      marked as not containing a selection.
 *      marked as not containing a selection.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasLostSelection(clientData)
CanvasLostSelection(clientData)
    ClientData clientData;              /* Information about entry widget. */
    ClientData clientData;              /* Information about entry widget. */
{
{
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
    TkCanvas *canvasPtr = (TkCanvas *) clientData;
 
 
    if (canvasPtr->textInfo.selItemPtr != NULL) {
    if (canvasPtr->textInfo.selItemPtr != NULL) {
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
        Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
                canvasPtr->textInfo.selItemPtr->x1,
                canvasPtr->textInfo.selItemPtr->x1,
                canvasPtr->textInfo.selItemPtr->y1,
                canvasPtr->textInfo.selItemPtr->y1,
                canvasPtr->textInfo.selItemPtr->x2,
                canvasPtr->textInfo.selItemPtr->x2,
                canvasPtr->textInfo.selItemPtr->y2);
                canvasPtr->textInfo.selItemPtr->y2);
    }
    }
    canvasPtr->textInfo.selItemPtr = NULL;
    canvasPtr->textInfo.selItemPtr = NULL;
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * GridAlign --
 * GridAlign --
 *
 *
 *      Given a coordinate and a grid spacing, this procedure
 *      Given a coordinate and a grid spacing, this procedure
 *      computes the location of the nearest grid line to the
 *      computes the location of the nearest grid line to the
 *      coordinate.
 *      coordinate.
 *
 *
 * Results:
 * Results:
 *      The return value is the location of the grid line nearest
 *      The return value is the location of the grid line nearest
 *      to coord.
 *      to coord.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static double
static double
GridAlign(coord, spacing)
GridAlign(coord, spacing)
    double coord;               /* Coordinate to grid-align. */
    double coord;               /* Coordinate to grid-align. */
    double spacing;             /* Spacing between grid lines.   If <= 0
    double spacing;             /* Spacing between grid lines.   If <= 0
                                 * then no alignment is done. */
                                 * then no alignment is done. */
{
{
    if (spacing <= 0.0) {
    if (spacing <= 0.0) {
        return coord;
        return coord;
    }
    }
    if (coord < 0) {
    if (coord < 0) {
        return -((int) ((-coord)/spacing + 0.5)) * spacing;
        return -((int) ((-coord)/spacing + 0.5)) * spacing;
    }
    }
    return ((int) (coord/spacing + 0.5)) * spacing;
    return ((int) (coord/spacing + 0.5)) * spacing;
}
}


/*
/*
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 *
 *
 * PrintScrollFractions --
 * PrintScrollFractions --
 *
 *
 *      Given the range that's visible in the window and the "100%
 *      Given the range that's visible in the window and the "100%
 *      range" for what's in the canvas, print a string containing
 *      range" for what's in the canvas, print a string containing
 *      the scroll fractions.  This procedure is used for both x
 *      the scroll fractions.  This procedure is used for both x
 *      and y scrolling.
 *      and y scrolling.
 *
 *
 * Results:
 * Results:
 *      The memory pointed to by string is modified to hold
 *      The memory pointed to by string is modified to hold
 *      two real numbers containing the scroll fractions (between
 *      two real numbers containing the scroll fractions (between
 *      0 and 1) corresponding to the other arguments.
 *      0 and 1) corresponding to the other arguments.
 *
 *
 * Side effects:
 * Side effects:
 *      None.
 *      None.
 *
 *
 *----------------------------------------------------------------------
 *----------------------------------------------------------------------
 */
 */
 
 
static void
static void
PrintScrollFractions(screen1, screen2, object1, object2, string)
PrintScrollFractions(screen1, screen2, object1, object2, string)
    int screen1;                /* Lowest coordinate visible in the window. */
    int screen1;                /* Lowest coordinate visible in the window. */
    int screen2;                /* Highest coordinate visible in the window. */
    int screen2;                /* Highest coordinate visible in the window. */
    int object1;                /* Lowest coordinate in the object. */
    int object1;                /* Lowest coordinate in the object. */
    int object2;                /* Highest coordinate in the object. */
    int object2;                /* Highest coordinate in the object. */
    char *string;               /* Two real numbers get printed here.  Must
    char *string;               /* Two real numbers get printed here.  Must
                                 * have enough storage for two %g
                                 * have enough storage for two %g
                                 * conversions. */
                                 * conversions. */
{
{
    double range, f1, f2;
    double range, f1, f2;
 
 
    range = object2 - object1;
    range = object2 - object1;
    if (range <= 0) {
    if (range <= 0) {
        f1 = 0;
        f1 = 0;
        f2 = 1.0;
        f2 = 1.0;
    } else {
    } else {
        f1 = (screen1 - object1)/range;
        f1 = (screen1 - object1)/range;
        if (f1 < 0) {
        if (f1 < 0) {
            f1 = 0.0;
            f1 = 0.0;
        }
        }
        f2 = (screen2 - object1)/range;
        f2 = (screen2 - object1)/range;
        if (f2 > 1.0) {
        if (f2 > 1.0) {
            f2 = 1.0;
            f2 = 1.0;
        }
        }
        if (f2 < f1) {
        if (f2 < f1) {
            f2 = f1;
            f2 = f1;
        }
        }
    }
    }
    sprintf(string, "%g %g", f1, f2);
    sprintf(string, "%g %g", f1, f2);
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasUpdateScrollbars --
 * CanvasUpdateScrollbars --
 *
 *
 *      This procedure is invoked whenever a canvas has changed in
 *      This procedure is invoked whenever a canvas has changed in
 *      a way that requires scrollbars to be redisplayed (e.g. the
 *      a way that requires scrollbars to be redisplayed (e.g. the
 *      view in the canvas has changed).
 *      view in the canvas has changed).
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      If there are scrollbars associated with the canvas, then
 *      If there are scrollbars associated with the canvas, then
 *      their scrolling commands are invoked to cause them to
 *      their scrolling commands are invoked to cause them to
 *      redisplay.  If errors occur, additional Tcl commands may
 *      redisplay.  If errors occur, additional Tcl commands may
 *      be invoked to process the errors.
 *      be invoked to process the errors.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasUpdateScrollbars(canvasPtr)
CanvasUpdateScrollbars(canvasPtr)
    TkCanvas *canvasPtr;                /* Information about canvas. */
    TkCanvas *canvasPtr;                /* Information about canvas. */
{
{
    int result;
    int result;
    char buffer[200];
    char buffer[200];
    Tcl_Interp *interp;
    Tcl_Interp *interp;
    int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2,
    int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2,
        scrollY1, scrollY2;
        scrollY1, scrollY2;
    char *xScrollCmd, *yScrollCmd;
    char *xScrollCmd, *yScrollCmd;
 
 
    /*
    /*
     * Save all the relevant values from the canvasPtr, because it might be
     * Save all the relevant values from the canvasPtr, because it might be
     * deleted as part of either of the two calls to Tcl_VarEval below.
     * deleted as part of either of the two calls to Tcl_VarEval below.
     */
     */
 
 
    interp = canvasPtr->interp;
    interp = canvasPtr->interp;
    Tcl_Preserve((ClientData) interp);
    Tcl_Preserve((ClientData) interp);
    xScrollCmd = canvasPtr->xScrollCmd;
    xScrollCmd = canvasPtr->xScrollCmd;
    if (xScrollCmd != (char *) NULL) {
    if (xScrollCmd != (char *) NULL) {
        Tcl_Preserve((ClientData) xScrollCmd);
        Tcl_Preserve((ClientData) xScrollCmd);
    }
    }
    yScrollCmd = canvasPtr->yScrollCmd;
    yScrollCmd = canvasPtr->yScrollCmd;
    if (yScrollCmd != (char *) NULL) {
    if (yScrollCmd != (char *) NULL) {
        Tcl_Preserve((ClientData) yScrollCmd);
        Tcl_Preserve((ClientData) yScrollCmd);
    }
    }
    xOrigin = canvasPtr->xOrigin;
    xOrigin = canvasPtr->xOrigin;
    yOrigin = canvasPtr->yOrigin;
    yOrigin = canvasPtr->yOrigin;
    inset = canvasPtr->inset;
    inset = canvasPtr->inset;
    width = Tk_Width(canvasPtr->tkwin);
    width = Tk_Width(canvasPtr->tkwin);
    height = Tk_Height(canvasPtr->tkwin);
    height = Tk_Height(canvasPtr->tkwin);
    scrollX1 = canvasPtr->scrollX1;
    scrollX1 = canvasPtr->scrollX1;
    scrollX2 = canvasPtr->scrollX2;
    scrollX2 = canvasPtr->scrollX2;
    scrollY1 = canvasPtr->scrollY1;
    scrollY1 = canvasPtr->scrollY1;
    scrollY2 = canvasPtr->scrollY2;
    scrollY2 = canvasPtr->scrollY2;
    canvasPtr->flags &= ~UPDATE_SCROLLBARS;
    canvasPtr->flags &= ~UPDATE_SCROLLBARS;
    if (canvasPtr->xScrollCmd != NULL) {
    if (canvasPtr->xScrollCmd != NULL) {
        PrintScrollFractions(xOrigin + inset, xOrigin + width - inset,
        PrintScrollFractions(xOrigin + inset, xOrigin + width - inset,
                scrollX1, scrollX2, buffer);
                scrollX1, scrollX2, buffer);
        result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);
        result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);
        if (result != TCL_OK) {
        if (result != TCL_OK) {
            Tcl_BackgroundError(interp);
            Tcl_BackgroundError(interp);
        }
        }
        Tcl_ResetResult(interp);
        Tcl_ResetResult(interp);
        Tcl_Release((ClientData) xScrollCmd);
        Tcl_Release((ClientData) xScrollCmd);
    }
    }
 
 
    if (yScrollCmd != NULL) {
    if (yScrollCmd != NULL) {
        PrintScrollFractions(yOrigin + inset, yOrigin + height - inset,
        PrintScrollFractions(yOrigin + inset, yOrigin + height - inset,
                scrollY1, scrollY2, buffer);
                scrollY1, scrollY2, buffer);
        result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);
        result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);
        if (result != TCL_OK) {
        if (result != TCL_OK) {
            Tcl_BackgroundError(interp);
            Tcl_BackgroundError(interp);
        }
        }
        Tcl_ResetResult(interp);
        Tcl_ResetResult(interp);
        Tcl_Release((ClientData) yScrollCmd);
        Tcl_Release((ClientData) yScrollCmd);
    }
    }
    Tcl_Release((ClientData) interp);
    Tcl_Release((ClientData) interp);
}
}


/*
/*
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 *
 *
 * CanvasSetOrigin --
 * CanvasSetOrigin --
 *
 *
 *      This procedure is invoked to change the mapping between
 *      This procedure is invoked to change the mapping between
 *      canvas coordinates and screen coordinates in the canvas
 *      canvas coordinates and screen coordinates in the canvas
 *      window.
 *      window.
 *
 *
 * Results:
 * Results:
 *      None.
 *      None.
 *
 *
 * Side effects:
 * Side effects:
 *      The canvas will be redisplayed to reflect the change in
 *      The canvas will be redisplayed to reflect the change in
 *      view.  In addition, scrollbars will be updated if there
 *      view.  In addition, scrollbars will be updated if there
 *      are any.
 *      are any.
 *
 *
 *--------------------------------------------------------------
 *--------------------------------------------------------------
 */
 */
 
 
static void
static void
CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)
CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)
    TkCanvas *canvasPtr;        /* Information about canvas. */
    TkCanvas *canvasPtr;        /* Information about canvas. */
    int xOrigin;                /* New X origin for canvas (canvas x-coord
    int xOrigin;                /* New X origin for canvas (canvas x-coord
                                 * corresponding to left edge of canvas
                                 * corresponding to left edge of canvas
                                 * window). */
                                 * window). */
    int yOrigin;                /* New Y origin for canvas (canvas y-coord
    int yOrigin;                /* New Y origin for canvas (canvas y-coord
                                 * corresponding to top edge of canvas
                                 * corresponding to top edge of canvas
                                 * window). */
                                 * window). */
{
{
    int left, right, top, bottom, delta;
    int left, right, top, bottom, delta;
 
 
    /*
    /*
     * If scroll increments have been set, round the window origin
     * If scroll increments have been set, round the window origin
     * to the nearest multiple of the increments.  Remember, the
     * to the nearest multiple of the increments.  Remember, the
     * origin is the place just inside the borders,  not the upper
     * origin is the place just inside the borders,  not the upper
     * left corner.
     * left corner.
     */
     */
 
 
    if (canvasPtr->xScrollIncrement > 0) {
    if (canvasPtr->xScrollIncrement > 0) {
        if (xOrigin >= 0) {
        if (xOrigin >= 0) {
            xOrigin += canvasPtr->xScrollIncrement/2;
            xOrigin += canvasPtr->xScrollIncrement/2;
            xOrigin -= (xOrigin + canvasPtr->inset)
            xOrigin -= (xOrigin + canvasPtr->inset)
                    % canvasPtr->xScrollIncrement;
                    % canvasPtr->xScrollIncrement;
        } else {
        } else {
            xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;
            xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;
            xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)
            xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)
                    % canvasPtr->xScrollIncrement);
                    % canvasPtr->xScrollIncrement);
        }
        }
    }
    }
    if (canvasPtr->yScrollIncrement > 0) {
    if (canvasPtr->yScrollIncrement > 0) {
        if (yOrigin >= 0) {
        if (yOrigin >= 0) {
            yOrigin += canvasPtr->yScrollIncrement/2;
            yOrigin += canvasPtr->yScrollIncrement/2;
            yOrigin -= (yOrigin + canvasPtr->inset)
            yOrigin -= (yOrigin + canvasPtr->inset)
                    % canvasPtr->yScrollIncrement;
                    % canvasPtr->yScrollIncrement;
        } else {
        } else {
            yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;
            yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;
            yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)
            yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)
                    % canvasPtr->yScrollIncrement);
                    % canvasPtr->yScrollIncrement);
        }
        }
    }
    }
 
 
    /*
    /*
     * Adjust the origin if necessary to keep as much as possible of the
     * Adjust the origin if necessary to keep as much as possible of the
     * canvas in the view.  The variables left, right, etc. keep track of
     * canvas in the view.  The variables left, right, etc. keep track of
     * how much extra space there is on each side of the view before it
     * how much extra space there is on each side of the view before it
     * will stick out past the scroll region.  If one side sticks out past
     * will stick out past the scroll region.  If one side sticks out past
     * the edge of the scroll region, adjust the view to bring that side
     * the edge of the scroll region, adjust the view to bring that side
     * back to the edge of the scrollregion (but don't move it so much that
     * back to the edge of the scrollregion (but don't move it so much that
     * the other side sticks out now).  If scroll increments are in effect,
     * the other side sticks out now).  If scroll increments are in effect,
     * be sure to adjust only by full increments.
     * be sure to adjust only by full increments.
     */
     */
 
 
    if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
    if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
        left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;
        left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;
        right = canvasPtr->scrollX2
        right = canvasPtr->scrollX2
                - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);
                - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);
        top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;
        top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;
        bottom = canvasPtr->scrollY2
        bottom = canvasPtr->scrollY2
                - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);
                - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);
        if ((left < 0) && (right > 0)) {
        if ((left < 0) && (right > 0)) {
            delta = (right > -left) ? -left : right;
            delta = (right > -left) ? -left : right;
            if (canvasPtr->xScrollIncrement > 0) {
            if (canvasPtr->xScrollIncrement > 0) {
                delta -= delta % canvasPtr->xScrollIncrement;
                delta -= delta % canvasPtr->xScrollIncrement;
            }
            }
            xOrigin += delta;
            xOrigin += delta;
        } else if ((right < 0) && (left > 0)) {
        } else if ((right < 0) && (left > 0)) {
            delta = (left > -right) ? -right : left;
            delta = (left > -right) ? -right : left;
            if (canvasPtr->xScrollIncrement > 0) {
            if (canvasPtr->xScrollIncrement > 0) {
                delta -= delta % canvasPtr->xScrollIncrement;
                delta -= delta % canvasPtr->xScrollIncrement;
            }
            }
            xOrigin -= delta;
            xOrigin -= delta;
        }
        }
        if ((top < 0) && (bottom > 0)) {
        if ((top < 0) && (bottom > 0)) {
            delta = (bottom > -top) ? -top : bottom;
            delta = (bottom > -top) ? -top : bottom;
            if (canvasPtr->yScrollIncrement > 0) {
            if (canvasPtr->yScrollIncrement > 0) {
                delta -= delta % canvasPtr->yScrollIncrement;
                delta -= delta % canvasPtr->yScrollIncrement;
            }
            }
            yOrigin += delta;
            yOrigin += delta;
        } else if ((bottom < 0) && (top > 0)) {
        } else if ((bottom < 0) && (top > 0)) {
            delta = (top > -bottom) ? -bottom : top;
            delta = (top > -bottom) ? -bottom : top;
            if (canvasPtr->yScrollIncrement > 0) {
            if (canvasPtr->yScrollIncrement > 0) {
                delta -= delta % canvasPtr->yScrollIncrement;
                delta -= delta % canvasPtr->yScrollIncrement;
            }
            }
            yOrigin -= delta;
            yOrigin -= delta;
        }
        }
    }
    }
 
 
    if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
    if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
        return;
        return;
    }
    }
 
 
    /*
    /*
     * Tricky point: must redisplay not only everything that's visible
     * Tricky point: must redisplay not only everything that's visible
     * in the window's final configuration, but also everything that was
     * in the window's final configuration, but also everything that was
     * visible in the initial configuration.  This is needed because some
     * visible in the initial configuration.  This is needed because some
     * item types, like windows, need to know when they move off-screen
     * item types, like windows, need to know when they move off-screen
     * so they can explicitly undisplay themselves.
     * so they can explicitly undisplay themselves.
     */
     */
 
 
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
    canvasPtr->xOrigin = xOrigin;
    canvasPtr->xOrigin = xOrigin;
    canvasPtr->yOrigin = yOrigin;
    canvasPtr->yOrigin = yOrigin;
    canvasPtr->flags |= UPDATE_SCROLLBARS;
    canvasPtr->flags |= UPDATE_SCROLLBARS;
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin, canvasPtr->yOrigin,
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
            canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.