Tk Source Code

Artifact [238426e5]
Login

Artifact 238426e59d7e1e4acdce410c740e3db8664a6e78:

Attachment "smallitems.patch" to ticket [e9a842a3] added by arjenmarkus 2013-12-28 14:42:20. (unpublished)
Index: generic/tk.h
==================================================================
--- generic/tk.h
+++ generic/tk.h
@@ -975,14 +975,17 @@
  * TK_ITEM_STATE_DEPENDANT -	1 means that object needs to be redrawn if the
  *				canvas state changes.
  * TK_ITEM_DONT_REDRAW - 	1 means that the object redraw is already been
  *				prepared, so the general canvas code doesn't
  *				need to do that any more.
+ * TK_ITEM_SMALL_ITEM - 	1 means that the object should not be drawn if
+ *				the option "suppress small items" is in effect.
  */
 
 #define TK_ITEM_STATE_DEPENDANT		1
 #define TK_ITEM_DONT_REDRAW		2
+#define TK_ITEM_SMALL_ITEM		4
 
 /*
  * Records of the following type are used to describe a type of item (e.g.
  * lines, circles, etc.) that can form part of a canvas widget.
  */

Index: generic/tkCanvas.c
==================================================================
--- generic/tkCanvas.c
+++ generic/tkCanvas.c
@@ -95,21 +95,31 @@
 #define SEARCH_TYPE_EXPR	4	/* Compound search */
 
 #endif /* USE_OLD_TAG_SEARCH */
 
 /*
- * Custom option for handling "-state" and "-offset"
+ * Custom option for handling "-state", "-offset" and "-suppresssmallitems"
  */
+static int		SuppressSmallItemsParseProc(ClientData clientData,
+			    Tcl_Interp *interp, Tk_Window tkwin, const char *value, char *widgRec,
+			    int offset);
+
+static const char *	SuppressSmallItemsPrintProc(ClientData clientData,
+			    Tk_Window tkwin, char *widgRec, int offset, Tcl_FreeProc **freeProcPtr);
 
 static const Tk_CustomOption stateOption = {
     TkStateParseProc, TkStatePrintProc,
     NULL		/* Only "normal" and "disabled". */
 };
 
 static const Tk_CustomOption offsetOption = {
     TkOffsetParseProc, TkOffsetPrintProc, INT2PTR(TK_OFFSET_RELATIVE)
 };
+
+static const Tk_CustomOption suppressSmallItemsOption = {
+    SuppressSmallItemsParseProc, SuppressSmallItemsPrintProc, NULL
+};
 
 /*
  * Information used for argv parsing.
  */
 
@@ -181,10 +191,13 @@
 	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_CUSTOM, "-suppresssmallitems", "SuppressSmallItems", "SuppressSmallItems",
+	"0", Tk_Offset(TkCanvas, flags),
+	TK_CONFIG_DONT_SET_DEFAULT, &suppressSmallItemsOption},
     {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},
@@ -309,12 +322,12 @@
 			    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);
+static Tk_Item *	TagSearchFirst(TagSearch *searchPtr, int suppressSmallItems);
+static Tk_Item *	TagSearchNext(TagSearch *searchPtr, int suppressSmallItems);
 #endif /* USE_OLD_TAG_SEARCH */
 
 /*
  * The structure below defines canvas class behavior by means of functions
  * that can be invoked from generic window code.
@@ -340,21 +353,21 @@
 #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) \
+#define FIRST_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,suppressSmallItems,errorExitClause) \
     if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \
 	errorExitClause; \
     } \
-    itemPtr = TagSearchFirst(*(searchPtrPtr));
-#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,errorExitClause) \
+    itemPtr = TagSearchFirst(*(searchPtrPtr),suppressSmallItems);
+#define FOR_EVERY_CANVAS_ITEM_MATCHING(objPtr,searchPtrPtr,suppressSmallIitems,errorExitClause) \
     if ((result=TagSearchScan(canvasPtr,(objPtr),(searchPtrPtr))) != TCL_OK){ \
 	errorExitClause; \
     } \
-    for (itemPtr = TagSearchFirst(*(searchPtrPtr)); \
-	    itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr)))
+    for (itemPtr = TagSearchFirst(*(searchPtrPtr),suppressSmallItems); \
+	    itemPtr != NULL; itemPtr = TagSearchNext(*(searchPtrPtr),suppressSmallItems))
 #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 */
