home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xt / TMstate.c.orig < prev    next >
Encoding:
Text File  |  1993-07-21  |  61.3 KB  |  2,197 lines

  1. /* $XConsortium: TMstate.c,v 1.162 92/03/25 16:47:39 converse Exp $ */
  2. /*LINTLIBRARY*/
  3.  
  4. /***********************************************************
  5. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  6. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  7.  
  8.                         All Rights Reserved
  9.  
  10. Permission to use, copy, modify, and distribute this software and its 
  11. documentation for any purpose and without fee is hereby granted, 
  12. provided that the above copyright notice appear in all copies and that
  13. both that copyright notice and this permission notice appear in 
  14. supporting documentation, and that the names of Digital or MIT not be
  15. used in advertising or publicity pertaining to distribution of the
  16. software without specific, written prior permission.  
  17.  
  18. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  19. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  20. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  21. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  23. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  24. SOFTWARE.
  25.  
  26. ******************************************************************/
  27.  
  28. /* TMstate.c -- maintains the state table of actions for the translation 
  29.  *              manager.
  30.  */
  31.  
  32. #include "IntrinsicI.h"
  33. #include "StringDefs.h"
  34.  
  35. #ifndef TM_NO_MATCH
  36. #define TM_NO_MATCH (-2)
  37. #endif /* TM_NO_MATCH */
  38.  
  39. /* forward definitions */
  40. static StatePtr NewState();
  41.  
  42.  
  43. static String XtNtranslationError = "translationError";
  44.  
  45. TMGlobalRec _XtGlobalTM; /* initialized to zero K&R */
  46.  
  47. #define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
  48.   (typeMatch->eventType == tmEvent->event.eventType && \
  49.    (typeMatch->matchEvent != NULL) && \
  50.    (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
  51.  
  52.  
  53. #define NumStateTrees(xlations) \
  54.   ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
  55.  
  56. static TMShortCard GetBranchHead(parseTree, typeIndex, modIndex, isDummy)
  57.     TMParseStateTree    parseTree;
  58.     TMShortCard        typeIndex;
  59.     TMShortCard        modIndex;
  60.     Boolean        isDummy;
  61. {
  62. #define TM_BRANCH_HEAD_TBL_ALLOC     8
  63. #define TM_BRANCH_HEAD_TBL_REALLOC     8
  64.  
  65.     register TMBranchHead branchHead = parseTree->branchHeadTbl;
  66.     TMShortCard    newSize, i;
  67.  
  68.     /*
  69.      * dummy is used as a place holder for later matching in old-style
  70.      * matching behavior. If there's already an entry we don't need
  71.      * another dummy.
  72.      */
  73.     if (isDummy) {
  74.     for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
  75.         if ((branchHead->typeIndex == typeIndex) &&
  76.         (branchHead->modIndex == modIndex))
  77.           return i;
  78.     }
  79.     }
  80.     if (parseTree->numBranchHeads == parseTree->branchHeadTblSize)
  81.       {
  82.       if (parseTree->branchHeadTblSize == 0)
  83.         parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_ALLOC;
  84.       else
  85.         parseTree->branchHeadTblSize +=
  86.           TM_BRANCH_HEAD_TBL_REALLOC;
  87.       newSize = (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec));
  88.       if (parseTree->isStackBranchHeads) {
  89.           TMBranchHead    oldBranchHeadTbl = parseTree->branchHeadTbl;
  90.           parseTree->branchHeadTbl = (TMBranchHead) XtMalloc(newSize);
  91.           XtBCopy(oldBranchHeadTbl, parseTree->branchHeadTbl, newSize);
  92.           parseTree->isStackBranchHeads = False;
  93.       }
  94.       else {
  95.           parseTree->branchHeadTbl = (TMBranchHead) 
  96.         XtRealloc((char *)parseTree->branchHeadTbl, 
  97.               (parseTree->branchHeadTblSize *
  98.                sizeof(TMBranchHeadRec)));
  99.       }
  100.       }
  101. #ifdef TRACE_TM
  102.     _XtGlobalTM.numBranchHeads++;
  103. #endif /* TRACE_TM */
  104.     branchHead = 
  105.       &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
  106.     branchHead->typeIndex = typeIndex;
  107.     branchHead->modIndex = modIndex;
  108.     branchHead->more = 0;
  109.     branchHead->isSimple = True;
  110.     branchHead->hasActions = False;
  111.     branchHead->hasCycles = False;
  112.     return parseTree->numBranchHeads-1;
  113. }
  114.  
  115. TMShortCard _XtGetQuarkIndex(parseTree, quark)
  116.     TMParseStateTree    parseTree;
  117.     XrmQuark        quark;
  118. {
  119. #define TM_QUARK_TBL_ALLOC     16
  120. #define TM_QUARK_TBL_REALLOC     16
  121.     register TMShortCard  i = parseTree->numQuarks;
  122.  
  123.     for (i=0; i < parseTree->numQuarks; i++)
  124.       if (parseTree->quarkTbl[i] == quark)
  125.         break;
  126.  
  127.     if (i == parseTree->numQuarks)
  128.       {
  129.       if (parseTree->numQuarks == parseTree->quarkTblSize)
  130.         {
  131.         TMShortCard    newSize;
  132.  
  133.         if (parseTree->quarkTblSize == 0)
  134.           parseTree->quarkTblSize += TM_QUARK_TBL_ALLOC;
  135.         else
  136.           parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC;
  137.         newSize = (parseTree->quarkTblSize * sizeof(XrmQuark));
  138.  
  139.         if (parseTree->isStackQuarks) {
  140.             XrmQuark    *oldquarkTbl = parseTree->quarkTbl;
  141.             parseTree->quarkTbl = (XrmQuark *) XtMalloc(newSize);
  142.             XtBCopy(oldquarkTbl, parseTree->quarkTbl, newSize);
  143.             parseTree->isStackQuarks = False;
  144.         }
  145.         else {
  146.             parseTree->quarkTbl = (XrmQuark *) 
  147.               XtRealloc((char *)parseTree->quarkTbl, 
  148.                 (parseTree->quarkTblSize *
  149.                  sizeof(XrmQuark)));
  150.         }
  151.         }
  152.       parseTree->quarkTbl[parseTree->numQuarks++] = quark;
  153.       }
  154.     return i;
  155. }
  156.  
  157. /*
  158.  * Get an entry from the parseTrees complex branchHead tbl. If there's none
  159.  * there then allocate one
  160.  */
  161. /*ARGSUSED*/
  162. static TMShortCard GetComplexBranchIndex(parseTree, typeIndex, modIndex)
  163.     TMParseStateTree    parseTree;
  164.     TMShortCard        typeIndex;
  165.     TMShortCard        modIndex;
  166. {
  167. #define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
  168. #define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
  169.     
  170.     if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
  171.     TMShortCard    newSize;
  172.     
  173.     if (parseTree->complexBranchHeadTblSize == 0)
  174.       parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_ALLOC;
  175.     else
  176.       parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_REALLOC;
  177.     
  178.     newSize = (parseTree->complexBranchHeadTblSize * sizeof(StatePtr));
  179.     
  180.     if (parseTree->isStackComplexBranchHeads) {
  181.         StatePtr *oldcomplexBranchHeadTbl 
  182.           = parseTree->complexBranchHeadTbl;
  183.         parseTree->complexBranchHeadTbl = (StatePtr *) XtMalloc(newSize);
  184.         XtBCopy(oldcomplexBranchHeadTbl, parseTree->complexBranchHeadTbl,
  185.             newSize);
  186.         parseTree->isStackComplexBranchHeads = False;
  187.     }
  188.     else {
  189.         parseTree->complexBranchHeadTbl = (StatePtr *) 
  190.           XtRealloc((char *)parseTree->complexBranchHeadTbl, 
  191.             (parseTree->complexBranchHeadTblSize *
  192.              sizeof(StatePtr)));    
  193.     }
  194.     }
  195.     parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
  196.     return parseTree->numComplexBranchHeads-1;
  197. }
  198.  
  199. TMShortCard _XtGetTypeIndex(event)
  200.     Event    *event;
  201. {
  202.     TMShortCard        i, j = TM_TYPE_SEGMENT_SIZE;
  203.     TMShortCard        typeIndex = 0;
  204.     TMTypeMatch     typeMatch;
  205.     TMTypeMatch        segment;
  206.  
  207.     for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
  208.     segment = _XtGlobalTM.typeMatchSegmentTbl[i];
  209.     for (j = 0; 
  210.          typeIndex < _XtGlobalTM.numTypeMatches && j <  TM_TYPE_SEGMENT_SIZE;
  211.          j++, typeIndex++) 
  212.       {
  213.           typeMatch = &(segment[j]);
  214.           if (event->eventType == typeMatch->eventType && 
  215.           event->eventCode == typeMatch->eventCode && 
  216.           event->eventCodeMask == typeMatch->eventCodeMask &&
  217.           event->matchEvent == typeMatch->matchEvent)
  218.             return typeIndex;
  219.       }
  220.     }
  221.     
  222.     if (j == TM_TYPE_SEGMENT_SIZE) {
  223.     if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) {
  224.         _XtGlobalTM.typeMatchSegmentTblSize += 4;
  225.         _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
  226.           XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl,
  227.             (_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch)));
  228.     }
  229.     _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] = 
  230.       segment = (TMTypeMatch)
  231.         XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec));
  232.     j = 0;
  233.     }
  234.     typeMatch = &segment[j];
  235.     typeMatch->eventType = event->eventType;
  236.     typeMatch->eventCode = event->eventCode;
  237.     typeMatch->eventCodeMask = event->eventCodeMask;
  238.     typeMatch->matchEvent = event->matchEvent;
  239.     _XtGlobalTM.numTypeMatches++;
  240.     return typeIndex;
  241. }
  242.  
  243. static Boolean CompareLateModifiers(lateBind1P, lateBind2P)
  244.     LateBindingsPtr lateBind1P, lateBind2P;
  245. {
  246.     LateBindingsPtr late1P = lateBind1P;
  247.     LateBindingsPtr late2P = lateBind2P;
  248.  
  249.     if (late1P != NULL || late2P != NULL) {
  250.     int i = 0;
  251.     int j = 0;
  252.     if (late1P != NULL)
  253.       for (; late1P->keysym != NoSymbol; i++) late1P++;
  254.     if (late2P != NULL)
  255.       for (; late2P->keysym != NoSymbol; j++) late2P++;
  256.     if (i != j) return FALSE;
  257.     late1P--;
  258.     while (late1P >= lateBind1P) {
  259.         Boolean last = True;
  260.         for (late2P = lateBind2P + i - 1;
  261.          late2P >= lateBind2P;
  262.          late2P--) {
  263.         if (late1P->keysym == late2P->keysym
  264.             && late1P->knot == late2P->knot) {
  265.             j--;
  266.             if (last) i--;
  267.             break;
  268.         }
  269.         last = False;
  270.         }
  271.         late1P--;
  272.     }
  273.     if (j != 0) return FALSE;
  274.     }
  275.     return TRUE;
  276. }
  277.  
  278. TMShortCard _XtGetModifierIndex(event)
  279.     Event    *event;
  280. {
  281.     TMShortCard        i, j = TM_MOD_SEGMENT_SIZE;
  282.     TMShortCard        modIndex = 0;
  283.     TMModifierMatch     modMatch;
  284.     TMModifierMatch    segment;
  285.     for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
  286.     segment = _XtGlobalTM.modMatchSegmentTbl[i];
  287.     for (j = 0; 
  288.          modIndex < _XtGlobalTM.numModMatches && j <  TM_MOD_SEGMENT_SIZE;
  289.          j++, modIndex++) {
  290.         modMatch = &(segment[j]);
  291.         if (event->modifiers == modMatch->modifiers && 
  292.         event->modifierMask == modMatch->modifierMask && 
  293.         event->standard == modMatch->standard && 
  294.         ((!event->lateModifiers && !modMatch->lateModifiers) || 
  295.          CompareLateModifiers(event->lateModifiers,
  296.                       modMatch->lateModifiers))) {
  297.         /*
  298.          * if we found a match then we can free the parser's
  299.          * late modifiers. If there isn't a match we use the
  300.          * parser's copy
  301.          */
  302.         if (event->lateModifiers &&
  303.             --event->lateModifiers->ref_count == 0) {
  304.             XtFree((char *)event->lateModifiers);
  305.             event->lateModifiers = NULL;
  306.         }
  307.         return modIndex;
  308.         }
  309.     }
  310.     }
  311.     
  312.     if (j == TM_MOD_SEGMENT_SIZE) {
  313.     if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) {
  314.         _XtGlobalTM.modMatchSegmentTblSize += 4;
  315.         _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
  316.           XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl,
  317.             (_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch)));
  318.     }
  319.     _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] = 
  320.       segment = (TMModifierMatch)
  321.         XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec));
  322.     j = 0;
  323.     }
  324.     modMatch = &segment[j];
  325.     modMatch->modifiers = event->modifiers;;
  326.     modMatch->modifierMask = event->modifierMask;
  327.     modMatch->standard = event->standard;
  328.     /*
  329.      * We use the parser's copy of the late binding array
  330.      */
  331. #ifdef TRACE_TM
  332.     if (event->lateModifiers)
  333.       _XtGlobalTM.numLateBindings++;
  334. #endif /* TRACE_TM */
  335.     modMatch->lateModifiers = event->lateModifiers;
  336.     _XtGlobalTM.numModMatches++;
  337.     return modIndex;
  338. }
  339.  
  340.  
  341. /*
  342.  * This is called from the SimpleStateHandler to match a stateTree
  343.  * entry to the event coming in
  344.  */
  345. static int MatchBranchHead(stateTree, startIndex, event) 
  346.     TMSimpleStateTree     stateTree;
  347.     int            startIndex;
  348.     register TMEventPtr    event;
  349. {
  350.     register TMBranchHead
  351.       branchHead = &stateTree->branchHeadTbl[startIndex];
  352.     register int i;
  353.  
  354.     for (i = startIndex;
  355.      i < (int)stateTree->numBranchHeads; 
  356.      i++, branchHead++)
  357.       {
  358.       TMTypeMatch         typeMatch;
  359.       TMModifierMatch    modMatch;
  360.       
  361.       typeMatch  = TMGetTypeMatch(branchHead->typeIndex);
  362.       modMatch = TMGetModifierMatch(branchHead->modIndex);
  363.       
  364.       if (MatchIncomingEvent(event, typeMatch, modMatch))
  365.         return i;
  366.       }    
  367.     return (TM_NO_MATCH);
  368. }
  369.  
  370. Boolean _XtRegularMatch(typeMatch, modMatch, eventSeq)
  371.     TMTypeMatch     typeMatch;
  372.     TMModifierMatch    modMatch;
  373.     TMEventPtr         eventSeq;
  374. {
  375.     Modifiers computed =0;
  376.     Modifiers computedMask =0;
  377.     Boolean resolved = TRUE;
  378.     if (typeMatch->eventCode != (eventSeq->event.eventCode &
  379.                   typeMatch->eventCodeMask)) return FALSE;
  380.     if (modMatch->lateModifiers != NULL)
  381.       resolved = 
  382.     _XtComputeLateBindings(modMatch->lateModifiers,
  383.                    eventSeq,
  384.                    &computed,
  385.                    &computedMask);
  386.     if (!resolved) return FALSE;
  387.     computed |= modMatch->modifiers;
  388.     computedMask |= modMatch->modifierMask;
  389.  
  390.     return ( (computed & computedMask) ==
  391.         (eventSeq->event.modifiers & computedMask));
  392. }
  393.  
  394. /*ARGSUSED*/
  395. Boolean _XtMatchAtom(typeMatch, modMatch, eventSeq)
  396.     TMTypeMatch     typeMatch;
  397.     TMModifierMatch    modMatch;
  398.     TMEventPtr         eventSeq;
  399. {
  400.     Atom    atom;
  401.  
  402.     atom = XInternAtom(eventSeq->xev->xany.display, 
  403.                XrmQuarkToString(typeMatch->eventCode),
  404.                False);
  405.     return (atom == eventSeq->event.eventCode);
  406. }
  407.  
  408. #define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7)))
  409.  
  410. /*
  411.  * there are certain cases where you want to ignore the event and stay
  412.  * in the same state.
  413.  */
  414. static Boolean Ignore(event)
  415.     register TMEventPtr event;
  416. {
  417.     register Display *dpy;
  418.     register XtPerDisplay pd;
  419.  
  420.     if (event->event.eventType == MotionNotify)
  421.     return TRUE;
  422.     if (!(event->event.eventType == KeyPress ||
  423.       event->event.eventType == KeyRelease))
  424.     return FALSE;
  425.     dpy = event->xev->xany.display;
  426.     pd = _XtGetPerDisplay(dpy);
  427.     _InitializeKeysymTables(dpy, pd);
  428.     return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
  429. }
  430.  
  431.  
  432. static void XEventToTMEvent(event, tmEvent)
  433.     register XEvent *event;
  434.     register TMEventPtr tmEvent;
  435. {
  436.     tmEvent->xev = event;
  437.     tmEvent->event.eventCodeMask = 0;
  438.     tmEvent->event.modifierMask = 0;
  439.     tmEvent->event.eventType = event->type;
  440.     tmEvent->event.lateModifiers = NULL;
  441.     tmEvent->event.matchEvent = NULL;
  442.     tmEvent->event.standard = FALSE;
  443.  
  444.     switch (event->type) {
  445.  
  446.     case KeyPress:
  447.     case KeyRelease:
  448.             tmEvent->event.eventCode = event->xkey.keycode;
  449.         tmEvent->event.modifiers = event->xkey.state;
  450.         break;
  451.  
  452.     case ButtonPress:
  453.     case ButtonRelease:
  454.         tmEvent->event.eventCode = event->xbutton.button;
  455.         tmEvent->event.modifiers = event->xbutton.state;
  456.         break;
  457.  
  458.     case MotionNotify:
  459.         tmEvent->event.eventCode = event->xmotion.is_hint;
  460.         tmEvent->event.modifiers = event->xmotion.state;
  461.         break;
  462.  
  463.     case EnterNotify:
  464.     case LeaveNotify:
  465.         tmEvent->event.eventCode = event->xcrossing.mode;
  466.         tmEvent->event.modifiers = event->xcrossing.state;
  467.         break;
  468.  
  469.     case PropertyNotify:
  470.         tmEvent->event.eventCode = event->xproperty.atom;
  471.         tmEvent->event.modifiers = 0;
  472.         break;
  473.  
  474.     case SelectionClear:
  475.         tmEvent->event.eventCode = event->xselectionclear.selection;
  476.         tmEvent->event.modifiers = 0;
  477.         break;
  478.  
  479.     case SelectionRequest:
  480.         tmEvent->event.eventCode = event->xselectionrequest.selection;
  481.         tmEvent->event.modifiers = 0;
  482.         break;
  483.  
  484.     case SelectionNotify:
  485.         tmEvent->event.eventCode = event->xselection.selection;
  486.         tmEvent->event.modifiers = 0;
  487.         break;
  488.  
  489.     case ClientMessage:
  490.         tmEvent->event.eventCode = event->xclient.message_type;
  491.         tmEvent->event.modifiers = 0;
  492.         break;
  493.  
  494.     case MappingNotify:
  495.         tmEvent->event.eventCode = event->xmapping.request;
  496.         tmEvent->event.modifiers = 0;
  497.         break;
  498.  
  499.     case FocusIn:
  500.     case FocusOut:
  501.         tmEvent->event.eventCode = event->xfocus.mode;
  502.         tmEvent->event.modifiers = 0;
  503.         break;
  504.  
  505.     default:
  506.         tmEvent->event.eventCode = 0;
  507.         tmEvent->event.modifiers = 0;
  508.         break;
  509.     }
  510. }
  511.  
  512.  
  513. static unsigned long GetTime(tm, event)
  514.     XtTM tm;
  515.     register XEvent *event;
  516. {
  517.     switch (event->type) {
  518.  
  519.         case KeyPress:
  520.     case KeyRelease:
  521.         return event->xkey.time;
  522.  
  523.         case ButtonPress:
  524.     case ButtonRelease:
  525.         return event->xbutton.time;
  526.  
  527.     default:
  528.         return tm->lastEventTime;
  529.  
  530.     }
  531.  
  532. }
  533.  
  534. static void HandleActions(w, event, stateTree, accelWidget, procs, actions)
  535.     Widget        w;
  536.     XEvent        *event;
  537.     TMSimpleStateTree    stateTree;
  538.     Widget        accelWidget;
  539.     XtActionProc    *procs;
  540.     ActionRec        *actions;
  541. {
  542.     ActionHook         actionHookList;
  543.     Widget        bindWidget;
  544.  
  545.     bindWidget = accelWidget ? accelWidget : w;
  546.     if (!XtIsSensitive(bindWidget))
  547.       return;
  548.  
  549.     actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
  550.  
  551.     while (actions != NULL) {
  552.     /* perform any actions */
  553.     if (procs[actions->idx] != NULL) {
  554.         if (actionHookList) {
  555.         ActionHook hook;
  556.         String procName =
  557.             XrmQuarkToString(stateTree->quarkTbl[actions->idx] );
  558.         
  559.         for (hook = actionHookList; hook != NULL; hook = hook->next) {
  560.             (*hook->proc)(bindWidget,
  561.                   hook->closure,
  562.                   procName,
  563.                   event,
  564.                   actions->params,
  565.                   &actions->num_params
  566.                   );
  567.         }
  568.         }
  569.         (*(procs[actions->idx]))
  570.           (bindWidget, event, 
  571.            actions->params, &actions->num_params );
  572.     }
  573.     actions = actions->next;
  574.     }
  575. }
  576.  
  577. typedef struct {
  578.     unsigned int isCycleStart:1;
  579.     unsigned int isCycleEnd:1;
  580.     TMShortCard typeIndex;
  581.     TMShortCard modIndex;
  582. }MatchPairRec, *MatchPair;
  583.  
  584. typedef struct TMContextRec{
  585.     TMShortCard    numMatches;
  586.     TMShortCard    maxMatches;
  587.     MatchPair    matches;
  588. }TMContextRec, *TMContext;
  589.  
  590. static TMContextRec    contextCache[2];
  591.  
  592. #define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
  593.  
  594. #define TM_CONTEXT_MATCHES_ALLOC 4
  595. #define TM_CONTEXT_MATCHES_REALLOC 2
  596.  
  597. static void PushContext(contextPtr, newState)
  598.     TMContext    *contextPtr;
  599.     StatePtr    newState;
  600. {
  601.     TMContext         context = *contextPtr;
  602.     
  603.     if (context == NULL)
  604.       {
  605.       if (contextCache[0].numMatches == 0)
  606.         context = &contextCache[0];
  607.       else if (contextCache[1].numMatches == 0)
  608.         context = &contextCache[1];
  609.       if (!context)
  610.         {
  611.         context = XtNew(TMContextRec);
  612.         context->matches = NULL;
  613.         context->numMatches =
  614.           context->maxMatches = 0;
  615.         }
  616.       }
  617.     if (context->numMatches && 
  618.     context->matches[context->numMatches-1].isCycleEnd)
  619.       {
  620.       TMShortCard    i;
  621.       for (i = 0; 
  622.            i < context->numMatches &&
  623.            !(context->matches[i].isCycleStart);
  624.            i++){};
  625.       if (i < context->numMatches)
  626.         context->numMatches = i+1;
  627. #ifdef DEBUG
  628.       else
  629.         XtWarning("pushing cycle end with no cycle start");
  630. #endif /* DEBUG */      
  631.       }
  632.     else 
  633.       {
  634.       if (context->numMatches == context->maxMatches)
  635.         {
  636.         if (context->maxMatches == 0)
  637.           context->maxMatches += TM_CONTEXT_MATCHES_ALLOC;
  638.         else
  639.           context->maxMatches += TM_CONTEXT_MATCHES_REALLOC;
  640.         context->matches = (MatchPairRec *) 
  641.           XtRealloc((char *)context->matches,
  642.                 context->maxMatches * sizeof(MatchPairRec));
  643.         }
  644.       context->matches[context->numMatches].isCycleStart = newState->isCycleStart;
  645.       context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
  646.       context->matches[context->numMatches].typeIndex = newState->typeIndex;
  647.       context->matches[context->numMatches++].modIndex = newState->modIndex;
  648.       *contextPtr = context;
  649.       }
  650. }
  651. static void FreeContext(contextPtr)
  652.     TMContext    *contextPtr;
  653. {
  654.     TMContext         context = NULL;
  655.     
  656.     if (&contextCache[0] == *contextPtr)
  657.       context = &contextCache[0];
  658.     else if (&contextCache[1] == *contextPtr)
  659.       context = &contextCache[1];
  660.     if (context)
  661.       context->numMatches = 0;
  662.     else
  663.       XtFree((char *)*contextPtr);
  664.     
  665.     *contextPtr = NULL;
  666. }
  667.  
  668. static int MatchExact(stateTree, startIndex, typeIndex, modIndex) 
  669.     TMSimpleStateTree     stateTree;
  670.     int            startIndex;
  671.     TMShortCard        typeIndex, modIndex;
  672. {
  673.     register TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
  674.     register int i;
  675.  
  676.     for (i = startIndex;
  677.      i < (int)stateTree->numBranchHeads; 
  678.      i++, branchHead++)
  679.       {
  680.       if ((branchHead->typeIndex == typeIndex) &&
  681.           (branchHead->modIndex == modIndex))
  682.         return i;
  683.       }    
  684.     return (TM_NO_MATCH);
  685. }
  686.  
  687.  
  688.  
  689. static void HandleSimpleState(w, tmRecPtr, curEventPtr)
  690.     Widget    w;
  691.     XtTM    tmRecPtr;
  692.     TMEventRec    *curEventPtr;
  693. {  
  694.     XtTranslations    xlations = tmRecPtr->translations;
  695.     TMSimpleStateTree    stateTree;
  696.     TMContext        *contextPtr = GetContextPtr(tmRecPtr);
  697.     TMShortCard        i;
  698.     ActionRec        *actions;
  699.     Boolean        matchExact = False;
  700.     Boolean               match = False; 
  701.     StatePtr        complexMatchState = NULL;
  702.     int            currIndex;
  703.     TMShortCard        typeIndex, modIndex;
  704.     int            matchTreeIndex = TM_NO_MATCH;
  705.     
  706.     
  707.     stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0];
  708.     
  709.     for (i = 0; 
  710.      ((!match || !complexMatchState) && (i < xlations->numStateTrees));
  711.      i++){
  712.     stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
  713.     currIndex = -1;
  714.     /*
  715.      * don't process this tree if we're only looking for a
  716.      * complexMatchState and there are no complex states
  717.      */
  718.     while (!(match && stateTree->isSimple) &&
  719.            ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
  720.         currIndex++;
  721.         if (matchExact)
  722.           currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex);
  723.         else
  724.           currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr);
  725.         if (currIndex != TM_NO_MATCH) {
  726.         TMBranchHead branchHead;
  727.         StatePtr currState;
  728.         
  729.         branchHead = &stateTree->branchHeadTbl[currIndex];
  730.         if (branchHead->isSimple)
  731.           currState = NULL;
  732.         else
  733.           currState = ((TMComplexStateTree)stateTree)
  734.             ->complexBranchHeadTbl[TMBranchMore(branchHead)];
  735.         
  736.         /*
  737.          * first check for a complete match
  738.          */
  739.         if (!match) {
  740.             if (branchHead->hasActions) {
  741.             if (branchHead->isSimple) {
  742.                 static ActionRec    dummyAction;
  743.                 
  744.                 dummyAction.idx = TMBranchMore(branchHead);
  745.                 actions = &dummyAction;
  746.             }
  747.             else 
  748.               actions = currState->actions;
  749.             tmRecPtr->lastEventTime = 
  750.               GetTime(tmRecPtr, curEventPtr->xev);
  751.             FreeContext((TMContext
  752.                      *)&tmRecPtr->current_state);
  753.             match = True;
  754.             matchTreeIndex = i;
  755.             }
  756.             /* 
  757.              * if it doesn't have actions and
  758.              * it's bc mode then it's a potential match node that is
  759.              * used to match later sequences.
  760.              */
  761.             if (!TMNewMatchSemantics() && !matchExact) {
  762.             matchExact = True;
  763.             typeIndex = branchHead->typeIndex;
  764.             modIndex = branchHead->modIndex;
  765.             }
  766.         }
  767.         /*
  768.          * check for it being an event sequence which can be
  769.          * a future match 
  770.          */
  771.         if (!branchHead->isSimple &&
  772.             !branchHead->hasActions &&
  773.             !complexMatchState) 
  774.           complexMatchState = currState;
  775.         }
  776.     }
  777.     }
  778.     if (match)
  779.       {
  780.       TMBindData    bindData = (TMBindData) tmRecPtr->proc_table;
  781.       XtActionProc    *procs;
  782.       Widget    accelWidget;
  783.  
  784.       if (bindData->simple.isComplex) {
  785.           TMComplexBindProcs bindProcs =
  786.         TMGetComplexBindEntry(bindData, matchTreeIndex);
  787.           procs = bindProcs->procs;
  788.           accelWidget = bindProcs->widget;
  789.       }
  790.       else {
  791.           TMSimpleBindProcs bindProcs = 
  792.         TMGetSimpleBindEntry(bindData, matchTreeIndex);
  793.           procs = bindProcs->procs;
  794.           accelWidget = NULL;
  795.       }
  796.       HandleActions
  797.         (w, 
  798.          curEventPtr->xev, 
  799.          (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex],
  800.          accelWidget,
  801.          procs,
  802.          actions);
  803.       }
  804.     if (complexMatchState)
  805.       PushContext(contextPtr, complexMatchState);
  806. }
  807.  
  808. static int MatchComplexBranch(stateTree, startIndex, context, leafStateRtn)
  809.     TMComplexStateTree    stateTree;
  810.     int            startIndex;
  811.     TMContext        context;
  812.     StatePtr        *leafStateRtn;
  813. {
  814.     TMShortCard    i;
  815.  
  816.     for (i = startIndex; i < stateTree->numComplexBranchHeads; i++)
  817.       {
  818.       StatePtr    candState;
  819.       TMShortCard    numMatches = context->numMatches;
  820.       MatchPair    statMatch = context->matches;
  821.  
  822.       for (candState = stateTree->complexBranchHeadTbl[i];
  823.            numMatches && candState;
  824.            numMatches--, statMatch++, candState = candState->nextLevel)
  825.         {
  826.         if ((statMatch->typeIndex != candState->typeIndex) ||
  827.             (statMatch->modIndex != candState->modIndex))
  828.           break;
  829.         }
  830.       if (numMatches == 0) {
  831.           *leafStateRtn = candState;
  832.           return i;
  833.       }
  834.       }
  835.     *leafStateRtn = NULL;
  836.     return (TM_NO_MATCH);
  837. }
  838.  
  839. static StatePtr TryCurrentTree(stateTreePtr, tmRecPtr, curEventPtr)
  840.     TMComplexStateTree    *stateTreePtr;
  841.     XtTM        tmRecPtr;
  842.     TMEventRec        *curEventPtr;
  843. {
  844.     StatePtr        candState = NULL, matchState = NULL;
  845.     TMContext        *contextPtr = GetContextPtr(tmRecPtr);
  846.     TMTypeMatch     typeMatch;
  847.     TMModifierMatch     modMatch;
  848.     int            currIndex = -1;
  849.     
  850.     /*
  851.      * we want the first sequence that both matches and has actions.
  852.      * we keep on looking till we find both
  853.      */
  854.     while ((currIndex = 
  855.         MatchComplexBranch(*stateTreePtr,
  856.                    ++currIndex,
  857.                    (*contextPtr),
  858.                    &candState))
  859.        != TM_NO_MATCH) {
  860.     if (candState  != NULL) {
  861.         typeMatch  = TMGetTypeMatch(candState->typeIndex);
  862.         modMatch = TMGetModifierMatch(candState->modIndex);
  863.         
  864.         /* does this state's index match? --> done */
  865.         if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch))
  866.           {
  867.           if (candState->actions) {
  868.               return candState;
  869.           }
  870.           else
  871.             matchState = candState;
  872.           }
  873.         /* is this an event timer? */
  874.         if (typeMatch->eventType == _XtEventTimerEventType) {
  875.         StatePtr nextState = candState->nextLevel;
  876.         
  877.         /* does the succeeding state match? */
  878.         if (nextState != NULL) {
  879.             TMTypeMatch     nextTypeMatch;
  880.             TMModifierMatch    nextModMatch;
  881.             
  882.             nextTypeMatch  = TMGetTypeMatch(nextState->typeIndex);
  883.             nextModMatch = TMGetModifierMatch(nextState->modIndex);
  884.             
  885.             /* is it within the timeout? */
  886.             if (MatchIncomingEvent(curEventPtr, 
  887.                        nextTypeMatch, 
  888.                        nextModMatch)) {
  889.             XEvent *xev = curEventPtr->xev;
  890.             unsigned long time = GetTime(tmRecPtr, xev);
  891.             XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
  892.             unsigned long delta = pd->multi_click_time;
  893.             
  894.             if ((tmRecPtr->lastEventTime + delta) >= time) {
  895.                 if (nextState->actions) {
  896.                 return candState;
  897.                 }
  898.                 else
  899.                   matchState = candState;
  900.             }
  901.             }
  902.         }
  903.         }
  904.     }
  905.     }
  906.     return matchState;
  907. }
  908.  
  909. static void HandleComplexState(w, tmRecPtr, curEventPtr)
  910.     Widget    w;
  911.     XtTM    tmRecPtr;
  912.     TMEventRec    *curEventPtr;
  913. {
  914.     XtTranslations     xlations = tmRecPtr->translations;
  915.     TMContext        *contextPtr = GetContextPtr(tmRecPtr);
  916.     TMShortCard        i, matchTreeIndex;
  917.     StatePtr        matchState = NULL, candState;
  918.     TMComplexStateTree     *stateTreePtr = 
  919.       (TMComplexStateTree *)&xlations->stateTreeTbl[0];
  920.     
  921.     for (i = 0;
  922.      i < xlations->numStateTrees;
  923.      i++, stateTreePtr++) {
  924.     /* 
  925.      * some compilers sign extend Boolean bit fields so test for
  926.      * false |||
  927.      */
  928.     if (((*stateTreePtr)->isSimple == False) &&
  929.         (candState = TryCurrentTree(stateTreePtr,
  930.                        tmRecPtr,
  931.                        curEventPtr))) {
  932.         matchTreeIndex = i;
  933.         matchState = candState;
  934.         if (candState->actions)
  935.           break;
  936.     }
  937.     }
  938.     if (matchState == NULL){
  939.     /* couldn't find it... */
  940.     if (!Ignore(curEventPtr))
  941.       {
  942.           FreeContext(contextPtr);
  943.           HandleSimpleState(w, tmRecPtr, curEventPtr);
  944.       }
  945.     }
  946.     else {
  947.     TMBindData    bindData = (TMBindData) tmRecPtr->proc_table;
  948.     XtActionProc    *procs;
  949.     Widget        accelWidget;
  950.     TMTypeMatch     typeMatch;
  951.     
  952.     typeMatch  = TMGetTypeMatch(matchState->typeIndex);
  953.  
  954.     PushContext(contextPtr, matchState);
  955.     if (typeMatch->eventType == _XtEventTimerEventType) {
  956.         matchState = matchState->nextLevel;
  957.         PushContext(contextPtr, matchState);
  958.     }
  959.     tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev);
  960.  
  961.     if (bindData->simple.isComplex) {
  962.         TMComplexBindProcs bindProcs =
  963.           TMGetComplexBindEntry(bindData, matchTreeIndex);
  964.         procs = bindProcs->procs;
  965.         accelWidget = bindProcs->widget;
  966.     }
  967.     else {
  968.         TMSimpleBindProcs bindProcs = 
  969.           TMGetSimpleBindEntry(bindData, matchTreeIndex);
  970.         procs = bindProcs->procs;
  971.         accelWidget = NULL;
  972.     }
  973.     HandleActions(w, 
  974.               curEventPtr->xev, 
  975.               (TMSimpleStateTree)
  976.               xlations->stateTreeTbl[matchTreeIndex],
  977.               accelWidget,
  978.               procs,
  979.               matchState->actions);
  980.     }
  981. }
  982.  
  983.  
  984. void _XtTranslateEvent (w, event)
  985.     Widget w;
  986.     register    XEvent * event;
  987. {
  988.     XtTM    tmRecPtr = &w->core.tm;
  989.     TMEventRec     curEvent;
  990.     StatePtr     current_state = tmRecPtr->current_state;
  991.  
  992.     XEventToTMEvent (event, &curEvent);
  993.     
  994.     if (! tmRecPtr->translations) {
  995.         XtAppWarningMsg(XtWidgetToApplicationContext(w),
  996.             XtNtranslationError,"nullTable",XtCXtToolkitError,
  997.             "Can't translate event through NULL table",
  998.             (String *)NULL, (Cardinal *)NULL);
  999.     return ;
  1000.     }
  1001.     if (current_state == NULL)
  1002.       HandleSimpleState(w, tmRecPtr, &curEvent);
  1003.     else
  1004.       HandleComplexState(w, tmRecPtr, &curEvent);
  1005. }
  1006.  
  1007.  
  1008. /*ARGSUSED*/
  1009. static StatePtr NewState(stateTree, typeIndex, modIndex)
  1010.     TMParseStateTree stateTree;
  1011.     TMShortCard    typeIndex, modIndex;
  1012. {
  1013.     register StatePtr state = XtNew(StateRec);
  1014.  
  1015. #ifdef TRACE_TM
  1016.     _XtGlobalTM.numComplexStates++;
  1017. #endif /* TRACE_TM */
  1018.     state->typeIndex = typeIndex;
  1019.     state->modIndex = modIndex;
  1020.     state->nextLevel = NULL;
  1021.     state->actions = NULL;
  1022.     state->isCycleStart = state->isCycleEnd = False;
  1023.     return state;
  1024. }
  1025.  
  1026. /*
  1027.  * This routine is an iterator for state trees. If the func returns
  1028.  * true then iteration is over.
  1029.  */
  1030. void _XtTraverseStateTree(tree, func, data)
  1031.     TMStateTree    tree;
  1032.     _XtTraversalProc func;
  1033.     XtPointer     data;
  1034. {
  1035.     register     TMComplexStateTree stateTree = (TMComplexStateTree)tree;
  1036.     TMBranchHead    currBH;
  1037.     TMShortCard        i;
  1038.     StateRec        dummyStateRec, *dummyState = &dummyStateRec;
  1039.     ActionRec        dummyActionRec, *dummyAction = &dummyActionRec;
  1040.     Boolean        firstSimple = True;
  1041.     StatePtr         currState;
  1042.  
  1043.     /* first traverse the complex states */
  1044.     if (stateTree->isSimple == False)
  1045.       for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
  1046.       currState = stateTree->complexBranchHeadTbl[i];
  1047.       for (; currState; currState = currState->nextLevel) {
  1048.           if (func(currState, data))
  1049.         return;
  1050.           if (currState->isCycleEnd) 
  1051.         break;
  1052.       }
  1053.       }
  1054.  
  1055.     /* now traverse the simple ones */
  1056.     for (i = 0, currBH = stateTree->branchHeadTbl;
  1057.      i < stateTree->numBranchHeads;
  1058.      i++, currBH++)
  1059.       {
  1060.       if (currBH->isSimple && currBH->hasActions)
  1061.         {
  1062.         if (firstSimple)
  1063.           {
  1064.               XtBZero((char *) dummyState, sizeof(StateRec));
  1065.               XtBZero((char *) dummyAction, sizeof(ActionRec));
  1066.               dummyState->actions = dummyAction;
  1067.               firstSimple = False;
  1068.           }
  1069.         dummyState->typeIndex = currBH->typeIndex;
  1070.         dummyState->modIndex = currBH->modIndex;
  1071.         dummyAction->idx = currBH->more;
  1072.         if (func(dummyState, data))
  1073.           return;
  1074.         }
  1075.       }
  1076. }
  1077.  
  1078. static EventMask EventToMask(typeMatch, modMatch)
  1079.     register TMTypeMatch     typeMatch;
  1080.     register TMModifierMatch modMatch;
  1081. {
  1082.     EventMask returnMask;
  1083.     unsigned long eventType = typeMatch->eventType;
  1084.  
  1085.     if (eventType == MotionNotify) {
  1086.         Modifiers modifierMask = modMatch->modifierMask;
  1087.         Modifiers tempMask;
  1088.  
  1089.     returnMask = 0;
  1090.         if (modifierMask == 0) {
  1091.         if (modMatch->modifiers == AnyButtonMask)
  1092.         return ButtonMotionMask;
  1093.         else
  1094.         return PointerMotionMask;
  1095.     }
  1096.         tempMask = modifierMask &
  1097.         (Button1Mask | Button2Mask | Button3Mask
  1098.          | Button4Mask | Button5Mask);
  1099.         if (tempMask == 0)
  1100.         return PointerMotionMask;
  1101.         if (tempMask & Button1Mask)
  1102.             returnMask |= Button1MotionMask;
  1103.         if (tempMask & Button2Mask)
  1104.             returnMask |= Button2MotionMask;
  1105.         if (tempMask & Button3Mask)
  1106.             returnMask |= Button3MotionMask;
  1107.         if (tempMask & Button4Mask)
  1108.             returnMask |= Button4MotionMask;
  1109.         if (tempMask & Button5Mask)
  1110.             returnMask |= Button5MotionMask;
  1111.         return returnMask;
  1112.     }
  1113.     returnMask = _XtConvertTypeToMask(eventType);
  1114.     if (returnMask == (StructureNotifyMask|SubstructureNotifyMask))
  1115.     returnMask = StructureNotifyMask;
  1116.     return returnMask;
  1117. }
  1118.  
  1119. /*ARGSUSED*/
  1120. static void DispatchMappingNotify(widget, closure, call_data)
  1121.     Widget widget;        /* will be NULL from _RefreshMapping */
  1122.     XtPointer closure;        /* real Widget */
  1123.     XtPointer call_data;    /* XEvent* */
  1124. {
  1125.     _XtTranslateEvent( (Widget)closure, (XEvent*)call_data);
  1126. }
  1127.  
  1128.   
  1129. /*ARGSUSED*/
  1130. static void RemoveFromMappingCallbacks(widget, closure, call_data)
  1131.     Widget widget;
  1132.     XtPointer closure;        /* target widget */
  1133.     XtPointer call_data;
  1134. {
  1135.     _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
  1136.                DispatchMappingNotify,
  1137.                closure
  1138.               );
  1139. }
  1140.  
  1141. static Boolean AggregateEventMask(state, data)
  1142.     StatePtr    state;
  1143.     XtPointer    data;
  1144. {
  1145.     *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex), 
  1146.                     TMGetModifierMatch(state->modIndex));
  1147.    return False;
  1148. }    
  1149.  
  1150. void _XtInstallTranslations(widget)
  1151.     Widget widget;
  1152. {
  1153.     XtTranslations xlations;
  1154.     register Cardinal    i;
  1155.     TMStateTree    stateTree;
  1156.     Boolean  mappingNotifyInterest = False;
  1157.  
  1158.     xlations = widget->core.tm.translations;
  1159.     if (xlations == NULL) return;
  1160.     
  1161.     /*
  1162.      * check for somebody stuffing the translations directly into the
  1163.      * instance structure. We will end up being called again out of
  1164.      * ComposeTranslations but we *should* have bindings by then
  1165.      */
  1166.     if (widget->core.tm.proc_table == NULL) {
  1167.     _XtMergeTranslations(widget, NULL, XtTableReplace);
  1168.     /* 
  1169.      * if we're realized then we'll be called out of
  1170.      * ComposeTranslations 
  1171.      */
  1172.     if (XtIsRealized(widget))
  1173.       return;
  1174.     }
  1175.  
  1176.     xlations->eventMask = 0;
  1177.     for (i = 0;
  1178.      i < xlations->numStateTrees;
  1179.      i++)
  1180.       {
  1181.       stateTree = xlations->stateTreeTbl[i];
  1182.       _XtTraverseStateTree(stateTree,
  1183.                 AggregateEventMask, 
  1184.                 (XtPointer)&xlations->eventMask);
  1185.       mappingNotifyInterest |= stateTree->simple.mappingNotifyInterest;
  1186.       }
  1187.     /* double click needs to make sure that you have selected on both
  1188.     button down and up. */
  1189.  
  1190.     if (xlations->eventMask & ButtonPressMask)
  1191.       xlations->eventMask |= ButtonReleaseMask;
  1192.     if (xlations->eventMask & ButtonReleaseMask)
  1193.       xlations->eventMask |= ButtonPressMask;
  1194.  
  1195.     if (mappingNotifyInterest) {
  1196.     XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
  1197.     if (pd->mapping_callbacks)
  1198.         _XtAddCallbackOnce(&(pd->mapping_callbacks),
  1199.                    DispatchMappingNotify,
  1200.                    (XtPointer)widget);
  1201.     else
  1202.         _XtAddCallback(&(pd->mapping_callbacks),
  1203.                DispatchMappingNotify,
  1204.                (XtPointer)widget);
  1205.  
  1206.     if (widget->core.destroy_callbacks != NULL)
  1207.         _XtAddCallbackOnce( (InternalCallbackList *)
  1208.                     &widget->core.destroy_callbacks,
  1209.                 RemoveFromMappingCallbacks,
  1210.                 (XtPointer)widget
  1211.                    );
  1212.     else
  1213.         _XtAddCallback((InternalCallbackList *)
  1214.                &widget->core.destroy_callbacks,
  1215.                RemoveFromMappingCallbacks,
  1216.                (XtPointer)widget
  1217.               );
  1218.     }
  1219.     _XtBindActions(widget, (XtTM)&widget->core.tm);
  1220.     _XtRegisterGrabs(widget);
  1221. }
  1222.  
  1223. void _XtRemoveTranslations(widget)
  1224.     Widget widget;
  1225. {
  1226.     register Cardinal    i;
  1227.     TMSimpleStateTree    stateTree;
  1228.     Boolean          mappingNotifyInterest = False;
  1229.     XtTranslations        xlations = widget->core.tm.translations;
  1230.     
  1231.     if (xlations == NULL) 
  1232.       return;
  1233.  
  1234.     for (i = 0;
  1235.      i < xlations->numStateTrees;
  1236.      i++)
  1237.       {
  1238.       stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
  1239.       mappingNotifyInterest |= stateTree->mappingNotifyInterest;
  1240.       }
  1241.     if (mappingNotifyInterest)
  1242.       RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL);
  1243. }
  1244.  
  1245. static void _XtUninstallTranslations(widget)
  1246.     Widget widget;
  1247. {
  1248.     XtTranslations    xlations = widget->core.tm.translations;
  1249.  
  1250.     _XtUnbindActions(widget, 
  1251.              xlations, 
  1252.              (TMBindData)widget->core.tm.proc_table);
  1253.     _XtRemoveTranslations(widget);
  1254.     widget->core.tm.translations = NULL;
  1255.     FreeContext((TMContext *)&widget->core.tm.current_state);
  1256. }
  1257.  
  1258. void _XtDestroyTMData(widget)
  1259.     Widget    widget;
  1260. {
  1261.     TMComplexBindData    cBindData;
  1262.  
  1263.     _XtUninstallTranslations(widget);
  1264.  
  1265.     if (cBindData = (TMComplexBindData)widget->core.tm.proc_table) {
  1266.     if (cBindData->isComplex) {
  1267.         ATranslations    aXlations, nXlations;
  1268.         
  1269.         nXlations = (ATranslations) cBindData->accel_context;
  1270.         while (nXlations){
  1271.         aXlations = nXlations;
  1272.         nXlations = nXlations->next;
  1273.         XtFree((char *)aXlations);
  1274.         }
  1275.     }
  1276.     XtFree((char *)cBindData);
  1277.     }
  1278. }
  1279.  
  1280. /*** Public procedures ***/
  1281.  
  1282.  
  1283. void XtUninstallTranslations(widget)
  1284.     Widget widget;
  1285. {
  1286.     EventMask    oldMask;
  1287.  
  1288.     if (! widget->core.tm.translations)
  1289.     return;
  1290.     oldMask = widget->core.tm.translations->eventMask;
  1291.     _XtUninstallTranslations(widget);
  1292.     if (XtIsRealized(widget) && oldMask)
  1293.     XSelectInput(XtDisplay(widget), XtWindow(widget), 
  1294.              XtBuildEventMask(widget));
  1295. }
  1296.  
  1297. #if NeedFunctionPrototypes
  1298. XtTranslations _XtCreateXlations(
  1299.     TMStateTree        *stateTrees,
  1300.     TMShortCard        numStateTrees,
  1301.     XtTranslations    first,
  1302.     XtTranslations    second)
  1303. #else
  1304. XtTranslations _XtCreateXlations(stateTrees, numStateTrees, first, second)
  1305.     TMStateTree        *stateTrees;
  1306.     TMShortCard        numStateTrees;
  1307.     XtTranslations    first, second;
  1308. #endif
  1309. {
  1310.     register XtTranslations    xlations;
  1311.     TMShortCard i;
  1312.  
  1313.     xlations = (XtTranslations)
  1314.       XtMalloc(sizeof(TranslationData) +
  1315.            (numStateTrees-1) * sizeof(TMStateTree));
  1316. #ifdef TRACE_TM
  1317.     if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
  1318.     _XtGlobalTM.tmTblSize += 16;
  1319.     _XtGlobalTM.tmTbl = (XtTranslations *)
  1320.       XtRealloc((char *)_XtGlobalTM.tmTbl,
  1321.            _XtGlobalTM.tmTblSize * sizeof(XtTranslations));
  1322.     }
  1323.     _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
  1324. #endif /* TRACE_TM */
  1325.  
  1326.     xlations->composers[0] = first;
  1327.     xlations->composers[1] = second;
  1328.     xlations->hasBindings = False;
  1329.     xlations->operation = XtTableReplace;
  1330.  
  1331.     for (i = 0;i < numStateTrees; i++)
  1332.       {
  1333.       xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
  1334.       stateTrees[i]->simple.refCount++;
  1335.       }
  1336.     xlations->numStateTrees = numStateTrees;
  1337.     xlations->eventMask = 0;
  1338.     return xlations;
  1339. }
  1340.  
  1341. TMStateTree _XtParseTreeToStateTree(parseTree)
  1342.     TMParseStateTree    parseTree;
  1343. {
  1344.     register TMSimpleStateTree  simpleTree;
  1345.     register unsigned int    tableSize;
  1346.  
  1347.     if (parseTree->numComplexBranchHeads) {
  1348.     register TMComplexStateTree complexTree;
  1349.  
  1350.     complexTree = XtNew(TMComplexStateTreeRec);
  1351.     complexTree->isSimple = False;
  1352.     tableSize = parseTree->numComplexBranchHeads * sizeof(StatePtr); 
  1353.     complexTree->complexBranchHeadTbl = (StatePtr *)
  1354.       XtMalloc(tableSize);
  1355.     XtBCopy(parseTree->complexBranchHeadTbl,
  1356.         complexTree->complexBranchHeadTbl,
  1357.         tableSize);
  1358.     complexTree->numComplexBranchHeads = 
  1359.       parseTree->numComplexBranchHeads;
  1360.     simpleTree = (TMSimpleStateTree)complexTree;
  1361.     }
  1362.     else {
  1363.     simpleTree = XtNew(TMSimpleStateTreeRec);
  1364.     simpleTree->isSimple = True;
  1365.     }
  1366.     simpleTree->isAccelerator = parseTree->isAccelerator;
  1367.     simpleTree->refCount = 0;
  1368.     simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
  1369.  
  1370.     tableSize = parseTree->numBranchHeads * sizeof(TMBranchHeadRec);
  1371.     simpleTree->branchHeadTbl = (TMBranchHead)
  1372.       XtMalloc(tableSize);
  1373.     XtBCopy(parseTree->branchHeadTbl, simpleTree->branchHeadTbl, tableSize);
  1374.     simpleTree->numBranchHeads = parseTree->numBranchHeads;
  1375.  
  1376.     tableSize = parseTree->numQuarks * sizeof(XrmQuark);
  1377.     simpleTree->quarkTbl = (XrmQuark *) XtMalloc(tableSize);
  1378.     XtBCopy(parseTree->quarkTbl, simpleTree->quarkTbl, tableSize);
  1379.     simpleTree->numQuarks = parseTree->numQuarks;
  1380.  
  1381.     return (TMStateTree)simpleTree;
  1382. }
  1383.  
  1384. static void FreeActions(actions)
  1385.     ActionPtr    actions;
  1386. {
  1387.     register ActionPtr action;
  1388.     register TMShortCard i;
  1389.     for (action = actions; action;) {
  1390.     ActionPtr nextAction = action->next;
  1391.     for (i = action->num_params; i;) {
  1392.         XtFree( action->params[--i] );
  1393.     }
  1394.     XtFree( (char*)action->params );
  1395.     XtFree((char*) action);
  1396.     action = nextAction;
  1397.     }
  1398. }
  1399.  
  1400. /*ARGSUSED*/
  1401. static void AmbigActions(initialEvent, state, stateTree)
  1402.     EventSeqPtr    initialEvent;
  1403.     StatePtr    *state;
  1404.     TMParseStateTree stateTree;
  1405. {
  1406.     String     params[3];
  1407.     Cardinal     numParams = 0;
  1408.  
  1409.     params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
  1410.     params[numParams++] = _XtPrintActions((*state)->actions,
  1411.                       stateTree->quarkTbl);
  1412.     XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError,
  1413.           "Previous entry was: %s %s", params, &numParams);
  1414.     XtFree((char *)params[0]);
  1415.     XtFree((char *)params[1]);
  1416.     numParams = 0;
  1417.     params[numParams++]  = _XtPrintActions(initialEvent->actions,
  1418.                        stateTree->quarkTbl);
  1419.     XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError,
  1420.           "New actions are:%s", params, &numParams);
  1421.     XtFree((char *)params[0]);
  1422.     XtWarningMsg (XtNtranslationError,"ambiguousActions", 
  1423.           XtCXtToolkitError,
  1424.           "Overriding earlier translation manager actions.",
  1425.           (String *)NULL, (Cardinal *)NULL);
  1426.  
  1427.     FreeActions((*state)->actions);
  1428.     (*state)->actions = NULL;
  1429. }
  1430.  
  1431.  
  1432. void _XtAddEventSeqToStateTree(eventSeq, stateTree)
  1433.     register EventSeqPtr     eventSeq;
  1434.     TMParseStateTree        stateTree;
  1435. {
  1436.     register StatePtr        *state;
  1437.     EventSeqPtr            initialEvent = eventSeq;
  1438.     TMBranchHead        branchHead;
  1439.     TMShortCard            idx, modIndex, typeIndex;
  1440.  
  1441.     if (eventSeq == NULL) return;
  1442.  
  1443.     /* note that all states in the event seq passed in start out null */
  1444.     /* we fill them in with the matching state as we traverse the list */
  1445.  
  1446.     /*
  1447.      * We need to free the parser data structures !!!
  1448.      */
  1449.  
  1450.     typeIndex = _XtGetTypeIndex(&eventSeq->event);
  1451.     modIndex = _XtGetModifierIndex(&eventSeq->event);
  1452.     idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
  1453.     branchHead = &stateTree->branchHeadTbl[idx];
  1454.  
  1455.     /*
  1456.      * Need to check for pre-existing actions with same lhs |||
  1457.      */
  1458.     
  1459.     /*
  1460.      * Check for optimized case. Don't assume that the eventSeq has actions.
  1461.      */
  1462.     if (!eventSeq->next && 
  1463.      eventSeq->actions && 
  1464.     !eventSeq->actions->next && 
  1465.     !eventSeq->actions->num_params)
  1466.       {
  1467.       if (eventSeq->event.eventType == MappingNotify)
  1468.         stateTree->mappingNotifyInterest = True;
  1469.       branchHead->hasActions = True;
  1470.       branchHead->more = eventSeq->actions->idx;
  1471.       FreeActions(eventSeq->actions);
  1472.       eventSeq->actions = NULL;
  1473.       return;
  1474.       }
  1475.     
  1476.     branchHead->isSimple = False;
  1477.     if (!eventSeq->next)
  1478.       branchHead->hasActions = True;
  1479.     branchHead->more = GetComplexBranchIndex(stateTree, typeIndex, modIndex);
  1480.     state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
  1481.     
  1482.     for (;;) {
  1483.     *state = NewState(stateTree, typeIndex, modIndex);
  1484.     
  1485.     if (eventSeq->event.eventType == MappingNotify)
  1486.         stateTree->mappingNotifyInterest = True;
  1487.     
  1488.     /* *state now points at state record matching event */
  1489.     eventSeq->state = *state;
  1490.     
  1491.     if (eventSeq->actions != NULL) {
  1492.         if ((*state)->actions != NULL)
  1493.           AmbigActions(initialEvent, state, stateTree);
  1494.         (*state)->actions = eventSeq->actions;
  1495. #ifdef TRACE_TM
  1496.         _XtGlobalTM.numComplexActions++;
  1497. #endif /* TRACE_TM */
  1498.     }
  1499.  
  1500.     if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
  1501.       break;
  1502.  
  1503.     state = &(*state)->nextLevel;
  1504.     typeIndex = _XtGetTypeIndex(&eventSeq->event);
  1505.     modIndex = _XtGetModifierIndex(&eventSeq->event);
  1506.     if (!TMNewMatchSemantics()) {
  1507.         /* 
  1508.          * force a potential empty entry into the branch head
  1509.          * table in order to emulate old matching behavior
  1510.          */
  1511.         (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
  1512.     }
  1513.     }
  1514.  
  1515.     if (eventSeq && eventSeq->state) {
  1516.     /* we've been here before... must be a cycle in the event seq. */
  1517.     branchHead->hasCycles = True;
  1518.     (*state)->nextLevel = eventSeq->state;
  1519.     eventSeq->state->isCycleStart = True;
  1520.     (*state)->isCycleEnd = TRUE;
  1521.     }
  1522. }
  1523.  
  1524.  
  1525. /*
  1526.  * Internal Converter for merging. Old and New must both be valid xlations
  1527.  */
  1528.  
  1529. /*ARGSUSED*/
  1530. Boolean _XtCvtMergeTranslations(dpy, args, num_args, from, to, closure_ret)
  1531.     Display    *dpy;
  1532.     XrmValuePtr args;
  1533.     Cardinal    *num_args;
  1534.     XrmValuePtr from,to;
  1535.     XtPointer    *closure_ret;
  1536. {
  1537.     XtTranslations     first, second, xlations;
  1538.     TMStateTree        *stateTrees, stackStateTrees[16];
  1539.     TMShortCard        numStateTrees, i;
  1540.  
  1541.     if (*num_args != 0)
  1542.     XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError,
  1543.              "MergeTM to TranslationTable needs no extra arguments",
  1544.                (String *)NULL, (Cardinal *)NULL);
  1545.  
  1546.     if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
  1547.     to->size = sizeof(XtTranslations);
  1548.     return False;
  1549.     }
  1550.     
  1551.     first = ((TMConvertRec*)from->addr)->old;
  1552.     second = ((TMConvertRec*)from->addr)->new;
  1553.  
  1554.     numStateTrees = first->numStateTrees + second->numStateTrees;
  1555.  
  1556.     stateTrees = (TMStateTree *)
  1557.       XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
  1558.  
  1559.     for (i = 0; i < first->numStateTrees; i++)
  1560.       stateTrees[i] = first->stateTreeTbl[i];
  1561.     for (i = 0; i < second->numStateTrees; i++)
  1562.       stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
  1563.  
  1564.     xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
  1565.  
  1566.     if (to->addr != NULL) {
  1567.     *(XtTranslations*)to->addr = xlations;
  1568.     }
  1569.     else {
  1570.     static XtTranslations staticStateTable;
  1571.     staticStateTable = xlations;
  1572.     to->addr= (XPointer)&staticStateTable;
  1573.     to->size = sizeof(XtTranslations);
  1574.     }
  1575.  
  1576.     XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees);
  1577.     return True;
  1578. }
  1579.  
  1580.  
  1581. static XtTranslations MergeThem(dest, first, second)
  1582.     Widget        dest;    
  1583.     XtTranslations    first, second;
  1584. {
  1585.     XtCacheRef         cache_ref;
  1586.     static XrmQuark     from_type = NULLQUARK, to_type;
  1587.     XrmValue         from, to;
  1588.     TMConvertRec     convert_rec;
  1589.     XtTranslations    newTable;
  1590.  
  1591.     if (from_type == NULLQUARK) {
  1592.     from_type = XrmPermStringToQuark(_XtRStateTablePair);
  1593.     to_type = XrmPermStringToQuark(XtRTranslationTable);
  1594.     }
  1595.     from.addr = (XPointer)&convert_rec;
  1596.     from.size = sizeof(TMConvertRec);
  1597.     to.addr = (XPointer)&newTable;
  1598.     to.size = sizeof(XtTranslations);
  1599.     convert_rec.old = first;
  1600.     convert_rec.new = second;
  1601.  
  1602.     if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref))
  1603.     return NULL;
  1604.     if (cache_ref)
  1605.     XtAddCallback(dest, XtNdestroyCallback,
  1606.               XtCallbackReleaseCacheRef, (XtPointer)cache_ref);
  1607.     return newTable;
  1608. }
  1609.  
  1610. /*
  1611.  * Unmerge will recursively traverse the xlation compose tree and
  1612.  * generate a new xlation that is the result of all instances of
  1613.  * xlations being removed. It currently doesn't differentiate between
  1614.  * the potential that an xlation will be both an accelerator and
  1615.  * normal. This is not supported by the spec anyway.
  1616.  */
  1617. static XtTranslations UnmergeTranslations(widget, xlations, unmergeXlations, 
  1618.                       currIndex,
  1619.                       oldBindings, numOldBindings,
  1620.                       newBindings, numNewBindingsRtn)
  1621.     Widget        widget;
  1622.     XtTranslations    xlations, unmergeXlations;
  1623.     TMComplexBindProcs    oldBindings, newBindings;
  1624.     TMShortCard        currIndex, numOldBindings, *numNewBindingsRtn;
  1625.  
  1626. {
  1627.     XtTranslations first, second, result;
  1628.     
  1629.     if (!xlations || (xlations == unmergeXlations))
  1630.       return NULL;
  1631.     
  1632.     if (xlations->composers[0]) {
  1633.     first = UnmergeTranslations(widget, xlations->composers[0],
  1634.                     unmergeXlations,  currIndex,
  1635.                     oldBindings, numOldBindings,
  1636.                     newBindings, numNewBindingsRtn);
  1637.     }
  1638.     else
  1639.       first = NULL;
  1640.     
  1641.     if (xlations->composers[1]) {
  1642.     second = UnmergeTranslations(widget, xlations->composers[1],
  1643.                      unmergeXlations,  
  1644.                      currIndex + 
  1645.                      xlations->composers[0]->numStateTrees,
  1646.                      oldBindings, numOldBindings,
  1647.                      newBindings, numNewBindingsRtn);
  1648.     }
  1649.     else
  1650.       second = NULL;
  1651.  
  1652.     if (first || second) {
  1653.     if (first && second) {
  1654.         if ((first != xlations->composers[0]) ||
  1655.         (second != xlations->composers[1]))
  1656.           result = MergeThem(widget, first, second);
  1657.         else result = xlations;
  1658.     }
  1659.     else {
  1660.         if (first)
  1661.           result = first;
  1662.         else
  1663.           result = second;
  1664.     }
  1665.     } else { /* only update for leaf nodes */
  1666.       if (numOldBindings) {
  1667.          Cardinal    i;
  1668.          for (i = 0; i < xlations->numStateTrees; i++) {
  1669.          if (xlations->stateTreeTbl[i]->simple.isAccelerator)
  1670.             newBindings[*numNewBindingsRtn] =
  1671.             oldBindings[currIndex + i];
  1672.          (*numNewBindingsRtn)++;
  1673.         }
  1674.     }
  1675.     result = xlations;
  1676.     }
  1677.     return result;
  1678. }
  1679.  
  1680. typedef struct {
  1681.     XtTranslations xlations;
  1682.     TMComplexBindProcs bindings;
  1683. }MergeBindRec, *MergeBind;
  1684.  
  1685. static XtTranslations MergeTranslations(widget, oldXlations, newXlations, 
  1686.                     operation, source, oldBindings, 
  1687.                     newBindings, numNewRtn)
  1688.     Widget        widget;
  1689.     XtTranslations    oldXlations, newXlations;
  1690.     _XtTranslateOp    operation;
  1691.     TMComplexBindProcs    oldBindings, newBindings;
  1692.     Widget        source;
  1693.     TMShortCard        *numNewRtn;
  1694. {
  1695.     XtTranslations      newTable, xlations;
  1696.     TMComplexBindProcs    bindings;
  1697.     TMShortCard        i, j;
  1698.     TMStateTree     *treePtr;
  1699.     TMShortCard        numNew = *numNewRtn;
  1700.     MergeBindRec    bindPair[2];
  1701.  
  1702.     /* If the new translation has an accelerator context then pull it
  1703.      * off and pass it and the real xlations in to the caching merge
  1704.      * routine. 
  1705.      */
  1706.     if (newXlations->hasBindings) {
  1707.     xlations = ((ATranslations) newXlations)->xlations;
  1708.     bindings = (TMComplexBindProcs)
  1709.         &((ATranslations) newXlations)->bindTbl[0];
  1710.     }
  1711.     else {
  1712.     xlations = newXlations;
  1713.     bindings = NULL;
  1714.     }
  1715.     switch(operation) {
  1716.       case XtTableReplace:
  1717.     newTable = bindPair[0].xlations = xlations;
  1718.     bindPair[0].bindings = bindings;
  1719.     bindPair[1].xlations = NULL;
  1720.     bindPair[1].bindings = NULL;
  1721.     break;
  1722.       case XtTableAugment:
  1723.     bindPair[0].xlations = oldXlations;
  1724.     bindPair[0].bindings = oldBindings;
  1725.     bindPair[1].xlations = xlations;
  1726.     bindPair[1].bindings = bindings;
  1727.     newTable = NULL;
  1728.     break;
  1729.       case XtTableOverride:
  1730.     bindPair[0].xlations = xlations;
  1731.     bindPair[0].bindings = bindings;
  1732.     bindPair[1].xlations = oldXlations;
  1733.     bindPair[1].bindings = oldBindings;
  1734.     newTable = NULL;
  1735.     break;
  1736.     }
  1737.     if (!newTable)
  1738.       newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
  1739.     
  1740.     for (i = 0, numNew = 0; i < 2; i++) {
  1741.     if (bindPair[i].xlations)
  1742.       for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
  1743.           if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
  1744.           if (bindPair[i].bindings)
  1745.             newBindings[numNew] = bindPair[i].bindings[j];
  1746.           else {
  1747.               newBindings[numNew].widget = source;
  1748.               newBindings[numNew].aXlations = 
  1749.             bindPair[i].xlations;
  1750.           }
  1751.         }
  1752.       }
  1753.     }
  1754.     *numNewRtn = numNew;
  1755.     treePtr = &newTable->stateTreeTbl[0];
  1756.     for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
  1757.       (*treePtr)->simple.refCount++;
  1758.     return newTable;
  1759. }
  1760.  
  1761. static TMBindData MakeBindData(bindings, numBindings, oldBindData)
  1762.     TMComplexBindProcs    bindings;
  1763.     TMShortCard        numBindings;
  1764.     TMBindData        oldBindData;
  1765. {
  1766.     TMLongCard        bytes;
  1767.     TMShortCard        i;
  1768.     Boolean        isComplex;
  1769.     TMBindData        bindData;
  1770.  
  1771.     if (numBindings == 0) 
  1772.       return NULL;
  1773.     for (i = 0; i < numBindings; i++)
  1774.       if (bindings[i].widget)
  1775.     break;
  1776.     isComplex = (i < numBindings);
  1777.     if (isComplex)
  1778.       bytes = (sizeof(TMComplexBindDataRec) + 
  1779.            ((numBindings - 1) * 
  1780.         sizeof(TMComplexBindProcsRec)));
  1781.     else
  1782.       bytes = (sizeof(TMSimpleBindDataRec) + 
  1783.            ((numBindings - 1) * 
  1784.         sizeof(TMSimpleBindProcsRec)));
  1785.  
  1786.     bindData = (TMBindData) XtCalloc(sizeof(char), bytes);
  1787.     bindData->simple.isComplex = isComplex;
  1788.     if (isComplex) {
  1789.     TMComplexBindData cBindData = (TMComplexBindData)bindData;
  1790.     /* 
  1791.      * If there were any accelerator contexts in the old bindData
  1792.      * then propagate them to the new one.
  1793.      */
  1794.     if (oldBindData && oldBindData->simple.isComplex)
  1795.         cBindData->accel_context = 
  1796.         ((TMComplexBindData) oldBindData)->accel_context;
  1797.     XtBCopy((char *)bindings,
  1798.         (char *)&cBindData->bindTbl[0],
  1799.         numBindings * sizeof(TMComplexBindProcsRec));
  1800.     }
  1801.     return bindData;
  1802. }
  1803.  
  1804. /*
  1805.  * This routine is the central clearinghouse for merging translations
  1806.  * into a widget. It takes care of preping the action bindings for
  1807.  * realize time and calling the converter or doing a straight merge if
  1808.  * the destination is empty. 
  1809.  */
  1810. static Boolean ComposeTranslations(dest, operation, source, newXlations)
  1811.     Widget dest, source;
  1812.     _XtTranslateOp operation;
  1813.     XtTranslations newXlations;
  1814. {
  1815.     XtTranslations     newTable, oldXlations;
  1816.     XtTranslations    accNewXlations;
  1817.     EventMask        oldMask;
  1818.     TMBindData        bindData;
  1819.     TMComplexBindProcs    oldBindings = NULL;
  1820.     TMShortCard        numOldBindings, numNewBindings = 0, numBytes;
  1821.     TMComplexBindProcsRec stackBindings[16], *newBindings;
  1822.  
  1823.     /*
  1824.      * how should we be handling the refcount decrement for the
  1825.      * replaced translation table ???
  1826.      */
  1827.     if (!newXlations)
  1828.       {
  1829.       XtAppWarningMsg(XtWidgetToApplicationContext(dest),
  1830.               XtNtranslationError,"nullTable",XtCXtToolkitError,
  1831.               "table to (un)merge must not be null",
  1832.               (String *)NULL, (Cardinal *)NULL);
  1833.       return False;
  1834.       }
  1835.  
  1836.     accNewXlations = newXlations;
  1837.     newXlations = ((newXlations->hasBindings)
  1838.            ? ((ATranslations)newXlations)->xlations
  1839.            : newXlations);
  1840.  
  1841.     if (!(oldXlations = dest->core.tm.translations))
  1842.       operation = XtTableReplace;
  1843.  
  1844.     /* 
  1845.      * try to avoid generation of duplicate state trees. If the source
  1846.      * isn't simple (1 state Tree) then it's too much hassle
  1847.      */
  1848.     if (((operation == XtTableAugment) || 
  1849.      (operation == XtTableOverride)) &&
  1850.     (newXlations->numStateTrees == 1)) {
  1851.     Cardinal    i;
  1852.     for (i = 0; i < oldXlations->numStateTrees; i++)
  1853.       if (oldXlations->stateTreeTbl[i] ==
  1854.           newXlations->stateTreeTbl[0])
  1855.         break;
  1856.     if (i < oldXlations->numStateTrees) {
  1857.         if (operation == XtTableAugment) {
  1858.         /* 
  1859.          * we don't need to do anything since it's already
  1860.          * there 
  1861.          */
  1862.         return True;
  1863.         }
  1864.         else {/* operation == XtTableOverride */
  1865.         /*
  1866.          * We'll get rid of the duplicate trees throughout the
  1867.          * and leave it with a pruned translation table. This
  1868.          * will only work if the same table has been merged
  1869.          * into this table (or one of it's composers
  1870.          */
  1871.         _XtUnmergeTranslations(dest, newXlations);
  1872.         /*
  1873.          * reset oldXlations so we're back in sync
  1874.          */
  1875.         if (!(oldXlations = dest->core.tm.translations))
  1876.           operation = XtTableReplace;
  1877.         }
  1878.     }
  1879.     }
  1880.  
  1881.     bindData = (TMBindData) dest->core.tm.proc_table;
  1882.     if (bindData) {
  1883.     numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
  1884.      if (bindData->simple.isComplex)
  1885.         oldBindings = &((TMComplexBindData)bindData)->bindTbl[0];
  1886.      else
  1887.         oldBindings = (TMComplexBindProcs)
  1888.         (&((TMSimpleBindData)bindData)->bindTbl[0]);
  1889.     }
  1890.  
  1891.     numBytes =(((oldXlations ? oldXlations->numStateTrees : 0)
  1892.         + newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec));
  1893.     newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes,  stackBindings);
  1894.     XtBZero((char *)newBindings, numBytes);
  1895.  
  1896.     if (operation == XtTableUnmerge) {
  1897.     newTable = UnmergeTranslations(dest, 
  1898.                        oldXlations,
  1899.                        newXlations,
  1900.                        0,
  1901.                        oldBindings, numOldBindings,
  1902.                        newBindings, &numNewBindings);
  1903. #ifdef DEBUG
  1904.     /* check for no match for unmerge */
  1905.     if (newTable == oldXlations) {
  1906.         XtWarning("attempt to unmerge invalid table");
  1907.         XtStackFree((char *)newBindings, (char *)stackBindings);
  1908.         return(newTable != NULL);
  1909.     }
  1910. #endif /* DEBUG */
  1911.     }
  1912.     else {
  1913.     newTable = MergeTranslations(dest, 
  1914.                      oldXlations,
  1915.                      accNewXlations,
  1916.                      operation,
  1917.                      source,
  1918.                      oldBindings,
  1919.                      newBindings,
  1920.                      &numNewBindings);
  1921.     }
  1922.     if (XtIsRealized(dest)) {
  1923.     oldMask = 0;
  1924.     if (oldXlations)
  1925.         oldMask = oldXlations->eventMask;
  1926.     _XtUninstallTranslations(dest);
  1927.     }
  1928.     
  1929.     dest->core.tm.proc_table = 
  1930.       (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
  1931.     
  1932.     if (bindData) XtFree((char *)bindData);
  1933.  
  1934.     dest->core.tm.translations = newTable;
  1935.  
  1936.     if (XtIsRealized(dest)) {
  1937.     EventMask mask = 0;
  1938.     _XtInstallTranslations(dest);
  1939.     if (newTable)
  1940.         mask = newTable->eventMask;
  1941.     if (mask != oldMask)
  1942.         XSelectInput(XtDisplay(dest), XtWindow(dest), 
  1943.              XtBuildEventMask(dest));
  1944.     }
  1945.     XtStackFree((char *)newBindings, (char *)stackBindings);
  1946.     return(newTable != NULL);
  1947. }
  1948.  
  1949. /*
  1950.  * If a GetValues is done on a translation resource that contains
  1951.  * accelerators we need to return the accelerator context in addition
  1952.  * to the pure translations.  Since this means returning memory that
  1953.  * the client controlls but we still own, we will track the "headers"
  1954.  * that we return (via a linked list pointed to from the bindData) and
  1955.  * free it at destroy time.
  1956.  */
  1957. XtTranslations _XtGetTranslationValue(w)
  1958.     Widget    w;
  1959. {
  1960.     XtTM        tmRecPtr = (XtTM) &w->core.tm;
  1961.     ATranslations    *aXlationsPtr;
  1962.     TMComplexBindData    cBindData = (TMComplexBindData) tmRecPtr->proc_table;
  1963.     XtTranslations    xlations = tmRecPtr->translations;
  1964.  
  1965.     if (!xlations || !cBindData || !cBindData->isComplex)
  1966.     return xlations;
  1967.  
  1968.     /* Walk the list looking to see if we already have generated a
  1969.      * header for the currently installed translations.  If we have,
  1970.      * just return that header.  Otherwise create a new header.
  1971.      */
  1972.     for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
  1973.      *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
  1974.      aXlationsPtr = &(*aXlationsPtr)->next)
  1975.     ;
  1976.     if (*aXlationsPtr)
  1977.     return (XtTranslations) *aXlationsPtr;
  1978.     else { 
  1979.     /* create a new aXlations context */
  1980.     ATranslations    aXlations;
  1981.     Cardinal    numBindings = xlations->numStateTrees;
  1982.  
  1983.     (*aXlationsPtr) = aXlations = (ATranslations)
  1984.         XtMalloc(sizeof(ATranslationData) + 
  1985.              (numBindings - 1) * sizeof(TMComplexBindProcsRec));
  1986.  
  1987.     aXlations->hasBindings = True;
  1988.     aXlations->xlations = xlations;
  1989.     aXlations->next = NULL;
  1990.     XtBCopy((char *) &cBindData->bindTbl[0],
  1991.         (char *) &aXlations->bindTbl[0],
  1992.         numBindings * sizeof(TMComplexBindProcsRec));
  1993.     return (XtTranslations) aXlations;
  1994.     }
  1995. }
  1996.  
  1997.  
  1998. /*ARGSUSED*/
  1999. static void RemoveStateTree(tree)
  2000.     TMStateTree    tree;
  2001. {
  2002. #ifdef REFCNT_TRANSLATIONS    
  2003.     TMComplexStateTree stateTree = (TMComplexStateTree)tree;
  2004.  
  2005.     if (--stateTree->refCount == 0) {
  2006.     /*
  2007.      * should we free/refcount the match recs ?
  2008.      */
  2009.     if (!stateTree->isSimple)  {
  2010.         StatePtr    currState, nextState;
  2011.         TMShortCard i;
  2012.         for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
  2013.         currState = 
  2014.           nextState = 
  2015.             stateTree->complexBranchHeadTbl[i];
  2016.         for (; nextState;){
  2017.             FreeActions(currState->actions);
  2018.             currState->actions = NULL;
  2019.             if (!currState->isCycleEnd)
  2020.               nextState = currState->nextLevel;
  2021.             else
  2022.               nextState = NULL;
  2023.             XtFree( (char*)currState );
  2024.         }
  2025.         }
  2026.         XtFree((char*)stateTree->complexBranchHeadTbl);
  2027.     }
  2028.     XtFree((char*)stateTree->branchHeadTbl);
  2029.     XtFree((char*)stateTree);
  2030.     }
  2031. #endif /* REFCNT_TRANSLATIONS */
  2032. }
  2033.  
  2034. void _XtRemoveStateTreeByIndex(xlations, i)
  2035.     XtTranslations    xlations;
  2036.     TMShortCard    i;
  2037. {
  2038.     TMStateTree        *stateTrees = xlations->stateTreeTbl;
  2039.  
  2040.     RemoveStateTree(stateTrees[i]);
  2041.     xlations->numStateTrees--;
  2042.  
  2043.     for (; i < xlations->numStateTrees; i++)
  2044.       {
  2045.       stateTrees[i] = stateTrees[i+1];
  2046.       }
  2047. }
  2048.  
  2049. /* ARGSUSED */
  2050. void _XtFreeTranslations(app, toVal, closure, args, num_args)
  2051.     XtAppContext app;
  2052.     XrmValuePtr    toVal;
  2053.     XtPointer    closure;
  2054.     XrmValuePtr    args;
  2055.     Cardinal    *num_args;
  2056. {
  2057.     XtTranslations     xlations;
  2058.     register int     i;
  2059.  
  2060.     if (*num_args != 0)
  2061.     XtAppWarningMsg(app,
  2062.       "invalidParameters","freeTranslations",XtCXtToolkitError,
  2063.           "Freeing XtTranslations requires no extra arguments",
  2064.       (String *)NULL, (Cardinal *)NULL);
  2065.  
  2066.     xlations = *(XtTranslations*)toVal->addr;
  2067.     for (i = 0; i < (int)xlations->numStateTrees; i++)
  2068.       RemoveStateTree(xlations->stateTreeTbl[i]);
  2069.     XtFree((char *)xlations);
  2070. }
  2071.  
  2072. /*  The spec is not clear on when actions specified in accelerators are bound;
  2073.  *  Bind them at Realize the same as translations
  2074.  */
  2075. void XtInstallAccelerators(destination, source)
  2076.     Widget destination, source;
  2077. {
  2078.     XtTranslations    aXlations;
  2079.     _XtTranslateOp    op;
  2080.     String        buf;
  2081.  
  2082.     /*
  2083.      * test that it was parsed as an accelarator table. Even though
  2084.      * there doesn't need to be a distinction it makes life easier if
  2085.      * we honor the spec implication that aXlations is an accelerator
  2086.      */
  2087.     if ((!XtIsWidget(source)) || 
  2088.     ((aXlations = source->core.accelerators) == NULL) ||
  2089.     (aXlations->stateTreeTbl[0]->simple.isAccelerator == False))
  2090.       return;
  2091.     
  2092.     aXlations = source->core.accelerators;
  2093.     op = aXlations->operation;
  2094.  
  2095.     if (ComposeTranslations(destination, op, source, aXlations) &&
  2096.     (XtClass(source)->core_class.display_accelerator != NULL)) {
  2097.     
  2098.     buf = _XtPrintXlations(destination, aXlations, source, False);
  2099.     (*(XtClass(source)->core_class.display_accelerator))(source,buf);
  2100.     XtFree(buf);
  2101.     }
  2102. }
  2103.   
  2104. void XtInstallAllAccelerators(destination,source)
  2105.     Widget destination,source;
  2106. {
  2107.     register int i;
  2108.     CompositeWidget cw;
  2109.  
  2110.     /* Recurse down normal children */
  2111.     if (XtIsComposite(source)) {
  2112.         cw = (CompositeWidget) source;
  2113.         for (i = 0; i < cw->composite.num_children; i++) {
  2114.             XtInstallAllAccelerators(destination,cw->composite.children[i]);
  2115.         }
  2116.     }
  2117.  
  2118.     /* Recurse down popup children */
  2119.     if (XtIsWidget(source)) {
  2120.         for (i = 0; i < source->core.num_popups; i++) {
  2121.             XtInstallAllAccelerators(destination,source->core.popup_list[i]);
  2122.         }
  2123.     }
  2124.     /* Finally, apply procedure to this widget */
  2125.     XtInstallAccelerators(destination,source);
  2126. }
  2127.  
  2128. #if 0 /* dead code */
  2129. static _XtTranslateOp _XtGetTMOperation(xlations)
  2130.     XtTranslations xlations;
  2131. {
  2132.     return ((xlations->hasBindings)
  2133.         ? ((ATranslations)xlations)->xlations->operation
  2134.         : xlations->operation);
  2135. }
  2136. #endif
  2137.  
  2138. void XtAugmentTranslations(widget, new)
  2139.     Widget widget;
  2140.     XtTranslations new;
  2141. {
  2142.     (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new);
  2143. }
  2144.  
  2145. void XtOverrideTranslations(widget, new)
  2146.     Widget widget;
  2147.     XtTranslations new;
  2148. {
  2149.     (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new);
  2150. }
  2151.  
  2152. void _XtMergeTranslations(widget, newXlations, op)
  2153.     Widget    widget;
  2154.     XtTranslations newXlations;
  2155.     _XtTranslateOp op;
  2156. {
  2157.     if (!newXlations){
  2158.     if (!widget->core.tm.translations)
  2159.       return;
  2160.     else {
  2161.       newXlations = widget->core.tm.translations;
  2162.       widget->core.tm.translations = NULL;
  2163.       }
  2164.     }
  2165.     (void) ComposeTranslations(widget, 
  2166.                  op,
  2167.                  (Widget)NULL, 
  2168.                  newXlations);
  2169. }
  2170.  
  2171. void _XtUnmergeTranslations(widget, xlations) 
  2172.    Widget        widget;
  2173.     XtTranslations    xlations;
  2174. {
  2175.     ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations);
  2176. }
  2177.  
  2178.  
  2179. void _XtPopupInitialize(app)
  2180.     XtAppContext app;
  2181. {
  2182.     /*
  2183.      * The _XtGlobalTM.newMatchSemantics flag determines whether
  2184.      * we support old or new matching
  2185.      * behavior. This is mainly an issue of whether subsequent lhs will
  2186.      * get pushed up in the match table if a lhs containing thier initial
  2187.      * sequence has already been encountered. Currently inited to False;
  2188.      */
  2189. #ifdef NEW_TM
  2190.     _XtGlobalTM.newMatchSemantics = True;
  2191. #else
  2192.     _XtGlobalTM.newMatchSemantics = False;
  2193. #endif
  2194.     _XtActionInitialize(app);
  2195.     _XtGrabInitialize(app);
  2196. }
  2197.