1 /*
2  * tkStyle.c --
3  *
4  *	This file implements the widget styles and themes support.
5  *
6  * Copyright (c) 1990-1993 The Regents of the University of California.
7  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution of
10  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  */
12 
13 #include "tkInt.h"
14 
15 /*
16  * The following structure is used to cache widget option specs matching an
17  * element's required options defined by Tk_ElementOptionSpecs. It also holds
18  * information behind Tk_StyledElement opaque tokens.
19  */
20 
21 typedef struct StyledWidgetSpec {
22     struct StyledElement *elementPtr;
23 				/* Pointer to the element holding this
24 				 * structure. */
25     Tk_OptionTable optionTable;	/* Option table for the widget class using the
26 				 * element. */
27     const Tk_OptionSpec **optionsPtr;
28 				/* Table of option spec pointers, matching the
29 				 * option list provided during element
30 				 * registration. Malloc'd. */
31 } StyledWidgetSpec;
32 
33 /*
34  * Elements are declared using static templates. But static information must
35  * be completed by dynamic information only accessible at runtime. For each
36  * registered element, an instance of the following structure is stored in
37  * each style engine and used to cache information about the widget types
38  * (identified by their optionTable) that use the given element.
39  */
40 
41 typedef struct StyledElement {
42     struct Tk_ElementSpec *specPtr;
43 				/* Filled with template provided during
44 				 * registration. NULL means no implementation
45 				 * is available for the current engine. */
46     int nbWidgetSpecs;		/* Size of the array below. Number of distinct
47 				 * widget classes (actually, distinct option
48 				 * tables) that used the element so far. */
49     StyledWidgetSpec *widgetSpecs;
50 				/* See above for the structure definition.
51 				 * Table grows dynamically as new widgets use
52 				 * the element. Malloc'd. */
53 } StyledElement;
54 
55 /*
56  * The following structure holds information behind Tk_StyleEngine opaque
57  * tokens.
58  */
59 
60 typedef struct StyleEngine {
61     const char *name;		/* Name of engine. Points to a hash key. */
62     StyledElement *elements;	/* Table of widget element descriptors. Each
63 				 * element is indexed by a unique system-wide
64 				 * ID. Table grows dynamically as new elements
65 				 * are registered. Malloc'd. */
66     struct StyleEngine *parentPtr;
67 				/* Parent engine. Engines may be layered to
68 				 * form a fallback chain, terminated by the
69 				 * default system engine. */
70 } StyleEngine;
71 
72 /*
73  * Styles are instances of style engines. The following structure holds
74  * information behind Tk_Style opaque tokens.
75  */
76 
77 typedef struct Style {
78     const char *name;		/* Name of style. Points to a hash key. */
79     StyleEngine *enginePtr;	/* Style engine of which the style is an
80 				 * instance. */
81     ClientData clientData;	/* Data provided during registration. */
82 } Style;
83 
84 /*
85  * Each registered element uses an instance of the following structure.
86  */
87 
88 typedef struct Element {
89     const char *name;		/* Name of element. Points to a hash key. */
90     int id;			/* Id of element. */
91     int genericId;		/* Id of generic element. */
92     int created;		/* Boolean, whether the element was created
93 				 * explicitly (was registered) or implicitly
94 				 * (by a derived element). */
95 } Element;
96 
97 /*
98  * Thread-local data.
99  */
100 
101 typedef struct ThreadSpecificData {
102     int nbInit;			/* Number of calls to the init proc. */
103     Tcl_HashTable engineTable;	/* Map a name to a style engine. Keys are
104 				 * strings, values are Tk_StyleEngine
105 				 * pointers. */
106     StyleEngine *defaultEnginePtr;
107 				/* Default, core-defined style engine. Global
108 				 * fallback for all engines. */
109     Tcl_HashTable styleTable;	/* Map a name to a style. Keys are strings,
110 				 * values are Tk_Style pointers.*/
111     int nbElements;		/* Size of the below tables. */
112     Tcl_HashTable elementTable;	/* Map a name to an element Id. Keys are
113 				 * strings, values are integer element IDs. */
114     Element *elements;		/* Array of Elements. */
115 } ThreadSpecificData;
116 
117 static Tcl_ThreadDataKey dataKey;
118 
119 /*
120  * Forward declarations for functions defined later in this file:
121  */
122 
123 static int		CreateElement(const char *name, int create);
124 static void		DupStyleObjProc(Tcl_Obj *srcObjPtr,
125 			    Tcl_Obj *dupObjPtr);
126 static void		FreeElement(Element *elementPtr);
127 static void		FreeStyledElement(StyledElement *elementPtr);
128 static void		FreeStyleEngine(StyleEngine *enginePtr);
129 static void		FreeStyleObjProc(Tcl_Obj *objPtr);
130 static void		FreeWidgetSpec(StyledWidgetSpec *widgetSpecPtr);
131 static StyledElement *	GetStyledElement(StyleEngine *enginePtr,
132 			    int elementId);
133 static StyledWidgetSpec*GetWidgetSpec(StyledElement *elementPtr,
134 			    Tk_OptionTable optionTable);
135 static void		InitElement(Element *elementPtr, const char *name,
136 			    int id, int genericId, int created);
137 static void		InitStyle(Style *stylePtr, const char *name,
138 			    StyleEngine *enginePtr, ClientData clientData);
139 static void		InitStyledElement(StyledElement *elementPtr);
140 static void		InitStyleEngine(StyleEngine *enginePtr,
141 			    const char *name, StyleEngine *parentPtr);
142 static void		InitWidgetSpec(StyledWidgetSpec *widgetSpecPtr,
143 			    StyledElement *elementPtr,
144 			    Tk_OptionTable optionTable);
145 static int		SetStyleFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
146 
147 /*
148  * The following structure defines the implementation of the "style" Tcl
149  * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of each style
150  * object points to the Style structure for the stylefont, or NULL.
151  */
152 
153 static Tcl_ObjType styleObjType = {
154     "style",			/* name */
155     FreeStyleObjProc,		/* freeIntRepProc */
156     DupStyleObjProc,		/* dupIntRepProc */
157     NULL,			/* updateStringProc */
158     SetStyleFromAny		/* setFromAnyProc */
159 };
160 
161 /*
162  *---------------------------------------------------------------------------
163  *
164  * TkStylePkgInit --
165  *
166  *	This function is called when an application is created. It initializes
167  *	all the structures that are used by the style package on a per
168  *	application basis.
169  *
170  * Results:
171  *	Stores data in thread-local storage.
172  *
173  * Side effects:
174  *	Memory allocated.
175  *
176  *---------------------------------------------------------------------------
177  */
178 
179 void
TkStylePkgInit(TkMainInfo * mainPtr)180 TkStylePkgInit(
181     TkMainInfo *mainPtr)	/* The application being created. */
182 {
183     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
184 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
185 
186     if (tsdPtr->nbInit != 0) {
187 	return;
188     }
189 
190     /*
191      * Initialize tables.
192      */
193 
194     Tcl_InitHashTable(&tsdPtr->engineTable, TCL_STRING_KEYS);
195     Tcl_InitHashTable(&tsdPtr->styleTable, TCL_STRING_KEYS);
196     Tcl_InitHashTable(&tsdPtr->elementTable, TCL_STRING_KEYS);
197     tsdPtr->nbElements = 0;
198     tsdPtr->elements = NULL;
199 
200     /*
201      * Create the default system engine.
202      */
203 
204     tsdPtr->defaultEnginePtr = (StyleEngine *)
205 	    Tk_RegisterStyleEngine(NULL, NULL);
206 
207     /*
208      * Create the default system style.
209      */
210 
211     Tk_CreateStyle(NULL, (Tk_StyleEngine) tsdPtr->defaultEnginePtr,
212 	    (ClientData) 0);
213 
214     tsdPtr->nbInit++;
215 }
216 
217 /*
218  *---------------------------------------------------------------------------
219  *
220  * TkStylePkgFree --
221  *
222  *	This function is called when an application is deleted. It deletes all
223  *	the structures that were used by the style package for this
224  *	application.
225  *
226  * Results:
227  *	None.
228  *
229  * Side effects:
230  *	Memory freed.
231  *
232  *---------------------------------------------------------------------------
233  */
234 
235 void
TkStylePkgFree(TkMainInfo * mainPtr)236 TkStylePkgFree(
237     TkMainInfo *mainPtr)	/* The application being deleted. */
238 {
239     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
240 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
241     Tcl_HashSearch search;
242     Tcl_HashEntry *entryPtr;
243     StyleEngine *enginePtr;
244     int i;
245 
246     tsdPtr->nbInit--;
247     if (tsdPtr->nbInit != 0) {
248 	return;
249     }
250 
251     /*
252      * Free styles.
253      */
254 
255     entryPtr = Tcl_FirstHashEntry(&tsdPtr->styleTable, &search);
256     while (entryPtr != NULL) {
257 	ckfree((char *) Tcl_GetHashValue(entryPtr));
258 	entryPtr = Tcl_NextHashEntry(&search);
259     }
260     Tcl_DeleteHashTable(&tsdPtr->styleTable);
261 
262     /*
263      * Free engines.
264      */
265 
266     entryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
267     while (entryPtr != NULL) {
268 	enginePtr = (StyleEngine *) Tcl_GetHashValue(entryPtr);
269 	FreeStyleEngine(enginePtr);
270 	ckfree((char *) enginePtr);
271 	entryPtr = Tcl_NextHashEntry(&search);
272     }
273     Tcl_DeleteHashTable(&tsdPtr->engineTable);
274 
275     /*
276      * Free elements.
277      */
278 
279     for (i = 0; i < tsdPtr->nbElements; i++) {
280 	FreeElement(tsdPtr->elements+i);
281     }
282     Tcl_DeleteHashTable(&tsdPtr->elementTable);
283     ckfree((char *) tsdPtr->elements);
284 }
285 
286 /*
287  *---------------------------------------------------------------------------
288  *
289  * Tk_RegisterStyleEngine --
290  *
291  *	This function is called to register a new style engine. Style engines
292  *	are stored in thread-local space.
293  *
294  * Results:
295  *	The newly allocated engine, or NULL if an engine with the same name
296  *	exists.
297  *
298  * Side effects:
299  *	Memory allocated. Data added to thread-local table.
300  *
301  *---------------------------------------------------------------------------
302  */
303 
304 Tk_StyleEngine
Tk_RegisterStyleEngine(const char * name,Tk_StyleEngine parent)305 Tk_RegisterStyleEngine(
306     const char *name,		/* Name of the engine to create. NULL or empty
307 				 * means the default system engine. */
308     Tk_StyleEngine parent)	/* The engine's parent. NULL means the default
309 				 * system engine. */
310 {
311     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
312 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
313     Tcl_HashEntry *entryPtr;
314     int newEntry;
315     StyleEngine *enginePtr;
316 
317     /*
318      * Attempt to create a new entry in the engine table.
319      */
320 
321     entryPtr = Tcl_CreateHashEntry(&tsdPtr->engineTable,
322 	    (name != NULL ? name : ""), &newEntry);
323     if (!newEntry) {
324 	/*
325 	 * An engine was already registered by that name.
326 	 */
327 
328 	return NULL;
329     }
330 
331     /*
332      * Allocate and intitialize a new engine.
333      */
334 
335     enginePtr = (StyleEngine *) ckalloc(sizeof(StyleEngine));
336     InitStyleEngine(enginePtr, Tcl_GetHashKey(&tsdPtr->engineTable, entryPtr),
337 	    (StyleEngine *) parent);
338     Tcl_SetHashValue(entryPtr, (ClientData) enginePtr);
339 
340     return (Tk_StyleEngine) enginePtr;
341 }
342 
343 /*
344  *---------------------------------------------------------------------------
345  *
346  * InitStyleEngine --
347  *
348  *	Initialize a newly allocated style engine.
349  *
350  * Results:
351  *	None.
352  *
353  * Side effects:
354  *	Memory allocated.
355  *
356  *---------------------------------------------------------------------------
357  */
358 
359 static void
InitStyleEngine(StyleEngine * enginePtr,const char * name,StyleEngine * parentPtr)360 InitStyleEngine(
361     StyleEngine *enginePtr,	/* Points to an uninitialized engine. */
362     const char *name,		/* Name of the registered engine. NULL or empty
363 				 * means the default system engine. Usually
364 				 * points to the hash key. */
365     StyleEngine *parentPtr)	/* The engine's parent. NULL means the default
366 				 * system engine. */
367 {
368     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
369 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
370     int elementId;
371 
372     if (name == NULL || *name == '\0') {
373 	/*
374 	 * This is the default style engine.
375 	 */
376 
377 	enginePtr->parentPtr = NULL;
378     } else if (parentPtr == NULL) {
379 	/*
380 	 * The default style engine is the parent.
381 	 */
382 
383 	enginePtr->parentPtr = tsdPtr->defaultEnginePtr;
384     } else {
385 	enginePtr->parentPtr = parentPtr;
386     }
387 
388     /*
389      * Allocate and initialize elements array.
390      */
391 
392     if (tsdPtr->nbElements > 0) {
393 	enginePtr->elements = (StyledElement *) ckalloc(
394 		sizeof(StyledElement) * tsdPtr->nbElements);
395 	for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
396 	    InitStyledElement(enginePtr->elements+elementId);
397 	}
398     } else {
399 	enginePtr->elements = NULL;
400     }
401 }
402 
403 /*
404  *---------------------------------------------------------------------------
405  *
406  * FreeStyleEngine --
407  *
408  *	Free an engine and its associated data.
409  *
410  * Results:
411  *	None
412  *
413  * Side effects:
414  *	Memory freed.
415  *
416  *---------------------------------------------------------------------------
417  */
418 
419 static void
FreeStyleEngine(StyleEngine * enginePtr)420 FreeStyleEngine(
421     StyleEngine *enginePtr)	/* The style engine to free. */
422 {
423     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
424 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
425     int elementId;
426 
427     /*
428      * Free allocated elements.
429      */
430 
431     for (elementId = 0; elementId < tsdPtr->nbElements; elementId++) {
432 	FreeStyledElement(enginePtr->elements+elementId);
433     }
434     ckfree((char *) enginePtr->elements);
435 }
436 
437 /*
438  *---------------------------------------------------------------------------
439  *
440  * Tk_GetStyleEngine --
441  *
442  *	Retrieve a registered style engine by its name.
443  *
444  * Results:
445  *	A pointer to the style engine, or NULL if none found.
446  *
447  * Side effects:
448  *	None.
449  *
450  *---------------------------------------------------------------------------
451  */
452 
453 Tk_StyleEngine
Tk_GetStyleEngine(const char * name)454 Tk_GetStyleEngine(
455     const char *name)		/* Name of the engine to retrieve. NULL or
456 				 * empty means the default system engine. */
457 {
458     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
459 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
460     Tcl_HashEntry *entryPtr;
461 
462     if (name == NULL) {
463 	return (Tk_StyleEngine) tsdPtr->defaultEnginePtr;
464     }
465 
466     entryPtr = Tcl_FindHashEntry(&tsdPtr->engineTable, (name!=NULL?name:""));
467     if (!entryPtr) {
468 	return NULL;
469     }
470 
471     return (Tk_StyleEngine) Tcl_GetHashValue(entryPtr);
472 }
473 
474 /*
475  *---------------------------------------------------------------------------
476  *
477  * InitElement --
478  *
479  *	Initialize a newly allocated element.
480  *
481  * Results:
482  *	None.
483  *
484  * Side effects:
485  *	None.
486  *
487  *---------------------------------------------------------------------------
488  */
489 
490 static void
InitElement(Element * elementPtr,const char * name,int id,int genericId,int created)491 InitElement(
492     Element *elementPtr,	/* Points to an uninitialized element.*/
493     const char *name,		/* Name of the registered element. Usually
494 				 * points to the hash key. */
495     int id,			/* Unique element ID. */
496     int genericId,		/* ID of generic element. -1 means none. */
497     int created)		/* Boolean, whether the element was created
498 				 * explicitly (was registered) or implicitly
499 				 * (by a derived element). */
500 {
501     elementPtr->name = name;
502     elementPtr->id = id;
503     elementPtr->genericId = genericId;
504     elementPtr->created = (created?1:0);
505 }
506 
507 /*
508  *---------------------------------------------------------------------------
509  *
510  * FreeElement --
511  *
512  *	Free an element and its associated data.
513  *
514  * Results:
515  *	None.
516  *
517  * Side effects:
518  *	Memory freed.
519  *
520  *---------------------------------------------------------------------------
521  */
522 
523 static void
FreeElement(Element * elementPtr)524 FreeElement(
525     Element *elementPtr)	/* The element to free. */
526 {
527     /* Nothing to do. */
528 }
529 
530 /*
531  *---------------------------------------------------------------------------
532  *
533  * InitStyledElement --
534  *
535  *	Initialize a newly allocated styled element.
536  *
537  * Results:
538  *	None.
539  *
540  * Side effects:
541  *	None.
542  *
543  *---------------------------------------------------------------------------
544  */
545 
546 static void
InitStyledElement(StyledElement * elementPtr)547 InitStyledElement(
548     StyledElement *elementPtr)	/* Points to an uninitialized element.*/
549 {
550     memset(elementPtr, 0, sizeof(StyledElement));
551 }
552 
553 /*
554  *---------------------------------------------------------------------------
555  *
556  * FreeStyledElement --
557  *
558  *	Free a styled element and its associated data.
559  *
560  * Results:
561  *	None.
562  *
563  * Side effects:
564  *	Memory freed.
565  *
566  *---------------------------------------------------------------------------
567  */
568 
569 static void
FreeStyledElement(StyledElement * elementPtr)570 FreeStyledElement(
571     StyledElement *elementPtr)	/* The styled element to free. */
572 {
573     int i;
574 
575     /*
576      * Free allocated widget specs.
577      */
578 
579     for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
580 	FreeWidgetSpec(elementPtr->widgetSpecs+i);
581     }
582     ckfree((char *) elementPtr->widgetSpecs);
583 }
584 
585 /*
586  *---------------------------------------------------------------------------
587  *
588  * CreateElement --
589  *
590  *	Find an existing or create a new element.
591  *
592  * Results:
593  *	The unique ID for the created or found element.
594  *
595  * Side effects:
596  *	Memory allocated.
597  *
598  *---------------------------------------------------------------------------
599  */
600 
601 static int
CreateElement(const char * name,int create)602 CreateElement(
603     const char *name,		/* Name of the element. */
604     int create)			/* Boolean, whether the element is being
605 				 * created explicitly (being registered) or
606 				 * implicitly (by a derived element). */
607 {
608     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
609 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
610     Tcl_HashEntry *entryPtr, *engineEntryPtr;
611     Tcl_HashSearch search;
612     int newEntry, elementId, genericId = -1;
613     char *dot;
614     StyleEngine *enginePtr;
615 
616     /*
617      * Find or create the element.
618      */
619 
620     entryPtr = Tcl_CreateHashEntry(&tsdPtr->elementTable, name, &newEntry);
621     if (!newEntry) {
622 	elementId = PTR2INT(Tcl_GetHashValue(entryPtr));
623 	if (create) {
624 	    tsdPtr->elements[elementId].created = 1;
625 	}
626 	return elementId;
627     }
628 
629     /*
630      * The element didn't exist. If it's a derived element, find or create its
631      * generic element ID.
632      */
633 
634     dot = strchr(name, '.');
635     if (dot) {
636 	genericId = CreateElement(dot+1, 0);
637     }
638 
639     elementId = tsdPtr->nbElements++;
640     Tcl_SetHashValue(entryPtr, (ClientData) INT2PTR(elementId));
641 
642     /*
643      * Reallocate element table.
644      */
645 
646     tsdPtr->elements = (Element *) ckrealloc((char *) tsdPtr->elements,
647 	    sizeof(Element) * tsdPtr->nbElements);
648     InitElement(tsdPtr->elements+elementId,
649 	    Tcl_GetHashKey(&tsdPtr->elementTable, entryPtr), elementId,
650 	    genericId, create);
651 
652     /*
653      * Reallocate style engines' element table.
654      */
655 
656     engineEntryPtr = Tcl_FirstHashEntry(&tsdPtr->engineTable, &search);
657     while (engineEntryPtr != NULL) {
658 	enginePtr = (StyleEngine *) Tcl_GetHashValue(engineEntryPtr);
659 
660 	enginePtr->elements = (StyledElement *) ckrealloc(
661 		(char *) enginePtr->elements,
662 		sizeof(StyledElement) * tsdPtr->nbElements);
663 	InitStyledElement(enginePtr->elements+elementId);
664 
665 	engineEntryPtr = Tcl_NextHashEntry(&search);
666     }
667 
668     return elementId;
669 }
670 
671 /*
672  *---------------------------------------------------------------------------
673  *
674  * Tk_GetElementId --
675  *
676  *	Find an existing element.
677  *
678  * Results:
679  *	The unique ID for the found element, or -1 if not found.
680  *
681  * Side effects:
682  *	Generic elements may be created.
683  *
684  *---------------------------------------------------------------------------
685  */
686 
687 int
Tk_GetElementId(const char * name)688 Tk_GetElementId(
689     const char *name)		/* Name of the element. */
690 {
691     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
692 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
693     Tcl_HashEntry *entryPtr;
694     int genericId = -1;
695     char *dot;
696 
697     /*
698      * Find the element Id.
699      */
700 
701     entryPtr = Tcl_FindHashEntry(&tsdPtr->elementTable, name);
702     if (entryPtr) {
703 	return PTR2INT(Tcl_GetHashValue(entryPtr));
704     }
705 
706     /*
707      * Element not found. If the given name was derived, then first search for
708      * the generic element. If found, create the new derived element.
709      */
710 
711     dot = strchr(name, '.');
712     if (!dot) {
713 	return -1;
714     }
715     genericId = Tk_GetElementId(dot+1);
716     if (genericId == -1) {
717 	return -1;
718     }
719     if (!tsdPtr->elements[genericId].created) {
720 	/*
721 	 * The generic element was created implicitly and thus has no real
722 	 * existence.
723 	 */
724 
725 	return -1;
726     } else {
727 	/*
728 	 * The generic element was created explicitly. Create the derived
729 	 * element.
730 	 */
731 
732 	return CreateElement(name, 1);
733     }
734 }
735 
736 /*
737  *---------------------------------------------------------------------------
738  *
739  * Tk_RegisterStyledElement --
740  *
741  *	Register an implementation of a new or existing element for the given
742  *	style engine.
743  *
744  * Results:
745  *	The unique ID for the created or found element.
746  *
747  * Side effects:
748  *	Elements may be created. Memory allocated.
749  *
750  *---------------------------------------------------------------------------
751  */
752 
753 int
Tk_RegisterStyledElement(Tk_StyleEngine engine,Tk_ElementSpec * templatePtr)754 Tk_RegisterStyledElement(
755     Tk_StyleEngine engine,	/* Style engine providing the
756 				 * implementation. */
757     Tk_ElementSpec *templatePtr)/* Static template information about the
758 				 * element. */
759 {
760     int elementId;
761     StyledElement *elementPtr;
762     Tk_ElementSpec *specPtr;
763     int nbOptions;
764     register Tk_ElementOptionSpec *srcOptions, *dstOptions;
765 
766     if (templatePtr->version != TK_STYLE_VERSION_1) {
767 	/*
768 	 * Version mismatch. Do nothing.
769 	 */
770 
771 	return -1;
772     }
773 
774     if (engine == NULL) {
775 	engine = Tk_GetStyleEngine(NULL);
776     }
777 
778     /*
779      * Register the element, allocating storage in the various engines if
780      * necessary.
781      */
782 
783     elementId = CreateElement(templatePtr->name, 1);
784 
785     /*
786      * Initialize the styled element.
787      */
788 
789     elementPtr = ((StyleEngine *) engine)->elements+elementId;
790 
791     specPtr = (Tk_ElementSpec *) ckalloc(sizeof(Tk_ElementSpec));
792     specPtr->version = templatePtr->version;
793     specPtr->name = ckalloc(strlen(templatePtr->name)+1);
794     strcpy(specPtr->name, templatePtr->name);
795     nbOptions = 0;
796     for (nbOptions = 0, srcOptions = templatePtr->options;
797 	    srcOptions->name != NULL; nbOptions++, srcOptions++) {
798 	/* empty body */
799     }
800     specPtr->options = (Tk_ElementOptionSpec *)
801 	    ckalloc(sizeof(Tk_ElementOptionSpec) * (nbOptions+1));
802     for (srcOptions = templatePtr->options, dstOptions = specPtr->options;
803 	    /* End condition within loop */; srcOptions++, dstOptions++) {
804 	if (srcOptions->name == NULL) {
805 	    dstOptions->name = NULL;
806 	    break;
807 	}
808 
809 	dstOptions->name = ckalloc(strlen(srcOptions->name)+1);
810 	strcpy(dstOptions->name, srcOptions->name);
811 	dstOptions->type = srcOptions->type;
812     }
813     specPtr->getSize = templatePtr->getSize;
814     specPtr->getBox = templatePtr->getBox;
815     specPtr->getBorderWidth = templatePtr->getBorderWidth;
816     specPtr->draw = templatePtr->draw;
817 
818     elementPtr->specPtr = specPtr;
819     elementPtr->nbWidgetSpecs = 0;
820     elementPtr->widgetSpecs = NULL;
821 
822     return elementId;
823 }
824 
825 /*
826  *---------------------------------------------------------------------------
827  *
828  * GetStyledElement --
829  *
830  *	Get a registered implementation of an existing element for the given
831  *	style engine.
832  *
833  * Results:
834  *	The styled element descriptor, or NULL if not found.
835  *
836  * Side effects:
837  *	None.
838  *
839  *---------------------------------------------------------------------------
840  */
841 
842 static StyledElement *
GetStyledElement(StyleEngine * enginePtr,int elementId)843 GetStyledElement(
844     StyleEngine *enginePtr,	/* Style engine providing the implementation.
845 				 * NULL means the default system engine. */
846     int elementId)		/* Unique element ID */
847 {
848     StyledElement *elementPtr;
849     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
850 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
851     StyleEngine *enginePtr2;
852 
853     if (enginePtr == NULL) {
854 	enginePtr = tsdPtr->defaultEnginePtr;
855     }
856 
857     while (elementId >= 0 && elementId < tsdPtr->nbElements) {
858 	/*
859 	 * Look for an implemented element through the engine chain.
860 	 */
861 
862 	enginePtr2 = enginePtr;
863 	do {
864 	    elementPtr = enginePtr2->elements+elementId;
865 	    if (elementPtr->specPtr != NULL) {
866 		return elementPtr;
867 	    }
868 	    enginePtr2 = enginePtr2->parentPtr;
869 	} while (enginePtr2 != NULL);
870 
871 	/*
872 	 * None found, try with the generic element.
873 	 */
874 
875 	elementId = tsdPtr->elements[elementId].genericId;
876     }
877 
878     /*
879      * No matching element found.
880      */
881 
882     return NULL;
883 }
884 
885 /*
886  *---------------------------------------------------------------------------
887  *
888  * InitWidgetSpec --
889  *
890  *	Initialize a newly allocated widget spec.
891  *
892  * Results:
893  *	None.
894  *
895  * Side effects:
896  *	Memory allocated.
897  *
898  *---------------------------------------------------------------------------
899  */
900 
901 static void
InitWidgetSpec(StyledWidgetSpec * widgetSpecPtr,StyledElement * elementPtr,Tk_OptionTable optionTable)902 InitWidgetSpec(
903     StyledWidgetSpec *widgetSpecPtr,
904 				/* Points to an uninitialized widget spec. */
905     StyledElement *elementPtr,	/* Styled element descriptor. */
906     Tk_OptionTable optionTable)	/* The widget's option table. */
907 {
908     int i, nbOptions;
909     Tk_ElementOptionSpec *elementOptionPtr;
910     const Tk_OptionSpec *widgetOptionPtr;
911 
912     widgetSpecPtr->elementPtr = elementPtr;
913     widgetSpecPtr->optionTable = optionTable;
914 
915     /*
916      * Count the number of options.
917      */
918 
919     for (nbOptions = 0, elementOptionPtr = elementPtr->specPtr->options;
920 	    elementOptionPtr->name != NULL; nbOptions++, elementOptionPtr++) {
921 	/* empty body */
922     }
923 
924     /*
925      * Build the widget option list.
926      */
927 
928     widgetSpecPtr->optionsPtr = (const Tk_OptionSpec **)
929 	    ckalloc(sizeof(Tk_OptionSpec *) * nbOptions);
930     for (i = 0, elementOptionPtr = elementPtr->specPtr->options;
931 	    i < nbOptions; i++, elementOptionPtr++) {
932 	widgetOptionPtr = TkGetOptionSpec(elementOptionPtr->name, optionTable);
933 
934 	/*
935 	 * Check that the widget option type is compatible with one of the
936 	 * element's required types.
937 	 */
938 
939 	if (elementOptionPtr->type == TK_OPTION_END
940 	    || elementOptionPtr->type == widgetOptionPtr->type) {
941 	    widgetSpecPtr->optionsPtr[i] = widgetOptionPtr;
942 	} else {
943 	    widgetSpecPtr->optionsPtr[i] = NULL;
944 	}
945     }
946 }
947 
948 /*
949  *---------------------------------------------------------------------------
950  *
951  * FreeWidgetSpec --
952  *
953  *	Free a widget spec and its associated data.
954  *
955  * Results:
956  *	None
957  *
958  * Side effects:
959  *	Memory freed.
960  *
961  *---------------------------------------------------------------------------
962  */
963 
964 static void
FreeWidgetSpec(StyledWidgetSpec * widgetSpecPtr)965 FreeWidgetSpec(
966     StyledWidgetSpec *widgetSpecPtr)
967 				/* The widget spec to free. */
968 {
969     ckfree((char *) widgetSpecPtr->optionsPtr);
970 }
971 
972 /*
973  *---------------------------------------------------------------------------
974  *
975  * GetWidgetSpec --
976  *
977  *	Return a new or existing widget spec for the given element and widget
978  *	type (identified by its option table).
979  *
980  * Results:
981  *	A pointer to the matching widget spec.
982  *
983  * Side effects:
984  *	Memory may be allocated.
985  *
986  *---------------------------------------------------------------------------
987  */
988 
989 static StyledWidgetSpec *
GetWidgetSpec(StyledElement * elementPtr,Tk_OptionTable optionTable)990 GetWidgetSpec(
991     StyledElement *elementPtr,	/* Styled element descriptor. */
992     Tk_OptionTable optionTable)	/* The widget's option table. */
993 {
994     StyledWidgetSpec *widgetSpecPtr;
995     int i;
996 
997     /*
998      * Try to find an existing widget spec.
999      */
1000 
1001     for (i = 0; i < elementPtr->nbWidgetSpecs; i++) {
1002 	widgetSpecPtr = elementPtr->widgetSpecs+i;
1003 	if (widgetSpecPtr->optionTable == optionTable) {
1004 	    return widgetSpecPtr;
1005 	}
1006     }
1007 
1008     /*
1009      * Create and initialize a new widget spec.
1010      */
1011 
1012     i = elementPtr->nbWidgetSpecs++;
1013     elementPtr->widgetSpecs = (StyledWidgetSpec *) ckrealloc(
1014 	    (char *) elementPtr->widgetSpecs,
1015 	    sizeof(StyledWidgetSpec) * elementPtr->nbWidgetSpecs);
1016     widgetSpecPtr = elementPtr->widgetSpecs+i;
1017     InitWidgetSpec(widgetSpecPtr, elementPtr, optionTable);
1018 
1019     return widgetSpecPtr;
1020 }
1021 
1022 /*
1023  *---------------------------------------------------------------------------
1024  *
1025  * Tk_GetStyledElement --
1026  *
1027  *	This function returns a styled instance of the given element.
1028  *
1029  * Results:
1030  *	None.
1031  *
1032  * Side effects:
1033  *	Cached data may be allocated or updated.
1034  *
1035  *---------------------------------------------------------------------------
1036  */
1037 
1038 Tk_StyledElement
Tk_GetStyledElement(Tk_Style style,int elementId,Tk_OptionTable optionTable)1039 Tk_GetStyledElement(
1040     Tk_Style style,		/* The widget style. */
1041     int elementId,		/* Unique element ID. */
1042     Tk_OptionTable optionTable)	/* Option table for the widget. */
1043 {
1044     Style *stylePtr = (Style *) style;
1045     StyledElement *elementPtr;
1046 
1047     /*
1048      * Get an element implementation and call corresponding hook.
1049      */
1050 
1051     elementPtr = GetStyledElement((stylePtr?stylePtr->enginePtr:NULL),
1052 	    elementId);
1053     if (!elementPtr) {
1054 	return NULL;
1055     }
1056 
1057     return (Tk_StyledElement) GetWidgetSpec(elementPtr, optionTable);
1058 }
1059 
1060 /*
1061  *---------------------------------------------------------------------------
1062  *
1063  * Tk_GetElementSize --
1064  *
1065  *	This function computes the size of the given widget element according
1066  *	to its style.
1067  *
1068  * Results:
1069  *	None.
1070  *
1071  * Side effects:
1072  *	Cached data may be allocated or updated.
1073  *
1074  *---------------------------------------------------------------------------
1075  */
1076 
1077 void
Tk_GetElementSize(Tk_Style style,Tk_StyledElement element,char * recordPtr,Tk_Window tkwin,int width,int height,int inner,int * widthPtr,int * heightPtr)1078 Tk_GetElementSize(
1079     Tk_Style style,		/* The widget style. */
1080     Tk_StyledElement element,	/* The styled element, previously returned by
1081 				 * Tk_GetStyledElement. */
1082     char *recordPtr,		/* The widget record. */
1083     Tk_Window tkwin,		/* The widget window. */
1084     int width, int height,	/* Requested size. */
1085     int inner,			/* If TRUE, compute the outer size according
1086 				 * to the requested minimum inner size. If
1087 				 * FALSE, compute the inner size according to
1088 				 * the requested maximum outer size. */
1089     int *widthPtr, int *heightPtr)
1090 				/* Returned size. */
1091 {
1092     Style *stylePtr = (Style *) style;
1093     StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
1094 
1095     widgetSpecPtr->elementPtr->specPtr->getSize(stylePtr->clientData,
1096 	    recordPtr, widgetSpecPtr->optionsPtr, tkwin, width, height, inner,
1097 	    widthPtr, heightPtr);
1098 }
1099 
1100 /*
1101  *---------------------------------------------------------------------------
1102  *
1103  * Tk_GetElementBox --
1104  *
1105  *	This function computes the bounding or inscribed box coordinates of
1106  *	the given widget element according to its style and within the given
1107  *	limits.
1108  *
1109  * Results:
1110  *	None.
1111  *
1112  * Side effects:
1113  *	Cached data may be allocated or updated.
1114  *
1115  *---------------------------------------------------------------------------
1116  */
1117 
1118 void
Tk_GetElementBox(Tk_Style style,Tk_StyledElement element,char * recordPtr,Tk_Window tkwin,int x,int y,int width,int height,int inner,int * xPtr,int * yPtr,int * widthPtr,int * heightPtr)1119 Tk_GetElementBox(
1120     Tk_Style style,		/* The widget style. */
1121     Tk_StyledElement element,	/* The styled element, previously returned by
1122 				 * Tk_GetStyledElement. */
1123     char *recordPtr,		/* The widget record. */
1124     Tk_Window tkwin,		/* The widget window. */
1125     int x, int y,		/* Top left corner of available area. */
1126     int width, int height,	/* Size of available area. */
1127     int inner,			/* Boolean. If TRUE, compute the bounding box
1128 				 * according to the requested inscribed box
1129 				 * size. If FALSE, compute the inscribed box
1130 				 * according to the requested bounding box. */
1131     int *xPtr, int *yPtr,	/* Returned top left corner. */
1132     int *widthPtr, int *heightPtr)
1133 				/* Returned size. */
1134 {
1135     Style *stylePtr = (Style *) style;
1136     StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
1137 
1138     widgetSpecPtr->elementPtr->specPtr->getBox(stylePtr->clientData,
1139 	    recordPtr, widgetSpecPtr->optionsPtr, tkwin, x, y, width, height,
1140 	    inner, xPtr, yPtr, widthPtr, heightPtr);
1141 }
1142 
1143 /*
1144  *---------------------------------------------------------------------------
1145  *
1146  * Tk_GetElementBorderWidth --
1147  *
1148  *	This function computes the border widthof the given widget element
1149  *	according to its style and within the given limits.
1150  *
1151  * Results:
1152  *	Border width in pixels. This value is uniform for all four sides.
1153  *
1154  * Side effects:
1155  *	Cached data may be allocated or updated.
1156  *
1157  *---------------------------------------------------------------------------
1158  */
1159 
1160 int
Tk_GetElementBorderWidth(Tk_Style style,Tk_StyledElement element,char * recordPtr,Tk_Window tkwin)1161 Tk_GetElementBorderWidth(
1162     Tk_Style style,		/* The widget style. */
1163     Tk_StyledElement element,	/* The styled element, previously returned by
1164 				 * Tk_GetStyledElement. */
1165     char *recordPtr,		/* The widget record. */
1166     Tk_Window tkwin)		/* The widget window. */
1167 {
1168     Style *stylePtr = (Style *) style;
1169     StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
1170 
1171     return widgetSpecPtr->elementPtr->specPtr->getBorderWidth(
1172 	    stylePtr->clientData, recordPtr, widgetSpecPtr->optionsPtr, tkwin);
1173 }
1174 
1175 /*
1176  *---------------------------------------------------------------------------
1177  *
1178  * Tk_DrawElement --
1179  *
1180  *	This function draw the given widget element in a given drawable area.
1181  *
1182  * Results:
1183  *	None
1184  *
1185  * Side effects:
1186  *	Cached data may be allocated or updated.
1187  *
1188  *---------------------------------------------------------------------------
1189  */
1190 
1191 void
Tk_DrawElement(Tk_Style style,Tk_StyledElement element,char * recordPtr,Tk_Window tkwin,Drawable d,int x,int y,int width,int height,int state)1192 Tk_DrawElement(
1193     Tk_Style style,		/* The widget style. */
1194     Tk_StyledElement element,	/* The styled element, previously returned by
1195 				 * Tk_GetStyledElement. */
1196     char *recordPtr,		/* The widget record. */
1197     Tk_Window tkwin,		/* The widget window. */
1198     Drawable d,			/* Where to draw element. */
1199     int x, int y,		/* Top left corner of element. */
1200     int width, int height,	/* Size of element. */
1201     int state)			/* Drawing state flags. */
1202 {
1203     Style *stylePtr = (Style *) style;
1204     StyledWidgetSpec *widgetSpecPtr = (StyledWidgetSpec *) element;
1205 
1206     widgetSpecPtr->elementPtr->specPtr->draw(stylePtr->clientData,
1207 	    recordPtr, widgetSpecPtr->optionsPtr, tkwin, d, x, y, width,
1208 	    height, state);
1209 }
1210 
1211 /*
1212  *---------------------------------------------------------------------------
1213  *
1214  * Tk_CreateStyle --
1215  *
1216  *	This function is called to create a new style as an instance of the
1217  *	given engine. Styles are stored in thread-local space.
1218  *
1219  * Results:
1220  *	The newly allocated style, or NULL if the style already exists.
1221  *
1222  * Side effects:
1223  *	Memory allocated. Data added to thread-local table.
1224  *
1225  *---------------------------------------------------------------------------
1226  */
1227 
1228 Tk_Style
Tk_CreateStyle(const char * name,Tk_StyleEngine engine,ClientData clientData)1229 Tk_CreateStyle(
1230     const char *name,		/* Name of the style to create. NULL or empty
1231 				 * means the default system style. */
1232     Tk_StyleEngine engine,	/* The style engine. */
1233     ClientData clientData)	/* Private data passed as is to engine code. */
1234 {
1235     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1236 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1237     Tcl_HashEntry *entryPtr;
1238     int newEntry;
1239     Style *stylePtr;
1240 
1241     /*
1242      * Attempt to create a new entry in the style table.
1243      */
1244 
1245     entryPtr = Tcl_CreateHashEntry(&tsdPtr->styleTable, (name?name:""),
1246 	    &newEntry);
1247     if (!newEntry) {
1248 	/*
1249 	 * A style was already registered by that name.
1250 	 */
1251 
1252 	return NULL;
1253     }
1254 
1255     /*
1256      * Allocate and intitialize a new style.
1257      */
1258 
1259     stylePtr = (Style *) ckalloc(sizeof(Style));
1260     InitStyle(stylePtr, Tcl_GetHashKey(&tsdPtr->styleTable, entryPtr),
1261 	    (engine!=NULL ? (StyleEngine *) engine : tsdPtr->defaultEnginePtr),
1262 	    clientData);
1263     Tcl_SetHashValue(entryPtr, (ClientData) stylePtr);
1264 
1265     return (Tk_Style) stylePtr;
1266 }
1267 
1268 /*
1269  *---------------------------------------------------------------------------
1270  *
1271  * Tk_NameOfStyle --
1272  *
1273  *	Given a style, return its registered name.
1274  *
1275  * Results:
1276  *	The return value is the name that was passed to Tk_CreateStyle() to
1277  *	create the style. The storage for the returned string is private (it
1278  *	points to the corresponding hash key) The caller should not modify
1279  *	this string.
1280  *
1281  * Side effects:
1282  *	None.
1283  *
1284  *---------------------------------------------------------------------------
1285  */
1286 
1287 const char *
Tk_NameOfStyle(Tk_Style style)1288 Tk_NameOfStyle(
1289     Tk_Style style)		/* Style whose name is desired. */
1290 {
1291     Style *stylePtr = (Style *) style;
1292 
1293     return stylePtr->name;
1294 }
1295 
1296 /*
1297  *---------------------------------------------------------------------------
1298  *
1299  * InitStyle --
1300  *
1301  *	Initialize a newly allocated style.
1302  *
1303  * Results:
1304  *	None.
1305  *
1306  * Side effects:
1307  *	None.
1308  *
1309  *---------------------------------------------------------------------------
1310  */
1311 
1312 static void
InitStyle(Style * stylePtr,const char * name,StyleEngine * enginePtr,ClientData clientData)1313 InitStyle(
1314     Style *stylePtr,		/* Points to an uninitialized style. */
1315     const char *name,		/* Name of the registered style. NULL or empty
1316 				 * means the default system style. Usually
1317 				 * points to the hash key. */
1318     StyleEngine *enginePtr,	/* The style engine. */
1319     ClientData clientData)	/* Private data passed as is to engine code. */
1320 {
1321     stylePtr->name = name;
1322     stylePtr->enginePtr = enginePtr;
1323     stylePtr->clientData = clientData;
1324 }
1325 
1326 /*
1327  *---------------------------------------------------------------------------
1328  *
1329  * Tk_GetStyle --
1330  *
1331  *	Retrieve a registered style by its name.
1332  *
1333  * Results:
1334  *	A pointer to the style engine, or NULL if none found. In the latter
1335  *	case and if the interp is not NULL, an error message is left in the
1336  *	interp's result.
1337  *
1338  * Side effects:
1339  *	None.
1340  *
1341  *---------------------------------------------------------------------------
1342  */
1343 
1344 Tk_Style
Tk_GetStyle(Tcl_Interp * interp,const char * name)1345 Tk_GetStyle(
1346     Tcl_Interp *interp,		/* Interp for error return. */
1347     const char *name)		/* Name of the style to retrieve. NULL or empty
1348 				 * means the default system style. */
1349 {
1350     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1351 	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1352     Tcl_HashEntry *entryPtr;
1353     Style *stylePtr;
1354 
1355     /*
1356      * Search for a corresponding entry in the style table.
1357      */
1358 
1359     entryPtr = Tcl_FindHashEntry(&tsdPtr->styleTable, (name!=NULL?name:""));
1360     if (entryPtr == NULL) {
1361 	if (interp != NULL) {
1362 	    Tcl_AppendResult(interp, "style \"", name, "\" doesn't exist",
1363 		    NULL);
1364 	}
1365 	return (Tk_Style) NULL;
1366     }
1367     stylePtr = (Style *) Tcl_GetHashValue(entryPtr);
1368 
1369     return (Tk_Style) stylePtr;
1370 }
1371 
1372 /*
1373  *---------------------------------------------------------------------------
1374  *
1375  * Tk_FreeStyle --
1376  *
1377  *	No-op. Present only for stubs compatibility.
1378  *
1379  *---------------------------------------------------------------------------
1380  */
1381 
1382 void
Tk_FreeStyle(Tk_Style style)1383 Tk_FreeStyle(
1384     Tk_Style style)
1385 {
1386 }
1387 
1388 /*
1389  *---------------------------------------------------------------------------
1390  *
1391  * Tk_AllocStyleFromObj --
1392  *
1393  *	Map the string name of a style to a corresponding Tk_Style. The style
1394  *	must have already been created by Tk_CreateStyle.
1395  *
1396  * Results:
1397  *	The return value is a token for the style that matches objPtr, or NULL
1398  *	if none found. If NULL is returned, an error message will be left in
1399  *	interp's result object.
1400  *
1401  *---------------------------------------------------------------------------
1402  */
1403 
1404 Tk_Style
Tk_AllocStyleFromObj(Tcl_Interp * interp,Tcl_Obj * objPtr)1405 Tk_AllocStyleFromObj(
1406     Tcl_Interp *interp,		/* Interp for error return. */
1407     Tcl_Obj *objPtr)		/* Object containing name of the style to
1408 				 * retrieve. */
1409 {
1410     Style *stylePtr;
1411 
1412     if (objPtr->typePtr != &styleObjType) {
1413 	SetStyleFromAny(interp, objPtr);
1414     }
1415     stylePtr = (Style *) objPtr->internalRep.twoPtrValue.ptr1;
1416 
1417     return (Tk_Style) stylePtr;
1418 }
1419 
1420 /*
1421  *----------------------------------------------------------------------
1422  *
1423  * Tk_GetStyleFromObj --
1424  *
1425  *	Find the style that corresponds to a given object. The style must have
1426  *	already been created by Tk_CreateStyle.
1427  *
1428  * Results:
1429  *	The return value is a token for the style that matches objPtr, or NULL
1430  *	if none found.
1431  *
1432  * Side effects:
1433  *	If the object is not already a style ref, the conversion will free any
1434  *	old internal representation.
1435  *
1436  *----------------------------------------------------------------------
1437  */
1438 
1439 Tk_Style
Tk_GetStyleFromObj(Tcl_Obj * objPtr)1440 Tk_GetStyleFromObj(
1441     Tcl_Obj *objPtr)		/* The object from which to get the style. */
1442 {
1443     if (objPtr->typePtr != &styleObjType) {
1444 	SetStyleFromAny(NULL, objPtr);
1445     }
1446 
1447     return (Tk_Style) objPtr->internalRep.twoPtrValue.ptr1;
1448 }
1449 
1450 /*
1451  *---------------------------------------------------------------------------
1452  *
1453  * Tk_FreeStyleFromObj --
1454  *
1455  *	No-op. Present only for stubs compatibility.
1456  *
1457  *---------------------------------------------------------------------------
1458  */
1459 void
Tk_FreeStyleFromObj(Tcl_Obj * objPtr)1460 Tk_FreeStyleFromObj(
1461     Tcl_Obj *objPtr)
1462 {
1463 }
1464 
1465 /*
1466  *----------------------------------------------------------------------
1467  *
1468  * SetStyleFromAny --
1469  *
1470  *	Convert the internal representation of a Tcl object to the style
1471  *	internal form.
1472  *
1473  * Results:
1474  *	Always returns TCL_OK. If an error occurs is returned (e.g. the style
1475  *	doesn't exist), an error message will be left in interp's result.
1476  *
1477  * Side effects:
1478  *	The object is left with its typePtr pointing to styleObjType.
1479  *
1480  *----------------------------------------------------------------------
1481  */
1482 
1483 static int
SetStyleFromAny(Tcl_Interp * interp,Tcl_Obj * objPtr)1484 SetStyleFromAny(
1485     Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
1486     Tcl_Obj *objPtr)		/* The object to convert. */
1487 {
1488     const Tcl_ObjType *typePtr;
1489     const char *name;
1490 
1491     /*
1492      * Free the old internalRep before setting the new one.
1493      */
1494 
1495     name = Tcl_GetString(objPtr);
1496     typePtr = objPtr->typePtr;
1497     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
1498 	(*typePtr->freeIntRepProc)(objPtr);
1499     }
1500 
1501     objPtr->typePtr = &styleObjType;
1502     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) Tk_GetStyle(interp, name);
1503 
1504     return TCL_OK;
1505 }
1506 
1507 /*
1508  *---------------------------------------------------------------------------
1509  *
1510  * FreeStyleObjProc --
1511  *
1512  *	This proc is called to release an object reference to a style. Called
1513  *	when the object's internal rep is released.
1514  *
1515  * Results:
1516  *	None.
1517  *
1518  *---------------------------------------------------------------------------
1519  */
1520 
1521 static void
FreeStyleObjProc(Tcl_Obj * objPtr)1522 FreeStyleObjProc(
1523     Tcl_Obj *objPtr)		/* The object we are releasing. */
1524 {
1525     objPtr->internalRep.twoPtrValue.ptr1 = NULL;
1526     objPtr->typePtr = NULL;
1527 }
1528 
1529 /*
1530  *---------------------------------------------------------------------------
1531  *
1532  * DupStyleObjProc --
1533  *
1534  *	When a cached style object is duplicated, this is called to update the
1535  *	internal reps.
1536  *
1537  *---------------------------------------------------------------------------
1538  */
1539 
1540 static void
DupStyleObjProc(Tcl_Obj * srcObjPtr,Tcl_Obj * dupObjPtr)1541 DupStyleObjProc(
1542     Tcl_Obj *srcObjPtr,		/* The object we are copying from. */
1543     Tcl_Obj *dupObjPtr)		/* The object we are copying to. */
1544 {
1545     dupObjPtr->typePtr = srcObjPtr->typePtr;
1546     dupObjPtr->internalRep.twoPtrValue.ptr1 =
1547 	    srcObjPtr->internalRep.twoPtrValue.ptr1;
1548 }
1549 
1550 /*
1551  * Local Variables:
1552  * mode: c
1553  * c-basic-offset: 4
1554  * fill-column: 78
1555  * End:
1556  */
1557