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