@@ -797,10 +810,11 @@
 #else /* USE_OLD_TAG_SEARCH */
     TagSearch *searchPtr = NULL;/* Allocated by first TagSearchScan, freed by
 				 * TagSearchDestroy */
 #endif /* USE_OLD_TAG_SEARCH */
 
+    int suppressSmallItems;
     int index;
     static const char *const optionStrings[] = {
 	"addtag",	"bbox",		"bind",		"canvasx",
 	"canvasy",	"cget",		"configure",	"coords",
 	"create",	"dchars",	"delete",	"dtag",
@@ -832,10 +846,12 @@
 	    &index) != TCL_OK) {
 	return TCL_ERROR;
     }
     Tcl_Preserve(canvasPtr);
 
+    suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0);
+
     result = TCL_OK;
     switch ((enum options) index) {
     case CANV_ADDTAG:
 	if (objc < 4) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "tag searchCommand ?arg ...?");
@@ -856,11 +872,11 @@
 	    result = TCL_ERROR;
 	    goto done;
 	}
 	gotAny = 0;
 	for (i = 2; i < objc; i++) {
-	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) {
+	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, suppressSmallItems, goto done) {
 		if ((itemPtr->x1 >= itemPtr->x2)
 			|| (itemPtr->y1 >= itemPtr->y2)) {
 		    continue;
 		}
 		if (!gotAny) {
@@ -1147,11 +1163,11 @@
 	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);
+	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done);
 	if (itemPtr != NULL) {
 	    if (objc != 3) {
 		EventuallyRedrawItem(canvasPtr, itemPtr);
 	    }
 	    result = ItemCoords(canvasPtr, itemPtr, objc-3, objv+3);
@@ -1182,11 +1198,11 @@
 	 * modifications in the loop.
 	 */
 
 	tmpObj = Tcl_NewListObj(2, objv+4);
 
-	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto doneImove) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto doneImove) {
 	    int index;
 	    int x1,x2,y1,y2;
 	    int dontRedraw1,dontRedraw2;
 
 	    /*
@@ -1339,11 +1355,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if ((itemPtr->typePtr->indexProc == NULL)
 		    || (itemPtr->typePtr->dCharsProc == NULL)) {
 		continue;
 	    }
 	    result = ItemIndex(canvasPtr, itemPtr, objv[3], &first);
@@ -1382,11 +1398,11 @@
     case CANV_DELETE: {
 	int i;
 	Tcl_HashEntry *entryPtr;
 
 	for (i = 2; i < objc; i++) {
-	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, goto done) {
+	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[i], &searchPtr, suppressSmallItems, goto done) {
 		EventuallyRedrawItem(canvasPtr, itemPtr);
 		if (canvasPtr->bindingTable != NULL) {
 		    Tk_DeleteAllBindings(canvasPtr->bindingTable, itemPtr);
 		}
 		ItemDelete(canvasPtr, itemPtr);
@@ -1446,11 +1462,11 @@
 	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_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, 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--;
 		}
@@ -1484,11 +1500,11 @@
 	}
 	if (Tcl_GetString(objv[2])[0] == 0) {
 	    canvasPtr->textInfo.focusItemPtr = NULL;
 	    goto done;
 	}
-	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if (itemPtr->typePtr->icursorProc != NULL) {
 		break;
 	    }
 	}
 	if (itemPtr == NULL) {
@@ -1503,11 +1519,11 @@
 	if (objc != 3) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId");
 	    result = TCL_ERROR;
 	    goto done;
 	}
-	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
+	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done);
 	if (itemPtr != NULL) {
 	    int i;
 	    Tcl_Obj *resultObj = Tcl_NewObj();
 
 	    for (i = 0; i < itemPtr->numTags; i++) {
@@ -1523,11 +1539,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if ((itemPtr->typePtr->indexProc == NULL)
 		    || (itemPtr->typePtr->icursorProc == NULL)) {
 		goto done;
 	    }
 	    result = ItemIndex(canvasPtr, itemPtr, objv[3], &index);
@@ -1548,11 +1564,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if (itemPtr->typePtr->indexProc != NULL) {
 		break;
 	    }
 	}
 	if (itemPtr == NULL) {
@@ -1577,11 +1593,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if ((itemPtr->typePtr->indexProc == NULL)
 		    || (itemPtr->typePtr->insertProc == NULL)) {
 		continue;
 	    }
 	    result = ItemIndex(canvasPtr, itemPtr, objv[3], &beforeThis);
@@ -1613,11 +1629,11 @@
 	if (objc != 4) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId option");
 	    result = TCL_ERROR;
 	    goto done;
 	}
-	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
+	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done);
 	if (itemPtr != NULL) {
 	    result = ItemConfigValue(canvasPtr, itemPtr, objv[3]);
 	}
 	break;
     case CANV_ITEMCONFIGURE:
@@ -1624,11 +1640,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if (objc == 3) {
 		result = ItemConfigInfo(canvasPtr, itemPtr, NULL);
 	    } else if (objc == 4) {
 		result = ItemConfigInfo(canvasPtr, itemPtr, objv[3]);
 	    } else {
@@ -1656,11 +1672,11 @@
 	 */
 
 	if (objc == 3) {
 	    itemPtr = NULL;
 	} else {
-	    FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done);
+	    FIRST_CANVAS_ITEM_MATCHING(objv[3], &searchPtr,suppressSmallItems, 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);
@@ -1684,11 +1700,11 @@
 		&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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    EventuallyRedrawItem(canvasPtr, itemPtr);
 	    ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount);
 	    EventuallyRedrawItem(canvasPtr, itemPtr);
 	    canvasPtr->flags |= REPICK_NEEDED;
 	}
@@ -1721,11 +1737,11 @@
 		objv[4], &newY) != TCL_OK) {
 	    result = TCL_ERROR;
 	    goto done;
 	}
 
-	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
+	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done);
 	if (itemPtr != NULL) {
 	    oldX = itemPtr->x1;
 	    oldY = itemPtr->y1;
 
 	    /*
@@ -1746,11 +1762,11 @@
 
 	    /*
 	     * Move the object(s).
 	     */
 
-	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
+	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 		EventuallyRedrawItem(canvasPtr, itemPtr);
 		ItemTranslate(canvasPtr, itemPtr, xAmount, yAmount);
 		EventuallyRedrawItem(canvasPtr, itemPtr);
 		canvasPtr->flags |= REPICK_NEEDED;
 	    }
@@ -1781,11 +1797,11 @@
 
 	if (objc == 3) {
 	    prevPtr = canvasPtr->lastItemPtr;
 	} else {
 	    prevPtr = NULL;
-	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, goto done) {
+	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, suppressSmallItems, goto done) {
 		prevPtr = itemPtr;
 	    }
 	    if (prevPtr == NULL) {
 		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
 			"tagOrId \"%s\" doesn't match any items",
@@ -1805,11 +1821,11 @@
 	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) {
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    if ((itemPtr->typePtr->indexProc == NULL)
 		    || (itemPtr->typePtr->dCharsProc == NULL)
 		    || (itemPtr->typePtr->insertProc == NULL)) {
 		continue;
 	    }
@@ -1868,11 +1884,12 @@
 		    "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) {
+	suppressSmallItems = 0; /* All items must be considered when scaling */
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done) {
 	    EventuallyRedrawItem(canvasPtr, itemPtr);
 	    ItemScale(canvasPtr, itemPtr, xOrigin, yOrigin, xScale, yScale);
 	    EventuallyRedrawItem(canvasPtr, itemPtr);
 	    canvasPtr->flags |= REPICK_NEEDED;
 	}
@@ -1935,11 +1952,11 @@
 	    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) {
+	    FOR_EVERY_CANVAS_ITEM_MATCHING(objv[3], &searchPtr, suppressSmallItems, goto done) {
 		if ((itemPtr->typePtr->indexProc != NULL)
 			&& (itemPtr->typePtr->selectionProc != NULL)){
 		    break;
 		}
 	    }
@@ -2027,11 +2044,11 @@
 	if (objc != 3) {
 	    Tcl_WrongNumArgs(interp, 2, objv, "tag");
 	    result = TCL_ERROR;
 	    goto done;
 	}
-	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done);
+	FIRST_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, suppressSmallItems, goto done);
 	if (itemPtr != NULL) {
 	    Tcl_SetObjResult(interp,
 		    Tcl_NewStringObj(itemPtr->typePtr->name, -1));
 	}
 	break;
@@ -2435,11 +2452,11 @@
 {
     TkCanvas *canvasPtr = clientData;
     Tk_Window tkwin = canvasPtr->tkwin;
     Tk_Item *itemPtr;
     Pixmap pixmap;
-    int screenX1, screenX2, screenY1, screenY2, width, height;
+    int screenX1, screenX2, screenY1, screenY2, width, height, suppressSmallItems;
 
     if (canvasPtr->tkwin == NULL) {
 	return;
     }
 
@@ -2567,12 +2584,17 @@
 	 * 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).
 	 */
 
