]>
cvs.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 *--------------------------------------------------------------
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. */
246 TkWindow
*winPtr
= ((TkWindow
*) tkwin
)->mainPtr
->winPtr
;
247 register ElArray
**arrayPtrPtr
;
248 register Element
*elPtr
;
252 int count
, firstField
, length
;
254 char tmp
[TMP_SIZE
+1];
256 if (winPtr
->mainPtr
->optionRootPtr
== NULL
) {
257 OptionInit(winPtr
->mainPtr
);
259 cachedWindow
= NULL
; /* Invalidate the cache. */
262 * Compute the priority for the new element, including both the
263 * overall level and the serial number (to disambiguate with the
269 } else if (priority
> TK_MAX_PRIO
) {
270 priority
= TK_MAX_PRIO
;
272 newEl
.priority
= (priority
<< 24) + serial
;
276 * Parse the option one field at a time.
279 arrayPtrPtr
= &(((TkWindow
*) tkwin
)->mainPtr
->optionRootPtr
);
281 for (firstField
= 1; ; firstField
= 0) {
284 * Scan the next field from the name and convert it to a Tk_Uid.
285 * Must copy the field before calling Tk_Uid, so that a terminating
286 * NULL may be added without modifying the source string.
290 newEl
.flags
= WILDCARD
;
296 while ((*p
!= 0) && (*p
!= '.') && (*p
!= '*')) {
300 if (length
> TMP_SIZE
) {
303 strncpy(tmp
, field
, length
);
305 newEl
.nameUid
= Tk_GetUid(tmp
);
306 if (isupper(*field
)) {
307 newEl
.flags
|= CLASS
;
313 * New element will be a node. If this option can't possibly
314 * apply to this main window, then just skip it. Otherwise,
315 * add it to the parent, if it isn't already there, and descend
320 if (firstField
&& !(newEl
.flags
& WILDCARD
)
321 && (newEl
.nameUid
!= winPtr
->nameUid
)
322 && (newEl
.nameUid
!= winPtr
->classUid
)) {
325 for (elPtr
= (*arrayPtrPtr
)->els
, count
= (*arrayPtrPtr
)->numUsed
;
326 ; elPtr
++, count
--) {
328 newEl
.child
.arrayPtr
= NewArray(5);
329 *arrayPtrPtr
= ExtendArray(*arrayPtrPtr
, &newEl
);
330 arrayPtrPtr
= &((*arrayPtrPtr
)->nextToUse
[-1].child
.arrayPtr
);
333 if ((elPtr
->nameUid
== newEl
.nameUid
)
334 && (elPtr
->flags
== newEl
.flags
)) {
335 arrayPtrPtr
= &(elPtr
->child
.arrayPtr
);
345 * New element is a leaf. Add it to the parent, if it isn't
346 * already there. If it exists already, keep whichever value
347 * has highest priority.
350 newEl
.child
.valueUid
= Tk_GetUid(value
);
351 for (elPtr
= (*arrayPtrPtr
)->els
, count
= (*arrayPtrPtr
)->numUsed
;
352 ; elPtr
++, count
--) {
354 *arrayPtrPtr
= ExtendArray(*arrayPtrPtr
, &newEl
);
357 if ((elPtr
->nameUid
== newEl
.nameUid
)
358 && (elPtr
->flags
== newEl
.flags
)) {
359 if (elPtr
->priority
< newEl
.priority
) {
360 elPtr
->priority
= newEl
.priority
;
361 elPtr
->child
.valueUid
= newEl
.child
.valueUid
;
371 *--------------------------------------------------------------
375 * Retrieve an option from the option database.
378 * The return value is the value specified in the option
379 * database for the given name and class on the given
380 * window. If there is nothing specified in the database
381 * for that option, then NULL is returned.
384 * The internal caches used to speed up option mapping
385 * may be modified, if this tkwin is different from the
386 * last tkwin used for option retrieval.
388 *--------------------------------------------------------------
393 Tk_Window tkwin
, /* Token for window that option is
394 * associated with. */
395 char *name
, /* Name of option. */
396 char *className
/* Class of option. NULL means there
397 * is no class for this option: just
401 Tk_Uid nameId
, classId
;
402 register Element
*elPtr
, *bestPtr
;
406 * Note: no need to call OptionInit here: it will be done by
407 * the SetupStacks call below (squeeze out those nanoseconds).
410 if (tkwin
!= (Tk_Window
) cachedWindow
) {
411 SetupStacks((TkWindow
*) tkwin
, 1);
414 nameId
= Tk_GetUid(name
);
415 bestPtr
= &defaultMatch
;
416 for (elPtr
= stacks
[EXACT_LEAF_NAME
]->els
,
417 count
= stacks
[EXACT_LEAF_NAME
]->numUsed
; count
> 0;
419 if ((elPtr
->nameUid
== nameId
)
420 && (elPtr
->priority
> bestPtr
->priority
)) {
424 for (elPtr
= stacks
[WILDCARD_LEAF_NAME
]->els
,
425 count
= stacks
[WILDCARD_LEAF_NAME
]->numUsed
; count
> 0;
427 if ((elPtr
->nameUid
== nameId
)
428 && (elPtr
->priority
> bestPtr
->priority
)) {
432 if (className
!= NULL
) {
433 classId
= Tk_GetUid(className
);
434 for (elPtr
= stacks
[EXACT_LEAF_CLASS
]->els
,
435 count
= stacks
[EXACT_LEAF_CLASS
]->numUsed
; count
> 0;
437 if ((elPtr
->nameUid
== classId
)
438 && (elPtr
->priority
> bestPtr
->priority
)) {
442 for (elPtr
= stacks
[WILDCARD_LEAF_CLASS
]->els
,
443 count
= stacks
[WILDCARD_LEAF_CLASS
]->numUsed
; count
> 0;
445 if ((elPtr
->nameUid
== classId
)
446 && (elPtr
->priority
> bestPtr
->priority
)) {
451 return bestPtr
->child
.valueUid
;
455 *--------------------------------------------------------------
459 * This procedure is invoked to process the "option" Tcl command.
460 * See the user documentation for details on what it does.
463 * A standard Tcl result.
466 * See the user documentation.
468 *--------------------------------------------------------------
473 ClientData clientData
, /* Main window associated with
475 Tcl_Interp
*interp
, /* Current interpreter. */
476 int argc
, /* Number of arguments. */
477 char **argv
/* Argument strings. */
480 Tk_Window tkwin
= (Tk_Window
) clientData
;
485 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
486 " cmd arg ?arg ...?\"", (char *) NULL
);
490 length
= strlen(argv
[1]);
491 if ((c
== 'a') && (strncmp(argv
[1], "add", length
) == 0)) {
494 if ((argc
!= 4) && (argc
!= 5)) {
495 Tcl_AppendResult(interp
, "wrong # args: should be \"",
496 argv
[0], " add pattern value ?priority?\"", (char *) NULL
);
500 priority
= TK_INTERACTIVE_PRIO
;
502 priority
= ParsePriority(interp
, argv
[4]);
507 Tk_AddOption(tkwin
, argv
[2], argv
[3], priority
);
509 } else if ((c
== 'c') && (strncmp(argv
[1], "clear", length
) == 0)) {
513 Tcl_AppendResult(interp
, "wrong # args: should be \"",
514 argv
[0], " clear\"", (char *) NULL
);
517 mainPtr
= ((TkWindow
*) tkwin
)->mainPtr
;
518 if (mainPtr
->optionRootPtr
!= NULL
) {
519 ClearOptionTree(mainPtr
->optionRootPtr
);
520 mainPtr
->optionRootPtr
= NULL
;
524 } else if ((c
== 'g') && (strncmp(argv
[1], "get", length
) == 0)) {
529 Tcl_AppendResult(interp
, "wrong # args: should be \"",
530 argv
[0], " get window name class\"", (char *) NULL
);
533 window
= Tk_NameToWindow(interp
, argv
[2], tkwin
);
534 if (window
== NULL
) {
537 value
= Tk_GetOption(window
, argv
[3], argv
[4]);
539 interp
->result
= value
;
542 } else if ((c
== 'r') && (strncmp(argv
[1], "readfile", length
) == 0)) {
545 if ((argc
!= 3) && (argc
!= 4)) {
546 Tcl_AppendResult(interp
, "wrong # args: should be \"",
547 argv
[0], " readfile fileName ?priority?\"",
552 priority
= ParsePriority(interp
, argv
[3]);
557 priority
= TK_INTERACTIVE_PRIO
;
559 return ReadOptionFile(interp
, tkwin
, argv
[2], priority
);
561 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
562 "\": must be add, clear, get, or readfile", (char *) NULL
);
568 *--------------------------------------------------------------
570 * TkOptionDeadWindow --
572 * This procedure is called whenever a window is deleted.
573 * It cleans up any option-related stuff associated with
580 * Option-related resources are freed. See code below
583 *--------------------------------------------------------------
588 register TkWindow
*winPtr
/* Window to be cleaned up. */
592 * If this window is in the option stacks, then clear the stacks.
595 if (winPtr
->optionLevel
!= -1) {
598 for (i
= 1; i
<= curLevel
; i
++) {
599 levels
[curLevel
].winPtr
->optionLevel
= -1;
606 * If this window was a main window, then delete its option
610 if ((winPtr
->mainPtr
->winPtr
== winPtr
)
611 && (winPtr
->mainPtr
->optionRootPtr
!= NULL
)) {
612 ClearOptionTree(winPtr
->mainPtr
->optionRootPtr
);
613 winPtr
->mainPtr
->optionRootPtr
= NULL
;
618 *----------------------------------------------------------------------
622 * Parse a string priority value.
625 * The return value is the integer priority level corresponding
626 * to string, or -1 if string doesn't point to a valid priority level.
627 * In this case, an error message is left in interp->result.
632 *----------------------------------------------------------------------
637 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
638 char *string
/* Describes a priority level, either
639 * symbolically or numerically. */
643 int length
, priority
;
646 length
= strlen(string
);
648 && (strncmp(string
, "widgetDefault", length
) == 0)) {
649 return TK_WIDGET_DEFAULT_PRIO
;
650 } else if ((c
== 's')
651 && (strncmp(string
, "startupFile", length
) == 0)) {
652 return TK_STARTUP_FILE_PRIO
;
653 } else if ((c
== 'u')
654 && (strncmp(string
, "userDefault", length
) == 0)) {
655 return TK_USER_DEFAULT_PRIO
;
656 } else if ((c
== 'i')
657 && (strncmp(string
, "interactive", length
) == 0)) {
658 return TK_INTERACTIVE_PRIO
;
662 priority
= strtoul(string
, &end
, 0);
663 if ((end
== string
) || (*end
!= 0) || (priority
< 0)
664 || (priority
> 100)) {
665 Tcl_AppendResult(interp
, "bad priority level \"", string
,
666 "\": must be widgetDefault, startupFile, userDefault, ",
667 "interactive, or a number between 0 and 100",
676 *----------------------------------------------------------------------
680 * Given a string containing lines in the standard format for
681 * X resources (see other documentation for details on what this
682 * is), parse the resource specifications and enter them as options
683 * for tkwin's main window.
686 * The return value is a standard Tcl return code. In the case of
687 * an error in parsing string, TCL_ERROR will be returned and an
688 * error message will be left in interp->result. The memory at
689 * string is totally trashed by this procedure. If you care about
690 * its contents, make a copy before calling here.
695 *----------------------------------------------------------------------
700 Tcl_Interp
*interp
, /* Interpreter to use for reporting results. */
701 Tk_Window tkwin
, /* Token for window: options are entered
702 * for this window's main window. */
703 char *string
, /* String containing option specifiers. */
704 int priority
/* Priority level to use for options in
705 * this string, such as TK_USER_DEFAULT_PRIO
706 * or TK_INTERACTIVE_PRIO. Must be between
707 * 0 and TK_MAX_PRIO. */
710 register char *src
, *dst
;
719 * Skip leading white space and empty lines and comment lines, and
720 * check for the end of the spec.
723 while ((*src
== ' ') || (*src
== '\t')) {
726 if ((*src
== '#') || (*src
== '!')) {
729 if ((src
[0] == '\\') && (src
[1] == '\n')) {
733 } while ((*src
!= '\n') && (*src
!= 0));
745 * Parse off the option name, collapsing out backslash-newline
746 * sequences of course.
750 while (*src
!= ':') {
751 if ((*src
== '\0') || (*src
== '\n')) {
752 sprintf(interp
->result
, "missing colon on line %d",
756 if ((src
[0] == '\\') && (src
[1] == '\n')) {
767 * Eliminate trailing white space on the name, and null-terminate
771 while ((dst
!= name
) && ((dst
[-1] == ' ') || (dst
[-1] == '\t'))) {
777 * Skip white space between the name and the value.
781 while ((*src
== ' ') || (*src
== '\t')) {
785 sprintf(interp
->result
, "missing value on line %d", lineNum
);
790 * Parse off the value, squeezing out backslash-newline sequences
795 while (*src
!= '\n') {
797 sprintf(interp
->result
, "missing newline on line %d",
801 if ((src
[0] == '\\') && (src
[1] == '\n')) {
813 * Enter the option into the database.
816 Tk_AddOption(tkwin
, name
, value
, priority
);
824 *----------------------------------------------------------------------
828 * Read a file of options ("resources" in the old X terminology)
829 * and load them into the option database.
832 * The return value is a standard Tcl return code. In the case of
833 * an error in parsing string, TCL_ERROR will be returned and an
834 * error message will be left in interp->result.
839 *----------------------------------------------------------------------
844 Tcl_Interp
*interp
, /* Interpreter to use for reporting results. */
845 Tk_Window tkwin
, /* Token for window: options are entered
846 * for this window's main window. */
847 char *fileName
, /* Name of file containing options. */
848 int priority
/* Priority level to use for options in
849 * this file, such as TK_USER_DEFAULT_PRIO
850 * or TK_INTERACTIVE_PRIO. Must be between
851 * 0 and TK_MAX_PRIO. */
854 char *realName
, *buffer
;
858 realName
= Tcl_TildeSubst(interp
, fileName
);
859 if (fileName
== NULL
) {
863 fileId
= open(realName
, O_RDONLY
| O_BINARY
, 0);
865 fileId
= open(realName
, O_RDONLY
, 0);
868 Tcl_AppendResult(interp
, "couldn't read file \"", fileName
, "\"",
872 if (fstat(fileId
, &statBuf
) == -1) {
873 Tcl_AppendResult(interp
, "couldn't stat file \"", fileName
, "\"",
878 buffer
= (char *) ckalloc((unsigned) statBuf
.st_size
+1);
880 if (read(fileId
, buffer
, (int) statBuf
.st_size
) < 0) {
882 if (read(fileId
, buffer
, (int) statBuf
.st_size
) != statBuf
.st_size
) {
884 Tcl_AppendResult(interp
, "error reading file \"", fileName
, "\"",
890 buffer
[statBuf
.st_size
] = 0;
891 result
= AddFromString(interp
, tkwin
, buffer
, priority
);
897 *--------------------------------------------------------------
901 * Create a new ElArray structure of a given size.
904 * The return value is a pointer to a properly initialized
905 * element array with "numEls" space. The array is marked
906 * as having no active elements.
909 * Memory is allocated.
911 *--------------------------------------------------------------
916 int numEls
/* How many elements of space to allocate. */
919 register ElArray
*arrayPtr
;
921 arrayPtr
= (ElArray
*) ckalloc(EL_ARRAY_SIZE(numEls
));
922 arrayPtr
->arraySize
= numEls
;
923 arrayPtr
->numUsed
= 0;
924 arrayPtr
->nextToUse
= arrayPtr
->els
;
929 *--------------------------------------------------------------
933 * Add a new element to an array, extending the array if
937 * The return value is a pointer to the new array, which
938 * will be different from arrayPtr if the array got expanded.
941 * Memory may be allocated or freed.
943 *--------------------------------------------------------------
948 register ElArray
*arrayPtr
, /* Array to be extended. */
949 register Element
*elPtr
/* Element to be copied into array. */
953 * If the current array has filled up, make it bigger.
956 if (arrayPtr
->numUsed
>= arrayPtr
->arraySize
) {
957 register ElArray
*newPtr
;
959 newPtr
= (ElArray
*) ckalloc(EL_ARRAY_SIZE(2*arrayPtr
->arraySize
));
960 newPtr
->arraySize
= 2*arrayPtr
->arraySize
;
961 newPtr
->numUsed
= arrayPtr
->numUsed
;
962 newPtr
->nextToUse
= &newPtr
->els
[newPtr
->numUsed
];
963 memcpy((VOID
*) newPtr
->els
, (VOID
*) arrayPtr
->els
,
964 (arrayPtr
->arraySize
*sizeof(Element
)));
965 ckfree((char *) arrayPtr
);
969 *arrayPtr
->nextToUse
= *elPtr
;
970 arrayPtr
->nextToUse
++;
976 *--------------------------------------------------------------
980 * Arrange the stacks so that they cache all the option
981 * information for a particular window.
987 * The stacks are modified to hold information for tkwin
988 * and all its ancestors in the window hierarchy.
990 *--------------------------------------------------------------
995 TkWindow
*winPtr
, /* Window for which information is to
997 int leaf
/* Non-zero means this is the leaf
998 * window being probed. Zero means this
999 * is an ancestor of the desired leaf. */
1002 int level
, i
, *iPtr
;
1003 register StackLevel
*levelPtr
;
1004 register ElArray
*arrayPtr
;
1007 * The following array defines the order in which the current
1008 * stacks are searched to find matching entries to add to the
1009 * stacks. Given the current priority-based scheme, the order
1010 * below is no longer relevant; all that matters is that an
1011 * element is on the list *somewhere*. The ordering is a relic
1012 * of the old days when priorities were determined differently.
1015 static int searchOrder
[] = {WILDCARD_NODE_CLASS
, WILDCARD_NODE_NAME
,
1016 EXACT_NODE_CLASS
, EXACT_NODE_NAME
, -1};
1018 if (winPtr
->mainPtr
->optionRootPtr
== NULL
) {
1019 OptionInit(winPtr
->mainPtr
);
1023 * Step 1: make sure that options are cached for this window's
1027 if (winPtr
->parentPtr
!= NULL
) {
1028 level
= winPtr
->parentPtr
->optionLevel
;
1029 if ((level
== -1) || (cachedWindow
== NULL
)) {
1030 SetupStacks(winPtr
->parentPtr
, 0);
1031 level
= winPtr
->parentPtr
->optionLevel
;
1039 * Step 2: pop extra unneeded information off the stacks and
1040 * mark those windows as no longer having cached information.
1043 if (curLevel
>= level
) {
1044 while (curLevel
>= level
) {
1045 levels
[curLevel
].winPtr
->optionLevel
= -1;
1048 levelPtr
= &levels
[level
];
1049 for (i
= 0; i
< NUM_STACKS
; i
++) {
1050 arrayPtr
= stacks
[i
];
1051 arrayPtr
->numUsed
= levelPtr
->bases
[i
];
1052 arrayPtr
->nextToUse
= &arrayPtr
->els
[arrayPtr
->numUsed
];
1055 curLevel
= winPtr
->optionLevel
= level
;
1058 * Step 3: if the root database information isn't loaded or
1059 * isn't valid, initialize level 0 of the stack from the
1060 * database root (this only happens if winPtr is a main window).
1064 && ((cachedWindow
== NULL
)
1065 || (cachedWindow
->mainPtr
!= winPtr
->mainPtr
))) {
1066 for (i
= 0; i
< NUM_STACKS
; i
++) {
1067 arrayPtr
= stacks
[i
];
1068 arrayPtr
->numUsed
= 0;
1069 arrayPtr
->nextToUse
= arrayPtr
->els
;
1071 ExtendStacks(winPtr
->mainPtr
->optionRootPtr
, 0);
1075 * Step 4: create a new stack level; grow the level array if
1076 * we've run out of levels. Clear the stacks for EXACT_LEAF_NAME
1077 * and EXACT_LEAF_CLASS (anything that was there is of no use
1081 if (curLevel
>= numLevels
) {
1082 StackLevel
*newLevels
;
1084 newLevels
= (StackLevel
*) ckalloc((unsigned)
1085 (numLevels
*2*sizeof(StackLevel
)));
1086 memcpy((VOID
*) newLevels
, (VOID
*) levels
,
1087 (numLevels
*sizeof(StackLevel
)));
1088 ckfree((char *) levels
);
1092 levelPtr
= &levels
[curLevel
];
1093 levelPtr
->winPtr
= winPtr
;
1094 arrayPtr
= stacks
[EXACT_LEAF_NAME
];
1095 arrayPtr
->numUsed
= 0;
1096 arrayPtr
->nextToUse
= arrayPtr
->els
;
1097 arrayPtr
= stacks
[EXACT_LEAF_CLASS
];
1098 arrayPtr
->numUsed
= 0;
1099 arrayPtr
->nextToUse
= arrayPtr
->els
;
1100 levelPtr
->bases
[EXACT_LEAF_NAME
] = stacks
[EXACT_LEAF_NAME
]->numUsed
;
1101 levelPtr
->bases
[EXACT_LEAF_CLASS
] = stacks
[EXACT_LEAF_CLASS
]->numUsed
;
1102 levelPtr
->bases
[EXACT_NODE_NAME
] = stacks
[EXACT_NODE_NAME
]->numUsed
;
1103 levelPtr
->bases
[EXACT_NODE_CLASS
] = stacks
[EXACT_NODE_CLASS
]->numUsed
;
1104 levelPtr
->bases
[WILDCARD_LEAF_NAME
] = stacks
[WILDCARD_LEAF_NAME
]->numUsed
;
1105 levelPtr
->bases
[WILDCARD_LEAF_CLASS
] = stacks
[WILDCARD_LEAF_CLASS
]->numUsed
;
1106 levelPtr
->bases
[WILDCARD_NODE_NAME
] = stacks
[WILDCARD_NODE_NAME
]->numUsed
;
1107 levelPtr
->bases
[WILDCARD_NODE_CLASS
] = stacks
[WILDCARD_NODE_CLASS
]->numUsed
;
1111 * Step 5: scan the current stack level looking for matches to this
1112 * window's name or class; where found, add new information to the
1116 for (iPtr
= searchOrder
; *iPtr
!= -1; iPtr
++) {
1117 register Element
*elPtr
;
1123 id
= winPtr
->classUid
;
1125 id
= winPtr
->nameUid
;
1127 elPtr
= stacks
[i
]->els
;
1128 count
= levelPtr
->bases
[i
];
1131 * For wildcard stacks, check all entries; for non-wildcard
1132 * stacks, only check things that matched in the parent.
1135 if (!(i
& WILDCARD
)) {
1136 elPtr
+= levelPtr
[-1].bases
[i
];
1137 count
-= levelPtr
[-1].bases
[i
];
1139 for ( ; count
> 0; elPtr
++, count
--) {
1140 if (elPtr
->nameUid
!= id
) {
1143 ExtendStacks(elPtr
->child
.arrayPtr
, leaf
);
1146 cachedWindow
= winPtr
;
1150 *--------------------------------------------------------------
1154 * Given an element array, copy all the elements from the
1155 * array onto the system stacks (except for irrelevant leaf
1162 * The option stacks are extended.
1164 *--------------------------------------------------------------
1169 ElArray
*arrayPtr
, /* Array of elements to copy onto stacks. */
1170 int leaf
/* If zero, then don't copy exact leaf
1175 register Element
*elPtr
;
1177 for (elPtr
= arrayPtr
->els
, count
= arrayPtr
->numUsed
;
1178 count
> 0; elPtr
++, count
--) {
1179 if (!(elPtr
->flags
& (NODE
|WILDCARD
)) && !leaf
) {
1182 stacks
[elPtr
->flags
] = ExtendArray(stacks
[elPtr
->flags
], elPtr
);
1187 *--------------------------------------------------------------
1191 * Initialize data structures for option handling.
1197 * Option-related data structures get initialized.
1199 *--------------------------------------------------------------
1204 register TkMainInfo
*mainPtr
/* Top-level information about
1205 * window that isn't initialized
1213 * First, once-only initialization.
1216 if (numLevels
== 0) {
1219 levels
= (StackLevel
*) ckalloc((unsigned) (5*sizeof(StackLevel
)));
1220 for (i
= 0; i
< NUM_STACKS
; i
++) {
1221 stacks
[i
] = NewArray(10);
1222 levels
[0].bases
[i
] = 0;
1225 defaultMatch
.nameUid
= NULL
;
1226 defaultMatch
.child
.valueUid
= NULL
;
1227 defaultMatch
.priority
= -1;
1228 defaultMatch
.flags
= 0;
1232 * Then, per-main-window initialization. Create and delete dummy
1233 * interpreter for message logging.
1236 mainPtr
->optionRootPtr
= NewArray(20);
1237 interp
= Tcl_CreateInterp();
1238 (void) GetDefaultOptions(interp
, mainPtr
->winPtr
);
1239 Tcl_DeleteInterp(interp
);
1243 *--------------------------------------------------------------
1245 * ClearOptionTree --
1247 * This procedure is called to erase everything in a
1248 * hierarchical option database.
1254 * All the options associated with arrayPtr are deleted,
1255 * along with all option subtrees. The space pointed to
1256 * by arrayPtr is freed.
1258 *--------------------------------------------------------------
1263 ElArray
*arrayPtr
/* Array of options; delete everything
1264 * referred to recursively by this. */
1267 register Element
*elPtr
;
1270 for (count
= arrayPtr
->numUsed
, elPtr
= arrayPtr
->els
; count
> 0;
1272 if (elPtr
->flags
& NODE
) {
1273 ClearOptionTree(elPtr
->child
.arrayPtr
);
1276 ckfree((char *) arrayPtr
);
1280 *--------------------------------------------------------------
1282 * GetDefaultOptions --
1284 * This procedure is invoked to load the default set of options
1291 * Options are added to those for winPtr's main window. If
1292 * there exists a RESOURCE_MANAGER proprety for winPtr's
1293 * display, that is used. Otherwise, the .Xdefaults file in
1294 * the user's home directory is used.
1296 *--------------------------------------------------------------
1301 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
1302 TkWindow
*winPtr
/* Fetch option defaults for main window
1303 * associated with this. */
1306 char *regProp
, *home
, *fileName
;
1307 int result
, actualFormat
;
1308 unsigned long numItems
, bytesAfter
;
1312 * Try the RESOURCE_MANAGER property on the root window first.
1316 result
= XGetWindowProperty(winPtr
->display
,
1317 Tk_DefaultRootWindow(winPtr
->display
),
1318 XA_RESOURCE_MANAGER
, 0, 100000,
1319 False
, XA_STRING
, &actualType
, &actualFormat
,
1320 &numItems
, &bytesAfter
, (unsigned char **) ®Prop
);
1322 if ((result
== Success
) && (actualType
== XA_STRING
)
1323 && (actualFormat
== 8)) {
1324 result
= AddFromString(interp
, (Tk_Window
) winPtr
, regProp
,
1325 TK_USER_DEFAULT_PRIO
);
1331 * No luck there. Try a .Xdefaults file in the user's home
1335 if (regProp
!= NULL
) {
1338 home
= getenv("HOME");
1340 sprintf(interp
->result
,
1341 "no RESOURCE_MANAGER property and no HOME envariable");
1344 fileName
= (char *) ckalloc((unsigned) (strlen(home
) + 20));
1345 sprintf(fileName
, "%s/.Xdefaults", home
);
1346 result
= ReadOptionFile(interp
, (Tk_Window
) winPtr
, fileName
,
1347 TK_USER_DEFAULT_PRIO
);