Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

TMstate.c

/* $Xorg: TMstate.c,v 1.6 2001/02/09 02:03:58 xorgcvs Exp $ */

/***********************************************************
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA.

                        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 names of Digital or Sun 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.

SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
ABLE  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.

******************************************************************/
/* $XFree86: xc/lib/Xt/TMstate.c,v 1.8 2001/12/14 19:56:31 dawes Exp $ */

/*

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);
}

Generated by  Doxygen 1.6.0   Back to index