]>
git.zerfleddert.de Git - micropolis/blob - src/tk/tkoption.c
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.
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.
19 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkOption.c,v 1.25 92/03/16 08:46:14 ouster Exp $ SPRITE (Berkeley)";
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.
36 typedef struct Element
{
37 Tk_Uid nameUid
; /* Name or class from one element of
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. */
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
54 int flags
; /* OR-ed combination of bits. See
55 * below for values. */
59 * Flags in NodeElement structures:
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.
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
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.
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
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
108 #define EL_ARRAY_SIZE(numEls) ((unsigned) (sizeof(ElArray) \
109 + ((numEls)-1)*sizeof(Element)))
110 #define INITIAL_SIZE 5
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".
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.
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.
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. */
158 * One of the following structures is used to keep track of each
159 * level in the stacks.
162 typedef struct StackLevel
{
163 TkWindow
*winPtr
; /* Window corresponding to this stack
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. */
172 * Information about all of the stack levels that are currently
173 * active. This array grows dynamically to become as large as needed.
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. */
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
189 static int serial
= 0;
192 * Special "no match" Element to use as default for searches.
195 static Element defaultMatch
;
198 * Forward declarations for procedures defined in this file:
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
,
206 static void ExtendStacks
_ANSI_ARGS_((ElArray
*arrayPtr
,
208 static int GetDefaultOptions
_ANSI_ARGS_((Tcl_Interp
*interp
,
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
,
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
));
219 *--------------------------------------------------------------
223 * Add a new option to the option database.
229 * Information is added to the option database.
231 *--------------------------------------------------------------
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. */
245 TkWindow
*winPtr
= ((TkWindow
*) tkwin
)->mainPtr
->winPtr
;
246 register ElArray
**arrayPtrPtr
;
247 register Element
*elPtr
;
251 int count
, firstField
, length
;
253 char tmp
[TMP_SIZE
+1];
255 if (winPtr
->mainPtr
->optionRootPtr
== NULL
) {
256 OptionInit(winPtr
->mainPtr
);
258 cachedWindow
= NULL
; /* Invalidate the cache. */
261 * Compute the priority for the new element, including both the
262 * overall level and the serial number (to disambiguate with the
268 } else if (priority
> TK_MAX_PRIO
) {
269 priority
= TK_MAX_PRIO
;
271 newEl
.priority
= (priority
<< 24) + serial
;
275 * Parse the option one field at a time.
278 arrayPtrPtr
= &(((TkWindow
*) tkwin
)->mainPtr
->optionRootPtr
);
280 for (firstField
= 1; ; firstField
= 0) {
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.
289 newEl
.flags
= WILDCARD
;
295 while ((*p
!= 0) && (*p
!= '.') && (*p
!= '*')) {
299 if (length
> TMP_SIZE
) {
302 strncpy(tmp
, field
, length
);
304 newEl
.nameUid
= Tk_GetUid(tmp
);
305 if (isupper(*field
)) {
306 newEl
.flags
|= CLASS
;
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
319 if (firstField
&& !(newEl
.flags
& WILDCARD
)
320 && (newEl
.nameUid
!= winPtr
->nameUid
)
321 && (newEl
.nameUid
!= winPtr
->classUid
)) {
324 for (elPtr
= (*arrayPtrPtr
)->els
, count
= (*arrayPtrPtr
)->numUsed
;
325 ; elPtr
++, count
--) {
327 newEl
.child
.arrayPtr
= NewArray(5);
328 *arrayPtrPtr
= ExtendArray(*arrayPtrPtr
, &newEl
);
329 arrayPtrPtr
= &((*arrayPtrPtr
)->nextToUse
[-1].child
.arrayPtr
);
332 if ((elPtr
->nameUid
== newEl
.nameUid
)
333 && (elPtr
->flags
== newEl
.flags
)) {
334 arrayPtrPtr
= &(elPtr
->child
.arrayPtr
);
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.
349 newEl
.child
.valueUid
= Tk_GetUid(value
);
350 for (elPtr
= (*arrayPtrPtr
)->els
, count
= (*arrayPtrPtr
)->numUsed
;
351 ; elPtr
++, count
--) {
353 *arrayPtrPtr
= ExtendArray(*arrayPtrPtr
, &newEl
);
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
;
370 *--------------------------------------------------------------
374 * Retrieve an option from the option database.
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.
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.
387 *--------------------------------------------------------------
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
399 Tk_Uid nameId
, classId
;
400 register Element
*elPtr
, *bestPtr
;
404 * Note: no need to call OptionInit here: it will be done by
405 * the SetupStacks call below (squeeze out those nanoseconds).
408 if (tkwin
!= (Tk_Window
) cachedWindow
) {
409 SetupStacks((TkWindow
*) tkwin
, 1);
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;
417 if ((elPtr
->nameUid
== nameId
)
418 && (elPtr
->priority
> bestPtr
->priority
)) {
422 for (elPtr
= stacks
[WILDCARD_LEAF_NAME
]->els
,
423 count
= stacks
[WILDCARD_LEAF_NAME
]->numUsed
; count
> 0;
425 if ((elPtr
->nameUid
== nameId
)
426 && (elPtr
->priority
> bestPtr
->priority
)) {
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;
435 if ((elPtr
->nameUid
== classId
)
436 && (elPtr
->priority
> bestPtr
->priority
)) {
440 for (elPtr
= stacks
[WILDCARD_LEAF_CLASS
]->els
,
441 count
= stacks
[WILDCARD_LEAF_CLASS
]->numUsed
; count
> 0;
443 if ((elPtr
->nameUid
== classId
)
444 && (elPtr
->priority
> bestPtr
->priority
)) {
449 return bestPtr
->child
.valueUid
;
453 *--------------------------------------------------------------
457 * This procedure is invoked to process the "option" Tcl command.
458 * See the user documentation for details on what it does.
461 * A standard Tcl result.
464 * See the user documentation.
466 *--------------------------------------------------------------
470 Tk_OptionCmd(clientData
, interp
, argc
, argv
)
471 ClientData clientData
; /* Main window associated with
473 Tcl_Interp
*interp
; /* Current interpreter. */
474 int argc
; /* Number of arguments. */
475 char **argv
; /* Argument strings. */
477 Tk_Window tkwin
= (Tk_Window
) clientData
;
482 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
483 " cmd arg ?arg ...?\"", (char *) NULL
);
487 length
= strlen(argv
[1]);
488 if ((c
== 'a') && (strncmp(argv
[1], "add", length
) == 0)) {
491 if ((argc
!= 4) && (argc
!= 5)) {
492 Tcl_AppendResult(interp
, "wrong # args: should be \"",
493 argv
[0], " add pattern value ?priority?\"", (char *) NULL
);
497 priority
= TK_INTERACTIVE_PRIO
;
499 priority
= ParsePriority(interp
, argv
[4]);
504 Tk_AddOption(tkwin
, argv
[2], argv
[3], priority
);
506 } else if ((c
== 'c') && (strncmp(argv
[1], "clear", length
) == 0)) {
510 Tcl_AppendResult(interp
, "wrong # args: should be \"",
511 argv
[0], " clear\"", (char *) NULL
);
514 mainPtr
= ((TkWindow
*) tkwin
)->mainPtr
;
515 if (mainPtr
->optionRootPtr
!= NULL
) {
516 ClearOptionTree(mainPtr
->optionRootPtr
);
517 mainPtr
->optionRootPtr
= NULL
;
521 } else if ((c
== 'g') && (strncmp(argv
[1], "get", length
) == 0)) {
526 Tcl_AppendResult(interp
, "wrong # args: should be \"",
527 argv
[0], " get window name class\"", (char *) NULL
);
530 window
= Tk_NameToWindow(interp
, argv
[2], tkwin
);
531 if (window
== NULL
) {
534 value
= Tk_GetOption(window
, argv
[3], argv
[4]);
536 interp
->result
= value
;
539 } else if ((c
== 'r') && (strncmp(argv
[1], "readfile", length
) == 0)) {
542 if ((argc
!= 3) && (argc
!= 4)) {
543 Tcl_AppendResult(interp
, "wrong # args: should be \"",
544 argv
[0], " readfile fileName ?priority?\"",
549 priority
= ParsePriority(interp
, argv
[3]);
554 priority
= TK_INTERACTIVE_PRIO
;
556 return ReadOptionFile(interp
, tkwin
, argv
[2], priority
);
558 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
559 "\": must be add, clear, get, or readfile", (char *) NULL
);
565 *--------------------------------------------------------------
567 * TkOptionDeadWindow --
569 * This procedure is called whenever a window is deleted.
570 * It cleans up any option-related stuff associated with
577 * Option-related resources are freed. See code below
580 *--------------------------------------------------------------
584 TkOptionDeadWindow(winPtr
)
585 register TkWindow
*winPtr
; /* Window to be cleaned up. */
588 * If this window is in the option stacks, then clear the stacks.
591 if (winPtr
->optionLevel
!= -1) {
594 for (i
= 1; i
<= curLevel
; i
++) {
595 levels
[curLevel
].winPtr
->optionLevel
= -1;
602 * If this window was a main window, then delete its option
606 if ((winPtr
->mainPtr
->winPtr
== winPtr
)
607 && (winPtr
->mainPtr
->optionRootPtr
!= NULL
)) {
608 ClearOptionTree(winPtr
->mainPtr
->optionRootPtr
);
609 winPtr
->mainPtr
->optionRootPtr
= NULL
;
614 *----------------------------------------------------------------------
618 * Parse a string priority value.
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.
628 *----------------------------------------------------------------------
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. */
638 int length
, priority
;
641 length
= strlen(string
);
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
;
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",
671 *----------------------------------------------------------------------
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.
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.
690 *----------------------------------------------------------------------
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. */
704 register char *src
, *dst
;
713 * Skip leading white space and empty lines and comment lines, and
714 * check for the end of the spec.
717 while ((*src
== ' ') || (*src
== '\t')) {
720 if ((*src
== '#') || (*src
== '!')) {
723 if ((src
[0] == '\\') && (src
[1] == '\n')) {
727 } while ((*src
!= '\n') && (*src
!= 0));
739 * Parse off the option name, collapsing out backslash-newline
740 * sequences of course.
744 while (*src
!= ':') {
745 if ((*src
== '\0') || (*src
== '\n')) {
746 sprintf(interp
->result
, "missing colon on line %d",
750 if ((src
[0] == '\\') && (src
[1] == '\n')) {
761 * Eliminate trailing white space on the name, and null-terminate
765 while ((dst
!= name
) && ((dst
[-1] == ' ') || (dst
[-1] == '\t'))) {
771 * Skip white space between the name and the value.
775 while ((*src
== ' ') || (*src
== '\t')) {
779 sprintf(interp
->result
, "missing value on line %d", lineNum
);
784 * Parse off the value, squeezing out backslash-newline sequences
789 while (*src
!= '\n') {
791 sprintf(interp
->result
, "missing newline on line %d",
795 if ((src
[0] == '\\') && (src
[1] == '\n')) {
807 * Enter the option into the database.
810 Tk_AddOption(tkwin
, name
, value
, priority
);
818 *----------------------------------------------------------------------
822 * Read a file of options ("resources" in the old X terminology)
823 * and load them into the option database.
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.
833 *----------------------------------------------------------------------
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. */
847 char *realName
, *buffer
;
851 realName
= Tcl_TildeSubst(interp
, fileName
);
852 if (fileName
== NULL
) {
856 fileId
= open(realName
, O_RDONLY
| O_BINARY
, 0);
858 fileId
= open(realName
, O_RDONLY
, 0);
861 Tcl_AppendResult(interp
, "couldn't read file \"", fileName
, "\"",
865 if (fstat(fileId
, &statBuf
) == -1) {
866 Tcl_AppendResult(interp
, "couldn't stat file \"", fileName
, "\"",
871 buffer
= (char *) ckalloc((unsigned) statBuf
.st_size
+1);
873 if (read(fileId
, buffer
, (int) statBuf
.st_size
) < 0) {
875 if (read(fileId
, buffer
, (int) statBuf
.st_size
) != statBuf
.st_size
) {
877 Tcl_AppendResult(interp
, "error reading file \"", fileName
, "\"",
883 buffer
[statBuf
.st_size
] = 0;
884 result
= AddFromString(interp
, tkwin
, buffer
, priority
);
890 *--------------------------------------------------------------
894 * Create a new ElArray structure of a given size.
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.
902 * Memory is allocated.
904 *--------------------------------------------------------------
909 int numEls
; /* How many elements of space to allocate. */
911 register ElArray
*arrayPtr
;
913 arrayPtr
= (ElArray
*) ckalloc(EL_ARRAY_SIZE(numEls
));
914 arrayPtr
->arraySize
= numEls
;
915 arrayPtr
->numUsed
= 0;
916 arrayPtr
->nextToUse
= arrayPtr
->els
;
921 *--------------------------------------------------------------
925 * Add a new element to an array, extending the array if
929 * The return value is a pointer to the new array, which
930 * will be different from arrayPtr if the array got expanded.
933 * Memory may be allocated or freed.
935 *--------------------------------------------------------------
939 ExtendArray(arrayPtr
, elPtr
)
940 register ElArray
*arrayPtr
; /* Array to be extended. */
941 register Element
*elPtr
; /* Element to be copied into array. */
944 * If the current array has filled up, make it bigger.
947 if (arrayPtr
->numUsed
>= arrayPtr
->arraySize
) {
948 register ElArray
*newPtr
;
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
);
960 *arrayPtr
->nextToUse
= *elPtr
;
961 arrayPtr
->nextToUse
++;
967 *--------------------------------------------------------------
971 * Arrange the stacks so that they cache all the option
972 * information for a particular window.
978 * The stacks are modified to hold information for tkwin
979 * and all its ancestors in the window hierarchy.
981 *--------------------------------------------------------------
985 SetupStacks(winPtr
, leaf
)
986 TkWindow
*winPtr
; /* Window for which information is to
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. */
993 register StackLevel
*levelPtr
;
994 register ElArray
*arrayPtr
;
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.
1005 static int searchOrder
[] = {WILDCARD_NODE_CLASS
, WILDCARD_NODE_NAME
,
1006 EXACT_NODE_CLASS
, EXACT_NODE_NAME
, -1};
1008 if (winPtr
->mainPtr
->optionRootPtr
== NULL
) {
1009 OptionInit(winPtr
->mainPtr
);
1013 * Step 1: make sure that options are cached for this window's
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
;
1029 * Step 2: pop extra unneeded information off the stacks and
1030 * mark those windows as no longer having cached information.
1033 if (curLevel
>= level
) {
1034 while (curLevel
>= level
) {
1035 levels
[curLevel
].winPtr
->optionLevel
= -1;
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
];
1045 curLevel
= winPtr
->optionLevel
= level
;
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).
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
;
1061 ExtendStacks(winPtr
->mainPtr
->optionRootPtr
, 0);
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
1071 if (curLevel
>= numLevels
) {
1072 StackLevel
*newLevels
;
1074 newLevels
= (StackLevel
*) ckalloc((unsigned)
1075 (numLevels
*2*sizeof(StackLevel
)));
1076 memcpy((VOID
*) newLevels
, (VOID
*) levels
,
1077 (numLevels
*sizeof(StackLevel
)));
1078 ckfree((char *) levels
);
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
;
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
1106 for (iPtr
= searchOrder
; *iPtr
!= -1; iPtr
++) {
1107 register Element
*elPtr
;
1113 id
= winPtr
->classUid
;
1115 id
= winPtr
->nameUid
;
1117 elPtr
= stacks
[i
]->els
;
1118 count
= levelPtr
->bases
[i
];
1121 * For wildcard stacks, check all entries; for non-wildcard
1122 * stacks, only check things that matched in the parent.
1125 if (!(i
& WILDCARD
)) {
1126 elPtr
+= levelPtr
[-1].bases
[i
];
1127 count
-= levelPtr
[-1].bases
[i
];
1129 for ( ; count
> 0; elPtr
++, count
--) {
1130 if (elPtr
->nameUid
!= id
) {
1133 ExtendStacks(elPtr
->child
.arrayPtr
, leaf
);
1136 cachedWindow
= winPtr
;
1140 *--------------------------------------------------------------
1144 * Given an element array, copy all the elements from the
1145 * array onto the system stacks (except for irrelevant leaf
1152 * The option stacks are extended.
1154 *--------------------------------------------------------------
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
1164 register Element
*elPtr
;
1166 for (elPtr
= arrayPtr
->els
, count
= arrayPtr
->numUsed
;
1167 count
> 0; elPtr
++, count
--) {
1168 if (!(elPtr
->flags
& (NODE
|WILDCARD
)) && !leaf
) {
1171 stacks
[elPtr
->flags
] = ExtendArray(stacks
[elPtr
->flags
], elPtr
);
1176 *--------------------------------------------------------------
1180 * Initialize data structures for option handling.
1186 * Option-related data structures get initialized.
1188 *--------------------------------------------------------------
1193 register TkMainInfo
*mainPtr
; /* Top-level information about
1194 * window that isn't initialized
1201 * First, once-only initialization.
1204 if (numLevels
== 0) {
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;
1213 defaultMatch
.nameUid
= NULL
;
1214 defaultMatch
.child
.valueUid
= NULL
;
1215 defaultMatch
.priority
= -1;
1216 defaultMatch
.flags
= 0;
1220 * Then, per-main-window initialization. Create and delete dummy
1221 * interpreter for message logging.
1224 mainPtr
->optionRootPtr
= NewArray(20);
1225 interp
= Tcl_CreateInterp();
1226 (void) GetDefaultOptions(interp
, mainPtr
->winPtr
);
1227 Tcl_DeleteInterp(interp
);
1231 *--------------------------------------------------------------
1233 * ClearOptionTree --
1235 * This procedure is called to erase everything in a
1236 * hierarchical option database.
1242 * All the options associated with arrayPtr are deleted,
1243 * along with all option subtrees. The space pointed to
1244 * by arrayPtr is freed.
1246 *--------------------------------------------------------------
1250 ClearOptionTree(arrayPtr
)
1251 ElArray
*arrayPtr
; /* Array of options; delete everything
1252 * referred to recursively by this. */
1254 register Element
*elPtr
;
1257 for (count
= arrayPtr
->numUsed
, elPtr
= arrayPtr
->els
; count
> 0;
1259 if (elPtr
->flags
& NODE
) {
1260 ClearOptionTree(elPtr
->child
.arrayPtr
);
1263 ckfree((char *) arrayPtr
);
1267 *--------------------------------------------------------------
1269 * GetDefaultOptions --
1271 * This procedure is invoked to load the default set of options
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.
1283 *--------------------------------------------------------------
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. */
1292 char *regProp
, *home
, *fileName
;
1293 int result
, actualFormat
;
1294 unsigned long numItems
, bytesAfter
;
1298 * Try the RESOURCE_MANAGER property on the root window first.
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
);
1308 if ((result
== Success
) && (actualType
== XA_STRING
)
1309 && (actualFormat
== 8)) {
1310 result
= AddFromString(interp
, (Tk_Window
) winPtr
, regProp
,
1311 TK_USER_DEFAULT_PRIO
);
1317 * No luck there. Try a .Xdefaults file in the user's home
1321 if (regProp
!= NULL
) {
1324 home
= getenv("HOME");
1326 sprintf(interp
->result
,
1327 "no RESOURCE_MANAGER property and no HOME envariable");
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
);