head	1.3;
access;
symbols
	core-8-5-9:1.1.4.1
	core-8-5-8:1.1
	macosx-cocoa-merge:1.3
	macosx-cocoa-premerge:1.3
	macosx-carbon-freeze:1.3
	core-8-5-7:1.1
	core-8-5-6:1.1
	core-8-6-b1:1.1
	core-8-6-a3:1.1
	core-8-5-5:1.1
	core-8-6-a2:1.1
	core-8-5-4:1.1
	core-8-5-3:1.1
	core-8-6-a1:1.1
	core-8-5-branch:1.1.0.4
	core-8-5-2:1.1
	core-8-5-1:1.1
	core-8-5-0:1.1
	core-8-5-b3:1.1
	core-8-5-b2:1.1
	core-8-5-b1:1.1
	core-stablilizer-merge:1.1
	core-stabilizer-branch:1.1.0.2
	core-stabilizer-merge:1.1
	core-8-5-a6:1.1;
locks; strict;
comment	@ * @;


1.3
date	2009.02.08.19.35.35;	author jenglish;	state Exp;
branches;
next	1.2;

1.2
date	2009.01.28.20.47.49;	author nijtmans;	state Exp;
branches;
next	1.1;

1.1
date	2006.10.31.01.42.26;	author hobbs;	state Exp;
branches
	1.1.4.1;
next	;

1.1.4.1
date	2010.08.26.02.06.09;	author hobbs;	state Exp;
branches;
next	;


desc
@@


1.3
log
@Renamed several internal data structures and functions:
ElementImpl -> ElementClass, LayoutNode -> Element.
Remove more unnecessary casts.
Add function Ttk_ClientRegion, common factor
of entry, scale, progress, and treeview widgets.
@
text
@/*
 * $Id: ttkCache.c,v 1.2 2009/01/28 20:47:49 nijtmans Exp $
 *      Theme engine resource cache.
 *
 * Copyright (c) 2004, Joe English
 *
 * The problem:
 *
 * Tk maintains reference counts for fonts, colors, and images,
 * and deallocates them when the reference count goes to zero.
 * With the theme engine, resources are allocated right before
 * drawing an element and released immediately after.
 * This causes a severe performance penalty, and on PseudoColor
 * visuals it causes colormap cycling as colormap entries are
 * released and reused.
 *
 * Solution: Acquire fonts, colors, and objects from a
 * resource cache instead of directly from Tk; the cache
 * holds a semipermanent reference to the resource to keep
 * it from being deallocated.
 *
 * The plumbing and control flow here is quite contorted;
 * it would be better to address this problem in the core instead.
 *
 * @@@@@@ BUGS/TODO: Need distinct caches for each combination
 * of display, visual, and colormap.
 *
 * @@@@@@ Colormap flashing on PseudoColor visuals is still possible,
 * but this will be a transient effect.
 */

#include <stdio.h>	/* for sprintf */
#include <tk.h>
#include "ttkTheme.h"

struct Ttk_ResourceCache_ {
    Tcl_Interp	  *interp;	/* Interpreter for error reporting */
    Tk_Window	  tkwin;	/* Cache window. */
    Tcl_HashTable fontTable;	/* Entries: Tcl_Obj* holding FontObjs */
    Tcl_HashTable colorTable;	/* Entries: Tcl_Obj* holding ColorObjs */
    Tcl_HashTable borderTable;	/* Entries: Tcl_Obj* holding BorderObjs */
    Tcl_HashTable imageTable;	/* Entries: Tk_Images */

    Tcl_HashTable namedColors;	/* Entries: RGB values as Tcl_StringObjs */
};

/*
 * Ttk_CreateResourceCache --
 * 	Initialize a new resource cache.
 */
Ttk_ResourceCache Ttk_CreateResourceCache(Tcl_Interp *interp)
{
    Ttk_ResourceCache cache = (Ttk_ResourceCache)ckalloc(sizeof(*cache));

    cache->tkwin = NULL;	/* initialized later */
    cache->interp = interp;
    Tcl_InitHashTable(&cache->fontTable, TCL_STRING_KEYS);
    Tcl_InitHashTable(&cache->colorTable, TCL_STRING_KEYS);
    Tcl_InitHashTable(&cache->borderTable, TCL_STRING_KEYS);
    Tcl_InitHashTable(&cache->imageTable, TCL_STRING_KEYS);
    Tcl_InitHashTable(&cache->namedColors, TCL_STRING_KEYS);

    return cache;
}

/*
 * Ttk_ClearCache --
 * 	Release references to all cached resources.
 */
