summaryrefslogtreecommitdiffstats
path: root/tk8.6/generic/tkCanvas.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/generic/tkCanvas.c')
-rw-r--r--tk8.6/generic/tkCanvas.c5979
1 files changed, 0 insertions, 5979 deletions
diff --git a/tk8.6/generic/tkCanvas.c b/tk8.6/generic/tkCanvas.c
deleted file mode 100644
index 9c4d60a..0000000
--- a/tk8.6/generic/tkCanvas.c
+++ /dev/null
@@ -1,5979 +0,0 @@
-/*
- * tkCanvas.c --
- *
- * This module implements canvas widgets for the Tk toolkit. A canvas
- * displays a background and a collection of graphical objects such as
- * rectangles, lines, and texts.
- *
- * Copyright (c) 1991-1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- * Copyright (c) 1998-1999 by Scriptics Corporation.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-/* #define USE_OLD_TAG_SEARCH 1 */
-
-#include "default.h"
-#include "tkInt.h"
-#include "tkCanvas.h"
-#ifdef TK_NO_DOUBLE_BUFFERING
-#ifdef MAC_OSX_TK
-#include "tkMacOSXInt.h"
-#endif
-#endif /* TK_NO_DOUBLE_BUFFERING */
-
-/*
- * See tkCanvas.h for key data structures used to implement canvases.
- */
-
-#ifdef USE_OLD_TAG_SEARCH
-/*
- * The structure defined below is used to keep track of a tag search in
- * progress. No field should be accessed by anyone other than StartTagSearch
- * and NextItem.
- */
-
-typedef struct TagSearch {
- TkCanvas *canvasPtr; /* Canvas widget being searched. */
- Tk_Uid tag; /* Tag to search for. 0 means return all
- * items. */
- Tk_Item *currentPtr; /* Pointer to last item returned. */
- Tk_Item *lastPtr; /* The item right before the currentPtr is
- * tracked so if the currentPtr is deleted we
- * don't have to start from the beginning. */
- int searchOver; /* Non-zero means NextItem should always
- * return NULL. */
-} TagSearch;
-
-#else /* USE_OLD_TAG_SEARCH */
-/*
- * The structure defined below is used to keep track of a tag search in
- * progress. No field should be accessed by anyone other than TagSearchScan,
- * TagSearchFirst, TagSearchNext, TagSearchScanExpr, TagSearchEvalExpr,
- * TagSearchExprInit, TagSearchExprDestroy, TagSearchDestroy.
- * (
- * Not quite accurate: the TagSearch structure is also accessed from:
- * CanvasWidgetCmd, FindItems, RelinkItems
- * The only instances of the structure are owned by:
- * CanvasWidgetCmd
- * CanvasWidgetCmd is the only function that calls:
- * FindItems, RelinkItems
- * CanvasWidgetCmd, FindItems, RelinkItems, are the only functions that call
- * TagSearch*
- * )
- */
-
-typedef struct TagSearch {
- TkCanvas *canvasPtr; /* Canvas widget being searched. */
- Tk_Item *currentPtr; /* Pointer to last item returned. */
- Tk_Item *lastPtr; /* The item right before the currentPtr is
- * tracked so if the currentPtr is deleted we
- * don't have to start from the beginning. */
- int searchOver; /* Non-zero means NextItem should always
- * return NULL. */
- int type; /* Search type (see #defs below) */
- int id; /* Item id for searches by id */
- const char *string; /* Tag expression string */
- int stringIndex; /* Current position in string scan */
- int stringLength; /* Length of tag expression string */
- char *rewritebuffer; /* Tag string (after removing escapes) */
- unsigned int rewritebufferAllocated;
- /* Available space for rewrites. */
- TagSearchExpr *expr; /* Compiled tag expression. */
-} TagSearch;
-
-/*
- * Values for the TagSearch type field.
- */
-
-#define SEARCH_TYPE_EMPTY 0 /* Looking for empty tag */
-#define SEARCH_TYPE_ID 1 /* Looking for an item by id */
-#define SEARCH_TYPE_ALL 2 /* Looking for all items */
-#define SEARCH_TYPE_TAG 3 /* Looking for an item by simple tag */
-#define SEARCH_TYPE_EXPR 4 /* Compound search */
-
-#endif /* USE_OLD_TAG_SEARCH */
-
-/*
- * Custom option for handling "-state" and "-offset"
- */
-
-static const Tk_CustomOption stateOption = {
- TkStateParseProc, TkStatePrintProc,
- NULL /* Only "normal" and "disabled". */
-};
-
-static const Tk_CustomOption offsetOption = {
- TkOffsetParseProc, TkOffsetPrintProc, INT2PTR(TK_OFFSET_RELATIVE)
-};
-
-/*
- * Information used for argv parsing.
- */
-
-static const Tk_ConfigSpec configSpecs[] = {
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_CANVAS_BG_COLOR, Tk_Offset(TkCanvas, bgBorder),
- TK_CONFIG_COLOR_ONLY, NULL},
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_CANVAS_BG_MONO, Tk_Offset(TkCanvas, bgBorder),
- TK_CONFIG_MONO_ONLY, NULL},
- {TK_CONFIG_SYNONYM, "-bd", "borderWidth", NULL, NULL, 0, 0, NULL},
- {TK_CONFIG_SYNONYM, "-bg", "background", NULL, NULL, 0, 0, NULL},
- {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
- DEF_CANVAS_BORDER_WIDTH, Tk_Offset(TkCanvas, borderWidth), 0, NULL},
- {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough",
- DEF_CANVAS_CLOSE_ENOUGH, Tk_Offset(TkCanvas, closeEnough), 0, NULL},
- {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine",
- DEF_CANVAS_CONFINE, Tk_Offset(TkCanvas, confine), 0, NULL},
- {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
- DEF_CANVAS_CURSOR, Tk_Offset(TkCanvas, cursor), TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_PIXELS, "-height", "height", "Height",
- DEF_CANVAS_HEIGHT, Tk_Offset(TkCanvas, height), 0, NULL},
- {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
- "HighlightBackground", DEF_CANVAS_HIGHLIGHT_BG,
- Tk_Offset(TkCanvas, highlightBgColorPtr), 0, NULL},
- {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
- DEF_CANVAS_HIGHLIGHT, Tk_Offset(TkCanvas, highlightColorPtr), 0, NULL},
- {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
- "HighlightThickness",
- DEF_CANVAS_HIGHLIGHT_WIDTH, Tk_Offset(TkCanvas, highlightWidth), 0, NULL},
- {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
- DEF_CANVAS_INSERT_BG, Tk_Offset(TkCanvas, textInfo.insertBorder), 0, NULL},
- {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
- DEF_CANVAS_INSERT_BD_COLOR,
- Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_COLOR_ONLY, NULL},
- {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
- DEF_CANVAS_INSERT_BD_MONO,
- Tk_Offset(TkCanvas, textInfo.insertBorderWidth), TK_CONFIG_MONO_ONLY, NULL},
- {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
- DEF_CANVAS_INSERT_OFF_TIME, Tk_Offset(TkCanvas, insertOffTime), 0, NULL},
- {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
- DEF_CANVAS_INSERT_ON_TIME, Tk_Offset(TkCanvas, insertOnTime), 0, NULL},
- {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
- DEF_CANVAS_INSERT_WIDTH, Tk_Offset(TkCanvas, textInfo.insertWidth), 0, NULL},
- {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0,0",
- Tk_Offset(TkCanvas, tsoffset),TK_CONFIG_DONT_SET_DEFAULT,
- &offsetOption},
- {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
- DEF_CANVAS_RELIEF, Tk_Offset(TkCanvas, relief), 0, NULL},
- {TK_CONFIG_STRING, "-scrollregion", "scrollRegion", "ScrollRegion",
- DEF_CANVAS_SCROLL_REGION, Tk_Offset(TkCanvas, regionString),
- TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
- DEF_CANVAS_SELECT_COLOR, Tk_Offset(TkCanvas, textInfo.selBorder),
- TK_CONFIG_COLOR_ONLY, NULL},
- {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
- DEF_CANVAS_SELECT_MONO, Tk_Offset(TkCanvas, textInfo.selBorder),
- TK_CONFIG_MONO_ONLY, NULL},
- {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
- DEF_CANVAS_SELECT_BD_COLOR,
- Tk_Offset(TkCanvas, textInfo.selBorderWidth), TK_CONFIG_COLOR_ONLY, NULL},
- {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
- DEF_CANVAS_SELECT_BD_MONO, Tk_Offset(TkCanvas, textInfo.selBorderWidth),
- TK_CONFIG_MONO_ONLY, NULL},
- {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
- DEF_CANVAS_SELECT_FG_COLOR, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
- TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
- DEF_CANVAS_SELECT_FG_MONO, Tk_Offset(TkCanvas, textInfo.selFgColorPtr),
- TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_CUSTOM, "-state", "state", "State",
- "normal", Tk_Offset(TkCanvas, canvas_state), TK_CONFIG_DONT_SET_DEFAULT,
- &stateOption},
- {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
- DEF_CANVAS_TAKE_FOCUS, Tk_Offset(TkCanvas, takeFocus),
- TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_PIXELS, "-width", "width", "Width",
- DEF_CANVAS_WIDTH, Tk_Offset(TkCanvas, width), 0, NULL},
- {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
- DEF_CANVAS_X_SCROLL_CMD, Tk_Offset(TkCanvas, xScrollCmd),
- TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_PIXELS, "-xscrollincrement", "xScrollIncrement",
- "ScrollIncrement",
- DEF_CANVAS_X_SCROLL_INCREMENT, Tk_Offset(TkCanvas, xScrollIncrement),
- 0, NULL},
- {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
- DEF_CANVAS_Y_SCROLL_CMD, Tk_Offset(TkCanvas, yScrollCmd),
- TK_CONFIG_NULL_OK, NULL},
- {TK_CONFIG_PIXELS, "-yscrollincrement", "yScrollIncrement",
- "ScrollIncrement",
- DEF_CANVAS_Y_SCROLL_INCREMENT, Tk_Offset(TkCanvas, yScrollIncrement),
- 0, NULL},
- {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0, NULL}
-};
-
-/*
- * List of all the item types known at present. This is *global* and is
- * protected by typeListMutex.
- */
-
-static Tk_ItemType *typeList = NULL;
- /* NULL means initialization hasn't been done
- * yet. */
-TCL_DECLARE_MUTEX(typeListMutex)
-
-#ifndef USE_OLD_TAG_SEARCH
-/*
- * Uids for operands in compiled advanced tag search expressions.
- * Initialization is done by GetStaticUids()
- */
-
-typedef struct {
- Tk_Uid allUid;
- Tk_Uid currentUid;
- Tk_Uid andUid;
- Tk_Uid orUid;
- Tk_Uid xorUid;
- Tk_Uid parenUid;
- Tk_Uid negparenUid;
- Tk_Uid endparenUid;
- Tk_Uid tagvalUid;
- Tk_Uid negtagvalUid;
-} SearchUids;
-
-static Tcl_ThreadDataKey dataKey;
-static SearchUids * GetStaticUids(void);
-#endif /* USE_OLD_TAG_SEARCH */
-
-/*
- * Prototypes for functions defined later in this file:
- */
-
-static void CanvasBindProc(ClientData clientData,
- XEvent *eventPtr);
-static void CanvasBlinkProc(ClientData clientData);
-static void CanvasCmdDeletedProc(ClientData clientData);
-static void CanvasDoEvent(TkCanvas *canvasPtr, XEvent *eventPtr);
-static void CanvasEventProc(ClientData clientData,
- XEvent *eventPtr);
-static int CanvasFetchSelection(ClientData clientData, int offset,
- char *buffer, int maxBytes);
-static Tk_Item * CanvasFindClosest(TkCanvas *canvasPtr,
- double coords[2]);
-static void CanvasFocusProc(TkCanvas *canvasPtr, int gotFocus);
-static void CanvasLostSelection(ClientData clientData);
-static void CanvasSelectTo(TkCanvas *canvasPtr,
- Tk_Item *itemPtr, int index);
-static void CanvasSetOrigin(TkCanvas *canvasPtr,
- int xOrigin, int yOrigin);
-static void CanvasUpdateScrollbars(TkCanvas *canvasPtr);
-static int CanvasWidgetCmd(ClientData clientData,
- Tcl_Interp *interp, int argc,
- Tcl_Obj *const *argv);
-static void CanvasWorldChanged(ClientData instanceData);
-static int ConfigureCanvas(Tcl_Interp *interp,
- TkCanvas *canvasPtr, int argc,
- Tcl_Obj *const *argv, int flags);
-static void DestroyCanvas(char *memPtr);
-static void DisplayCanvas(ClientData clientData);
-static void DoItem(Tcl_Obj *accumObj,
- Tk_Item *itemPtr, Tk_Uid tag);
-static void EventuallyRedrawItem(TkCanvas *canvasPtr,
- Tk_Item *itemPtr);
-#ifdef USE_OLD_TAG_SEARCH
-static int FindItems(Tcl_Interp *interp, TkCanvas *canvasPtr,
- int argc, Tcl_Obj *const *argv,
- Tcl_Obj *newTagObj, int first);
-#else /* USE_OLD_TAG_SEARCH */
-static int FindItems(Tcl_Interp *interp, TkCanvas *canvasPtr,
- int argc, Tcl_Obj *const *argv,
- Tcl_Obj *newTagObj, int first,
- TagSearch **searchPtrPtr);
-#endif /* USE_OLD_TAG_SEARCH */
-static int FindArea(Tcl_Interp *interp, TkCanvas *canvasPtr,
- Tcl_Obj *const *argv, Tk_Uid uid, int enclosed);
-static double GridAlign(double coord, double spacing);
-static const char** TkGetStringsFromObjs(int argc, Tcl_Obj *const *objv);
-static void InitCanvas(void);
-#ifdef USE_OLD_TAG_SEARCH
-static Tk_Item * NextItem(TagSearch *searchPtr);
-#endif /* USE_OLD_TAG_SEARCH */
-static void PickCurrentItem(TkCanvas *canvasPtr, XEvent *eventPtr);
-static Tcl_Obj * ScrollFractions(int screen1,
- int screen2, int object1, int object2);
-#ifdef USE_OLD_TAG_SEARCH
-static void RelinkItems(TkCanvas *canvasPtr,
- Tcl_Obj *tag, Tk_Item *prevPtr);
-static Tk_Item * StartTagSearch(TkCanvas *canvasPtr,
- Tcl_Obj *tag, TagSearch *searchPtr);
-#else /* USE_OLD_TAG_SEARCH */
-static int RelinkItems(TkCanvas *canvasPtr, Tcl_Obj *tag,
- Tk_Item *prevPtr, TagSearch **searchPtrPtr);
-static void TagSearchExprInit(TagSearchExpr **exprPtrPtr);
-static void TagSearchExprDestroy(TagSearchExpr *expr);
-static void TagSearchDestroy(TagSearch *searchPtr);
-static int TagSearchScan(TkCanvas *canvasPtr,
- Tcl_Obj *tag, TagSearch **searchPtrPtr);
-static int TagSearchScanExpr(Tcl_Interp *interp,
- TagSearch *searchPtr, TagSearchExpr *expr);
-static int TagSearchEvalExpr(TagSearchExpr *expr,
- Tk_Item *itemPtr);
-static Tk_Item * TagSearchFirst(TagSearch *searchPtr);
-static Tk_Item * TagSearchNext(TagSearch *searchPtr);
-#endif /* USE_OLD_TAG_SEARCH */
-
-/*
- * The structure below defines canvas class behavior by means of functions
- * that can be invoked from generic window code.
- */
-
-static const Tk_ClassProcs canvasClass = {
- sizeof(Tk_ClassProcs), /* size */
- CanvasWorldChanged, /* worldChangedProc */
- NULL, /* createProc */
- NULL /* modalProc */
-};
-
-/*
- * Macros that significantly simplify all code that finds items.
- */
-
-#ifdef USE_OLD_TAG_SEARCH
-#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \
- itemPtr = StartTagSearch(canvasPtr,(objPtr),&search)
-#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \
- for (itemPtr = StartTagSearch(canvasPtr, (objPtr), &search); \
- itemPtr != NULL; itemPtr = NextItem(&search))
-#define FIND_ITEMS(objPtr, n) \
- FindItems(interp, canvasPtr, objc, objv, (objPtr), (n))
-#define RELINK_ITEMS(objPtr, itemPtr) \
- RelinkItems(canvasPtr, (objPtr), (itemPtr))
-#else /* USE_OLD_TAG_SEARCH */
-#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \
- if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \
- errorExitClause; \
- } \
- itemPtr = TagSearchFirst(*(searchPtrPtr));
-#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \
- if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \
- errorExitClause; \
- } \
- for (itemPtr = TagSearchFirst(*(searchPtrPtr)); \
- itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr)))
-#define FIND_ITEMS(objPtr, n) \
- FindItems(interp, canvasPtr, objc, objv, (objPtr), (n), &searchPtr)
-#define RELINK_ITEMS(objPtr, itemPtr) \
- result = RelinkItems(canvasPtr, (objPtr), (itemPtr), &searchPtr)
-#endif /* USE_OLD_TAG_SEARCH */
-
-/*
- * ----------------------------------------------------------------------
- *
- * AlwaysRedraw, ItemConfigure, ItemCoords, etc. --
- *
- * Helper functions that make access to canvas item functions simpler.
- * Note that these are all inline functions.
- *
- * ----------------------------------------------------------------------
- */
-
-static inline int
-AlwaysRedraw(
- Tk_Item *itemPtr)
-{
- return itemPtr->typePtr->alwaysRedraw & 1;
-}
-
-static inline int
-ItemConfigure(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int objc,
- Tcl_Obj *const objv[])
-{
- Tcl_Interp *interp = canvasPtr->interp;
- int result;
-
- if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
- result = itemPtr->typePtr->configProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc, objv, TK_CONFIG_ARGV_ONLY);
- } else {
- const char **args = TkGetStringsFromObjs(objc, objv);
-
- result = itemPtr->typePtr->configProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc, (Tcl_Obj **) args, TK_CONFIG_ARGV_ONLY);
- if (args != NULL) {
- ckfree(args);
- }
- }
- return result;
-}
-
-static inline int
-ItemConfigInfo(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- Tcl_Obj *fieldName)
-{
- return Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
- itemPtr->typePtr->configSpecs, (char *) itemPtr,
- (fieldName ? Tcl_GetString(fieldName) : NULL), 0);
-}
-
-static inline int
-ItemConfigValue(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- Tcl_Obj *fieldName)
-{
- return Tk_ConfigureValue(canvasPtr->interp, canvasPtr->tkwin,
- itemPtr->typePtr->configSpecs, (char *) itemPtr,
- Tcl_GetString(fieldName), 0);
-}
-
-static inline int
-ItemCoords(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int objc,
- Tcl_Obj *const objv[])
-{
- Tcl_Interp *interp = canvasPtr->interp;
- int result;
-
- if (itemPtr->typePtr->coordProc == NULL) {
- result = TCL_OK;
- } else if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
- result = itemPtr->typePtr->coordProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc, objv);
- } else {
- const char **args = TkGetStringsFromObjs(objc, objv);
-
- result = itemPtr->typePtr->coordProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc, (Tcl_Obj **) args);
- if (args != NULL) {
- ckfree(args);
- }
- }
- return result;
-}
-
-static inline int
-ItemCreate(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr, /* Warning: incomplete! typePtr field must be
- * set by this point. */
- int objc,
- Tcl_Obj *const objv[])
-{
- Tcl_Interp *interp = canvasPtr->interp;
- int result;
-
- if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
- result = itemPtr->typePtr->createProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc-3, objv+3);
- } else {
- const char **args = TkGetStringsFromObjs(objc-3, objv+3);
-
- result = itemPtr->typePtr->createProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objc-3, (Tcl_Obj **) args);
- if (args != NULL) {
- ckfree(args);
- }
- }
- return result;
-}
-
-static inline void
-ItemCursor(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int index)
-{
- itemPtr->typePtr->icursorProc((Tk_Canvas) canvasPtr, itemPtr, index);
-}
-
-static inline void
-ItemDelChars(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int first,
- int last)
-{
- itemPtr->typePtr->dCharsProc((Tk_Canvas) canvasPtr, itemPtr, first, last);
-}
-
-static inline void
-ItemDelete(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr)
-{
- itemPtr->typePtr->deleteProc((Tk_Canvas) canvasPtr, itemPtr,
- canvasPtr->display);
-}
-
-static inline void
-ItemDisplay(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- Pixmap pixmap,
- int screenX1, int screenY1,
- int width, int height)
-{
- itemPtr->typePtr->displayProc((Tk_Canvas) canvasPtr, itemPtr,
- canvasPtr->display, pixmap, screenX1, screenY1, width, height);
-}
-
-static inline int
-ItemIndex(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- Tcl_Obj *objPtr,
- int *indexPtr)
-{
- Tcl_Interp *interp = canvasPtr->interp;
-
- if (itemPtr->typePtr->indexProc == NULL) {
- return TCL_OK;
- } else if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
- return itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, objPtr, indexPtr);
- } else {
- return itemPtr->typePtr->indexProc(interp, (Tk_Canvas) canvasPtr,
- itemPtr, (Tcl_Obj *) Tcl_GetString(objPtr), indexPtr);
- }
-}
-
-static inline void
-ItemInsert(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int beforeThis,
- Tcl_Obj *toInsert)
-{
- if (itemPtr->typePtr->alwaysRedraw & TK_CONFIG_OBJS) {
- itemPtr->typePtr->insertProc((Tk_Canvas) canvasPtr, itemPtr,
- beforeThis, toInsert);
- } else {
- itemPtr->typePtr->insertProc((Tk_Canvas) canvasPtr, itemPtr,
- beforeThis, (Tcl_Obj *) Tcl_GetString(toInsert));
- }
-}
-
-static inline int
-ItemOverlap(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- double rect[])
-{
- return itemPtr->typePtr->areaProc((Tk_Canvas) canvasPtr, itemPtr, rect);
-}
-
-static inline double
-ItemPoint(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- double coords[],
- double halo)
-{
- double dist;
-
- dist = itemPtr->typePtr->pointProc((Tk_Canvas) canvasPtr, itemPtr,
- coords) - halo;
- return (dist < 0.0) ? 0.0 : dist;
-}
-
-static inline void
-ItemScale(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- double xOrigin, double yOrigin,
- double xScale, double yScale)
-{
- itemPtr->typePtr->scaleProc((Tk_Canvas) canvasPtr, itemPtr,
- xOrigin, yOrigin, xScale, yScale);
-}
-
-static inline int
-ItemSelection(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- int offset,
- char *buffer,
- int maxBytes)
-{
- if (itemPtr == NULL || itemPtr->typePtr->selectionProc == NULL) {
- return -1;
- }
-
- return itemPtr->typePtr->selectionProc((Tk_Canvas) canvasPtr, itemPtr,
- offset, buffer, maxBytes);
-}
-
-static inline void
-ItemTranslate(
- TkCanvas *canvasPtr,
- Tk_Item *itemPtr,
- double xDelta,
- double yDelta)
-{
- itemPtr->typePtr->translateProc((Tk_Canvas) canvasPtr, itemPtr,
- xDelta, yDelta);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasObjCmd --
- *
- * This function is invoked to process the "canvas" Tcl command. See the
- * user documentation for details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-int
-Tk_CanvasObjCmd(
- ClientData clientData, /* Main window associated with interpreter. */
- Tcl_Interp *interp, /* Current interpreter. */
- int argc, /* Number of arguments. */
- Tcl_Obj *const argv[]) /* Argument objects. */
-{
- Tk_Window tkwin = clientData;
- TkCanvas *canvasPtr;
- Tk_Window newWin;
-
- if (typeList == NULL) {
- InitCanvas();
- }
-
- if (argc < 2) {
- Tcl_WrongNumArgs(interp, 1, argv, "pathName ?-option value ...?");
- return TCL_ERROR;
- }
-
- newWin = Tk_CreateWindowFromPath(interp,tkwin,Tcl_GetString(argv[1]),NULL);
- if (newWin == NULL) {
- return TCL_ERROR;
- }
-
- /*
- * Initialize fields that won't be initialized by ConfigureCanvas, or
- * which ConfigureCanvas expects to have reasonable values (e.g. resource
- * pointers).
- */
-
- canvasPtr = ckalloc(sizeof(TkCanvas));
- canvasPtr->tkwin = newWin;
- canvasPtr->display = Tk_Display(newWin);
- canvasPtr->interp = interp;
- canvasPtr->widgetCmd = Tcl_CreateObjCommand(interp,
- Tk_PathName(canvasPtr->tkwin), CanvasWidgetCmd, canvasPtr,
- CanvasCmdDeletedProc);
- canvasPtr->firstItemPtr = NULL;
- canvasPtr->lastItemPtr = NULL;
- canvasPtr->borderWidth = 0;
- canvasPtr->bgBorder = NULL;
- canvasPtr->relief = TK_RELIEF_FLAT;
- canvasPtr->highlightWidth = 0;
- canvasPtr->highlightBgColorPtr = NULL;
- canvasPtr->highlightColorPtr = NULL;
- canvasPtr->inset = 0;
- canvasPtr->pixmapGC = None;
- canvasPtr->width = None;
- canvasPtr->height = None;
- canvasPtr->confine = 0;
- canvasPtr->textInfo.selBorder = NULL;
- canvasPtr->textInfo.selBorderWidth = 0;
- canvasPtr->textInfo.selFgColorPtr = NULL;
- canvasPtr->textInfo.selItemPtr = NULL;
- canvasPtr->textInfo.selectFirst = -1;
- canvasPtr->textInfo.selectLast = -1;
- canvasPtr->textInfo.anchorItemPtr = NULL;
- canvasPtr->textInfo.selectAnchor = 0;
- canvasPtr->textInfo.insertBorder = NULL;
- canvasPtr->textInfo.insertWidth = 0;
- canvasPtr->textInfo.insertBorderWidth = 0;
- canvasPtr->textInfo.focusItemPtr = NULL;
- canvasPtr->textInfo.gotFocus = 0;
- canvasPtr->textInfo.cursorOn = 0;
- canvasPtr->insertOnTime = 0;
- canvasPtr->insertOffTime = 0;
- canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
- canvasPtr->xOrigin = canvasPtr->yOrigin = 0;
- canvasPtr->drawableXOrigin = canvasPtr->drawableYOrigin = 0;
- canvasPtr->bindingTable = NULL;
- canvasPtr->currentItemPtr = NULL;
- canvasPtr->newCurrentPtr = NULL;
- canvasPtr->closeEnough = 0.0;
- canvasPtr->pickEvent.type = LeaveNotify;
- canvasPtr->pickEvent.xcrossing.x = 0;
- canvasPtr->pickEvent.xcrossing.y = 0;
- canvasPtr->state = 0;
- canvasPtr->xScrollCmd = NULL;
- canvasPtr->yScrollCmd = NULL;
- canvasPtr->scrollX1 = 0;
- canvasPtr->scrollY1 = 0;
- canvasPtr->scrollX2 = 0;
- canvasPtr->scrollY2 = 0;
- canvasPtr->regionString = NULL;
- canvasPtr->xScrollIncrement = 0;
- canvasPtr->yScrollIncrement = 0;
- canvasPtr->scanX = 0;
- canvasPtr->scanXOrigin = 0;
- canvasPtr->scanY = 0;
- canvasPtr->scanYOrigin = 0;
- canvasPtr->hotPtr = NULL;
- canvasPtr->hotPrevPtr = NULL;
- canvasPtr->cursor = None;
- canvasPtr->takeFocus = NULL;
- canvasPtr->pixelsPerMM = WidthOfScreen(Tk_Screen(newWin));
- canvasPtr->pixelsPerMM /= WidthMMOfScreen(Tk_Screen(newWin));
- canvasPtr->flags = 0;
- canvasPtr->nextId = 1;
- canvasPtr->psInfo = NULL;
- canvasPtr->canvas_state = TK_STATE_NORMAL;
- canvasPtr->tsoffset.flags = 0;
- canvasPtr->tsoffset.xoffset = 0;
- canvasPtr->tsoffset.yoffset = 0;
-#ifndef USE_OLD_TAG_SEARCH
- canvasPtr->bindTagExprs = NULL;
-#endif
- Tcl_InitHashTable(&canvasPtr->idTable, TCL_ONE_WORD_KEYS);
-
- Tk_SetClass(canvasPtr->tkwin, "Canvas");
- Tk_SetClassProcs(canvasPtr->tkwin, &canvasClass, canvasPtr);
- Tk_CreateEventHandler(canvasPtr->tkwin,
- ExposureMask|StructureNotifyMask|FocusChangeMask,
- CanvasEventProc, canvasPtr);
- Tk_CreateEventHandler(canvasPtr->tkwin, KeyPressMask|KeyReleaseMask
- |ButtonPressMask|ButtonReleaseMask|EnterWindowMask
- |LeaveWindowMask|PointerMotionMask|VirtualEventMask,
- CanvasBindProc, canvasPtr);
- Tk_CreateSelHandler(canvasPtr->tkwin, XA_PRIMARY, XA_STRING,
- CanvasFetchSelection, canvasPtr, XA_STRING);
- if (ConfigureCanvas(interp, canvasPtr, argc-2, argv+2, 0) != TCL_OK) {
- goto error;
- }
-
- Tcl_SetObjResult(interp, TkNewWindowObj(canvasPtr->tkwin));
- return TCL_OK;
-
- error:
- Tk_DestroyWindow(canvasPtr->tkwin);
- return TCL_ERROR;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasWidgetCmd --
- *
- * This function is invoked to process the Tcl command that corresponds
- * to a widget managed by this module. See the user documentation for
- * details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-static int
-CanvasWidgetCmd(
- ClientData clientData, /* Information about canvas widget. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- TkCanvas *canvasPtr = clientData;
- int c, result;
- Tk_Item *itemPtr = NULL; /* Initialization needed only to prevent
- * compiler warning. */
-#ifdef USE_OLD_TAG_SEARCH
- TagSearch search;
-#else /* USE_OLD_TAG_SEARCH */
- TagSearch *searchPtr = NULL;/* Allocated by first TagSearchScan, freed by
- * TagSearchDestroy */
-#endif /* USE_OLD_TAG_SEARCH */
-
- int index;
- static const char *const optionStrings[] = {
- "addtag", "bbox", "bind", "canvasx",
- "canvasy", "cget", "configure", "coords",
- "create", "dchars", "delete", "dtag",
- "find", "focus", "gettags", "icursor",
- "imove", "index", "insert", "itemcget",
- "itemconfigure",
- "lower", "move", "moveto", "postscript",
- "raise", "rchars", "scale", "scan",
- "select", "type", "xview", "yview",
- NULL
- };
- enum options {
- CANV_ADDTAG, CANV_BBOX, CANV_BIND, CANV_CANVASX,
- CANV_CANVASY, CANV_CGET, CANV_CONFIGURE, CANV_COORDS,
- CANV_CREATE, CANV_DCHARS, CANV_DELETE, CANV_DTAG,
- CANV_FIND, CANV_FOCUS, CANV_GETTAGS, CANV_ICURSOR,
- CANV_IMOVE, CANV_INDEX, CANV_INSERT, CANV_ITEMCGET,
- CANV_ITEMCONFIGURE,
- CANV_LOWER, CANV_MOVE, CANV_MOVETO, CANV_POSTSCRIPT,
- CANV_RAISE, CANV_RCHARS, CANV_SCALE, CANV_SCAN,
- CANV_SELECT, CANV_TYPE, CANV_XVIEW, CANV_YVIEW
- };
-
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
- return TCL_ERROR;
- }
- if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
- &index) != TCL_OK) {
- return TCL_ERROR;
- }
- Tcl_Preserve(canvasPtr);
-
- result = TCL_OK;
- switch ((enum options) index) {
- case CANV_ADDTAG:
- if (objc < 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "tag searchCommand ?arg ...?");
- result = TCL_ERROR;
- goto done;
- }
- result = FIND_ITEMS(objv[2], 3);
- break;
-
- case CANV_BBOX: {
- int i, gotAny;
- int x1 = 0, y1 = 0, x2 = 0, y2 = 0; /* Initializations needed only
- * to prevent overcautious
- * compiler warnings. */
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagOrId ...?");
- result = TCL_ERROR;
- goto done;
- }
- gotAny = 0;
- for (i = 2; i < objc; i++) {
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) {
- if ((itemPtr->x1 >= itemPtr->x2)
- || (itemPtr->y1 >= itemPtr->y2)) {
- continue;
- }
- if (!gotAny) {
- x1 = itemPtr->x1;
- y1 = itemPtr->y1;
- x2 = itemPtr->x2;
- y2 = itemPtr->y2;
- gotAny = 1;
- } else {
- if (itemPtr->x1 < x1) {
- x1 = itemPtr->x1;
- }
- if (itemPtr->y1 < y1) {
- y1 = itemPtr->y1;
- }
- if (itemPtr->x2 > x2) {
- x2 = itemPtr->x2;
- }
- if (itemPtr->y2 > y2) {
- y2 = itemPtr->y2;
- }
- }
- }
- }
- if (gotAny) {
- Tcl_Obj *resultObjs[4];
-
- resultObjs[0] = Tcl_NewIntObj(x1);
- resultObjs[1] = Tcl_NewIntObj(y1);
- resultObjs[2] = Tcl_NewIntObj(x2);
- resultObjs[3] = Tcl_NewIntObj(y2);
- Tcl_SetObjResult(interp, Tcl_NewListObj(4, resultObjs));
- }
- break;
- }
- case CANV_BIND: {
- ClientData object;
-
- if ((objc < 3) || (objc > 5)) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?sequence? ?command?");
- result = TCL_ERROR;
- goto done;
- }
-
- /*
- * Figure out what object to use for the binding (individual item vs.
- * tag).
- */
-
- object = NULL;
-#ifdef USE_OLD_TAG_SEARCH
- if (isdigit(UCHAR(Tcl_GetString(objv[2])[0]))) {
- int id;
- char *end;
- Tcl_HashEntry *entryPtr;
-
- id = strtoul(Tcl_GetString(objv[2]), &end, 0);
- if (*end != 0) {
- goto bindByTag;
- }
- entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char *) id);
- if (entryPtr != NULL) {
- itemPtr = Tcl_GetHashValue(entryPtr);
- object = itemPtr;
- }
-
- if (object == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "item \"%s\" doesn't exist", Tcl_GetString(objv[2])));
- Tcl_SetErrorCode(interp, "TK", "LOOKUP", "CANVAS_ITEM",
- Tcl_GetString(objv[2]), NULL);
- result = TCL_ERROR;
- goto done;
- }
- } else {
- bindByTag:
- object = Tk_GetUid(Tcl_GetString(objv[2]));
- }
-#else /* USE_OLD_TAG_SEARCH */
- result = TagSearchScan(canvasPtr, objv[2], &searchPtr);
- if (result != TCL_OK) {
- goto done;
- }
- if (searchPtr->type == SEARCH_TYPE_ID) {
- Tcl_HashEntry *entryPtr;
-
- entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
- (char *) INT2PTR(searchPtr->id));
- if (entryPtr != NULL) {
- itemPtr = Tcl_GetHashValue(entryPtr);
- object = itemPtr;
- }
-
- if (object == 0) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "item \"%s\" doesn't exist", Tcl_GetString(objv[2])));
- Tcl_SetErrorCode(interp, "TK", "LOOKUP", "CANVAS_ITEM",
- Tcl_GetString(objv[2]), NULL);
- result = TCL_ERROR;
- goto done;
- }
- } else {
- object = (ClientData) searchPtr->expr->uid;
- }
-#endif /* USE_OLD_TAG_SEARCH */
-
- /*
- * Make a binding table if the canvas doesn't already have one.
- */
-
- if (canvasPtr->bindingTable == NULL) {
- canvasPtr->bindingTable = Tk_CreateBindingTable(interp);
- }
-
- if (objc == 5) {
- int append = 0;
- unsigned long mask;
- const char *argv4 = Tcl_GetString(objv[4]);
-
- if (argv4[0] == 0) {
- result = Tk_DeleteBinding(interp, canvasPtr->bindingTable,
- object, Tcl_GetString(objv[3]));
- goto done;
- }
-#ifndef USE_OLD_TAG_SEARCH
- if (searchPtr->type == SEARCH_TYPE_EXPR) {
- /*
- * If new tag expression, then insert in linked list.
- */
-
- TagSearchExpr *expr, **lastPtr;
-
- lastPtr = &(canvasPtr->bindTagExprs);
- while ((expr = *lastPtr) != NULL) {
- if (expr->uid == searchPtr->expr->uid) {
- break;
- }
- lastPtr = &(expr->next);
- }
- if (!expr) {
- /*
- * Transfer ownership of expr to bindTagExprs list.
- */
-
- *lastPtr = searchPtr->expr;
- searchPtr->expr->next = NULL;
-
- /*
- * Flag in TagSearch that expr has changed ownership so
- * that TagSearchDestroy doesn't try to free it.
- */
-
- searchPtr->expr = NULL;
- }
- }
-#endif /* not USE_OLD_TAG_SEARCH */
- if (argv4[0] == '+') {
- argv4++;
- append = 1;
- }
- mask = Tk_CreateBinding(interp, canvasPtr->bindingTable,
- object, Tcl_GetString(objv[3]), argv4, append);
- if (mask == 0) {
- result = TCL_ERROR;
- goto done;
- }
- if (mask & (unsigned) ~(ButtonMotionMask|Button1MotionMask
- |Button2MotionMask|Button3MotionMask|Button4MotionMask
- |Button5MotionMask|ButtonPressMask|ButtonReleaseMask
- |EnterWindowMask|LeaveWindowMask|KeyPressMask
- |KeyReleaseMask|PointerMotionMask|VirtualEventMask)) {
- Tk_DeleteBinding(interp, canvasPtr->bindingTable,
- object, Tcl_GetString(objv[3]));
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "requested illegal events; only key, button, motion,"
- " enter, leave, and virtual events may be used", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "BAD_EVENTS", NULL);
- result = TCL_ERROR;
- goto done;
- }
- } else if (objc == 4) {
- const char *command;
-
- command = Tk_GetBinding(interp, canvasPtr->bindingTable,
- object, Tcl_GetString(objv[3]));
- if (command == NULL) {
- const char *string = Tcl_GetString(Tcl_GetObjResult(interp));
-
- /*
- * Ignore missing binding errors. This is a special hack that
- * relies on the error message returned by FindSequence in
- * tkBind.c.
- */
-
- if (string[0] != '\0') {
- result = TCL_ERROR;
- goto done;
- }
- Tcl_ResetResult(interp);
- } else {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(command, -1));
- }
- } else {
- Tk_GetAllBindings(interp, canvasPtr->bindingTable, object);
- }
- break;
- }
- case CANV_CANVASX: {
- int x;
- double grid;
-
- if ((objc < 3) || (objc > 4)) {
- Tcl_WrongNumArgs(interp, 2, objv, "screenx ?gridspacing?");
- result = TCL_ERROR;
- goto done;
- }
- if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2],
- &x) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
- if (objc == 4) {
- if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[3], &grid) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
- } else {
- grid = 0.0;
- }
- x += canvasPtr->xOrigin;
- Tcl_SetObjResult(interp, Tcl_NewDoubleObj(GridAlign((double)x,grid)));
- break;
- }
- case CANV_CANVASY: {
- int y;
- double grid;
-
- if ((objc < 3) || (objc > 4)) {
- Tcl_WrongNumArgs(interp, 2, objv, "screeny ?gridspacing?");
- result = TCL_ERROR;
- goto done;
- }
- if (Tk_GetPixelsFromObj(interp, canvasPtr->tkwin, objv[2],
- &y) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
- if (objc == 4) {
- if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[3], &grid) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
- } else {
- grid = 0.0;
- }
- y += canvasPtr->yOrigin;
- Tcl_SetObjResult(interp, Tcl_NewDoubleObj(GridAlign((double)y,grid)));
- break;
- }
- case CANV_CGET:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "option");
- result = TCL_ERROR;
- goto done;
- }
- result = Tk_ConfigureValue(interp, canvasPtr->tkwin, configSpecs,
- (char *) canvasPtr, Tcl_GetString(objv[2]), 0);
- break;
- case CANV_CONFIGURE:
- if (objc == 2) {
- result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
- (char *) canvasPtr, NULL, 0);
- } else if (objc == 3) {
- result = Tk_ConfigureInfo(interp, canvasPtr->tkwin, configSpecs,
- (char *) canvasPtr, Tcl_GetString(objv[2]), 0);
- } else {
- result = ConfigureCanvas(interp, canvasPtr, objc-2, objv+2,
- TK_CONFIG_ARGV_ONLY);
- }
- break;
- case CANV_COORDS:
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?x y x y ...?");
- result = TCL_ERROR;
- goto done;
- }
- FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
- if (itemPtr != NULL) {
- if (objc != 3) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- result = ItemCoords(canvasPtr, itemPtr, objc-3, objv+3);
- if (objc != 3) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- }
- break;
- case CANV_IMOVE: {
- double ignored;
- Tcl_Obj *tmpObj;
-
- if (objc != 6) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index x y");
- result = TCL_ERROR;
- goto done;
- }
- if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[4], &ignored) != TCL_OK
- || Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[5], &ignored) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
-
- /*
- * Make a temporary object here that we can reuse for all the
- * modifications in the loop.
- */
-
- tmpObj = Tcl_NewListObj(2, objv+4);
-
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto doneImove) {
- int index;
- int x1,x2,y1,y2;
- int dontRedraw1,dontRedraw2;
-
- /*
- * The TK_MOVABLE_POINTS flag should only be set for types that
- * support the same semantics of index, dChars and insert methods
- * as lines and canvases.
- */
-
- if (itemPtr == NULL ||
- !(itemPtr->typePtr->alwaysRedraw & TK_MOVABLE_POINTS)) {
- continue;
- }
-
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &index);
- if (result != TCL_OK) {
- break;
- }
-
- /*
- * Redraw both item's old and new areas: it's possible that a
- * replace could result in a new area larger than the old area.
- * Except if the dCharsProc or insertProc sets the
- * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
- */
-
- x1 = itemPtr->x1; y1 = itemPtr->y1;
- x2 = itemPtr->x2; y2 = itemPtr->y2;
-
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- ItemDelChars(canvasPtr, itemPtr, index, index);
- dontRedraw1=itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;
-
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- ItemInsert(canvasPtr, itemPtr, index, tmpObj);
- dontRedraw2=itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;
-
- if (!(dontRedraw1 && dontRedraw2)) {
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- x1, y1, x2, y2);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- }
-
- doneImove:
- Tcl_DecrRefCount(tmpObj);
- break;
- }
- case CANV_CREATE: {
- Tk_ItemType *typePtr;
- Tk_ItemType *matchPtr = NULL;
- Tk_Item *itemPtr;
- int isNew = 0;
- Tcl_HashEntry *entryPtr;
- const char *arg;
- size_t length;
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "type coords ?arg ...?");
- result = TCL_ERROR;
- goto done;
- }
- arg = Tcl_GetString(objv[2]);
- length = objv[2]->length;
- c = arg[0];
-
- /*
- * Lock because the list of types is a global resource that could be
- * updated by another thread. That's fairly unlikely, but not
- * impossible.
- */
-
- Tcl_MutexLock(&typeListMutex);
- for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->nextPtr){
- if ((c == typePtr->name[0])
- && (!strncmp(arg, typePtr->name, length))) {
- if (matchPtr != NULL) {
- Tcl_MutexUnlock(&typeListMutex);
- goto badType;
- }
- matchPtr = typePtr;
- }
- }
-
- /*
- * Can unlock now because we no longer look at the fields of the
- * matched item type that are potentially modified by other threads.
- */
-
- Tcl_MutexUnlock(&typeListMutex);
- if (matchPtr == NULL) {
- badType:
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "unknown or ambiguous item type \"%s\"", arg));
- Tcl_SetErrorCode(interp, "TK", "LOOKUP", "CANVAS_ITEM_TYPE", arg,
- NULL);
- result = TCL_ERROR;
- goto done;
- }
- if (objc < 4) {
- /*
- * Allow more specific error return.
- */
-
- Tcl_WrongNumArgs(interp, 3, objv, "coords ?arg ...?");
- result = TCL_ERROR;
- goto done;
- }
-
- typePtr = matchPtr;
- itemPtr = ckalloc(typePtr->itemSize);
- itemPtr->id = canvasPtr->nextId;
- canvasPtr->nextId++;
- itemPtr->tagPtr = itemPtr->staticTagSpace;
- itemPtr->tagSpace = TK_TAG_SPACE;
- itemPtr->numTags = 0;
- itemPtr->typePtr = typePtr;
- itemPtr->state = TK_STATE_NULL;
- itemPtr->redraw_flags = 0;
-
- if (ItemCreate(canvasPtr, itemPtr, objc, objv) != TCL_OK) {
- ckfree(itemPtr);
- result = TCL_ERROR;
- goto done;
- }
-
- itemPtr->nextPtr = NULL;
- entryPtr = Tcl_CreateHashEntry(&canvasPtr->idTable,
- (char *) INT2PTR(itemPtr->id), &isNew);
- Tcl_SetHashValue(entryPtr, itemPtr);
- itemPtr->prevPtr = canvasPtr->lastItemPtr;
- canvasPtr->hotPtr = itemPtr;
- canvasPtr->hotPrevPtr = canvasPtr->lastItemPtr;
- if (canvasPtr->lastItemPtr == NULL) {
- canvasPtr->firstItemPtr = itemPtr;
- } else {
- canvasPtr->lastItemPtr->nextPtr = itemPtr;
- }
- canvasPtr->lastItemPtr = itemPtr;
- itemPtr->redraw_flags |= FORCE_REDRAW;
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- Tcl_SetObjResult(interp, Tcl_NewIntObj(itemPtr->id));
- break;
- }
- case CANV_DCHARS: {
- int first, last;
- int x1,x2,y1,y2;
-
- if ((objc != 4) && (objc != 5)) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if ((itemPtr->typePtr->indexProc == NULL)
- || (itemPtr->typePtr->dCharsProc == NULL)) {
- continue;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &first);
- if (result != TCL_OK) {
- goto done;
- }
- if (objc == 5) {
- result = ItemIndex(canvasPtr, itemPtr, objv[4], &last);
- if (result != TCL_OK) {
- goto done;
- }
- } else {
- last = first;
- }
-
- /*
- * Redraw both item's old and new areas: it's possible that a
- * delete could result in a new area larger than the old area.
- * Except if the insertProc sets the TK_ITEM_DONT_REDRAW flag,
- * nothing more needs to be done.
- */
-
- x1 = itemPtr->x1; y1 = itemPtr->y1;
- x2 = itemPtr->x2; y2 = itemPtr->y2;
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- ItemDelChars(canvasPtr, itemPtr, first, last);
- if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- x1, y1, x2, y2);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- }
- break;
- }
- case CANV_DELETE: {
- int i;
- Tcl_HashEntry *entryPtr;
-
- for (i = 2; i < objc; i++) {
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- if (canvasPtr->bindingTable != NULL) {
- Tk_DeleteAllBindings(canvasPtr->bindingTable, itemPtr);
- }
- ItemDelete(canvasPtr, itemPtr);
- if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
- ckfree(itemPtr->tagPtr);
- }
- entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable,
- (char *) INT2PTR(itemPtr->id));
- Tcl_DeleteHashEntry(entryPtr);
- if (itemPtr->nextPtr != NULL) {
- itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
- }
- if (itemPtr->prevPtr != NULL) {
- itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
- }
- if (canvasPtr->firstItemPtr == itemPtr) {
- canvasPtr->firstItemPtr = itemPtr->nextPtr;
- if (canvasPtr->firstItemPtr == NULL) {
- canvasPtr->lastItemPtr = NULL;
- }
- }
- if (canvasPtr->lastItemPtr == itemPtr) {
- canvasPtr->lastItemPtr = itemPtr->prevPtr;
- }
- ckfree(itemPtr);
- if (itemPtr == canvasPtr->currentItemPtr) {
- canvasPtr->currentItemPtr = NULL;
- canvasPtr->flags |= REPICK_NEEDED;
- }
- if (itemPtr == canvasPtr->newCurrentPtr) {
- canvasPtr->newCurrentPtr = NULL;
- canvasPtr->flags |= REPICK_NEEDED;
- }
- if (itemPtr == canvasPtr->textInfo.focusItemPtr) {
- canvasPtr->textInfo.focusItemPtr = NULL;
- }
- if (itemPtr == canvasPtr->textInfo.selItemPtr) {
- canvasPtr->textInfo.selItemPtr = NULL;
- }
- if ((itemPtr == canvasPtr->hotPtr)
- || (itemPtr == canvasPtr->hotPrevPtr)) {
- canvasPtr->hotPtr = NULL;
- }
- }
- }
- break;
- }
- case CANV_DTAG: {
- Tk_Uid tag;
- int i;
-
- if ((objc != 3) && (objc != 4)) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?tagToDelete?");
- result = TCL_ERROR;
- goto done;
- }
- if (objc == 4) {
- tag = Tk_GetUid(Tcl_GetString(objv[3]));
- } else {
- tag = Tk_GetUid(Tcl_GetString(objv[2]));
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- for (i = itemPtr->numTags-1; i >= 0; i--) {
- if (itemPtr->tagPtr[i] == tag) {
- itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
- itemPtr->numTags--;
- }
- }
- }
- break;
- }
- case CANV_FIND:
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "searchCommand ?arg ...?");
- result = TCL_ERROR;
- goto done;
- }
- result = FIND_ITEMS(NULL, 2);
- break;
- case CANV_FOCUS:
- if (objc > 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "?tagOrId?");
- result = TCL_ERROR;
- goto done;
- }
- itemPtr = canvasPtr->textInfo.focusItemPtr;
- if (objc == 2) {
- if (itemPtr != NULL) {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(itemPtr->id));
- }
- goto done;
- }
- if (canvasPtr->textInfo.gotFocus) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- if (Tcl_GetString(objv[2])[0] == 0) {
- canvasPtr->textInfo.focusItemPtr = NULL;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if (itemPtr->typePtr->icursorProc != NULL) {
- break;
- }
- }
- if (itemPtr == NULL) {
- goto done;
- }
- canvasPtr->textInfo.focusItemPtr = itemPtr;
- if (canvasPtr->textInfo.gotFocus) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- break;
- case CANV_GETTAGS:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId");
- result = TCL_ERROR;
- goto done;
- }
- FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
- if (itemPtr != NULL) {
- int i;
- Tcl_Obj *resultObj = Tcl_NewObj();
-
- for (i = 0; i < itemPtr->numTags; i++) {
- Tcl_ListObjAppendElement(NULL, resultObj,
- Tcl_NewStringObj(itemPtr->tagPtr[i], -1));
- }
- Tcl_SetObjResult(interp, resultObj);
- }
- break;
- case CANV_ICURSOR: {
- int index;
-
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if ((itemPtr->typePtr->indexProc == NULL)
- || (itemPtr->typePtr->icursorProc == NULL)) {
- goto done;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &index);
- if (result != TCL_OK) {
- goto done;
- }
- ItemCursor(canvasPtr, itemPtr, index);
- if ((itemPtr == canvasPtr->textInfo.focusItemPtr)
- && (canvasPtr->textInfo.cursorOn)) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- }
- break;
- }
- case CANV_INDEX: {
- int index;
-
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId string");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if (itemPtr->typePtr->indexProc != NULL) {
- break;
- }
- }
- if (itemPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't find an indexable item \"%s\"",
- Tcl_GetString(objv[2])));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "INDEXABLE_ITEM", NULL);
- result = TCL_ERROR;
- goto done;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &index);
- if (result != TCL_OK) {
- goto done;
- }
- Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
- break;
- }
- case CANV_INSERT: {
- int beforeThis;
- int x1,x2,y1,y2;
-
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if ((itemPtr->typePtr->indexProc == NULL)
- || (itemPtr->typePtr->insertProc == NULL)) {
- continue;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &beforeThis);
- if (result != TCL_OK) {
- goto done;
- }
-
- /*
- * Redraw both item's old and new areas: it's possible that an
- * insertion could result in a new area either larger or smaller
- * than the old area. Except if the insertProc sets the
- * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
- */
-
- x1 = itemPtr->x1; y1 = itemPtr->y1;
- x2 = itemPtr->x2; y2 = itemPtr->y2;
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- ItemInsert(canvasPtr, itemPtr, beforeThis, objv[4]);
- if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- x1, y1, x2, y2);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- }
- break;
- }
- case CANV_ITEMCGET:
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId option");
- result = TCL_ERROR;
- goto done;
- }
- FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
- if (itemPtr != NULL) {
- result = ItemConfigValue(canvasPtr, itemPtr, objv[3]);
- }
- break;
- case CANV_ITEMCONFIGURE:
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?-option value ...?");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if (objc == 3) {
- result = ItemConfigInfo(canvasPtr, itemPtr, NULL);
- } else if (objc == 4) {
- result = ItemConfigInfo(canvasPtr, itemPtr, objv[3]);
- } else {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- result = ItemConfigure(canvasPtr, itemPtr, objc-3, objv+3);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- }
- if ((result != TCL_OK) || (objc < 5)) {
- break;
- }
- }
- break;
- case CANV_LOWER: {
- Tk_Item *itemPtr;
-
- if ((objc != 3) && (objc != 4)) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?belowThis?");
- result = TCL_ERROR;
- goto done;
- }
-
- /*
- * First find the item just after which we'll insert the named items.
- */
-
- if (objc == 3) {
- itemPtr = NULL;
- } else {
- FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done);
- if (itemPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "tagOrId \"%s\" doesn't match any items",
- Tcl_GetString(objv[3])));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "ITEM", NULL);
- result = TCL_ERROR;
- goto done;
- }
- itemPtr = itemPtr->prevPtr;
- }
- RELINK_ITEMS(objv[2], itemPtr);
- break;
- }
- case CANV_MOVE: {
- double xAmount, yAmount;
-
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId xAmount yAmount");
- result = TCL_ERROR;
- goto done;
- }
- if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, objv[3],
- &xAmount) != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp,
- (Tk_Canvas) canvasPtr, objv[4], &yAmount) != TCL_OK)) {
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- }
- break;
- }
- case CANV_MOVETO: {
- int xBlank, yBlank;
- double xAmount, yAmount;
- double oldX = 0, oldY = 0, newX, newY;
-
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId x y");
- result = TCL_ERROR;
- goto done;
- }
-
- xBlank = 0;
- if (Tcl_GetString(objv[3])[0] == '\0') {
- xBlank = 1;
- } else if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[3], &newX) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
-
- yBlank = 0;
- if (Tcl_GetString(objv[4])[0] == '\0') {
- yBlank = 1;
- } else if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[4], &newY) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
-
- FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
- if (itemPtr != NULL) {
- oldX = itemPtr->x1;
- oldY = itemPtr->y1;
-
- /*
- * Calculate the displacement.
- */
-
- if (xBlank) {
- xAmount = 0;
- } else {
- xAmount = newX - oldX;
- }
-
- if (yBlank) {
- yAmount = 0;
- } else {
- yAmount = newY - oldY;
- }
-
- /*
- * Move the object(s).
- */
-
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- }
- }
- break;
- }
- case CANV_POSTSCRIPT: {
- const char **args = TkGetStringsFromObjs(objc, objv);
-
- result = TkCanvPostscriptCmd(canvasPtr, interp, objc, args);
- if (args != NULL) {
- ckfree(args);
- }
- break;
- }
- case CANV_RAISE: {
- Tk_Item *prevPtr;
-
- if ((objc != 3) && (objc != 4)) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId ?aboveThis?");
- result = TCL_ERROR;
- goto done;
- }
-
- /*
- * First find the item just after which we'll insert the named items.
- */
-
- if (objc == 3) {
- prevPtr = canvasPtr->lastItemPtr;
- } else {
- prevPtr = NULL;
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) {
- prevPtr = itemPtr;
- }
- if (prevPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "tagOrId \"%s\" doesn't match any items",
- Tcl_GetString(objv[3])));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "ITEM", NULL);
- result = TCL_ERROR;
- goto done;
- }
- }
- RELINK_ITEMS(objv[2], prevPtr);
- break;
- }
- case CANV_RCHARS: {
- int first, last;
- int x1,x2,y1,y2;
-
- if (objc != 6) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first last string");
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- if ((itemPtr->typePtr->indexProc == NULL)
- || (itemPtr->typePtr->dCharsProc == NULL)
- || (itemPtr->typePtr->insertProc == NULL)) {
- continue;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[3], &first);
- if (result != TCL_OK) {
- goto done;
- }
- result = ItemIndex(canvasPtr, itemPtr, objv[4], &last);
- if (result != TCL_OK) {
- goto done;
- }
-
- /*
- * Redraw both item's old and new areas: it's possible that a
- * replace could result in a new area larger than the old area.
- * Except if the dCharsProc or insertProc sets the
- * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
- */
-
- x1 = itemPtr->x1; y1 = itemPtr->y1;
- x2 = itemPtr->x2; y2 = itemPtr->y2;
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
-
- ItemDelChars(canvasPtr, itemPtr, first, last);
- ItemInsert(canvasPtr, itemPtr, first, objv[5]);
-
- if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- x1, y1, x2, y2);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
- itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
- }
- break;
- }
- case CANV_SCALE: {
- double xOrigin, yOrigin, xScale, yScale;
-
- if (objc != 7) {
- Tcl_WrongNumArgs(interp, 2, objv,
- "tagOrId xOrigin yOrigin xScale yScale");
- result = TCL_ERROR;
- goto done;
- }
- if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[3], &xOrigin) != TCL_OK)
- || (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[4], &yOrigin) != TCL_OK)
- || (Tcl_GetDoubleFromObj(interp, objv[5], &xScale)!=TCL_OK)
- || (Tcl_GetDoubleFromObj(interp, objv[6], &yScale)!=TCL_OK)) {
- result = TCL_ERROR;
- goto done;
- }
- if ((xScale == 0.0) || (yScale == 0.0)) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "scale factor cannot be zero", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "BAD_SCALE", NULL);
- result = TCL_ERROR;
- goto done;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- ItemScale(canvasPtr, itemPtr, xOrigin, yOrigin, xScale, yScale);
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- }
- break;
- }
- case CANV_SCAN: {
- int x, y, gain = 10;
- static const char *const optionStrings[] = {
- "mark", "dragto", NULL
- };
-
- if (objc < 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?dragGain?");
- result = TCL_ERROR;
- } else if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings,
- "scan option", 0, &index) != TCL_OK) {
- result = TCL_ERROR;
- } else if ((objc != 5) && (objc != 5+index)) {
- Tcl_WrongNumArgs(interp, 3, objv, index?"x y ?gain?":"x y");
- result = TCL_ERROR;
- } else if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
- || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
- result = TCL_ERROR;
- } else if ((objc == 6) &&
- (Tcl_GetIntFromObj(interp, objv[5], &gain) != TCL_OK)) {
- result = TCL_ERROR;
- } else if (!index) {
- canvasPtr->scanX = x;
- canvasPtr->scanXOrigin = canvasPtr->xOrigin;
- canvasPtr->scanY = y;
- canvasPtr->scanYOrigin = canvasPtr->yOrigin;
- } else {
- int newXOrigin, newYOrigin, tmp;
-
- /*
- * Compute a new view origin for the canvas, amplifying the
- * mouse motion.
- */
-
- tmp = canvasPtr->scanXOrigin - gain*(x - canvasPtr->scanX)
- - canvasPtr->scrollX1;
- newXOrigin = canvasPtr->scrollX1 + tmp;
- tmp = canvasPtr->scanYOrigin - gain*(y - canvasPtr->scanY)
- - canvasPtr->scrollY1;
- newYOrigin = canvasPtr->scrollY1 + tmp;
- CanvasSetOrigin(canvasPtr, newXOrigin, newYOrigin);
- }
- break;
- }
- case CANV_SELECT: {
- int index, optionindex;
- static const char *const optionStrings[] = {
- "adjust", "clear", "from", "item", "to", NULL
- };
- enum options {
- CANV_ADJUST, CANV_CLEAR, CANV_FROM, CANV_ITEM, CANV_TO
- };
-
- if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "option ?tagOrId? ?arg?");
- result = TCL_ERROR;
- goto done;
- }
- if (objc >= 4) {
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) {
- if ((itemPtr->typePtr->indexProc != NULL)
- && (itemPtr->typePtr->selectionProc != NULL)){
- break;
- }
- }
- if (itemPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't find an indexable and selectable item \"%s\"",
- Tcl_GetString(objv[3])));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SELECTABLE_ITEM",
- NULL);
- result = TCL_ERROR;
- goto done;
- }
- }
- if (objc == 5) {
- result = ItemIndex(canvasPtr, itemPtr, objv[4], &index);
- if (result != TCL_OK) {
- goto done;
- }
- }
- if (Tcl_GetIndexFromObj(interp, objv[2], optionStrings,
- "select option", 0, &optionindex) != TCL_OK) {
- result = TCL_ERROR;
- goto done;
- }
- switch ((enum options) optionindex) {
- case CANV_ADJUST:
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index");
- result = TCL_ERROR;
- goto done;
- }
- if (canvasPtr->textInfo.selItemPtr == itemPtr) {
- if (index < (canvasPtr->textInfo.selectFirst
- + canvasPtr->textInfo.selectLast)/2) {
- canvasPtr->textInfo.selectAnchor =
- canvasPtr->textInfo.selectLast + 1;
- } else {
- canvasPtr->textInfo.selectAnchor =
- canvasPtr->textInfo.selectFirst;
- }
- }
- CanvasSelectTo(canvasPtr, itemPtr, index);
- break;
- case CANV_CLEAR:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 3, objv, NULL);
- result = TCL_ERROR;
- goto done;
- }
- EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.selItemPtr);
- canvasPtr->textInfo.selItemPtr = NULL;
- break;
- case CANV_FROM:
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 3, objv, "tagOrId index");
- result = TCL_ERROR;
- goto done;
- }
- canvasPtr->textInfo.anchorItemPtr = itemPtr;
- canvasPtr->textInfo.selectAnchor = index;
- break;
- case CANV_ITEM:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 3, objv, NULL);
- result = TCL_ERROR;
- goto done;
- }
- if (canvasPtr->textInfo.selItemPtr != NULL) {
- Tcl_SetObjResult(interp,
- Tcl_NewIntObj(canvasPtr->textInfo.selItemPtr->id));
- }
- break;
- case CANV_TO:
- if (objc != 5) {
- Tcl_WrongNumArgs(interp, 2, objv, "tagOrId index");
- result = TCL_ERROR;
- goto done;
- }
- CanvasSelectTo(canvasPtr, itemPtr, index);
- break;
- }
- break;
- }
- case CANV_TYPE:
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "tag");
- result = TCL_ERROR;
- goto done;
- }
- FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
- if (itemPtr != NULL) {
- Tcl_SetObjResult(interp,
- Tcl_NewStringObj(itemPtr->typePtr->name, -1));
- }
- break;
- case CANV_XVIEW: {
- int count, type;
- int newX = 0; /* Initialization needed only to prevent gcc
- * warnings. */
- double fraction;
- const char **args;
-
- if (objc == 2) {
- Tcl_SetObjResult(interp, ScrollFractions(
- canvasPtr->xOrigin + canvasPtr->inset,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)
- - canvasPtr->inset, canvasPtr->scrollX1,
- canvasPtr->scrollX2));
- break;
- }
-
- args = TkGetStringsFromObjs(objc, objv);
- type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count);
- if (args != NULL) {
- ckfree(args);
- }
- switch (type) {
- case TK_SCROLL_ERROR:
- result = TCL_ERROR;
- goto done;
- case TK_SCROLL_MOVETO:
- newX = canvasPtr->scrollX1 - canvasPtr->inset
- + (int) (fraction * (canvasPtr->scrollX2
- - canvasPtr->scrollX1) + 0.5);
- break;
- case TK_SCROLL_PAGES:
- newX = (int) (canvasPtr->xOrigin + count * .9
- * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
- break;
- case TK_SCROLL_UNITS:
- if (canvasPtr->xScrollIncrement > 0) {
- newX = canvasPtr->xOrigin + count*canvasPtr->xScrollIncrement;
- } else {
- newX = (int) (canvasPtr->xOrigin + count * .1
- * (Tk_Width(canvasPtr->tkwin) - 2*canvasPtr->inset));
- }
- break;
- }
- CanvasSetOrigin(canvasPtr, newX, canvasPtr->yOrigin);
- break;
- }
- case CANV_YVIEW: {
- int count, type;
- int newY = 0; /* Initialization needed only to prevent gcc
- * warnings. */
- double fraction;
- const char **args;
-
- if (objc == 2) {
- Tcl_SetObjResult(interp, ScrollFractions(
- canvasPtr->yOrigin + canvasPtr->inset,
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin)
- - canvasPtr->inset,
- canvasPtr->scrollY1, canvasPtr->scrollY2));
- break;
- }
-
- args = TkGetStringsFromObjs(objc, objv);
- type = Tk_GetScrollInfo(interp, objc, args, &fraction, &count);
- if (args != NULL) {
- ckfree(args);
- }
- switch (type) {
- case TK_SCROLL_ERROR:
- result = TCL_ERROR;
- goto done;
- case TK_SCROLL_MOVETO:
- newY = canvasPtr->scrollY1 - canvasPtr->inset + (int) (
- fraction*(canvasPtr->scrollY2-canvasPtr->scrollY1) + 0.5);
- break;
- case TK_SCROLL_PAGES:
- newY = (int) (canvasPtr->yOrigin + count * .9
- * (Tk_Height(canvasPtr->tkwin) - 2*canvasPtr->inset));
- break;
- case TK_SCROLL_UNITS:
- if (canvasPtr->yScrollIncrement > 0) {
- newY = canvasPtr->yOrigin + count*canvasPtr->yScrollIncrement;
- } else {
- newY = (int) (canvasPtr->yOrigin + count * .1
- * (Tk_Height(canvasPtr->tkwin) - 2*canvasPtr->inset));
- }
- break;
- }
- CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
- break;
- }
- }
-
- done:
-#ifndef USE_OLD_TAG_SEARCH
- TagSearchDestroy(searchPtr);
-#endif /* not USE_OLD_TAG_SEARCH */
- Tcl_Release(canvasPtr);
- return result;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DestroyCanvas --
- *
- * This function is invoked by Tcl_EventuallyFree or Tcl_Release to clean
- * up the internal structure of a canvas at a safe time (when no-one is
- * using it anymore).
- *
- * Results:
- * None.
- *
- * Side effects:
- * Everything associated with the canvas is freed up.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DestroyCanvas(
- char *memPtr) /* Info about canvas widget. */
-{
- TkCanvas *canvasPtr = (TkCanvas *) memPtr;
- Tk_Item *itemPtr;
-#ifndef USE_OLD_TAG_SEARCH
- TagSearchExpr *expr, *next;
-#endif
-
- /*
- * Free up all of the items in the canvas.
- */
-
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = canvasPtr->firstItemPtr) {
- canvasPtr->firstItemPtr = itemPtr->nextPtr;
- ItemDelete(canvasPtr, itemPtr);
- if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
- ckfree(itemPtr->tagPtr);
- }
- ckfree(itemPtr);
- }
-
- /*
- * Free up all the stuff that requires special handling, then let
- * Tk_FreeOptions handle all the standard option-related stuff.
- */
-
- Tcl_DeleteHashTable(&canvasPtr->idTable);
- if (canvasPtr->pixmapGC != None) {
- Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
- }
-#ifndef USE_OLD_TAG_SEARCH
- expr = canvasPtr->bindTagExprs;
- while (expr) {
- next = expr->next;
- TagSearchExprDestroy(expr);
- expr = next;
- }
-#endif /* USE_OLD_TAG_SEARCH */
- Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
- if (canvasPtr->bindingTable != NULL) {
- Tk_DeleteBindingTable(canvasPtr->bindingTable);
- }
- Tk_FreeOptions(configSpecs, (char *) canvasPtr, canvasPtr->display, 0);
- canvasPtr->tkwin = NULL;
- ckfree(canvasPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ConfigureCanvas --
- *
- * This function is called to process an objv/objc list, plus the Tk
- * option database, in order to configure (or reconfigure) a canvas
- * widget.
- *
- * Results:
- * The return value is a standard Tcl result. If TCL_ERROR is returned,
- * then the interp's result contains an error message.
- *
- * Side effects:
- * Configuration information, such as colors, border width, etc. get set
- * for canvasPtr; old resources get freed, if there were any.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ConfigureCanvas(
- Tcl_Interp *interp, /* Used for error reporting. */
- TkCanvas *canvasPtr, /* Information about widget; may or may not
- * already have values for some fields. */
- int objc, /* Number of valid entries in objv. */
- Tcl_Obj *const objv[], /* Argument objects. */
- int flags) /* Flags to pass to Tk_ConfigureWidget. */
-{
- XGCValues gcValues;
- GC newGC;
- Tk_State old_canvas_state=canvasPtr->canvas_state;
-
- if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs,
- objc, (const char **) objv, (char *) canvasPtr,
- flags|TK_CONFIG_OBJS) != TCL_OK) {
- return TCL_ERROR;
- }
-
- /*
- * A few options need special processing, such as setting the background
- * from a 3-D border and creating a GC for copying bits to the screen.
- */
-
- Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder);
-
- if (canvasPtr->highlightWidth < 0) {
- canvasPtr->highlightWidth = 0;
- }
- canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth;
-
- gcValues.function = GXcopy;
- gcValues.graphics_exposures = False;
- gcValues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
- newGC = Tk_GetGC(canvasPtr->tkwin,
- GCFunction|GCGraphicsExposures|GCForeground, &gcValues);
- if (canvasPtr->pixmapGC != None) {
- Tk_FreeGC(canvasPtr->display, canvasPtr->pixmapGC);
- }
- canvasPtr->pixmapGC = newGC;
-
- /*
- * Reconfigure items to reflect changed state disabled/normal.
- */
-
- if ( old_canvas_state != canvasPtr->canvas_state ) {
- Tk_Item *itemPtr;
- int result;
-
- for ( itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if ( itemPtr->state == TK_STATE_NULL ) {
- result = (*itemPtr->typePtr->configProc)(canvasPtr->interp,
- (Tk_Canvas) canvasPtr, itemPtr, 0, NULL,
- TK_CONFIG_ARGV_ONLY);
- if (result != TCL_OK) {
- Tcl_ResetResult(canvasPtr->interp);
- }
- }
- }
- }
-
- /*
- * Reset the desired dimensions for the window.
- */
-
- Tk_GeometryRequest(canvasPtr->tkwin, canvasPtr->width + 2*canvasPtr->inset,
- canvasPtr->height + 2*canvasPtr->inset);
-
- /*
- * Restart the cursor timing sequence in case the on-time or off-time just
- * changed.
- */
-
- if (canvasPtr->textInfo.gotFocus) {
- CanvasFocusProc(canvasPtr, 1);
- }
-
- /*
- * Recompute the scroll region.
- */
-
- canvasPtr->scrollX1 = 0;
- canvasPtr->scrollY1 = 0;
- canvasPtr->scrollX2 = 0;
- canvasPtr->scrollY2 = 0;
- if (canvasPtr->regionString != NULL) {
- int argc2;
- const char **argv2;
-
- if (Tcl_SplitList(canvasPtr->interp, canvasPtr->regionString,
- &argc2, &argv2) != TCL_OK) {
- return TCL_ERROR;
- }
- if (argc2 != 4) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad scrollRegion \"%s\"", canvasPtr->regionString));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SCROLL_REGION", NULL);
- badRegion:
- ckfree(canvasPtr->regionString);
- ckfree(argv2);
- canvasPtr->regionString = NULL;
- return TCL_ERROR;
- }
- if ((Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
- argv2[0], &canvasPtr->scrollX1) != TCL_OK)
- || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
- argv2[1], &canvasPtr->scrollY1) != TCL_OK)
- || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
- argv2[2], &canvasPtr->scrollX2) != TCL_OK)
- || (Tk_GetPixels(canvasPtr->interp, canvasPtr->tkwin,
- argv2[3], &canvasPtr->scrollY2) != TCL_OK)) {
- goto badRegion;
- }
- ckfree(argv2);
- }
-
- flags = canvasPtr->tsoffset.flags;
- if (flags & TK_OFFSET_LEFT) {
- canvasPtr->tsoffset.xoffset = 0;
- } else if (flags & TK_OFFSET_CENTER) {
- canvasPtr->tsoffset.xoffset = canvasPtr->width/2;
- } else if (flags & TK_OFFSET_RIGHT) {
- canvasPtr->tsoffset.xoffset = canvasPtr->width;
- }
- if (flags & TK_OFFSET_TOP) {
- canvasPtr->tsoffset.yoffset = 0;
- } else if (flags & TK_OFFSET_MIDDLE) {
- canvasPtr->tsoffset.yoffset = canvasPtr->height/2;
- } else if (flags & TK_OFFSET_BOTTOM) {
- canvasPtr->tsoffset.yoffset = canvasPtr->height;
- }
-
- /*
- * Reset the canvas's origin (this is a no-op unless confine mode has just
- * been turned on or the scroll region has changed).
- */
-
- CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
- canvasPtr->flags |= UPDATE_SCROLLBARS|REDRAW_BORDERS;
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- canvasPtr->xOrigin, canvasPtr->yOrigin,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasWorldChanged --
- *
- * This function is called when the world has changed in some way and the
- * widget needs to recompute all its graphics contexts and determine its
- * new geometry.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Configures all items in the canvas with a empty argc/argv, for the
- * side effect of causing all the items to recompute their geometry and
- * to be redisplayed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasWorldChanged(
- ClientData instanceData) /* Information about widget. */
-{
- TkCanvas *canvasPtr = instanceData;
- Tk_Item *itemPtr;
-
- itemPtr = canvasPtr->firstItemPtr;
- for ( ; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
- if (ItemConfigure(canvasPtr, itemPtr, 0, NULL) != TCL_OK) {
- Tcl_ResetResult(canvasPtr->interp);
- }
- }
- canvasPtr->flags |= REPICK_NEEDED;
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- canvasPtr->xOrigin, canvasPtr->yOrigin,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * DisplayCanvas --
- *
- * This function redraws the contents of a canvas window. It is invoked
- * as a do-when-idle handler, so it only runs when there's nothing else
- * for the application to do.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Information appears on the screen.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DisplayCanvas(
- ClientData clientData) /* Information about widget. */
-{
- TkCanvas *canvasPtr = clientData;
- Tk_Window tkwin = canvasPtr->tkwin;
- Tk_Item *itemPtr;
- Pixmap pixmap;
- int screenX1, screenX2, screenY1, screenY2, width, height;
-
- if (canvasPtr->tkwin == NULL) {
- return;
- }
-
- if (!Tk_IsMapped(tkwin)) {
- goto done;
- }
-
-#ifdef MAC_OSX_TK
- /*
- * If drawing is disabled, all we need to do is
- * clear the REDRAW_PENDING flag.
- */
- TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin);
- MacDrawable *macWin = winPtr->privatePtr;
- if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){
- canvasPtr->flags &= ~REDRAW_PENDING;
- return;
- }
-#endif
-
- /*
- * Choose a new current item if that is needed (this could cause event
- * handlers to be invoked).
- */
-
- while (canvasPtr->flags & REPICK_NEEDED) {
- Tcl_Preserve(canvasPtr);
- canvasPtr->flags &= ~REPICK_NEEDED;
- PickCurrentItem(canvasPtr, &canvasPtr->pickEvent);
- tkwin = canvasPtr->tkwin;
- Tcl_Release(canvasPtr);
- if (tkwin == NULL) {
- return;
- }
- }
-
- /*
- * Scan through the item list, registering the bounding box for all items
- * that didn't do that for the final coordinates yet. This can be
- * determined by the FORCE_REDRAW flag.
- */
-
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if (itemPtr->redraw_flags & FORCE_REDRAW) {
- itemPtr->redraw_flags &= ~FORCE_REDRAW;
- EventuallyRedrawItem(canvasPtr, itemPtr);
- itemPtr->redraw_flags &= ~FORCE_REDRAW;
- }
- }
-
- /*
- * Compute the intersection between the area that needs redrawing and the
- * area that's visible on the screen.
- */
-
- if ((canvasPtr->redrawX1 < canvasPtr->redrawX2)
- && (canvasPtr->redrawY1 < canvasPtr->redrawY2)) {
- screenX1 = canvasPtr->xOrigin + canvasPtr->inset;
- screenY1 = canvasPtr->yOrigin + canvasPtr->inset;
- screenX2 = canvasPtr->xOrigin + Tk_Width(tkwin) - canvasPtr->inset;
- screenY2 = canvasPtr->yOrigin + Tk_Height(tkwin) - canvasPtr->inset;
- if (canvasPtr->redrawX1 > screenX1) {
- screenX1 = canvasPtr->redrawX1;
- }
- if (canvasPtr->redrawY1 > screenY1) {
- screenY1 = canvasPtr->redrawY1;
- }
- if (canvasPtr->redrawX2 < screenX2) {
- screenX2 = canvasPtr->redrawX2;
- }
- if (canvasPtr->redrawY2 < screenY2) {
- screenY2 = canvasPtr->redrawY2;
- }
- if ((screenX1 >= screenX2) || (screenY1 >= screenY2)) {
- goto borders;
- }
-
- width = screenX2 - screenX1;
- height = screenY2 - screenY1;
-
-#ifndef TK_NO_DOUBLE_BUFFERING
- /*
- * Redrawing is done in a temporary pixmap that is allocated here and
- * freed at the end of the function. All drawing is done to the
- * pixmap, and the pixmap is copied to the screen at the end of the
- * function. The temporary pixmap serves two purposes:
- *
- * 1. It provides a smoother visual effect (no clearing and gradual
- * redraw will be visible to users).
- * 2. It allows us to redraw only the objects that overlap the redraw
- * area. Otherwise incorrect results could occur from redrawing
- * things that stick outside of the redraw area (we'd have to
- * redraw everything in order to make the overlaps look right).
- *
- * Some tricky points about the pixmap:
- *
- * 1. We only allocate a large enough pixmap to hold the area that has
- * to be redisplayed. This saves time in in the X server for large
- * objects that cover much more than the area being redisplayed:
- * only the area of the pixmap will actually have to be redrawn.
- * 2. Some X servers (e.g. the one for DECstations) have troubles with
- * with characters that overlap an edge of the pixmap (on the DEC
- * servers, as of 8/18/92, such characters are drawn one pixel too
- * far to the right). To handle this problem, make the pixmap a bit
- * larger than is absolutely needed so that for normal-sized fonts
- * the characters that overlap the edge of the pixmap will be
- * outside the area we care about.
- */
-
- canvasPtr->drawableXOrigin = screenX1 - 30;
- canvasPtr->drawableYOrigin = screenY1 - 30;
- pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
- (screenX2 + 30 - canvasPtr->drawableXOrigin),
- (screenY2 + 30 - canvasPtr->drawableYOrigin),
- Tk_Depth(tkwin));
-#else
- canvasPtr->drawableXOrigin = canvasPtr->xOrigin;
- canvasPtr->drawableYOrigin = canvasPtr->yOrigin;
- pixmap = Tk_WindowId(tkwin);
- TkpClipDrawableToRect(Tk_Display(tkwin), pixmap,
- screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin,
- width, height);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-
- /*
- * Clear the area to be redrawn.
- */
-
- XFillRectangle(Tk_Display(tkwin), pixmap, canvasPtr->pixmapGC,
- screenX1 - canvasPtr->drawableXOrigin,
- screenY1 - canvasPtr->drawableYOrigin, (unsigned int) width,
- (unsigned int) height);
-
- /*
- * Scan through the item list, redrawing those items that need it. An
- * item must be redraw if either (a) it intersects the smaller
- * on-screen area or (b) it intersects the full canvas area and its
- * type requests that it be redrawn always (e.g. so subwindows can be
- * unmapped when they move off-screen).
- */
-
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if ((itemPtr->x1 >= screenX2)
- || (itemPtr->y1 >= screenY2)
- || (itemPtr->x2 < screenX1)
- || (itemPtr->y2 < screenY1)) {
- if (!AlwaysRedraw(itemPtr)
- || (itemPtr->x1 >= canvasPtr->redrawX2)
- || (itemPtr->y1 >= canvasPtr->redrawY2)
- || (itemPtr->x2 < canvasPtr->redrawX1)
- || (itemPtr->y2 < canvasPtr->redrawY1)) {
- continue;
- }
- }
- if (itemPtr->state == TK_STATE_HIDDEN ||
- (itemPtr->state == TK_STATE_NULL &&
- canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
- continue;
- }
- ItemDisplay(canvasPtr, itemPtr, pixmap, screenX1, screenY1, width,
- height);
- }
-
-#ifndef TK_NO_DOUBLE_BUFFERING
- /*
- * Copy from the temporary pixmap to the screen, then free up the
- * temporary pixmap.
- */
-
- XCopyArea(Tk_Display(tkwin), pixmap, Tk_WindowId(tkwin),
- canvasPtr->pixmapGC,
- screenX1 - canvasPtr->drawableXOrigin,
- screenY1 - canvasPtr->drawableYOrigin,
- (unsigned int) width, (unsigned int) height,
- screenX1 - canvasPtr->xOrigin, screenY1 - canvasPtr->yOrigin);
- Tk_FreePixmap(Tk_Display(tkwin), pixmap);
-#else
- TkpClipDrawableToRect(Tk_Display(tkwin), pixmap, 0, 0, -1, -1);
-#endif /* TK_NO_DOUBLE_BUFFERING */
- }
-
- /*
- * Draw the window borders, if needed.
- */
-
- borders:
- if (canvasPtr->flags & REDRAW_BORDERS) {
- canvasPtr->flags &= ~REDRAW_BORDERS;
- if (canvasPtr->borderWidth > 0) {
- Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin),
- canvasPtr->bgBorder, canvasPtr->highlightWidth,
- canvasPtr->highlightWidth,
- Tk_Width(tkwin) - 2*canvasPtr->highlightWidth,
- Tk_Height(tkwin) - 2*canvasPtr->highlightWidth,
- canvasPtr->borderWidth, canvasPtr->relief);
- }
- if (canvasPtr->highlightWidth != 0) {
- GC fgGC, bgGC;
-
- bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr,
- Tk_WindowId(tkwin));
- if (canvasPtr->textInfo.gotFocus) {
- fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr,
- Tk_WindowId(tkwin));
- TkpDrawHighlightBorder(tkwin, fgGC, bgGC,
- canvasPtr->highlightWidth, Tk_WindowId(tkwin));
- } else {
- TkpDrawHighlightBorder(tkwin, bgGC, bgGC,
- canvasPtr->highlightWidth, Tk_WindowId(tkwin));
- }
- }
- }
-
- done:
- canvasPtr->flags &= ~(REDRAW_PENDING|BBOX_NOT_EMPTY);
- canvasPtr->redrawX1 = canvasPtr->redrawX2 = 0;
- canvasPtr->redrawY1 = canvasPtr->redrawY2 = 0;
- if (canvasPtr->flags & UPDATE_SCROLLBARS) {
- CanvasUpdateScrollbars(canvasPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasEventProc --
- *
- * This function is invoked by the Tk dispatcher for various events on
- * canvases.
- *
- * Results:
- * None.
- *
- * Side effects:
- * When the window gets deleted, internal structures get cleaned up. When
- * it gets exposed, it is redisplayed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasEventProc(
- ClientData clientData, /* Information about window. */
- XEvent *eventPtr) /* Information about event. */
-{
- TkCanvas *canvasPtr = clientData;
-
- if (eventPtr->type == Expose) {
- int x, y;
-
- x = eventPtr->xexpose.x + canvasPtr->xOrigin;
- y = eventPtr->xexpose.y + canvasPtr->yOrigin;
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, x, y,
- x + eventPtr->xexpose.width,
- y + eventPtr->xexpose.height);
- if ((eventPtr->xexpose.x < canvasPtr->inset)
- || (eventPtr->xexpose.y < canvasPtr->inset)
- || ((eventPtr->xexpose.x + eventPtr->xexpose.width)
- > (Tk_Width(canvasPtr->tkwin) - canvasPtr->inset))
- || ((eventPtr->xexpose.y + eventPtr->xexpose.height)
- > (Tk_Height(canvasPtr->tkwin) - canvasPtr->inset))) {
- canvasPtr->flags |= REDRAW_BORDERS;
- }
- } else if (eventPtr->type == DestroyNotify) {
- if (canvasPtr->tkwin != NULL) {
- canvasPtr->tkwin = NULL;
- Tcl_DeleteCommandFromToken(canvasPtr->interp,
- canvasPtr->widgetCmd);
- }
- if (canvasPtr->flags & REDRAW_PENDING) {
- Tcl_CancelIdleCall(DisplayCanvas, canvasPtr);
- }
- Tcl_EventuallyFree(canvasPtr, (Tcl_FreeProc *) DestroyCanvas);
- } else if (eventPtr->type == ConfigureNotify) {
- canvasPtr->flags |= UPDATE_SCROLLBARS;
-
- /*
- * The call below is needed in order to recenter the canvas if it's
- * confined and its scroll region is smaller than the window.
- */
-
- CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, canvasPtr->yOrigin);
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr, canvasPtr->xOrigin,
- canvasPtr->yOrigin,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
- canvasPtr->flags |= REDRAW_BORDERS;
- } else if (eventPtr->type == FocusIn) {
- if (eventPtr->xfocus.detail != NotifyInferior) {
- CanvasFocusProc(canvasPtr, 1);
- }
- } else if (eventPtr->type == FocusOut) {
- if (eventPtr->xfocus.detail != NotifyInferior) {
- CanvasFocusProc(canvasPtr, 0);
- }
- } else if (eventPtr->type == UnmapNotify) {
- Tk_Item *itemPtr;
-
- /*
- * Special hack: if the canvas is unmapped, then must notify all items
- * with "alwaysRedraw" set, so that they know that they are no longer
- * displayed.
- */
-
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if (AlwaysRedraw(itemPtr)) {
- ItemDisplay(canvasPtr, itemPtr, None, 0, 0, 0, 0);
- }
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasCmdDeletedProc --
- *
- * This function is invoked when a widget command is deleted. If the
- * widget isn't already in the process of being destroyed, this command
- * destroys it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The widget is destroyed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasCmdDeletedProc(
- ClientData clientData) /* Pointer to widget record for widget. */
-{
- TkCanvas *canvasPtr = clientData;
- Tk_Window tkwin = canvasPtr->tkwin;
-
- /*
- * This function could be invoked either because the window was destroyed
- * and the command was then deleted (in which case tkwin is NULL) or
- * because the command was deleted, and then this function destroys the
- * widget.
- */
-
- if (tkwin != NULL) {
- canvasPtr->tkwin = NULL;
- Tk_DestroyWindow(tkwin);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tk_CanvasEventuallyRedraw --
- *
- * Arrange for part or all of a canvas widget to redrawn at some
- * convenient time in the future.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The screen will eventually be refreshed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tk_CanvasEventuallyRedraw(
- Tk_Canvas canvas, /* Information about widget. */
- int x1, int y1, /* Upper left corner of area to redraw. Pixels
- * on edge are redrawn. */
- int x2, int y2) /* Lower right corner of area to redraw.
- * Pixels on edge are not redrawn. */
-{
- TkCanvas *canvasPtr = Canvas(canvas);
-
- /*
- * If tkwin is NULL, the canvas has been destroyed, so we can't really
- * redraw it.
- */
-
- if (canvasPtr->tkwin == NULL) {
- return;
- }
-
- if ((x1 >= x2) || (y1 >= y2) ||
- (x2 < canvasPtr->xOrigin) || (y2 < canvasPtr->yOrigin) ||
- (x1 >= canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin)) ||
- (y1 >= canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin))) {
- return;
- }
- if (canvasPtr->flags & BBOX_NOT_EMPTY) {
- if (x1 <= canvasPtr->redrawX1) {
- canvasPtr->redrawX1 = x1;
- }
- if (y1 <= canvasPtr->redrawY1) {
- canvasPtr->redrawY1 = y1;
- }
- if (x2 >= canvasPtr->redrawX2) {
- canvasPtr->redrawX2 = x2;
- }
- if (y2 >= canvasPtr->redrawY2) {
- canvasPtr->redrawY2 = y2;
- }
- } else {
- canvasPtr->redrawX1 = x1;
- canvasPtr->redrawY1 = y1;
- canvasPtr->redrawX2 = x2;
- canvasPtr->redrawY2 = y2;
- canvasPtr->flags |= BBOX_NOT_EMPTY;
- }
- if (!(canvasPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DisplayCanvas, canvasPtr);
- canvasPtr->flags |= REDRAW_PENDING;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * EventuallyRedrawItem --
- *
- * Arrange for part or all of a canvas widget to redrawn at some
- * convenient time in the future.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The screen will eventually be refreshed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-EventuallyRedrawItem(
- TkCanvas *canvasPtr, /* Information about widget. */
- Tk_Item *itemPtr) /* Item to be redrawn. May be NULL, in which
- * case nothing happens. */
-{
- if (itemPtr == NULL) {
- return;
- }
- if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||
- (itemPtr->x2 < canvasPtr->xOrigin) ||
- (itemPtr->y2 < canvasPtr->yOrigin) ||
- (itemPtr->x1 >= canvasPtr->xOrigin+Tk_Width(canvasPtr->tkwin)) ||
- (itemPtr->y1 >= canvasPtr->yOrigin+Tk_Height(canvasPtr->tkwin))) {
- if (!AlwaysRedraw(itemPtr)) {
- return;
- }
- }
- if (!(itemPtr->redraw_flags & FORCE_REDRAW)) {
- if (canvasPtr->flags & BBOX_NOT_EMPTY) {
- if (itemPtr->x1 <= canvasPtr->redrawX1) {
- canvasPtr->redrawX1 = itemPtr->x1;
- }
- if (itemPtr->y1 <= canvasPtr->redrawY1) {
- canvasPtr->redrawY1 = itemPtr->y1;
- }
- if (itemPtr->x2 >= canvasPtr->redrawX2) {
- canvasPtr->redrawX2 = itemPtr->x2;
- }
- if (itemPtr->y2 >= canvasPtr->redrawY2) {
- canvasPtr->redrawY2 = itemPtr->y2;
- }
- } else {
- canvasPtr->redrawX1 = itemPtr->x1;
- canvasPtr->redrawY1 = itemPtr->y1;
- canvasPtr->redrawX2 = itemPtr->x2;
- canvasPtr->redrawY2 = itemPtr->y2;
- canvasPtr->flags |= BBOX_NOT_EMPTY;
- }
- itemPtr->redraw_flags |= FORCE_REDRAW;
- }
- if (!(canvasPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DisplayCanvas, canvasPtr);
- canvasPtr->flags |= REDRAW_PENDING;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tk_CreateItemType --
- *
- * This function may be invoked to add a new kind of canvas element to
- * the core item types supported by Tk.
- *
- * Results:
- * None.
- *
- * Side effects:
- * From now on, the new item type will be useable in canvas widgets
- * (e.g. typePtr->name can be used as the item type in "create" widget
- * commands). If there was already a type with the same name as in
- * typePtr, it is replaced with the new type.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tk_CreateItemType(
- Tk_ItemType *typePtr) /* Information about item type; storage must
- * be statically allocated (must live
- * forever). */
-{
- Tk_ItemType *typePtr2, *prevPtr;
-
- if (typeList == NULL) {
- InitCanvas();
- }
-
- /*
- * If there's already an item type with the given name, remove it.
- */
-
- Tcl_MutexLock(&typeListMutex);
- for (typePtr2 = typeList, prevPtr = NULL; typePtr2 != NULL;
- prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
- if (strcmp(typePtr2->name, typePtr->name) == 0) {
- if (prevPtr == NULL) {
- typeList = typePtr2->nextPtr;
- } else {
- prevPtr->nextPtr = typePtr2->nextPtr;
- }
- break;
- }
- }
- typePtr->nextPtr = typeList;
- typeList = typePtr;
- Tcl_MutexUnlock(&typeListMutex);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tk_GetItemTypes --
- *
- * This function returns a pointer to the list of all item types. Note
- * that this is inherently thread-unsafe, but since item types are only
- * ever registered very rarely this is unlikely to be a problem in
- * practice.
- *
- * Results:
- * The return value is a pointer to the first in the list of item types
- * currently supported by canvases.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Tk_ItemType *
-Tk_GetItemTypes(void)
-{
- if (typeList == NULL) {
- InitCanvas();
- }
- return typeList;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * InitCanvas --
- *
- * This function is invoked to perform once-only-ever initialization for
- * the module, such as setting up the type table.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-InitCanvas(void)
-{
- Tcl_MutexLock(&typeListMutex);
- if (typeList != NULL) {
- Tcl_MutexUnlock(&typeListMutex);
- return;
- }
- typeList = &tkRectangleType;
- tkRectangleType.nextPtr = &tkTextType;
- tkTextType.nextPtr = &tkLineType;
- tkLineType.nextPtr = &tkPolygonType;
- tkPolygonType.nextPtr = &tkImageType;
- tkImageType.nextPtr = &tkOvalType;
- tkOvalType.nextPtr = &tkBitmapType;
- tkBitmapType.nextPtr = &tkArcType;
- tkArcType.nextPtr = &tkWindowType;
- tkWindowType.nextPtr = NULL;
- Tcl_MutexUnlock(&typeListMutex);
-}
-
-#ifdef USE_OLD_TAG_SEARCH
-/*
- *--------------------------------------------------------------
- *
- * StartTagSearch --
- *
- * This function is called to initiate an enumeration of all items in a
- * given canvas that contain a given tag.
- *
- * Results:
- * The return value is a pointer to the first item in canvasPtr that
- * matches tag, or NULL if there is no such item. The information at
- * *searchPtr is initialized such that successive calls to NextItem will
- * return successive items that match tag.
- *
- * Side effects:
- * SearchPtr is linked into a list of searches in progress on canvasPtr,
- * so that elements can safely be deleted while the search is in
- * progress. EndTagSearch must be called at the end of the search to
- * unlink searchPtr from this list.
- *
- *--------------------------------------------------------------
- */
-
-static Tk_Item *
-StartTagSearch(
- TkCanvas *canvasPtr, /* Canvas whose items are to be searched. */
- Tcl_Obj *tagObj, /* Object giving tag value. */
- TagSearch *searchPtr) /* Record describing tag search; will be
- * initialized here. */
-{
- int id;
- Tk_Item *itemPtr, *lastPtr;
- Tk_Uid *tagPtr;
- Tk_Uid uid;
- char *tag = Tcl_GetString(tagObj);
- int count;
- TkWindow *tkwin = (TkWindow *) canvasPtr->tkwin;
- TkDisplay *dispPtr = tkwin->dispPtr;
-
- /*
- * Initialize the search.
- */
-
- searchPtr->canvasPtr = canvasPtr;
- searchPtr->searchOver = 0;
-
- /*
- * Find the first matching item in one of several ways. If the tag is a
- * number then it selects the single item with the matching identifier.
- * In this case see if the item being requested is the hot item, in which
- * case the search can be skipped.
- */
-
- if (isdigit(UCHAR(*tag))) {
- char *end;
- Tcl_HashEntry *entryPtr;
-
- dispPtr->numIdSearches++;
- id = strtoul(tag, &end, 0);
- if (*end == 0) {
- itemPtr = canvasPtr->hotPtr;
- lastPtr = canvasPtr->hotPrevPtr;
- if ((itemPtr == NULL) || (itemPtr->id != id) || (lastPtr == NULL)
- || (lastPtr->nextPtr != itemPtr)) {
- dispPtr->numSlowSearches++;
- entryPtr = Tcl_FindHashEntry(&canvasPtr->idTable, (char*) id);
- if (entryPtr != NULL) {
- itemPtr = Tcl_GetHashValue(entryPtr);
- lastPtr = itemPtr->prevPtr;
- } else {
- lastPtr = itemPtr = NULL;
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- canvasPtr->hotPtr = itemPtr;
- canvasPtr->hotPrevPtr = lastPtr;
- return itemPtr;
- }
- }
-
- searchPtr->tag = uid = Tk_GetUid(tag);
- if (uid == Tk_GetUid("all")) {
- /*
- * All items match.
- */
-
- searchPtr->tag = NULL;
- searchPtr->lastPtr = NULL;
- searchPtr->currentPtr = canvasPtr->firstItemPtr;
- return canvasPtr->firstItemPtr;
- }
-
- /*
- * None of the above. Search for an item with a matching tag.
- */
-
- for (lastPtr = NULL, itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- return NULL;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * NextItem --
- *
- * This function returns successive items that match a given tag; it
- * should be called only after StartTagSearch has been used to begin a
- * search.
- *
- * Results:
- * The return value is a pointer to the next item that matches the tag
- * specified to StartTagSearch, or NULL if no such item exists.
- * *SearchPtr is updated so that the next call to this function will
- * return the next item.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-static Tk_Item *
-NextItem(
- TagSearch *searchPtr) /* Record describing search in progress. */
-{
- Tk_Item *itemPtr, *lastPtr;
- int count;
- Tk_Uid uid;
- Tk_Uid *tagPtr;
-
- /*
- * Find next item in list (this may not actually be a suitable one to
- * return), and return if there are no items left.
- */
-
- lastPtr = searchPtr->lastPtr;
- if (lastPtr == NULL) {
- itemPtr = searchPtr->canvasPtr->firstItemPtr;
- } else {
- itemPtr = lastPtr->nextPtr;
- }
- if ((itemPtr == NULL) || (searchPtr->searchOver)) {
- searchPtr->searchOver = 1;
- return NULL;
- }
- if (itemPtr != searchPtr->currentPtr) {
- /*
- * The structure of the list has changed. Probably the previously-
- * returned item was removed from the list. In this case, don't
- * advance lastPtr; just return its new successor (i.e. do nothing
- * here).
- */
- } else {
- lastPtr = itemPtr;
- itemPtr = lastPtr->nextPtr;
- }
-
- /*
- * Handle special case of "all" search by returning next item.
- */
-
- uid = searchPtr->tag;
- if (uid == NULL) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
-
- /*
- * Look for an item with a particular tag.
- */
-
- for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- return NULL;
-}
-
-#else /* !USE_OLD_TAG_SEARCH */
-/*
- *----------------------------------------------------------------------
- *
- * GetStaticUids --
- *
- * This function is invoked to return a structure filled with the Uids
- * used when doing tag searching. If it was never before called in the
- * current thread, it initializes the structure for that thread (uids are
- * only ever local to one thread [Bug 1114977]).
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static SearchUids *
-GetStaticUids(void)
-{
- SearchUids *searchUids =
- Tcl_GetThreadData(&dataKey, sizeof(SearchUids));
-
- if (searchUids->allUid == NULL) {
- searchUids->allUid = Tk_GetUid("all");
- searchUids->currentUid = Tk_GetUid("current");
- searchUids->andUid = Tk_GetUid("&&");
- searchUids->orUid = Tk_GetUid("||");
- searchUids->xorUid = Tk_GetUid("^");
- searchUids->parenUid = Tk_GetUid("(");
- searchUids->endparenUid = Tk_GetUid(")");
- searchUids->negparenUid = Tk_GetUid("!(");
- searchUids->tagvalUid = Tk_GetUid("!!");
- searchUids->negtagvalUid = Tk_GetUid("!");
- }
- return searchUids;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchExprInit --
- *
- * This function allocates and initializes one TagSearchExpr struct.
- *
- * Results:
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-static void
-TagSearchExprInit(
- TagSearchExpr **exprPtrPtr)
-{
- TagSearchExpr *expr = *exprPtrPtr;
-
- if (expr == NULL) {
- expr = ckalloc(sizeof(TagSearchExpr));
- expr->allocated = 0;
- expr->uids = NULL;
- expr->next = NULL;
- }
- expr->uid = NULL;
- expr->index = 0;
- expr->length = 0;
- *exprPtrPtr = expr;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchExprDestroy --
- *
- * This function destroys one TagSearchExpr structure.
- *
- * Results:
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-static void
-TagSearchExprDestroy(
- TagSearchExpr *expr)
-{
- if (expr != NULL) {
- if (expr->uids) {
- ckfree(expr->uids);
- }
- ckfree(expr);
- }
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchScan --
- *
- * This function is called to initiate an enumeration of all items in a
- * given canvas that contain a tag that matches the tagOrId expression.
- *
- * Results:
- * The return value indicates if the tagOrId expression was successfully
- * scanned (syntax). The information at *searchPtr is initialized such
- * that a call to TagSearchFirst, followed by successive calls to
- * TagSearchNext will return items that match tag.
- *
- * Side effects:
- * SearchPtr is linked into a list of searches in progress on canvasPtr,
- * so that elements can safely be deleted while the search is in
- * progress.
- *
- *--------------------------------------------------------------
- */
-
-static int
-TagSearchScan(
- TkCanvas *canvasPtr, /* Canvas whose items are to be searched. */
- Tcl_Obj *tagObj, /* Object giving tag value. */
- TagSearch **searchPtrPtr) /* Record describing tag search; will be
- * initialized here. */
-{
- const char *tag = Tcl_GetString(tagObj);
- int i;
- TagSearch *searchPtr;
-
- /*
- * Initialize the search.
- */
-
- if (*searchPtrPtr != NULL) {
- searchPtr = *searchPtrPtr;
- } else {
- /*
- * Allocate primary search struct on first call.
- */
-
- *searchPtrPtr = searchPtr = ckalloc(sizeof(TagSearch));
- searchPtr->expr = NULL;
-
- /*
- * Allocate buffer for rewritten tags (after de-escaping).
- */
-
- searchPtr->rewritebufferAllocated = 100;
- searchPtr->rewritebuffer = ckalloc(searchPtr->rewritebufferAllocated);
- }
- TagSearchExprInit(&searchPtr->expr);
-
- /*
- * How long is the tagOrId?
- */
-
- searchPtr->stringLength = strlen(tag);
-
- /*
- * Make sure there is enough buffer to hold rewritten tags.
- */
-
- if ((unsigned) searchPtr->stringLength >=
- searchPtr->rewritebufferAllocated) {
- searchPtr->rewritebufferAllocated = searchPtr->stringLength + 100;
- searchPtr->rewritebuffer =
- ckrealloc(searchPtr->rewritebuffer,
- searchPtr->rewritebufferAllocated);
- }
-
- /*
- * Initialize search.
- */
-
- searchPtr->canvasPtr = canvasPtr;
- searchPtr->searchOver = 0;
- searchPtr->type = SEARCH_TYPE_EMPTY;
-
- /*
- * Find the first matching item in one of several ways. If the tag is a
- * number then it selects the single item with the matching identifier.
- * In this case see if the item being requested is the hot item, in which
- * case the search can be skipped.
- */
-
- if (searchPtr->stringLength && isdigit(UCHAR(*tag))) {
- char *end;
-
- searchPtr->id = strtoul(tag, &end, 0);
- if (*end == 0) {
- searchPtr->type = SEARCH_TYPE_ID;
- return TCL_OK;
- }
- }
-
- /*
- * For all other tags and tag expressions convert to a UID. This UID is
- * kept forever, but this should be thought of as a cache rather than as a
- * memory leak.
- */
-
- searchPtr->expr->uid = Tk_GetUid(tag);
-
- /*
- * Short circuit impossible searches for null tags.
- */
-
- if (searchPtr->stringLength == 0) {
- return TCL_OK;
- }
-
- /*
- * Pre-scan tag for at least one unquoted "&&" "||" "^" "!"; if not found
- * then use string as simple tag.
- */
-
- for (i = 0; i < searchPtr->stringLength ; i++) {
- if (tag[i] == '"') {
- i++;
- for ( ; i < searchPtr->stringLength; i++) {
- if (tag[i] == '\\') {
- i++;
- continue;
- }
- if (tag[i] == '"') {
- break;
- }
- }
- } else if ((tag[i] == '&' && tag[i+1] == '&')
- || (tag[i] == '|' && tag[i+1] == '|')
- || (tag[i] == '^')
- || (tag[i] == '!')) {
- searchPtr->type = SEARCH_TYPE_EXPR;
- break;
- }
- }
-
- searchPtr->string = tag;
- searchPtr->stringIndex = 0;
- if (searchPtr->type == SEARCH_TYPE_EXPR) {
- /*
- * An operator was found in the prescan, so now compile the tag
- * expression into array of Tk_Uid flagging any syntax errors found.
- */
-
- if (TagSearchScanExpr(canvasPtr->interp, searchPtr,
- searchPtr->expr) != TCL_OK) {
- /*
- * Syntax error in tag expression. The result message was set by
- * TagSearchScanExpr.
- */
-
- return TCL_ERROR;
- }
- searchPtr->expr->length = searchPtr->expr->index;
- } else if (searchPtr->expr->uid == GetStaticUids()->allUid) {
- /*
- * All items match.
- */
-
- searchPtr->type = SEARCH_TYPE_ALL;
- } else {
- /*
- * Optimized single-tag search
- */
-
- searchPtr->type = SEARCH_TYPE_TAG;
- }
- return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchDestroy --
- *
- * This function destroys any dynamic structures that may have been
- * allocated by TagSearchScan.
- *
- * Results:
- * None
- *
- * Side effects:
- * Deallocates memory.
- *
- *--------------------------------------------------------------
- */
-
-static void
-TagSearchDestroy(
- TagSearch *searchPtr) /* Record describing tag search. */
-{
- if (searchPtr) {
- TagSearchExprDestroy(searchPtr->expr);
- ckfree(searchPtr->rewritebuffer);
- ckfree(searchPtr);
- }
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchScanExpr --
- *
- * This recursive function is called to scan a tag expression and compile
- * it into an array of Tk_Uids.
- *
- * Results:
- * The return value indicates if the tagOrId expression was successfully
- * scanned (syntax). The information at *searchPtr is initialized such
- * that a call to TagSearchFirst, followed by successive calls to
- * TagSearchNext will return items that match tag.
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-static int
-TagSearchScanExpr(
- Tcl_Interp *interp, /* Current interpreter. */
- TagSearch *searchPtr, /* Search data. */
- TagSearchExpr *expr) /* Compiled expression result. */
-{
- int looking_for_tag; /* When true, scanner expects next char(s) to
- * be a tag, else operand expected. */
- int found_tag; /* One or more tags found. */
- int found_endquote; /* For quoted tag string parsing. */
- int negate_result; /* Pending negation of next tag value. */
- char *tag; /* Tag from tag expression string. */
- char c;
- SearchUids *searchUids; /* Collection of uids for basic search
- * expression terms. */
-
- searchUids = GetStaticUids();
- negate_result = 0;
- found_tag = 0;
- looking_for_tag = 1;
- while (searchPtr->stringIndex < searchPtr->stringLength) {
- c = searchPtr->string[searchPtr->stringIndex++];
-
- /*
- * Need two slots free at this point, not one. [Bug 2931374]
- */
-
- if (expr->index >= expr->allocated-1) {
- expr->allocated += 15;
- if (expr->uids) {
- expr->uids = ckrealloc(expr->uids,
- expr->allocated * sizeof(Tk_Uid));
- } else {
- expr->uids = ckalloc(expr->allocated * sizeof(Tk_Uid));
- }
- }
-
- if (looking_for_tag) {
- switch (c) {
- case ' ': /* Ignore unquoted whitespace */
- case '\t':
- case '\n':
- case '\r':
- break;
-
- case '!': /* Negate next tag or subexpr */
- if (looking_for_tag > 1) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "too many '!' in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "COMPLEXITY", NULL);
- return TCL_ERROR;
- }
- looking_for_tag++;
- negate_result = 1;
- break;
-
- case '(': /* Scan (negated) subexpr recursively */
- if (negate_result) {
- expr->uids[expr->index++] = searchUids->negparenUid;
- negate_result = 0;
- } else {
- expr->uids[expr->index++] = searchUids->parenUid;
- }
- if (TagSearchScanExpr(interp, searchPtr, expr) != TCL_OK) {
- /*
- * Result string should be already set by nested call to
- * tag_expr_scan()
- */
-
- return TCL_ERROR;
- }
- looking_for_tag = 0;
- found_tag = 1;
- break;
-
- case '"': /* Quoted tag string */
- if (negate_result) {
- expr->uids[expr->index++] = searchUids->negtagvalUid;
- negate_result = 0;
- } else {
- expr->uids[expr->index++] = searchUids->tagvalUid;
- }
- tag = searchPtr->rewritebuffer;
- found_endquote = 0;
- while (searchPtr->stringIndex < searchPtr->stringLength) {
- c = searchPtr->string[searchPtr->stringIndex++];
- if (c == '\\') {
- c = searchPtr->string[searchPtr->stringIndex++];
- }
- if (c == '"') {
- found_endquote = 1;
- break;
- }
- *tag++ = c;
- }
- if (!found_endquote) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "missing endquote in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "ENDQUOTE", NULL);
- return TCL_ERROR;
- }
- if (!(tag - searchPtr->rewritebuffer)) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "null quoted tag string in tag search expression",
- -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "EMPTY", NULL);
- return TCL_ERROR;
- }
- *tag++ = '\0';
- expr->uids[expr->index++] =
- Tk_GetUid(searchPtr->rewritebuffer);
- looking_for_tag = 0;
- found_tag = 1;
- break;
-
- case '&': /* Illegal chars when looking for tag */
- case '|':
- case '^':
- case ')':
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "unexpected operator in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "UNEXPECTED", NULL);
- return TCL_ERROR;
-
- default: /* Unquoted tag string */
- if (negate_result) {
- expr->uids[expr->index++] = searchUids->negtagvalUid;
- negate_result = 0;
- } else {
- expr->uids[expr->index++] = searchUids->tagvalUid;
- }
- tag = searchPtr->rewritebuffer;
- *tag++ = c;
-
- /*
- * Copy rest of tag, including any embedded whitespace.
- */
-
- while (searchPtr->stringIndex < searchPtr->stringLength) {
- c = searchPtr->string[searchPtr->stringIndex];
- if (c == '!' || c == '&' || c == '|' || c == '^'
- || c == '(' || c == ')' || c == '"') {
- break;
- }
- *tag++ = c;
- searchPtr->stringIndex++;
- }
-
- /*
- * Remove trailing whitespace.
- */
-
- while (1) {
- c = *--tag;
-
- /*
- * There must have been one non-whitespace char, so this
- * will terminate.
- */
-
- if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
- break;
- }
- }
- *++tag = '\0';
- expr->uids[expr->index++] =
- Tk_GetUid(searchPtr->rewritebuffer);
- looking_for_tag = 0;
- found_tag = 1;
- }
-
- } else { /* ! looking_for_tag */
- switch (c) {
- case ' ': /* Ignore whitespace */
- case '\t':
- case '\n':
- case '\r':
- break;
-
- case '&': /* AND operator */
- c = searchPtr->string[searchPtr->stringIndex++];
- if (c != '&') {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "singleton '&' in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "INCOMPLETE_OP", NULL);
- return TCL_ERROR;
- }
- expr->uids[expr->index++] = searchUids->andUid;
- looking_for_tag = 1;
- break;
-
- case '|': /* OR operator */
- c = searchPtr->string[searchPtr->stringIndex++];
- if (c != '|') {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "singleton '|' in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH",
- "INCOMPLETE_OP", NULL);
- return TCL_ERROR;
- }
- expr->uids[expr->index++] = searchUids->orUid;
- looking_for_tag = 1;
- break;
-
- case '^': /* XOR operator */
- expr->uids[expr->index++] = searchUids->xorUid;
- looking_for_tag = 1;
- break;
-
- case ')': /* End subexpression */
- expr->uids[expr->index++] = searchUids->endparenUid;
- goto breakwhile;
-
- default: /* syntax error */
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "invalid boolean operator in tag search expression",
- -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH", "BAD_OP",
- NULL);
- return TCL_ERROR;
- }
- }
- }
-
- breakwhile:
- if (found_tag && !looking_for_tag) {
- return TCL_OK;
- }
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "missing tag in tag search expression", -1));
- Tcl_SetErrorCode(interp, "TK", "CANVAS", "SEARCH", "NO_TAG", NULL);
- return TCL_ERROR;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchEvalExpr --
- *
- * This recursive function is called to eval a tag expression.
- *
- * Results:
- * The return value indicates if the tagOrId expression successfully
- * matched the tags of the current item.
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-static int
-TagSearchEvalExpr(
- TagSearchExpr *expr, /* Search expression */
- Tk_Item *itemPtr) /* Item being test for match */
-{
- int looking_for_tag; /* When true, scanner expects next char(s) to
- * be a tag, else operand expected. */
- int negate_result; /* Pending negation of next tag value */
- Tk_Uid uid;
- Tk_Uid *tagPtr;
- int count;
- int result; /* Value of expr so far */
- int parendepth;
- SearchUids *searchUids; /* Collection of uids for basic search
- * expression terms. */
-
- searchUids = GetStaticUids();
- result = 0; /* Just to keep the compiler quiet. */
-
- negate_result = 0;
- looking_for_tag = 1;
- while (expr->index < expr->length) {
- uid = expr->uids[expr->index++];
- if (looking_for_tag) {
- if (uid == searchUids->tagvalUid) {
-/*
- * assert(expr->index < expr->length);
- */
- uid = expr->uids[expr->index++];
- result = 0;
-
- /*
- * set result 1 if tag is found in item's tags
- */
-
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- result = 1;
- break;
- }
- }
-
- } else if (uid == searchUids->negtagvalUid) {
- negate_result = ! negate_result;
-/*
- * assert(expr->index < expr->length);
- */
- uid = expr->uids[expr->index++];
- result = 0;
-
- /*
- * set result 1 if tag is found in item's tags.
- */
-
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- result = 1;
- break;
- }
- }
-
- } else if (uid == searchUids->parenUid) {
- /*
- * Evaluate subexpressions with recursion.
- */
-
- result = TagSearchEvalExpr(expr, itemPtr);
-
- } else if (uid == searchUids->negparenUid) {
- negate_result = !negate_result;
-
- /*
- * Evaluate subexpressions with recursion.
- */
-
- result = TagSearchEvalExpr(expr, itemPtr);
- }
- if (negate_result) {
- result = ! result;
- negate_result = 0;
- }
- looking_for_tag = 0;
- } else { /* ! looking_for_tag */
- if (((uid == searchUids->andUid) && (!result)) ||
- ((uid == searchUids->orUid) && result)) {
- /*
- * Short circuit expression evaluation.
- *
- * if result before && is 0, or result before || is 1, then
- * the expression is decided and no further evaluation is
- * needed.
- */
-
- parendepth = 0;
- while (expr->index < expr->length) {
- uid = expr->uids[expr->index++];
- if (uid == searchUids->tagvalUid ||
- uid == searchUids->negtagvalUid) {
- expr->index++;
- continue;
- }
- if (uid == searchUids->parenUid ||
- uid == searchUids->negparenUid) {
- parendepth++;
- continue;
- }
- if (uid == searchUids->endparenUid) {
- parendepth--;
- if (parendepth < 0) {
- break;
- }
- }
- }
- return result;
-
- } else if (uid == searchUids->xorUid) {
- /*
- * If the previous result was 1 then negate the next result.
- */
-
- negate_result = result;
-
- } else if (uid == searchUids->endparenUid) {
- return result;
- }
- looking_for_tag = 1;
- }
- }
-/*
- * assert(!looking_for_tag);
- */
- return result;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchFirst --
- *
- * This function is called to get the first item item that matches a
- * preestablished search predicate that was set by TagSearchScan.
- *
- * Results:
- * The return value is a pointer to the first item, or NULL if there is
- * no such item. The information at *searchPtr is updated such that
- * successive calls to TagSearchNext will return successive items.
- *
- * Side effects:
- * SearchPtr is linked into a list of searches in progress on canvasPtr,
- * so that elements can safely be deleted while the search is in
- * progress.
- *
- *--------------------------------------------------------------
- */
-
-static Tk_Item *
-TagSearchFirst(
- TagSearch *searchPtr) /* Record describing tag search */
-{
- Tk_Item *itemPtr, *lastPtr;
- Tk_Uid uid, *tagPtr;
- int count;
-
- /*
- * Short circuit impossible searches for null tags.
- */
-
- if (searchPtr->stringLength == 0) {
- return NULL;
- }
-
- /*
- * Find the first matching item in one of several ways. If the tag is a
- * number then it selects the single item with the matching identifier.
- * In this case see if the item being requested is the hot item, in which
- * case the search can be skipped.
- */
-
- if (searchPtr->type == SEARCH_TYPE_ID) {
- Tcl_HashEntry *entryPtr;
-
- itemPtr = searchPtr->canvasPtr->hotPtr;
- lastPtr = searchPtr->canvasPtr->hotPrevPtr;
- if ((itemPtr == NULL) || (itemPtr->id != searchPtr->id)
- || (lastPtr == NULL) || (lastPtr->nextPtr != itemPtr)) {
- entryPtr = Tcl_FindHashEntry(&searchPtr->canvasPtr->idTable,
- (char *) INT2PTR(searchPtr->id));
- if (entryPtr != NULL) {
- itemPtr = Tcl_GetHashValue(entryPtr);
- lastPtr = itemPtr->prevPtr;
- } else {
- lastPtr = itemPtr = NULL;
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- searchPtr->canvasPtr->hotPtr = itemPtr;
- searchPtr->canvasPtr->hotPrevPtr = lastPtr;
- return itemPtr;
- }
-
- if (searchPtr->type == SEARCH_TYPE_ALL) {
- /*
- * All items match.
- */
-
- searchPtr->lastPtr = NULL;
- searchPtr->currentPtr = searchPtr->canvasPtr->firstItemPtr;
- return searchPtr->canvasPtr->firstItemPtr;
- }
-
- if (searchPtr->type == SEARCH_TYPE_TAG) {
- /*
- * Optimized single-tag search
- */
-
- uid = searchPtr->expr->uid;
- for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;
- itemPtr != NULL; lastPtr=itemPtr, itemPtr=itemPtr->nextPtr) {
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- }
- } else {
- /*
- * None of the above. Search for an item matching the tag expression.
- */
-
- for (lastPtr = NULL, itemPtr = searchPtr->canvasPtr->firstItemPtr;
- itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
- searchPtr->expr->index = 0;
- if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- return NULL;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TagSearchNext --
- *
- * This function returns successive items that match a given tag; it
- * should be called only after TagSearchFirst has been used to begin a
- * search.
- *
- * Results:
- * The return value is a pointer to the next item that matches the tag
- * expr specified to TagSearchScan, or NULL if no such item exists.
- * *SearchPtr is updated so that the next call to this function will
- * return the next item.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-static Tk_Item *
-TagSearchNext(
- TagSearch *searchPtr) /* Record describing search in progress. */
-{
- Tk_Item *itemPtr, *lastPtr;
- Tk_Uid uid, *tagPtr;
- int count;
-
- /*
- * Find next item in list (this may not actually be a suitable one to
- * return), and return if there are no items left.
- */
-
- lastPtr = searchPtr->lastPtr;
- if (lastPtr == NULL) {
- itemPtr = searchPtr->canvasPtr->firstItemPtr;
- } else {
- itemPtr = lastPtr->nextPtr;
- }
- if ((itemPtr == NULL) || (searchPtr->searchOver)) {
- searchPtr->searchOver = 1;
- return NULL;
- }
- if (itemPtr != searchPtr->currentPtr) {
- /*
- * The structure of the list has changed. Probably the previously-
- * returned item was removed from the list. In this case, don't
- * advance lastPtr; just return its new successor (i.e. do nothing
- * here).
- */
- } else {
- lastPtr = itemPtr;
- itemPtr = lastPtr->nextPtr;
- }
-
- if (searchPtr->type == SEARCH_TYPE_ALL) {
- /*
- * All items match.
- */
-
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
-
- if (searchPtr->type == SEARCH_TYPE_TAG) {
- /*
- * Optimized single-tag search
- */
-
- uid = searchPtr->expr->uid;
- for (; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (*tagPtr == uid) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- return NULL;
- }
-
- /*
- * Else.... evaluate tag expression
- */
-
- for ( ; itemPtr != NULL; lastPtr = itemPtr, itemPtr = itemPtr->nextPtr) {
- searchPtr->expr->index = 0;
- if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
- searchPtr->lastPtr = lastPtr;
- searchPtr->currentPtr = itemPtr;
- return itemPtr;
- }
- }
- searchPtr->lastPtr = lastPtr;
- searchPtr->searchOver = 1;
- return NULL;
-}
-#endif /* USE_OLD_TAG_SEARCH */
-
-/*
- *--------------------------------------------------------------
- *
- * DoItem --
- *
- * This is a utility function called by FindItems. It either adds
- * itemPtr's id to the list being constructed, or it adds a new tag to
- * itemPtr, depending on the value of tag.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If tag is NULL then itemPtr's id is added as an element to the
- * supplied object; otherwise tag is added to itemPtr's list of tags.
- *
- *--------------------------------------------------------------
- */
-
-static void
-DoItem(
- Tcl_Obj *accumObj, /* Object in which to (possibly) record item
- * id. */
- Tk_Item *itemPtr, /* Item to (possibly) modify. */
- Tk_Uid tag) /* Tag to add to those already present for
- * item, or NULL. */
-{
- Tk_Uid *tagPtr;
- int count;
-
- /*
- * Handle the "add-to-result" case and return, if appropriate.
- */
-
- if (tag == NULL) {
- Tcl_ListObjAppendElement(NULL, accumObj, Tcl_NewIntObj(itemPtr->id));
- return;
- }
-
- for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
- count > 0; tagPtr++, count--) {
- if (tag == *tagPtr) {
- return;
- }
- }
-
- /*
- * Grow the tag space if there's no more room left in the current block.
- */
-
- if (itemPtr->tagSpace == itemPtr->numTags) {
- Tk_Uid *newTagPtr;
-
- itemPtr->tagSpace += 5;
- newTagPtr = ckalloc(itemPtr->tagSpace * sizeof(Tk_Uid));
- memcpy((void *) newTagPtr, itemPtr->tagPtr,
- itemPtr->numTags * sizeof(Tk_Uid));
- if (itemPtr->tagPtr != itemPtr->staticTagSpace) {
- ckfree(itemPtr->tagPtr);
- }
- itemPtr->tagPtr = newTagPtr;
- tagPtr = &itemPtr->tagPtr[itemPtr->numTags];
- }
-
- /*
- * Add in the new tag.
- */
-
- *tagPtr = tag;
- itemPtr->numTags++;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * FindItems --
- *
- * This function does all the work of implementing the "find" and
- * "addtag" options of the canvas widget command, which locate items that
- * have certain features (location, tags, position in display list, etc.)
- *
- * Results:
- * A standard Tcl return value. If newTag is NULL, then a list of ids
- * from all the items that match objc/objv is returned in the interp's
- * result. If newTag is NULL, then the normal the interp's result is an
- * empty string. If an error occurs, then the interp's result will hold
- * an error message.
- *
- * Side effects:
- * If newTag is non-NULL, then all the items that match the information
- * in objc/objv have that tag added to their lists of tags.
- *
- *--------------------------------------------------------------
- */
-
-static int
-FindItems(
- Tcl_Interp *interp, /* Interpreter for error reporting. */
- TkCanvas *canvasPtr, /* Canvas whose items are to be searched. */
- int objc, /* Number of entries in argv. Must be greater
- * than zero. */
- Tcl_Obj *const *objv, /* Arguments that describe what items to
- * search for (see user doc on "find" and
- * "addtag" options). */
- Tcl_Obj *newTag, /* If non-NULL, gives new tag to set on all
- * found items; if NULL, then ids of found
- * items are returned in the interp's
- * result. */
- int first /* For error messages: gives number of
- * elements of objv which are already
- * handled. */
-#ifndef USE_OLD_TAG_SEARCH
- ,TagSearch **searchPtrPtr /* From CanvasWidgetCmd local vars*/
-#endif /* not USE_OLD_TAG_SEARCH */
- )
-{
-#ifdef USE_OLD_TAG_SEARCH
- TagSearch search;
-#endif /* USE_OLD_TAG_SEARCH */
- Tk_Item *itemPtr;
- Tk_Uid uid;
- int index, result;
- Tcl_Obj *resultObj;
- static const char *const optionStrings[] = {
- "above", "all", "below", "closest",
- "enclosed", "overlapping", "withtag", NULL
- };
- enum options {
- CANV_ABOVE, CANV_ALL, CANV_BELOW, CANV_CLOSEST,
- CANV_ENCLOSED, CANV_OVERLAPPING, CANV_WITHTAG
- };
-
- if (newTag != NULL) {
- uid = Tk_GetUid(Tcl_GetString(newTag));
- } else {
- uid = NULL;
- }
- if (Tcl_GetIndexFromObj(interp, objv[first], optionStrings,
- "search command", 0, &index) != TCL_OK) {
- return TCL_ERROR;
- }
- switch ((enum options) index) {
- case CANV_ABOVE: {
- Tk_Item *lastPtr = NULL;
-
- if (objc != first+2) {
- Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId");
- return TCL_ERROR;
- }
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr,
- return TCL_ERROR) {
- lastPtr = itemPtr;
- }
- if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
- resultObj = Tcl_NewObj();
- DoItem(resultObj, lastPtr->nextPtr, uid);
- Tcl_SetObjResult(interp, resultObj);
- }
- break;
- }
- case CANV_ALL:
- if (objc != first+1) {
- Tcl_WrongNumArgs(interp, first+1, objv, NULL);
- return TCL_ERROR;
- }
-
- resultObj = Tcl_NewObj();
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- DoItem(resultObj, itemPtr, uid);
- }
- Tcl_SetObjResult(interp, resultObj);
- break;
-
- case CANV_BELOW:
- if (objc != first+2) {
- Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId");
- return TCL_ERROR;
- }
- FIRST_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr,
- return TCL_ERROR);
- if ((itemPtr != NULL) && (itemPtr->prevPtr != NULL)) {
- resultObj = Tcl_NewObj();
- DoItem(resultObj, itemPtr->prevPtr, uid);
- Tcl_SetObjResult(interp, resultObj);
- }
- break;
- case CANV_CLOSEST: {
- double closestDist;
- Tk_Item *startPtr, *closestPtr;
- double coords[2], halo;
- int x1, y1, x2, y2;
-
- if ((objc < first+3) || (objc > first+5)) {
- Tcl_WrongNumArgs(interp, first+1, objv, "x y ?halo? ?start?");
- return TCL_ERROR;
- }
- if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[first+1], &coords[0]) != TCL_OK
- || Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[first+2], &coords[1]) != TCL_OK) {
- return TCL_ERROR;
- }
- if (objc > first+3) {
- if (Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr,
- objv[first+3], &halo) != TCL_OK) {
- return TCL_ERROR;
- }
- if (halo < 0.0) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't have negative halo value \"%f\"", halo));
- return TCL_ERROR;
- }
- } else {
- halo = 0.0;
- }
-
- /*
- * Find the item at which to start the search.
- */
-
- startPtr = canvasPtr->firstItemPtr;
- if (objc == first+5) {
- FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr,
- return TCL_ERROR);
- if (itemPtr != NULL) {
- startPtr = itemPtr;
- }
- }
-
- /*
- * The code below is optimized so that it can eliminate most items
- * without having to call their item-specific functions. This is done
- * by keeping a bounding box (x1, y1, x2, y2) that an item's bbox must
- * overlap if the item is to have any chance of being closer than the
- * closest so far.
- */
-
- itemPtr = startPtr;
- while(itemPtr && (itemPtr->state == TK_STATE_HIDDEN ||
- (itemPtr->state == TK_STATE_NULL &&
- canvasPtr->canvas_state == TK_STATE_HIDDEN))) {
- itemPtr = itemPtr->nextPtr;
- }
- if (itemPtr == NULL) {
- return TCL_OK;
- }
- closestDist = ItemPoint(canvasPtr, itemPtr, coords, halo);
- while (1) {
- double newDist;
-
- /*
- * Update the bounding box using itemPtr, which is the new closest
- * item.
- */
-
- x1 = (int) (coords[0] - closestDist - halo - 1);
- y1 = (int) (coords[1] - closestDist - halo - 1);
- x2 = (int) (coords[0] + closestDist + halo + 1);
- y2 = (int) (coords[1] + closestDist + halo + 1);
- closestPtr = itemPtr;
-
- /*
- * Search for an item that beats the current closest one. Work
- * circularly through the canvas's item list until getting back to
- * the starting item.
- */
-
- while (1) {
- itemPtr = itemPtr->nextPtr;
- if (itemPtr == NULL) {
- itemPtr = canvasPtr->firstItemPtr;
- }
- if (itemPtr == startPtr) {
- resultObj = Tcl_NewObj();
- DoItem(resultObj, closestPtr, uid);
- Tcl_SetObjResult(interp, resultObj);
- return TCL_OK;
- }
- if (itemPtr->state == TK_STATE_HIDDEN ||
- (itemPtr->state == TK_STATE_NULL &&
- canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
- continue;
- }
- if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
- || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
- continue;
- }
- newDist = ItemPoint(canvasPtr, itemPtr, coords, halo);
- if (newDist <= closestDist) {
- closestDist = newDist;
- break;
- }
- }
- }
- break;
- }
- case CANV_ENCLOSED:
- if (objc != first+5) {
- Tcl_WrongNumArgs(interp, first+1, objv, "x1 y1 x2 y2");
- return TCL_ERROR;
- }
- return FindArea(interp, canvasPtr, objv+first+1, uid, 1);
- case CANV_OVERLAPPING:
- if (objc != first+5) {
- Tcl_WrongNumArgs(interp, first+1, objv, "x1 y1 x2 y2");
- return TCL_ERROR;
- }
- return FindArea(interp, canvasPtr, objv+first+1, uid, 0);
- case CANV_WITHTAG:
- if (objc != first+2) {
- Tcl_WrongNumArgs(interp, first+1, objv, "tagOrId");
- return TCL_ERROR;
- }
- resultObj = Tcl_NewObj();
- FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr,
- goto badWithTagSearch) {
- DoItem(resultObj, itemPtr, uid);
- }
- Tcl_SetObjResult(interp, resultObj);
- return TCL_OK;
- badWithTagSearch:
- Tcl_DecrRefCount(resultObj);
- return TCL_ERROR;
- }
- return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * FindArea --
- *
- * This function implements area searches for the "find" and "addtag"
- * options.
- *
- * Results:
- * A standard Tcl return value. If newTag is NULL, then a list of ids
- * from all the items overlapping or enclosed by the rectangle given by
- * objc is returned in the interp's result. If newTag is NULL, then the
- * normal the interp's result is an empty string. If an error occurs,
- * then the interp's result will hold an error message.
- *
- * Side effects:
- * If uid is non-NULL, then all the items overlapping or enclosed by the
- * area in objv have that tag added to their lists of tags.
- *
- *--------------------------------------------------------------
- */
-
-static int
-FindArea(
- Tcl_Interp *interp, /* Interpreter for error reporting and result
- * storing. */
- TkCanvas *canvasPtr, /* Canvas whose items are to be searched. */
- Tcl_Obj *const *objv, /* Array of four arguments that give the
- * coordinates of the rectangular area to
- * search. */
- Tk_Uid uid, /* If non-NULL, gives new tag to set on all
- * found items; if NULL, then ids of found
- * items are returned in the interp's
- * result. */
- int enclosed) /* 0 means overlapping or enclosed items are
- * OK, 1 means only enclosed items are OK. */
-{
- double rect[4], tmp;
- int x1, y1, x2, y2;
- Tk_Item *itemPtr;
- Tcl_Obj *resultObj;
-
- if ((Tk_CanvasGetCoordFromObj(interp, (Tk_Canvas) canvasPtr, objv[0],
- &rect[0]) != TCL_OK)
- || (Tk_CanvasGetCoordFromObj(interp,(Tk_Canvas)canvasPtr,objv[1],
- &rect[1]) != TCL_OK)
- || (Tk_CanvasGetCoordFromObj(interp,(Tk_Canvas)canvasPtr,objv[2],
- &rect[2]) != TCL_OK)
- || (Tk_CanvasGetCoordFromObj(interp,(Tk_Canvas)canvasPtr,objv[3],
- &rect[3]) != TCL_OK)) {
- return TCL_ERROR;
- }
- if (rect[0] > rect[2]) {
- tmp = rect[0]; rect[0] = rect[2]; rect[2] = tmp;
- }
- if (rect[1] > rect[3]) {
- tmp = rect[1]; rect[1] = rect[3]; rect[3] = tmp;
- }
-
- /*
- * Use an integer bounding box for a quick test, to avoid calling
- * item-specific code except for items that are close.
- */
-
- x1 = (int) (rect[0] - 1.0);
- y1 = (int) (rect[1] - 1.0);
- x2 = (int) (rect[2] + 1.0);
- y2 = (int) (rect[3] + 1.0);
- resultObj = Tcl_NewObj();
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if (itemPtr->state == TK_STATE_HIDDEN ||
- (itemPtr->state == TK_STATE_NULL
- && canvasPtr->canvas_state == TK_STATE_HIDDEN)) {
- continue;
- }
- if ((itemPtr->x1 >= x2) || (itemPtr->x2 <= x1)
- || (itemPtr->y1 >= y2) || (itemPtr->y2 <= y1)) {
- continue;
- }
- if (ItemOverlap(canvasPtr, itemPtr, rect) >= enclosed) {
- DoItem(resultObj, itemPtr, uid);
- }
- }
- Tcl_SetObjResult(interp, resultObj);
- return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * RelinkItems --
- *
- * Move one or more items to a different place in the display order for a
- * canvas.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The items identified by "tag" are moved so that they are all together
- * in the display list and immediately after prevPtr. The order of the
- * moved items relative to each other is not changed.
- *
- *--------------------------------------------------------------
- */
-
-#ifdef USE_OLD_TAG_SEARCH
-static void
-RelinkItems(
- TkCanvas *canvasPtr, /* Canvas to be modified. */
- Tcl_Obj *tag, /* Tag identifying items to be moved in the
- * redisplay list. */
- Tk_Item *prevPtr) /* Reposition the items so that they go just
- * after this item (NULL means put at
- * beginning of list). */
-#else /* USE_OLD_TAG_SEARCH */
-static int
-RelinkItems(
- TkCanvas *canvasPtr, /* Canvas to be modified. */
- Tcl_Obj *tag, /* Tag identifying items to be moved in the
- * redisplay list. */
- Tk_Item *prevPtr, /* Reposition the items so that they go just
- * after this item (NULL means put at
- * beginning of list). */
- TagSearch **searchPtrPtr) /* From CanvasWidgetCmd local vars */
-#endif /* USE_OLD_TAG_SEARCH */
-{
- Tk_Item *itemPtr;
-#ifdef USE_OLD_TAG_SEARCH
- TagSearch search;
-#endif /* USE_OLD_TAG_SEARCH */
- Tk_Item *firstMovePtr, *lastMovePtr;
- int result;
-
- /*
- * Find all of the items to be moved and remove them from the list, making
- * an auxiliary list running from firstMovePtr to lastMovePtr. Record
- * their areas for redisplay.
- */
-
- firstMovePtr = lastMovePtr = NULL;
- FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, return TCL_ERROR) {
- if (itemPtr == prevPtr) {
- /*
- * Item after which insertion is to occur is being moved! Switch
- * to insert after its predecessor.
- */
-
- prevPtr = prevPtr->prevPtr;
- }
- if (itemPtr->prevPtr == NULL) {
- if (itemPtr->nextPtr != NULL) {
- itemPtr->nextPtr->prevPtr = NULL;
- }
- canvasPtr->firstItemPtr = itemPtr->nextPtr;
- } else {
- if (itemPtr->nextPtr != NULL) {
- itemPtr->nextPtr->prevPtr = itemPtr->prevPtr;
- }
- itemPtr->prevPtr->nextPtr = itemPtr->nextPtr;
- }
- if (canvasPtr->lastItemPtr == itemPtr) {
- canvasPtr->lastItemPtr = itemPtr->prevPtr;
- }
- if (firstMovePtr == NULL) {
- itemPtr->prevPtr = NULL;
- firstMovePtr = itemPtr;
- } else {
- itemPtr->prevPtr = lastMovePtr;
- lastMovePtr->nextPtr = itemPtr;
- }
- lastMovePtr = itemPtr;
- EventuallyRedrawItem(canvasPtr, itemPtr);
- canvasPtr->flags |= REPICK_NEEDED;
- }
-
- /*
- * Insert the list of to-be-moved items back into the canvas's at the
- * desired position.
- */
-
- if (firstMovePtr == NULL) {
-#ifdef USE_OLD_TAG_SEARCH
- return;
-#else /* USE_OLD_TAG_SEARCH */
- return TCL_OK;
-#endif /* USE_OLD_TAG_SEARCH */
- }
- if (prevPtr == NULL) {
- if (canvasPtr->firstItemPtr != NULL) {
- canvasPtr->firstItemPtr->prevPtr = lastMovePtr;
- }
- lastMovePtr->nextPtr = canvasPtr->firstItemPtr;
- canvasPtr->firstItemPtr = firstMovePtr;
- } else {
- if (prevPtr->nextPtr != NULL) {
- prevPtr->nextPtr->prevPtr = lastMovePtr;
- }
- lastMovePtr->nextPtr = prevPtr->nextPtr;
- if (firstMovePtr != NULL) {
- firstMovePtr->prevPtr = prevPtr;
- }
- prevPtr->nextPtr = firstMovePtr;
- }
- if (canvasPtr->lastItemPtr == prevPtr) {
- canvasPtr->lastItemPtr = lastMovePtr;
- }
-#ifndef USE_OLD_TAG_SEARCH
- return TCL_OK;
-#endif /* not USE_OLD_TAG_SEARCH */
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasBindProc --
- *
- * This function is invoked by the Tk dispatcher to handle events
- * associated with bindings on items.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Depends on the command invoked as part of the binding (if there was
- * any).
- *
- *--------------------------------------------------------------
- */
-
-static void
-CanvasBindProc(
- ClientData clientData, /* Pointer to canvas structure. */
- XEvent *eventPtr) /* Pointer to X event that just happened. */
-{
- TkCanvas *canvasPtr = clientData;
- int mask;
-
- Tcl_Preserve(canvasPtr);
-
- /*
- * This code below keeps track of the current modifier state in
- * canvasPtr>state. This information is used to defer repicks of the
- * current item while buttons are down.
- */
-
- switch (eventPtr->type) {
- case ButtonPress:
- case ButtonRelease:
- switch (eventPtr->xbutton.button) {
- case Button1:
- mask = Button1Mask;
- break;
- case Button2:
- mask = Button2Mask;
- break;
- case Button3:
- mask = Button3Mask;
- break;
- case Button4:
- mask = Button4Mask;
- break;
- case Button5:
- mask = Button5Mask;
- break;
- default:
- mask = 0;
- break;
- }
-
- /*
- * For button press events, repick the current item using the button
- * state before the event, then process the event. For button release
- * events, first process the event, then repick the current item using
- * the button state *after* the event (the button has logically gone
- * up before we change the current item).
- */
-
- if (eventPtr->type == ButtonPress) {
- /*
- * On a button press, first repick the current item using the
- * button state before the event, the process the event.
- */
-
- canvasPtr->state = eventPtr->xbutton.state;
- PickCurrentItem(canvasPtr, eventPtr);
- canvasPtr->state ^= mask;
- CanvasDoEvent(canvasPtr, eventPtr);
- } else {
- /*
- * Button release: first process the event, with the button still
- * considered to be down. Then repick the current item under the
- * assumption that the button is no longer down.
- */
-
- canvasPtr->state = eventPtr->xbutton.state;
- CanvasDoEvent(canvasPtr, eventPtr);
- eventPtr->xbutton.state ^= mask;
- canvasPtr->state = eventPtr->xbutton.state;
- PickCurrentItem(canvasPtr, eventPtr);
- eventPtr->xbutton.state ^= mask;
- }
- break;
- case EnterNotify:
- case LeaveNotify:
- canvasPtr->state = eventPtr->xcrossing.state;
- PickCurrentItem(canvasPtr, eventPtr);
- break;
- case MotionNotify:
- canvasPtr->state = eventPtr->xmotion.state;
- PickCurrentItem(canvasPtr, eventPtr);
- /* fallthrough */
- default:
- CanvasDoEvent(canvasPtr, eventPtr);
- }
-
- Tcl_Release(canvasPtr);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * PickCurrentItem --
- *
- * Find the topmost item in a canvas that contains a given location and
- * mark the the current item. If the current item has changed, generate a
- * fake exit event on the old current item, a fake enter event on the new
- * current item item and force a redraw of the two items. Canvas items
- * that are hidden or disabled are ignored.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The current item for canvasPtr may change. If it does, then the
- * commands associated with item entry and exit could do just about
- * anything. A binding script could delete the canvas, so callers should
- * protect themselves with Tcl_Preserve and Tcl_Release.
- *
- *--------------------------------------------------------------
- */
-
-static void
-PickCurrentItem(
- TkCanvas *canvasPtr, /* Canvas widget in which to select current
- * item. */
- XEvent *eventPtr) /* Event describing location of mouse cursor.
- * Must be EnterWindow, LeaveWindow,
- * ButtonRelease, or MotionNotify. */
-{
- double coords[2];
- int buttonDown;
- Tk_Item *prevItemPtr;
-#ifndef USE_OLD_TAG_SEARCH
- SearchUids *searchUids = GetStaticUids();
-#endif
-
- /*
- * Check whether or not a button is down. If so, we'll log entry and exit
- * into and out of the current item, but not entry into any other item.
- * This implements a form of grabbing equivalent to what the X server does
- * for windows.
- */
-
- buttonDown = canvasPtr->state
- & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
-
- /*
- * Save information about this event in the canvas. The event in the
- * canvas is used for two purposes:
- *
- * 1. Event bindings: if the current item changes, fake events are
- * generated to allow item-enter and item-leave bindings to trigger.
- * 2. Reselection: if the current item gets deleted, can use the saved
- * event to find a new current item.
- *
- * Translate MotionNotify events into EnterNotify events, since that's
- * what gets reported to item handlers.
- */
-
- if (eventPtr != &canvasPtr->pickEvent) {
- if ((eventPtr->type == MotionNotify)
- || (eventPtr->type == ButtonRelease)) {
- canvasPtr->pickEvent.xcrossing.type = EnterNotify;
- canvasPtr->pickEvent.xcrossing.serial = eventPtr->xmotion.serial;
- canvasPtr->pickEvent.xcrossing.send_event
- = eventPtr->xmotion.send_event;
- canvasPtr->pickEvent.xcrossing.display = eventPtr->xmotion.display;
- canvasPtr->pickEvent.xcrossing.window = eventPtr->xmotion.window;
- canvasPtr->pickEvent.xcrossing.root = eventPtr->xmotion.root;
- canvasPtr->pickEvent.xcrossing.subwindow = None;
- canvasPtr->pickEvent.xcrossing.time = eventPtr->xmotion.time;
- canvasPtr->pickEvent.xcrossing.x = eventPtr->xmotion.x;
- canvasPtr->pickEvent.xcrossing.y = eventPtr->xmotion.y;
- canvasPtr->pickEvent.xcrossing.x_root = eventPtr->xmotion.x_root;
- canvasPtr->pickEvent.xcrossing.y_root = eventPtr->xmotion.y_root;
- canvasPtr->pickEvent.xcrossing.mode = NotifyNormal;
- canvasPtr->pickEvent.xcrossing.detail = NotifyNonlinear;
- canvasPtr->pickEvent.xcrossing.same_screen =
- eventPtr->xmotion.same_screen;
- canvasPtr->pickEvent.xcrossing.focus = False;
- canvasPtr->pickEvent.xcrossing.state = eventPtr->xmotion.state;
- } else {
- canvasPtr->pickEvent = *eventPtr;
- }
- }
-
- /*
- * If this is a recursive call (there's already a partially completed call
- * pending on the stack; it's in the middle of processing a Leave event
- * handler for the old current item) then just return; the pending call
- * will do everything that's needed.
- */
-
- if (canvasPtr->flags & REPICK_IN_PROGRESS) {
- return;
- }
-
- /*
- * A LeaveNotify event automatically means that there's no current object,
- * so the check for closest item can be skipped.
- */
-
- coords[0] = canvasPtr->pickEvent.xcrossing.x + canvasPtr->xOrigin;
- coords[1] = canvasPtr->pickEvent.xcrossing.y + canvasPtr->yOrigin;
- if (canvasPtr->pickEvent.type != LeaveNotify) {
- canvasPtr->newCurrentPtr = CanvasFindClosest(canvasPtr, coords);
- } else {
- canvasPtr->newCurrentPtr = NULL;
- }
-
- if ((canvasPtr->newCurrentPtr == canvasPtr->currentItemPtr)
- && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
- /*
- * Nothing to do: the current item hasn't changed.
- */
-
- return;
- }
-
- if (!buttonDown) {
- canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
- }
-
- /*
- * Simulate a LeaveNotify event on the previous current item and an
- * EnterNotify event on the new current item. Remove the "current" tag
- * from the previous current item and place it on the new current item.
- */
-
- if ((canvasPtr->newCurrentPtr != canvasPtr->currentItemPtr)
- && (canvasPtr->currentItemPtr != NULL)
- && !(canvasPtr->flags & LEFT_GRABBED_ITEM)) {
- XEvent event;
- Tk_Item *itemPtr = canvasPtr->currentItemPtr;
- int i;
-
- event = canvasPtr->pickEvent;
- event.type = LeaveNotify;
-
- /*
- * If the event's detail happens to be NotifyInferior the binding
- * mechanism will discard the event. To be consistent, always use
- * NotifyAncestor.
- */
-
- event.xcrossing.detail = NotifyAncestor;
- canvasPtr->flags |= REPICK_IN_PROGRESS;
- CanvasDoEvent(canvasPtr, &event);
- canvasPtr->flags &= ~REPICK_IN_PROGRESS;
-
- /*
- * The check below is needed because there could be an event handler
- * for <LeaveNotify> that deletes the current item.
- */
-
- if ((itemPtr == canvasPtr->currentItemPtr) && !buttonDown) {
- for (i = itemPtr->numTags-1; i >= 0; i--) {
-#ifdef USE_OLD_TAG_SEARCH
- if (itemPtr->tagPtr[i] == Tk_GetUid("current"))
-#else /* USE_OLD_TAG_SEARCH */
- if (itemPtr->tagPtr[i] == searchUids->currentUid)
-#endif /* USE_OLD_TAG_SEARCH */
- /* then */ {
- itemPtr->tagPtr[i] = itemPtr->tagPtr[itemPtr->numTags-1];
- itemPtr->numTags--;
- break;
- }
- }
- }
-
- /*
- * Note: during CanvasDoEvent above, it's possible that
- * canvasPtr->newCurrentPtr got reset to NULL because the item was
- * deleted.
- */
- }
- if ((canvasPtr->newCurrentPtr!=canvasPtr->currentItemPtr) && buttonDown) {
- canvasPtr->flags |= LEFT_GRABBED_ITEM;
- return;
- }
-
- /*
- * Special note: it's possible that canvasPtr->newCurrentPtr ==
- * canvasPtr->currentItemPtr here. This can happen, for example, if
- * LEFT_GRABBED_ITEM was set.
- */
-
- prevItemPtr = canvasPtr->currentItemPtr;
- canvasPtr->flags &= ~LEFT_GRABBED_ITEM;
- canvasPtr->currentItemPtr = canvasPtr->newCurrentPtr;
- if (prevItemPtr != NULL && prevItemPtr != canvasPtr->currentItemPtr &&
- (prevItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT)) {
- EventuallyRedrawItem(canvasPtr, prevItemPtr);
- ItemConfigure(canvasPtr, prevItemPtr, 0, NULL);
- }
- if (canvasPtr->currentItemPtr != NULL) {
- XEvent event;
-
-#ifdef USE_OLD_TAG_SEARCH
- DoItem(NULL, canvasPtr->currentItemPtr, Tk_GetUid("current"));
-#else /* USE_OLD_TAG_SEARCH */
- DoItem(NULL, canvasPtr->currentItemPtr, searchUids->currentUid);
-#endif /* USE_OLD_TAG_SEARCH */
- if ((canvasPtr->currentItemPtr->redraw_flags & TK_ITEM_STATE_DEPENDANT
- && prevItemPtr != canvasPtr->currentItemPtr)) {
- ItemConfigure(canvasPtr, canvasPtr->currentItemPtr, 0, NULL);
- EventuallyRedrawItem(canvasPtr, canvasPtr->currentItemPtr);
- }
- event = canvasPtr->pickEvent;
- event.type = EnterNotify;
- event.xcrossing.detail = NotifyAncestor;
- CanvasDoEvent(canvasPtr, &event);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasFindClosest --
- *
- * Given x and y coordinates, find the topmost canvas item that is
- * "close" to the coordinates. Canvas items that are hidden or disabled
- * are ignored.
- *
- * Results:
- * The return value is a pointer to the topmost item that is close to
- * (x,y), or NULL if no item is close.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static Tk_Item *
-CanvasFindClosest(
- TkCanvas *canvasPtr, /* Canvas widget to search. */
- double coords[2]) /* Desired x,y position in canvas, not screen,
- * coordinates.) */
-{
- Tk_Item *itemPtr;
- Tk_Item *bestPtr;
- int x1, y1, x2, y2;
-
- x1 = (int) (coords[0] - canvasPtr->closeEnough);
- y1 = (int) (coords[1] - canvasPtr->closeEnough);
- x2 = (int) (coords[0] + canvasPtr->closeEnough);
- y2 = (int) (coords[1] + canvasPtr->closeEnough);
-
- bestPtr = NULL;
- for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
- itemPtr = itemPtr->nextPtr) {
- if (itemPtr->state == TK_STATE_HIDDEN ||
- itemPtr->state==TK_STATE_DISABLED ||
- (itemPtr->state == TK_STATE_NULL &&
- (canvasPtr->canvas_state == TK_STATE_HIDDEN ||
- canvasPtr->canvas_state == TK_STATE_DISABLED))) {
- continue;
- }
- if ((itemPtr->x1 > x2) || (itemPtr->x2 < x1)
- || (itemPtr->y1 > y2) || (itemPtr->y2 < y1)) {
- continue;
- }
- if (ItemPoint(canvasPtr,itemPtr,coords,0) <= canvasPtr->closeEnough) {
- bestPtr = itemPtr;
- }
- }
- return bestPtr;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasDoEvent --
- *
- * This function is called to invoke binding processing for a new event
- * that is associated with the current item for a canvas.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Depends on the bindings for the canvas. A binding script could delete
- * the canvas, so callers should protect themselves with Tcl_Preserve and
- * Tcl_Release.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CanvasDoEvent(
- TkCanvas *canvasPtr, /* Canvas widget in which event occurred. */
- XEvent *eventPtr) /* Real or simulated X event that is to be
- * processed. */
-{
-#define NUM_STATIC 3
- ClientData staticObjects[NUM_STATIC];
- ClientData *objectPtr;
- int numObjects, i;
- Tk_Item *itemPtr;
-#ifndef USE_OLD_TAG_SEARCH
- TagSearchExpr *expr;
- int numExprs;
- SearchUids *searchUids = GetStaticUids();
-#endif /* not USE_OLD_TAG_SEARCH */
-
- if (canvasPtr->bindingTable == NULL) {
- return;
- }
-
- itemPtr = canvasPtr->currentItemPtr;
- if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) {
- itemPtr = canvasPtr->textInfo.focusItemPtr;
- }
- if (itemPtr == NULL) {
- return;
- }
-
-#ifdef USE_OLD_TAG_SEARCH
- /*
- * Set up an array with all the relevant objects for processing this
- * event. The relevant objects are (a) the event's item, (b) the tags
- * associated with the event's item, and (c) the tag "all". If there are a
- * lot of tags then malloc an array to hold all of the objects.
- */
-
- numObjects = itemPtr->numTags + 2;
-#else /* USE_OLD_TAG_SEARCH */
- /*
- * Set up an array with all the relevant objects for processing this
- * event. The relevant objects are:
- * (a) the event's item,
- * (b) the tags associated with the event's item,
- * (c) the expressions that are true for the event's item's tags, and
- * (d) the tag "all".
- *
- * If there are a lot of tags then malloc an array to hold all of the
- * objects.
- */
-
- /*
- * Flag and count all expressions that match item's tags.
- */
-
- numExprs = 0;
- expr = canvasPtr->bindTagExprs;
- while (expr) {
- expr->index = 0;
- expr->match = TagSearchEvalExpr(expr, itemPtr);
- if (expr->match) {
- numExprs++;
- }
- expr = expr->next;
- }
-
- numObjects = itemPtr->numTags + numExprs + 2;
-#endif /* not USE_OLD_TAG_SEARCH */
- if (numObjects <= NUM_STATIC) {
- objectPtr = staticObjects;
- } else {
- objectPtr = ckalloc(numObjects * sizeof(ClientData));
- }
-#ifdef USE_OLD_TAG_SEARCH
- objectPtr[0] = (ClientData) Tk_GetUid("all");
-#else /* USE_OLD_TAG_SEARCH */
- objectPtr[0] = (ClientData) searchUids->allUid;
-#endif /* USE_OLD_TAG_SEARCH */
- for (i = itemPtr->numTags-1; i >= 0; i--) {
- objectPtr[i+1] = (ClientData) itemPtr->tagPtr[i];
- }
- objectPtr[itemPtr->numTags+1] = itemPtr;
-
-#ifndef USE_OLD_TAG_SEARCH
- /*
- * Copy uids of matching expressions into object array
- */
-
- i = itemPtr->numTags+2;
- expr = canvasPtr->bindTagExprs;
- while (expr) {
- if (expr->match) {
- objectPtr[i++] = (int *) expr->uid;
- }
- expr = expr->next;
- }
-#endif /* not USE_OLD_TAG_SEARCH */
-
- /*
- * Invoke the binding system, then free up the object array if it was
- * malloc-ed.
- */
-
- if (canvasPtr->tkwin != NULL) {
- Tk_BindEvent(canvasPtr->bindingTable, eventPtr, canvasPtr->tkwin,
- numObjects, objectPtr);
- }
- if (objectPtr != staticObjects) {
- ckfree(objectPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasBlinkProc --
- *
- * This function is called as a timer handler to blink the insertion
- * cursor off and on.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The cursor gets turned on or off, redisplay gets invoked, and this
- * function reschedules itself.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasBlinkProc(
- ClientData clientData) /* Pointer to record describing entry. */
-{
- TkCanvas *canvasPtr = clientData;
-
- if (!canvasPtr->textInfo.gotFocus || (canvasPtr->insertOffTime == 0)) {
- return;
- }
- if (canvasPtr->textInfo.cursorOn) {
- canvasPtr->textInfo.cursorOn = 0;
- canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
- canvasPtr->insertOffTime, CanvasBlinkProc, canvasPtr);
- } else {
- canvasPtr->textInfo.cursorOn = 1;
- canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
- canvasPtr->insertOnTime, CanvasBlinkProc, canvasPtr);
- }
- EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.focusItemPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasFocusProc --
- *
- * This function is called whenever a canvas gets or loses the input
- * focus. It's also called whenever the window is reconfigured while it
- * has the focus.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The cursor gets turned on or off.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasFocusProc(
- TkCanvas *canvasPtr, /* Canvas that just got or lost focus. */
- int gotFocus) /* 1 means window is getting focus, 0 means
- * it's losing it. */
-{
- Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler);
- if (gotFocus) {
- canvasPtr->textInfo.gotFocus = 1;
- canvasPtr->textInfo.cursorOn = 1;
- if (canvasPtr->insertOffTime != 0) {
- canvasPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
- canvasPtr->insertOffTime, CanvasBlinkProc, canvasPtr);
- }
- } else {
- canvasPtr->textInfo.gotFocus = 0;
- canvasPtr->textInfo.cursorOn = 0;
- canvasPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
- }
- EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.focusItemPtr);
- if (canvasPtr->highlightWidth > 0) {
- canvasPtr->flags |= REDRAW_BORDERS;
- if (!(canvasPtr->flags & REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DisplayCanvas, canvasPtr);
- canvasPtr->flags |= REDRAW_PENDING;
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasSelectTo --
- *
- * Modify the selection by moving its un-anchored end. This could make
- * the selection either larger or smaller.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The selection changes.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasSelectTo(
- TkCanvas *canvasPtr, /* Information about widget. */
- Tk_Item *itemPtr, /* Item that is to hold selection. */
- int index) /* Index of element that is to become the
- * "other" end of the selection. */
-{
- int oldFirst, oldLast;
- Tk_Item *oldSelPtr;
-
- oldFirst = canvasPtr->textInfo.selectFirst;
- oldLast = canvasPtr->textInfo.selectLast;
- oldSelPtr = canvasPtr->textInfo.selItemPtr;
-
- /*
- * Grab the selection if we don't own it already.
- */
-
- if (canvasPtr->textInfo.selItemPtr == NULL) {
- Tk_OwnSelection(canvasPtr->tkwin, XA_PRIMARY, CanvasLostSelection,
- canvasPtr);
- } else if (canvasPtr->textInfo.selItemPtr != itemPtr) {
- EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.selItemPtr);
- }
- canvasPtr->textInfo.selItemPtr = itemPtr;
-
- if (canvasPtr->textInfo.anchorItemPtr != itemPtr) {
- canvasPtr->textInfo.anchorItemPtr = itemPtr;
- canvasPtr->textInfo.selectAnchor = index;
- }
- if (canvasPtr->textInfo.selectAnchor <= index) {
- canvasPtr->textInfo.selectFirst = canvasPtr->textInfo.selectAnchor;
- canvasPtr->textInfo.selectLast = index;
- } else {
- canvasPtr->textInfo.selectFirst = index;
- canvasPtr->textInfo.selectLast = canvasPtr->textInfo.selectAnchor - 1;
- }
- if ((canvasPtr->textInfo.selectFirst != oldFirst)
- || (canvasPtr->textInfo.selectLast != oldLast)
- || (itemPtr != oldSelPtr)) {
- EventuallyRedrawItem(canvasPtr, itemPtr);
- }
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasFetchSelection --
- *
- * This function is invoked by Tk to return part or all of the selection,
- * when the selection is in a canvas widget. This function always returns
- * the selection as a STRING.
- *
- * Results:
- * The return value is the number of non-NULL bytes stored at buffer.
- * Buffer is filled (or partially filled) with a NULL-terminated string
- * containing part or all of the selection, as given by offset and
- * maxBytes.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-static int
-CanvasFetchSelection(
- ClientData clientData, /* Information about canvas widget. */
- int offset, /* Offset within selection of first character
- * to be returned. */
- char *buffer, /* Location in which to place selection. */
- int maxBytes) /* Maximum number of bytes to place at buffer,
- * not including terminating NULL
- * character. */
-{
- TkCanvas *canvasPtr = clientData;
-
- return ItemSelection(canvasPtr, canvasPtr->textInfo.selItemPtr, offset,
- buffer, maxBytes);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * CanvasLostSelection --
- *
- * This function is called back by Tk when the selection is grabbed away
- * from a canvas widget.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The existing selection is unhighlighted, and the window is marked as
- * not containing a selection.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-CanvasLostSelection(
- ClientData clientData) /* Information about entry widget. */
-{
- TkCanvas *canvasPtr = clientData;
-
- EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.selItemPtr);
- canvasPtr->textInfo.selItemPtr = NULL;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * GridAlign --
- *
- * Given a coordinate and a grid spacing, this function computes the
- * location of the nearest grid line to the coordinate.
- *
- * Results:
- * The return value is the location of the grid line nearest to coord.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-static double
-GridAlign(
- double coord, /* Coordinate to grid-align. */
- double spacing) /* Spacing between grid lines. If <= 0 then no
- * alignment is done. */
-{
- if (spacing <= 0.0) {
- return coord;
- }
- if (coord < 0) {
- return -((int) ((-coord)/spacing + 0.5)) * spacing;
- }
- return ((int) (coord/spacing + 0.5)) * spacing;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ScrollFractions --
- *
- * Given the range that's visible in the window and the "100% range" for
- * what's in the canvas, return a list of two doubles representing the
- * scroll fractions. This function is used for both x and y scrolling.
- *
- * Results:
- * A List Tcl_Obj with two real numbers (Double Tcl_Objs) containing the
- * scroll fractions (between 0 and 1) corresponding to the other
- * arguments.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static Tcl_Obj *
-ScrollFractions(
- int screen1, /* Lowest coordinate visible in the window. */
- int screen2, /* Highest coordinate visible in the window. */
- int object1, /* Lowest coordinate in the object. */
- int object2) /* Highest coordinate in the object. */
-{
- Tcl_Obj *buffer[2];
- double range, f1, f2;
-
- range = object2 - object1;
- if (range <= 0) {
- f1 = 0;
- f2 = 1.0;
- } else {
- f1 = (screen1 - object1)/range;
- if (f1 < 0) {
- f1 = 0.0;
- }
- f2 = (screen2 - object1)/range;
- if (f2 > 1.0) {
- f2 = 1.0;
- }
- if (f2 < f1) {
- f2 = f1;
- }
- }
- buffer[0] = Tcl_NewDoubleObj(f1);
- buffer[1] = Tcl_NewDoubleObj(f2);
- return Tcl_NewListObj(2, buffer);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasUpdateScrollbars --
- *
- * This function is invoked whenever a canvas has changed in a way that
- * requires scrollbars to be redisplayed (e.g. the view in the canvas has
- * changed).
- *
- * Results:
- * None.
- *
- * Side effects:
- * If there are scrollbars associated with the canvas, then their
- * scrolling commands are invoked to cause them to redisplay. If errors
- * occur, additional Tcl commands may be invoked to process the errors.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CanvasUpdateScrollbars(
- TkCanvas *canvasPtr) /* Information about canvas. */
-{
- int result;
- Tcl_Interp *interp;
- int xOrigin, yOrigin, inset, width, height;
- int scrollX1, scrollX2, scrollY1, scrollY2;
- char *xScrollCmd, *yScrollCmd;
- Tcl_DString buf;
-
- /*
- * Save all the relevant values from the canvasPtr, because it might be
- * deleted as part of either of the two calls to Tcl_VarEval below.
- */
-
- interp = canvasPtr->interp;
- Tcl_Preserve(interp);
- xScrollCmd = canvasPtr->xScrollCmd;
- if (xScrollCmd != NULL) {
- Tcl_Preserve(xScrollCmd);
- }
- yScrollCmd = canvasPtr->yScrollCmd;
- if (yScrollCmd != NULL) {
- Tcl_Preserve(yScrollCmd);
- }
- xOrigin = canvasPtr->xOrigin;
- yOrigin = canvasPtr->yOrigin;
- inset = canvasPtr->inset;
- width = Tk_Width(canvasPtr->tkwin);
- height = Tk_Height(canvasPtr->tkwin);
- scrollX1 = canvasPtr->scrollX1;
- scrollX2 = canvasPtr->scrollX2;
- scrollY1 = canvasPtr->scrollY1;
- scrollY2 = canvasPtr->scrollY2;
- canvasPtr->flags &= ~UPDATE_SCROLLBARS;
- if (canvasPtr->xScrollCmd != NULL) {
- Tcl_Obj *fractions = ScrollFractions(xOrigin + inset,
- xOrigin + width - inset, scrollX1, scrollX2);
-
- Tcl_DStringInit(&buf);
- Tcl_DStringAppend(&buf, xScrollCmd, -1);
- Tcl_DStringAppend(&buf, " ", -1);
- Tcl_DStringAppend(&buf, Tcl_GetString(fractions), -1);
- result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
- Tcl_DStringFree(&buf);
- Tcl_DecrRefCount(fractions);
- if (result != TCL_OK) {
- Tcl_BackgroundException(interp, result);
- }
- Tcl_ResetResult(interp);
- Tcl_Release(xScrollCmd);
- }
-
- if (yScrollCmd != NULL) {
- Tcl_Obj *fractions = ScrollFractions(yOrigin + inset,
- yOrigin + height - inset, scrollY1, scrollY2);
-
- Tcl_DStringInit(&buf);
- Tcl_DStringAppend(&buf, yScrollCmd, -1);
- Tcl_DStringAppend(&buf, " ", -1);
- Tcl_DStringAppend(&buf, Tcl_GetString(fractions), -1);
- result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
- Tcl_DStringFree(&buf);
- Tcl_DecrRefCount(fractions);
- if (result != TCL_OK) {
- Tcl_BackgroundException(interp, result);
- }
- Tcl_ResetResult(interp);
- Tcl_Release(yScrollCmd);
- }
- Tcl_Release(interp);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * CanvasSetOrigin --
- *
- * This function is invoked to change the mapping between canvas
- * coordinates and screen coordinates in the canvas window.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The canvas will be redisplayed to reflect the change in view. In
- * addition, scrollbars will be updated if there are any.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CanvasSetOrigin(
- TkCanvas *canvasPtr, /* Information about canvas. */
- int xOrigin, /* New X origin for canvas (canvas x-coord
- * corresponding to left edge of canvas
- * window). */
- int yOrigin) /* New Y origin for canvas (canvas y-coord
- * corresponding to top edge of canvas
- * window). */
-{
- int left, right, top, bottom, delta;
-
- /*
- * If scroll increments have been set, round the window origin to the
- * nearest multiple of the increments. Remember, the origin is the place
- * just inside the borders, not the upper left corner.
- */
-
- if (canvasPtr->xScrollIncrement > 0) {
- if (xOrigin >= 0) {
- xOrigin += canvasPtr->xScrollIncrement/2;
- xOrigin -= (xOrigin + canvasPtr->inset)
- % canvasPtr->xScrollIncrement;
- } else {
- xOrigin = (-xOrigin) + canvasPtr->xScrollIncrement/2;
- xOrigin = -(xOrigin - (xOrigin - canvasPtr->inset)
- % canvasPtr->xScrollIncrement);
- }
- }
- if (canvasPtr->yScrollIncrement > 0) {
- if (yOrigin >= 0) {
- yOrigin += canvasPtr->yScrollIncrement/2;
- yOrigin -= (yOrigin + canvasPtr->inset)
- % canvasPtr->yScrollIncrement;
- } else {
- yOrigin = (-yOrigin) + canvasPtr->yScrollIncrement/2;
- yOrigin = -(yOrigin - (yOrigin - canvasPtr->inset)
- % canvasPtr->yScrollIncrement);
- }
- }
-
- /*
- * Adjust the origin if necessary to keep as much as possible of the
- * canvas in the view. The variables left, right, etc. keep track of how
- * much extra space there is on each side of the view before it will stick
- * out past the scroll region. If one side sticks out past the edge of the
- * scroll region, adjust the view to bring that side back to the edge of
- * the scrollregion (but don't move it so much that the other side sticks
- * out now). If scroll increments are in effect, be sure to adjust only by
- * full increments.
- */
-
- if ((canvasPtr->confine) && (canvasPtr->regionString != NULL)) {
- left = xOrigin + canvasPtr->inset - canvasPtr->scrollX1;
- right = canvasPtr->scrollX2
- - (xOrigin + Tk_Width(canvasPtr->tkwin) - canvasPtr->inset);
- top = yOrigin + canvasPtr->inset - canvasPtr->scrollY1;
- bottom = canvasPtr->scrollY2
- - (yOrigin + Tk_Height(canvasPtr->tkwin) - canvasPtr->inset);
- if ((left < 0) && (right > 0)) {
- delta = (right > -left) ? -left : right;
- if (canvasPtr->xScrollIncrement > 0) {
- delta -= delta % canvasPtr->xScrollIncrement;
- }
- xOrigin += delta;
- } else if ((right < 0) && (left > 0)) {
- delta = (left > -right) ? -right : left;
- if (canvasPtr->xScrollIncrement > 0) {
- delta -= delta % canvasPtr->xScrollIncrement;
- }
- xOrigin -= delta;
- }
- if ((top < 0) && (bottom > 0)) {
- delta = (bottom > -top) ? -top : bottom;
- if (canvasPtr->yScrollIncrement > 0) {
- delta -= delta % canvasPtr->yScrollIncrement;
- }
- yOrigin += delta;
- } else if ((bottom < 0) && (top > 0)) {
- delta = (top > -bottom) ? -bottom : top;
- if (canvasPtr->yScrollIncrement > 0) {
- delta -= delta % canvasPtr->yScrollIncrement;
- }
- yOrigin -= delta;
- }
- }
-
- if ((xOrigin == canvasPtr->xOrigin) && (yOrigin == canvasPtr->yOrigin)) {
- return;
- }
-
- /*
- * Tricky point: must redisplay not only everything that's visible in the
- * window's final configuration, but also everything that was visible in
- * the initial configuration. This is needed because some item types, like
- * windows, need to know when they move off-screen so they can explicitly
- * undisplay themselves.
- */
-
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- canvasPtr->xOrigin, canvasPtr->yOrigin,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
- canvasPtr->xOrigin = xOrigin;
- canvasPtr->yOrigin = yOrigin;
- canvasPtr->flags |= UPDATE_SCROLLBARS;
- Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
- canvasPtr->xOrigin, canvasPtr->yOrigin,
- canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
- canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkGetStringsFromObjs --
- *
- * Results:
- * Converts object list into string list.
- *
- * Side effects:
- * Memory is allocated for the objv array, which must be freed using
- * ckfree() when no longer needed.
- *
- *----------------------------------------------------------------------
- */
-
-/* ARGSUSED */
-static const char **
-TkGetStringsFromObjs(
- int objc,
- Tcl_Obj *const objv[])
-{
- register int i;
- const char **argv;
-
- if (objc <= 0) {
- return NULL;
- }
- argv = ckalloc((objc+1) * sizeof(char *));
- for (i = 0; i < objc; i++) {
- argv[i] = Tcl_GetString(objv[i]);
- }
- argv[objc] = 0;
- return argv;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsColor --
- *
- * This function is called by individual canvas items when they want to
- * set a color value for output. Given information about an X color, this
- * function will generate Postscript commands to set up an appropriate
- * color in Postscript.
- *
- * Results:
- * Returns a standard Tcl return value. If an error occurs then an error
- * message will be left in interp->result. If no error occurs, then
- * additional Postscript will be appended to interp->result.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-int
-Tk_CanvasPsColor(
- Tcl_Interp *interp, /* Interpreter for returning Postscript or
- * error message. */
- Tk_Canvas canvas, /* Information about canvas. */
- XColor *colorPtr) /* Information about color. */
-{
- return Tk_PostscriptColor(interp, Canvas(canvas)->psInfo, colorPtr);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsFont --
- *
- * This function is called by individual canvas items when they want to
- * output text. Given information about an X font, this function will
- * generate Postscript commands to set up an appropriate font in
- * Postscript.
- *
- * Results:
- * Returns a standard Tcl return value. If an error occurs then an error
- * message will be left in interp->result. If no error occurs, then
- * additional Postscript will be appended to the interp->result.
- *
- * Side effects:
- * The Postscript font name is entered into psInfoPtr->fontTable if it
- * wasn't already there.
- *
- *--------------------------------------------------------------
- */
-
-int
-Tk_CanvasPsFont(
- Tcl_Interp *interp, /* Interpreter for returning Postscript or
- * error message. */
- Tk_Canvas canvas, /* Information about canvas. */
- Tk_Font tkfont) /* Information about font in which text is to
- * be printed. */
-{
- return Tk_PostscriptFont(interp, Canvas(canvas)->psInfo, tkfont);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsBitmap --
- *
- * This function is called to output the contents of a sub-region of a
- * bitmap in proper image data format for Postscript (i.e. data between
- * angle brackets, one bit per pixel).
- *
- * Results:
- * Returns a standard Tcl return value. If an error occurs then an error
- * message will be left in interp->result. If no error occurs, then
- * additional Postscript will be appended to interp->result.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-int
-Tk_CanvasPsBitmap(
- Tcl_Interp *interp, /* Interpreter for returning Postscript or
- * error message. */
- Tk_Canvas canvas, /* Information about canvas. */
- Pixmap bitmap, /* Bitmap for which to generate Postscript. */
- int startX, int startY, /* Coordinates of upper-left corner of
- * rectangular region to output. */
- int width, int height) /* Size of rectangular region. */
-{
- return Tk_PostscriptBitmap(interp, Canvas(canvas)->tkwin,
- Canvas(canvas)->psInfo, bitmap, startX, startY, width, height);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsStipple --
- *
- * This function is called by individual canvas items when they have
- * created a path that they'd like to be filled with a stipple pattern.
- * Given information about an X bitmap, this function will generate
- * Postscript commands to fill the current clip region using a stipple
- * pattern defined by the bitmap.
- *
- * Results:
- * Returns a standard Tcl return value. If an error occurs then an error
- * message will be left in interp->result. If no error occurs, then
- * additional Postscript will be appended to interp->result.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-int
-Tk_CanvasPsStipple(
- Tcl_Interp *interp, /* Interpreter for returning Postscript or
- * error message. */
- Tk_Canvas canvas, /* Information about canvas. */
- Pixmap bitmap) /* Bitmap to use for stippling. */
-{
- return Tk_PostscriptStipple(interp, Canvas(canvas)->tkwin,
- Canvas(canvas)->psInfo, bitmap);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsY --
- *
- * Given a y-coordinate in canvas coordinates, this function returns a
- * y-coordinate to use for Postscript output.
- *
- * Results:
- * Returns the Postscript coordinate that corresponds to "y".
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-double
-Tk_CanvasPsY(
- Tk_Canvas canvas, /* Token for canvas on whose behalf Postscript
- * is being generated. */
- double y) /* Y-coordinate in canvas coords. */
-{
- return Tk_PostscriptY(y, Canvas(canvas)->psInfo);
-}
-
-/*
- *--------------------------------------------------------------
- *
- * Tk_CanvasPsPath --
- *
- * Given an array of points for a path, generate Postscript commands to
- * create the path.
- *
- * Results:
- * Postscript commands get appended to what's in interp->result.
- *
- * Side effects:
- * None.
- *
- *--------------------------------------------------------------
- */
-
-void
-Tk_CanvasPsPath(
- Tcl_Interp *interp, /* Put generated Postscript in this
- * interpreter's result field. */
- Tk_Canvas canvas, /* Canvas on whose behalf Postscript is being
- * generated. */
- double *coordPtr, /* Pointer to first in array of 2*numPoints
- * coordinates giving points for path. */
- int numPoints) /* Number of points at *coordPtr. */
-{
- Tk_PostscriptPath(interp, Canvas(canvas)->psInfo, coordPtr, numPoints);
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */