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