/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkoption.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkoption.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25