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