diff options
author | ericm <ericm> | 2000-05-27 01:43:45 (GMT) |
---|---|---|
committer | ericm <ericm> | 2000-05-27 01:43:45 (GMT) |
commit | ce3669a362d5ee468d51566ce6e126f5a761b315 (patch) | |
tree | 00968ee57898e5b8d8cca9d4c6a9146262aa6550 /generic | |
parent | b1ecdd6bed804198c1cb6a6af95704954f4345ee (diff) | |
download | tk-ce3669a362d5ee468d51566ce6e126f5a761b315.zip tk-ce3669a362d5ee468d51566ce6e126f5a761b315.tar.gz tk-ce3669a362d5ee468d51566ce6e126f5a761b315.tar.bz2 |
* generic/tkOption.c (Tk_GetOption): Extended Tk_GetOption to
support a new syntax for option names in option tables. If the
option name has an embedded ".", it indicates that the name field
contains both an option name and an overriding widget class, in
the form "class.option". The lookup for the option value will be
performed as though the widget class is that specified, rather
than the actual widget class.
(SetupStacks): Replaced several lines of array element copying
with a for loop for conciseness.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkOption.c | 169 |
1 files changed, 141 insertions, 28 deletions
diff --git a/generic/tkOption.c b/generic/tkOption.c index f35534f..4f09e99 100644 --- a/generic/tkOption.c +++ b/generic/tkOption.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkOption.c,v 1.4 2000/03/24 23:13:18 ericm Exp $ + * RCS: @(#) $Id: tkOption.c,v 1.5 2000/05/27 01:43:46 ericm Exp $ */ #include "tkPort.h" @@ -397,8 +397,11 @@ Tk_GetOption(tkwin, name, className) * check for name. */ { Tk_Uid nameId, classId; + char *masqName; register Element *elPtr, *bestPtr; register int count; + StackLevel *levelPtr; + int stackDepth[NUM_STACKS]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -411,43 +414,168 @@ Tk_GetOption(tkwin, name, className) SetupStacks((TkWindow *) tkwin, 1); } - nameId = Tk_GetUid(name); + /* + * Get a default "best" match. + */ + bestPtr = &tsdPtr->defaultMatch; + + /* + * For megawidget support, we want to have some widget options masquerade + * as options for other widgets. For example, a combobox has a button in + * it; this button ought to pick up the *Button.background, etc., options. + * But because the class of the widget is Combobox, our normal search + * won't get that option. + * + * To work around this, the option name field syntax was extended to allow + * for a "." in the name; if this character occurs in the name, then it + * indicates that this name contains a new window class and an option name, + * ie, "Button.foreground". If we see this form in the name field, we + * query the option database directly (since the option stacks will not + * have the information we need). + */ + + masqName = strchr(name, (int)'.'); + if (masqName != NULL) { + /* + * This option is masquerading with a different window class. + * Instead of using the current level, search the stack to the + * current level - 1, then do a direct probe on the option database + * to get the extra bits. + */ + levelPtr = &tsdPtr->levels[tsdPtr->curLevel]; + nameId = Tk_GetUid(masqName+1); + for (count = 0; count < NUM_STACKS; count++) { + stackDepth[count] = levelPtr->bases[count]; + } + } else { + /* + * No option masquerading here. Just use the current level to get the + * stack depths. + */ + nameId = Tk_GetUid(name); + for (count = 0; count < NUM_STACKS; count++) { + stackDepth[count] = tsdPtr->stacks[count]->numUsed; + } + } + + /* + * Probe the stacks for matches. + */ + for (elPtr = tsdPtr->stacks[EXACT_LEAF_NAME]->els, - count = tsdPtr->stacks[EXACT_LEAF_NAME]->numUsed; count > 0; - elPtr++, count--) { + count = stackDepth[EXACT_LEAF_NAME]; count > 0; + elPtr++, count--) { if ((elPtr->nameUid == nameId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } for (elPtr = tsdPtr->stacks[WILDCARD_LEAF_NAME]->els, - count = tsdPtr->stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0; - elPtr++, count--) { + count = stackDepth[WILDCARD_LEAF_NAME]; count > 0; + elPtr++, count--) { if ((elPtr->nameUid == nameId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } + if (className != NULL) { classId = Tk_GetUid(className); for (elPtr = tsdPtr->stacks[EXACT_LEAF_CLASS]->els, - count = tsdPtr->stacks[EXACT_LEAF_CLASS]->numUsed; count > 0; - elPtr++, count--) { + count = stackDepth[EXACT_LEAF_CLASS]; count > 0; + elPtr++, count--) { if ((elPtr->nameUid == classId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } for (elPtr = tsdPtr->stacks[WILDCARD_LEAF_CLASS]->els, - count = tsdPtr->stacks[WILDCARD_LEAF_CLASS]->numUsed; - count > 0; elPtr++, count--) { + count = stackDepth[WILDCARD_LEAF_CLASS]; count > 0; + elPtr++, count--) { if ((elPtr->nameUid == classId) && (elPtr->priority > bestPtr->priority)) { bestPtr = elPtr; } } } + + /* + * If this option was masquerading with a different window class, + * probe the option database now. Note that this will be inefficient + * if the option database is densely populated, or if the widget has many + * masquerading options. + */ + + if (masqName != NULL) { + char *masqClass; + Tk_Uid nodeId, winClassId, winNameId; + unsigned int classNameLength; + register Element *nodePtr, *leafPtr; + static int searchOrder[] = { EXACT_NODE_NAME, + WILDCARD_NODE_NAME, + EXACT_NODE_CLASS, + WILDCARD_NODE_CLASS, + -1 }; + int *currentPtr, currentStack, leafCount; + + /* + * Extract the masquerade class name from the name field. + */ + + classNameLength = (unsigned int)(masqName - name); + masqClass = (char *)malloc(classNameLength + 1); + strncpy(masqClass, name, classNameLength); + masqClass[classNameLength] = '\0'; + + winClassId = Tk_GetUid(masqClass); + winNameId = ((TkWindow *)tkwin)->nameUid; + + levelPtr = &tsdPtr->levels[tsdPtr->curLevel]; + + for (currentPtr = searchOrder; *currentPtr != -1; currentPtr++) { + currentStack = *currentPtr; + nodePtr = tsdPtr->stacks[currentStack]->els; + count = levelPtr->bases[currentStack]; + + /* + * For wildcard stacks, check all entries; for non-wildcard + * stacks, only check things that matched in the parent. + */ + + if (!(currentStack & WILDCARD)) { + nodePtr += levelPtr[-1].bases[currentStack]; + count -= levelPtr[-1].bases[currentStack]; + } + + if (currentStack && CLASS) { + nodeId = winClassId; + } else { + nodeId = winNameId; + } + + for ( ; count > 0; nodePtr++, count--) { + if (nodePtr->nameUid == nodeId) { + leafPtr = nodePtr->child.arrayPtr->els; + leafCount = nodePtr->child.arrayPtr->numUsed; + for ( ; leafCount > 0; leafPtr++, leafCount--) { + if (leafPtr->flags & CLASS && className != NULL) { + if (leafPtr->nameUid == classId && + leafPtr->priority > bestPtr->priority) { + bestPtr = leafPtr; + } + } else { + if (leafPtr->nameUid == nameId && + leafPtr->priority > bestPtr->priority) { + bestPtr = leafPtr; + } + } + } + } + } + } + } + return bestPtr->child.valueUid; } @@ -1195,24 +1323,9 @@ SetupStacks(winPtr, leaf) arrayPtr = tsdPtr->stacks[EXACT_LEAF_CLASS]; arrayPtr->numUsed = 0; arrayPtr->nextToUse = arrayPtr->els; - levelPtr->bases[EXACT_LEAF_NAME] = tsdPtr->stacks[EXACT_LEAF_NAME] - ->numUsed; - levelPtr->bases[EXACT_LEAF_CLASS] = tsdPtr->stacks[EXACT_LEAF_CLASS] - ->numUsed; - levelPtr->bases[EXACT_NODE_NAME] = tsdPtr->stacks[EXACT_NODE_NAME] - ->numUsed; - levelPtr->bases[EXACT_NODE_CLASS] = tsdPtr->stacks[EXACT_NODE_CLASS] - ->numUsed; - levelPtr->bases[WILDCARD_LEAF_NAME] = tsdPtr->stacks[WILDCARD_LEAF_NAME] - ->numUsed; - levelPtr->bases[WILDCARD_LEAF_CLASS] = tsdPtr->stacks[WILDCARD_LEAF_CLASS] - ->numUsed; - levelPtr->bases[WILDCARD_NODE_NAME] = tsdPtr->stacks[WILDCARD_NODE_NAME] - ->numUsed; - levelPtr->bases[WILDCARD_NODE_CLASS] = tsdPtr->stacks[WILDCARD_NODE_CLASS] - ->numUsed; - - + for (i = 0; i < NUM_STACKS; i++) { + levelPtr->bases[i] = tsdPtr->stacks[i]->numUsed; + } /* * Step 5: scan the current stack level looking for matches to this * window's name or class; where found, add new information to the |