/[dtapublic]/projs/emts/trunk/src/c_tk_base_7_5_w_mods/tkcanvas.c
ViewVC logotype

Diff of /projs/emts/trunk/src/c_tk_base_7_5_w_mods/tkcanvas.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 70 by dashley, Sat Nov 5 10:54:17 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2    
3  /*  /*
4   * tkCanvas.c --   * tkCanvas.c --
5   *   *
6   *      This module implements canvas widgets for the Tk toolkit.   *      This module implements canvas widgets for the Tk toolkit.
7   *      A canvas displays a background and a collection of graphical   *      A canvas displays a background and a collection of graphical
8   *      objects such as rectangles, lines, and texts.   *      objects such as rectangles, lines, and texts.
9   *   *
10   * Copyright (c) 1991-1994 The Regents of the University of California.   * Copyright (c) 1991-1994 The Regents of the University of California.
11   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12   * Copyright (c) 1998-1999 by Scriptics Corporation.   * Copyright (c) 1998-1999 by Scriptics Corporation.
13   *   *
14   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
15   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16   *   *
17   * RCS: @(#) $Id: tkcanvas.c,v 1.1.1.1 2001/06/13 04:56:02 dtashley Exp $   * RCS: @(#) $Id: tkcanvas.c,v 1.1.1.1 2001/06/13 04:56:02 dtashley Exp $
18   */   */
19    
20  /* #define USE_OLD_TAG_SEARCH 1 */  /* #define USE_OLD_TAG_SEARCH 1 */
21    
22  #include "default.h"  #include "default.h"
23  #include "tkInt.h"  #include "tkInt.h"
24  #include "tkPort.h"  #include "tkPort.h"
25  #include "tkCanvas.h"  #include "tkCanvas.h"
26    
27  /*  /*
28   * See tkCanvas.h for key data structures used to implement canvases.   * See tkCanvas.h for key data structures used to implement canvases.
29   */   */
30    
31  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
32  /*  /*
33   * The structure defined below is used to keep track of a tag search   * The structure defined below is used to keep track of a tag search
34   * in progress.  No field should be accessed by anyone other than   * in progress.  No field should be accessed by anyone other than
35   * StartTagSearch and NextItem.   * StartTagSearch and NextItem.
36   */   */
37    
38  typedef struct TagSearch {  typedef struct TagSearch {
39      TkCanvas *canvasPtr;        /* Canvas widget being searched. */      TkCanvas *canvasPtr;        /* Canvas widget being searched. */
40      Tk_Uid tag;                 /* Tag to search for.   0 means return      Tk_Uid tag;                 /* Tag to search for.   0 means return
41                                   * all items. */                                   * all items. */
42      Tk_Item *currentPtr;        /* Pointer to last item returned. */      Tk_Item *currentPtr;        /* Pointer to last item returned. */
43      Tk_Item *lastPtr;           /* The item right before the currentPtr      Tk_Item *lastPtr;           /* The item right before the currentPtr
44                                   * is tracked so if the currentPtr is                                   * is tracked so if the currentPtr is
45                                   * deleted we don't have to start from the                                   * deleted we don't have to start from the
46                                   * beginning. */                                   * beginning. */
47      int searchOver;             /* Non-zero means NextItem should always      int searchOver;             /* Non-zero means NextItem should always
48                                   * return NULL. */                                   * return NULL. */
49  } TagSearch;  } TagSearch;
50    
51  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
52  /*  /*
53   * The structure defined below is used to keep track of a tag search   * The structure defined below is used to keep track of a tag search
54   * in progress.  No field should be accessed by anyone other than   * in progress.  No field should be accessed by anyone other than
55   * TagSearchScan, TagSearchFirst, TagSearchNext,   * TagSearchScan, TagSearchFirst, TagSearchNext,
56   * TagSearchScanExpr, TagSearchEvalExpr,   * TagSearchScanExpr, TagSearchEvalExpr,
57   * TagSearchExprInit, TagSearchExprDestroy,   * TagSearchExprInit, TagSearchExprDestroy,
58   * TagSearchDestroy.   * TagSearchDestroy.
59   * (   * (
60   *   Not quite accurate: the TagSearch structure is also accessed from:   *   Not quite accurate: the TagSearch structure is also accessed from:
61   *    CanvasWidgetCmd, FindItems, RelinkItems   *    CanvasWidgetCmd, FindItems, RelinkItems
62   *   The only instances of the structure are owned by:   *   The only instances of the structure are owned by:
63   *    CanvasWidgetCmd   *    CanvasWidgetCmd
64   *   CanvasWidgetCmd is the only function that calls:   *   CanvasWidgetCmd is the only function that calls:
65   *    FindItems, RelinkItems   *    FindItems, RelinkItems
66   *   CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call   *   CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call
67   *    TagSearch*   *    TagSearch*
68   * )   * )
69   */   */
70    
71  typedef struct TagSearch {  typedef struct TagSearch {
72      TkCanvas *canvasPtr;        /* Canvas widget being searched. */      TkCanvas *canvasPtr;        /* Canvas widget being searched. */
73      Tk_Item *currentPtr;        /* Pointer to last item returned. */      Tk_Item *currentPtr;        /* Pointer to last item returned. */
74      Tk_Item *lastPtr;           /* The item right before the currentPtr      Tk_Item *lastPtr;           /* The item right before the currentPtr
75                                   * is tracked so if the currentPtr is                                   * is tracked so if the currentPtr is
76                                   * deleted we don't have to start from the                                   * deleted we don't have to start from the
77                                   * beginning. */                                   * beginning. */
78      int searchOver;             /* Non-zero means NextItem should always      int searchOver;             /* Non-zero means NextItem should always
79                                   * return NULL. */                                   * return NULL. */
80      int type;                   /* search type */      int type;                   /* search type */
81      int id;                     /* item id for searches by id */      int id;                     /* item id for searches by id */
82    
83      char *string;               /* tag expression string */      char *string;               /* tag expression string */
84      int stringIndex;            /* current position in string scan */      int stringIndex;            /* current position in string scan */
85      int stringLength;           /* length of tag expression string */      int stringLength;           /* length of tag expression string */
86    
87      char *rewritebuffer;        /* tag string (after removing escapes) */      char *rewritebuffer;        /* tag string (after removing escapes) */
88      unsigned int rewritebufferAllocated;        /* available space for rewrites */      unsigned int rewritebufferAllocated;        /* available space for rewrites */
89    
90      TagSearchExpr *expr;        /* compiled tag expression */      TagSearchExpr *expr;        /* compiled tag expression */
91  } TagSearch;  } TagSearch;
92  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
93    
94  /*  /*
95   * Custom option for handling "-state" and "-offset"   * Custom option for handling "-state" and "-offset"
96   */   */
97    
98  static Tk_CustomOption stateOption = {  static Tk_CustomOption stateOption = {
99      (Tk_OptionParseProc *) TkStateParseProc,      (Tk_OptionParseProc *) TkStateParseProc,
100      TkStatePrintProc,      TkStatePrintProc,
101      (ClientData) NULL   /* only "normal" and "disabled" */      (ClientData) NULL   /* only "normal" and "disabled" */
102  };  };
103    
104  static Tk_CustomOption offsetOption = {  static Tk_CustomOption offsetOption = {
105      (Tk_OptionParseProc *) TkOffsetParseProc,      (Tk_OptionParseProc *) TkOffsetParseProc,
106      TkOffsetPrintProc,      TkOffsetPrintProc,
107      (ClientData) TK_OFFSET_RELATIVE      (ClientData) TK_OFFSET_RELATIVE
108  };  };
109    
110  /*  /*
111   * Information used for argv parsing.   * Information used for argv parsing.
112   */   */
113    
114  static Tk_ConfigSpec configSpecs[] = {  static Tk_ConfigSpec configSpecs[] = {
115      {TK_CONFIG_BORDER, "-background", "background", "Background",      {TK_CONFIG_BORDER, "-background", "background", "Background",
116          DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),          DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
117          TK_CONFIG_COLOR_ONLY},          TK_CONFIG_COLOR_ONLY},
118      {TK_CONFIG_BORDER, "-background", "background", "Background",      {TK_CONFIG_BORDER, "-background", "background", "Background",
119          DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),          DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
120          TK_CONFIG_MONO_ONLY},          TK_CONFIG_MONO_ONLY},
121      {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,      {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
122          (char *) NULL, 0, 0},          (char *) NULL, 0, 0},
123      {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,      {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
124          (char *) NULL, 0, 0},          (char *) NULL, 0, 0},
125      {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",      {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
126          DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},          DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0},
127      {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",      {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
128          DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},          DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0},
129      {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",      {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
130          DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},          DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0},
131      {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",      {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
132          DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},          DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK},
133      {TK_CONFIG_PIXELS, "-height", "height", "Height",      {TK_CONFIG_PIXELS, "-height", "height", "Height",
134          DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},          DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0},
135      {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",      {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
136          "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,          "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
137          Tk_Offset(TkCanvas, highlightBgColorPtr), 0},          Tk_Offset(TkCanvas, highlightBgColorPtr), 0},
138      {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",      {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
139          DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},          DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0},
140      {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",      {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
141          "HighlightThickness",          "HighlightThickness",
142          DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},          DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0},
143      {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",      {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
144          DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},          DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0},
145      {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",      {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
146          DEF_CANVAS_INSERT_BD_COLOR,          DEF_CANVAS_INSERT_BD_COLOR,
147          Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},          Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY},
148      {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",      {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
149          DEF_CANVAS_INSERT_BD_MONO,          DEF_CANVAS_INSERT_BD_MONO,
150          Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},          Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY},
151      {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",      {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
152          DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},          DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0},
153      {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",      {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
154          DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0},          DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0},
155      {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",      {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
156          DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0},          DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0},
157      {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0",      {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0",
158          Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT,          Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT,
159          &offsetOption},          &offsetOption},
160      {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",      {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
161          DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},          DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0},
162      {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",      {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
163          DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),          DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
164          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
165      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
166          DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),          DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
167          TK_CONFIG_COLOR_ONLY},          TK_CONFIG_COLOR_ONLY},
168      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",      {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
169          DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),          DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
170          TK_CONFIG_MONO_ONLY},          TK_CONFIG_MONO_ONLY},
171      {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",      {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
172          DEF_CANVAS_SELECT_BD_COLOR,          DEF_CANVAS_SELECT_BD_COLOR,
173          Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},          Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY},
174      {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",      {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
175          DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),          DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
176          TK_CONFIG_MONO_ONLY},          TK_CONFIG_MONO_ONLY},
177      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
178          DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),          DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
179          TK_CONFIG_COLOR_ONLY},          TK_CONFIG_COLOR_ONLY},
180      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",      {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
181          DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),          DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
182          TK_CONFIG_MONO_ONLY},          TK_CONFIG_MONO_ONLY},
183      {TK_CONFIG_CUSTOM, "-state", "state", "State",      {TK_CONFIG_CUSTOM, "-state", "state", "State",
184          "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT,          "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT,
185          &stateOption},          &stateOption},
186      {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",      {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
187          DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),          DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
188          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
189      {TK_CONFIG_PIXELS, "-width", "width", "Width",      {TK_CONFIG_PIXELS, "-width", "width", "Width",
190          DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},          DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0},
191      {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",      {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
192          DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),          DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
193          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
194      {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",      {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
195          "ScrollIncrement",          "ScrollIncrement",
196          DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),          DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
197          0},          0},
198      {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",      {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
199          DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),          DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
200          TK_CONFIG_NULL_OK},          TK_CONFIG_NULL_OK},
201      {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",      {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
202          "ScrollIncrement",          "ScrollIncrement",
203          DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),          DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
204          0},          0},
205      {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,      {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
206          (char *) NULL, 0, 0}          (char *) NULL, 0, 0}
207  };  };
208    
209  /*  /*
210   * List of all the item types known at present:   * List of all the item types known at present:
211   */   */
212    
213  static Tk_ItemType *typeList = NULL;    /* NULL means initialization hasn't  static Tk_ItemType *typeList = NULL;    /* NULL means initialization hasn't
214                                           * been done yet. */                                           * been done yet. */
215    
216  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
217  /*  /*
218   * Uids for operands in compiled advanced tag search expressions   * Uids for operands in compiled advanced tag search expressions
219   * Initialization is done by InitCanvas()   * Initialization is done by InitCanvas()
220   */   */
221  static Tk_Uid allUid = NULL;  static Tk_Uid allUid = NULL;
222  static Tk_Uid currentUid = NULL;  static Tk_Uid currentUid = NULL;
223  static Tk_Uid andUid = NULL;  static Tk_Uid andUid = NULL;
224  static Tk_Uid orUid = NULL;  static Tk_Uid orUid = NULL;
225  static Tk_Uid xorUid = NULL;  static Tk_Uid xorUid = NULL;
226  static Tk_Uid parenUid = NULL;  static Tk_Uid parenUid = NULL;
227  static Tk_Uid negparenUid = NULL;  static Tk_Uid negparenUid = NULL;
228  static Tk_Uid endparenUid = NULL;  static Tk_Uid endparenUid = NULL;
229  static Tk_Uid tagvalUid = NULL;  static Tk_Uid tagvalUid = NULL;
230  static Tk_Uid negtagvalUid = NULL;  static Tk_Uid negtagvalUid = NULL;
231  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
232    
233  /*  /*
234   * Standard item types provided by Tk:   * Standard item types provided by Tk:
235   */   */
236    
237  extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;  extern Tk_ItemType tkArcType, tkBitmapType, tkImageType, tkLineType;
238  extern Tk_ItemType tkOvalType, tkPolygonType;  extern Tk_ItemType tkOvalType, tkPolygonType;
239  extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;  extern Tk_ItemType tkRectangleType, tkTextType, tkWindowType;
240    
241  /*  /*
242   * Prototypes for procedures defined later in this file:   * Prototypes for procedures defined later in this file:
243   */   */
244    
245  static void             CanvasBindProc _ANSI_ARGS_((ClientData clientData,  static void             CanvasBindProc _ANSI_ARGS_((ClientData clientData,
246                              XEvent *eventPtr));                              XEvent *eventPtr));
247  static void             CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));  static void             CanvasBlinkProc _ANSI_ARGS_((ClientData clientData));
248  static void             CanvasCmdDeletedProc _ANSI_ARGS_((  static void             CanvasCmdDeletedProc _ANSI_ARGS_((
249                              ClientData clientData));                              ClientData clientData));
250  static void             CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             CanvasDoEvent _ANSI_ARGS_((TkCanvas *canvasPtr,
251                              XEvent *eventPtr));                              XEvent *eventPtr));
252  static void             CanvasEventProc _ANSI_ARGS_((ClientData clientData,  static void             CanvasEventProc _ANSI_ARGS_((ClientData clientData,
253                              XEvent *eventPtr));                              XEvent *eventPtr));
254  static int              CanvasFetchSelection _ANSI_ARGS_((  static int              CanvasFetchSelection _ANSI_ARGS_((
255                              ClientData clientData, int offset,                              ClientData clientData, int offset,
256                              char *buffer, int maxBytes));                              char *buffer, int maxBytes));
257  static Tk_Item *        CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,  static Tk_Item *        CanvasFindClosest _ANSI_ARGS_((TkCanvas *canvasPtr,
258                              double coords[2]));                              double coords[2]));
259  static void             CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             CanvasFocusProc _ANSI_ARGS_((TkCanvas *canvasPtr,
260                              int gotFocus));                              int gotFocus));
261  static void             CanvasLostSelection _ANSI_ARGS_((  static void             CanvasLostSelection _ANSI_ARGS_((
262                              ClientData clientData));                              ClientData clientData));
263  static void             CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             CanvasSelectTo _ANSI_ARGS_((TkCanvas *canvasPtr,
264                              Tk_Item *itemPtr, int index));                              Tk_Item *itemPtr, int index));
265  static void             CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             CanvasSetOrigin _ANSI_ARGS_((TkCanvas *canvasPtr,
266                              int xOrigin, int yOrigin));                              int xOrigin, int yOrigin));
267  static void             CanvasUpdateScrollbars _ANSI_ARGS_((  static void             CanvasUpdateScrollbars _ANSI_ARGS_((
268                              TkCanvas *canvasPtr));                              TkCanvas *canvasPtr));
269  static int              CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,  static int              CanvasWidgetCmd _ANSI_ARGS_((ClientData clientData,
270                              Tcl_Interp *interp, int argc, Tcl_Obj *CONST *argv));                              Tcl_Interp *interp, int argc, Tcl_Obj *CONST *argv));
271  static void             CanvasWorldChanged _ANSI_ARGS_((  static void             CanvasWorldChanged _ANSI_ARGS_((
272                              ClientData instanceData));                              ClientData instanceData));
273  static int              ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,  static int              ConfigureCanvas _ANSI_ARGS_((Tcl_Interp *interp,
274                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
275                              int flags));                              int flags));
276  static void             DestroyCanvas _ANSI_ARGS_((char *memPtr));  static void             DestroyCanvas _ANSI_ARGS_((char *memPtr));
277  static void             DisplayCanvas _ANSI_ARGS_((ClientData clientData));  static void             DisplayCanvas _ANSI_ARGS_((ClientData clientData));
278  static void             DoItem _ANSI_ARGS_((Tcl_Interp *interp,  static void             DoItem _ANSI_ARGS_((Tcl_Interp *interp,
279                              Tk_Item *itemPtr, Tk_Uid tag));                              Tk_Item *itemPtr, Tk_Uid tag));
280  static void             EventuallyRedrawItem _ANSI_ARGS_((Tk_Canvas canvas,  static void             EventuallyRedrawItem _ANSI_ARGS_((Tk_Canvas canvas,
281                              Tk_Item *itemPtr));                              Tk_Item *itemPtr));
282  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
283  static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,  static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,
284                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
285                              Tcl_Obj *newTagObj, int first));                              Tcl_Obj *newTagObj, int first));
286  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
287  static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,  static int              FindItems _ANSI_ARGS_((Tcl_Interp *interp,
288                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,                              TkCanvas *canvasPtr, int argc, Tcl_Obj *CONST *argv,
289                              Tcl_Obj *newTagObj, int first,                              Tcl_Obj *newTagObj, int first,
290                              TagSearch **searchPtrPtr));                              TagSearch **searchPtrPtr));
291  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
292  static int              FindArea _ANSI_ARGS_((Tcl_Interp *interp,  static int              FindArea _ANSI_ARGS_((Tcl_Interp *interp,
293                              TkCanvas *canvasPtr, Tcl_Obj *CONST *argv, Tk_Uid uid,                              TkCanvas *canvasPtr, Tcl_Obj *CONST *argv, Tk_Uid uid,
294                              int enclosed));                              int enclosed));
295  static double           GridAlign _ANSI_ARGS_((double coord, double spacing));  static double           GridAlign _ANSI_ARGS_((double coord, double spacing));
296  static char**           GetStringsFromObjs _ANSI_ARGS_((int argc,  static char**           GetStringsFromObjs _ANSI_ARGS_((int argc,
297                              Tcl_Obj *CONST *objv));                              Tcl_Obj *CONST *objv));
298  static void             InitCanvas _ANSI_ARGS_((void));  static void             InitCanvas _ANSI_ARGS_((void));
299  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
300  static Tk_Item *        NextItem _ANSI_ARGS_((TagSearch *searchPtr));  static Tk_Item *        NextItem _ANSI_ARGS_((TagSearch *searchPtr));
301  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
302  static void             PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             PickCurrentItem _ANSI_ARGS_((TkCanvas *canvasPtr,
303                              XEvent *eventPtr));                              XEvent *eventPtr));
304  static void             PrintScrollFractions _ANSI_ARGS_((int screen1,  static void             PrintScrollFractions _ANSI_ARGS_((int screen1,
305                              int screen2, int object1, int object2,                              int screen2, int object1, int object2,
306                              char *string));                              char *string));
307  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
308  static void             RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,  static void             RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
309                              Tcl_Obj *tag, Tk_Item *prevPtr));                              Tcl_Obj *tag, Tk_Item *prevPtr));
310  static Tk_Item *        StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,  static Tk_Item *        StartTagSearch _ANSI_ARGS_((TkCanvas *canvasPtr,
311                              Tcl_Obj *tag, TagSearch *searchPtr));                              Tcl_Obj *tag, TagSearch *searchPtr));
312  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
313  static int              RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,  static int              RelinkItems _ANSI_ARGS_((TkCanvas *canvasPtr,
314                              Tcl_Obj *tag, Tk_Item *prevPtr,                              Tcl_Obj *tag, Tk_Item *prevPtr,
315                              TagSearch **searchPtrPtr));                              TagSearch **searchPtrPtr));
316  static void             TagSearchExprInit _ANSI_ARGS_ ((  static void             TagSearchExprInit _ANSI_ARGS_ ((
317                              TagSearchExpr **exprPtrPtr));                              TagSearchExpr **exprPtrPtr));
318  static void             TagSearchExprDestroy _ANSI_ARGS_((TagSearchExpr *expr));  static void             TagSearchExprDestroy _ANSI_ARGS_((TagSearchExpr *expr));
319  static void             TagSearchDestroy _ANSI_ARGS_((TagSearch *searchPtr));  static void             TagSearchDestroy _ANSI_ARGS_((TagSearch *searchPtr));
320  static int              TagSearchScan _ANSI_ARGS_((TkCanvas *canvasPtr,  static int              TagSearchScan _ANSI_ARGS_((TkCanvas *canvasPtr,
321                              Tcl_Obj *tag, TagSearch **searchPtrPtr));                              Tcl_Obj *tag, TagSearch **searchPtrPtr));
322  static int              TagSearchScanExpr _ANSI_ARGS_((Tcl_Interp *interp,  static int              TagSearchScanExpr _ANSI_ARGS_((Tcl_Interp *interp,
323                              TagSearch *searchPtr, TagSearchExpr *expr));                              TagSearch *searchPtr, TagSearchExpr *expr));
324  static int              TagSearchEvalExpr _ANSI_ARGS_((TagSearchExpr *expr,  static int              TagSearchEvalExpr _ANSI_ARGS_((TagSearchExpr *expr,
325                              Tk_Item *itemPtr));                              Tk_Item *itemPtr));
326  static Tk_Item *        TagSearchFirst _ANSI_ARGS_((TagSearch *searchPtr));  static Tk_Item *        TagSearchFirst _ANSI_ARGS_((TagSearch *searchPtr));
327  static Tk_Item *        TagSearchNext _ANSI_ARGS_((TagSearch *searchPtr));  static Tk_Item *        TagSearchNext _ANSI_ARGS_((TagSearch *searchPtr));
328  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
329    
330  /*  /*
331   * The structure below defines canvas class behavior by means of procedures   * The structure below defines canvas class behavior by means of procedures
332   * that can be invoked from generic window code.   * that can be invoked from generic window code.
333   */   */
334    
335  static TkClassProcs canvasClass = {  static TkClassProcs canvasClass = {
336      NULL,                       /* createProc. */      NULL,                       /* createProc. */
337      CanvasWorldChanged,         /* geometryProc. */      CanvasWorldChanged,         /* geometryProc. */
338      NULL                        /* modalProc. */      NULL                        /* modalProc. */
339  };  };
340    
341    
342  /*  /*
343   *--------------------------------------------------------------   *--------------------------------------------------------------
344   *   *
345   * Tk_CanvasObjCmd --   * Tk_CanvasObjCmd --
346   *   *
347   *      This procedure is invoked to process the "canvas" Tcl   *      This procedure is invoked to process the "canvas" Tcl
348   *      command.  See the user documentation for details on what   *      command.  See the user documentation for details on what
349   *      it does.   *      it does.
350   *   *
351   * Results:   * Results:
352   *      A standard Tcl result.   *      A standard Tcl result.
353   *   *
354   * Side effects:   * Side effects:
355   *      See the user documentation.   *      See the user documentation.
356   *   *
357   *--------------------------------------------------------------   *--------------------------------------------------------------
358   */   */
359    
360  int  int
361  Tk_CanvasObjCmd(clientData, interp, argc, argv)  Tk_CanvasObjCmd(clientData, interp, argc, argv)
362      ClientData clientData;              /* Main window associated with      ClientData clientData;              /* Main window associated with
363                                   * interpreter. */                                   * interpreter. */
364      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
365      int argc;                   /* Number of arguments. */      int argc;                   /* Number of arguments. */
366      Tcl_Obj *CONST argv[];      /* Argument objects. */      Tcl_Obj *CONST argv[];      /* Argument objects. */
367  {  {
368      Tk_Window tkwin = (Tk_Window) clientData;      Tk_Window tkwin = (Tk_Window) clientData;
369      TkCanvas *canvasPtr;      TkCanvas *canvasPtr;
370      Tk_Window new;      Tk_Window new;
371    
372      if (typeList == NULL) {      if (typeList == NULL) {
373          InitCanvas();          InitCanvas();
374      }      }
375    
376      if (argc < 2) {      if (argc < 2) {
377          Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?");          Tcl_WrongNumArgs(interp, 1, argv, "pathName ?options?");
378          return TCL_ERROR;          return TCL_ERROR;
379      }      }
380    
381      new = Tk_CreateWindowFromPath(interp, tkwin,      new = Tk_CreateWindowFromPath(interp, tkwin,
382              Tcl_GetString(argv[1]), (char *) NULL);              Tcl_GetString(argv[1]), (char *) NULL);
383      if (new == NULL) {      if (new == NULL) {
384          return TCL_ERROR;          return TCL_ERROR;
385      }      }
386    
387      /*      /*
388       * Initialize fields that won't be initialized by ConfigureCanvas,       * Initialize fields that won't be initialized by ConfigureCanvas,
389       * or which ConfigureCanvas expects to have reasonable values       * or which ConfigureCanvas expects to have reasonable values
390       * (e.g. resource pointers).       * (e.g. resource pointers).
391       */       */
392    
393      canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));      canvasPtr = (TkCanvas *) ckalloc(sizeof(TkCanvas));
394      canvasPtr->tkwin = new;      canvasPtr->tkwin = new;
395      canvasPtr->display = Tk_Display(new);      canvasPtr->display = Tk_Display(new);
396      canvasPtr->interp = interp;      canvasPtr->interp = interp;
397      canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp,      canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp,
398              Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,              Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd,
399              (ClientData) canvasPtr, CanvasCmdDeletedProc);              (ClientData) canvasPtr, CanvasCmdDeletedProc);
400      canvasPtr->firstItemPtr = NULL;      canvasPtr->firstItemPtr = NULL;
401      canvasPtr->lastItemPtr = NULL;      canvasPtr->lastItemPtr = NULL;
402      canvasPtr->borderWidth = 0;      canvasPtr->borderWidth = 0;
403      canvasPtr->bgBorder = NULL;      canvasPtr->bgBorder = NULL;
404      canvasPtr->relief = TK_RELIEF_FLAT;      canvasPtr->relief = TK_RELIEF_FLAT;
405      canvasPtr->highlightWidth = 0;      canvasPtr->highlightWidth = 0;
406      canvasPtr->highlightBgColorPtr = NULL;      canvasPtr->highlightBgColorPtr = NULL;
407      canvasPtr->highlightColorPtr = NULL;      canvasPtr->highlightColorPtr = NULL;
408      canvasPtr->inset = 0;      canvasPtr->inset = 0;
409      canvasPtr->pixmapGC = None;      canvasPtr->pixmapGC = None;
410      canvasPtr->width = None;      canvasPtr->width = None;
411      canvasPtr->height = None;      canvasPtr->height = None;
412      canvasPtr->confine = 0;      canvasPtr->confine = 0;
413      canvasPtr->textInfo.selBorder = NULL;      canvasPtr->textInfo.selBorder = NULL;
414      canvasPtr->textInfo.selBorderWidth = 0;      canvasPtr->textInfo.selBorderWidth = 0;
415      canvasPtr->textInfo.selFgColorPtr = NULL;      canvasPtr->textInfo.selFgColorPtr = NULL;
416      canvasPtr->textInfo.selItemPtr = NULL;      canvasPtr->textInfo.selItemPtr = NULL;
417      canvasPtr->textInfo.selectFirst = -1;      canvasPtr->textInfo.selectFirst = -1;
418      canvasPtr->textInfo.selectLast = -1;      canvasPtr->textInfo.selectLast = -1;
419      canvasPtr->textInfo.anchorItemPtr = NULL;      canvasPtr->textInfo.anchorItemPtr = NULL;
420      canvasPtr->textInfo.selectAnchor = 0;      canvasPtr->textInfo.selectAnchor = 0;
421      canvasPtr->textInfo.insertBorder = NULL;      canvasPtr->textInfo.insertBorder = NULL;
422      canvasPtr->textInfo.insertWidth = 0;      canvasPtr->textInfo.insertWidth = 0;
423      canvasPtr->textInfo.insertBorderWidth = 0;      canvasPtr->textInfo.insertBorderWidth = 0;
424      canvasPtr->textInfo.focusItemPtr = NULL;      canvasPtr->textInfo.focusItemPtr = NULL;
425      canvasPtr->textInfo.gotFocus = 0;      canvasPtr->textInfo.gotFocus = 0;
426      canvasPtr->textInfo.cursorOn = 0;      canvasPtr->textInfo.cursorOn = 0;
427      canvasPtr->insertOnTime = 0;      canvasPtr->insertOnTime = 0;
428      canvasPtr->insertOffTime = 0;      canvasPtr->insertOffTime = 0;
429      canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;      canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
430      canvasPtr->xOrigin = canvasPtr->yOrigin = 0;      canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
431      canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;      canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
432      canvasPtr->bindingTable = NULL;      canvasPtr->bindingTable = NULL;
433      canvasPtr->currentItemPtr = NULL;      canvasPtr->currentItemPtr = NULL;
434      canvasPtr->newCurrentPtr = NULL;      canvasPtr->newCurrentPtr = NULL;
435      canvasPtr->closeEnough = 0.0;      canvasPtr->closeEnough = 0.0;
436      canvasPtr->pickEvent.type = LeaveNotify;      canvasPtr->pickEvent.type = LeaveNotify;
437      canvasPtr->pickEvent.xcrossing.x = 0;      canvasPtr->pickEvent.xcrossing.x = 0;
438      canvasPtr->pickEvent.xcrossing.y = 0;      canvasPtr->pickEvent.xcrossing.y = 0;
439      canvasPtr->state = 0;      canvasPtr->state = 0;
440      canvasPtr->xScrollCmd = NULL;      canvasPtr->xScrollCmd = NULL;
441      canvasPtr->yScrollCmd = NULL;      canvasPtr->yScrollCmd = NULL;
442      canvasPtr->scrollX1 = 0;      canvasPtr->scrollX1 = 0;
443      canvasPtr->scrollY1 = 0;      canvasPtr->scrollY1 = 0;
444      canvasPtr->scrollX2 = 0;      canvasPtr->scrollX2 = 0;
445      canvasPtr->scrollY2 = 0;      canvasPtr->scrollY2 = 0;
446      canvasPtr->regionString = NULL;      canvasPtr->regionString = NULL;
447      canvasPtr->xScrollIncrement = 0;      canvasPtr->xScrollIncrement = 0;
448      canvasPtr->yScrollIncrement = 0;      canvasPtr->yScrollIncrement = 0;
449      canvasPtr->scanX = 0;      canvasPtr->scanX = 0;
450      canvasPtr->scanXOrigin = 0;      canvasPtr->scanXOrigin = 0;
451      canvasPtr->scanY = 0;      canvasPtr->scanY = 0;
452      canvasPtr->scanYOrigin = 0;      canvasPtr->scanYOrigin = 0;
453      canvasPtr->hotPtr = NULL;      canvasPtr->hotPtr = NULL;
454      canvasPtr->hotPrevPtr = NULL;      canvasPtr->hotPrevPtr = NULL;
455      canvasPtr->cursor = None;      canvasPtr->cursor = None;
456      canvasPtr->takeFocus = NULL;      canvasPtr->takeFocus = NULL;
457      canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));      canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(new));
458      canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));      canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(new));
459      canvasPtr->flags = 0;      canvasPtr->flags = 0;
460      canvasPtr->nextId = 1;      canvasPtr->nextId = 1;
461      canvasPtr->psInfo = NULL;      canvasPtr->psInfo = NULL;
462      canvasPtr->canvas_state = TK_STATE_NORMAL;      canvasPtr->canvas_state = TK_STATE_NORMAL;
463      canvasPtr->tsoffset.flags = 0;      canvasPtr->tsoffset.flags = 0;
464      canvasPtr->tsoffset.xoffset = 0;      canvasPtr->tsoffset.xoffset = 0;
465      canvasPtr->tsoffset.yoffset = 0;      canvasPtr->tsoffset.yoffset = 0;
466  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
467      canvasPtr->bindTagExprs = NULL;      canvasPtr->bindTagExprs = NULL;
468  #endif  #endif
469      Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);      Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);
470    
471      Tk_SetClass(canvasPtr->tkwin, "Canvas");      Tk_SetClass(canvasPtr->tkwin, "Canvas");
472      TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr);      TkSetClassProcs(canvasPtr->tkwin, &canvasClass, (ClientData) canvasPtr);
473      Tk_CreateEventHandler(canvasPtr->tkwin,      Tk_CreateEventHandler(canvasPtr->tkwin,
474              ExposureMask|StructureNotifyMask|FocusChangeMask,              ExposureMask|StructureNotifyMask|FocusChangeMask,
475              CanvasEventProc, (ClientData) canvasPtr);              CanvasEventProc, (ClientData) canvasPtr);
476      Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask      Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
477              |ButtonPressMask|ButtonReleaseMask|EnterWindowMask              |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
478              |LeaveWindowMask|PointerMotionMask|VirtualEventMask,              |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
479              CanvasBindProc, (ClientData) canvasPtr);              CanvasBindProc, (ClientData) canvasPtr);
480      Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,      Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
481              CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);              CanvasFetchSelection, (ClientData) canvasPtr, XA_STRING);
482      if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {      if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
483          goto error;          goto error;
484      }      }
485    
486      Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC);      Tcl_SetResult(interp, Tk_PathName(canvasPtr->tkwin), TCL_STATIC);
487      return TCL_OK;      return TCL_OK;
488    
489      error:      error:
490      Tk_DestroyWindow(canvasPtr->tkwin);      Tk_DestroyWindow(canvasPtr->tkwin);
491      return TCL_ERROR;      return TCL_ERROR;
492  }  }
493    
494  /*  /*
495   *--------------------------------------------------------------   *--------------------------------------------------------------
496   *   *
497   * CanvasWidgetCmd --   * CanvasWidgetCmd --
498   *   *
499   *      This procedure is invoked to process the Tcl command   *      This procedure is invoked to process the Tcl command
500   *      that corresponds to a widget managed by this module.   *      that corresponds to a widget managed by this module.
501   *      See the user documentation for details on what it does.   *      See the user documentation for details on what it does.
502   *   *
503   * Results:   * Results:
504   *      A standard Tcl result.   *      A standard Tcl result.
505   *   *
506   * Side effects:   * Side effects:
507   *      See the user documentation.   *      See the user documentation.
508   *   *
509   *--------------------------------------------------------------   *--------------------------------------------------------------
510   */   */
511    
512  static int  static int
513  CanvasWidgetCmd(clientData, interp, argc, argv)  CanvasWidgetCmd(clientData, interp, argc, argv)
514      ClientData clientData;              /* Information about canvas      ClientData clientData;              /* Information about canvas
515                                           * widget. */                                           * widget. */
516      Tcl_Interp *interp;                 /* Current interpreter. */      Tcl_Interp *interp;                 /* Current interpreter. */
517      int argc;                           /* Number of arguments. */      int argc;                           /* Number of arguments. */
518      Tcl_Obj *CONST argv[];              /* Argument objects. */      Tcl_Obj *CONST argv[];              /* Argument objects. */
519  {  {
520      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
521      unsigned int length;      unsigned int length;
522      int c, result;      int c, result;
523      Tk_Item *itemPtr = NULL;            /* Initialization needed only to      Tk_Item *itemPtr = NULL;            /* Initialization needed only to
524                                           * prevent compiler warning. */                                           * prevent compiler warning. */
525  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
526      TagSearch search;      TagSearch search;
527  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
528      TagSearch *searchPtr = NULL;        /* Allocated by first TagSearchScan      TagSearch *searchPtr = NULL;        /* Allocated by first TagSearchScan
529                                           * Freed by TagSearchDestroy */                                           * Freed by TagSearchDestroy */
530  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
531    
532      int index;      int index;
533      static char *optionStrings[] = {      static char *optionStrings[] = {
534          "addtag",       "bbox",         "bind",         "canvasx",          "addtag",       "bbox",         "bind",         "canvasx",
535          "canvasy",      "cget",         "configure",    "coords",          "canvasy",      "cget",         "configure",    "coords",
536          "create",       "dchars",       "delete",       "dtag",          "create",       "dchars",       "delete",       "dtag",
537          "find",         "focus",        "gettags",      "icursor",          "find",         "focus",        "gettags",      "icursor",
538          "index",        "insert",       "itemcget",     "itemconfigure",          "index",        "insert",       "itemcget",     "itemconfigure",
539          "lower",        "move",         "postscript",   "raise",          "lower",        "move",         "postscript",   "raise",
540          "scale",        "scan",         "select",       "type",          "scale",        "scan",         "select",       "type",
541          "xview",        "yview",          "xview",        "yview",
542          NULL          NULL
543      };      };
544      enum options {      enum options {
545          CANV_ADDTAG,    CANV_BBOX,      CANV_BIND,      CANV_CANVASX,          CANV_ADDTAG,    CANV_BBOX,      CANV_BIND,      CANV_CANVASX,
546          CANV_CANVASY,   CANV_CGET,      CANV_CONFIGURE, CANV_COORDS,          CANV_CANVASY,   CANV_CGET,      CANV_CONFIGURE, CANV_COORDS,
547          CANV_CREATE,    CANV_DCHARS,    CANV_DELETE,    CANV_DTAG,          CANV_CREATE,    CANV_DCHARS,    CANV_DELETE,    CANV_DTAG,
548          CANV_FIND,      CANV_FOCUS,     CANV_GETTAGS,   CANV_ICURSOR,          CANV_FIND,      CANV_FOCUS,     CANV_GETTAGS,   CANV_ICURSOR,
549          CANV_INDEX,     CANV_INSERT,    CANV_ITEMCGET,  CANV_ITEMCONFIGURE,          CANV_INDEX,     CANV_INSERT,    CANV_ITEMCGET,  CANV_ITEMCONFIGURE,
550          CANV_LOWER,     CANV_MOVE,      CANV_POSTSCRIPT,CANV_RAISE,          CANV_LOWER,     CANV_MOVE,      CANV_POSTSCRIPT,CANV_RAISE,
551          CANV_SCALE,     CANV_SCAN,      CANV_SELECT,    CANV_TYPE,          CANV_SCALE,     CANV_SCAN,      CANV_SELECT,    CANV_TYPE,
552          CANV_XVIEW,     CANV_YVIEW          CANV_XVIEW,     CANV_YVIEW
553      };      };
554    
555      if (argc < 2) {      if (argc < 2) {
556          Tcl_WrongNumArgs(interp, 1, argv, "option ?arg arg ...?");          Tcl_WrongNumArgs(interp, 1, argv, "option ?arg arg ...?");
557          return TCL_ERROR;          return TCL_ERROR;
558      }      }
559      if (Tcl_GetIndexFromObj(interp, argv[1], optionStrings, "option", 0,      if (Tcl_GetIndexFromObj(interp, argv[1], optionStrings, "option", 0,
560              &index) != TCL_OK) {              &index) != TCL_OK) {
561          return TCL_ERROR;          return TCL_ERROR;
562      }      }
563      Tcl_Preserve((ClientData) canvasPtr);      Tcl_Preserve((ClientData) canvasPtr);
564    
565      result = TCL_OK;      result = TCL_OK;
566      switch ((enum options) index) {      switch ((enum options) index) {
567        case CANV_ADDTAG: {        case CANV_ADDTAG: {
568          if (argc < 4) {          if (argc < 4) {
569              Tcl_WrongNumArgs(interp, 2, argv, "tag searchCommand ?arg arg ...?");              Tcl_WrongNumArgs(interp, 2, argv, "tag searchCommand ?arg arg ...?");
570              result = TCL_ERROR;              result = TCL_ERROR;
571              goto done;              goto done;
572          }          }
573  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
574          result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3);          result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3);
575  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
576          result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3, &searchPtr);          result = FindItems(interp, canvasPtr, argc, argv, argv[2], 3, &searchPtr);
577  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
578          break;          break;
579        }        }
580    
581        case CANV_BBOX: {        case CANV_BBOX: {
582          int i, gotAny;          int i, gotAny;
583          int x1 = 0, y1 = 0, x2 = 0, y2 = 0;     /* Initializations needed          int x1 = 0, y1 = 0, x2 = 0, y2 = 0;     /* Initializations needed
584                                                   * only to prevent compiler                                                   * only to prevent compiler
585                                                   * warnings. */                                                   * warnings. */
586    
587          if (argc < 3) {          if (argc < 3) {
588              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagOrId ...?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagOrId ...?");
589              result = TCL_ERROR;              result = TCL_ERROR;
590              goto done;              goto done;
591          }          }
592          gotAny = 0;          gotAny = 0;
593          for (i = 2; i < argc; i++) {          for (i = 2; i < argc; i++) {
594  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
595              for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);              for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
596                      itemPtr != NULL; itemPtr = NextItem(&search)) {                      itemPtr != NULL; itemPtr = NextItem(&search)) {
597  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
598              if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) {              if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) {
599                  goto done;                  goto done;
600              }              }
601              for (itemPtr = TagSearchFirst(searchPtr);              for (itemPtr = TagSearchFirst(searchPtr);
602                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
603  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
604    
605                  if ((itemPtr->x1 >= itemPtr->x2)                  if ((itemPtr->x1 >= itemPtr->x2)
606                          || (itemPtr->y1 >= itemPtr->y2)) {                          || (itemPtr->y1 >= itemPtr->y2)) {
607                      continue;                      continue;
608                  }                  }
609                  if (!gotAny) {                  if (!gotAny) {
610                      x1 = itemPtr->x1;                      x1 = itemPtr->x1;
611                      y1 = itemPtr->y1;                      y1 = itemPtr->y1;
612                      x2 = itemPtr->x2;                      x2 = itemPtr->x2;
613                      y2 = itemPtr->y2;                      y2 = itemPtr->y2;
614                      gotAny = 1;                      gotAny = 1;
615                  } else {                  } else {
616                      if (itemPtr->x1 < x1) {                      if (itemPtr->x1 < x1) {
617                          x1 = itemPtr->x1;                          x1 = itemPtr->x1;
618                      }                      }
619                      if (itemPtr->y1 < y1) {                      if (itemPtr->y1 < y1) {
620                          y1 = itemPtr->y1;                          y1 = itemPtr->y1;
621                      }                      }
622                      if (itemPtr->x2 > x2) {                      if (itemPtr->x2 > x2) {
623                          x2 = itemPtr->x2;                          x2 = itemPtr->x2;
624                      }                      }
625                      if (itemPtr->y2 > y2) {                      if (itemPtr->y2 > y2) {
626                          y2 = itemPtr->y2;                          y2 = itemPtr->y2;
627                      }                      }
628                  }                  }
629              }              }
630          }          }
631          if (gotAny) {          if (gotAny) {
632              char buf[TCL_INTEGER_SPACE * 4];              char buf[TCL_INTEGER_SPACE * 4];
633                            
634              sprintf(buf, "%d %d %d %d", x1, y1, x2, y2);              sprintf(buf, "%d %d %d %d", x1, y1, x2, y2);
635              Tcl_SetResult(interp, buf, TCL_VOLATILE);              Tcl_SetResult(interp, buf, TCL_VOLATILE);
636          }          }
637          break;          break;
638        }        }
639        case CANV_BIND: {        case CANV_BIND: {
640          ClientData object;          ClientData object;
641    
642          if ((argc < 3) || (argc > 5)) {          if ((argc < 3) || (argc > 5)) {
643              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?sequence? ?command?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?sequence? ?command?");
644              result = TCL_ERROR;              result = TCL_ERROR;
645              goto done;              goto done;
646          }          }
647    
648          /*          /*
649           * Figure out what object to use for the binding (individual           * Figure out what object to use for the binding (individual
650           * item vs. tag).           * item vs. tag).
651           */           */
652    
653          object = 0;          object = 0;
654  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
655          if (isdigit(UCHAR(Tcl_GetString(argv[2])[0]))) {          if (isdigit(UCHAR(Tcl_GetString(argv[2])[0]))) {
656              int id;              int id;
657              char *end;              char *end;
658              Tcl_HashEntry *entryPtr;              Tcl_HashEntry *entryPtr;
659    
660              id = strtoul(Tcl_GetString(argv[2]), &end, 0);              id = strtoul(Tcl_GetString(argv[2]), &end, 0);
661              if (*end != 0) {              if (*end != 0) {
662                  goto bindByTag;                  goto bindByTag;
663              }              }
664              entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);              entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
665              if (entryPtr != NULL) {              if (entryPtr != NULL) {
666                  itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);                  itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
667                  object = (ClientData) itemPtr;                  object = (ClientData) itemPtr;
668              }              }
669    
670              if (object == 0) {              if (object == 0) {
671                  Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]),                  Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]),
672                          "\" doesn't exist", (char *) NULL);                          "\" doesn't exist", (char *) NULL);
673                  result = TCL_ERROR;                  result = TCL_ERROR;
674                  goto done;                  goto done;
675              }              }
676          } else {          } else {
677              bindByTag:              bindByTag:
678              object = (ClientData) Tk_GetUid(Tcl_GetString(argv[2]));              object = (ClientData) Tk_GetUid(Tcl_GetString(argv[2]));
679          }          }
680  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
681          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
682              goto done;              goto done;
683          }          }
684          if (searchPtr->type == 1) {          if (searchPtr->type == 1) {
685              Tcl_HashEntry *entryPtr;              Tcl_HashEntry *entryPtr;
686    
687              entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) searchPtr->id);              entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) searchPtr->id);
688              if (entryPtr != NULL) {              if (entryPtr != NULL) {
689                  itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);                  itemPtr = (Tk_Item *) Tcl_GetHashValue(entryPtr);
690                  object = (ClientData) itemPtr;                  object = (ClientData) itemPtr;
691              }              }
692    
693              if (object == 0) {              if (object == 0) {
694                  Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]),                  Tcl_AppendResult(interp, "item \"", Tcl_GetString(argv[2]),
695                          "\" doesn't exist", (char *) NULL);                          "\" doesn't exist", (char *) NULL);
696                  result = TCL_ERROR;                  result = TCL_ERROR;
697                  goto done;                  goto done;
698              }              }
699          } else {          } else {
700              object = (ClientData) searchPtr->expr->uid;              object = (ClientData) searchPtr->expr->uid;
701          }          }
702  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
703    
704          /*          /*
705           * Make a binding table if the canvas doesn't already have           * Make a binding table if the canvas doesn't already have
706           * one.           * one.
707           */           */
708    
709          if (canvasPtr->bindingTable == NULL) {          if (canvasPtr->bindingTable == NULL) {
710              canvasPtr->bindingTable = Tk_CreateBindingTable(interp);              canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
711          }          }
712    
713          if (argc == 5) {          if (argc == 5) {
714              int append = 0;              int append = 0;
715              unsigned long mask;              unsigned long mask;
716              char* argv4 = Tcl_GetStringFromObj(argv[4],NULL);              char* argv4 = Tcl_GetStringFromObj(argv[4],NULL);
717    
718              if (argv4[0] == 0) {              if (argv4[0] == 0) {
719                  result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,                  result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
720                          object, Tcl_GetStringFromObj(argv[3], NULL));                          object, Tcl_GetStringFromObj(argv[3], NULL));
721                  goto done;                  goto done;
722              }              }
723  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
724              if (searchPtr->type == 4) {              if (searchPtr->type == 4) {
725                  /*                  /*
726                   * if new tag expression, then insert in linked list                   * if new tag expression, then insert in linked list
727                   */                   */
728                  TagSearchExpr *expr, **lastPtr;                  TagSearchExpr *expr, **lastPtr;
729    
730                  lastPtr = &(canvasPtr->bindTagExprs);                  lastPtr = &(canvasPtr->bindTagExprs);
731                  while ((expr = *lastPtr) != NULL) {                  while ((expr = *lastPtr) != NULL) {
732                      if (expr->uid == searchPtr->expr->uid) {                      if (expr->uid == searchPtr->expr->uid) {
733                          break;                          break;
734                      }                      }
735                      lastPtr = &(expr->next);                      lastPtr = &(expr->next);
736                  }                  }
737                  if (!expr) {                  if (!expr) {
738                      /*                      /*
739                       * transfer ownership of expr to bindTagExprs list                       * transfer ownership of expr to bindTagExprs list
740                       */                       */
741                      *lastPtr = searchPtr->expr;                      *lastPtr = searchPtr->expr;
742                      searchPtr->expr->next = NULL;                      searchPtr->expr->next = NULL;
743    
744                      /*                      /*
745                       * flag in TagSearch that expr has changed ownership                       * flag in TagSearch that expr has changed ownership
746                       * so that TagSearchDestroy doesn't try to free it                       * so that TagSearchDestroy doesn't try to free it
747                       */                       */
748                      searchPtr->expr = NULL;                      searchPtr->expr = NULL;
749                  }                  }
750              }              }
751  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
752              if (argv4[0] == '+') {              if (argv4[0] == '+') {
753                  argv4++;                  argv4++;
754                  append = 1;                  append = 1;
755              }              }
756              mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,              mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
757                      object, Tcl_GetStringFromObj(argv[3],NULL), argv4, append);                      object, Tcl_GetStringFromObj(argv[3],NULL), argv4, append);
758              if (mask == 0) {              if (mask == 0) {
759                  result = TCL_ERROR;                  result = TCL_ERROR;
760                  goto done;                  goto done;
761              }              }
762              if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask              if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
763                      |Button2MotionMask|Button3MotionMask|Button4MotionMask                      |Button2MotionMask|Button3MotionMask|Button4MotionMask
764                      |Button5MotionMask|ButtonPressMask|ButtonReleaseMask                      |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
765                      |EnterWindowMask|LeaveWindowMask|KeyPressMask                      |EnterWindowMask|LeaveWindowMask|KeyPressMask
766                      |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {                      |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
767                  Tk_DeleteBinding(interp, canvasPtr->bindingTable,                  Tk_DeleteBinding(interp, canvasPtr->bindingTable,
768                          object, Tcl_GetStringFromObj(argv[3], NULL));                          object, Tcl_GetStringFromObj(argv[3], NULL));
769                  Tcl_ResetResult(interp);                  Tcl_ResetResult(interp);
770                  Tcl_AppendResult(interp, "requested illegal events; ",                  Tcl_AppendResult(interp, "requested illegal events; ",
771                          "only key, button, motion, enter, leave, and virtual ",                          "only key, button, motion, enter, leave, and virtual ",
772                          "events may be used", (char *) NULL);                          "events may be used", (char *) NULL);
773                  result = TCL_ERROR;                  result = TCL_ERROR;
774                  goto done;                  goto done;
775              }              }
776          } else if (argc == 4) {          } else if (argc == 4) {
777              char *command;              char *command;
778            
779              command = Tk_GetBinding(interp, canvasPtr->bindingTable,              command = Tk_GetBinding(interp, canvasPtr->bindingTable,
780                      object, Tcl_GetStringFromObj(argv[3], NULL));                      object, Tcl_GetStringFromObj(argv[3], NULL));
781              if (command == NULL) {              if (command == NULL) {
782                  char *string;                  char *string;
783    
784                  string = Tcl_GetStringResult(interp);                  string = Tcl_GetStringResult(interp);
785                  /*                  /*
786                   * Ignore missing binding errors.  This is a special hack                   * Ignore missing binding errors.  This is a special hack
787                   * that relies on the error message returned by FindSequence                   * that relies on the error message returned by FindSequence
788                   * in tkBind.c.                   * in tkBind.c.
789                   */                   */
790    
791                  if (string[0] != '\0') {                  if (string[0] != '\0') {
792                      result = TCL_ERROR;                      result = TCL_ERROR;
793                      goto done;                      goto done;
794                  } else {                  } else {
795                      Tcl_ResetResult(interp);                      Tcl_ResetResult(interp);
796                  }                  }
797              } else {              } else {
798                  Tcl_SetResult(interp, command, TCL_STATIC);                  Tcl_SetResult(interp, command, TCL_STATIC);
799              }              }
800          } else {          } else {
801              Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);              Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
802          }          }
803          break;          break;
804        }        }
805        case CANV_CANVASX: {        case CANV_CANVASX: {
806          int x;          int x;
807          double grid;          double grid;
808          char buf[TCL_DOUBLE_SPACE];          char buf[TCL_DOUBLE_SPACE];
809    
810          if ((argc < 3) || (argc > 4)) {          if ((argc < 3) || (argc > 4)) {
811              Tcl_WrongNumArgs(interp, 2, argv, "screenx ?gridspacing?");              Tcl_WrongNumArgs(interp, 2, argv, "screenx ?gridspacing?");
812              result = TCL_ERROR;              result = TCL_ERROR;
813              goto done;              goto done;
814          }          }
815          if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {          if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &x) != TCL_OK) {
816              result = TCL_ERROR;              result = TCL_ERROR;
817              goto done;              goto done;
818          }          }
819          if (argc == 4) {          if (argc == 4) {
820              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],
821                      &grid) != TCL_OK) {                      &grid) != TCL_OK) {
822                  result = TCL_ERROR;                  result = TCL_ERROR;
823                  goto done;                  goto done;
824              }              }
825          } else {          } else {
826              grid = 0.0;              grid = 0.0;
827          }          }
828          x += canvasPtr->xOrigin;          x += canvasPtr->xOrigin;
829          Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf);          Tcl_PrintDouble(interp, GridAlign((double) x, grid), buf);
830          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
831          break;          break;
832        }        }
833        case CANV_CANVASY: {        case CANV_CANVASY: {
834          int y;          int y;
835          double grid;          double grid;
836          char buf[TCL_DOUBLE_SPACE];          char buf[TCL_DOUBLE_SPACE];
837    
838          if ((argc < 3) || (argc > 4)) {          if ((argc < 3) || (argc > 4)) {
839              Tcl_WrongNumArgs(interp, 2, argv, "screeny ?gridspacing?");              Tcl_WrongNumArgs(interp, 2, argv, "screeny ?gridspacing?");
840              result = TCL_ERROR;              result = TCL_ERROR;
841              goto done;              goto done;
842          }          }
843          if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {          if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, argv[2], &y) != TCL_OK) {
844              result = TCL_ERROR;              result = TCL_ERROR;
845              goto done;              goto done;
846          }          }
847          if (argc == 4) {          if (argc == 4) {
848              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
849                      argv[3], &grid) != TCL_OK) {                      argv[3], &grid) != TCL_OK) {
850                  result = TCL_ERROR;                  result = TCL_ERROR;
851                  goto done;                  goto done;
852              }              }
853          } else {          } else {
854              grid = 0.0;              grid = 0.0;
855          }          }
856          y += canvasPtr->yOrigin;          y += canvasPtr->yOrigin;
857          Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf);          Tcl_PrintDouble(interp, GridAlign((double) y, grid), buf);
858          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
859          break;          break;
860        }        }
861        case CANV_CGET: {        case CANV_CGET: {
862          if (argc != 3) {          if (argc != 3) {
863              Tcl_WrongNumArgs(interp, 2, argv, "option");              Tcl_WrongNumArgs(interp, 2, argv, "option");
864              result = TCL_ERROR;              result = TCL_ERROR;
865              goto done;              goto done;
866          }          }
867          result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,          result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
868                  (char *) canvasPtr, Tcl_GetString(argv[2]), 0);                  (char *) canvasPtr, Tcl_GetString(argv[2]), 0);
869          break;          break;
870        }        }
871        case CANV_CONFIGURE: {        case CANV_CONFIGURE: {
872          if (argc == 2) {          if (argc == 2) {
873              result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,              result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
874                      (char *) canvasPtr, (char *) NULL, 0);                      (char *) canvasPtr, (char *) NULL, 0);
875          } else if (argc == 3) {          } else if (argc == 3) {
876              result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,              result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
877                      (char *) canvasPtr, Tcl_GetString(argv[2]), 0);                      (char *) canvasPtr, Tcl_GetString(argv[2]), 0);
878          } else {          } else {
879              result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,              result = ConfigureCanvas(interp, canvasPtr, argc-2, argv+2,
880                      TK_CONFIG_ARGV_ONLY);                      TK_CONFIG_ARGV_ONLY);
881          }          }
882          break;          break;
883        }        }
884        case CANV_COORDS: {        case CANV_COORDS: {
885          if (argc < 3) {          if (argc < 3) {
886              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?x y x y ...?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?x y x y ...?");
887              result = TCL_ERROR;              result = TCL_ERROR;
888              goto done;              goto done;
889          }          }
890  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
891          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
892  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
893          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
894              goto done;              goto done;
895          }          }
896          itemPtr = TagSearchFirst(searchPtr);          itemPtr = TagSearchFirst(searchPtr);
897  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
898          if (itemPtr != NULL) {          if (itemPtr != NULL) {
899              if (argc != 3) {              if (argc != 3) {
900                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
901              }              }
902              if (itemPtr->typePtr->coordProc != NULL) {              if (itemPtr->typePtr->coordProc != NULL) {
903                if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {                if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
904                  result = (*itemPtr->typePtr->coordProc)(interp,                  result = (*itemPtr->typePtr->coordProc)(interp,
905                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3);
906                } else {                } else {
907                  char **args = GetStringsFromObjs(argc-3, argv+3);                  char **args = GetStringsFromObjs(argc-3, argv+3);
908                  result = (*itemPtr->typePtr->coordProc)(interp,                  result = (*itemPtr->typePtr->coordProc)(interp,
909                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args);                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args);
910                  if (args) ckfree((char *) args);                  if (args) ckfree((char *) args);
911                }                }
912              }              }
913              if (argc != 3) {              if (argc != 3) {
914                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
915              }              }
916          }          }
917          break;          break;
918        }        }
919        case CANV_CREATE: {        case CANV_CREATE: {
920          Tk_ItemType *typePtr;          Tk_ItemType *typePtr;
921          Tk_ItemType *matchPtr = NULL;          Tk_ItemType *matchPtr = NULL;
922          Tk_Item *itemPtr;          Tk_Item *itemPtr;
923          char buf[TCL_INTEGER_SPACE];          char buf[TCL_INTEGER_SPACE];
924          int isNew = 0;          int isNew = 0;
925          Tcl_HashEntry *entryPtr;          Tcl_HashEntry *entryPtr;
926          char *arg;          char *arg;
927    
928          if (argc < 3) {          if (argc < 3) {
929              Tcl_WrongNumArgs(interp, 2, argv, "type ?arg arg ...?");              Tcl_WrongNumArgs(interp, 2, argv, "type ?arg arg ...?");
930              result = TCL_ERROR;              result = TCL_ERROR;
931              goto done;              goto done;
932          }          }
933          arg = Tcl_GetStringFromObj(argv[2], (int *) &length);          arg = Tcl_GetStringFromObj(argv[2], (int *) &length);
934          c = arg[0];          c = arg[0];
935          for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {          for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr) {
936              if ((c == typePtr->name[0])              if ((c == typePtr->name[0])
937                      && (strncmp(arg, typePtr->name, length) == 0)) {                      && (strncmp(arg, typePtr->name, length) == 0)) {
938                  if (matchPtr != NULL) {                  if (matchPtr != NULL) {
939                      badType:                      badType:
940                      Tcl_AppendResult(interp,                      Tcl_AppendResult(interp,
941                              "unknown or ambiguous item type \"",                              "unknown or ambiguous item type \"",
942                              arg, "\"", (char *) NULL);                              arg, "\"", (char *) NULL);
943                      result = TCL_ERROR;                      result = TCL_ERROR;
944                      goto done;                      goto done;
945                  }                  }
946                  matchPtr = typePtr;                  matchPtr = typePtr;
947              }              }
948          }          }
949          if (matchPtr == NULL) {          if (matchPtr == NULL) {
950              goto badType;              goto badType;
951          }          }
952          typePtr = matchPtr;          typePtr = matchPtr;
953          itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);          itemPtr = (Tk_Item *) ckalloc((unsigned) typePtr->itemSize);
954          itemPtr->id = canvasPtr->nextId;          itemPtr->id = canvasPtr->nextId;
955          canvasPtr->nextId++;          canvasPtr->nextId++;
956          itemPtr->tagPtr = itemPtr->staticTagSpace;          itemPtr->tagPtr = itemPtr->staticTagSpace;
957          itemPtr->tagSpace = TK_TAG_SPACE;          itemPtr->tagSpace = TK_TAG_SPACE;
958          itemPtr->numTags = 0;          itemPtr->numTags = 0;
959          itemPtr->typePtr = typePtr;          itemPtr->typePtr = typePtr;
960          itemPtr->state = TK_STATE_NULL;          itemPtr->state = TK_STATE_NULL;
961          itemPtr->redraw_flags = 0;          itemPtr->redraw_flags = 0;
962          if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {          if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
963            result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,            result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
964                  itemPtr, argc-3, argv+3);                  itemPtr, argc-3, argv+3);
965          } else {          } else {
966            char **args = GetStringsFromObjs(argc-3, argv+3);            char **args = GetStringsFromObjs(argc-3, argv+3);
967            result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,            result = (*typePtr->createProc)(interp, (Tk_Canvas) canvasPtr,
968                  itemPtr, argc-3, (Tcl_Obj **) args);                  itemPtr, argc-3, (Tcl_Obj **) args);
969            if (args) ckfree((char *) args);            if (args) ckfree((char *) args);
970          }          }
971          if (result != TCL_OK) {          if (result != TCL_OK) {
972              ckfree((char *) itemPtr);              ckfree((char *) itemPtr);
973              result = TCL_ERROR;              result = TCL_ERROR;
974              goto done;              goto done;
975          }          }
976          itemPtr->nextPtr = NULL;          itemPtr->nextPtr = NULL;
977          entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,          entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,
978                  (char *) itemPtr->id, &isNew);                  (char *) itemPtr->id, &isNew);
979          Tcl_SetHashValue(entryPtr, itemPtr);          Tcl_SetHashValue(entryPtr, itemPtr);
980          itemPtr->prevPtr = canvasPtr->lastItemPtr;          itemPtr->prevPtr = canvasPtr->lastItemPtr;
981          canvasPtr->hotPtr = itemPtr;          canvasPtr->hotPtr = itemPtr;
982          canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;          canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
983          if (canvasPtr->lastItemPtr == NULL) {          if (canvasPtr->lastItemPtr == NULL) {
984              canvasPtr->firstItemPtr = itemPtr;              canvasPtr->firstItemPtr = itemPtr;
985          } else {          } else {
986              canvasPtr->lastItemPtr->nextPtr = itemPtr;              canvasPtr->lastItemPtr->nextPtr = itemPtr;
987          }          }
988          canvasPtr->lastItemPtr = itemPtr;          canvasPtr->lastItemPtr = itemPtr;
989          itemPtr->redraw_flags |= FORCE_REDRAW;          itemPtr->redraw_flags |= FORCE_REDRAW;
990          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
991          canvasPtr->flags |= REPICK_NEEDED;          canvasPtr->flags |= REPICK_NEEDED;
992          sprintf(buf, "%d", itemPtr->id);          sprintf(buf, "%d", itemPtr->id);
993          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
994          break;          break;
995        }        }
996        case CANV_DCHARS: {        case CANV_DCHARS: {
997          int first, last;          int first, last;
998          int x1,x2,y1,y2;          int x1,x2,y1,y2;
999    
1000          if ((argc != 4) && (argc != 5)) {          if ((argc != 4) && (argc != 5)) {
1001              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId first ?last?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId first ?last?");
1002              result = TCL_ERROR;              result = TCL_ERROR;
1003              goto done;              goto done;
1004          }          }
1005  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1006          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1007                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1008  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1009          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1010              goto done;              goto done;
1011          }          }
1012          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1013                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1014  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1015              if ((itemPtr->typePtr->indexProc == NULL)              if ((itemPtr->typePtr->indexProc == NULL)
1016                      || (itemPtr->typePtr->dCharsProc == NULL)) {                      || (itemPtr->typePtr->dCharsProc == NULL)) {
1017                  continue;                  continue;
1018              }              }
1019              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1020                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1021                          itemPtr, (char *) argv[3], &first);                          itemPtr, (char *) argv[3], &first);
1022              } else {              } else {
1023                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1024                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &first);                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &first);
1025              }              }
1026              if (result != TCL_OK) {              if (result != TCL_OK) {
1027                  goto done;                  goto done;
1028              }              }
1029              if (argc == 5) {              if (argc == 5) {
1030                  if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {                  if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1031                      result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                      result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1032                              itemPtr, (char *) argv[4], &last);                              itemPtr, (char *) argv[4], &last);
1033                  } else {                  } else {
1034                      result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                      result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1035                              itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &last);                              itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &last);
1036                  }                  }
1037                  if (result != TCL_OK) {                  if (result != TCL_OK) {
1038                      goto done;                      goto done;
1039                  }                  }
1040              } else {              } else {
1041                  last = first;                  last = first;
1042              }              }
1043    
1044              /*              /*
1045               * Redraw both item's old and new areas:  it's possible               * Redraw both item's old and new areas:  it's possible
1046               * that a delete could result in a new area larger than               * that a delete could result in a new area larger than
1047               * the old area. Except if the insertProc sets the               * the old area. Except if the insertProc sets the
1048               * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.               * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
1049               */               */
1050    
1051              x1 = itemPtr->x1; y1 = itemPtr->y1;              x1 = itemPtr->x1; y1 = itemPtr->y1;
1052              x2 = itemPtr->x2; y2 = itemPtr->y2;              x2 = itemPtr->x2; y2 = itemPtr->y2;
1053              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
1054              (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,              (*itemPtr->typePtr->dCharsProc)((Tk_Canvas) canvasPtr,
1055                      itemPtr, first, last);                      itemPtr, first, last);
1056              if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {              if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
1057                  Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,                  Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
1058                          x1, y1, x2, y2);                          x1, y1, x2, y2);
1059                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1060              }              }
1061              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
1062          }          }
1063          break;          break;
1064        }        }
1065        case CANV_DELETE: {        case CANV_DELETE: {
1066          int i;          int i;
1067          Tcl_HashEntry *entryPtr;          Tcl_HashEntry *entryPtr;
1068    
1069          for (i = 2; i < argc; i++) {          for (i = 2; i < argc; i++) {
1070  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1071              for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);              for (itemPtr = StartTagSearch(canvasPtr, argv[i], &search);
1072                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1073  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1074              if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) {              if ((result = TagSearchScan(canvasPtr, argv[i], &searchPtr)) != TCL_OK) {
1075                  goto done;                  goto done;
1076              }              }
1077              for (itemPtr = TagSearchFirst(searchPtr);              for (itemPtr = TagSearchFirst(searchPtr);
1078                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1079  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1080                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1081                  if (canvasPtr->bindingTable != NULL) {                  if (canvasPtr->bindingTable != NULL) {
1082                      Tk_DeleteAllBindings(canvasPtr->bindingTable,                      Tk_DeleteAllBindings(canvasPtr->bindingTable,
1083                              (ClientData) itemPtr);                              (ClientData) itemPtr);
1084                  }                  }
1085                  (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,                  (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
1086                          canvasPtr->display);                          canvasPtr->display);
1087                  if (itemPtr->tagPtr != itemPtr->staticTagSpace) {                  if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
1088                      ckfree((char *) itemPtr->tagPtr);                      ckfree((char *) itemPtr->tagPtr);
1089                  }                  }
1090                  entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,                  entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
1091                          (char *) itemPtr->id);                          (char *) itemPtr->id);
1092                  Tcl_DeleteHashEntry(entryPtr);                  Tcl_DeleteHashEntry(entryPtr);
1093                  if (itemPtr->nextPtr != NULL) {                  if (itemPtr->nextPtr != NULL) {
1094                      itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;                      itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
1095                  }                  }
1096                  if (itemPtr->prevPtr != NULL) {                  if (itemPtr->prevPtr != NULL) {
1097                      itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;                      itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
1098                  }                  }
1099                  if (canvasPtr->firstItemPtr == itemPtr) {                  if (canvasPtr->firstItemPtr == itemPtr) {
1100                      canvasPtr->firstItemPtr = itemPtr->nextPtr;                      canvasPtr->firstItemPtr = itemPtr->nextPtr;
1101                      if (canvasPtr->firstItemPtr == NULL) {                      if (canvasPtr->firstItemPtr == NULL) {
1102                          canvasPtr->lastItemPtr = NULL;                          canvasPtr->lastItemPtr = NULL;
1103                      }                      }
1104                  }                  }
1105                  if (canvasPtr->lastItemPtr == itemPtr) {                  if (canvasPtr->lastItemPtr == itemPtr) {
1106                      canvasPtr->lastItemPtr = itemPtr->prevPtr;                      canvasPtr->lastItemPtr = itemPtr->prevPtr;
1107                  }                  }
1108                  ckfree((char *) itemPtr);                  ckfree((char *) itemPtr);
1109                  if (itemPtr == canvasPtr->currentItemPtr) {                  if (itemPtr == canvasPtr->currentItemPtr) {
1110                      canvasPtr->currentItemPtr = NULL;                      canvasPtr->currentItemPtr = NULL;
1111                      canvasPtr->flags |= REPICK_NEEDED;                      canvasPtr->flags |= REPICK_NEEDED;
1112                  }                  }
1113                  if (itemPtr == canvasPtr->newCurrentPtr) {                  if (itemPtr == canvasPtr->newCurrentPtr) {
1114                      canvasPtr->newCurrentPtr = NULL;                      canvasPtr->newCurrentPtr = NULL;
1115                      canvasPtr->flags |= REPICK_NEEDED;                      canvasPtr->flags |= REPICK_NEEDED;
1116                  }                  }
1117                  if (itemPtr == canvasPtr->textInfo.focusItemPtr) {                  if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
1118                      canvasPtr->textInfo.focusItemPtr = NULL;                      canvasPtr->textInfo.focusItemPtr = NULL;
1119                  }                  }
1120                  if (itemPtr == canvasPtr->textInfo.selItemPtr) {                  if (itemPtr == canvasPtr->textInfo.selItemPtr) {
1121                      canvasPtr->textInfo.selItemPtr = NULL;                      canvasPtr->textInfo.selItemPtr = NULL;
1122                  }                  }
1123                  if ((itemPtr == canvasPtr->hotPtr)                  if ((itemPtr == canvasPtr->hotPtr)
1124                          || (itemPtr == canvasPtr->hotPrevPtr)) {                          || (itemPtr == canvasPtr->hotPrevPtr)) {
1125                      canvasPtr->hotPtr = NULL;                      canvasPtr->hotPtr = NULL;
1126                  }                  }
1127              }              }
1128          }          }
1129          break;          break;
1130        }        }
1131        case CANV_DTAG: {        case CANV_DTAG: {
1132          Tk_Uid tag;          Tk_Uid tag;
1133          int i;          int i;
1134    
1135          if ((argc != 3) && (argc != 4)) {          if ((argc != 3) && (argc != 4)) {
1136              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagToDelete?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?tagToDelete?");
1137              result = TCL_ERROR;              result = TCL_ERROR;
1138              goto done;              goto done;
1139          }          }
1140          if (argc == 4) {          if (argc == 4) {
1141              tag = Tk_GetUid(Tcl_GetStringFromObj(argv[3], NULL));              tag = Tk_GetUid(Tcl_GetStringFromObj(argv[3], NULL));
1142          } else {          } else {
1143              tag = Tk_GetUid(Tcl_GetStringFromObj(argv[2], NULL));              tag = Tk_GetUid(Tcl_GetStringFromObj(argv[2], NULL));
1144          }          }
1145  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1146          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1147                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1148  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1149          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1150              goto done;              goto done;
1151          }          }
1152          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1153                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1154  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1155              for (i = itemPtr->numTags-1; i >= 0; i--) {              for (i = itemPtr->numTags-1; i >= 0; i--) {
1156                  if (itemPtr->tagPtr[i] == tag) {                  if (itemPtr->tagPtr[i] == tag) {
1157                      itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];                      itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
1158                      itemPtr->numTags--;                      itemPtr->numTags--;
1159                  }                  }
1160              }              }
1161          }          }
1162          break;          break;
1163        }        }
1164        case CANV_FIND: {        case CANV_FIND: {
1165          if (argc < 3) {          if (argc < 3) {
1166              Tcl_WrongNumArgs(interp, 2, argv, "searchCommand ?arg arg ...?");              Tcl_WrongNumArgs(interp, 2, argv, "searchCommand ?arg arg ...?");
1167              result = TCL_ERROR;              result = TCL_ERROR;
1168              goto done;              goto done;
1169          }          }
1170  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1171          result = FindItems(interp, canvasPtr, argc, argv, (Tcl_Obj *) NULL, 2);          result = FindItems(interp, canvasPtr, argc, argv, (Tcl_Obj *) NULL, 2);
1172  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1173          result = FindItems(interp, canvasPtr, argc, argv,          result = FindItems(interp, canvasPtr, argc, argv,
1174              (Tcl_Obj *) NULL, 2, &searchPtr);              (Tcl_Obj *) NULL, 2, &searchPtr);
1175  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1176          break;          break;
1177        }        }
1178        case CANV_FOCUS: {        case CANV_FOCUS: {
1179          if (argc > 3) {          if (argc > 3) {
1180              Tcl_WrongNumArgs(interp, 2, argv, "?tagOrId?");              Tcl_WrongNumArgs(interp, 2, argv, "?tagOrId?");
1181              result = TCL_ERROR;              result = TCL_ERROR;
1182              goto done;              goto done;
1183          }          }
1184          itemPtr = canvasPtr->textInfo.focusItemPtr;          itemPtr = canvasPtr->textInfo.focusItemPtr;
1185          if (argc == 2) {          if (argc == 2) {
1186              if (itemPtr != NULL) {              if (itemPtr != NULL) {
1187                  char buf[TCL_INTEGER_SPACE];                  char buf[TCL_INTEGER_SPACE];
1188                                    
1189                  sprintf(buf, "%d", itemPtr->id);                  sprintf(buf, "%d", itemPtr->id);
1190                  Tcl_SetResult(interp, buf, TCL_VOLATILE);                  Tcl_SetResult(interp, buf, TCL_VOLATILE);
1191              }              }
1192              goto done;              goto done;
1193          }          }
1194          if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {          if ((itemPtr != NULL) && (canvasPtr->textInfo.gotFocus)) {
1195              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1196          }          }
1197          if (Tcl_GetStringFromObj(argv[2], NULL)[0] == 0) {          if (Tcl_GetStringFromObj(argv[2], NULL)[0] == 0) {
1198              canvasPtr->textInfo.focusItemPtr = NULL;              canvasPtr->textInfo.focusItemPtr = NULL;
1199              goto done;              goto done;
1200          }          }
1201  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1202          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1203                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1204  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1205          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1206              goto done;              goto done;
1207          }          }
1208          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1209                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1210  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1211              if (itemPtr->typePtr->icursorProc != NULL) {              if (itemPtr->typePtr->icursorProc != NULL) {
1212                  break;                  break;
1213              }              }
1214          }          }
1215          if (itemPtr == NULL) {          if (itemPtr == NULL) {
1216              goto done;              goto done;
1217          }          }
1218          canvasPtr->textInfo.focusItemPtr = itemPtr;          canvasPtr->textInfo.focusItemPtr = itemPtr;
1219          if (canvasPtr->textInfo.gotFocus) {          if (canvasPtr->textInfo.gotFocus) {
1220              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1221          }          }
1222          break;          break;
1223        }        }
1224        case CANV_GETTAGS: {        case CANV_GETTAGS: {
1225          if (argc != 3) {          if (argc != 3) {
1226              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId");
1227              result = TCL_ERROR;              result = TCL_ERROR;
1228              goto done;              goto done;
1229          }          }
1230  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1231          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1232  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1233          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1234              goto done;              goto done;
1235          }          }
1236          itemPtr = TagSearchFirst(searchPtr);          itemPtr = TagSearchFirst(searchPtr);
1237  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1238          if (itemPtr != NULL) {          if (itemPtr != NULL) {
1239              int i;              int i;
1240              for (i = 0; i < itemPtr->numTags; i++) {              for (i = 0; i < itemPtr->numTags; i++) {
1241                  Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]);                  Tcl_AppendElement(interp, (char *) itemPtr->tagPtr[i]);
1242              }              }
1243          }          }
1244          break;          break;
1245        }        }
1246        case CANV_ICURSOR: {        case CANV_ICURSOR: {
1247          int index;          int index;
1248    
1249          if (argc != 4) {          if (argc != 4) {
1250              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index");
1251              result = TCL_ERROR;              result = TCL_ERROR;
1252              goto done;              goto done;
1253          }          }
1254  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1255          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1256                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1257  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1258          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1259              goto done;              goto done;
1260          }          }
1261          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1262                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1263  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1264              if ((itemPtr->typePtr->indexProc == NULL)              if ((itemPtr->typePtr->indexProc == NULL)
1265                      || (itemPtr->typePtr->icursorProc == NULL)) {                      || (itemPtr->typePtr->icursorProc == NULL)) {
1266                  goto done;                  goto done;
1267              }              }
1268              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1269                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1270                          itemPtr, (char *) argv[3], &index);                          itemPtr, (char *) argv[3], &index);
1271              } else {              } else {
1272                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1273                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index);                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index);
1274              }              }
1275              if (result != TCL_OK) {              if (result != TCL_OK) {
1276                  goto done;                  goto done;
1277              }              }
1278              (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr,              (*itemPtr->typePtr->icursorProc)((Tk_Canvas) canvasPtr, itemPtr,
1279                      index);                      index);
1280              if ((itemPtr == canvasPtr->textInfo.focusItemPtr)              if ((itemPtr == canvasPtr->textInfo.focusItemPtr)
1281                      && (canvasPtr->textInfo.cursorOn)) {                      && (canvasPtr->textInfo.cursorOn)) {
1282                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1283              }              }
1284          }          }
1285          break;          break;
1286        }        }
1287        case CANV_INDEX: {        case CANV_INDEX: {
1288    
1289          int index;          int index;
1290          char buf[TCL_INTEGER_SPACE];          char buf[TCL_INTEGER_SPACE];
1291    
1292          if (argc != 4) {          if (argc != 4) {
1293              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId string");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId string");
1294              result = TCL_ERROR;              result = TCL_ERROR;
1295              goto done;              goto done;
1296          }          }
1297  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1298          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1299                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1300  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1301          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1302              goto done;              goto done;
1303          }          }
1304          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1305                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1306  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1307              if (itemPtr->typePtr->indexProc != NULL) {              if (itemPtr->typePtr->indexProc != NULL) {
1308                  break;                  break;
1309              }              }
1310          }          }
1311          if (itemPtr == NULL) {          if (itemPtr == NULL) {
1312              Tcl_AppendResult(interp, "can't find an indexable item \"",              Tcl_AppendResult(interp, "can't find an indexable item \"",
1313                      Tcl_GetStringFromObj(argv[2], NULL), "\"", (char *) NULL);                      Tcl_GetStringFromObj(argv[2], NULL), "\"", (char *) NULL);
1314              result = TCL_ERROR;              result = TCL_ERROR;
1315              goto done;              goto done;
1316          }          }
1317          if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {          if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1318              result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,              result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1319                      itemPtr, (char *) argv[3], &index);                      itemPtr, (char *) argv[3], &index);
1320          } else {          } else {
1321              result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,              result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1322                      itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index);                      itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &index);
1323          }          }
1324          if (result != TCL_OK) {          if (result != TCL_OK) {
1325              goto done;              goto done;
1326          }          }
1327          sprintf(buf, "%d", index);          sprintf(buf, "%d", index);
1328          Tcl_SetResult(interp, buf, TCL_VOLATILE);          Tcl_SetResult(interp, buf, TCL_VOLATILE);
1329          break;          break;
1330        }        }
1331        case CANV_INSERT: {        case CANV_INSERT: {
1332          int beforeThis;          int beforeThis;
1333          int x1,x2,y1,y2;          int x1,x2,y1,y2;
1334    
1335          if (argc != 5) {          if (argc != 5) {
1336              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId beforeThis string");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId beforeThis string");
1337              result = TCL_ERROR;              result = TCL_ERROR;
1338              goto done;              goto done;
1339          }          }
1340  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1341          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1342                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1343  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1344          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1345              goto done;              goto done;
1346          }          }
1347          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1348                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1349  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1350              if ((itemPtr->typePtr->indexProc == NULL)              if ((itemPtr->typePtr->indexProc == NULL)
1351                      || (itemPtr->typePtr->insertProc == NULL)) {                      || (itemPtr->typePtr->insertProc == NULL)) {
1352                  continue;                  continue;
1353              }              }
1354              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1355                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1356                          itemPtr, (char *) argv[3], &beforeThis);                          itemPtr, (char *) argv[3], &beforeThis);
1357              } else {              } else {
1358                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1359                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &beforeThis);                          itemPtr, Tcl_GetStringFromObj(argv[3], NULL), &beforeThis);
1360              }              }
1361              if (result != TCL_OK) {              if (result != TCL_OK) {
1362                  goto done;                  goto done;
1363              }              }
1364    
1365              /*              /*
1366               * Redraw both item's old and new areas:  it's possible               * Redraw both item's old and new areas:  it's possible
1367               * that an insertion could result in a new area either               * that an insertion could result in a new area either
1368               * larger or smaller than the old area. Except if the               * larger or smaller than the old area. Except if the
1369               * insertProc sets the TK_ITEM_DONT_REDRAW flag, nothing               * insertProc sets the TK_ITEM_DONT_REDRAW flag, nothing
1370               * more needs to be done.               * more needs to be done.
1371               */               */
1372    
1373              x1 = itemPtr->x1; y1 = itemPtr->y1;              x1 = itemPtr->x1; y1 = itemPtr->y1;
1374              x2 = itemPtr->x2; y2 = itemPtr->y2;              x2 = itemPtr->x2; y2 = itemPtr->y2;
1375              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
1376              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1377                  (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,                  (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
1378                          itemPtr, beforeThis, (char *) argv[4]);                          itemPtr, beforeThis, (char *) argv[4]);
1379              } else {              } else {
1380                  (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,                  (*itemPtr->typePtr->insertProc)((Tk_Canvas) canvasPtr,
1381                          itemPtr, beforeThis, Tcl_GetStringFromObj(argv[4], NULL));                          itemPtr, beforeThis, Tcl_GetStringFromObj(argv[4], NULL));
1382              }              }
1383              if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {              if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
1384                  Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,                  Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
1385                          x1, y1, x2, y2);                          x1, y1, x2, y2);
1386                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1387              }              }
1388              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;              itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
1389          }          }
1390          break;          break;
1391        }        }
1392        case CANV_ITEMCGET: {        case CANV_ITEMCGET: {
1393          if (argc != 4) {          if (argc != 4) {
1394              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId option");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId option");
1395              return TCL_ERROR;              return TCL_ERROR;
1396          }          }
1397  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1398          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1399  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1400          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1401              goto done;              goto done;
1402          }          }
1403          itemPtr = TagSearchFirst(searchPtr);          itemPtr = TagSearchFirst(searchPtr);
1404  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1405          if (itemPtr != NULL) {          if (itemPtr != NULL) {
1406              result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,              result = Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
1407                      itemPtr->typePtr->configSpecs, (char *) itemPtr,                      itemPtr->typePtr->configSpecs, (char *) itemPtr,
1408                      Tcl_GetStringFromObj(argv[3], NULL), 0);                      Tcl_GetStringFromObj(argv[3], NULL), 0);
1409          }          }
1410          break;          break;
1411        }        }
1412        case CANV_ITEMCONFIGURE: {        case CANV_ITEMCONFIGURE: {
1413          if (argc < 3) {          if (argc < 3) {
1414              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?option value ...?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?option value ...?");
1415              result = TCL_ERROR;              result = TCL_ERROR;
1416              goto done;              goto done;
1417          }          }
1418  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1419          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1420                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1421  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1422          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1423              goto done;              goto done;
1424          }          }
1425          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1426                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1427  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1428              if (argc == 3) {              if (argc == 3) {
1429                  result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,                  result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
1430                          itemPtr->typePtr->configSpecs, (char *) itemPtr,                          itemPtr->typePtr->configSpecs, (char *) itemPtr,
1431                          (char *) NULL, 0);                          (char *) NULL, 0);
1432              } else if (argc == 4) {              } else if (argc == 4) {
1433                  result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,                  result = Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
1434                          itemPtr->typePtr->configSpecs, (char *) itemPtr,                          itemPtr->typePtr->configSpecs, (char *) itemPtr,
1435                          Tcl_GetString(argv[3]), 0);                          Tcl_GetString(argv[3]), 0);
1436              } else {              } else {
1437                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1438                  if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {                  if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1439                  result = (*itemPtr->typePtr->configProc)(interp,                  result = (*itemPtr->typePtr->configProc)(interp,
1440                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, argv+3,
1441                          TK_CONFIG_ARGV_ONLY);                          TK_CONFIG_ARGV_ONLY);
1442                  } else {                  } else {
1443                  char **args = GetStringsFromObjs(argc-3, argv+3);                  char **args = GetStringsFromObjs(argc-3, argv+3);
1444                  result = (*itemPtr->typePtr->configProc)(interp,                  result = (*itemPtr->typePtr->configProc)(interp,
1445                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args,                          (Tk_Canvas) canvasPtr, itemPtr, argc-3, (Tcl_Obj **) args,
1446                          TK_CONFIG_ARGV_ONLY);                          TK_CONFIG_ARGV_ONLY);
1447                  if (args) ckfree((char *) args);                  if (args) ckfree((char *) args);
1448                  }                  }
1449                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);                  EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1450                  canvasPtr->flags |= REPICK_NEEDED;                  canvasPtr->flags |= REPICK_NEEDED;
1451              }              }
1452              if ((result != TCL_OK) || (argc < 5)) {              if ((result != TCL_OK) || (argc < 5)) {
1453                  break;                  break;
1454              }              }
1455          }          }
1456          break;          break;
1457        }        }
1458        case CANV_LOWER: {        case CANV_LOWER: {
1459          Tk_Item *itemPtr;          Tk_Item *itemPtr;
1460    
1461          if ((argc != 3) && (argc != 4)) {          if ((argc != 3) && (argc != 4)) {
1462              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?belowThis?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?belowThis?");
1463              result = TCL_ERROR;              result = TCL_ERROR;
1464              goto done;              goto done;
1465          }          }
1466    
1467          /*          /*
1468           * First find the item just after which we'll insert the           * First find the item just after which we'll insert the
1469           * named items.           * named items.
1470           */           */
1471    
1472          if (argc == 3) {          if (argc == 3) {
1473              itemPtr = NULL;              itemPtr = NULL;
1474          } else {          } else {
1475  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1476              itemPtr = StartTagSearch(canvasPtr, argv[3], &search);              itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
1477  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1478              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {
1479                  goto done;                  goto done;
1480              }              }
1481              itemPtr = TagSearchFirst(searchPtr);              itemPtr = TagSearchFirst(searchPtr);
1482  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1483              if (itemPtr == NULL) {              if (itemPtr == NULL) {
1484                  Tcl_AppendResult(interp, "tag \"", Tcl_GetString(argv[3]),                  Tcl_AppendResult(interp, "tag \"", Tcl_GetString(argv[3]),
1485                          "\" doesn't match any items", (char *) NULL);                          "\" doesn't match any items", (char *) NULL);
1486                  goto done;                  goto done;
1487              }              }
1488              itemPtr = itemPtr->prevPtr;              itemPtr = itemPtr->prevPtr;
1489          }          }
1490  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1491          RelinkItems(canvasPtr, argv[2], itemPtr);          RelinkItems(canvasPtr, argv[2], itemPtr);
1492  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1493          if ((result = RelinkItems(canvasPtr, argv[2], itemPtr, &searchPtr)) != TCL_OK) {          if ((result = RelinkItems(canvasPtr, argv[2], itemPtr, &searchPtr)) != TCL_OK) {
1494              goto done;              goto done;
1495          }          }
1496  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1497          break;          break;
1498        }        }
1499        case CANV_MOVE: {        case CANV_MOVE: {
1500          double xAmount, yAmount;          double xAmount, yAmount;
1501    
1502          if (argc != 5) {          if (argc != 5) {
1503              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xAmount yAmount");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xAmount yAmount");
1504              result = TCL_ERROR;              result = TCL_ERROR;
1505              goto done;              goto done;
1506          }          }
1507          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],
1508                  &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,                  &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,
1509                  (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) {                  (Tk_Canvas) canvasPtr, argv[4], &yAmount) != TCL_OK)) {
1510              result = TCL_ERROR;              result = TCL_ERROR;
1511              goto done;              goto done;
1512          }          }
1513  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1514          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1515                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1516  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1517          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1518              goto done;              goto done;
1519          }          }
1520          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1521                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1522  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1523              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1524              (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,              (void) (*itemPtr->typePtr->translateProc)((Tk_Canvas) canvasPtr,
1525                      itemPtr,  xAmount, yAmount);                      itemPtr,  xAmount, yAmount);
1526              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1527              canvasPtr->flags |= REPICK_NEEDED;              canvasPtr->flags |= REPICK_NEEDED;
1528          }          }
1529          break;          break;
1530        }        }
1531        case CANV_POSTSCRIPT: {        case CANV_POSTSCRIPT: {
1532          char **args = GetStringsFromObjs(argc, argv);          char **args = GetStringsFromObjs(argc, argv);
1533          result = TkCanvPostscriptCmd(canvasPtr, interp, argc, args);          result = TkCanvPostscriptCmd(canvasPtr, interp, argc, args);
1534          if (args) ckfree((char *) args);          if (args) ckfree((char *) args);
1535          break;          break;
1536        }        }
1537        case CANV_RAISE: {        case CANV_RAISE: {
1538          Tk_Item *prevPtr;          Tk_Item *prevPtr;
1539    
1540          if ((argc != 3) && (argc != 4)) {          if ((argc != 3) && (argc != 4)) {
1541              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?aboveThis?");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId ?aboveThis?");
1542              result = TCL_ERROR;              result = TCL_ERROR;
1543              goto done;              goto done;
1544          }          }
1545    
1546          /*          /*
1547           * First find the item just after which we'll insert the           * First find the item just after which we'll insert the
1548           * named items.           * named items.
1549           */           */
1550    
1551          if (argc == 3) {          if (argc == 3) {
1552              prevPtr = canvasPtr->lastItemPtr;              prevPtr = canvasPtr->lastItemPtr;
1553          } else {          } else {
1554              prevPtr = NULL;              prevPtr = NULL;
1555  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1556              for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);              for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
1557                      itemPtr != NULL; itemPtr = NextItem(&search)) {                      itemPtr != NULL; itemPtr = NextItem(&search)) {
1558  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1559              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {
1560                  goto done;                  goto done;
1561              }              }
1562              for (itemPtr = TagSearchFirst(searchPtr);              for (itemPtr = TagSearchFirst(searchPtr);
1563                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1564  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1565                  prevPtr = itemPtr;                  prevPtr = itemPtr;
1566              }              }
1567              if (prevPtr == NULL) {              if (prevPtr == NULL) {
1568                  Tcl_AppendResult(interp, "tagOrId \"", Tcl_GetStringFromObj(argv[3], NULL),                  Tcl_AppendResult(interp, "tagOrId \"", Tcl_GetStringFromObj(argv[3], NULL),
1569                          "\" doesn't match any items", (char *) NULL);                          "\" doesn't match any items", (char *) NULL);
1570                  result = TCL_ERROR;                  result = TCL_ERROR;
1571                  goto done;                  goto done;
1572              }              }
1573          }          }
1574  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1575          RelinkItems(canvasPtr, argv[2], prevPtr);          RelinkItems(canvasPtr, argv[2], prevPtr);
1576  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1577          result = RelinkItems(canvasPtr, argv[2], prevPtr, &searchPtr);          result = RelinkItems(canvasPtr, argv[2], prevPtr, &searchPtr);
1578          if (result != TCL_OK) {          if (result != TCL_OK) {
1579              goto done;              goto done;
1580          }          }
1581  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1582          break;          break;
1583        }        }
1584        case CANV_SCALE: {        case CANV_SCALE: {
1585          double xOrigin, yOrigin, xScale, yScale;          double xOrigin, yOrigin, xScale, yScale;
1586    
1587          if (argc != 7) {          if (argc != 7) {
1588              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xOrigin yOrigin xScale yScale");              Tcl_WrongNumArgs(interp, 2, argv, "tagOrId xOrigin yOrigin xScale yScale");
1589              result = TCL_ERROR;              result = TCL_ERROR;
1590              goto done;              goto done;
1591          }          }
1592          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
1593                      argv[3], &xOrigin) != TCL_OK)                      argv[3], &xOrigin) != TCL_OK)
1594                  || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,                  || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
1595                      argv[4], &yOrigin) != TCL_OK)                      argv[4], &yOrigin) != TCL_OK)
1596                  || (Tcl_GetDoubleFromObj(interp, argv[5], &xScale) != TCL_OK)                  || (Tcl_GetDoubleFromObj(interp, argv[5], &xScale) != TCL_OK)
1597                  || (Tcl_GetDoubleFromObj(interp, argv[6], &yScale) != TCL_OK)) {                  || (Tcl_GetDoubleFromObj(interp, argv[6], &yScale) != TCL_OK)) {
1598              result = TCL_ERROR;              result = TCL_ERROR;
1599              goto done;              goto done;
1600          }          }
1601          if ((xScale == 0.0) || (yScale == 0.0)) {          if ((xScale == 0.0) || (yScale == 0.0)) {
1602              Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC);              Tcl_SetResult(interp, "scale factor cannot be zero", TCL_STATIC);
1603              result = TCL_ERROR;              result = TCL_ERROR;
1604              goto done;              goto done;
1605          }          }
1606  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1607          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1608                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
1609  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1610          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1611              goto done;              goto done;
1612          }          }
1613          for (itemPtr = TagSearchFirst(searchPtr);          for (itemPtr = TagSearchFirst(searchPtr);
1614                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1615  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1616              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1617              (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,              (void) (*itemPtr->typePtr->scaleProc)((Tk_Canvas) canvasPtr,
1618                      itemPtr, xOrigin, yOrigin, xScale, yScale);                      itemPtr, xOrigin, yOrigin, xScale, yScale);
1619              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
1620              canvasPtr->flags |= REPICK_NEEDED;              canvasPtr->flags |= REPICK_NEEDED;
1621          }          }
1622          break;          break;
1623        }        }
1624        case CANV_SCAN: {        case CANV_SCAN: {
1625          int x, y, gain=10;          int x, y, gain=10;
1626          static char *optionStrings[] = {          static char *optionStrings[] = {
1627              "mark", "dragto", NULL              "mark", "dragto", NULL
1628          };          };
1629    
1630          if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "scan option", 0,          if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "scan option", 0,
1631                  &index) != TCL_OK) {                  &index) != TCL_OK) {
1632              return TCL_ERROR;              return TCL_ERROR;
1633          }          }
1634    
1635          if ((argc != 5) && (argc != 5+index)) {          if ((argc != 5) && (argc != 5+index)) {
1636              Tcl_WrongNumArgs(interp, 3, argv, index?"x y ?gain?":"x y");              Tcl_WrongNumArgs(interp, 3, argv, index?"x y ?gain?":"x y");
1637              result = TCL_ERROR;              result = TCL_ERROR;
1638              goto done;              goto done;
1639          }          }
1640          if ((Tcl_GetIntFromObj(interp, argv[3], &x) != TCL_OK)          if ((Tcl_GetIntFromObj(interp, argv[3], &x) != TCL_OK)
1641                  || (Tcl_GetIntFromObj(interp, argv[4], &y) != TCL_OK)){                  || (Tcl_GetIntFromObj(interp, argv[4], &y) != TCL_OK)){
1642              result = TCL_ERROR;              result = TCL_ERROR;
1643              goto done;              goto done;
1644          }          }
1645          if ((argc == 6) && (Tcl_GetIntFromObj(interp, argv[5], &gain) != TCL_OK)) {          if ((argc == 6) && (Tcl_GetIntFromObj(interp, argv[5], &gain) != TCL_OK)) {
1646              result = TCL_ERROR;              result = TCL_ERROR;
1647              goto done;              goto done;
1648          }          }
1649          if (!index) {          if (!index) {
1650              canvasPtr->scanX = x;              canvasPtr->scanX = x;
1651              canvasPtr->scanXOrigin = canvasPtr->xOrigin;              canvasPtr->scanXOrigin = canvasPtr->xOrigin;
1652              canvasPtr->scanY = y;              canvasPtr->scanY = y;
1653              canvasPtr->scanYOrigin = canvasPtr->yOrigin;              canvasPtr->scanYOrigin = canvasPtr->yOrigin;
1654          } else {          } else {
1655              int newXOrigin, newYOrigin, tmp;              int newXOrigin, newYOrigin, tmp;
1656    
1657              /*              /*
1658               * Compute a new view origin for the canvas, amplifying the               * Compute a new view origin for the canvas, amplifying the
1659               * mouse motion.               * mouse motion.
1660               */               */
1661    
1662              tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX)              tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX)
1663                      - canvasPtr->scrollX1;                      - canvasPtr->scrollX1;
1664              newXOrigin = canvasPtr->scrollX1 + tmp;              newXOrigin = canvasPtr->scrollX1 + tmp;
1665              tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY)              tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY)
1666                      - canvasPtr->scrollY1;                      - canvasPtr->scrollY1;
1667              newYOrigin = canvasPtr->scrollY1 + tmp;              newYOrigin = canvasPtr->scrollY1 + tmp;
1668              CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);              CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
1669          }          }
1670          break;          break;
1671        }        }
1672        case CANV_SELECT: {        case CANV_SELECT: {
1673          int index, optionindex;          int index, optionindex;
1674          static char *optionStrings[] = {          static char *optionStrings[] = {
1675              "adjust", "clear", "from", "item", "to", NULL              "adjust", "clear", "from", "item", "to", NULL
1676          };          };
1677          enum options {          enum options {
1678              CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO              CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO
1679          };          };
1680    
1681          if (argc < 3) {          if (argc < 3) {
1682              Tcl_WrongNumArgs(interp, 2, argv, "option ?tagOrId? ?arg?");              Tcl_WrongNumArgs(interp, 2, argv, "option ?tagOrId? ?arg?");
1683              result = TCL_ERROR;              result = TCL_ERROR;
1684              goto done;              goto done;
1685          }          }
1686          if (argc >= 4) {          if (argc >= 4) {
1687  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1688              for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);              for (itemPtr = StartTagSearch(canvasPtr, argv[3], &search);
1689                      itemPtr != NULL; itemPtr = NextItem(&search)) {                      itemPtr != NULL; itemPtr = NextItem(&search)) {
1690  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1691              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {              if ((result = TagSearchScan(canvasPtr, argv[3], &searchPtr)) != TCL_OK) {
1692                  goto done;                  goto done;
1693              }              }
1694              for (itemPtr = TagSearchFirst(searchPtr);              for (itemPtr = TagSearchFirst(searchPtr);
1695                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {                      itemPtr != NULL; itemPtr = TagSearchNext(searchPtr)) {
1696  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1697                  if ((itemPtr->typePtr->indexProc != NULL)                  if ((itemPtr->typePtr->indexProc != NULL)
1698                          && (itemPtr->typePtr->selectionProc != NULL)){                          && (itemPtr->typePtr->selectionProc != NULL)){
1699                      break;                      break;
1700                  }                  }
1701              }              }
1702              if (itemPtr == NULL) {              if (itemPtr == NULL) {
1703                  Tcl_AppendResult(interp,                  Tcl_AppendResult(interp,
1704                          "can't find an indexable and selectable item \"",                          "can't find an indexable and selectable item \"",
1705                          Tcl_GetStringFromObj(argv[3], NULL), "\"", (char *) NULL);                          Tcl_GetStringFromObj(argv[3], NULL), "\"", (char *) NULL);
1706                  result = TCL_ERROR;                  result = TCL_ERROR;
1707                  goto done;                  goto done;
1708              }              }
1709          }          }
1710          if (argc == 5) {          if (argc == 5) {
1711              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {              if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
1712                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1713                          itemPtr, (char *) argv[4], &index);                          itemPtr, (char *) argv[4], &index);
1714              } else {              } else {
1715                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,                  result = itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
1716                          itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &index);                          itemPtr, Tcl_GetStringFromObj(argv[4], NULL), &index);
1717              }              }
1718              if (result != TCL_OK) {              if (result != TCL_OK) {
1719                  goto done;                  goto done;
1720              }              }
1721          }          }
1722          if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "select option", 0,          if (Tcl_GetIndexFromObj(interp, argv[2], optionStrings, "select option", 0,
1723                  &optionindex) != TCL_OK) {                  &optionindex) != TCL_OK) {
1724              return TCL_ERROR;              return TCL_ERROR;
1725          }          }
1726          switch ((enum options) optionindex) {          switch ((enum options) optionindex) {
1727            case CANV_ADJUST: {            case CANV_ADJUST: {
1728              if (argc != 5) {              if (argc != 5) {
1729                  Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index");                  Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index");
1730                  result = TCL_ERROR;                  result = TCL_ERROR;
1731                  goto done;                  goto done;
1732              }              }
1733              if (canvasPtr->textInfo.selItemPtr == itemPtr) {              if (canvasPtr->textInfo.selItemPtr == itemPtr) {
1734                  if (index < (canvasPtr->textInfo.selectFirst                  if (index < (canvasPtr->textInfo.selectFirst
1735                          + canvasPtr->textInfo.selectLast)/2) {                          + canvasPtr->textInfo.selectLast)/2) {
1736                      canvasPtr->textInfo.selectAnchor =                      canvasPtr->textInfo.selectAnchor =
1737                              canvasPtr->textInfo.selectLast + 1;                              canvasPtr->textInfo.selectLast + 1;
1738                  } else {                  } else {
1739                      canvasPtr->textInfo.selectAnchor =                      canvasPtr->textInfo.selectAnchor =
1740                              canvasPtr->textInfo.selectFirst;                              canvasPtr->textInfo.selectFirst;
1741                  }                  }
1742              }              }
1743              CanvasSelectTo(canvasPtr, itemPtr, index);              CanvasSelectTo(canvasPtr, itemPtr, index);
1744              break;              break;
1745            }            }
1746            case CANV_CLEAR: {            case CANV_CLEAR: {
1747              if (argc != 3) {              if (argc != 3) {
1748                  Tcl_AppendResult(interp, 3, argv, (char *) NULL);                  Tcl_AppendResult(interp, 3, argv, (char *) NULL);
1749                  result = TCL_ERROR;                  result = TCL_ERROR;
1750                  goto done;                  goto done;
1751              }              }
1752              if (canvasPtr->textInfo.selItemPtr != NULL) {              if (canvasPtr->textInfo.selItemPtr != NULL) {
1753                  EventuallyRedrawItem((Tk_Canvas) canvasPtr,                  EventuallyRedrawItem((Tk_Canvas) canvasPtr,
1754                          canvasPtr->textInfo.selItemPtr);                          canvasPtr->textInfo.selItemPtr);
1755                  canvasPtr->textInfo.selItemPtr = NULL;                  canvasPtr->textInfo.selItemPtr = NULL;
1756              }              }
1757              goto done;              goto done;
1758              break;              break;
1759            }            }
1760            case CANV_FROM: {            case CANV_FROM: {
1761              if (argc != 5) {              if (argc != 5) {
1762                  Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index");                  Tcl_WrongNumArgs(interp, 3, argv, "tagOrId index");
1763                  result = TCL_ERROR;                  result = TCL_ERROR;
1764                  goto done;                  goto done;
1765              }              }
1766              canvasPtr->textInfo.anchorItemPtr = itemPtr;              canvasPtr->textInfo.anchorItemPtr = itemPtr;
1767              canvasPtr->textInfo.selectAnchor = index;              canvasPtr->textInfo.selectAnchor = index;
1768              break;              break;
1769            }            }
1770            case CANV_ITEM: {            case CANV_ITEM: {
1771              if (argc != 3) {              if (argc != 3) {
1772                  Tcl_WrongNumArgs(interp, 3, argv, (char *) NULL);                  Tcl_WrongNumArgs(interp, 3, argv, (char *) NULL);
1773                  result = TCL_ERROR;                  result = TCL_ERROR;
1774                  goto done;                  goto done;
1775              }              }
1776              if (canvasPtr->textInfo.selItemPtr != NULL) {              if (canvasPtr->textInfo.selItemPtr != NULL) {
1777                  char buf[TCL_INTEGER_SPACE];                  char buf[TCL_INTEGER_SPACE];
1778                                    
1779                  sprintf(buf, "%d", canvasPtr->textInfo.selItemPtr->id);                  sprintf(buf, "%d", canvasPtr->textInfo.selItemPtr->id);
1780                  Tcl_SetResult(interp, buf, TCL_VOLATILE);                  Tcl_SetResult(interp, buf, TCL_VOLATILE);
1781              }              }
1782              break;              break;
1783            }            }
1784            case CANV_TO: {            case CANV_TO: {
1785              if (argc != 5) {              if (argc != 5) {
1786                  Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index");                  Tcl_WrongNumArgs(interp, 2, argv, "tagOrId index");
1787                  result = TCL_ERROR;                  result = TCL_ERROR;
1788                  goto done;                  goto done;
1789              }              }
1790              CanvasSelectTo(canvasPtr, itemPtr, index);              CanvasSelectTo(canvasPtr, itemPtr, index);
1791              break;              break;
1792            }            }
1793          }          }
1794          break;          break;
1795        }        }
1796        case CANV_TYPE: {        case CANV_TYPE: {
1797          if (argc != 3) {          if (argc != 3) {
1798              Tcl_WrongNumArgs(interp, 2, argv, "tag");              Tcl_WrongNumArgs(interp, 2, argv, "tag");
1799              result = TCL_ERROR;              result = TCL_ERROR;
1800              goto done;              goto done;
1801          }          }
1802  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
1803          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);          itemPtr = StartTagSearch(canvasPtr, argv[2], &search);
1804  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
1805          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {          if ((result = TagSearchScan(canvasPtr, argv[2], &searchPtr)) != TCL_OK) {
1806              goto done;              goto done;
1807          }          }
1808          itemPtr = TagSearchFirst(searchPtr);          itemPtr = TagSearchFirst(searchPtr);
1809  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
1810          if (itemPtr != NULL) {          if (itemPtr != NULL) {
1811              Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC);              Tcl_SetResult(interp, itemPtr->typePtr->name, TCL_STATIC);
1812          }          }
1813          break;          break;
1814        }        }
1815        case CANV_XVIEW: {        case CANV_XVIEW: {
1816          int count, type;          int count, type;
1817          int newX = 0;           /* Initialization needed only to prevent          int newX = 0;           /* Initialization needed only to prevent
1818                                   * gcc warnings. */                                   * gcc warnings. */
1819          double fraction;          double fraction;
1820    
1821          if (argc == 2) {          if (argc == 2) {
1822              PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset,              PrintScrollFractions(canvasPtr->xOrigin + canvasPtr->inset,
1823                      canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)                      canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
1824                      - canvasPtr->inset, canvasPtr->scrollX1,                      - canvasPtr->inset, canvasPtr->scrollX1,
1825                      canvasPtr->scrollX2, Tcl_GetStringResult(interp));                      canvasPtr->scrollX2, Tcl_GetStringResult(interp));
1826          } else {          } else {
1827              char **args = GetStringsFromObjs(argc, argv);              char **args = GetStringsFromObjs(argc, argv);
1828              type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count);              type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count);
1829              if (args) ckfree((char *) args);              if (args) ckfree((char *) args);
1830              switch (type) {              switch (type) {
1831                  case TK_SCROLL_ERROR:                  case TK_SCROLL_ERROR:
1832                      result = TCL_ERROR;                      result = TCL_ERROR;
1833                      goto done;                      goto done;
1834                  case TK_SCROLL_MOVETO:                  case TK_SCROLL_MOVETO:
1835                      newX = canvasPtr->scrollX1 - canvasPtr->inset                      newX = canvasPtr->scrollX1 - canvasPtr->inset
1836                              + (int) (fraction * (canvasPtr->scrollX2                              + (int) (fraction * (canvasPtr->scrollX2
1837                              - canvasPtr->scrollX1) + 0.5);                              - canvasPtr->scrollX1) + 0.5);
1838                      break;                      break;
1839                  case TK_SCROLL_PAGES:                  case TK_SCROLL_PAGES:
1840                      newX = (int) (canvasPtr->xOrigin + count * .9                      newX = (int) (canvasPtr->xOrigin + count * .9
1841                              * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));                              * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
1842                      break;                      break;
1843                  case TK_SCROLL_UNITS:                  case TK_SCROLL_UNITS:
1844                      if (canvasPtr->xScrollIncrement > 0) {                      if (canvasPtr->xScrollIncrement > 0) {
1845                          newX = canvasPtr->xOrigin                          newX = canvasPtr->xOrigin
1846                                  + count*canvasPtr->xScrollIncrement;                                  + count*canvasPtr->xScrollIncrement;
1847                      } else {                      } else {
1848                          newX = (int) (canvasPtr->xOrigin + count * .1                          newX = (int) (canvasPtr->xOrigin + count * .1
1849                                  * (Tk_Width(canvasPtr->tkwin)                                  * (Tk_Width(canvasPtr->tkwin)
1850                                  - 2*canvasPtr->inset));                                  - 2*canvasPtr->inset));
1851                      }                      }
1852                      break;                      break;
1853              }              }
1854              CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);              CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
1855          }          }
1856          break;          break;
1857        }        }
1858        case CANV_YVIEW: {        case CANV_YVIEW: {
1859          int count, type;          int count, type;
1860          int newY = 0;           /* Initialization needed only to prevent          int newY = 0;           /* Initialization needed only to prevent
1861                                   * gcc warnings. */                                   * gcc warnings. */
1862          double fraction;          double fraction;
1863    
1864          if (argc == 2) {          if (argc == 2) {
1865              PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset,              PrintScrollFractions(canvasPtr->yOrigin + canvasPtr->inset,
1866                      canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)                      canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
1867                      - canvasPtr->inset, canvasPtr->scrollY1,                      - canvasPtr->inset, canvasPtr->scrollY1,
1868                      canvasPtr->scrollY2, Tcl_GetStringResult(interp));                      canvasPtr->scrollY2, Tcl_GetStringResult(interp));
1869          } else {          } else {
1870              char **args = GetStringsFromObjs(argc, argv);              char **args = GetStringsFromObjs(argc, argv);
1871              type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count);              type = Tk_GetScrollInfo(interp, argc, args, &fraction, &count);
1872              if (args) ckfree((char *) args);              if (args) ckfree((char *) args);
1873              switch (type) {              switch (type) {
1874                  case TK_SCROLL_ERROR:                  case TK_SCROLL_ERROR:
1875                      result = TCL_ERROR;                      result = TCL_ERROR;
1876                      goto done;                      goto done;
1877                  case TK_SCROLL_MOVETO:                  case TK_SCROLL_MOVETO:
1878                      newY = canvasPtr->scrollY1 - canvasPtr->inset                      newY = canvasPtr->scrollY1 - canvasPtr->inset
1879                              + (int) (fraction*(canvasPtr->scrollY2                              + (int) (fraction*(canvasPtr->scrollY2
1880                              - canvasPtr->scrollY1) + 0.5);                              - canvasPtr->scrollY1) + 0.5);
1881                      break;                      break;
1882                  case TK_SCROLL_PAGES:                  case TK_SCROLL_PAGES:
1883                      newY = (int) (canvasPtr->yOrigin + count * .9                      newY = (int) (canvasPtr->yOrigin + count * .9
1884                              * (Tk_Height(canvasPtr->tkwin)                              * (Tk_Height(canvasPtr->tkwin)
1885                              - 2*canvasPtr->inset));                              - 2*canvasPtr->inset));
1886                      break;                      break;
1887                  case TK_SCROLL_UNITS:                  case TK_SCROLL_UNITS:
1888                      if (canvasPtr->yScrollIncrement > 0) {                      if (canvasPtr->yScrollIncrement > 0) {
1889                          newY = canvasPtr->yOrigin                          newY = canvasPtr->yOrigin
1890                                  + count*canvasPtr->yScrollIncrement;                                  + count*canvasPtr->yScrollIncrement;
1891                      } else {                      } else {
1892                          newY = (int) (canvasPtr->yOrigin + count * .1                          newY = (int) (canvasPtr->yOrigin + count * .1
1893                                  * (Tk_Height(canvasPtr->tkwin)                                  * (Tk_Height(canvasPtr->tkwin)
1894                                  - 2*canvasPtr->inset));                                  - 2*canvasPtr->inset));
1895                      }                      }
1896                      break;                      break;
1897              }              }
1898              CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);              CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
1899          }          }
1900          break;          break;
1901        }        }
1902      }      }
1903      done:      done:
1904  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
1905      TagSearchDestroy(searchPtr);      TagSearchDestroy(searchPtr);
1906  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
1907      Tcl_Release((ClientData) canvasPtr);      Tcl_Release((ClientData) canvasPtr);
1908      return result;      return result;
1909  }  }
1910    
1911  /*  /*
1912   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1913   *   *
1914   * DestroyCanvas --   * DestroyCanvas --
1915   *   *
1916   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release   *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
1917   *      to clean up the internal structure of a canvas at a safe time   *      to clean up the internal structure of a canvas at a safe time
1918   *      (when no-one is using it anymore).   *      (when no-one is using it anymore).
1919   *   *
1920   * Results:   * Results:
1921   *      None.   *      None.
1922   *   *
1923   * Side effects:   * Side effects:
1924   *      Everything associated with the canvas is freed up.   *      Everything associated with the canvas is freed up.
1925   *   *
1926   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1927   */   */
1928    
1929  static void  static void
1930  DestroyCanvas(memPtr)  DestroyCanvas(memPtr)
1931      char *memPtr;               /* Info about canvas widget. */      char *memPtr;               /* Info about canvas widget. */
1932  {  {
1933      TkCanvas *canvasPtr = (TkCanvas *) memPtr;      TkCanvas *canvasPtr = (TkCanvas *) memPtr;
1934      Tk_Item *itemPtr;      Tk_Item *itemPtr;
1935    
1936      if (canvasPtr->tkwin != NULL) {      if (canvasPtr->tkwin != NULL) {
1937          Tcl_DeleteCommandFromToken(canvasPtr->interp, canvasPtr->widgetCmd);          Tcl_DeleteCommandFromToken(canvasPtr->interp, canvasPtr->widgetCmd);
1938      }      }
1939      if (canvasPtr->flags & REDRAW_PENDING) {      if (canvasPtr->flags & REDRAW_PENDING) {
1940          Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);          Tcl_CancelIdleCall(DisplayCanvas, (ClientData) canvasPtr);
1941      }      }
1942                    
1943      /*      /*
1944       * Free up all of the items in the canvas.       * Free up all of the items in the canvas.
1945       */       */
1946    
1947      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
1948              itemPtr = canvasPtr->firstItemPtr) {              itemPtr = canvasPtr->firstItemPtr) {
1949          canvasPtr->firstItemPtr = itemPtr->nextPtr;          canvasPtr->firstItemPtr = itemPtr->nextPtr;
1950          (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,          (*itemPtr->typePtr->deleteProc)((Tk_Canvas) canvasPtr, itemPtr,
1951                  canvasPtr->display);                  canvasPtr->display);
1952          if (itemPtr->tagPtr != itemPtr->staticTagSpace) {          if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
1953              ckfree((char *) itemPtr->tagPtr);              ckfree((char *) itemPtr->tagPtr);
1954          }          }
1955          ckfree((char *) itemPtr);          ckfree((char *) itemPtr);
1956      }      }
1957    
1958      /*      /*
1959       * Free up all the stuff that requires special handling,       * Free up all the stuff that requires special handling,
1960       * then let Tk_FreeOptions handle all the standard option-related       * then let Tk_FreeOptions handle all the standard option-related
1961       * stuff.       * stuff.
1962       */       */
1963    
1964      Tcl_DeleteHashTable(&canvasPtr->idTable);      Tcl_DeleteHashTable(&canvasPtr->idTable);
1965      if (canvasPtr->pixmapGC != None) {      if (canvasPtr->pixmapGC != None) {
1966          Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);          Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
1967      }      }
1968  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
1969      {      {
1970          TagSearchExpr *expr, *next;          TagSearchExpr *expr, *next;
1971    
1972          expr = canvasPtr->bindTagExprs;          expr = canvasPtr->bindTagExprs;
1973          while (expr) {          while (expr) {
1974              next = expr->next;              next = expr->next;
1975              TagSearchExprDestroy(expr);              TagSearchExprDestroy(expr);
1976              expr = next;              expr = next;
1977          }          }
1978      }      }
1979  #endif  #endif
1980      Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);      Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
1981      if (canvasPtr->bindingTable != NULL) {      if (canvasPtr->bindingTable != NULL) {
1982          Tk_DeleteBindingTable(canvasPtr->bindingTable);          Tk_DeleteBindingTable(canvasPtr->bindingTable);
1983      }      }
1984      Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);      Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
1985      canvasPtr->tkwin = NULL;      canvasPtr->tkwin = NULL;
1986      ckfree((char *) canvasPtr);      ckfree((char *) canvasPtr);
1987  }  }
1988    
1989  /*  /*
1990   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1991   *   *
1992   * ConfigureCanvas --   * ConfigureCanvas --
1993   *   *
1994   *      This procedure is called to process an argv/argc list, plus   *      This procedure is called to process an argv/argc list, plus
1995   *      the Tk option database, in order to configure (or   *      the Tk option database, in order to configure (or
1996   *      reconfigure) a canvas widget.   *      reconfigure) a canvas widget.
1997   *   *
1998   * Results:   * Results:
1999   *      The return value is a standard Tcl result.  If TCL_ERROR is   *      The return value is a standard Tcl result.  If TCL_ERROR is
2000   *      returned, then the interp's result contains an error message.   *      returned, then the interp's result contains an error message.
2001   *   *
2002   * Side effects:   * Side effects:
2003   *      Configuration information, such as colors, border width,   *      Configuration information, such as colors, border width,
2004   *      etc. get set for canvasPtr;  old resources get freed,   *      etc. get set for canvasPtr;  old resources get freed,
2005   *      if there were any.   *      if there were any.
2006   *   *
2007   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2008   */   */
2009    
2010  static int  static int
2011  ConfigureCanvas(interp, canvasPtr, argc, argv, flags)  ConfigureCanvas(interp, canvasPtr, argc, argv, flags)
2012      Tcl_Interp *interp;         /* Used for error reporting. */      Tcl_Interp *interp;         /* Used for error reporting. */
2013      TkCanvas *canvasPtr;        /* Information about widget;  may or may      TkCanvas *canvasPtr;        /* Information about widget;  may or may
2014                                   * not already have values for some fields. */                                   * not already have values for some fields. */
2015      int argc;                   /* Number of valid entries in argv. */      int argc;                   /* Number of valid entries in argv. */
2016      Tcl_Obj *CONST argv[];      /* Argument objects. */      Tcl_Obj *CONST argv[];      /* Argument objects. */
2017      int flags;                  /* Flags to pass to Tk_ConfigureWidget. */      int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
2018  {  {
2019      XGCValues gcValues;      XGCValues gcValues;
2020      GC new;      GC new;
2021    
2022      if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,      if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
2023              argc, (char **) argv, (char *) canvasPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {              argc, (char **) argv, (char *) canvasPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
2024          return TCL_ERROR;          return TCL_ERROR;
2025      }      }
2026    
2027      /*      /*
2028       * A few options need special processing, such as setting the       * A few options need special processing, such as setting the
2029       * background from a 3-D border and creating a GC for copying       * background from a 3-D border and creating a GC for copying
2030       * bits to the screen.       * bits to the screen.
2031       */       */
2032    
2033      Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);      Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
2034    
2035      if (canvasPtr->highlightWidth < 0) {      if (canvasPtr->highlightWidth < 0) {
2036          canvasPtr->highlightWidth = 0;          canvasPtr->highlightWidth = 0;
2037      }      }
2038      canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;      canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
2039    
2040      gcValues.function = GXcopy;      gcValues.function = GXcopy;
2041      gcValues.graphics_exposures = False;      gcValues.graphics_exposures = False;
2042      gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;      gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
2043      new = Tk_GetGC(canvasPtr->tkwin,      new = Tk_GetGC(canvasPtr->tkwin,
2044              GCFunction|GCGraphicsExposures|GCForeground, &gcValues);              GCFunction|GCGraphicsExposures|GCForeground, &gcValues);
2045      if (canvasPtr->pixmapGC != None) {      if (canvasPtr->pixmapGC != None) {
2046          Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);          Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
2047      }      }
2048      canvasPtr->pixmapGC = new;      canvasPtr->pixmapGC = new;
2049    
2050      /*      /*
2051       * Reset the desired dimensions for the window.       * Reset the desired dimensions for the window.
2052       */       */
2053    
2054      Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,      Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
2055              canvasPtr->height + 2*canvasPtr->inset);              canvasPtr->height + 2*canvasPtr->inset);
2056    
2057      /*      /*
2058       * Restart the cursor timing sequence in case the on-time or off-time       * Restart the cursor timing sequence in case the on-time or off-time
2059       * just changed.       * just changed.
2060       */       */
2061    
2062      if (canvasPtr->textInfo.gotFocus) {      if (canvasPtr->textInfo.gotFocus) {
2063          CanvasFocusProc(canvasPtr, 1);          CanvasFocusProc(canvasPtr, 1);
2064      }      }
2065    
2066      /*      /*
2067       * Recompute the scroll region.       * Recompute the scroll region.
2068       */       */
2069    
2070      canvasPtr->scrollX1 = 0;      canvasPtr->scrollX1 = 0;
2071      canvasPtr->scrollY1 = 0;      canvasPtr->scrollY1 = 0;
2072      canvasPtr->scrollX2 = 0;      canvasPtr->scrollX2 = 0;
2073      canvasPtr->scrollY2 = 0;      canvasPtr->scrollY2 = 0;
2074      if (canvasPtr->regionString != NULL) {      if (canvasPtr->regionString != NULL) {
2075          int argc2;          int argc2;
2076          char **argv2;          char **argv2;
2077    
2078          if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,          if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
2079                  &argc2, &argv2) != TCL_OK) {                  &argc2, &argv2) != TCL_OK) {
2080              return TCL_ERROR;              return TCL_ERROR;
2081          }          }
2082          if (argc2 != 4) {          if (argc2 != 4) {
2083              Tcl_AppendResult(interp, "bad scrollRegion \"",              Tcl_AppendResult(interp, "bad scrollRegion \"",
2084                      canvasPtr->regionString, "\"", (char *) NULL);                      canvasPtr->regionString, "\"", (char *) NULL);
2085              badRegion:              badRegion:
2086              ckfree(canvasPtr->regionString);              ckfree(canvasPtr->regionString);
2087              ckfree((char *) argv2);              ckfree((char *) argv2);
2088              canvasPtr->regionString = NULL;              canvasPtr->regionString = NULL;
2089              return TCL_ERROR;              return TCL_ERROR;
2090          }          }
2091          if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,          if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
2092                      argv2[0], &canvasPtr->scrollX1) != TCL_OK)                      argv2[0], &canvasPtr->scrollX1) != TCL_OK)
2093                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
2094                      argv2[1], &canvasPtr->scrollY1) != TCL_OK)                      argv2[1], &canvasPtr->scrollY1) != TCL_OK)
2095                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
2096                      argv2[2], &canvasPtr->scrollX2) != TCL_OK)                      argv2[2], &canvasPtr->scrollX2) != TCL_OK)
2097                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,                  || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
2098                      argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {                      argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
2099              goto badRegion;              goto badRegion;
2100          }          }
2101          ckfree((char *) argv2);          ckfree((char *) argv2);
2102      }      }
2103    
2104      flags = canvasPtr->tsoffset.flags;      flags = canvasPtr->tsoffset.flags;
2105      if (flags & TK_OFFSET_LEFT) {      if (flags & TK_OFFSET_LEFT) {
2106          canvasPtr->tsoffset.xoffset = 0;          canvasPtr->tsoffset.xoffset = 0;
2107      } else if (flags & TK_OFFSET_CENTER) {      } else if (flags & TK_OFFSET_CENTER) {
2108          canvasPtr->tsoffset.xoffset = canvasPtr->width/2;          canvasPtr->tsoffset.xoffset = canvasPtr->width/2;
2109      } else if (flags & TK_OFFSET_RIGHT) {      } else if (flags & TK_OFFSET_RIGHT) {
2110          canvasPtr->tsoffset.xoffset = canvasPtr->width;          canvasPtr->tsoffset.xoffset = canvasPtr->width;
2111      }      }
2112      if (flags & TK_OFFSET_TOP) {      if (flags & TK_OFFSET_TOP) {
2113          canvasPtr->tsoffset.yoffset = 0;          canvasPtr->tsoffset.yoffset = 0;
2114      } else if (flags & TK_OFFSET_MIDDLE) {      } else if (flags & TK_OFFSET_MIDDLE) {
2115          canvasPtr->tsoffset.yoffset = canvasPtr->height/2;          canvasPtr->tsoffset.yoffset = canvasPtr->height/2;
2116      } else if (flags & TK_OFFSET_BOTTOM) {      } else if (flags & TK_OFFSET_BOTTOM) {
2117          canvasPtr->tsoffset.yoffset = canvasPtr->height;          canvasPtr->tsoffset.yoffset = canvasPtr->height;
2118      }      }
2119    
2120      /*      /*
2121       * Reset the canvas's origin (this is a no-op unless confine       * Reset the canvas's origin (this is a no-op unless confine
2122       * mode has just been turned on or the scroll region has changed).       * mode has just been turned on or the scroll region has changed).
2123       */       */
2124    
2125      CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);      CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
2126      canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;      canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
2127      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
2128              canvasPtr->xOrigin, canvasPtr->yOrigin,              canvasPtr->xOrigin, canvasPtr->yOrigin,
2129              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
2130              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
2131      return TCL_OK;      return TCL_OK;
2132  }  }
2133    
2134  /*  /*
2135   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2136   *   *
2137   * CanvasWorldChanged --   * CanvasWorldChanged --
2138   *   *
2139   *      This procedure is called when the world has changed in some   *      This procedure is called when the world has changed in some
2140   *      way and the widget needs to recompute all its graphics contexts   *      way and the widget needs to recompute all its graphics contexts
2141   *      and determine its new geometry.   *      and determine its new geometry.
2142   *   *
2143   * Results:   * Results:
2144   *      None.   *      None.
2145   *   *
2146   * Side effects:   * Side effects:
2147   *      Configures all items in the canvas with a empty argc/argv, for   *      Configures all items in the canvas with a empty argc/argv, for
2148   *      the side effect of causing all the items to recompute their   *      the side effect of causing all the items to recompute their
2149   *      geometry and to be redisplayed.   *      geometry and to be redisplayed.
2150   *   *
2151   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
2152   */   */
2153    
2154  static void  static void
2155  CanvasWorldChanged(instanceData)  CanvasWorldChanged(instanceData)
2156      ClientData instanceData;    /* Information about widget. */      ClientData instanceData;    /* Information about widget. */
2157  {  {
2158      TkCanvas *canvasPtr;      TkCanvas *canvasPtr;
2159      Tk_Item *itemPtr;      Tk_Item *itemPtr;
2160      int result;      int result;
2161    
2162      canvasPtr = (TkCanvas *) instanceData;      canvasPtr = (TkCanvas *) instanceData;
2163      itemPtr = canvasPtr->firstItemPtr;      itemPtr = canvasPtr->firstItemPtr;
2164      for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {      for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
2165          result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,          result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,
2166                  (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,                  (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
2167                  TK_CONFIG_ARGV_ONLY);                  TK_CONFIG_ARGV_ONLY);
2168          if (result != TCL_OK) {          if (result != TCL_OK) {
2169              Tcl_ResetResult(canvasPtr->interp);              Tcl_ResetResult(canvasPtr->interp);
2170          }          }
2171      }      }
2172      canvasPtr->flags |= REPICK_NEEDED;      canvasPtr->flags |= REPICK_NEEDED;
2173      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
2174              canvasPtr->xOrigin, canvasPtr->yOrigin,              canvasPtr->xOrigin, canvasPtr->yOrigin,
2175              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
2176              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
2177  }  }
2178    
2179  /*  /*
2180   *--------------------------------------------------------------   *--------------------------------------------------------------
2181   *   *
2182   * DisplayCanvas --   * DisplayCanvas --
2183   *   *
2184   *      This procedure redraws the contents of a canvas window.   *      This procedure redraws the contents of a canvas window.
2185   *      It is invoked as a do-when-idle handler, so it only runs   *      It is invoked as a do-when-idle handler, so it only runs
2186   *      when there's nothing else for the application to do.   *      when there's nothing else for the application to do.
2187   *   *
2188   * Results:   * Results:
2189   *      None.   *      None.
2190   *   *
2191   * Side effects:   * Side effects:
2192   *      Information appears on the screen.   *      Information appears on the screen.
2193   *   *
2194   *--------------------------------------------------------------   *--------------------------------------------------------------
2195   */   */
2196    
2197  static void  static void
2198  DisplayCanvas(clientData)  DisplayCanvas(clientData)
2199      ClientData clientData;      /* Information about widget. */      ClientData clientData;      /* Information about widget. */
2200  {  {
2201      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
2202      Tk_Window tkwin = canvasPtr->tkwin;      Tk_Window tkwin = canvasPtr->tkwin;
2203      Tk_Item *itemPtr;      Tk_Item *itemPtr;
2204      Pixmap pixmap;      Pixmap pixmap;
2205      int screenX1, screenX2, screenY1, screenY2, width, height;      int screenX1, screenX2, screenY1, screenY2, width, height;
2206    
2207      if (canvasPtr->tkwin == NULL) {      if (canvasPtr->tkwin == NULL) {
2208          return;          return;
2209      }      }
2210    
2211      if (!Tk_IsMapped(tkwin)) {      if (!Tk_IsMapped(tkwin)) {
2212          goto done;          goto done;
2213      }      }
2214    
2215      /*      /*
2216       * Choose a new current item if that is needed (this could cause       * Choose a new current item if that is needed (this could cause
2217       * event handlers to be invoked).       * event handlers to be invoked).
2218       */       */
2219    
2220      while (canvasPtr->flags & REPICK_NEEDED) {      while (canvasPtr->flags & REPICK_NEEDED) {
2221          Tcl_Preserve((ClientData) canvasPtr);          Tcl_Preserve((ClientData) canvasPtr);
2222          canvasPtr->flags &= ~REPICK_NEEDED;          canvasPtr->flags &= ~REPICK_NEEDED;
2223          PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);          PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
2224          tkwin = canvasPtr->tkwin;          tkwin = canvasPtr->tkwin;
2225          Tcl_Release((ClientData) canvasPtr);          Tcl_Release((ClientData) canvasPtr);
2226          if (tkwin == NULL) {          if (tkwin == NULL) {
2227              return;              return;
2228          }          }
2229      }      }
2230    
2231      /*      /*
2232       * Scan through the item list, registering the bounding box       * Scan through the item list, registering the bounding box
2233       * for all items that didn't do that for the final coordinates       * for all items that didn't do that for the final coordinates
2234       * yet. This can be determined by the FORCE_REDRAW flag.       * yet. This can be determined by the FORCE_REDRAW flag.
2235       */       */
2236    
2237      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
2238                  itemPtr = itemPtr->nextPtr) {                  itemPtr = itemPtr->nextPtr) {
2239          if (itemPtr->redraw_flags & FORCE_REDRAW) {          if (itemPtr->redraw_flags & FORCE_REDRAW) {
2240              itemPtr->redraw_flags &= ~FORCE_REDRAW;              itemPtr->redraw_flags &= ~FORCE_REDRAW;
2241              EventuallyRedrawItem((Tk_Canvas)canvasPtr, itemPtr);              EventuallyRedrawItem((Tk_Canvas)canvasPtr, itemPtr);
2242              itemPtr->redraw_flags &= ~FORCE_REDRAW;              itemPtr->redraw_flags &= ~FORCE_REDRAW;
2243          }          }
2244      }      }
2245      /*      /*
2246       * Compute the intersection between the area that needs redrawing       * Compute the intersection between the area that needs redrawing
2247       * and the area that's visible on the screen.       * and the area that's visible on the screen.
2248       */       */
2249    
2250      if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)      if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
2251              && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {              && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
2252          screenX1 = canvasPtr->xOrigin + canvasPtr->inset;          screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
2253          screenY1 = canvasPtr->yOrigin + canvasPtr->inset;          screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
2254          screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;          screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
2255          screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;          screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
2256          if (canvasPtr->redrawX1 > screenX1) {          if (canvasPtr->redrawX1 > screenX1) {
2257              screenX1 = canvasPtr->redrawX1;              screenX1 = canvasPtr->redrawX1;
2258          }          }
2259          if (canvasPtr->redrawY1 > screenY1) {          if (canvasPtr->redrawY1 > screenY1) {
2260              screenY1 = canvasPtr->redrawY1;              screenY1 = canvasPtr->redrawY1;
2261          }          }
2262          if (canvasPtr->redrawX2 < screenX2) {          if (canvasPtr->redrawX2 < screenX2) {
2263              screenX2 = canvasPtr->redrawX2;              screenX2 = canvasPtr->redrawX2;
2264          }          }
2265          if (canvasPtr->redrawY2 < screenY2) {          if (canvasPtr->redrawY2 < screenY2) {
2266              screenY2 = canvasPtr->redrawY2;              screenY2 = canvasPtr->redrawY2;
2267          }          }
2268          if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {          if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
2269              goto borders;              goto borders;
2270          }          }
2271            
2272          /*          /*
2273           * Redrawing is done in a temporary pixmap that is allocated           * Redrawing is done in a temporary pixmap that is allocated
2274           * here and freed at the end of the procedure.  All drawing           * here and freed at the end of the procedure.  All drawing
2275           * is done to the pixmap, and the pixmap is copied to the           * is done to the pixmap, and the pixmap is copied to the
2276           * screen at the end of the procedure. The temporary pixmap           * screen at the end of the procedure. The temporary pixmap
2277           * serves two purposes:           * serves two purposes:
2278           *           *
2279           * 1. It provides a smoother visual effect (no clearing and           * 1. It provides a smoother visual effect (no clearing and
2280           *    gradual redraw will be visible to users).           *    gradual redraw will be visible to users).
2281           * 2. It allows us to redraw only the objects that overlap           * 2. It allows us to redraw only the objects that overlap
2282           *    the redraw area.  Otherwise incorrect results could           *    the redraw area.  Otherwise incorrect results could
2283           *        occur from redrawing things that stick outside of           *        occur from redrawing things that stick outside of
2284           *        the redraw area (we'd have to redraw everything in           *        the redraw area (we'd have to redraw everything in
2285           *    order to make the overlaps look right).           *    order to make the overlaps look right).
2286           *           *
2287           * Some tricky points about the pixmap:           * Some tricky points about the pixmap:
2288           *           *
2289           * 1. We only allocate a large enough pixmap to hold the           * 1. We only allocate a large enough pixmap to hold the
2290           *    area that has to be redisplayed.  This saves time in           *    area that has to be redisplayed.  This saves time in
2291           *    in the X server for large objects that cover much           *    in the X server for large objects that cover much
2292           *    more than the area being redisplayed:  only the area           *    more than the area being redisplayed:  only the area
2293           *    of the pixmap will actually have to be redrawn.           *    of the pixmap will actually have to be redrawn.
2294           * 2. Some X servers (e.g. the one for DECstations) have troubles           * 2. Some X servers (e.g. the one for DECstations) have troubles
2295           *    with characters that overlap an edge of the pixmap (on the           *    with characters that overlap an edge of the pixmap (on the
2296           *    DEC servers, as of 8/18/92, such characters are drawn one           *    DEC servers, as of 8/18/92, such characters are drawn one
2297           *    pixel too far to the right).  To handle this problem,           *    pixel too far to the right).  To handle this problem,
2298           *    make the pixmap a bit larger than is absolutely needed           *    make the pixmap a bit larger than is absolutely needed
2299           *    so that for normal-sized fonts the characters that overlap           *    so that for normal-sized fonts the characters that overlap
2300           *    the edge of the pixmap will be outside the area we care           *    the edge of the pixmap will be outside the area we care
2301           *    about.           *    about.
2302           */           */
2303            
2304          canvasPtr->drawableXOrigin = screenX1 - 30;          canvasPtr->drawableXOrigin = screenX1 - 30;
2305          canvasPtr->drawableYOrigin = screenY1 - 30;          canvasPtr->drawableYOrigin = screenY1 - 30;
2306          pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),          pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
2307              (screenX2 + 30 - canvasPtr->drawableXOrigin),              (screenX2 + 30 - canvasPtr->drawableXOrigin),
2308              (screenY2 + 30 - canvasPtr->drawableYOrigin),              (screenY2 + 30 - canvasPtr->drawableYOrigin),
2309              Tk_Depth(tkwin));              Tk_Depth(tkwin));
2310            
2311          /*          /*
2312           * Clear the area to be redrawn.           * Clear the area to be redrawn.
2313           */           */
2314            
2315          width = screenX2 - screenX1;          width = screenX2 - screenX1;
2316          height = screenY2 - screenY1;          height = screenY2 - screenY1;
2317            
2318          XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,          XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
2319                  screenX1 - canvasPtr->drawableXOrigin,                  screenX1 - canvasPtr->drawableXOrigin,
2320                  screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,                  screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
2321                  (unsigned int) height);                  (unsigned int) height);
2322            
2323          /*          /*
2324           * Scan through the item list, redrawing those items that need it.           * Scan through the item list, redrawing those items that need it.
2325           * An item must be redraw if either (a) it intersects the smaller           * An item must be redraw if either (a) it intersects the smaller
2326           * on-screen area or (b) it intersects the full canvas area and its           * on-screen area or (b) it intersects the full canvas area and its
2327           * type requests that it be redrawn always (e.g. so subwindows can           * type requests that it be redrawn always (e.g. so subwindows can
2328           * be unmapped when they move off-screen).           * be unmapped when they move off-screen).
2329           */           */
2330            
2331          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
2332                  itemPtr = itemPtr->nextPtr) {                  itemPtr = itemPtr->nextPtr) {
2333              if ((itemPtr->x1 >= screenX2)              if ((itemPtr->x1 >= screenX2)
2334                      || (itemPtr->y1 >= screenY2)                      || (itemPtr->y1 >= screenY2)
2335                      || (itemPtr->x2 < screenX1)                      || (itemPtr->x2 < screenX1)
2336                      || (itemPtr->y2 < screenY1)) {                      || (itemPtr->y2 < screenY1)) {
2337                  if (!(itemPtr->typePtr->alwaysRedraw & 1)                  if (!(itemPtr->typePtr->alwaysRedraw & 1)
2338                          || (itemPtr->x1 >= canvasPtr->redrawX2)                          || (itemPtr->x1 >= canvasPtr->redrawX2)
2339                          || (itemPtr->y1 >= canvasPtr->redrawY2)                          || (itemPtr->y1 >= canvasPtr->redrawY2)
2340                          || (itemPtr->x2 < canvasPtr->redrawX1)                          || (itemPtr->x2 < canvasPtr->redrawX1)
2341                          || (itemPtr->y2 < canvasPtr->redrawY1)) {                          || (itemPtr->y2 < canvasPtr->redrawY1)) {
2342                      continue;                      continue;
2343                  }                  }
2344              }              }
2345              if (itemPtr->state == TK_STATE_HIDDEN ||              if (itemPtr->state == TK_STATE_HIDDEN ||
2346                  (itemPtr->state == TK_STATE_NULL &&                  (itemPtr->state == TK_STATE_NULL &&
2347                   canvasPtr->canvas_state == TK_STATE_HIDDEN)) {                   canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
2348                  continue;                  continue;
2349              }              }
2350              (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,              (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr, itemPtr,
2351                      canvasPtr->display, pixmap, screenX1, screenY1, width,                      canvasPtr->display, pixmap, screenX1, screenY1, width,
2352                      height);                      height);
2353          }          }
2354            
2355          /*          /*
2356           * Copy from the temporary pixmap to the screen, then free up           * Copy from the temporary pixmap to the screen, then free up
2357           * the temporary pixmap.           * the temporary pixmap.
2358           */           */
2359            
2360          XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),          XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
2361                  canvasPtr->pixmapGC,                  canvasPtr->pixmapGC,
2362                  screenX1 - canvasPtr->drawableXOrigin,                  screenX1 - canvasPtr->drawableXOrigin,
2363                  screenY1 - canvasPtr->drawableYOrigin,                  screenY1 - canvasPtr->drawableYOrigin,
2364                  (unsigned) (screenX2 - screenX1),                  (unsigned) (screenX2 - screenX1),
2365                  (unsigned) (screenY2 - screenY1),                  (unsigned) (screenY2 - screenY1),
2366                  screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);                  screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
2367          Tk_FreePixmap(Tk_Display(tkwin), pixmap);          Tk_FreePixmap(Tk_Display(tkwin), pixmap);
2368      }      }
2369    
2370      /*      /*
2371       * Draw the window borders, if needed.       * Draw the window borders, if needed.
2372       */       */
2373    
2374      borders:      borders:
2375      if (canvasPtr->flags & REDRAW_BORDERS) {      if (canvasPtr->flags & REDRAW_BORDERS) {
2376          canvasPtr->flags &= ~REDRAW_BORDERS;          canvasPtr->flags &= ~REDRAW_BORDERS;
2377          if (canvasPtr->borderWidth > 0) {          if (canvasPtr->borderWidth > 0) {
2378              Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),              Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
2379                      canvasPtr->bgBorder, canvasPtr->highlightWidth,                      canvasPtr->bgBorder, canvasPtr->highlightWidth,
2380                      canvasPtr->highlightWidth,                      canvasPtr->highlightWidth,
2381                      Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,                      Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
2382                      Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,                      Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
2383                      canvasPtr->borderWidth, canvasPtr->relief);                      canvasPtr->borderWidth, canvasPtr->relief);
2384          }          }
2385          if (canvasPtr->highlightWidth != 0) {          if (canvasPtr->highlightWidth != 0) {
2386              GC fgGC, bgGC;              GC fgGC, bgGC;
2387    
2388              bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr,              bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
2389                      Tk_WindowId(tkwin));                      Tk_WindowId(tkwin));
2390              if (canvasPtr->textInfo.gotFocus) {              if (canvasPtr->textInfo.gotFocus) {
2391                  fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr,                  fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr,
2392                          Tk_WindowId(tkwin));                          Tk_WindowId(tkwin));
2393                  TkpDrawHighlightBorder(tkwin, fgGC, bgGC,                  TkpDrawHighlightBorder(tkwin, fgGC, bgGC,
2394                          canvasPtr->highlightWidth, Tk_WindowId(tkwin));                          canvasPtr->highlightWidth, Tk_WindowId(tkwin));
2395              } else {              } else {
2396                  TkpDrawHighlightBorder(tkwin, bgGC, bgGC,                  TkpDrawHighlightBorder(tkwin, bgGC, bgGC,
2397                          canvasPtr->highlightWidth, Tk_WindowId(tkwin));                          canvasPtr->highlightWidth, Tk_WindowId(tkwin));
2398              }              }
2399          }          }
2400      }      }
2401    
2402      done:      done:
2403      canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY);      canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY);
2404      canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;      canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
2405      canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;      canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
2406      if (canvasPtr->flags & UPDATE_SCROLLBARS) {      if (canvasPtr->flags & UPDATE_SCROLLBARS) {
2407          CanvasUpdateScrollbars(canvasPtr);          CanvasUpdateScrollbars(canvasPtr);
2408      }      }
2409  }  }
2410    
2411  /*  /*
2412   *--------------------------------------------------------------   *--------------------------------------------------------------
2413   *   *
2414   * CanvasEventProc --   * CanvasEventProc --
2415   *   *
2416   *      This procedure is invoked by the Tk dispatcher for various   *      This procedure is invoked by the Tk dispatcher for various
2417   *      events on canvases.   *      events on canvases.
2418   *   *
2419   * Results:   * Results:
2420   *      None.   *      None.
2421   *   *
2422   * Side effects:   * Side effects:
2423   *      When the window gets deleted, internal structures get   *      When the window gets deleted, internal structures get
2424   *      cleaned up.  When it gets exposed, it is redisplayed.   *      cleaned up.  When it gets exposed, it is redisplayed.
2425   *   *
2426   *--------------------------------------------------------------   *--------------------------------------------------------------
2427   */   */
2428    
2429  static void  static void
2430  CanvasEventProc(clientData, eventPtr)  CanvasEventProc(clientData, eventPtr)
2431      ClientData clientData;      /* Information about window. */      ClientData clientData;      /* Information about window. */
2432      XEvent *eventPtr;           /* Information about event. */      XEvent *eventPtr;           /* Information about event. */
2433  {  {
2434      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
2435    
2436      if (eventPtr->type == Expose) {      if (eventPtr->type == Expose) {
2437          int x, y;          int x, y;
2438    
2439          x = eventPtr->xexpose.x + canvasPtr->xOrigin;          x = eventPtr->xexpose.x + canvasPtr->xOrigin;
2440          y = eventPtr->xexpose.y + canvasPtr->yOrigin;          y = eventPtr->xexpose.y + canvasPtr->yOrigin;
2441          Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,          Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
2442                  x + eventPtr->xexpose.width,                  x + eventPtr->xexpose.width,
2443                  y + eventPtr->xexpose.height);                  y + eventPtr->xexpose.height);
2444          if ((eventPtr->xexpose.x < canvasPtr->inset)          if ((eventPtr->xexpose.x < canvasPtr->inset)
2445                  || (eventPtr->xexpose.y < canvasPtr->inset)                  || (eventPtr->xexpose.y < canvasPtr->inset)
2446                  || ((eventPtr->xexpose.x + eventPtr->xexpose.width)                  || ((eventPtr->xexpose.x + eventPtr->xexpose.width)
2447                      > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))                      > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
2448                  || ((eventPtr->xexpose.y + eventPtr->xexpose.height)                  || ((eventPtr->xexpose.y + eventPtr->xexpose.height)
2449                      > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {                      > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
2450              canvasPtr->flags |= REDRAW_BORDERS;              canvasPtr->flags |= REDRAW_BORDERS;
2451          }          }
2452      } else if (eventPtr->type == DestroyNotify) {      } else if (eventPtr->type == DestroyNotify) {
2453          DestroyCanvas((char *) canvasPtr);          DestroyCanvas((char *) canvasPtr);
2454      } else if (eventPtr->type == ConfigureNotify) {      } else if (eventPtr->type == ConfigureNotify) {
2455          canvasPtr->flags |= UPDATE_SCROLLBARS;          canvasPtr->flags |= UPDATE_SCROLLBARS;
2456    
2457          /*          /*
2458           * The call below is needed in order to recenter the canvas if           * The call below is needed in order to recenter the canvas if
2459           * it's confined and its scroll region is smaller than the window.           * it's confined and its scroll region is smaller than the window.
2460           */           */
2461    
2462          CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);          CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
2463          Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,          Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
2464                  canvasPtr->yOrigin,                  canvasPtr->yOrigin,
2465                  canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),                  canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
2466                  canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));                  canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
2467          canvasPtr->flags |= REDRAW_BORDERS;          canvasPtr->flags |= REDRAW_BORDERS;
2468      } else if (eventPtr->type == FocusIn) {      } else if (eventPtr->type == FocusIn) {
2469          if (eventPtr->xfocus.detail != NotifyInferior) {          if (eventPtr->xfocus.detail != NotifyInferior) {
2470              CanvasFocusProc(canvasPtr, 1);              CanvasFocusProc(canvasPtr, 1);
2471          }          }
2472      } else if (eventPtr->type == FocusOut) {      } else if (eventPtr->type == FocusOut) {
2473          if (eventPtr->xfocus.detail != NotifyInferior) {          if (eventPtr->xfocus.detail != NotifyInferior) {
2474              CanvasFocusProc(canvasPtr, 0);              CanvasFocusProc(canvasPtr, 0);
2475          }          }
2476      } else if (eventPtr->type == UnmapNotify) {      } else if (eventPtr->type == UnmapNotify) {
2477          Tk_Item *itemPtr;          Tk_Item *itemPtr;
2478    
2479          /*          /*
2480           * Special hack:  if the canvas is unmapped, then must notify           * Special hack:  if the canvas is unmapped, then must notify
2481           * all items with "alwaysRedraw" set, so that they know that           * all items with "alwaysRedraw" set, so that they know that
2482           * they are no longer displayed.           * they are no longer displayed.
2483           */           */
2484    
2485          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
2486                  itemPtr = itemPtr->nextPtr) {                  itemPtr = itemPtr->nextPtr) {
2487              if (itemPtr->typePtr->alwaysRedraw & 1) {              if (itemPtr->typePtr->alwaysRedraw & 1) {
2488                  (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,                  (*itemPtr->typePtr->displayProc)((Tk_Canvas) canvasPtr,
2489                          itemPtr, canvasPtr->display, None, 0, 0, 0, 0);                          itemPtr, canvasPtr->display, None, 0, 0, 0, 0);
2490              }              }
2491          }          }
2492      }      }
2493  }  }
2494    
2495  /*  /*
2496   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2497   *   *
2498   * CanvasCmdDeletedProc --   * CanvasCmdDeletedProc --
2499   *   *
2500   *      This procedure is invoked when a widget command is deleted.  If   *      This procedure is invoked when a widget command is deleted.  If
2501   *      the widget isn't already in the process of being destroyed,   *      the widget isn't already in the process of being destroyed,
2502   *      this command destroys it.   *      this command destroys it.
2503   *   *
2504   * Results:   * Results:
2505   *      None.   *      None.
2506   *   *
2507   * Side effects:   * Side effects:
2508   *      The widget is destroyed.   *      The widget is destroyed.
2509   *   *
2510   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2511   */   */
2512    
2513  static void  static void
2514  CanvasCmdDeletedProc(clientData)  CanvasCmdDeletedProc(clientData)
2515      ClientData clientData;      /* Pointer to widget record for widget. */      ClientData clientData;      /* Pointer to widget record for widget. */
2516  {  {
2517      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
2518      Tk_Window tkwin = canvasPtr->tkwin;      Tk_Window tkwin = canvasPtr->tkwin;
2519    
2520      /*      /*
2521       * This procedure could be invoked either because the window was       * This procedure could be invoked either because the window was
2522       * destroyed and the command was then deleted (in which case tkwin       * destroyed and the command was then deleted (in which case tkwin
2523       * is NULL) or because the command was deleted, and then this procedure       * is NULL) or because the command was deleted, and then this procedure
2524       * destroys the widget.       * destroys the widget.
2525       */       */
2526    
2527      if (tkwin != NULL) {      if (tkwin != NULL) {
2528          canvasPtr->tkwin = NULL;          canvasPtr->tkwin = NULL;
2529          Tk_DestroyWindow(tkwin);          Tk_DestroyWindow(tkwin);
2530      }      }
2531  }  }
2532    
2533  /*  /*
2534   *--------------------------------------------------------------   *--------------------------------------------------------------
2535   *   *
2536   * Tk_CanvasEventuallyRedraw --   * Tk_CanvasEventuallyRedraw --
2537   *   *
2538   *      Arrange for part or all of a canvas widget to redrawn at   *      Arrange for part or all of a canvas widget to redrawn at
2539   *      some convenient time in the future.   *      some convenient time in the future.
2540   *   *
2541   * Results:   * Results:
2542   *      None.   *      None.
2543   *   *
2544   * Side effects:   * Side effects:
2545   *      The screen will eventually be refreshed.   *      The screen will eventually be refreshed.
2546   *   *
2547   *--------------------------------------------------------------   *--------------------------------------------------------------
2548   */   */
2549    
2550  void  void
2551  Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)  Tk_CanvasEventuallyRedraw(canvas, x1, y1, x2, y2)
2552      Tk_Canvas canvas;           /* Information about widget. */      Tk_Canvas canvas;           /* Information about widget. */
2553      int x1, y1;                 /* Upper left corner of area to redraw.      int x1, y1;                 /* Upper left corner of area to redraw.
2554                                   * Pixels on edge are redrawn. */                                   * Pixels on edge are redrawn. */
2555      int x2, y2;                 /* Lower right corner of area to redraw.      int x2, y2;                 /* Lower right corner of area to redraw.
2556                                   * Pixels on edge are not redrawn. */                                   * Pixels on edge are not redrawn. */
2557  {  {
2558      TkCanvas *canvasPtr = (TkCanvas *) canvas;      TkCanvas *canvasPtr = (TkCanvas *) canvas;
2559      /*      /*
2560       * If tkwin is NULL, the canvas has been destroyed, so we can't really       * If tkwin is NULL, the canvas has been destroyed, so we can't really
2561       * redraw it.       * redraw it.
2562       */       */
2563      if (canvasPtr->tkwin == NULL) {      if (canvasPtr->tkwin == NULL) {
2564          return;          return;
2565      }      }
2566    
2567      if ((x1 >= x2) || (y1 >= y2) ||      if ((x1 >= x2) || (y1 >= y2) ||
2568              (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) ||              (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) ||
2569              (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||              (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||
2570              (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {              (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {
2571          return;          return;
2572      }      }
2573      if (canvasPtr->flags & BBOX_NOT_EMPTY) {      if (canvasPtr->flags & BBOX_NOT_EMPTY) {
2574          if (x1 <= canvasPtr->redrawX1) {          if (x1 <= canvasPtr->redrawX1) {
2575              canvasPtr->redrawX1 = x1;              canvasPtr->redrawX1 = x1;
2576          }          }
2577          if (y1 <= canvasPtr->redrawY1) {          if (y1 <= canvasPtr->redrawY1) {
2578              canvasPtr->redrawY1 = y1;              canvasPtr->redrawY1 = y1;
2579          }          }
2580          if (x2 >= canvasPtr->redrawX2) {          if (x2 >= canvasPtr->redrawX2) {
2581              canvasPtr->redrawX2 = x2;              canvasPtr->redrawX2 = x2;
2582          }          }
2583          if (y2 >= canvasPtr->redrawY2) {          if (y2 >= canvasPtr->redrawY2) {
2584              canvasPtr->redrawY2 = y2;              canvasPtr->redrawY2 = y2;
2585          }          }
2586      } else {      } else {
2587          canvasPtr->redrawX1 = x1;          canvasPtr->redrawX1 = x1;
2588          canvasPtr->redrawY1 = y1;          canvasPtr->redrawY1 = y1;
2589          canvasPtr->redrawX2 = x2;          canvasPtr->redrawX2 = x2;
2590          canvasPtr->redrawY2 = y2;          canvasPtr->redrawY2 = y2;
2591          canvasPtr->flags |= BBOX_NOT_EMPTY;          canvasPtr->flags |= BBOX_NOT_EMPTY;
2592      }      }
2593      if (!(canvasPtr->flags & REDRAW_PENDING)) {      if (!(canvasPtr->flags & REDRAW_PENDING)) {
2594          Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);          Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
2595          canvasPtr->flags |= REDRAW_PENDING;          canvasPtr->flags |= REDRAW_PENDING;
2596      }      }
2597  }  }
2598    
2599  /*  /*
2600   *--------------------------------------------------------------   *--------------------------------------------------------------
2601   *   *
2602   * EventuallyRedrawItem --   * EventuallyRedrawItem --
2603   *   *
2604   *      Arrange for part or all of a canvas widget to redrawn at   *      Arrange for part or all of a canvas widget to redrawn at
2605   *      some convenient time in the future.   *      some convenient time in the future.
2606   *   *
2607   * Results:   * Results:
2608   *      None.   *      None.
2609   *   *
2610   * Side effects:   * Side effects:
2611   *      The screen will eventually be refreshed.   *      The screen will eventually be refreshed.
2612   *   *
2613   *--------------------------------------------------------------   *--------------------------------------------------------------
2614   */   */
2615    
2616  static void  static void
2617  EventuallyRedrawItem(canvas, itemPtr)  EventuallyRedrawItem(canvas, itemPtr)
2618      Tk_Canvas canvas;           /* Information about widget. */      Tk_Canvas canvas;           /* Information about widget. */
2619      Tk_Item *itemPtr;           /* item to be redrawn. */      Tk_Item *itemPtr;           /* item to be redrawn. */
2620  {  {
2621      TkCanvas *canvasPtr = (TkCanvas *) canvas;      TkCanvas *canvasPtr = (TkCanvas *) canvas;
2622      if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||      if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||
2623              (itemPtr->x2 < canvasPtr->xOrigin) ||              (itemPtr->x2 < canvasPtr->xOrigin) ||
2624              (itemPtr->y2 < canvasPtr->yOrigin) ||              (itemPtr->y2 < canvasPtr->yOrigin) ||
2625              (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||              (itemPtr->x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||
2626              (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {              (itemPtr->y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {
2627          if (!(itemPtr->typePtr->alwaysRedraw & 1)) {          if (!(itemPtr->typePtr->alwaysRedraw & 1)) {
2628              return;              return;
2629          }          }
2630      }      }
2631      if (!(itemPtr->redraw_flags & FORCE_REDRAW)) {      if (!(itemPtr->redraw_flags & FORCE_REDRAW)) {
2632          if (canvasPtr->flags & BBOX_NOT_EMPTY) {          if (canvasPtr->flags & BBOX_NOT_EMPTY) {
2633              if (itemPtr->x1 <= canvasPtr->redrawX1) {              if (itemPtr->x1 <= canvasPtr->redrawX1) {
2634                  canvasPtr->redrawX1 = itemPtr->x1;                  canvasPtr->redrawX1 = itemPtr->x1;
2635              }              }
2636              if (itemPtr->y1 <= canvasPtr->redrawY1) {              if (itemPtr->y1 <= canvasPtr->redrawY1) {
2637                  canvasPtr->redrawY1 = itemPtr->y1;                  canvasPtr->redrawY1 = itemPtr->y1;
2638              }              }
2639              if (itemPtr->x2 >= canvasPtr->redrawX2) {              if (itemPtr->x2 >= canvasPtr->redrawX2) {
2640                  canvasPtr->redrawX2 = itemPtr->x2;                  canvasPtr->redrawX2 = itemPtr->x2;
2641              }              }
2642              if (itemPtr->y2 >= canvasPtr->redrawY2) {              if (itemPtr->y2 >= canvasPtr->redrawY2) {
2643                  canvasPtr->redrawY2 = itemPtr->y2;                  canvasPtr->redrawY2 = itemPtr->y2;
2644              }              }
2645          } else {          } else {
2646              canvasPtr->redrawX1 = itemPtr->x1;              canvasPtr->redrawX1 = itemPtr->x1;
2647              canvasPtr->redrawY1 = itemPtr->y1;              canvasPtr->redrawY1 = itemPtr->y1;
2648              canvasPtr->redrawX2 = itemPtr->x2;              canvasPtr->redrawX2 = itemPtr->x2;
2649              canvasPtr->redrawY2 = itemPtr->y2;              canvasPtr->redrawY2 = itemPtr->y2;
2650              canvasPtr->flags |= BBOX_NOT_EMPTY;              canvasPtr->flags |= BBOX_NOT_EMPTY;
2651          }          }
2652          itemPtr->redraw_flags |= FORCE_REDRAW;          itemPtr->redraw_flags |= FORCE_REDRAW;
2653      }      }
2654      if (!(canvasPtr->flags & REDRAW_PENDING)) {      if (!(canvasPtr->flags & REDRAW_PENDING)) {
2655          Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);          Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
2656          canvasPtr->flags |= REDRAW_PENDING;          canvasPtr->flags |= REDRAW_PENDING;
2657      }      }
2658  }  }
2659    
2660  /*  /*
2661   *--------------------------------------------------------------   *--------------------------------------------------------------
2662   *   *
2663   * Tk_CreateItemType --   * Tk_CreateItemType --
2664   *   *
2665   *      This procedure may be invoked to add a new kind of canvas   *      This procedure may be invoked to add a new kind of canvas
2666   *      element to the core item types supported by Tk.   *      element to the core item types supported by Tk.
2667   *   *
2668   * Results:   * Results:
2669   *      None.   *      None.
2670   *   *
2671   * Side effects:   * Side effects:
2672   *      From now on, the new item type will be useable in canvas   *      From now on, the new item type will be useable in canvas
2673   *      widgets (e.g. typePtr->name can be used as the item type   *      widgets (e.g. typePtr->name can be used as the item type
2674   *      in "create" widget commands).  If there was already a   *      in "create" widget commands).  If there was already a
2675   *      type with the same name as in typePtr, it is replaced with   *      type with the same name as in typePtr, it is replaced with
2676   *      the new type.   *      the new type.
2677   *   *
2678   *--------------------------------------------------------------   *--------------------------------------------------------------
2679   */   */
2680    
2681  void  void
2682  Tk_CreateItemType(typePtr)  Tk_CreateItemType(typePtr)
2683      Tk_ItemType *typePtr;               /* Information about item type;      Tk_ItemType *typePtr;               /* Information about item type;
2684                                           * storage must be statically                                           * storage must be statically
2685                                           * allocated (must live forever). */                                           * allocated (must live forever). */
2686  {  {
2687      Tk_ItemType *typePtr2, *prevPtr;      Tk_ItemType *typePtr2, *prevPtr;
2688    
2689      if (typeList == NULL) {      if (typeList == NULL) {
2690          InitCanvas();          InitCanvas();
2691      }      }
2692    
2693      /*      /*
2694       * If there's already an item type with the given name, remove it.       * If there's already an item type with the given name, remove it.
2695       */       */
2696    
2697      for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;      for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
2698              prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {              prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
2699          if (strcmp(typePtr2->name, typePtr->name) == 0) {          if (strcmp(typePtr2->name, typePtr->name) == 0) {
2700              if (prevPtr == NULL) {              if (prevPtr == NULL) {
2701                  typeList = typePtr2->nextPtr;                  typeList = typePtr2->nextPtr;
2702              } else {              } else {
2703                  prevPtr->nextPtr = typePtr2->nextPtr;                  prevPtr->nextPtr = typePtr2->nextPtr;
2704              }              }
2705              break;              break;
2706          }          }
2707      }      }
2708      typePtr->nextPtr = typeList;      typePtr->nextPtr = typeList;
2709      typeList = typePtr;      typeList = typePtr;
2710  }  }
2711    
2712  /*  /*
2713   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2714   *   *
2715   * Tk_GetItemTypes --   * Tk_GetItemTypes --
2716   *   *
2717   *      This procedure returns a pointer to the list of all item   *      This procedure returns a pointer to the list of all item
2718   *      types.   *      types.
2719   *   *
2720   * Results:   * Results:
2721   *      The return value is a pointer to the first in the list   *      The return value is a pointer to the first in the list
2722   *      of item types currently supported by canvases.   *      of item types currently supported by canvases.
2723   *   *
2724   * Side effects:   * Side effects:
2725   *      None.   *      None.
2726   *   *
2727   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2728   */   */
2729    
2730  Tk_ItemType *  Tk_ItemType *
2731  Tk_GetItemTypes()  Tk_GetItemTypes()
2732  {  {
2733      if (typeList == NULL) {      if (typeList == NULL) {
2734          InitCanvas();          InitCanvas();
2735      }      }
2736      return typeList;      return typeList;
2737  }  }
2738    
2739  /*  /*
2740   *--------------------------------------------------------------   *--------------------------------------------------------------
2741   *   *
2742   * InitCanvas --   * InitCanvas --
2743   *   *
2744   *      This procedure is invoked to perform once-only-ever   *      This procedure is invoked to perform once-only-ever
2745   *      initialization for the module, such as setting up   *      initialization for the module, such as setting up
2746   *      the type table.   *      the type table.
2747   *   *
2748   * Results:   * Results:
2749   *      None.   *      None.
2750   *   *
2751   * Side effects:   * Side effects:
2752   *      None.   *      None.
2753   *   *
2754   *--------------------------------------------------------------   *--------------------------------------------------------------
2755   */   */
2756    
2757  static void  static void
2758  InitCanvas()  InitCanvas()
2759  {  {
2760      if (typeList != NULL) {      if (typeList != NULL) {
2761          return;          return;
2762      }      }
2763      typeList = &tkRectangleType;      typeList = &tkRectangleType;
2764      tkRectangleType.nextPtr = &tkTextType;      tkRectangleType.nextPtr = &tkTextType;
2765      tkTextType.nextPtr = &tkLineType;      tkTextType.nextPtr = &tkLineType;
2766      tkLineType.nextPtr = &tkPolygonType;      tkLineType.nextPtr = &tkPolygonType;
2767      tkPolygonType.nextPtr = &tkImageType;      tkPolygonType.nextPtr = &tkImageType;
2768      tkImageType.nextPtr = &tkOvalType;      tkImageType.nextPtr = &tkOvalType;
2769      tkOvalType.nextPtr = &tkBitmapType;      tkOvalType.nextPtr = &tkBitmapType;
2770      tkBitmapType.nextPtr = &tkArcType;      tkBitmapType.nextPtr = &tkArcType;
2771      tkArcType.nextPtr = &tkWindowType;      tkArcType.nextPtr = &tkWindowType;
2772      tkWindowType.nextPtr = NULL;      tkWindowType.nextPtr = NULL;
2773  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
2774      allUid = Tk_GetUid("all");      allUid = Tk_GetUid("all");
2775      currentUid = Tk_GetUid("current");      currentUid = Tk_GetUid("current");
2776      andUid = Tk_GetUid("&&");      andUid = Tk_GetUid("&&");
2777      orUid = Tk_GetUid("||");      orUid = Tk_GetUid("||");
2778      xorUid = Tk_GetUid("^");      xorUid = Tk_GetUid("^");
2779      parenUid = Tk_GetUid("(");      parenUid = Tk_GetUid("(");
2780      endparenUid = Tk_GetUid(")");      endparenUid = Tk_GetUid(")");
2781      negparenUid = Tk_GetUid("!(");      negparenUid = Tk_GetUid("!(");
2782      tagvalUid = Tk_GetUid("!!");      tagvalUid = Tk_GetUid("!!");
2783      negtagvalUid = Tk_GetUid("!");      negtagvalUid = Tk_GetUid("!");
2784  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
2785  }  }
2786    
2787  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
2788  /*  /*
2789   *--------------------------------------------------------------   *--------------------------------------------------------------
2790   *   *
2791   * StartTagSearch --   * StartTagSearch --
2792   *   *
2793   *      This procedure is called to initiate an enumeration of   *      This procedure is called to initiate an enumeration of
2794   *      all items in a given canvas that contain a given tag.   *      all items in a given canvas that contain a given tag.
2795   *   *
2796   * Results:   * Results:
2797   *      The return value is a pointer to the first item in   *      The return value is a pointer to the first item in
2798   *      canvasPtr that matches tag, or NULL if there is no   *      canvasPtr that matches tag, or NULL if there is no
2799   *      such item.  The information at *searchPtr is initialized   *      such item.  The information at *searchPtr is initialized
2800   *      such that successive calls to NextItem will return   *      such that successive calls to NextItem will return
2801   *      successive items that match tag.   *      successive items that match tag.
2802   *   *
2803   * Side effects:   * Side effects:
2804   *      SearchPtr is linked into a list of searches in progress   *      SearchPtr is linked into a list of searches in progress
2805   *      on canvasPtr, so that elements can safely be deleted   *      on canvasPtr, so that elements can safely be deleted
2806   *      while the search is in progress.  EndTagSearch must be   *      while the search is in progress.  EndTagSearch must be
2807   *      called at the end of the search to unlink searchPtr from   *      called at the end of the search to unlink searchPtr from
2808   *      this list.   *      this list.
2809   *   *
2810   *--------------------------------------------------------------   *--------------------------------------------------------------
2811   */   */
2812    
2813  static Tk_Item *  static Tk_Item *
2814  StartTagSearch(canvasPtr, tagObj, searchPtr)  StartTagSearch(canvasPtr, tagObj, searchPtr)
2815      TkCanvas *canvasPtr;                /* Canvas whose items are to be      TkCanvas *canvasPtr;                /* Canvas whose items are to be
2816                                           * searched. */                                           * searched. */
2817      Tcl_Obj *tagObj;                    /* Object giving tag value. */      Tcl_Obj *tagObj;                    /* Object giving tag value. */
2818      TagSearch *searchPtr;               /* Record describing tag search;      TagSearch *searchPtr;               /* Record describing tag search;
2819                                           * will be initialized here. */                                           * will be initialized here. */
2820  {  {
2821      int id;      int id;
2822      Tk_Item *itemPtr, *lastPtr;      Tk_Item *itemPtr, *lastPtr;
2823      Tk_Uid *tagPtr;      Tk_Uid *tagPtr;
2824      Tk_Uid uid;      Tk_Uid uid;
2825      char *tag = Tcl_GetString(tagObj);      char *tag = Tcl_GetString(tagObj);
2826      int count;      int count;
2827      TkWindow *tkwin;      TkWindow *tkwin;
2828      TkDisplay *dispPtr;      TkDisplay *dispPtr;
2829    
2830      tkwin = (TkWindow *) canvasPtr->tkwin;      tkwin = (TkWindow *) canvasPtr->tkwin;
2831      dispPtr = tkwin->dispPtr;      dispPtr = tkwin->dispPtr;
2832    
2833      /*      /*
2834       * Initialize the search.       * Initialize the search.
2835       */       */
2836    
2837      searchPtr->canvasPtr = canvasPtr;      searchPtr->canvasPtr = canvasPtr;
2838      searchPtr->searchOver = 0;      searchPtr->searchOver = 0;
2839    
2840      /*      /*
2841       * Find the first matching item in one of several ways. If the tag       * Find the first matching item in one of several ways. If the tag
2842       * is a number then it selects the single item with the matching       * is a number then it selects the single item with the matching
2843       * identifier.  In this case see if the item being requested is the       * identifier.  In this case see if the item being requested is the
2844       * hot item, in which case the search can be skipped.       * hot item, in which case the search can be skipped.
2845       */       */
2846    
2847      if (isdigit(UCHAR(*tag))) {      if (isdigit(UCHAR(*tag))) {
2848          char *end;          char *end;
2849          Tcl_HashEntry *entryPtr;          Tcl_HashEntry *entryPtr;
2850    
2851          dispPtr->numIdSearches++;          dispPtr->numIdSearches++;
2852          id = strtoul(tag, &end, 0);          id = strtoul(tag, &end, 0);
2853          if (*end == 0) {          if (*end == 0) {
2854              itemPtr = canvasPtr->hotPtr;              itemPtr = canvasPtr->hotPtr;
2855              lastPtr = canvasPtr->hotPrevPtr;              lastPtr = canvasPtr->hotPrevPtr;
2856              if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)              if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)
2857                      || (lastPtr->nextPtr != itemPtr)) {                      || (lastPtr->nextPtr != itemPtr)) {
2858                  dispPtr->numSlowSearches++;                  dispPtr->numSlowSearches++;
2859                  entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);                  entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
2860                  if (entryPtr != NULL) {                  if (entryPtr != NULL) {
2861                      itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);                      itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);
2862                      lastPtr = itemPtr->prevPtr;                      lastPtr = itemPtr->prevPtr;
2863                  } else {                  } else {
2864                      lastPtr = itemPtr = NULL;                      lastPtr = itemPtr = NULL;
2865                  }                  }
2866              }              }
2867              searchPtr->lastPtr = lastPtr;              searchPtr->lastPtr = lastPtr;
2868              searchPtr->searchOver = 1;              searchPtr->searchOver = 1;
2869              canvasPtr->hotPtr = itemPtr;              canvasPtr->hotPtr = itemPtr;
2870              canvasPtr->hotPrevPtr = lastPtr;              canvasPtr->hotPrevPtr = lastPtr;
2871              return itemPtr;              return itemPtr;
2872          }          }
2873      }      }
2874    
2875      searchPtr->tag = uid = Tk_GetUid(tag);      searchPtr->tag = uid = Tk_GetUid(tag);
2876      if (uid == Tk_GetUid("all")) {      if (uid == Tk_GetUid("all")) {
2877          /*          /*
2878           * All items match.           * All items match.
2879           */           */
2880    
2881          searchPtr->tag = NULL;          searchPtr->tag = NULL;
2882          searchPtr->lastPtr = NULL;          searchPtr->lastPtr = NULL;
2883          searchPtr->currentPtr = canvasPtr->firstItemPtr;          searchPtr->currentPtr = canvasPtr->firstItemPtr;
2884          return canvasPtr->firstItemPtr;          return canvasPtr->firstItemPtr;
2885      }      }
2886    
2887      /*      /*
2888       * None of the above.  Search for an item with a matching tag.       * None of the above.  Search for an item with a matching tag.
2889       */       */
2890    
2891      for (lastPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;      for (lastPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
2892              lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {              lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
2893          for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;          for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
2894                  count > 0; tagPtr++, count--) {                  count > 0; tagPtr++, count--) {
2895              if (*tagPtr == uid) {              if (*tagPtr == uid) {
2896                  searchPtr->lastPtr = lastPtr;                  searchPtr->lastPtr = lastPtr;
2897                  searchPtr->currentPtr = itemPtr;                  searchPtr->currentPtr = itemPtr;
2898                  return itemPtr;                  return itemPtr;
2899              }              }
2900          }          }
2901      }      }
2902      searchPtr->lastPtr = lastPtr;      searchPtr->lastPtr = lastPtr;
2903      searchPtr->searchOver = 1;      searchPtr->searchOver = 1;
2904      return NULL;      return NULL;
2905  }  }
2906    
2907  /*  /*
2908   *--------------------------------------------------------------   *--------------------------------------------------------------
2909   *   *
2910   * NextItem --   * NextItem --
2911   *   *
2912   *      This procedure returns successive items that match a given   *      This procedure returns successive items that match a given
2913   *      tag;  it should be called only after StartTagSearch has been   *      tag;  it should be called only after StartTagSearch has been
2914   *      used to begin a search.   *      used to begin a search.
2915   *   *
2916   * Results:   * Results:
2917   *      The return value is a pointer to the next item that matches   *      The return value is a pointer to the next item that matches
2918   *      the tag specified to StartTagSearch, or NULL if no such   *      the tag specified to StartTagSearch, or NULL if no such
2919   *      item exists.  *SearchPtr is updated so that the next call   *      item exists.  *SearchPtr is updated so that the next call
2920   *      to this procedure will return the next item.   *      to this procedure will return the next item.
2921   *   *
2922   * Side effects:   * Side effects:
2923   *      None.   *      None.
2924   *   *
2925   *--------------------------------------------------------------   *--------------------------------------------------------------
2926   */   */
2927    
2928  static Tk_Item *  static Tk_Item *
2929  NextItem(searchPtr)  NextItem(searchPtr)
2930      TagSearch *searchPtr;               /* Record describing search in      TagSearch *searchPtr;               /* Record describing search in
2931                                           * progress. */                                           * progress. */
2932  {  {
2933      Tk_Item *itemPtr, *lastPtr;      Tk_Item *itemPtr, *lastPtr;
2934      int count;      int count;
2935      Tk_Uid uid;      Tk_Uid uid;
2936      Tk_Uid *tagPtr;      Tk_Uid *tagPtr;
2937    
2938      /*      /*
2939       * Find next item in list (this may not actually be a suitable       * Find next item in list (this may not actually be a suitable
2940       * one to return), and return if there are no items left.       * one to return), and return if there are no items left.
2941       */       */
2942    
2943      lastPtr = searchPtr->lastPtr;      lastPtr = searchPtr->lastPtr;
2944      if (lastPtr == NULL) {      if (lastPtr == NULL) {
2945          itemPtr = searchPtr->canvasPtr->firstItemPtr;          itemPtr = searchPtr->canvasPtr->firstItemPtr;
2946      } else {      } else {
2947          itemPtr = lastPtr->nextPtr;          itemPtr = lastPtr->nextPtr;
2948      }      }
2949      if ((itemPtr == NULL) || (searchPtr->searchOver)) {      if ((itemPtr == NULL) || (searchPtr->searchOver)) {
2950          searchPtr->searchOver = 1;          searchPtr->searchOver = 1;
2951          return NULL;          return NULL;
2952      }      }
2953      if (itemPtr != searchPtr->currentPtr) {      if (itemPtr != searchPtr->currentPtr) {
2954          /*          /*
2955           * The structure of the list has changed.  Probably the           * The structure of the list has changed.  Probably the
2956           * previously-returned item was removed from the list.           * previously-returned item was removed from the list.
2957           * In this case, don't advance lastPtr;  just return           * In this case, don't advance lastPtr;  just return
2958           * its new successor (i.e. do nothing here).           * its new successor (i.e. do nothing here).
2959           */           */
2960      } else {      } else {
2961          lastPtr = itemPtr;          lastPtr = itemPtr;
2962          itemPtr = lastPtr->nextPtr;          itemPtr = lastPtr->nextPtr;
2963      }      }
2964    
2965      /*      /*
2966       * Handle special case of "all" search by returning next item.       * Handle special case of "all" search by returning next item.
2967       */       */
2968    
2969      uid = searchPtr->tag;      uid = searchPtr->tag;
2970      if (uid == NULL) {      if (uid == NULL) {
2971          searchPtr->lastPtr = lastPtr;          searchPtr->lastPtr = lastPtr;
2972          searchPtr->currentPtr = itemPtr;          searchPtr->currentPtr = itemPtr;
2973          return itemPtr;          return itemPtr;
2974      }      }
2975    
2976      /*      /*
2977       * Look for an item with a particular tag.       * Look for an item with a particular tag.
2978       */       */
2979    
2980      for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {      for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
2981          for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;          for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
2982                  count > 0; tagPtr++, count--) {                  count > 0; tagPtr++, count--) {
2983              if (*tagPtr == uid) {              if (*tagPtr == uid) {
2984                  searchPtr->lastPtr = lastPtr;                  searchPtr->lastPtr = lastPtr;
2985                  searchPtr->currentPtr = itemPtr;                  searchPtr->currentPtr = itemPtr;
2986                  return itemPtr;                  return itemPtr;
2987              }              }
2988          }          }
2989      }      }
2990      searchPtr->lastPtr = lastPtr;      searchPtr->lastPtr = lastPtr;
2991      searchPtr->searchOver = 1;      searchPtr->searchOver = 1;
2992      return NULL;      return NULL;
2993  }  }
2994    
2995  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
2996  /*  /*
2997   *--------------------------------------------------------------   *--------------------------------------------------------------
2998   *   *
2999   * TagSearchExprInit --   * TagSearchExprInit --
3000   *   *
3001   *      This procedure allocates and initializes one TagSearchExpr struct.   *      This procedure allocates and initializes one TagSearchExpr struct.
3002   *   *
3003   * Results:   * Results:
3004   *   *
3005   * Side effects:   * Side effects:
3006   *   *
3007   *--------------------------------------------------------------   *--------------------------------------------------------------
3008   */   */
3009    
3010  static void  static void
3011  TagSearchExprInit(exprPtrPtr)  TagSearchExprInit(exprPtrPtr)
3012  TagSearchExpr **exprPtrPtr;  TagSearchExpr **exprPtrPtr;
3013  {  {
3014      TagSearchExpr* expr = *exprPtrPtr;      TagSearchExpr* expr = *exprPtrPtr;
3015    
3016      if (! expr) {      if (! expr) {
3017          expr = (TagSearchExpr *) ckalloc(sizeof(TagSearchExpr));          expr = (TagSearchExpr *) ckalloc(sizeof(TagSearchExpr));
3018          expr->allocated = 0;          expr->allocated = 0;
3019          expr->uids = NULL;          expr->uids = NULL;
3020          expr->next = NULL;          expr->next = NULL;
3021      }      }
3022      expr->uid = NULL;      expr->uid = NULL;
3023      expr->index = 0;      expr->index = 0;
3024      expr->length = 0;      expr->length = 0;
3025      *exprPtrPtr = expr;      *exprPtrPtr = expr;
3026  }  }
3027    
3028  /*  /*
3029   *--------------------------------------------------------------   *--------------------------------------------------------------
3030   *   *
3031   * TagSearchExprDestroy --   * TagSearchExprDestroy --
3032   *   *
3033   *      This procedure destroys one TagSearchExpr structure.   *      This procedure destroys one TagSearchExpr structure.
3034   *   *
3035   * Results:   * Results:
3036   *   *
3037   * Side effects:   * Side effects:
3038   *   *
3039   *--------------------------------------------------------------   *--------------------------------------------------------------
3040       */       */
3041    
3042  static void  static void
3043  TagSearchExprDestroy(expr)  TagSearchExprDestroy(expr)
3044      TagSearchExpr *expr;      TagSearchExpr *expr;
3045  {  {
3046      if (expr) {      if (expr) {
3047          if (expr->uids) {          if (expr->uids) {
3048                  ckfree((char *)expr->uids);                  ckfree((char *)expr->uids);
3049          }          }
3050          ckfree((char *)expr);          ckfree((char *)expr);
3051      }      }
3052  }  }
3053    
3054  /*  /*
3055   *--------------------------------------------------------------   *--------------------------------------------------------------
3056   *   *
3057   * TagSearchScan --   * TagSearchScan --
3058   *   *
3059   *      This procedure is called to initiate an enumeration of   *      This procedure is called to initiate an enumeration of
3060   *      all items in a given canvas that contain a tag that matches   *      all items in a given canvas that contain a tag that matches
3061   *      the tagOrId expression.   *      the tagOrId expression.
3062   *   *
3063   * Results:   * Results:
3064   *      The return value indicates if the tagOrId expression   *      The return value indicates if the tagOrId expression
3065   *      was successfully scanned (syntax).   *      was successfully scanned (syntax).
3066   *      The information at *searchPtr is initialized   *      The information at *searchPtr is initialized
3067   *      such that a call to TagSearchFirst, followed by   *      such that a call to TagSearchFirst, followed by
3068   *      successive calls to TagSearchNext will return items   *      successive calls to TagSearchNext will return items
3069   *      that match tag.   *      that match tag.
3070   *   *
3071   * Side effects:   * Side effects:
3072   *      SearchPtr is linked into a list of searches in progress   *      SearchPtr is linked into a list of searches in progress
3073   *      on canvasPtr, so that elements can safely be deleted   *      on canvasPtr, so that elements can safely be deleted
3074   *      while the search is in progress.   *      while the search is in progress.
3075   *   *
3076   *--------------------------------------------------------------   *--------------------------------------------------------------
3077   */   */
3078    
3079  static int  static int
3080  TagSearchScan(canvasPtr, tagObj, searchPtrPtr)  TagSearchScan(canvasPtr, tagObj, searchPtrPtr)
3081      TkCanvas *canvasPtr;                /* Canvas whose items are to be      TkCanvas *canvasPtr;                /* Canvas whose items are to be
3082                                           * searched. */                                           * searched. */
3083      Tcl_Obj *tagObj;                    /* Object giving tag value. */      Tcl_Obj *tagObj;                    /* Object giving tag value. */
3084      TagSearch **searchPtrPtr;           /* Record describing tag search;      TagSearch **searchPtrPtr;           /* Record describing tag search;
3085                                           * will be initialized here. */                                           * will be initialized here. */
3086  {  {
3087      char *tag = Tcl_GetStringFromObj(tagObj,NULL);      char *tag = Tcl_GetStringFromObj(tagObj,NULL);
3088      int i;      int i;
3089      TagSearch *searchPtr;      TagSearch *searchPtr;
3090    
3091      /*      /*
3092       * Initialize the search.       * Initialize the search.
3093       */       */
3094    
3095      if (*searchPtrPtr) {      if (*searchPtrPtr) {
3096          searchPtr = *searchPtrPtr;          searchPtr = *searchPtrPtr;
3097      } else {      } else {
3098          /* Allocate primary search struct on first call */          /* Allocate primary search struct on first call */
3099          *searchPtrPtr = searchPtr = (TagSearch *) ckalloc(sizeof(TagSearch));          *searchPtrPtr = searchPtr = (TagSearch *) ckalloc(sizeof(TagSearch));
3100          searchPtr->expr = NULL;          searchPtr->expr = NULL;
3101    
3102          /* Allocate buffer for rewritten tags (after de-escaping) */          /* Allocate buffer for rewritten tags (after de-escaping) */
3103          searchPtr->rewritebufferAllocated = 100;          searchPtr->rewritebufferAllocated = 100;
3104          searchPtr->rewritebuffer =          searchPtr->rewritebuffer =
3105              ckalloc(searchPtr->rewritebufferAllocated);              ckalloc(searchPtr->rewritebufferAllocated);
3106      }      }
3107      TagSearchExprInit(&(searchPtr->expr));      TagSearchExprInit(&(searchPtr->expr));
3108    
3109      /* How long is the tagOrId ? */      /* How long is the tagOrId ? */
3110      searchPtr->stringLength = strlen(tag);      searchPtr->stringLength = strlen(tag);
3111    
3112      /* Make sure there is enough buffer to hold rewritten tags */      /* Make sure there is enough buffer to hold rewritten tags */
3113      if ((unsigned int)searchPtr->stringLength >=      if ((unsigned int)searchPtr->stringLength >=
3114              searchPtr->rewritebufferAllocated) {              searchPtr->rewritebufferAllocated) {
3115          searchPtr->rewritebufferAllocated = searchPtr->stringLength + 100;          searchPtr->rewritebufferAllocated = searchPtr->stringLength + 100;
3116          searchPtr->rewritebuffer =          searchPtr->rewritebuffer =
3117              ckrealloc(searchPtr->rewritebuffer,              ckrealloc(searchPtr->rewritebuffer,
3118                      searchPtr->rewritebufferAllocated);                      searchPtr->rewritebufferAllocated);
3119      }      }
3120    
3121      /* Initialize search */      /* Initialize search */
3122      searchPtr->canvasPtr = canvasPtr;      searchPtr->canvasPtr = canvasPtr;
3123      searchPtr->searchOver = 0;      searchPtr->searchOver = 0;
3124      searchPtr->type = 0;      searchPtr->type = 0;
3125    
3126      /*      /*
3127       * Find the first matching item in one of several ways. If the tag       * Find the first matching item in one of several ways. If the tag
3128       * is a number then it selects the single item with the matching       * is a number then it selects the single item with the matching
3129       * identifier.  In this case see if the item being requested is the       * identifier.  In this case see if the item being requested is the
3130       * hot item, in which case the search can be skipped.       * hot item, in which case the search can be skipped.
3131       */       */
3132    
3133      if (searchPtr->stringLength && isdigit(UCHAR(*tag))) {      if (searchPtr->stringLength && isdigit(UCHAR(*tag))) {
3134          char *end;          char *end;
3135    
3136          searchPtr->id = strtoul(tag, &end, 0);          searchPtr->id = strtoul(tag, &end, 0);
3137          if (*end == 0) {          if (*end == 0) {
3138              searchPtr->type = 1;              searchPtr->type = 1;
3139              return TCL_OK;              return TCL_OK;
3140          }          }
3141      }      }
3142    
3143      /*      /*
3144       * For all other tags and tag expressions convert to a UID.       * For all other tags and tag expressions convert to a UID.
3145       * This UID is kept forever, but this should be thought of       * This UID is kept forever, but this should be thought of
3146       * as a cache rather than as a memory leak.       * as a cache rather than as a memory leak.
3147       */       */
3148      searchPtr->expr->uid = Tk_GetUid(tag);      searchPtr->expr->uid = Tk_GetUid(tag);
3149    
3150      /* short circuit impossible searches for null tags */      /* short circuit impossible searches for null tags */
3151      if (searchPtr->stringLength == 0) {      if (searchPtr->stringLength == 0) {
3152          return TCL_OK;          return TCL_OK;
3153      }      }
3154    
3155      /*      /*
3156       * Pre-scan tag for at least one unquoted "&&" "||" "^" "!"       * Pre-scan tag for at least one unquoted "&&" "||" "^" "!"
3157       *   if not found then use string as simple tag       *   if not found then use string as simple tag
3158       */       */
3159      for (i = 0; i < searchPtr->stringLength ; i++) {      for (i = 0; i < searchPtr->stringLength ; i++) {
3160          if (tag[i] == '"') {          if (tag[i] == '"') {
3161              i++;              i++;
3162              for ( ; i < searchPtr->stringLength; i++) {              for ( ; i < searchPtr->stringLength; i++) {
3163                  if (tag[i] == '\\') {                  if (tag[i] == '\\') {
3164                      i++;                      i++;
3165                      continue;                      continue;
3166                  }                  }
3167                  if (tag[i] == '"') {                  if (tag[i] == '"') {
3168                      break;                      break;
3169                  }                  }
3170              }              }
3171          } else {          } else {
3172              if ((tag[i] == '&' && tag[i+1] == '&')              if ((tag[i] == '&' && tag[i+1] == '&')
3173               || (tag[i] == '|' && tag[i+1] == '|')               || (tag[i] == '|' && tag[i+1] == '|')
3174               || (tag[i] == '^')               || (tag[i] == '^')
3175               || (tag[i] == '!')) {               || (tag[i] == '!')) {
3176                  searchPtr->type = 4;                  searchPtr->type = 4;
3177                  break;                  break;
3178              }              }
3179          }          }
3180      }      }
3181    
3182      searchPtr->string = tag;      searchPtr->string = tag;
3183      searchPtr->stringIndex = 0;      searchPtr->stringIndex = 0;
3184      if (searchPtr->type == 4) {      if (searchPtr->type == 4) {
3185          /*          /*
3186           * an operator was found in the prescan, so           * an operator was found in the prescan, so
3187           * now compile the tag expression into array of Tk_Uid           * now compile the tag expression into array of Tk_Uid
3188           * flagging any syntax errors found           * flagging any syntax errors found
3189           */           */
3190          if (TagSearchScanExpr(canvasPtr->interp, searchPtr, searchPtr->expr) != TCL_OK) {          if (TagSearchScanExpr(canvasPtr->interp, searchPtr, searchPtr->expr) != TCL_OK) {
3191              /* Syntax error in tag expression */              /* Syntax error in tag expression */
3192              /* Result message set by TagSearchScanExpr */              /* Result message set by TagSearchScanExpr */
3193              return TCL_ERROR;              return TCL_ERROR;
3194          }          }
3195          searchPtr->expr->length = searchPtr->expr->index;          searchPtr->expr->length = searchPtr->expr->index;
3196      } else {      } else {
3197          if (searchPtr->expr->uid == allUid) {          if (searchPtr->expr->uid == allUid) {
3198              /*              /*
3199               * All items match.               * All items match.
3200               */               */
3201              searchPtr->type = 2;              searchPtr->type = 2;
3202          } else {          } else {
3203              /*              /*
3204               * Optimized single-tag search               * Optimized single-tag search
3205               */               */
3206              searchPtr->type = 3;              searchPtr->type = 3;
3207          }          }
3208      }      }
3209      return TCL_OK;      return TCL_OK;
3210  }  }
3211    
3212  /*  /*
3213   *--------------------------------------------------------------   *--------------------------------------------------------------
3214   *   *
3215   * TagSearchDestroy --   * TagSearchDestroy --
3216   *   *
3217   *      This procedure destroys any dynamic structures that   *      This procedure destroys any dynamic structures that
3218   *      may have been allocated by TagSearchScan.   *      may have been allocated by TagSearchScan.
3219   *   *
3220   * Results:   * Results:
3221   *   *
3222   * Side effects:   * Side effects:
3223   *   *
3224   *--------------------------------------------------------------   *--------------------------------------------------------------
3225   */   */
3226    
3227  static void  static void
3228  TagSearchDestroy(searchPtr)  TagSearchDestroy(searchPtr)
3229      TagSearch *searchPtr;               /* Record describing tag search */      TagSearch *searchPtr;               /* Record describing tag search */
3230  {  {
3231      if (searchPtr) {      if (searchPtr) {
3232          TagSearchExprDestroy(searchPtr->expr);          TagSearchExprDestroy(searchPtr->expr);
3233          ckfree((char *)searchPtr->rewritebuffer);          ckfree((char *)searchPtr->rewritebuffer);
3234          ckfree((char *)searchPtr);          ckfree((char *)searchPtr);
3235      }      }
3236  }  }
3237    
3238  /*  /*
3239   *--------------------------------------------------------------   *--------------------------------------------------------------
3240   *   *
3241   * TagSearchScanExpr --   * TagSearchScanExpr --
3242   *   *
3243   *      This recursive procedure is called to scan a tag expression   *      This recursive procedure is called to scan a tag expression
3244   *      and compile it into an array of Tk_Uids.   *      and compile it into an array of Tk_Uids.
3245   *   *
3246   * Results:   * Results:
3247   *      The return value indicates if the tagOrId expression   *      The return value indicates if the tagOrId expression
3248   *      was successfully scanned (syntax).   *      was successfully scanned (syntax).
3249   *      The information at *searchPtr is initialized   *      The information at *searchPtr is initialized
3250   *      such that a call to TagSearchFirst, followed by   *      such that a call to TagSearchFirst, followed by
3251   *      successive calls to TagSearchNext will return items   *      successive calls to TagSearchNext will return items
3252   *      that match tag.   *      that match tag.
3253   *   *
3254   * Side effects:   * Side effects:
3255   *   *
3256   *--------------------------------------------------------------   *--------------------------------------------------------------
3257   */   */
3258    
3259  static int  static int
3260  TagSearchScanExpr(interp, searchPtr, expr)  TagSearchScanExpr(interp, searchPtr, expr)
3261      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
3262      TagSearch *searchPtr;       /* Search data */      TagSearch *searchPtr;       /* Search data */
3263      TagSearchExpr *expr;        /* compiled expression result */      TagSearchExpr *expr;        /* compiled expression result */
3264  {  {
3265      int looking_for_tag;        /* When true, scanner expects      int looking_for_tag;        /* When true, scanner expects
3266                                   * next char(s) to be a tag,                                   * next char(s) to be a tag,
3267                                   * else operand expected */                                   * else operand expected */
3268      int found_tag;              /* One or more tags found */      int found_tag;              /* One or more tags found */
3269      int found_endquote;         /* For quoted tag string parsing */      int found_endquote;         /* For quoted tag string parsing */
3270      int negate_result;          /* Pending negation of next tag value */      int negate_result;          /* Pending negation of next tag value */
3271      char *tag;                  /* tag from tag expression string */      char *tag;                  /* tag from tag expression string */
3272      char c;      char c;
3273    
3274      negate_result = 0;      negate_result = 0;
3275      found_tag = 0;      found_tag = 0;
3276      looking_for_tag = 1;      looking_for_tag = 1;
3277      while (searchPtr->stringIndex < searchPtr->stringLength) {      while (searchPtr->stringIndex < searchPtr->stringLength) {
3278          c = searchPtr->string[searchPtr->stringIndex++];          c = searchPtr->string[searchPtr->stringIndex++];
3279    
3280          if (expr->allocated == expr->index) {          if (expr->allocated == expr->index) {
3281              expr->allocated += 15;              expr->allocated += 15;
3282              if (expr->uids) {              if (expr->uids) {
3283                  expr->uids =                  expr->uids =
3284                      (Tk_Uid *) ckrealloc((char *)(expr->uids),                      (Tk_Uid *) ckrealloc((char *)(expr->uids),
3285                      (expr->allocated)*sizeof(Tk_Uid));                      (expr->allocated)*sizeof(Tk_Uid));
3286              } else {              } else {
3287                  expr->uids =                  expr->uids =
3288                  (Tk_Uid *) ckalloc((expr->allocated)*sizeof(Tk_Uid));                  (Tk_Uid *) ckalloc((expr->allocated)*sizeof(Tk_Uid));
3289              }              }
3290          }          }
3291    
3292          if (looking_for_tag) {          if (looking_for_tag) {
3293    
3294              switch (c) {              switch (c) {
3295                  case ' '  :     /* ignore unquoted whitespace */                  case ' '  :     /* ignore unquoted whitespace */
3296                  case '\t' :                  case '\t' :
3297                  case '\n' :                  case '\n' :
3298                  case '\r' :                  case '\r' :
3299                      break;                      break;
3300    
3301                  case '!'  :     /* negate next tag or subexpr */                  case '!'  :     /* negate next tag or subexpr */
3302                      if (looking_for_tag > 1) {                      if (looking_for_tag > 1) {
3303                          Tcl_AppendResult(interp,                          Tcl_AppendResult(interp,
3304                              "Too many '!' in tag search expression",                              "Too many '!' in tag search expression",
3305                              (char *) NULL);                              (char *) NULL);
3306                          return TCL_ERROR;                          return TCL_ERROR;
3307                      }                      }
3308                      looking_for_tag++;                      looking_for_tag++;
3309                      negate_result = 1;                      negate_result = 1;
3310                      break;                      break;
3311    
3312                  case '('  :     /* scan (negated) subexpr recursively */                  case '('  :     /* scan (negated) subexpr recursively */
3313                      if (negate_result) {                      if (negate_result) {
3314                          expr->uids[expr->index++] = negparenUid;                          expr->uids[expr->index++] = negparenUid;
3315                          negate_result = 0;                          negate_result = 0;
3316                      } else {                      } else {
3317                          expr->uids[expr->index++] = parenUid;                          expr->uids[expr->index++] = parenUid;
3318                      }                      }
3319                      if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) {                      if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) {
3320                          /* Result string should be already set                          /* Result string should be already set
3321                           * by nested call to tag_expr_scan() */                           * by nested call to tag_expr_scan() */
3322                          return TCL_ERROR;                          return TCL_ERROR;
3323                      }                      }
3324                      looking_for_tag = 0;                      looking_for_tag = 0;
3325                      found_tag = 1;                      found_tag = 1;
3326                      break;                      break;
3327    
3328                  case '"'  :     /* quoted tag string */                  case '"'  :     /* quoted tag string */
3329                      if (negate_result) {                      if (negate_result) {
3330                          expr->uids[expr->index++] = negtagvalUid;                          expr->uids[expr->index++] = negtagvalUid;
3331                          negate_result = 0;                          negate_result = 0;
3332                      } else {                      } else {
3333                          expr->uids[expr->index++] = tagvalUid;                          expr->uids[expr->index++] = tagvalUid;
3334                      }                      }
3335                      tag = searchPtr->rewritebuffer;                      tag = searchPtr->rewritebuffer;
3336                      found_endquote = 0;                      found_endquote = 0;
3337                      while (searchPtr->stringIndex < searchPtr->stringLength) {                      while (searchPtr->stringIndex < searchPtr->stringLength) {
3338                          c = searchPtr->string[searchPtr->stringIndex++];                          c = searchPtr->string[searchPtr->stringIndex++];
3339                          if (c == '\\') {                          if (c == '\\') {
3340                              c = searchPtr->string[searchPtr->stringIndex++];                              c = searchPtr->string[searchPtr->stringIndex++];
3341                          }                          }
3342                          if (c == '"') {                          if (c == '"') {
3343                              found_endquote = 1;                              found_endquote = 1;
3344                              break;                              break;
3345                          }                          }
3346                          *tag++ = c;                          *tag++ = c;
3347                      }                      }
3348                      if (! found_endquote) {                      if (! found_endquote) {
3349                          Tcl_AppendResult(interp,                          Tcl_AppendResult(interp,
3350                                  "Missing endquote in tag search expression",                                  "Missing endquote in tag search expression",
3351                                  (char *) NULL);                                  (char *) NULL);
3352                          return TCL_ERROR;                          return TCL_ERROR;
3353                      }                      }
3354                      if (! (tag - searchPtr->rewritebuffer)) {                      if (! (tag - searchPtr->rewritebuffer)) {
3355                          Tcl_AppendResult(interp,                          Tcl_AppendResult(interp,
3356                              "Null quoted tag string in tag search expression",                              "Null quoted tag string in tag search expression",
3357                              (char *) NULL);                              (char *) NULL);
3358                          return TCL_ERROR;                          return TCL_ERROR;
3359                      }                      }
3360                      *tag++ = '\0';                      *tag++ = '\0';
3361                      expr->uids[expr->index++] =                      expr->uids[expr->index++] =
3362                          Tk_GetUid(searchPtr->rewritebuffer);                          Tk_GetUid(searchPtr->rewritebuffer);
3363                      looking_for_tag = 0;                      looking_for_tag = 0;
3364                      found_tag = 1;                      found_tag = 1;
3365                      break;                      break;
3366    
3367                  case '&'  :     /* illegal chars when looking for tag */                  case '&'  :     /* illegal chars when looking for tag */
3368                  case '|'  :                  case '|'  :
3369                  case '^'  :                  case '^'  :
3370                  case ')'  :                  case ')'  :
3371                      Tcl_AppendResult(interp,                      Tcl_AppendResult(interp,
3372                              "Unexpected operator in tag search expression",                              "Unexpected operator in tag search expression",
3373                              (char *) NULL);                              (char *) NULL);
3374                      return TCL_ERROR;                      return TCL_ERROR;
3375    
3376                  default :       /* unquoted tag string */                  default :       /* unquoted tag string */
3377                      if (negate_result) {                      if (negate_result) {
3378                          expr->uids[expr->index++] = negtagvalUid;                          expr->uids[expr->index++] = negtagvalUid;
3379                          negate_result = 0;                          negate_result = 0;
3380                      } else {                      } else {
3381                          expr->uids[expr->index++] = tagvalUid;                          expr->uids[expr->index++] = tagvalUid;
3382                      }                      }
3383                      tag = searchPtr->rewritebuffer;                      tag = searchPtr->rewritebuffer;
3384                      *tag++ = c;                      *tag++ = c;
3385                      /* copy rest of tag, including any embedded whitespace */                      /* copy rest of tag, including any embedded whitespace */
3386                      while (searchPtr->stringIndex < searchPtr->stringLength) {                      while (searchPtr->stringIndex < searchPtr->stringLength) {
3387                          c = searchPtr->string[searchPtr->stringIndex];                          c = searchPtr->string[searchPtr->stringIndex];
3388                          if (c == '!' || c == '&' || c == '|' || c == '^'                          if (c == '!' || c == '&' || c == '|' || c == '^'
3389                                  || c == '(' || c == ')' || c == '"') {                                  || c == '(' || c == ')' || c == '"') {
3390                              break;                              break;
3391                          }                          }
3392                          *tag++ = c;                          *tag++ = c;
3393                          searchPtr->stringIndex++;                          searchPtr->stringIndex++;
3394                      }                      }
3395                      /* remove trailing whitespace */                      /* remove trailing whitespace */
3396                      while (1) {                      while (1) {
3397                          c = *--tag;                          c = *--tag;
3398                          /* there must have been one non-whitespace char,                          /* there must have been one non-whitespace char,
3399                           *  so this will terminate */                           *  so this will terminate */
3400                          if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {                          if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
3401                              break;                              break;
3402                          }                          }
3403                      }                      }
3404                      *++tag = '\0';                      *++tag = '\0';
3405                      expr->uids[expr->index++] =                      expr->uids[expr->index++] =
3406                          Tk_GetUid(searchPtr->rewritebuffer);                          Tk_GetUid(searchPtr->rewritebuffer);
3407                      looking_for_tag = 0;                      looking_for_tag = 0;
3408                      found_tag = 1;                      found_tag = 1;
3409              }              }
3410    
3411          } else {    /* ! looking_for_tag */          } else {    /* ! looking_for_tag */
3412    
3413              switch (c) {              switch (c) {
3414                  case ' '  :     /* ignore whitespace */                  case ' '  :     /* ignore whitespace */
3415                  case '\t' :                  case '\t' :
3416                  case '\n' :                  case '\n' :
3417                  case '\r' :                  case '\r' :
3418                      break;                      break;
3419    
3420                  case '&'  :     /* AND operator */                  case '&'  :     /* AND operator */
3421                      c = searchPtr->string[searchPtr->stringIndex++];                      c = searchPtr->string[searchPtr->stringIndex++];
3422                      if (c != '&') {                      if (c != '&') {
3423                          Tcl_AppendResult(interp,                          Tcl_AppendResult(interp,
3424                                  "Singleton '&' in tag search expression",                                  "Singleton '&' in tag search expression",
3425                                  (char *) NULL);                                  (char *) NULL);
3426                          return TCL_ERROR;                          return TCL_ERROR;
3427                      }                      }
3428                      expr->uids[expr->index++] = andUid;                      expr->uids[expr->index++] = andUid;
3429                      looking_for_tag = 1;                      looking_for_tag = 1;
3430                      break;                      break;
3431    
3432                  case '|'  :     /* OR operator */                  case '|'  :     /* OR operator */
3433                      c = searchPtr->string[searchPtr->stringIndex++];                      c = searchPtr->string[searchPtr->stringIndex++];
3434                      if (c != '|') {                      if (c != '|') {
3435                          Tcl_AppendResult(interp,                          Tcl_AppendResult(interp,
3436                                  "Singleton '|' in tag search expression",                                  "Singleton '|' in tag search expression",
3437                                  (char *) NULL);                                  (char *) NULL);
3438                          return TCL_ERROR;                          return TCL_ERROR;
3439                      }                      }
3440                      expr->uids[expr->index++] = orUid;                      expr->uids[expr->index++] = orUid;
3441                      looking_for_tag = 1;                      looking_for_tag = 1;
3442                      break;                      break;
3443    
3444                  case '^'  :     /* XOR operator */                  case '^'  :     /* XOR operator */
3445                      expr->uids[expr->index++] = xorUid;                      expr->uids[expr->index++] = xorUid;
3446                      looking_for_tag = 1;                      looking_for_tag = 1;
3447                      break;                      break;
3448    
3449                  case ')'  :     /* end subexpression */                  case ')'  :     /* end subexpression */
3450                      expr->uids[expr->index++] = endparenUid;                      expr->uids[expr->index++] = endparenUid;
3451                      goto breakwhile;                      goto breakwhile;
3452    
3453                  default   :     /* syntax error */                  default   :     /* syntax error */
3454                      Tcl_AppendResult(interp,                      Tcl_AppendResult(interp,
3455                              "Invalid boolean operator in tag search expression",                              "Invalid boolean operator in tag search expression",
3456                              (char *) NULL);                              (char *) NULL);
3457                      return TCL_ERROR;                      return TCL_ERROR;
3458              }              }
3459          }          }
3460      }      }
3461      breakwhile:      breakwhile:
3462      if (found_tag && ! looking_for_tag) {      if (found_tag && ! looking_for_tag) {
3463          return TCL_OK;          return TCL_OK;
3464      }      }
3465      Tcl_AppendResult(interp, "Missing tag in tag search expression",      Tcl_AppendResult(interp, "Missing tag in tag search expression",
3466              (char *) NULL);              (char *) NULL);
3467      return TCL_ERROR;      return TCL_ERROR;
3468  }  }
3469    
3470  /*  /*
3471   *--------------------------------------------------------------   *--------------------------------------------------------------
3472   *   *
3473   * TagSearchEvalExpr --   * TagSearchEvalExpr --
3474   *   *
3475   *      This recursive procedure is called to eval a tag expression.   *      This recursive procedure is called to eval a tag expression.
3476   *   *
3477   * Results:   * Results:
3478   *      The return value indicates if the tagOrId expression   *      The return value indicates if the tagOrId expression
3479   *      successfully matched the tags of the current item.   *      successfully matched the tags of the current item.
3480   *   *
3481   * Side effects:   * Side effects:
3482   *   *
3483   *--------------------------------------------------------------   *--------------------------------------------------------------
3484   */   */
3485    
3486  static int  static int
3487  TagSearchEvalExpr(expr, itemPtr)  TagSearchEvalExpr(expr, itemPtr)
3488      TagSearchExpr *expr;        /* Search expression */      TagSearchExpr *expr;        /* Search expression */
3489      Tk_Item *itemPtr;           /* Item being test for match */      Tk_Item *itemPtr;           /* Item being test for match */
3490  {  {
3491      int looking_for_tag;        /* When true, scanner expects      int looking_for_tag;        /* When true, scanner expects
3492                                   * next char(s) to be a tag,                                   * next char(s) to be a tag,
3493                                   * else operand expected */                                   * else operand expected */
3494      int negate_result;          /* Pending negation of next tag value */      int negate_result;          /* Pending negation of next tag value */
3495      Tk_Uid uid;      Tk_Uid uid;
3496      Tk_Uid *tagPtr;      Tk_Uid *tagPtr;
3497      int count;      int count;
3498      int result;                 /* Value of expr so far */      int result;                 /* Value of expr so far */
3499      int parendepth;      int parendepth;
3500    
3501      result = 0;  /* just to keep the compiler quiet */      result = 0;  /* just to keep the compiler quiet */
3502    
3503      negate_result = 0;      negate_result = 0;
3504      looking_for_tag = 1;      looking_for_tag = 1;
3505      while (expr->index < expr->length) {      while (expr->index < expr->length) {
3506          uid = expr->uids[expr->index++];          uid = expr->uids[expr->index++];
3507          if (looking_for_tag) {          if (looking_for_tag) {
3508              if (uid == tagvalUid) {              if (uid == tagvalUid) {
3509  /*  /*
3510   *              assert(expr->index < expr->length);   *              assert(expr->index < expr->length);
3511   */   */
3512                  uid = expr->uids[expr->index++];                  uid = expr->uids[expr->index++];
3513                  result = 0;                  result = 0;
3514                  /*                  /*
3515                   * set result 1 if tag is found in item's tags                   * set result 1 if tag is found in item's tags
3516                   */                   */
3517                  for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;                  for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
3518                      count > 0; tagPtr++, count--) {                      count > 0; tagPtr++, count--) {
3519                      if (*tagPtr == uid) {                      if (*tagPtr == uid) {
3520                          result = 1;                          result = 1;
3521                          break;                          break;
3522                      }                      }
3523                  }                  }
3524    
3525              } else if (uid == negtagvalUid) {              } else if (uid == negtagvalUid) {
3526                  negate_result = ! negate_result;                  negate_result = ! negate_result;
3527  /*  /*
3528   *              assert(expr->index < expr->length);   *              assert(expr->index < expr->length);
3529   */   */
3530                  uid = expr->uids[expr->index++];                  uid = expr->uids[expr->index++];
3531                  result = 0;                  result = 0;
3532                  /*                  /*
3533                   * set result 1 if tag is found in item's tags                   * set result 1 if tag is found in item's tags
3534                   */                   */
3535                  for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;                  for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
3536                      count > 0; tagPtr++, count--) {                      count > 0; tagPtr++, count--) {
3537                      if (*tagPtr == uid) {                      if (*tagPtr == uid) {
3538                          result = 1;                          result = 1;
3539                          break;                          break;
3540                      }                      }
3541                  }                  }
3542    
3543              } else if (uid == parenUid) {              } else if (uid == parenUid) {
3544                  /*                  /*
3545                   * evaluate subexpressions with recursion                   * evaluate subexpressions with recursion
3546                   */                   */
3547                  result = TagSearchEvalExpr(expr, itemPtr);                  result = TagSearchEvalExpr(expr, itemPtr);
3548    
3549              } else if (uid == negparenUid) {              } else if (uid == negparenUid) {
3550                  negate_result = ! negate_result;                  negate_result = ! negate_result;
3551                  /*                  /*
3552                   * evaluate subexpressions with recursion                   * evaluate subexpressions with recursion
3553                   */                   */
3554                  result = TagSearchEvalExpr(expr, itemPtr);                  result = TagSearchEvalExpr(expr, itemPtr);
3555  /*  /*
3556   *          } else {   *          } else {
3557   *              assert(0);   *              assert(0);
3558   */   */
3559              }              }
3560              if (negate_result) {              if (negate_result) {
3561                  result = ! result;                  result = ! result;
3562                  negate_result = 0;                  negate_result = 0;
3563              }              }
3564              looking_for_tag = 0;              looking_for_tag = 0;
3565          } else {    /* ! looking_for_tag */          } else {    /* ! looking_for_tag */
3566              if (((uid == andUid) && (!result)) || ((uid == orUid) && result)) {              if (((uid == andUid) && (!result)) || ((uid == orUid) && result)) {
3567                  /*                  /*
3568                   * short circuit expression evaluation                   * short circuit expression evaluation
3569                   *                   *
3570                   * if result before && is 0, or result before || is 1,                   * if result before && is 0, or result before || is 1,
3571                   *   then the expression is decided and no further                   *   then the expression is decided and no further
3572                   *   evaluation is needed.                   *   evaluation is needed.
3573                   */                   */
3574    
3575                      parendepth = 0;                      parendepth = 0;
3576                  while (expr->index < expr->length) {                  while (expr->index < expr->length) {
3577                      uid = expr->uids[expr->index++];                      uid = expr->uids[expr->index++];
3578                      if (uid == tagvalUid || uid == negtagvalUid) {                      if (uid == tagvalUid || uid == negtagvalUid) {
3579                          expr->index++;                          expr->index++;
3580                          continue;                          continue;
3581                      }                      }
3582                          if (uid == parenUid || uid == negparenUid) {                          if (uid == parenUid || uid == negparenUid) {
3583                              parendepth++;                              parendepth++;
3584                          continue;                          continue;
3585                      }                      }
3586                      if (uid == endparenUid) {                      if (uid == endparenUid) {
3587                              parendepth--;                              parendepth--;
3588                              if (parendepth < 0) {                              if (parendepth < 0) {
3589                                  break;                                  break;
3590                              }                              }
3591                          }                          }
3592                      }                      }
3593                  return result;                  return result;
3594    
3595              } else if (uid == xorUid) {              } else if (uid == xorUid) {
3596                  /*                  /*
3597                   * if the previous result was 1                   * if the previous result was 1
3598                   *   then negate the next result                   *   then negate the next result
3599                   */                   */
3600                  negate_result = result;                  negate_result = result;
3601    
3602              } else if (uid == endparenUid) {              } else if (uid == endparenUid) {
3603                  return result;                  return result;
3604  /*  /*
3605   *          } else {   *          } else {
3606   *               assert(0);   *               assert(0);
3607   */   */
3608              }              }
3609              looking_for_tag = 1;              looking_for_tag = 1;
3610          }          }
3611      }      }
3612  /*  /*
3613   *  assert(! looking_for_tag);   *  assert(! looking_for_tag);
3614   */   */
3615      return result;      return result;
3616  }  }
3617    
3618  /*  /*
3619   *--------------------------------------------------------------   *--------------------------------------------------------------
3620   *   *
3621   * TagSearchFirst --   * TagSearchFirst --
3622   *   *
3623   *      This procedure is called to get the first item   *      This procedure is called to get the first item
3624   *      item that matches a preestablished search predicate   *      item that matches a preestablished search predicate
3625   *      that was set by TagSearchScan.   *      that was set by TagSearchScan.
3626   *   *
3627   * Results:   * Results:
3628   *      The return value is a pointer to the first item, or NULL   *      The return value is a pointer to the first item, or NULL
3629   *      if there is no such item.  The information at *searchPtr   *      if there is no such item.  The information at *searchPtr
3630   *      is updated such that successive calls to TagSearchNext   *      is updated such that successive calls to TagSearchNext
3631   *      will return successive items.   *      will return successive items.
3632   *   *
3633   * Side effects:   * Side effects:
3634   *      SearchPtr is linked into a list of searches in progress   *      SearchPtr is linked into a list of searches in progress
3635   *      on canvasPtr, so that elements can safely be deleted   *      on canvasPtr, so that elements can safely be deleted
3636   *      while the search is in progress.   *      while the search is in progress.
3637   *   *
3638   *--------------------------------------------------------------   *--------------------------------------------------------------
3639   */   */
3640    
3641  static Tk_Item *  static Tk_Item *
3642  TagSearchFirst(searchPtr)  TagSearchFirst(searchPtr)
3643      TagSearch *searchPtr;               /* Record describing tag search */      TagSearch *searchPtr;               /* Record describing tag search */
3644  {  {
3645      Tk_Item *itemPtr, *lastPtr;      Tk_Item *itemPtr, *lastPtr;
3646      Tk_Uid uid, *tagPtr;      Tk_Uid uid, *tagPtr;
3647      int count;      int count;
3648    
3649      /* short circuit impossible searches for null tags */      /* short circuit impossible searches for null tags */
3650      if (searchPtr->stringLength == 0) {      if (searchPtr->stringLength == 0) {
3651          return NULL;          return NULL;
3652      }      }
3653    
3654      /*      /*
3655       * Find the first matching item in one of several ways. If the tag       * Find the first matching item in one of several ways. If the tag
3656       * is a number then it selects the single item with the matching       * is a number then it selects the single item with the matching
3657       * identifier.  In this case see if the item being requested is the       * identifier.  In this case see if the item being requested is the
3658       * hot item, in which case the search can be skipped.       * hot item, in which case the search can be skipped.
3659       */       */
3660    
3661      if (searchPtr->type == 1) {      if (searchPtr->type == 1) {
3662          Tcl_HashEntry *entryPtr;          Tcl_HashEntry *entryPtr;
3663    
3664          itemPtr = searchPtr->canvasPtr->hotPtr;          itemPtr = searchPtr->canvasPtr->hotPtr;
3665          lastPtr = searchPtr->canvasPtr->hotPrevPtr;          lastPtr = searchPtr->canvasPtr->hotPrevPtr;
3666          if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id) || (lastPtr == NULL)          if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id) || (lastPtr == NULL)
3667              || (lastPtr->nextPtr != itemPtr)) {              || (lastPtr->nextPtr != itemPtr)) {
3668              entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable,              entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable,
3669                  (char *) searchPtr->id);                  (char *) searchPtr->id);
3670              if (entryPtr != NULL) {              if (entryPtr != NULL) {
3671                  itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);                  itemPtr = (Tk_Item *)Tcl_GetHashValue(entryPtr);
3672                  lastPtr = itemPtr->prevPtr;                  lastPtr = itemPtr->prevPtr;
3673              } else {              } else {
3674                  lastPtr = itemPtr = NULL;                  lastPtr = itemPtr = NULL;
3675              }              }
3676          }          }
3677          searchPtr->lastPtr = lastPtr;          searchPtr->lastPtr = lastPtr;
3678          searchPtr->searchOver = 1;          searchPtr->searchOver = 1;
3679          searchPtr->canvasPtr->hotPtr = itemPtr;          searchPtr->canvasPtr->hotPtr = itemPtr;
3680          searchPtr->canvasPtr->hotPrevPtr = lastPtr;          searchPtr->canvasPtr->hotPrevPtr = lastPtr;
3681          return itemPtr;          return itemPtr;
3682      }      }
3683    
3684      if (searchPtr->type == 2) {      if (searchPtr->type == 2) {
3685    
3686          /*          /*
3687           * All items match.           * All items match.
3688           */           */
3689    
3690          searchPtr->lastPtr = NULL;          searchPtr->lastPtr = NULL;
3691          searchPtr->currentPtr = searchPtr->canvasPtr->firstItemPtr;          searchPtr->currentPtr = searchPtr->canvasPtr->firstItemPtr;
3692          return searchPtr->canvasPtr->firstItemPtr;          return searchPtr->canvasPtr->firstItemPtr;
3693      }      }
3694    
3695      if (searchPtr->type == 3) {      if (searchPtr->type == 3) {
3696    
3697          /*          /*
3698           * Optimized single-tag search           * Optimized single-tag search
3699           */           */
3700    
3701          uid = searchPtr->expr->uid;          uid = searchPtr->expr->uid;
3702          for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;          for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;
3703                  itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {                  itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
3704              for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;              for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
3705                      count > 0; tagPtr++, count--) {                      count > 0; tagPtr++, count--) {
3706                  if (*tagPtr == uid) {                  if (*tagPtr == uid) {
3707                      searchPtr->lastPtr = lastPtr;                      searchPtr->lastPtr = lastPtr;
3708                      searchPtr->currentPtr = itemPtr;                      searchPtr->currentPtr = itemPtr;
3709                      return itemPtr;                      return itemPtr;
3710                  }                  }
3711              }              }
3712          }          }
3713      } else {      } else {
3714    
3715      /*      /*
3716           * None of the above.  Search for an item matching the tag expression.           * None of the above.  Search for an item matching the tag expression.
3717       */       */
3718    
3719      for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;      for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;
3720                  itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {                  itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
3721              searchPtr->expr->index = 0;              searchPtr->expr->index = 0;
3722              if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {              if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
3723              searchPtr->lastPtr = lastPtr;              searchPtr->lastPtr = lastPtr;
3724              searchPtr->currentPtr = itemPtr;              searchPtr->currentPtr = itemPtr;
3725              return itemPtr;              return itemPtr;
3726          }          }
3727          }          }
3728      }      }
3729      searchPtr->lastPtr = lastPtr;      searchPtr->lastPtr = lastPtr;
3730      searchPtr->searchOver = 1;      searchPtr->searchOver = 1;
3731      return NULL;      return NULL;
3732  }  }
3733    
3734  /*  /*
3735   *--------------------------------------------------------------   *--------------------------------------------------------------
3736   *   *
3737   * TagSearchNext --   * TagSearchNext --
3738   *   *
3739   *      This procedure returns successive items that match a given   *      This procedure returns successive items that match a given
3740   *      tag;  it should be called only after TagSearchFirst has been   *      tag;  it should be called only after TagSearchFirst has been
3741   *      used to begin a search.   *      used to begin a search.
3742   *   *
3743   * Results:   * Results:
3744   *      The return value is a pointer to the next item that matches   *      The return value is a pointer to the next item that matches
3745   *      the tag expr specified to TagSearchScan, or NULL if no such   *      the tag expr specified to TagSearchScan, or NULL if no such
3746   *      item exists.  *SearchPtr is updated so that the next call   *      item exists.  *SearchPtr is updated so that the next call
3747   *      to this procedure will return the next item.   *      to this procedure will return the next item.
3748   *   *
3749   * Side effects:   * Side effects:
3750   *      None.   *      None.
3751   *   *
3752   *--------------------------------------------------------------   *--------------------------------------------------------------
3753   */   */
3754    
3755  static Tk_Item *  static Tk_Item *
3756  TagSearchNext(searchPtr)  TagSearchNext(searchPtr)
3757      TagSearch *searchPtr;               /* Record describing search in      TagSearch *searchPtr;               /* Record describing search in
3758                                           * progress. */                                           * progress. */
3759  {  {
3760      Tk_Item *itemPtr, *lastPtr;      Tk_Item *itemPtr, *lastPtr;
3761      Tk_Uid uid, *tagPtr;      Tk_Uid uid, *tagPtr;
3762      int count;      int count;
3763    
3764      /*      /*
3765       * Find next item in list (this may not actually be a suitable       * Find next item in list (this may not actually be a suitable
3766       * one to return), and return if there are no items left.       * one to return), and return if there are no items left.
3767       */       */
3768    
3769      lastPtr = searchPtr->lastPtr;      lastPtr = searchPtr->lastPtr;
3770      if (lastPtr == NULL) {      if (lastPtr == NULL) {
3771          itemPtr = searchPtr->canvasPtr->firstItemPtr;          itemPtr = searchPtr->canvasPtr->firstItemPtr;
3772      } else {      } else {
3773          itemPtr = lastPtr->nextPtr;          itemPtr = lastPtr->nextPtr;
3774      }      }
3775      if ((itemPtr == NULL) || (searchPtr->searchOver)) {      if ((itemPtr == NULL) || (searchPtr->searchOver)) {
3776          searchPtr->searchOver = 1;          searchPtr->searchOver = 1;
3777          return NULL;          return NULL;
3778      }      }
3779      if (itemPtr != searchPtr->currentPtr) {      if (itemPtr != searchPtr->currentPtr) {
3780          /*          /*
3781           * The structure of the list has changed.  Probably the           * The structure of the list has changed.  Probably the
3782           * previously-returned item was removed from the list.           * previously-returned item was removed from the list.
3783           * In this case, don't advance lastPtr;  just return           * In this case, don't advance lastPtr;  just return
3784           * its new successor (i.e. do nothing here).           * its new successor (i.e. do nothing here).
3785           */           */
3786      } else {      } else {
3787          lastPtr = itemPtr;          lastPtr = itemPtr;
3788          itemPtr = lastPtr->nextPtr;          itemPtr = lastPtr->nextPtr;
3789      }      }
3790    
3791      if (searchPtr->type == 2) {      if (searchPtr->type == 2) {
3792    
3793          /*          /*
3794           * All items match.           * All items match.
3795           */           */
3796    
3797          searchPtr->lastPtr = lastPtr;          searchPtr->lastPtr = lastPtr;
3798          searchPtr->currentPtr = itemPtr;          searchPtr->currentPtr = itemPtr;
3799          return itemPtr;          return itemPtr;
3800      }      }
3801    
3802      if (searchPtr->type == 3) {      if (searchPtr->type == 3) {
3803    
3804          /*          /*
3805           * Optimized single-tag search           * Optimized single-tag search
3806           */           */
3807    
3808          uid = searchPtr->expr->uid;          uid = searchPtr->expr->uid;
3809          for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {          for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
3810              for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;              for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
3811                      count > 0; tagPtr++, count--) {                      count > 0; tagPtr++, count--) {
3812                  if (*tagPtr == uid) {                  if (*tagPtr == uid) {
3813                      searchPtr->lastPtr = lastPtr;                      searchPtr->lastPtr = lastPtr;
3814                      searchPtr->currentPtr = itemPtr;                      searchPtr->currentPtr = itemPtr;
3815                      return itemPtr;                      return itemPtr;
3816                  }                  }
3817              }              }
3818          }          }
3819          searchPtr->lastPtr = lastPtr;          searchPtr->lastPtr = lastPtr;
3820          searchPtr->searchOver = 1;          searchPtr->searchOver = 1;
3821          return NULL;          return NULL;
3822      }      }
3823    
3824      /*      /*
3825       * Else.... evaluate tag expression       * Else.... evaluate tag expression
3826       */       */
3827    
3828      for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {      for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
3829          searchPtr->expr->index = 0;          searchPtr->expr->index = 0;
3830          if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {          if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
3831              searchPtr->lastPtr = lastPtr;              searchPtr->lastPtr = lastPtr;
3832              searchPtr->currentPtr = itemPtr;              searchPtr->currentPtr = itemPtr;
3833              return itemPtr;              return itemPtr;
3834          }          }
3835      }      }
3836      searchPtr->lastPtr = lastPtr;      searchPtr->lastPtr = lastPtr;
3837      searchPtr->searchOver = 1;      searchPtr->searchOver = 1;
3838      return NULL;      return NULL;
3839  }  }
3840  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
3841    
3842  /*  /*
3843   *--------------------------------------------------------------   *--------------------------------------------------------------
3844   *   *
3845   * DoItem --   * DoItem --
3846   *   *
3847   *      This is a utility procedure called by FindItems.  It   *      This is a utility procedure called by FindItems.  It
3848   *      either adds itemPtr's id to the result forming in interp,   *      either adds itemPtr's id to the result forming in interp,
3849   *      or it adds a new tag to itemPtr, depending on the value   *      or it adds a new tag to itemPtr, depending on the value
3850   *      of tag.   *      of tag.
3851   *   *
3852   * Results:   * Results:
3853   *      None.   *      None.
3854   *   *
3855   * Side effects:   * Side effects:
3856   *      If tag is NULL then itemPtr's id is added as a list element   *      If tag is NULL then itemPtr's id is added as a list element
3857   *      to the interp's result;  otherwise tag is added to itemPtr's   *      to the interp's result;  otherwise tag is added to itemPtr's
3858   *      list of tags.   *      list of tags.
3859   *   *
3860   *--------------------------------------------------------------   *--------------------------------------------------------------
3861   */   */
3862    
3863  static void  static void
3864  DoItem(interp, itemPtr, tag)  DoItem(interp, itemPtr, tag)
3865      Tcl_Interp *interp;                 /* Interpreter in which to (possibly)      Tcl_Interp *interp;                 /* Interpreter in which to (possibly)
3866                                           * record item id. */                                           * record item id. */
3867      Tk_Item *itemPtr;                   /* Item to (possibly) modify. */      Tk_Item *itemPtr;                   /* Item to (possibly) modify. */
3868      Tk_Uid tag;                         /* Tag to add to those already      Tk_Uid tag;                         /* Tag to add to those already
3869                                           * present for item, or NULL. */                                           * present for item, or NULL. */
3870  {  {
3871      Tk_Uid *tagPtr;      Tk_Uid *tagPtr;
3872      int count;      int count;
3873    
3874      /*      /*
3875       * Handle the "add-to-result" case and return, if appropriate.       * Handle the "add-to-result" case and return, if appropriate.
3876       */       */
3877    
3878      if (tag == NULL) {      if (tag == NULL) {
3879          char msg[TCL_INTEGER_SPACE];          char msg[TCL_INTEGER_SPACE];
3880    
3881          sprintf(msg, "%d", itemPtr->id);          sprintf(msg, "%d", itemPtr->id);
3882          Tcl_AppendElement(interp, msg);          Tcl_AppendElement(interp, msg);
3883          return;          return;
3884      }      }
3885    
3886      for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;      for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
3887              count > 0; tagPtr++, count--) {              count > 0; tagPtr++, count--) {
3888          if (tag == *tagPtr) {          if (tag == *tagPtr) {
3889              return;              return;
3890          }          }
3891      }      }
3892    
3893      /*      /*
3894       * Grow the tag space if there's no more room left in the current       * Grow the tag space if there's no more room left in the current
3895       * block.       * block.
3896       */       */
3897    
3898      if (itemPtr->tagSpace == itemPtr->numTags) {      if (itemPtr->tagSpace == itemPtr->numTags) {
3899          Tk_Uid *newTagPtr;          Tk_Uid *newTagPtr;
3900    
3901          itemPtr->tagSpace += 5;          itemPtr->tagSpace += 5;
3902          newTagPtr = (Tk_Uid *) ckalloc((unsigned)          newTagPtr = (Tk_Uid *) ckalloc((unsigned)
3903                  (itemPtr->tagSpace * sizeof(Tk_Uid)));                  (itemPtr->tagSpace * sizeof(Tk_Uid)));
3904          memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,          memcpy((VOID *) newTagPtr, (VOID *) itemPtr->tagPtr,
3905                  (itemPtr->numTags * sizeof(Tk_Uid)));                  (itemPtr->numTags * sizeof(Tk_Uid)));
3906          if (itemPtr->tagPtr != itemPtr->staticTagSpace) {          if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
3907              ckfree((char *) itemPtr->tagPtr);              ckfree((char *) itemPtr->tagPtr);
3908          }          }
3909          itemPtr->tagPtr = newTagPtr;          itemPtr->tagPtr = newTagPtr;
3910          tagPtr = &itemPtr->tagPtr[itemPtr->numTags];          tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
3911      }      }
3912    
3913      /*      /*
3914       * Add in the new tag.       * Add in the new tag.
3915       */       */
3916    
3917      *tagPtr = tag;      *tagPtr = tag;
3918      itemPtr->numTags++;      itemPtr->numTags++;
3919  }  }
3920    
3921  /*  /*
3922   *--------------------------------------------------------------   *--------------------------------------------------------------
3923   *   *
3924   * FindItems --   * FindItems --
3925   *   *
3926   *      This procedure does all the work of implementing the   *      This procedure does all the work of implementing the
3927   *      "find" and "addtag" options of the canvas widget command,   *      "find" and "addtag" options of the canvas widget command,
3928   *      which locate items that have certain features (location,   *      which locate items that have certain features (location,
3929   *      tags, position in display list, etc.).   *      tags, position in display list, etc.).
3930   *   *
3931   * Results:   * Results:
3932   *      A standard Tcl return value.  If newTag is NULL, then a   *      A standard Tcl return value.  If newTag is NULL, then a
3933   *      list of ids from all the items that match argc/argv is   *      list of ids from all the items that match argc/argv is
3934   *      returned in the interp's result.  If newTag is NULL, then   *      returned in the interp's result.  If newTag is NULL, then
3935   *      the normal the interp's result is an empty string.  If an error   *      the normal the interp's result is an empty string.  If an error
3936   *      occurs, then the interp's result will hold an error message.   *      occurs, then the interp's result will hold an error message.
3937   *   *
3938   * Side effects:   * Side effects:
3939   *      If newTag is non-NULL, then all the items that match the   *      If newTag is non-NULL, then all the items that match the
3940   *      information in argc/argv have that tag added to their   *      information in argc/argv have that tag added to their
3941   *      lists of tags.   *      lists of tags.
3942   *   *
3943   *--------------------------------------------------------------   *--------------------------------------------------------------
3944   */   */
3945    
3946  static int  static int
3947  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
3948  FindItems(interp, canvasPtr, argc, argv, newTag, first)  FindItems(interp, canvasPtr, argc, argv, newTag, first)
3949  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
3950  FindItems(interp, canvasPtr, argc, argv, newTag, first, searchPtrPtr)  FindItems(interp, canvasPtr, argc, argv, newTag, first, searchPtrPtr)
3951  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
3952      Tcl_Interp *interp;                 /* Interpreter for error reporting. */      Tcl_Interp *interp;                 /* Interpreter for error reporting. */
3953      TkCanvas *canvasPtr;                /* Canvas whose items are to be      TkCanvas *canvasPtr;                /* Canvas whose items are to be
3954                                           * searched. */                                           * searched. */
3955      int argc;                           /* Number of entries in argv.  Must be      int argc;                           /* Number of entries in argv.  Must be
3956                                           * greater than zero. */                                           * greater than zero. */
3957      Tcl_Obj *CONST *argv;               /* Arguments that describe what items      Tcl_Obj *CONST *argv;               /* Arguments that describe what items
3958                                           * to search for (see user doc on                                           * to search for (see user doc on
3959                                           * "find" and "addtag" options). */                                           * "find" and "addtag" options). */
3960      Tcl_Obj *newTag;                    /* If non-NULL, gives new tag to set      Tcl_Obj *newTag;                    /* If non-NULL, gives new tag to set
3961                                           * on all found items;  if NULL, then                                           * on all found items;  if NULL, then
3962                                           * ids of found items are returned                                           * ids of found items are returned
3963                                           * in the interp's result. */                                           * in the interp's result. */
3964      int first;                          /* For error messages:  gives number      int first;                          /* For error messages:  gives number
3965                                           * of elements of argv which are already                                           * of elements of argv which are already
3966                                           * handled. */                                           * handled. */
3967  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
3968      TagSearch **searchPtrPtr;           /* From CanvasWidgetCmd local vars*/      TagSearch **searchPtrPtr;           /* From CanvasWidgetCmd local vars*/
3969  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
3970  {  {
3971  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
3972      TagSearch search;      TagSearch search;
3973  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
3974      Tk_Item *itemPtr;      Tk_Item *itemPtr;
3975      Tk_Uid uid;      Tk_Uid uid;
3976      int index;      int index;
3977      static char *optionStrings[] = {      static char *optionStrings[] = {
3978          "above", "all", "below", "closest",          "above", "all", "below", "closest",
3979          "enclosed", "overlapping", "withtag", NULL          "enclosed", "overlapping", "withtag", NULL
3980      };      };
3981      enum options {      enum options {
3982          CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST,          CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST,
3983          CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG          CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG
3984      };      };
3985    
3986      if (newTag != NULL) {      if (newTag != NULL) {
3987          uid = Tk_GetUid(Tcl_GetStringFromObj(newTag, NULL));          uid = Tk_GetUid(Tcl_GetStringFromObj(newTag, NULL));
3988      } else {      } else {
3989          uid = NULL;          uid = NULL;
3990      }      }
3991      if (Tcl_GetIndexFromObj(interp, argv[first], optionStrings, "search command", 0,      if (Tcl_GetIndexFromObj(interp, argv[first], optionStrings, "search command", 0,
3992              &index) != TCL_OK) {              &index) != TCL_OK) {
3993          return TCL_ERROR;          return TCL_ERROR;
3994      }      }
3995      switch ((enum options) index) {      switch ((enum options) index) {
3996        case CANV_ABOVE: {        case CANV_ABOVE: {
3997          Tk_Item *lastPtr = NULL;          Tk_Item *lastPtr = NULL;
3998          if (argc != first+2) {          if (argc != first+2) {
3999              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");
4000              return TCL_ERROR;              return TCL_ERROR;
4001          }          }
4002  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4003          for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);
4004                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
4005  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4006          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {
4007              return TCL_ERROR;              return TCL_ERROR;
4008          }          }
4009          for (itemPtr = TagSearchFirst(*searchPtrPtr);          for (itemPtr = TagSearchFirst(*searchPtrPtr);
4010                  itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {
4011  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4012              lastPtr = itemPtr;              lastPtr = itemPtr;
4013          }          }
4014          if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {          if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
4015              DoItem(interp, lastPtr->nextPtr, uid);              DoItem(interp, lastPtr->nextPtr, uid);
4016          }          }
4017          break;          break;
4018        }        }
4019        case CANV_ALL: {        case CANV_ALL: {
4020          if (argc != first+1) {          if (argc != first+1) {
4021              Tcl_WrongNumArgs(interp, first+1, argv, (char *) NULL);              Tcl_WrongNumArgs(interp, first+1, argv, (char *) NULL);
4022              return TCL_ERROR;              return TCL_ERROR;
4023          }          }
4024    
4025          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;          for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
4026                  itemPtr = itemPtr->nextPtr) {                  itemPtr = itemPtr->nextPtr) {
4027              DoItem(interp, itemPtr, uid);              DoItem(interp, itemPtr, uid);
4028          }          }
4029          break;          break;
4030        }        }
4031        case CANV_BELOW: {        case CANV_BELOW: {
4032          Tk_Item *itemPtr;          Tk_Item *itemPtr;
4033    
4034          if (argc != first+2) {          if (argc != first+2) {
4035              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");
4036              return TCL_ERROR;              return TCL_ERROR;
4037          }          }
4038  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4039          itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);          itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);
4040  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4041          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {
4042              return TCL_ERROR;              return TCL_ERROR;
4043          }          }
4044          itemPtr = TagSearchFirst(*searchPtrPtr);          itemPtr = TagSearchFirst(*searchPtrPtr);
4045  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4046          if (itemPtr != NULL) {          if (itemPtr != NULL) {
4047              if (itemPtr->prevPtr != NULL) {              if (itemPtr->prevPtr != NULL) {
4048                  DoItem(interp, itemPtr->prevPtr, uid);                  DoItem(interp, itemPtr->prevPtr, uid);
4049              }              }
4050          }          }
4051          break;          break;
4052        }        }
4053        case CANV_CLOSEST: {        case CANV_CLOSEST: {
4054          double closestDist;          double closestDist;
4055          Tk_Item *startPtr, *closestPtr;          Tk_Item *startPtr, *closestPtr;
4056          double coords[2], halo;          double coords[2], halo;
4057          int x1, y1, x2, y2;          int x1, y1, x2, y2;
4058    
4059          if ((argc < first+3) || (argc > first+5)) {          if ((argc < first+3) || (argc > first+5)) {
4060              Tcl_WrongNumArgs(interp, first+1, argv, "x y ?halo? ?start?");              Tcl_WrongNumArgs(interp, first+1, argv, "x y ?halo? ?start?");
4061              return TCL_ERROR;              return TCL_ERROR;
4062          }          }
4063          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+1],          if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+1],
4064                  &coords[0]) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,                  &coords[0]) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,
4065                  (Tk_Canvas) canvasPtr, argv[first+2], &coords[1]) != TCL_OK)) {                  (Tk_Canvas) canvasPtr, argv[first+2], &coords[1]) != TCL_OK)) {
4066              return TCL_ERROR;              return TCL_ERROR;
4067          }          }
4068          if (argc > first+3) {          if (argc > first+3) {
4069              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+3],              if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[first+3],
4070                      &halo) != TCL_OK) {                      &halo) != TCL_OK) {
4071                  return TCL_ERROR;                  return TCL_ERROR;
4072              }              }
4073              if (halo < 0.0) {              if (halo < 0.0) {
4074                  Tcl_AppendResult(interp, "can't have negative halo value \"",                  Tcl_AppendResult(interp, "can't have negative halo value \"",
4075                          Tcl_GetString(argv[3]), "\"", (char *) NULL);                          Tcl_GetString(argv[3]), "\"", (char *) NULL);
4076                  return TCL_ERROR;                  return TCL_ERROR;
4077              }              }
4078          } else {          } else {
4079              halo = 0.0;              halo = 0.0;
4080          }          }
4081    
4082          /*          /*
4083           * Find the item at which to start the search.           * Find the item at which to start the search.
4084           */           */
4085    
4086          startPtr = canvasPtr->firstItemPtr;          startPtr = canvasPtr->firstItemPtr;
4087          if (argc == first+5) {          if (argc == first+5) {
4088  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4089              itemPtr = StartTagSearch(canvasPtr, argv[first+4], &search);              itemPtr = StartTagSearch(canvasPtr, argv[first+4], &search);
4090  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4091              if (TagSearchScan(canvasPtr, argv[first+4], searchPtrPtr) != TCL_OK) {              if (TagSearchScan(canvasPtr, argv[first+4], searchPtrPtr) != TCL_OK) {
4092                  return TCL_ERROR;                  return TCL_ERROR;
4093              }              }
4094              itemPtr = TagSearchFirst(*searchPtrPtr);              itemPtr = TagSearchFirst(*searchPtrPtr);
4095  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4096              if (itemPtr != NULL) {              if (itemPtr != NULL) {
4097                  startPtr = itemPtr;                  startPtr = itemPtr;
4098              }              }
4099          }          }
4100    
4101          /*          /*
4102           * The code below is optimized so that it can eliminate most           * The code below is optimized so that it can eliminate most
4103           * items without having to call their item-specific procedures.           * items without having to call their item-specific procedures.
4104           * This is done by keeping a bounding box (x1, y1, x2, y2) that           * This is done by keeping a bounding box (x1, y1, x2, y2) that
4105           * an item's bbox must overlap if the item is to have any           * an item's bbox must overlap if the item is to have any
4106           * chance of being closer than the closest so far.           * chance of being closer than the closest so far.
4107           */           */
4108    
4109          itemPtr = startPtr;          itemPtr = startPtr;
4110          while(itemPtr && (itemPtr->state == TK_STATE_HIDDEN ||          while(itemPtr && (itemPtr->state == TK_STATE_HIDDEN ||
4111              (itemPtr->state == TK_STATE_NULL && canvasPtr->canvas_state == TK_STATE_HIDDEN))) {              (itemPtr->state == TK_STATE_NULL && canvasPtr->canvas_state == TK_STATE_HIDDEN))) {
4112              itemPtr = itemPtr->nextPtr;              itemPtr = itemPtr->nextPtr;
4113          }          }
4114          if (itemPtr == NULL) {          if (itemPtr == NULL) {
4115              return TCL_OK;              return TCL_OK;
4116          }          }
4117          closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,          closestDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
4118                  itemPtr, coords) - halo;                  itemPtr, coords) - halo;
4119          if (closestDist < 0.0) {          if (closestDist < 0.0) {
4120              closestDist = 0.0;              closestDist = 0.0;
4121          }          }
4122          while (1) {          while (1) {
4123              double newDist;              double newDist;
4124    
4125              /*              /*
4126               * Update the bounding box using itemPtr, which is the               * Update the bounding box using itemPtr, which is the
4127               * new closest item.               * new closest item.
4128               */               */
4129    
4130              x1 = (int) (coords[0] - closestDist - halo - 1);              x1 = (int) (coords[0] - closestDist - halo - 1);
4131              y1 = (int) (coords[1] - closestDist - halo - 1);              y1 = (int) (coords[1] - closestDist - halo - 1);
4132              x2 = (int) (coords[0] + closestDist + halo + 1);              x2 = (int) (coords[0] + closestDist + halo + 1);
4133              y2 = (int) (coords[1] + closestDist + halo + 1);              y2 = (int) (coords[1] + closestDist + halo + 1);
4134              closestPtr = itemPtr;              closestPtr = itemPtr;
4135    
4136              /*              /*
4137               * Search for an item that beats the current closest one.               * Search for an item that beats the current closest one.
4138               * Work circularly through the canvas's item list until               * Work circularly through the canvas's item list until
4139               * getting back to the starting item.               * getting back to the starting item.
4140               */               */
4141    
4142              while (1) {              while (1) {
4143                  itemPtr = itemPtr->nextPtr;                  itemPtr = itemPtr->nextPtr;
4144                  if (itemPtr == NULL) {                  if (itemPtr == NULL) {
4145                      itemPtr = canvasPtr->firstItemPtr;                      itemPtr = canvasPtr->firstItemPtr;
4146                  }                  }
4147                  if (itemPtr == startPtr) {                  if (itemPtr == startPtr) {
4148                      DoItem(interp, closestPtr, uid);                      DoItem(interp, closestPtr, uid);
4149                      return TCL_OK;                      return TCL_OK;
4150                  }                  }
4151                  if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL &&                  if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL &&
4152                          canvasPtr->canvas_state == TK_STATE_HIDDEN)) {                          canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
4153                      continue;                      continue;
4154                  }                  }
4155                  if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)                  if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
4156                          || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {                          || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
4157                      continue;                      continue;
4158                  }                  }
4159                  newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,                  newDist = (*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
4160                          itemPtr, coords) - halo;                          itemPtr, coords) - halo;
4161                  if (newDist < 0.0) {                  if (newDist < 0.0) {
4162                      newDist = 0.0;                      newDist = 0.0;
4163                  }                  }
4164                  if (newDist <= closestDist) {                  if (newDist <= closestDist) {
4165                      closestDist = newDist;                      closestDist = newDist;
4166                      break;                      break;
4167                  }                  }
4168              }              }
4169          }          }
4170          break;          break;
4171        }        }
4172        case CANV_ENCLOSED: {        case CANV_ENCLOSED: {
4173          if (argc != first+5) {          if (argc != first+5) {
4174              Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2");              Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2");
4175              return TCL_ERROR;              return TCL_ERROR;
4176          }          }
4177          return FindArea(interp, canvasPtr, argv+first+1, uid, 1);          return FindArea(interp, canvasPtr, argv+first+1, uid, 1);
4178        }        }
4179        case CANV_OVERLAPPING: {        case CANV_OVERLAPPING: {
4180          if (argc != first+5) {          if (argc != first+5) {
4181              Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2");              Tcl_WrongNumArgs(interp, first+1, argv, "x1 y1 x2 y2");
4182              return TCL_ERROR;              return TCL_ERROR;
4183          }          }
4184          return FindArea(interp, canvasPtr, argv+first+1, uid, 0);          return FindArea(interp, canvasPtr, argv+first+1, uid, 0);
4185        }        }
4186        case CANV_WITHTAG: {        case CANV_WITHTAG: {
4187          if (argc != first+2) {          if (argc != first+2) {
4188              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");              Tcl_WrongNumArgs(interp, first+1, argv, "tagOrId");
4189              return TCL_ERROR;              return TCL_ERROR;
4190          }          }
4191  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4192          for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);          for (itemPtr = StartTagSearch(canvasPtr, argv[first+1], &search);
4193                  itemPtr != NULL; itemPtr = NextItem(&search)) {                  itemPtr != NULL; itemPtr = NextItem(&search)) {
4194  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4195          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {          if (TagSearchScan(canvasPtr, argv[first+1], searchPtrPtr) != TCL_OK) {
4196              return TCL_ERROR;              return TCL_ERROR;
4197          }          }
4198          for (itemPtr = TagSearchFirst(*searchPtrPtr);          for (itemPtr = TagSearchFirst(*searchPtrPtr);
4199                  itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {                  itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {
4200  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4201              DoItem(interp, itemPtr, uid);              DoItem(interp, itemPtr, uid);
4202          }          }
4203        }        }
4204      }      }
4205      return TCL_OK;      return TCL_OK;
4206  }  }
4207    
4208  /*  /*
4209   *--------------------------------------------------------------   *--------------------------------------------------------------
4210   *   *
4211   * FindArea --   * FindArea --
4212   *   *
4213   *      This procedure implements area searches for the "find"   *      This procedure implements area searches for the "find"
4214   *      and "addtag" options.   *      and "addtag" options.
4215   *   *
4216   * Results:   * Results:
4217   *      A standard Tcl return value.  If newTag is NULL, then a   *      A standard Tcl return value.  If newTag is NULL, then a
4218   *      list of ids from all the items overlapping or enclosed   *      list of ids from all the items overlapping or enclosed
4219   *      by the rectangle given by argc is returned in the interp's result.   *      by the rectangle given by argc is returned in the interp's result.
4220   *      If newTag is NULL, then the normal the interp's result is an   *      If newTag is NULL, then the normal the interp's result is an
4221   *      empty string.  If an error occurs, then the interp's result will   *      empty string.  If an error occurs, then the interp's result will
4222   *      hold an error message.   *      hold an error message.
4223   *   *
4224   * Side effects:   * Side effects:
4225   *      If uid is non-NULL, then all the items overlapping   *      If uid is non-NULL, then all the items overlapping
4226   *      or enclosed by the area in argv have that tag added to   *      or enclosed by the area in argv have that tag added to
4227   *      their lists of tags.   *      their lists of tags.
4228   *   *
4229   *--------------------------------------------------------------   *--------------------------------------------------------------
4230   */   */
4231    
4232  static int  static int
4233  FindArea(interp, canvasPtr, argv, uid, enclosed)  FindArea(interp, canvasPtr, argv, uid, enclosed)
4234      Tcl_Interp *interp;                 /* Interpreter for error reporting      Tcl_Interp *interp;                 /* Interpreter for error reporting
4235                                           * and result storing. */                                           * and result storing. */
4236      TkCanvas *canvasPtr;                /* Canvas whose items are to be      TkCanvas *canvasPtr;                /* Canvas whose items are to be
4237                                           * searched. */                                           * searched. */
4238      Tcl_Obj *CONST *argv;               /* Array of four arguments that      Tcl_Obj *CONST *argv;               /* Array of four arguments that
4239                                           * give the coordinates of the                                           * give the coordinates of the
4240                                           * rectangular area to search. */                                           * rectangular area to search. */
4241      Tk_Uid uid;                         /* If non-NULL, gives new tag to set      Tk_Uid uid;                         /* If non-NULL, gives new tag to set
4242                                           * on all found items;  if NULL, then                                           * on all found items;  if NULL, then
4243                                           * ids of found items are returned                                           * ids of found items are returned
4244                                           * in the interp's result. */                                           * in the interp's result. */
4245      int enclosed;                       /* 0 means overlapping or enclosed      int enclosed;                       /* 0 means overlapping or enclosed
4246                                           * items are OK, 1 means only enclosed                                           * items are OK, 1 means only enclosed
4247                                           * items are OK. */                                           * items are OK. */
4248  {  {
4249      double rect[4], tmp;      double rect[4], tmp;
4250      int x1, y1, x2, y2;      int x1, y1, x2, y2;
4251      Tk_Item *itemPtr;      Tk_Item *itemPtr;
4252    
4253      if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[0],      if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[0],
4254                  &rect[0]) != TCL_OK)                  &rect[0]) != TCL_OK)
4255              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[1],              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[1],
4256                  &rect[1]) != TCL_OK)                  &rect[1]) != TCL_OK)
4257              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[2],              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[2],
4258                  &rect[2]) != TCL_OK)                  &rect[2]) != TCL_OK)
4259              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],              || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, argv[3],
4260                  &rect[3]) != TCL_OK)) {                  &rect[3]) != TCL_OK)) {
4261          return TCL_ERROR;          return TCL_ERROR;
4262      }      }
4263      if (rect[0] > rect[2]) {      if (rect[0] > rect[2]) {
4264          tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;          tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
4265      }      }
4266      if (rect[1] > rect[3]) {      if (rect[1] > rect[3]) {
4267          tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;          tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
4268      }      }
4269    
4270      /*      /*
4271       * Use an integer bounding box for a quick test, to avoid       * Use an integer bounding box for a quick test, to avoid
4272       * calling item-specific code except for items that are close.       * calling item-specific code except for items that are close.
4273       */       */
4274    
4275      x1 = (int) (rect[0]-1.0);      x1 = (int) (rect[0]-1.0);
4276      y1 = (int) (rect[1]-1.0);      y1 = (int) (rect[1]-1.0);
4277      x2 = (int) (rect[2]+1.0);      x2 = (int) (rect[2]+1.0);
4278      y2 = (int) (rect[3]+1.0);      y2 = (int) (rect[3]+1.0);
4279      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
4280              itemPtr = itemPtr->nextPtr) {              itemPtr = itemPtr->nextPtr) {
4281          if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL &&          if (itemPtr->state == TK_STATE_HIDDEN || (itemPtr->state == TK_STATE_NULL &&
4282                  canvasPtr->canvas_state == TK_STATE_HIDDEN)) {                  canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
4283              continue;              continue;
4284          }          }
4285          if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)          if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
4286                  || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {                  || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
4287              continue;              continue;
4288          }          }
4289          if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect)          if ((*itemPtr->typePtr->areaProc)((Tk_Canvas) canvasPtr, itemPtr, rect)
4290                  >= enclosed) {                  >= enclosed) {
4291              DoItem(interp, itemPtr, uid);              DoItem(interp, itemPtr, uid);
4292          }          }
4293      }      }
4294      return TCL_OK;      return TCL_OK;
4295  }  }
4296    
4297  /*  /*
4298   *--------------------------------------------------------------   *--------------------------------------------------------------
4299   *   *
4300   * RelinkItems --   * RelinkItems --
4301   *   *
4302   *      Move one or more items to a different place in the   *      Move one or more items to a different place in the
4303   *      display order for a canvas.   *      display order for a canvas.
4304   *   *
4305   * Results:   * Results:
4306   *      None.   *      None.
4307   *   *
4308   * Side effects:   * Side effects:
4309   *      The items identified by "tag" are moved so that they   *      The items identified by "tag" are moved so that they
4310   *      are all together in the display list and immediately   *      are all together in the display list and immediately
4311   *      after prevPtr.  The order of the moved items relative   *      after prevPtr.  The order of the moved items relative
4312   *      to each other is not changed.   *      to each other is not changed.
4313   *   *
4314   *--------------------------------------------------------------   *--------------------------------------------------------------
4315   */   */
4316    
4317  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4318  static void  static void
4319  RelinkItems(canvasPtr, tag, prevPtr)  RelinkItems(canvasPtr, tag, prevPtr)
4320  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4321  static int  static int
4322  RelinkItems(canvasPtr, tag, prevPtr, searchPtrPtr)  RelinkItems(canvasPtr, tag, prevPtr, searchPtrPtr)
4323  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4324      TkCanvas *canvasPtr;        /* Canvas to be modified. */      TkCanvas *canvasPtr;        /* Canvas to be modified. */
4325      Tcl_Obj *tag;               /* Tag identifying items to be moved      Tcl_Obj *tag;               /* Tag identifying items to be moved
4326                                   * in the redisplay list. */                                   * in the redisplay list. */
4327      Tk_Item *prevPtr;           /* Reposition the items so that they      Tk_Item *prevPtr;           /* Reposition the items so that they
4328                                   * go just after this item (NULL means                                   * go just after this item (NULL means
4329                                   * put at beginning of list). */                                   * put at beginning of list). */
4330  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
4331      TagSearch **searchPtrPtr;   /* From CanvasWidgetCmd local vars */      TagSearch **searchPtrPtr;   /* From CanvasWidgetCmd local vars */
4332  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
4333  {  {
4334      Tk_Item *itemPtr;      Tk_Item *itemPtr;
4335  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4336      TagSearch search;      TagSearch search;
4337  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4338      Tk_Item *firstMovePtr, *lastMovePtr;      Tk_Item *firstMovePtr, *lastMovePtr;
4339    
4340      /*      /*
4341       * Find all of the items to be moved and remove them from       * Find all of the items to be moved and remove them from
4342       * the list, making an auxiliary list running from firstMovePtr       * the list, making an auxiliary list running from firstMovePtr
4343       * to lastMovePtr.  Record their areas for redisplay.       * to lastMovePtr.  Record their areas for redisplay.
4344       */       */
4345    
4346      firstMovePtr = lastMovePtr = NULL;      firstMovePtr = lastMovePtr = NULL;
4347  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4348      for (itemPtr = StartTagSearch(canvasPtr, tag, &search);      for (itemPtr = StartTagSearch(canvasPtr, tag, &search);
4349              itemPtr != NULL; itemPtr = NextItem(&search)) {              itemPtr != NULL; itemPtr = NextItem(&search)) {
4350  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4351      if (TagSearchScan(canvasPtr, tag, searchPtrPtr) != TCL_OK) {      if (TagSearchScan(canvasPtr, tag, searchPtrPtr) != TCL_OK) {
4352          return TCL_ERROR;          return TCL_ERROR;
4353      }      }
4354      for (itemPtr = TagSearchFirst(*searchPtrPtr);      for (itemPtr = TagSearchFirst(*searchPtrPtr);
4355              itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {              itemPtr != NULL; itemPtr = TagSearchNext(*searchPtrPtr)) {
4356  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4357          if (itemPtr == prevPtr) {          if (itemPtr == prevPtr) {
4358              /*              /*
4359               * Item after which insertion is to occur is being               * Item after which insertion is to occur is being
4360               * moved!  Switch to insert after its predecessor.               * moved!  Switch to insert after its predecessor.
4361               */               */
4362    
4363              prevPtr = prevPtr->prevPtr;              prevPtr = prevPtr->prevPtr;
4364          }          }
4365          if (itemPtr->prevPtr == NULL) {          if (itemPtr->prevPtr == NULL) {
4366              if (itemPtr->nextPtr != NULL) {              if (itemPtr->nextPtr != NULL) {
4367                  itemPtr->nextPtr->prevPtr = NULL;                  itemPtr->nextPtr->prevPtr = NULL;
4368              }              }
4369              canvasPtr->firstItemPtr = itemPtr->nextPtr;              canvasPtr->firstItemPtr = itemPtr->nextPtr;
4370          } else {          } else {
4371              if (itemPtr->nextPtr != NULL) {              if (itemPtr->nextPtr != NULL) {
4372                  itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;                  itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
4373              }              }
4374              itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;              itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
4375          }          }
4376          if (canvasPtr->lastItemPtr == itemPtr) {          if (canvasPtr->lastItemPtr == itemPtr) {
4377              canvasPtr->lastItemPtr = itemPtr->prevPtr;              canvasPtr->lastItemPtr = itemPtr->prevPtr;
4378          }          }
4379          if (firstMovePtr == NULL) {          if (firstMovePtr == NULL) {
4380              itemPtr->prevPtr = NULL;              itemPtr->prevPtr = NULL;
4381              firstMovePtr = itemPtr;              firstMovePtr = itemPtr;
4382          } else {          } else {
4383              itemPtr->prevPtr = lastMovePtr;              itemPtr->prevPtr = lastMovePtr;
4384              lastMovePtr->nextPtr = itemPtr;              lastMovePtr->nextPtr = itemPtr;
4385          }          }
4386          lastMovePtr = itemPtr;          lastMovePtr = itemPtr;
4387          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
4388          canvasPtr->flags |= REPICK_NEEDED;          canvasPtr->flags |= REPICK_NEEDED;
4389      }      }
4390    
4391      /*      /*
4392       * Insert the list of to-be-moved items back into the canvas's       * Insert the list of to-be-moved items back into the canvas's
4393       * at the desired position.       * at the desired position.
4394       */       */
4395    
4396      if (firstMovePtr == NULL) {      if (firstMovePtr == NULL) {
4397  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4398          return;          return;
4399  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4400          return TCL_OK;          return TCL_OK;
4401  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4402      }      }
4403      if (prevPtr == NULL) {      if (prevPtr == NULL) {
4404          if (canvasPtr->firstItemPtr != NULL) {          if (canvasPtr->firstItemPtr != NULL) {
4405              canvasPtr->firstItemPtr->prevPtr = lastMovePtr;              canvasPtr->firstItemPtr->prevPtr = lastMovePtr;
4406          }          }
4407          lastMovePtr->nextPtr = canvasPtr->firstItemPtr;          lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
4408          canvasPtr->firstItemPtr = firstMovePtr;          canvasPtr->firstItemPtr = firstMovePtr;
4409      } else {      } else {
4410          if (prevPtr->nextPtr != NULL) {          if (prevPtr->nextPtr != NULL) {
4411              prevPtr->nextPtr->prevPtr = lastMovePtr;              prevPtr->nextPtr->prevPtr = lastMovePtr;
4412          }          }
4413          lastMovePtr->nextPtr = prevPtr->nextPtr;          lastMovePtr->nextPtr = prevPtr->nextPtr;
4414          if (firstMovePtr != NULL) {          if (firstMovePtr != NULL) {
4415              firstMovePtr->prevPtr = prevPtr;              firstMovePtr->prevPtr = prevPtr;
4416          }          }
4417          prevPtr->nextPtr = firstMovePtr;          prevPtr->nextPtr = firstMovePtr;
4418      }      }
4419      if (canvasPtr->lastItemPtr == prevPtr) {      if (canvasPtr->lastItemPtr == prevPtr) {
4420          canvasPtr->lastItemPtr = lastMovePtr;          canvasPtr->lastItemPtr = lastMovePtr;
4421      }      }
4422  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
4423      return TCL_OK;      return TCL_OK;
4424  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
4425  }  }
4426    
4427  /*  /*
4428   *--------------------------------------------------------------   *--------------------------------------------------------------
4429   *   *
4430   * CanvasBindProc --   * CanvasBindProc --
4431   *   *
4432   *      This procedure is invoked by the Tk dispatcher to handle   *      This procedure is invoked by the Tk dispatcher to handle
4433   *      events associated with bindings on items.   *      events associated with bindings on items.
4434   *   *
4435   * Results:   * Results:
4436   *      None.   *      None.
4437   *   *
4438   * Side effects:   * Side effects:
4439   *      Depends on the command invoked as part of the binding   *      Depends on the command invoked as part of the binding
4440   *      (if there was any).   *      (if there was any).
4441   *   *
4442   *--------------------------------------------------------------   *--------------------------------------------------------------
4443   */   */
4444    
4445  static void  static void
4446  CanvasBindProc(clientData, eventPtr)  CanvasBindProc(clientData, eventPtr)
4447      ClientData clientData;              /* Pointer to canvas structure. */      ClientData clientData;              /* Pointer to canvas structure. */
4448      XEvent *eventPtr;                   /* Pointer to X event that just      XEvent *eventPtr;                   /* Pointer to X event that just
4449                                           * happened. */                                           * happened. */
4450  {  {
4451      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
4452    
4453      Tcl_Preserve((ClientData) canvasPtr);      Tcl_Preserve((ClientData) canvasPtr);
4454    
4455      /*      /*
4456       * This code below keeps track of the current modifier state in       * This code below keeps track of the current modifier state in
4457       * canvasPtr>state.  This information is used to defer repicks of       * canvasPtr>state.  This information is used to defer repicks of
4458       * the current item while buttons are down.       * the current item while buttons are down.
4459       */       */
4460    
4461      if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {      if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
4462          int mask;          int mask;
4463    
4464          switch (eventPtr->xbutton.button) {          switch (eventPtr->xbutton.button) {
4465              case Button1:              case Button1:
4466                  mask = Button1Mask;                  mask = Button1Mask;
4467                  break;                  break;
4468              case Button2:              case Button2:
4469                  mask = Button2Mask;                  mask = Button2Mask;
4470                  break;                  break;
4471              case Button3:              case Button3:
4472                  mask = Button3Mask;                  mask = Button3Mask;
4473                  break;                  break;
4474              case Button4:              case Button4:
4475                  mask = Button4Mask;                  mask = Button4Mask;
4476                  break;                  break;
4477              case Button5:              case Button5:
4478                  mask = Button5Mask;                  mask = Button5Mask;
4479                  break;                  break;
4480              default:              default:
4481                  mask = 0;                  mask = 0;
4482                  break;                  break;
4483          }          }
4484    
4485          /*          /*
4486           * For button press events, repick the current item using the           * For button press events, repick the current item using the
4487           * button state before the event, then process the event.  For           * button state before the event, then process the event.  For
4488           * button release events, first process the event, then repick           * button release events, first process the event, then repick
4489           * the current item using the button state *after* the event           * the current item using the button state *after* the event
4490           * (the button has logically gone up before we change the           * (the button has logically gone up before we change the
4491           * current item).           * current item).
4492           */           */
4493    
4494          if (eventPtr->type == ButtonPress) {          if (eventPtr->type == ButtonPress) {
4495              /*              /*
4496               * On a button press, first repick the current item using               * On a button press, first repick the current item using
4497               * the button state before the event, the process the event.               * the button state before the event, the process the event.
4498               */               */
4499    
4500              canvasPtr->state = eventPtr->xbutton.state;              canvasPtr->state = eventPtr->xbutton.state;
4501              PickCurrentItem(canvasPtr, eventPtr);              PickCurrentItem(canvasPtr, eventPtr);
4502              canvasPtr->state ^= mask;              canvasPtr->state ^= mask;
4503              CanvasDoEvent(canvasPtr, eventPtr);              CanvasDoEvent(canvasPtr, eventPtr);
4504          } else {          } else {
4505              /*              /*
4506               * Button release: first process the event, with the button               * Button release: first process the event, with the button
4507               * still considered to be down.  Then repick the current               * still considered to be down.  Then repick the current
4508               * item under the assumption that the button is no longer down.               * item under the assumption that the button is no longer down.
4509               */               */
4510    
4511              canvasPtr->state = eventPtr->xbutton.state;              canvasPtr->state = eventPtr->xbutton.state;
4512              CanvasDoEvent(canvasPtr, eventPtr);              CanvasDoEvent(canvasPtr, eventPtr);
4513              eventPtr->xbutton.state ^= mask;              eventPtr->xbutton.state ^= mask;
4514              canvasPtr->state = eventPtr->xbutton.state;              canvasPtr->state = eventPtr->xbutton.state;
4515              PickCurrentItem(canvasPtr, eventPtr);              PickCurrentItem(canvasPtr, eventPtr);
4516              eventPtr->xbutton.state ^= mask;              eventPtr->xbutton.state ^= mask;
4517          }          }
4518          goto done;          goto done;
4519      } else if ((eventPtr->type == EnterNotify)      } else if ((eventPtr->type == EnterNotify)
4520              || (eventPtr->type == LeaveNotify)) {              || (eventPtr->type == LeaveNotify)) {
4521          canvasPtr->state = eventPtr->xcrossing.state;          canvasPtr->state = eventPtr->xcrossing.state;
4522          PickCurrentItem(canvasPtr, eventPtr);          PickCurrentItem(canvasPtr, eventPtr);
4523          goto done;          goto done;
4524      } else if (eventPtr->type == MotionNotify) {      } else if (eventPtr->type == MotionNotify) {
4525          canvasPtr->state = eventPtr->xmotion.state;          canvasPtr->state = eventPtr->xmotion.state;
4526          PickCurrentItem(canvasPtr, eventPtr);          PickCurrentItem(canvasPtr, eventPtr);
4527      }      }
4528      CanvasDoEvent(canvasPtr, eventPtr);      CanvasDoEvent(canvasPtr, eventPtr);
4529    
4530      done:      done:
4531      Tcl_Release((ClientData) canvasPtr);      Tcl_Release((ClientData) canvasPtr);
4532  }  }
4533    
4534  /*  /*
4535   *--------------------------------------------------------------   *--------------------------------------------------------------
4536   *   *
4537   * PickCurrentItem --   * PickCurrentItem --
4538   *   *
4539   *      Find the topmost item in a canvas that contains a given   *      Find the topmost item in a canvas that contains a given
4540   *      location and mark the the current item.  If the current   *      location and mark the the current item.  If the current
4541   *      item has changed, generate a fake exit event on the old   *      item has changed, generate a fake exit event on the old
4542   *      current item, a fake enter event on the new current item   *      current item, a fake enter event on the new current item
4543   *      item and force a redraw of the two items. Canvas items   *      item and force a redraw of the two items. Canvas items
4544   *      that are hidden or disabled are ignored.   *      that are hidden or disabled are ignored.
4545   *   *
4546   * Results:   * Results:
4547   *      None.   *      None.
4548   *   *
4549   * Side effects:   * Side effects:
4550   *      The current item for canvasPtr may change.  If it does,   *      The current item for canvasPtr may change.  If it does,
4551   *      then the commands associated with item entry and exit   *      then the commands associated with item entry and exit
4552   *      could do just about anything.  A binding script could   *      could do just about anything.  A binding script could
4553   *      delete the canvas, so callers should protect themselves   *      delete the canvas, so callers should protect themselves
4554   *      with Tcl_Preserve and Tcl_Release.   *      with Tcl_Preserve and Tcl_Release.
4555   *   *
4556   *--------------------------------------------------------------   *--------------------------------------------------------------
4557   */   */
4558    
4559  static void  static void
4560  PickCurrentItem(canvasPtr, eventPtr)  PickCurrentItem(canvasPtr, eventPtr)
4561      TkCanvas *canvasPtr;                /* Canvas widget in which to select      TkCanvas *canvasPtr;                /* Canvas widget in which to select
4562                                           * current item. */                                           * current item. */
4563      XEvent *eventPtr;                   /* Event describing location of      XEvent *eventPtr;                   /* Event describing location of
4564                                           * mouse cursor.  Must be EnterWindow,                                           * mouse cursor.  Must be EnterWindow,
4565                                           * LeaveWindow, ButtonRelease, or                                           * LeaveWindow, ButtonRelease, or
4566                                           * MotionNotify. */                                           * MotionNotify. */
4567  {  {
4568      double coords[2];      double coords[2];
4569      int buttonDown;      int buttonDown;
4570      Tk_Item *prevItemPtr;      Tk_Item *prevItemPtr;
4571    
4572      /*      /*
4573       * Check whether or not a button is down.  If so, we'll log entry       * Check whether or not a button is down.  If so, we'll log entry
4574       * and exit into and out of the current item, but not entry into       * and exit into and out of the current item, but not entry into
4575       * any other item.  This implements a form of grabbing equivalent       * any other item.  This implements a form of grabbing equivalent
4576       * to what the X server does for windows.       * to what the X server does for windows.
4577       */       */
4578    
4579      buttonDown = canvasPtr->state      buttonDown = canvasPtr->state
4580              & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);              & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
4581      if (!buttonDown) {      if (!buttonDown) {
4582          canvasPtr->flags &= ~LEFT_GRABBED_ITEM;          canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
4583      }      }
4584    
4585      /*      /*
4586       * Save information about this event in the canvas.  The event in       * Save information about this event in the canvas.  The event in
4587       * the canvas is used for two purposes:       * the canvas is used for two purposes:
4588       *       *
4589       * 1. Event bindings: if the current item changes, fake events are       * 1. Event bindings: if the current item changes, fake events are
4590       *    generated to allow item-enter and item-leave bindings to trigger.       *    generated to allow item-enter and item-leave bindings to trigger.
4591       * 2. Reselection: if the current item gets deleted, can use the       * 2. Reselection: if the current item gets deleted, can use the
4592       *    saved event to find a new current item.       *    saved event to find a new current item.
4593       * Translate MotionNotify events into EnterNotify events, since that's       * Translate MotionNotify events into EnterNotify events, since that's
4594       * what gets reported to item handlers.       * what gets reported to item handlers.
4595       */       */
4596    
4597      if (eventPtr != &canvasPtr->pickEvent) {      if (eventPtr != &canvasPtr->pickEvent) {
4598          if ((eventPtr->type == MotionNotify)          if ((eventPtr->type == MotionNotify)
4599                  || (eventPtr->type == ButtonRelease)) {                  || (eventPtr->type == ButtonRelease)) {
4600              canvasPtr->pickEvent.xcrossing.type = EnterNotify;              canvasPtr->pickEvent.xcrossing.type = EnterNotify;
4601              canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;              canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
4602              canvasPtr->pickEvent.xcrossing.send_event              canvasPtr->pickEvent.xcrossing.send_event
4603                      = eventPtr->xmotion.send_event;                      = eventPtr->xmotion.send_event;
4604              canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;              canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
4605              canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;              canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
4606              canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;              canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
4607              canvasPtr->pickEvent.xcrossing.subwindow = None;              canvasPtr->pickEvent.xcrossing.subwindow = None;
4608              canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;              canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
4609              canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;              canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
4610              canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;              canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
4611              canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;              canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
4612              canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;              canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
4613              canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;              canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
4614              canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;              canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
4615              canvasPtr->pickEvent.xcrossing.same_screen              canvasPtr->pickEvent.xcrossing.same_screen
4616                      = eventPtr->xmotion.same_screen;                      = eventPtr->xmotion.same_screen;
4617              canvasPtr->pickEvent.xcrossing.focus = False;              canvasPtr->pickEvent.xcrossing.focus = False;
4618              canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;              canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
4619          } else  {          } else  {
4620              canvasPtr->pickEvent = *eventPtr;              canvasPtr->pickEvent = *eventPtr;
4621          }          }
4622      }      }
4623    
4624      /*      /*
4625       * If this is a recursive call (there's already a partially completed       * If this is a recursive call (there's already a partially completed
4626       * call pending on the stack;  it's in the middle of processing a       * call pending on the stack;  it's in the middle of processing a
4627       * Leave event handler for the old current item) then just return;       * Leave event handler for the old current item) then just return;
4628       * the pending call will do everything that's needed.       * the pending call will do everything that's needed.
4629       */       */
4630    
4631      if (canvasPtr->flags & REPICK_IN_PROGRESS) {      if (canvasPtr->flags & REPICK_IN_PROGRESS) {
4632          return;          return;
4633      }      }
4634    
4635      /*      /*
4636       * A LeaveNotify event automatically means that there's no current       * A LeaveNotify event automatically means that there's no current
4637       * object, so the check for closest item can be skipped.       * object, so the check for closest item can be skipped.
4638       */       */
4639    
4640      coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;      coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
4641      coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;      coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
4642      if (canvasPtr->pickEvent.type != LeaveNotify) {      if (canvasPtr->pickEvent.type != LeaveNotify) {
4643          canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);          canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);
4644      } else {      } else {
4645          canvasPtr->newCurrentPtr = NULL;          canvasPtr->newCurrentPtr = NULL;
4646      }      }
4647    
4648      if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)      if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)
4649              && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {              && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
4650          /*          /*
4651           * Nothing to do:  the current item hasn't changed.           * Nothing to do:  the current item hasn't changed.
4652           */           */
4653    
4654          return;          return;
4655      }      }
4656    
4657      /*      /*
4658       * Simulate a LeaveNotify event on the previous current item and       * Simulate a LeaveNotify event on the previous current item and
4659       * an EnterNotify event on the new current item.  Remove the "current"       * an EnterNotify event on the new current item.  Remove the "current"
4660       * tag from the previous current item and place it on the new current       * tag from the previous current item and place it on the new current
4661       * item.       * item.
4662       */       */
4663    
4664      if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)      if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)
4665              && (canvasPtr->currentItemPtr != NULL)              && (canvasPtr->currentItemPtr != NULL)
4666              && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {              && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
4667          XEvent event;          XEvent event;
4668          Tk_Item *itemPtr = canvasPtr->currentItemPtr;          Tk_Item *itemPtr = canvasPtr->currentItemPtr;
4669          int i;          int i;
4670    
4671          event = canvasPtr->pickEvent;          event = canvasPtr->pickEvent;
4672          event.type = LeaveNotify;          event.type = LeaveNotify;
4673    
4674          /*          /*
4675           * If the event's detail happens to be NotifyInferior the           * If the event's detail happens to be NotifyInferior the
4676           * binding mechanism will discard the event.  To be consistent,           * binding mechanism will discard the event.  To be consistent,
4677           * always use NotifyAncestor.           * always use NotifyAncestor.
4678           */           */
4679    
4680          event.xcrossing.detail = NotifyAncestor;          event.xcrossing.detail = NotifyAncestor;
4681          canvasPtr->flags |= REPICK_IN_PROGRESS;          canvasPtr->flags |= REPICK_IN_PROGRESS;
4682          CanvasDoEvent(canvasPtr, &event);          CanvasDoEvent(canvasPtr, &event);
4683          canvasPtr->flags &= ~REPICK_IN_PROGRESS;          canvasPtr->flags &= ~REPICK_IN_PROGRESS;
4684    
4685          /*          /*
4686           * The check below is needed because there could be an event           * The check below is needed because there could be an event
4687           * handler for <LeaveNotify> that deletes the current item.           * handler for <LeaveNotify> that deletes the current item.
4688           */           */
4689    
4690          if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {          if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {
4691              for (i = itemPtr->numTags-1; i >= 0; i--) {              for (i = itemPtr->numTags-1; i >= 0; i--) {
4692  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4693                  if (itemPtr->tagPtr[i] == Tk_GetUid("current")) {                  if (itemPtr->tagPtr[i] == Tk_GetUid("current")) {
4694  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4695                  if (itemPtr->tagPtr[i] == currentUid) {                  if (itemPtr->tagPtr[i] == currentUid) {
4696  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4697                      itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];                      itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
4698                      itemPtr->numTags--;                      itemPtr->numTags--;
4699                      break;                      break;
4700                  }                  }
4701              }              }
4702          }          }
4703            
4704          /*          /*
4705           * Note:  during CanvasDoEvent above, it's possible that           * Note:  during CanvasDoEvent above, it's possible that
4706           * canvasPtr->newCurrentPtr got reset to NULL because the           * canvasPtr->newCurrentPtr got reset to NULL because the
4707           * item was deleted.           * item was deleted.
4708           */           */
4709      }      }
4710      if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) {      if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr) && buttonDown) {
4711          canvasPtr->flags |= LEFT_GRABBED_ITEM;          canvasPtr->flags |= LEFT_GRABBED_ITEM;
4712          return;          return;
4713      }      }
4714    
4715      /*      /*
4716       * Special note:  it's possible that canvasPtr->newCurrentPtr ==       * Special note:  it's possible that canvasPtr->newCurrentPtr ==
4717       * canvasPtr->currentItemPtr here.  This can happen, for example,       * canvasPtr->currentItemPtr here.  This can happen, for example,
4718       * if LEFT_GRABBED_ITEM was set.       * if LEFT_GRABBED_ITEM was set.
4719       */       */
4720    
4721      prevItemPtr = canvasPtr->currentItemPtr;      prevItemPtr = canvasPtr->currentItemPtr;
4722      canvasPtr->flags &= ~LEFT_GRABBED_ITEM;      canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
4723      canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;      canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;
4724      if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr &&      if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr &&
4725              (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) {              (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) {
4726          EventuallyRedrawItem((Tk_Canvas) canvasPtr, prevItemPtr);          EventuallyRedrawItem((Tk_Canvas) canvasPtr, prevItemPtr);
4727          (*prevItemPtr->typePtr->configProc)(canvasPtr->interp,          (*prevItemPtr->typePtr->configProc)(canvasPtr->interp,
4728                  (Tk_Canvas) canvasPtr, prevItemPtr, 0, (Tcl_Obj **) NULL,                  (Tk_Canvas) canvasPtr, prevItemPtr, 0, (Tcl_Obj **) NULL,
4729                  TK_CONFIG_ARGV_ONLY);                  TK_CONFIG_ARGV_ONLY);
4730      }      }
4731      if (canvasPtr->currentItemPtr != NULL) {      if (canvasPtr->currentItemPtr != NULL) {
4732          XEvent event;          XEvent event;
4733    
4734  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4735          DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr,          DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr,
4736                  Tk_GetUid("current"));                  Tk_GetUid("current"));
4737  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4738          DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid);          DoItem((Tcl_Interp *) NULL, canvasPtr->currentItemPtr, currentUid);
4739  #endif /* USE_OLD_TAG_SEA */  #endif /* USE_OLD_TAG_SEA */
4740          if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT &&          if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT &&
4741                  prevItemPtr != canvasPtr->currentItemPtr)) {                  prevItemPtr != canvasPtr->currentItemPtr)) {
4742              (*canvasPtr->currentItemPtr->typePtr->configProc)(canvasPtr->interp,              (*canvasPtr->currentItemPtr->typePtr->configProc)(canvasPtr->interp,
4743                      (Tk_Canvas) canvasPtr, canvasPtr->currentItemPtr, 0, (Tcl_Obj **) NULL,                      (Tk_Canvas) canvasPtr, canvasPtr->currentItemPtr, 0, (Tcl_Obj **) NULL,
4744                      TK_CONFIG_ARGV_ONLY);                      TK_CONFIG_ARGV_ONLY);
4745              EventuallyRedrawItem((Tk_Canvas) canvasPtr,              EventuallyRedrawItem((Tk_Canvas) canvasPtr,
4746                      canvasPtr->currentItemPtr);                      canvasPtr->currentItemPtr);
4747          }          }
4748          event = canvasPtr->pickEvent;          event = canvasPtr->pickEvent;
4749          event.type = EnterNotify;          event.type = EnterNotify;
4750          event.xcrossing.detail = NotifyAncestor;          event.xcrossing.detail = NotifyAncestor;
4751          CanvasDoEvent(canvasPtr, &event);          CanvasDoEvent(canvasPtr, &event);
4752      }      }
4753  }  }
4754    
4755  /*  /*
4756   *----------------------------------------------------------------------   *----------------------------------------------------------------------
4757   *   *
4758   * CanvasFindClosest --   * CanvasFindClosest --
4759   *   *
4760   *      Given x and y coordinates, find the topmost canvas item that   *      Given x and y coordinates, find the topmost canvas item that
4761   *      is "close" to the coordinates. Canvas items that are hidden   *      is "close" to the coordinates. Canvas items that are hidden
4762   *      or disabled are ignored.   *      or disabled are ignored.
4763   *   *
4764   * Results:   * Results:
4765   *      The return value is a pointer to the topmost item that is   *      The return value is a pointer to the topmost item that is
4766   *      close to (x,y), or NULL if no item is close.   *      close to (x,y), or NULL if no item is close.
4767   *   *
4768   * Side effects:   * Side effects:
4769   *      None.   *      None.
4770   *   *
4771   *----------------------------------------------------------------------   *----------------------------------------------------------------------
4772   */   */
4773    
4774  static Tk_Item *  static Tk_Item *
4775  CanvasFindClosest(canvasPtr, coords)  CanvasFindClosest(canvasPtr, coords)
4776      TkCanvas *canvasPtr;                /* Canvas widget to search. */      TkCanvas *canvasPtr;                /* Canvas widget to search. */
4777      double coords[2];                   /* Desired x,y position in canvas,      double coords[2];                   /* Desired x,y position in canvas,
4778                                           * not screen, coordinates.) */                                           * not screen, coordinates.) */
4779  {  {
4780      Tk_Item *itemPtr;      Tk_Item *itemPtr;
4781      Tk_Item *bestPtr;      Tk_Item *bestPtr;
4782      int x1, y1, x2, y2;      int x1, y1, x2, y2;
4783    
4784      x1 = (int) (coords[0] - canvasPtr->closeEnough);      x1 = (int) (coords[0] - canvasPtr->closeEnough);
4785      y1 = (int) (coords[1] - canvasPtr->closeEnough);      y1 = (int) (coords[1] - canvasPtr->closeEnough);
4786      x2 = (int) (coords[0] + canvasPtr->closeEnough);      x2 = (int) (coords[0] + canvasPtr->closeEnough);
4787      y2 = (int) (coords[1] + canvasPtr->closeEnough);      y2 = (int) (coords[1] + canvasPtr->closeEnough);
4788    
4789      bestPtr = NULL;      bestPtr = NULL;
4790      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;      for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
4791              itemPtr = itemPtr->nextPtr) {              itemPtr = itemPtr->nextPtr) {
4792          if (itemPtr->state == TK_STATE_HIDDEN || itemPtr->state==TK_STATE_DISABLED ||          if (itemPtr->state == TK_STATE_HIDDEN || itemPtr->state==TK_STATE_DISABLED ||
4793                  (itemPtr->state == TK_STATE_NULL && (canvasPtr->canvas_state == TK_STATE_HIDDEN ||                  (itemPtr->state == TK_STATE_NULL && (canvasPtr->canvas_state == TK_STATE_HIDDEN ||
4794                  canvasPtr->canvas_state == TK_STATE_DISABLED))) {                  canvasPtr->canvas_state == TK_STATE_DISABLED))) {
4795              continue;              continue;
4796          }          }
4797          if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)          if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)
4798                  || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {                  || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {
4799              continue;              continue;
4800          }          }
4801          if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,          if ((*itemPtr->typePtr->pointProc)((Tk_Canvas) canvasPtr,
4802                  itemPtr, coords) <= canvasPtr->closeEnough) {                  itemPtr, coords) <= canvasPtr->closeEnough) {
4803              bestPtr = itemPtr;              bestPtr = itemPtr;
4804          }          }
4805      }      }
4806      return bestPtr;      return bestPtr;
4807  }  }
4808    
4809  /*  /*
4810   *--------------------------------------------------------------   *--------------------------------------------------------------
4811   *   *
4812   * CanvasDoEvent --   * CanvasDoEvent --
4813   *   *
4814   *      This procedure is called to invoke binding processing   *      This procedure is called to invoke binding processing
4815   *      for a new event that is associated with the current item   *      for a new event that is associated with the current item
4816   *      for a canvas.   *      for a canvas.
4817   *   *
4818   * Results:   * Results:
4819   *      None.   *      None.
4820   *   *
4821   * Side effects:   * Side effects:
4822   *      Depends on the bindings for the canvas.  A binding script   *      Depends on the bindings for the canvas.  A binding script
4823   *      could delete the canvas, so callers should protect themselves   *      could delete the canvas, so callers should protect themselves
4824   *      with Tcl_Preserve and Tcl_Release.   *      with Tcl_Preserve and Tcl_Release.
4825   *   *
4826   *--------------------------------------------------------------   *--------------------------------------------------------------
4827   */   */
4828    
4829  static void  static void
4830  CanvasDoEvent(canvasPtr, eventPtr)  CanvasDoEvent(canvasPtr, eventPtr)
4831      TkCanvas *canvasPtr;                /* Canvas widget in which event      TkCanvas *canvasPtr;                /* Canvas widget in which event
4832                                           * occurred. */                                           * occurred. */
4833      XEvent *eventPtr;                   /* Real or simulated X event that      XEvent *eventPtr;                   /* Real or simulated X event that
4834                                           * is to be processed. */                                           * is to be processed. */
4835  {  {
4836  #define NUM_STATIC 3  #define NUM_STATIC 3
4837      ClientData staticObjects[NUM_STATIC];      ClientData staticObjects[NUM_STATIC];
4838      ClientData *objectPtr;      ClientData *objectPtr;
4839      int numObjects, i;      int numObjects, i;
4840      Tk_Item *itemPtr;      Tk_Item *itemPtr;
4841  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
4842      TagSearchExpr *expr;      TagSearchExpr *expr;
4843      int numExprs;      int numExprs;
4844  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
4845    
4846      if (canvasPtr->bindingTable == NULL) {      if (canvasPtr->bindingTable == NULL) {
4847          return;          return;
4848      }      }
4849    
4850      itemPtr = canvasPtr->currentItemPtr;      itemPtr = canvasPtr->currentItemPtr;
4851      if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {      if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
4852          itemPtr = canvasPtr->textInfo.focusItemPtr;          itemPtr = canvasPtr->textInfo.focusItemPtr;
4853      }      }
4854      if (itemPtr == NULL) {      if (itemPtr == NULL) {
4855          return;          return;
4856      }      }
4857    
4858  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4859      /*      /*
4860       * Set up an array with all the relevant objects for processing       * Set up an array with all the relevant objects for processing
4861       * this event.  The relevant objects are (a) the event's item,       * this event.  The relevant objects are (a) the event's item,
4862       * (b) the tags associated with the event's item, and (c) the       * (b) the tags associated with the event's item, and (c) the
4863       * tag "all".  If there are a lot of tags then malloc an array       * tag "all".  If there are a lot of tags then malloc an array
4864       * to hold all of the objects.       * to hold all of the objects.
4865       */       */
4866    
4867      numObjects = itemPtr->numTags + 2;      numObjects = itemPtr->numTags + 2;
4868  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4869      /*      /*
4870       * Set up an array with all the relevant objects for processing       * Set up an array with all the relevant objects for processing
4871       * this event.  The relevant objects are:       * this event.  The relevant objects are:
4872       * (a) the event's item,       * (a) the event's item,
4873       * (b) the tags associated with the event's item,       * (b) the tags associated with the event's item,
4874       * (c) the expressions that are true for the event's item's tags, and       * (c) the expressions that are true for the event's item's tags, and
4875       * (d) the tag "all".       * (d) the tag "all".
4876       *       *
4877       * If there are a lot of tags then malloc an array to hold all of       * If there are a lot of tags then malloc an array to hold all of
4878       * the objects.       * the objects.
4879       */       */
4880    
4881      /*      /*
4882       * flag and count all expressions that match item's tags       * flag and count all expressions that match item's tags
4883       */       */
4884      numExprs = 0;      numExprs = 0;
4885      expr = canvasPtr->bindTagExprs;      expr = canvasPtr->bindTagExprs;
4886      while (expr) {      while (expr) {
4887          expr->index = 0;          expr->index = 0;
4888          expr->match = TagSearchEvalExpr(expr, itemPtr);          expr->match = TagSearchEvalExpr(expr, itemPtr);
4889          if (expr->match) {          if (expr->match) {
4890              numExprs++;              numExprs++;
4891          }          }
4892          expr = expr->next;          expr = expr->next;
4893      }      }
4894    
4895      numObjects = itemPtr->numTags + numExprs + 2;      numObjects = itemPtr->numTags + numExprs + 2;
4896  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
4897      if (numObjects <= NUM_STATIC) {      if (numObjects <= NUM_STATIC) {
4898          objectPtr = staticObjects;          objectPtr = staticObjects;
4899      } else {      } else {
4900          objectPtr = (ClientData *) ckalloc((unsigned)          objectPtr = (ClientData *) ckalloc((unsigned)
4901                  (numObjects * sizeof(ClientData)));                  (numObjects * sizeof(ClientData)));
4902      }      }
4903  #ifdef USE_OLD_TAG_SEARCH  #ifdef USE_OLD_TAG_SEARCH
4904      objectPtr[0] = (ClientData) Tk_GetUid("all");      objectPtr[0] = (ClientData) Tk_GetUid("all");
4905  #else /* USE_OLD_TAG_SEARCH */  #else /* USE_OLD_TAG_SEARCH */
4906      objectPtr[0] = (ClientData) allUid;      objectPtr[0] = (ClientData) allUid;
4907  #endif /* USE_OLD_TAG_SEARCH */  #endif /* USE_OLD_TAG_SEARCH */
4908      for (i = itemPtr->numTags-1; i >= 0; i--) {      for (i = itemPtr->numTags-1; i >= 0; i--) {
4909          objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];          objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
4910      }      }
4911      objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr;      objectPtr[itemPtr->numTags+1] = (ClientData) itemPtr;
4912  #ifndef USE_OLD_TAG_SEARCH  #ifndef USE_OLD_TAG_SEARCH
4913      /*      /*
4914       * copy uids of matching expressions into object array       * copy uids of matching expressions into object array
4915       */       */
4916      i = itemPtr->numTags+2;      i = itemPtr->numTags+2;
4917      expr = canvasPtr->bindTagExprs;      expr = canvasPtr->bindTagExprs;
4918      while (expr) {      while (expr) {
4919          if (expr->match) {          if (expr->match) {
4920              objectPtr[i++] = (int *) expr->uid;              objectPtr[i++] = (int *) expr->uid;
4921          }          }
4922          expr = expr->next;          expr = expr->next;
4923      }      }
4924  #endif /* not USE_OLD_TAG_SEARCH */  #endif /* not USE_OLD_TAG_SEARCH */
4925    
4926      /*      /*
4927       * Invoke the binding system, then free up the object array if       * Invoke the binding system, then free up the object array if
4928       * it was malloc-ed.       * it was malloc-ed.
4929       */       */
4930    
4931      if (canvasPtr->tkwin != NULL) {      if (canvasPtr->tkwin != NULL) {
4932          Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,          Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
4933                  numObjects, objectPtr);                  numObjects, objectPtr);
4934      }      }
4935      if (objectPtr != staticObjects) {      if (objectPtr != staticObjects) {
4936          ckfree((char *) objectPtr);          ckfree((char *) objectPtr);
4937      }      }
4938  }  }
4939    
4940  /*  /*
4941   *----------------------------------------------------------------------   *----------------------------------------------------------------------
4942   *   *
4943   * CanvasBlinkProc --   * CanvasBlinkProc --
4944   *   *
4945   *      This procedure is called as a timer handler to blink the   *      This procedure is called as a timer handler to blink the
4946   *      insertion cursor off and on.   *      insertion cursor off and on.
4947   *   *
4948   * Results:   * Results:
4949   *      None.   *      None.
4950   *   *
4951   * Side effects:   * Side effects:
4952   *      The cursor gets turned on or off, redisplay gets invoked,   *      The cursor gets turned on or off, redisplay gets invoked,
4953   *      and this procedure reschedules itself.   *      and this procedure reschedules itself.
4954   *   *
4955   *----------------------------------------------------------------------   *----------------------------------------------------------------------
4956   */   */
4957    
4958  static void  static void
4959  CanvasBlinkProc(clientData)  CanvasBlinkProc(clientData)
4960      ClientData clientData;      /* Pointer to record describing entry. */      ClientData clientData;      /* Pointer to record describing entry. */
4961  {  {
4962      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
4963    
4964      if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {      if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {
4965          return;          return;
4966      }      }
4967      if (canvasPtr->textInfo.cursorOn) {      if (canvasPtr->textInfo.cursorOn) {
4968          canvasPtr->textInfo.cursorOn = 0;          canvasPtr->textInfo.cursorOn = 0;
4969          canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(          canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
4970                  canvasPtr->insertOffTime, CanvasBlinkProc,                  canvasPtr->insertOffTime, CanvasBlinkProc,
4971                  (ClientData) canvasPtr);                  (ClientData) canvasPtr);
4972      } else {      } else {
4973          canvasPtr->textInfo.cursorOn = 1;          canvasPtr->textInfo.cursorOn = 1;
4974          canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(          canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
4975                  canvasPtr->insertOnTime, CanvasBlinkProc,                  canvasPtr->insertOnTime, CanvasBlinkProc,
4976                  (ClientData) canvasPtr);                  (ClientData) canvasPtr);
4977      }      }
4978      if (canvasPtr->textInfo.focusItemPtr != NULL) {      if (canvasPtr->textInfo.focusItemPtr != NULL) {
4979          EventuallyRedrawItem((Tk_Canvas) canvasPtr,          EventuallyRedrawItem((Tk_Canvas) canvasPtr,
4980                  canvasPtr->textInfo.focusItemPtr);                  canvasPtr->textInfo.focusItemPtr);
4981      }      }
4982  }  }
4983    
4984  /*  /*
4985   *----------------------------------------------------------------------   *----------------------------------------------------------------------
4986   *   *
4987   * CanvasFocusProc --   * CanvasFocusProc --
4988   *   *
4989   *      This procedure is called whenever a canvas gets or loses the   *      This procedure is called whenever a canvas gets or loses the
4990   *      input focus.  It's also called whenever the window is   *      input focus.  It's also called whenever the window is
4991   *      reconfigured while it has the focus.   *      reconfigured while it has the focus.
4992   *   *
4993   * Results:   * Results:
4994   *      None.   *      None.
4995   *   *
4996   * Side effects:   * Side effects:
4997   *      The cursor gets turned on or off.   *      The cursor gets turned on or off.
4998   *   *
4999   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5000   */   */
5001    
5002  static void  static void
5003  CanvasFocusProc(canvasPtr, gotFocus)  CanvasFocusProc(canvasPtr, gotFocus)
5004      TkCanvas *canvasPtr;        /* Canvas that just got or lost focus. */      TkCanvas *canvasPtr;        /* Canvas that just got or lost focus. */
5005      int gotFocus;               /* 1 means window is getting focus, 0 means      int gotFocus;               /* 1 means window is getting focus, 0 means
5006                                   * it's losing it. */                                   * it's losing it. */
5007  {  {
5008      Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);      Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
5009      if (gotFocus) {      if (gotFocus) {
5010          canvasPtr->textInfo.gotFocus = 1;          canvasPtr->textInfo.gotFocus = 1;
5011          canvasPtr->textInfo.cursorOn = 1;          canvasPtr->textInfo.cursorOn = 1;
5012          if (canvasPtr->insertOffTime != 0) {          if (canvasPtr->insertOffTime != 0) {
5013              canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(              canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
5014                      canvasPtr->insertOffTime, CanvasBlinkProc,                      canvasPtr->insertOffTime, CanvasBlinkProc,
5015                      (ClientData) canvasPtr);                      (ClientData) canvasPtr);
5016          }          }
5017      } else {      } else {
5018          canvasPtr->textInfo.gotFocus = 0;          canvasPtr->textInfo.gotFocus = 0;
5019          canvasPtr->textInfo.cursorOn = 0;          canvasPtr->textInfo.cursorOn = 0;
5020          canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;          canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
5021      }      }
5022      if (canvasPtr->textInfo.focusItemPtr != NULL) {      if (canvasPtr->textInfo.focusItemPtr != NULL) {
5023          EventuallyRedrawItem((Tk_Canvas) canvasPtr,          EventuallyRedrawItem((Tk_Canvas) canvasPtr,
5024                  canvasPtr->textInfo.focusItemPtr);                  canvasPtr->textInfo.focusItemPtr);
5025      }      }
5026      if (canvasPtr->highlightWidth > 0) {      if (canvasPtr->highlightWidth > 0) {
5027          canvasPtr->flags |= REDRAW_BORDERS;          canvasPtr->flags |= REDRAW_BORDERS;
5028          if (!(canvasPtr->flags & REDRAW_PENDING)) {          if (!(canvasPtr->flags & REDRAW_PENDING)) {
5029              Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);              Tcl_DoWhenIdle(DisplayCanvas, (ClientData) canvasPtr);
5030              canvasPtr->flags |= REDRAW_PENDING;              canvasPtr->flags |= REDRAW_PENDING;
5031          }          }
5032      }      }
5033  }  }
5034    
5035  /*  /*
5036   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5037   *   *
5038   * CanvasSelectTo --   * CanvasSelectTo --
5039   *   *
5040   *      Modify the selection by moving its un-anchored end.  This could   *      Modify the selection by moving its un-anchored end.  This could
5041   *      make the selection either larger or smaller.   *      make the selection either larger or smaller.
5042   *   *
5043   * Results:   * Results:
5044   *      None.   *      None.
5045   *   *
5046   * Side effects:   * Side effects:
5047   *      The selection changes.   *      The selection changes.
5048   *   *
5049   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5050   */   */
5051    
5052  static void  static void
5053  CanvasSelectTo(canvasPtr, itemPtr, index)  CanvasSelectTo(canvasPtr, itemPtr, index)
5054      TkCanvas *canvasPtr;        /* Information about widget. */      TkCanvas *canvasPtr;        /* Information about widget. */
5055      Tk_Item *itemPtr;           /* Item that is to hold selection. */      Tk_Item *itemPtr;           /* Item that is to hold selection. */
5056      int index;                  /* Index of element that is to become the      int index;                  /* Index of element that is to become the
5057                                   * "other" end of the selection. */                                   * "other" end of the selection. */
5058  {  {
5059      int oldFirst, oldLast;      int oldFirst, oldLast;
5060      Tk_Item *oldSelPtr;      Tk_Item *oldSelPtr;
5061    
5062      oldFirst = canvasPtr->textInfo.selectFirst;      oldFirst = canvasPtr->textInfo.selectFirst;
5063      oldLast = canvasPtr->textInfo.selectLast;      oldLast = canvasPtr->textInfo.selectLast;
5064      oldSelPtr = canvasPtr->textInfo.selItemPtr;      oldSelPtr = canvasPtr->textInfo.selItemPtr;
5065    
5066      /*      /*
5067       * Grab the selection if we don't own it already.       * Grab the selection if we don't own it already.
5068       */       */
5069    
5070      if (canvasPtr->textInfo.selItemPtr == NULL) {      if (canvasPtr->textInfo.selItemPtr == NULL) {
5071          Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,          Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
5072                  (ClientData) canvasPtr);                  (ClientData) canvasPtr);
5073      } else if (canvasPtr->textInfo.selItemPtr != itemPtr) {      } else if (canvasPtr->textInfo.selItemPtr != itemPtr) {
5074          EventuallyRedrawItem((Tk_Canvas) canvasPtr,          EventuallyRedrawItem((Tk_Canvas) canvasPtr,
5075                  canvasPtr->textInfo.selItemPtr);                  canvasPtr->textInfo.selItemPtr);
5076      }      }
5077      canvasPtr->textInfo.selItemPtr = itemPtr;      canvasPtr->textInfo.selItemPtr = itemPtr;
5078    
5079      if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {      if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {
5080          canvasPtr->textInfo.anchorItemPtr = itemPtr;          canvasPtr->textInfo.anchorItemPtr = itemPtr;
5081          canvasPtr->textInfo.selectAnchor = index;          canvasPtr->textInfo.selectAnchor = index;
5082      }      }
5083      if (canvasPtr->textInfo.selectAnchor <= index) {      if (canvasPtr->textInfo.selectAnchor <= index) {
5084          canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;          canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;
5085          canvasPtr->textInfo.selectLast = index;          canvasPtr->textInfo.selectLast = index;
5086      } else {      } else {
5087          canvasPtr->textInfo.selectFirst = index;          canvasPtr->textInfo.selectFirst = index;
5088          canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;          canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;
5089      }      }
5090      if ((canvasPtr->textInfo.selectFirst != oldFirst)      if ((canvasPtr->textInfo.selectFirst != oldFirst)
5091              || (canvasPtr->textInfo.selectLast != oldLast)              || (canvasPtr->textInfo.selectLast != oldLast)
5092              || (itemPtr != oldSelPtr)) {              || (itemPtr != oldSelPtr)) {
5093          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);          EventuallyRedrawItem((Tk_Canvas) canvasPtr, itemPtr);
5094      }      }
5095  }  }
5096    
5097  /*  /*
5098   *--------------------------------------------------------------   *--------------------------------------------------------------
5099   *   *
5100   * CanvasFetchSelection --   * CanvasFetchSelection --
5101   *   *
5102   *      This procedure is invoked by Tk to return part or all of   *      This procedure is invoked by Tk to return part or all of
5103   *      the selection, when the selection is in a canvas widget.   *      the selection, when the selection is in a canvas widget.
5104   *      This procedure always returns the selection as a STRING.   *      This procedure always returns the selection as a STRING.
5105   *   *
5106   * Results:   * Results:
5107   *      The return value is the number of non-NULL bytes stored   *      The return value is the number of non-NULL bytes stored
5108   *      at buffer.  Buffer is filled (or partially filled) with a   *      at buffer.  Buffer is filled (or partially filled) with a
5109   *      NULL-terminated string containing part or all of the selection,   *      NULL-terminated string containing part or all of the selection,
5110   *      as given by offset and maxBytes.   *      as given by offset and maxBytes.
5111   *   *
5112   * Side effects:   * Side effects:
5113   *      None.   *      None.
5114   *   *
5115   *--------------------------------------------------------------   *--------------------------------------------------------------
5116   */   */
5117    
5118  static int  static int
5119  CanvasFetchSelection(clientData, offset, buffer, maxBytes)  CanvasFetchSelection(clientData, offset, buffer, maxBytes)
5120      ClientData clientData;              /* Information about canvas widget. */      ClientData clientData;              /* Information about canvas widget. */
5121      int offset;                         /* Offset within selection of first      int offset;                         /* Offset within selection of first
5122                                           * character to be returned. */                                           * character to be returned. */
5123      char *buffer;                       /* Location in which to place      char *buffer;                       /* Location in which to place
5124                                           * selection. */                                           * selection. */
5125      int maxBytes;                       /* Maximum number of bytes to place      int maxBytes;                       /* Maximum number of bytes to place
5126                                           * at buffer, not including terminating                                           * at buffer, not including terminating
5127                                           * NULL character. */                                           * NULL character. */
5128  {  {
5129      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
5130    
5131      if (canvasPtr->textInfo.selItemPtr == NULL) {      if (canvasPtr->textInfo.selItemPtr == NULL) {
5132          return -1;          return -1;
5133      }      }
5134      if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) {      if (canvasPtr->textInfo.selItemPtr->typePtr->selectionProc == NULL) {
5135          return -1;          return -1;
5136      }      }
5137      return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)(      return (*canvasPtr->textInfo.selItemPtr->typePtr->selectionProc)(
5138              (Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset,              (Tk_Canvas) canvasPtr, canvasPtr->textInfo.selItemPtr, offset,
5139              buffer, maxBytes);              buffer, maxBytes);
5140  }  }
5141    
5142  /*  /*
5143   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5144   *   *
5145   * CanvasLostSelection --   * CanvasLostSelection --
5146   *   *
5147   *      This procedure is called back by Tk when the selection is   *      This procedure is called back by Tk when the selection is
5148   *      grabbed away from a canvas widget.   *      grabbed away from a canvas widget.
5149   *   *
5150   * Results:   * Results:
5151   *      None.   *      None.
5152   *   *
5153   * Side effects:   * Side effects:
5154   *      The existing selection is unhighlighted, and the window is   *      The existing selection is unhighlighted, and the window is
5155   *      marked as not containing a selection.   *      marked as not containing a selection.
5156   *   *
5157   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5158   */   */
5159    
5160  static void  static void
5161  CanvasLostSelection(clientData)  CanvasLostSelection(clientData)
5162      ClientData clientData;              /* Information about entry widget. */      ClientData clientData;              /* Information about entry widget. */
5163  {  {
5164      TkCanvas *canvasPtr = (TkCanvas *) clientData;      TkCanvas *canvasPtr = (TkCanvas *) clientData;
5165    
5166      if (canvasPtr->textInfo.selItemPtr != NULL) {      if (canvasPtr->textInfo.selItemPtr != NULL) {
5167          EventuallyRedrawItem((Tk_Canvas) canvasPtr,          EventuallyRedrawItem((Tk_Canvas) canvasPtr,
5168                  canvasPtr->textInfo.selItemPtr);                  canvasPtr->textInfo.selItemPtr);
5169      }      }
5170      canvasPtr->textInfo.selItemPtr = NULL;      canvasPtr->textInfo.selItemPtr = NULL;
5171  }  }
5172    
5173  /*  /*
5174   *--------------------------------------------------------------   *--------------------------------------------------------------
5175   *   *
5176   * GridAlign --   * GridAlign --
5177   *   *
5178   *      Given a coordinate and a grid spacing, this procedure   *      Given a coordinate and a grid spacing, this procedure
5179   *      computes the location of the nearest grid line to the   *      computes the location of the nearest grid line to the
5180   *      coordinate.   *      coordinate.
5181   *   *
5182   * Results:   * Results:
5183   *      The return value is the location of the grid line nearest   *      The return value is the location of the grid line nearest
5184   *      to coord.   *      to coord.
5185   *   *
5186   * Side effects:   * Side effects:
5187   *      None.   *      None.
5188   *   *
5189   *--------------------------------------------------------------   *--------------------------------------------------------------
5190   */   */
5191    
5192  static double  static double
5193  GridAlign(coord, spacing)  GridAlign(coord, spacing)
5194      double coord;               /* Coordinate to grid-align. */      double coord;               /* Coordinate to grid-align. */
5195      double spacing;             /* Spacing between grid lines.   If <= 0      double spacing;             /* Spacing between grid lines.   If <= 0
5196                                   * then no alignment is done. */                                   * then no alignment is done. */
5197  {  {
5198      if (spacing <= 0.0) {      if (spacing <= 0.0) {
5199          return coord;          return coord;
5200      }      }
5201      if (coord < 0) {      if (coord < 0) {
5202          return -((int) ((-coord)/spacing + 0.5)) * spacing;          return -((int) ((-coord)/spacing + 0.5)) * spacing;
5203      }      }
5204      return ((int) (coord/spacing + 0.5)) * spacing;      return ((int) (coord/spacing + 0.5)) * spacing;
5205  }  }
5206    
5207  /*  /*
5208   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5209   *   *
5210   * PrintScrollFractions --   * PrintScrollFractions --
5211   *   *
5212   *      Given the range that's visible in the window and the "100%   *      Given the range that's visible in the window and the "100%
5213   *      range" for what's in the canvas, print a string containing   *      range" for what's in the canvas, print a string containing
5214   *      the scroll fractions.  This procedure is used for both x   *      the scroll fractions.  This procedure is used for both x
5215   *      and y scrolling.   *      and y scrolling.
5216   *   *
5217   * Results:   * Results:
5218   *      The memory pointed to by string is modified to hold   *      The memory pointed to by string is modified to hold
5219   *      two real numbers containing the scroll fractions (between   *      two real numbers containing the scroll fractions (between
5220   *      0 and 1) corresponding to the other arguments.   *      0 and 1) corresponding to the other arguments.
5221   *   *
5222   * Side effects:   * Side effects:
5223   *      None.   *      None.
5224   *   *
5225   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5226   */   */
5227    
5228  static void  static void
5229  PrintScrollFractions(screen1, screen2, object1, object2, string)  PrintScrollFractions(screen1, screen2, object1, object2, string)
5230      int screen1;                /* Lowest coordinate visible in the window. */      int screen1;                /* Lowest coordinate visible in the window. */
5231      int screen2;                /* Highest coordinate visible in the window. */      int screen2;                /* Highest coordinate visible in the window. */
5232      int object1;                /* Lowest coordinate in the object. */      int object1;                /* Lowest coordinate in the object. */
5233      int object2;                /* Highest coordinate in the object. */      int object2;                /* Highest coordinate in the object. */
5234      char *string;               /* Two real numbers get printed here.  Must      char *string;               /* Two real numbers get printed here.  Must
5235                                   * have enough storage for two %g                                   * have enough storage for two %g
5236                                   * conversions. */                                   * conversions. */
5237  {  {
5238      double range, f1, f2;      double range, f1, f2;
5239    
5240      range = object2 - object1;      range = object2 - object1;
5241      if (range <= 0) {      if (range <= 0) {
5242          f1 = 0;          f1 = 0;
5243          f2 = 1.0;          f2 = 1.0;
5244      } else {      } else {
5245          f1 = (screen1 - object1)/range;          f1 = (screen1 - object1)/range;
5246          if (f1 < 0) {          if (f1 < 0) {
5247              f1 = 0.0;              f1 = 0.0;
5248          }          }
5249          f2 = (screen2 - object1)/range;          f2 = (screen2 - object1)/range;
5250          if (f2 > 1.0) {          if (f2 > 1.0) {
5251              f2 = 1.0;              f2 = 1.0;
5252          }          }
5253          if (f2 < f1) {          if (f2 < f1) {
5254              f2 = f1;              f2 = f1;
5255          }          }
5256      }      }
5257      sprintf(string, "%g %g", f1, f2);      sprintf(string, "%g %g", f1, f2);
5258  }  }
5259    
5260  /*  /*
5261   *--------------------------------------------------------------   *--------------------------------------------------------------
5262   *   *
5263   * CanvasUpdateScrollbars --   * CanvasUpdateScrollbars --
5264   *   *
5265   *      This procedure is invoked whenever a canvas has changed in   *      This procedure is invoked whenever a canvas has changed in
5266   *      a way that requires scrollbars to be redisplayed (e.g. the   *      a way that requires scrollbars to be redisplayed (e.g. the
5267   *      view in the canvas has changed).   *      view in the canvas has changed).
5268   *   *
5269   * Results:   * Results:
5270   *      None.   *      None.
5271   *   *
5272   * Side effects:   * Side effects:
5273   *      If there are scrollbars associated with the canvas, then   *      If there are scrollbars associated with the canvas, then
5274   *      their scrolling commands are invoked to cause them to   *      their scrolling commands are invoked to cause them to
5275   *      redisplay.  If errors occur, additional Tcl commands may   *      redisplay.  If errors occur, additional Tcl commands may
5276   *      be invoked to process the errors.   *      be invoked to process the errors.
5277   *   *
5278   *--------------------------------------------------------------   *--------------------------------------------------------------
5279   */   */
5280    
5281  static void  static void
5282  CanvasUpdateScrollbars(canvasPtr)  CanvasUpdateScrollbars(canvasPtr)
5283      TkCanvas *canvasPtr;                /* Information about canvas. */      TkCanvas *canvasPtr;                /* Information about canvas. */
5284  {  {
5285      int result;      int result;
5286      char buffer[200];      char buffer[200];
5287      Tcl_Interp *interp;      Tcl_Interp *interp;
5288      int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2,      int xOrigin, yOrigin, inset, width, height, scrollX1, scrollX2,
5289          scrollY1, scrollY2;          scrollY1, scrollY2;
5290      char *xScrollCmd, *yScrollCmd;      char *xScrollCmd, *yScrollCmd;
5291    
5292      /*      /*
5293       * Save all the relevant values from the canvasPtr, because it might be       * Save all the relevant values from the canvasPtr, because it might be
5294       * deleted as part of either of the two calls to Tcl_VarEval below.       * deleted as part of either of the two calls to Tcl_VarEval below.
5295       */       */
5296            
5297      interp = canvasPtr->interp;      interp = canvasPtr->interp;
5298      Tcl_Preserve((ClientData) interp);      Tcl_Preserve((ClientData) interp);
5299      xScrollCmd = canvasPtr->xScrollCmd;      xScrollCmd = canvasPtr->xScrollCmd;
5300      if (xScrollCmd != (char *) NULL) {      if (xScrollCmd != (char *) NULL) {
5301          Tcl_Preserve((ClientData) xScrollCmd);          Tcl_Preserve((ClientData) xScrollCmd);
5302      }      }
5303      yScrollCmd = canvasPtr->yScrollCmd;      yScrollCmd = canvasPtr->yScrollCmd;
5304      if (yScrollCmd != (char *) NULL) {      if (yScrollCmd != (char *) NULL) {
5305          Tcl_Preserve((ClientData) yScrollCmd);          Tcl_Preserve((ClientData) yScrollCmd);
5306      }      }
5307      xOrigin = canvasPtr->xOrigin;      xOrigin = canvasPtr->xOrigin;
5308      yOrigin = canvasPtr->yOrigin;      yOrigin = canvasPtr->yOrigin;
5309      inset = canvasPtr->inset;      inset = canvasPtr->inset;
5310      width = Tk_Width(canvasPtr->tkwin);      width = Tk_Width(canvasPtr->tkwin);
5311      height = Tk_Height(canvasPtr->tkwin);      height = Tk_Height(canvasPtr->tkwin);
5312      scrollX1 = canvasPtr->scrollX1;      scrollX1 = canvasPtr->scrollX1;
5313      scrollX2 = canvasPtr->scrollX2;      scrollX2 = canvasPtr->scrollX2;
5314      scrollY1 = canvasPtr->scrollY1;      scrollY1 = canvasPtr->scrollY1;
5315      scrollY2 = canvasPtr->scrollY2;      scrollY2 = canvasPtr->scrollY2;
5316      canvasPtr->flags &= ~UPDATE_SCROLLBARS;      canvasPtr->flags &= ~UPDATE_SCROLLBARS;
5317      if (canvasPtr->xScrollCmd != NULL) {      if (canvasPtr->xScrollCmd != NULL) {
5318          PrintScrollFractions(xOrigin + inset, xOrigin + width - inset,          PrintScrollFractions(xOrigin + inset, xOrigin + width - inset,
5319                  scrollX1, scrollX2, buffer);                  scrollX1, scrollX2, buffer);
5320          result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);          result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);
5321          if (result != TCL_OK) {          if (result != TCL_OK) {
5322              Tcl_BackgroundError(interp);              Tcl_BackgroundError(interp);
5323          }          }
5324          Tcl_ResetResult(interp);          Tcl_ResetResult(interp);
5325          Tcl_Release((ClientData) xScrollCmd);          Tcl_Release((ClientData) xScrollCmd);
5326      }      }
5327    
5328      if (yScrollCmd != NULL) {      if (yScrollCmd != NULL) {
5329          PrintScrollFractions(yOrigin + inset, yOrigin + height - inset,          PrintScrollFractions(yOrigin + inset, yOrigin + height - inset,
5330                  scrollY1, scrollY2, buffer);                  scrollY1, scrollY2, buffer);
5331          result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);          result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);
5332          if (result != TCL_OK) {          if (result != TCL_OK) {
5333              Tcl_BackgroundError(interp);              Tcl_BackgroundError(interp);
5334          }          }
5335          Tcl_ResetResult(interp);          Tcl_ResetResult(interp);
5336          Tcl_Release((ClientData) yScrollCmd);          Tcl_Release((ClientData) yScrollCmd);
5337      }      }
5338      Tcl_Release((ClientData) interp);      Tcl_Release((ClientData) interp);
5339  }  }
5340    
5341  /*  /*
5342   *--------------------------------------------------------------   *--------------------------------------------------------------
5343   *   *
5344   * CanvasSetOrigin --   * CanvasSetOrigin --
5345   *   *
5346   *      This procedure is invoked to change the mapping between   *      This procedure is invoked to change the mapping between
5347   *      canvas coordinates and screen coordinates in the canvas   *      canvas coordinates and screen coordinates in the canvas
5348   *      window.   *      window.
5349   *   *
5350   * Results:   * Results:
5351   *      None.   *      None.
5352   *   *
5353   * Side effects:   * Side effects:
5354   *      The canvas will be redisplayed to reflect the change in   *      The canvas will be redisplayed to reflect the change in
5355   *      view.  In addition, scrollbars will be updated if there   *      view.  In addition, scrollbars will be updated if there
5356   *      are any.   *      are any.
5357   *   *
5358   *--------------------------------------------------------------   *--------------------------------------------------------------
5359   */   */
5360    
5361  static void  static void
5362  CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)  CanvasSetOrigin(canvasPtr, xOrigin, yOrigin)
5363      TkCanvas *canvasPtr;        /* Information about canvas. */      TkCanvas *canvasPtr;        /* Information about canvas. */
5364      int xOrigin;                /* New X origin for canvas (canvas x-coord      int xOrigin;                /* New X origin for canvas (canvas x-coord
5365                                   * corresponding to left edge of canvas                                   * corresponding to left edge of canvas
5366                                   * window). */                                   * window). */
5367      int yOrigin;                /* New Y origin for canvas (canvas y-coord      int yOrigin;                /* New Y origin for canvas (canvas y-coord
5368                                   * corresponding to top edge of canvas                                   * corresponding to top edge of canvas
5369                                   * window). */                                   * window). */
5370  {  {
5371      int left, right, top, bottom, delta;      int left, right, top, bottom, delta;
5372    
5373      /*      /*
5374       * If scroll increments have been set, round the window origin       * If scroll increments have been set, round the window origin
5375       * to the nearest multiple of the increments.  Remember, the       * to the nearest multiple of the increments.  Remember, the
5376       * origin is the place just inside the borders,  not the upper       * origin is the place just inside the borders,  not the upper
5377       * left corner.       * left corner.
5378       */       */
5379    
5380      if (canvasPtr->xScrollIncrement > 0) {      if (canvasPtr->xScrollIncrement > 0) {
5381          if (xOrigin >= 0) {          if (xOrigin >= 0) {
5382              xOrigin += canvasPtr->xScrollIncrement/2;              xOrigin += canvasPtr->xScrollIncrement/2;
5383              xOrigin -= (xOrigin + canvasPtr->inset)              xOrigin -= (xOrigin + canvasPtr->inset)
5384                      % canvasPtr->xScrollIncrement;                      % canvasPtr->xScrollIncrement;
5385          } else {          } else {
5386              xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;              xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;
5387              xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)              xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)
5388                      % canvasPtr->xScrollIncrement);                      % canvasPtr->xScrollIncrement);
5389          }          }
5390      }      }
5391      if (canvasPtr->yScrollIncrement > 0) {      if (canvasPtr->yScrollIncrement > 0) {
5392          if (yOrigin >= 0) {          if (yOrigin >= 0) {
5393              yOrigin += canvasPtr->yScrollIncrement/2;              yOrigin += canvasPtr->yScrollIncrement/2;
5394              yOrigin -= (yOrigin + canvasPtr->inset)              yOrigin -= (yOrigin + canvasPtr->inset)
5395                      % canvasPtr->yScrollIncrement;                      % canvasPtr->yScrollIncrement;
5396          } else {          } else {
5397              yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;              yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;
5398              yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)              yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)
5399                      % canvasPtr->yScrollIncrement);                      % canvasPtr->yScrollIncrement);
5400          }          }
5401      }      }
5402    
5403      /*      /*
5404       * Adjust the origin if necessary to keep as much as possible of the       * Adjust the origin if necessary to keep as much as possible of the
5405       * canvas in the view.  The variables left, right, etc. keep track of       * canvas in the view.  The variables left, right, etc. keep track of
5406       * how much extra space there is on each side of the view before it       * how much extra space there is on each side of the view before it
5407       * will stick out past the scroll region.  If one side sticks out past       * will stick out past the scroll region.  If one side sticks out past
5408       * the edge of the scroll region, adjust the view to bring that side       * the edge of the scroll region, adjust the view to bring that side
5409       * back to the edge of the scrollregion (but don't move it so much that       * back to the edge of the scrollregion (but don't move it so much that
5410       * the other side sticks out now).  If scroll increments are in effect,       * the other side sticks out now).  If scroll increments are in effect,
5411       * be sure to adjust only by full increments.       * be sure to adjust only by full increments.
5412       */       */
5413    
5414      if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {      if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
5415          left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;          left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;
5416          right = canvasPtr->scrollX2          right = canvasPtr->scrollX2
5417                  - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);                  - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);
5418          top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;          top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;
5419          bottom = canvasPtr->scrollY2          bottom = canvasPtr->scrollY2
5420                  - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);                  - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);
5421          if ((left < 0) && (right > 0)) {          if ((left < 0) && (right > 0)) {
5422              delta = (right > -left) ? -left : right;              delta = (right > -left) ? -left : right;
5423              if (canvasPtr->xScrollIncrement > 0) {              if (canvasPtr->xScrollIncrement > 0) {
5424                  delta -= delta % canvasPtr->xScrollIncrement;                  delta -= delta % canvasPtr->xScrollIncrement;
5425              }              }
5426              xOrigin += delta;              xOrigin += delta;
5427          } else if ((right < 0) && (left > 0)) {          } else if ((right < 0) && (left > 0)) {
5428              delta = (left > -right) ? -right : left;              delta = (left > -right) ? -right : left;
5429              if (canvasPtr->xScrollIncrement > 0) {              if (canvasPtr->xScrollIncrement > 0) {
5430                  delta -= delta % canvasPtr->xScrollIncrement;                  delta -= delta % canvasPtr->xScrollIncrement;
5431              }              }
5432              xOrigin -= delta;              xOrigin -= delta;
5433          }          }
5434          if ((top < 0) && (bottom > 0)) {          if ((top < 0) && (bottom > 0)) {
5435              delta = (bottom > -top) ? -top : bottom;              delta = (bottom > -top) ? -top : bottom;
5436              if (canvasPtr->yScrollIncrement > 0) {              if (canvasPtr->yScrollIncrement > 0) {
5437                  delta -= delta % canvasPtr->yScrollIncrement;                  delta -= delta % canvasPtr->yScrollIncrement;
5438              }              }
5439              yOrigin += delta;              yOrigin += delta;
5440          } else if ((bottom < 0) && (top > 0)) {          } else if ((bottom < 0) && (top > 0)) {
5441              delta = (top > -bottom) ? -bottom : top;              delta = (top > -bottom) ? -bottom : top;
5442              if (canvasPtr->yScrollIncrement > 0) {              if (canvasPtr->yScrollIncrement > 0) {
5443                  delta -= delta % canvasPtr->yScrollIncrement;                  delta -= delta % canvasPtr->yScrollIncrement;
5444              }              }
5445              yOrigin -= delta;              yOrigin -= delta;
5446          }          }
5447      }      }
5448    
5449      if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {      if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
5450          return;          return;
5451      }      }
5452    
5453      /*      /*
5454       * Tricky point: must redisplay not only everything that's visible       * Tricky point: must redisplay not only everything that's visible
5455       * in the window's final configuration, but also everything that was       * in the window's final configuration, but also everything that was
5456       * visible in the initial configuration.  This is needed because some       * visible in the initial configuration.  This is needed because some
5457       * item types, like windows, need to know when they move off-screen       * item types, like windows, need to know when they move off-screen
5458       * so they can explicitly undisplay themselves.       * so they can explicitly undisplay themselves.
5459       */       */
5460    
5461      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
5462              canvasPtr->xOrigin, canvasPtr->yOrigin,              canvasPtr->xOrigin, canvasPtr->yOrigin,
5463              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
5464              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
5465      canvasPtr->xOrigin = xOrigin;      canvasPtr->xOrigin = xOrigin;
5466      canvasPtr->yOrigin = yOrigin;      canvasPtr->yOrigin = yOrigin;
5467      canvasPtr->flags |= UPDATE_SCROLLBARS;      canvasPtr->flags |= UPDATE_SCROLLBARS;
5468      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,      Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
5469              canvasPtr->xOrigin, canvasPtr->yOrigin,              canvasPtr->xOrigin, canvasPtr->yOrigin,
5470              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),              canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
5471              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));              canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
5472  }  }
5473    
5474  /*  /*
5475   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5476   *   *
5477   * GetStringsFromObjs   * GetStringsFromObjs
5478   *   *
5479   * Results:   * Results:
5480   *      Converts object list into string list.   *      Converts object list into string list.
5481   *   *
5482   * Side effects:   * Side effects:
5483   *      Memory is allocated for the argv array, which must   *      Memory is allocated for the argv array, which must
5484   *      be freed using ckfree() when no longer needed.   *      be freed using ckfree() when no longer needed.
5485   *   *
5486   *----------------------------------------------------------------------   *----------------------------------------------------------------------
5487   */   */
5488  /* ARGSUSED */  /* ARGSUSED */
5489  static char **  static char **
5490  GetStringsFromObjs(argc, objv)  GetStringsFromObjs(argc, objv)
5491      int argc;      int argc;
5492      Tcl_Obj *CONST objv[];      Tcl_Obj *CONST objv[];
5493  {  {
5494      register int i;      register int i;
5495      char **argv;      char **argv;
5496      if (argc <= 0) {      if (argc <= 0) {
5497          return NULL;          return NULL;
5498      }      }
5499      argv = (char **) ckalloc((argc+1) * sizeof(char *));      argv = (char **) ckalloc((argc+1) * sizeof(char *));
5500      for (i = 0; i < argc; i++) {      for (i = 0; i < argc; i++) {
5501          argv[i]=Tcl_GetStringFromObj(objv[i], (int *) NULL);          argv[i]=Tcl_GetStringFromObj(objv[i], (int *) NULL);
5502      }      }
5503      argv[argc] = 0;      argv[argc] = 0;
5504      return argv;      return argv;
5505  }  }
5506    
5507  /*  /*
5508   *--------------------------------------------------------------   *--------------------------------------------------------------
5509   *   *
5510   * Tk_CanvasPsColor --   * Tk_CanvasPsColor --
5511   *   *
5512   *      This procedure is called by individual canvas items when   *      This procedure is called by individual canvas items when
5513   *      they want to set a color value for output.  Given information   *      they want to set a color value for output.  Given information
5514   *      about an X color, this procedure will generate Postscript   *      about an X color, this procedure will generate Postscript
5515   *      commands to set up an appropriate color in Postscript.   *      commands to set up an appropriate color in Postscript.
5516   *   *
5517   * Results:   * Results:
5518   *      Returns a standard Tcl return value.  If an error occurs   *      Returns a standard Tcl return value.  If an error occurs
5519   *      then an error message will be left in interp->result.   *      then an error message will be left in interp->result.
5520   *      If no error occurs, then additional Postscript will be   *      If no error occurs, then additional Postscript will be
5521   *      appended to interp->result.   *      appended to interp->result.
5522   *   *
5523   * Side effects:   * Side effects:
5524   *      None.   *      None.
5525   *   *
5526   *--------------------------------------------------------------   *--------------------------------------------------------------
5527   */   */
5528    
5529  int  int
5530  Tk_CanvasPsColor(interp, canvas, colorPtr)  Tk_CanvasPsColor(interp, canvas, colorPtr)
5531      Tcl_Interp *interp;                 /* Interpreter for returning Postscript      Tcl_Interp *interp;                 /* Interpreter for returning Postscript
5532                                           * or error message. */                                           * or error message. */
5533      Tk_Canvas canvas;                   /* Information about canvas. */      Tk_Canvas canvas;                   /* Information about canvas. */
5534      XColor *colorPtr;                   /* Information about color. */      XColor *colorPtr;                   /* Information about color. */
5535  {  {
5536      return Tk_PostscriptColor(interp, ((TkCanvas *) canvas)->psInfo,      return Tk_PostscriptColor(interp, ((TkCanvas *) canvas)->psInfo,
5537              colorPtr);              colorPtr);
5538  }  }
5539    
5540  /*  /*
5541   *--------------------------------------------------------------   *--------------------------------------------------------------
5542   *   *
5543   * Tk_CanvasPsFont --   * Tk_CanvasPsFont --
5544   *   *
5545   *      This procedure is called by individual canvas items when   *      This procedure is called by individual canvas items when
5546   *      they want to output text.  Given information about an X   *      they want to output text.  Given information about an X
5547   *      font, this procedure will generate Postscript commands   *      font, this procedure will generate Postscript commands
5548   *      to set up an appropriate font in Postscript.   *      to set up an appropriate font in Postscript.
5549   *   *
5550   * Results:   * Results:
5551   *      Returns a standard Tcl return value.  If an error occurs   *      Returns a standard Tcl return value.  If an error occurs
5552   *      then an error message will be left in interp->result.   *      then an error message will be left in interp->result.
5553   *      If no error occurs, then additional Postscript will be   *      If no error occurs, then additional Postscript will be
5554   *      appended to the interp->result.   *      appended to the interp->result.
5555   *   *
5556   * Side effects:   * Side effects:
5557   *      The Postscript font name is entered into psInfoPtr->fontTable   *      The Postscript font name is entered into psInfoPtr->fontTable
5558   *      if it wasn't already there.   *      if it wasn't already there.
5559   *   *
5560   *--------------------------------------------------------------   *--------------------------------------------------------------
5561   */   */
5562    
5563  int  int
5564  Tk_CanvasPsFont(interp, canvas, tkfont)  Tk_CanvasPsFont(interp, canvas, tkfont)
5565      Tcl_Interp *interp;                 /* Interpreter for returning Postscript      Tcl_Interp *interp;                 /* Interpreter for returning Postscript
5566                                           * or error message. */                                           * or error message. */
5567      Tk_Canvas canvas;                   /* Information about canvas. */      Tk_Canvas canvas;                   /* Information about canvas. */
5568      Tk_Font tkfont;                     /* Information about font in which text      Tk_Font tkfont;                     /* Information about font in which text
5569                                           * is to be printed. */                                           * is to be printed. */
5570  {  {
5571      return Tk_PostscriptFont(interp, ((TkCanvas *) canvas)->psInfo, tkfont);      return Tk_PostscriptFont(interp, ((TkCanvas *) canvas)->psInfo, tkfont);
5572  }  }
5573    
5574  /*  /*
5575   *--------------------------------------------------------------   *--------------------------------------------------------------
5576   *   *
5577   * Tk_CanvasPsBitmap --   * Tk_CanvasPsBitmap --
5578   *   *
5579   *      This procedure is called to output the contents of a   *      This procedure is called to output the contents of a
5580   *      sub-region of a bitmap in proper image data format for   *      sub-region of a bitmap in proper image data format for
5581   *      Postscript (i.e. data between angle brackets, one bit   *      Postscript (i.e. data between angle brackets, one bit
5582   *      per pixel).   *      per pixel).
5583   *   *
5584   * Results:   * Results:
5585   *      Returns a standard Tcl return value.  If an error occurs   *      Returns a standard Tcl return value.  If an error occurs
5586   *      then an error message will be left in interp->result.   *      then an error message will be left in interp->result.
5587   *      If no error occurs, then additional Postscript will be   *      If no error occurs, then additional Postscript will be
5588   *      appended to interp->result.   *      appended to interp->result.
5589   *   *
5590   * Side effects:   * Side effects:
5591   *      None.   *      None.
5592   *   *
5593   *--------------------------------------------------------------   *--------------------------------------------------------------
5594   */   */
5595    
5596  int  int
5597  Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height)  Tk_CanvasPsBitmap(interp, canvas, bitmap, startX, startY, width, height)
5598      Tcl_Interp *interp;                 /* Interpreter for returning Postscript      Tcl_Interp *interp;                 /* Interpreter for returning Postscript
5599                                           * or error message. */                                           * or error message. */
5600      Tk_Canvas canvas;                   /* Information about canvas. */      Tk_Canvas canvas;                   /* Information about canvas. */
5601      Pixmap bitmap;                      /* Bitmap for which to generate      Pixmap bitmap;                      /* Bitmap for which to generate
5602                                           * Postscript. */                                           * Postscript. */
5603      int startX, startY;                 /* Coordinates of upper-left corner      int startX, startY;                 /* Coordinates of upper-left corner
5604                                           * of rectangular region to output. */                                           * of rectangular region to output. */
5605      int width, height;                  /* Height of rectangular region. */      int width, height;                  /* Height of rectangular region. */
5606  {  {
5607      return Tk_PostscriptBitmap(interp, ((TkCanvas *) canvas)->tkwin,      return Tk_PostscriptBitmap(interp, ((TkCanvas *) canvas)->tkwin,
5608              ((TkCanvas *) canvas)->psInfo, bitmap, startX, startY,              ((TkCanvas *) canvas)->psInfo, bitmap, startX, startY,
5609              width, height);              width, height);
5610  }  }
5611    
5612  /*  /*
5613   *--------------------------------------------------------------   *--------------------------------------------------------------
5614   *   *
5615   * Tk_CanvasPsStipple --   * Tk_CanvasPsStipple --
5616   *   *
5617   *      This procedure is called by individual canvas items when   *      This procedure is called by individual canvas items when
5618   *      they have created a path that they'd like to be filled with   *      they have created a path that they'd like to be filled with
5619   *      a stipple pattern.  Given information about an X bitmap,   *      a stipple pattern.  Given information about an X bitmap,
5620   *      this procedure will generate Postscript commands to fill   *      this procedure will generate Postscript commands to fill
5621   *      the current clip region using a stipple pattern defined by the   *      the current clip region using a stipple pattern defined by the
5622   *      bitmap.   *      bitmap.
5623   *   *
5624   * Results:   * Results:
5625   *      Returns a standard Tcl return value.  If an error occurs   *      Returns a standard Tcl return value.  If an error occurs
5626   *      then an error message will be left in interp->result.   *      then an error message will be left in interp->result.
5627   *      If no error occurs, then additional Postscript will be   *      If no error occurs, then additional Postscript will be
5628   *      appended to interp->result.   *      appended to interp->result.
5629   *   *
5630   * Side effects:   * Side effects:
5631   *      None.   *      None.
5632   *   *
5633   *--------------------------------------------------------------   *--------------------------------------------------------------
5634   */   */
5635    
5636  int  int
5637  Tk_CanvasPsStipple(interp, canvas, bitmap)  Tk_CanvasPsStipple(interp, canvas, bitmap)
5638      Tcl_Interp *interp;                 /* Interpreter for returning Postscript      Tcl_Interp *interp;                 /* Interpreter for returning Postscript
5639                                           * or error message. */                                           * or error message. */
5640      Tk_Canvas canvas;                   /* Information about canvas. */      Tk_Canvas canvas;                   /* Information about canvas. */
5641      Pixmap bitmap;                      /* Bitmap to use for stippling. */      Pixmap bitmap;                      /* Bitmap to use for stippling. */
5642  {  {
5643      return Tk_PostscriptStipple(interp, ((TkCanvas *) canvas)->tkwin,      return Tk_PostscriptStipple(interp, ((TkCanvas *) canvas)->tkwin,
5644              ((TkCanvas *) canvas)->psInfo, bitmap);              ((TkCanvas *) canvas)->psInfo, bitmap);
5645  }  }
5646    
5647  /*  /*
5648   *--------------------------------------------------------------   *--------------------------------------------------------------
5649   *   *
5650   * Tk_CanvasPsY --   * Tk_CanvasPsY --
5651   *   *
5652   *      Given a y-coordinate in canvas coordinates, this procedure   *      Given a y-coordinate in canvas coordinates, this procedure
5653   *      returns a y-coordinate to use for Postscript output.   *      returns a y-coordinate to use for Postscript output.
5654   *   *
5655   * Results:   * Results:
5656   *      Returns the Postscript coordinate that corresponds to   *      Returns the Postscript coordinate that corresponds to
5657   *      "y".   *      "y".
5658   *   *
5659   * Side effects:   * Side effects:
5660   *      None.   *      None.
5661   *   *
5662   *--------------------------------------------------------------   *--------------------------------------------------------------
5663   */   */
5664    
5665  double  double
5666  Tk_CanvasPsY(canvas, y)  Tk_CanvasPsY(canvas, y)
5667      Tk_Canvas canvas;                   /* Token for canvas on whose behalf      Tk_Canvas canvas;                   /* Token for canvas on whose behalf
5668                                           * Postscript is being generated. */                                           * Postscript is being generated. */
5669      double y;                           /* Y-coordinate in canvas coords. */      double y;                           /* Y-coordinate in canvas coords. */
5670  {  {
5671      return Tk_PostscriptY(y, ((TkCanvas *) canvas)->psInfo);      return Tk_PostscriptY(y, ((TkCanvas *) canvas)->psInfo);
5672  }  }
5673    
5674  /*  /*
5675   *--------------------------------------------------------------   *--------------------------------------------------------------
5676   *   *
5677   * Tk_CanvasPsPath --   * Tk_CanvasPsPath --
5678   *   *
5679   *      Given an array of points for a path, generate Postscript   *      Given an array of points for a path, generate Postscript
5680   *      commands to create the path.   *      commands to create the path.
5681   *   *
5682   * Results:   * Results:
5683   *      Postscript commands get appended to what's in interp->result.   *      Postscript commands get appended to what's in interp->result.
5684   *   *
5685   * Side effects:   * Side effects:
5686   *      None.   *      None.
5687   *   *
5688   *--------------------------------------------------------------   *--------------------------------------------------------------
5689   */   */
5690    
5691  void  void
5692  Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints)  Tk_CanvasPsPath(interp, canvas, coordPtr, numPoints)
5693      Tcl_Interp *interp;                 /* Put generated Postscript in this      Tcl_Interp *interp;                 /* Put generated Postscript in this
5694                                           * interpreter's result field. */                                           * interpreter's result field. */
5695      Tk_Canvas canvas;                   /* Canvas on whose behalf Postscript      Tk_Canvas canvas;                   /* Canvas on whose behalf Postscript
5696                                           * is being generated. */                                           * is being generated. */
5697      double *coordPtr;                   /* Pointer to first in array of      double *coordPtr;                   /* Pointer to first in array of
5698                                           * 2*numPoints coordinates giving                                           * 2*numPoints coordinates giving
5699                                           * points for path. */                                           * points for path. */
5700      int numPoints;                      /* Number of points at *coordPtr. */      int numPoints;                      /* Number of points at *coordPtr. */
5701  {  {
5702      Tk_PostscriptPath(interp, ((TkCanvas *) canvas)->psInfo,      Tk_PostscriptPath(interp, ((TkCanvas *) canvas)->psInfo,
5703              coordPtr, numPoints);              coordPtr, numPoints);
5704  }  }
5705    
5706  /* End of tkcanvas.c */  /* End of tkcanvas.c */

Legend:
Removed from v.70  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25