summaryrefslogtreecommitdiffstats
path: root/generic/tkTreeCtrl.c
diff options
context:
space:
mode:
authortreectrl <treectrl>2006-10-18 22:21:16 (GMT)
committertreectrl <treectrl>2006-10-18 22:21:16 (GMT)
commit68cd6a827d8e55c4798902dae979e518dddc1dbd (patch)
tree83e7408bea2f388740d9ab67a79f917325f71fcf /generic/tkTreeCtrl.c
parentdd26f4fc3ee310adaa5d80ecbe0ee40f95705187 (diff)
downloadtktreectrl-68cd6a827d8e55c4798902dae979e518dddc1dbd.zip
tktreectrl-68cd6a827d8e55c4798902dae979e518dddc1dbd.tar.gz
tktreectrl-68cd6a827d8e55c4798902dae979e518dddc1dbd.tar.bz2
Tree_GetImage now uses reference counting on images. Tree_FreeImage decrements the reference count and frees the image when needed.
Diffstat (limited to 'generic/tkTreeCtrl.c')
-rw-r--r--generic/tkTreeCtrl.c100
1 files changed, 80 insertions, 20 deletions
diff --git a/generic/tkTreeCtrl.c b/generic/tkTreeCtrl.c
index 8bb2d93..a788e77 100644
--- a/generic/tkTreeCtrl.c
+++ b/generic/tkTreeCtrl.c
@@ -7,7 +7,7 @@
* Copyright (c) 2002-2003 Christian Krone
* Copyright (c) 2003-2005 ActiveState, a division of Sophos
*
- * RCS: @(#) $Id: tkTreeCtrl.c,v 1.71 2006/10/16 01:17:22 treectrl Exp $
+ * RCS: @(#) $Id: tkTreeCtrl.c,v 1.72 2006/10/18 22:21:16 treectrl Exp $
*/
#include "tkTreeCtrl.h"
@@ -34,6 +34,13 @@
#define TK_PHOTOPUTZOOMEDBLOCK Tk_PhotoPutZoomedBlock
#endif
+/* This structure is used for reference-counted images. */
+typedef struct TreeImageRef {
+ int count; /* Reference count. */
+ Tk_Image image; /* Image token. */
+ Tcl_HashEntry *hPtr; /* Entry in tree->imageNameHash. */
+} TreeImageRef;
+
static CONST char *bgModeST[] = {
"column", "order", "ordervisible", "row", "index", "visindex", (char *) NULL
};
@@ -376,7 +383,8 @@ TreeObjCmd(
Tcl_InitHashTable(&tree->itemHash, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&tree->elementHash, TCL_STRING_KEYS);
Tcl_InitHashTable(&tree->styleHash, TCL_STRING_KEYS);
- Tcl_InitHashTable(&tree->imageHash, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tree->imageNameHash, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tree->imageTokenHash, TCL_ONE_WORD_KEYS);
TreeItemList_Init(tree, &tree->preserveItemList, 0);
@@ -1223,7 +1231,10 @@ TreeConfigure(
*/
if (mask & TREE_CONF_BG_IMAGE) {
- tree->backgroundImage = NULL;
+ if (tree->backgroundImage != NULL) {
+ Tree_FreeImage(tree, tree->backgroundImage);
+ tree->backgroundImage = NULL;
+ }
if (tree->backgroundImageString != NULL) {
Tk_Image image = Tree_GetImage(tree, tree->backgroundImageString);
if (image == NULL)
@@ -1624,7 +1635,6 @@ TreeDestroy(
TreeItem item;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
- Tk_Image image;
int i;
hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
@@ -1637,14 +1647,6 @@ TreeDestroy(
TreeItemList_Free(&tree->preserveItemList);
- hPtr = Tcl_FirstHashEntry(&tree->imageHash, &search);
- while (hPtr != NULL) {
- image = (Tk_Image) Tcl_GetHashValue(hPtr);
- Tk_FreeImage(image);
- hPtr = Tcl_NextHashEntry(&search);
- }
- Tcl_DeleteHashTable(&tree->imageHash);
-
TreeStyle_Free(tree);
TreeDragImage_Free(tree->dragImage);
@@ -1673,6 +1675,16 @@ TreeDestroy(
Tk_FreeConfigOptions((char *) tree, tree->optionTable, tree->tkwin);
+ hPtr = Tcl_FirstHashEntry(&tree->imageNameHash, &search);
+ while (hPtr != NULL) {
+ TreeImageRef *ref = (TreeImageRef *) Tcl_GetHashValue(hPtr);
+ Tk_FreeImage(ref->image);
+ ckfree((char *) ref->image);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_DeleteHashTable(&tree->imageNameHash);
+ Tcl_DeleteHashTable(&tree->imageTokenHash);
+
Tcl_DeleteHashTable(&tree->selection);
#ifdef ALLOC_HAX
@@ -1944,8 +1956,8 @@ ImageChangedProc(
* the same image to be used hundreds of times (a folder image for
* example) and want to avoid allocating an instance for every usage.
*
- * Any image instances created by this procedure are not freed until
- * the widget is destroyed.
+ * For each call to this function, there must be a matching call
+ * to Tree_FreeImage.
*
* Results:
* Token for the image instance. If an error occurs the result is
@@ -1963,11 +1975,12 @@ Tree_GetImage(
char *imageName /* Name of an existing image. */
)
{
- Tcl_HashEntry *hPtr;
+ Tcl_HashEntry *hPtr, *h2Ptr;
+ TreeImageRef *ref;
Tk_Image image;
int isNew;
- hPtr = Tcl_CreateHashEntry(&tree->imageHash, imageName, &isNew);
+ hPtr = Tcl_CreateHashEntry(&tree->imageNameHash, imageName, &isNew);
if (isNew) {
image = Tk_GetImage(tree->interp, tree->tkwin, imageName,
ImageChangedProc, (ClientData) tree);
@@ -1975,9 +1988,57 @@ Tree_GetImage(
Tcl_DeleteHashEntry(hPtr);
return NULL;
}
- Tcl_SetHashValue(hPtr, image);
+ ref = (TreeImageRef *) ckalloc(sizeof(TreeImageRef));
+ ref->count = 0;
+ ref->image = image;
+ ref->hPtr = hPtr;
+ Tcl_SetHashValue(hPtr, ref);
+
+ h2Ptr = Tcl_CreateHashEntry(&tree->imageTokenHash, (char *) image,
+ &isNew);
+ Tcl_SetHashValue(h2Ptr, ref);
+ }
+ ref = (TreeImageRef *) Tcl_GetHashValue(hPtr);
+ ref->count++;
+ return ref->image;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tree_FreeImage --
+ *
+ * Decrement the reference count on an image.
+ *
+ * Results:
+ * If the reference count hits zero, frees the image instance and
+ * hash table entries.
+ *
+ * Side effects:
+ * Memory may be freed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tree_FreeImage(
+ TreeCtrl *tree, /* Widget info. */
+ Tk_Image image /* Image token. */
+ )
+{
+ Tcl_HashEntry *hPtr;
+ TreeImageRef *ref;
+
+ hPtr = Tcl_FindHashEntry(&tree->imageTokenHash, (char *) image);
+ if (hPtr != NULL) {
+ ref = (TreeImageRef *) Tcl_GetHashValue(hPtr);
+ if (--ref->count == 0) {
+ Tcl_DeleteHashEntry(ref->hPtr); /* imageNameHash */
+ Tcl_DeleteHashEntry(hPtr);
+ Tk_FreeImage(ref->image);
+ ckfree((char *) ref);
+ }
}
- return (Tk_Image) Tcl_GetHashValue(hPtr);
}
/*
@@ -3145,8 +3206,7 @@ TreeDebugCmd(
case COMMAND_ALLOC:
{
#ifdef TREECTRL_DEBUG
- char *buf = AllocHax_Stats(tree->allocData);
- Tcl_SetResult(interp, buf, TCL_DYNAMIC);
+ AllocHax_Stats(interp, tree->allocData);
#else
FormatResult(interp, "TREECTRL_DEBUG is not defined");
#endif