OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkOption.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.