|
|
1.1 ! root 1: /* ! 2: * tkOption.c -- ! 3: * ! 4: * This module contains procedures to manage the option ! 5: * database, which allows various strings to be associated ! 6: * with windows either by name or by class or both. ! 7: * ! 8: * Copyright 1990 Regents of the University of California. ! 9: * Permission to use, copy, modify, and distribute this ! 10: * software and its documentation for any purpose and without ! 11: * fee is hereby granted, provided that the above copyright ! 12: * notice appear in all copies. The University of California ! 13: * makes no representations about the suitability of this ! 14: * software for any purpose. It is provided "as is" without ! 15: * express or implied warranty. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkOption.c,v 1.25 92/03/16 08:46:14 ouster Exp $ SPRITE (Berkeley)"; ! 20: #endif ! 21: ! 22: #include "tkconfig.h" ! 23: #include "tkint.h" ! 24: ! 25: /* ! 26: * The option database is stored as one tree for each main window. ! 27: * Each name or class field in an option is associated with a node or ! 28: * leaf of the tree. For example, the options "x.y.z" and "x.y*a" ! 29: * each correspond to three nodes in the tree; they share the nodes ! 30: * "x" and "x.y", but have different leaf nodes. One of the following ! 31: * structures exists for each node or leaf in the option tree. It is ! 32: * actually stored as part of the parent node, and describes a particular ! 33: * child of the parent. ! 34: */ ! 35: ! 36: typedef struct Element { ! 37: Tk_Uid nameUid; /* Name or class from one element of ! 38: * an option spec. */ ! 39: union { ! 40: struct ElArray *arrayPtr; /* If this is an intermediate node, ! 41: * a pointer to a structure describing ! 42: * the remaining elements of all ! 43: * options whose prefixes are the ! 44: * same up through this element. */ ! 45: Tk_Uid valueUid; /* For leaf nodes, this is the string ! 46: * value of the option. */ ! 47: } child; ! 48: int priority; /* Used to select among matching ! 49: * options. Includes both the ! 50: * priority level and a serial #. ! 51: * Greater value means higher ! 52: * priority. Irrelevant except in ! 53: * leaf nodes. */ ! 54: int flags; /* OR-ed combination of bits. See ! 55: * below for values. */ ! 56: } Element; ! 57: ! 58: /* ! 59: * Flags in NodeElement structures: ! 60: * ! 61: * CLASS - Non-zero means this element refers to a class, ! 62: * Zero means this element refers to a name. ! 63: * NODE - Zero means this is a leaf element (the child ! 64: * field is a value, not a pointer to another node). ! 65: * One means this is a node element. ! 66: * WILDCARD - Non-zero means this there was a star in the ! 67: * original specification just before this element. ! 68: * Zero means there was a dot. ! 69: */ ! 70: ! 71: #define TYPE_MASK 0x7 ! 72: ! 73: #define CLASS 0x1 ! 74: #define NODE 0x2 ! 75: #define WILDCARD 0x4 ! 76: ! 77: #define EXACT_LEAF_NAME 0x0 ! 78: #define EXACT_LEAF_CLASS 0x1 ! 79: #define EXACT_NODE_NAME 0x2 ! 80: #define EXACT_NODE_CLASS 0x3 ! 81: #define WILDCARD_LEAF_NAME 0x4 ! 82: #define WILDCARD_LEAF_CLASS 0x5 ! 83: #define WILDCARD_NODE_NAME 0x6 ! 84: #define WILDCARD_NODE_CLASS 0x7 ! 85: ! 86: /* ! 87: * The following structure is used to manage a dynamic array of ! 88: * Elements. These structures are used for two purposes: to store ! 89: * the contents of a node in the option tree, and for the option ! 90: * stacks described below. ! 91: */ ! 92: ! 93: typedef struct ElArray { ! 94: int arraySize; /* Number of elements actually ! 95: * allocated in the "els" array. */ ! 96: int numUsed; /* Number of elements currently in ! 97: * use out of els. */ ! 98: Element *nextToUse; /* Pointer to &els[numUsed]. */ ! 99: Element els[1]; /* Array of structures describing ! 100: * children of this node. The ! 101: * array will actually contain enough ! 102: * elements for all of the children ! 103: * (and even a few extras, perhaps). ! 104: * This must be the last field in ! 105: * the structure. */ ! 106: } ElArray; ! 107: ! 108: #define EL_ARRAY_SIZE(numEls) ((unsigned) (sizeof(ElArray) \ ! 109: + ((numEls)-1)*sizeof(Element))) ! 110: #define INITIAL_SIZE 5 ! 111: ! 112: /* ! 113: * In addition to the option tree, which is a relatively static structure, ! 114: * there are eight additional structures called "stacks", which are used ! 115: * to speed up queries into the option database. The stack structures ! 116: * are designed for the situation where an individual widget makes repeated ! 117: * requests for its particular options. The requests differ only in ! 118: * their last name/class, so during the first request we extract all ! 119: * the options pertaining to the particular widget and save them in a ! 120: * stack-like cache; subsequent requests for the same widget can search ! 121: * the cache relatively quickly. In fact, the cache is a hierarchical ! 122: * one, storing a list of relevant options for this widget and all of ! 123: * its ancestors up to the application root; hence the name "stack". ! 124: * ! 125: * Each of the eight stacks consists of an array of Elements, ordered in ! 126: * terms of levels in the window hierarchy. All the elements relevant ! 127: * for the top-level widget appear first in the array, followed by all ! 128: * those from the next-level widget on the path to the current widget, ! 129: * etc. down to those for the current widget. ! 130: * ! 131: * Cached information is divided into eight stacks according to the ! 132: * CLASS, NODE, and WILDCARD flags. Leaf and non-leaf information is ! 133: * kept separate to speed up individual probes (non-leaf information is ! 134: * only relevant when building the stacks, but isn't relevant when ! 135: * making probes; similarly, only non-leaf information is relevant ! 136: * when the stacks are being extended to the next widget down in the ! 137: * widget hierarchy). Wildcard elements are handled separately from ! 138: * "exact" elements because once they appear at a particular level in ! 139: * the stack they remain active for all deeper levels; exact elements ! 140: * are only relevant at a particular level. For example, when searching ! 141: * for options relevant in a particular window, the entire wildcard ! 142: * stacks get checked, but only the portions of the exact stacks that ! 143: * pertain to the window's parent. Lastly, name and class stacks are ! 144: * kept separate because different search keys are used when searching ! 145: * them; keeping them separate speeds up the searches. ! 146: */ ! 147: ! 148: #define NUM_STACKS 8 ! 149: static ElArray *stacks[NUM_STACKS]; ! 150: static TkWindow *cachedWindow = NULL; /* Lowest-level window currently ! 151: * loaded in stacks at present. ! 152: * NULL means stacks have never ! 153: * been used, or have been ! 154: * invalidated because of a change ! 155: * to the database. */ ! 156: ! 157: /* ! 158: * One of the following structures is used to keep track of each ! 159: * level in the stacks. ! 160: */ ! 161: ! 162: typedef struct StackLevel { ! 163: TkWindow *winPtr; /* Window corresponding to this stack ! 164: * level. */ ! 165: int bases[NUM_STACKS]; /* For each stack, index of first ! 166: * element on stack corresponding to ! 167: * this level (used to restore "numUsed" ! 168: * fields when popping out of a level. */ ! 169: } StackLevel; ! 170: ! 171: /* ! 172: * Information about all of the stack levels that are currently ! 173: * active. This array grows dynamically to become as large as needed. ! 174: */ ! 175: ! 176: static StackLevel *levels = NULL; ! 177: /* Array describing current stack. */ ! 178: static int numLevels = 0; /* Total space allocated. */ ! 179: static int curLevel = 0; /* Highest level currently in use. */ ! 180: ! 181: /* ! 182: * The variable below is a serial number for all options entered into ! 183: * the database so far. It increments on each addition to the option ! 184: * database. It is used in computing option priorities, so that the ! 185: * most recent entry wins when choosing between options at the same ! 186: * priority level. ! 187: */ ! 188: ! 189: static int serial = 0; ! 190: ! 191: /* ! 192: * Special "no match" Element to use as default for searches. ! 193: */ ! 194: ! 195: static Element defaultMatch; ! 196: ! 197: /* ! 198: * Forward declarations for procedures defined in this file: ! 199: */ ! 200: ! 201: static int AddFromString _ANSI_ARGS_((Tcl_Interp *interp, ! 202: Tk_Window tkwin, char *string, int priority)); ! 203: static void ClearOptionTree _ANSI_ARGS_((ElArray *arrayPtr)); ! 204: static ElArray * ExtendArray _ANSI_ARGS_((ElArray *arrayPtr, ! 205: Element *elPtr)); ! 206: static void ExtendStacks _ANSI_ARGS_((ElArray *arrayPtr, ! 207: int leaf)); ! 208: static int GetDefaultOptions _ANSI_ARGS_((Tcl_Interp *interp, ! 209: TkWindow *winPtr)); ! 210: static ElArray * NewArray _ANSI_ARGS_((int numEls)); ! 211: static void OptionInit _ANSI_ARGS_((TkMainInfo *mainPtr)); ! 212: static int ParsePriority _ANSI_ARGS_((Tcl_Interp *interp, ! 213: char *string)); ! 214: static int ReadOptionFile _ANSI_ARGS_((Tcl_Interp *interp, ! 215: Tk_Window tkwin, char *fileName, int priority)); ! 216: static void SetupStacks _ANSI_ARGS_((TkWindow *winPtr, int leaf)); ! 217: ! 218: /* ! 219: *-------------------------------------------------------------- ! 220: * ! 221: * Tk_AddOption -- ! 222: * ! 223: * Add a new option to the option database. ! 224: * ! 225: * Results: ! 226: * None. ! 227: * ! 228: * Side effects: ! 229: * Information is added to the option database. ! 230: * ! 231: *-------------------------------------------------------------- ! 232: */ ! 233: ! 234: void ! 235: Tk_AddOption(tkwin, name, value, priority) ! 236: Tk_Window tkwin; /* Window token; option will be associated ! 237: * with main window for this window. */ ! 238: char *name; /* Multi-element name of option. */ ! 239: char *value; /* String value for option. */ ! 240: int priority; /* Overall priority level to use for ! 241: * this option, such as TK_USER_DEFAULT_PRIO ! 242: * or TK_INTERACTIVE_PRIO. Must be between ! 243: * 0 and TK_MAX_PRIO. */ ! 244: { ! 245: TkWindow *winPtr = ((TkWindow *) tkwin)->mainPtr->winPtr; ! 246: register ElArray **arrayPtrPtr; ! 247: register Element *elPtr; ! 248: Element newEl; ! 249: register char *p; ! 250: char *field; ! 251: int count, firstField, length; ! 252: #define TMP_SIZE 100 ! 253: char tmp[TMP_SIZE+1]; ! 254: ! 255: if (winPtr->mainPtr->optionRootPtr == NULL) { ! 256: OptionInit(winPtr->mainPtr); ! 257: } ! 258: cachedWindow = NULL; /* Invalidate the cache. */ ! 259: ! 260: /* ! 261: * Compute the priority for the new element, including both the ! 262: * overall level and the serial number (to disambiguate with the ! 263: * level). ! 264: */ ! 265: ! 266: if (priority < 0) { ! 267: priority = 0; ! 268: } else if (priority > TK_MAX_PRIO) { ! 269: priority = TK_MAX_PRIO; ! 270: } ! 271: newEl.priority = (priority << 24) + serial; ! 272: serial++; ! 273: ! 274: /* ! 275: * Parse the option one field at a time. ! 276: */ ! 277: ! 278: arrayPtrPtr = &(((TkWindow *) tkwin)->mainPtr->optionRootPtr); ! 279: p = name; ! 280: for (firstField = 1; ; firstField = 0) { ! 281: ! 282: /* ! 283: * Scan the next field from the name and convert it to a Tk_Uid. ! 284: * Must copy the field before calling Tk_Uid, so that a terminating ! 285: * NULL may be added without modifying the source string. ! 286: */ ! 287: ! 288: if (*p == '*') { ! 289: newEl.flags = WILDCARD; ! 290: p++; ! 291: } else { ! 292: newEl.flags = 0; ! 293: } ! 294: field = p; ! 295: while ((*p != 0) && (*p != '.') && (*p != '*')) { ! 296: p++; ! 297: } ! 298: length = p - field; ! 299: if (length > TMP_SIZE) { ! 300: length = TMP_SIZE; ! 301: } ! 302: strncpy(tmp, field, length); ! 303: tmp[length] = 0; ! 304: newEl.nameUid = Tk_GetUid(tmp); ! 305: if (isupper(*field)) { ! 306: newEl.flags |= CLASS; ! 307: } ! 308: ! 309: if (*p != 0) { ! 310: ! 311: /* ! 312: * New element will be a node. If this option can't possibly ! 313: * apply to this main window, then just skip it. Otherwise, ! 314: * add it to the parent, if it isn't already there, and descend ! 315: * into it. ! 316: */ ! 317: ! 318: newEl.flags |= NODE; ! 319: if (firstField && !(newEl.flags & WILDCARD) ! 320: && (newEl.nameUid != winPtr->nameUid) ! 321: && (newEl.nameUid != winPtr->classUid)) { ! 322: return; ! 323: } ! 324: for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; ! 325: ; elPtr++, count--) { ! 326: if (count == 0) { ! 327: newEl.child.arrayPtr = NewArray(5); ! 328: *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); ! 329: arrayPtrPtr = &((*arrayPtrPtr)->nextToUse[-1].child.arrayPtr); ! 330: break; ! 331: } ! 332: if ((elPtr->nameUid == newEl.nameUid) ! 333: && (elPtr->flags == newEl.flags)) { ! 334: arrayPtrPtr = &(elPtr->child.arrayPtr); ! 335: break; ! 336: } ! 337: } ! 338: if (*p == '.') { ! 339: p++; ! 340: } ! 341: } else { ! 342: ! 343: /* ! 344: * New element is a leaf. Add it to the parent, if it isn't ! 345: * already there. If it exists already, keep whichever value ! 346: * has highest priority. ! 347: */ ! 348: ! 349: newEl.child.valueUid = Tk_GetUid(value); ! 350: for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed; ! 351: ; elPtr++, count--) { ! 352: if (count == 0) { ! 353: *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl); ! 354: return; ! 355: } ! 356: if ((elPtr->nameUid == newEl.nameUid) ! 357: && (elPtr->flags == newEl.flags)) { ! 358: if (elPtr->priority < newEl.priority) { ! 359: elPtr->priority = newEl.priority; ! 360: elPtr->child.valueUid = newEl.child.valueUid; ! 361: } ! 362: return; ! 363: } ! 364: } ! 365: } ! 366: } ! 367: } ! 368: ! 369: /* ! 370: *-------------------------------------------------------------- ! 371: * ! 372: * Tk_GetOption -- ! 373: * ! 374: * Retrieve an option from the option database. ! 375: * ! 376: * Results: ! 377: * The return value is the value specified in the option ! 378: * database for the given name and class on the given ! 379: * window. If there is nothing specified in the database ! 380: * for that option, then NULL is returned. ! 381: * ! 382: * Side effects: ! 383: * The internal caches used to speed up option mapping ! 384: * may be modified, if this tkwin is different from the ! 385: * last tkwin used for option retrieval. ! 386: * ! 387: *-------------------------------------------------------------- ! 388: */ ! 389: ! 390: Tk_Uid ! 391: Tk_GetOption(tkwin, name, className) ! 392: Tk_Window tkwin; /* Token for window that option is ! 393: * associated with. */ ! 394: char *name; /* Name of option. */ ! 395: char *className; /* Class of option. NULL means there ! 396: * is no class for this option: just ! 397: * check for name. */ ! 398: { ! 399: Tk_Uid nameId, classId; ! 400: register Element *elPtr, *bestPtr; ! 401: register int count; ! 402: ! 403: /* ! 404: * Note: no need to call OptionInit here: it will be done by ! 405: * the SetupStacks call below (squeeze out those nanoseconds). ! 406: */ ! 407: ! 408: if (tkwin != (Tk_Window) cachedWindow) { ! 409: SetupStacks((TkWindow *) tkwin, 1); ! 410: } ! 411: ! 412: nameId = Tk_GetUid(name); ! 413: bestPtr = &defaultMatch; ! 414: for (elPtr = stacks[EXACT_LEAF_NAME]->els, ! 415: count = stacks[EXACT_LEAF_NAME]->numUsed; count > 0; ! 416: elPtr++, count--) { ! 417: if ((elPtr->nameUid == nameId) ! 418: && (elPtr->priority > bestPtr->priority)) { ! 419: bestPtr = elPtr; ! 420: } ! 421: } ! 422: for (elPtr = stacks[WILDCARD_LEAF_NAME]->els, ! 423: count = stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0; ! 424: elPtr++, count--) { ! 425: if ((elPtr->nameUid == nameId) ! 426: && (elPtr->priority > bestPtr->priority)) { ! 427: bestPtr = elPtr; ! 428: } ! 429: } ! 430: if (className != NULL) { ! 431: classId = Tk_GetUid(className); ! 432: for (elPtr = stacks[EXACT_LEAF_CLASS]->els, ! 433: count = stacks[EXACT_LEAF_CLASS]->numUsed; count > 0; ! 434: elPtr++, count--) { ! 435: if ((elPtr->nameUid == classId) ! 436: && (elPtr->priority > bestPtr->priority)) { ! 437: bestPtr = elPtr; ! 438: } ! 439: } ! 440: for (elPtr = stacks[WILDCARD_LEAF_CLASS]->els, ! 441: count = stacks[WILDCARD_LEAF_CLASS]->numUsed; count > 0; ! 442: elPtr++, count--) { ! 443: if ((elPtr->nameUid == classId) ! 444: && (elPtr->priority > bestPtr->priority)) { ! 445: bestPtr = elPtr; ! 446: } ! 447: } ! 448: } ! 449: return bestPtr->child.valueUid; ! 450: } ! 451: ! 452: /* ! 453: *-------------------------------------------------------------- ! 454: * ! 455: * Tk_OptionCmd -- ! 456: * ! 457: * This procedure is invoked to process the "option" Tcl command. ! 458: * See the user documentation for details on what it does. ! 459: * ! 460: * Results: ! 461: * A standard Tcl result. ! 462: * ! 463: * Side effects: ! 464: * See the user documentation. ! 465: * ! 466: *-------------------------------------------------------------- ! 467: */ ! 468: ! 469: int ! 470: Tk_OptionCmd(clientData, interp, argc, argv) ! 471: ClientData clientData; /* Main window associated with ! 472: * interpreter. */ ! 473: Tcl_Interp *interp; /* Current interpreter. */ ! 474: int argc; /* Number of arguments. */ ! 475: char **argv; /* Argument strings. */ ! 476: { ! 477: Tk_Window tkwin = (Tk_Window) clientData; ! 478: int length; ! 479: char c; ! 480: ! 481: if (argc < 2) { ! 482: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], ! 483: " cmd arg ?arg ...?\"", (char *) NULL); ! 484: return TCL_ERROR; ! 485: } ! 486: c = argv[1][0]; ! 487: length = strlen(argv[1]); ! 488: if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)) { ! 489: int priority; ! 490: ! 491: if ((argc != 4) && (argc != 5)) { ! 492: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 493: argv[0], " add pattern value ?priority?\"", (char *) NULL); ! 494: return TCL_ERROR; ! 495: } ! 496: if (argc == 4) { ! 497: priority = TK_INTERACTIVE_PRIO; ! 498: } else { ! 499: priority = ParsePriority(interp, argv[4]); ! 500: if (priority < 0) { ! 501: return TCL_ERROR; ! 502: } ! 503: } ! 504: Tk_AddOption(tkwin, argv[2], argv[3], priority); ! 505: return TCL_OK; ! 506: } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) { ! 507: TkMainInfo *mainPtr; ! 508: ! 509: if (argc != 2) { ! 510: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 511: argv[0], " clear\"", (char *) NULL); ! 512: return TCL_ERROR; ! 513: } ! 514: mainPtr = ((TkWindow *) tkwin)->mainPtr; ! 515: if (mainPtr->optionRootPtr != NULL) { ! 516: ClearOptionTree(mainPtr->optionRootPtr); ! 517: mainPtr->optionRootPtr = NULL; ! 518: } ! 519: cachedWindow = NULL; ! 520: return TCL_OK; ! 521: } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { ! 522: Tk_Window window; ! 523: Tk_Uid value; ! 524: ! 525: if (argc != 5) { ! 526: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 527: argv[0], " get window name class\"", (char *) NULL); ! 528: return TCL_ERROR; ! 529: } ! 530: window = Tk_NameToWindow(interp, argv[2], tkwin); ! 531: if (window == NULL) { ! 532: return TCL_ERROR; ! 533: } ! 534: value = Tk_GetOption(window, argv[3], argv[4]); ! 535: if (value != NULL) { ! 536: interp->result = value; ! 537: } ! 538: return TCL_OK; ! 539: } else if ((c == 'r') && (strncmp(argv[1], "readfile", length) == 0)) { ! 540: int priority; ! 541: ! 542: if ((argc != 3) && (argc != 4)) { ! 543: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 544: argv[0], " readfile fileName ?priority?\"", ! 545: (char *) NULL); ! 546: return TCL_ERROR; ! 547: } ! 548: if (argc == 4) { ! 549: priority = ParsePriority(interp, argv[3]); ! 550: if (priority < 0) { ! 551: return TCL_ERROR; ! 552: } ! 553: } else { ! 554: priority = TK_INTERACTIVE_PRIO; ! 555: } ! 556: return ReadOptionFile(interp, tkwin, argv[2], priority); ! 557: } else { ! 558: Tcl_AppendResult(interp, "bad option \"", argv[1], ! 559: "\": must be add, clear, get, or readfile", (char *) NULL); ! 560: return TCL_ERROR; ! 561: } ! 562: } ! 563: ! 564: /* ! 565: *-------------------------------------------------------------- ! 566: * ! 567: * TkOptionDeadWindow -- ! 568: * ! 569: * This procedure is called whenever a window is deleted. ! 570: * It cleans up any option-related stuff associated with ! 571: * the window. ! 572: * ! 573: * Results: ! 574: * None. ! 575: * ! 576: * Side effects: ! 577: * Option-related resources are freed. See code below ! 578: * for details. ! 579: * ! 580: *-------------------------------------------------------------- ! 581: */ ! 582: ! 583: void ! 584: TkOptionDeadWindow(winPtr) ! 585: register TkWindow *winPtr; /* Window to be cleaned up. */ ! 586: { ! 587: /* ! 588: * If this window is in the option stacks, then clear the stacks. ! 589: */ ! 590: ! 591: if (winPtr->optionLevel != -1) { ! 592: int i; ! 593: ! 594: for (i = 1; i <= curLevel; i++) { ! 595: levels[curLevel].winPtr->optionLevel = -1; ! 596: } ! 597: curLevel = 0; ! 598: cachedWindow = NULL; ! 599: } ! 600: ! 601: /* ! 602: * If this window was a main window, then delete its option ! 603: * database. ! 604: */ ! 605: ! 606: if ((winPtr->mainPtr->winPtr == winPtr) ! 607: && (winPtr->mainPtr->optionRootPtr != NULL)) { ! 608: ClearOptionTree(winPtr->mainPtr->optionRootPtr); ! 609: winPtr->mainPtr->optionRootPtr = NULL; ! 610: } ! 611: } ! 612: ! 613: /* ! 614: *---------------------------------------------------------------------- ! 615: * ! 616: * ParsePriority -- ! 617: * ! 618: * Parse a string priority value. ! 619: * ! 620: * Results: ! 621: * The return value is the integer priority level corresponding ! 622: * to string, or -1 if string doesn't point to a valid priority level. ! 623: * In this case, an error message is left in interp->result. ! 624: * ! 625: * Side effects: ! 626: * None. ! 627: * ! 628: *---------------------------------------------------------------------- ! 629: */ ! 630: ! 631: static int ! 632: ParsePriority(interp, string) ! 633: Tcl_Interp *interp; /* Interpreter to use for error reporting. */ ! 634: char *string; /* Describes a priority level, either ! 635: * symbolically or numerically. */ ! 636: { ! 637: char c; ! 638: int length, priority; ! 639: ! 640: c = string[0]; ! 641: length = strlen(string); ! 642: if ((c == 'w') ! 643: && (strncmp(string, "widgetDefault", length) == 0)) { ! 644: return TK_WIDGET_DEFAULT_PRIO; ! 645: } else if ((c == 's') ! 646: && (strncmp(string, "startupFile", length) == 0)) { ! 647: return TK_STARTUP_FILE_PRIO; ! 648: } else if ((c == 'u') ! 649: && (strncmp(string, "userDefault", length) == 0)) { ! 650: return TK_USER_DEFAULT_PRIO; ! 651: } else if ((c == 'i') ! 652: && (strncmp(string, "interactive", length) == 0)) { ! 653: return TK_INTERACTIVE_PRIO; ! 654: } else { ! 655: char *end; ! 656: ! 657: priority = strtoul(string, &end, 0); ! 658: if ((end == string) || (*end != 0) || (priority < 0) ! 659: || (priority > 100)) { ! 660: Tcl_AppendResult(interp, "bad priority level \"", string, ! 661: "\": must be widgetDefault, startupFile, userDefault, ", ! 662: "interactive, or a number between 0 and 100", ! 663: (char *) NULL); ! 664: return -1; ! 665: } ! 666: } ! 667: return priority; ! 668: } ! 669: ! 670: /* ! 671: *---------------------------------------------------------------------- ! 672: * ! 673: * AddFromString -- ! 674: * ! 675: * Given a string containing lines in the standard format for ! 676: * X resources (see other documentation for details on what this ! 677: * is), parse the resource specifications and enter them as options ! 678: * for tkwin's main window. ! 679: * ! 680: * Results: ! 681: * The return value is a standard Tcl return code. In the case of ! 682: * an error in parsing string, TCL_ERROR will be returned and an ! 683: * error message will be left in interp->result. The memory at ! 684: * string is totally trashed by this procedure. If you care about ! 685: * its contents, make a copy before calling here. ! 686: * ! 687: * Side effects: ! 688: * None. ! 689: * ! 690: *---------------------------------------------------------------------- ! 691: */ ! 692: ! 693: static int ! 694: AddFromString(interp, tkwin, string, priority) ! 695: Tcl_Interp *interp; /* Interpreter to use for reporting results. */ ! 696: Tk_Window tkwin; /* Token for window: options are entered ! 697: * for this window's main window. */ ! 698: char *string; /* String containing option specifiers. */ ! 699: int priority; /* Priority level to use for options in ! 700: * this string, such as TK_USER_DEFAULT_PRIO ! 701: * or TK_INTERACTIVE_PRIO. Must be between ! 702: * 0 and TK_MAX_PRIO. */ ! 703: { ! 704: register char *src, *dst; ! 705: char *name, *value; ! 706: int lineNum; ! 707: ! 708: src = string; ! 709: lineNum = 1; ! 710: while (1) { ! 711: ! 712: /* ! 713: * Skip leading white space and empty lines and comment lines, and ! 714: * check for the end of the spec. ! 715: */ ! 716: ! 717: while ((*src == ' ') || (*src == '\t')) { ! 718: src++; ! 719: } ! 720: if ((*src == '#') || (*src == '!')) { ! 721: do { ! 722: src++; ! 723: if ((src[0] == '\\') && (src[1] == '\n')) { ! 724: src += 2; ! 725: lineNum++; ! 726: } ! 727: } while ((*src != '\n') && (*src != 0)); ! 728: } ! 729: if (*src == '\n') { ! 730: src++; ! 731: lineNum++; ! 732: continue; ! 733: } ! 734: if (*src == '\0') { ! 735: break; ! 736: } ! 737: ! 738: /* ! 739: * Parse off the option name, collapsing out backslash-newline ! 740: * sequences of course. ! 741: */ ! 742: ! 743: dst = name = src; ! 744: while (*src != ':') { ! 745: if ((*src == '\0') || (*src == '\n')) { ! 746: sprintf(interp->result, "missing colon on line %d", ! 747: lineNum); ! 748: return TCL_ERROR; ! 749: } ! 750: if ((src[0] == '\\') && (src[1] == '\n')) { ! 751: src += 2; ! 752: lineNum++; ! 753: } else { ! 754: *dst = *src; ! 755: dst++; ! 756: src++; ! 757: } ! 758: } ! 759: ! 760: /* ! 761: * Eliminate trailing white space on the name, and null-terminate ! 762: * it. ! 763: */ ! 764: ! 765: while ((dst != name) && ((dst[-1] == ' ') || (dst[-1] == '\t'))) { ! 766: dst--; ! 767: } ! 768: *dst = '\0'; ! 769: ! 770: /* ! 771: * Skip white space between the name and the value. ! 772: */ ! 773: ! 774: src++; ! 775: while ((*src == ' ') || (*src == '\t')) { ! 776: src++; ! 777: } ! 778: if (*src == '\0') { ! 779: sprintf(interp->result, "missing value on line %d", lineNum); ! 780: return TCL_ERROR; ! 781: } ! 782: ! 783: /* ! 784: * Parse off the value, squeezing out backslash-newline sequences ! 785: * along the way. ! 786: */ ! 787: ! 788: dst = value = src; ! 789: while (*src != '\n') { ! 790: if (*src == '\0') { ! 791: sprintf(interp->result, "missing newline on line %d", ! 792: lineNum); ! 793: return TCL_ERROR; ! 794: } ! 795: if ((src[0] == '\\') && (src[1] == '\n')) { ! 796: src += 2; ! 797: lineNum++; ! 798: } else { ! 799: *dst = *src; ! 800: dst++; ! 801: src++; ! 802: } ! 803: } ! 804: *dst = 0; ! 805: ! 806: /* ! 807: * Enter the option into the database. ! 808: */ ! 809: ! 810: Tk_AddOption(tkwin, name, value, priority); ! 811: src++; ! 812: lineNum++; ! 813: } ! 814: return TCL_OK; ! 815: } ! 816: ! 817: /* ! 818: *---------------------------------------------------------------------- ! 819: * ! 820: * ReadOptionFile -- ! 821: * ! 822: * Read a file of options ("resources" in the old X terminology) ! 823: * and load them into the option database. ! 824: * ! 825: * Results: ! 826: * The return value is a standard Tcl return code. In the case of ! 827: * an error in parsing string, TCL_ERROR will be returned and an ! 828: * error message will be left in interp->result. ! 829: * ! 830: * Side effects: ! 831: * None. ! 832: * ! 833: *---------------------------------------------------------------------- ! 834: */ ! 835: ! 836: static int ! 837: ReadOptionFile(interp, tkwin, fileName, priority) ! 838: Tcl_Interp *interp; /* Interpreter to use for reporting results. */ ! 839: Tk_Window tkwin; /* Token for window: options are entered ! 840: * for this window's main window. */ ! 841: char *fileName; /* Name of file containing options. */ ! 842: int priority; /* Priority level to use for options in ! 843: * this file, such as TK_USER_DEFAULT_PRIO ! 844: * or TK_INTERACTIVE_PRIO. Must be between ! 845: * 0 and TK_MAX_PRIO. */ ! 846: { ! 847: char *realName, *buffer; ! 848: int fileId, result; ! 849: struct stat statBuf; ! 850: ! 851: realName = Tcl_TildeSubst(interp, fileName); ! 852: if (fileName == NULL) { ! 853: return TCL_ERROR; ! 854: } ! 855: #ifdef MSDOS ! 856: fileId = open(realName, O_RDONLY | O_BINARY, 0); ! 857: #else ! 858: fileId = open(realName, O_RDONLY, 0); ! 859: #endif ! 860: if (fileId < 0) { ! 861: Tcl_AppendResult(interp, "couldn't read file \"", fileName, "\"", ! 862: (char *) NULL); ! 863: return TCL_ERROR; ! 864: } ! 865: if (fstat(fileId, &statBuf) == -1) { ! 866: Tcl_AppendResult(interp, "couldn't stat file \"", fileName, "\"", ! 867: (char *) NULL); ! 868: close(fileId); ! 869: return TCL_ERROR; ! 870: } ! 871: buffer = (char *) ckalloc((unsigned) statBuf.st_size+1); ! 872: #ifdef MSDOS ! 873: if (read(fileId, buffer, (int) statBuf.st_size) < 0) { ! 874: #else ! 875: if (read(fileId, buffer, (int) statBuf.st_size) != statBuf.st_size) { ! 876: #endif ! 877: Tcl_AppendResult(interp, "error reading file \"", fileName, "\"", ! 878: (char *) NULL); ! 879: close(fileId); ! 880: return TCL_ERROR; ! 881: } ! 882: close(fileId); ! 883: buffer[statBuf.st_size] = 0; ! 884: result = AddFromString(interp, tkwin, buffer, priority); ! 885: ckfree(buffer); ! 886: return result; ! 887: } ! 888: ! 889: /* ! 890: *-------------------------------------------------------------- ! 891: * ! 892: * NewArray -- ! 893: * ! 894: * Create a new ElArray structure of a given size. ! 895: * ! 896: * Results: ! 897: * The return value is a pointer to a properly initialized ! 898: * element array with "numEls" space. The array is marked ! 899: * as having no active elements. ! 900: * ! 901: * Side effects: ! 902: * Memory is allocated. ! 903: * ! 904: *-------------------------------------------------------------- ! 905: */ ! 906: ! 907: static ElArray * ! 908: NewArray(numEls) ! 909: int numEls; /* How many elements of space to allocate. */ ! 910: { ! 911: register ElArray *arrayPtr; ! 912: ! 913: arrayPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(numEls)); ! 914: arrayPtr->arraySize = numEls; ! 915: arrayPtr->numUsed = 0; ! 916: arrayPtr->nextToUse = arrayPtr->els; ! 917: return arrayPtr; ! 918: } ! 919: ! 920: /* ! 921: *-------------------------------------------------------------- ! 922: * ! 923: * ExtendArray -- ! 924: * ! 925: * Add a new element to an array, extending the array if ! 926: * necessary. ! 927: * ! 928: * Results: ! 929: * The return value is a pointer to the new array, which ! 930: * will be different from arrayPtr if the array got expanded. ! 931: * ! 932: * Side effects: ! 933: * Memory may be allocated or freed. ! 934: * ! 935: *-------------------------------------------------------------- ! 936: */ ! 937: ! 938: static ElArray * ! 939: ExtendArray(arrayPtr, elPtr) ! 940: register ElArray *arrayPtr; /* Array to be extended. */ ! 941: register Element *elPtr; /* Element to be copied into array. */ ! 942: { ! 943: /* ! 944: * If the current array has filled up, make it bigger. ! 945: */ ! 946: ! 947: if (arrayPtr->numUsed >= arrayPtr->arraySize) { ! 948: register ElArray *newPtr; ! 949: ! 950: newPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(2*arrayPtr->arraySize)); ! 951: newPtr->arraySize = 2*arrayPtr->arraySize; ! 952: newPtr->numUsed = arrayPtr->numUsed; ! 953: newPtr->nextToUse = &newPtr->els[newPtr->numUsed]; ! 954: memcpy((VOID *) newPtr->els, (VOID *) arrayPtr->els, ! 955: (arrayPtr->arraySize*sizeof(Element))); ! 956: ckfree((char *) arrayPtr); ! 957: arrayPtr = newPtr; ! 958: } ! 959: ! 960: *arrayPtr->nextToUse = *elPtr; ! 961: arrayPtr->nextToUse++; ! 962: arrayPtr->numUsed++; ! 963: return arrayPtr; ! 964: } ! 965: ! 966: /* ! 967: *-------------------------------------------------------------- ! 968: * ! 969: * SetupStacks -- ! 970: * ! 971: * Arrange the stacks so that they cache all the option ! 972: * information for a particular window. ! 973: * ! 974: * Results: ! 975: * None. ! 976: * ! 977: * Side effects: ! 978: * The stacks are modified to hold information for tkwin ! 979: * and all its ancestors in the window hierarchy. ! 980: * ! 981: *-------------------------------------------------------------- ! 982: */ ! 983: ! 984: static void ! 985: SetupStacks(winPtr, leaf) ! 986: TkWindow *winPtr; /* Window for which information is to ! 987: * be cached. */ ! 988: int leaf; /* Non-zero means this is the leaf ! 989: * window being probed. Zero means this ! 990: * is an ancestor of the desired leaf. */ ! 991: { ! 992: int level, i, *iPtr; ! 993: register StackLevel *levelPtr; ! 994: register ElArray *arrayPtr; ! 995: ! 996: /* ! 997: * The following array defines the order in which the current ! 998: * stacks are searched to find matching entries to add to the ! 999: * stacks. Given the current priority-based scheme, the order ! 1000: * below is no longer relevant; all that matters is that an ! 1001: * element is on the list *somewhere*. The ordering is a relic ! 1002: * of the old days when priorities were determined differently. ! 1003: */ ! 1004: ! 1005: static int searchOrder[] = {WILDCARD_NODE_CLASS, WILDCARD_NODE_NAME, ! 1006: EXACT_NODE_CLASS, EXACT_NODE_NAME, -1}; ! 1007: ! 1008: if (winPtr->mainPtr->optionRootPtr == NULL) { ! 1009: OptionInit(winPtr->mainPtr); ! 1010: } ! 1011: ! 1012: /* ! 1013: * Step 1: make sure that options are cached for this window's ! 1014: * parent. ! 1015: */ ! 1016: ! 1017: if (winPtr->parentPtr != NULL) { ! 1018: level = winPtr->parentPtr->optionLevel; ! 1019: if ((level == -1) || (cachedWindow == NULL)) { ! 1020: SetupStacks(winPtr->parentPtr, 0); ! 1021: level = winPtr->parentPtr->optionLevel; ! 1022: } ! 1023: level++; ! 1024: } else { ! 1025: level = 1; ! 1026: } ! 1027: ! 1028: /* ! 1029: * Step 2: pop extra unneeded information off the stacks and ! 1030: * mark those windows as no longer having cached information. ! 1031: */ ! 1032: ! 1033: if (curLevel >= level) { ! 1034: while (curLevel >= level) { ! 1035: levels[curLevel].winPtr->optionLevel = -1; ! 1036: curLevel--; ! 1037: } ! 1038: levelPtr = &levels[level]; ! 1039: for (i = 0; i < NUM_STACKS; i++) { ! 1040: arrayPtr = stacks[i]; ! 1041: arrayPtr->numUsed = levelPtr->bases[i]; ! 1042: arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed]; ! 1043: } ! 1044: } ! 1045: curLevel = winPtr->optionLevel = level; ! 1046: ! 1047: /* ! 1048: * Step 3: if the root database information isn't loaded or ! 1049: * isn't valid, initialize level 0 of the stack from the ! 1050: * database root (this only happens if winPtr is a main window). ! 1051: */ ! 1052: ! 1053: if ((curLevel == 1) ! 1054: && ((cachedWindow == NULL) ! 1055: || (cachedWindow->mainPtr != winPtr->mainPtr))) { ! 1056: for (i = 0; i < NUM_STACKS; i++) { ! 1057: arrayPtr = stacks[i]; ! 1058: arrayPtr->numUsed = 0; ! 1059: arrayPtr->nextToUse = arrayPtr->els; ! 1060: } ! 1061: ExtendStacks(winPtr->mainPtr->optionRootPtr, 0); ! 1062: } ! 1063: ! 1064: /* ! 1065: * Step 4: create a new stack level; grow the level array if ! 1066: * we've run out of levels. Clear the stacks for EXACT_LEAF_NAME ! 1067: * and EXACT_LEAF_CLASS (anything that was there is of no use ! 1068: * any more). ! 1069: */ ! 1070: ! 1071: if (curLevel >= numLevels) { ! 1072: StackLevel *newLevels; ! 1073: ! 1074: newLevels = (StackLevel *) ckalloc((unsigned) ! 1075: (numLevels*2*sizeof(StackLevel))); ! 1076: memcpy((VOID *) newLevels, (VOID *) levels, ! 1077: (numLevels*sizeof(StackLevel))); ! 1078: ckfree((char *) levels); ! 1079: numLevels *= 2; ! 1080: levels = newLevels; ! 1081: } ! 1082: levelPtr = &levels[curLevel]; ! 1083: levelPtr->winPtr = winPtr; ! 1084: arrayPtr = stacks[EXACT_LEAF_NAME]; ! 1085: arrayPtr->numUsed = 0; ! 1086: arrayPtr->nextToUse = arrayPtr->els; ! 1087: arrayPtr = stacks[EXACT_LEAF_CLASS]; ! 1088: arrayPtr->numUsed = 0; ! 1089: arrayPtr->nextToUse = arrayPtr->els; ! 1090: levelPtr->bases[EXACT_LEAF_NAME] = stacks[EXACT_LEAF_NAME]->numUsed; ! 1091: levelPtr->bases[EXACT_LEAF_CLASS] = stacks[EXACT_LEAF_CLASS]->numUsed; ! 1092: levelPtr->bases[EXACT_NODE_NAME] = stacks[EXACT_NODE_NAME]->numUsed; ! 1093: levelPtr->bases[EXACT_NODE_CLASS] = stacks[EXACT_NODE_CLASS]->numUsed; ! 1094: levelPtr->bases[WILDCARD_LEAF_NAME] = stacks[WILDCARD_LEAF_NAME]->numUsed; ! 1095: levelPtr->bases[WILDCARD_LEAF_CLASS] = stacks[WILDCARD_LEAF_CLASS]->numUsed; ! 1096: levelPtr->bases[WILDCARD_NODE_NAME] = stacks[WILDCARD_NODE_NAME]->numUsed; ! 1097: levelPtr->bases[WILDCARD_NODE_CLASS] = stacks[WILDCARD_NODE_CLASS]->numUsed; ! 1098: ! 1099: ! 1100: /* ! 1101: * Step 5: scan the current stack level looking for matches to this ! 1102: * window's name or class; where found, add new information to the ! 1103: * stacks. ! 1104: */ ! 1105: ! 1106: for (iPtr = searchOrder; *iPtr != -1; iPtr++) { ! 1107: register Element *elPtr; ! 1108: int count; ! 1109: Tk_Uid id; ! 1110: ! 1111: i = *iPtr; ! 1112: if (i & CLASS) { ! 1113: id = winPtr->classUid; ! 1114: } else { ! 1115: id = winPtr->nameUid; ! 1116: } ! 1117: elPtr = stacks[i]->els; ! 1118: count = levelPtr->bases[i]; ! 1119: ! 1120: /* ! 1121: * For wildcard stacks, check all entries; for non-wildcard ! 1122: * stacks, only check things that matched in the parent. ! 1123: */ ! 1124: ! 1125: if (!(i & WILDCARD)) { ! 1126: elPtr += levelPtr[-1].bases[i]; ! 1127: count -= levelPtr[-1].bases[i]; ! 1128: } ! 1129: for ( ; count > 0; elPtr++, count--) { ! 1130: if (elPtr->nameUid != id) { ! 1131: continue; ! 1132: } ! 1133: ExtendStacks(elPtr->child.arrayPtr, leaf); ! 1134: } ! 1135: } ! 1136: cachedWindow = winPtr; ! 1137: } ! 1138: ! 1139: /* ! 1140: *-------------------------------------------------------------- ! 1141: * ! 1142: * ExtendStacks -- ! 1143: * ! 1144: * Given an element array, copy all the elements from the ! 1145: * array onto the system stacks (except for irrelevant leaf ! 1146: * elements). ! 1147: * ! 1148: * Results: ! 1149: * None. ! 1150: * ! 1151: * Side effects: ! 1152: * The option stacks are extended. ! 1153: * ! 1154: *-------------------------------------------------------------- ! 1155: */ ! 1156: ! 1157: static void ! 1158: ExtendStacks(arrayPtr, leaf) ! 1159: ElArray *arrayPtr; /* Array of elements to copy onto stacks. */ ! 1160: int leaf; /* If zero, then don't copy exact leaf ! 1161: * elements. */ ! 1162: { ! 1163: register int count; ! 1164: register Element *elPtr; ! 1165: ! 1166: for (elPtr = arrayPtr->els, count = arrayPtr->numUsed; ! 1167: count > 0; elPtr++, count--) { ! 1168: if (!(elPtr->flags & (NODE|WILDCARD)) && !leaf) { ! 1169: continue; ! 1170: } ! 1171: stacks[elPtr->flags] = ExtendArray(stacks[elPtr->flags], elPtr); ! 1172: } ! 1173: } ! 1174: ! 1175: /* ! 1176: *-------------------------------------------------------------- ! 1177: * ! 1178: * OptionInit -- ! 1179: * ! 1180: * Initialize data structures for option handling. ! 1181: * ! 1182: * Results: ! 1183: * None. ! 1184: * ! 1185: * Side effects: ! 1186: * Option-related data structures get initialized. ! 1187: * ! 1188: *-------------------------------------------------------------- ! 1189: */ ! 1190: ! 1191: static void ! 1192: OptionInit(mainPtr) ! 1193: register TkMainInfo *mainPtr; /* Top-level information about ! 1194: * window that isn't initialized ! 1195: * yet. */ ! 1196: { ! 1197: int i; ! 1198: Tcl_Interp *interp; ! 1199: ! 1200: /* ! 1201: * First, once-only initialization. ! 1202: */ ! 1203: ! 1204: if (numLevels == 0) { ! 1205: ! 1206: numLevels = 5; ! 1207: levels = (StackLevel *) ckalloc((unsigned) (5*sizeof(StackLevel))); ! 1208: for (i = 0; i < NUM_STACKS; i++) { ! 1209: stacks[i] = NewArray(10); ! 1210: levels[0].bases[i] = 0; ! 1211: } ! 1212: ! 1213: defaultMatch.nameUid = NULL; ! 1214: defaultMatch.child.valueUid = NULL; ! 1215: defaultMatch.priority = -1; ! 1216: defaultMatch.flags = 0; ! 1217: } ! 1218: ! 1219: /* ! 1220: * Then, per-main-window initialization. Create and delete dummy ! 1221: * interpreter for message logging. ! 1222: */ ! 1223: ! 1224: mainPtr->optionRootPtr = NewArray(20); ! 1225: interp = Tcl_CreateInterp(); ! 1226: (void) GetDefaultOptions(interp, mainPtr->winPtr); ! 1227: Tcl_DeleteInterp(interp); ! 1228: } ! 1229: ! 1230: /* ! 1231: *-------------------------------------------------------------- ! 1232: * ! 1233: * ClearOptionTree -- ! 1234: * ! 1235: * This procedure is called to erase everything in a ! 1236: * hierarchical option database. ! 1237: * ! 1238: * Results: ! 1239: * None. ! 1240: * ! 1241: * Side effects: ! 1242: * All the options associated with arrayPtr are deleted, ! 1243: * along with all option subtrees. The space pointed to ! 1244: * by arrayPtr is freed. ! 1245: * ! 1246: *-------------------------------------------------------------- ! 1247: */ ! 1248: ! 1249: static void ! 1250: ClearOptionTree(arrayPtr) ! 1251: ElArray *arrayPtr; /* Array of options; delete everything ! 1252: * referred to recursively by this. */ ! 1253: { ! 1254: register Element *elPtr; ! 1255: int count; ! 1256: ! 1257: for (count = arrayPtr->numUsed, elPtr = arrayPtr->els; count > 0; ! 1258: count--, elPtr++) { ! 1259: if (elPtr->flags & NODE) { ! 1260: ClearOptionTree(elPtr->child.arrayPtr); ! 1261: } ! 1262: } ! 1263: ckfree((char *) arrayPtr); ! 1264: } ! 1265: ! 1266: /* ! 1267: *-------------------------------------------------------------- ! 1268: * ! 1269: * GetDefaultOptions -- ! 1270: * ! 1271: * This procedure is invoked to load the default set of options ! 1272: * for a window. ! 1273: * ! 1274: * Results: ! 1275: * None. ! 1276: * ! 1277: * Side effects: ! 1278: * Options are added to those for winPtr's main window. If ! 1279: * there exists a RESOURCE_MANAGER proprety for winPtr's ! 1280: * display, that is used. Otherwise, the .Xdefaults file in ! 1281: * the user's home directory is used. ! 1282: * ! 1283: *-------------------------------------------------------------- ! 1284: */ ! 1285: ! 1286: static int ! 1287: GetDefaultOptions(interp, winPtr) ! 1288: Tcl_Interp *interp; /* Interpreter to use for error reporting. */ ! 1289: TkWindow *winPtr; /* Fetch option defaults for main window ! 1290: * associated with this. */ ! 1291: { ! 1292: char *regProp, *home, *fileName; ! 1293: int result, actualFormat; ! 1294: unsigned long numItems, bytesAfter; ! 1295: Atom actualType; ! 1296: ! 1297: /* ! 1298: * Try the RESOURCE_MANAGER property on the root window first. ! 1299: */ ! 1300: ! 1301: regProp = NULL; ! 1302: result = XGetWindowProperty(winPtr->display, ! 1303: Tk_DefaultRootWindow(winPtr->display), ! 1304: XA_RESOURCE_MANAGER, 0, 100000, ! 1305: False, XA_STRING, &actualType, &actualFormat, ! 1306: &numItems, &bytesAfter, (unsigned char **) ®Prop); ! 1307: ! 1308: if ((result == Success) && (actualType == XA_STRING) ! 1309: && (actualFormat == 8)) { ! 1310: result = AddFromString(interp, (Tk_Window) winPtr, regProp, ! 1311: TK_USER_DEFAULT_PRIO); ! 1312: XFree(regProp); ! 1313: return result; ! 1314: } ! 1315: ! 1316: /* ! 1317: * No luck there. Try a .Xdefaults file in the user's home ! 1318: * directory. ! 1319: */ ! 1320: ! 1321: if (regProp != NULL) { ! 1322: XFree(regProp); ! 1323: } ! 1324: home = getenv("HOME"); ! 1325: if (home == NULL) { ! 1326: sprintf(interp->result, ! 1327: "no RESOURCE_MANAGER property and no HOME envariable"); ! 1328: return TCL_ERROR; ! 1329: } ! 1330: fileName = (char *) ckalloc((unsigned) (strlen(home) + 20)); ! 1331: sprintf(fileName, "%s/.Xdefaults", home); ! 1332: result = ReadOptionFile(interp, (Tk_Window) winPtr, fileName, ! 1333: TK_USER_DEFAULT_PRIO); ! 1334: ckfree(fileName); ! 1335: return result; ! 1336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.