+	suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0);
+
 	for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL;
 		itemPtr = itemPtr->nextPtr) {
+	    if (suppressSmallItems && ((itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+		    continue;
+	    }
 	    if ((itemPtr->x1 >= screenX2)
 		    || (itemPtr->y1 >= screenY2)
 		    || (itemPtr->x2 < screenX1)
 		    || (itemPtr->y2 < screenY1)) {
 		if (!AlwaysRedraw(itemPtr)
@@ -3069,10 +3091,11 @@
     Tk_Uid uid;
     char *tag = Tcl_GetString(tagObj);
     int count;
     TkWindow *tkwin = (TkWindow *) canvasPtr->tkwin;
     TkDisplay *dispPtr = tkwin->dispPtr;
+    int suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0);
 
     /*
      * Initialize the search.
      */
 
@@ -3082,10 +3105,12 @@
     /*
      * 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.
+     *
+     * TODO: should we accept a numerical ID/tag even if the item is too small?
      */
 
     if (isdigit(UCHAR(*tag))) {
 	char *end;
 	Tcl_HashEntry *entryPtr;
@@ -3116,10 +3141,11 @@
 
     searchPtr->tag = uid = Tk_GetUid(tag);
     if (uid == Tk_GetUid("all")) {
 	/*
 	 * All items match.
+	 * TODO: how to implement the suppression?
 	 */
 
 	searchPtr->tag = NULL;
 	searchPtr->lastPtr = NULL;
 	searchPtr->currentPtr = canvasPtr->firstItemPtr;
@@ -3130,18 +3156,20 @@
      * 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;
-	    }
-	}
+	    if (!(suppressSmallItems && ((itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0))) {
+		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;
 }
@@ -3203,10 +3231,11 @@
 	itemPtr = lastPtr->nextPtr;
     }
 
     /*
      * Handle special case of "all" search by returning next item.
+     * TODO: how to implement the suppression?
      */
 
     uid = searchPtr->tag;
     if (uid == NULL) {
 	searchPtr->lastPtr = lastPtr;
@@ -3217,16 +3246,18 @@
     /*
      * 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;
+	if (!(suppressSmallItems && (entryPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+	   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;
@@ -3966,11 +3997,12 @@
  *--------------------------------------------------------------
  */
 
 static Tk_Item *
 TagSearchFirst(
-    TagSearch *searchPtr)	/* Record describing tag search */
+    TagSearch *searchPtr, 	/* Record describing tag search */
+    int suppressSmallItems)	/* Suppress items tagged as small? */
 {
     Tk_Item *itemPtr, *lastPtr;
     Tk_Uid uid, *tagPtr;
     int count;
 
@@ -3985,10 +4017,12 @@
     /*
      * 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.
+     *
+     * TODO: Accept an item given by its numerical ID, even if it is too small?
      */
 
     if (searchPtr->type == SEARCH_TYPE_ID) {
 	Tcl_HashEntry *entryPtr;
 
@@ -4028,16 +4062,18 @@
 	 */
 
 	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;
+	    if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+		for (tagPtr = itemPtr->tagPtr, count = itemPtr->numTags;
 		    count > 0; tagPtr++, count--) {
-		if (*tagPtr == uid) {
-		    searchPtr->lastPtr = lastPtr;
-		    searchPtr->currentPtr = itemPtr;
-		    return itemPtr;
+		    if (*tagPtr == uid) {
+			searchPtr->lastPtr = lastPtr;
+			searchPtr->currentPtr = itemPtr;
+			return itemPtr;
+		    }
 		}
 	    }
 	}
     } else {
 	/*
@@ -4044,15 +4080,17 @@
 	 * 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;
+	    if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+		searchPtr->expr->index = 0;
+		if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
+		    searchPtr->lastPtr = lastPtr;
+		    searchPtr->currentPtr = itemPtr;
+		    return itemPtr;
+		}
 	    }
 	}
     }
     searchPtr->lastPtr = lastPtr;
     searchPtr->searchOver = 1;
@@ -4080,11 +4118,12 @@
  *--------------------------------------------------------------
  */
 
 static Tk_Item *
 TagSearchNext(
-    TagSearch *searchPtr)	/* Record describing search in progress. */
+    TagSearch *searchPtr,	/* Record describing search in progress. */
+    int suppressSmallItems)	/* Suppress items tagged as small? */
 {
     Tk_Item *itemPtr, *lastPtr;
     Tk_Uid uid, *tagPtr;
     int count;
 
@@ -4130,16 +4169,18 @@
 	 * 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;
+	    if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+		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;
@@ -4150,14 +4191,16 @@
      * 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;
+	if (!(suppressSmallItems && (itemPtr->redraw_flags & TK_ITEM_SMALL_ITEM) != 0)) {
+	    if (TagSearchEvalExpr(searchPtr->expr, itemPtr)) {
+		searchPtr->lastPtr = lastPtr;
+		searchPtr->currentPtr = itemPtr;
+		return itemPtr;
+	   }
 	}
     }
     searchPtr->lastPtr = lastPtr;
     searchPtr->searchOver = 1;
     return NULL;
@@ -4283,11 +4326,11 @@
 #ifdef USE_OLD_TAG_SEARCH
     TagSearch search;
 #endif /* USE_OLD_TAG_SEARCH */
     Tk_Item *itemPtr;
     Tk_Uid uid;
-    int index, result;
+    int index, result, suppressSmallItems;
     Tcl_Obj *resultObj;
     static const char *const optionStrings[] = {
 	"above", "all", "below", "closest",
 	"enclosed", "overlapping", "withtag", NULL
     };
@@ -4303,19 +4346,22 @@
     }
     if (Tcl_GetIndexFromObj(interp, objv[first], optionStrings,
 	    "search command", 0, &index) != TCL_OK) {
 	return TCL_ERROR;
     }
+
+    suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0);
+
     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,
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems,
 		return TCL_ERROR) {
 	    lastPtr = itemPtr;
 	}
 	if ((lastPtr != NULL) && (lastPtr->nextPtr != NULL)) {
 	    resultObj = Tcl_NewObj();
@@ -4341,11 +4387,11 @@
     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,
+	FIRST_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems,
 		return TCL_ERROR);
 	if ((itemPtr != NULL) && (itemPtr->prevPtr != NULL)) {
 	    resultObj = Tcl_NewObj();
 	    DoItem(resultObj, itemPtr->prevPtr, uid);
 	    Tcl_SetObjResult(interp, resultObj);
@@ -4385,11 +4431,11 @@
 	 * Find the item at which to start the search.
 	 */
 
 	startPtr = canvasPtr->firstItemPtr;
 	if (objc == first+5) {
-	    FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr,
+	    FIRST_CANVAS_ITEM_MATCHING(objv[first+4], searchPtrPtr, suppressSmallItems,
 		    return TCL_ERROR);
 	    if (itemPtr != NULL) {
 		startPtr = itemPtr;
 	    }
 	}
@@ -4477,11 +4523,11 @@
 	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,
+	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[first+1], searchPtrPtr, suppressSmallItems,
 		goto badWithTagSearch) {
 	    DoItem(resultObj, itemPtr, uid);
 	}
 	Tcl_SetObjResult(interp, resultObj);
 	return TCL_OK;
@@ -4624,19 +4670,21 @@
 #ifdef USE_OLD_TAG_SEARCH
     TagSearch search;
 #endif /* USE_OLD_TAG_SEARCH */
     Tk_Item *firstMovePtr, *lastMovePtr;
     int result;
+    int suppressSmallItems;
 
     /*
      * 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.
      */
+    suppressSmallItems = ((canvasPtr->flags & SUPPRESS_SMALL_ITEMS) != 0);
 
     firstMovePtr = lastMovePtr = NULL;
-    FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, return TCL_ERROR) {
+    FOR_EVERY_CANVAS_ITEM_MATCHING(tag, searchPtrPtr, suppressSmallItems, return TCL_ERROR) {
 	if (itemPtr == prevPtr) {
 	    /*
 	     * Item after which insertion is to occur is being moved! Switch
 	     * to insert after its predecessor.
 	     */
@@ -5954,13 +6002,103 @@
 				 * coordinates giving points for path. */
     int numPoints)		/* Number of points at *coordPtr. */
 {
     Tk_PostscriptPath(interp, Canvas(canvas)->psInfo, coordPtr, numPoints);
 }
+
+/*
+ *--------------------------------------------------------------
+ *
+ * SuppressSmallItemsParseProc --
+ *
+ *	Parse the -suppresssmallitems option
+ *
+ * Results:
+ *	A standard Tcl return value
+ *
+ * Side effects:
+ *	The flag for suppressing the drawing of small items is set
+ *	or cleared
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+SuppressSmallItemsParseProc(
+    ClientData clientData,	/* Not used.*/
+    Tcl_Interp *interp,		/* Used for reporting errors. */
+    Tk_Window tkwin,		/* Window containing canvas widget. */
+    const char *value,		/* Value of option (boolean value). */
+    char *widgRec,		/* Pointer to record in canvas. */
+    int offset)			/* Offset into the widget structure. */
+{
+    int optionValue;
+    int *canvasFlags = (int *)(widgRec+offset);
+
+    /*
+     * Parse the given string as a boolean value and store the
+     * result as a bit flag
+     */
+
+    if (Tcl_GetBoolean(interp, value, &optionValue) != TCL_OK) {
+        return TCL_ERROR;
+    }
+
+    if (optionValue) {
+        (*canvasFlags) |= SUPPRESS_SMALL_ITEMS;
+    } else {
+        (*canvasFlags) &= ~SUPPRESS_SMALL_ITEMS;
+    }
+    return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * SuppressSmallItemsPrintProc --
+ *
+ *      This function is invoked by the Tk configuration code to produce a
+ *      printable string for the "-suppresssmallitems" configuration option
+ *      for the canvas itself.
+ *
+ * Results:
+ *      The return value is a string "1" or "0", depending on the value.
+ *
+ * Side effects:
+ *      None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static const char *
+SuppressSmallItemsPrintProc(
+    ClientData clientData,	/* Ignored. */
+    Tk_Window tkwin,		/* Window containing canvas widget. */
+    char *widgRec,		/* Pointer to record for item. */
+    int offset,			/* Offset into the widget structure. */
+    Tcl_FreeProc **freeProcPtr)	/* Pointer to variable to fill in with
+				 * information about how to reclaim storage
+				 * for return string. */
+{
+    int *canvasFlags = (int *)(widgRec+offset);
+
+    FILE *outf;
+    outf = fopen( "arjen.out", "w" );
+    fprintf( outf, "Flags: %p\n", canvasFlags );
+    fclose( outf );
+
+    *freeProcPtr = TCL_STATIC;
+
+    if ((*canvasFlags) & SUPPRESS_SMALL_ITEMS) {
+        return "1";
+    } else {
+        return "0";
+    }
+}
 
 /*
  * Local Variables:
  * mode: c
  * c-basic-offset: 4
  * fill-column: 78
  * End:
  */

Index: generic/tkCanvas.h
==================================================================
--- generic/tkCanvas.h
+++ generic/tkCanvas.h
@@ -260,10 +260,12 @@
  * REPICK_IN_PROGRESS -		1 means PickCurrentItem is currently
  *				executing. If it should be called recursively,
  *				it should simply return immediately.
  * BBOX_NOT_EMPTY -		1 means that the bounding box of the area that
  *				should be redrawn is not empty.
+ * HIDE_SMALL_ITEMS -		1 means that items smaller than 2 pixels are
+ *				not drawn (performance improvement).
  */
 
 #define REDRAW_PENDING		1
 #define REDRAW_BORDERS		2
 #define REPICK_NEEDED		4
@@ -271,10 +273,11 @@
 #define CURSOR_ON		0x10
 #define UPDATE_SCROLLBARS	0x20
 #define LEFT_GRABBED_ITEM	0x40
 #define REPICK_IN_PROGRESS	0x100
 #define BBOX_NOT_EMPTY		0x200
+#define SUPPRESS_SMALL_ITEMS		0x400
 
 /*
  * Flag bits for canvas items (redraw_flags):
  *
  * FORCE_REDRAW -		1 means that the new coordinates of some item

Index: generic/tkRectOval.c
==================================================================
--- generic/tkRectOval.c
+++ generic/tkRectOval.c
@@ -624,10 +624,16 @@
     RectOvalItem *rectOvalPtr)	/* Item whose bbox is to be recomputed. */
 {
     int bloat, tmp;
     double dtmp, width;
     Tk_State state = rectOvalPtr->header.state;
+
+    if ( (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0] ) < 2  || (rectOvalPtr->bbox[3] - rectOvalPtr->bbox[1] ) < 2  ) {
+	rectOvalPtr->header.redraw_flags |= TK_ITEM_SMALL_ITEM;
+    } else {
+	rectOvalPtr->header.redraw_flags &= ~TK_ITEM_SMALL_ITEM;
+    }
 
     if (state == TK_STATE_NULL) {
 	state = Canvas(canvas)->canvas_state;
     }
 
@@ -1223,10 +1229,11 @@
 
     rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX);
     rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY);
     rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX);
     rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY);
+
     ComputeRectOvalBbox(canvas, rectOvalPtr);
 }
 
 /*
  *--------------------------------------------------------------