diff options
Diffstat (limited to 'libXt/src/TMstate.c')
-rw-r--r-- | libXt/src/TMstate.c | 4714 |
1 files changed, 2357 insertions, 2357 deletions
diff --git a/libXt/src/TMstate.c b/libXt/src/TMstate.c index 4a634b439..45f02b60b 100644 --- a/libXt/src/TMstate.c +++ b/libXt/src/TMstate.c @@ -1,2357 +1,2357 @@ -/*********************************************************** -Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - -Copyright 1987, 1988, 1994, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -*/ - -/* TMstate.c -- maintains the state table of actions for the translation - * manager. - */ -/*LINTLIBRARY*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include "IntrinsicI.h" - -#ifndef TM_NO_MATCH -#define TM_NO_MATCH (-2) -#endif /* TM_NO_MATCH */ - -/* forward definitions */ -static StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard); - - -static String XtNtranslationError = "translationError"; - -#ifndef __EMX__ -TMGlobalRec _XtGlobalTM; /* initialized to zero K&R */ -#else -TMGlobalRec _XtGlobalTM = {0}; -#endif - -#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \ - (typeMatch->eventType == tmEvent->event.eventType && \ - (typeMatch->matchEvent != NULL) && \ - (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent)) - - -#define NumStateTrees(xlations) \ - ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees) - -static TMShortCard GetBranchHead( - TMParseStateTree parseTree, - TMShortCard typeIndex, - TMShortCard modIndex, - Boolean isDummy) -{ -#define TM_BRANCH_HEAD_TBL_ALLOC 8 -#define TM_BRANCH_HEAD_TBL_REALLOC 8 - - TMBranchHead branchHead = parseTree->branchHeadTbl; - TMShortCard newSize, i; - - /* - * dummy is used as a place holder for later matching in old-style - * matching behavior. If there's already an entry we don't need - * another dummy. - */ - if (isDummy) { - for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) { - if ((branchHead->typeIndex == typeIndex) && - (branchHead->modIndex == modIndex)) - return i; - } - } - if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) - { - if (parseTree->branchHeadTblSize == 0) - parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_ALLOC; - else - parseTree->branchHeadTblSize += - TM_BRANCH_HEAD_TBL_REALLOC; - newSize = (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec)); - if (parseTree->isStackBranchHeads) { - TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl; - parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize); - XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize); - parseTree->isStackBranchHeads = False; - } - else { - parseTree->branchHeadTbl = (TMBranchHead) - XtRealloc((char *)parseTree->branchHeadTbl, - (parseTree->branchHeadTblSize * - sizeof(TMBranchHeadRec))); - } - } -#ifdef TRACE_TM - LOCK_PROCESS; - _XtGlobalTM.numBranchHeads++; - UNLOCK_PROCESS; -#endif /* TRACE_TM */ - branchHead = - &parseTree->branchHeadTbl[parseTree->numBranchHeads++]; - branchHead->typeIndex = typeIndex; - branchHead->modIndex = modIndex; - branchHead->more = 0; - branchHead->isSimple = True; - branchHead->hasActions = False; - branchHead->hasCycles = False; - return parseTree->numBranchHeads-1; -} - -TMShortCard _XtGetQuarkIndex( - TMParseStateTree parseTree, - XrmQuark quark) -{ -#define TM_QUARK_TBL_ALLOC 16 -#define TM_QUARK_TBL_REALLOC 16 - TMShortCard i = parseTree->numQuarks; - - for (i=0; i < parseTree->numQuarks; i++) - if (parseTree->quarkTbl[i] == quark) - break; - - if (i == parseTree->numQuarks) - { - if (parseTree->numQuarks == parseTree->quarkTblSize) - { - TMShortCard newSize; - - if (parseTree->quarkTblSize == 0) - parseTree->quarkTblSize += TM_QUARK_TBL_ALLOC; - else - parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC; - newSize = (parseTree->quarkTblSize * sizeof(XrmQuark)); - - if (parseTree->isStackQuarks) { - XrmQuark *oldquarkTbl = parseTree->quarkTbl; - parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize); - XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize); - parseTree->isStackQuarks = False; - } - else { - parseTree->quarkTbl = (XrmQuark *) - XtRealloc((char *)parseTree->quarkTbl, - (parseTree->quarkTblSize * - sizeof(XrmQuark))); - } - } - parseTree->quarkTbl[parseTree->numQuarks++] = quark; - } - return i; -} - -/* - * Get an entry from the parseTrees complex branchHead tbl. If there's none - * there then allocate one - */ -/*ARGSUSED*/ -static TMShortCard GetComplexBranchIndex( - TMParseStateTree parseTree, - TMShortCard typeIndex, - TMShortCard modIndex) -{ -#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8 -#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4 - - if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) { - TMShortCard newSize; - - if (parseTree->complexBranchHeadTblSize == 0) - parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_ALLOC; - else - parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_REALLOC; - - newSize = (parseTree->complexBranchHeadTblSize * sizeof(StatePtr)); - - if (parseTree->isStackComplexBranchHeads) { - StatePtr *oldcomplexBranchHeadTbl - = parseTree->complexBranchHeadTbl; - parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize); - XtMemmove(parseTree->complexBranchHeadTbl, - oldcomplexBranchHeadTbl, newSize); - parseTree->isStackComplexBranchHeads = False; - } - else { - parseTree->complexBranchHeadTbl = (StatePtr *) - XtRealloc((char *)parseTree->complexBranchHeadTbl, - (parseTree->complexBranchHeadTblSize * - sizeof(StatePtr))); - } - } - parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL; - return parseTree->numComplexBranchHeads-1; -} - -TMShortCard _XtGetTypeIndex( - Event *event) -{ - TMShortCard i, j = TM_TYPE_SEGMENT_SIZE; - TMShortCard typeIndex = 0; - TMTypeMatch typeMatch; - TMTypeMatch segment = NULL; - - LOCK_PROCESS; - for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) { - segment = _XtGlobalTM.typeMatchSegmentTbl[i]; - for (j = 0; - typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE; - j++, typeIndex++) - { - typeMatch = &(segment[j]); - if (event->eventType == typeMatch->eventType && - event->eventCode == typeMatch->eventCode && - event->eventCodeMask == typeMatch->eventCodeMask && - event->matchEvent == typeMatch->matchEvent) { - UNLOCK_PROCESS; - return typeIndex; - } - } - } - - if (j == TM_TYPE_SEGMENT_SIZE) { - if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) { - _XtGlobalTM.typeMatchSegmentTblSize += 4; - _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *) - XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl, - (_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch))); - } - _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] = - segment = (TMTypeMatch) - __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec)); - j = 0; - } - typeMatch = &segment[j]; - typeMatch->eventType = event->eventType; - typeMatch->eventCode = event->eventCode; - typeMatch->eventCodeMask = event->eventCodeMask; - typeMatch->matchEvent = event->matchEvent; - _XtGlobalTM.numTypeMatches++; - UNLOCK_PROCESS; - return typeIndex; -} - -static Boolean CompareLateModifiers( - LateBindingsPtr lateBind1P, - LateBindingsPtr lateBind2P) -{ - LateBindingsPtr late1P = lateBind1P; - LateBindingsPtr late2P = lateBind2P; - - if (late1P != NULL || late2P != NULL) { - int i = 0; - int j = 0; - if (late1P != NULL) - for (; late1P->keysym != NoSymbol; i++) late1P++; - if (late2P != NULL) - for (; late2P->keysym != NoSymbol; j++) late2P++; - if (i != j) return FALSE; - late1P--; - while (late1P >= lateBind1P) { - Boolean last = True; - for (late2P = lateBind2P + i - 1; - late2P >= lateBind2P; - late2P--) { - if (late1P->keysym == late2P->keysym - && late1P->knot == late2P->knot) { - j--; - if (last) i--; - break; - } - last = False; - } - late1P--; - } - if (j != 0) return FALSE; - } - return TRUE; -} - -TMShortCard _XtGetModifierIndex( - Event *event) -{ - TMShortCard i, j = TM_MOD_SEGMENT_SIZE; - TMShortCard modIndex = 0; - TMModifierMatch modMatch; - TMModifierMatch segment = NULL; - - LOCK_PROCESS; - for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) { - segment = _XtGlobalTM.modMatchSegmentTbl[i]; - for (j = 0; - modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE; - j++, modIndex++) { - modMatch = &(segment[j]); - if (event->modifiers == modMatch->modifiers && - event->modifierMask == modMatch->modifierMask && - event->standard == modMatch->standard && - ((!event->lateModifiers && !modMatch->lateModifiers) || - CompareLateModifiers(event->lateModifiers, - modMatch->lateModifiers))) { - /* - * if we found a match then we can free the parser's - * late modifiers. If there isn't a match we use the - * parser's copy - */ - if (event->lateModifiers && - --event->lateModifiers->ref_count == 0) { - XtFree((char *)event->lateModifiers); - event->lateModifiers = NULL; - } - UNLOCK_PROCESS; - return modIndex; - } - } - } - - if (j == TM_MOD_SEGMENT_SIZE) { - if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) { - _XtGlobalTM.modMatchSegmentTblSize += 4; - _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *) - XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl, - (_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch))); - } - _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] = - segment = (TMModifierMatch) - __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec)); - j = 0; - } - modMatch = &segment[j]; - modMatch->modifiers = event->modifiers;; - modMatch->modifierMask = event->modifierMask; - modMatch->standard = event->standard; - /* - * We use the parser's copy of the late binding array - */ -#ifdef TRACE_TM - if (event->lateModifiers) - _XtGlobalTM.numLateBindings++; -#endif /* TRACE_TM */ - modMatch->lateModifiers = event->lateModifiers; - _XtGlobalTM.numModMatches++; - UNLOCK_PROCESS; - return modIndex; -} - - -/* - * This is called from the SimpleStateHandler to match a stateTree - * entry to the event coming in - */ -static int MatchBranchHead( - TMSimpleStateTree stateTree, - int startIndex, - TMEventPtr event) -{ - TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex]; - int i; - - LOCK_PROCESS; - for (i = startIndex; - i < (int)stateTree->numBranchHeads; - i++, branchHead++) - { - TMTypeMatch typeMatch; - TMModifierMatch modMatch; - - typeMatch = TMGetTypeMatch(branchHead->typeIndex); - modMatch = TMGetModifierMatch(branchHead->modIndex); - - if (MatchIncomingEvent(event, typeMatch, modMatch)) { - UNLOCK_PROCESS; - return i; - } - } - UNLOCK_PROCESS; - return (TM_NO_MATCH); -} - -Boolean _XtRegularMatch( - TMTypeMatch typeMatch, - TMModifierMatch modMatch, - TMEventPtr eventSeq) -{ - Modifiers computed =0; - Modifiers computedMask =0; - Boolean resolved = TRUE; - if (typeMatch->eventCode != (eventSeq->event.eventCode & - typeMatch->eventCodeMask)) return FALSE; - if (modMatch->lateModifiers != NULL) - resolved = _XtComputeLateBindings(eventSeq->xev->xany.display, - modMatch->lateModifiers, - &computed, &computedMask); - if (!resolved) return FALSE; - computed |= modMatch->modifiers; - computedMask |= modMatch->modifierMask; - - return ( (computed & computedMask) == - (eventSeq->event.modifiers & computedMask)); -} - -/*ARGSUSED*/ -Boolean _XtMatchAtom( - TMTypeMatch typeMatch, - TMModifierMatch modMatch, - TMEventPtr eventSeq) -{ - Atom atom; - - atom = XInternAtom(eventSeq->xev->xany.display, - XrmQuarkToString(typeMatch->eventCode), - False); - return (atom == eventSeq->event.eventCode); -} - -#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7))) - -/* - * there are certain cases where you want to ignore the event and stay - * in the same state. - */ -static Boolean Ignore( - TMEventPtr event) -{ - Display *dpy; - XtPerDisplay pd; - - if (event->event.eventType == MotionNotify) - return TRUE; - if (!(event->event.eventType == KeyPress || - event->event.eventType == KeyRelease)) - return FALSE; - dpy = event->xev->xany.display; - pd = _XtGetPerDisplay(dpy); - _InitializeKeysymTables(dpy, pd); - return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE; -} - - -static void XEventToTMEvent( - XEvent *event, - TMEventPtr tmEvent) -{ - tmEvent->xev = event; - tmEvent->event.eventCodeMask = 0; - tmEvent->event.modifierMask = 0; - tmEvent->event.eventType = event->type; - tmEvent->event.lateModifiers = NULL; - tmEvent->event.matchEvent = NULL; - tmEvent->event.standard = FALSE; - - switch (event->type) { - - case KeyPress: - case KeyRelease: - tmEvent->event.eventCode = event->xkey.keycode; - tmEvent->event.modifiers = event->xkey.state; - break; - - case ButtonPress: - case ButtonRelease: - tmEvent->event.eventCode = event->xbutton.button; - tmEvent->event.modifiers = event->xbutton.state; - break; - - case MotionNotify: - tmEvent->event.eventCode = event->xmotion.is_hint; - tmEvent->event.modifiers = event->xmotion.state; - break; - - case EnterNotify: - case LeaveNotify: - tmEvent->event.eventCode = event->xcrossing.mode; - tmEvent->event.modifiers = event->xcrossing.state; - break; - - case PropertyNotify: - tmEvent->event.eventCode = event->xproperty.atom; - tmEvent->event.modifiers = 0; - break; - - case SelectionClear: - tmEvent->event.eventCode = event->xselectionclear.selection; - tmEvent->event.modifiers = 0; - break; - - case SelectionRequest: - tmEvent->event.eventCode = event->xselectionrequest.selection; - tmEvent->event.modifiers = 0; - break; - - case SelectionNotify: - tmEvent->event.eventCode = event->xselection.selection; - tmEvent->event.modifiers = 0; - break; - - case ClientMessage: - tmEvent->event.eventCode = event->xclient.message_type; - tmEvent->event.modifiers = 0; - break; - - case MappingNotify: - tmEvent->event.eventCode = event->xmapping.request; - tmEvent->event.modifiers = 0; - break; - - case FocusIn: - case FocusOut: - tmEvent->event.eventCode = event->xfocus.mode; - tmEvent->event.modifiers = 0; - break; - - default: - tmEvent->event.eventCode = 0; - tmEvent->event.modifiers = 0; - break; - } -} - - -static unsigned long GetTime( - XtTM tm, - XEvent *event) -{ - switch (event->type) { - - case KeyPress: - case KeyRelease: - return event->xkey.time; - - case ButtonPress: - case ButtonRelease: - return event->xbutton.time; - - default: - return tm->lastEventTime; - - } - -} - -static void HandleActions( - Widget w, - XEvent *event, - TMSimpleStateTree stateTree, - Widget accelWidget, - XtActionProc *procs, - ActionRec *actions) -{ - ActionHook actionHookList; - Widget bindWidget; - - bindWidget = accelWidget ? accelWidget : w; - if (accelWidget && !XtIsSensitive(accelWidget) && - (event->type == KeyPress || event->type == KeyRelease || - event->type == ButtonPress || event->type == ButtonRelease || - event->type == MotionNotify || event->type == EnterNotify || - event->type == LeaveNotify || event->type == FocusIn || - event->type == FocusOut)) - return; - - actionHookList = XtWidgetToApplicationContext(w)->action_hook_list; - - while (actions != NULL) { - /* perform any actions */ - if (procs[actions->idx] != NULL) { - if (actionHookList) { - ActionHook hook; - ActionHook next_hook; - String procName = - XrmQuarkToString(stateTree->quarkTbl[actions->idx] ); - - for (hook = actionHookList; hook != NULL; ) { - /* - * Need to cache hook->next because the following action - * proc may free hook via XtRemoveActionHook making - * hook->next invalid upon return from the action proc. - */ - next_hook = hook->next; - (*hook->proc)(bindWidget, - hook->closure, - procName, - event, - actions->params, - &actions->num_params - ); - hook = next_hook; - } - } - (*(procs[actions->idx])) - (bindWidget, event, - actions->params, &actions->num_params ); - } - actions = actions->next; - } -} - -typedef struct { - unsigned int isCycleStart:1; - unsigned int isCycleEnd:1; - TMShortCard typeIndex; - TMShortCard modIndex; -}MatchPairRec, *MatchPair; - -typedef struct TMContextRec{ - TMShortCard numMatches; - TMShortCard maxMatches; - MatchPair matches; -}TMContextRec, *TMContext; - -static TMContextRec contextCache[2]; - -#define GetContextPtr(tm) ((TMContext *)&(tm->current_state)) - -#define TM_CONTEXT_MATCHES_ALLOC 4 -#define TM_CONTEXT_MATCHES_REALLOC 2 - -static void PushContext( - TMContext *contextPtr, - StatePtr newState) -{ - TMContext context = *contextPtr; - - LOCK_PROCESS; - if (context == NULL) - { - if (contextCache[0].numMatches == 0) - context = &contextCache[0]; - else if (contextCache[1].numMatches == 0) - context = &contextCache[1]; - if (!context) - { - context = XtNew(TMContextRec); - context->matches = NULL; - context->numMatches = - context->maxMatches = 0; - } - } - if (context->numMatches && - context->matches[context->numMatches-1].isCycleEnd) - { - TMShortCard i; - for (i = 0; - i < context->numMatches && - !(context->matches[i].isCycleStart); - i++){}; - if (i < context->numMatches) - context->numMatches = i+1; -#ifdef DEBUG - else - XtWarning("pushing cycle end with no cycle start"); -#endif /* DEBUG */ - } - else - { - if (context->numMatches == context->maxMatches) - { - if (context->maxMatches == 0) - context->maxMatches += TM_CONTEXT_MATCHES_ALLOC; - else - context->maxMatches += TM_CONTEXT_MATCHES_REALLOC; - context->matches = (MatchPairRec *) - XtRealloc((char *)context->matches, - context->maxMatches * sizeof(MatchPairRec)); - } - context->matches[context->numMatches].isCycleStart = newState->isCycleStart; - context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd; - context->matches[context->numMatches].typeIndex = newState->typeIndex; - context->matches[context->numMatches++].modIndex = newState->modIndex; - *contextPtr = context; - } - UNLOCK_PROCESS; -} - -static void FreeContext( - TMContext *contextPtr) -{ - TMContext context = NULL; - - LOCK_PROCESS; - - if (&contextCache[0] == *contextPtr) - context = &contextCache[0]; - else if (&contextCache[1] == *contextPtr) - context = &contextCache[1]; - - if (context) - context->numMatches = 0; - else if (*contextPtr) - { - if ((*contextPtr)->matches) - XtFree ((char *) ((*contextPtr)->matches)); - XtFree((char *)*contextPtr); - } - - *contextPtr = NULL; - UNLOCK_PROCESS; -} - -static int MatchExact( - TMSimpleStateTree stateTree, - int startIndex, - TMShortCard typeIndex, - TMShortCard modIndex) -{ - TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]); - int i; - - for (i = startIndex; - i < (int)stateTree->numBranchHeads; - i++, branchHead++) - { - if ((branchHead->typeIndex == typeIndex) && - (branchHead->modIndex == modIndex)) - return i; - } - return (TM_NO_MATCH); -} - - - -static void HandleSimpleState( - Widget w, - XtTM tmRecPtr, - TMEventRec *curEventPtr) -{ - XtTranslations xlations = tmRecPtr->translations; - TMSimpleStateTree stateTree; - TMContext *contextPtr = GetContextPtr(tmRecPtr); - TMShortCard i; - ActionRec *actions = NULL; - Boolean matchExact = False; - Boolean match = False; - StatePtr complexMatchState = NULL; - int currIndex; - TMShortCard typeIndex = 0, modIndex = 0; - int matchTreeIndex = TM_NO_MATCH; - - LOCK_PROCESS; - stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0]; - - for (i = 0; - ((!match || !complexMatchState) && (i < xlations->numStateTrees)); - i++){ - stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; - currIndex = -1; - /* - * don't process this tree if we're only looking for a - * complexMatchState and there are no complex states - */ - while (!(match && stateTree->isSimple) && - ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) { - currIndex++; - if (matchExact) - currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex); - else - currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr); - if (currIndex != TM_NO_MATCH) { - TMBranchHead branchHead; - StatePtr currState; - - branchHead = &stateTree->branchHeadTbl[currIndex]; - if (branchHead->isSimple) - currState = NULL; - else - currState = ((TMComplexStateTree)stateTree) - ->complexBranchHeadTbl[TMBranchMore(branchHead)]; - - /* - * first check for a complete match - */ - if (!match) { - if (branchHead->hasActions) { - if (branchHead->isSimple) { - static ActionRec dummyAction; - - dummyAction.idx = TMBranchMore(branchHead); - actions = &dummyAction; - } - else - actions = currState->actions; - tmRecPtr->lastEventTime = - GetTime(tmRecPtr, curEventPtr->xev); - FreeContext((TMContext - *)&tmRecPtr->current_state); - match = True; - matchTreeIndex = i; - } - /* - * if it doesn't have actions and - * it's bc mode then it's a potential match node that is - * used to match later sequences. - */ - if (!TMNewMatchSemantics() && !matchExact) { - matchExact = True; - typeIndex = branchHead->typeIndex; - modIndex = branchHead->modIndex; - } - } - /* - * check for it being an event sequence which can be - * a future match - */ - if (!branchHead->isSimple && - !branchHead->hasActions && - !complexMatchState) - complexMatchState = currState; - } - } - } - if (match) - { - TMBindData bindData = (TMBindData) tmRecPtr->proc_table; - XtActionProc *procs; - Widget accelWidget; - - if (bindData->simple.isComplex) { - TMComplexBindProcs bindProcs = - TMGetComplexBindEntry(bindData, matchTreeIndex); - procs = bindProcs->procs; - accelWidget = bindProcs->widget; - } - else { - TMSimpleBindProcs bindProcs = - TMGetSimpleBindEntry(bindData, matchTreeIndex); - procs = bindProcs->procs; - accelWidget = NULL; - } - HandleActions - (w, - curEventPtr->xev, - (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex], - accelWidget, - procs, - actions); - } - if (complexMatchState) - PushContext(contextPtr, complexMatchState); - UNLOCK_PROCESS; -} - -static int MatchComplexBranch( - TMComplexStateTree stateTree, - int startIndex, - TMContext context, - StatePtr *leafStateRtn) -{ - TMShortCard i; - - LOCK_PROCESS; - for (i = startIndex; i < stateTree->numComplexBranchHeads; i++) - { - StatePtr candState; - TMShortCard numMatches = context->numMatches; - MatchPair statMatch = context->matches; - - for (candState = stateTree->complexBranchHeadTbl[i]; - numMatches && candState; - numMatches--, statMatch++, candState = candState->nextLevel) - { - if ((statMatch->typeIndex != candState->typeIndex) || - (statMatch->modIndex != candState->modIndex)) - break; - } - if (numMatches == 0) { - *leafStateRtn = candState; - UNLOCK_PROCESS; - return i; - } - } - *leafStateRtn = NULL; - UNLOCK_PROCESS; - return (TM_NO_MATCH); -} - -static StatePtr TryCurrentTree( - TMComplexStateTree *stateTreePtr, - XtTM tmRecPtr, - TMEventRec *curEventPtr) -{ - StatePtr candState = NULL, matchState = NULL; - TMContext *contextPtr = GetContextPtr(tmRecPtr); - TMTypeMatch typeMatch; - TMModifierMatch modMatch; - int currIndex = -1; - - /* - * we want the first sequence that both matches and has actions. - * we keep on looking till we find both - */ - LOCK_PROCESS; - while ((currIndex = - MatchComplexBranch(*stateTreePtr, - ++currIndex, - (*contextPtr), - &candState)) - != TM_NO_MATCH) { - if (candState != NULL) { - typeMatch = TMGetTypeMatch(candState->typeIndex); - modMatch = TMGetModifierMatch(candState->modIndex); - - /* does this state's index match? --> done */ - if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) - { - if (candState->actions) { - UNLOCK_PROCESS; - return candState; - } - else - matchState = candState; - } - /* is this an event timer? */ - if (typeMatch->eventType == _XtEventTimerEventType) { - StatePtr nextState = candState->nextLevel; - - /* does the succeeding state match? */ - if (nextState != NULL) { - TMTypeMatch nextTypeMatch; - TMModifierMatch nextModMatch; - - nextTypeMatch = TMGetTypeMatch(nextState->typeIndex); - nextModMatch = TMGetModifierMatch(nextState->modIndex); - - /* is it within the timeout? */ - if (MatchIncomingEvent(curEventPtr, - nextTypeMatch, - nextModMatch)) { - XEvent *xev = curEventPtr->xev; - unsigned long time = GetTime(tmRecPtr, xev); - XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display); - unsigned long delta = pd->multi_click_time; - - if ((tmRecPtr->lastEventTime + delta) >= time) { - if (nextState->actions) { - UNLOCK_PROCESS; - return candState; - } - else - matchState = candState; - } - } - } - } - } - } - UNLOCK_PROCESS; - return matchState; -} - -static void HandleComplexState( - Widget w, - XtTM tmRecPtr, - TMEventRec *curEventPtr) -{ - XtTranslations xlations = tmRecPtr->translations; - TMContext *contextPtr = GetContextPtr(tmRecPtr); - TMShortCard i, matchTreeIndex = 0; - StatePtr matchState = NULL, candState; - TMComplexStateTree *stateTreePtr = - (TMComplexStateTree *)&xlations->stateTreeTbl[0]; - - LOCK_PROCESS; - for (i = 0; - i < xlations->numStateTrees; - i++, stateTreePtr++) { - /* - * some compilers sign extend Boolean bit fields so test for - * false ||| - */ - if (((*stateTreePtr)->isSimple == False) && - (candState = TryCurrentTree(stateTreePtr, - tmRecPtr, - curEventPtr))) { - if (!matchState || candState->actions) { - matchTreeIndex = i; - matchState = candState; - if (candState->actions) - break; - } - } - } - if (matchState == NULL){ - /* couldn't find it... */ - if (!Ignore(curEventPtr)) - { - FreeContext(contextPtr); - HandleSimpleState(w, tmRecPtr, curEventPtr); - } - } - else { - TMBindData bindData = (TMBindData) tmRecPtr->proc_table; - XtActionProc *procs; - Widget accelWidget; - TMTypeMatch typeMatch; - - typeMatch = TMGetTypeMatch(matchState->typeIndex); - - PushContext(contextPtr, matchState); - if (typeMatch->eventType == _XtEventTimerEventType) { - matchState = matchState->nextLevel; - PushContext(contextPtr, matchState); - } - tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev); - - if (bindData->simple.isComplex) { - TMComplexBindProcs bindProcs = - TMGetComplexBindEntry(bindData, matchTreeIndex); - procs = bindProcs->procs; - accelWidget = bindProcs->widget; - } - else { - TMSimpleBindProcs bindProcs = - TMGetSimpleBindEntry(bindData, matchTreeIndex); - procs = bindProcs->procs; - accelWidget = NULL; - } - HandleActions(w, - curEventPtr->xev, - (TMSimpleStateTree) - xlations->stateTreeTbl[matchTreeIndex], - accelWidget, - procs, - matchState->actions); - } - UNLOCK_PROCESS; -} - - -void _XtTranslateEvent ( - Widget w, - XEvent * event) -{ - XtTM tmRecPtr = &w->core.tm; - TMEventRec curEvent; - StatePtr current_state = tmRecPtr->current_state; - - XEventToTMEvent (event, &curEvent); - - if (! tmRecPtr->translations) { - XtAppWarningMsg(XtWidgetToApplicationContext(w), - XtNtranslationError,"nullTable",XtCXtToolkitError, - "Can't translate event through NULL table", - (String *)NULL, (Cardinal *)NULL); - return ; - } - if (current_state == NULL) - HandleSimpleState(w, tmRecPtr, &curEvent); - else - HandleComplexState(w, tmRecPtr, &curEvent); -} - - -/*ARGSUSED*/ -static StatePtr NewState( - TMParseStateTree stateTree, - TMShortCard typeIndex, - TMShortCard modIndex) -{ - StatePtr state = XtNew(StateRec); - -#ifdef TRACE_TM - LOCK_PROCESS; - _XtGlobalTM.numComplexStates++; - UNLOCK_PROCESS; -#endif /* TRACE_TM */ - state->typeIndex = typeIndex; - state->modIndex = modIndex; - state->nextLevel = NULL; - state->actions = NULL; - state->isCycleStart = state->isCycleEnd = False; - return state; -} - -/* - * This routine is an iterator for state trees. If the func returns - * true then iteration is over. - */ -void _XtTraverseStateTree( - TMStateTree tree, - _XtTraversalProc func, - XtPointer data) -{ - TMComplexStateTree stateTree = (TMComplexStateTree)tree; - TMBranchHead currBH; - TMShortCard i; - StateRec dummyStateRec, *dummyState = &dummyStateRec; - ActionRec dummyActionRec, *dummyAction = &dummyActionRec; - Boolean firstSimple = True; - StatePtr currState; - - /* first traverse the complex states */ - if (stateTree->isSimple == False) - for (i = 0; i < stateTree->numComplexBranchHeads; i++) { - currState = stateTree->complexBranchHeadTbl[i]; - for (; currState; currState = currState->nextLevel) { - if (func(currState, data)) - return; - if (currState->isCycleEnd) - break; - } - } - - /* now traverse the simple ones */ - for (i = 0, currBH = stateTree->branchHeadTbl; - i < stateTree->numBranchHeads; - i++, currBH++) - { - if (currBH->isSimple && currBH->hasActions) - { - if (firstSimple) - { - XtBZero((char *) dummyState, sizeof(StateRec)); - XtBZero((char *) dummyAction, sizeof(ActionRec)); - dummyState->actions = dummyAction; - firstSimple = False; - } - dummyState->typeIndex = currBH->typeIndex; - dummyState->modIndex = currBH->modIndex; - dummyAction->idx = currBH->more; - if (func(dummyState, data)) - return; - } - } -} - -static EventMask EventToMask( - TMTypeMatch typeMatch, - TMModifierMatch modMatch) -{ - EventMask returnMask; - unsigned long eventType = typeMatch->eventType; - - if (eventType == MotionNotify) { - Modifiers modifierMask = modMatch->modifierMask; - Modifiers tempMask; - - returnMask = 0; - if (modifierMask == 0) { - if (modMatch->modifiers == AnyButtonMask) - return ButtonMotionMask; - else - return PointerMotionMask; - } - tempMask = modifierMask & - (Button1Mask | Button2Mask | Button3Mask - | Button4Mask | Button5Mask); - if (tempMask == 0) - return PointerMotionMask; - if (tempMask & Button1Mask) - returnMask |= Button1MotionMask; - if (tempMask & Button2Mask) - returnMask |= Button2MotionMask; - if (tempMask & Button3Mask) - returnMask |= Button3MotionMask; - if (tempMask & Button4Mask) - returnMask |= Button4MotionMask; - if (tempMask & Button5Mask) - returnMask |= Button5MotionMask; - return returnMask; - } - returnMask = _XtConvertTypeToMask(eventType); - if (returnMask == (StructureNotifyMask|SubstructureNotifyMask)) - returnMask = StructureNotifyMask; - return returnMask; -} - -/*ARGSUSED*/ -static void DispatchMappingNotify( - Widget widget, /* will be NULL from _RefreshMapping */ - XtPointer closure, /* real Widget */ - XtPointer call_data) /* XEvent* */ -{ - _XtTranslateEvent( (Widget)closure, (XEvent*)call_data); -} - - -/*ARGSUSED*/ -static void RemoveFromMappingCallbacks( - Widget widget, - XtPointer closure, /* target widget */ - XtPointer call_data) -{ - _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks, - DispatchMappingNotify, - closure - ); -} - -static Boolean AggregateEventMask( - StatePtr state, - XtPointer data) -{ - LOCK_PROCESS; - *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex), - TMGetModifierMatch(state->modIndex)); - UNLOCK_PROCESS; - return False; -} - -void _XtInstallTranslations( - Widget widget) -{ - XtTranslations xlations; - Cardinal i; - TMStateTree stateTree; - Boolean mappingNotifyInterest = False; - - xlations = widget->core.tm.translations; - if (xlations == NULL) return; - - /* - * check for somebody stuffing the translations directly into the - * instance structure. We will end up being called again out of - * ComposeTranslations but we *should* have bindings by then - */ - if (widget->core.tm.proc_table == NULL) { - _XtMergeTranslations(widget, NULL, XtTableReplace); - /* - * if we're realized then we'll be called out of - * ComposeTranslations - */ - if (XtIsRealized(widget)) - return; - } - - xlations->eventMask = 0; - for (i = 0; - i < xlations->numStateTrees; - i++) - { - stateTree = xlations->stateTreeTbl[i]; - _XtTraverseStateTree(stateTree, - AggregateEventMask, - (XtPointer)&xlations->eventMask); - mappingNotifyInterest |= stateTree->simple.mappingNotifyInterest; - } - /* double click needs to make sure that you have selected on both - button down and up. */ - - if (xlations->eventMask & ButtonPressMask) - xlations->eventMask |= ButtonReleaseMask; - if (xlations->eventMask & ButtonReleaseMask) - xlations->eventMask |= ButtonPressMask; - - if (mappingNotifyInterest) { - XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget)); - if (pd->mapping_callbacks) - _XtAddCallbackOnce(&(pd->mapping_callbacks), - DispatchMappingNotify, - (XtPointer)widget); - else - _XtAddCallback(&(pd->mapping_callbacks), - DispatchMappingNotify, - (XtPointer)widget); - - if (widget->core.destroy_callbacks != NULL) - _XtAddCallbackOnce( (InternalCallbackList *) - &widget->core.destroy_callbacks, - RemoveFromMappingCallbacks, - (XtPointer)widget - ); - else - _XtAddCallback((InternalCallbackList *) - &widget->core.destroy_callbacks, - RemoveFromMappingCallbacks, - (XtPointer)widget - ); - } - _XtBindActions(widget, (XtTM)&widget->core.tm); - _XtRegisterGrabs(widget); -} - -void _XtRemoveTranslations( - Widget widget) -{ - Cardinal i; - TMSimpleStateTree stateTree; - Boolean mappingNotifyInterest = False; - XtTranslations xlations = widget->core.tm.translations; - - if (xlations == NULL) - return; - - for (i = 0; - i < xlations->numStateTrees; - i++) - { - stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; - mappingNotifyInterest |= stateTree->mappingNotifyInterest; - } - if (mappingNotifyInterest) - RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL); -} - -static void _XtUninstallTranslations( - Widget widget) -{ - XtTranslations xlations = widget->core.tm.translations; - - _XtUnbindActions(widget, - xlations, - (TMBindData)widget->core.tm.proc_table); - _XtRemoveTranslations(widget); - widget->core.tm.translations = NULL; - FreeContext((TMContext *)&widget->core.tm.current_state); -} - -void _XtDestroyTMData( - Widget widget) -{ - TMComplexBindData cBindData; - - _XtUninstallTranslations(widget); - - if ((cBindData = (TMComplexBindData)widget->core.tm.proc_table)) { - if (cBindData->isComplex) { - ATranslations aXlations, nXlations; - - nXlations = (ATranslations) cBindData->accel_context; - while (nXlations){ - aXlations = nXlations; - nXlations = nXlations->next; - XtFree((char *)aXlations); - } - } - XtFree((char *)cBindData); - } -} - -/*** Public procedures ***/ - - -void XtUninstallTranslations( - Widget widget) -{ - EventMask oldMask; - Widget hookobj; - WIDGET_TO_APPCON(widget); - - LOCK_APP(app); - if (! widget->core.tm.translations) { - UNLOCK_APP(app); - return; - } - oldMask = widget->core.tm.translations->eventMask; - _XtUninstallTranslations(widget); - if (XtIsRealized(widget) && oldMask) - XSelectInput(XtDisplay(widget), XtWindow(widget), - XtBuildEventMask(widget)); - hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); - if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { - XtChangeHookDataRec call_data; - - call_data.type = XtHuninstallTranslations; - call_data.widget = widget; - XtCallCallbackList(hookobj, - ((HookObject)hookobj)->hooks.changehook_callbacks, - (XtPointer)&call_data); - } - UNLOCK_APP(app); -} - -XtTranslations _XtCreateXlations( - TMStateTree *stateTrees, - TMShortCard numStateTrees, - XtTranslations first, - XtTranslations second) -{ - XtTranslations xlations; - TMShortCard i; - - xlations = (XtTranslations) - __XtMalloc(sizeof(TranslationData) + - (numStateTrees-1) * sizeof(TMStateTree)); -#ifdef TRACE_TM - LOCK_PROCESS; - if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) { - _XtGlobalTM.tmTblSize += 16; - _XtGlobalTM.tmTbl = (XtTranslations *) - XtRealloc((char *)_XtGlobalTM.tmTbl, - _XtGlobalTM.tmTblSize * sizeof(XtTranslations)); - } - _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations; - UNLOCK_PROCESS; -#endif /* TRACE_TM */ - - xlations->composers[0] = first; - xlations->composers[1] = second; - xlations->hasBindings = False; - xlations->operation = XtTableReplace; - - for (i = 0;i < numStateTrees; i++) - { - xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i]; - stateTrees[i]->simple.refCount++; - } - xlations->numStateTrees = numStateTrees; - xlations->eventMask = 0; - return xlations; -} - -TMStateTree _XtParseTreeToStateTree( - TMParseStateTree parseTree) -{ - TMSimpleStateTree simpleTree; - unsigned int tableSize; - - if (parseTree->numComplexBranchHeads) { - TMComplexStateTree complexTree; - - complexTree = XtNew(TMComplexStateTreeRec); - complexTree->isSimple = False; - tableSize = parseTree->numComplexBranchHeads * sizeof(StatePtr); - complexTree->complexBranchHeadTbl = (StatePtr *) - __XtMalloc(tableSize); - XtMemmove(complexTree->complexBranchHeadTbl, - parseTree->complexBranchHeadTbl, tableSize); - complexTree->numComplexBranchHeads = - parseTree->numComplexBranchHeads; - simpleTree = (TMSimpleStateTree)complexTree; - } - else { - simpleTree = XtNew(TMSimpleStateTreeRec); - simpleTree->isSimple = True; - } - simpleTree->isAccelerator = parseTree->isAccelerator; - simpleTree->refCount = 0; - simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest; - - tableSize = parseTree->numBranchHeads * sizeof(TMBranchHeadRec); - simpleTree->branchHeadTbl = (TMBranchHead) - __XtMalloc(tableSize); - XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize); - simpleTree->numBranchHeads = parseTree->numBranchHeads; - - tableSize = parseTree->numQuarks * sizeof(XrmQuark); - simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize); - XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize); - simpleTree->numQuarks = parseTree->numQuarks; - - return (TMStateTree)simpleTree; -} - -static void FreeActions( - ActionPtr actions) -{ - ActionPtr action; - TMShortCard i; - for (action = actions; action;) { - ActionPtr nextAction = action->next; - for (i = action->num_params; i;) { - XtFree( action->params[--i] ); - } - XtFree( (char*)action->params ); - XtFree((char*) action); - action = nextAction; - } -} - -/*ARGSUSED*/ -static void AmbigActions( - EventSeqPtr initialEvent, - StatePtr *state, - TMParseStateTree stateTree) -{ - String params[3]; - Cardinal numParams = 0; - - params[numParams++] = _XtPrintEventSeq(initialEvent, NULL); - params[numParams++] = _XtPrintActions((*state)->actions, - stateTree->quarkTbl); - XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError, - "Previous entry was: %s %s", params, &numParams); - XtFree((char *)params[0]); - XtFree((char *)params[1]); - numParams = 0; - params[numParams++] = _XtPrintActions(initialEvent->actions, - stateTree->quarkTbl); - XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError, - "New actions are:%s", params, &numParams); - XtFree((char *)params[0]); - XtWarningMsg (XtNtranslationError,"ambiguousActions", - XtCXtToolkitError, - "Overriding earlier translation manager actions.", - (String *)NULL, (Cardinal *)NULL); - - FreeActions((*state)->actions); - (*state)->actions = NULL; -} - - -void _XtAddEventSeqToStateTree( - EventSeqPtr eventSeq, - TMParseStateTree stateTree) -{ - StatePtr *state; - EventSeqPtr initialEvent = eventSeq; - TMBranchHead branchHead; - TMShortCard idx, modIndex, typeIndex; - - if (eventSeq == NULL) return; - - /* note that all states in the event seq passed in start out null */ - /* we fill them in with the matching state as we traverse the list */ - - /* - * We need to free the parser data structures !!! - */ - - typeIndex = _XtGetTypeIndex(&eventSeq->event); - modIndex = _XtGetModifierIndex(&eventSeq->event); - idx = GetBranchHead(stateTree, typeIndex, modIndex, False); - branchHead = &stateTree->branchHeadTbl[idx]; - - /* - * Need to check for pre-existing actions with same lhs ||| - */ - - /* - * Check for optimized case. Don't assume that the eventSeq has actions. - */ - if (!eventSeq->next && - eventSeq->actions && - !eventSeq->actions->next && - !eventSeq->actions->num_params) - { - if (eventSeq->event.eventType == MappingNotify) - stateTree->mappingNotifyInterest = True; - branchHead->hasActions = True; - branchHead->more = eventSeq->actions->idx; - FreeActions(eventSeq->actions); - eventSeq->actions = NULL; - return; - } - - branchHead->isSimple = False; - if (!eventSeq->next) - branchHead->hasActions = True; - branchHead->more = GetComplexBranchIndex(stateTree, typeIndex, modIndex); - state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)]; - - for (;;) { - *state = NewState(stateTree, typeIndex, modIndex); - - if (eventSeq->event.eventType == MappingNotify) - stateTree->mappingNotifyInterest = True; - - /* *state now points at state record matching event */ - eventSeq->state = *state; - - if (eventSeq->actions != NULL) { - if ((*state)->actions != NULL) - AmbigActions(initialEvent, state, stateTree); - (*state)->actions = eventSeq->actions; -#ifdef TRACE_TM - LOCK_PROCESS - _XtGlobalTM.numComplexActions++; - UNLOCK_PROCESS; -#endif /* TRACE_TM */ - } - - if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state)) - break; - - state = &(*state)->nextLevel; - typeIndex = _XtGetTypeIndex(&eventSeq->event); - modIndex = _XtGetModifierIndex(&eventSeq->event); - LOCK_PROCESS; - if (!TMNewMatchSemantics()) { - /* - * force a potential empty entry into the branch head - * table in order to emulate old matching behavior - */ - (void) GetBranchHead(stateTree, typeIndex, modIndex, True); - } - UNLOCK_PROCESS; - } - - if (eventSeq && eventSeq->state) { - /* we've been here before... must be a cycle in the event seq. */ - branchHead->hasCycles = True; - (*state)->nextLevel = eventSeq->state; - eventSeq->state->isCycleStart = True; - (*state)->isCycleEnd = TRUE; - } -} - - -/* - * Internal Converter for merging. Old and New must both be valid xlations - */ - -/*ARGSUSED*/ -Boolean _XtCvtMergeTranslations( - Display *dpy, - XrmValuePtr args, - Cardinal *num_args, - XrmValuePtr from, - XrmValuePtr to, - XtPointer *closure_ret) -{ - XtTranslations first, second, xlations; - TMStateTree *stateTrees, stackStateTrees[16]; - TMShortCard numStateTrees, i; - - if (*num_args != 0) - XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError, - "MergeTM to TranslationTable needs no extra arguments", - (String *)NULL, (Cardinal *)NULL); - - if (to->addr != NULL && to->size < sizeof(XtTranslations)) { - to->size = sizeof(XtTranslations); - return False; - } - - first = ((TMConvertRec*)from->addr)->old; - second = ((TMConvertRec*)from->addr)->new; - - numStateTrees = first->numStateTrees + second->numStateTrees; - - stateTrees = (TMStateTree *) - XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees); - - for (i = 0; i < first->numStateTrees; i++) - stateTrees[i] = first->stateTreeTbl[i]; - for (i = 0; i < second->numStateTrees; i++) - stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i]; - - xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second); - - if (to->addr != NULL) { - *(XtTranslations*)to->addr = xlations; - } - else { - static XtTranslations staticStateTable; - staticStateTable = xlations; - to->addr= (XPointer)&staticStateTable; - to->size = sizeof(XtTranslations); - } - - XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees); - return True; -} - - -static XtTranslations MergeThem( - Widget dest, - XtTranslations first, - XtTranslations second) -{ - XtCacheRef cache_ref; - static XrmQuark from_type = NULLQUARK, to_type; - XrmValue from, to; - TMConvertRec convert_rec; - XtTranslations newTable; - - LOCK_PROCESS; - if (from_type == NULLQUARK) { - from_type = XrmPermStringToQuark(_XtRStateTablePair); - to_type = XrmPermStringToQuark(XtRTranslationTable); - } - UNLOCK_PROCESS; - from.addr = (XPointer)&convert_rec; - from.size = sizeof(TMConvertRec); - to.addr = (XPointer)&newTable; - to.size = sizeof(XtTranslations); - convert_rec.old = first; - convert_rec.new = second; - - LOCK_PROCESS; - if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) { - UNLOCK_PROCESS; - return NULL; - } - UNLOCK_PROCESS; - -#ifndef REFCNT_TRANSLATIONS - - if (cache_ref) - XtAddCallback(dest, XtNdestroyCallback, - XtCallbackReleaseCacheRef, (XtPointer)cache_ref); - -#endif - - return newTable; -} - -/* - * Unmerge will recursively traverse the xlation compose tree and - * generate a new xlation that is the result of all instances of - * xlations being removed. It currently doesn't differentiate between - * the potential that an xlation will be both an accelerator and - * normal. This is not supported by the spec anyway. - */ -static XtTranslations UnmergeTranslations( - Widget widget, - XtTranslations xlations, - XtTranslations unmergeXlations, - TMShortCard currIndex, - TMComplexBindProcs oldBindings, - TMShortCard numOldBindings, - TMComplexBindProcs newBindings, - TMShortCard *numNewBindingsRtn) - -{ - XtTranslations first, second, result; - - if (!xlations || (xlations == unmergeXlations)) - return NULL; - - if (xlations->composers[0]) { - first = UnmergeTranslations(widget, xlations->composers[0], - unmergeXlations, currIndex, - oldBindings, numOldBindings, - newBindings, numNewBindingsRtn); - } - else - first = NULL; - - if (xlations->composers[1]) { - second = UnmergeTranslations(widget, xlations->composers[1], - unmergeXlations, - currIndex + - xlations->composers[0]->numStateTrees, - oldBindings, numOldBindings, - newBindings, numNewBindingsRtn); - } - else - second = NULL; - - if (first || second) { - if (first && second) { - if ((first != xlations->composers[0]) || - (second != xlations->composers[1])) - result = MergeThem(widget, first, second); - else result = xlations; - } - else { - if (first) - result = first; - else - result = second; - } - } else { /* only update for leaf nodes */ - if (numOldBindings) { - Cardinal i; - for (i = 0; i < xlations->numStateTrees; i++) { - if (xlations->stateTreeTbl[i]->simple.isAccelerator) - newBindings[*numNewBindingsRtn] = - oldBindings[currIndex + i]; - (*numNewBindingsRtn)++; - } - } - result = xlations; - } - return result; -} - -typedef struct { - XtTranslations xlations; - TMComplexBindProcs bindings; -}MergeBindRec, *MergeBind; - -static XtTranslations MergeTranslations( - Widget widget, - XtTranslations oldXlations, - XtTranslations newXlations, - _XtTranslateOp operation, - Widget source, - TMComplexBindProcs oldBindings, - TMComplexBindProcs newBindings, - TMShortCard *numNewRtn) -{ - XtTranslations newTable = NULL, xlations; - TMComplexBindProcs bindings; - TMShortCard i, j; - TMStateTree *treePtr; - TMShortCard numNew = *numNewRtn; - MergeBindRec bindPair[2]; - - /* If the new translation has an accelerator context then pull it - * off and pass it and the real xlations in to the caching merge - * routine. - */ - if (newXlations->hasBindings) { - xlations = ((ATranslations) newXlations)->xlations; - bindings = (TMComplexBindProcs) - &((ATranslations) newXlations)->bindTbl[0]; - } - else { - xlations = newXlations; - bindings = NULL; - } - switch(operation) { - case XtTableReplace: - newTable = bindPair[0].xlations = xlations; - bindPair[0].bindings = bindings; - bindPair[1].xlations = NULL; - bindPair[1].bindings = NULL; - break; - case XtTableAugment: - bindPair[0].xlations = oldXlations; - bindPair[0].bindings = oldBindings; - bindPair[1].xlations = xlations; - bindPair[1].bindings = bindings; - newTable = NULL; - break; - case XtTableOverride: - bindPair[0].xlations = xlations; - bindPair[0].bindings = bindings; - bindPair[1].xlations = oldXlations; - bindPair[1].bindings = oldBindings; - newTable = NULL; - break; - } - if (!newTable) - newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations); - - for (i = 0, numNew = 0; i < 2; i++) { - if (bindPair[i].xlations) - for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) { - if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) { - if (bindPair[i].bindings) - newBindings[numNew] = bindPair[i].bindings[j]; - else { - newBindings[numNew].widget = source; - newBindings[numNew].aXlations = - bindPair[i].xlations; - } - } - } - } - *numNewRtn = numNew; - treePtr = &newTable->stateTreeTbl[0]; - for (i = 0; i < newTable->numStateTrees; i++, treePtr++) - (*treePtr)->simple.refCount++; - return newTable; -} - -static TMBindData MakeBindData( - TMComplexBindProcs bindings, - TMShortCard numBindings, - TMBindData oldBindData) -{ - TMLongCard bytes; - TMShortCard i; - Boolean isComplex; - TMBindData bindData; - - if (numBindings == 0) - return NULL; - for (i = 0; i < numBindings; i++) - if (bindings[i].widget) - break; - isComplex = (i < numBindings); - if (isComplex) - bytes = (sizeof(TMComplexBindDataRec) + - ((numBindings - 1) * - sizeof(TMComplexBindProcsRec))); - else - bytes = (sizeof(TMSimpleBindDataRec) + - ((numBindings - 1) * - sizeof(TMSimpleBindProcsRec))); - - bindData = (TMBindData) __XtCalloc(sizeof(char), bytes); - bindData->simple.isComplex = isComplex; - if (isComplex) { - TMComplexBindData cBindData = (TMComplexBindData)bindData; - /* - * If there were any accelerator contexts in the old bindData - * then propagate them to the new one. - */ - if (oldBindData && oldBindData->simple.isComplex) - cBindData->accel_context = - ((TMComplexBindData) oldBindData)->accel_context; - XtMemmove((char *)&cBindData->bindTbl[0], (char *)bindings, - numBindings * sizeof(TMComplexBindProcsRec)); - } - return bindData; -} - -/* - * This routine is the central clearinghouse for merging translations - * into a widget. It takes care of preping the action bindings for - * realize time and calling the converter or doing a straight merge if - * the destination is empty. - */ -static Boolean ComposeTranslations( - Widget dest, - _XtTranslateOp operation, - Widget source, - XtTranslations newXlations) -{ - XtTranslations newTable, oldXlations; - XtTranslations accNewXlations; - EventMask oldMask = 0; - TMBindData bindData; - TMComplexBindProcs oldBindings = NULL; - TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes; - TMComplexBindProcsRec stackBindings[16], *newBindings; - - /* - * how should we be handling the refcount decrement for the - * replaced translation table ??? - */ - if (!newXlations) - { - XtAppWarningMsg(XtWidgetToApplicationContext(dest), - XtNtranslationError,"nullTable",XtCXtToolkitError, - "table to (un)merge must not be null", - (String *)NULL, (Cardinal *)NULL); - return False; - } - - accNewXlations = newXlations; - newXlations = ((newXlations->hasBindings) - ? ((ATranslations)newXlations)->xlations - : newXlations); - - if (!(oldXlations = dest->core.tm.translations)) - operation = XtTableReplace; - - /* - * try to avoid generation of duplicate state trees. If the source - * isn't simple (1 state Tree) then it's too much hassle - */ - if (((operation == XtTableAugment) || - (operation == XtTableOverride)) && - (newXlations->numStateTrees == 1)) { - Cardinal i; - for (i = 0; i < oldXlations->numStateTrees; i++) - if (oldXlations->stateTreeTbl[i] == - newXlations->stateTreeTbl[0]) - break; - if (i < oldXlations->numStateTrees) { - if (operation == XtTableAugment) { - /* - * we don't need to do anything since it's already - * there - */ - return True; - } - else {/* operation == XtTableOverride */ - /* - * We'll get rid of the duplicate trees throughout the - * and leave it with a pruned translation table. This - * will only work if the same table has been merged - * into this table (or one of it's composers - */ - _XtUnmergeTranslations(dest, newXlations); - /* - * reset oldXlations so we're back in sync - */ - if (!(oldXlations = dest->core.tm.translations)) - operation = XtTableReplace; - } - } - } - - bindData = (TMBindData) dest->core.tm.proc_table; - if (bindData) { - numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0); - if (bindData->simple.isComplex) - oldBindings = &((TMComplexBindData)bindData)->bindTbl[0]; - else - oldBindings = (TMComplexBindProcs) - (&((TMSimpleBindData)bindData)->bindTbl[0]); - } - - numBytes =(((oldXlations ? oldXlations->numStateTrees : 0) - + newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec)); - newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings); - XtBZero((char *)newBindings, numBytes); - - if (operation == XtTableUnmerge) { - newTable = UnmergeTranslations(dest, - oldXlations, - newXlations, - 0, - oldBindings, numOldBindings, - newBindings, &numNewBindings); -#ifdef DEBUG - /* check for no match for unmerge */ - if (newTable == oldXlations) { - XtWarning("attempt to unmerge invalid table"); - XtStackFree((char *)newBindings, (char *)stackBindings); - return(newTable != NULL); - } -#endif /* DEBUG */ - } - else { - newTable = MergeTranslations(dest, - oldXlations, - accNewXlations, - operation, - source, - oldBindings, - newBindings, - &numNewBindings); - } - if (XtIsRealized(dest)) { - oldMask = 0; - if (oldXlations) - oldMask = oldXlations->eventMask; - _XtUninstallTranslations(dest); - } - - dest->core.tm.proc_table = - (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData); - - if (bindData) XtFree((char *)bindData); - - dest->core.tm.translations = newTable; - - if (XtIsRealized(dest)) { - EventMask mask = 0; - _XtInstallTranslations(dest); - if (newTable) - mask = newTable->eventMask; - if (mask != oldMask) - XSelectInput(XtDisplay(dest), XtWindow(dest), - XtBuildEventMask(dest)); - } - XtStackFree((XtPointer)newBindings, (XtPointer)stackBindings); - return(newTable != NULL); -} - -/* - * If a GetValues is done on a translation resource that contains - * accelerators we need to return the accelerator context in addition - * to the pure translations. Since this means returning memory that - * the client controlls but we still own, we will track the "headers" - * that we return (via a linked list pointed to from the bindData) and - * free it at destroy time. - */ -XtTranslations _XtGetTranslationValue( - Widget w) -{ - XtTM tmRecPtr = (XtTM) &w->core.tm; - ATranslations *aXlationsPtr; - TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table; - XtTranslations xlations = tmRecPtr->translations; - - if (!xlations || !cBindData || !cBindData->isComplex) - return xlations; - - /* Walk the list looking to see if we already have generated a - * header for the currently installed translations. If we have, - * just return that header. Otherwise create a new header. - */ - for (aXlationsPtr = (ATranslations *) &cBindData->accel_context; - *aXlationsPtr && (*aXlationsPtr)->xlations != xlations; - aXlationsPtr = &(*aXlationsPtr)->next) - ; - if (*aXlationsPtr) - return (XtTranslations) *aXlationsPtr; - else { - /* create a new aXlations context */ - ATranslations aXlations; - Cardinal numBindings = xlations->numStateTrees; - - (*aXlationsPtr) = aXlations = (ATranslations) - __XtMalloc(sizeof(ATranslationData) + - (numBindings - 1) * sizeof(TMComplexBindProcsRec)); - - aXlations->hasBindings = True; - aXlations->xlations = xlations; - aXlations->next = NULL; - XtMemmove((char *) &aXlations->bindTbl[0], - (char *) &cBindData->bindTbl[0], - numBindings * sizeof(TMComplexBindProcsRec)); - return (XtTranslations) aXlations; - } -} - - -/*ARGSUSED*/ -static void RemoveStateTree( - TMStateTree tree) -{ -#ifdef REFCNT_TRANSLATIONS - TMComplexStateTree stateTree = (TMComplexStateTree)tree; - - if (--stateTree->refCount == 0) { - /* - * should we free/refcount the match recs ? - */ - if (!stateTree->isSimple) { - StatePtr currState, nextState; - TMShortCard i; - for (i = 0; i < stateTree->numComplexBranchHeads; i++) { - currState = - nextState = - stateTree->complexBranchHeadTbl[i]; - for (; nextState;){ - FreeActions(currState->actions); - currState->actions = NULL; - if (!currState->isCycleEnd) - nextState = currState->nextLevel; - else - nextState = NULL; - XtFree( (char*)currState ); - } - } - XtFree((char*)stateTree->complexBranchHeadTbl); - } - XtFree((char*)stateTree->branchHeadTbl); - XtFree((char*)stateTree); - } -#endif /* REFCNT_TRANSLATIONS */ -} - -void _XtRemoveStateTreeByIndex( - XtTranslations xlations, - TMShortCard i) -{ - TMStateTree *stateTrees = xlations->stateTreeTbl; - - RemoveStateTree(stateTrees[i]); - xlations->numStateTrees--; - - for (; i < xlations->numStateTrees; i++) - { - stateTrees[i] = stateTrees[i+1]; - } -} - -/* ARGSUSED */ -void _XtFreeTranslations( - XtAppContext app, - XrmValuePtr toVal, - XtPointer closure, - XrmValuePtr args, - Cardinal *num_args) -{ - XtTranslations xlations; - int i; - - if (*num_args != 0) - XtAppWarningMsg(app, - "invalidParameters","freeTranslations",XtCXtToolkitError, - "Freeing XtTranslations requires no extra arguments", - (String *)NULL, (Cardinal *)NULL); - - xlations = *(XtTranslations*)toVal->addr; - for (i = 0; i < (int)xlations->numStateTrees; i++) - RemoveStateTree(xlations->stateTreeTbl[i]); - XtFree((char *)xlations); -} - -/* The spec is not clear on when actions specified in accelerators are bound; - * Bind them at Realize the same as translations - */ -void XtInstallAccelerators( - Widget destination, Widget source) -{ - XtTranslations aXlations; - _XtTranslateOp op; - String buf; - WIDGET_TO_APPCON(destination); - - /* - * test that it was parsed as an accelarator table. Even though - * there doesn't need to be a distinction it makes life easier if - * we honor the spec implication that aXlations is an accelerator - */ - LOCK_APP(app); - LOCK_PROCESS; - if ((!XtIsWidget(source)) || - ((aXlations = source->core.accelerators) == NULL) || - (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) { - UNLOCK_PROCESS; - UNLOCK_APP(app); - return; - } - - aXlations = source->core.accelerators; - op = aXlations->operation; - - if (ComposeTranslations(destination, op, source, aXlations) && - (XtClass(source)->core_class.display_accelerator != NULL)) { - - buf = _XtPrintXlations(destination, aXlations, source, False); - (*(XtClass(source)->core_class.display_accelerator))(source,buf); - XtFree(buf); - } - UNLOCK_PROCESS; - UNLOCK_APP(app); -} - -void XtInstallAllAccelerators( - Widget destination, - Widget source) -{ - Cardinal i; - CompositeWidget cw; - WIDGET_TO_APPCON(destination); - - /* Recurse down normal children */ - LOCK_APP(app); - LOCK_PROCESS; - if (XtIsComposite(source)) { - cw = (CompositeWidget) source; - for (i = 0; i < cw->composite.num_children; i++) { - XtInstallAllAccelerators(destination,cw->composite.children[i]); - } - } - - /* Recurse down popup children */ - if (XtIsWidget(source)) { - for (i = 0; i < source->core.num_popups; i++) { - XtInstallAllAccelerators(destination,source->core.popup_list[i]); - } - } - /* Finally, apply procedure to this widget */ - XtInstallAccelerators(destination,source); - UNLOCK_PROCESS; - UNLOCK_APP(app); -} - -#if 0 /* dead code */ -static _XtTranslateOp _XtGetTMOperation( - XtTranslations xlations) -{ - return ((xlations->hasBindings) - ? ((ATranslations)xlations)->xlations->operation - : xlations->operation); -} -#endif - -void XtAugmentTranslations( - Widget widget, - XtTranslations new) -{ - Widget hookobj; - WIDGET_TO_APPCON(widget); - - LOCK_APP(app); - LOCK_PROCESS; - (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new); - hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); - if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { - XtChangeHookDataRec call_data; - - call_data.type = XtHaugmentTranslations; - call_data.widget = widget; - XtCallCallbackList(hookobj, - ((HookObject)hookobj)->hooks.changehook_callbacks, - (XtPointer)&call_data); - } - UNLOCK_PROCESS; - UNLOCK_APP(app); -} - -void XtOverrideTranslations( - Widget widget, - XtTranslations new) -{ - Widget hookobj; - WIDGET_TO_APPCON(widget); - - LOCK_APP(app); - LOCK_PROCESS; - (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new); - hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); - if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { - XtChangeHookDataRec call_data; - - call_data.type = XtHoverrideTranslations; - call_data.widget = widget; - XtCallCallbackList(hookobj, - ((HookObject)hookobj)->hooks.changehook_callbacks, - (XtPointer)&call_data); - } - UNLOCK_PROCESS; - UNLOCK_APP(app); -} - -void _XtMergeTranslations( - Widget widget, - XtTranslations newXlations, - _XtTranslateOp op) -{ - if (!newXlations){ - if (!widget->core.tm.translations) - return; - else { - newXlations = widget->core.tm.translations; - widget->core.tm.translations = NULL; - } - } - (void) ComposeTranslations(widget, - op, - (Widget)NULL, - newXlations); -} - -void _XtUnmergeTranslations( - Widget widget, - XtTranslations xlations) -{ - ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations); -} +/***********************************************************
+Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+
+Copyright 1987, 1988, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+/* TMstate.c -- maintains the state table of actions for the translation
+ * manager.
+ */
+/*LINTLIBRARY*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "IntrinsicI.h"
+
+#ifndef TM_NO_MATCH
+#define TM_NO_MATCH (-2)
+#endif /* TM_NO_MATCH */
+
+/* forward definitions */
+static StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard);
+
+
+static String XtNtranslationError = "translationError";
+
+#ifndef __EMX__
+TMGlobalRec _XtGlobalTM; /* initialized to zero K&R */
+#else
+TMGlobalRec _XtGlobalTM = {0};
+#endif
+
+#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
+ (typeMatch->eventType == tmEvent->event.eventType && \
+ (typeMatch->matchEvent != NULL) && \
+ (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
+
+
+#define NumStateTrees(xlations) \
+ ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
+
+static TMShortCard GetBranchHead(
+ TMParseStateTree parseTree,
+ TMShortCard typeIndex,
+ TMShortCard modIndex,
+ Boolean isDummy)
+{
+#define TM_BRANCH_HEAD_TBL_ALLOC 8
+#define TM_BRANCH_HEAD_TBL_REALLOC 8
+
+ TMBranchHead branchHead = parseTree->branchHeadTbl;
+ TMShortCard newSize, i;
+
+ /*
+ * dummy is used as a place holder for later matching in old-style
+ * matching behavior. If there's already an entry we don't need
+ * another dummy.
+ */
+ if (isDummy) {
+ for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
+ if ((branchHead->typeIndex == typeIndex) &&
+ (branchHead->modIndex == modIndex))
+ return i;
+ }
+ }
+ if (parseTree->numBranchHeads == parseTree->branchHeadTblSize)
+ {
+ if (parseTree->branchHeadTblSize == 0)
+ parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_ALLOC;
+ else
+ parseTree->branchHeadTblSize +=
+ TM_BRANCH_HEAD_TBL_REALLOC;
+ newSize = (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec));
+ if (parseTree->isStackBranchHeads) {
+ TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl;
+ parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize);
+ XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize);
+ parseTree->isStackBranchHeads = False;
+ }
+ else {
+ parseTree->branchHeadTbl = (TMBranchHead)
+ XtRealloc((char *)parseTree->branchHeadTbl,
+ (parseTree->branchHeadTblSize *
+ sizeof(TMBranchHeadRec)));
+ }
+ }
+#ifdef TRACE_TM
+ LOCK_PROCESS;
+ _XtGlobalTM.numBranchHeads++;
+ UNLOCK_PROCESS;
+#endif /* TRACE_TM */
+ branchHead =
+ &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
+ branchHead->typeIndex = typeIndex;
+ branchHead->modIndex = modIndex;
+ branchHead->more = 0;
+ branchHead->isSimple = True;
+ branchHead->hasActions = False;
+ branchHead->hasCycles = False;
+ return parseTree->numBranchHeads-1;
+}
+
+TMShortCard _XtGetQuarkIndex(
+ TMParseStateTree parseTree,
+ XrmQuark quark)
+{
+#define TM_QUARK_TBL_ALLOC 16
+#define TM_QUARK_TBL_REALLOC 16
+ TMShortCard i = parseTree->numQuarks;
+
+ for (i=0; i < parseTree->numQuarks; i++)
+ if (parseTree->quarkTbl[i] == quark)
+ break;
+
+ if (i == parseTree->numQuarks)
+ {
+ if (parseTree->numQuarks == parseTree->quarkTblSize)
+ {
+ TMShortCard newSize;
+
+ if (parseTree->quarkTblSize == 0)
+ parseTree->quarkTblSize += TM_QUARK_TBL_ALLOC;
+ else
+ parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC;
+ newSize = (parseTree->quarkTblSize * sizeof(XrmQuark));
+
+ if (parseTree->isStackQuarks) {
+ XrmQuark *oldquarkTbl = parseTree->quarkTbl;
+ parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize);
+ XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize);
+ parseTree->isStackQuarks = False;
+ }
+ else {
+ parseTree->quarkTbl = (XrmQuark *)
+ XtRealloc((char *)parseTree->quarkTbl,
+ (parseTree->quarkTblSize *
+ sizeof(XrmQuark)));
+ }
+ }
+ parseTree->quarkTbl[parseTree->numQuarks++] = quark;
+ }
+ return i;
+}
+
+/*
+ * Get an entry from the parseTrees complex branchHead tbl. If there's none
+ * there then allocate one
+ */
+/*ARGSUSED*/
+static TMShortCard GetComplexBranchIndex(
+ TMParseStateTree parseTree,
+ TMShortCard typeIndex,
+ TMShortCard modIndex)
+{
+#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
+#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
+
+ if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
+ TMShortCard newSize;
+
+ if (parseTree->complexBranchHeadTblSize == 0)
+ parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_ALLOC;
+ else
+ parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_REALLOC;
+
+ newSize = (parseTree->complexBranchHeadTblSize * sizeof(StatePtr));
+
+ if (parseTree->isStackComplexBranchHeads) {
+ StatePtr *oldcomplexBranchHeadTbl
+ = parseTree->complexBranchHeadTbl;
+ parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize);
+ XtMemmove(parseTree->complexBranchHeadTbl,
+ oldcomplexBranchHeadTbl, newSize);
+ parseTree->isStackComplexBranchHeads = False;
+ }
+ else {
+ parseTree->complexBranchHeadTbl = (StatePtr *)
+ XtRealloc((char *)parseTree->complexBranchHeadTbl,
+ (parseTree->complexBranchHeadTblSize *
+ sizeof(StatePtr)));
+ }
+ }
+ parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
+ return parseTree->numComplexBranchHeads-1;
+}
+
+TMShortCard _XtGetTypeIndex(
+ Event *event)
+{
+ TMShortCard i, j = TM_TYPE_SEGMENT_SIZE;
+ TMShortCard typeIndex = 0;
+ TMTypeMatch typeMatch;
+ TMTypeMatch segment = NULL;
+
+ LOCK_PROCESS;
+ for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
+ segment = _XtGlobalTM.typeMatchSegmentTbl[i];
+ for (j = 0;
+ typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE;
+ j++, typeIndex++)
+ {
+ typeMatch = &(segment[j]);
+ if (event->eventType == typeMatch->eventType &&
+ event->eventCode == typeMatch->eventCode &&
+ event->eventCodeMask == typeMatch->eventCodeMask &&
+ event->matchEvent == typeMatch->matchEvent) {
+ UNLOCK_PROCESS;
+ return typeIndex;
+ }
+ }
+ }
+
+ if (j == TM_TYPE_SEGMENT_SIZE) {
+ if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) {
+ _XtGlobalTM.typeMatchSegmentTblSize += 4;
+ _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
+ XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl,
+ (_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch)));
+ }
+ _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] =
+ segment = (TMTypeMatch)
+ __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec));
+ j = 0;
+ }
+ typeMatch = &segment[j];
+ typeMatch->eventType = event->eventType;
+ typeMatch->eventCode = event->eventCode;
+ typeMatch->eventCodeMask = event->eventCodeMask;
+ typeMatch->matchEvent = event->matchEvent;
+ _XtGlobalTM.numTypeMatches++;
+ UNLOCK_PROCESS;
+ return typeIndex;
+}
+
+static Boolean CompareLateModifiers(
+ LateBindingsPtr lateBind1P,
+ LateBindingsPtr lateBind2P)
+{
+ LateBindingsPtr late1P = lateBind1P;
+ LateBindingsPtr late2P = lateBind2P;
+
+ if (late1P != NULL || late2P != NULL) {
+ int i = 0;
+ int j = 0;
+ if (late1P != NULL)
+ for (; late1P->keysym != NoSymbol; i++) late1P++;
+ if (late2P != NULL)
+ for (; late2P->keysym != NoSymbol; j++) late2P++;
+ if (i != j) return FALSE;
+ late1P--;
+ while (late1P >= lateBind1P) {
+ Boolean last = True;
+ for (late2P = lateBind2P + i - 1;
+ late2P >= lateBind2P;
+ late2P--) {
+ if (late1P->keysym == late2P->keysym
+ && late1P->knot == late2P->knot) {
+ j--;
+ if (last) i--;
+ break;
+ }
+ last = False;
+ }
+ late1P--;
+ }
+ if (j != 0) return FALSE;
+ }
+ return TRUE;
+}
+
+TMShortCard _XtGetModifierIndex(
+ Event *event)
+{
+ TMShortCard i, j = TM_MOD_SEGMENT_SIZE;
+ TMShortCard modIndex = 0;
+ TMModifierMatch modMatch;
+ TMModifierMatch segment = NULL;
+
+ LOCK_PROCESS;
+ for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
+ segment = _XtGlobalTM.modMatchSegmentTbl[i];
+ for (j = 0;
+ modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE;
+ j++, modIndex++) {
+ modMatch = &(segment[j]);
+ if (event->modifiers == modMatch->modifiers &&
+ event->modifierMask == modMatch->modifierMask &&
+ event->standard == modMatch->standard &&
+ ((!event->lateModifiers && !modMatch->lateModifiers) ||
+ CompareLateModifiers(event->lateModifiers,
+ modMatch->lateModifiers))) {
+ /*
+ * if we found a match then we can free the parser's
+ * late modifiers. If there isn't a match we use the
+ * parser's copy
+ */
+ if (event->lateModifiers &&
+ --event->lateModifiers->ref_count == 0) {
+ XtFree((char *)event->lateModifiers);
+ event->lateModifiers = NULL;
+ }
+ UNLOCK_PROCESS;
+ return modIndex;
+ }
+ }
+ }
+
+ if (j == TM_MOD_SEGMENT_SIZE) {
+ if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) {
+ _XtGlobalTM.modMatchSegmentTblSize += 4;
+ _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
+ XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl,
+ (_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch)));
+ }
+ _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] =
+ segment = (TMModifierMatch)
+ __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec));
+ j = 0;
+ }
+ modMatch = &segment[j];
+ modMatch->modifiers = event->modifiers;;
+ modMatch->modifierMask = event->modifierMask;
+ modMatch->standard = event->standard;
+ /*
+ * We use the parser's copy of the late binding array
+ */
+#ifdef TRACE_TM
+ if (event->lateModifiers)
+ _XtGlobalTM.numLateBindings++;
+#endif /* TRACE_TM */
+ modMatch->lateModifiers = event->lateModifiers;
+ _XtGlobalTM.numModMatches++;
+ UNLOCK_PROCESS;
+ return modIndex;
+}
+
+
+/*
+ * This is called from the SimpleStateHandler to match a stateTree
+ * entry to the event coming in
+ */
+static int MatchBranchHead(
+ TMSimpleStateTree stateTree,
+ int startIndex,
+ TMEventPtr event)
+{
+ TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex];
+ int i;
+
+ LOCK_PROCESS;
+ for (i = startIndex;
+ i < (int)stateTree->numBranchHeads;
+ i++, branchHead++)
+ {
+ TMTypeMatch typeMatch;
+ TMModifierMatch modMatch;
+
+ typeMatch = TMGetTypeMatch(branchHead->typeIndex);
+ modMatch = TMGetModifierMatch(branchHead->modIndex);
+
+ if (MatchIncomingEvent(event, typeMatch, modMatch)) {
+ UNLOCK_PROCESS;
+ return i;
+ }
+ }
+ UNLOCK_PROCESS;
+ return (TM_NO_MATCH);
+}
+
+Boolean _XtRegularMatch(
+ TMTypeMatch typeMatch,
+ TMModifierMatch modMatch,
+ TMEventPtr eventSeq)
+{
+ Modifiers computed =0;
+ Modifiers computedMask =0;
+ Boolean resolved = TRUE;
+ if (typeMatch->eventCode != (eventSeq->event.eventCode &
+ typeMatch->eventCodeMask)) return FALSE;
+ if (modMatch->lateModifiers != NULL)
+ resolved = _XtComputeLateBindings(eventSeq->xev->xany.display,
+ modMatch->lateModifiers,
+ &computed, &computedMask);
+ if (!resolved) return FALSE;
+ computed |= modMatch->modifiers;
+ computedMask |= modMatch->modifierMask;
+
+ return ( (computed & computedMask) ==
+ (eventSeq->event.modifiers & computedMask));
+}
+
+/*ARGSUSED*/
+Boolean _XtMatchAtom(
+ TMTypeMatch typeMatch,
+ TMModifierMatch modMatch,
+ TMEventPtr eventSeq)
+{
+ Atom atom;
+
+ atom = XInternAtom(eventSeq->xev->xany.display,
+ XrmQuarkToString(typeMatch->eventCode),
+ False);
+ return (atom == eventSeq->event.eventCode);
+}
+
+#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7)))
+
+/*
+ * there are certain cases where you want to ignore the event and stay
+ * in the same state.
+ */
+static Boolean Ignore(
+ TMEventPtr event)
+{
+ Display *dpy;
+ XtPerDisplay pd;
+
+ if (event->event.eventType == MotionNotify)
+ return TRUE;
+ if (!(event->event.eventType == KeyPress ||
+ event->event.eventType == KeyRelease))
+ return FALSE;
+ dpy = event->xev->xany.display;
+ pd = _XtGetPerDisplay(dpy);
+ _InitializeKeysymTables(dpy, pd);
+ return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
+}
+
+
+static void XEventToTMEvent(
+ XEvent *event,
+ TMEventPtr tmEvent)
+{
+ tmEvent->xev = event;
+ tmEvent->event.eventCodeMask = 0;
+ tmEvent->event.modifierMask = 0;
+ tmEvent->event.eventType = event->type;
+ tmEvent->event.lateModifiers = NULL;
+ tmEvent->event.matchEvent = NULL;
+ tmEvent->event.standard = FALSE;
+
+ switch (event->type) {
+
+ case KeyPress:
+ case KeyRelease:
+ tmEvent->event.eventCode = event->xkey.keycode;
+ tmEvent->event.modifiers = event->xkey.state;
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ tmEvent->event.eventCode = event->xbutton.button;
+ tmEvent->event.modifiers = event->xbutton.state;
+ break;
+
+ case MotionNotify:
+ tmEvent->event.eventCode = event->xmotion.is_hint;
+ tmEvent->event.modifiers = event->xmotion.state;
+ break;
+
+ case EnterNotify:
+ case LeaveNotify:
+ tmEvent->event.eventCode = event->xcrossing.mode;
+ tmEvent->event.modifiers = event->xcrossing.state;
+ break;
+
+ case PropertyNotify:
+ tmEvent->event.eventCode = event->xproperty.atom;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case SelectionClear:
+ tmEvent->event.eventCode = event->xselectionclear.selection;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case SelectionRequest:
+ tmEvent->event.eventCode = event->xselectionrequest.selection;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case SelectionNotify:
+ tmEvent->event.eventCode = event->xselection.selection;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case ClientMessage:
+ tmEvent->event.eventCode = event->xclient.message_type;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case MappingNotify:
+ tmEvent->event.eventCode = event->xmapping.request;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ tmEvent->event.eventCode = event->xfocus.mode;
+ tmEvent->event.modifiers = 0;
+ break;
+
+ default:
+ tmEvent->event.eventCode = 0;
+ tmEvent->event.modifiers = 0;
+ break;
+ }
+}
+
+
+static unsigned long GetTime(
+ XtTM tm,
+ XEvent *event)
+{
+ switch (event->type) {
+
+ case KeyPress:
+ case KeyRelease:
+ return event->xkey.time;
+
+ case ButtonPress:
+ case ButtonRelease:
+ return event->xbutton.time;
+
+ default:
+ return tm->lastEventTime;
+
+ }
+
+}
+
+static void HandleActions(
+ Widget w,
+ XEvent *event,
+ TMSimpleStateTree stateTree,
+ Widget accelWidget,
+ XtActionProc *procs,
+ ActionRec *actions)
+{
+ ActionHook actionHookList;
+ Widget bindWidget;
+
+ bindWidget = accelWidget ? accelWidget : w;
+ if (accelWidget && !XtIsSensitive(accelWidget) &&
+ (event->type == KeyPress || event->type == KeyRelease ||
+ event->type == ButtonPress || event->type == ButtonRelease ||
+ event->type == MotionNotify || event->type == EnterNotify ||
+ event->type == LeaveNotify || event->type == FocusIn ||
+ event->type == FocusOut))
+ return;
+
+ actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
+
+ while (actions != NULL) {
+ /* perform any actions */
+ if (procs[actions->idx] != NULL) {
+ if (actionHookList) {
+ ActionHook hook;
+ ActionHook next_hook;
+ String procName =
+ XrmQuarkToString(stateTree->quarkTbl[actions->idx] );
+
+ for (hook = actionHookList; hook != NULL; ) {
+ /*
+ * Need to cache hook->next because the following action
+ * proc may free hook via XtRemoveActionHook making
+ * hook->next invalid upon return from the action proc.
+ */
+ next_hook = hook->next;
+ (*hook->proc)(bindWidget,
+ hook->closure,
+ procName,
+ event,
+ actions->params,
+ &actions->num_params
+ );
+ hook = next_hook;
+ }
+ }
+ (*(procs[actions->idx]))
+ (bindWidget, event,
+ actions->params, &actions->num_params );
+ }
+ actions = actions->next;
+ }
+}
+
+typedef struct {
+ unsigned int isCycleStart:1;
+ unsigned int isCycleEnd:1;
+ TMShortCard typeIndex;
+ TMShortCard modIndex;
+}MatchPairRec, *MatchPair;
+
+typedef struct TMContextRec{
+ TMShortCard numMatches;
+ TMShortCard maxMatches;
+ MatchPair matches;
+}TMContextRec, *TMContext;
+
+static TMContextRec contextCache[2];
+
+#define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
+
+#define TM_CONTEXT_MATCHES_ALLOC 4
+#define TM_CONTEXT_MATCHES_REALLOC 2
+
+static void PushContext(
+ TMContext *contextPtr,
+ StatePtr newState)
+{
+ TMContext context = *contextPtr;
+
+ LOCK_PROCESS;
+ if (context == NULL)
+ {
+ if (contextCache[0].numMatches == 0)
+ context = &contextCache[0];
+ else if (contextCache[1].numMatches == 0)
+ context = &contextCache[1];
+ if (!context)
+ {
+ context = XtNew(TMContextRec);
+ context->matches = NULL;
+ context->numMatches =
+ context->maxMatches = 0;
+ }
+ }
+ if (context->numMatches &&
+ context->matches[context->numMatches-1].isCycleEnd)
+ {
+ TMShortCard i;
+ for (i = 0;
+ i < context->numMatches &&
+ !(context->matches[i].isCycleStart);
+ i++){};
+ if (i < context->numMatches)
+ context->numMatches = i+1;
+#ifdef DEBUG
+ else
+ XtWarning("pushing cycle end with no cycle start");
+#endif /* DEBUG */
+ }
+ else
+ {
+ if (context->numMatches == context->maxMatches)
+ {
+ if (context->maxMatches == 0)
+ context->maxMatches += TM_CONTEXT_MATCHES_ALLOC;
+ else
+ context->maxMatches += TM_CONTEXT_MATCHES_REALLOC;
+ context->matches = (MatchPairRec *)
+ XtRealloc((char *)context->matches,
+ context->maxMatches * sizeof(MatchPairRec));
+ }
+ context->matches[context->numMatches].isCycleStart = newState->isCycleStart;
+ context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
+ context->matches[context->numMatches].typeIndex = newState->typeIndex;
+ context->matches[context->numMatches++].modIndex = newState->modIndex;
+ *contextPtr = context;
+ }
+ UNLOCK_PROCESS;
+}
+
+static void FreeContext(
+ TMContext *contextPtr)
+{
+ TMContext context = NULL;
+
+ LOCK_PROCESS;
+
+ if (&contextCache[0] == *contextPtr)
+ context = &contextCache[0];
+ else if (&contextCache[1] == *contextPtr)
+ context = &contextCache[1];
+
+ if (context)
+ context->numMatches = 0;
+ else if (*contextPtr)
+ {
+ if ((*contextPtr)->matches)
+ XtFree ((char *) ((*contextPtr)->matches));
+ XtFree((char *)*contextPtr);
+ }
+
+ *contextPtr = NULL;
+ UNLOCK_PROCESS;
+}
+
+static int MatchExact(
+ TMSimpleStateTree stateTree,
+ int startIndex,
+ TMShortCard typeIndex,
+ TMShortCard modIndex)
+{
+ TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
+ int i;
+
+ for (i = startIndex;
+ i < (int)stateTree->numBranchHeads;
+ i++, branchHead++)
+ {
+ if ((branchHead->typeIndex == typeIndex) &&
+ (branchHead->modIndex == modIndex))
+ return i;
+ }
+ return (TM_NO_MATCH);
+}
+
+
+
+static void HandleSimpleState(
+ Widget w,
+ XtTM tmRecPtr,
+ TMEventRec *curEventPtr)
+{
+ XtTranslations xlations = tmRecPtr->translations;
+ TMSimpleStateTree stateTree;
+ TMContext *contextPtr = GetContextPtr(tmRecPtr);
+ TMShortCard i;
+ ActionRec *actions = NULL;
+ Boolean matchExact = False;
+ Boolean match = False;
+ StatePtr complexMatchState = NULL;
+ int currIndex;
+ TMShortCard typeIndex = 0, modIndex = 0;
+ int matchTreeIndex = TM_NO_MATCH;
+
+ LOCK_PROCESS;
+ stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0];
+
+ for (i = 0;
+ ((!match || !complexMatchState) && (i < xlations->numStateTrees));
+ i++){
+ stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
+ currIndex = -1;
+ /*
+ * don't process this tree if we're only looking for a
+ * complexMatchState and there are no complex states
+ */
+ while (!(match && stateTree->isSimple) &&
+ ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
+ currIndex++;
+ if (matchExact)
+ currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex);
+ else
+ currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr);
+ if (currIndex != TM_NO_MATCH) {
+ TMBranchHead branchHead;
+ StatePtr currState;
+
+ branchHead = &stateTree->branchHeadTbl[currIndex];
+ if (branchHead->isSimple)
+ currState = NULL;
+ else
+ currState = ((TMComplexStateTree)stateTree)
+ ->complexBranchHeadTbl[TMBranchMore(branchHead)];
+
+ /*
+ * first check for a complete match
+ */
+ if (!match) {
+ if (branchHead->hasActions) {
+ if (branchHead->isSimple) {
+ static ActionRec dummyAction;
+
+ dummyAction.idx = TMBranchMore(branchHead);
+ actions = &dummyAction;
+ }
+ else
+ actions = currState->actions;
+ tmRecPtr->lastEventTime =
+ GetTime(tmRecPtr, curEventPtr->xev);
+ FreeContext((TMContext
+ *)&tmRecPtr->current_state);
+ match = True;
+ matchTreeIndex = i;
+ }
+ /*
+ * if it doesn't have actions and
+ * it's bc mode then it's a potential match node that is
+ * used to match later sequences.
+ */
+ if (!TMNewMatchSemantics() && !matchExact) {
+ matchExact = True;
+ typeIndex = branchHead->typeIndex;
+ modIndex = branchHead->modIndex;
+ }
+ }
+ /*
+ * check for it being an event sequence which can be
+ * a future match
+ */
+ if (!branchHead->isSimple &&
+ !branchHead->hasActions &&
+ !complexMatchState)
+ complexMatchState = currState;
+ }
+ }
+ }
+ if (match)
+ {
+ TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
+ XtActionProc *procs;
+ Widget accelWidget;
+
+ if (bindData->simple.isComplex) {
+ TMComplexBindProcs bindProcs =
+ TMGetComplexBindEntry(bindData, matchTreeIndex);
+ procs = bindProcs->procs;
+ accelWidget = bindProcs->widget;
+ }
+ else {
+ TMSimpleBindProcs bindProcs =
+ TMGetSimpleBindEntry(bindData, matchTreeIndex);
+ procs = bindProcs->procs;
+ accelWidget = NULL;
+ }
+ HandleActions
+ (w,
+ curEventPtr->xev,
+ (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex],
+ accelWidget,
+ procs,
+ actions);
+ }
+ if (complexMatchState)
+ PushContext(contextPtr, complexMatchState);
+ UNLOCK_PROCESS;
+}
+
+static int MatchComplexBranch(
+ TMComplexStateTree stateTree,
+ int startIndex,
+ TMContext context,
+ StatePtr *leafStateRtn)
+{
+ TMShortCard i;
+
+ LOCK_PROCESS;
+ for (i = startIndex; i < stateTree->numComplexBranchHeads; i++)
+ {
+ StatePtr candState;
+ TMShortCard numMatches = context->numMatches;
+ MatchPair statMatch = context->matches;
+
+ for (candState = stateTree->complexBranchHeadTbl[i];
+ numMatches && candState;
+ numMatches--, statMatch++, candState = candState->nextLevel)
+ {
+ if ((statMatch->typeIndex != candState->typeIndex) ||
+ (statMatch->modIndex != candState->modIndex))
+ break;
+ }
+ if (numMatches == 0) {
+ *leafStateRtn = candState;
+ UNLOCK_PROCESS;
+ return i;
+ }
+ }
+ *leafStateRtn = NULL;
+ UNLOCK_PROCESS;
+ return (TM_NO_MATCH);
+}
+
+static StatePtr TryCurrentTree(
+ TMComplexStateTree *stateTreePtr,
+ XtTM tmRecPtr,
+ TMEventRec *curEventPtr)
+{
+ StatePtr candState = NULL, matchState = NULL;
+ TMContext *contextPtr = GetContextPtr(tmRecPtr);
+ TMTypeMatch typeMatch;
+ TMModifierMatch modMatch;
+ int currIndex = -1;
+
+ /*
+ * we want the first sequence that both matches and has actions.
+ * we keep on looking till we find both
+ */
+ LOCK_PROCESS;
+ while ((currIndex =
+ MatchComplexBranch(*stateTreePtr,
+ ++currIndex,
+ (*contextPtr),
+ &candState))
+ != TM_NO_MATCH) {
+ if (candState != NULL) {
+ typeMatch = TMGetTypeMatch(candState->typeIndex);
+ modMatch = TMGetModifierMatch(candState->modIndex);
+
+ /* does this state's index match? --> done */
+ if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch))
+ {
+ if (candState->actions) {
+ UNLOCK_PROCESS;
+ return candState;
+ }
+ else
+ matchState = candState;
+ }
+ /* is this an event timer? */
+ if (typeMatch->eventType == _XtEventTimerEventType) {
+ StatePtr nextState = candState->nextLevel;
+
+ /* does the succeeding state match? */
+ if (nextState != NULL) {
+ TMTypeMatch nextTypeMatch;
+ TMModifierMatch nextModMatch;
+
+ nextTypeMatch = TMGetTypeMatch(nextState->typeIndex);
+ nextModMatch = TMGetModifierMatch(nextState->modIndex);
+
+ /* is it within the timeout? */
+ if (MatchIncomingEvent(curEventPtr,
+ nextTypeMatch,
+ nextModMatch)) {
+ XEvent *xev = curEventPtr->xev;
+ unsigned long time = GetTime(tmRecPtr, xev);
+ XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
+ unsigned long delta = pd->multi_click_time;
+
+ if ((tmRecPtr->lastEventTime + delta) >= time) {
+ if (nextState->actions) {
+ UNLOCK_PROCESS;
+ return candState;
+ }
+ else
+ matchState = candState;
+ }
+ }
+ }
+ }
+ }
+ }
+ UNLOCK_PROCESS;
+ return matchState;
+}
+
+static void HandleComplexState(
+ Widget w,
+ XtTM tmRecPtr,
+ TMEventRec *curEventPtr)
+{
+ XtTranslations xlations = tmRecPtr->translations;
+ TMContext *contextPtr = GetContextPtr(tmRecPtr);
+ TMShortCard i, matchTreeIndex = 0;
+ StatePtr matchState = NULL, candState;
+ TMComplexStateTree *stateTreePtr =
+ (TMComplexStateTree *)&xlations->stateTreeTbl[0];
+
+ LOCK_PROCESS;
+ for (i = 0;
+ i < xlations->numStateTrees;
+ i++, stateTreePtr++) {
+ /*
+ * some compilers sign extend Boolean bit fields so test for
+ * false |||
+ */
+ if (((*stateTreePtr)->isSimple == False) &&
+ (candState = TryCurrentTree(stateTreePtr,
+ tmRecPtr,
+ curEventPtr))) {
+ if (!matchState || candState->actions) {
+ matchTreeIndex = i;
+ matchState = candState;
+ if (candState->actions)
+ break;
+ }
+ }
+ }
+ if (matchState == NULL){
+ /* couldn't find it... */
+ if (!Ignore(curEventPtr))
+ {
+ FreeContext(contextPtr);
+ HandleSimpleState(w, tmRecPtr, curEventPtr);
+ }
+ }
+ else {
+ TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
+ XtActionProc *procs;
+ Widget accelWidget;
+ TMTypeMatch typeMatch;
+
+ typeMatch = TMGetTypeMatch(matchState->typeIndex);
+
+ PushContext(contextPtr, matchState);
+ if (typeMatch->eventType == _XtEventTimerEventType) {
+ matchState = matchState->nextLevel;
+ PushContext(contextPtr, matchState);
+ }
+ tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev);
+
+ if (bindData->simple.isComplex) {
+ TMComplexBindProcs bindProcs =
+ TMGetComplexBindEntry(bindData, matchTreeIndex);
+ procs = bindProcs->procs;
+ accelWidget = bindProcs->widget;
+ }
+ else {
+ TMSimpleBindProcs bindProcs =
+ TMGetSimpleBindEntry(bindData, matchTreeIndex);
+ procs = bindProcs->procs;
+ accelWidget = NULL;
+ }
+ HandleActions(w,
+ curEventPtr->xev,
+ (TMSimpleStateTree)
+ xlations->stateTreeTbl[matchTreeIndex],
+ accelWidget,
+ procs,
+ matchState->actions);
+ }
+ UNLOCK_PROCESS;
+}
+
+
+void _XtTranslateEvent (
+ Widget w,
+ XEvent * event)
+{
+ XtTM tmRecPtr = &w->core.tm;
+ TMEventRec curEvent;
+ StatePtr current_state = tmRecPtr->current_state;
+
+ XEventToTMEvent (event, &curEvent);
+
+ if (! tmRecPtr->translations) {
+ XtAppWarningMsg(XtWidgetToApplicationContext(w),
+ XtNtranslationError,"nullTable",XtCXtToolkitError,
+ "Can't translate event through NULL table",
+ (String *)NULL, (Cardinal *)NULL);
+ return ;
+ }
+ if (current_state == NULL)
+ HandleSimpleState(w, tmRecPtr, &curEvent);
+ else
+ HandleComplexState(w, tmRecPtr, &curEvent);
+}
+
+
+/*ARGSUSED*/
+static StatePtr NewState(
+ TMParseStateTree stateTree,
+ TMShortCard typeIndex,
+ TMShortCard modIndex)
+{
+ StatePtr state = XtNew(StateRec);
+
+#ifdef TRACE_TM
+ LOCK_PROCESS;
+ _XtGlobalTM.numComplexStates++;
+ UNLOCK_PROCESS;
+#endif /* TRACE_TM */
+ state->typeIndex = typeIndex;
+ state->modIndex = modIndex;
+ state->nextLevel = NULL;
+ state->actions = NULL;
+ state->isCycleStart = state->isCycleEnd = False;
+ return state;
+}
+
+/*
+ * This routine is an iterator for state trees. If the func returns
+ * true then iteration is over.
+ */
+void _XtTraverseStateTree(
+ TMStateTree tree,
+ _XtTraversalProc func,
+ XtPointer data)
+{
+ TMComplexStateTree stateTree = (TMComplexStateTree)tree;
+ TMBranchHead currBH;
+ TMShortCard i;
+ StateRec dummyStateRec, *dummyState = &dummyStateRec;
+ ActionRec dummyActionRec, *dummyAction = &dummyActionRec;
+ Boolean firstSimple = True;
+ StatePtr currState;
+
+ /* first traverse the complex states */
+ if (stateTree->isSimple == False)
+ for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
+ currState = stateTree->complexBranchHeadTbl[i];
+ for (; currState; currState = currState->nextLevel) {
+ if (func(currState, data))
+ return;
+ if (currState->isCycleEnd)
+ break;
+ }
+ }
+
+ /* now traverse the simple ones */
+ for (i = 0, currBH = stateTree->branchHeadTbl;
+ i < stateTree->numBranchHeads;
+ i++, currBH++)
+ {
+ if (currBH->isSimple && currBH->hasActions)
+ {
+ if (firstSimple)
+ {
+ XtBZero((char *) dummyState, sizeof(StateRec));
+ XtBZero((char *) dummyAction, sizeof(ActionRec));
+ dummyState->actions = dummyAction;
+ firstSimple = False;
+ }
+ dummyState->typeIndex = currBH->typeIndex;
+ dummyState->modIndex = currBH->modIndex;
+ dummyAction->idx = currBH->more;
+ if (func(dummyState, data))
+ return;
+ }
+ }
+}
+
+static EventMask EventToMask(
+ TMTypeMatch typeMatch,
+ TMModifierMatch modMatch)
+{
+ EventMask returnMask;
+ unsigned long eventType = typeMatch->eventType;
+
+ if (eventType == MotionNotify) {
+ Modifiers modifierMask = modMatch->modifierMask;
+ Modifiers tempMask;
+
+ returnMask = 0;
+ if (modifierMask == 0) {
+ if (modMatch->modifiers == AnyButtonMask)
+ return ButtonMotionMask;
+ else
+ return PointerMotionMask;
+ }
+ tempMask = modifierMask &
+ (Button1Mask | Button2Mask | Button3Mask
+ | Button4Mask | Button5Mask);
+ if (tempMask == 0)
+ return PointerMotionMask;
+ if (tempMask & Button1Mask)
+ returnMask |= Button1MotionMask;
+ if (tempMask & Button2Mask)
+ returnMask |= Button2MotionMask;
+ if (tempMask & Button3Mask)
+ returnMask |= Button3MotionMask;
+ if (tempMask & Button4Mask)
+ returnMask |= Button4MotionMask;
+ if (tempMask & Button5Mask)
+ returnMask |= Button5MotionMask;
+ return returnMask;
+ }
+ returnMask = _XtConvertTypeToMask(eventType);
+ if (returnMask == (StructureNotifyMask|SubstructureNotifyMask))
+ returnMask = StructureNotifyMask;
+ return returnMask;
+}
+
+/*ARGSUSED*/
+static void DispatchMappingNotify(
+ Widget widget, /* will be NULL from _RefreshMapping */
+ XtPointer closure, /* real Widget */
+ XtPointer call_data) /* XEvent* */
+{
+ _XtTranslateEvent( (Widget)closure, (XEvent*)call_data);
+}
+
+
+/*ARGSUSED*/
+static void RemoveFromMappingCallbacks(
+ Widget widget,
+ XtPointer closure, /* target widget */
+ XtPointer call_data)
+{
+ _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
+ DispatchMappingNotify,
+ closure
+ );
+}
+
+static Boolean AggregateEventMask(
+ StatePtr state,
+ XtPointer data)
+{
+ LOCK_PROCESS;
+ *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex),
+ TMGetModifierMatch(state->modIndex));
+ UNLOCK_PROCESS;
+ return False;
+}
+
+void _XtInstallTranslations(
+ Widget widget)
+{
+ XtTranslations xlations;
+ Cardinal i;
+ TMStateTree stateTree;
+ Boolean mappingNotifyInterest = False;
+
+ xlations = widget->core.tm.translations;
+ if (xlations == NULL) return;
+
+ /*
+ * check for somebody stuffing the translations directly into the
+ * instance structure. We will end up being called again out of
+ * ComposeTranslations but we *should* have bindings by then
+ */
+ if (widget->core.tm.proc_table == NULL) {
+ _XtMergeTranslations(widget, NULL, XtTableReplace);
+ /*
+ * if we're realized then we'll be called out of
+ * ComposeTranslations
+ */
+ if (XtIsRealized(widget))
+ return;
+ }
+
+ xlations->eventMask = 0;
+ for (i = 0;
+ i < xlations->numStateTrees;
+ i++)
+ {
+ stateTree = xlations->stateTreeTbl[i];
+ _XtTraverseStateTree(stateTree,
+ AggregateEventMask,
+ (XtPointer)&xlations->eventMask);
+ mappingNotifyInterest |= stateTree->simple.mappingNotifyInterest;
+ }
+ /* double click needs to make sure that you have selected on both
+ button down and up. */
+
+ if (xlations->eventMask & ButtonPressMask)
+ xlations->eventMask |= ButtonReleaseMask;
+ if (xlations->eventMask & ButtonReleaseMask)
+ xlations->eventMask |= ButtonPressMask;
+
+ if (mappingNotifyInterest) {
+ XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
+ if (pd->mapping_callbacks)
+ _XtAddCallbackOnce(&(pd->mapping_callbacks),
+ DispatchMappingNotify,
+ (XtPointer)widget);
+ else
+ _XtAddCallback(&(pd->mapping_callbacks),
+ DispatchMappingNotify,
+ (XtPointer)widget);
+
+ if (widget->core.destroy_callbacks != NULL)
+ _XtAddCallbackOnce( (InternalCallbackList *)
+ &widget->core.destroy_callbacks,
+ RemoveFromMappingCallbacks,
+ (XtPointer)widget
+ );
+ else
+ _XtAddCallback((InternalCallbackList *)
+ &widget->core.destroy_callbacks,
+ RemoveFromMappingCallbacks,
+ (XtPointer)widget
+ );
+ }
+ _XtBindActions(widget, (XtTM)&widget->core.tm);
+ _XtRegisterGrabs(widget);
+}
+
+void _XtRemoveTranslations(
+ Widget widget)
+{
+ Cardinal i;
+ TMSimpleStateTree stateTree;
+ Boolean mappingNotifyInterest = False;
+ XtTranslations xlations = widget->core.tm.translations;
+
+ if (xlations == NULL)
+ return;
+
+ for (i = 0;
+ i < xlations->numStateTrees;
+ i++)
+ {
+ stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
+ mappingNotifyInterest |= stateTree->mappingNotifyInterest;
+ }
+ if (mappingNotifyInterest)
+ RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL);
+}
+
+static void _XtUninstallTranslations(
+ Widget widget)
+{
+ XtTranslations xlations = widget->core.tm.translations;
+
+ _XtUnbindActions(widget,
+ xlations,
+ (TMBindData)widget->core.tm.proc_table);
+ _XtRemoveTranslations(widget);
+ widget->core.tm.translations = NULL;
+ FreeContext((TMContext *)&widget->core.tm.current_state);
+}
+
+void _XtDestroyTMData(
+ Widget widget)
+{
+ TMComplexBindData cBindData;
+
+ _XtUninstallTranslations(widget);
+
+ if ((cBindData = (TMComplexBindData)widget->core.tm.proc_table)) {
+ if (cBindData->isComplex) {
+ ATranslations aXlations, nXlations;
+
+ nXlations = (ATranslations) cBindData->accel_context;
+ while (nXlations){
+ aXlations = nXlations;
+ nXlations = nXlations->next;
+ XtFree((char *)aXlations);
+ }
+ }
+ XtFree((char *)cBindData);
+ }
+}
+
+/*** Public procedures ***/
+
+
+void XtUninstallTranslations(
+ Widget widget)
+{
+ EventMask oldMask;
+ Widget hookobj;
+ WIDGET_TO_APPCON(widget);
+
+ LOCK_APP(app);
+ if (! widget->core.tm.translations) {
+ UNLOCK_APP(app);
+ return;
+ }
+ oldMask = widget->core.tm.translations->eventMask;
+ _XtUninstallTranslations(widget);
+ if (XtIsRealized(widget) && oldMask)
+ XSelectInput(XtDisplay(widget), XtWindow(widget),
+ XtBuildEventMask(widget));
+ hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
+ if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
+ XtChangeHookDataRec call_data;
+
+ call_data.type = XtHuninstallTranslations;
+ call_data.widget = widget;
+ XtCallCallbackList(hookobj,
+ ((HookObject)hookobj)->hooks.changehook_callbacks,
+ (XtPointer)&call_data);
+ }
+ UNLOCK_APP(app);
+}
+
+XtTranslations _XtCreateXlations(
+ TMStateTree *stateTrees,
+ TMShortCard numStateTrees,
+ XtTranslations first,
+ XtTranslations second)
+{
+ XtTranslations xlations;
+ TMShortCard i;
+
+ xlations = (XtTranslations)
+ __XtMalloc(sizeof(TranslationData) +
+ (numStateTrees-1) * sizeof(TMStateTree));
+#ifdef TRACE_TM
+ LOCK_PROCESS;
+ if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
+ _XtGlobalTM.tmTblSize += 16;
+ _XtGlobalTM.tmTbl = (XtTranslations *)
+ XtRealloc((char *)_XtGlobalTM.tmTbl,
+ _XtGlobalTM.tmTblSize * sizeof(XtTranslations));
+ }
+ _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
+ UNLOCK_PROCESS;
+#endif /* TRACE_TM */
+
+ xlations->composers[0] = first;
+ xlations->composers[1] = second;
+ xlations->hasBindings = False;
+ xlations->operation = XtTableReplace;
+
+ for (i = 0;i < numStateTrees; i++)
+ {
+ xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
+ stateTrees[i]->simple.refCount++;
+ }
+ xlations->numStateTrees = numStateTrees;
+ xlations->eventMask = 0;
+ return xlations;
+}
+
+TMStateTree _XtParseTreeToStateTree(
+ TMParseStateTree parseTree)
+{
+ TMSimpleStateTree simpleTree;
+ unsigned int tableSize;
+
+ if (parseTree->numComplexBranchHeads) {
+ TMComplexStateTree complexTree;
+
+ complexTree = XtNew(TMComplexStateTreeRec);
+ complexTree->isSimple = False;
+ tableSize = parseTree->numComplexBranchHeads * sizeof(StatePtr);
+ complexTree->complexBranchHeadTbl = (StatePtr *)
+ __XtMalloc(tableSize);
+ XtMemmove(complexTree->complexBranchHeadTbl,
+ parseTree->complexBranchHeadTbl, tableSize);
+ complexTree->numComplexBranchHeads =
+ parseTree->numComplexBranchHeads;
+ simpleTree = (TMSimpleStateTree)complexTree;
+ }
+ else {
+ simpleTree = XtNew(TMSimpleStateTreeRec);
+ simpleTree->isSimple = True;
+ }
+ simpleTree->isAccelerator = parseTree->isAccelerator;
+ simpleTree->refCount = 0;
+ simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
+
+ tableSize = parseTree->numBranchHeads * sizeof(TMBranchHeadRec);
+ simpleTree->branchHeadTbl = (TMBranchHead)
+ __XtMalloc(tableSize);
+ XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize);
+ simpleTree->numBranchHeads = parseTree->numBranchHeads;
+
+ tableSize = parseTree->numQuarks * sizeof(XrmQuark);
+ simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize);
+ XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize);
+ simpleTree->numQuarks = parseTree->numQuarks;
+
+ return (TMStateTree)simpleTree;
+}
+
+static void FreeActions(
+ ActionPtr actions)
+{
+ ActionPtr action;
+ TMShortCard i;
+ for (action = actions; action;) {
+ ActionPtr nextAction = action->next;
+ for (i = action->num_params; i;) {
+ XtFree( action->params[--i] );
+ }
+ XtFree( (char*)action->params );
+ XtFree((char*) action);
+ action = nextAction;
+ }
+}
+
+/*ARGSUSED*/
+static void AmbigActions(
+ EventSeqPtr initialEvent,
+ StatePtr *state,
+ TMParseStateTree stateTree)
+{
+ String params[3];
+ Cardinal numParams = 0;
+
+ params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
+ params[numParams++] = _XtPrintActions((*state)->actions,
+ stateTree->quarkTbl);
+ XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError,
+ "Previous entry was: %s %s", params, &numParams);
+ XtFree((char *)params[0]);
+ XtFree((char *)params[1]);
+ numParams = 0;
+ params[numParams++] = _XtPrintActions(initialEvent->actions,
+ stateTree->quarkTbl);
+ XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError,
+ "New actions are:%s", params, &numParams);
+ XtFree((char *)params[0]);
+ XtWarningMsg (XtNtranslationError,"ambiguousActions",
+ XtCXtToolkitError,
+ "Overriding earlier translation manager actions.",
+ (String *)NULL, (Cardinal *)NULL);
+
+ FreeActions((*state)->actions);
+ (*state)->actions = NULL;
+}
+
+
+void _XtAddEventSeqToStateTree(
+ EventSeqPtr eventSeq,
+ TMParseStateTree stateTree)
+{
+ StatePtr *state;
+ EventSeqPtr initialEvent = eventSeq;
+ TMBranchHead branchHead;
+ TMShortCard idx, modIndex, typeIndex;
+
+ if (eventSeq == NULL) return;
+
+ /* note that all states in the event seq passed in start out null */
+ /* we fill them in with the matching state as we traverse the list */
+
+ /*
+ * We need to free the parser data structures !!!
+ */
+
+ typeIndex = _XtGetTypeIndex(&eventSeq->event);
+ modIndex = _XtGetModifierIndex(&eventSeq->event);
+ idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
+ branchHead = &stateTree->branchHeadTbl[idx];
+
+ /*
+ * Need to check for pre-existing actions with same lhs |||
+ */
+
+ /*
+ * Check for optimized case. Don't assume that the eventSeq has actions.
+ */
+ if (!eventSeq->next &&
+ eventSeq->actions &&
+ !eventSeq->actions->next &&
+ !eventSeq->actions->num_params)
+ {
+ if (eventSeq->event.eventType == MappingNotify)
+ stateTree->mappingNotifyInterest = True;
+ branchHead->hasActions = True;
+ branchHead->more = eventSeq->actions->idx;
+ FreeActions(eventSeq->actions);
+ eventSeq->actions = NULL;
+ return;
+ }
+
+ branchHead->isSimple = False;
+ if (!eventSeq->next)
+ branchHead->hasActions = True;
+ branchHead->more = GetComplexBranchIndex(stateTree, typeIndex, modIndex);
+ state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
+
+ for (;;) {
+ *state = NewState(stateTree, typeIndex, modIndex);
+
+ if (eventSeq->event.eventType == MappingNotify)
+ stateTree->mappingNotifyInterest = True;
+
+ /* *state now points at state record matching event */
+ eventSeq->state = *state;
+
+ if (eventSeq->actions != NULL) {
+ if ((*state)->actions != NULL)
+ AmbigActions(initialEvent, state, stateTree);
+ (*state)->actions = eventSeq->actions;
+#ifdef TRACE_TM
+ LOCK_PROCESS
+ _XtGlobalTM.numComplexActions++;
+ UNLOCK_PROCESS;
+#endif /* TRACE_TM */
+ }
+
+ if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
+ break;
+
+ state = &(*state)->nextLevel;
+ typeIndex = _XtGetTypeIndex(&eventSeq->event);
+ modIndex = _XtGetModifierIndex(&eventSeq->event);
+ LOCK_PROCESS;
+ if (!TMNewMatchSemantics()) {
+ /*
+ * force a potential empty entry into the branch head
+ * table in order to emulate old matching behavior
+ */
+ (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
+ }
+ UNLOCK_PROCESS;
+ }
+
+ if (eventSeq && eventSeq->state) {
+ /* we've been here before... must be a cycle in the event seq. */
+ branchHead->hasCycles = True;
+ (*state)->nextLevel = eventSeq->state;
+ eventSeq->state->isCycleStart = True;
+ (*state)->isCycleEnd = TRUE;
+ }
+}
+
+
+/*
+ * Internal Converter for merging. Old and New must both be valid xlations
+ */
+
+/*ARGSUSED*/
+Boolean _XtCvtMergeTranslations(
+ Display *dpy,
+ XrmValuePtr args,
+ Cardinal *num_args,
+ XrmValuePtr from,
+ XrmValuePtr to,
+ XtPointer *closure_ret)
+{
+ XtTranslations first, second, xlations;
+ TMStateTree *stateTrees, stackStateTrees[16];
+ TMShortCard numStateTrees, i;
+
+ if (*num_args != 0)
+ XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError,
+ "MergeTM to TranslationTable needs no extra arguments",
+ (String *)NULL, (Cardinal *)NULL);
+
+ if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
+ to->size = sizeof(XtTranslations);
+ return False;
+ }
+
+ first = ((TMConvertRec*)from->addr)->old;
+ second = ((TMConvertRec*)from->addr)->new;
+
+ numStateTrees = first->numStateTrees + second->numStateTrees;
+
+ stateTrees = (TMStateTree *)
+ XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
+
+ for (i = 0; i < first->numStateTrees; i++)
+ stateTrees[i] = first->stateTreeTbl[i];
+ for (i = 0; i < second->numStateTrees; i++)
+ stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
+
+ xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
+
+ if (to->addr != NULL) {
+ *(XtTranslations*)to->addr = xlations;
+ }
+ else {
+ static XtTranslations staticStateTable;
+ staticStateTable = xlations;
+ to->addr= (XPointer)&staticStateTable;
+ to->size = sizeof(XtTranslations);
+ }
+
+ XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees);
+ return True;
+}
+
+
+static XtTranslations MergeThem(
+ Widget dest,
+ XtTranslations first,
+ XtTranslations second)
+{
+ XtCacheRef cache_ref;
+ static XrmQuark from_type = NULLQUARK, to_type;
+ XrmValue from, to;
+ TMConvertRec convert_rec;
+ XtTranslations newTable;
+
+ LOCK_PROCESS;
+ if (from_type == NULLQUARK) {
+ from_type = XrmPermStringToQuark(_XtRStateTablePair);
+ to_type = XrmPermStringToQuark(XtRTranslationTable);
+ }
+ UNLOCK_PROCESS;
+ from.addr = (XPointer)&convert_rec;
+ from.size = sizeof(TMConvertRec);
+ to.addr = (XPointer)&newTable;
+ to.size = sizeof(XtTranslations);
+ convert_rec.old = first;
+ convert_rec.new = second;
+
+ LOCK_PROCESS;
+ if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) {
+ UNLOCK_PROCESS;
+ return NULL;
+ }
+ UNLOCK_PROCESS;
+
+#ifndef REFCNT_TRANSLATIONS
+
+ if (cache_ref)
+ XtAddCallback(dest, XtNdestroyCallback,
+ XtCallbackReleaseCacheRef, (XtPointer)cache_ref);
+
+#endif
+
+ return newTable;
+}
+
+/*
+ * Unmerge will recursively traverse the xlation compose tree and
+ * generate a new xlation that is the result of all instances of
+ * xlations being removed. It currently doesn't differentiate between
+ * the potential that an xlation will be both an accelerator and
+ * normal. This is not supported by the spec anyway.
+ */
+static XtTranslations UnmergeTranslations(
+ Widget widget,
+ XtTranslations xlations,
+ XtTranslations unmergeXlations,
+ TMShortCard currIndex,
+ TMComplexBindProcs oldBindings,
+ TMShortCard numOldBindings,
+ TMComplexBindProcs newBindings,
+ TMShortCard *numNewBindingsRtn)
+
+{
+ XtTranslations first, second, result;
+
+ if (!xlations || (xlations == unmergeXlations))
+ return NULL;
+
+ if (xlations->composers[0]) {
+ first = UnmergeTranslations(widget, xlations->composers[0],
+ unmergeXlations, currIndex,
+ oldBindings, numOldBindings,
+ newBindings, numNewBindingsRtn);
+ }
+ else
+ first = NULL;
+
+ if (xlations->composers[1]) {
+ second = UnmergeTranslations(widget, xlations->composers[1],
+ unmergeXlations,
+ currIndex +
+ xlations->composers[0]->numStateTrees,
+ oldBindings, numOldBindings,
+ newBindings, numNewBindingsRtn);
+ }
+ else
+ second = NULL;
+
+ if (first || second) {
+ if (first && second) {
+ if ((first != xlations->composers[0]) ||
+ (second != xlations->composers[1]))
+ result = MergeThem(widget, first, second);
+ else result = xlations;
+ }
+ else {
+ if (first)
+ result = first;
+ else
+ result = second;
+ }
+ } else { /* only update for leaf nodes */
+ if (numOldBindings) {
+ Cardinal i;
+ for (i = 0; i < xlations->numStateTrees; i++) {
+ if (xlations->stateTreeTbl[i]->simple.isAccelerator)
+ newBindings[*numNewBindingsRtn] =
+ oldBindings[currIndex + i];
+ (*numNewBindingsRtn)++;
+ }
+ }
+ result = xlations;
+ }
+ return result;
+}
+
+typedef struct {
+ XtTranslations xlations;
+ TMComplexBindProcs bindings;
+}MergeBindRec, *MergeBind;
+
+static XtTranslations MergeTranslations(
+ Widget widget,
+ XtTranslations oldXlations,
+ XtTranslations newXlations,
+ _XtTranslateOp operation,
+ Widget source,
+ TMComplexBindProcs oldBindings,
+ TMComplexBindProcs newBindings,
+ TMShortCard *numNewRtn)
+{
+ XtTranslations newTable = NULL, xlations;
+ TMComplexBindProcs bindings;
+ TMShortCard i, j;
+ TMStateTree *treePtr;
+ TMShortCard numNew = *numNewRtn;
+ MergeBindRec bindPair[2];
+
+ /* If the new translation has an accelerator context then pull it
+ * off and pass it and the real xlations in to the caching merge
+ * routine.
+ */
+ if (newXlations->hasBindings) {
+ xlations = ((ATranslations) newXlations)->xlations;
+ bindings = (TMComplexBindProcs)
+ &((ATranslations) newXlations)->bindTbl[0];
+ }
+ else {
+ xlations = newXlations;
+ bindings = NULL;
+ }
+ switch(operation) {
+ case XtTableReplace:
+ newTable = bindPair[0].xlations = xlations;
+ bindPair[0].bindings = bindings;
+ bindPair[1].xlations = NULL;
+ bindPair[1].bindings = NULL;
+ break;
+ case XtTableAugment:
+ bindPair[0].xlations = oldXlations;
+ bindPair[0].bindings = oldBindings;
+ bindPair[1].xlations = xlations;
+ bindPair[1].bindings = bindings;
+ newTable = NULL;
+ break;
+ case XtTableOverride:
+ bindPair[0].xlations = xlations;
+ bindPair[0].bindings = bindings;
+ bindPair[1].xlations = oldXlations;
+ bindPair[1].bindings = oldBindings;
+ newTable = NULL;
+ break;
+ }
+ if (!newTable)
+ newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
+
+ for (i = 0, numNew = 0; i < 2; i++) {
+ if (bindPair[i].xlations)
+ for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
+ if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
+ if (bindPair[i].bindings)
+ newBindings[numNew] = bindPair[i].bindings[j];
+ else {
+ newBindings[numNew].widget = source;
+ newBindings[numNew].aXlations =
+ bindPair[i].xlations;
+ }
+ }
+ }
+ }
+ *numNewRtn = numNew;
+ treePtr = &newTable->stateTreeTbl[0];
+ for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
+ (*treePtr)->simple.refCount++;
+ return newTable;
+}
+
+static TMBindData MakeBindData(
+ TMComplexBindProcs bindings,
+ TMShortCard numBindings,
+ TMBindData oldBindData)
+{
+ TMLongCard bytes;
+ TMShortCard i;
+ Boolean isComplex;
+ TMBindData bindData;
+
+ if (numBindings == 0)
+ return NULL;
+ for (i = 0; i < numBindings; i++)
+ if (bindings[i].widget)
+ break;
+ isComplex = (i < numBindings);
+ if (isComplex)
+ bytes = (sizeof(TMComplexBindDataRec) +
+ ((numBindings - 1) *
+ sizeof(TMComplexBindProcsRec)));
+ else
+ bytes = (sizeof(TMSimpleBindDataRec) +
+ ((numBindings - 1) *
+ sizeof(TMSimpleBindProcsRec)));
+
+ bindData = (TMBindData) __XtCalloc(sizeof(char), bytes);
+ bindData->simple.isComplex = isComplex;
+ if (isComplex) {
+ TMComplexBindData cBindData = (TMComplexBindData)bindData;
+ /*
+ * If there were any accelerator contexts in the old bindData
+ * then propagate them to the new one.
+ */
+ if (oldBindData && oldBindData->simple.isComplex)
+ cBindData->accel_context =
+ ((TMComplexBindData) oldBindData)->accel_context;
+ XtMemmove((char *)&cBindData->bindTbl[0], (char *)bindings,
+ numBindings * sizeof(TMComplexBindProcsRec));
+ }
+ return bindData;
+}
+
+/*
+ * This routine is the central clearinghouse for merging translations
+ * into a widget. It takes care of preping the action bindings for
+ * realize time and calling the converter or doing a straight merge if
+ * the destination is empty.
+ */
+static Boolean ComposeTranslations(
+ Widget dest,
+ _XtTranslateOp operation,
+ Widget source,
+ XtTranslations newXlations)
+{
+ XtTranslations newTable, oldXlations;
+ XtTranslations accNewXlations;
+ EventMask oldMask = 0;
+ TMBindData bindData;
+ TMComplexBindProcs oldBindings = NULL;
+ TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes;
+ TMComplexBindProcsRec stackBindings[16], *newBindings;
+
+ /*
+ * how should we be handling the refcount decrement for the
+ * replaced translation table ???
+ */
+ if (!newXlations)
+ {
+ XtAppWarningMsg(XtWidgetToApplicationContext(dest),
+ XtNtranslationError,"nullTable",XtCXtToolkitError,
+ "table to (un)merge must not be null",
+ (String *)NULL, (Cardinal *)NULL);
+ return False;
+ }
+
+ accNewXlations = newXlations;
+ newXlations = ((newXlations->hasBindings)
+ ? ((ATranslations)newXlations)->xlations
+ : newXlations);
+
+ if (!(oldXlations = dest->core.tm.translations))
+ operation = XtTableReplace;
+
+ /*
+ * try to avoid generation of duplicate state trees. If the source
+ * isn't simple (1 state Tree) then it's too much hassle
+ */
+ if (((operation == XtTableAugment) ||
+ (operation == XtTableOverride)) &&
+ (newXlations->numStateTrees == 1)) {
+ Cardinal i;
+ for (i = 0; i < oldXlations->numStateTrees; i++)
+ if (oldXlations->stateTreeTbl[i] ==
+ newXlations->stateTreeTbl[0])
+ break;
+ if (i < oldXlations->numStateTrees) {
+ if (operation == XtTableAugment) {
+ /*
+ * we don't need to do anything since it's already
+ * there
+ */
+ return True;
+ }
+ else {/* operation == XtTableOverride */
+ /*
+ * We'll get rid of the duplicate trees throughout the
+ * and leave it with a pruned translation table. This
+ * will only work if the same table has been merged
+ * into this table (or one of it's composers
+ */
+ _XtUnmergeTranslations(dest, newXlations);
+ /*
+ * reset oldXlations so we're back in sync
+ */
+ if (!(oldXlations = dest->core.tm.translations))
+ operation = XtTableReplace;
+ }
+ }
+ }
+
+ bindData = (TMBindData) dest->core.tm.proc_table;
+ if (bindData) {
+ numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
+ if (bindData->simple.isComplex)
+ oldBindings = &((TMComplexBindData)bindData)->bindTbl[0];
+ else
+ oldBindings = (TMComplexBindProcs)
+ (&((TMSimpleBindData)bindData)->bindTbl[0]);
+ }
+
+ numBytes =(((oldXlations ? oldXlations->numStateTrees : 0)
+ + newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec));
+ newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings);
+ XtBZero((char *)newBindings, numBytes);
+
+ if (operation == XtTableUnmerge) {
+ newTable = UnmergeTranslations(dest,
+ oldXlations,
+ newXlations,
+ 0,
+ oldBindings, numOldBindings,
+ newBindings, &numNewBindings);
+#ifdef DEBUG
+ /* check for no match for unmerge */
+ if (newTable == oldXlations) {
+ XtWarning("attempt to unmerge invalid table");
+ XtStackFree((char *)newBindings, (char *)stackBindings);
+ return(newTable != NULL);
+ }
+#endif /* DEBUG */
+ }
+ else {
+ newTable = MergeTranslations(dest,
+ oldXlations,
+ accNewXlations,
+ operation,
+ source,
+ oldBindings,
+ newBindings,
+ &numNewBindings);
+ }
+ if (XtIsRealized(dest)) {
+ oldMask = 0;
+ if (oldXlations)
+ oldMask = oldXlations->eventMask;
+ _XtUninstallTranslations(dest);
+ }
+
+ dest->core.tm.proc_table =
+ (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
+
+ if (bindData) XtFree((char *)bindData);
+
+ dest->core.tm.translations = newTable;
+
+ if (XtIsRealized(dest)) {
+ EventMask mask = 0;
+ _XtInstallTranslations(dest);
+ if (newTable)
+ mask = newTable->eventMask;
+ if (mask != oldMask)
+ XSelectInput(XtDisplay(dest), XtWindow(dest),
+ XtBuildEventMask(dest));
+ }
+ XtStackFree((XtPointer)newBindings, (XtPointer)stackBindings);
+ return(newTable != NULL);
+}
+
+/*
+ * If a GetValues is done on a translation resource that contains
+ * accelerators we need to return the accelerator context in addition
+ * to the pure translations. Since this means returning memory that
+ * the client controlls but we still own, we will track the "headers"
+ * that we return (via a linked list pointed to from the bindData) and
+ * free it at destroy time.
+ */
+XtTranslations _XtGetTranslationValue(
+ Widget w)
+{
+ XtTM tmRecPtr = (XtTM) &w->core.tm;
+ ATranslations *aXlationsPtr;
+ TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table;
+ XtTranslations xlations = tmRecPtr->translations;
+
+ if (!xlations || !cBindData || !cBindData->isComplex)
+ return xlations;
+
+ /* Walk the list looking to see if we already have generated a
+ * header for the currently installed translations. If we have,
+ * just return that header. Otherwise create a new header.
+ */
+ for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
+ *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
+ aXlationsPtr = &(*aXlationsPtr)->next)
+ ;
+ if (*aXlationsPtr)
+ return (XtTranslations) *aXlationsPtr;
+ else {
+ /* create a new aXlations context */
+ ATranslations aXlations;
+ Cardinal numBindings = xlations->numStateTrees;
+
+ (*aXlationsPtr) = aXlations = (ATranslations)
+ __XtMalloc(sizeof(ATranslationData) +
+ (numBindings - 1) * sizeof(TMComplexBindProcsRec));
+
+ aXlations->hasBindings = True;
+ aXlations->xlations = xlations;
+ aXlations->next = NULL;
+ XtMemmove((char *) &aXlations->bindTbl[0],
+ (char *) &cBindData->bindTbl[0],
+ numBindings * sizeof(TMComplexBindProcsRec));
+ return (XtTranslations) aXlations;
+ }
+}
+
+
+/*ARGSUSED*/
+static void RemoveStateTree(
+ TMStateTree tree)
+{
+#ifdef REFCNT_TRANSLATIONS
+ TMComplexStateTree stateTree = (TMComplexStateTree)tree;
+
+ if (--stateTree->refCount == 0) {
+ /*
+ * should we free/refcount the match recs ?
+ */
+ if (!stateTree->isSimple) {
+ StatePtr currState, nextState;
+ TMShortCard i;
+ for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
+ currState =
+ nextState =
+ stateTree->complexBranchHeadTbl[i];
+ for (; nextState;){
+ FreeActions(currState->actions);
+ currState->actions = NULL;
+ if (!currState->isCycleEnd)
+ nextState = currState->nextLevel;
+ else
+ nextState = NULL;
+ XtFree( (char*)currState );
+ }
+ }
+ XtFree((char*)stateTree->complexBranchHeadTbl);
+ }
+ XtFree((char*)stateTree->branchHeadTbl);
+ XtFree((char*)stateTree);
+ }
+#endif /* REFCNT_TRANSLATIONS */
+}
+
+void _XtRemoveStateTreeByIndex(
+ XtTranslations xlations,
+ TMShortCard i)
+{
+ TMStateTree *stateTrees = xlations->stateTreeTbl;
+
+ RemoveStateTree(stateTrees[i]);
+ xlations->numStateTrees--;
+
+ for (; i < xlations->numStateTrees; i++)
+ {
+ stateTrees[i] = stateTrees[i+1];
+ }
+}
+
+/* ARGSUSED */
+void _XtFreeTranslations(
+ XtAppContext app,
+ XrmValuePtr toVal,
+ XtPointer closure,
+ XrmValuePtr args,
+ Cardinal *num_args)
+{
+ XtTranslations xlations;
+ int i;
+
+ if (*num_args != 0)
+ XtAppWarningMsg(app,
+ "invalidParameters","freeTranslations",XtCXtToolkitError,
+ "Freeing XtTranslations requires no extra arguments",
+ (String *)NULL, (Cardinal *)NULL);
+
+ xlations = *(XtTranslations*)toVal->addr;
+ for (i = 0; i < (int)xlations->numStateTrees; i++)
+ RemoveStateTree(xlations->stateTreeTbl[i]);
+ XtFree((char *)xlations);
+}
+
+/* The spec is not clear on when actions specified in accelerators are bound;
+ * Bind them at Realize the same as translations
+ */
+void XtInstallAccelerators(
+ Widget destination, Widget source)
+{
+ XtTranslations aXlations;
+ _XtTranslateOp op;
+ String buf;
+ WIDGET_TO_APPCON(destination);
+
+ /*
+ * test that it was parsed as an accelarator table. Even though
+ * there doesn't need to be a distinction it makes life easier if
+ * we honor the spec implication that aXlations is an accelerator
+ */
+ LOCK_APP(app);
+ LOCK_PROCESS;
+ if ((!XtIsWidget(source)) ||
+ ((aXlations = source->core.accelerators) == NULL) ||
+ (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) {
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+ return;
+ }
+
+ aXlations = source->core.accelerators;
+ op = aXlations->operation;
+
+ if (ComposeTranslations(destination, op, source, aXlations) &&
+ (XtClass(source)->core_class.display_accelerator != NULL)) {
+
+ buf = _XtPrintXlations(destination, aXlations, source, False);
+ (*(XtClass(source)->core_class.display_accelerator))(source,buf);
+ XtFree(buf);
+ }
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+}
+
+void XtInstallAllAccelerators(
+ Widget destination,
+ Widget source)
+{
+ Cardinal i;
+ CompositeWidget cw;
+ WIDGET_TO_APPCON(destination);
+
+ /* Recurse down normal children */
+ LOCK_APP(app);
+ LOCK_PROCESS;
+ if (XtIsComposite(source)) {
+ cw = (CompositeWidget) source;
+ for (i = 0; i < cw->composite.num_children; i++) {
+ XtInstallAllAccelerators(destination,cw->composite.children[i]);
+ }
+ }
+
+ /* Recurse down popup children */
+ if (XtIsWidget(source)) {
+ for (i = 0; i < source->core.num_popups; i++) {
+ XtInstallAllAccelerators(destination,source->core.popup_list[i]);
+ }
+ }
+ /* Finally, apply procedure to this widget */
+ XtInstallAccelerators(destination,source);
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+}
+
+#if 0 /* dead code */
+static _XtTranslateOp _XtGetTMOperation(
+ XtTranslations xlations)
+{
+ return ((xlations->hasBindings)
+ ? ((ATranslations)xlations)->xlations->operation
+ : xlations->operation);
+}
+#endif
+
+void XtAugmentTranslations(
+ Widget widget,
+ XtTranslations new)
+{
+ Widget hookobj;
+ WIDGET_TO_APPCON(widget);
+
+ LOCK_APP(app);
+ LOCK_PROCESS;
+ (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new);
+ hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
+ if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
+ XtChangeHookDataRec call_data;
+
+ call_data.type = XtHaugmentTranslations;
+ call_data.widget = widget;
+ XtCallCallbackList(hookobj,
+ ((HookObject)hookobj)->hooks.changehook_callbacks,
+ (XtPointer)&call_data);
+ }
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+}
+
+void XtOverrideTranslations(
+ Widget widget,
+ XtTranslations new)
+{
+ Widget hookobj;
+ WIDGET_TO_APPCON(widget);
+
+ LOCK_APP(app);
+ LOCK_PROCESS;
+ (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new);
+ hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
+ if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
+ XtChangeHookDataRec call_data;
+
+ call_data.type = XtHoverrideTranslations;
+ call_data.widget = widget;
+ XtCallCallbackList(hookobj,
+ ((HookObject)hookobj)->hooks.changehook_callbacks,
+ (XtPointer)&call_data);
+ }
+ UNLOCK_PROCESS;
+ UNLOCK_APP(app);
+}
+
+void _XtMergeTranslations(
+ Widget widget,
+ XtTranslations newXlations,
+ _XtTranslateOp op)
+{
+ if (!newXlations){
+ if (!widget->core.tm.translations)
+ return;
+ else {
+ newXlations = widget->core.tm.translations;
+ widget->core.tm.translations = NULL;
+ }
+ }
+ (void) ComposeTranslations(widget,
+ op,
+ (Widget)NULL,
+ newXlations);
+}
+
+void _XtUnmergeTranslations(
+ Widget widget,
+ XtTranslations xlations)
+{
+ ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations);
+}
|