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