static void Ttk_ClearCache(Ttk_ResourceCache cache)
{
    Tcl_HashSearch search;
    Tcl_HashEntry *entryPtr;

    /*
     * Free fonts:
     */
    entryPtr = Tcl_FirstHashEntry(&cache->fontTable, &search);
    while (entryPtr != NULL) {
	Tcl_Obj *fontObj = Tcl_GetHashValue(entryPtr);
	if (fontObj) {
	    Tk_FreeFontFromObj(cache->tkwin, fontObj);
	    Tcl_DecrRefCount(fontObj);
	}
	entryPtr = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(&cache->fontTable);
    Tcl_InitHashTable(&cache->fontTable, TCL_STRING_KEYS);

    /*
     * Free colors:
     */
    entryPtr = Tcl_FirstHashEntry(&cache->colorTable, &search);
    while (entryPtr != NULL) {
	Tcl_Obj *colorObj = Tcl_GetHashValue(entryPtr);
	if (colorObj) {
	    Tk_FreeColorFromObj(cache->tkwin, colorObj);
	    Tcl_DecrRefCount(colorObj);
	}
	entryPtr = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(&cache->colorTable);
    Tcl_InitHashTable(&cache->colorTable, TCL_STRING_KEYS);

    /*
     * Free borders:
     */
    entryPtr = Tcl_FirstHashEntry(&cache->borderTable, &search);
    while (entryPtr != NULL) {
	Tcl_Obj *borderObj = Tcl_GetHashValue(entryPtr);
	if (borderObj) {
	    Tk_Free3DBorderFromObj(cache->tkwin, borderObj);
	    Tcl_DecrRefCount(borderObj);
	}
	entryPtr = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(&cache->borderTable);
    Tcl_InitHashTable(&cache->borderTable, TCL_STRING_KEYS);

    /*
     * Free images:
     */
    entryPtr = Tcl_FirstHashEntry(&cache->imageTable, &search);
    while (entryPtr != NULL) {
	Tk_Image image = Tcl_GetHashValue(entryPtr);
	if (image) {
	    Tk_FreeImage(image);
	}
	entryPtr = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(&cache->imageTable);
    Tcl_InitHashTable(&cache->imageTable, TCL_STRING_KEYS);

    return;
}

/*
 * Ttk_FreeResourceCache --
 * 	Release references to all cached resources, delete the cache.
 */

void Ttk_FreeResourceCache(Ttk_ResourceCache cache)
{
    Tcl_HashEntry *entryPtr;
    Tcl_HashSearch search;

    Ttk_ClearCache(cache);

    Tcl_DeleteHashTable(&cache->colorTable);
    Tcl_DeleteHashTable(&cache->fontTable);
    Tcl_DeleteHashTable(&cache->imageTable);

    /*
     * Free named colors:
     */
    entryPtr = Tcl_FirstHashEntry(&cache->namedColors, &search);
    while (entryPtr != NULL) {
	Tcl_Obj *colorNameObj = Tcl_GetHashValue(entryPtr);
	Tcl_DecrRefCount(colorNameObj);
	entryPtr = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(&cache->namedColors);

    ckfree((ClientData)cache);
}

/*
 * CacheWinEventHandler --
 * 	Detect when the cache window is destroyed, clear cache.
 */
static void CacheWinEventHandler(ClientData clientData, XEvent *eventPtr)
{
    Ttk_ResourceCache cache = clientData;

    if (eventPtr->type != DestroyNotify) {
	return;
    }
    Tk_DeleteEventHandler(cache->tkwin, StructureNotifyMask,
	    CacheWinEventHandler, clientData);
    Ttk_ClearCache(cache);
    cache->tkwin = NULL;
}

/*
 * InitCacheWindow --
 * 	Specify the cache window if not already set.
 * 	@@@@@@ SHOULD: use separate caches for each combination
 * 	@@@@@@ of display, visual, and colormap.
 */
static void InitCacheWindow(Ttk_ResourceCache cache, Tk_Window tkwin)
{
    if (cache->tkwin == NULL) {
	cache->tkwin = tkwin;
	Tk_CreateEventHandler(tkwin, StructureNotifyMask,
		CacheWinEventHandler, cache);
    }
}

/*
 * Ttk_RegisterNamedColor --
 *	Specify an RGB triplet as a named color.
 *	Overrides any previous named color specification.
 */
void Ttk_RegisterNamedColor(
    Ttk_ResourceCache cache,
    const char *colorName,
    XColor *colorPtr)
{
    int newEntry;
    Tcl_HashEntry *entryPtr;
    char nameBuf[14];
    Tcl_Obj *colorNameObj;

    sprintf(nameBuf, "#%04X%04X%04X",
    	colorPtr->red, colorPtr->green, colorPtr->blue);
    colorNameObj = Tcl_NewStringObj(nameBuf, -1);
    Tcl_IncrRefCount(colorNameObj);

    entryPtr = Tcl_CreateHashEntry(&cache->namedColors, colorName, &newEntry);
    if (!newEntry) {
    	Tcl_Obj *oldColor = Tcl_GetHashValue(entryPtr);
	Tcl_DecrRefCount(oldColor);
    }

    Tcl_SetHashValue(entryPtr, colorNameObj);
}

/*
 * CheckNamedColor(objPtr) --
 *	If objPtr is a registered color name, return a Tcl_Obj *
 *	containing the registered color value specification.
 *	Otherwise, return the input argument.
 */
static Tcl_Obj *CheckNamedColor(Ttk_ResourceCache cache, Tcl_Obj *objPtr)
{
    Tcl_HashEntry *entryPtr =
    	Tcl_FindHashEntry(&cache->namedColors, Tcl_GetString(objPtr));
    if (entryPtr) {	/* Use named color instead */
    	objPtr = Tcl_GetHashValue(entryPtr);
    }
    return objPtr;
}

/*
 * Template for allocation routines:
 */
typedef void *(*Allocator)(Tcl_Interp *, Tk_Window, Tcl_Obj *);

static Tcl_Obj *Ttk_Use(
    Tcl_Interp *interp,
    Tcl_HashTable *table,
    Allocator allocate,
    Tk_Window tkwin,
    Tcl_Obj *objPtr)
{
    int newEntry;
    Tcl_HashEntry *entryPtr =
	Tcl_CreateHashEntry(table,Tcl_GetString(objPtr),&newEntry);
    Tcl_Obj *cacheObj;

    if (!newEntry) {
	return Tcl_GetHashValue(entryPtr);
    }

    cacheObj = Tcl_DuplicateObj(objPtr);
    Tcl_IncrRefCount(cacheObj);

    if (allocate(interp, tkwin, cacheObj)) {
	Tcl_SetHashValue(entryPtr, cacheObj);
	return cacheObj;
    } else {
	Tcl_DecrRefCount(cacheObj);
	Tcl_SetHashValue(entryPtr, NULL);
	Tcl_BackgroundError(interp);
	return NULL;
    }
}

/*
 * Ttk_UseFont --
 * 	Acquire a font from the cache.
 */
Tcl_Obj *Ttk_UseFont(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
    InitCacheWindow(cache, tkwin);
    return Ttk_Use(cache->interp,
	&cache->fontTable,(Allocator)Tk_AllocFontFromObj, tkwin, objPtr);
}

/*
 * Ttk_UseColor --
 * 	Acquire a color from the cache.
 */
Tcl_Obj *Ttk_UseColor(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
    objPtr = CheckNamedColor(cache, objPtr);
    InitCacheWindow(cache, tkwin);
    return Ttk_Use(cache->interp,
	&cache->colorTable,(Allocator)Tk_AllocColorFromObj, tkwin, objPtr);
}

/*
 * Ttk_UseBorder --
 * 	Acquire a Tk_3DBorder from the cache.
 */
Tcl_Obj *Ttk_UseBorder(
    Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
    objPtr = CheckNamedColor(cache, objPtr);
    InitCacheWindow(cache, tkwin);
    return Ttk_Use(cache->interp,
	&cache->borderTable,(Allocator)Tk_Alloc3DBorderFromObj, tkwin, objPtr);
}

/* NullImageChanged --
 * 	Tk_ImageChangedProc for Ttk_UseImage
 */

static void NullImageChanged(ClientData clientData,
    int x, int y, int width, int height, int imageWidth, int imageHeight)
{ /* No-op */ }

/*
 * Ttk_UseImage --
 * 	Acquire a Tk_Image from the cache.
 */
Tk_Image Ttk_UseImage(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr)
{
    const char *imageName = Tcl_GetString(objPtr);
    int newEntry;
    Tcl_HashEntry *entryPtr =
	Tcl_CreateHashEntry(&cache->imageTable,imageName,&newEntry);
    Tk_Image image;

    InitCacheWindow(cache, tkwin);

    if (!newEntry) {
	return Tcl_GetHashValue(entryPtr);
    }

    image = Tk_GetImage(cache->interp, tkwin, imageName, NullImageChanged,0);
    Tcl_SetHashValue(entryPtr, image);

    if (!image) {
	Tcl_BackgroundError(cache->interp);
    }

    return image;
}

/*EOF*/
@


1.2
log
@- eliminate some unnessary type casts
- some internal const decorations
- spacing
@
text
@d2 2
a3 2
 * $Id: ttkCache.c,v 1.1 2006/10/31 01:42:26 hobbs Exp $
 *      Ttk theme engine, resource cache.
d80 1
a80 1
	Tcl_Obj *fontObj = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d95 1
a95 1
	Tcl_Obj *colorObj = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d110 1
a110 1
	Tcl_Obj *borderObj = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d125 1
a125 1
	Tk_Image image = (Tk_Image)Tcl_GetHashValue(entryPtr);
d158 1
a158 1
	Tcl_Obj *colorNameObj = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d173 1
a173 1
    Ttk_ResourceCache cache = (Ttk_ResourceCache)clientData;
d195 1
a195 1
		CacheWinEventHandler, (ClientData)cache);
a202 1
 *
d221 1
a221 1
    	Tcl_Obj *oldColor = (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d239 1
a239 1
    	objPtr = (Tcl_Obj *)Tcl_GetHashValue(entryPtr);
d262 1
a262 1
	return (Tcl_Obj*)Tcl_GetHashValue(entryPtr);
d338 1
a338 1
	return (Tk_Image)Tcl_GetHashValue(entryPtr);
@


1.1
log
@	* doc/ttk_Geometry.3, doc/ttk_Theme.3, doc/ttk_button.n:
	* doc/ttk_checkbutton.n, doc/ttk_combobox.n, doc/ttk_dialog.n:
	* doc/ttk_entry.n, doc/ttk_frame.n, doc/ttk_image.n:
	* doc/ttk_intro.n, doc/ttk_label.n, doc/ttk_labelframe.n:
	* doc/ttk_menubutton.n, doc/ttk_notebook.n, doc/ttk_panedwindow.n:
	* doc/ttk_progressbar.n, doc/ttk_radiobutton.n, doc/ttk_scrollbar.n:
	* doc/ttk_separator.n, doc/ttk_sizegrip.n, doc/ttk_style.n:
	* doc/ttk_treeview.n, doc/ttk_widget.n,:
	* generic/ttk/ttk.decls, generic/ttk/ttkBlink.c:
	* generic/ttk/ttkButton.c, generic/ttk/ttkCache.c:
	* generic/ttk/ttkClamTheme.c, generic/ttk/ttkClassicTheme.c:
	* generic/ttk/ttkDecls.h, generic/ttk/ttkDefaultTheme.c:
	* generic/ttk/ttkElements.c, generic/ttk/ttkEntry.c:
	* generic/ttk/ttkFrame.c, generic/ttk/ttkImage.c:
	* generic/ttk/ttkInit.c, generic/ttk/ttkLabel.c:
	* generic/ttk/ttkLayout.c, generic/ttk/ttkManager.c:
	* generic/ttk/ttkManager.h, generic/ttk/ttkNotebook.c:
	* generic/ttk/ttkPanedwindow.c, generic/ttk/ttkProgress.c:
	* generic/ttk/ttkScale.c, generic/ttk/ttkScroll.c:
	* generic/ttk/ttkScrollbar.c, generic/ttk/ttkSeparator.c:
	* generic/ttk/ttkSquare.c, generic/ttk/ttkState.c:
	* generic/ttk/ttkStubInit.c, generic/ttk/ttkStubLib.c:
	* generic/ttk/ttkTagSet.c, generic/ttk/ttkTheme.c:
	* generic/ttk/ttkTheme.h, generic/ttk/ttkThemeInt.h:
	* generic/ttk/ttkTrace.c, generic/ttk/ttkTrack.c:
	* generic/ttk/ttkTreeview.c, generic/ttk/ttkWidget.c:
	* generic/ttk/ttkWidget.h:
	* library/demos/ttk_demo.tcl, library/demos/ttk_iconlib.tcl:
	* library/demos/ttk_repeater.tcl:
	* library/ttk/altTheme.tcl, library/ttk/aquaTheme.tcl:
	* library/ttk/button.tcl, library/ttk/clamTheme.tcl:
	* library/ttk/classicTheme.tcl, library/ttk/combobox.tcl:
	* library/ttk/cursors.tcl, library/ttk/defaults.tcl:
	* library/ttk/dialog.tcl, library/ttk/entry.tcl:
	* library/ttk/fonts.tcl, library/ttk/icons.tcl:
	* library/ttk/keynav.tcl, library/ttk/menubutton.tcl:
	* library/ttk/notebook.tcl, library/ttk/panedwindow.tcl:
	* library/ttk/progress.tcl, library/ttk/scale.tcl:
	* library/ttk/scrollbar.tcl, library/ttk/sizegrip.tcl:
	* library/ttk/treeview.tcl, library/ttk/ttk.tcl:
	* library/ttk/utils.tcl, library/ttk/winTheme.tcl:
	* library/ttk/xpTheme.tcl:
	* macosx/ttkMacOSXTheme.c:
	* tests/ttk/all.tcl, tests/ttk/bwidget.test, tests/ttk/combobox.test:
	* tests/ttk/entry.test, tests/ttk/image.test:
	* tests/ttk/labelframe.test, tests/ttk/layout.test:
	* tests/ttk/misc.test, tests/ttk/notebook.test:
	* tests/ttk/panedwindow.test, tests/ttk/progressbar.test:
	* tests/ttk/scrollbar.test, tests/ttk/treetags.test:
	* tests/ttk/treeview.test, tests/ttk/ttk.test, tests/ttk/validate.test:
	* win/ttkWinMonitor.c, win/ttkWinTheme.c, win/ttkWinXPTheme.c:
	First import of Ttk themed Tk widgets as branched from tile 0.7.8

	* generic/tkInt.h, generic/tkWindow.c: add Ttk_Init call, copy
	tk classic widgets to ::tk namespace.
	* library/tk.tcl: add source of ttk/ttk.tcl, define $::ttk::library.
	* unix/Makefile.in, win/Makefile.in: add Ttk build bits
	* win/configure, win/configure.in: check for uxtheme.h (XP theme).
@
text
@d2 1
a2 1
 * $Id: cache.c,v 1.10 2005/06/26 16:28:00 jenglish Exp $
d144 1
a144 1
    Tcl_HashEntry *entryPtr; 
d203 1
a203 1
 *	
d206 1
a206 1
    Ttk_ResourceCache cache, 
d215 1
a215 1
    sprintf(nameBuf, "#%04X%04X%04X", 
d226 1
a226 1
    Tcl_SetHashValue(entryPtr, (ClientData)colorNameObj);
d237 1
a237 1
    Tcl_HashEntry *entryPtr = 
d252 1
a252 1
    Tcl_HashTable *table, 
@


1.1.4.1
log
@        Major backport of 8.6 Ttk for 8.5.9.  Most changes were only being
        committed to head (8.6), although they could apply for 8.5 as well.
        This re-sync makes future work easier to maintain and adds some
        useful work for 8.5 users. Notable changes:
        - Lots of code cleanup
        - Some bug fixes never backported
        - Addition of ttk::spinbox
        - minor color changes
        - Improved Vista/7 styling
        - Move to tile version 0.8.6 (pseudo-package)
        - ABI and API compatible (even $w identify)
        - minor new features (extended $w identify)
@
text
@d2 2
a3 2
 * $Id: ttkCache.c,v 1.3 2009/02/08 19:35:35 jenglish Exp $
 *      Theme engine resource cache.
d80 1
a80 1
	Tcl_Obj *fontObj = Tcl_GetHashValue(entryPtr);
d95 1
a95 1
	Tcl_Obj *colorObj = Tcl_GetHashValue(entryPtr);
d110 1
a110 1
	Tcl_Obj *borderObj = Tcl_GetHashValue(entryPtr);
d125 1
a125 1
	Tk_Image image = Tcl_GetHashValue(entryPtr);
d144 1
a144 1
    Tcl_HashEntry *entryPtr;
d158 1
a158 1
	Tcl_Obj *colorNameObj = Tcl_GetHashValue(entryPtr);
d173 1
a173 1
    Ttk_ResourceCache cache = clientData;
d195 1
a195 1
		CacheWinEventHandler, cache);
d203 1
d206 1
a206 1
    Ttk_ResourceCache cache,
d215 1
a215 1
    sprintf(nameBuf, "#%04X%04X%04X",
d222 1
a222 1
    	Tcl_Obj *oldColor = Tcl_GetHashValue(entryPtr);
d226 1
a226 1
    Tcl_SetHashValue(entryPtr, colorNameObj);
d237 1
a237 1
    Tcl_HashEntry *entryPtr =
d240 1
a240 1
    	objPtr = Tcl_GetHashValue(entryPtr);
d252 1
a252 1
    Tcl_HashTable *table,
d263 1
a263 1
	return Tcl_GetHashValue(entryPtr);
d339 1
a339 1
	return Tcl_GetHashValue(entryPtr);
@


