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