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