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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 29 - (hide annotations) (download)
Sat Oct 8 07:08:47 2016 UTC (7 years, 5 months ago) by dashley
Original Path: to_be_filed/sf_code/esrgpcpj/shared/tk_base/tkoption.c
File MIME type: text/plain
File size: 43161 byte(s)
Directories relocated.
1 dashley 25 /* $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