TMstate.c revision 249c3046
1444c061aSmrg/***********************************************************
2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg/* TMstate.c -- maintains the state table of actions for the translation
72444c061aSmrg *              manager.
73444c061aSmrg */
74444c061aSmrg/*LINTLIBRARY*/
75444c061aSmrg
76444c061aSmrg#ifdef HAVE_CONFIG_H
77444c061aSmrg#include <config.h>
78444c061aSmrg#endif
79444c061aSmrg#include "IntrinsicI.h"
80444c061aSmrg
81444c061aSmrg#ifndef TM_NO_MATCH
82444c061aSmrg#define TM_NO_MATCH (-2)
83444c061aSmrg#endif /* TM_NO_MATCH */
84444c061aSmrg
85444c061aSmrg/* forward definitions */
86444c061aSmrgstatic StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard);
87444c061aSmrg
88444c061aSmrg
89444c061aSmrgstatic String XtNtranslationError = "translationError";
90444c061aSmrg
91444c061aSmrg#ifndef __EMX__
92444c061aSmrgTMGlobalRec _XtGlobalTM; /* initialized to zero K&R */
93444c061aSmrg#else
94444c061aSmrgTMGlobalRec _XtGlobalTM = {0};
95444c061aSmrg#endif
96444c061aSmrg
97444c061aSmrg#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
98444c061aSmrg  (typeMatch->eventType == tmEvent->event.eventType && \
99444c061aSmrg   (typeMatch->matchEvent != NULL) && \
100444c061aSmrg   (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
101444c061aSmrg
102444c061aSmrg
103444c061aSmrg#define NumStateTrees(xlations) \
104444c061aSmrg  ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
105444c061aSmrg
106444c061aSmrgstatic TMShortCard GetBranchHead(
107444c061aSmrg    TMParseStateTree	parseTree,
108444c061aSmrg    TMShortCard		typeIndex,
109444c061aSmrg    TMShortCard		modIndex,
110444c061aSmrg    Boolean		isDummy)
111444c061aSmrg{
112444c061aSmrg#define TM_BRANCH_HEAD_TBL_ALLOC 	8
113444c061aSmrg#define TM_BRANCH_HEAD_TBL_REALLOC 	8
114444c061aSmrg
115444c061aSmrg    TMBranchHead branchHead = parseTree->branchHeadTbl;
116444c061aSmrg    TMShortCard	newSize, i;
117444c061aSmrg
118444c061aSmrg    /*
119444c061aSmrg     * dummy is used as a place holder for later matching in old-style
120444c061aSmrg     * matching behavior. If there's already an entry we don't need
121444c061aSmrg     * another dummy.
122444c061aSmrg     */
123444c061aSmrg    if (isDummy) {
124444c061aSmrg	for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
125444c061aSmrg	    if ((branchHead->typeIndex == typeIndex) &&
126444c061aSmrg		(branchHead->modIndex == modIndex))
127444c061aSmrg	      return i;
128444c061aSmrg	}
129444c061aSmrg    }
130444c061aSmrg    if (parseTree->numBranchHeads == parseTree->branchHeadTblSize)
131444c061aSmrg      {
132444c061aSmrg	  if (parseTree->branchHeadTblSize == 0)
133444c061aSmrg	    parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_ALLOC;
134444c061aSmrg	  else
135444c061aSmrg	    parseTree->branchHeadTblSize +=
136444c061aSmrg	      TM_BRANCH_HEAD_TBL_REALLOC;
137444c061aSmrg	  newSize = (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec));
138444c061aSmrg	  if (parseTree->isStackBranchHeads) {
139444c061aSmrg	      TMBranchHead	oldBranchHeadTbl = parseTree->branchHeadTbl;
140444c061aSmrg	      parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize);
141444c061aSmrg	      XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize);
142444c061aSmrg	      parseTree->isStackBranchHeads = False;
143444c061aSmrg	  }
144444c061aSmrg	  else {
145444c061aSmrg	      parseTree->branchHeadTbl = (TMBranchHead)
146444c061aSmrg		XtRealloc((char *)parseTree->branchHeadTbl,
147444c061aSmrg			  (parseTree->branchHeadTblSize *
148444c061aSmrg			   sizeof(TMBranchHeadRec)));
149444c061aSmrg	  }
150444c061aSmrg      }
151444c061aSmrg#ifdef TRACE_TM
152444c061aSmrg    LOCK_PROCESS;
153444c061aSmrg    _XtGlobalTM.numBranchHeads++;
154444c061aSmrg    UNLOCK_PROCESS;
155444c061aSmrg#endif /* TRACE_TM */
156444c061aSmrg    branchHead =
157444c061aSmrg      &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
158444c061aSmrg    branchHead->typeIndex = typeIndex;
159444c061aSmrg    branchHead->modIndex = modIndex;
160444c061aSmrg    branchHead->more = 0;
161444c061aSmrg    branchHead->isSimple = True;
162444c061aSmrg    branchHead->hasActions = False;
163444c061aSmrg    branchHead->hasCycles = False;
164444c061aSmrg    return parseTree->numBranchHeads-1;
165444c061aSmrg}
166444c061aSmrg
167444c061aSmrgTMShortCard _XtGetQuarkIndex(
168444c061aSmrg    TMParseStateTree	parseTree,
169444c061aSmrg    XrmQuark		quark)
170444c061aSmrg{
171444c061aSmrg#define TM_QUARK_TBL_ALLOC 	16
172444c061aSmrg#define TM_QUARK_TBL_REALLOC 	16
173444c061aSmrg    TMShortCard  i = parseTree->numQuarks;
174444c061aSmrg
175444c061aSmrg    for (i=0; i < parseTree->numQuarks; i++)
176444c061aSmrg      if (parseTree->quarkTbl[i] == quark)
177444c061aSmrg	    break;
178444c061aSmrg
179444c061aSmrg    if (i == parseTree->numQuarks)
180444c061aSmrg      {
181444c061aSmrg	  if (parseTree->numQuarks == parseTree->quarkTblSize)
182444c061aSmrg	    {
183444c061aSmrg		TMShortCard	newSize;
184444c061aSmrg
185444c061aSmrg		if (parseTree->quarkTblSize == 0)
186444c061aSmrg		  parseTree->quarkTblSize += TM_QUARK_TBL_ALLOC;
187444c061aSmrg		else
188444c061aSmrg		  parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC;
189444c061aSmrg		newSize = (parseTree->quarkTblSize * sizeof(XrmQuark));
190444c061aSmrg
191444c061aSmrg		if (parseTree->isStackQuarks) {
192444c061aSmrg		    XrmQuark	*oldquarkTbl = parseTree->quarkTbl;
193444c061aSmrg		    parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize);
194444c061aSmrg		    XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize);
195444c061aSmrg		    parseTree->isStackQuarks = False;
196444c061aSmrg		}
197444c061aSmrg		else {
198444c061aSmrg		    parseTree->quarkTbl = (XrmQuark *)
199444c061aSmrg		      XtRealloc((char *)parseTree->quarkTbl,
200444c061aSmrg				(parseTree->quarkTblSize *
201444c061aSmrg				 sizeof(XrmQuark)));
202444c061aSmrg		}
203444c061aSmrg	    }
204444c061aSmrg	  parseTree->quarkTbl[parseTree->numQuarks++] = quark;
205444c061aSmrg      }
206444c061aSmrg    return i;
207444c061aSmrg}
208444c061aSmrg
209444c061aSmrg/*
210444c061aSmrg * Get an entry from the parseTrees complex branchHead tbl. If there's none
211444c061aSmrg * there then allocate one
212444c061aSmrg */
213444c061aSmrg/*ARGSUSED*/
214444c061aSmrgstatic TMShortCard GetComplexBranchIndex(
215444c061aSmrg    TMParseStateTree	parseTree,
216444c061aSmrg    TMShortCard		typeIndex,
217444c061aSmrg    TMShortCard		modIndex)
218444c061aSmrg{
219444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
220444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
221444c061aSmrg
222444c061aSmrg    if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
223444c061aSmrg	TMShortCard	newSize;
224444c061aSmrg
225444c061aSmrg	if (parseTree->complexBranchHeadTblSize == 0)
226444c061aSmrg	  parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_ALLOC;
227444c061aSmrg	else
228444c061aSmrg	  parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_REALLOC;
229444c061aSmrg
230444c061aSmrg	newSize = (parseTree->complexBranchHeadTblSize * sizeof(StatePtr));
231444c061aSmrg
232444c061aSmrg	if (parseTree->isStackComplexBranchHeads) {
233444c061aSmrg	    StatePtr *oldcomplexBranchHeadTbl
234444c061aSmrg	      = parseTree->complexBranchHeadTbl;
235444c061aSmrg	    parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize);
236444c061aSmrg	    XtMemmove(parseTree->complexBranchHeadTbl,
237444c061aSmrg		      oldcomplexBranchHeadTbl, newSize);
238444c061aSmrg	    parseTree->isStackComplexBranchHeads = False;
239444c061aSmrg	}
240444c061aSmrg	else {
241444c061aSmrg	    parseTree->complexBranchHeadTbl = (StatePtr *)
242444c061aSmrg	      XtRealloc((char *)parseTree->complexBranchHeadTbl,
243444c061aSmrg			(parseTree->complexBranchHeadTblSize *
244444c061aSmrg			 sizeof(StatePtr)));
245444c061aSmrg	}
246444c061aSmrg    }
247444c061aSmrg    parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
248444c061aSmrg    return parseTree->numComplexBranchHeads-1;
249444c061aSmrg}
250444c061aSmrg
251444c061aSmrgTMShortCard _XtGetTypeIndex(
252444c061aSmrg    Event	*event)
253444c061aSmrg{
254444c061aSmrg    TMShortCard		i, j = TM_TYPE_SEGMENT_SIZE;
255444c061aSmrg    TMShortCard		typeIndex = 0;
256444c061aSmrg    TMTypeMatch 	typeMatch;
257444c061aSmrg    TMTypeMatch		segment = NULL;
258444c061aSmrg
259444c061aSmrg    LOCK_PROCESS;
260444c061aSmrg    for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
261444c061aSmrg	segment = _XtGlobalTM.typeMatchSegmentTbl[i];
262444c061aSmrg	for (j = 0;
263444c061aSmrg	     typeIndex < _XtGlobalTM.numTypeMatches && j <  TM_TYPE_SEGMENT_SIZE;
264444c061aSmrg	     j++, typeIndex++)
265444c061aSmrg	  {
266444c061aSmrg	      typeMatch = &(segment[j]);
267444c061aSmrg	      if (event->eventType == typeMatch->eventType &&
268444c061aSmrg		  event->eventCode == typeMatch->eventCode &&
269444c061aSmrg		  event->eventCodeMask == typeMatch->eventCodeMask &&
270444c061aSmrg		  event->matchEvent == typeMatch->matchEvent) {
271444c061aSmrg		    UNLOCK_PROCESS;
272444c061aSmrg		    return typeIndex;
273444c061aSmrg		  }
274444c061aSmrg	  }
275444c061aSmrg    }
276444c061aSmrg
277444c061aSmrg    if (j == TM_TYPE_SEGMENT_SIZE) {
278444c061aSmrg	if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) {
279444c061aSmrg	    _XtGlobalTM.typeMatchSegmentTblSize += 4;
280444c061aSmrg	    _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
281444c061aSmrg	      XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl,
282444c061aSmrg			(_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch)));
283444c061aSmrg	}
284444c061aSmrg	_XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] =
285444c061aSmrg	  segment = (TMTypeMatch)
286444c061aSmrg	    __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec));
287444c061aSmrg	j = 0;
288444c061aSmrg    }
289444c061aSmrg    typeMatch = &segment[j];
290444c061aSmrg    typeMatch->eventType = event->eventType;
291444c061aSmrg    typeMatch->eventCode = event->eventCode;
292444c061aSmrg    typeMatch->eventCodeMask = event->eventCodeMask;
293444c061aSmrg    typeMatch->matchEvent = event->matchEvent;
294444c061aSmrg    _XtGlobalTM.numTypeMatches++;
295444c061aSmrg    UNLOCK_PROCESS;
296444c061aSmrg    return typeIndex;
297444c061aSmrg}
298444c061aSmrg
299444c061aSmrgstatic Boolean CompareLateModifiers(
300444c061aSmrg    LateBindingsPtr lateBind1P,
301444c061aSmrg    LateBindingsPtr lateBind2P)
302444c061aSmrg{
303444c061aSmrg    LateBindingsPtr late1P = lateBind1P;
304444c061aSmrg    LateBindingsPtr late2P = lateBind2P;
305444c061aSmrg
306444c061aSmrg    if (late1P != NULL || late2P != NULL) {
307444c061aSmrg	int i = 0;
308444c061aSmrg	int j = 0;
309444c061aSmrg	if (late1P != NULL)
310444c061aSmrg	  for (; late1P->keysym != NoSymbol; i++) late1P++;
311444c061aSmrg	if (late2P != NULL)
312444c061aSmrg	  for (; late2P->keysym != NoSymbol; j++) late2P++;
313444c061aSmrg	if (i != j) return FALSE;
314444c061aSmrg	late1P--;
315444c061aSmrg	while (late1P >= lateBind1P) {
316444c061aSmrg	    Boolean last = True;
317444c061aSmrg	    for (late2P = lateBind2P + i - 1;
318444c061aSmrg		 late2P >= lateBind2P;
319444c061aSmrg		 late2P--) {
320444c061aSmrg		if (late1P->keysym == late2P->keysym
321444c061aSmrg		    && late1P->knot == late2P->knot) {
322444c061aSmrg		    j--;
323444c061aSmrg		    if (last) i--;
324444c061aSmrg		    break;
325444c061aSmrg		}
326444c061aSmrg		last = False;
327444c061aSmrg	    }
328444c061aSmrg	    late1P--;
329444c061aSmrg	}
330444c061aSmrg	if (j != 0) return FALSE;
331444c061aSmrg    }
332444c061aSmrg    return TRUE;
333444c061aSmrg}
334444c061aSmrg
335444c061aSmrgTMShortCard _XtGetModifierIndex(
336444c061aSmrg    Event	*event)
337444c061aSmrg{
338444c061aSmrg    TMShortCard		i, j = TM_MOD_SEGMENT_SIZE;
339444c061aSmrg    TMShortCard		modIndex = 0;
340444c061aSmrg    TMModifierMatch 	modMatch;
341444c061aSmrg    TMModifierMatch	segment = NULL;
342444c061aSmrg
343444c061aSmrg    LOCK_PROCESS;
344444c061aSmrg    for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
345444c061aSmrg	segment = _XtGlobalTM.modMatchSegmentTbl[i];
346444c061aSmrg	for (j = 0;
347444c061aSmrg	     modIndex < _XtGlobalTM.numModMatches && j <  TM_MOD_SEGMENT_SIZE;
348444c061aSmrg	     j++, modIndex++) {
349444c061aSmrg	    modMatch = &(segment[j]);
350444c061aSmrg	    if (event->modifiers == modMatch->modifiers &&
351444c061aSmrg		event->modifierMask == modMatch->modifierMask &&
352444c061aSmrg		event->standard == modMatch->standard &&
353444c061aSmrg		((!event->lateModifiers && !modMatch->lateModifiers) ||
354444c061aSmrg		 CompareLateModifiers(event->lateModifiers,
355444c061aSmrg				      modMatch->lateModifiers))) {
356444c061aSmrg		/*
357444c061aSmrg		 * if we found a match then we can free the parser's
358444c061aSmrg		 * late modifiers. If there isn't a match we use the
359444c061aSmrg		 * parser's copy
360444c061aSmrg		 */
361444c061aSmrg		if (event->lateModifiers &&
362444c061aSmrg		    --event->lateModifiers->ref_count == 0) {
363444c061aSmrg		    XtFree((char *)event->lateModifiers);
364444c061aSmrg		    event->lateModifiers = NULL;
365444c061aSmrg		}
366444c061aSmrg		UNLOCK_PROCESS;
367444c061aSmrg		return modIndex;
368444c061aSmrg	    }
369444c061aSmrg	}
370444c061aSmrg    }
371444c061aSmrg
372444c061aSmrg    if (j == TM_MOD_SEGMENT_SIZE) {
373444c061aSmrg	if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) {
374444c061aSmrg	    _XtGlobalTM.modMatchSegmentTblSize += 4;
375444c061aSmrg	    _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
376444c061aSmrg	      XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl,
377444c061aSmrg			(_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch)));
378444c061aSmrg	}
379444c061aSmrg	_XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] =
380444c061aSmrg	  segment = (TMModifierMatch)
381444c061aSmrg	    __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec));
382444c061aSmrg	j = 0;
383444c061aSmrg    }
384444c061aSmrg    modMatch = &segment[j];
385444c061aSmrg    modMatch->modifiers = event->modifiers;;
386444c061aSmrg    modMatch->modifierMask = event->modifierMask;
387444c061aSmrg    modMatch->standard = event->standard;
388444c061aSmrg    /*
389444c061aSmrg     * We use the parser's copy of the late binding array
390444c061aSmrg     */
391444c061aSmrg#ifdef TRACE_TM
392444c061aSmrg    if (event->lateModifiers)
393444c061aSmrg      _XtGlobalTM.numLateBindings++;
394444c061aSmrg#endif /* TRACE_TM */
395444c061aSmrg    modMatch->lateModifiers = event->lateModifiers;
396444c061aSmrg    _XtGlobalTM.numModMatches++;
397444c061aSmrg    UNLOCK_PROCESS;
398444c061aSmrg    return modIndex;
399444c061aSmrg}
400444c061aSmrg
401444c061aSmrg
402444c061aSmrg/*
403444c061aSmrg * This is called from the SimpleStateHandler to match a stateTree
404444c061aSmrg * entry to the event coming in
405444c061aSmrg */
406444c061aSmrgstatic int MatchBranchHead(
407444c061aSmrg    TMSimpleStateTree 	stateTree,
408444c061aSmrg    int			startIndex,
409444c061aSmrg    TMEventPtr		event)
410444c061aSmrg{
411444c061aSmrg    TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex];
412444c061aSmrg    int i;
413444c061aSmrg
414444c061aSmrg    LOCK_PROCESS;
415444c061aSmrg    for (i = startIndex;
416444c061aSmrg	 i < (int)stateTree->numBranchHeads;
417444c061aSmrg	 i++, branchHead++)
418444c061aSmrg      {
419444c061aSmrg	  TMTypeMatch 		typeMatch;
420444c061aSmrg	  TMModifierMatch	modMatch;
421444c061aSmrg
422444c061aSmrg	  typeMatch  = TMGetTypeMatch(branchHead->typeIndex);
423444c061aSmrg	  modMatch = TMGetModifierMatch(branchHead->modIndex);
424444c061aSmrg
425444c061aSmrg	  if (MatchIncomingEvent(event, typeMatch, modMatch)) {
426444c061aSmrg	    UNLOCK_PROCESS;
427444c061aSmrg	    return i;
428444c061aSmrg	  }
429444c061aSmrg      }
430444c061aSmrg    UNLOCK_PROCESS;
431444c061aSmrg    return (TM_NO_MATCH);
432444c061aSmrg}
433444c061aSmrg
434444c061aSmrgBoolean _XtRegularMatch(
435444c061aSmrg    TMTypeMatch 	typeMatch,
436444c061aSmrg    TMModifierMatch	modMatch,
437444c061aSmrg    TMEventPtr 		eventSeq)
438444c061aSmrg{
439444c061aSmrg    Modifiers computed =0;
440444c061aSmrg    Modifiers computedMask =0;
441444c061aSmrg    Boolean resolved = TRUE;
442444c061aSmrg    if (typeMatch->eventCode != (eventSeq->event.eventCode &
443444c061aSmrg				  typeMatch->eventCodeMask)) return FALSE;
444444c061aSmrg    if (modMatch->lateModifiers != NULL)
445444c061aSmrg	resolved = _XtComputeLateBindings(eventSeq->xev->xany.display,
446444c061aSmrg					  modMatch->lateModifiers,
447444c061aSmrg					  &computed, &computedMask);
448444c061aSmrg    if (!resolved) return FALSE;
449444c061aSmrg    computed |= modMatch->modifiers;
450444c061aSmrg    computedMask |= modMatch->modifierMask;
451444c061aSmrg
452444c061aSmrg    return ( (computed & computedMask) ==
453444c061aSmrg	    (eventSeq->event.modifiers & computedMask));
454444c061aSmrg}
455444c061aSmrg
456444c061aSmrg/*ARGSUSED*/
457444c061aSmrgBoolean _XtMatchAtom(
458444c061aSmrg    TMTypeMatch 	typeMatch,
459444c061aSmrg    TMModifierMatch	modMatch,
460444c061aSmrg    TMEventPtr 		eventSeq)
461444c061aSmrg{
462444c061aSmrg    Atom	atom;
463444c061aSmrg
464444c061aSmrg    atom = XInternAtom(eventSeq->xev->xany.display,
465444c061aSmrg		       XrmQuarkToString(typeMatch->eventCode),
466444c061aSmrg		       False);
467444c061aSmrg    return (atom == eventSeq->event.eventCode);
468444c061aSmrg}
469444c061aSmrg
470444c061aSmrg#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7)))
471444c061aSmrg
472444c061aSmrg/*
473444c061aSmrg * there are certain cases where you want to ignore the event and stay
474444c061aSmrg * in the same state.
475444c061aSmrg */
476444c061aSmrgstatic Boolean Ignore(
477444c061aSmrg    TMEventPtr event)
478444c061aSmrg{
479444c061aSmrg    Display *dpy;
480444c061aSmrg    XtPerDisplay pd;
481444c061aSmrg
482444c061aSmrg    if (event->event.eventType == MotionNotify)
483444c061aSmrg	return TRUE;
484444c061aSmrg    if (!(event->event.eventType == KeyPress ||
485444c061aSmrg	  event->event.eventType == KeyRelease))
486444c061aSmrg	return FALSE;
487444c061aSmrg    dpy = event->xev->xany.display;
488444c061aSmrg    pd = _XtGetPerDisplay(dpy);
489444c061aSmrg    _InitializeKeysymTables(dpy, pd);
490444c061aSmrg    return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
491444c061aSmrg}
492444c061aSmrg
493444c061aSmrg
494444c061aSmrgstatic void XEventToTMEvent(
495444c061aSmrg    XEvent *event,
496444c061aSmrg    TMEventPtr tmEvent)
497444c061aSmrg{
498444c061aSmrg    tmEvent->xev = event;
499444c061aSmrg    tmEvent->event.eventCodeMask = 0;
500444c061aSmrg    tmEvent->event.modifierMask = 0;
501444c061aSmrg    tmEvent->event.eventType = event->type;
502444c061aSmrg    tmEvent->event.lateModifiers = NULL;
503444c061aSmrg    tmEvent->event.matchEvent = NULL;
504444c061aSmrg    tmEvent->event.standard = FALSE;
505444c061aSmrg
506444c061aSmrg    switch (event->type) {
507444c061aSmrg
508444c061aSmrg	case KeyPress:
509444c061aSmrg	case KeyRelease:
510444c061aSmrg            tmEvent->event.eventCode = event->xkey.keycode;
511444c061aSmrg	    tmEvent->event.modifiers = event->xkey.state;
512444c061aSmrg	    break;
513444c061aSmrg
514444c061aSmrg	case ButtonPress:
515444c061aSmrg	case ButtonRelease:
516444c061aSmrg	    tmEvent->event.eventCode = event->xbutton.button;
517444c061aSmrg	    tmEvent->event.modifiers = event->xbutton.state;
518444c061aSmrg	    break;
519444c061aSmrg
520444c061aSmrg	case MotionNotify:
521444c061aSmrg	    tmEvent->event.eventCode = event->xmotion.is_hint;
522444c061aSmrg	    tmEvent->event.modifiers = event->xmotion.state;
523444c061aSmrg	    break;
524444c061aSmrg
525444c061aSmrg	case EnterNotify:
526444c061aSmrg	case LeaveNotify:
527444c061aSmrg	    tmEvent->event.eventCode = event->xcrossing.mode;
528444c061aSmrg	    tmEvent->event.modifiers = event->xcrossing.state;
529444c061aSmrg	    break;
530444c061aSmrg
531444c061aSmrg	case PropertyNotify:
532444c061aSmrg	    tmEvent->event.eventCode = event->xproperty.atom;
533444c061aSmrg	    tmEvent->event.modifiers = 0;
534444c061aSmrg	    break;
535444c061aSmrg
536444c061aSmrg	case SelectionClear:
537444c061aSmrg	    tmEvent->event.eventCode = event->xselectionclear.selection;
538444c061aSmrg	    tmEvent->event.modifiers = 0;
539444c061aSmrg	    break;
540444c061aSmrg
541444c061aSmrg	case SelectionRequest:
542444c061aSmrg	    tmEvent->event.eventCode = event->xselectionrequest.selection;
543444c061aSmrg	    tmEvent->event.modifiers = 0;
544444c061aSmrg	    break;
545444c061aSmrg
546444c061aSmrg	case SelectionNotify:
547444c061aSmrg	    tmEvent->event.eventCode = event->xselection.selection;
548444c061aSmrg	    tmEvent->event.modifiers = 0;
549444c061aSmrg	    break;
550444c061aSmrg
551444c061aSmrg	case ClientMessage:
552444c061aSmrg	    tmEvent->event.eventCode = event->xclient.message_type;
553444c061aSmrg	    tmEvent->event.modifiers = 0;
554444c061aSmrg	    break;
555444c061aSmrg
556444c061aSmrg	case MappingNotify:
557444c061aSmrg	    tmEvent->event.eventCode = event->xmapping.request;
558444c061aSmrg	    tmEvent->event.modifiers = 0;
559444c061aSmrg	    break;
560444c061aSmrg
561444c061aSmrg	case FocusIn:
562444c061aSmrg	case FocusOut:
563444c061aSmrg	    tmEvent->event.eventCode = event->xfocus.mode;
564444c061aSmrg	    tmEvent->event.modifiers = 0;
565444c061aSmrg	    break;
566444c061aSmrg
567444c061aSmrg	default:
568444c061aSmrg	    tmEvent->event.eventCode = 0;
569444c061aSmrg	    tmEvent->event.modifiers = 0;
570444c061aSmrg	    break;
571444c061aSmrg    }
572444c061aSmrg}
573444c061aSmrg
574444c061aSmrg
575444c061aSmrgstatic unsigned long GetTime(
576444c061aSmrg    XtTM tm,
577444c061aSmrg    XEvent *event)
578444c061aSmrg{
579444c061aSmrg    switch (event->type) {
580444c061aSmrg
581444c061aSmrg        case KeyPress:
582444c061aSmrg	case KeyRelease:
583444c061aSmrg	    return event->xkey.time;
584444c061aSmrg
585444c061aSmrg        case ButtonPress:
586444c061aSmrg	case ButtonRelease:
587444c061aSmrg	    return event->xbutton.time;
588444c061aSmrg
589444c061aSmrg	default:
590444c061aSmrg	    return tm->lastEventTime;
591444c061aSmrg
592444c061aSmrg    }
593444c061aSmrg
594444c061aSmrg}
595444c061aSmrg
596444c061aSmrgstatic void HandleActions(
597444c061aSmrg    Widget		w,
598444c061aSmrg    XEvent		*event,
599444c061aSmrg    TMSimpleStateTree	stateTree,
600444c061aSmrg    Widget		accelWidget,
601444c061aSmrg    XtActionProc	*procs,
602444c061aSmrg    ActionRec		*actions)
603444c061aSmrg{
604444c061aSmrg    ActionHook	 	actionHookList;
605444c061aSmrg    Widget		bindWidget;
606444c061aSmrg
607444c061aSmrg    bindWidget = accelWidget ? accelWidget : w;
608444c061aSmrg    if (accelWidget && !XtIsSensitive(accelWidget) &&
609444c061aSmrg	(event->type == KeyPress || event->type == KeyRelease ||
610444c061aSmrg	event->type == ButtonPress || event->type == ButtonRelease ||
611444c061aSmrg	event->type == MotionNotify || event->type == EnterNotify ||
612444c061aSmrg	event->type == LeaveNotify || event->type == FocusIn ||
613444c061aSmrg	event->type == FocusOut))
614444c061aSmrg	return;
615444c061aSmrg
616444c061aSmrg    actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
617444c061aSmrg
618444c061aSmrg    while (actions != NULL) {
619444c061aSmrg	/* perform any actions */
620444c061aSmrg	if (procs[actions->idx] != NULL) {
621444c061aSmrg	    if (actionHookList) {
622444c061aSmrg		ActionHook hook;
623444c061aSmrg		ActionHook next_hook;
624444c061aSmrg		String procName =
625444c061aSmrg		    XrmQuarkToString(stateTree->quarkTbl[actions->idx] );
626444c061aSmrg
627444c061aSmrg		for (hook = actionHookList; hook != NULL; ) {
628444c061aSmrg		    /*
629444c061aSmrg		     * Need to cache hook->next because the following action
630444c061aSmrg		     * proc may free hook via XtRemoveActionHook making
631444c061aSmrg		     * hook->next invalid upon return from the action proc.
632444c061aSmrg		     */
633444c061aSmrg		    next_hook = hook->next;
634444c061aSmrg		    (*hook->proc)(bindWidget,
635444c061aSmrg				  hook->closure,
636444c061aSmrg				  procName,
637444c061aSmrg				  event,
638444c061aSmrg				  actions->params,
639444c061aSmrg				  &actions->num_params
640444c061aSmrg				  );
641444c061aSmrg		    hook = next_hook;
642444c061aSmrg		}
643444c061aSmrg	    }
644444c061aSmrg	    (*(procs[actions->idx]))
645444c061aSmrg	      (bindWidget, event,
646444c061aSmrg	       actions->params, &actions->num_params );
647444c061aSmrg	}
648444c061aSmrg	actions = actions->next;
649444c061aSmrg    }
650444c061aSmrg}
651444c061aSmrg
652444c061aSmrgtypedef struct {
653444c061aSmrg    unsigned int isCycleStart:1;
654444c061aSmrg    unsigned int isCycleEnd:1;
655444c061aSmrg    TMShortCard typeIndex;
656444c061aSmrg    TMShortCard modIndex;
657444c061aSmrg}MatchPairRec, *MatchPair;
658444c061aSmrg
659444c061aSmrgtypedef struct TMContextRec{
660444c061aSmrg    TMShortCard	numMatches;
661444c061aSmrg    TMShortCard	maxMatches;
662444c061aSmrg    MatchPair	matches;
663444c061aSmrg}TMContextRec, *TMContext;
664444c061aSmrg
665444c061aSmrgstatic TMContextRec	contextCache[2];
666444c061aSmrg
667444c061aSmrg#define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
668444c061aSmrg
669444c061aSmrg#define TM_CONTEXT_MATCHES_ALLOC 4
670444c061aSmrg#define TM_CONTEXT_MATCHES_REALLOC 2
671444c061aSmrg
672444c061aSmrgstatic void PushContext(
673444c061aSmrg    TMContext	*contextPtr,
674444c061aSmrg    StatePtr	newState)
675444c061aSmrg{
676444c061aSmrg    TMContext 		context = *contextPtr;
677444c061aSmrg
678444c061aSmrg    LOCK_PROCESS;
679444c061aSmrg    if (context == NULL)
680444c061aSmrg      {
681444c061aSmrg	  if (contextCache[0].numMatches == 0)
682444c061aSmrg	    context = &contextCache[0];
683444c061aSmrg	  else if (contextCache[1].numMatches == 0)
684444c061aSmrg	    context = &contextCache[1];
685444c061aSmrg	  if (!context)
686444c061aSmrg	    {
687444c061aSmrg		context = XtNew(TMContextRec);
688444c061aSmrg		context->matches = NULL;
689444c061aSmrg		context->numMatches =
690444c061aSmrg		  context->maxMatches = 0;
691444c061aSmrg	    }
692444c061aSmrg      }
693444c061aSmrg    if (context->numMatches &&
694444c061aSmrg	context->matches[context->numMatches-1].isCycleEnd)
695444c061aSmrg      {
696444c061aSmrg	  TMShortCard	i;
697444c061aSmrg	  for (i = 0;
698444c061aSmrg	       i < context->numMatches &&
699444c061aSmrg	       !(context->matches[i].isCycleStart);
700444c061aSmrg	       i++){};
701444c061aSmrg	  if (i < context->numMatches)
702444c061aSmrg	    context->numMatches = i+1;
703444c061aSmrg#ifdef DEBUG
704444c061aSmrg	  else
705444c061aSmrg	    XtWarning("pushing cycle end with no cycle start");
706444c061aSmrg#endif /* DEBUG */
707444c061aSmrg      }
708444c061aSmrg    else
709444c061aSmrg      {
710444c061aSmrg	  if (context->numMatches == context->maxMatches)
711444c061aSmrg	    {
712444c061aSmrg		if (context->maxMatches == 0)
713444c061aSmrg		  context->maxMatches += TM_CONTEXT_MATCHES_ALLOC;
714444c061aSmrg		else
715444c061aSmrg		  context->maxMatches += TM_CONTEXT_MATCHES_REALLOC;
716444c061aSmrg		context->matches = (MatchPairRec *)
717444c061aSmrg		  XtRealloc((char *)context->matches,
718444c061aSmrg			    context->maxMatches * sizeof(MatchPairRec));
719444c061aSmrg	    }
720444c061aSmrg	  context->matches[context->numMatches].isCycleStart = newState->isCycleStart;
721444c061aSmrg	  context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
722444c061aSmrg	  context->matches[context->numMatches].typeIndex = newState->typeIndex;
723444c061aSmrg	  context->matches[context->numMatches++].modIndex = newState->modIndex;
724444c061aSmrg	  *contextPtr = context;
725444c061aSmrg      }
726444c061aSmrg      UNLOCK_PROCESS;
727444c061aSmrg}
728444c061aSmrg
729444c061aSmrgstatic void FreeContext(
730444c061aSmrg    TMContext	*contextPtr)
731444c061aSmrg{
732444c061aSmrg    TMContext 		context = NULL;
733444c061aSmrg
734444c061aSmrg    LOCK_PROCESS;
735444c061aSmrg
736444c061aSmrg    if (&contextCache[0] == *contextPtr)
737444c061aSmrg      context = &contextCache[0];
738444c061aSmrg    else if (&contextCache[1] == *contextPtr)
739444c061aSmrg      context = &contextCache[1];
740444c061aSmrg
741444c061aSmrg    if (context)
742444c061aSmrg      context->numMatches = 0;
743444c061aSmrg    else if (*contextPtr)
744444c061aSmrg    {
745444c061aSmrg      if ((*contextPtr)->matches)
746444c061aSmrg        XtFree ((char *) ((*contextPtr)->matches));
747444c061aSmrg      XtFree((char *)*contextPtr);
748444c061aSmrg    }
749444c061aSmrg
750444c061aSmrg    *contextPtr = NULL;
751444c061aSmrg    UNLOCK_PROCESS;
752444c061aSmrg}
753444c061aSmrg
754444c061aSmrgstatic int MatchExact(
755444c061aSmrg    TMSimpleStateTree 	stateTree,
756444c061aSmrg    int			startIndex,
757444c061aSmrg    TMShortCard		typeIndex,
758444c061aSmrg    TMShortCard		modIndex)
759444c061aSmrg{
760444c061aSmrg    TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
761444c061aSmrg    int i;
762444c061aSmrg
763444c061aSmrg    for (i = startIndex;
764444c061aSmrg	 i < (int)stateTree->numBranchHeads;
765444c061aSmrg	 i++, branchHead++)
766444c061aSmrg      {
767444c061aSmrg	  if ((branchHead->typeIndex == typeIndex) &&
768444c061aSmrg	      (branchHead->modIndex == modIndex))
769444c061aSmrg	    return i;
770444c061aSmrg      }
771444c061aSmrg    return (TM_NO_MATCH);
772444c061aSmrg}
773444c061aSmrg
774444c061aSmrg
775444c061aSmrg
776444c061aSmrgstatic void HandleSimpleState(
777444c061aSmrg    Widget	w,
778444c061aSmrg    XtTM	tmRecPtr,
779444c061aSmrg    TMEventRec	*curEventPtr)
780444c061aSmrg{
781444c061aSmrg    XtTranslations	xlations = tmRecPtr->translations;
782444c061aSmrg    TMSimpleStateTree	stateTree;
783444c061aSmrg    TMContext		*contextPtr = GetContextPtr(tmRecPtr);
784444c061aSmrg    TMShortCard		i;
785444c061aSmrg    ActionRec		*actions = NULL;
786444c061aSmrg    Boolean		matchExact = False;
787444c061aSmrg    Boolean	       	match = False;
788444c061aSmrg    StatePtr		complexMatchState = NULL;
789444c061aSmrg    int			currIndex;
790444c061aSmrg    TMShortCard		typeIndex = 0, modIndex = 0;
791444c061aSmrg    int			matchTreeIndex = TM_NO_MATCH;
792444c061aSmrg
793444c061aSmrg    LOCK_PROCESS;
794444c061aSmrg    stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0];
795444c061aSmrg
796444c061aSmrg    for (i = 0;
797444c061aSmrg	 ((!match || !complexMatchState) && (i < xlations->numStateTrees));
798444c061aSmrg	 i++){
799444c061aSmrg	stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
800444c061aSmrg	currIndex = -1;
801444c061aSmrg	/*
802444c061aSmrg	 * don't process this tree if we're only looking for a
803444c061aSmrg	 * complexMatchState and there are no complex states
804444c061aSmrg	 */
805444c061aSmrg	while (!(match && stateTree->isSimple) &&
806444c061aSmrg	       ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
807444c061aSmrg	    currIndex++;
808444c061aSmrg	    if (matchExact)
809444c061aSmrg	      currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex);
810444c061aSmrg	    else
811444c061aSmrg	      currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr);
812444c061aSmrg	    if (currIndex != TM_NO_MATCH) {
813444c061aSmrg		TMBranchHead branchHead;
814444c061aSmrg		StatePtr currState;
815444c061aSmrg
816444c061aSmrg		branchHead = &stateTree->branchHeadTbl[currIndex];
817444c061aSmrg		if (branchHead->isSimple)
818444c061aSmrg		  currState = NULL;
819444c061aSmrg		else
820444c061aSmrg		  currState = ((TMComplexStateTree)stateTree)
821444c061aSmrg		    ->complexBranchHeadTbl[TMBranchMore(branchHead)];
822444c061aSmrg
823444c061aSmrg		/*
824444c061aSmrg		 * first check for a complete match
825444c061aSmrg		 */
826444c061aSmrg		if (!match) {
827444c061aSmrg		    if (branchHead->hasActions) {
828444c061aSmrg			if (branchHead->isSimple) {
829444c061aSmrg			    static ActionRec	dummyAction;
830444c061aSmrg
831444c061aSmrg			    dummyAction.idx = TMBranchMore(branchHead);
832444c061aSmrg			    actions = &dummyAction;
833444c061aSmrg			}
834444c061aSmrg			else
835444c061aSmrg			  actions = currState->actions;
836444c061aSmrg			tmRecPtr->lastEventTime =
837444c061aSmrg			  GetTime(tmRecPtr, curEventPtr->xev);
838444c061aSmrg			FreeContext((TMContext
839444c061aSmrg				     *)&tmRecPtr->current_state);
840444c061aSmrg			match = True;
841444c061aSmrg			matchTreeIndex = i;
842444c061aSmrg		    }
843444c061aSmrg		    /*
844444c061aSmrg		     * if it doesn't have actions and
845444c061aSmrg		     * it's bc mode then it's a potential match node that is
846444c061aSmrg		     * used to match later sequences.
847444c061aSmrg		     */
848444c061aSmrg		    if (!TMNewMatchSemantics() && !matchExact) {
849444c061aSmrg			matchExact = True;
850444c061aSmrg			typeIndex = branchHead->typeIndex;
851444c061aSmrg			modIndex = branchHead->modIndex;
852444c061aSmrg		    }
853444c061aSmrg		}
854444c061aSmrg		/*
855444c061aSmrg		 * check for it being an event sequence which can be
856444c061aSmrg		 * a future match
857444c061aSmrg		 */
858444c061aSmrg		if (!branchHead->isSimple &&
859444c061aSmrg		    !branchHead->hasActions &&
860444c061aSmrg		    !complexMatchState)
861444c061aSmrg		  complexMatchState = currState;
862444c061aSmrg	    }
863444c061aSmrg	}
864444c061aSmrg    }
865444c061aSmrg    if (match)
866444c061aSmrg      {
867444c061aSmrg	  TMBindData	bindData = (TMBindData) tmRecPtr->proc_table;
868444c061aSmrg	  XtActionProc	*procs;
869444c061aSmrg	  Widget	accelWidget;
870444c061aSmrg
871444c061aSmrg	  if (bindData->simple.isComplex) {
872444c061aSmrg	      TMComplexBindProcs bindProcs =
873444c061aSmrg		TMGetComplexBindEntry(bindData, matchTreeIndex);
874444c061aSmrg	      procs = bindProcs->procs;
875444c061aSmrg	      accelWidget = bindProcs->widget;
876444c061aSmrg	  }
877444c061aSmrg	  else {
878444c061aSmrg	      TMSimpleBindProcs bindProcs =
879444c061aSmrg		TMGetSimpleBindEntry(bindData, matchTreeIndex);
880444c061aSmrg	      procs = bindProcs->procs;
881444c061aSmrg	      accelWidget = NULL;
882444c061aSmrg	  }
883444c061aSmrg	  HandleActions
884444c061aSmrg	    (w,
885444c061aSmrg	     curEventPtr->xev,
886444c061aSmrg	     (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex],
887444c061aSmrg	     accelWidget,
888444c061aSmrg	     procs,
889444c061aSmrg	     actions);
890444c061aSmrg      }
891444c061aSmrg    if (complexMatchState)
892444c061aSmrg      PushContext(contextPtr, complexMatchState);
893444c061aSmrg    UNLOCK_PROCESS;
894444c061aSmrg}
895444c061aSmrg
896444c061aSmrgstatic int MatchComplexBranch(
897444c061aSmrg    TMComplexStateTree	stateTree,
898444c061aSmrg    int			startIndex,
899444c061aSmrg    TMContext		context,
900444c061aSmrg    StatePtr		*leafStateRtn)
901444c061aSmrg{
902444c061aSmrg    TMShortCard	i;
903444c061aSmrg
904444c061aSmrg    LOCK_PROCESS;
905444c061aSmrg    for (i = startIndex; i < stateTree->numComplexBranchHeads; i++)
906444c061aSmrg      {
907444c061aSmrg	  StatePtr	candState;
908444c061aSmrg	  TMShortCard	numMatches = context->numMatches;
909444c061aSmrg	  MatchPair	statMatch = context->matches;
910444c061aSmrg
911444c061aSmrg	  for (candState = stateTree->complexBranchHeadTbl[i];
912444c061aSmrg	       numMatches && candState;
913444c061aSmrg	       numMatches--, statMatch++, candState = candState->nextLevel)
914444c061aSmrg	    {
915444c061aSmrg		if ((statMatch->typeIndex != candState->typeIndex) ||
916444c061aSmrg		    (statMatch->modIndex != candState->modIndex))
917444c061aSmrg		  break;
918444c061aSmrg	    }
919444c061aSmrg	  if (numMatches == 0) {
920444c061aSmrg	      *leafStateRtn = candState;
921444c061aSmrg	      UNLOCK_PROCESS;
922444c061aSmrg	      return i;
923444c061aSmrg	  }
924444c061aSmrg      }
925444c061aSmrg    *leafStateRtn = NULL;
926444c061aSmrg    UNLOCK_PROCESS;
927444c061aSmrg    return (TM_NO_MATCH);
928444c061aSmrg}
929444c061aSmrg
930444c061aSmrgstatic StatePtr TryCurrentTree(
931444c061aSmrg    TMComplexStateTree	*stateTreePtr,
932444c061aSmrg    XtTM		tmRecPtr,
933444c061aSmrg    TMEventRec		*curEventPtr)
934444c061aSmrg{
935444c061aSmrg    StatePtr		candState = NULL, matchState = NULL;
936444c061aSmrg    TMContext		*contextPtr = GetContextPtr(tmRecPtr);
937444c061aSmrg    TMTypeMatch 	typeMatch;
938444c061aSmrg    TMModifierMatch 	modMatch;
939444c061aSmrg    int			currIndex = -1;
940444c061aSmrg
941444c061aSmrg    /*
942444c061aSmrg     * we want the first sequence that both matches and has actions.
943444c061aSmrg     * we keep on looking till we find both
944444c061aSmrg     */
945444c061aSmrg    LOCK_PROCESS;
946444c061aSmrg    while ((currIndex =
947444c061aSmrg	    MatchComplexBranch(*stateTreePtr,
948444c061aSmrg			       ++currIndex,
949444c061aSmrg			       (*contextPtr),
950444c061aSmrg			       &candState))
951444c061aSmrg	   != TM_NO_MATCH) {
952444c061aSmrg	if (candState  != NULL) {
953444c061aSmrg	    typeMatch  = TMGetTypeMatch(candState->typeIndex);
954444c061aSmrg	    modMatch = TMGetModifierMatch(candState->modIndex);
955444c061aSmrg
956444c061aSmrg	    /* does this state's index match? --> done */
957444c061aSmrg	    if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch))
958444c061aSmrg	      {
959444c061aSmrg		  if (candState->actions) {
960444c061aSmrg		      UNLOCK_PROCESS;
961444c061aSmrg		      return candState;
962444c061aSmrg		  }
963444c061aSmrg		  else
964444c061aSmrg		    matchState = candState;
965444c061aSmrg	      }
966444c061aSmrg	    /* is this an event timer? */
967444c061aSmrg	    if (typeMatch->eventType == _XtEventTimerEventType) {
968444c061aSmrg		StatePtr nextState = candState->nextLevel;
969444c061aSmrg
970444c061aSmrg		/* does the succeeding state match? */
971444c061aSmrg		if (nextState != NULL) {
972444c061aSmrg		    TMTypeMatch 	nextTypeMatch;
973444c061aSmrg		    TMModifierMatch	nextModMatch;
974444c061aSmrg
975444c061aSmrg		    nextTypeMatch  = TMGetTypeMatch(nextState->typeIndex);
976444c061aSmrg		    nextModMatch = TMGetModifierMatch(nextState->modIndex);
977444c061aSmrg
978444c061aSmrg		    /* is it within the timeout? */
979444c061aSmrg		    if (MatchIncomingEvent(curEventPtr,
980444c061aSmrg					   nextTypeMatch,
981444c061aSmrg					   nextModMatch)) {
982444c061aSmrg			XEvent *xev = curEventPtr->xev;
983444c061aSmrg			unsigned long time = GetTime(tmRecPtr, xev);
984444c061aSmrg			XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
985444c061aSmrg			unsigned long delta = pd->multi_click_time;
986444c061aSmrg
987444c061aSmrg			if ((tmRecPtr->lastEventTime + delta) >= time) {
988444c061aSmrg			    if (nextState->actions) {
989444c061aSmrg				UNLOCK_PROCESS;
990444c061aSmrg				return candState;
991444c061aSmrg			    }
992444c061aSmrg			    else
993444c061aSmrg			      matchState = candState;
994444c061aSmrg			}
995444c061aSmrg		    }
996444c061aSmrg		}
997444c061aSmrg	    }
998444c061aSmrg	}
999444c061aSmrg    }
1000444c061aSmrg    UNLOCK_PROCESS;
1001444c061aSmrg    return matchState;
1002444c061aSmrg}
1003444c061aSmrg
1004444c061aSmrgstatic void HandleComplexState(
1005444c061aSmrg    Widget	w,
1006444c061aSmrg    XtTM	tmRecPtr,
1007444c061aSmrg    TMEventRec	*curEventPtr)
1008444c061aSmrg{
1009444c061aSmrg    XtTranslations 	xlations = tmRecPtr->translations;
1010444c061aSmrg    TMContext		*contextPtr = GetContextPtr(tmRecPtr);
1011444c061aSmrg    TMShortCard		i, matchTreeIndex = 0;
1012444c061aSmrg    StatePtr		matchState = NULL, candState;
1013444c061aSmrg    TMComplexStateTree 	*stateTreePtr =
1014444c061aSmrg      (TMComplexStateTree *)&xlations->stateTreeTbl[0];
1015444c061aSmrg
1016444c061aSmrg    LOCK_PROCESS;
1017444c061aSmrg    for (i = 0;
1018444c061aSmrg	 i < xlations->numStateTrees;
1019444c061aSmrg	 i++, stateTreePtr++) {
1020444c061aSmrg	/*
1021444c061aSmrg	 * some compilers sign extend Boolean bit fields so test for
1022444c061aSmrg	 * false |||
1023444c061aSmrg	 */
1024444c061aSmrg	if (((*stateTreePtr)->isSimple == False) &&
1025444c061aSmrg	    (candState = TryCurrentTree(stateTreePtr,
1026444c061aSmrg				       tmRecPtr,
1027444c061aSmrg				       curEventPtr))) {
1028444c061aSmrg	    if (!matchState || candState->actions) {
1029444c061aSmrg		matchTreeIndex = i;
1030444c061aSmrg		matchState = candState;
1031444c061aSmrg		if (candState->actions)
1032444c061aSmrg		    break;
1033444c061aSmrg	    }
1034444c061aSmrg	}
1035444c061aSmrg    }
1036444c061aSmrg    if (matchState == NULL){
1037444c061aSmrg	/* couldn't find it... */
1038444c061aSmrg	if (!Ignore(curEventPtr))
1039444c061aSmrg	  {
1040444c061aSmrg	      FreeContext(contextPtr);
1041444c061aSmrg	      HandleSimpleState(w, tmRecPtr, curEventPtr);
1042444c061aSmrg	  }
1043444c061aSmrg    }
1044444c061aSmrg    else {
1045444c061aSmrg	TMBindData	bindData = (TMBindData) tmRecPtr->proc_table;
1046444c061aSmrg	XtActionProc	*procs;
1047444c061aSmrg	Widget		accelWidget;
1048444c061aSmrg	TMTypeMatch 	typeMatch;
1049444c061aSmrg
1050444c061aSmrg	typeMatch  = TMGetTypeMatch(matchState->typeIndex);
1051444c061aSmrg
1052444c061aSmrg	PushContext(contextPtr, matchState);
1053444c061aSmrg	if (typeMatch->eventType == _XtEventTimerEventType) {
1054444c061aSmrg	    matchState = matchState->nextLevel;
1055444c061aSmrg	    PushContext(contextPtr, matchState);
1056444c061aSmrg	}
1057444c061aSmrg	tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev);
1058444c061aSmrg
1059444c061aSmrg	if (bindData->simple.isComplex) {
1060444c061aSmrg	    TMComplexBindProcs bindProcs =
1061444c061aSmrg	      TMGetComplexBindEntry(bindData, matchTreeIndex);
1062444c061aSmrg	    procs = bindProcs->procs;
1063444c061aSmrg	    accelWidget = bindProcs->widget;
1064444c061aSmrg	}
1065444c061aSmrg	else {
1066444c061aSmrg	    TMSimpleBindProcs bindProcs =
1067444c061aSmrg	      TMGetSimpleBindEntry(bindData, matchTreeIndex);
1068444c061aSmrg	    procs = bindProcs->procs;
1069444c061aSmrg	    accelWidget = NULL;
1070444c061aSmrg	}
1071444c061aSmrg	HandleActions(w,
1072444c061aSmrg		      curEventPtr->xev,
1073444c061aSmrg		      (TMSimpleStateTree)
1074444c061aSmrg		      xlations->stateTreeTbl[matchTreeIndex],
1075444c061aSmrg		      accelWidget,
1076444c061aSmrg		      procs,
1077444c061aSmrg		      matchState->actions);
1078444c061aSmrg    }
1079444c061aSmrg    UNLOCK_PROCESS;
1080444c061aSmrg}
1081444c061aSmrg
1082444c061aSmrg
1083444c061aSmrgvoid _XtTranslateEvent (
1084444c061aSmrg    Widget w,
1085444c061aSmrg    XEvent * event)
1086444c061aSmrg{
1087444c061aSmrg    XtTM	tmRecPtr = &w->core.tm;
1088444c061aSmrg    TMEventRec 	curEvent;
1089444c061aSmrg    StatePtr 	current_state = tmRecPtr->current_state;
1090444c061aSmrg
1091444c061aSmrg    XEventToTMEvent (event, &curEvent);
1092444c061aSmrg
1093444c061aSmrg    if (! tmRecPtr->translations) {
1094444c061aSmrg        XtAppWarningMsg(XtWidgetToApplicationContext(w),
1095444c061aSmrg			XtNtranslationError,"nullTable",XtCXtToolkitError,
1096444c061aSmrg			"Can't translate event through NULL table",
1097444c061aSmrg			(String *)NULL, (Cardinal *)NULL);
1098444c061aSmrg	return ;
1099444c061aSmrg    }
1100444c061aSmrg    if (current_state == NULL)
1101444c061aSmrg	  HandleSimpleState(w, tmRecPtr, &curEvent);
1102444c061aSmrg    else
1103444c061aSmrg	  HandleComplexState(w, tmRecPtr, &curEvent);
1104444c061aSmrg}
1105444c061aSmrg
1106444c061aSmrg
1107444c061aSmrg/*ARGSUSED*/
1108444c061aSmrgstatic StatePtr NewState(
1109444c061aSmrg    TMParseStateTree stateTree,
1110444c061aSmrg    TMShortCard	typeIndex,
1111444c061aSmrg    TMShortCard	modIndex)
1112444c061aSmrg{
1113444c061aSmrg    StatePtr state = XtNew(StateRec);
1114444c061aSmrg
1115444c061aSmrg#ifdef TRACE_TM
1116444c061aSmrg    LOCK_PROCESS;
1117444c061aSmrg    _XtGlobalTM.numComplexStates++;
1118444c061aSmrg    UNLOCK_PROCESS;
1119444c061aSmrg#endif /* TRACE_TM */
1120444c061aSmrg    state->typeIndex = typeIndex;
1121444c061aSmrg    state->modIndex = modIndex;
1122444c061aSmrg    state->nextLevel = NULL;
1123444c061aSmrg    state->actions = NULL;
1124444c061aSmrg    state->isCycleStart = state->isCycleEnd = False;
1125444c061aSmrg    return state;
1126444c061aSmrg}
1127444c061aSmrg
1128444c061aSmrg/*
1129444c061aSmrg * This routine is an iterator for state trees. If the func returns
1130444c061aSmrg * true then iteration is over.
1131444c061aSmrg */
1132444c061aSmrgvoid _XtTraverseStateTree(
1133444c061aSmrg    TMStateTree	tree,
1134444c061aSmrg    _XtTraversalProc func,
1135444c061aSmrg    XtPointer 	data)
1136444c061aSmrg{
1137444c061aSmrg    TMComplexStateTree stateTree = (TMComplexStateTree)tree;
1138444c061aSmrg    TMBranchHead	currBH;
1139444c061aSmrg    TMShortCard		i;
1140444c061aSmrg    StateRec		dummyStateRec, *dummyState = &dummyStateRec;
1141444c061aSmrg    ActionRec		dummyActionRec, *dummyAction = &dummyActionRec;
1142444c061aSmrg    Boolean		firstSimple = True;
1143444c061aSmrg    StatePtr 		currState;
1144444c061aSmrg
1145444c061aSmrg    /* first traverse the complex states */
1146444c061aSmrg    if (stateTree->isSimple == False)
1147444c061aSmrg      for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
1148444c061aSmrg	  currState = stateTree->complexBranchHeadTbl[i];
1149444c061aSmrg	  for (; currState; currState = currState->nextLevel) {
1150444c061aSmrg	      if (func(currState, data))
1151444c061aSmrg		return;
1152444c061aSmrg	      if (currState->isCycleEnd)
1153444c061aSmrg		break;
1154444c061aSmrg	  }
1155444c061aSmrg      }
1156444c061aSmrg
1157444c061aSmrg    /* now traverse the simple ones */
1158444c061aSmrg    for (i = 0, currBH = stateTree->branchHeadTbl;
1159444c061aSmrg	 i < stateTree->numBranchHeads;
1160444c061aSmrg	 i++, currBH++)
1161444c061aSmrg      {
1162444c061aSmrg	  if (currBH->isSimple && currBH->hasActions)
1163444c061aSmrg	    {
1164444c061aSmrg		if (firstSimple)
1165444c061aSmrg		  {
1166444c061aSmrg		      XtBZero((char *) dummyState, sizeof(StateRec));
1167444c061aSmrg		      XtBZero((char *) dummyAction, sizeof(ActionRec));
1168444c061aSmrg		      dummyState->actions = dummyAction;
1169444c061aSmrg		      firstSimple = False;
1170444c061aSmrg		  }
1171444c061aSmrg		dummyState->typeIndex = currBH->typeIndex;
1172444c061aSmrg		dummyState->modIndex = currBH->modIndex;
1173444c061aSmrg		dummyAction->idx = currBH->more;
1174444c061aSmrg		if (func(dummyState, data))
1175444c061aSmrg		  return;
1176444c061aSmrg	    }
1177444c061aSmrg      }
1178444c061aSmrg}
1179444c061aSmrg
1180444c061aSmrgstatic EventMask EventToMask(
1181444c061aSmrg    TMTypeMatch     typeMatch,
1182444c061aSmrg    TMModifierMatch modMatch)
1183444c061aSmrg{
1184444c061aSmrg    EventMask returnMask;
1185444c061aSmrg    unsigned long eventType = typeMatch->eventType;
1186444c061aSmrg
1187444c061aSmrg    if (eventType == MotionNotify) {
1188444c061aSmrg        Modifiers modifierMask = modMatch->modifierMask;
1189444c061aSmrg        Modifiers tempMask;
1190444c061aSmrg
1191444c061aSmrg	returnMask = 0;
1192444c061aSmrg        if (modifierMask == 0) {
1193444c061aSmrg	    if (modMatch->modifiers == AnyButtonMask)
1194444c061aSmrg		return ButtonMotionMask;
1195444c061aSmrg	    else
1196444c061aSmrg		return PointerMotionMask;
1197444c061aSmrg	}
1198444c061aSmrg        tempMask = modifierMask &
1199444c061aSmrg	    (Button1Mask | Button2Mask | Button3Mask
1200444c061aSmrg	     | Button4Mask | Button5Mask);
1201444c061aSmrg        if (tempMask == 0)
1202444c061aSmrg	    return PointerMotionMask;
1203444c061aSmrg        if (tempMask & Button1Mask)
1204444c061aSmrg            returnMask |= Button1MotionMask;
1205444c061aSmrg        if (tempMask & Button2Mask)
1206444c061aSmrg            returnMask |= Button2MotionMask;
1207444c061aSmrg        if (tempMask & Button3Mask)
1208444c061aSmrg            returnMask |= Button3MotionMask;
1209444c061aSmrg        if (tempMask & Button4Mask)
1210444c061aSmrg            returnMask |= Button4MotionMask;
1211444c061aSmrg        if (tempMask & Button5Mask)
1212444c061aSmrg            returnMask |= Button5MotionMask;
1213444c061aSmrg        return returnMask;
1214444c061aSmrg    }
1215444c061aSmrg    returnMask = _XtConvertTypeToMask(eventType);
1216444c061aSmrg    if (returnMask == (StructureNotifyMask|SubstructureNotifyMask))
1217444c061aSmrg	returnMask = StructureNotifyMask;
1218444c061aSmrg    return returnMask;
1219444c061aSmrg}
1220444c061aSmrg
1221444c061aSmrg/*ARGSUSED*/
1222444c061aSmrgstatic void DispatchMappingNotify(
1223444c061aSmrg    Widget widget,		/* will be NULL from _RefreshMapping */
1224444c061aSmrg    XtPointer closure,		/* real Widget */
1225444c061aSmrg    XtPointer call_data)	/* XEvent* */
1226444c061aSmrg{
1227444c061aSmrg    _XtTranslateEvent( (Widget)closure, (XEvent*)call_data);
1228444c061aSmrg}
1229444c061aSmrg
1230444c061aSmrg
1231444c061aSmrg/*ARGSUSED*/
1232444c061aSmrgstatic void RemoveFromMappingCallbacks(
1233444c061aSmrg    Widget widget,
1234444c061aSmrg    XtPointer closure,		/* target widget */
1235444c061aSmrg    XtPointer call_data)
1236444c061aSmrg{
1237444c061aSmrg    _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
1238444c061aSmrg		       DispatchMappingNotify,
1239444c061aSmrg		       closure
1240444c061aSmrg		      );
1241444c061aSmrg}
1242444c061aSmrg
1243444c061aSmrgstatic Boolean AggregateEventMask(
1244444c061aSmrg    StatePtr	state,
1245444c061aSmrg    XtPointer	data)
1246444c061aSmrg{
1247444c061aSmrg    LOCK_PROCESS;
1248444c061aSmrg    *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex),
1249444c061aSmrg					TMGetModifierMatch(state->modIndex));
1250444c061aSmrg    UNLOCK_PROCESS;
1251444c061aSmrg    return False;
1252444c061aSmrg}
1253444c061aSmrg
1254444c061aSmrgvoid _XtInstallTranslations(
1255444c061aSmrg    Widget widget)
1256444c061aSmrg{
1257444c061aSmrg    XtTranslations xlations;
1258444c061aSmrg    Cardinal	i;
1259444c061aSmrg    TMStateTree	stateTree;
1260444c061aSmrg    Boolean  mappingNotifyInterest = False;
1261444c061aSmrg
1262444c061aSmrg    xlations = widget->core.tm.translations;
1263444c061aSmrg    if (xlations == NULL) return;
1264444c061aSmrg
1265444c061aSmrg    /*
1266444c061aSmrg     * check for somebody stuffing the translations directly into the
1267444c061aSmrg     * instance structure. We will end up being called again out of
1268444c061aSmrg     * ComposeTranslations but we *should* have bindings by then
1269444c061aSmrg     */
1270444c061aSmrg    if (widget->core.tm.proc_table == NULL) {
1271444c061aSmrg	_XtMergeTranslations(widget, NULL, XtTableReplace);
1272444c061aSmrg	/*
1273444c061aSmrg	 * if we're realized then we'll be called out of
1274444c061aSmrg	 * ComposeTranslations
1275444c061aSmrg	 */
1276444c061aSmrg	if (XtIsRealized(widget))
1277444c061aSmrg	  return;
1278444c061aSmrg    }
1279444c061aSmrg
1280444c061aSmrg    xlations->eventMask = 0;
1281444c061aSmrg    for (i = 0;
1282444c061aSmrg	 i < xlations->numStateTrees;
1283444c061aSmrg	 i++)
1284444c061aSmrg      {
1285444c061aSmrg	  stateTree = xlations->stateTreeTbl[i];
1286444c061aSmrg	  _XtTraverseStateTree(stateTree,
1287444c061aSmrg			    AggregateEventMask,
1288444c061aSmrg			    (XtPointer)&xlations->eventMask);
1289444c061aSmrg	  mappingNotifyInterest |= stateTree->simple.mappingNotifyInterest;
1290444c061aSmrg      }
1291444c061aSmrg    /* double click needs to make sure that you have selected on both
1292444c061aSmrg	button down and up. */
1293444c061aSmrg
1294444c061aSmrg    if (xlations->eventMask & ButtonPressMask)
1295444c061aSmrg      xlations->eventMask |= ButtonReleaseMask;
1296444c061aSmrg    if (xlations->eventMask & ButtonReleaseMask)
1297444c061aSmrg      xlations->eventMask |= ButtonPressMask;
1298444c061aSmrg
1299444c061aSmrg    if (mappingNotifyInterest) {
1300444c061aSmrg	XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
1301444c061aSmrg	if (pd->mapping_callbacks)
1302444c061aSmrg	    _XtAddCallbackOnce(&(pd->mapping_callbacks),
1303444c061aSmrg			       DispatchMappingNotify,
1304444c061aSmrg			       (XtPointer)widget);
1305444c061aSmrg	else
1306444c061aSmrg	    _XtAddCallback(&(pd->mapping_callbacks),
1307444c061aSmrg			   DispatchMappingNotify,
1308444c061aSmrg			   (XtPointer)widget);
1309444c061aSmrg
1310444c061aSmrg	if (widget->core.destroy_callbacks != NULL)
1311444c061aSmrg	    _XtAddCallbackOnce( (InternalCallbackList *)
1312444c061aSmrg			        &widget->core.destroy_callbacks,
1313444c061aSmrg				RemoveFromMappingCallbacks,
1314444c061aSmrg				(XtPointer)widget
1315444c061aSmrg			       );
1316444c061aSmrg	else
1317444c061aSmrg	    _XtAddCallback((InternalCallbackList *)
1318444c061aSmrg			   &widget->core.destroy_callbacks,
1319444c061aSmrg			   RemoveFromMappingCallbacks,
1320444c061aSmrg			   (XtPointer)widget
1321444c061aSmrg			  );
1322444c061aSmrg    }
1323444c061aSmrg    _XtBindActions(widget, (XtTM)&widget->core.tm);
1324444c061aSmrg    _XtRegisterGrabs(widget);
1325444c061aSmrg}
1326444c061aSmrg
1327444c061aSmrgvoid _XtRemoveTranslations(
1328444c061aSmrg    Widget widget)
1329444c061aSmrg{
1330444c061aSmrg    Cardinal	i;
1331444c061aSmrg    TMSimpleStateTree	stateTree;
1332444c061aSmrg    Boolean  		mappingNotifyInterest = False;
1333444c061aSmrg    XtTranslations		xlations = widget->core.tm.translations;
1334444c061aSmrg
1335444c061aSmrg    if (xlations == NULL)
1336444c061aSmrg      return;
1337444c061aSmrg
1338444c061aSmrg    for (i = 0;
1339444c061aSmrg	 i < xlations->numStateTrees;
1340444c061aSmrg	 i++)
1341444c061aSmrg      {
1342444c061aSmrg	  stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i];
1343444c061aSmrg	  mappingNotifyInterest |= stateTree->mappingNotifyInterest;
1344444c061aSmrg      }
1345444c061aSmrg    if (mappingNotifyInterest)
1346444c061aSmrg      RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL);
1347444c061aSmrg}
1348444c061aSmrg
1349444c061aSmrgstatic void _XtUninstallTranslations(
1350444c061aSmrg    Widget widget)
1351444c061aSmrg{
1352444c061aSmrg    XtTranslations	xlations = widget->core.tm.translations;
1353444c061aSmrg
1354444c061aSmrg    _XtUnbindActions(widget,
1355444c061aSmrg		     xlations,
1356444c061aSmrg		     (TMBindData)widget->core.tm.proc_table);
1357444c061aSmrg    _XtRemoveTranslations(widget);
1358444c061aSmrg    widget->core.tm.translations = NULL;
1359444c061aSmrg    FreeContext((TMContext *)&widget->core.tm.current_state);
1360444c061aSmrg}
1361444c061aSmrg
1362444c061aSmrgvoid _XtDestroyTMData(
1363444c061aSmrg    Widget	widget)
1364444c061aSmrg{
1365444c061aSmrg    TMComplexBindData	cBindData;
1366444c061aSmrg
1367444c061aSmrg    _XtUninstallTranslations(widget);
1368444c061aSmrg
1369444c061aSmrg    if ((cBindData = (TMComplexBindData)widget->core.tm.proc_table)) {
1370444c061aSmrg	if (cBindData->isComplex) {
1371444c061aSmrg	    ATranslations	aXlations, nXlations;
1372444c061aSmrg
1373444c061aSmrg	    nXlations = (ATranslations) cBindData->accel_context;
1374444c061aSmrg	    while (nXlations){
1375444c061aSmrg		aXlations = nXlations;
1376444c061aSmrg		nXlations = nXlations->next;
1377444c061aSmrg		XtFree((char *)aXlations);
1378444c061aSmrg	    }
1379444c061aSmrg	}
1380444c061aSmrg	XtFree((char *)cBindData);
1381444c061aSmrg    }
1382444c061aSmrg}
1383444c061aSmrg
1384444c061aSmrg/*** Public procedures ***/
1385444c061aSmrg
1386444c061aSmrg
1387444c061aSmrgvoid XtUninstallTranslations(
1388444c061aSmrg    Widget widget)
1389444c061aSmrg{
1390444c061aSmrg    EventMask	oldMask;
1391444c061aSmrg    Widget hookobj;
1392444c061aSmrg    WIDGET_TO_APPCON(widget);
1393444c061aSmrg
1394444c061aSmrg    LOCK_APP(app);
1395444c061aSmrg    if (! widget->core.tm.translations) {
1396444c061aSmrg	UNLOCK_APP(app);
1397444c061aSmrg	return;
1398444c061aSmrg    }
1399444c061aSmrg    oldMask = widget->core.tm.translations->eventMask;
1400444c061aSmrg    _XtUninstallTranslations(widget);
1401444c061aSmrg    if (XtIsRealized(widget) && oldMask)
1402444c061aSmrg	XSelectInput(XtDisplay(widget), XtWindow(widget),
1403444c061aSmrg		     XtBuildEventMask(widget));
1404444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
1405444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
1406444c061aSmrg	XtChangeHookDataRec call_data;
1407444c061aSmrg
1408444c061aSmrg	call_data.type = XtHuninstallTranslations;
1409444c061aSmrg	call_data.widget = widget;
1410444c061aSmrg	XtCallCallbackList(hookobj,
1411444c061aSmrg		((HookObject)hookobj)->hooks.changehook_callbacks,
1412444c061aSmrg		(XtPointer)&call_data);
1413444c061aSmrg    }
1414444c061aSmrg    UNLOCK_APP(app);
1415444c061aSmrg}
1416444c061aSmrg
1417444c061aSmrgXtTranslations _XtCreateXlations(
1418444c061aSmrg    TMStateTree		*stateTrees,
1419444c061aSmrg    TMShortCard		numStateTrees,
1420444c061aSmrg    XtTranslations	first,
1421444c061aSmrg    XtTranslations	second)
1422444c061aSmrg{
1423444c061aSmrg    XtTranslations	xlations;
1424444c061aSmrg    TMShortCard i;
1425444c061aSmrg
1426444c061aSmrg    xlations = (XtTranslations)
1427444c061aSmrg      __XtMalloc(sizeof(TranslationData) +
1428444c061aSmrg	       (numStateTrees-1) * sizeof(TMStateTree));
1429444c061aSmrg#ifdef TRACE_TM
1430444c061aSmrg    LOCK_PROCESS;
1431444c061aSmrg    if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
1432444c061aSmrg	_XtGlobalTM.tmTblSize += 16;
1433444c061aSmrg	_XtGlobalTM.tmTbl = (XtTranslations *)
1434444c061aSmrg	  XtRealloc((char *)_XtGlobalTM.tmTbl,
1435444c061aSmrg		   _XtGlobalTM.tmTblSize * sizeof(XtTranslations));
1436444c061aSmrg    }
1437444c061aSmrg    _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
1438444c061aSmrg    UNLOCK_PROCESS;
1439444c061aSmrg#endif /* TRACE_TM */
1440444c061aSmrg
1441444c061aSmrg    xlations->composers[0] = first;
1442444c061aSmrg    xlations->composers[1] = second;
1443444c061aSmrg    xlations->hasBindings = False;
1444444c061aSmrg    xlations->operation = XtTableReplace;
1445444c061aSmrg
1446444c061aSmrg    for (i = 0;i < numStateTrees; i++)
1447444c061aSmrg      {
1448444c061aSmrg	  xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
1449444c061aSmrg	  stateTrees[i]->simple.refCount++;
1450444c061aSmrg      }
1451444c061aSmrg    xlations->numStateTrees = numStateTrees;
1452444c061aSmrg    xlations->eventMask = 0;
1453444c061aSmrg    return xlations;
1454444c061aSmrg}
1455444c061aSmrg
1456444c061aSmrgTMStateTree _XtParseTreeToStateTree(
1457444c061aSmrg    TMParseStateTree	parseTree)
1458444c061aSmrg{
1459444c061aSmrg    TMSimpleStateTree  simpleTree;
1460444c061aSmrg    unsigned int	tableSize;
1461444c061aSmrg
1462444c061aSmrg    if (parseTree->numComplexBranchHeads) {
1463444c061aSmrg	TMComplexStateTree complexTree;
1464444c061aSmrg
1465444c061aSmrg	complexTree = XtNew(TMComplexStateTreeRec);
1466444c061aSmrg	complexTree->isSimple = False;
1467444c061aSmrg	tableSize = parseTree->numComplexBranchHeads * sizeof(StatePtr);
1468444c061aSmrg	complexTree->complexBranchHeadTbl = (StatePtr *)
1469444c061aSmrg	  __XtMalloc(tableSize);
1470444c061aSmrg	XtMemmove(complexTree->complexBranchHeadTbl,
1471444c061aSmrg		  parseTree->complexBranchHeadTbl, tableSize);
1472444c061aSmrg	complexTree->numComplexBranchHeads =
1473444c061aSmrg	  parseTree->numComplexBranchHeads;
1474444c061aSmrg	simpleTree = (TMSimpleStateTree)complexTree;
1475444c061aSmrg    }
1476444c061aSmrg    else {
1477444c061aSmrg	simpleTree = XtNew(TMSimpleStateTreeRec);
1478444c061aSmrg	simpleTree->isSimple = True;
1479444c061aSmrg    }
1480444c061aSmrg    simpleTree->isAccelerator = parseTree->isAccelerator;
1481444c061aSmrg    simpleTree->refCount = 0;
1482444c061aSmrg    simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
1483444c061aSmrg
1484444c061aSmrg    tableSize = parseTree->numBranchHeads * sizeof(TMBranchHeadRec);
1485444c061aSmrg    simpleTree->branchHeadTbl = (TMBranchHead)
1486444c061aSmrg      __XtMalloc(tableSize);
1487444c061aSmrg    XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize);
1488444c061aSmrg    simpleTree->numBranchHeads = parseTree->numBranchHeads;
1489444c061aSmrg
1490444c061aSmrg    tableSize = parseTree->numQuarks * sizeof(XrmQuark);
1491444c061aSmrg    simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize);
1492444c061aSmrg    XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize);
1493444c061aSmrg    simpleTree->numQuarks = parseTree->numQuarks;
1494444c061aSmrg
1495444c061aSmrg    return (TMStateTree)simpleTree;
1496444c061aSmrg}
1497444c061aSmrg
1498444c061aSmrgstatic void FreeActions(
1499444c061aSmrg    ActionPtr	actions)
1500444c061aSmrg{
1501444c061aSmrg    ActionPtr action;
1502444c061aSmrg    TMShortCard i;
1503444c061aSmrg    for (action = actions; action;) {
1504444c061aSmrg	ActionPtr nextAction = action->next;
1505444c061aSmrg	for (i = action->num_params; i;) {
1506444c061aSmrg	    XtFree( action->params[--i] );
1507444c061aSmrg	}
1508444c061aSmrg	XtFree( (char*)action->params );
1509444c061aSmrg	XtFree((char*) action);
1510444c061aSmrg	action = nextAction;
1511444c061aSmrg    }
1512444c061aSmrg}
1513444c061aSmrg
1514444c061aSmrg/*ARGSUSED*/
1515444c061aSmrgstatic void AmbigActions(
1516444c061aSmrg    EventSeqPtr	initialEvent,
1517444c061aSmrg    StatePtr	*state,
1518444c061aSmrg    TMParseStateTree stateTree)
1519444c061aSmrg{
1520444c061aSmrg    String 	params[3];
1521444c061aSmrg    Cardinal 	numParams = 0;
1522444c061aSmrg
1523444c061aSmrg    params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
1524444c061aSmrg    params[numParams++] = _XtPrintActions((*state)->actions,
1525444c061aSmrg					  stateTree->quarkTbl);
1526444c061aSmrg    XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError,
1527444c061aSmrg		  "Previous entry was: %s %s", params, &numParams);
1528444c061aSmrg    XtFree((char *)params[0]);
1529444c061aSmrg    XtFree((char *)params[1]);
1530444c061aSmrg    numParams = 0;
1531444c061aSmrg    params[numParams++]  = _XtPrintActions(initialEvent->actions,
1532444c061aSmrg					   stateTree->quarkTbl);
1533444c061aSmrg    XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError,
1534444c061aSmrg		  "New actions are:%s", params, &numParams);
1535444c061aSmrg    XtFree((char *)params[0]);
1536444c061aSmrg    XtWarningMsg (XtNtranslationError,"ambiguousActions",
1537444c061aSmrg		  XtCXtToolkitError,
1538444c061aSmrg		  "Overriding earlier translation manager actions.",
1539444c061aSmrg		  (String *)NULL, (Cardinal *)NULL);
1540444c061aSmrg
1541444c061aSmrg    FreeActions((*state)->actions);
1542444c061aSmrg    (*state)->actions = NULL;
1543444c061aSmrg}
1544444c061aSmrg
1545444c061aSmrg
1546444c061aSmrgvoid _XtAddEventSeqToStateTree(
1547444c061aSmrg    EventSeqPtr 	eventSeq,
1548444c061aSmrg    TMParseStateTree	stateTree)
1549444c061aSmrg{
1550444c061aSmrg    StatePtr		*state;
1551444c061aSmrg    EventSeqPtr		initialEvent = eventSeq;
1552444c061aSmrg    TMBranchHead	branchHead;
1553444c061aSmrg    TMShortCard		idx, modIndex, typeIndex;
1554444c061aSmrg
1555444c061aSmrg    if (eventSeq == NULL) return;
1556444c061aSmrg
1557444c061aSmrg    /* note that all states in the event seq passed in start out null */
1558444c061aSmrg    /* we fill them in with the matching state as we traverse the list */
1559444c061aSmrg
1560444c061aSmrg    /*
1561444c061aSmrg     * We need to free the parser data structures !!!
1562444c061aSmrg     */
1563444c061aSmrg
1564444c061aSmrg    typeIndex = _XtGetTypeIndex(&eventSeq->event);
1565444c061aSmrg    modIndex = _XtGetModifierIndex(&eventSeq->event);
1566444c061aSmrg    idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
1567444c061aSmrg    branchHead = &stateTree->branchHeadTbl[idx];
1568444c061aSmrg
1569444c061aSmrg    /*
1570444c061aSmrg     * Need to check for pre-existing actions with same lhs |||
1571444c061aSmrg     */
1572444c061aSmrg
1573444c061aSmrg    /*
1574444c061aSmrg     * Check for optimized case. Don't assume that the eventSeq has actions.
1575444c061aSmrg     */
1576444c061aSmrg    if (!eventSeq->next &&
1577444c061aSmrg	 eventSeq->actions &&
1578444c061aSmrg	!eventSeq->actions->next &&
1579444c061aSmrg	!eventSeq->actions->num_params)
1580444c061aSmrg      {
1581444c061aSmrg	  if (eventSeq->event.eventType == MappingNotify)
1582444c061aSmrg	    stateTree->mappingNotifyInterest = True;
1583444c061aSmrg	  branchHead->hasActions = True;
1584444c061aSmrg	  branchHead->more = eventSeq->actions->idx;
1585444c061aSmrg	  FreeActions(eventSeq->actions);
1586444c061aSmrg	  eventSeq->actions = NULL;
1587444c061aSmrg	  return;
1588444c061aSmrg      }
1589444c061aSmrg
1590444c061aSmrg    branchHead->isSimple = False;
1591444c061aSmrg    if (!eventSeq->next)
1592444c061aSmrg      branchHead->hasActions = True;
1593444c061aSmrg    branchHead->more = GetComplexBranchIndex(stateTree, typeIndex, modIndex);
1594444c061aSmrg    state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
1595444c061aSmrg
1596444c061aSmrg    for (;;) {
1597444c061aSmrg	*state = NewState(stateTree, typeIndex, modIndex);
1598444c061aSmrg
1599444c061aSmrg	if (eventSeq->event.eventType == MappingNotify)
1600444c061aSmrg	    stateTree->mappingNotifyInterest = True;
1601444c061aSmrg
1602444c061aSmrg	/* *state now points at state record matching event */
1603444c061aSmrg	eventSeq->state = *state;
1604444c061aSmrg
1605444c061aSmrg	if (eventSeq->actions != NULL) {
1606444c061aSmrg	    if ((*state)->actions != NULL)
1607444c061aSmrg	      AmbigActions(initialEvent, state, stateTree);
1608444c061aSmrg	    (*state)->actions = eventSeq->actions;
1609444c061aSmrg#ifdef TRACE_TM
1610444c061aSmrg	    LOCK_PROCESS
1611444c061aSmrg	    _XtGlobalTM.numComplexActions++;
1612444c061aSmrg	    UNLOCK_PROCESS;
1613444c061aSmrg#endif /* TRACE_TM */
1614444c061aSmrg	}
1615444c061aSmrg
1616444c061aSmrg	if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
1617444c061aSmrg	  break;
1618444c061aSmrg
1619444c061aSmrg	state = &(*state)->nextLevel;
1620444c061aSmrg	typeIndex = _XtGetTypeIndex(&eventSeq->event);
1621444c061aSmrg	modIndex = _XtGetModifierIndex(&eventSeq->event);
1622444c061aSmrg	LOCK_PROCESS;
1623444c061aSmrg	if (!TMNewMatchSemantics()) {
1624444c061aSmrg	    /*
1625444c061aSmrg	     * force a potential empty entry into the branch head
1626444c061aSmrg	     * table in order to emulate old matching behavior
1627444c061aSmrg	     */
1628444c061aSmrg	    (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
1629444c061aSmrg	}
1630444c061aSmrg	UNLOCK_PROCESS;
1631444c061aSmrg    }
1632444c061aSmrg
1633444c061aSmrg    if (eventSeq && eventSeq->state) {
1634444c061aSmrg	/* we've been here before... must be a cycle in the event seq. */
1635444c061aSmrg	branchHead->hasCycles = True;
1636444c061aSmrg	(*state)->nextLevel = eventSeq->state;
1637444c061aSmrg	eventSeq->state->isCycleStart = True;
1638444c061aSmrg	(*state)->isCycleEnd = TRUE;
1639444c061aSmrg    }
1640444c061aSmrg}
1641444c061aSmrg
1642444c061aSmrg
1643444c061aSmrg/*
1644444c061aSmrg * Internal Converter for merging. Old and New must both be valid xlations
1645444c061aSmrg */
1646444c061aSmrg
1647444c061aSmrg/*ARGSUSED*/
1648444c061aSmrgBoolean _XtCvtMergeTranslations(
1649444c061aSmrg    Display	*dpy,
1650444c061aSmrg    XrmValuePtr args,
1651444c061aSmrg    Cardinal    *num_args,
1652444c061aSmrg    XrmValuePtr from,
1653444c061aSmrg    XrmValuePtr to,
1654444c061aSmrg    XtPointer	*closure_ret)
1655444c061aSmrg{
1656444c061aSmrg    XtTranslations 	first, second, xlations;
1657444c061aSmrg    TMStateTree		*stateTrees, stackStateTrees[16];
1658444c061aSmrg    TMShortCard		numStateTrees, i;
1659444c061aSmrg
1660444c061aSmrg    if (*num_args != 0)
1661444c061aSmrg	XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError,
1662444c061aSmrg             "MergeTM to TranslationTable needs no extra arguments",
1663444c061aSmrg               (String *)NULL, (Cardinal *)NULL);
1664444c061aSmrg
1665444c061aSmrg    if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
1666444c061aSmrg	to->size = sizeof(XtTranslations);
1667444c061aSmrg	return False;
1668444c061aSmrg    }
1669444c061aSmrg
1670444c061aSmrg    first = ((TMConvertRec*)from->addr)->old;
1671444c061aSmrg    second = ((TMConvertRec*)from->addr)->new;
1672444c061aSmrg
1673444c061aSmrg    numStateTrees = first->numStateTrees + second->numStateTrees;
1674444c061aSmrg
1675444c061aSmrg    stateTrees = (TMStateTree *)
1676444c061aSmrg      XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
1677444c061aSmrg
1678444c061aSmrg    for (i = 0; i < first->numStateTrees; i++)
1679444c061aSmrg      stateTrees[i] = first->stateTreeTbl[i];
1680444c061aSmrg    for (i = 0; i < second->numStateTrees; i++)
1681444c061aSmrg      stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
1682444c061aSmrg
1683444c061aSmrg    xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
1684444c061aSmrg
1685444c061aSmrg    if (to->addr != NULL) {
1686444c061aSmrg	*(XtTranslations*)to->addr = xlations;
1687444c061aSmrg    }
1688444c061aSmrg    else {
1689444c061aSmrg	static XtTranslations staticStateTable;
1690444c061aSmrg	staticStateTable = xlations;
1691444c061aSmrg	to->addr= (XPointer)&staticStateTable;
1692444c061aSmrg	to->size = sizeof(XtTranslations);
1693444c061aSmrg    }
1694444c061aSmrg
1695444c061aSmrg    XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees);
1696444c061aSmrg    return True;
1697444c061aSmrg}
1698444c061aSmrg
1699444c061aSmrg
1700444c061aSmrgstatic XtTranslations MergeThem(
1701444c061aSmrg    Widget		dest,
1702444c061aSmrg    XtTranslations	first,
1703444c061aSmrg    XtTranslations	second)
1704444c061aSmrg{
1705444c061aSmrg    XtCacheRef 		cache_ref;
1706444c061aSmrg    static XrmQuark 	from_type = NULLQUARK, to_type;
1707444c061aSmrg    XrmValue 		from, to;
1708444c061aSmrg    TMConvertRec 	convert_rec;
1709444c061aSmrg    XtTranslations	newTable;
1710444c061aSmrg
1711444c061aSmrg    LOCK_PROCESS;
1712444c061aSmrg    if (from_type == NULLQUARK) {
1713444c061aSmrg	from_type = XrmPermStringToQuark(_XtRStateTablePair);
1714444c061aSmrg	to_type = XrmPermStringToQuark(XtRTranslationTable);
1715444c061aSmrg    }
1716444c061aSmrg    UNLOCK_PROCESS;
1717444c061aSmrg    from.addr = (XPointer)&convert_rec;
1718444c061aSmrg    from.size = sizeof(TMConvertRec);
1719444c061aSmrg    to.addr = (XPointer)&newTable;
1720444c061aSmrg    to.size = sizeof(XtTranslations);
1721444c061aSmrg    convert_rec.old = first;
1722444c061aSmrg    convert_rec.new = second;
1723444c061aSmrg
1724444c061aSmrg    LOCK_PROCESS;
1725444c061aSmrg    if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) {
1726444c061aSmrg	UNLOCK_PROCESS;
1727444c061aSmrg	return NULL;
1728444c061aSmrg    }
1729444c061aSmrg    UNLOCK_PROCESS;
1730444c061aSmrg
1731444c061aSmrg#ifndef REFCNT_TRANSLATIONS
1732444c061aSmrg
1733444c061aSmrg    if (cache_ref)
1734444c061aSmrg	XtAddCallback(dest, XtNdestroyCallback,
1735444c061aSmrg		      XtCallbackReleaseCacheRef, (XtPointer)cache_ref);
1736444c061aSmrg
1737444c061aSmrg#endif
1738444c061aSmrg
1739444c061aSmrg    return newTable;
1740444c061aSmrg}
1741444c061aSmrg
1742444c061aSmrg/*
1743444c061aSmrg * Unmerge will recursively traverse the xlation compose tree and
1744444c061aSmrg * generate a new xlation that is the result of all instances of
1745444c061aSmrg * xlations being removed. It currently doesn't differentiate between
1746444c061aSmrg * the potential that an xlation will be both an accelerator and
1747444c061aSmrg * normal. This is not supported by the spec anyway.
1748444c061aSmrg */
1749444c061aSmrgstatic XtTranslations UnmergeTranslations(
1750444c061aSmrg    Widget		widget,
1751444c061aSmrg    XtTranslations	xlations,
1752444c061aSmrg    XtTranslations	unmergeXlations,
1753444c061aSmrg    TMShortCard		currIndex,
1754444c061aSmrg    TMComplexBindProcs	oldBindings,
1755444c061aSmrg    TMShortCard		numOldBindings,
1756444c061aSmrg    TMComplexBindProcs	newBindings,
1757444c061aSmrg    TMShortCard		*numNewBindingsRtn)
1758444c061aSmrg
1759444c061aSmrg{
1760444c061aSmrg    XtTranslations first, second, result;
1761444c061aSmrg
1762444c061aSmrg    if (!xlations || (xlations == unmergeXlations))
1763444c061aSmrg      return NULL;
1764444c061aSmrg
1765444c061aSmrg    if (xlations->composers[0]) {
1766444c061aSmrg	first = UnmergeTranslations(widget, xlations->composers[0],
1767444c061aSmrg				    unmergeXlations,  currIndex,
1768444c061aSmrg				    oldBindings, numOldBindings,
1769444c061aSmrg				    newBindings, numNewBindingsRtn);
1770444c061aSmrg    }
1771444c061aSmrg    else
1772444c061aSmrg      first = NULL;
1773444c061aSmrg
1774444c061aSmrg    if (xlations->composers[1]) {
1775444c061aSmrg	second = UnmergeTranslations(widget, xlations->composers[1],
1776444c061aSmrg				     unmergeXlations,
1777444c061aSmrg				     currIndex +
1778444c061aSmrg				     xlations->composers[0]->numStateTrees,
1779444c061aSmrg				     oldBindings, numOldBindings,
1780444c061aSmrg				     newBindings, numNewBindingsRtn);
1781444c061aSmrg    }
1782444c061aSmrg    else
1783444c061aSmrg      second = NULL;
1784444c061aSmrg
1785444c061aSmrg    if (first || second) {
1786444c061aSmrg	if (first && second) {
1787444c061aSmrg	    if ((first != xlations->composers[0]) ||
1788444c061aSmrg		(second != xlations->composers[1]))
1789444c061aSmrg	      result = MergeThem(widget, first, second);
1790444c061aSmrg	    else result = xlations;
1791444c061aSmrg	}
1792444c061aSmrg	else {
1793444c061aSmrg	    if (first)
1794444c061aSmrg	      result = first;
1795444c061aSmrg	    else
1796444c061aSmrg	      result = second;
1797444c061aSmrg	}
1798444c061aSmrg    } else { /* only update for leaf nodes */
1799444c061aSmrg  	if (numOldBindings) {
1800444c061aSmrg 	    Cardinal	i;
1801444c061aSmrg 	    for (i = 0; i < xlations->numStateTrees; i++) {
1802444c061aSmrg 		if (xlations->stateTreeTbl[i]->simple.isAccelerator)
1803444c061aSmrg		    newBindings[*numNewBindingsRtn] =
1804444c061aSmrg			oldBindings[currIndex + i];
1805444c061aSmrg 		(*numNewBindingsRtn)++;
1806444c061aSmrg	    }
1807444c061aSmrg	}
1808444c061aSmrg	result = xlations;
1809444c061aSmrg    }
1810444c061aSmrg    return result;
1811444c061aSmrg}
1812444c061aSmrg
1813444c061aSmrgtypedef struct {
1814444c061aSmrg    XtTranslations xlations;
1815444c061aSmrg    TMComplexBindProcs bindings;
1816444c061aSmrg}MergeBindRec, *MergeBind;
1817444c061aSmrg
1818444c061aSmrgstatic XtTranslations MergeTranslations(
1819444c061aSmrg    Widget		widget,
1820444c061aSmrg    XtTranslations	oldXlations,
1821444c061aSmrg    XtTranslations	newXlations,
1822444c061aSmrg    _XtTranslateOp	operation,
1823444c061aSmrg    Widget		source,
1824444c061aSmrg    TMComplexBindProcs	oldBindings,
1825444c061aSmrg    TMComplexBindProcs	newBindings,
1826444c061aSmrg    TMShortCard		*numNewRtn)
1827444c061aSmrg{
1828444c061aSmrg    XtTranslations      newTable = NULL, xlations;
1829444c061aSmrg    TMComplexBindProcs	bindings;
1830444c061aSmrg    TMShortCard		i, j;
1831444c061aSmrg    TMStateTree 	*treePtr;
1832444c061aSmrg    TMShortCard		numNew = *numNewRtn;
1833444c061aSmrg    MergeBindRec	bindPair[2];
1834444c061aSmrg
1835444c061aSmrg    /* If the new translation has an accelerator context then pull it
1836444c061aSmrg     * off and pass it and the real xlations in to the caching merge
1837444c061aSmrg     * routine.
1838444c061aSmrg     */
1839444c061aSmrg    if (newXlations->hasBindings) {
1840444c061aSmrg	xlations = ((ATranslations) newXlations)->xlations;
1841444c061aSmrg	bindings = (TMComplexBindProcs)
1842444c061aSmrg	    &((ATranslations) newXlations)->bindTbl[0];
1843444c061aSmrg    }
1844444c061aSmrg    else {
1845444c061aSmrg	xlations = newXlations;
1846444c061aSmrg	bindings = NULL;
1847444c061aSmrg    }
1848444c061aSmrg    switch(operation) {
1849444c061aSmrg      case XtTableReplace:
1850444c061aSmrg	newTable = bindPair[0].xlations = xlations;
1851444c061aSmrg	bindPair[0].bindings = bindings;
1852444c061aSmrg	bindPair[1].xlations = NULL;
1853444c061aSmrg	bindPair[1].bindings = NULL;
1854444c061aSmrg	break;
1855444c061aSmrg      case XtTableAugment:
1856444c061aSmrg	bindPair[0].xlations = oldXlations;
1857444c061aSmrg	bindPair[0].bindings = oldBindings;
1858444c061aSmrg	bindPair[1].xlations = xlations;
1859444c061aSmrg	bindPair[1].bindings = bindings;
1860444c061aSmrg	newTable = NULL;
1861444c061aSmrg	break;
1862444c061aSmrg      case XtTableOverride:
1863444c061aSmrg	bindPair[0].xlations = xlations;
1864444c061aSmrg	bindPair[0].bindings = bindings;
1865444c061aSmrg	bindPair[1].xlations = oldXlations;
1866444c061aSmrg	bindPair[1].bindings = oldBindings;
1867444c061aSmrg	newTable = NULL;
1868444c061aSmrg	break;
1869444c061aSmrg    }
1870444c061aSmrg    if (!newTable)
1871444c061aSmrg      newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
1872444c061aSmrg
1873444c061aSmrg    for (i = 0, numNew = 0; i < 2; i++) {
1874444c061aSmrg	if (bindPair[i].xlations)
1875444c061aSmrg	  for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
1876444c061aSmrg	      if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
1877444c061aSmrg		  if (bindPair[i].bindings)
1878444c061aSmrg		    newBindings[numNew] = bindPair[i].bindings[j];
1879444c061aSmrg		  else {
1880444c061aSmrg		      newBindings[numNew].widget = source;
1881444c061aSmrg		      newBindings[numNew].aXlations =
1882444c061aSmrg			bindPair[i].xlations;
1883444c061aSmrg		  }
1884444c061aSmrg		}
1885444c061aSmrg	  }
1886444c061aSmrg    }
1887444c061aSmrg    *numNewRtn = numNew;
1888444c061aSmrg    treePtr = &newTable->stateTreeTbl[0];
1889444c061aSmrg    for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
1890444c061aSmrg      (*treePtr)->simple.refCount++;
1891444c061aSmrg    return newTable;
1892444c061aSmrg}
1893444c061aSmrg
1894444c061aSmrgstatic TMBindData MakeBindData(
1895444c061aSmrg    TMComplexBindProcs	bindings,
1896444c061aSmrg    TMShortCard		numBindings,
1897444c061aSmrg    TMBindData		oldBindData)
1898444c061aSmrg{
1899444c061aSmrg    TMLongCard		bytes;
1900444c061aSmrg    TMShortCard		i;
1901444c061aSmrg    Boolean		isComplex;
1902444c061aSmrg    TMBindData		bindData;
1903444c061aSmrg
1904444c061aSmrg    if (numBindings == 0)
1905444c061aSmrg      return NULL;
1906444c061aSmrg    for (i = 0; i < numBindings; i++)
1907444c061aSmrg      if (bindings[i].widget)
1908444c061aSmrg	break;
1909444c061aSmrg    isComplex = (i < numBindings);
1910444c061aSmrg    if (isComplex)
1911444c061aSmrg      bytes = (sizeof(TMComplexBindDataRec) +
1912444c061aSmrg	       ((numBindings - 1) *
1913444c061aSmrg		sizeof(TMComplexBindProcsRec)));
1914444c061aSmrg    else
1915444c061aSmrg      bytes = (sizeof(TMSimpleBindDataRec) +
1916444c061aSmrg	       ((numBindings - 1) *
1917444c061aSmrg		sizeof(TMSimpleBindProcsRec)));
1918444c061aSmrg
1919444c061aSmrg    bindData = (TMBindData) __XtCalloc(sizeof(char), bytes);
1920444c061aSmrg    bindData->simple.isComplex = isComplex;
1921444c061aSmrg    if (isComplex) {
1922444c061aSmrg	TMComplexBindData cBindData = (TMComplexBindData)bindData;
1923444c061aSmrg	/*
1924444c061aSmrg	 * If there were any accelerator contexts in the old bindData
1925444c061aSmrg	 * then propagate them to the new one.
1926444c061aSmrg	 */
1927444c061aSmrg	if (oldBindData && oldBindData->simple.isComplex)
1928444c061aSmrg	    cBindData->accel_context =
1929444c061aSmrg		((TMComplexBindData) oldBindData)->accel_context;
1930444c061aSmrg	XtMemmove((char *)&cBindData->bindTbl[0], (char *)bindings,
1931444c061aSmrg		  numBindings * sizeof(TMComplexBindProcsRec));
1932444c061aSmrg    }
1933444c061aSmrg    return bindData;
1934444c061aSmrg}
1935444c061aSmrg
1936444c061aSmrg/*
1937444c061aSmrg * This routine is the central clearinghouse for merging translations
1938444c061aSmrg * into a widget. It takes care of preping the action bindings for
1939444c061aSmrg * realize time and calling the converter or doing a straight merge if
1940444c061aSmrg * the destination is empty.
1941444c061aSmrg */
1942444c061aSmrgstatic Boolean ComposeTranslations(
1943444c061aSmrg    Widget dest,
1944444c061aSmrg    _XtTranslateOp operation,
1945444c061aSmrg    Widget source,
1946444c061aSmrg    XtTranslations newXlations)
1947444c061aSmrg{
1948444c061aSmrg    XtTranslations 	newTable, oldXlations;
1949444c061aSmrg    XtTranslations	accNewXlations;
1950444c061aSmrg    EventMask		oldMask = 0;
1951444c061aSmrg    TMBindData		bindData;
1952444c061aSmrg    TMComplexBindProcs	oldBindings = NULL;
1953444c061aSmrg    TMShortCard		numOldBindings = 0, numNewBindings = 0, numBytes;
1954444c061aSmrg    TMComplexBindProcsRec stackBindings[16], *newBindings;
1955444c061aSmrg
1956444c061aSmrg    /*
1957444c061aSmrg     * how should we be handling the refcount decrement for the
1958444c061aSmrg     * replaced translation table ???
1959444c061aSmrg     */
1960444c061aSmrg    if (!newXlations)
1961444c061aSmrg      {
1962444c061aSmrg	  XtAppWarningMsg(XtWidgetToApplicationContext(dest),
1963444c061aSmrg			  XtNtranslationError,"nullTable",XtCXtToolkitError,
1964444c061aSmrg			  "table to (un)merge must not be null",
1965444c061aSmrg			  (String *)NULL, (Cardinal *)NULL);
1966444c061aSmrg	  return False;
1967444c061aSmrg      }
1968444c061aSmrg
1969444c061aSmrg    accNewXlations = newXlations;
1970444c061aSmrg    newXlations = ((newXlations->hasBindings)
1971444c061aSmrg		   ? ((ATranslations)newXlations)->xlations
1972444c061aSmrg		   : newXlations);
1973444c061aSmrg
1974444c061aSmrg    if (!(oldXlations = dest->core.tm.translations))
1975444c061aSmrg      operation = XtTableReplace;
1976444c061aSmrg
1977444c061aSmrg    /*
1978444c061aSmrg     * try to avoid generation of duplicate state trees. If the source
1979444c061aSmrg     * isn't simple (1 state Tree) then it's too much hassle
1980444c061aSmrg     */
1981444c061aSmrg    if (((operation == XtTableAugment) ||
1982444c061aSmrg	 (operation == XtTableOverride)) &&
1983444c061aSmrg	(newXlations->numStateTrees == 1)) {
1984444c061aSmrg	Cardinal	i;
1985444c061aSmrg	for (i = 0; i < oldXlations->numStateTrees; i++)
1986444c061aSmrg	  if (oldXlations->stateTreeTbl[i] ==
1987444c061aSmrg	      newXlations->stateTreeTbl[0])
1988444c061aSmrg	    break;
1989444c061aSmrg	if (i < oldXlations->numStateTrees) {
1990444c061aSmrg	    if (operation == XtTableAugment) {
1991444c061aSmrg		/*
1992444c061aSmrg		 * we don't need to do anything since it's already
1993444c061aSmrg		 * there
1994444c061aSmrg		 */
1995444c061aSmrg		return True;
1996444c061aSmrg	    }
1997444c061aSmrg	    else {/* operation == XtTableOverride */
1998444c061aSmrg		/*
1999444c061aSmrg		 * We'll get rid of the duplicate trees throughout the
2000444c061aSmrg		 * and leave it with a pruned translation table. This
2001444c061aSmrg		 * will only work if the same table has been merged
2002444c061aSmrg		 * into this table (or one of it's composers
2003444c061aSmrg		 */
2004444c061aSmrg		_XtUnmergeTranslations(dest, newXlations);
2005444c061aSmrg		/*
2006444c061aSmrg		 * reset oldXlations so we're back in sync
2007444c061aSmrg		 */
2008444c061aSmrg		if (!(oldXlations = dest->core.tm.translations))
2009444c061aSmrg		  operation = XtTableReplace;
2010444c061aSmrg	    }
2011444c061aSmrg	}
2012444c061aSmrg    }
2013444c061aSmrg
2014444c061aSmrg    bindData = (TMBindData) dest->core.tm.proc_table;
2015444c061aSmrg    if (bindData) {
2016444c061aSmrg	numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
2017444c061aSmrg 	if (bindData->simple.isComplex)
2018444c061aSmrg	    oldBindings = &((TMComplexBindData)bindData)->bindTbl[0];
2019444c061aSmrg 	else
2020444c061aSmrg	    oldBindings = (TMComplexBindProcs)
2021444c061aSmrg		(&((TMSimpleBindData)bindData)->bindTbl[0]);
2022444c061aSmrg    }
2023444c061aSmrg
2024444c061aSmrg    numBytes =(((oldXlations ? oldXlations->numStateTrees : 0)
2025444c061aSmrg		+ newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec));
2026444c061aSmrg    newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes,  stackBindings);
2027444c061aSmrg    XtBZero((char *)newBindings, numBytes);
2028444c061aSmrg
2029444c061aSmrg    if (operation == XtTableUnmerge) {
2030444c061aSmrg	newTable = UnmergeTranslations(dest,
2031444c061aSmrg				       oldXlations,
2032444c061aSmrg				       newXlations,
2033444c061aSmrg				       0,
2034444c061aSmrg				       oldBindings, numOldBindings,
2035444c061aSmrg				       newBindings, &numNewBindings);
2036444c061aSmrg#ifdef DEBUG
2037444c061aSmrg	/* check for no match for unmerge */
2038444c061aSmrg	if (newTable == oldXlations) {
2039444c061aSmrg	    XtWarning("attempt to unmerge invalid table");
2040444c061aSmrg	    XtStackFree((char *)newBindings, (char *)stackBindings);
2041444c061aSmrg	    return(newTable != NULL);
2042444c061aSmrg	}
2043444c061aSmrg#endif /* DEBUG */
2044444c061aSmrg    }
2045444c061aSmrg    else {
2046444c061aSmrg	newTable = MergeTranslations(dest,
2047444c061aSmrg				     oldXlations,
2048444c061aSmrg				     accNewXlations,
2049444c061aSmrg				     operation,
2050444c061aSmrg				     source,
2051444c061aSmrg				     oldBindings,
2052444c061aSmrg				     newBindings,
2053444c061aSmrg				     &numNewBindings);
2054444c061aSmrg    }
2055444c061aSmrg    if (XtIsRealized(dest)) {
2056444c061aSmrg	oldMask = 0;
2057444c061aSmrg	if (oldXlations)
2058444c061aSmrg	    oldMask = oldXlations->eventMask;
2059444c061aSmrg	_XtUninstallTranslations(dest);
2060444c061aSmrg    }
2061444c061aSmrg
2062444c061aSmrg    dest->core.tm.proc_table =
2063444c061aSmrg      (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
2064444c061aSmrg
2065444c061aSmrg    if (bindData) XtFree((char *)bindData);
2066444c061aSmrg
2067444c061aSmrg    dest->core.tm.translations = newTable;
2068444c061aSmrg
2069444c061aSmrg    if (XtIsRealized(dest)) {
2070444c061aSmrg	EventMask mask = 0;
2071444c061aSmrg	_XtInstallTranslations(dest);
2072444c061aSmrg	if (newTable)
2073444c061aSmrg	    mask = newTable->eventMask;
2074444c061aSmrg	if (mask != oldMask)
2075444c061aSmrg	    XSelectInput(XtDisplay(dest), XtWindow(dest),
2076444c061aSmrg			 XtBuildEventMask(dest));
2077444c061aSmrg    }
2078444c061aSmrg    XtStackFree((XtPointer)newBindings, (XtPointer)stackBindings);
2079444c061aSmrg    return(newTable != NULL);
2080444c061aSmrg}
2081444c061aSmrg
2082444c061aSmrg/*
2083444c061aSmrg * If a GetValues is done on a translation resource that contains
2084444c061aSmrg * accelerators we need to return the accelerator context in addition
2085444c061aSmrg * to the pure translations.  Since this means returning memory that
2086444c061aSmrg * the client controlls but we still own, we will track the "headers"
2087444c061aSmrg * that we return (via a linked list pointed to from the bindData) and
2088444c061aSmrg * free it at destroy time.
2089444c061aSmrg */
2090444c061aSmrgXtTranslations _XtGetTranslationValue(
2091444c061aSmrg    Widget	w)
2092444c061aSmrg{
2093444c061aSmrg    XtTM		tmRecPtr = (XtTM) &w->core.tm;
2094444c061aSmrg    ATranslations	*aXlationsPtr;
2095444c061aSmrg    TMComplexBindData	cBindData = (TMComplexBindData) tmRecPtr->proc_table;
2096444c061aSmrg    XtTranslations	xlations = tmRecPtr->translations;
2097444c061aSmrg
2098444c061aSmrg    if (!xlations || !cBindData || !cBindData->isComplex)
2099444c061aSmrg	return xlations;
2100444c061aSmrg
2101444c061aSmrg    /* Walk the list looking to see if we already have generated a
2102444c061aSmrg     * header for the currently installed translations.  If we have,
2103444c061aSmrg     * just return that header.  Otherwise create a new header.
2104444c061aSmrg     */
2105444c061aSmrg    for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
2106444c061aSmrg	 *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
2107444c061aSmrg	 aXlationsPtr = &(*aXlationsPtr)->next)
2108444c061aSmrg	;
2109444c061aSmrg    if (*aXlationsPtr)
2110444c061aSmrg	return (XtTranslations) *aXlationsPtr;
2111444c061aSmrg    else {
2112444c061aSmrg	/* create a new aXlations context */
2113444c061aSmrg	ATranslations	aXlations;
2114444c061aSmrg	Cardinal	numBindings = xlations->numStateTrees;
2115444c061aSmrg
2116444c061aSmrg	(*aXlationsPtr) = aXlations = (ATranslations)
2117444c061aSmrg	    __XtMalloc(sizeof(ATranslationData) +
2118444c061aSmrg		     (numBindings - 1) * sizeof(TMComplexBindProcsRec));
2119444c061aSmrg
2120444c061aSmrg	aXlations->hasBindings = True;
2121444c061aSmrg	aXlations->xlations = xlations;
2122444c061aSmrg	aXlations->next = NULL;
2123444c061aSmrg	XtMemmove((char *) &aXlations->bindTbl[0],
2124444c061aSmrg		  (char *) &cBindData->bindTbl[0],
2125444c061aSmrg		  numBindings * sizeof(TMComplexBindProcsRec));
2126444c061aSmrg	return (XtTranslations) aXlations;
2127444c061aSmrg    }
2128444c061aSmrg}
2129444c061aSmrg
2130444c061aSmrg
2131444c061aSmrg/*ARGSUSED*/
2132444c061aSmrgstatic void RemoveStateTree(
2133444c061aSmrg    TMStateTree	tree)
2134444c061aSmrg{
2135444c061aSmrg#ifdef REFCNT_TRANSLATIONS
2136444c061aSmrg    TMComplexStateTree stateTree = (TMComplexStateTree)tree;
2137444c061aSmrg
2138444c061aSmrg    if (--stateTree->refCount == 0) {
2139444c061aSmrg	/*
2140444c061aSmrg	 * should we free/refcount the match recs ?
2141444c061aSmrg	 */
2142444c061aSmrg	if (!stateTree->isSimple)  {
2143444c061aSmrg	    StatePtr	currState, nextState;
2144444c061aSmrg	    TMShortCard i;
2145444c061aSmrg	    for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
2146444c061aSmrg		currState =
2147444c061aSmrg		  nextState =
2148444c061aSmrg		    stateTree->complexBranchHeadTbl[i];
2149444c061aSmrg		for (; nextState;){
2150444c061aSmrg		    FreeActions(currState->actions);
2151444c061aSmrg		    currState->actions = NULL;
2152444c061aSmrg		    if (!currState->isCycleEnd)
2153444c061aSmrg		      nextState = currState->nextLevel;
2154444c061aSmrg		    else
2155444c061aSmrg		      nextState = NULL;
2156444c061aSmrg		    XtFree( (char*)currState );
2157444c061aSmrg		}
2158444c061aSmrg	    }
2159444c061aSmrg	    XtFree((char*)stateTree->complexBranchHeadTbl);
2160444c061aSmrg	}
2161444c061aSmrg	XtFree((char*)stateTree->branchHeadTbl);
2162444c061aSmrg	XtFree((char*)stateTree);
2163444c061aSmrg    }
2164444c061aSmrg#endif /* REFCNT_TRANSLATIONS */
2165444c061aSmrg}
2166444c061aSmrg
2167444c061aSmrgvoid _XtRemoveStateTreeByIndex(
2168444c061aSmrg    XtTranslations	xlations,
2169444c061aSmrg    TMShortCard	i)
2170444c061aSmrg{
2171444c061aSmrg    TMStateTree		*stateTrees = xlations->stateTreeTbl;
2172444c061aSmrg
2173444c061aSmrg    RemoveStateTree(stateTrees[i]);
2174444c061aSmrg    xlations->numStateTrees--;
2175444c061aSmrg
2176444c061aSmrg    for (; i < xlations->numStateTrees; i++)
2177444c061aSmrg      {
2178444c061aSmrg	  stateTrees[i] = stateTrees[i+1];
2179444c061aSmrg      }
2180444c061aSmrg}
2181444c061aSmrg
2182444c061aSmrg/* ARGSUSED */
2183444c061aSmrgvoid _XtFreeTranslations(
2184444c061aSmrg    XtAppContext app,
2185444c061aSmrg    XrmValuePtr	toVal,
2186444c061aSmrg    XtPointer	closure,
2187444c061aSmrg    XrmValuePtr	args,
2188444c061aSmrg    Cardinal	*num_args)
2189444c061aSmrg{
2190444c061aSmrg    XtTranslations 	xlations;
2191444c061aSmrg    int 	i;
2192444c061aSmrg
2193444c061aSmrg    if (*num_args != 0)
2194444c061aSmrg	XtAppWarningMsg(app,
2195444c061aSmrg	  "invalidParameters","freeTranslations",XtCXtToolkitError,
2196444c061aSmrg          "Freeing XtTranslations requires no extra arguments",
2197444c061aSmrg	  (String *)NULL, (Cardinal *)NULL);
2198444c061aSmrg
2199444c061aSmrg    xlations = *(XtTranslations*)toVal->addr;
2200444c061aSmrg    for (i = 0; i < (int)xlations->numStateTrees; i++)
2201444c061aSmrg      RemoveStateTree(xlations->stateTreeTbl[i]);
2202444c061aSmrg    XtFree((char *)xlations);
2203444c061aSmrg}
2204444c061aSmrg
2205444c061aSmrg/*  The spec is not clear on when actions specified in accelerators are bound;
2206444c061aSmrg *  Bind them at Realize the same as translations
2207444c061aSmrg */
2208444c061aSmrgvoid XtInstallAccelerators(
2209444c061aSmrg    Widget destination, Widget source)
2210444c061aSmrg{
2211444c061aSmrg    XtTranslations	aXlations;
2212444c061aSmrg    _XtTranslateOp	op;
2213444c061aSmrg    String		buf;
2214444c061aSmrg    WIDGET_TO_APPCON(destination);
2215444c061aSmrg
2216444c061aSmrg    /*
2217444c061aSmrg     * test that it was parsed as an accelarator table. Even though
2218444c061aSmrg     * there doesn't need to be a distinction it makes life easier if
2219444c061aSmrg     * we honor the spec implication that aXlations is an accelerator
2220444c061aSmrg     */
2221444c061aSmrg    LOCK_APP(app);
2222444c061aSmrg    LOCK_PROCESS;
2223444c061aSmrg    if ((!XtIsWidget(source)) ||
2224444c061aSmrg	((aXlations = source->core.accelerators) == NULL) ||
2225444c061aSmrg	(aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) {
2226444c061aSmrg	UNLOCK_PROCESS;
2227444c061aSmrg	UNLOCK_APP(app);
2228444c061aSmrg	return;
2229444c061aSmrg    }
2230444c061aSmrg
2231444c061aSmrg    aXlations = source->core.accelerators;
2232444c061aSmrg    op = aXlations->operation;
2233444c061aSmrg
2234444c061aSmrg    if (ComposeTranslations(destination, op, source, aXlations) &&
2235444c061aSmrg	(XtClass(source)->core_class.display_accelerator != NULL)) {
2236444c061aSmrg
2237444c061aSmrg	buf = _XtPrintXlations(destination, aXlations, source, False);
2238444c061aSmrg	(*(XtClass(source)->core_class.display_accelerator))(source,buf);
2239444c061aSmrg	XtFree(buf);
2240444c061aSmrg    }
2241444c061aSmrg    UNLOCK_PROCESS;
2242444c061aSmrg    UNLOCK_APP(app);
2243444c061aSmrg}
2244444c061aSmrg
2245444c061aSmrgvoid XtInstallAllAccelerators(
2246444c061aSmrg    Widget destination,
2247444c061aSmrg    Widget source)
2248444c061aSmrg{
2249444c061aSmrg    Cardinal i;
2250444c061aSmrg    CompositeWidget cw;
2251444c061aSmrg    WIDGET_TO_APPCON(destination);
2252444c061aSmrg
2253444c061aSmrg    /* Recurse down normal children */
2254444c061aSmrg    LOCK_APP(app);
2255444c061aSmrg    LOCK_PROCESS;
2256444c061aSmrg    if (XtIsComposite(source)) {
2257444c061aSmrg        cw = (CompositeWidget) source;
2258444c061aSmrg        for (i = 0; i < cw->composite.num_children; i++) {
2259444c061aSmrg            XtInstallAllAccelerators(destination,cw->composite.children[i]);
2260444c061aSmrg        }
2261444c061aSmrg    }
2262444c061aSmrg
2263444c061aSmrg    /* Recurse down popup children */
2264444c061aSmrg    if (XtIsWidget(source)) {
2265444c061aSmrg        for (i = 0; i < source->core.num_popups; i++) {
2266444c061aSmrg            XtInstallAllAccelerators(destination,source->core.popup_list[i]);
2267444c061aSmrg        }
2268444c061aSmrg    }
2269444c061aSmrg    /* Finally, apply procedure to this widget */
2270444c061aSmrg    XtInstallAccelerators(destination,source);
2271444c061aSmrg    UNLOCK_PROCESS;
2272444c061aSmrg    UNLOCK_APP(app);
2273444c061aSmrg}
2274444c061aSmrg
2275444c061aSmrg#if 0 /* dead code */
2276444c061aSmrgstatic _XtTranslateOp _XtGetTMOperation(
2277444c061aSmrg    XtTranslations xlations)
2278444c061aSmrg{
2279444c061aSmrg    return ((xlations->hasBindings)
2280444c061aSmrg	    ? ((ATranslations)xlations)->xlations->operation
2281444c061aSmrg	    : xlations->operation);
2282444c061aSmrg}
2283444c061aSmrg#endif
2284444c061aSmrg
2285444c061aSmrgvoid XtAugmentTranslations(
2286444c061aSmrg    Widget widget,
2287444c061aSmrg    XtTranslations new)
2288444c061aSmrg{
2289444c061aSmrg    Widget hookobj;
2290444c061aSmrg    WIDGET_TO_APPCON(widget);
2291444c061aSmrg
2292444c061aSmrg    LOCK_APP(app);
2293444c061aSmrg    LOCK_PROCESS;
2294444c061aSmrg    (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new);
2295444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2296444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2297444c061aSmrg	XtChangeHookDataRec call_data;
2298444c061aSmrg
2299444c061aSmrg	call_data.type = XtHaugmentTranslations;
2300444c061aSmrg	call_data.widget = widget;
2301444c061aSmrg	XtCallCallbackList(hookobj,
2302444c061aSmrg		((HookObject)hookobj)->hooks.changehook_callbacks,
2303444c061aSmrg		(XtPointer)&call_data);
2304444c061aSmrg    }
2305444c061aSmrg    UNLOCK_PROCESS;
2306444c061aSmrg    UNLOCK_APP(app);
2307444c061aSmrg}
2308444c061aSmrg
2309444c061aSmrgvoid XtOverrideTranslations(
2310444c061aSmrg    Widget widget,
2311444c061aSmrg    XtTranslations new)
2312444c061aSmrg{
2313444c061aSmrg    Widget hookobj;
2314444c061aSmrg    WIDGET_TO_APPCON(widget);
2315444c061aSmrg
2316444c061aSmrg    LOCK_APP(app);
2317444c061aSmrg    LOCK_PROCESS;
2318444c061aSmrg    (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new);
2319444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2320444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2321444c061aSmrg	XtChangeHookDataRec call_data;
2322444c061aSmrg
2323444c061aSmrg	call_data.type = XtHoverrideTranslations;
2324444c061aSmrg	call_data.widget = widget;
2325444c061aSmrg	XtCallCallbackList(hookobj,
2326444c061aSmrg		((HookObject)hookobj)->hooks.changehook_callbacks,
2327444c061aSmrg		(XtPointer)&call_data);
2328444c061aSmrg    }
2329444c061aSmrg    UNLOCK_PROCESS;
2330444c061aSmrg    UNLOCK_APP(app);
2331444c061aSmrg}
2332444c061aSmrg
2333444c061aSmrgvoid _XtMergeTranslations(
2334444c061aSmrg    Widget	widget,
2335444c061aSmrg    XtTranslations newXlations,
2336444c061aSmrg    _XtTranslateOp op)
2337444c061aSmrg{
2338444c061aSmrg    if (!newXlations){
2339444c061aSmrg	if (!widget->core.tm.translations)
2340444c061aSmrg	  return;
2341444c061aSmrg	else {
2342444c061aSmrg	  newXlations = widget->core.tm.translations;
2343444c061aSmrg	  widget->core.tm.translations = NULL;
2344444c061aSmrg      }
2345444c061aSmrg    }
2346444c061aSmrg    (void) ComposeTranslations(widget,
2347444c061aSmrg			     op,
2348444c061aSmrg			     (Widget)NULL,
2349444c061aSmrg			     newXlations);
2350444c061aSmrg}
2351444c061aSmrg
2352444c061aSmrgvoid _XtUnmergeTranslations(
2353444c061aSmrg   Widget		widget,
2354444c061aSmrg    XtTranslations	xlations)
2355444c061aSmrg{
2356444c061aSmrg    ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations);
2357444c061aSmrg}
2358