summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkStyle.c3326
1 files changed, 1663 insertions, 1663 deletions
diff --git a/generic/tkStyle.c b/generic/tkStyle.c
index bb48e21..30ad2f8 100644
--- a/generic/tkStyle.c
+++ b/generic/tkStyle.c
@@ -1,1663 +1,1663 @@
-/*
- * tkStyle.c --
- *
- * This file implements the widget styles and themes support.
- *
- * Copyright (c) 1990-1993 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkStyle.c,v 1.1 2002/06/18 23:51:46 dkf Exp $
- */
-
-#include "tkInt.h"
-
-/*
- * The following structure is used to cache widget option specs matching an
- * element's required options defined by Tk_ElementOptionSpecs. It also holds
- * information behind Tk_StyledElement opaque tokens.
- */
-
-typedef struct StyledWidgetSpec {
- struct StyledElement *elementPtr; /* Pointer to the element holding this
- * structure. */
- Tk_OptionTable optionTable; /* Option table for the widget class
- * using the element. */
- CONST Tk_OptionSpec **optionsPtr; /* Table of option spec pointers,
- * matching the option list provided
- * during element registration.
- * Malloc'd. */
-} StyledWidgetSpec;
-
-/*
- * Elements are declared using static templates. But static
- * information must be completed by dynamic information only
- * accessible at runtime. For each registered element, an instance of
- * the following structure is stored in each style engine and used to
- * cache information about the widget types (identified by their
- * optionTable) that use the given element.
- */
-
-typedef struct StyledElement {
- struct Tk_ElementSpec *specPtr;
- /* Filled with template provided during
- * registration. NULL means no implementation
- * is available for the current engine. */
- int nbWidgetSpecs; /* Size of the array below. Number of distinct
- * widget classes (actually, distinct option
- * tables) that used the element so far. */
- StyledWidgetSpec *widgetSpecs;
- /* See above for the structure definition.
- * Table grows dynamically as new widgets
- * use the element. Malloc'd. */
-} StyledElement;
-
-/*
- * The following structure holds information behind Tk_StyleEngine opaque
- * tokens.
- */
-
-typedef struct StyleEngine {
- CONST char *name; /* Name of engine. Points to a hash key. */
- StyledElement *elements; /* Table of widget element descriptors. Each
- * element is indexed by a unique system-wide
- * ID. Table grows dynamically as new elements
- * are registered. Malloc'd*/
- struct StyleEngine *parentPtr;
- /* Parent engine. Engines may be layered to form
- * a fallback chain, terminated by the default
- * system engine. */
-} StyleEngine;
-
-/*
- * Styles are instances of style engines. The following structure holds
- * information behind Tk_Style opaque tokens.
- */
-
-typedef struct Style {
- int refCount; /* Number of active uses of this style.
- * If this count is 0, then this Style
- * structure is no longer valid. */
- Tcl_HashEntry *hashPtr; /* Entry in style table for this structure,
- * used when deleting it. */
- CONST char *name; /* Name of style. Points to a hash key. */
- StyleEngine *enginePtr; /* Style engine of which the style is an
- * instance. */
- ClientData clientData; /* Data provided during registration. */
-} Style;
-
-/*
- * Each registered element uses an instance of the following structure.
- */
-
-typedef struct Element {
- CONST char *name; /* Name of element. Points to a hash key. */
- int id; /* Id of element. */
- int genericId; /* Id of generic element. */
- int created; /* Boolean, whether the element was created
- * explicitly (was registered) or implicitly
- * (by a derived element). */
-} Element;
-
-/*
- * Thread-local data.
- */
-
-typedef struct ThreadSpecificData {
- int nbInit; /* Number of calls to the init proc. */
- Tcl_HashTable engineTable; /* Map a name to a style engine. Keys are
- * strings, values are Tk_StyleEngine
- * pointers. */
- StyleEngine *defaultEnginePtr;
- /* Default, core-defined style engine. Global
- * fallback for all engines. */
- Tcl_HashTable styleTable; /* Map a name to a style. Keys are strings,
- * values are Tk_Style pointers.*/
- int nbElements; /* Size of the below tables. */
- Tcl_HashTable elementTable; /* Map a name to an element Id. Keys are
- * strings, values are integer element IDs. */
- Element *elements; /* Array of Elements. */
-} ThreadSpecificData;
-
-static Tcl_ThreadDataKey dataKey;
-
-/*
- * Forward declarations for procedures defined later in this file:
- */
-
-/* TODO: sort alpha. */
-static int CreateElement _ANSI_ARGS_((char *name, int create));
-static void DupStyleObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
- Tcl_Obj *dupObjPtr));
-static void FreeElement _ANSI_ARGS_((Element *elementPtr));
-static void FreeStyle _ANSI_ARGS_((Style *stylePtr));
-static void FreeStyledElement _ANSI_ARGS_((
- StyledElement *elementPtr));
-static void FreeStyleEngine _ANSI_ARGS_((
- StyleEngine *enginePtr));
-static void FreeStyleObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
-static void FreeWidgetSpec _ANSI_ARGS_((
- StyledWidgetSpec *widgetSpecPtr));
-static StyledElement * GetStyledElement _ANSI_ARGS_((
- StyleEngine *enginePtr, int elementId));
-static StyledWidgetSpec * GetWidgetSpec _ANSI_ARGS_((StyledElement *elementPtr,
- Tk_OptionTable optionTable));
-static void InitElement _ANSI_ARGS_((Element *elementPtr,
- CONST char *name, int id, int genericId,
- int created));
-static void InitStyle _ANSI_ARGS_((Style *stylePtr,
- Tcl_HashEntry *hashPtr, CONST char *name,
- StyleEngine *enginePtr, ClientData clientData));
-static void InitStyledElement _ANSI_ARGS_((
- StyledElement *elementPtr));
-static void InitStyleEngine _ANSI_ARGS_((StyleEngine *enginePtr,
- CONST char *name, StyleEngine *parentPtr));
-static void InitWidgetSpec _ANSI_ARGS_((
- StyledWidgetSpec *widgetSpecPtr,
- StyledElement *elementPtr,
- Tk_OptionTable optionTable));
-static int SetStyleFromAny _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Obj *objPtr));
-
-/*
- * The following structure defines the implementation of the "style" Tcl
- * object, used for drawing. The internalRep.otherValuePtr field of
- * each style object points to the Style structure for the stylefont, or
- * NULL.
- */
-
-static Tcl_ObjType styleObjType = {
- "style", /* name */
- FreeStyleObjProc, /* freeIntRepProc */
- DupStyleObjProc, /* dupIntRepProc */
- NULL, /* updateStringProc */
- SetStyleFromAny /* setFromAnyProc */
-};
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkStylePkgInit --
- *
- * This procedure is called when an application is created. It
- * initializes all the structures that are used by the style
- * package on a per application basis.
- *
- * Results:
- * Stores data in thread-local storage.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-TkStylePkgInit(mainPtr)
- TkMainInfo *mainPtr; /* The application being created. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
-
- if (tsdPtr->nbInit != 0) return;
-
- /*
- * Initialize tables.
- */
-
- Tcl_InitHashTable(&tsdPtr->engineTable, TCL_STRING_KEYS);
- Tcl_InitHashTable(&tsdPtr->styleTable, TCL_STRING_KEYS);
- Tcl_InitHashTable(&tsdPtr->elementTable, TCL_STRING_KEYS);
- tsdPtr->nbElements = 0;
- tsdPtr->elements = NULL;
-
- /*
- * Create the default system engine.
- */
-
- tsdPtr->defaultEnginePtr =
- (StyleEngine *) Tk_RegisterStyleEngine(NULL, NULL);
-
- /*
- * Create the default system style.
- */
-
- Tk_CreateStyle(NULL, (Tk_StyleEngine) tsdPtr->defaultEnginePtr,
- (ClientData) 0);
-
- tsdPtr->nbInit++;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TkStylePkgFree --
- *
- * This procedure is called when an application is deleted. It
- * deletes all the structures that were used by the style package
- * for this application.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-TkStylePkgFree(mainPtr)
- TkMainInfo *mainPtr; /* The application being deleted. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashSearch search;
- Tcl_HashEntry *entryPtr;
- StyleEngine *enginePtr;
- int i;
-
- tsdPtr->nbInit--;
- if (tsdPtr->nbInit != 0) return;
-
- /*
- * Free styles.
- */
-
- entryPtr = Tcl_FirstHashEntry(&tsdPtr->styleTable, &search);
- while (entryPtr != NULL) {
- ckfree((char *) Tcl_GetHashValue(entryPtr));
- entryPtr = Tcl_NextHashEntry(&search);
- }
- Tcl_DeleteHashTable(&tsdPtr->styleTable);
-
- /*
- * Free engines.
- */
-
- entryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
- while (entryPtr != NULL) {
- enginePtr = (StyleEngine *) Tcl_GetHashValue(entryPtr);
- FreeStyleEngine(enginePtr);
- ckfree((char *) enginePtr);
- entryPtr = Tcl_NextHashEntry(&search);
- }
- Tcl_DeleteHashTable(&tsdPtr->engineTable);
-
- /*
- * Free elements.
- */
-
- for (i = 0; i < tsdPtr->nbElements; i++) {
- FreeElement(tsdPtr->elements+i);
- }
- Tcl_DeleteHashTable(&tsdPtr->elementTable);
- ckfree((char *) tsdPtr->elements);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_RegisterStyleEngine --
- *
- * This procedure is called to register a new style engine. Style engines
- * are stored in thread-local space.
- *
- * Results:
- * The newly allocated engine.
- *
- * Side effects:
- * Memory allocated. Data added to thread-local table.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_StyleEngine
-Tk_RegisterStyleEngine(name, parent)
- char *name; /* Name of the engine to create. NULL or empty
- * means the default system engine. */
- Tk_StyleEngine parent; /* The engine's parent. NULL means the default
- * system engine. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
- int newEntry;
- StyleEngine *enginePtr;
-
- /*
- * Attempt to create a new entry in the engine table.
- */
-
- entryPtr = Tcl_CreateHashEntry(&tsdPtr->engineTable, (name?name:""),
- &newEntry);
- if (!newEntry) {
- /*
- * An engine was already registered by that name.
- */
-
- return NULL;
- }
-
- /*
- * Allocate and intitialize a new engine.
- */
-
- enginePtr = (StyleEngine *) ckalloc(sizeof(StyleEngine));
- InitStyleEngine(enginePtr, Tcl_GetHashKey(&tsdPtr->engineTable, entryPtr),
- (StyleEngine *) parent);
- Tcl_SetHashValue(entryPtr, (ClientData) enginePtr);
-
- return (Tk_StyleEngine) enginePtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitStyleEngine --
- *
- * Initialize a newly allocated style engine.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitStyleEngine(enginePtr, name, parentPtr)
- StyleEngine *enginePtr; /* Points to an uninitialized engine. */
- CONST char *name; /* Name of the registered engine. NULL or empty
- * means the default system engine. Usually
- * points to the hash key. */
- StyleEngine *parentPtr; /* The engine's parent. NULL means the default
- * system engine. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- int elementId;
-
- if (name == NULL || *name == '\0') {
- /*
- * This is the default style engine.
- */
-
- enginePtr->parentPtr = NULL;
-
- } else if (parentPtr == NULL) {
- /*
- * The default style engine is the parent.
- */
-
- enginePtr->parentPtr = tsdPtr->defaultEnginePtr;
-
- } else {
- enginePtr->parentPtr = parentPtr;
- }
-
- /*
- * Allocate and initialize elements array.
- */
-
- if (tsdPtr->nbElements > 0) {
- enginePtr->elements = (StyledElement *) ckalloc(
- sizeof(StyledElement) * tsdPtr->nbElements);
- for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
- InitStyledElement(enginePtr->elements+elementId);
- }
- } else {
- enginePtr->elements = NULL;
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeStyleEngine --
- *
- * Free an engine and its associated data.
- *
- * Results:
- * None
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeStyleEngine(enginePtr)
- StyleEngine *enginePtr; /* The style engine to free. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- int elementId;
-
- /*
- * Free allocated elements.
- */
-
- for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
- FreeStyledElement(enginePtr->elements+elementId);
- }
- ckfree((char *) enginePtr->elements);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetStyleEngine --
- *
- * Retrieve a registered style engine by its name.
- *
- * Results:
- * A pointer to the style engine, or NULL if none found.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_StyleEngine
-Tk_GetStyleEngine(name)
- char *name; /* Name of the engine to retrieve. NULL or
- * empty means the default system engine. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
-
- if (name == NULL) {
- return (Tk_StyleEngine) tsdPtr->defaultEnginePtr;
- }
-
- entryPtr = Tcl_FindHashEntry(&tsdPtr->engineTable, (name?name:""));
- if (!entryPtr) {
- return NULL;
- }
-
- return (Tk_StyleEngine) Tcl_GetHashValue(entryPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitElement --
- *
- * Initialize a newly allocated element.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitElement(elementPtr, name, id, genericId, created)
- Element *elementPtr; /* Points to an uninitialized element.*/
- CONST char *name; /* Name of the registered element. Usually
- * points to the hash key. */
- int id; /* Unique element ID. */
- int genericId; /* ID of generic element. -1 means none. */
- int created; /* Boolean, whether the element was created
- * explicitly (was registered) or implicitly
- * (by a derived element). */
-{
- elementPtr->name = name;
- elementPtr->id = id;
- elementPtr->genericId = genericId;
- elementPtr->created = (created?1:0);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeElement --
- *
- * Free an element and its associated data.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeElement(elementPtr)
- Element *elementPtr; /* The element to free. */
-{
- /* Nothing to do. */
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitStyledElement --
- *
- * Initialize a newly allocated styled element.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitStyledElement(elementPtr)
- StyledElement *elementPtr; /* Points to an uninitialized element.*/
-{
- memset(elementPtr, 0, sizeof(StyledElement));
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeStyledElement --
- *
- * Free a styled element and its associated data.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeStyledElement(elementPtr)
- StyledElement *elementPtr; /* The styled element to free. */
-{
- int i;
-
- /*
- * Free allocated widget specs.
- */
-
- for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
- FreeWidgetSpec(elementPtr->widgetSpecs+i);
- }
- ckfree((char *) elementPtr->widgetSpecs);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * CreateElement --
- *
- * Find an existing or create a new element.
- *
- * Results:
- * The unique ID for the created or found element.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static int
-CreateElement(name, create)
- char *name; /* Name of the element. */
- int create; /* Boolean, whether the element is being created
- * explicitly (being registered) or implicitly (by a
- * derived element). */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr, *engineEntryPtr;
- Tcl_HashSearch search;
- int newEntry;
- int elementId, genericId = -1;
- char *dot;
- StyleEngine *enginePtr;
-
- /*
- * Find or create the element.
- */
-
- entryPtr = Tcl_CreateHashEntry(&tsdPtr->elementTable, name, &newEntry);
- if (!newEntry) {
- elementId = (int) Tcl_GetHashValue(entryPtr);
- if (create) {
- tsdPtr->elements[elementId].created = 1;
- }
- return elementId;
- }
-
- /*
- * The element didn't exist. If it's a derived element, find or
- * create its generic element ID.
- */
-
- dot = strchr(name, '.');
- if (dot) {
- genericId = CreateElement(dot+1, 0);
- }
-
- elementId = tsdPtr->nbElements++;
- Tcl_SetHashValue(entryPtr, (ClientData) elementId);
-
- /*
- * Reallocate element table.
- */
-
- tsdPtr->elements = (Element *) ckrealloc((char *) tsdPtr->elements,
- sizeof(Element) * tsdPtr->nbElements);
- InitElement(tsdPtr->elements+elementId,
- Tcl_GetHashKey(&tsdPtr->elementTable, entryPtr), elementId,
- genericId, create);
-
- /*
- * Reallocate style engines' element table.
- */
-
- engineEntryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
- while (engineEntryPtr != NULL) {
- enginePtr = (StyleEngine *) Tcl_GetHashValue(engineEntryPtr);
-
- enginePtr->elements = (StyledElement *) ckrealloc(
- (char *) enginePtr->elements,
- sizeof(StyledElement) * tsdPtr->nbElements);
- InitStyledElement(enginePtr->elements+elementId);
-
- engineEntryPtr = Tcl_NextHashEntry(&search);
- }
-
- return elementId;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetElementId --
- *
- * Find an existing element.
- *
- * Results:
- * The unique ID for the found element, or -1 if not found.
- *
- * Side effects:
- * Generic elements may be created.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-Tk_GetElementId(name)
- char *name; /* Name of the element. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
- int genericId = -1;
- char *dot;
-
- /*
- * Find the element Id.
- */
-
- entryPtr = Tcl_FindHashEntry(&tsdPtr->elementTable, name);
- if (entryPtr) {
- return (int) Tcl_GetHashValue(entryPtr);
- }
-
- /*
- * Element not found. If the given name was derived, then first search for
- * the generic element. If found, create the new derived element.
- */
-
- dot = strchr(name, '.');
- if (!dot) {
- return -1;
- }
- genericId = Tk_GetElementId(dot+1);
- if (genericId == -1) {
- return -1;
- }
- if (!tsdPtr->elements[genericId].created) {
- /*
- * The generic element was created implicitly and thus has no real
- * existence.
- */
-
- return -1;
- } else {
- /*
- * The generic element was created explicitly. Create the derived
- * element.
- */
-
- return CreateElement(name, 1);
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_RegisterStyledElement --
- *
- * Register an implementation of a new or existing element for the
- * given style engine.
- *
- * Results:
- * The unique ID for the created or found element.
- *
- * Side effects:
- * Elements may be created. Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-Tk_RegisterStyledElement(engine, templatePtr)
- Tk_StyleEngine engine; /* Style engine providing the
- * implementation. */
- Tk_ElementSpec *templatePtr; /* Static template information about
- * the element. */
-{
- int elementId;
- StyledElement *elementPtr;
- Tk_ElementSpec *specPtr;
- int nbOptions;
- register Tk_ElementOptionSpec *srcOptions, *dstOptions;
-
- if (templatePtr->version != TK_STYLE_VERSION_1) {
- /*
- * Version mismatch. Do nothing.
- */
-
- return -1;
- }
-
- if (engine == NULL) {
- engine = Tk_GetStyleEngine(NULL);
- }
-
- /*
- * Register the element, allocating storage in the various engines if
- * necessary.
- */
-
- elementId = CreateElement(templatePtr->name, 1);
-
- /*
- * Initialize the styled element.
- */
-
- elementPtr = ((StyleEngine *) engine)->elements+elementId;
-
- specPtr = (Tk_ElementSpec *) ckalloc(sizeof(Tk_ElementSpec));
- specPtr->version = templatePtr->version;
- specPtr->name = ckalloc(strlen(templatePtr->name)+1);
- strcpy(specPtr->name, templatePtr->name);
- nbOptions = 0;
- for (nbOptions = 0, srcOptions = templatePtr->options;
- srcOptions->name != NULL;
- nbOptions++, srcOptions++);
- specPtr->options = (Tk_ElementOptionSpec *) ckalloc(
- sizeof(Tk_ElementOptionSpec) * (nbOptions+1));
- for (srcOptions = templatePtr->options, dstOptions = specPtr->options;
- /* End condition within loop */;
- srcOptions++, dstOptions++) {
- if (srcOptions->name == NULL) {
- dstOptions->name = NULL;
- break;
- }
-
- dstOptions->name = ckalloc(strlen(srcOptions->name)+1);
- strcpy(dstOptions->name, srcOptions->name);
- dstOptions->type = srcOptions->type;
- }
- specPtr->getSize = templatePtr->getSize;
- specPtr->getBox = templatePtr->getBox;
- specPtr->getBorderWidth = templatePtr->getBorderWidth;
- specPtr->draw = templatePtr->draw;
-
- elementPtr->specPtr = specPtr;
- elementPtr->nbWidgetSpecs = 0;
- elementPtr->widgetSpecs = NULL;
-
- return elementId;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetStyledElement --
- *
- * Get a registered implementation of an existing element for the
- * given style engine.
- *
- * Results:
- * The styled element descriptor, or NULL if not found.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static StyledElement *
-GetStyledElement(enginePtr, elementId)
- StyleEngine *enginePtr; /* Style engine providing the implementation.
- * NULL means the default system engine. */
- int elementId; /* Unique element ID */{
- StyledElement *elementPtr;
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- StyleEngine *enginePtr2;
-
- if (enginePtr == NULL) {
- enginePtr = tsdPtr->defaultEnginePtr;
- }
-
- while (elementId >= 0 && elementId < tsdPtr->nbElements) {
- /*
- * Look for an implemented element through the engine chain.
- */
-
- enginePtr2 = enginePtr;
- do {
- elementPtr = enginePtr2->elements+elementId;
- if (elementPtr->specPtr != NULL) {
- return elementPtr;
- }
- enginePtr2 = enginePtr2->parentPtr;
- } while (enginePtr2 != NULL);
-
- /*
- * None found, try with the generic element.
- */
-
- elementId = tsdPtr->elements[elementId].genericId;
- }
-
- /*
- * No matching element found.
- */
-
- return NULL;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitWidgetSpec --
- *
- * Initialize a newly allocated widget spec.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitWidgetSpec(widgetSpecPtr, elementPtr, optionTable)
- StyledWidgetSpec *widgetSpecPtr; /* Points to an uninitialized widget
- * spec. */
- StyledElement *elementPtr; /* Styled element descriptor. */
- Tk_OptionTable optionTable; /* The widget's option table. */
-{
- int i, nbOptions;
- Tk_ElementOptionSpec *elementOptionPtr;
- CONST Tk_OptionSpec *widgetOptionPtr;
-
- widgetSpecPtr->elementPtr = elementPtr;
- widgetSpecPtr->optionTable = optionTable;
-
- /*
- * Count the number of options.
- */
-
- for (nbOptions = 0, elementOptionPtr = elementPtr->specPtr->options;
- elementOptionPtr->name != NULL;
- nbOptions++, elementOptionPtr++) {
- }
-
- /*
- * Build the widget option list.
- */
-
- widgetSpecPtr->optionsPtr = (CONST Tk_OptionSpec **) ckalloc(
- sizeof(Tk_OptionSpec *) * nbOptions);
- for (i = 0, elementOptionPtr = elementPtr->specPtr->options;
- i < nbOptions;
- i++, elementOptionPtr++) {
- widgetOptionPtr = TkGetOptionSpec(elementOptionPtr->name, optionTable);
-
- /*
- * Check that the widget option type is compatible with one of the
- * element's required types.
- */
-
- if ( elementOptionPtr->type == TK_OPTION_END
- || elementOptionPtr->type == widgetOptionPtr->type) {
- widgetSpecPtr->optionsPtr[i] = widgetOptionPtr;
- } else {
- widgetSpecPtr->optionsPtr[i] = NULL;
- }
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeWidgetSpec --
- *
- * Free a widget spec and its associated data.
- *
- * Results:
- * None
- *
- * Side effects:
- * Memory freed.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeWidgetSpec(widgetSpecPtr)
- StyledWidgetSpec *widgetSpecPtr; /* The widget spec to free. */
-{
- ckfree((char *) widgetSpecPtr->optionsPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * GetWidgetSpec --
- *
- * Return a new or existing widget spec for the given element and
- * widget type (identified by its option table).
- *
- * Results:
- * A pointer to the matching widget spec.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *---------------------------------------------------------------------------
- */
-
-static StyledWidgetSpec *
-GetWidgetSpec(elementPtr, optionTable)
- StyledElement *elementPtr; /* Styled element descriptor. */
- Tk_OptionTable optionTable; /* The widget's option table. */
-{
- StyledWidgetSpec *widgetSpecPtr;
- int i;
-
- /*
- * Try to find an existing widget spec.
- */
-
- for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
- widgetSpecPtr = elementPtr->widgetSpecs+i;
- if (widgetSpecPtr->optionTable == optionTable) {
- return widgetSpecPtr;
- }
- }
-
- /*
- * Create and initialize a new widget spec.
- */
-
- i = elementPtr->nbWidgetSpecs++;
- elementPtr->widgetSpecs = (StyledWidgetSpec *) ckrealloc(
- (char *) elementPtr->widgetSpecs,
- sizeof(StyledWidgetSpec) * elementPtr->nbWidgetSpecs);
- widgetSpecPtr = elementPtr->widgetSpecs+i;
- InitWidgetSpec(widgetSpecPtr, elementPtr, optionTable);
-
- return widgetSpecPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetStyledElement --
- *
- * This procedure returns a styled instance of the given element.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Cached data may be allocated or updated.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_StyledElement
-Tk_GetStyledElement(style, elementId, optionTable)
- Tk_Style style; /* The widget style. */
- int elementId; /* Unique element ID. */
- Tk_OptionTable optionTable; /* Option table for the widget. */
-{
- Style *stylePtr = (Style *) style;
- StyledElement *elementPtr;
-
- /*
- * Get an element implementation and call corresponding hook.
- */
-
- elementPtr = GetStyledElement((stylePtr?stylePtr->enginePtr:NULL),
- elementId);
- if (!elementPtr) {
- return NULL;
- }
-
- return (Tk_StyledElement) GetWidgetSpec(elementPtr, optionTable);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetElementSize --
- *
- * This procedure computes the size of the given widget element according
- * to its style.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Cached data may be allocated or updated.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_GetElementSize(style, element, recordPtr, tkwin, width, height, inner, widthPtr,
- heightPtr)
- Tk_Style style; /* The widget style. */
- Tk_StyledElement element; /* The styled element, previously
- * returned by Tk_GetStyledElement. */
- char *recordPtr; /* The widget record. */
- Tk_Window tkwin; /* The widget window. */
- int width, height; /* Requested size. */
- int inner; /* Boolean. If TRUE, compute the outer
- * size according to the requested
- * minimum inner size. If FALSE, compute
- * the inner size according to the
- * requested maximum outer size. */
- int *widthPtr, *heightPtr; /* Returned size. */
-{
- Style *stylePtr = (Style *) style;
- StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
-
- widgetSpecPtr->elementPtr->specPtr->getSize(stylePtr->clientData,
- recordPtr, widgetSpecPtr->optionsPtr, tkwin, width, height, inner,
- widthPtr, heightPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetElementBox --
- *
- * This procedure computes the bounding or inscribed box coordinates
- * of the given widget element according to its style and within the
- * given limits.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Cached data may be allocated or updated.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_GetElementBox(style, element, recordPtr, tkwin, x, y, width, height, inner,
- xPtr, yPtr, widthPtr, heightPtr)
- Tk_Style style; /* The widget style. */
- Tk_StyledElement element; /* The styled element, previously
- * returned by Tk_GetStyledElement. */
- char *recordPtr; /* The widget record. */
- Tk_Window tkwin; /* The widget window. */
- int x, y; /* Top left corner of available area. */
- int width, height; /* Size of available area. */
- int inner; /* Boolean. If TRUE, compute the
- * bounding box according to the
- * requested inscribed box size. If
- * FALSE, compute the inscribed box
- * according to the requested bounding
- * box. */
- int *xPtr, *yPtr; /* Returned top left corner. */
- int *widthPtr, *heightPtr; /* Returned size. */
-{
- Style *stylePtr = (Style *) style;
- StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
-
- widgetSpecPtr->elementPtr->specPtr->getBox(stylePtr->clientData,
- recordPtr, widgetSpecPtr->optionsPtr, tkwin, x, y, width, height,
- inner, xPtr, yPtr, widthPtr, heightPtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetElementBorderWidth --
- *
- * This procedure computes the border widthof the given widget element
- * according to its style and within the given limits.
- *
- * Results:
- * Border width in pixels. This value is uniform for all four sides.
- *
- * Side effects:
- * Cached data may be allocated or updated.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-Tk_GetElementBorderWidth(style, element, recordPtr, tkwin)
- Tk_Style style; /* The widget style. */
- Tk_StyledElement element; /* The styled element, previously
- * returned by Tk_GetStyledElement. */
- char *recordPtr; /* The widget record. */
- Tk_Window tkwin; /* The widget window. */
-{
- Style *stylePtr = (Style *) style;
- StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
-
- return widgetSpecPtr->elementPtr->specPtr->getBorderWidth(
- stylePtr->clientData, recordPtr, widgetSpecPtr->optionsPtr, tkwin);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_DrawElement --
- *
- * This procedure draw the given widget element in a given drawable area.
- *
- * Results:
- * None
- *
- * Side effects:
- * Cached data may be allocated or updated.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_DrawElement(style, element, recordPtr, tkwin, d, x, y, width, height, state)
- Tk_Style style; /* The widget style. */
- Tk_StyledElement element; /* The styled element, previously
- * returned by Tk_GetStyledElement. */
- char *recordPtr; /* The widget record. */
- Tk_Window tkwin; /* The widget window. */
- Drawable d; /* Where to draw element. */
- int x, y; /* Top left corner of element. */
- int width, height; /* Size of element. */
- int state; /* Drawing state flags. */
-{
- Style *stylePtr = (Style *) style;
- StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
-
- widgetSpecPtr->elementPtr->specPtr->draw(stylePtr->clientData,
- recordPtr, widgetSpecPtr->optionsPtr, tkwin, d, x, y, width,
- height, state);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_CreateStyle --
- *
- * This procedure is called to create a new style as an instance of the
- * given engine. Styles are stored in thread-local space.
- *
- * Results:
- * The newly allocated style.
- *
- * Side effects:
- * Memory allocated. Data added to thread-local table. The style's
- * refCount is incremented.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_Style
-Tk_CreateStyle(name, engine, clientData)
- CONST char *name; /* Name of the style to create. NULL or empty
- * means the default system style. */
- Tk_StyleEngine engine; /* The style engine. */
- ClientData clientData; /* Private data passed as is to engine code. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
- int newEntry;
- Style *stylePtr;
-
- /*
- * Attempt to create a new entry in the style table.
- */
-
- entryPtr = Tcl_CreateHashEntry(&tsdPtr->styleTable, (name?name:""),
- &newEntry);
- if (!newEntry) {
- /*
- * A style was already registered by that name.
- */
-
- return NULL;
- }
-
- /*
- * Allocate and intitialize a new style.
- */
-
- stylePtr = (Style *) ckalloc(sizeof(Style));
- InitStyle(stylePtr, entryPtr, Tcl_GetHashKey(&tsdPtr->styleTable, entryPtr),
- (engine?(StyleEngine *) engine:tsdPtr->defaultEnginePtr), clientData);
- Tcl_SetHashValue(entryPtr, (ClientData) stylePtr);
- stylePtr->refCount++;
-
- return (Tk_Style) stylePtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_NameOfStyle --
- *
- * Given a style, return its registered name.
- *
- * Results:
- * The return value is the name that was passed to Tk_CreateStyle() to
- * create the style. The storage for the returned string is private
- * (it points to the corresponding hash key) The caller should not modify
- * this string.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-CONST char *
-Tk_NameOfStyle(style)
- Tk_Style style; /* Style whose name is desired. */
-{
- Style *stylePtr = (Style *) style;
-
- return stylePtr->name;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * InitStyle --
- *
- * Initialize a newly allocated style.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-InitStyle(stylePtr, hashPtr, name, enginePtr, clientData)
- Style *stylePtr; /* Points to an uninitialized style. */
- Tcl_HashEntry *hashPtr; /* Hash entry for the registered style. */
- CONST char *name; /* Name of the registered style. NULL or empty
- * means the default system style. Usually
- * points to the hash key. */
- StyleEngine *enginePtr; /* The style engine. */
- ClientData clientData; /* Private data passed as is to engine code. */
-{
- stylePtr->refCount = 0;
- stylePtr->hashPtr = hashPtr;
- stylePtr->name = name;
- stylePtr->enginePtr = enginePtr;
- stylePtr->clientData = clientData;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeStyle --
- *
- * Free a style and its associated data.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeStyle(stylePtr)
- Style *stylePtr; /* The style to free. */
-{
- /* Nothing to do. */
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_GetStyle --
- *
- * Retrieve a registered style by its name.
- *
- * Results:
- * A pointer to the style engine, or NULL if none found. In the latter
- * case and if the interp is not NULL, an error message is left in the
- * interp's result.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_Style
-Tk_GetStyle(interp, name)
- Tcl_Interp *interp; /* Interp for error return. */
- CONST char *name; /* Name of the style to retrieve. NULL or empty
- * means the default system style. */
-{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- Tcl_HashEntry *entryPtr;
- Style *stylePtr;
-
- /*
- * Search for a corresponding entry in the style table.
- */
-
- entryPtr = Tcl_FindHashEntry(&tsdPtr->styleTable, (name?name:""));
- if (entryPtr == NULL) {
- if (interp != NULL) {
- Tcl_AppendResult(interp, "style \"", name, "\" doesn't exist", NULL);
- }
- return (Tk_Style) NULL;
- }
- stylePtr = (Style *) Tcl_GetHashValue(entryPtr);
- stylePtr->refCount++;
-
- return (Tk_Style) stylePtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_FreeStyle --
- *
- * Free a style previously created by Tk_CreateStyle.
- *
- * Results:
- * None
- *
- * Side effects:
- * The style's refCount is decremented. If it reaches zero, the style
- * is freed.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_FreeStyle(style)
- Tk_Style style; /* The style to free. */
-{
- Style *stylePtr = (Style *) style;
-
- if (stylePtr == NULL) {
- return;
- }
- stylePtr->refCount--;
- if (stylePtr->refCount > 0) {
- return;
- }
-
- /*
- * Keep the default style alive.
- */
-
- if (*stylePtr->name == '\0') {
- stylePtr->refCount = 1;
- return;
- }
-
- Tcl_DeleteHashEntry(stylePtr->hashPtr);
- FreeStyle(stylePtr);
- ckfree((char *) stylePtr);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_AllocStyleFromObj --
- *
- * Map the string name of a style to a corresponding Tk_Style. The style
- * must have already been created by Tk_CreateStyle.
- *
- * Results:
- * The return value is a token for the style that matches objPtr, or
- * NULL if none found. If NULL is returned, an error message will be
- * left in interp's result object.
- *
- * Side effects:
- * The style's reference count is incremented. For each call to this
- * procedure, there should eventually be a call to Tk_FreeStyle() or
- * Tk_FreeStyleFromObj() so that the database is cleaned up when styles
- * aren't in use anymore.
- *
- *---------------------------------------------------------------------------
- */
-
-Tk_Style
-Tk_AllocStyleFromObj(interp, objPtr)
- Tcl_Interp *interp; /* Interp for error return. */
- Tcl_Obj *objPtr; /* Object containing name of the style to
- * retrieve. */
-{
- Style *stylePtr;
-
- if (objPtr->typePtr != &styleObjType) {
- SetStyleFromAny(interp, objPtr);
- stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
- } else {
- stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
- stylePtr->refCount++;
- }
-
- return (Tk_Style) stylePtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tk_GetStyleFromObj --
- *
- * Find the style that corresponds to a given object. The style must
- * have already been created by Tk_CreateStyle.
- *
- * Results:
- * The return value is a token for the style that matches objPtr, or
- * NULL if none found.
- *
- * Side effects:
- * If the object is not already a style ref, the conversion will free
- * any old internal representation.
- *
- *----------------------------------------------------------------------
- */
-
-Tk_Style
-Tk_GetStyleFromObj(objPtr)
- Tcl_Obj *objPtr; /* The object from which to get the style. */
-{
- if (objPtr->typePtr != &styleObjType) {
- SetStyleFromAny((Tcl_Interp *) NULL, objPtr);
- }
-
- return (Tk_Style) objPtr->internalRep.otherValuePtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * Tk_FreeStyleFromObj --
- *
- * Called to release a style inside a Tcl_Obj *.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If the object is a style ref, the conversion will free its
- * internal representation.
- *
- *---------------------------------------------------------------------------
- */
-
-void
-Tk_FreeStyleFromObj(objPtr)
- Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
-{
- if (objPtr->typePtr == &styleObjType) {
- FreeStyleObjProc(objPtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * SetStyleFromAny --
- *
- * Convert the internal representation of a Tcl object to the
- * style internal form.
- *
- * Results:
- * Always returns TCL_OK. If an error occurs is returned (e.g. the
- * style doesn't exist), an error message will be left in interp's
- * result.
- *
- * Side effects:
- * The object is left with its typePtr pointing to styleObjType.
- * The reference count is incremented (in Tk_GetStyle()).
- *
- *----------------------------------------------------------------------
- */
-
-static int
-SetStyleFromAny(interp, objPtr)
- Tcl_Interp *interp; /* Used for error reporting if not NULL. */
- Tcl_Obj *objPtr; /* The object to convert. */
-{
- Tcl_ObjType *typePtr;
- char *name;
-
- /*
- * Free the old internalRep before setting the new one.
- */
-
- name = Tcl_GetString(objPtr);
- typePtr = objPtr->typePtr;
- if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
- (*typePtr->freeIntRepProc)(objPtr);
- }
-
- objPtr->typePtr = &styleObjType;
- objPtr->internalRep.otherValuePtr = (VOID *) Tk_GetStyle(interp, name);
-
- return TCL_OK;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * FreeStyleObjProc --
- *
- * This proc is called to release an object reference to a style.
- * Called when the object's internal rep is released.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The reference count is decremented (in Tk_FreeStyle()).
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-FreeStyleObjProc(objPtr)
- Tcl_Obj *objPtr; /* The object we are releasing. */
-{
- Style *stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
-
- if (stylePtr != NULL) {
- Tk_FreeStyle((Tk_Style) stylePtr);
- objPtr->internalRep.otherValuePtr = NULL;
- }
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * DupStyleObjProc --
- *
- * When a cached style object is duplicated, this is called to
- * update the internal reps.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The style's refCount is incremented and the internal rep of the copy
- * is set to point to it.
- *
- *---------------------------------------------------------------------------
- */
-
-static void
-DupStyleObjProc(srcObjPtr, dupObjPtr)
- Tcl_Obj *srcObjPtr; /* The object we are copying from. */
- Tcl_Obj *dupObjPtr; /* The object we are copying to. */
-{
- Style *stylePtr = (Style *) srcObjPtr->internalRep.otherValuePtr;
-
- dupObjPtr->typePtr = srcObjPtr->typePtr;
- dupObjPtr->internalRep.otherValuePtr = (VOID *) stylePtr;
-
- if (stylePtr != NULL) {
- stylePtr->refCount++;
- }
-}
+/*
+ * tkStyle.c --
+ *
+ * This file implements the widget styles and themes support.
+ *
+ * Copyright (c) 1990-1993 The Regents of the University of California.
+ * Copyright (c) 1994-1997 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id: tkStyle.c,v 1.2 2002/06/26 22:53:13 davygrvy Exp $
+ */
+
+#include "tkInt.h"
+
+/*
+ * The following structure is used to cache widget option specs matching an
+ * element's required options defined by Tk_ElementOptionSpecs. It also holds
+ * information behind Tk_StyledElement opaque tokens.
+ */
+
+typedef struct StyledWidgetSpec {
+ struct StyledElement *elementPtr; /* Pointer to the element holding this
+ * structure. */
+ Tk_OptionTable optionTable; /* Option table for the widget class
+ * using the element. */
+ CONST Tk_OptionSpec **optionsPtr; /* Table of option spec pointers,
+ * matching the option list provided
+ * during element registration.
+ * Malloc'd. */
+} StyledWidgetSpec;
+
+/*
+ * Elements are declared using static templates. But static
+ * information must be completed by dynamic information only
+ * accessible at runtime. For each registered element, an instance of
+ * the following structure is stored in each style engine and used to
+ * cache information about the widget types (identified by their
+ * optionTable) that use the given element.
+ */
+
+typedef struct StyledElement {
+ struct Tk_ElementSpec *specPtr;
+ /* Filled with template provided during
+ * registration. NULL means no implementation
+ * is available for the current engine. */
+ int nbWidgetSpecs; /* Size of the array below. Number of distinct
+ * widget classes (actually, distinct option
+ * tables) that used the element so far. */
+ StyledWidgetSpec *widgetSpecs;
+ /* See above for the structure definition.
+ * Table grows dynamically as new widgets
+ * use the element. Malloc'd. */
+} StyledElement;
+
+/*
+ * The following structure holds information behind Tk_StyleEngine opaque
+ * tokens.
+ */
+
+typedef struct StyleEngine {
+ CONST char *name; /* Name of engine. Points to a hash key. */
+ StyledElement *elements; /* Table of widget element descriptors. Each
+ * element is indexed by a unique system-wide
+ * ID. Table grows dynamically as new elements
+ * are registered. Malloc'd*/
+ struct StyleEngine *parentPtr;
+ /* Parent engine. Engines may be layered to form
+ * a fallback chain, terminated by the default
+ * system engine. */
+} StyleEngine;
+
+/*
+ * Styles are instances of style engines. The following structure holds
+ * information behind Tk_Style opaque tokens.
+ */
+
+typedef struct Style {
+ int refCount; /* Number of active uses of this style.
+ * If this count is 0, then this Style
+ * structure is no longer valid. */
+ Tcl_HashEntry *hashPtr; /* Entry in style table for this structure,
+ * used when deleting it. */
+ CONST char *name; /* Name of style. Points to a hash key. */
+ StyleEngine *enginePtr; /* Style engine of which the style is an
+ * instance. */
+ ClientData clientData; /* Data provided during registration. */
+} Style;
+
+/*
+ * Each registered element uses an instance of the following structure.
+ */
+
+typedef struct Element {
+ CONST char *name; /* Name of element. Points to a hash key. */
+ int id; /* Id of element. */
+ int genericId; /* Id of generic element. */
+ int created; /* Boolean, whether the element was created
+ * explicitly (was registered) or implicitly
+ * (by a derived element). */
+} Element;
+
+/*
+ * Thread-local data.
+ */
+
+typedef struct ThreadSpecificData {
+ int nbInit; /* Number of calls to the init proc. */
+ Tcl_HashTable engineTable; /* Map a name to a style engine. Keys are
+ * strings, values are Tk_StyleEngine
+ * pointers. */
+ StyleEngine *defaultEnginePtr;
+ /* Default, core-defined style engine. Global
+ * fallback for all engines. */
+ Tcl_HashTable styleTable; /* Map a name to a style. Keys are strings,
+ * values are Tk_Style pointers.*/
+ int nbElements; /* Size of the below tables. */
+ Tcl_HashTable elementTable; /* Map a name to an element Id. Keys are
+ * strings, values are integer element IDs. */
+ Element *elements; /* Array of Elements. */
+} ThreadSpecificData;
+
+static Tcl_ThreadDataKey dataKey;
+
+/*
+ * Forward declarations for procedures defined later in this file:
+ */
+
+/* TODO: sort alpha. */
+static int CreateElement _ANSI_ARGS_((char *name, int create));
+static void DupStyleObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
+ Tcl_Obj *dupObjPtr));
+static void FreeElement _ANSI_ARGS_((Element *elementPtr));
+static void FreeStyle _ANSI_ARGS_((Style *stylePtr));
+static void FreeStyledElement _ANSI_ARGS_((
+ StyledElement *elementPtr));
+static void FreeStyleEngine _ANSI_ARGS_((
+ StyleEngine *enginePtr));
+static void FreeStyleObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
+static void FreeWidgetSpec _ANSI_ARGS_((
+ StyledWidgetSpec *widgetSpecPtr));
+static StyledElement * GetStyledElement _ANSI_ARGS_((
+ StyleEngine *enginePtr, int elementId));
+static StyledWidgetSpec * GetWidgetSpec _ANSI_ARGS_((StyledElement *elementPtr,
+ Tk_OptionTable optionTable));
+static void InitElement _ANSI_ARGS_((Element *elementPtr,
+ CONST char *name, int id, int genericId,
+ int created));
+static void InitStyle _ANSI_ARGS_((Style *stylePtr,
+ Tcl_HashEntry *hashPtr, CONST char *name,
+ StyleEngine *enginePtr, ClientData clientData));
+static void InitStyledElement _ANSI_ARGS_((
+ StyledElement *elementPtr));
+static void InitStyleEngine _ANSI_ARGS_((StyleEngine *enginePtr,
+ CONST char *name, StyleEngine *parentPtr));
+static void InitWidgetSpec _ANSI_ARGS_((
+ StyledWidgetSpec *widgetSpecPtr,
+ StyledElement *elementPtr,
+ Tk_OptionTable optionTable));
+static int SetStyleFromAny _ANSI_ARGS_((Tcl_Interp *interp,
+ Tcl_Obj *objPtr));
+
+/*
+ * The following structure defines the implementation of the "style" Tcl
+ * object, used for drawing. The internalRep.otherValuePtr field of
+ * each style object points to the Style structure for the stylefont, or
+ * NULL.
+ */
+
+static Tcl_ObjType styleObjType = {
+ "style", /* name */
+ FreeStyleObjProc, /* freeIntRepProc */
+ DupStyleObjProc, /* dupIntRepProc */
+ NULL, /* updateStringProc */
+ SetStyleFromAny /* setFromAnyProc */
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkStylePkgInit --
+ *
+ * This procedure is called when an application is created. It
+ * initializes all the structures that are used by the style
+ * package on a per application basis.
+ *
+ * Results:
+ * Stores data in thread-local storage.
+ *
+ * Side effects:
+ * Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TkStylePkgInit(mainPtr)
+ TkMainInfo *mainPtr; /* The application being created. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ if (tsdPtr->nbInit != 0) return;
+
+ /*
+ * Initialize tables.
+ */
+
+ Tcl_InitHashTable(&tsdPtr->engineTable, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tsdPtr->styleTable, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tsdPtr->elementTable, TCL_STRING_KEYS);
+ tsdPtr->nbElements = 0;
+ tsdPtr->elements = NULL;
+
+ /*
+ * Create the default system engine.
+ */
+
+ tsdPtr->defaultEnginePtr =
+ (StyleEngine *) Tk_RegisterStyleEngine(NULL, NULL);
+
+ /*
+ * Create the default system style.
+ */
+
+ Tk_CreateStyle(NULL, (Tk_StyleEngine) tsdPtr->defaultEnginePtr,
+ (ClientData) 0);
+
+ tsdPtr->nbInit++;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkStylePkgFree --
+ *
+ * This procedure is called when an application is deleted. It
+ * deletes all the structures that were used by the style package
+ * for this application.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TkStylePkgFree(mainPtr)
+ TkMainInfo *mainPtr; /* The application being deleted. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashSearch search;
+ Tcl_HashEntry *entryPtr;
+ StyleEngine *enginePtr;
+ int i;
+
+ tsdPtr->nbInit--;
+ if (tsdPtr->nbInit != 0) return;
+
+ /*
+ * Free styles.
+ */
+
+ entryPtr = Tcl_FirstHashEntry(&tsdPtr->styleTable, &search);
+ while (entryPtr != NULL) {
+ ckfree((char *) Tcl_GetHashValue(entryPtr));
+ entryPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_DeleteHashTable(&tsdPtr->styleTable);
+
+ /*
+ * Free engines.
+ */
+
+ entryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
+ while (entryPtr != NULL) {
+ enginePtr = (StyleEngine *) Tcl_GetHashValue(entryPtr);
+ FreeStyleEngine(enginePtr);
+ ckfree((char *) enginePtr);
+ entryPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_DeleteHashTable(&tsdPtr->engineTable);
+
+ /*
+ * Free elements.
+ */
+
+ for (i = 0; i < tsdPtr->nbElements; i++) {
+ FreeElement(tsdPtr->elements+i);
+ }
+ Tcl_DeleteHashTable(&tsdPtr->elementTable);
+ ckfree((char *) tsdPtr->elements);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_RegisterStyleEngine --
+ *
+ * This procedure is called to register a new style engine. Style engines
+ * are stored in thread-local space.
+ *
+ * Results:
+ * The newly allocated engine.
+ *
+ * Side effects:
+ * Memory allocated. Data added to thread-local table.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_StyleEngine
+Tk_RegisterStyleEngine(name, parent)
+ char *name; /* Name of the engine to create. NULL or empty
+ * means the default system engine. */
+ Tk_StyleEngine parent; /* The engine's parent. NULL means the default
+ * system engine. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr;
+ int newEntry;
+ StyleEngine *enginePtr;
+
+ /*
+ * Attempt to create a new entry in the engine table.
+ */
+
+ entryPtr = Tcl_CreateHashEntry(&tsdPtr->engineTable, (name?name:""),
+ &newEntry);
+ if (!newEntry) {
+ /*
+ * An engine was already registered by that name.
+ */
+
+ return NULL;
+ }
+
+ /*
+ * Allocate and intitialize a new engine.
+ */
+
+ enginePtr = (StyleEngine *) ckalloc(sizeof(StyleEngine));
+ InitStyleEngine(enginePtr, Tcl_GetHashKey(&tsdPtr->engineTable, entryPtr),
+ (StyleEngine *) parent);
+ Tcl_SetHashValue(entryPtr, (ClientData) enginePtr);
+
+ return (Tk_StyleEngine) enginePtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitStyleEngine --
+ *
+ * Initialize a newly allocated style engine.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitStyleEngine(enginePtr, name, parentPtr)
+ StyleEngine *enginePtr; /* Points to an uninitialized engine. */
+ CONST char *name; /* Name of the registered engine. NULL or empty
+ * means the default system engine. Usually
+ * points to the hash key. */
+ StyleEngine *parentPtr; /* The engine's parent. NULL means the default
+ * system engine. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ int elementId;
+
+ if (name == NULL || *name == '\0') {
+ /*
+ * This is the default style engine.
+ */
+
+ enginePtr->parentPtr = NULL;
+
+ } else if (parentPtr == NULL) {
+ /*
+ * The default style engine is the parent.
+ */
+
+ enginePtr->parentPtr = tsdPtr->defaultEnginePtr;
+
+ } else {
+ enginePtr->parentPtr = parentPtr;
+ }
+
+ /*
+ * Allocate and initialize elements array.
+ */
+
+ if (tsdPtr->nbElements > 0) {
+ enginePtr->elements = (StyledElement *) ckalloc(
+ sizeof(StyledElement) * tsdPtr->nbElements);
+ for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
+ InitStyledElement(enginePtr->elements+elementId);
+ }
+ } else {
+ enginePtr->elements = NULL;
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeStyleEngine --
+ *
+ * Free an engine and its associated data.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Memory freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeStyleEngine(enginePtr)
+ StyleEngine *enginePtr; /* The style engine to free. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ int elementId;
+
+ /*
+ * Free allocated elements.
+ */
+
+ for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
+ FreeStyledElement(enginePtr->elements+elementId);
+ }
+ ckfree((char *) enginePtr->elements);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetStyleEngine --
+ *
+ * Retrieve a registered style engine by its name.
+ *
+ * Results:
+ * A pointer to the style engine, or NULL if none found.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_StyleEngine
+Tk_GetStyleEngine(name)
+ char *name; /* Name of the engine to retrieve. NULL or
+ * empty means the default system engine. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr;
+
+ if (name == NULL) {
+ return (Tk_StyleEngine) tsdPtr->defaultEnginePtr;
+ }
+
+ entryPtr = Tcl_FindHashEntry(&tsdPtr->engineTable, (name?name:""));
+ if (!entryPtr) {
+ return NULL;
+ }
+
+ return (Tk_StyleEngine) Tcl_GetHashValue(entryPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitElement --
+ *
+ * Initialize a newly allocated element.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitElement(elementPtr, name, id, genericId, created)
+ Element *elementPtr; /* Points to an uninitialized element.*/
+ CONST char *name; /* Name of the registered element. Usually
+ * points to the hash key. */
+ int id; /* Unique element ID. */
+ int genericId; /* ID of generic element. -1 means none. */
+ int created; /* Boolean, whether the element was created
+ * explicitly (was registered) or implicitly
+ * (by a derived element). */
+{
+ elementPtr->name = name;
+ elementPtr->id = id;
+ elementPtr->genericId = genericId;
+ elementPtr->created = (created?1:0);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeElement --
+ *
+ * Free an element and its associated data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeElement(elementPtr)
+ Element *elementPtr; /* The element to free. */
+{
+ /* Nothing to do. */
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitStyledElement --
+ *
+ * Initialize a newly allocated styled element.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitStyledElement(elementPtr)
+ StyledElement *elementPtr; /* Points to an uninitialized element.*/
+{
+ memset(elementPtr, 0, sizeof(StyledElement));
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeStyledElement --
+ *
+ * Free a styled element and its associated data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeStyledElement(elementPtr)
+ StyledElement *elementPtr; /* The styled element to free. */
+{
+ int i;
+
+ /*
+ * Free allocated widget specs.
+ */
+
+ for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
+ FreeWidgetSpec(elementPtr->widgetSpecs+i);
+ }
+ ckfree((char *) elementPtr->widgetSpecs);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * CreateElement --
+ *
+ * Find an existing or create a new element.
+ *
+ * Results:
+ * The unique ID for the created or found element.
+ *
+ * Side effects:
+ * Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static int
+CreateElement(name, create)
+ char *name; /* Name of the element. */
+ int create; /* Boolean, whether the element is being created
+ * explicitly (being registered) or implicitly (by a
+ * derived element). */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr, *engineEntryPtr;
+ Tcl_HashSearch search;
+ int newEntry;
+ int elementId, genericId = -1;
+ char *dot;
+ StyleEngine *enginePtr;
+
+ /*
+ * Find or create the element.
+ */
+
+ entryPtr = Tcl_CreateHashEntry(&tsdPtr->elementTable, name, &newEntry);
+ if (!newEntry) {
+ elementId = (int) Tcl_GetHashValue(entryPtr);
+ if (create) {
+ tsdPtr->elements[elementId].created = 1;
+ }
+ return elementId;
+ }
+
+ /*
+ * The element didn't exist. If it's a derived element, find or
+ * create its generic element ID.
+ */
+
+ dot = strchr(name, '.');
+ if (dot) {
+ genericId = CreateElement(dot+1, 0);
+ }
+
+ elementId = tsdPtr->nbElements++;
+ Tcl_SetHashValue(entryPtr, (ClientData) elementId);
+
+ /*
+ * Reallocate element table.
+ */
+
+ tsdPtr->elements = (Element *) ckrealloc((char *) tsdPtr->elements,
+ sizeof(Element) * tsdPtr->nbElements);
+ InitElement(tsdPtr->elements+elementId,
+ Tcl_GetHashKey(&tsdPtr->elementTable, entryPtr), elementId,
+ genericId, create);
+
+ /*
+ * Reallocate style engines' element table.
+ */
+
+ engineEntryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
+ while (engineEntryPtr != NULL) {
+ enginePtr = (StyleEngine *) Tcl_GetHashValue(engineEntryPtr);
+
+ enginePtr->elements = (StyledElement *) ckrealloc(
+ (char *) enginePtr->elements,
+ sizeof(StyledElement) * tsdPtr->nbElements);
+ InitStyledElement(enginePtr->elements+elementId);
+
+ engineEntryPtr = Tcl_NextHashEntry(&search);
+ }
+
+ return elementId;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetElementId --
+ *
+ * Find an existing element.
+ *
+ * Results:
+ * The unique ID for the found element, or -1 if not found.
+ *
+ * Side effects:
+ * Generic elements may be created.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+Tk_GetElementId(name)
+ char *name; /* Name of the element. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr;
+ int genericId = -1;
+ char *dot;
+
+ /*
+ * Find the element Id.
+ */
+
+ entryPtr = Tcl_FindHashEntry(&tsdPtr->elementTable, name);
+ if (entryPtr) {
+ return (int) Tcl_GetHashValue(entryPtr);
+ }
+
+ /*
+ * Element not found. If the given name was derived, then first search for
+ * the generic element. If found, create the new derived element.
+ */
+
+ dot = strchr(name, '.');
+ if (!dot) {
+ return -1;
+ }
+ genericId = Tk_GetElementId(dot+1);
+ if (genericId == -1) {
+ return -1;
+ }
+ if (!tsdPtr->elements[genericId].created) {
+ /*
+ * The generic element was created implicitly and thus has no real
+ * existence.
+ */
+
+ return -1;
+ } else {
+ /*
+ * The generic element was created explicitly. Create the derived
+ * element.
+ */
+
+ return CreateElement(name, 1);
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_RegisterStyledElement --
+ *
+ * Register an implementation of a new or existing element for the
+ * given style engine.
+ *
+ * Results:
+ * The unique ID for the created or found element.
+ *
+ * Side effects:
+ * Elements may be created. Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+Tk_RegisterStyledElement(engine, templatePtr)
+ Tk_StyleEngine engine; /* Style engine providing the
+ * implementation. */
+ Tk_ElementSpec *templatePtr; /* Static template information about
+ * the element. */
+{
+ int elementId;
+ StyledElement *elementPtr;
+ Tk_ElementSpec *specPtr;
+ int nbOptions;
+ register Tk_ElementOptionSpec *srcOptions, *dstOptions;
+
+ if (templatePtr->version != TK_STYLE_VERSION_1) {
+ /*
+ * Version mismatch. Do nothing.
+ */
+
+ return -1;
+ }
+
+ if (engine == NULL) {
+ engine = Tk_GetStyleEngine(NULL);
+ }
+
+ /*
+ * Register the element, allocating storage in the various engines if
+ * necessary.
+ */
+
+ elementId = CreateElement(templatePtr->name, 1);
+
+ /*
+ * Initialize the styled element.
+ */
+
+ elementPtr = ((StyleEngine *) engine)->elements+elementId;
+
+ specPtr = (Tk_ElementSpec *) ckalloc(sizeof(Tk_ElementSpec));
+ specPtr->version = templatePtr->version;
+ specPtr->name = ckalloc(strlen(templatePtr->name)+1);
+ strcpy(specPtr->name, templatePtr->name);
+ nbOptions = 0;
+ for (nbOptions = 0, srcOptions = templatePtr->options;
+ srcOptions->name != NULL;
+ nbOptions++, srcOptions++);
+ specPtr->options = (Tk_ElementOptionSpec *) ckalloc(
+ sizeof(Tk_ElementOptionSpec) * (nbOptions+1));
+ for (srcOptions = templatePtr->options, dstOptions = specPtr->options;
+ /* End condition within loop */;
+ srcOptions++, dstOptions++) {
+ if (srcOptions->name == NULL) {
+ dstOptions->name = NULL;
+ break;
+ }
+
+ dstOptions->name = ckalloc(strlen(srcOptions->name)+1);
+ strcpy(dstOptions->name, srcOptions->name);
+ dstOptions->type = srcOptions->type;
+ }
+ specPtr->getSize = templatePtr->getSize;
+ specPtr->getBox = templatePtr->getBox;
+ specPtr->getBorderWidth = templatePtr->getBorderWidth;
+ specPtr->draw = templatePtr->draw;
+
+ elementPtr->specPtr = specPtr;
+ elementPtr->nbWidgetSpecs = 0;
+ elementPtr->widgetSpecs = NULL;
+
+ return elementId;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetStyledElement --
+ *
+ * Get a registered implementation of an existing element for the
+ * given style engine.
+ *
+ * Results:
+ * The styled element descriptor, or NULL if not found.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static StyledElement *
+GetStyledElement(enginePtr, elementId)
+ StyleEngine *enginePtr; /* Style engine providing the implementation.
+ * NULL means the default system engine. */
+ int elementId; /* Unique element ID */{
+ StyledElement *elementPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ StyleEngine *enginePtr2;
+
+ if (enginePtr == NULL) {
+ enginePtr = tsdPtr->defaultEnginePtr;
+ }
+
+ while (elementId >= 0 && elementId < tsdPtr->nbElements) {
+ /*
+ * Look for an implemented element through the engine chain.
+ */
+
+ enginePtr2 = enginePtr;
+ do {
+ elementPtr = enginePtr2->elements+elementId;
+ if (elementPtr->specPtr != NULL) {
+ return elementPtr;
+ }
+ enginePtr2 = enginePtr2->parentPtr;
+ } while (enginePtr2 != NULL);
+
+ /*
+ * None found, try with the generic element.
+ */
+
+ elementId = tsdPtr->elements[elementId].genericId;
+ }
+
+ /*
+ * No matching element found.
+ */
+
+ return NULL;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitWidgetSpec --
+ *
+ * Initialize a newly allocated widget spec.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Memory allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitWidgetSpec(widgetSpecPtr, elementPtr, optionTable)
+ StyledWidgetSpec *widgetSpecPtr; /* Points to an uninitialized widget
+ * spec. */
+ StyledElement *elementPtr; /* Styled element descriptor. */
+ Tk_OptionTable optionTable; /* The widget's option table. */
+{
+ int i, nbOptions;
+ Tk_ElementOptionSpec *elementOptionPtr;
+ CONST Tk_OptionSpec *widgetOptionPtr;
+
+ widgetSpecPtr->elementPtr = elementPtr;
+ widgetSpecPtr->optionTable = optionTable;
+
+ /*
+ * Count the number of options.
+ */
+
+ for (nbOptions = 0, elementOptionPtr = elementPtr->specPtr->options;
+ elementOptionPtr->name != NULL;
+ nbOptions++, elementOptionPtr++) {
+ }
+
+ /*
+ * Build the widget option list.
+ */
+
+ widgetSpecPtr->optionsPtr = (CONST Tk_OptionSpec **) ckalloc(
+ sizeof(Tk_OptionSpec *) * nbOptions);
+ for (i = 0, elementOptionPtr = elementPtr->specPtr->options;
+ i < nbOptions;
+ i++, elementOptionPtr++) {
+ widgetOptionPtr = TkGetOptionSpec(elementOptionPtr->name, optionTable);
+
+ /*
+ * Check that the widget option type is compatible with one of the
+ * element's required types.
+ */
+
+ if ( elementOptionPtr->type == TK_OPTION_END
+ || elementOptionPtr->type == widgetOptionPtr->type) {
+ widgetSpecPtr->optionsPtr[i] = widgetOptionPtr;
+ } else {
+ widgetSpecPtr->optionsPtr[i] = NULL;
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeWidgetSpec --
+ *
+ * Free a widget spec and its associated data.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Memory freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeWidgetSpec(widgetSpecPtr)
+ StyledWidgetSpec *widgetSpecPtr; /* The widget spec to free. */
+{
+ ckfree((char *) widgetSpecPtr->optionsPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * GetWidgetSpec --
+ *
+ * Return a new or existing widget spec for the given element and
+ * widget type (identified by its option table).
+ *
+ * Results:
+ * A pointer to the matching widget spec.
+ *
+ * Side effects:
+ * Memory may be allocated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static StyledWidgetSpec *
+GetWidgetSpec(elementPtr, optionTable)
+ StyledElement *elementPtr; /* Styled element descriptor. */
+ Tk_OptionTable optionTable; /* The widget's option table. */
+{
+ StyledWidgetSpec *widgetSpecPtr;
+ int i;
+
+ /*
+ * Try to find an existing widget spec.
+ */
+
+ for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
+ widgetSpecPtr = elementPtr->widgetSpecs+i;
+ if (widgetSpecPtr->optionTable == optionTable) {
+ return widgetSpecPtr;
+ }
+ }
+
+ /*
+ * Create and initialize a new widget spec.
+ */
+
+ i = elementPtr->nbWidgetSpecs++;
+ elementPtr->widgetSpecs = (StyledWidgetSpec *) ckrealloc(
+ (char *) elementPtr->widgetSpecs,
+ sizeof(StyledWidgetSpec) * elementPtr->nbWidgetSpecs);
+ widgetSpecPtr = elementPtr->widgetSpecs+i;
+ InitWidgetSpec(widgetSpecPtr, elementPtr, optionTable);
+
+ return widgetSpecPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetStyledElement --
+ *
+ * This procedure returns a styled instance of the given element.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Cached data may be allocated or updated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_StyledElement
+Tk_GetStyledElement(style, elementId, optionTable)
+ Tk_Style style; /* The widget style. */
+ int elementId; /* Unique element ID. */
+ Tk_OptionTable optionTable; /* Option table for the widget. */
+{
+ Style *stylePtr = (Style *) style;
+ StyledElement *elementPtr;
+
+ /*
+ * Get an element implementation and call corresponding hook.
+ */
+
+ elementPtr = GetStyledElement((stylePtr?stylePtr->enginePtr:NULL),
+ elementId);
+ if (!elementPtr) {
+ return NULL;
+ }
+
+ return (Tk_StyledElement) GetWidgetSpec(elementPtr, optionTable);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetElementSize --
+ *
+ * This procedure computes the size of the given widget element according
+ * to its style.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Cached data may be allocated or updated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+Tk_GetElementSize(style, element, recordPtr, tkwin, width, height, inner, widthPtr,
+ heightPtr)
+ Tk_Style style; /* The widget style. */
+ Tk_StyledElement element; /* The styled element, previously
+ * returned by Tk_GetStyledElement. */
+ char *recordPtr; /* The widget record. */
+ Tk_Window tkwin; /* The widget window. */
+ int width, height; /* Requested size. */
+ int inner; /* Boolean. If TRUE, compute the outer
+ * size according to the requested
+ * minimum inner size. If FALSE, compute
+ * the inner size according to the
+ * requested maximum outer size. */
+ int *widthPtr, *heightPtr; /* Returned size. */
+{
+ Style *stylePtr = (Style *) style;
+ StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
+
+ widgetSpecPtr->elementPtr->specPtr->getSize(stylePtr->clientData,
+ recordPtr, widgetSpecPtr->optionsPtr, tkwin, width, height, inner,
+ widthPtr, heightPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetElementBox --
+ *
+ * This procedure computes the bounding or inscribed box coordinates
+ * of the given widget element according to its style and within the
+ * given limits.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Cached data may be allocated or updated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+Tk_GetElementBox(style, element, recordPtr, tkwin, x, y, width, height, inner,
+ xPtr, yPtr, widthPtr, heightPtr)
+ Tk_Style style; /* The widget style. */
+ Tk_StyledElement element; /* The styled element, previously
+ * returned by Tk_GetStyledElement. */
+ char *recordPtr; /* The widget record. */
+ Tk_Window tkwin; /* The widget window. */
+ int x, y; /* Top left corner of available area. */
+ int width, height; /* Size of available area. */
+ int inner; /* Boolean. If TRUE, compute the
+ * bounding box according to the
+ * requested inscribed box size. If
+ * FALSE, compute the inscribed box
+ * according to the requested bounding
+ * box. */
+ int *xPtr, *yPtr; /* Returned top left corner. */
+ int *widthPtr, *heightPtr; /* Returned size. */
+{
+ Style *stylePtr = (Style *) style;
+ StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
+
+ widgetSpecPtr->elementPtr->specPtr->getBox(stylePtr->clientData,
+ recordPtr, widgetSpecPtr->optionsPtr, tkwin, x, y, width, height,
+ inner, xPtr, yPtr, widthPtr, heightPtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetElementBorderWidth --
+ *
+ * This procedure computes the border widthof the given widget element
+ * according to its style and within the given limits.
+ *
+ * Results:
+ * Border width in pixels. This value is uniform for all four sides.
+ *
+ * Side effects:
+ * Cached data may be allocated or updated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+Tk_GetElementBorderWidth(style, element, recordPtr, tkwin)
+ Tk_Style style; /* The widget style. */
+ Tk_StyledElement element; /* The styled element, previously
+ * returned by Tk_GetStyledElement. */
+ char *recordPtr; /* The widget record. */
+ Tk_Window tkwin; /* The widget window. */
+{
+ Style *stylePtr = (Style *) style;
+ StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
+
+ return widgetSpecPtr->elementPtr->specPtr->getBorderWidth(
+ stylePtr->clientData, recordPtr, widgetSpecPtr->optionsPtr, tkwin);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_DrawElement --
+ *
+ * This procedure draw the given widget element in a given drawable area.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Cached data may be allocated or updated.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+Tk_DrawElement(style, element, recordPtr, tkwin, d, x, y, width, height, state)
+ Tk_Style style; /* The widget style. */
+ Tk_StyledElement element; /* The styled element, previously
+ * returned by Tk_GetStyledElement. */
+ char *recordPtr; /* The widget record. */
+ Tk_Window tkwin; /* The widget window. */
+ Drawable d; /* Where to draw element. */
+ int x, y; /* Top left corner of element. */
+ int width, height; /* Size of element. */
+ int state; /* Drawing state flags. */
+{
+ Style *stylePtr = (Style *) style;
+ StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
+
+ widgetSpecPtr->elementPtr->specPtr->draw(stylePtr->clientData,
+ recordPtr, widgetSpecPtr->optionsPtr, tkwin, d, x, y, width,
+ height, state);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_CreateStyle --
+ *
+ * This procedure is called to create a new style as an instance of the
+ * given engine. Styles are stored in thread-local space.
+ *
+ * Results:
+ * The newly allocated style.
+ *
+ * Side effects:
+ * Memory allocated. Data added to thread-local table. The style's
+ * refCount is incremented.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_Style
+Tk_CreateStyle(name, engine, clientData)
+ CONST char *name; /* Name of the style to create. NULL or empty
+ * means the default system style. */
+ Tk_StyleEngine engine; /* The style engine. */
+ ClientData clientData; /* Private data passed as is to engine code. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr;
+ int newEntry;
+ Style *stylePtr;
+
+ /*
+ * Attempt to create a new entry in the style table.
+ */
+
+ entryPtr = Tcl_CreateHashEntry(&tsdPtr->styleTable, (name?name:""),
+ &newEntry);
+ if (!newEntry) {
+ /*
+ * A style was already registered by that name.
+ */
+
+ return NULL;
+ }
+
+ /*
+ * Allocate and intitialize a new style.
+ */
+
+ stylePtr = (Style *) ckalloc(sizeof(Style));
+ InitStyle(stylePtr, entryPtr, Tcl_GetHashKey(&tsdPtr->styleTable, entryPtr),
+ (engine?(StyleEngine *) engine:tsdPtr->defaultEnginePtr), clientData);
+ Tcl_SetHashValue(entryPtr, (ClientData) stylePtr);
+ stylePtr->refCount++;
+
+ return (Tk_Style) stylePtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_NameOfStyle --
+ *
+ * Given a style, return its registered name.
+ *
+ * Results:
+ * The return value is the name that was passed to Tk_CreateStyle() to
+ * create the style. The storage for the returned string is private
+ * (it points to the corresponding hash key) The caller should not modify
+ * this string.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+CONST char *
+Tk_NameOfStyle(style)
+ Tk_Style style; /* Style whose name is desired. */
+{
+ Style *stylePtr = (Style *) style;
+
+ return stylePtr->name;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * InitStyle --
+ *
+ * Initialize a newly allocated style.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+InitStyle(stylePtr, hashPtr, name, enginePtr, clientData)
+ Style *stylePtr; /* Points to an uninitialized style. */
+ Tcl_HashEntry *hashPtr; /* Hash entry for the registered style. */
+ CONST char *name; /* Name of the registered style. NULL or empty
+ * means the default system style. Usually
+ * points to the hash key. */
+ StyleEngine *enginePtr; /* The style engine. */
+ ClientData clientData; /* Private data passed as is to engine code. */
+{
+ stylePtr->refCount = 0;
+ stylePtr->hashPtr = hashPtr;
+ stylePtr->name = name;
+ stylePtr->enginePtr = enginePtr;
+ stylePtr->clientData = clientData;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeStyle --
+ *
+ * Free a style and its associated data.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeStyle(stylePtr)
+ Style *stylePtr; /* The style to free. */
+{
+ /* Nothing to do. */
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_GetStyle --
+ *
+ * Retrieve a registered style by its name.
+ *
+ * Results:
+ * A pointer to the style engine, or NULL if none found. In the latter
+ * case and if the interp is not NULL, an error message is left in the
+ * interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_Style
+Tk_GetStyle(interp, name)
+ Tcl_Interp *interp; /* Interp for error return. */
+ CONST char *name; /* Name of the style to retrieve. NULL or empty
+ * means the default system style. */
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ Tcl_HashEntry *entryPtr;
+ Style *stylePtr;
+
+ /*
+ * Search for a corresponding entry in the style table.
+ */
+
+ entryPtr = Tcl_FindHashEntry(&tsdPtr->styleTable, (name?name:""));
+ if (entryPtr == NULL) {
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "style \"", name, "\" doesn't exist", NULL);
+ }
+ return (Tk_Style) NULL;
+ }
+ stylePtr = (Style *) Tcl_GetHashValue(entryPtr);
+ stylePtr->refCount++;
+
+ return (Tk_Style) stylePtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_FreeStyle --
+ *
+ * Free a style previously created by Tk_CreateStyle.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * The style's refCount is decremented. If it reaches zero, the style
+ * is freed.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+Tk_FreeStyle(style)
+ Tk_Style style; /* The style to free. */
+{
+ Style *stylePtr = (Style *) style;
+
+ if (stylePtr == NULL) {
+ return;
+ }
+ stylePtr->refCount--;
+ if (stylePtr->refCount > 0) {
+ return;
+ }
+
+ /*
+ * Keep the default style alive.
+ */
+
+ if (*stylePtr->name == '\0') {
+ stylePtr->refCount = 1;
+ return;
+ }
+
+ Tcl_DeleteHashEntry(stylePtr->hashPtr);
+ FreeStyle(stylePtr);
+ ckfree((char *) stylePtr);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_AllocStyleFromObj --
+ *
+ * Map the string name of a style to a corresponding Tk_Style. The style
+ * must have already been created by Tk_CreateStyle.
+ *
+ * Results:
+ * The return value is a token for the style that matches objPtr, or
+ * NULL if none found. If NULL is returned, an error message will be
+ * left in interp's result object.
+ *
+ * Side effects:
+ * The style's reference count is incremented. For each call to this
+ * procedure, there should eventually be a call to Tk_FreeStyle() or
+ * Tk_FreeStyleFromObj() so that the database is cleaned up when styles
+ * aren't in use anymore.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+Tk_Style
+Tk_AllocStyleFromObj(interp, objPtr)
+ Tcl_Interp *interp; /* Interp for error return. */
+ Tcl_Obj *objPtr; /* Object containing name of the style to
+ * retrieve. */
+{
+ Style *stylePtr;
+
+ if (objPtr->typePtr != &styleObjType) {
+ SetStyleFromAny(interp, objPtr);
+ stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
+ } else {
+ stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
+ stylePtr->refCount++;
+ }
+
+ return (Tk_Style) stylePtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_GetStyleFromObj --
+ *
+ * Find the style that corresponds to a given object. The style must
+ * have already been created by Tk_CreateStyle.
+ *
+ * Results:
+ * The return value is a token for the style that matches objPtr, or
+ * NULL if none found.
+ *
+ * Side effects:
+ * If the object is not already a style ref, the conversion will free
+ * any old internal representation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Tk_Style
+Tk_GetStyleFromObj(objPtr)
+ Tcl_Obj *objPtr; /* The object from which to get the style. */
+{
+ if (objPtr->typePtr != &styleObjType) {
+ SetStyleFromAny((Tcl_Interp *) NULL, objPtr);
+ }
+
+ return (Tk_Style) objPtr->internalRep.otherValuePtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Tk_FreeStyleFromObj --
+ *
+ * Called to release a style inside a Tcl_Obj *.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If the object is a style ref, the conversion will free its
+ * internal representation.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+Tk_FreeStyleFromObj(objPtr)
+ Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
+{
+ if (objPtr->typePtr == &styleObjType) {
+ FreeStyleObjProc(objPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SetStyleFromAny --
+ *
+ * Convert the internal representation of a Tcl object to the
+ * style internal form.
+ *
+ * Results:
+ * Always returns TCL_OK. If an error occurs is returned (e.g. the
+ * style doesn't exist), an error message will be left in interp's
+ * result.
+ *
+ * Side effects:
+ * The object is left with its typePtr pointing to styleObjType.
+ * The reference count is incremented (in Tk_GetStyle()).
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+SetStyleFromAny(interp, objPtr)
+ Tcl_Interp *interp; /* Used for error reporting if not NULL. */
+ Tcl_Obj *objPtr; /* The object to convert. */
+{
+ Tcl_ObjType *typePtr;
+ char *name;
+
+ /*
+ * Free the old internalRep before setting the new one.
+ */
+
+ name = Tcl_GetString(objPtr);
+ typePtr = objPtr->typePtr;
+ if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
+ (*typePtr->freeIntRepProc)(objPtr);
+ }
+
+ objPtr->typePtr = &styleObjType;
+ objPtr->internalRep.otherValuePtr = (VOID *) Tk_GetStyle(interp, name);
+
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FreeStyleObjProc --
+ *
+ * This proc is called to release an object reference to a style.
+ * Called when the object's internal rep is released.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The reference count is decremented (in Tk_FreeStyle()).
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+FreeStyleObjProc(objPtr)
+ Tcl_Obj *objPtr; /* The object we are releasing. */
+{
+ Style *stylePtr = (Style *) objPtr->internalRep.otherValuePtr;
+
+ if (stylePtr != NULL) {
+ Tk_FreeStyle((Tk_Style) stylePtr);
+ objPtr->internalRep.otherValuePtr = NULL;
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DupStyleObjProc --
+ *
+ * When a cached style object is duplicated, this is called to
+ * update the internal reps.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The style's refCount is incremented and the internal rep of the copy
+ * is set to point to it.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+static void
+DupStyleObjProc(srcObjPtr, dupObjPtr)
+ Tcl_Obj *srcObjPtr; /* The object we are copying from. */
+ Tcl_Obj *dupObjPtr; /* The object we are copying to. */
+{
+ Style *stylePtr = (Style *) srcObjPtr->internalRep.otherValuePtr;
+
+ dupObjPtr->typePtr = srcObjPtr->typePtr;
+ dupObjPtr->internalRep.otherValuePtr = (VOID *) stylePtr;
+
+ if (stylePtr != NULL) {
+ stylePtr->refCount++;
+ }
+}