tkCanvas.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:173k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkCanvas.c --
  3.  *
  4.  * This module implements canvas widgets for the Tk toolkit.
  5.  * A canvas displays a background and a collection of graphical
  6.  * objects such as rectangles, lines, and texts.
  7.  *
  8.  * Copyright (c) 1991-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  10.  * Copyright (c) 1998-1999 by Scriptics Corporation.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tkCanvas.c,v 1.21.2.4 2007/04/29 02:24:01 das Exp $
  16.  */
  17. /* #define USE_OLD_TAG_SEARCH 1 */
  18. #include "default.h"
  19. #include "tkInt.h"
  20. #include "tkPort.h"
  21. #include "tkCanvas.h"
  22. #ifdef TK_NO_DOUBLE_BUFFERING
  23. #ifdef MAC_OSX_TK
  24. #include "tkMacOSXInt.h"
  25. #endif
  26. #endif /* TK_NO_DOUBLE_BUFFERING */
  27. /*
  28.  * See tkCanvas.h for key data structures used to implement canvases.
  29.  */
  30. #ifdef USE_OLD_TAG_SEARCH
  31. /*
  32.  * The structure defined below is used to keep track of a tag search
  33.  * in progress.  No field should be accessed by anyone other than
  34.  * StartTagSearch and NextItem.
  35.  */
  36. typedef struct TagSearch {
  37.     TkCanvas *canvasPtr; /* Canvas widget being searched. */
  38.     Tk_Uid tag; /* Tag to search for.   0 means return
  39.  * all items. */
  40.     Tk_Item *currentPtr; /* Pointer to last item returned. */
  41.     Tk_Item *lastPtr; /* The item right before the currentPtr
  42.  * is tracked so if the currentPtr is
  43.  * deleted we don't have to start from the
  44.  * beginning. */
  45.     int searchOver; /* Non-zero means NextItem should always
  46.  * return NULL. */
  47. } TagSearch;
  48. #else /* USE_OLD_TAG_SEARCH */
  49. /*
  50.  * The structure defined below is used to keep track of a tag search
  51.  * in progress.  No field should be accessed by anyone other than
  52.  * TagSearchScan, TagSearchFirst, TagSearchNext,
  53.  * TagSearchScanExpr, TagSearchEvalExpr, 
  54.  * TagSearchExprInit, TagSearchExprDestroy,
  55.  * TagSearchDestroy.
  56.  * (
  57.  *   Not quite accurate: the TagSearch structure is also accessed from:
  58.  *    CanvasWidgetCmd, FindItems, RelinkItems
  59.  *   The only instances of the structure are owned by:
  60.  *    CanvasWidgetCmd
  61.  *   CanvasWidgetCmd is the only function that calls:
  62.  *    FindItems, RelinkItems
  63.  *   CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call
  64.  *    TagSearch*
  65.  * )
  66.  */
  67. typedef struct TagSearch {
  68.     TkCanvas *canvasPtr; /* Canvas widget being searched. */
  69.     Tk_Item *currentPtr; /* Pointer to last item returned. */
  70.     Tk_Item *lastPtr; /* The item right before the currentPtr
  71.  * is tracked so if the currentPtr is
  72.  * deleted we don't have to start from the
  73.  * beginning. */
  74.     int searchOver; /* Non-zero means NextItem should always
  75.  * return NULL. */
  76.     int type; /* search type */
  77.     int id; /* item id for searches by id */
  78.     char *string; /* tag expression string */
  79.     int stringIndex; /* current position in string scan */
  80.     int stringLength; /* length of tag expression string */
  81.     char *rewritebuffer; /* tag string (after removing escapes) */
  82.     unsigned int rewritebufferAllocated; /* available space for rewrites */
  83.     TagSearchExpr *expr; /* compiled tag expression */
  84. } TagSearch;
  85. #endif /* USE_OLD_TAG_SEARCH */
  86. /*
  87.  * Custom option for handling "-state" and "-offset"
  88.  */
  89. static Tk_CustomOption stateOption = {
  90.     (Tk_OptionParseProc *) TkStateParseProc,
  91.     TkStatePrintProc,
  92.     (ClientData) NULL /* only "normal" and "disabled" */
  93. };
  94. static Tk_CustomOption offsetOption = {
  95.     (Tk_OptionParseProc *) TkOffsetParseProc,
  96.     TkOffsetPrintProc,
  97.     (ClientData) TK_OFFSET_RELATIVE
  98. };
  99. /*
  100.  * Information used for argv parsing.
  101.  */
  102. static Tk_ConfigSpec configSpecs[] = {
  103.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  104. DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
  105. TK_CONFIG_COLOR_ONLY},
  106.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  107. DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
  108. TK_CONFIG_MONO_ONLY},
  109.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  110. (char *) NULL, 0, 0},
  111.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  112. (char *) NULL, 0, 0},
  113.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  114. DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},
  115.     {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
  116. DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},
  117.     {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
  118. DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},
  119.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  120. DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},
  121.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  122. DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},
  123.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  124. "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
  125. Tk_Offset(TkCanvas, highlightBgColorPtr), 0},
  126.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  127. DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},
  128.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  129. "HighlightThickness",
  130. DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},
  131.     {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
  132. DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},
  133.     {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
  134. DEF_CANVAS_INSERT_BD_COLOR,
  135. Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},
  136.     {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
  137. DEF_CANVAS_INSERT_BD_MONO,
  138. Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},
  139.     {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
  140. DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},
  141.     {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
  142. DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0},
  143.     {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
  144. DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0},
  145.     {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0",
  146. Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT,
  147. &offsetOption},
  148.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  149. DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},
  150.     {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
  151. DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
  152. TK_CONFIG_NULL_OK},
  153.     {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
  154. DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
  155. TK_CONFIG_COLOR_ONLY},
  156.     {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
  157. DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
  158. TK_CONFIG_MONO_ONLY},
  159.     {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
  160. DEF_CANVAS_SELECT_BD_COLOR,
  161. Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},
  162.     {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
  163. DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
  164. TK_CONFIG_MONO_ONLY},
  165.     {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
  166. DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
  167. TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
  168.     {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
  169. DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
  170. TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
  171.     {TK_CONFIG_CUSTOM, "-state", "state", "State",
  172. "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT,
  173. &stateOption},
  174.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  175. DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
  176. TK_CONFIG_NULL_OK},
  177.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  178. DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},
  179.     {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
  180. DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
  181. TK_CONFIG_NULL_OK},
  182.     {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
  183. "ScrollIncrement",
  184. DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
  185. 0},
  186.     {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
  187. DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
  188. TK_CONFIG_NULL_OK},
  189.     {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
  190. "ScrollIncrement",
  191. DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
  192. 0},
  193.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  194. (char *) NULL, 0, 0}
  195. };
  196. /*
  197.  * List of all the item types known at present. This is *global* and
  198.  * is protected by typeListMutex.
  199.  */
  200. static Tk_ItemType *typeList = NULL; /* NULL means initialization hasn't
  201.  * been done yet. */
  202. TCL_DECLARE_MUTEX(typeListMutex)
  203. #ifndef USE_OLD_TAG_SEARCH
  204. /*
  205.  * Uids for operands in compiled advanced tag search expressions
  206.  * Initialization is done by GetStaticUids()
  207.  */
  208. typedef struct {
  209.     Tk_Uid allUid;
  210.     Tk_Uid currentUid;
  211.     Tk_Uid andUid;
  212.     Tk_Uid orUid;
  213.     Tk_Uid xorUid;
  214.     Tk_Uid parenUid;
  215.     Tk_Uid negparenUid;
  216.     Tk_Uid endparenUid;
  217.     Tk_Uid tagvalUid;
  218.     Tk_Uid negtagvalUid;
  219. } SearchUids;
  220. static Tcl_ThreadDataKey dataKey;
  221. static SearchUids *GetStaticUids _ANSI_ARGS_((void));
  222. #endif /* USE_OLD_TAG_SEARCH */
  223. /*
  224.  * Standard item types provided by Tk:
  225.  */
  226. extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;
  227. extern Tk_ItemType tkOvalType, tkPolygonType;
  228. extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
  229. /*
  230.  * Prototypes for procedures defined later in this file:
  231.  */
  232. static void CanvasBindProc _ANSI_ARGS_((ClientData clientData,
  233.     XEvent *eventPtr));
  234. static void CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
  235. static void CanvasCmdDeletedProc _ANSI_ARGS_((
  236.     ClientData clientData));
  237. static void CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,
  238.     XEvent *eventPtr));
  239. static void CanvasEventProc _ANSI_ARGS_((ClientData clientData,
  240.     XEvent *eventPtr));
  241. static int CanvasFetchSelection _ANSI_ARGS_((
  242.     ClientData clientData, int offset,
  243.     char *buffer, int maxBytes));
  244. static Tk_Item * CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,
  245.     double coords[2]));
  246. static void CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,
  247.     int gotFocus));
  248. static void CanvasLostSelection _ANSI_ARGS_((
  249.     ClientData clientData));
  250. static void CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,
  251.     Tk_Item *itemPtr, int index));
  252. static void CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,
  253.     int xOrigin, int yOrigin));
  254. static void CanvasUpdateScrollbars _ANSI_ARGS_((
  255.     TkCanvas *canvasPtr));
  256. static int CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
  257.     Tcl_Interp *interp, int argc, Tcl_Obj *CONST *argv));
  258. static void CanvasWorldChanged _ANSI_ARGS_((
  259.     ClientData instanceData));
  260. static int ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
  261.     TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
  262.     int flags));
  263. static void DestroyCanvas _ANSI_ARGS_((char *memPtr));
  264. static void DisplayCanvas _ANSI_ARGS_((ClientData clientData));
  265. static void DoItem _ANSI_ARGS_((Tcl_Interp *interp,
  266.     Tk_Item *itemPtr, Tk_Uid tag));
  267. static void EventuallyRedrawItem _ANSI_ARGS_((Tk_Canvas canvas,
  268.     Tk_Item *itemPtr));
  269. #ifdef USE_OLD_TAG_SEARCH
  270. static int FindItems _ANSI_ARGS_((Tcl_Interp *interp,
  271.     TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
  272.     Tcl_Obj *newTagObj, int first));
  273. #else /* USE_OLD_TAG_SEARCH */
  274. static int FindItems _ANSI_ARGS_((Tcl_Interp *interp,
  275.     TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
  276.     Tcl_Obj *newTagObj, int first,
  277.     TagSearch **searchPtrPtr));
  278. #endif /* USE_OLD_TAG_SEARCH */
  279. static int FindArea _ANSI_ARGS_((Tcl_Interp *interp,
  280.     TkCanvas *canvasPtr, Tcl_Obj *CONST *argv, Tk_Uid uid,
  281.     int enclosed));
  282. static double GridAlign _ANSI_ARGS_((double coord, double spacing));
  283. static CONST char** GetStringsFromObjs _ANSI_ARGS_((int argc,
  284.     Tcl_Obj *CONST *objv));
  285. static void InitCanvas _ANSI_ARGS_((void));
  286. #ifdef USE_OLD_TAG_SEARCH
  287. static Tk_Item * NextItem _ANSI_ARGS_((TagSearch *searchPtr));
  288. #endif /* USE_OLD_TAG_SEARCH */
  289. static void PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,
  290.     XEvent *eventPtr));
  291. static Tcl_Obj * ScrollFractions _ANSI_ARGS_((int screen1,
  292.     int screen2, int object1, int object2));
  293. #ifdef USE_OLD_TAG_SEARCH
  294. static void RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
  295.     Tcl_Obj *tag, Tk_Item *prevPtr));
  296. static Tk_Item * StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
  297.     Tcl_Obj *tag, TagSearch *searchPtr));
  298. #else /* USE_OLD_TAG_SEARCH */
  299. static int RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
  300.     Tcl_Obj *tag, Tk_Item *prevPtr,
  301.     TagSearch **searchPtrPtr));
  302. static void  TagSearchExprInit _ANSI_ARGS_ ((
  303.     TagSearchExpr **exprPtrPtr));
  304. static void TagSearchExprDestroy _ANSI_ARGS_((TagSearchExpr *expr));
  305. static void TagSearchDestroy _ANSI_ARGS_((TagSearch *searchPtr));
  306. static int TagSearchScan _ANSI_ARGS_((TkCanvas *canvasPtr,
  307.     Tcl_Obj *tag, TagSearch **searchPtrPtr));
  308. static int TagSearchScanExpr _ANSI_ARGS_((Tcl_Interp *interp,
  309.     TagSearch *searchPtr, TagSearchExpr *expr));
  310. static int TagSearchEvalExpr _ANSI_ARGS_((TagSearchExpr *expr,
  311.     Tk_Item *itemPtr));
  312. static Tk_Item * TagSearchFirst _ANSI_ARGS_((TagSearch *searchPtr));
  313. static Tk_Item * TagSearchNext _ANSI_ARGS_((TagSearch *searchPtr));
  314. #endif /* USE_OLD_TAG_SEARCH */
  315. /*
  316.  * The structure below defines canvas class behavior by means of procedures
  317.  * that can be invoked from generic window code.
  318.  */
  319. static Tk_ClassProcs canvasClass = {
  320.     sizeof(Tk_ClassProcs), /* size */
  321.     CanvasWorldChanged, /* worldChangedProc */
  322. };
  323. /*
  324.  *--------------------------------------------------------------
  325.  *
  326.  * Tk_CanvasObjCmd --
  327.  *
  328.  * This procedure is invoked to process the "canvas" Tcl
  329.  * command.  See the user documentation for details on what
  330.  * it does.
  331.  *
  332.  * Results:
  333.  * A standard Tcl result.
  334.  *
  335.  * Side effects:
  336.  * See the user documentation.
  337.  *
  338.  *--------------------------------------------------------------
  339.  */
  340. int
  341. Tk_CanvasObjCmd(clientData, interp, argc, argv)
  342.     ClientData clientData; /* Main window associated with
  343.  * interpreter. */
  344.     Tcl_Interp *interp; /* Current interpreter. */
  345.     int argc; /* Number of arguments. */
  346.     Tcl_Obj *CONST argv[]; /* Argument objects. */
  347. {
  348.     Tk_Window tkwin = (Tk_Window) clientData;
  349.     TkCanvas *canvasPtr;
  350.     Tk_Window new;
  351.     if (typeList == NULL) {
  352. InitCanvas();
  353.     }
  354.     if (argc < 2) {
  355. Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?");
  356. return TCL_ERROR;
  357.     }
  358.     new = Tk_CreateWindowFromPath(interp, tkwin,
  359.     Tcl_GetString(argv[1]), (char *) NULL);
  360.     if (new == NULL) {
  361. return TCL_ERROR;
  362.     }
  363.     /*
  364.      * Initialize fields that won't be initialized by ConfigureCanvas,
  365.      * or which ConfigureCanvas expects to have reasonable values
  366.      * (e.g. resource pointers).
  367.      */
  368.     canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));
  369.     canvasPtr->tkwin = new;
  370.     canvasPtr->display = Tk_Display(new);
  371.     canvasPtr->interp = interp;
  372.     canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp,
  373.     Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
  374.     (ClientData) canvasPtr, CanvasCmdDeletedProc);
  375.     canvasPtr->firstItemPtr = NULL;
  376.     canvasPtr->lastItemPtr = NULL;
  377.     canvasPtr->borderWidth = 0;
  378.     canvasPtr->bgBorder = NULL;
  379.     canvasPtr->relief = TK_RELIEF_FLAT;
  380.     canvasPtr->highlightWidth = 0;
  381.     canvasPtr->highlightBgColorPtr = NULL;
  382.     canvasPtr->highlightColorPtr = NULL;
  383.     canvasPtr->inset = 0;
  384.     canvasPtr->pixmapGC = None;
  385.     canvasPtr->width = None;
  386.     canvasPtr->height = None;
  387.     canvasPtr->confine = 0;
  388.     canvasPtr->textInfo.selBorder = NULL;
  389.     canvasPtr->textInfo.selBorderWidth = 0;
  390.     canvasPtr->textInfo.selFgColorPtr = NULL;
  391.     canvasPtr->textInfo.selItemPtr = NULL;
  392.     canvasPtr->textInfo.selectFirst = -1;
  393.     canvasPtr->textInfo.selectLast = -1;
  394.     canvasPtr->textInfo.anchorItemPtr = NULL;
  395.     canvasPtr->textInfo.selectAnchor = 0;
  396.     canvasPtr->textInfo.insertBorder = NULL;
  397.     canvasPtr->textInfo.insertWidth = 0;
  398.     canvasPtr->textInfo.insertBorderWidth = 0;
  399.     canvasPtr->textInfo.focusItemPtr = NULL;
  400.     canvasPtr->textInfo.gotFocus = 0;
  401.     canvasPtr->textInfo.cursorOn = 0;
  402.     canvasPtr->insertOnTime = 0;
  403.     canvasPtr->insertOffTime = 0;
  404.     canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
  405.     canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
  406.     canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
  407.     canvasPtr->bindingTable = NULL;
  408.     canvasPtr->currentItemPtr = NULL;
  409.     canvasPtr->newCurrentPtr = NULL;
  410.     canvasPtr->closeEnough = 0.0;
  411.     canvasPtr->pickEvent.type = LeaveNotify;
  412.     canvasPtr->pickEvent.xcrossing.x = 0;
  413.     canvasPtr->pickEvent.xcrossing.y = 0;
  414.     canvasPtr->state = 0;
  415.     canvasPtr->xScrollCmd = NULL;
  416.     canvasPtr->yScrollCmd = NULL;
  417.     canvasPtr->scrollX1 = 0;
  418.     canvasPtr->scrollY1 = 0;
  419.     canvasPtr->scrollX2 = 0;
  420.     canvasPtr->scrollY2 = 0;
  421.     canvasPtr->regionString = NULL;
  422.     canvasPtr->xScrollIncrement = 0;
  423.     canvasPtr->yScrollIncrement = 0;
  424.     canvasPtr->scanX = 0;
  425.     canvasPtr->scanXOrigin = 0;
  426.     canvasPtr->scanY = 0;
  427.     canvasPtr->scanYOrigin = 0;
  428.     canvasPtr->hotPtr = NULL;
  429.     canvasPtr->hotPrevPtr = NULL;
  430.     canvasPtr->cursor = None;
  431.     canvasPtr->takeFocus = NULL;
  432.     canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
  433.     canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
  434.     canvasPtr->flags = 0;
  435.     canvasPtr->nextId = 1;
  436.     canvasPtr->psInfo = NULL;
  437.     canvasPtr->canvas_state = TK_STATE_NORMAL;
  438.     canvasPtr->tsoffset.flags = 0;
  439.     canvasPtr->tsoffset.xoffset = 0;
  440.     canvasPtr->tsoffset.yoffset = 0;
  441. #ifndef USE_OLD_TAG_SEARCH
  442.     canvasPtr->bindTagExprs = NULL;
  443. #endif
  444.     Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);
  445.     Tk_SetClass(canvasPtr->tkwin, "Canvas");
  446.     Tk_SetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr);
  447.     Tk_CreateEventHandler(canvasPtr->tkwin,
  448.     ExposureMask|StructureNotifyMask|FocusChangeMask,
  449.     CanvasEventProc, (ClientData) canvasPtr);
  450.     Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
  451.     |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
  452.     |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
  453.     CanvasBindProc, (ClientData) canvasPtr);
  454.     Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
  455.     CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
  456.     if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
  457. goto error;
  458.     }
  459.     Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC);
  460.     return TCL_OK;
  461.     error:
  462.     Tk_DestroyWindow(canvasPtr->tkwin);
  463.     return TCL_ERROR;
  464. }
  465. /*
  466.  *--------------------------------------------------------------
  467.  *
  468.  * CanvasWidgetCmd --
  469.  *
  470.  * This procedure is invoked to process the Tcl command
  471.  * that corresponds to a widget managed by this module.
  472.  * See the user documentation for details on what it does.
  473.  *
  474.  * Results:
  475.  * A standard Tcl result.
  476.  *
  477.  * Side effects:
  478.  * See the user documentation.
  479.  *
  480.  *--------------------------------------------------------------
  481.  */
  482. static int
  483. CanvasWidgetCmd(clientData, interp, objc, objv)
  484.     ClientData clientData; /* Information about canvas
  485.  * widget. */
  486.     Tcl_Interp *interp; /* Current interpreter. */
  487.     int objc; /* Number of arguments. */
  488.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  489. {
  490.     TkCanvas *canvasPtr = (TkCanvas *) clientData;
  491.     int c, length, result;
  492.     Tk_Item *itemPtr = NULL; /* Initialization needed only to
  493.  * prevent compiler warning. */
  494. #ifdef USE_OLD_TAG_SEARCH
  495.     TagSearch search;
  496. #else /* USE_OLD_TAG_SEARCH */
  497.     TagSearch *searchPtr = NULL; /* Allocated by first TagSearchScan
  498.  * Freed by TagSearchDestroy */
  499. #endif /* USE_OLD_TAG_SEARCH */
  500.     int index;
  501.     static CONST char *optionStrings[] = {
  502. "addtag", "bbox", "bind", "canvasx",
  503. "canvasy", "cget", "configure", "coords",
  504. "create", "dchars", "delete", "dtag",
  505. "find", "focus", "gettags", "icursor",
  506. "index", "insert", "itemcget", "itemconfigure",
  507. "lower", "move", "postscript", "raise",
  508. "scale", "scan", "select", "type",
  509. "xview", "yview",
  510. NULL
  511.     };
  512.     enum options {
  513. CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX,
  514. CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS,
  515. CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG,
  516. CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR,
  517. CANV_INDEX, CANV_INSERT, CANV_ITEMCGET, CANV_ITEMCONFIGURE,
  518. CANV_LOWER, CANV_MOVE, CANV_POSTSCRIPT,CANV_RAISE,
  519. CANV_SCALE, CANV_SCAN, CANV_SELECT, CANV_TYPE,
  520. CANV_XVIEW, CANV_YVIEW
  521.     };
  522.     if (objc < 2) {
  523. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
  524. return TCL_ERROR;
  525.     }
  526.     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
  527.     &index) != TCL_OK) {
  528. return TCL_ERROR;
  529.     }
  530.     Tcl_Preserve((ClientData) canvasPtr);
  531.     result = TCL_OK;
  532.     switch ((enum options) index) {
  533.       case CANV_ADDTAG: {
  534. if (objc < 4) {
  535.     Tcl_WrongNumArgs(interp, 2, objv, "tag searchCommand ?arg arg ...?");
  536.     result = TCL_ERROR;
  537.     goto done;
  538. }
  539. #ifdef USE_OLD_TAG_SEARCH
  540. result = FindItems(interp, canvasPtr, objc, objv, objv[2], 3);
  541. #else /* USE_OLD_TAG_SEARCH */
  542. result = FindItems(interp, canvasPtr, objc, objv, objv[2], 3, &searchPtr);
  543. #endif /* USE_OLD_TAG_SEARCH */
  544. break;
  545.       }
  546.       case CANV_BBOX: {
  547. int i, gotAny;
  548. int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed
  549.  * only to prevent compiler
  550.  * warnings. */
  551. if (objc < 3) {
  552.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagOrId ...?");
  553.     result = TCL_ERROR;
  554.     goto done;
  555. }
  556. gotAny = 0;
  557. for (i = 2; i < objc; i++) {
  558. #ifdef USE_OLD_TAG_SEARCH
  559.     for (itemPtr = StartTagSearch(canvasPtr, objv[i], &search);
  560.     itemPtr != NULL; itemPtr = NextItem(&search)) {
  561. #else /* USE_OLD_TAG_SEARCH */
  562.     if ((result = TagSearchScan(canvasPtr, objv[i], &searchPtr)) != TCL_OK) {
  563. goto done;
  564.     }
  565.     for (itemPtr = TagSearchFirst(searchPtr);
  566.     itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  567. #endif /* USE_OLD_TAG_SEARCH */
  568. if ((itemPtr->x1 >= itemPtr->x2)
  569. || (itemPtr->y1 >= itemPtr->y2)) {
  570.     continue;
  571. }
  572. if (!gotAny) {
  573.     x1 = itemPtr->x1;
  574.     y1 = itemPtr->y1;
  575.     x2 = itemPtr->x2;
  576.     y2 = itemPtr->y2;
  577.     gotAny = 1;
  578. } else {
  579.     if (itemPtr->x1 < x1) {
  580. x1 = itemPtr->x1;
  581.     }
  582.     if (itemPtr->y1 < y1) {
  583. y1 = itemPtr->y1;
  584.     }
  585.     if (itemPtr->x2 > x2) {
  586. x2 = itemPtr->x2;
  587.     }
  588.     if (itemPtr->y2 > y2) {
  589. y2 = itemPtr->y2;
  590.     }
  591. }
  592.     }
  593. }
  594. if (gotAny) {
  595.     char buf[TCL_INTEGER_SPACE * 4];
  596.     
  597.     sprintf(buf, "%d %d %d %d", x1, y1, x2, y2);
  598.     Tcl_SetResult(interp, buf, TCL_VOLATILE);
  599. }
  600. break;
  601.       }
  602.       case CANV_BIND: {
  603. ClientData object;
  604. if ((objc < 3) || (objc > 5)) {
  605.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?sequence? ?command?");
  606.     result = TCL_ERROR;
  607.     goto done;
  608. }
  609. /*
  610.  * Figure out what object to use for the binding (individual
  611.  * item vs. tag).
  612.  */
  613. object = 0;
  614. #ifdef USE_OLD_TAG_SEARCH
  615. if (isdigit(UCHAR(Tcl_GetString(objv[2])[0]))) {
  616.     int id;
  617.     char *end;
  618.     Tcl_HashEntry *entryPtr;
  619.     id = strtoul(Tcl_GetString(objv[2]), &end, 0);
  620.     if (*end != 0) {
  621. goto bindByTag;
  622.     }
  623.     entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
  624.     if (entryPtr != NULL) {
  625. itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
  626. object = (ClientData) itemPtr;
  627.     }
  628.     if (object == 0) {
  629. Tcl_AppendResult(interp, "item "", Tcl_GetString(objv[2]),
  630. "" doesn't exist", (char *) NULL);
  631. result = TCL_ERROR;
  632. goto done;
  633.     }
  634. } else {
  635.     bindByTag:
  636.     object = (ClientData) Tk_GetUid(Tcl_GetString(objv[2]));
  637. }
  638. #else /* USE_OLD_TAG_SEARCH */
  639. if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  640.     goto done;
  641. }
  642. if (searchPtr->type == 1) {
  643.     Tcl_HashEntry *entryPtr;
  644.     entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) searchPtr->id);
  645.     if (entryPtr != NULL) {
  646. itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
  647. object = (ClientData) itemPtr;
  648.     }
  649.     if (object == 0) {
  650. Tcl_AppendResult(interp, "item "", Tcl_GetString(objv[2]),
  651. "" doesn't exist", (char *) NULL);
  652. result = TCL_ERROR;
  653. goto done;
  654.     }
  655. } else {
  656.          object = (ClientData) searchPtr->expr->uid;
  657. }
  658. #endif /* USE_OLD_TAG_SEARCH */
  659. /*
  660.  * Make a binding table if the canvas doesn't already have
  661.  * one.
  662.  */
  663. if (canvasPtr->bindingTable == NULL) {
  664.     canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
  665. }
  666. if (objc == 5) {
  667.     int append = 0;
  668.     unsigned long mask;
  669.     char* argv4 = Tcl_GetStringFromObj(objv[4],NULL);
  670.     if (argv4[0] == 0) {
  671. result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
  672. object, Tcl_GetStringFromObj(objv[3], NULL));
  673. goto done;
  674.     }
  675. #ifndef USE_OLD_TAG_SEARCH
  676.     if (searchPtr->type == 4) {
  677.         /*
  678.          * if new tag expression, then insert in linked list
  679.          */
  680.      TagSearchExpr *expr, **lastPtr;
  681. lastPtr = &(canvasPtr->bindTagExprs);
  682. while ((expr = *lastPtr) != NULL) {
  683.     if (expr->uid == searchPtr->expr->uid) {
  684. break;
  685.     }
  686.     lastPtr = &(expr->next);
  687. }
  688. if (!expr) {
  689.     /*
  690.      * transfer ownership of expr to bindTagExprs list
  691.      */
  692.     *lastPtr = searchPtr->expr;
  693.     searchPtr->expr->next = NULL;
  694.     /*
  695.      * flag in TagSearch that expr has changed ownership
  696.      * so that TagSearchDestroy doesn't try to free it
  697.      */
  698.     searchPtr->expr = NULL;
  699. }
  700.             }
  701. #endif /* not USE_OLD_TAG_SEARCH */
  702.     if (argv4[0] == '+') {
  703. argv4++;
  704. append = 1;
  705.     }
  706.     mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
  707.     object, Tcl_GetStringFromObj(objv[3],NULL), argv4, append);
  708.     if (mask == 0) {
  709. result = TCL_ERROR;
  710. goto done;
  711.     }
  712.     if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
  713.     |Button2MotionMask|Button3MotionMask|Button4MotionMask
  714.     |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
  715.     |EnterWindowMask|LeaveWindowMask|KeyPressMask
  716.     |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
  717. Tk_DeleteBinding(interp, canvasPtr->bindingTable,
  718. object, Tcl_GetStringFromObj(objv[3], NULL));
  719. Tcl_ResetResult(interp);
  720. Tcl_AppendResult(interp, "requested illegal events; ",
  721. "only key, button, motion, enter, leave, and virtual ",
  722. "events may be used", (char *) NULL);
  723. result = TCL_ERROR;
  724. goto done;
  725.     }
  726. } else if (objc == 4) {
  727.     CONST char *command;
  728.     
  729.     command = Tk_GetBinding(interp, canvasPtr->bindingTable,
  730.     object, Tcl_GetStringFromObj(objv[3], NULL));
  731.     if (command == NULL) {
  732. CONST char *string;
  733. string = Tcl_GetStringResult(interp); 
  734. /*
  735.  * Ignore missing binding errors.  This is a special hack
  736.  * that relies on the error message returned by FindSequence
  737.  * in tkBind.c.
  738.  */
  739. if (string[0] != '') {
  740.     result = TCL_ERROR;
  741.     goto done;
  742. } else {
  743.     Tcl_ResetResult(interp);
  744. }
  745.     } else {
  746. Tcl_SetResult(interp, (char *) command, TCL_STATIC);
  747.     }
  748. } else {
  749.     Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
  750. }
  751. break;
  752.       }
  753.       case CANV_CANVASX: {
  754. int x;
  755. double grid;
  756. char buf[TCL_DOUBLE_SPACE];
  757. if ((objc < 3) || (objc > 4)) {
  758.     Tcl_WrongNumArgs(interp, 2, objv, "screenx ?gridspacing?");
  759.     result = TCL_ERROR;
  760.     goto done;
  761. }
  762. if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2], &x) != TCL_OK) {
  763.     result = TCL_ERROR;
  764.     goto done;
  765. }
  766. if (objc == 4) {
  767.     if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, objv[3],
  768.     &grid) != TCL_OK) {
  769. result = TCL_ERROR;
  770. goto done;
  771.     }
  772. } else {
  773.     grid = 0.0;
  774. }
  775. x += canvasPtr->xOrigin;
  776. Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf);
  777. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  778. break;
  779.       }
  780.       case CANV_CANVASY: {
  781. int y;
  782. double grid;
  783. char buf[TCL_DOUBLE_SPACE];
  784. if ((objc < 3) || (objc > 4)) {
  785.     Tcl_WrongNumArgs(interp, 2, objv, "screeny ?gridspacing?");
  786.     result = TCL_ERROR;
  787.     goto done;
  788. }
  789. if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2], &y) != TCL_OK) {
  790.     result = TCL_ERROR;
  791.     goto done;
  792. }
  793. if (objc == 4) {
  794.     if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
  795.     objv[3], &grid) != TCL_OK) {
  796. result = TCL_ERROR;
  797. goto done;
  798.     }
  799. } else {
  800.     grid = 0.0;
  801. }
  802. y += canvasPtr->yOrigin;
  803. Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf);
  804. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  805. break;
  806.       }
  807.       case CANV_CGET: {
  808. if (objc != 3) {
  809.     Tcl_WrongNumArgs(interp, 2, objv, "option");
  810.     result = TCL_ERROR;
  811.     goto done;
  812. }
  813. result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
  814. (char *) canvasPtr, Tcl_GetString(objv[2]), 0);
  815. break;
  816.       }
  817.       case CANV_CONFIGURE: {
  818. if (objc == 2) {
  819.     result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
  820.     (char *) canvasPtr, (char *) NULL, 0);
  821. } else if (objc == 3) {
  822.     result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
  823.     (char *) canvasPtr, Tcl_GetString(objv[2]), 0);
  824. } else {
  825.     result = ConfigureCanvas(interp, canvasPtr, objc-2, objv+2,
  826.     TK_CONFIG_ARGV_ONLY);
  827. }
  828. break;
  829.       }
  830.       case CANV_COORDS: {
  831. if (objc < 3) {
  832.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?x y x y ...?");
  833.     result = TCL_ERROR;
  834.     goto done;
  835. }
  836. #ifdef USE_OLD_TAG_SEARCH
  837. itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  838. #else /* USE_OLD_TAG_SEARCH */
  839. if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  840.     goto done;
  841. }
  842. itemPtr = TagSearchFirst(searchPtr);
  843. #endif /* USE_OLD_TAG_SEARCH */
  844. if (itemPtr != NULL) {
  845.     if (objc != 3) {
  846. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  847.     }
  848.     if (itemPtr->typePtr->coordProc != NULL) {
  849.       if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  850. result = (*itemPtr->typePtr->coordProc)(interp,
  851. (Tk_Canvas) canvasPtr, itemPtr, objc-3, objv+3);
  852.       } else {
  853. CONST char **args = GetStringsFromObjs(objc-3, objv+3);
  854. result = (*itemPtr->typePtr->coordProc)(interp,
  855. (Tk_Canvas) canvasPtr, itemPtr, objc-3, (Tcl_Obj **) args);
  856. if (args) ckfree((char *) args);
  857.       }
  858.     }
  859.     if (objc != 3) {
  860. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  861.     }
  862. }
  863. break;
  864.       }
  865.       case CANV_CREATE: {
  866. Tk_ItemType *typePtr;
  867. Tk_ItemType *matchPtr = NULL;
  868. Tk_Item *itemPtr;
  869. char buf[TCL_INTEGER_SPACE];
  870. int isNew = 0;
  871. Tcl_HashEntry *entryPtr;
  872. char *arg;
  873. if (objc < 3) {
  874.     Tcl_WrongNumArgs(interp, 2, objv, "type coords ?arg arg ...?");
  875.     result = TCL_ERROR;
  876.     goto done;
  877. }
  878. arg = Tcl_GetStringFromObj(objv[2], &length);
  879. c = arg[0];
  880. Tcl_MutexLock(&typeListMutex);
  881. for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
  882.     if ((c == typePtr->name[0])
  883.     && (strncmp(arg, typePtr->name, (unsigned) length) == 0)) {
  884. if (matchPtr != NULL) {
  885.     Tcl_MutexUnlock(&typeListMutex);
  886.   badType:
  887.     Tcl_AppendResult(interp,
  888.     "unknown or ambiguous item type "",
  889.     arg, """, (char *) NULL);
  890.     result = TCL_ERROR;
  891.     goto done;
  892. }
  893. matchPtr = typePtr;
  894.     }
  895. }
  896. /*
  897.  * Can unlock now because we no longer look at the fields of
  898.  * the matched item type that are potentially modified by
  899.  * other threads.
  900.  */
  901. Tcl_MutexUnlock(&typeListMutex);
  902. if (matchPtr == NULL) {
  903.     goto badType;
  904. }
  905. if (objc < 4) {
  906.     /*
  907.      * Allow more specific error return.
  908.      */
  909.     Tcl_WrongNumArgs(interp, 3, objv, "coords ?arg arg ...?");
  910.     result = TCL_ERROR;
  911.     goto done;
  912. }
  913. typePtr = matchPtr;
  914. itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
  915. itemPtr->id = canvasPtr->nextId;
  916. canvasPtr->nextId++;
  917. itemPtr->tagPtr = itemPtr->staticTagSpace;
  918. itemPtr->tagSpace = TK_TAG_SPACE;
  919. itemPtr->numTags = 0;
  920. itemPtr->typePtr = typePtr;
  921. itemPtr->state = TK_STATE_NULL;
  922. itemPtr->redraw_flags = 0;
  923. if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  924.     result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
  925.     itemPtr, objc-3, objv+3);
  926. } else {
  927.     CONST char **args = GetStringsFromObjs(objc-3, objv+3);
  928.     result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
  929.     itemPtr, objc-3, (Tcl_Obj **) args);
  930.     if (args) ckfree((char *) args);
  931. }
  932. if (result != TCL_OK) {
  933.     ckfree((char *) itemPtr);
  934.     result = TCL_ERROR;
  935.     goto done;
  936. }
  937. itemPtr->nextPtr = NULL;
  938. entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,
  939. (char *) itemPtr->id, &isNew);
  940. Tcl_SetHashValue(entryPtr, itemPtr);
  941. itemPtr->prevPtr = canvasPtr->lastItemPtr;
  942. canvasPtr->hotPtr = itemPtr;
  943. canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
  944. if (canvasPtr->lastItemPtr == NULL) {
  945.     canvasPtr->firstItemPtr = itemPtr;
  946. } else {
  947.     canvasPtr->lastItemPtr->nextPtr = itemPtr;
  948. }
  949. canvasPtr->lastItemPtr = itemPtr;
  950. itemPtr->redraw_flags |= FORCE_REDRAW;
  951. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  952. canvasPtr->flags |= REPICK_NEEDED;
  953. sprintf(buf, "%d", itemPtr->id);
  954. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  955. break;
  956.       }
  957.       case CANV_DCHARS: {
  958. int first, last;
  959. int x1,x2,y1,y2;
  960. if ((objc != 4) && (objc != 5)) {
  961.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?");
  962.     result = TCL_ERROR;
  963.     goto done;
  964. }
  965. #ifdef USE_OLD_TAG_SEARCH
  966. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  967. itemPtr != NULL; itemPtr = NextItem(&search)) {
  968. #else /* USE_OLD_TAG_SEARCH */
  969. if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  970.     goto done;
  971. }
  972. for (itemPtr = TagSearchFirst(searchPtr);
  973. itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  974. #endif /* USE_OLD_TAG_SEARCH */
  975.     if ((itemPtr->typePtr->indexProc == NULL)
  976.     || (itemPtr->typePtr->dCharsProc == NULL)) {
  977. continue;
  978.     }
  979.     if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  980. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  981. itemPtr, (char *) objv[3], &first);
  982.     } else {
  983. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  984. itemPtr, Tcl_GetStringFromObj(objv[3], NULL), &first);
  985.     }
  986.     if (result != TCL_OK) {
  987. goto done;
  988.     }
  989.     if (objc == 5) {
  990. if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  991.     result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  992.     itemPtr, (char *) objv[4], &last);
  993. } else {
  994.     result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  995.     itemPtr, Tcl_GetStringFromObj(objv[4], NULL), &last);
  996. }
  997. if (result != TCL_OK) {
  998.     goto done;
  999. }
  1000.     } else {
  1001. last = first;
  1002.     }
  1003.     /*
  1004.      * Redraw both item's old and new areas:  it's possible
  1005.      * that a delete could result in a new area larger than
  1006.      * the old area. Except if the insertProc sets the
  1007.      * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
  1008.      */
  1009.     x1 = itemPtr->x1; y1 = itemPtr->y1;
  1010.     x2 = itemPtr->x2; y2 = itemPtr->y2;
  1011.     itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
  1012.     (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
  1013.     itemPtr, first, last);
  1014.     if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
  1015. Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
  1016. x1, y1, x2, y2);
  1017. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1018.     }
  1019.     itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
  1020. }
  1021. break;
  1022.       }
  1023.       case CANV_DELETE: {
  1024. int i;
  1025. Tcl_HashEntry *entryPtr;
  1026. for (i = 2; i < objc; i++) {
  1027. #ifdef USE_OLD_TAG_SEARCH
  1028.     for (itemPtr = StartTagSearch(canvasPtr, objv[i], &search);
  1029. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1030. #else /* USE_OLD_TAG_SEARCH */
  1031.     if ((result = TagSearchScan(canvasPtr, objv[i], &searchPtr)) != TCL_OK) {
  1032. goto done;
  1033.     }
  1034.     for (itemPtr = TagSearchFirst(searchPtr);
  1035. itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1036. #endif /* USE_OLD_TAG_SEARCH */
  1037. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1038. if (canvasPtr->bindingTable != NULL) {
  1039.     Tk_DeleteAllBindings(canvasPtr->bindingTable,
  1040.     (ClientData) itemPtr);
  1041. }
  1042. (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
  1043. canvasPtr->display);
  1044. if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
  1045.     ckfree((char *) itemPtr->tagPtr);
  1046. }
  1047. entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
  1048. (char *) itemPtr->id);
  1049. Tcl_DeleteHashEntry(entryPtr);
  1050. if (itemPtr->nextPtr != NULL) {
  1051.     itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
  1052. }
  1053. if (itemPtr->prevPtr != NULL) {
  1054.     itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
  1055. }
  1056. if (canvasPtr->firstItemPtr == itemPtr) {
  1057.     canvasPtr->firstItemPtr = itemPtr->nextPtr;
  1058.     if (canvasPtr->firstItemPtr == NULL) {
  1059. canvasPtr->lastItemPtr = NULL;
  1060.     }
  1061. }
  1062. if (canvasPtr->lastItemPtr == itemPtr) {
  1063.     canvasPtr->lastItemPtr = itemPtr->prevPtr;
  1064. }
  1065. ckfree((char *) itemPtr);
  1066. if (itemPtr == canvasPtr->currentItemPtr) {
  1067.     canvasPtr->currentItemPtr = NULL;
  1068.     canvasPtr->flags |= REPICK_NEEDED;
  1069. }
  1070. if (itemPtr == canvasPtr->newCurrentPtr) {
  1071.     canvasPtr->newCurrentPtr = NULL;
  1072.     canvasPtr->flags |= REPICK_NEEDED;
  1073. }
  1074. if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
  1075.     canvasPtr->textInfo.focusItemPtr = NULL;
  1076. }
  1077. if (itemPtr == canvasPtr->textInfo.selItemPtr) {
  1078.     canvasPtr->textInfo.selItemPtr = NULL;
  1079. }
  1080. if ((itemPtr == canvasPtr->hotPtr)
  1081. || (itemPtr == canvasPtr->hotPrevPtr)) {
  1082.     canvasPtr->hotPtr = NULL;
  1083. }
  1084.     }
  1085. }
  1086. break;
  1087.       }
  1088.       case CANV_DTAG: {
  1089. Tk_Uid tag;
  1090. int i;
  1091. if ((objc != 3) && (objc != 4)) {
  1092.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagToDelete?");
  1093.     result = TCL_ERROR;
  1094.     goto done;
  1095. }
  1096. if (objc == 4) {
  1097.     tag = Tk_GetUid(Tcl_GetStringFromObj(objv[3], NULL));
  1098. } else {
  1099.     tag = Tk_GetUid(Tcl_GetStringFromObj(objv[2], NULL));
  1100. }
  1101. #ifdef USE_OLD_TAG_SEARCH
  1102. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1103. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1104. #else /* USE_OLD_TAG_SEARCH */
  1105.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1106.             goto done;
  1107.         }
  1108.         for (itemPtr = TagSearchFirst(searchPtr);
  1109.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1110. #endif /* USE_OLD_TAG_SEARCH */
  1111.     for (i = itemPtr->numTags-1; i >= 0; i--) {
  1112. if (itemPtr->tagPtr[i] == tag) {
  1113.     itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
  1114.     itemPtr->numTags--;
  1115. }
  1116.     }
  1117. }
  1118. break;
  1119.       }
  1120.       case CANV_FIND: {
  1121. if (objc < 3) {
  1122.     Tcl_WrongNumArgs(interp, 2, objv, "searchCommand ?arg arg ...?");
  1123.     result = TCL_ERROR;
  1124.     goto done;
  1125. }
  1126. #ifdef USE_OLD_TAG_SEARCH
  1127. result = FindItems(interp, canvasPtr, objc, objv, (Tcl_Obj *) NULL, 2);
  1128. #else /* USE_OLD_TAG_SEARCH */
  1129. result = FindItems(interp, canvasPtr, objc, objv,
  1130.     (Tcl_Obj *) NULL, 2, &searchPtr);
  1131. #endif /* USE_OLD_TAG_SEARCH */
  1132. break;
  1133.       }
  1134.       case CANV_FOCUS: {
  1135. if (objc > 3) {
  1136.     Tcl_WrongNumArgs(interp, 2, objv, "?tagOrId?");
  1137.     result = TCL_ERROR;
  1138.     goto done;
  1139. }
  1140. itemPtr = canvasPtr->textInfo.focusItemPtr;
  1141. if (objc == 2) {
  1142.     if (itemPtr != NULL) {
  1143. char buf[TCL_INTEGER_SPACE];
  1144. sprintf(buf, "%d", itemPtr->id);
  1145. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  1146.     }
  1147.     goto done;
  1148. }
  1149. if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {
  1150.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1151. }
  1152. if (Tcl_GetStringFromObj(objv[2], NULL)[0] == 0) {
  1153.     canvasPtr->textInfo.focusItemPtr = NULL;
  1154.     goto done;
  1155. }
  1156. #ifdef USE_OLD_TAG_SEARCH
  1157. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1158. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1159. #else /* USE_OLD_TAG_SEARCH */
  1160.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1161.             goto done;
  1162.         }
  1163.         for (itemPtr = TagSearchFirst(searchPtr);
  1164.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1165. #endif /* USE_OLD_TAG_SEARCH */
  1166.     if (itemPtr->typePtr->icursorProc != NULL) {
  1167. break;
  1168.     }
  1169. }
  1170. if (itemPtr == NULL) {
  1171.     goto done;
  1172. }
  1173. canvasPtr->textInfo.focusItemPtr = itemPtr;
  1174. if (canvasPtr->textInfo.gotFocus) {
  1175.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1176. }
  1177. break;
  1178.       }
  1179.       case CANV_GETTAGS: {
  1180. if (objc != 3) {
  1181.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId");
  1182.     result = TCL_ERROR;
  1183.     goto done;
  1184. }
  1185. #ifdef USE_OLD_TAG_SEARCH
  1186. itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1187. #else /* USE_OLD_TAG_SEARCH */
  1188.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1189.             goto done;
  1190.         }
  1191.         itemPtr = TagSearchFirst(searchPtr);
  1192. #endif /* USE_OLD_TAG_SEARCH */
  1193. if (itemPtr != NULL) {
  1194.     int i;
  1195.     for (i = 0; i < itemPtr->numTags; i++) {
  1196. Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]);
  1197.     }
  1198. }
  1199. break;
  1200.       }
  1201.       case CANV_ICURSOR: {
  1202. int index;
  1203. if (objc != 4) {
  1204.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index");
  1205.     result = TCL_ERROR;
  1206.     goto done;
  1207. }
  1208. #ifdef USE_OLD_TAG_SEARCH
  1209. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1210. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1211. #else /* USE_OLD_TAG_SEARCH */
  1212.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1213.             goto done;
  1214.         }
  1215.         for (itemPtr = TagSearchFirst(searchPtr);
  1216.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1217. #endif /* USE_OLD_TAG_SEARCH */
  1218.     if ((itemPtr->typePtr->indexProc == NULL)
  1219.     || (itemPtr->typePtr->icursorProc == NULL)) {
  1220. goto done;
  1221.     }
  1222.     if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1223. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1224. itemPtr, (char *) objv[3], &index);
  1225.     } else {
  1226. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1227. itemPtr, Tcl_GetStringFromObj(objv[3], NULL), &index);
  1228.     }
  1229.     if (result != TCL_OK) {
  1230. goto done;
  1231.     }
  1232.     (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr,
  1233.     index);
  1234.     if ((itemPtr == canvasPtr->textInfo.focusItemPtr)
  1235.     && (canvasPtr->textInfo.cursorOn)) {
  1236. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1237.     }
  1238. }
  1239. break;
  1240.       }
  1241.       case CANV_INDEX: {
  1242. int index;
  1243. char buf[TCL_INTEGER_SPACE];
  1244. if (objc != 4) {
  1245.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId string");
  1246.     result = TCL_ERROR;
  1247.     goto done;
  1248. }
  1249. #ifdef USE_OLD_TAG_SEARCH
  1250. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1251. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1252. #else /* USE_OLD_TAG_SEARCH */
  1253.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1254.             goto done;
  1255.         }
  1256.         for (itemPtr = TagSearchFirst(searchPtr);
  1257.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1258. #endif /* USE_OLD_TAG_SEARCH */
  1259.     if (itemPtr->typePtr->indexProc != NULL) {
  1260. break;
  1261.     }
  1262. }
  1263. if (itemPtr == NULL) {
  1264.     Tcl_AppendResult(interp, "can't find an indexable item "",
  1265.     Tcl_GetStringFromObj(objv[2], NULL), """, (char *) NULL);
  1266.     result = TCL_ERROR;
  1267.     goto done;
  1268. }
  1269. if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1270.     result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1271.     itemPtr, (char *) objv[3], &index);
  1272. } else {
  1273.     result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1274.     itemPtr, Tcl_GetStringFromObj(objv[3], NULL), &index);
  1275. }
  1276. if (result != TCL_OK) {
  1277.     goto done;
  1278. }
  1279. sprintf(buf, "%d", index);
  1280. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  1281. break;
  1282.       }
  1283.       case CANV_INSERT: {
  1284. int beforeThis;
  1285. int x1,x2,y1,y2;
  1286. if (objc != 5) {
  1287.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string");
  1288.     result = TCL_ERROR;
  1289.     goto done;
  1290. }
  1291. #ifdef USE_OLD_TAG_SEARCH
  1292. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1293. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1294. #else /* USE_OLD_TAG_SEARCH */
  1295.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1296.             goto done;
  1297.         }
  1298.         for (itemPtr = TagSearchFirst(searchPtr);
  1299.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1300. #endif /* USE_OLD_TAG_SEARCH */
  1301.     if ((itemPtr->typePtr->indexProc == NULL)
  1302.     || (itemPtr->typePtr->insertProc == NULL)) {
  1303. continue;
  1304.     }
  1305.     if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1306. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1307. itemPtr, (char *) objv[3], &beforeThis);
  1308.     } else {
  1309. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1310. itemPtr, Tcl_GetStringFromObj(objv[3], NULL), &beforeThis);
  1311.     }
  1312.     if (result != TCL_OK) {
  1313. goto done;
  1314.     }
  1315.     /*
  1316.      * Redraw both item's old and new areas:  it's possible
  1317.      * that an insertion could result in a new area either
  1318.      * larger or smaller than the old area. Except if the
  1319.      * insertProc sets the TK_ITEM_DONT_REDRAW flag, nothing
  1320.      * more needs to be done.
  1321.      */
  1322.     x1 = itemPtr->x1; y1 = itemPtr->y1;
  1323.     x2 = itemPtr->x2; y2 = itemPtr->y2;
  1324.     itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
  1325.     if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1326. (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
  1327. itemPtr, beforeThis, (char *) objv[4]);
  1328.     } else {
  1329. (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
  1330. itemPtr, beforeThis, Tcl_GetStringFromObj(objv[4], NULL));
  1331.     }
  1332.     if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
  1333. Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
  1334. x1, y1, x2, y2);
  1335. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1336.     }
  1337.     itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
  1338. }
  1339. break;
  1340.       }
  1341.       case CANV_ITEMCGET: {
  1342. if (objc != 4) {
  1343.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId option");
  1344.     result = TCL_ERROR;
  1345.     goto done;
  1346. }
  1347. #ifdef USE_OLD_TAG_SEARCH
  1348. itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1349. #else /* USE_OLD_TAG_SEARCH */
  1350.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1351.             goto done;
  1352.         }
  1353.         itemPtr = TagSearchFirst(searchPtr);
  1354. #endif /* USE_OLD_TAG_SEARCH */
  1355. if (itemPtr != NULL) {
  1356.     result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
  1357.     itemPtr->typePtr->configSpecs, (char *) itemPtr,
  1358.     Tcl_GetStringFromObj(objv[3], NULL), 0);
  1359. }
  1360. break;
  1361.       }
  1362.       case CANV_ITEMCONFIGURE: {
  1363. if (objc < 3) {
  1364.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?option value ...?");
  1365.     result = TCL_ERROR;
  1366.     goto done;
  1367. }
  1368. #ifdef USE_OLD_TAG_SEARCH
  1369. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1370. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1371. #else /* USE_OLD_TAG_SEARCH */
  1372.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1373.             goto done;
  1374.         }
  1375.         for (itemPtr = TagSearchFirst(searchPtr);
  1376.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1377. #endif /* USE_OLD_TAG_SEARCH */
  1378.     if (objc == 3) {
  1379. result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
  1380. itemPtr->typePtr->configSpecs, (char *) itemPtr,
  1381. (char *) NULL, 0);
  1382.     } else if (objc == 4) {
  1383. result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
  1384. itemPtr->typePtr->configSpecs, (char *) itemPtr,
  1385. Tcl_GetString(objv[3]), 0);
  1386.     } else {
  1387. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1388. if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1389. result = (*itemPtr->typePtr->configProc)(interp,
  1390. (Tk_Canvas) canvasPtr, itemPtr, objc-3, objv+3,
  1391. TK_CONFIG_ARGV_ONLY);
  1392. } else {
  1393. CONST char **args = GetStringsFromObjs(objc-3, objv+3);
  1394. result = (*itemPtr->typePtr->configProc)(interp,
  1395. (Tk_Canvas) canvasPtr, itemPtr, objc-3, (Tcl_Obj **) args,
  1396. TK_CONFIG_ARGV_ONLY);
  1397. if (args) ckfree((char *) args);
  1398. }
  1399. EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1400. canvasPtr->flags |= REPICK_NEEDED;
  1401.     }
  1402.     if ((result != TCL_OK) || (objc < 5)) {
  1403. break;
  1404.     }
  1405. }
  1406. break;
  1407.       }
  1408.       case CANV_LOWER: {
  1409. Tk_Item *itemPtr;
  1410. if ((objc != 3) && (objc != 4)) {
  1411.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?belowThis?");
  1412.     result = TCL_ERROR;
  1413.     goto done;
  1414. }
  1415. /*
  1416.  * First find the item just after which we'll insert the
  1417.  * named items.
  1418.  */
  1419. if (objc == 3) {
  1420.     itemPtr = NULL;
  1421. } else {
  1422. #ifdef USE_OLD_TAG_SEARCH
  1423.     itemPtr = StartTagSearch(canvasPtr, objv[3], &search);
  1424. #else /* USE_OLD_TAG_SEARCH */
  1425.             if ((result = TagSearchScan(canvasPtr, objv[3], &searchPtr)) != TCL_OK) {
  1426.                 goto done;
  1427.             }
  1428.             itemPtr = TagSearchFirst(searchPtr);
  1429. #endif /* USE_OLD_TAG_SEARCH */
  1430.     if (itemPtr == NULL) {
  1431. Tcl_AppendResult(interp, "tag "", Tcl_GetString(objv[3]),
  1432. "" doesn't match any items", (char *) NULL);
  1433. goto done;
  1434.     }
  1435.     itemPtr = itemPtr->prevPtr;
  1436. }
  1437. #ifdef USE_OLD_TAG_SEARCH
  1438. RelinkItems(canvasPtr, objv[2], itemPtr);
  1439. #else /* USE_OLD_TAG_SEARCH */
  1440.         if ((result = RelinkItems(canvasPtr, objv[2], itemPtr, &searchPtr)) != TCL_OK) {
  1441.             goto done;
  1442.         }
  1443. #endif /* USE_OLD_TAG_SEARCH */
  1444. break;
  1445.       }
  1446.       case CANV_MOVE: {
  1447. double xAmount, yAmount;
  1448. if (objc != 5) {
  1449.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId xAmount yAmount");
  1450.     result = TCL_ERROR;
  1451.     goto done;
  1452. }
  1453. if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, objv[3],
  1454. &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,
  1455. (Tk_Canvas) canvasPtr, objv[4], &yAmount) != TCL_OK)) {
  1456.     result = TCL_ERROR;
  1457.     goto done;
  1458. }
  1459. #ifdef USE_OLD_TAG_SEARCH
  1460. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1461. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1462. #else /* USE_OLD_TAG_SEARCH */
  1463.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1464.             goto done;
  1465.         }
  1466.         for (itemPtr = TagSearchFirst(searchPtr);
  1467.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1468. #endif /* USE_OLD_TAG_SEARCH */
  1469.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1470.     (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
  1471.     itemPtr,  xAmount, yAmount);
  1472.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1473.     canvasPtr->flags |= REPICK_NEEDED;
  1474. }
  1475. break;
  1476.       }
  1477.       case CANV_POSTSCRIPT: {
  1478. CONST char **args = GetStringsFromObjs(objc, objv);
  1479. result = TkCanvPostscriptCmd(canvasPtr, interp, objc, args);
  1480. if (args) ckfree((char *) args);
  1481. break;
  1482.       }
  1483.       case CANV_RAISE: {
  1484. Tk_Item *prevPtr;
  1485. if ((objc != 3) && (objc != 4)) {
  1486.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?aboveThis?");
  1487.     result = TCL_ERROR;
  1488.     goto done;
  1489. }
  1490. /*
  1491.  * First find the item just after which we'll insert the
  1492.  * named items.
  1493.  */
  1494. if (objc == 3) {
  1495.     prevPtr = canvasPtr->lastItemPtr;
  1496. } else {
  1497.     prevPtr = NULL;
  1498. #ifdef USE_OLD_TAG_SEARCH
  1499.     for (itemPtr = StartTagSearch(canvasPtr, objv[3], &search);
  1500.     itemPtr != NULL; itemPtr = NextItem(&search)) {
  1501. #else /* USE_OLD_TAG_SEARCH */
  1502.             if ((result = TagSearchScan(canvasPtr, objv[3], &searchPtr)) != TCL_OK) {
  1503.                 goto done;
  1504.             }
  1505.             for (itemPtr = TagSearchFirst(searchPtr);
  1506.                     itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1507. #endif /* USE_OLD_TAG_SEARCH */
  1508. prevPtr = itemPtr;
  1509.     }
  1510.     if (prevPtr == NULL) {
  1511. Tcl_AppendResult(interp, "tagOrId "", Tcl_GetStringFromObj(objv[3], NULL),
  1512. "" doesn't match any items", (char *) NULL);
  1513. result = TCL_ERROR;
  1514. goto done;
  1515.     }
  1516. }
  1517. #ifdef USE_OLD_TAG_SEARCH
  1518. RelinkItems(canvasPtr, objv[2], prevPtr);
  1519. #else /* USE_OLD_TAG_SEARCH */
  1520.         result = RelinkItems(canvasPtr, objv[2], prevPtr, &searchPtr);
  1521.         if (result != TCL_OK) {
  1522.             goto done;
  1523.         }
  1524. #endif /* USE_OLD_TAG_SEARCH */
  1525. break;
  1526.       }
  1527.       case CANV_SCALE: {
  1528. double xOrigin, yOrigin, xScale, yScale;
  1529. if (objc != 7) {
  1530.     Tcl_WrongNumArgs(interp, 2, objv, "tagOrId xOrigin yOrigin xScale yScale");
  1531.     result = TCL_ERROR;
  1532.     goto done;
  1533. }
  1534. if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
  1535.     objv[3], &xOrigin) != TCL_OK)
  1536. || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
  1537.     objv[4], &yOrigin) != TCL_OK)
  1538. || (Tcl_GetDoubleFromObj(interp, objv[5], &xScale) != TCL_OK)
  1539. || (Tcl_GetDoubleFromObj(interp, objv[6], &yScale) != TCL_OK)) {
  1540.     result = TCL_ERROR;
  1541.     goto done;
  1542. }
  1543. if ((xScale == 0.0) || (yScale == 0.0)) {
  1544.     Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC);
  1545.     result = TCL_ERROR;
  1546.     goto done;
  1547. }
  1548. #ifdef USE_OLD_TAG_SEARCH
  1549. for (itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1550. itemPtr != NULL; itemPtr = NextItem(&search)) {
  1551. #else /* USE_OLD_TAG_SEARCH */
  1552.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1553.             goto done;
  1554.         }
  1555.         for (itemPtr = TagSearchFirst(searchPtr);
  1556.                 itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1557. #endif /* USE_OLD_TAG_SEARCH */
  1558.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1559.     (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
  1560.     itemPtr, xOrigin, yOrigin, xScale, yScale);
  1561.     EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
  1562.     canvasPtr->flags |= REPICK_NEEDED;
  1563. }
  1564. break;
  1565.       }
  1566.       case CANV_SCAN: {
  1567. int x, y, gain=10;
  1568. static CONST char *optionStrings[] = {
  1569.     "mark", "dragto", NULL
  1570. };
  1571. if (objc < 5) {
  1572.     Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?dragGain?");
  1573.     result = TCL_ERROR;
  1574. } else if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings,
  1575. "scan option", 0, &index) != TCL_OK) {
  1576.     result = TCL_ERROR;
  1577. } else if ((objc != 5) && (objc != 5+index)) {
  1578.     Tcl_WrongNumArgs(interp, 3, objv, index?"x y ?gain?":"x y");
  1579.     result = TCL_ERROR;
  1580. } else if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
  1581. || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
  1582.     result = TCL_ERROR;
  1583. } else if ((objc == 6) &&
  1584. (Tcl_GetIntFromObj(interp, objv[5], &gain) != TCL_OK)) {
  1585.     result = TCL_ERROR;
  1586. } else if (!index) {
  1587.     canvasPtr->scanX = x;
  1588.     canvasPtr->scanXOrigin = canvasPtr->xOrigin;
  1589.     canvasPtr->scanY = y;
  1590.     canvasPtr->scanYOrigin = canvasPtr->yOrigin;
  1591. } else {
  1592.     int newXOrigin, newYOrigin, tmp;
  1593.     /*
  1594.      * Compute a new view origin for the canvas, amplifying the
  1595.      * mouse motion.
  1596.      */
  1597.     tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX)
  1598.     - canvasPtr->scrollX1;
  1599.     newXOrigin = canvasPtr->scrollX1 + tmp;
  1600.     tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY)
  1601.     - canvasPtr->scrollY1;
  1602.     newYOrigin = canvasPtr->scrollY1 + tmp;
  1603.     CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
  1604. }
  1605. break;
  1606.       }
  1607.       case CANV_SELECT: {
  1608. int index, optionindex;
  1609. static CONST char *optionStrings[] = {
  1610.     "adjust", "clear", "from", "item", "to", NULL
  1611. };
  1612. enum options {
  1613.     CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO
  1614. };
  1615. if (objc < 3) {
  1616.     Tcl_WrongNumArgs(interp, 2, objv, "option ?tagOrId? ?arg?");
  1617.     result = TCL_ERROR;
  1618.     goto done;
  1619. }
  1620. if (objc >= 4) {
  1621. #ifdef USE_OLD_TAG_SEARCH
  1622.     for (itemPtr = StartTagSearch(canvasPtr, objv[3], &search);
  1623.     itemPtr != NULL; itemPtr = NextItem(&search)) {
  1624. #else /* USE_OLD_TAG_SEARCH */
  1625.             if ((result = TagSearchScan(canvasPtr, objv[3], &searchPtr)) != TCL_OK) {
  1626.                 goto done;
  1627.             }
  1628.             for (itemPtr = TagSearchFirst(searchPtr);
  1629.                     itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
  1630. #endif /* USE_OLD_TAG_SEARCH */
  1631. if ((itemPtr->typePtr->indexProc != NULL)
  1632. && (itemPtr->typePtr->selectionProc != NULL)){
  1633.     break;
  1634. }
  1635.     }
  1636.     if (itemPtr == NULL) {
  1637. Tcl_AppendResult(interp,
  1638. "can't find an indexable and selectable item "",
  1639. Tcl_GetStringFromObj(objv[3], NULL), """, (char *) NULL);
  1640. result = TCL_ERROR;
  1641. goto done;
  1642.     }
  1643. }
  1644. if (objc == 5) {
  1645.     if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
  1646. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1647. itemPtr, (char *) objv[4], &index);
  1648.     } else {
  1649. result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
  1650. itemPtr, Tcl_GetStringFromObj(objv[4], NULL), &index);
  1651.     }
  1652.     if (result != TCL_OK) {
  1653. goto done;
  1654.     }
  1655. }
  1656. if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings, "select option", 0,
  1657. &optionindex) != TCL_OK) {
  1658.     result = TCL_ERROR;
  1659.     goto done;
  1660. }
  1661. switch ((enum options) optionindex) {
  1662.   case CANV_ADJUST: {
  1663.     if (objc != 5) {
  1664. Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index");
  1665. result = TCL_ERROR;
  1666. goto done;
  1667.     }
  1668.     if (canvasPtr->textInfo.selItemPtr == itemPtr) {
  1669. if (index < (canvasPtr->textInfo.selectFirst
  1670. + canvasPtr->textInfo.selectLast)/2) {
  1671.     canvasPtr->textInfo.selectAnchor =
  1672.     canvasPtr->textInfo.selectLast + 1;
  1673. } else {
  1674.     canvasPtr->textInfo.selectAnchor =
  1675.     canvasPtr->textInfo.selectFirst;
  1676. }
  1677.     }
  1678.     CanvasSelectTo(canvasPtr, itemPtr, index);
  1679.     break;
  1680.   }
  1681.   case CANV_CLEAR: {
  1682.     if (objc != 3) {
  1683. Tcl_AppendResult(interp, 3, objv, (char *) NULL);
  1684. result = TCL_ERROR;
  1685. goto done;
  1686.     }
  1687.     if (canvasPtr->textInfo.selItemPtr != NULL) {
  1688. EventuallyRedrawItem((Tk_Canvas) canvasPtr,
  1689. canvasPtr->textInfo.selItemPtr);
  1690. canvasPtr->textInfo.selItemPtr = NULL;
  1691.     }
  1692.     goto done;
  1693.     break;
  1694.   }
  1695.   case CANV_FROM: {
  1696.     if (objc != 5) {
  1697. Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index");
  1698. result = TCL_ERROR;
  1699. goto done;
  1700.     }
  1701.     canvasPtr->textInfo.anchorItemPtr = itemPtr;
  1702.     canvasPtr->textInfo.selectAnchor = index;
  1703.     break;
  1704.   }
  1705.   case CANV_ITEM: {
  1706.     if (objc != 3) {
  1707. Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
  1708. result = TCL_ERROR;
  1709. goto done;
  1710.     }
  1711.     if (canvasPtr->textInfo.selItemPtr != NULL) {
  1712. char buf[TCL_INTEGER_SPACE];
  1713. sprintf(buf, "%d", canvasPtr->textInfo.selItemPtr->id);
  1714. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  1715.     }
  1716.     break;
  1717.   }
  1718.   case CANV_TO: {
  1719.     if (objc != 5) {
  1720. Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index");
  1721. result = TCL_ERROR;
  1722. goto done;
  1723.     }
  1724.     CanvasSelectTo(canvasPtr, itemPtr, index);
  1725.     break;
  1726.   }
  1727. }
  1728. break;
  1729.       }
  1730.       case CANV_TYPE: {
  1731. if (objc != 3) {
  1732.     Tcl_WrongNumArgs(interp, 2, objv, "tag");
  1733.     result = TCL_ERROR;
  1734.     goto done;
  1735. }
  1736. #ifdef USE_OLD_TAG_SEARCH
  1737. itemPtr = StartTagSearch(canvasPtr, objv[2], &search);
  1738. #else /* USE_OLD_TAG_SEARCH */
  1739.         if ((result = TagSearchScan(canvasPtr, objv[2], &searchPtr)) != TCL_OK) {
  1740.             goto done;
  1741.         }
  1742.         itemPtr = TagSearchFirst(searchPtr);
  1743. #endif /* USE_OLD_TAG_SEARCH */
  1744. if (itemPtr != NULL) {
  1745.     Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC);
  1746. }
  1747. break;
  1748.       }
  1749.       case CANV_XVIEW: {
  1750. int count, type;
  1751. int newX = 0; /* Initialization needed only to prevent
  1752.  * gcc warnings. */
  1753. double fraction;
  1754. if (objc == 2) {
  1755.     Tcl_SetObjResult(interp, ScrollFractions(
  1756.     canvasPtr->xOrigin + canvasPtr->inset,
  1757.     canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
  1758.     - canvasPtr->inset, canvasPtr->scrollX1,
  1759.     canvasPtr->scrollX2));
  1760. } else {
  1761.     CONST char **args = GetStringsFromObjs(objc, objv);
  1762.     type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count);
  1763.     if (args) ckfree((char *) args);
  1764.     switch (type) {
  1765. case TK_SCROLL_ERROR:
  1766.     result = TCL_ERROR;
  1767.     goto done;
  1768. case TK_SCROLL_MOVETO:
  1769.     newX = canvasPtr->scrollX1 - canvasPtr->inset
  1770.     + (int) (fraction * (canvasPtr->scrollX2
  1771.     - canvasPtr->scrollX1) + 0.5);
  1772.     break;
  1773. case TK_SCROLL_PAGES:
  1774.     newX = (int) (canvasPtr->xOrigin + count * .9
  1775.     * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
  1776.     break;
  1777. case TK_SCROLL_UNITS:
  1778.     if (canvasPtr->xScrollIncrement > 0) {
  1779. newX = canvasPtr->xOrigin
  1780. + count*canvasPtr->xScrollIncrement;
  1781.     } else {
  1782. newX = (int) (canvasPtr->xOrigin + count * .1
  1783. * (Tk_Width(canvasPtr->tkwin)
  1784. - 2*canvasPtr->inset));
  1785.     }
  1786.     break;
  1787.     }
  1788.     CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
  1789. }
  1790. break;
  1791.       }
  1792.       case CANV_YVIEW: {
  1793. int count, type;
  1794. int newY = 0; /* Initialization needed only to prevent
  1795.  * gcc warnings. */
  1796. double fraction;
  1797. if (objc == 2) {
  1798.     Tcl_SetObjResult(interp,ScrollFractions(
  1799.     canvasPtr->yOrigin + canvasPtr->inset,
  1800.     canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
  1801.     - canvasPtr->inset, canvasPtr->scrollY1,
  1802.     canvasPtr->scrollY2));
  1803. } else {
  1804.     CONST char **args = GetStringsFromObjs(objc, objv);
  1805.     type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count);
  1806.     if (args) ckfree((char *) args);
  1807.     switch (type) {
  1808. case TK_SCROLL_ERROR:
  1809.     result = TCL_ERROR;
  1810.     goto done;
  1811. case TK_SCROLL_MOVETO:
  1812.     newY = canvasPtr->scrollY1 - canvasPtr->inset
  1813.     + (int) (fraction*(canvasPtr->scrollY2
  1814.     - canvasPtr->scrollY1) + 0.5);
  1815.     break;
  1816. case TK_SCROLL_PAGES:
  1817.     newY = (int) (canvasPtr->yOrigin + count * .9
  1818.     * (Tk_Height(canvasPtr->tkwin)
  1819.     - 2*canvasPtr->inset));
  1820.     break;
  1821. case TK_SCROLL_UNITS:
  1822.     if (canvasPtr->yScrollIncrement > 0) {
  1823. newY = canvasPtr->yOrigin
  1824. + count*canvasPtr->yScrollIncrement;
  1825.     } else {
  1826. newY = (int) (canvasPtr->yOrigin + count * .1
  1827. * (Tk_Height(canvasPtr->tkwin)
  1828. - 2*canvasPtr->inset));
  1829.     }
  1830.     break;
  1831.     }
  1832.     CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
  1833. }
  1834. break;
  1835.       }
  1836.     }
  1837.     done:
  1838. #ifndef USE_OLD_TAG_SEARCH
  1839.     TagSearchDestroy(searchPtr);
  1840. #endif /* not USE_OLD_TAG_SEARCH */
  1841.     Tcl_Release((ClientData) canvasPtr);
  1842.     return result;
  1843. }
  1844. /*
  1845.  *----------------------------------------------------------------------
  1846.  *
  1847.  * DestroyCanvas --
  1848.  *
  1849.  * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  1850.  * to clean up the internal structure of a canvas at a safe time
  1851.  * (when no-one is using it anymore).
  1852.  *
  1853.  * Results:
  1854.  * None.
  1855.  *
  1856.  * Side effects:
  1857.  * Everything associated with the canvas is freed up.
  1858.  *
  1859.  *----------------------------------------------------------------------
  1860.  */
  1861. static void
  1862. DestroyCanvas(memPtr)
  1863.     char *memPtr; /* Info about canvas widget. */
  1864. {
  1865.     TkCanvas *canvasPtr = (TkCanvas *) memPtr;
  1866.     Tk_Item *itemPtr;
  1867. #ifndef USE_OLD_TAG_SEARCH
  1868.     TagSearchExpr *expr, *next;
  1869. #endif
  1870.     /*
  1871.      * Free up all of the items in the canvas.
  1872.      */
  1873.     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  1874.     itemPtr = canvasPtr->firstItemPtr) {
  1875. canvasPtr->firstItemPtr = itemPtr->nextPtr;
  1876. (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
  1877. canvasPtr->display);
  1878. if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
  1879.     ckfree((char *) itemPtr->tagPtr);
  1880. }
  1881. ckfree((char *) itemPtr);
  1882.     }
  1883.     /*
  1884.      * Free up all the stuff that requires special handling,
  1885.      * then let Tk_FreeOptions handle all the standard option-related
  1886.      * stuff.
  1887.      */
  1888.     Tcl_DeleteHashTable(&canvasPtr->idTable);
  1889.     if (canvasPtr->pixmapGC != None) {
  1890. Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
  1891.     }
  1892. #ifndef USE_OLD_TAG_SEARCH
  1893.     expr = canvasPtr->bindTagExprs;
  1894.     while (expr) {
  1895. next = expr->next;
  1896. TagSearchExprDestroy(expr);
  1897. expr = next;
  1898.     }
  1899. #endif
  1900.     Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
  1901.     if (canvasPtr->bindingTable != NULL) {
  1902. Tk_DeleteBindingTable(canvasPtr->bindingTable);
  1903.     }
  1904.     Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
  1905.     canvasPtr->tkwin = NULL;
  1906.     ckfree((char *) canvasPtr);
  1907. }
  1908. /*
  1909.  *----------------------------------------------------------------------
  1910.  *
  1911.  * ConfigureCanvas --
  1912.  *
  1913.  * This procedure is called to process an objv/objc list, plus
  1914.  * the Tk option database, in order to configure (or
  1915.  * reconfigure) a canvas widget.
  1916.  *
  1917.  * Results:
  1918.  * The return value is a standard Tcl result.  If TCL_ERROR is
  1919.  * returned, then the interp's result contains an error message.
  1920.  *
  1921.  * Side effects:
  1922.  * Configuration information, such as colors, border width,
  1923.  * etc. get set for canvasPtr;  old resources get freed,
  1924.  * if there were any.
  1925.  *
  1926.  *----------------------------------------------------------------------
  1927.  */
  1928. static int
  1929. ConfigureCanvas(interp, canvasPtr, objc, objv, flags)
  1930.     Tcl_Interp *interp; /* Used for error reporting. */
  1931.     TkCanvas *canvasPtr; /* Information about widget;  may or may
  1932.  * not already have values for some fields. */
  1933.     int objc; /* Number of valid entries in objv. */
  1934.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1935.     int flags; /* Flags to pass to Tk_ConfigureWidget. */
  1936. {
  1937.     XGCValues gcValues;
  1938.     GC new;
  1939.     if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
  1940.     objc, (CONST char **) objv, (char *) canvasPtr,
  1941.     flags|TK_CONFIG_OBJS) != TCL_OK) {
  1942. return TCL_ERROR;
  1943.     }
  1944.     /*
  1945.      * A few options need special processing, such as setting the
  1946.      * background from a 3-D border and creating a GC for copying
  1947.      * bits to the screen.
  1948.      */
  1949.     Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
  1950.     if (canvasPtr->highlightWidth < 0) {
  1951. canvasPtr->highlightWidth = 0;
  1952.     }
  1953.     canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
  1954.     gcValues.function = GXcopy;
  1955.     gcValues.graphics_exposures = False;
  1956.     gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
  1957.     new = Tk_GetGC(canvasPtr->tkwin,
  1958.     GCFunction|GCGraphicsExposures|GCForeground, &gcValues);
  1959.     if (canvasPtr->pixmapGC != None) {
  1960. Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
  1961.     }
  1962.     canvasPtr->pixmapGC = new;
  1963.     /*
  1964.      * Reset the desired dimensions for the window.
  1965.      */
  1966.     Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
  1967.     canvasPtr->height + 2*canvasPtr->inset);
  1968.     /*
  1969.      * Restart the cursor timing sequence in case the on-time or off-time
  1970.      * just changed.
  1971.      */
  1972.     if (canvasPtr->textInfo.gotFocus) {
  1973. CanvasFocusProc(canvasPtr, 1);
  1974.     }
  1975.     /*
  1976.      * Recompute the scroll region.
  1977.      */
  1978.     canvasPtr->scrollX1 = 0;
  1979.     canvasPtr->scrollY1 = 0;
  1980.     canvasPtr->scrollX2 = 0;
  1981.     canvasPtr->scrollY2 = 0;
  1982.     if (canvasPtr->regionString != NULL) {
  1983. int argc2;
  1984. CONST char **argv2;
  1985. if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
  1986. &argc2, &argv2) != TCL_OK) {
  1987.     return TCL_ERROR;
  1988. }
  1989. if (argc2 != 4) {
  1990.     Tcl_AppendResult(interp, "bad scrollRegion "",
  1991.     canvasPtr->regionString, """, (char *) NULL);
  1992.     badRegion:
  1993.     ckfree(canvasPtr->regionString);
  1994.     ckfree((char *) argv2);
  1995.     canvasPtr->regionString = NULL;
  1996.     return TCL_ERROR;
  1997. }
  1998. if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
  1999.     argv2[0], &canvasPtr->scrollX1) != TCL_OK)
  2000. || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
  2001.     argv2[1], &canvasPtr->scrollY1) != TCL_OK)
  2002. || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
  2003.     argv2[2], &canvasPtr->scrollX2) != TCL_OK)
  2004. || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
  2005.     argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
  2006.     goto badRegion;
  2007. }
  2008. ckfree((char *) argv2);
  2009.     }
  2010.     flags = canvasPtr->tsoffset.flags;
  2011.     if (flags & TK_OFFSET_LEFT) {
  2012. canvasPtr->tsoffset.xoffset = 0;
  2013.     } else if (flags & TK_OFFSET_CENTER) {
  2014. canvasPtr->tsoffset.xoffset = canvasPtr->width/2;
  2015.     } else if (flags & TK_OFFSET_RIGHT) {
  2016. canvasPtr->tsoffset.xoffset = canvasPtr->width;
  2017.     }
  2018.     if (flags & TK_OFFSET_TOP) {
  2019. canvasPtr->tsoffset.yoffset = 0;
  2020.     } else if (flags & TK_OFFSET_MIDDLE) {
  2021. canvasPtr->tsoffset.yoffset = canvasPtr->height/2;
  2022.     } else if (flags & TK_OFFSET_BOTTOM) {
  2023. canvasPtr->tsoffset.yoffset = canvasPtr->height;
  2024.     }
  2025.     /*
  2026.      * Reset the canvas's origin (this is a no-op unless confine
  2027.      * mode has just been turned on or the scroll region has changed).
  2028.      */
  2029.     CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
  2030.     canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
  2031.     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
  2032.     canvasPtr->xOrigin, canvasPtr->yOrigin,
  2033.     canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
  2034.     canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
  2035.     return TCL_OK;
  2036. }
  2037. /*
  2038.  *---------------------------------------------------------------------------
  2039.  *
  2040.  * CanvasWorldChanged --
  2041.  *
  2042.  *      This procedure is called when the world has changed in some
  2043.  *      way and the widget needs to recompute all its graphics contexts
  2044.  * and determine its new geometry.
  2045.  *
  2046.  * Results:
  2047.  *      None.
  2048.  *
  2049.  * Side effects:
  2050.  * Configures all items in the canvas with a empty argc/argv, for
  2051.  * the side effect of causing all the items to recompute their
  2052.  * geometry and to be redisplayed.
  2053.  *
  2054.  *---------------------------------------------------------------------------
  2055.  */
  2056.  
  2057. static void
  2058. CanvasWorldChanged(instanceData)
  2059.     ClientData instanceData; /* Information about widget. */
  2060. {
  2061.     TkCanvas *canvasPtr;
  2062.     Tk_Item *itemPtr;
  2063.     int result;
  2064.     canvasPtr = (TkCanvas *) instanceData;
  2065.     itemPtr = canvasPtr->firstItemPtr;
  2066.     for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
  2067. result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,
  2068. (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
  2069. TK_CONFIG_ARGV_ONLY);
  2070. if (result != TCL_OK) {
  2071.     Tcl_ResetResult(canvasPtr->interp);
  2072. }
  2073.     }
  2074.     canvasPtr->flags |= REPICK_NEEDED;
  2075.     Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
  2076.     canvasPtr->xOrigin, canvasPtr->yOrigin,
  2077.     canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
  2078.     canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
  2079. }
  2080. /*
  2081.  *--------------------------------------------------------------
  2082.  *
  2083.  * DisplayCanvas --
  2084.  *
  2085.  * This procedure redraws the contents of a canvas window.
  2086.  * It is invoked as a do-when-idle handler, so it only runs
  2087.  * when there's nothing else for the application to do.
  2088.  *
  2089.  * Results:
  2090.  * None.
  2091.  *
  2092.  * Side effects:
  2093.  * Information appears on the screen.
  2094.  *
  2095.  *--------------------------------------------------------------
  2096.  */
  2097. static void
  2098. DisplayCanvas(clientData)
  2099.     ClientData clientData; /* Information about widget. */
  2100. {
  2101.     TkCanvas *canvasPtr = (TkCanvas *) clientData;
  2102.     Tk_Window tkwin = canvasPtr->tkwin;
  2103.     Tk_Item *itemPtr;
  2104.     Pixmap pixmap;
  2105.     int screenX1, screenX2, screenY1, screenY2, width, height;
  2106.     if (canvasPtr->tkwin == NULL) {
  2107. return;
  2108.     }
  2109.     if (!Tk_IsMapped(tkwin)) {
  2110. goto done;
  2111.     }
  2112.     /*
  2113.      * Choose a new current item if that is needed (this could cause
  2114.      * event handlers to be invoked).
  2115.      */
  2116.     while (canvasPtr->flags & REPICK_NEEDED) {
  2117. Tcl_Preserve((ClientData) canvasPtr);
  2118. canvasPtr->flags &= ~REPICK_NEEDED;
  2119. PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
  2120. tkwin = canvasPtr->tkwin;
  2121. Tcl_Release((ClientData) canvasPtr);
  2122. if (tkwin == NULL) {
  2123.     return;
  2124. }
  2125.     }
  2126.     /*
  2127.      * Scan through the item list, registering the bounding box
  2128.      * for all items that didn't do that for the final coordinates
  2129.      * yet. This can be determined by the FORCE_REDRAW flag.
  2130.      */
  2131.     for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  2132. itemPtr = itemPtr->nextPtr) {
  2133. if (itemPtr->redraw_flags & FORCE_REDRAW) {
  2134.     itemPtr->redraw_flags &= ~FORCE_REDRAW;
  2135.     EventuallyRedrawItem((Tk_Canvas)canvasPtr, itemPtr);
  2136.     itemPtr->redraw_flags &= ~FORCE_REDRAW;
  2137. }
  2138.     }
  2139.     /*
  2140.      * Compute the intersection between the area that needs redrawing
  2141.      * and the area that's visible on the screen.
  2142.      */
  2143.     if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
  2144.     && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
  2145. screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
  2146. screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
  2147. screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
  2148. screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
  2149. if (canvasPtr->redrawX1 > screenX1) {
  2150.     screenX1 = canvasPtr->redrawX1;
  2151. }
  2152. if (canvasPtr->redrawY1 > screenY1) {
  2153.     screenY1 = canvasPtr->redrawY1;
  2154. }
  2155. if (canvasPtr->redrawX2 < screenX2) {
  2156.     screenX2 = canvasPtr->redrawX2;
  2157. }
  2158. if (canvasPtr->redrawY2 < screenY2) {
  2159.     screenY2 = canvasPtr->redrawY2;
  2160. }
  2161. if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
  2162.     goto borders;
  2163. }
  2164.     
  2165. width = screenX2 - screenX1;
  2166. height = screenY2 - screenY1;
  2167. #ifndef TK_NO_DOUBLE_BUFFERING
  2168. /*
  2169.  * Redrawing is done in a temporary pixmap that is allocated
  2170.  * here and freed at the end of the procedure.  All drawing
  2171.  * is done to the pixmap, and the pixmap is copied to the
  2172.  * screen at the end of the procedure. The temporary pixmap
  2173.  * serves two purposes:
  2174.  *
  2175.  * 1. It provides a smoother visual effect (no clearing and
  2176.  *    gradual redraw will be visible to users).
  2177.  * 2. It allows us to redraw only the objects that overlap
  2178.  *    the redraw area.  Otherwise incorrect results could
  2179.  *   occur from redrawing things that stick outside of
  2180.  *   the redraw area (we'd have to redraw everything in
  2181.  *    order to make the overlaps look right).
  2182.  *
  2183.  * Some tricky points about the pixmap:
  2184.  *
  2185.  * 1. We only allocate a large enough pixmap to hold the
  2186.  *    area that has to be redisplayed.  This saves time in
  2187.  *    in the X server for large objects that cover much
  2188.  *    more than the area being redisplayed:  only the area
  2189.  *    of the pixmap will actually have to be redrawn.
  2190.  * 2. Some X servers (e.g. the one for DECstations) have troubles
  2191.  *    with characters that overlap an edge of the pixmap (on the
  2192.  *    DEC servers, as of 8/18/92, such characters are drawn one
  2193.  *    pixel too far to the right).  To handle this problem,
  2194.  *    make the pixmap a bit larger than is absolutely needed
  2195.  *    so that for normal-sized fonts the characters that overlap
  2196.  *    the edge of the pixmap will be outside the area we care
  2197.  *    about.
  2198.  */
  2199.     
  2200. canvasPtr->drawableXOrigin = screenX1 - 30;
  2201. canvasPtr->drawableYOrigin = screenY1 - 30;
  2202. pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
  2203.     (screenX2 + 30 - canvasPtr->drawableXOrigin),
  2204.     (screenY2 + 30 - canvasPtr->drawableYOrigin),
  2205.     Tk_Depth(tkwin));
  2206. #else
  2207. canvasPtr->drawableXOrigin = canvasPtr->xOrigin;
  2208. canvasPtr->drawableYOrigin = canvasPtr->yOrigin;
  2209. pixmap = Tk_WindowId(tkwin);
  2210. TkpClipDrawableToRect(Tk_Display(tkwin), pixmap,
  2211. screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin,
  2212. width, height);
  2213. #endif /* TK_NO_DOUBLE_BUFFERING */
  2214.     
  2215. /*
  2216.  * Clear the area to be redrawn.
  2217.  */
  2218.     
  2219. XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
  2220. screenX1 - canvasPtr->drawableXOrigin,
  2221. screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
  2222. (unsigned int) height);
  2223.     
  2224. /*
  2225.  * Scan through the item list, redrawing those items that need it.
  2226.  * An item must be redraw if either (a) it intersects the smaller
  2227.  * on-screen area or (b) it intersects the full canvas area and its
  2228.  * type requests that it be redrawn always (e.g. so subwindows can
  2229.  * be unmapped when they move off-screen).
  2230.  */
  2231.     
  2232. for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  2233. itemPtr = itemPtr->nextPtr) {
  2234.     if ((itemPtr->x1 >= screenX2)
  2235.     || (itemPtr->y1 >= screenY2)
  2236.     || (itemPtr->x2 < screenX1)
  2237.     || (itemPtr->y2 < screenY1)) {
  2238. if (!(itemPtr->typePtr->alwaysRedraw & 1)
  2239. || (itemPtr->x1 >= canvasPtr->redrawX2)
  2240. || (itemPtr->y1 >= canvasPtr->redrawY2)
  2241. || (itemPtr->x2 < canvasPtr->redrawX1)
  2242. || (itemPtr->y2 < canvasPtr->redrawY1)) {
  2243.     continue;
  2244. }
  2245.     }
  2246.     if (itemPtr->state == TK_STATE_HIDDEN ||
  2247. (itemPtr->state == TK_STATE_NULL &&
  2248.  canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
  2249. continue;
  2250.     }
  2251.     (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
  2252.     canvasPtr->display, pixmap, screenX1, screenY1, width,
  2253.     height);
  2254. }
  2255.     
  2256. #ifndef TK_NO_DOUBLE_BUFFERING
  2257. /*
  2258.  * Copy from the temporary pixmap to the screen, then free up
  2259.  * the temporary pixmap.
  2260.  */
  2261.     
  2262. XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
  2263. canvasPtr->pixmapGC,
  2264. screenX1 - canvasPtr->drawableXOrigin,
  2265. screenY1 - canvasPtr->drawableYOrigin,
  2266. (unsigned int) width, (unsigned int) height,
  2267. screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
  2268. Tk_FreePixmap(Tk_Display(tkwin), pixmap);
  2269. #else
  2270. TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, 0, 0, -1, -1);
  2271. #endif /* TK_NO_DOUBLE_BUFFERING */
  2272.     }
  2273.     /*
  2274.      * Draw the window borders, if needed.
  2275.      */
  2276.     borders:
  2277.     if (canvasPtr->flags & REDRAW_BORDERS) {
  2278. canvasPtr->flags &= ~REDRAW_BORDERS;
  2279. if (canvasPtr->borderWidth > 0) {
  2280.     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
  2281.     canvasPtr->bgBorder, canvasPtr->highlightWidth,
  2282.     canvasPtr->highlightWidth,
  2283.     Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
  2284.     Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
  2285.     canvasPtr->borderWidth, canvasPtr->relief);
  2286. }
  2287. if (canvasPtr->highlightWidth != 0) {
  2288.     GC fgGC, bgGC;
  2289.     bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
  2290.     Tk_WindowId(tkwin));
  2291.     if (canvasPtr->textInfo.gotFocus) {
  2292. fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr,
  2293. Tk_WindowId(tkwin));
  2294.      TkpDrawHighlightBorder(tkwin, fgGC, bgGC,
  2295. canvasPtr->highlightWidth, Tk_WindowId(tkwin));
  2296.     } else {
  2297.      TkpDrawHighlightBorder(tkwin, bgGC, bgGC,
  2298. canvasPtr->highlightWidth, Tk_WindowId(tkwin));
  2299.     }
  2300. }
  2301.     }
  2302.     done:
  2303.     canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY);
  2304.     canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
  2305.     canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
  2306.     if (canvasPtr->flags & UPDATE_SCROLLBARS) {
  2307. CanvasUpdateScrollbars(canvasPtr);
  2308.     }
  2309. }
  2310. /*
  2311.  *--------------------------------------------------------------
  2312.  *
  2313.  * CanvasEventProc --
  2314.  *
  2315.  * This procedure is invoked by the Tk dispatcher for various
  2316.  * events on canvases.
  2317.  *
  2318.  * Results:
  2319.  * None.
  2320.  *
  2321.  * Side effects:
  2322.  * When the window gets deleted, internal structures get
  2323.  * cleaned up.  When it gets exposed, it is redisplayed.
  2324.  *
  2325.  *--------------------------------------------------------------
  2326.  */
  2327. static void
  2328. CanvasEventProc(clientData, eventPtr)
  2329.     ClientData clientData; /* Information about window. */
  2330.     XEvent *eventPtr; /* Information about event. */
  2331. {
  2332.     TkCanvas *canvasPtr = (TkCanvas *) clientData;
  2333.     if (eventPtr->type == Expose) {
  2334. int x, y;
  2335. x = eventPtr->xexpose.x + canvasPtr->xOrigin;
  2336. y = eventPtr->xexpose.y + canvasPtr->yOrigin;
  2337. Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
  2338. x + eventPtr->xexpose.width,
  2339. y + eventPtr->xexpose.height);
  2340. if ((eventPtr->xexpose.x < canvasPtr->inset)
  2341. || (eventPtr->xexpose.y < canvasPtr->inset)
  2342. || ((eventPtr->xexpose.x + eventPtr->xexpose.width)
  2343.     > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
  2344. || ((eventPtr->xexpose.y + eventPtr->xexpose.height)
  2345.     > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
  2346.     canvasPtr->flags |= REDRAW_BORDERS;
  2347. }
  2348.     } else if (eventPtr->type == DestroyNotify) {
  2349. if (canvasPtr->tkwin != NULL) {
  2350.     canvasPtr->tkwin = NULL;
  2351.     Tcl_DeleteCommandFromToken(canvasPtr->interp,
  2352.     canvasPtr->widgetCmd);
  2353. }
  2354. if (canvasPtr->flags & REDRAW_PENDING) {
  2355.     Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
  2356. }
  2357. Tcl_EventuallyFree((ClientData) canvasPtr,
  2358. (Tcl_FreeProc *) DestroyCanvas);
  2359.     } else if (eventPtr->type == ConfigureNotify) {
  2360. canvasPtr->flags |= UPDATE_SCROLLBARS;
  2361. /*
  2362.  * The call below is needed in order to recenter the canvas if
  2363.  * it's confined and its scroll region is smaller than the window.
  2364.  */
  2365. CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
  2366. Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
  2367. canvasPtr->yOrigin,
  2368. canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
  2369. canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
  2370. canvasPtr->flags |= REDRAW_BORDERS;
  2371.     } else if (eventPtr->type == FocusIn) {
  2372. if (eventPtr->xfocus.detail != NotifyInferior) {
  2373.     CanvasFocusProc(canvasPtr, 1);
  2374. }
  2375.     } else if (eventPtr->type == FocusOut) {
  2376. if (eventPtr->xfocus.detail != NotifyInferior) {
  2377.     CanvasFocusProc(canvasPtr, 0);
  2378. }
  2379.     } else if (eventPtr->type == UnmapNotify) {
  2380. Tk_Item *itemPtr;
  2381. /*
  2382.  * Special hack:  if the canvas is unmapped, then must notify
  2383.  * all items with "alwaysRedraw" set, so that they know that
  2384.  * they are no longer displayed.
  2385.  */
  2386. for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
  2387. itemPtr = itemPtr->nextPtr) {
  2388.     if (itemPtr->typePtr->alwaysRedraw & 1) {
  2389. (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,
  2390. itemPtr, canvasPtr->display, None, 0, 0, 0, 0);
  2391.     }
  2392. }
  2393.     }
  2394. }
  2395. /*
  2396.  *----------------------------------------------------------------------
  2397.  *
  2398.  * CanvasCmdDeletedProc --
  2399.  *
  2400.  * This procedure is invoked when a widget command is deleted.  If
  2401.  * the widget isn't already in the process of being destroyed,
  2402.  * this command destroys it.
  2403.  *
  2404.  * Results:
  2405.  * None.
  2406.  *
  2407.  * Side effects:
  2408.  * The widget is destroyed.
  2409.  *
  2410.  *----------------------------------------------------------------------
  2411.  */
  2412. static void
  2413. CanvasCmdDeletedProc(clientData)
  2414.     ClientData clientData; /* Pointer to widget record for widget. */
  2415. {
  2416.     TkCanvas *canvasPtr = (TkCanvas *) clientData;
  2417.     Tk_Window tkwin = canvasPtr->tkwin;
  2418.     /*
  2419.      * This procedure could be invoked either because the window was
  2420.      * destroyed and the command was then deleted (in which case tkwin
  2421.      * is NULL) or because the command was deleted, and then this procedure
  2422.      * destroys the widget.
  2423.      */
  2424.     if (tkwin != NULL) {
  2425. canvasPtr->tkwin = NULL;
  2426. Tk_DestroyWindow(tkwin);
  2427.     }
  2428. }
  2429. /*
  2430.  *--------------------------------------------------------------
  2431.  *
  2432.  * Tk_CanvasEventuallyRedraw --
  2433.  *
  2434.  * Arrange for part or all of a canvas widget to redrawn at
  2435.  * some convenient time in the future.
  2436.  *
  2437.  * Results:
  2438.  * None.
  2439.  *
  2440.  * Side effects:
  2441.  * The screen will eventually be refreshed.
  2442.  *
  2443.  *--------------------------------------------------------------
  2444.  */
  2445. void
  2446. Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
  2447.     Tk_Canvas canvas; /* Information about widget. */
  2448.     int x1, y1; /* Upper left corner of area to redraw.
  2449.  * Pixels on edge are redrawn. */
  2450.     int x2, y2; /* Lower right corner of area to redraw.
  2451.  * Pixels on edge are not redrawn. */
  2452. {
  2453.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  2454.     /*
  2455.      * If tkwin is NULL, the canvas has been destroyed, so we can't really
  2456.      * redraw it.
  2457.      */
  2458.     if (canvasPtr->tkwin == NULL) {
  2459. return;
  2460.     }
  2461.     if ((x1 >= x2) || (y1 >= y2) ||
  2462.       (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) ||
  2463.     (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||
  2464.     (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {
  2465. return;
  2466.     }
  2467.     if (canvasPtr->flags & BBOX_NOT_EMPTY) {
  2468. if (x1 <= canvasPtr->redrawX1) {
  2469.     canvasPtr->redrawX1 = x1;
  2470. }
  2471. if (y1 <= canvasPtr->redrawY1) {
  2472.     canvasPtr->redrawY1 = y1;
  2473. }
  2474. if (x2 >= canvasPtr->redrawX2) {
  2475.     canvasPtr->redrawX2 = x2;
  2476. }
  2477. if (y2 >= canvasPtr->redrawY2) {
  2478.     canvasPtr->redrawY2 = y2;
  2479. }
  2480.     } else {
  2481. canvasPtr->redrawX1 = x1;
  2482. canvasPtr->redrawY1 = y1;
  2483. canvasPtr->redrawX2 = x2;
  2484. canvasPtr->redrawY2 = y2;
  2485. canvasPtr->flags |= BBOX_NOT_EMPTY;
  2486.     }
  2487.     if (!(canvasPtr->flags & REDRAW_PENDING)) {
  2488. Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
  2489. canvasPtr->flags |= REDRAW_PENDING;
  2490.     }
  2491. }
  2492. /*
  2493.  *--------------------------------------------------------------
  2494.  *
  2495.  * EventuallyRedrawItem --
  2496.  *
  2497.  * Arrange for part or all of a canvas widget to redrawn at
  2498.  * some convenient time in the future.
  2499.  *
  2500.  * Results:
  2501.  * None.
  2502.  *
  2503.  * Side effects:
  2504.  * The screen will eventually be refreshed.
  2505.  *
  2506.  *--------------------------------------------------------------
  2507.  */
  2508. static void
  2509. EventuallyRedrawItem(canvas, itemPtr)
  2510.     Tk_Canvas canvas; /* Information about widget. */
  2511.     Tk_Item *itemPtr; /* item to be redrawn. */
  2512. {
  2513.     TkCanvas *canvasPtr = (TkCanvas *) canvas;
  2514.     if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||
  2515.       (itemPtr->x2 < canvasPtr->xOrigin) ||
  2516.     (itemPtr->y2 < canvasPtr->yOrigin) ||
  2517.     (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||
  2518.     (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {
  2519. if (!(itemPtr->typePtr->alwaysRedraw & 1)) {
  2520.     return;
  2521. }
  2522.     }
  2523.     if (!(itemPtr->redraw_flags & FORCE_REDRAW)) {
  2524. if (canvasPtr->flags & BBOX_NOT_EMPTY) {
  2525.     if (itemPtr->x1 <= canvasPtr->redrawX1) {
  2526. canvasPtr->redrawX1 = itemPtr->x1;
  2527.     }
  2528.     if (itemPtr->y1 <= canvasPtr->redrawY1) {
  2529. canvasPtr->redrawY1 = itemPtr->y1;
  2530.     }
  2531.     if (itemPtr->x2 >= canvasPtr->redrawX2) {
  2532. canvasPtr->redrawX2 = itemPtr->x2;
  2533.     }
  2534.     if (itemPtr->y2 >= canvasPtr->redrawY2) {
  2535. canvasPtr->redrawY2 = itemPtr->y2;
  2536.     }
  2537. } else {
  2538.     canvasPtr->redrawX1 = itemPtr->x1;
  2539.     canvasPtr->redrawY1 = itemPtr->y1;
  2540.     canvasPtr->redrawX2 = itemPtr->x2;
  2541.     canvasPtr->redrawY2 = itemPtr->y2;
  2542.     canvasPtr->flags |= BBOX_NOT_EMPTY;
  2543. }
  2544. itemPtr->redraw_flags |= FORCE_REDRAW;
  2545.     }
  2546.     if (!(canvasPtr->flags & REDRAW_PENDING)) {
  2547. Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
  2548. canvasPtr->flags |= REDRAW_PENDING;
  2549.     }
  2550. }
  2551. /*
  2552.  *--------------------------------------------------------------
  2553.  *
  2554.  * Tk_CreateItemType --
  2555.  *
  2556.  * This procedure may be invoked to add a new kind of canvas
  2557.  * element to the core item types supported by Tk.
  2558.  *
  2559.  * Results:
  2560.  * None.
  2561.  *
  2562.  * Side effects:
  2563.  * From now on, the new item type will be useable in canvas
  2564.  * widgets (e.g. typePtr->name can be used as the item type
  2565.  * in "create" widget commands).  If there was already a
  2566.  * type with the same name as in typePtr, it is replaced with
  2567.  * the new type.
  2568.  *
  2569.  *--------------------------------------------------------------
  2570.  */
  2571. void
  2572. Tk_CreateItemType(typePtr)
  2573.     Tk_ItemType *typePtr; /* Information about item type;
  2574.  * storage must be statically
  2575.  * allocated (must live forever). */
  2576. {
  2577.     Tk_ItemType *typePtr2, *prevPtr;
  2578.     if (typeList == NULL) {
  2579. InitCanvas();
  2580.     }
  2581.     /*
  2582.      * If there's already an item type with the given name, remove it.
  2583.      */
  2584.     Tcl_MutexLock(&typeListMutex);
  2585.     for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
  2586.     prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
  2587. if (strcmp(typePtr2->name, typePtr->name) == 0) {
  2588.     if (prevPtr == NULL) {
  2589. typeList = typePtr2->nextPtr;
  2590.     } else {
  2591. prevPtr->nextPtr = typePtr2->nextPtr;
  2592.     }
  2593.     break;
  2594. }
  2595.     }
  2596.     typePtr->nextPtr = typeList;
  2597.     typeList = typePtr;
  2598.     Tcl_MutexUnlock(&typeListMutex);
  2599. }
  2600. /*
  2601.  *----------------------------------------------------------------------
  2602.  *
  2603.  * Tk_GetItemTypes --
  2604.  *
  2605.  * This procedure returns a pointer to the list of all item
  2606.  * types. Note that this is inherently thread-unsafe, but since
  2607.  * item types are only ever registered very rarely this is
  2608.  * unlikely to be a problem in practice.
  2609.  *
  2610.  * Results:
  2611.  * The return value is a pointer to the first in the list
  2612.  * of item types currently supported by canvases.
  2613.  *
  2614.  * Side effects:
  2615.  * None.
  2616.  *
  2617.  *----------------------------------------------------------------------
  2618.  */
  2619. Tk_ItemType *
  2620. Tk_GetItemTypes()
  2621. {
  2622.     if (typeList == NULL) {
  2623. InitCanvas();
  2624.     }
  2625.     return typeList;
  2626. }
  2627. /*
  2628.  *--------------------------------------------------------------
  2629.  *
  2630.  * InitCanvas --
  2631.  *
  2632.  * This procedure is invoked to perform once-only-ever
  2633.  * initialization for the module, such as setting up the type
  2634.  * table.
  2635.  *
  2636.  * Results:
  2637.  * None.
  2638.  *
  2639.  * Side effects:
  2640.  * None.
  2641.  *
  2642.  *--------------------------------------------------------------
  2643.  */
  2644. static void
  2645. InitCanvas()
  2646. {
  2647.     Tcl_MutexLock(&typeListMutex);
  2648.     if (typeList != NULL) {
  2649. Tcl_MutexUnlock(&typeListMutex);
  2650. return;
  2651.     }
  2652.     typeList = &tkRectangleType;
  2653.     tkRectangleType.nextPtr = &tkTextType;
  2654.     tkTextType.nextPtr = &tkLineType;
  2655.     tkLineType.nextPtr = &tkPolygonType;
  2656.     tkPolygonType.nextPtr = &tkImageType;
  2657.     tkImageType.nextPtr = &tkOvalType;
  2658.     tkOvalType.nextPtr = &tkBitmapType;
  2659.     tkBitmapType.nextPtr = &tkArcType;
  2660.     tkArcType.nextPtr = &tkWindowType;
  2661.     tkWindowType.nextPtr = NULL;
  2662.     Tcl_MutexUnlock(&typeListMutex);
  2663. }
  2664. #ifdef USE_OLD_TAG_SEARCH
  2665. /*
  2666.  *--------------------------------------------------------------
  2667.  *
  2668.  * StartTagSearch --
  2669.  *
  2670.  * This procedure is called to initiate an enumeration of
  2671.  * all items in a given canvas that contain a given tag.
  2672.  *
  2673.  * Results:
  2674.  * The return value is a pointer to the first item in
  2675.  * canvasPtr that matches tag, or NULL if there is no
  2676.  * such item.  The information at *searchPtr is initialized
  2677.  * such that successive calls to NextItem will return
  2678.  * successive items that match tag.
  2679.  *
  2680.  * Side effects:
  2681.  * SearchPtr is linked into a list of searches in progress
  2682.  * on canvasPtr, so that elements can safely be deleted
  2683.  * while the search is in progress.  EndTagSearch must be
  2684.  * called at the end of the search to unlink searchPtr from
  2685.  * this list.
  2686.  *
  2687.  *--------------------------------------------------------------
  2688.  */
  2689. static Tk_Item *
  2690. StartTagSearch(canvasPtr, tagObj, searchPtr)
  2691.     TkCanvas *canvasPtr; /* Canvas whose items are to be
  2692.  * searched. */
  2693.     Tcl_Obj *tagObj; /* Object giving tag value. */
  2694.     TagSearch *searchPtr; /* Record describing tag search;
  2695.  * will be initialized here. */
  2696. {
  2697.     int id;
  2698.     Tk_Item *itemPtr, *lastPtr;
  2699.     Tk_Uid *tagPtr;
  2700.     Tk_Uid uid;
  2701.     char *tag = Tcl_GetString(tagObj);
  2702.     int count;
  2703.     TkWindow *tkwin;
  2704.     TkDisplay *dispPtr;
  2705.     tkwin = (TkWindow *) canvasPtr->tkwin;
  2706.     dispPtr = tkwin->dispPtr;
  2707.     /*
  2708.      * Initialize the search.
  2709.      */
  2710.     searchPtr->canvasPtr = canvasPtr;
  2711.     searchPtr->searchOver = 0;
  2712.     /*
  2713.      * Find the first matching item in one of several ways. If the tag
  2714.      * is a number then it selects the single item with the matching
  2715.      * identifier.  In this case see if the item being requested is the
  2716.      * hot item, in which case the search can be skipped.
  2717.      */
  2718.     if (isdigit(UCHAR(*tag))) {
  2719. char *end;
  2720. Tcl_HashEntry *entryPtr;
  2721. dispPtr->numIdSearches++;
  2722. id = strtoul(tag, &end, 0);
  2723. if (*end == 0) {
  2724.     itemPtr = canvasPtr->hotPtr;
  2725.             lastPtr = canvasPtr->hotPrevPtr;
  2726.     if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)
  2727.     || (lastPtr->nextPtr != itemPtr)) {
  2728. dispPtr->numSlowSearches++;
  2729. entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
  2730. if (entryPtr != NULL) {
  2731.     itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);
  2732.     lastPtr = itemPtr->prevPtr;
  2733. } else {
  2734.     lastPtr = itemPtr = NULL;
  2735. }