TMstate.c revision fdf6a26f
1444c061aSmrg/***********************************************************
2fdf6a26fSmrgCopyright (c) 1993, Oracle and/or its affiliates.
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#ifdef HAVE_CONFIG_H
75444c061aSmrg#include <config.h>
76444c061aSmrg#endif
77444c061aSmrg#include "IntrinsicI.h"
78444c061aSmrg#ifndef TM_NO_MATCH
79444c061aSmrg#define TM_NO_MATCH (-2)
80a3bd7f05Smrg#endif                          /* TM_NO_MATCH */
81444c061aSmrg/* forward definitions */
82444c061aSmrgstatic StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard);
83444c061aSmrg
84444c061aSmrgstatic String XtNtranslationError = "translationError";
85444c061aSmrg
86444c061aSmrg#ifndef __EMX__
87a3bd7f05SmrgTMGlobalRec _XtGlobalTM;        /* initialized to zero K&R */
88444c061aSmrg#else
89a3bd7f05SmrgTMGlobalRec _XtGlobalTM = { 0 };
90444c061aSmrg#endif
91444c061aSmrg
92444c061aSmrg#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
93444c061aSmrg  (typeMatch->eventType == tmEvent->event.eventType && \
94444c061aSmrg   (typeMatch->matchEvent != NULL) && \
95444c061aSmrg   (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
96444c061aSmrg
97444c061aSmrg#define NumStateTrees(xlations) \
98444c061aSmrg  ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
99444c061aSmrg
100a3bd7f05Smrgstatic TMShortCard
101a3bd7f05SmrgGetBranchHead(TMParseStateTree parseTree,
102a3bd7f05Smrg              TMShortCard typeIndex,
103a3bd7f05Smrg              TMShortCard modIndex,
104a3bd7f05Smrg              Boolean isDummy)
105444c061aSmrg{
106fdf6a26fSmrg#define TM_BRANCH_HEAD_TBL_ALLOC        ((TMShortCard) 8)
107fdf6a26fSmrg#define TM_BRANCH_HEAD_TBL_REALLOC      ((TMShortCard) 8)
108444c061aSmrg
109444c061aSmrg    TMBranchHead branchHead = parseTree->branchHeadTbl;
110a3bd7f05Smrg
111444c061aSmrg    /*
112444c061aSmrg     * dummy is used as a place holder for later matching in old-style
113444c061aSmrg     * matching behavior. If there's already an entry we don't need
114444c061aSmrg     * another dummy.
115444c061aSmrg     */
116444c061aSmrg    if (isDummy) {
117a3bd7f05Smrg        TMShortCard i;
118a3bd7f05Smrg
119a3bd7f05Smrg        for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
120a3bd7f05Smrg            if ((branchHead->typeIndex == typeIndex) &&
121a3bd7f05Smrg                (branchHead->modIndex == modIndex))
122a3bd7f05Smrg                return i;
123a3bd7f05Smrg        }
124a3bd7f05Smrg    }
125a3bd7f05Smrg    if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) {
126a3bd7f05Smrg
127a3bd7f05Smrg        if (parseTree->branchHeadTblSize == 0)
128fdf6a26fSmrg            parseTree->branchHeadTblSize = TM_BRANCH_HEAD_TBL_ALLOC;
129a3bd7f05Smrg        else
130fdf6a26fSmrg            parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_REALLOC;
131fdf6a26fSmrg
132a3bd7f05Smrg        if (parseTree->isStackBranchHeads) {
133a3bd7f05Smrg            TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl;
134a3bd7f05Smrg
135fdf6a26fSmrg            parseTree->branchHeadTbl =
136fdf6a26fSmrg                XtMallocArray((Cardinal) parseTree->branchHeadTblSize,
137fdf6a26fSmrg                              (Cardinal) sizeof(TMBranchHeadRec));
138fdf6a26fSmrg            memcpy(parseTree->branchHeadTbl, oldBranchHeadTbl,
139fdf6a26fSmrg                   parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec));
140a3bd7f05Smrg            parseTree->isStackBranchHeads = False;
141a3bd7f05Smrg        }
142a3bd7f05Smrg        else {
143a3bd7f05Smrg            parseTree->branchHeadTbl = (TMBranchHead)
144fdf6a26fSmrg                XtReallocArray(parseTree->branchHeadTbl,
145fdf6a26fSmrg                               (Cardinal) parseTree->branchHeadTblSize,
146fdf6a26fSmrg                               (Cardinal) sizeof(TMBranchHeadRec));
147a3bd7f05Smrg        }
148a3bd7f05Smrg    }
149444c061aSmrg#ifdef TRACE_TM
150444c061aSmrg    LOCK_PROCESS;
151444c061aSmrg    _XtGlobalTM.numBranchHeads++;
152444c061aSmrg    UNLOCK_PROCESS;
153a3bd7f05Smrg#endif                          /* TRACE_TM */
154a3bd7f05Smrg    branchHead = &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
155444c061aSmrg    branchHead->typeIndex = typeIndex;
156444c061aSmrg    branchHead->modIndex = modIndex;
157444c061aSmrg    branchHead->more = 0;
158444c061aSmrg    branchHead->isSimple = True;
159444c061aSmrg    branchHead->hasActions = False;
160444c061aSmrg    branchHead->hasCycles = False;
1610568f49bSmrg    return (TMShortCard) (parseTree->numBranchHeads - 1);
162444c061aSmrg}
163444c061aSmrg
164a3bd7f05SmrgTMShortCard
165a3bd7f05Smrg_XtGetQuarkIndex(TMParseStateTree parseTree, XrmQuark quark)
166444c061aSmrg{
167fdf6a26fSmrg#define TM_QUARK_TBL_ALLOC      ((TMShortCard) 16)
168fdf6a26fSmrg#define TM_QUARK_TBL_REALLOC    ((TMShortCard) 16)
1690568f49bSmrg    TMShortCard i;
170444c061aSmrg
171a3bd7f05Smrg    for (i = 0; i < parseTree->numQuarks; i++)
172a3bd7f05Smrg        if (parseTree->quarkTbl[i] == quark)
173a3bd7f05Smrg            break;
174a3bd7f05Smrg
175a3bd7f05Smrg    if (i == parseTree->numQuarks) {
176a3bd7f05Smrg        if (parseTree->numQuarks == parseTree->quarkTblSize) {
177a3bd7f05Smrg
178a3bd7f05Smrg            if (parseTree->quarkTblSize == 0)
179fdf6a26fSmrg                parseTree->quarkTblSize = TM_QUARK_TBL_ALLOC;
180a3bd7f05Smrg            else
181fdf6a26fSmrg                parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC;
182a3bd7f05Smrg
183a3bd7f05Smrg            if (parseTree->isStackQuarks) {
184a3bd7f05Smrg                XrmQuark *oldquarkTbl = parseTree->quarkTbl;
185a3bd7f05Smrg
186fdf6a26fSmrg                parseTree->quarkTbl =
187fdf6a26fSmrg                    XtMallocArray((Cardinal) parseTree->quarkTblSize,
188fdf6a26fSmrg                                  (Cardinal) sizeof(XrmQuark));
189fdf6a26fSmrg                memcpy(parseTree->quarkTbl, oldquarkTbl,
190fdf6a26fSmrg                       parseTree->quarkTblSize * sizeof(XrmQuark));
191a3bd7f05Smrg                parseTree->isStackQuarks = False;
192a3bd7f05Smrg            }
193a3bd7f05Smrg            else {
194a3bd7f05Smrg                parseTree->quarkTbl = (XrmQuark *)
195fdf6a26fSmrg                    XtReallocArray(parseTree->quarkTbl,
196fdf6a26fSmrg                                   (Cardinal) parseTree->quarkTblSize,
197fdf6a26fSmrg                                   (Cardinal) sizeof(XrmQuark));
198a3bd7f05Smrg            }
199a3bd7f05Smrg        }
200a3bd7f05Smrg        parseTree->quarkTbl[parseTree->numQuarks++] = quark;
201a3bd7f05Smrg    }
202444c061aSmrg    return i;
203444c061aSmrg}
204444c061aSmrg
205444c061aSmrg/*
206444c061aSmrg * Get an entry from the parseTrees complex branchHead tbl. If there's none
207444c061aSmrg * there then allocate one
208444c061aSmrg */
209a3bd7f05Smrgstatic TMShortCard
210a3bd7f05SmrgGetComplexBranchIndex(TMParseStateTree parseTree,
211a3bd7f05Smrg                      TMShortCard typeIndex _X_UNUSED,
212a3bd7f05Smrg                      TMShortCard modIndex _X_UNUSED)
213444c061aSmrg{
214444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
215444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
216444c061aSmrg
217444c061aSmrg    if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
218a3bd7f05Smrg        if (parseTree->complexBranchHeadTblSize == 0)
219a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
220a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
221a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_ALLOC);
222a3bd7f05Smrg        else
223a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
224a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
225a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_REALLOC);
226a3bd7f05Smrg
227a3bd7f05Smrg        if (parseTree->isStackComplexBranchHeads) {
228a3bd7f05Smrg            StatePtr *oldcomplexBranchHeadTbl = parseTree->complexBranchHeadTbl;
229a3bd7f05Smrg
230fdf6a26fSmrg            parseTree->complexBranchHeadTbl =
231fdf6a26fSmrg                XtMallocArray((Cardinal) parseTree->complexBranchHeadTblSize,
232fdf6a26fSmrg                              (Cardinal) sizeof(StatePtr));
233fdf6a26fSmrg            memcpy(parseTree->complexBranchHeadTbl, oldcomplexBranchHeadTbl,
234fdf6a26fSmrg                   parseTree->complexBranchHeadTblSize * sizeof(StatePtr));
235a3bd7f05Smrg            parseTree->isStackComplexBranchHeads = False;
236a3bd7f05Smrg        }
237a3bd7f05Smrg        else {
238a3bd7f05Smrg            parseTree->complexBranchHeadTbl = (StatePtr *)
239fdf6a26fSmrg                XtReallocArray(parseTree->complexBranchHeadTbl,
240fdf6a26fSmrg                               (Cardinal) parseTree->complexBranchHeadTblSize,
241fdf6a26fSmrg                               (Cardinal) sizeof(StatePtr));
242a3bd7f05Smrg        }
243444c061aSmrg    }
244444c061aSmrg    parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
2450568f49bSmrg    return (TMShortCard) (parseTree->numComplexBranchHeads - 1);
246444c061aSmrg}
247444c061aSmrg
248a3bd7f05SmrgTMShortCard
249a3bd7f05Smrg_XtGetTypeIndex(Event *event)
250444c061aSmrg{
251a3bd7f05Smrg    TMShortCard i, j = TM_TYPE_SEGMENT_SIZE;
252a3bd7f05Smrg    TMShortCard typeIndex = 0;
253a3bd7f05Smrg    TMTypeMatch typeMatch;
254a3bd7f05Smrg    TMTypeMatch segment = NULL;
255444c061aSmrg
256444c061aSmrg    LOCK_PROCESS;
257444c061aSmrg    for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
258a3bd7f05Smrg        segment = _XtGlobalTM.typeMatchSegmentTbl[i];
259a3bd7f05Smrg        for (j = 0;
260a3bd7f05Smrg             typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE;
261a3bd7f05Smrg             j++, typeIndex++) {
262a3bd7f05Smrg            typeMatch = &(segment[j]);
263a3bd7f05Smrg            if (event->eventType == typeMatch->eventType &&
264a3bd7f05Smrg                event->eventCode == typeMatch->eventCode &&
265a3bd7f05Smrg                event->eventCodeMask == typeMatch->eventCodeMask &&
266a3bd7f05Smrg                event->matchEvent == typeMatch->matchEvent) {
267a3bd7f05Smrg                UNLOCK_PROCESS;
268a3bd7f05Smrg                return typeIndex;
269a3bd7f05Smrg            }
270a3bd7f05Smrg        }
271444c061aSmrg    }
272444c061aSmrg
273444c061aSmrg    if (j == TM_TYPE_SEGMENT_SIZE) {
274a3bd7f05Smrg        if (_XtGlobalTM.numTypeMatchSegments ==
275a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize) {
276a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize =
277a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.typeMatchSegmentTblSize + 4);
278a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
279fdf6a26fSmrg                XtReallocArray(_XtGlobalTM.typeMatchSegmentTbl,
280fdf6a26fSmrg                               (Cardinal) _XtGlobalTM.typeMatchSegmentTblSize,
281fdf6a26fSmrg                               (Cardinal) sizeof(TMTypeMatch));
282a3bd7f05Smrg        }
283a3bd7f05Smrg        _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] =
284fdf6a26fSmrg            segment = XtMallocArray(TM_TYPE_SEGMENT_SIZE,
285fdf6a26fSmrg                                    (Cardinal) sizeof(TMTypeMatchRec));
286a3bd7f05Smrg        j = 0;
287444c061aSmrg    }
288444c061aSmrg    typeMatch = &segment[j];
289444c061aSmrg    typeMatch->eventType = event->eventType;
290444c061aSmrg    typeMatch->eventCode = event->eventCode;
291444c061aSmrg    typeMatch->eventCodeMask = event->eventCodeMask;
292444c061aSmrg    typeMatch->matchEvent = event->matchEvent;
293444c061aSmrg    _XtGlobalTM.numTypeMatches++;
294444c061aSmrg    UNLOCK_PROCESS;
295444c061aSmrg    return typeIndex;
296444c061aSmrg}
297444c061aSmrg
298a3bd7f05Smrgstatic Boolean
299a3bd7f05SmrgCompareLateModifiers(LateBindingsPtr lateBind1P, LateBindingsPtr lateBind2P)
300444c061aSmrg{
301444c061aSmrg    LateBindingsPtr late1P = lateBind1P;
302444c061aSmrg    LateBindingsPtr late2P = lateBind2P;
303444c061aSmrg
304444c061aSmrg    if (late1P != NULL || late2P != NULL) {
305a3bd7f05Smrg        int i = 0;
306a3bd7f05Smrg        int j = 0;
307a3bd7f05Smrg
308a3bd7f05Smrg        if (late1P != NULL)
309a3bd7f05Smrg            for (; late1P->keysym != NoSymbol; i++)
310a3bd7f05Smrg                late1P++;
311a3bd7f05Smrg        if (late2P != NULL)
312a3bd7f05Smrg            for (; late2P->keysym != NoSymbol; j++)
313a3bd7f05Smrg                late2P++;
314a3bd7f05Smrg        if (i != j)
315a3bd7f05Smrg            return FALSE;
316a3bd7f05Smrg        late1P--;
317a3bd7f05Smrg        while (late1P >= lateBind1P) {
318a3bd7f05Smrg            Boolean last = True;
319a3bd7f05Smrg
320a3bd7f05Smrg            for (late2P = lateBind2P + i - 1; late2P >= lateBind2P; late2P--) {
321a3bd7f05Smrg                if (late1P->keysym == late2P->keysym
322a3bd7f05Smrg                    && late1P->knot == late2P->knot) {
323a3bd7f05Smrg                    j--;
324a3bd7f05Smrg                    if (last)
325a3bd7f05Smrg                        i--;
326a3bd7f05Smrg                    break;
327a3bd7f05Smrg                }
328a3bd7f05Smrg                last = False;
329a3bd7f05Smrg            }
330a3bd7f05Smrg            late1P--;
331a3bd7f05Smrg        }
332a3bd7f05Smrg        if (j != 0)
333a3bd7f05Smrg            return FALSE;
334444c061aSmrg    }
335444c061aSmrg    return TRUE;
336444c061aSmrg}
337444c061aSmrg
338a3bd7f05SmrgTMShortCard
339a3bd7f05Smrg_XtGetModifierIndex(Event *event)
340444c061aSmrg{
341a3bd7f05Smrg    TMShortCard i, j = TM_MOD_SEGMENT_SIZE;
342a3bd7f05Smrg    TMShortCard modIndex = 0;
343a3bd7f05Smrg    TMModifierMatch modMatch;
344a3bd7f05Smrg    TMModifierMatch segment = NULL;
345444c061aSmrg
346444c061aSmrg    LOCK_PROCESS;
347444c061aSmrg    for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
348a3bd7f05Smrg        segment = _XtGlobalTM.modMatchSegmentTbl[i];
349a3bd7f05Smrg        for (j = 0;
350a3bd7f05Smrg             modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE;
351a3bd7f05Smrg             j++, modIndex++) {
352a3bd7f05Smrg            modMatch = &(segment[j]);
353a3bd7f05Smrg            if (event->modifiers == modMatch->modifiers &&
354a3bd7f05Smrg                event->modifierMask == modMatch->modifierMask &&
355a3bd7f05Smrg                event->standard == modMatch->standard &&
356a3bd7f05Smrg                ((!event->lateModifiers && !modMatch->lateModifiers) ||
357a3bd7f05Smrg                 CompareLateModifiers(event->lateModifiers,
358a3bd7f05Smrg                                      modMatch->lateModifiers))) {
359a3bd7f05Smrg                /*
360a3bd7f05Smrg                 * if we found a match then we can free the parser's
361a3bd7f05Smrg                 * late modifiers. If there isn't a match we use the
362a3bd7f05Smrg                 * parser's copy
363a3bd7f05Smrg                 */
364a3bd7f05Smrg                if (event->lateModifiers &&
365a3bd7f05Smrg                    --event->lateModifiers->ref_count == 0) {
366a3bd7f05Smrg                    XtFree((char *) event->lateModifiers);
367a3bd7f05Smrg                    event->lateModifiers = NULL;
368a3bd7f05Smrg                }
369a3bd7f05Smrg                UNLOCK_PROCESS;
370a3bd7f05Smrg                return modIndex;
371a3bd7f05Smrg            }
372a3bd7f05Smrg        }
373444c061aSmrg    }
374444c061aSmrg
375444c061aSmrg    if (j == TM_MOD_SEGMENT_SIZE) {
376a3bd7f05Smrg        if (_XtGlobalTM.numModMatchSegments ==
377a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize) {
378a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize =
379a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.modMatchSegmentTblSize + 4);
380a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
381fdf6a26fSmrg                XtReallocArray(_XtGlobalTM.modMatchSegmentTbl,
382fdf6a26fSmrg                               (Cardinal) _XtGlobalTM.modMatchSegmentTblSize,
383fdf6a26fSmrg                               (Cardinal) sizeof(TMModifierMatch));
384a3bd7f05Smrg        }
385a3bd7f05Smrg        _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] =
386fdf6a26fSmrg            segment = XtMallocArray(TM_MOD_SEGMENT_SIZE,
387fdf6a26fSmrg                                    (Cardinal) sizeof(TMModifierMatchRec));
388a3bd7f05Smrg        j = 0;
389444c061aSmrg    }
390444c061aSmrg    modMatch = &segment[j];
3910568f49bSmrg    modMatch->modifiers = event->modifiers;
392444c061aSmrg    modMatch->modifierMask = event->modifierMask;
393444c061aSmrg    modMatch->standard = event->standard;
394444c061aSmrg    /*
395444c061aSmrg     * We use the parser's copy of the late binding array
396444c061aSmrg     */
397444c061aSmrg#ifdef TRACE_TM
398444c061aSmrg    if (event->lateModifiers)
399a3bd7f05Smrg        _XtGlobalTM.numLateBindings++;
400a3bd7f05Smrg#endif                          /* TRACE_TM */
401444c061aSmrg    modMatch->lateModifiers = event->lateModifiers;
402444c061aSmrg    _XtGlobalTM.numModMatches++;
403444c061aSmrg    UNLOCK_PROCESS;
404444c061aSmrg    return modIndex;
405444c061aSmrg}
406444c061aSmrg
407444c061aSmrg/*
408444c061aSmrg * This is called from the SimpleStateHandler to match a stateTree
409444c061aSmrg * entry to the event coming in
410444c061aSmrg */
411a3bd7f05Smrgstatic int
412a3bd7f05SmrgMatchBranchHead(TMSimpleStateTree stateTree, int startIndex, TMEventPtr event)
413444c061aSmrg{
414444c061aSmrg    TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex];
415444c061aSmrg    int i;
416444c061aSmrg
417444c061aSmrg    LOCK_PROCESS;
418a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
419a3bd7f05Smrg        TMTypeMatch typeMatch;
420a3bd7f05Smrg        TMModifierMatch modMatch;
421a3bd7f05Smrg
422a3bd7f05Smrg        typeMatch = TMGetTypeMatch(branchHead->typeIndex);
423a3bd7f05Smrg        modMatch = TMGetModifierMatch(branchHead->modIndex);
424a3bd7f05Smrg
425a3bd7f05Smrg        if (MatchIncomingEvent(event, typeMatch, modMatch)) {
426a3bd7f05Smrg            UNLOCK_PROCESS;
427a3bd7f05Smrg            return i;
428a3bd7f05Smrg        }
429a3bd7f05Smrg    }
430444c061aSmrg    UNLOCK_PROCESS;
431444c061aSmrg    return (TM_NO_MATCH);
432444c061aSmrg}
433444c061aSmrg
434a3bd7f05SmrgBoolean
435a3bd7f05Smrg_XtRegularMatch(TMTypeMatch typeMatch,
436a3bd7f05Smrg                TMModifierMatch modMatch,
437a3bd7f05Smrg                TMEventPtr eventSeq)
438444c061aSmrg{
439a3bd7f05Smrg    Modifiers computed = 0;
440a3bd7f05Smrg    Modifiers computedMask = 0;
441444c061aSmrg    Boolean resolved = TRUE;
442a3bd7f05Smrg
443444c061aSmrg    if (typeMatch->eventCode != (eventSeq->event.eventCode &
444a3bd7f05Smrg                                 typeMatch->eventCodeMask))
445a3bd7f05Smrg        return FALSE;
446444c061aSmrg    if (modMatch->lateModifiers != NULL)
447a3bd7f05Smrg        resolved = _XtComputeLateBindings(eventSeq->xev->xany.display,
448a3bd7f05Smrg                                          modMatch->lateModifiers,
449a3bd7f05Smrg                                          &computed, &computedMask);
450a3bd7f05Smrg    if (!resolved)
451a3bd7f05Smrg        return FALSE;
4520568f49bSmrg    computed = (Modifiers) (computed | modMatch->modifiers);
4530568f49bSmrg    computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
454444c061aSmrg
455a3bd7f05Smrg    return ((computed & computedMask) ==
456a3bd7f05Smrg            (eventSeq->event.modifiers & computedMask));
457444c061aSmrg}
458444c061aSmrg
459a3bd7f05SmrgBoolean
460a3bd7f05Smrg_XtMatchAtom(TMTypeMatch typeMatch,
461a3bd7f05Smrg             TMModifierMatch modMatch _X_UNUSED,
462a3bd7f05Smrg             TMEventPtr eventSeq)
463444c061aSmrg{
464a3bd7f05Smrg    Atom atom;
465444c061aSmrg
466444c061aSmrg    atom = XInternAtom(eventSeq->xev->xany.display,
467a3bd7f05Smrg                       XrmQuarkToString((XrmQuark) (typeMatch->eventCode)),
468a3bd7f05Smrg                       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 */
478a3bd7f05Smrgstatic Boolean
479a3bd7f05SmrgIgnore(TMEventPtr event)
480444c061aSmrg{
481444c061aSmrg    Display *dpy;
482444c061aSmrg    XtPerDisplay pd;
483444c061aSmrg
484444c061aSmrg    if (event->event.eventType == MotionNotify)
485a3bd7f05Smrg        return TRUE;
486444c061aSmrg    if (!(event->event.eventType == KeyPress ||
487a3bd7f05Smrg          event->event.eventType == KeyRelease))
488a3bd7f05Smrg        return FALSE;
489444c061aSmrg    dpy = event->xev->xany.display;
490a3bd7f05Smrg
491444c061aSmrg    pd = _XtGetPerDisplay(dpy);
492444c061aSmrg    _InitializeKeysymTables(dpy, pd);
493444c061aSmrg    return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
494444c061aSmrg}
495444c061aSmrg
496a3bd7f05Smrgstatic void
497a3bd7f05SmrgXEventToTMEvent(XEvent *event, TMEventPtr tmEvent)
498444c061aSmrg{
499444c061aSmrg    tmEvent->xev = event;
500444c061aSmrg    tmEvent->event.eventCodeMask = 0;
501444c061aSmrg    tmEvent->event.modifierMask = 0;
5020568f49bSmrg    tmEvent->event.eventType = (TMLongCard) event->type;
503444c061aSmrg    tmEvent->event.lateModifiers = NULL;
504444c061aSmrg    tmEvent->event.matchEvent = NULL;
505444c061aSmrg    tmEvent->event.standard = FALSE;
506444c061aSmrg
507444c061aSmrg    switch (event->type) {
508444c061aSmrg
509a3bd7f05Smrg    case KeyPress:
510a3bd7f05Smrg    case KeyRelease:
511a3bd7f05Smrg        tmEvent->event.eventCode = event->xkey.keycode;
512a3bd7f05Smrg        tmEvent->event.modifiers = event->xkey.state;
513a3bd7f05Smrg        break;
514a3bd7f05Smrg
515a3bd7f05Smrg    case ButtonPress:
516a3bd7f05Smrg    case ButtonRelease:
517a3bd7f05Smrg        tmEvent->event.eventCode = event->xbutton.button;
518a3bd7f05Smrg        tmEvent->event.modifiers = event->xbutton.state;
519a3bd7f05Smrg        break;
520a3bd7f05Smrg
521a3bd7f05Smrg    case MotionNotify:
522a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmotion.is_hint;
523a3bd7f05Smrg        tmEvent->event.modifiers = event->xmotion.state;
524a3bd7f05Smrg        break;
525a3bd7f05Smrg
526a3bd7f05Smrg    case EnterNotify:
527a3bd7f05Smrg    case LeaveNotify:
528a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xcrossing.mode;
529a3bd7f05Smrg        tmEvent->event.modifiers = event->xcrossing.state;
530a3bd7f05Smrg        break;
531a3bd7f05Smrg
532a3bd7f05Smrg    case PropertyNotify:
533a3bd7f05Smrg        tmEvent->event.eventCode = event->xproperty.atom;
534a3bd7f05Smrg        tmEvent->event.modifiers = 0;
535a3bd7f05Smrg        break;
536a3bd7f05Smrg
537a3bd7f05Smrg    case SelectionClear:
538a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionclear.selection;
539a3bd7f05Smrg        tmEvent->event.modifiers = 0;
540a3bd7f05Smrg        break;
541a3bd7f05Smrg
542a3bd7f05Smrg    case SelectionRequest:
543a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionrequest.selection;
544a3bd7f05Smrg        tmEvent->event.modifiers = 0;
545a3bd7f05Smrg        break;
546a3bd7f05Smrg
547a3bd7f05Smrg    case SelectionNotify:
548a3bd7f05Smrg        tmEvent->event.eventCode = event->xselection.selection;
549a3bd7f05Smrg        tmEvent->event.modifiers = 0;
550a3bd7f05Smrg        break;
551a3bd7f05Smrg
552a3bd7f05Smrg    case ClientMessage:
553a3bd7f05Smrg        tmEvent->event.eventCode = event->xclient.message_type;
554a3bd7f05Smrg        tmEvent->event.modifiers = 0;
555a3bd7f05Smrg        break;
556a3bd7f05Smrg
557a3bd7f05Smrg    case MappingNotify:
558a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmapping.request;
559a3bd7f05Smrg        tmEvent->event.modifiers = 0;
560a3bd7f05Smrg        break;
561a3bd7f05Smrg
562a3bd7f05Smrg    case FocusIn:
563a3bd7f05Smrg    case FocusOut:
564a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xfocus.mode;
565a3bd7f05Smrg        tmEvent->event.modifiers = 0;
566a3bd7f05Smrg        break;
567a3bd7f05Smrg
568a3bd7f05Smrg    default:
569a3bd7f05Smrg        tmEvent->event.eventCode = 0;
570a3bd7f05Smrg        tmEvent->event.modifiers = 0;
571a3bd7f05Smrg        break;
572444c061aSmrg    }
573444c061aSmrg}
574444c061aSmrg
575a3bd7f05Smrgstatic unsigned long
576a3bd7f05SmrgGetTime(XtTM tm, XEvent *event)
577444c061aSmrg{
578444c061aSmrg    switch (event->type) {
579444c061aSmrg
580a3bd7f05Smrg    case KeyPress:
581a3bd7f05Smrg    case KeyRelease:
582a3bd7f05Smrg        return event->xkey.time;
583444c061aSmrg
584a3bd7f05Smrg    case ButtonPress:
585a3bd7f05Smrg    case ButtonRelease:
586a3bd7f05Smrg        return event->xbutton.time;
587444c061aSmrg
588a3bd7f05Smrg    default:
589a3bd7f05Smrg        return tm->lastEventTime;
590444c061aSmrg
591444c061aSmrg    }
592444c061aSmrg
593444c061aSmrg}
594444c061aSmrg
595a3bd7f05Smrgstatic void
596a3bd7f05SmrgHandleActions(Widget w,
597a3bd7f05Smrg              XEvent *event,
598a3bd7f05Smrg              TMSimpleStateTree stateTree,
599a3bd7f05Smrg              Widget accelWidget,
600a3bd7f05Smrg              XtActionProc *procs,
601a3bd7f05Smrg              ActionRec *actions)
602444c061aSmrg{
603a3bd7f05Smrg    ActionHook actionHookList;
604a3bd7f05Smrg    Widget bindWidget;
605444c061aSmrg
606444c061aSmrg    bindWidget = accelWidget ? accelWidget : w;
607444c061aSmrg    if (accelWidget && !XtIsSensitive(accelWidget) &&
608a3bd7f05Smrg        (event->type == KeyPress || event->type == KeyRelease ||
609a3bd7f05Smrg         event->type == ButtonPress || event->type == ButtonRelease ||
610a3bd7f05Smrg         event->type == MotionNotify || event->type == EnterNotify ||
611a3bd7f05Smrg         event->type == LeaveNotify || event->type == FocusIn ||
612a3bd7f05Smrg         event->type == FocusOut))
613a3bd7f05Smrg        return;
614444c061aSmrg
615444c061aSmrg    actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
616444c061aSmrg
617444c061aSmrg    while (actions != NULL) {
618a3bd7f05Smrg        /* perform any actions */
619a3bd7f05Smrg        if (procs[actions->idx] != NULL) {
620a3bd7f05Smrg            if (actionHookList) {
621a3bd7f05Smrg                ActionHook hook;
622a3bd7f05Smrg                ActionHook next_hook;
623a3bd7f05Smrg                String procName =
624a3bd7f05Smrg                    XrmQuarkToString(stateTree->quarkTbl[actions->idx]);
625a3bd7f05Smrg
626a3bd7f05Smrg                for (hook = actionHookList; hook != NULL;) {
627a3bd7f05Smrg                    /*
628a3bd7f05Smrg                     * Need to cache hook->next because the following action
629a3bd7f05Smrg                     * proc may free hook via XtRemoveActionHook making
630a3bd7f05Smrg                     * hook->next invalid upon return from the action proc.
631a3bd7f05Smrg                     */
632a3bd7f05Smrg                    next_hook = hook->next;
633a3bd7f05Smrg                    (*hook->proc) (bindWidget,
634a3bd7f05Smrg                                   hook->closure,
635a3bd7f05Smrg                                   procName,
636a3bd7f05Smrg                                   event,
637a3bd7f05Smrg                                   actions->params, &actions->num_params);
638a3bd7f05Smrg                    hook = next_hook;
639a3bd7f05Smrg                }
640a3bd7f05Smrg            }
641a3bd7f05Smrg            (*(procs[actions->idx]))
642a3bd7f05Smrg                (bindWidget, event, actions->params, &actions->num_params);
643a3bd7f05Smrg        }
644a3bd7f05Smrg        actions = actions->next;
645444c061aSmrg    }
646444c061aSmrg}
647444c061aSmrg
648444c061aSmrgtypedef struct {
649444c061aSmrg    unsigned int isCycleStart:1;
650444c061aSmrg    unsigned int isCycleEnd:1;
651444c061aSmrg    TMShortCard typeIndex;
652444c061aSmrg    TMShortCard modIndex;
653a3bd7f05Smrg} MatchPairRec, *MatchPair;
654444c061aSmrg
655a3bd7f05Smrgtypedef struct TMContextRec {
656a3bd7f05Smrg    TMShortCard numMatches;
657a3bd7f05Smrg    TMShortCard maxMatches;
658a3bd7f05Smrg    MatchPair matches;
659a3bd7f05Smrg} TMContextRec, *TMContext;
660444c061aSmrg
661a3bd7f05Smrgstatic TMContextRec contextCache[2];
662444c061aSmrg
663444c061aSmrg#define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
664444c061aSmrg
665444c061aSmrg#define TM_CONTEXT_MATCHES_ALLOC 4
666444c061aSmrg#define TM_CONTEXT_MATCHES_REALLOC 2
667444c061aSmrg
668a3bd7f05Smrgstatic void
669a3bd7f05SmrgPushContext(TMContext *contextPtr, StatePtr newState)
670444c061aSmrg{
671a3bd7f05Smrg    TMContext context = *contextPtr;
672444c061aSmrg
673444c061aSmrg    LOCK_PROCESS;
674a3bd7f05Smrg    if (context == NULL) {
675a3bd7f05Smrg        if (contextCache[0].numMatches == 0)
676a3bd7f05Smrg            context = &contextCache[0];
677a3bd7f05Smrg        else if (contextCache[1].numMatches == 0)
678a3bd7f05Smrg            context = &contextCache[1];
679a3bd7f05Smrg        if (!context) {
680a3bd7f05Smrg            context = XtNew(TMContextRec);
681a3bd7f05Smrg            context->matches = NULL;
682a3bd7f05Smrg            context->numMatches = context->maxMatches = 0;
683a3bd7f05Smrg        }
684a3bd7f05Smrg    }
685444c061aSmrg    if (context->numMatches &&
686a3bd7f05Smrg        context->matches[context->numMatches - 1].isCycleEnd) {
687a3bd7f05Smrg        TMShortCard i;
688a3bd7f05Smrg
689a3bd7f05Smrg        for (i = 0;
690a3bd7f05Smrg             i < context->numMatches &&
691a3bd7f05Smrg             !(context->matches[i].isCycleStart); i++) {
692a3bd7f05Smrg        };
693a3bd7f05Smrg        if (i < context->numMatches)
694a3bd7f05Smrg            context->numMatches = (TMShortCard) (i + 1);
695444c061aSmrg#ifdef DEBUG
696a3bd7f05Smrg        else
697a3bd7f05Smrg            XtWarning("pushing cycle end with no cycle start");
698a3bd7f05Smrg#endif                          /* DEBUG */
699a3bd7f05Smrg    }
700a3bd7f05Smrg    else {
701a3bd7f05Smrg        if (context->numMatches == context->maxMatches) {
702a3bd7f05Smrg            if (context->maxMatches == 0)
703a3bd7f05Smrg                context->maxMatches =
704a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
705a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_ALLOC);
706a3bd7f05Smrg            else
707a3bd7f05Smrg                context->maxMatches =
708a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
709a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_REALLOC);
710a3bd7f05Smrg            context->matches = (MatchPairRec *)
711fdf6a26fSmrg                XtReallocArray(context->matches,
712fdf6a26fSmrg                               (Cardinal) context->maxMatches,
713fdf6a26fSmrg                               sizeof(MatchPairRec));
714a3bd7f05Smrg        }
715a3bd7f05Smrg        context->matches[context->numMatches].isCycleStart =
716a3bd7f05Smrg            newState->isCycleStart;
717a3bd7f05Smrg        context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
718a3bd7f05Smrg        context->matches[context->numMatches].typeIndex = newState->typeIndex;
719a3bd7f05Smrg        context->matches[context->numMatches++].modIndex = newState->modIndex;
720a3bd7f05Smrg        *contextPtr = context;
721a3bd7f05Smrg    }
722a3bd7f05Smrg    UNLOCK_PROCESS;
723444c061aSmrg}
724444c061aSmrg
725a3bd7f05Smrgstatic void
726a3bd7f05SmrgFreeContext(TMContext *contextPtr)
727444c061aSmrg{
728a3bd7f05Smrg    TMContext context = NULL;
729444c061aSmrg
730444c061aSmrg    LOCK_PROCESS;
731444c061aSmrg
732444c061aSmrg    if (&contextCache[0] == *contextPtr)
733a3bd7f05Smrg        context = &contextCache[0];
734444c061aSmrg    else if (&contextCache[1] == *contextPtr)
735a3bd7f05Smrg        context = &contextCache[1];
736444c061aSmrg
737444c061aSmrg    if (context)
738a3bd7f05Smrg        context->numMatches = 0;
739a3bd7f05Smrg    else if (*contextPtr) {
740a3bd7f05Smrg        XtFree((char *) ((*contextPtr)->matches));
741a3bd7f05Smrg        XtFree((char *) *contextPtr);
742444c061aSmrg    }
743444c061aSmrg
744444c061aSmrg    *contextPtr = NULL;
745444c061aSmrg    UNLOCK_PROCESS;
746444c061aSmrg}
747444c061aSmrg
748a3bd7f05Smrgstatic int
749a3bd7f05SmrgMatchExact(TMSimpleStateTree stateTree,
750a3bd7f05Smrg           int startIndex,
751a3bd7f05Smrg           TMShortCard typeIndex,
752a3bd7f05Smrg           TMShortCard modIndex)
753444c061aSmrg{
754444c061aSmrg    TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
755444c061aSmrg    int i;
756444c061aSmrg
757a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
758a3bd7f05Smrg        if ((branchHead->typeIndex == typeIndex) &&
759a3bd7f05Smrg            (branchHead->modIndex == modIndex))
760a3bd7f05Smrg            return i;
761a3bd7f05Smrg    }
762444c061aSmrg    return (TM_NO_MATCH);
763444c061aSmrg}
764444c061aSmrg
765a3bd7f05Smrgstatic void
766a3bd7f05SmrgHandleSimpleState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
767444c061aSmrg{
768a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
769a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
770a3bd7f05Smrg    TMShortCard i;
771a3bd7f05Smrg    ActionRec *actions = NULL;
772a3bd7f05Smrg    Boolean matchExact = False;
773a3bd7f05Smrg    Boolean match = False;
774a3bd7f05Smrg    StatePtr complexMatchState = NULL;
775a3bd7f05Smrg    TMShortCard typeIndex = 0, modIndex = 0;
776a3bd7f05Smrg    int matchTreeIndex = TM_NO_MATCH;
777444c061aSmrg
778444c061aSmrg    LOCK_PROCESS;
779444c061aSmrg    for (i = 0;
780a3bd7f05Smrg         ((!match || !complexMatchState) && (i < xlations->numStateTrees));
781a3bd7f05Smrg         i++) {
782a3bd7f05Smrg        int currIndex = -1;
783a3bd7f05Smrg        TMSimpleStateTree stateTree =
784a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
785a3bd7f05Smrg
786a3bd7f05Smrg        /*
787a3bd7f05Smrg         * don't process this tree if we're only looking for a
788a3bd7f05Smrg         * complexMatchState and there are no complex states
789a3bd7f05Smrg         */
790a3bd7f05Smrg        while (!(match && stateTree->isSimple) &&
791a3bd7f05Smrg               ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
792a3bd7f05Smrg            currIndex++;
793a3bd7f05Smrg            if (matchExact)
794a3bd7f05Smrg                currIndex =
795a3bd7f05Smrg                    MatchExact(stateTree, currIndex, typeIndex, modIndex);
796a3bd7f05Smrg            else
797a3bd7f05Smrg                currIndex = MatchBranchHead(stateTree, currIndex, curEventPtr);
798a3bd7f05Smrg            if (currIndex != TM_NO_MATCH) {
799a3bd7f05Smrg                TMBranchHead branchHead;
800a3bd7f05Smrg                StatePtr currState;
801a3bd7f05Smrg
802a3bd7f05Smrg                branchHead = &stateTree->branchHeadTbl[currIndex];
803a3bd7f05Smrg                if (branchHead->isSimple)
804a3bd7f05Smrg                    currState = NULL;
805a3bd7f05Smrg                else
806a3bd7f05Smrg                    currState = ((TMComplexStateTree) stateTree)
807a3bd7f05Smrg                        ->complexBranchHeadTbl[TMBranchMore(branchHead)];
808a3bd7f05Smrg
809a3bd7f05Smrg                /*
810a3bd7f05Smrg                 * first check for a complete match
811a3bd7f05Smrg                 */
812a3bd7f05Smrg                if (!match) {
813a3bd7f05Smrg                    if (branchHead->hasActions) {
814a3bd7f05Smrg                        if (branchHead->isSimple) {
815a3bd7f05Smrg                            static ActionRec dummyAction;
816a3bd7f05Smrg
817a3bd7f05Smrg                            dummyAction.idx = TMBranchMore(branchHead);
818a3bd7f05Smrg                            actions = &dummyAction;
819a3bd7f05Smrg                        }
820a3bd7f05Smrg                        else
821a3bd7f05Smrg                            actions = currState->actions;
822a3bd7f05Smrg                        tmRecPtr->lastEventTime =
823a3bd7f05Smrg                            GetTime(tmRecPtr, curEventPtr->xev);
824a3bd7f05Smrg                        FreeContext((TMContext *) &tmRecPtr->current_state);
825a3bd7f05Smrg                        match = True;
826a3bd7f05Smrg                        matchTreeIndex = i;
827a3bd7f05Smrg                    }
828a3bd7f05Smrg                    /*
829a3bd7f05Smrg                     * if it doesn't have actions and
830a3bd7f05Smrg                     * it's bc mode then it's a potential match node that is
831a3bd7f05Smrg                     * used to match later sequences.
832a3bd7f05Smrg                     */
833a3bd7f05Smrg                    if (!TMNewMatchSemantics() && !matchExact) {
834a3bd7f05Smrg                        matchExact = True;
835a3bd7f05Smrg                        typeIndex = branchHead->typeIndex;
836a3bd7f05Smrg                        modIndex = branchHead->modIndex;
837a3bd7f05Smrg                    }
838a3bd7f05Smrg                }
839a3bd7f05Smrg                /*
840a3bd7f05Smrg                 * check for it being an event sequence which can be
841a3bd7f05Smrg                 * a future match
842a3bd7f05Smrg                 */
843a3bd7f05Smrg                if (!branchHead->isSimple &&
844a3bd7f05Smrg                    !branchHead->hasActions && !complexMatchState)
845a3bd7f05Smrg                    complexMatchState = currState;
846a3bd7f05Smrg            }
847a3bd7f05Smrg        }
848a3bd7f05Smrg    }
849a3bd7f05Smrg    if (match) {
850a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
851a3bd7f05Smrg        XtActionProc *procs;
852a3bd7f05Smrg        Widget accelWidget;
853a3bd7f05Smrg
854a3bd7f05Smrg        if (bindData->simple.isComplex) {
855a3bd7f05Smrg            TMComplexBindProcs bindProcs =
856a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
857a3bd7f05Smrg            procs = bindProcs->procs;
858a3bd7f05Smrg            accelWidget = bindProcs->widget;
859a3bd7f05Smrg        }
860a3bd7f05Smrg        else {
861a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
862a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
863a3bd7f05Smrg            procs = bindProcs->procs;
864a3bd7f05Smrg            accelWidget = NULL;
865a3bd7f05Smrg        }
866a3bd7f05Smrg        HandleActions
867a3bd7f05Smrg            (w,
868a3bd7f05Smrg             curEventPtr->xev,
869a3bd7f05Smrg             (TMSimpleStateTree) xlations->stateTreeTbl[matchTreeIndex],
870a3bd7f05Smrg             accelWidget, procs, actions);
871a3bd7f05Smrg    }
872444c061aSmrg    if (complexMatchState)
873a3bd7f05Smrg        PushContext(contextPtr, complexMatchState);
874444c061aSmrg    UNLOCK_PROCESS;
875444c061aSmrg}
876444c061aSmrg
877a3bd7f05Smrgstatic int
878a3bd7f05SmrgMatchComplexBranch(TMComplexStateTree stateTree,
879a3bd7f05Smrg                   int startIndex,
880a3bd7f05Smrg                   TMContext context,
881a3bd7f05Smrg                   StatePtr *leafStateRtn)
882444c061aSmrg{
883a3bd7f05Smrg    TMShortCard i;
884444c061aSmrg
885444c061aSmrg    LOCK_PROCESS;
886a3bd7f05Smrg    for (i = (TMShortCard) startIndex; i < stateTree->numComplexBranchHeads;
887a3bd7f05Smrg         i++) {
888a3bd7f05Smrg        StatePtr candState;
889a3bd7f05Smrg        TMShortCard numMatches = context->numMatches;
890a3bd7f05Smrg        MatchPair statMatch = context->matches;
891a3bd7f05Smrg
892a3bd7f05Smrg        for (candState = stateTree->complexBranchHeadTbl[i];
893a3bd7f05Smrg             numMatches && candState;
894a3bd7f05Smrg             numMatches--, statMatch++, candState = candState->nextLevel) {
895a3bd7f05Smrg            if ((statMatch->typeIndex != candState->typeIndex) ||
896a3bd7f05Smrg                (statMatch->modIndex != candState->modIndex))
897a3bd7f05Smrg                break;
898a3bd7f05Smrg        }
899a3bd7f05Smrg        if (numMatches == 0) {
900a3bd7f05Smrg            *leafStateRtn = candState;
901a3bd7f05Smrg            UNLOCK_PROCESS;
902a3bd7f05Smrg            return i;
903a3bd7f05Smrg        }
904a3bd7f05Smrg    }
905444c061aSmrg    *leafStateRtn = NULL;
906444c061aSmrg    UNLOCK_PROCESS;
907444c061aSmrg    return (TM_NO_MATCH);
908444c061aSmrg}
909444c061aSmrg
910a3bd7f05Smrgstatic StatePtr
911a3bd7f05SmrgTryCurrentTree(TMComplexStateTree *stateTreePtr,
912a3bd7f05Smrg               XtTM tmRecPtr,
913a3bd7f05Smrg               TMEventRec *curEventPtr)
914444c061aSmrg{
915a3bd7f05Smrg    StatePtr candState = NULL, matchState = NULL;
916a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
917a3bd7f05Smrg    TMTypeMatch typeMatch;
918a3bd7f05Smrg    TMModifierMatch modMatch;
919a3bd7f05Smrg    int currIndex = -1;
920444c061aSmrg
921444c061aSmrg    /*
922444c061aSmrg     * we want the first sequence that both matches and has actions.
923444c061aSmrg     * we keep on looking till we find both
924444c061aSmrg     */
925444c061aSmrg    LOCK_PROCESS;
926444c061aSmrg    while ((currIndex =
927a3bd7f05Smrg            MatchComplexBranch(*stateTreePtr,
928a3bd7f05Smrg                               ++currIndex, (*contextPtr), &candState))
929a3bd7f05Smrg           != TM_NO_MATCH) {
930a3bd7f05Smrg        if (candState != NULL) {
931a3bd7f05Smrg            typeMatch = TMGetTypeMatch(candState->typeIndex);
932a3bd7f05Smrg            modMatch = TMGetModifierMatch(candState->modIndex);
933a3bd7f05Smrg
934a3bd7f05Smrg            /* does this state's index match? --> done */
935a3bd7f05Smrg            if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) {
936a3bd7f05Smrg                if (candState->actions) {
937a3bd7f05Smrg                    UNLOCK_PROCESS;
938a3bd7f05Smrg                    return candState;
939a3bd7f05Smrg                }
940a3bd7f05Smrg                else
941a3bd7f05Smrg                    matchState = candState;
942a3bd7f05Smrg            }
943a3bd7f05Smrg            /* is this an event timer? */
944a3bd7f05Smrg            if (typeMatch->eventType == _XtEventTimerEventType) {
945a3bd7f05Smrg                StatePtr nextState = candState->nextLevel;
946a3bd7f05Smrg
947a3bd7f05Smrg                /* does the succeeding state match? */
948a3bd7f05Smrg                if (nextState != NULL) {
949a3bd7f05Smrg                    TMTypeMatch nextTypeMatch;
950a3bd7f05Smrg                    TMModifierMatch nextModMatch;
951a3bd7f05Smrg
952a3bd7f05Smrg                    nextTypeMatch = TMGetTypeMatch(nextState->typeIndex);
953a3bd7f05Smrg                    nextModMatch = TMGetModifierMatch(nextState->modIndex);
954a3bd7f05Smrg
955a3bd7f05Smrg                    /* is it within the timeout? */
956a3bd7f05Smrg                    if (MatchIncomingEvent(curEventPtr,
957a3bd7f05Smrg                                           nextTypeMatch, nextModMatch)) {
958a3bd7f05Smrg                        XEvent *xev = curEventPtr->xev;
959a3bd7f05Smrg                        unsigned long time = GetTime(tmRecPtr, xev);
960a3bd7f05Smrg                        XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
961a3bd7f05Smrg                        unsigned long delta =
962a3bd7f05Smrg                            (unsigned long) pd->multi_click_time;
963a3bd7f05Smrg
964a3bd7f05Smrg                        if ((tmRecPtr->lastEventTime + delta) >= time) {
965a3bd7f05Smrg                            if (nextState->actions) {
966a3bd7f05Smrg                                UNLOCK_PROCESS;
967a3bd7f05Smrg                                return candState;
968a3bd7f05Smrg                            }
969a3bd7f05Smrg                            else
970a3bd7f05Smrg                                matchState = candState;
971a3bd7f05Smrg                        }
972a3bd7f05Smrg                    }
973a3bd7f05Smrg                }
974a3bd7f05Smrg            }
975a3bd7f05Smrg        }
976444c061aSmrg    }
977444c061aSmrg    UNLOCK_PROCESS;
978444c061aSmrg    return matchState;
979444c061aSmrg}
980444c061aSmrg
981a3bd7f05Smrgstatic void
982a3bd7f05SmrgHandleComplexState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
983444c061aSmrg{
984a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
985a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
986a3bd7f05Smrg    TMShortCard i, matchTreeIndex = 0;
987a3bd7f05Smrg    StatePtr matchState = NULL, candState;
988a3bd7f05Smrg    TMComplexStateTree *stateTreePtr =
989a3bd7f05Smrg        (TMComplexStateTree *) &xlations->stateTreeTbl[0];
990444c061aSmrg
991444c061aSmrg    LOCK_PROCESS;
992a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) {
993a3bd7f05Smrg        /*
994a3bd7f05Smrg         * some compilers sign extend Boolean bit fields so test for
995a3bd7f05Smrg         * false |||
996a3bd7f05Smrg         */
997a3bd7f05Smrg        if (((*stateTreePtr)->isSimple == False) &&
998a3bd7f05Smrg            (candState = TryCurrentTree(stateTreePtr, tmRecPtr, curEventPtr))) {
999a3bd7f05Smrg            if (!matchState || candState->actions) {
1000a3bd7f05Smrg                matchTreeIndex = i;
1001a3bd7f05Smrg                matchState = candState;
1002a3bd7f05Smrg                if (candState->actions)
1003a3bd7f05Smrg                    break;
1004a3bd7f05Smrg            }
1005a3bd7f05Smrg        }
1006a3bd7f05Smrg    }
1007a3bd7f05Smrg    if (matchState == NULL) {
1008a3bd7f05Smrg        /* couldn't find it... */
1009a3bd7f05Smrg        if (!Ignore(curEventPtr)) {
1010a3bd7f05Smrg            FreeContext(contextPtr);
1011a3bd7f05Smrg            HandleSimpleState(w, tmRecPtr, curEventPtr);
1012a3bd7f05Smrg        }
1013444c061aSmrg    }
1014444c061aSmrg    else {
1015a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
1016a3bd7f05Smrg        XtActionProc *procs;
1017a3bd7f05Smrg        Widget accelWidget;
1018a3bd7f05Smrg        TMTypeMatch typeMatch;
1019a3bd7f05Smrg
1020a3bd7f05Smrg        typeMatch = TMGetTypeMatch(matchState->typeIndex);
1021a3bd7f05Smrg
1022a3bd7f05Smrg        PushContext(contextPtr, matchState);
1023a3bd7f05Smrg        if (typeMatch->eventType == _XtEventTimerEventType) {
1024a3bd7f05Smrg            matchState = matchState->nextLevel;
1025a3bd7f05Smrg            PushContext(contextPtr, matchState);
1026a3bd7f05Smrg        }
1027a3bd7f05Smrg        tmRecPtr->lastEventTime = GetTime(tmRecPtr, curEventPtr->xev);
1028a3bd7f05Smrg
1029a3bd7f05Smrg        if (bindData->simple.isComplex) {
1030a3bd7f05Smrg            TMComplexBindProcs bindProcs =
1031a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
1032a3bd7f05Smrg            procs = bindProcs->procs;
1033a3bd7f05Smrg            accelWidget = bindProcs->widget;
1034a3bd7f05Smrg        }
1035a3bd7f05Smrg        else {
1036a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
1037a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
1038a3bd7f05Smrg            procs = bindProcs->procs;
1039a3bd7f05Smrg            accelWidget = NULL;
1040a3bd7f05Smrg        }
1041a3bd7f05Smrg        HandleActions(w, curEventPtr->xev, (TMSimpleStateTree)
1042a3bd7f05Smrg                      xlations->stateTreeTbl[matchTreeIndex],
1043a3bd7f05Smrg                      accelWidget, procs, matchState->actions);
1044444c061aSmrg    }
1045444c061aSmrg    UNLOCK_PROCESS;
1046444c061aSmrg}
1047444c061aSmrg
1048a3bd7f05Smrgvoid
1049a3bd7f05Smrg_XtTranslateEvent(Widget w, XEvent *event)
1050444c061aSmrg{
1051a3bd7f05Smrg    XtTM tmRecPtr = &w->core.tm;
1052a3bd7f05Smrg    TMEventRec curEvent;
1053a3bd7f05Smrg    StatePtr current_state = tmRecPtr->current_state;
1054444c061aSmrg
1055a3bd7f05Smrg    XEventToTMEvent(event, &curEvent);
1056444c061aSmrg
1057a3bd7f05Smrg    if (!tmRecPtr->translations) {
1058444c061aSmrg        XtAppWarningMsg(XtWidgetToApplicationContext(w),
1059a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1060a3bd7f05Smrg                        "Can't translate event through NULL table", NULL, NULL);
1061a3bd7f05Smrg        return;
1062444c061aSmrg    }
1063444c061aSmrg    if (current_state == NULL)
1064a3bd7f05Smrg        HandleSimpleState(w, tmRecPtr, &curEvent);
1065444c061aSmrg    else
1066a3bd7f05Smrg        HandleComplexState(w, tmRecPtr, &curEvent);
1067444c061aSmrg}
1068444c061aSmrg
1069a3bd7f05Smrgstatic StatePtr
1070a3bd7f05SmrgNewState(TMParseStateTree stateTree _X_UNUSED,
1071a3bd7f05Smrg         TMShortCard typeIndex,
1072a3bd7f05Smrg         TMShortCard modIndex)
1073444c061aSmrg{
1074444c061aSmrg    StatePtr state = XtNew(StateRec);
1075444c061aSmrg
1076444c061aSmrg#ifdef TRACE_TM
1077444c061aSmrg    LOCK_PROCESS;
1078444c061aSmrg    _XtGlobalTM.numComplexStates++;
1079444c061aSmrg    UNLOCK_PROCESS;
1080a3bd7f05Smrg#endif                          /* TRACE_TM */
1081444c061aSmrg    state->typeIndex = typeIndex;
1082444c061aSmrg    state->modIndex = modIndex;
1083444c061aSmrg    state->nextLevel = NULL;
1084444c061aSmrg    state->actions = NULL;
1085444c061aSmrg    state->isCycleStart = state->isCycleEnd = False;
1086444c061aSmrg    return state;
1087444c061aSmrg}
1088444c061aSmrg
1089444c061aSmrg/*
1090444c061aSmrg * This routine is an iterator for state trees. If the func returns
1091444c061aSmrg * true then iteration is over.
1092444c061aSmrg */
1093a3bd7f05Smrgvoid
1094a3bd7f05Smrg_XtTraverseStateTree(TMStateTree tree, _XtTraversalProc func, XtPointer data)
1095444c061aSmrg{
1096a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
1097a3bd7f05Smrg    TMBranchHead currBH;
1098a3bd7f05Smrg    TMShortCard i;
1099a3bd7f05Smrg    StateRec dummyStateRec, *dummyState = &dummyStateRec;
1100a3bd7f05Smrg    ActionRec dummyActionRec, *dummyAction = &dummyActionRec;
1101a3bd7f05Smrg    Boolean firstSimple = True;
1102a3bd7f05Smrg    StatePtr currState;
1103444c061aSmrg
1104444c061aSmrg    /* first traverse the complex states */
1105444c061aSmrg    if (stateTree->isSimple == False)
1106a3bd7f05Smrg        for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
1107a3bd7f05Smrg            currState = stateTree->complexBranchHeadTbl[i];
1108a3bd7f05Smrg            for (; currState; currState = currState->nextLevel) {
1109a3bd7f05Smrg                if (func(currState, data))
1110a3bd7f05Smrg                    return;
1111a3bd7f05Smrg                if (currState->isCycleEnd)
1112a3bd7f05Smrg                    break;
1113a3bd7f05Smrg            }
1114a3bd7f05Smrg        }
1115444c061aSmrg
1116444c061aSmrg    /* now traverse the simple ones */
1117444c061aSmrg    for (i = 0, currBH = stateTree->branchHeadTbl;
1118a3bd7f05Smrg         i < stateTree->numBranchHeads; i++, currBH++) {
1119a3bd7f05Smrg        if (currBH->isSimple && currBH->hasActions) {
1120a3bd7f05Smrg            if (firstSimple) {
1121a3bd7f05Smrg                XtBZero((char *) dummyState, sizeof(StateRec));
1122a3bd7f05Smrg                XtBZero((char *) dummyAction, sizeof(ActionRec));
1123a3bd7f05Smrg                dummyState->actions = dummyAction;
1124a3bd7f05Smrg                firstSimple = False;
1125a3bd7f05Smrg            }
1126a3bd7f05Smrg            dummyState->typeIndex = currBH->typeIndex;
1127a3bd7f05Smrg            dummyState->modIndex = currBH->modIndex;
1128a3bd7f05Smrg            dummyAction->idx = currBH->more;
1129a3bd7f05Smrg            if (func(dummyState, data))
1130a3bd7f05Smrg                return;
1131a3bd7f05Smrg        }
1132a3bd7f05Smrg    }
1133444c061aSmrg}
1134444c061aSmrg
1135a3bd7f05Smrgstatic EventMask
1136a3bd7f05SmrgEventToMask(TMTypeMatch typeMatch, TMModifierMatch modMatch)
1137444c061aSmrg{
1138444c061aSmrg    EventMask returnMask;
1139444c061aSmrg    unsigned long eventType = typeMatch->eventType;
1140444c061aSmrg
1141444c061aSmrg    if (eventType == MotionNotify) {
11420568f49bSmrg        Modifiers modifierMask = (Modifiers) modMatch->modifierMask;
1143444c061aSmrg        Modifiers tempMask;
1144444c061aSmrg
1145a3bd7f05Smrg        returnMask = 0;
1146444c061aSmrg        if (modifierMask == 0) {
1147a3bd7f05Smrg            if (modMatch->modifiers == AnyButtonMask)
1148a3bd7f05Smrg                return ButtonMotionMask;
1149a3bd7f05Smrg            else
1150a3bd7f05Smrg                return PointerMotionMask;
1151a3bd7f05Smrg        }
1152444c061aSmrg        tempMask = modifierMask &
1153a3bd7f05Smrg            (Button1Mask | Button2Mask | Button3Mask
1154a3bd7f05Smrg             | Button4Mask | Button5Mask);
1155444c061aSmrg        if (tempMask == 0)
1156a3bd7f05Smrg            return PointerMotionMask;
1157444c061aSmrg        if (tempMask & Button1Mask)
1158444c061aSmrg            returnMask |= Button1MotionMask;
1159444c061aSmrg        if (tempMask & Button2Mask)
1160444c061aSmrg            returnMask |= Button2MotionMask;
1161444c061aSmrg        if (tempMask & Button3Mask)
1162444c061aSmrg            returnMask |= Button3MotionMask;
1163444c061aSmrg        if (tempMask & Button4Mask)
1164444c061aSmrg            returnMask |= Button4MotionMask;
1165444c061aSmrg        if (tempMask & Button5Mask)
1166444c061aSmrg            returnMask |= Button5MotionMask;
1167444c061aSmrg        return returnMask;
1168444c061aSmrg    }
1169a3bd7f05Smrg    returnMask = _XtConvertTypeToMask((int) eventType);
1170a3bd7f05Smrg    if (returnMask == (StructureNotifyMask | SubstructureNotifyMask))
1171a3bd7f05Smrg        returnMask = StructureNotifyMask;
1172444c061aSmrg    return returnMask;
1173444c061aSmrg}
1174444c061aSmrg
1175a3bd7f05Smrgstatic void
1176a3bd7f05SmrgDispatchMappingNotify(Widget widget _X_UNUSED,  /* will be NULL from _RefreshMapping */
1177a3bd7f05Smrg                      XtPointer closure,        /* real Widget */
1178a3bd7f05Smrg                      XtPointer call_data)      /* XEvent* */
1179444c061aSmrg{
1180a3bd7f05Smrg    _XtTranslateEvent((Widget) closure, (XEvent *) call_data);
1181444c061aSmrg}
1182444c061aSmrg
1183a3bd7f05Smrgstatic void
1184a3bd7f05SmrgRemoveFromMappingCallbacks(Widget widget,
1185a3bd7f05Smrg                           XtPointer closure,    /* target widget */
1186a3bd7f05Smrg                           XtPointer call_data _X_UNUSED)
1187444c061aSmrg{
1188a3bd7f05Smrg    _XtRemoveCallback(&_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
1189a3bd7f05Smrg                      DispatchMappingNotify, closure);
1190444c061aSmrg}
1191444c061aSmrg
1192a3bd7f05Smrgstatic Boolean
1193a3bd7f05SmrgAggregateEventMask(StatePtr state, XtPointer data)
1194444c061aSmrg{
1195444c061aSmrg    LOCK_PROCESS;
1196a3bd7f05Smrg    *((EventMask *) data) |= EventToMask(TMGetTypeMatch(state->typeIndex),
1197a3bd7f05Smrg                                         TMGetModifierMatch(state->modIndex));
1198444c061aSmrg    UNLOCK_PROCESS;
1199444c061aSmrg    return False;
1200444c061aSmrg}
1201444c061aSmrg
1202a3bd7f05Smrgvoid
1203a3bd7f05Smrg_XtInstallTranslations(Widget widget)
1204444c061aSmrg{
1205444c061aSmrg    XtTranslations xlations;
1206a3bd7f05Smrg    Cardinal i;
1207a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1208444c061aSmrg
1209444c061aSmrg    xlations = widget->core.tm.translations;
1210a3bd7f05Smrg    if (xlations == NULL)
1211a3bd7f05Smrg        return;
1212444c061aSmrg
1213444c061aSmrg    /*
1214444c061aSmrg     * check for somebody stuffing the translations directly into the
1215444c061aSmrg     * instance structure. We will end up being called again out of
1216444c061aSmrg     * ComposeTranslations but we *should* have bindings by then
1217444c061aSmrg     */
1218444c061aSmrg    if (widget->core.tm.proc_table == NULL) {
1219a3bd7f05Smrg        _XtMergeTranslations(widget, NULL, XtTableReplace);
1220a3bd7f05Smrg        /*
1221a3bd7f05Smrg         * if we're realized then we'll be called out of
1222a3bd7f05Smrg         * ComposeTranslations
1223a3bd7f05Smrg         */
1224a3bd7f05Smrg        if (XtIsRealized(widget))
1225a3bd7f05Smrg            return;
1226444c061aSmrg    }
1227444c061aSmrg
1228444c061aSmrg    xlations->eventMask = 0;
1229a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1230a3bd7f05Smrg        TMStateTree stateTree = xlations->stateTreeTbl[i];
1231a3bd7f05Smrg
1232a3bd7f05Smrg        _XtTraverseStateTree(stateTree,
1233a3bd7f05Smrg                             AggregateEventMask,
1234a3bd7f05Smrg                             (XtPointer) &xlations->eventMask);
1235a3bd7f05Smrg        mappingNotifyInterest =
1236a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1237a3bd7f05Smrg                       stateTree->simple.mappingNotifyInterest);
1238a3bd7f05Smrg    }
1239444c061aSmrg    /* double click needs to make sure that you have selected on both
1240a3bd7f05Smrg       button down and up. */
1241444c061aSmrg
1242444c061aSmrg    if (xlations->eventMask & ButtonPressMask)
1243a3bd7f05Smrg        xlations->eventMask |= ButtonReleaseMask;
1244444c061aSmrg    if (xlations->eventMask & ButtonReleaseMask)
1245a3bd7f05Smrg        xlations->eventMask |= ButtonPressMask;
1246444c061aSmrg
1247444c061aSmrg    if (mappingNotifyInterest) {
1248a3bd7f05Smrg        XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
1249a3bd7f05Smrg
1250a3bd7f05Smrg        if (pd->mapping_callbacks)
1251a3bd7f05Smrg            _XtAddCallbackOnce(&(pd->mapping_callbacks),
1252a3bd7f05Smrg                               DispatchMappingNotify, (XtPointer) widget);
1253a3bd7f05Smrg        else
1254a3bd7f05Smrg            _XtAddCallback(&(pd->mapping_callbacks),
1255a3bd7f05Smrg                           DispatchMappingNotify, (XtPointer) widget);
1256a3bd7f05Smrg
1257a3bd7f05Smrg        if (widget->core.destroy_callbacks != NULL)
1258a3bd7f05Smrg            _XtAddCallbackOnce((InternalCallbackList *)
1259a3bd7f05Smrg                               &widget->core.destroy_callbacks,
1260a3bd7f05Smrg                               RemoveFromMappingCallbacks, (XtPointer) widget);
1261a3bd7f05Smrg        else
1262a3bd7f05Smrg            _XtAddCallback((InternalCallbackList *)
1263a3bd7f05Smrg                           &widget->core.destroy_callbacks,
1264a3bd7f05Smrg                           RemoveFromMappingCallbacks, (XtPointer) widget);
1265a3bd7f05Smrg    }
1266a3bd7f05Smrg    _XtBindActions(widget, (XtTM) &widget->core.tm);
1267444c061aSmrg    _XtRegisterGrabs(widget);
1268444c061aSmrg}
1269444c061aSmrg
1270a3bd7f05Smrgvoid
1271a3bd7f05Smrg_XtRemoveTranslations(Widget widget)
1272444c061aSmrg{
1273a3bd7f05Smrg    Cardinal i;
1274a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1275a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1276444c061aSmrg
1277444c061aSmrg    if (xlations == NULL)
1278a3bd7f05Smrg        return;
1279a3bd7f05Smrg
1280a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1281a3bd7f05Smrg        TMSimpleStateTree stateTree =
1282a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
1283a3bd7f05Smrg        mappingNotifyInterest =
1284a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1285a3bd7f05Smrg                       stateTree->mappingNotifyInterest);
1286a3bd7f05Smrg    }
1287444c061aSmrg    if (mappingNotifyInterest)
1288a3bd7f05Smrg        RemoveFromMappingCallbacks(widget, (XtPointer) widget, NULL);
1289444c061aSmrg}
1290444c061aSmrg
1291a3bd7f05Smrgstatic void
1292a3bd7f05Smrg_XtUninstallTranslations(Widget widget)
1293444c061aSmrg{
1294a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1295444c061aSmrg
1296a3bd7f05Smrg    _XtUnbindActions(widget, xlations, (TMBindData) widget->core.tm.proc_table);
1297444c061aSmrg    _XtRemoveTranslations(widget);
1298444c061aSmrg    widget->core.tm.translations = NULL;
1299a3bd7f05Smrg    FreeContext((TMContext *) &widget->core.tm.current_state);
1300444c061aSmrg}
1301444c061aSmrg
1302a3bd7f05Smrgvoid
1303a3bd7f05Smrg_XtDestroyTMData(Widget widget)
1304444c061aSmrg{
1305a3bd7f05Smrg    TMComplexBindData cBindData;
1306444c061aSmrg
1307444c061aSmrg    _XtUninstallTranslations(widget);
1308444c061aSmrg
1309a3bd7f05Smrg    if ((cBindData = (TMComplexBindData) widget->core.tm.proc_table)) {
1310a3bd7f05Smrg        if (cBindData->isComplex) {
1311a3bd7f05Smrg            ATranslations nXlations = (ATranslations) cBindData->accel_context;
1312a3bd7f05Smrg
1313a3bd7f05Smrg            while (nXlations) {
1314a3bd7f05Smrg                ATranslations aXlations = nXlations;
1315a3bd7f05Smrg
1316a3bd7f05Smrg                nXlations = nXlations->next;
1317a3bd7f05Smrg                XtFree((char *) aXlations);
1318a3bd7f05Smrg            }
1319a3bd7f05Smrg        }
1320a3bd7f05Smrg        XtFree((char *) cBindData);
1321444c061aSmrg    }
1322444c061aSmrg}
1323444c061aSmrg
1324444c061aSmrg/*** Public procedures ***/
1325444c061aSmrg
1326a3bd7f05Smrgvoid
1327a3bd7f05SmrgXtUninstallTranslations(Widget widget)
1328444c061aSmrg{
1329a3bd7f05Smrg    EventMask oldMask;
1330444c061aSmrg    Widget hookobj;
1331a3bd7f05Smrg
1332444c061aSmrg    WIDGET_TO_APPCON(widget);
1333444c061aSmrg
1334444c061aSmrg    LOCK_APP(app);
1335a3bd7f05Smrg    if (!widget->core.tm.translations) {
1336a3bd7f05Smrg        UNLOCK_APP(app);
1337a3bd7f05Smrg        return;
1338444c061aSmrg    }
1339444c061aSmrg    oldMask = widget->core.tm.translations->eventMask;
1340444c061aSmrg    _XtUninstallTranslations(widget);
1341444c061aSmrg    if (XtIsRealized(widget) && oldMask)
1342a3bd7f05Smrg        XSelectInput(XtDisplay(widget), XtWindow(widget),
1343a3bd7f05Smrg                     (long) XtBuildEventMask(widget));
1344444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
1345444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
1346a3bd7f05Smrg        XtChangeHookDataRec call_data;
1347444c061aSmrg
1348a3bd7f05Smrg        call_data.type = XtHuninstallTranslations;
1349a3bd7f05Smrg        call_data.widget = widget;
1350a3bd7f05Smrg        XtCallCallbackList(hookobj,
1351a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
1352a3bd7f05Smrg                           (XtPointer) &call_data);
1353444c061aSmrg    }
1354444c061aSmrg    UNLOCK_APP(app);
1355444c061aSmrg}
1356444c061aSmrg
1357a3bd7f05SmrgXtTranslations
1358a3bd7f05Smrg_XtCreateXlations(TMStateTree *stateTrees,
1359a3bd7f05Smrg                  TMShortCard numStateTrees,
1360a3bd7f05Smrg                  XtTranslations first,
1361a3bd7f05Smrg                  XtTranslations second)
1362444c061aSmrg{
1363a3bd7f05Smrg    XtTranslations xlations;
1364444c061aSmrg    TMShortCard i;
1365444c061aSmrg
1366444c061aSmrg    xlations = (XtTranslations)
1367a3bd7f05Smrg        __XtMalloc((Cardinal) (sizeof(TranslationData) +
1368a3bd7f05Smrg                               (size_t) (numStateTrees -
1369a3bd7f05Smrg                                         1) * sizeof(TMStateTree)));
1370444c061aSmrg#ifdef TRACE_TM
1371444c061aSmrg    LOCK_PROCESS;
1372444c061aSmrg    if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
1373a3bd7f05Smrg        _XtGlobalTM.tmTblSize = (TMShortCard) (_XtGlobalTM.tmTblSize + 16);
1374a3bd7f05Smrg        _XtGlobalTM.tmTbl = (XtTranslations *)
1375fdf6a26fSmrg            XtReallocArray(_XtGlobalTM.tmTbl,
1376fdf6a26fSmrg                           (Cardinal) _XtGlobalTM.tmTblSize,
1377fdf6a26fSmrg                           (Cardinal) sizeof(XtTranslations));
1378444c061aSmrg    }
1379444c061aSmrg    _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
1380444c061aSmrg    UNLOCK_PROCESS;
1381a3bd7f05Smrg#endif                          /* TRACE_TM */
1382444c061aSmrg
1383444c061aSmrg    xlations->composers[0] = first;
1384444c061aSmrg    xlations->composers[1] = second;
1385444c061aSmrg    xlations->hasBindings = False;
1386444c061aSmrg    xlations->operation = XtTableReplace;
1387444c061aSmrg
1388a3bd7f05Smrg    for (i = 0; i < numStateTrees; i++) {
1389a3bd7f05Smrg        xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
1390a3bd7f05Smrg        stateTrees[i]->simple.refCount++;
1391a3bd7f05Smrg    }
1392444c061aSmrg    xlations->numStateTrees = numStateTrees;
1393444c061aSmrg    xlations->eventMask = 0;
1394444c061aSmrg    return xlations;
1395444c061aSmrg}
1396444c061aSmrg
1397a3bd7f05SmrgTMStateTree
1398a3bd7f05Smrg_XtParseTreeToStateTree(TMParseStateTree parseTree)
1399444c061aSmrg{
1400a3bd7f05Smrg    TMSimpleStateTree simpleTree;
1401444c061aSmrg
1402444c061aSmrg    if (parseTree->numComplexBranchHeads) {
1403a3bd7f05Smrg        TMComplexStateTree complexTree;
1404a3bd7f05Smrg
1405a3bd7f05Smrg        complexTree = XtNew(TMComplexStateTreeRec);
1406a3bd7f05Smrg        complexTree->isSimple = False;
1407fdf6a26fSmrg        complexTree->complexBranchHeadTbl =
1408fdf6a26fSmrg            XtMallocArray((Cardinal) parseTree->numComplexBranchHeads,
1409fdf6a26fSmrg                          (Cardinal) sizeof(StatePtr));
1410fdf6a26fSmrg        memcpy(complexTree->complexBranchHeadTbl,
1411fdf6a26fSmrg               parseTree->complexBranchHeadTbl,
1412fdf6a26fSmrg               parseTree->numComplexBranchHeads * sizeof(StatePtr));
1413a3bd7f05Smrg        complexTree->numComplexBranchHeads = parseTree->numComplexBranchHeads;
1414a3bd7f05Smrg        simpleTree = (TMSimpleStateTree) complexTree;
1415444c061aSmrg    }
1416444c061aSmrg    else {
1417a3bd7f05Smrg        simpleTree = XtNew(TMSimpleStateTreeRec);
1418a3bd7f05Smrg        simpleTree->isSimple = True;
1419444c061aSmrg    }
1420444c061aSmrg    simpleTree->isAccelerator = parseTree->isAccelerator;
1421444c061aSmrg    simpleTree->refCount = 0;
1422444c061aSmrg    simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
1423444c061aSmrg
1424fdf6a26fSmrg    simpleTree->branchHeadTbl =
1425fdf6a26fSmrg        XtMallocArray((Cardinal) parseTree->numBranchHeads,
1426fdf6a26fSmrg                      (Cardinal) sizeof(TMBranchHeadRec));
1427fdf6a26fSmrg    memcpy(simpleTree->branchHeadTbl, parseTree->branchHeadTbl,
1428fdf6a26fSmrg           parseTree->numBranchHeads * sizeof(TMBranchHeadRec));
1429444c061aSmrg    simpleTree->numBranchHeads = parseTree->numBranchHeads;
1430444c061aSmrg
1431fdf6a26fSmrg    simpleTree->quarkTbl = XtMallocArray((Cardinal) parseTree->numQuarks,
1432fdf6a26fSmrg                                         (Cardinal) sizeof(XrmQuark));
1433fdf6a26fSmrg    memcpy(simpleTree->quarkTbl, parseTree->quarkTbl,
1434fdf6a26fSmrg           parseTree->numQuarks * sizeof(XrmQuark));
1435444c061aSmrg    simpleTree->numQuarks = parseTree->numQuarks;
1436444c061aSmrg
1437a3bd7f05Smrg    return (TMStateTree) simpleTree;
1438444c061aSmrg}
1439444c061aSmrg
1440a3bd7f05Smrgstatic void
1441a3bd7f05SmrgFreeActions(ActionPtr actions)
1442444c061aSmrg{
1443444c061aSmrg    ActionPtr action;
1444444c061aSmrg    TMShortCard i;
1445a3bd7f05Smrg
1446444c061aSmrg    for (action = actions; action;) {
1447a3bd7f05Smrg        ActionPtr nextAction = action->next;
1448a3bd7f05Smrg
1449a3bd7f05Smrg        for (i = (TMShortCard) action->num_params; i;) {
1450a3bd7f05Smrg            XtFree((_XtString) action->params[--i]);
1451a3bd7f05Smrg        }
1452a3bd7f05Smrg        XtFree((char *) action->params);
1453a3bd7f05Smrg        XtFree((char *) action);
1454a3bd7f05Smrg        action = nextAction;
1455444c061aSmrg    }
1456444c061aSmrg}
1457444c061aSmrg
1458a3bd7f05Smrgstatic void
1459a3bd7f05SmrgAmbigActions(EventSeqPtr initialEvent,
1460a3bd7f05Smrg             StatePtr *state,
1461a3bd7f05Smrg             TMParseStateTree stateTree)
1462444c061aSmrg{
1463a3bd7f05Smrg    String params[3];
1464a3bd7f05Smrg    Cardinal numParams = 0;
1465444c061aSmrg
1466444c061aSmrg    params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
1467444c061aSmrg    params[numParams++] = _XtPrintActions((*state)->actions,
1468a3bd7f05Smrg                                          stateTree->quarkTbl);
1469a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "oldActions", XtCXtToolkitError,
1470a3bd7f05Smrg                 "Previous entry was: %s %s", params, &numParams);
1471a3bd7f05Smrg    XtFree((char *) params[0]);
1472a3bd7f05Smrg    XtFree((char *) params[1]);
1473444c061aSmrg    numParams = 0;
1474a3bd7f05Smrg    params[numParams++] = _XtPrintActions(initialEvent->actions,
1475a3bd7f05Smrg                                          stateTree->quarkTbl);
1476a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "newActions", XtCXtToolkitError,
1477a3bd7f05Smrg                 "New actions are:%s", params, &numParams);
1478a3bd7f05Smrg    XtFree((char *) params[0]);
1479a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "ambiguousActions",
1480a3bd7f05Smrg                 XtCXtToolkitError,
1481a3bd7f05Smrg                 "Overriding earlier translation manager actions.", NULL, NULL);
1482444c061aSmrg
1483444c061aSmrg    FreeActions((*state)->actions);
1484444c061aSmrg    (*state)->actions = NULL;
1485444c061aSmrg}
1486444c061aSmrg
1487a3bd7f05Smrgvoid
1488a3bd7f05Smrg_XtAddEventSeqToStateTree(EventSeqPtr eventSeq, TMParseStateTree stateTree)
1489444c061aSmrg{
1490a3bd7f05Smrg    StatePtr *state;
1491a3bd7f05Smrg    EventSeqPtr initialEvent = eventSeq;
1492a3bd7f05Smrg    TMBranchHead branchHead;
1493a3bd7f05Smrg    TMShortCard idx, modIndex, typeIndex;
1494444c061aSmrg
1495a3bd7f05Smrg    if (eventSeq == NULL)
1496a3bd7f05Smrg        return;
1497444c061aSmrg
1498444c061aSmrg    /* note that all states in the event seq passed in start out null */
1499444c061aSmrg    /* we fill them in with the matching state as we traverse the list */
1500444c061aSmrg
1501444c061aSmrg    /*
1502444c061aSmrg     * We need to free the parser data structures !!!
1503444c061aSmrg     */
1504444c061aSmrg
1505444c061aSmrg    typeIndex = _XtGetTypeIndex(&eventSeq->event);
1506444c061aSmrg    modIndex = _XtGetModifierIndex(&eventSeq->event);
1507444c061aSmrg    idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
1508444c061aSmrg    branchHead = &stateTree->branchHeadTbl[idx];
1509444c061aSmrg
1510444c061aSmrg    /*
1511444c061aSmrg     * Need to check for pre-existing actions with same lhs |||
1512444c061aSmrg     */
1513444c061aSmrg
1514444c061aSmrg    /*
1515444c061aSmrg     * Check for optimized case. Don't assume that the eventSeq has actions.
1516444c061aSmrg     */
1517444c061aSmrg    if (!eventSeq->next &&
1518a3bd7f05Smrg        eventSeq->actions &&
1519a3bd7f05Smrg        !eventSeq->actions->next && !eventSeq->actions->num_params) {
1520a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1521a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1522a3bd7f05Smrg        branchHead->hasActions = True;
1523a3bd7f05Smrg        XtSetBits(branchHead->more, eventSeq->actions->idx, 13);
1524a3bd7f05Smrg        FreeActions(eventSeq->actions);
1525a3bd7f05Smrg        eventSeq->actions = NULL;
1526a3bd7f05Smrg        return;
1527a3bd7f05Smrg    }
1528444c061aSmrg
1529444c061aSmrg    branchHead->isSimple = False;
1530444c061aSmrg    if (!eventSeq->next)
1531a3bd7f05Smrg        branchHead->hasActions = True;
1532a3bd7f05Smrg    XtSetBits(branchHead->more,
1533a3bd7f05Smrg              GetComplexBranchIndex(stateTree, typeIndex, modIndex), 13);
1534444c061aSmrg    state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
1535444c061aSmrg
1536444c061aSmrg    for (;;) {
1537a3bd7f05Smrg        *state = NewState(stateTree, typeIndex, modIndex);
1538444c061aSmrg
1539a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1540a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1541444c061aSmrg
1542a3bd7f05Smrg        /* *state now points at state record matching event */
1543a3bd7f05Smrg        eventSeq->state = *state;
1544444c061aSmrg
1545a3bd7f05Smrg        if (eventSeq->actions != NULL) {
1546a3bd7f05Smrg            if ((*state)->actions != NULL)
1547a3bd7f05Smrg                AmbigActions(initialEvent, state, stateTree);
1548a3bd7f05Smrg            (*state)->actions = eventSeq->actions;
1549444c061aSmrg#ifdef TRACE_TM
1550a3bd7f05Smrg            LOCK_PROCESS;
1551a3bd7f05Smrg            _XtGlobalTM.numComplexActions++;
1552a3bd7f05Smrg            UNLOCK_PROCESS;
1553a3bd7f05Smrg#endif                          /* TRACE_TM */
1554a3bd7f05Smrg        }
1555a3bd7f05Smrg
1556a3bd7f05Smrg        if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
1557a3bd7f05Smrg            break;
1558a3bd7f05Smrg
1559a3bd7f05Smrg        state = &(*state)->nextLevel;
1560a3bd7f05Smrg        typeIndex = _XtGetTypeIndex(&eventSeq->event);
1561a3bd7f05Smrg        modIndex = _XtGetModifierIndex(&eventSeq->event);
1562a3bd7f05Smrg        LOCK_PROCESS;
1563a3bd7f05Smrg        if (!TMNewMatchSemantics()) {
1564a3bd7f05Smrg            /*
1565a3bd7f05Smrg             * force a potential empty entry into the branch head
1566a3bd7f05Smrg             * table in order to emulate old matching behavior
1567a3bd7f05Smrg             */
1568a3bd7f05Smrg            (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
1569a3bd7f05Smrg        }
1570a3bd7f05Smrg        UNLOCK_PROCESS;
1571444c061aSmrg    }
1572444c061aSmrg
1573444c061aSmrg    if (eventSeq && eventSeq->state) {
1574a3bd7f05Smrg        /* we've been here before... must be a cycle in the event seq. */
1575a3bd7f05Smrg        branchHead->hasCycles = True;
1576a3bd7f05Smrg        (*state)->nextLevel = eventSeq->state;
1577a3bd7f05Smrg        eventSeq->state->isCycleStart = True;
1578a3bd7f05Smrg        (*state)->isCycleEnd = TRUE;
1579444c061aSmrg    }
1580444c061aSmrg}
1581444c061aSmrg
1582444c061aSmrg/*
1583444c061aSmrg * Internal Converter for merging. Old and New must both be valid xlations
1584444c061aSmrg */
1585a3bd7f05SmrgBoolean
1586a3bd7f05Smrg_XtCvtMergeTranslations(Display *dpy _X_UNUSED,
1587a3bd7f05Smrg                        XrmValuePtr args _X_UNUSED,
1588a3bd7f05Smrg                        Cardinal *num_args,
1589a3bd7f05Smrg                        XrmValuePtr from,
1590a3bd7f05Smrg                        XrmValuePtr to,
1591a3bd7f05Smrg                        XtPointer *closure_ret _X_UNUSED)
1592444c061aSmrg{
1593a3bd7f05Smrg    XtTranslations first, second, xlations;
1594a3bd7f05Smrg    TMStateTree *stateTrees, stackStateTrees[16];
1595a3bd7f05Smrg    TMShortCard numStateTrees, i;
1596444c061aSmrg
1597444c061aSmrg    if (*num_args != 0)
1598a3bd7f05Smrg        XtWarningMsg("invalidParameters", "mergeTranslations",
1599a3bd7f05Smrg                     XtCXtToolkitError,
1600a3bd7f05Smrg                     "MergeTM to TranslationTable needs no extra arguments",
1601a3bd7f05Smrg                     NULL, NULL);
1602444c061aSmrg
1603444c061aSmrg    if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
1604a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1605a3bd7f05Smrg        return False;
1606444c061aSmrg    }
1607444c061aSmrg
1608a3bd7f05Smrg    first = ((TMConvertRec *) from->addr)->old;
1609a3bd7f05Smrg    second = ((TMConvertRec *) from->addr)->new;
1610444c061aSmrg
1611a3bd7f05Smrg    numStateTrees =
1612a3bd7f05Smrg        (TMShortCard) (first->numStateTrees + second->numStateTrees);
1613444c061aSmrg
1614444c061aSmrg    stateTrees = (TMStateTree *)
1615a3bd7f05Smrg        XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
1616444c061aSmrg
1617444c061aSmrg    for (i = 0; i < first->numStateTrees; i++)
1618a3bd7f05Smrg        stateTrees[i] = first->stateTreeTbl[i];
1619444c061aSmrg    for (i = 0; i < second->numStateTrees; i++)
1620a3bd7f05Smrg        stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
1621444c061aSmrg
1622444c061aSmrg    xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
1623444c061aSmrg
1624444c061aSmrg    if (to->addr != NULL) {
1625a3bd7f05Smrg        *(XtTranslations *) to->addr = xlations;
1626444c061aSmrg    }
1627444c061aSmrg    else {
1628a3bd7f05Smrg        static XtTranslations staticStateTable;
1629a3bd7f05Smrg
1630a3bd7f05Smrg        staticStateTable = xlations;
1631a3bd7f05Smrg        to->addr = (XPointer) &staticStateTable;
1632a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1633444c061aSmrg    }
1634444c061aSmrg
1635a3bd7f05Smrg    XtStackFree((XtPointer) stateTrees, (XtPointer) stackStateTrees);
1636444c061aSmrg    return True;
1637444c061aSmrg}
1638444c061aSmrg
1639a3bd7f05Smrgstatic XtTranslations
1640a3bd7f05SmrgMergeThem(Widget dest, XtTranslations first, XtTranslations second)
1641444c061aSmrg{
1642a3bd7f05Smrg    XtCacheRef cache_ref;
1643a3bd7f05Smrg    static XrmQuark from_type = NULLQUARK, to_type;
1644a3bd7f05Smrg    XrmValue from, to;
1645a3bd7f05Smrg    TMConvertRec convert_rec;
1646a3bd7f05Smrg    XtTranslations newTable;
1647444c061aSmrg
1648444c061aSmrg    LOCK_PROCESS;
1649444c061aSmrg    if (from_type == NULLQUARK) {
1650a3bd7f05Smrg        from_type = XrmPermStringToQuark(_XtRStateTablePair);
1651a3bd7f05Smrg        to_type = XrmPermStringToQuark(XtRTranslationTable);
1652444c061aSmrg    }
1653444c061aSmrg    UNLOCK_PROCESS;
1654a3bd7f05Smrg    from.addr = (XPointer) &convert_rec;
1655444c061aSmrg    from.size = sizeof(TMConvertRec);
1656a3bd7f05Smrg    to.addr = (XPointer) &newTable;
1657444c061aSmrg    to.size = sizeof(XtTranslations);
1658444c061aSmrg    convert_rec.old = first;
1659444c061aSmrg    convert_rec.new = second;
1660444c061aSmrg
1661444c061aSmrg    LOCK_PROCESS;
1662a3bd7f05Smrg    if (!_XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) {
1663a3bd7f05Smrg        UNLOCK_PROCESS;
1664a3bd7f05Smrg        return NULL;
1665444c061aSmrg    }
1666444c061aSmrg    UNLOCK_PROCESS;
1667444c061aSmrg
1668444c061aSmrg#ifndef REFCNT_TRANSLATIONS
1669444c061aSmrg
1670444c061aSmrg    if (cache_ref)
1671a3bd7f05Smrg        XtAddCallback(dest, XtNdestroyCallback,
1672a3bd7f05Smrg                      XtCallbackReleaseCacheRef, (XtPointer) cache_ref);
1673444c061aSmrg
1674444c061aSmrg#endif
1675444c061aSmrg
1676444c061aSmrg    return newTable;
1677444c061aSmrg}
1678444c061aSmrg
1679444c061aSmrg/*
1680444c061aSmrg * Unmerge will recursively traverse the xlation compose tree and
1681444c061aSmrg * generate a new xlation that is the result of all instances of
1682444c061aSmrg * xlations being removed. It currently doesn't differentiate between
1683444c061aSmrg * the potential that an xlation will be both an accelerator and
1684444c061aSmrg * normal. This is not supported by the spec anyway.
1685444c061aSmrg */
1686a3bd7f05Smrgstatic XtTranslations
1687a3bd7f05SmrgUnmergeTranslations(Widget widget,
1688a3bd7f05Smrg                    XtTranslations xlations,
1689a3bd7f05Smrg                    XtTranslations unmergeXlations,
1690a3bd7f05Smrg                    TMShortCard currIndex,
1691a3bd7f05Smrg                    TMComplexBindProcs oldBindings,
1692a3bd7f05Smrg                    TMShortCard numOldBindings,
1693a3bd7f05Smrg                    TMComplexBindProcs newBindings,
1694a3bd7f05Smrg                    TMShortCard *numNewBindingsRtn)
1695444c061aSmrg{
1696444c061aSmrg    XtTranslations first, second, result;
1697444c061aSmrg
1698444c061aSmrg    if (!xlations || (xlations == unmergeXlations))
1699a3bd7f05Smrg        return NULL;
1700444c061aSmrg
1701444c061aSmrg    if (xlations->composers[0]) {
1702a3bd7f05Smrg        first = UnmergeTranslations(widget, xlations->composers[0],
1703a3bd7f05Smrg                                    unmergeXlations, currIndex,
1704a3bd7f05Smrg                                    oldBindings, numOldBindings,
1705a3bd7f05Smrg                                    newBindings, numNewBindingsRtn);
1706444c061aSmrg    }
1707444c061aSmrg    else
1708a3bd7f05Smrg        first = NULL;
1709444c061aSmrg
17100568f49bSmrg    if (xlations->composers[0]
1711a3bd7f05Smrg        && xlations->composers[1]) {
1712a3bd7f05Smrg        second = UnmergeTranslations(widget, xlations->composers[1],
1713a3bd7f05Smrg                                     unmergeXlations, (TMShortCard)
1714a3bd7f05Smrg                                     (currIndex +
1715a3bd7f05Smrg                                      xlations->composers[0]->numStateTrees),
1716a3bd7f05Smrg                                     oldBindings,
1717a3bd7f05Smrg                                     numOldBindings, newBindings,
1718a3bd7f05Smrg                                     numNewBindingsRtn);
1719444c061aSmrg    }
1720444c061aSmrg    else
1721a3bd7f05Smrg        second = NULL;
1722444c061aSmrg
1723444c061aSmrg    if (first || second) {
1724a3bd7f05Smrg        if (first && second) {
1725a3bd7f05Smrg            if ((first != xlations->composers[0]) ||
1726a3bd7f05Smrg                (second != xlations->composers[1]))
1727a3bd7f05Smrg                result = MergeThem(widget, first, second);
1728a3bd7f05Smrg            else
1729a3bd7f05Smrg                result = xlations;
1730a3bd7f05Smrg        }
1731a3bd7f05Smrg        else {
1732a3bd7f05Smrg            if (first)
1733a3bd7f05Smrg                result = first;
1734a3bd7f05Smrg            else
1735a3bd7f05Smrg                result = second;
1736a3bd7f05Smrg        }
1737a3bd7f05Smrg    }
1738a3bd7f05Smrg    else {                      /* only update for leaf nodes */
1739a3bd7f05Smrg        if (numOldBindings) {
1740a3bd7f05Smrg            Cardinal i;
1741a3bd7f05Smrg
1742a3bd7f05Smrg            for (i = 0; i < xlations->numStateTrees; i++) {
1743a3bd7f05Smrg                if (xlations->stateTreeTbl[i]->simple.isAccelerator)
1744a3bd7f05Smrg                    newBindings[*numNewBindingsRtn] =
1745a3bd7f05Smrg                        oldBindings[currIndex + i];
1746a3bd7f05Smrg                (*numNewBindingsRtn)++;
1747a3bd7f05Smrg            }
1748a3bd7f05Smrg        }
1749a3bd7f05Smrg        result = xlations;
1750444c061aSmrg    }
1751444c061aSmrg    return result;
1752444c061aSmrg}
1753444c061aSmrg
1754444c061aSmrgtypedef struct {
1755444c061aSmrg    XtTranslations xlations;
1756444c061aSmrg    TMComplexBindProcs bindings;
1757a3bd7f05Smrg} MergeBindRec, *MergeBind;
1758a3bd7f05Smrg
1759a3bd7f05Smrgstatic XtTranslations
1760a3bd7f05SmrgMergeTranslations(Widget widget,
1761a3bd7f05Smrg                  XtTranslations oldXlations,
1762a3bd7f05Smrg                  XtTranslations newXlations,
1763a3bd7f05Smrg                  _XtTranslateOp operation,
1764a3bd7f05Smrg                  Widget source,
1765a3bd7f05Smrg                  TMComplexBindProcs oldBindings,
1766a3bd7f05Smrg                  TMComplexBindProcs newBindings,
1767a3bd7f05Smrg                  TMShortCard *numNewRtn)
1768444c061aSmrg{
1769a3bd7f05Smrg    XtTranslations newTable = NULL, xlations;
1770a3bd7f05Smrg    TMComplexBindProcs bindings;
1771a3bd7f05Smrg    TMShortCard i, j;
1772a3bd7f05Smrg    TMStateTree *treePtr;
1773a3bd7f05Smrg    TMShortCard numNew;
1774a3bd7f05Smrg    MergeBindRec bindPair[2];
1775444c061aSmrg
1776444c061aSmrg    /* If the new translation has an accelerator context then pull it
1777444c061aSmrg     * off and pass it and the real xlations in to the caching merge
1778444c061aSmrg     * routine.
1779444c061aSmrg     */
1780444c061aSmrg    if (newXlations->hasBindings) {
1781a3bd7f05Smrg        xlations = ((ATranslations) newXlations)->xlations;
1782a3bd7f05Smrg        bindings = (TMComplexBindProcs)
1783a3bd7f05Smrg            &((ATranslations) newXlations)->bindTbl[0];
1784444c061aSmrg    }
1785444c061aSmrg    else {
1786a3bd7f05Smrg        xlations = newXlations;
1787a3bd7f05Smrg        bindings = NULL;
1788a3bd7f05Smrg    }
1789a3bd7f05Smrg    switch (operation) {
1790fdf6a26fSmrg    default:
1791a3bd7f05Smrg    case XtTableReplace:
1792a3bd7f05Smrg        newTable = bindPair[0].xlations = xlations;
1793a3bd7f05Smrg        bindPair[0].bindings = bindings;
1794a3bd7f05Smrg        bindPair[1].xlations = NULL;
1795a3bd7f05Smrg        bindPair[1].bindings = NULL;
1796a3bd7f05Smrg        break;
1797a3bd7f05Smrg    case XtTableAugment:
1798a3bd7f05Smrg        bindPair[0].xlations = oldXlations;
1799a3bd7f05Smrg        bindPair[0].bindings = oldBindings;
1800a3bd7f05Smrg        bindPair[1].xlations = xlations;
1801a3bd7f05Smrg        bindPair[1].bindings = bindings;
1802a3bd7f05Smrg        newTable = NULL;
1803a3bd7f05Smrg        break;
1804a3bd7f05Smrg    case XtTableOverride:
1805a3bd7f05Smrg        bindPair[0].xlations = xlations;
1806a3bd7f05Smrg        bindPair[0].bindings = bindings;
1807a3bd7f05Smrg        bindPair[1].xlations = oldXlations;
1808a3bd7f05Smrg        bindPair[1].bindings = oldBindings;
1809a3bd7f05Smrg        newTable = NULL;
1810a3bd7f05Smrg        break;
1811444c061aSmrg    }
1812444c061aSmrg    if (!newTable)
1813a3bd7f05Smrg        newTable =
1814a3bd7f05Smrg            MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
1815444c061aSmrg
1816444c061aSmrg    for (i = 0, numNew = 0; i < 2; i++) {
1817a3bd7f05Smrg        if (bindPair[i].xlations)
1818a3bd7f05Smrg            for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
1819a3bd7f05Smrg                if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
1820a3bd7f05Smrg                    if (bindPair[i].bindings)
1821a3bd7f05Smrg                        newBindings[numNew] = bindPair[i].bindings[j];
1822a3bd7f05Smrg                    else {
1823a3bd7f05Smrg                        newBindings[numNew].widget = source;
1824a3bd7f05Smrg                        newBindings[numNew].aXlations = bindPair[i].xlations;
1825a3bd7f05Smrg                    }
1826a3bd7f05Smrg                }
1827a3bd7f05Smrg            }
1828444c061aSmrg    }
1829444c061aSmrg    *numNewRtn = numNew;
1830444c061aSmrg    treePtr = &newTable->stateTreeTbl[0];
1831444c061aSmrg    for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
1832a3bd7f05Smrg        (*treePtr)->simple.refCount++;
1833444c061aSmrg    return newTable;
1834444c061aSmrg}
1835444c061aSmrg
1836a3bd7f05Smrgstatic TMBindData
1837a3bd7f05SmrgMakeBindData(TMComplexBindProcs bindings,
1838a3bd7f05Smrg             TMShortCard numBindings,
1839a3bd7f05Smrg             TMBindData oldBindData)
1840444c061aSmrg{
1841a3bd7f05Smrg    TMLongCard bytes;
1842a3bd7f05Smrg    TMShortCard i;
1843a3bd7f05Smrg    Boolean isComplex;
1844a3bd7f05Smrg    TMBindData bindData;
1845444c061aSmrg
1846444c061aSmrg    if (numBindings == 0)
1847a3bd7f05Smrg        return NULL;
1848444c061aSmrg    for (i = 0; i < numBindings; i++)
1849a3bd7f05Smrg        if (bindings[i].widget)
1850a3bd7f05Smrg            break;
1851444c061aSmrg    isComplex = (i < numBindings);
1852444c061aSmrg    if (isComplex)
1853a3bd7f05Smrg        bytes = (sizeof(TMComplexBindDataRec) +
1854a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1855a3bd7f05Smrg                  sizeof(TMComplexBindProcsRec)));
1856444c061aSmrg    else
1857a3bd7f05Smrg        bytes = (sizeof(TMSimpleBindDataRec) +
1858a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1859a3bd7f05Smrg                  sizeof(TMSimpleBindProcsRec)));
1860444c061aSmrg
1861a3bd7f05Smrg    bindData =
1862a3bd7f05Smrg        (TMBindData) __XtCalloc((Cardinal) sizeof(char), (Cardinal) bytes);
18630568f49bSmrg    XtSetBit(bindData->simple.isComplex, isComplex);
1864444c061aSmrg    if (isComplex) {
1865a3bd7f05Smrg        TMComplexBindData cBindData = (TMComplexBindData) bindData;
1866a3bd7f05Smrg
1867a3bd7f05Smrg        /*
1868a3bd7f05Smrg         * If there were any accelerator contexts in the old bindData
1869a3bd7f05Smrg         * then propagate them to the new one.
1870a3bd7f05Smrg         */
1871a3bd7f05Smrg        if (oldBindData && oldBindData->simple.isComplex)
1872a3bd7f05Smrg            cBindData->accel_context =
1873a3bd7f05Smrg                ((TMComplexBindData) oldBindData)->accel_context;
1874fdf6a26fSmrg        memcpy(&cBindData->bindTbl[0], bindings,
1875fdf6a26fSmrg               numBindings * sizeof(TMComplexBindProcsRec));
1876444c061aSmrg    }
1877444c061aSmrg    return bindData;
1878444c061aSmrg}
1879444c061aSmrg
1880444c061aSmrg/*
1881444c061aSmrg * This routine is the central clearinghouse for merging translations
1882444c061aSmrg * into a widget. It takes care of preping the action bindings for
1883444c061aSmrg * realize time and calling the converter or doing a straight merge if
1884444c061aSmrg * the destination is empty.
1885444c061aSmrg */
1886a3bd7f05Smrgstatic Boolean
1887a3bd7f05SmrgComposeTranslations(Widget dest,
1888a3bd7f05Smrg                    _XtTranslateOp operation,
1889a3bd7f05Smrg                    Widget source,
1890a3bd7f05Smrg                    XtTranslations newXlations)
1891444c061aSmrg{
1892a3bd7f05Smrg    XtTranslations newTable, oldXlations;
1893a3bd7f05Smrg    XtTranslations accNewXlations;
1894a3bd7f05Smrg    EventMask oldMask = 0;
1895a3bd7f05Smrg    TMBindData bindData;
1896a3bd7f05Smrg    TMComplexBindProcs oldBindings = NULL;
1897a3bd7f05Smrg    TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes;
1898444c061aSmrg    TMComplexBindProcsRec stackBindings[16], *newBindings;
1899444c061aSmrg
1900444c061aSmrg    /*
1901444c061aSmrg     * how should we be handling the refcount decrement for the
1902444c061aSmrg     * replaced translation table ???
1903444c061aSmrg     */
1904a3bd7f05Smrg    if (!newXlations) {
1905a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(dest),
1906a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1907a3bd7f05Smrg                        "table to (un)merge must not be null", NULL, NULL);
1908a3bd7f05Smrg        return False;
1909a3bd7f05Smrg    }
1910444c061aSmrg
1911444c061aSmrg    accNewXlations = newXlations;
1912444c061aSmrg    newXlations = ((newXlations->hasBindings)
1913a3bd7f05Smrg                   ? ((ATranslations) newXlations)->xlations : newXlations);
1914444c061aSmrg
1915444c061aSmrg    if (!(oldXlations = dest->core.tm.translations))
1916a3bd7f05Smrg        operation = XtTableReplace;
1917444c061aSmrg
1918444c061aSmrg    /*
1919444c061aSmrg     * try to avoid generation of duplicate state trees. If the source
1920444c061aSmrg     * isn't simple (1 state Tree) then it's too much hassle
1921444c061aSmrg     */
1922444c061aSmrg    if (((operation == XtTableAugment) ||
1923a3bd7f05Smrg         (operation == XtTableOverride)) && (newXlations->numStateTrees == 1)) {
1924a3bd7f05Smrg        Cardinal i;
1925a3bd7f05Smrg
1926a3bd7f05Smrg        for (i = 0; i < oldXlations->numStateTrees; i++)
1927a3bd7f05Smrg            if (oldXlations->stateTreeTbl[i] == newXlations->stateTreeTbl[0])
1928a3bd7f05Smrg                break;
1929a3bd7f05Smrg        if (i < oldXlations->numStateTrees) {
1930a3bd7f05Smrg            if (operation == XtTableAugment) {
1931a3bd7f05Smrg                /*
1932a3bd7f05Smrg                 * we don't need to do anything since it's already
1933a3bd7f05Smrg                 * there
1934a3bd7f05Smrg                 */
1935a3bd7f05Smrg                return True;
1936a3bd7f05Smrg            }
1937a3bd7f05Smrg            else {              /* operation == XtTableOverride */
1938a3bd7f05Smrg                /*
1939a3bd7f05Smrg                 * We'll get rid of the duplicate trees throughout the
1940a3bd7f05Smrg                 * and leave it with a pruned translation table. This
1941a3bd7f05Smrg                 * will only work if the same table has been merged
1942a3bd7f05Smrg                 * into this table (or one of it's composers
1943a3bd7f05Smrg                 */
1944a3bd7f05Smrg                _XtUnmergeTranslations(dest, newXlations);
1945a3bd7f05Smrg                /*
1946a3bd7f05Smrg                 * reset oldXlations so we're back in sync
1947a3bd7f05Smrg                 */
1948a3bd7f05Smrg                if (!(oldXlations = dest->core.tm.translations))
1949a3bd7f05Smrg                    operation = XtTableReplace;
1950a3bd7f05Smrg            }
1951a3bd7f05Smrg        }
1952444c061aSmrg    }
1953444c061aSmrg
1954444c061aSmrg    bindData = (TMBindData) dest->core.tm.proc_table;
1955444c061aSmrg    if (bindData) {
1956a3bd7f05Smrg        numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
1957a3bd7f05Smrg        if (bindData->simple.isComplex)
1958a3bd7f05Smrg            oldBindings = &((TMComplexBindData) bindData)->bindTbl[0];
1959a3bd7f05Smrg        else
1960a3bd7f05Smrg            oldBindings = (TMComplexBindProcs)
1961a3bd7f05Smrg                (&((TMSimpleBindData) bindData)->bindTbl[0]);
1962444c061aSmrg    }
1963444c061aSmrg
1964a3bd7f05Smrg    numBytes =
1965a3bd7f05Smrg        (TMShortCard) ((size_t) ((oldXlations ? oldXlations->numStateTrees : 0)
1966a3bd7f05Smrg                                 +
1967a3bd7f05Smrg                                 newXlations->numStateTrees) *
1968a3bd7f05Smrg                       sizeof(TMComplexBindProcsRec));
1969a3bd7f05Smrg    newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings);
1970a3bd7f05Smrg    XtBZero((char *) newBindings, numBytes);
1971444c061aSmrg
1972444c061aSmrg    if (operation == XtTableUnmerge) {
1973a3bd7f05Smrg        newTable = UnmergeTranslations(dest,
1974a3bd7f05Smrg                                       oldXlations,
1975a3bd7f05Smrg                                       newXlations,
1976a3bd7f05Smrg                                       0,
1977a3bd7f05Smrg                                       oldBindings, numOldBindings,
1978a3bd7f05Smrg                                       newBindings, &numNewBindings);
1979444c061aSmrg#ifdef DEBUG
1980a3bd7f05Smrg        /* check for no match for unmerge */
1981a3bd7f05Smrg        if (newTable == oldXlations) {
1982a3bd7f05Smrg            XtWarning("attempt to unmerge invalid table");
1983a3bd7f05Smrg            XtStackFree((char *) newBindings, (char *) stackBindings);
1984a3bd7f05Smrg            return (newTable != NULL);
1985a3bd7f05Smrg        }
1986a3bd7f05Smrg#endif                          /* DEBUG */
1987444c061aSmrg    }
1988444c061aSmrg    else {
1989a3bd7f05Smrg        newTable = MergeTranslations(dest,
1990a3bd7f05Smrg                                     oldXlations,
1991a3bd7f05Smrg                                     accNewXlations,
1992a3bd7f05Smrg                                     operation,
1993a3bd7f05Smrg                                     source,
1994a3bd7f05Smrg                                     oldBindings, newBindings, &numNewBindings);
1995444c061aSmrg    }
1996444c061aSmrg    if (XtIsRealized(dest)) {
1997a3bd7f05Smrg        oldMask = 0;
1998a3bd7f05Smrg        if (oldXlations)
1999a3bd7f05Smrg            oldMask = oldXlations->eventMask;
2000a3bd7f05Smrg        _XtUninstallTranslations(dest);
2001444c061aSmrg    }
2002444c061aSmrg
2003444c061aSmrg    dest->core.tm.proc_table =
2004a3bd7f05Smrg        (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
2005444c061aSmrg
2006a3bd7f05Smrg    XtFree((char *) bindData);
2007444c061aSmrg
2008444c061aSmrg    dest->core.tm.translations = newTable;
2009444c061aSmrg
2010444c061aSmrg    if (XtIsRealized(dest)) {
2011a3bd7f05Smrg        EventMask mask = 0;
2012a3bd7f05Smrg
2013a3bd7f05Smrg        _XtInstallTranslations(dest);
2014a3bd7f05Smrg        if (newTable)
2015a3bd7f05Smrg            mask = newTable->eventMask;
2016a3bd7f05Smrg        if (mask != oldMask)
2017a3bd7f05Smrg            XSelectInput(XtDisplay(dest), XtWindow(dest),
2018a3bd7f05Smrg                         (long) XtBuildEventMask(dest));
2019a3bd7f05Smrg    }
2020a3bd7f05Smrg    XtStackFree((XtPointer) newBindings, (XtPointer) stackBindings);
2021a3bd7f05Smrg    return (newTable != NULL);
2022444c061aSmrg}
2023444c061aSmrg
2024444c061aSmrg/*
2025444c061aSmrg * If a GetValues is done on a translation resource that contains
2026444c061aSmrg * accelerators we need to return the accelerator context in addition
2027444c061aSmrg * to the pure translations.  Since this means returning memory that
2028fdf6a26fSmrg * the client controls but we still own, we will track the "headers"
2029444c061aSmrg * that we return (via a linked list pointed to from the bindData) and
2030444c061aSmrg * free it at destroy time.
2031444c061aSmrg */
2032a3bd7f05SmrgXtTranslations
2033a3bd7f05Smrg_XtGetTranslationValue(Widget w)
2034444c061aSmrg{
2035a3bd7f05Smrg    XtTM tmRecPtr = (XtTM) &w->core.tm;
2036a3bd7f05Smrg    ATranslations *aXlationsPtr;
2037a3bd7f05Smrg    TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table;
2038a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
2039444c061aSmrg
2040444c061aSmrg    if (!xlations || !cBindData || !cBindData->isComplex)
2041a3bd7f05Smrg        return xlations;
2042444c061aSmrg
2043444c061aSmrg    /* Walk the list looking to see if we already have generated a
2044444c061aSmrg     * header for the currently installed translations.  If we have,
2045444c061aSmrg     * just return that header.  Otherwise create a new header.
2046444c061aSmrg     */
2047444c061aSmrg    for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
2048a3bd7f05Smrg         *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
2049a3bd7f05Smrg         aXlationsPtr = &(*aXlationsPtr)->next);
2050444c061aSmrg    if (*aXlationsPtr)
2051a3bd7f05Smrg        return (XtTranslations) *aXlationsPtr;
2052444c061aSmrg    else {
2053a3bd7f05Smrg        /* create a new aXlations context */
2054a3bd7f05Smrg        ATranslations aXlations;
2055a3bd7f05Smrg        Cardinal numBindings = xlations->numStateTrees;
2056a3bd7f05Smrg
2057a3bd7f05Smrg        (*aXlationsPtr) = aXlations = (ATranslations)
2058a3bd7f05Smrg            __XtMalloc((Cardinal) (sizeof(ATranslationData) +
2059a3bd7f05Smrg                                   (numBindings -
2060a3bd7f05Smrg                                    1) * sizeof(TMComplexBindProcsRec)));
2061a3bd7f05Smrg
2062a3bd7f05Smrg        aXlations->hasBindings = True;
2063a3bd7f05Smrg        aXlations->xlations = xlations;
2064a3bd7f05Smrg        aXlations->next = NULL;
2065fdf6a26fSmrg        memcpy(&aXlations->bindTbl[0],
2066fdf6a26fSmrg               &cBindData->bindTbl[0],
2067fdf6a26fSmrg               numBindings * sizeof(TMComplexBindProcsRec));
2068a3bd7f05Smrg        return (XtTranslations) aXlations;
2069444c061aSmrg    }
2070444c061aSmrg}
2071444c061aSmrg
2072a3bd7f05Smrgstatic void
2073a3bd7f05SmrgRemoveStateTree(TMStateTree tree _X_UNUSED)
2074444c061aSmrg{
2075444c061aSmrg#ifdef REFCNT_TRANSLATIONS
2076a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
2077444c061aSmrg
2078444c061aSmrg    if (--stateTree->refCount == 0) {
2079a3bd7f05Smrg        /*
2080a3bd7f05Smrg         * should we free/refcount the match recs ?
2081a3bd7f05Smrg         */
2082a3bd7f05Smrg        if (!stateTree->isSimple) {
2083a3bd7f05Smrg            StatePtr currState, nextState;
2084a3bd7f05Smrg            TMShortCard i;
2085a3bd7f05Smrg
2086a3bd7f05Smrg            for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
2087a3bd7f05Smrg                currState = nextState = stateTree->complexBranchHeadTbl[i];
2088a3bd7f05Smrg                for (; nextState;) {
2089a3bd7f05Smrg                    FreeActions(currState->actions);
2090a3bd7f05Smrg                    currState->actions = NULL;
2091a3bd7f05Smrg                    if (!currState->isCycleEnd)
2092a3bd7f05Smrg                        nextState = currState->nextLevel;
2093a3bd7f05Smrg                    else
2094a3bd7f05Smrg                        nextState = NULL;
2095a3bd7f05Smrg                    XtFree((char *) currState);
2096a3bd7f05Smrg                }
2097a3bd7f05Smrg            }
2098a3bd7f05Smrg            XtFree((char *) stateTree->complexBranchHeadTbl);
2099a3bd7f05Smrg        }
2100a3bd7f05Smrg        XtFree((char *) stateTree->branchHeadTbl);
2101a3bd7f05Smrg        XtFree((char *) stateTree);
2102a3bd7f05Smrg    }
2103a3bd7f05Smrg#endif                          /* REFCNT_TRANSLATIONS */
2104444c061aSmrg}
2105444c061aSmrg
2106a3bd7f05Smrgvoid
2107a3bd7f05Smrg_XtRemoveStateTreeByIndex(XtTranslations xlations, TMShortCard i)
2108444c061aSmrg{
2109a3bd7f05Smrg    TMStateTree *stateTrees = xlations->stateTreeTbl;
2110444c061aSmrg
2111444c061aSmrg    RemoveStateTree(stateTrees[i]);
2112444c061aSmrg    xlations->numStateTrees--;
2113444c061aSmrg
2114a3bd7f05Smrg    for (; i < xlations->numStateTrees; i++) {
2115a3bd7f05Smrg        stateTrees[i] = stateTrees[i + 1];
2116a3bd7f05Smrg    }
2117444c061aSmrg}
2118444c061aSmrg
2119a3bd7f05Smrgvoid
2120a3bd7f05Smrg_XtFreeTranslations(XtAppContext app,
2121a3bd7f05Smrg                    XrmValuePtr toVal,
2122a3bd7f05Smrg                    XtPointer closure _X_UNUSED,
2123a3bd7f05Smrg                    XrmValuePtr args _X_UNUSED,
2124a3bd7f05Smrg                    Cardinal *num_args)
2125444c061aSmrg{
2126a3bd7f05Smrg    XtTranslations xlations;
2127a3bd7f05Smrg    int i;
2128444c061aSmrg
2129444c061aSmrg    if (*num_args != 0)
2130a3bd7f05Smrg        XtAppWarningMsg(app,
2131a3bd7f05Smrg                        "invalidParameters", "freeTranslations",
2132a3bd7f05Smrg                        XtCXtToolkitError,
2133a3bd7f05Smrg                        "Freeing XtTranslations requires no extra arguments",
2134a3bd7f05Smrg                        NULL, NULL);
2135a3bd7f05Smrg
2136a3bd7f05Smrg    xlations = *(XtTranslations *) toVal->addr;
2137a3bd7f05Smrg    for (i = 0; i < (int) xlations->numStateTrees; i++)
2138a3bd7f05Smrg        RemoveStateTree(xlations->stateTreeTbl[i]);
2139a3bd7f05Smrg    XtFree((char *) xlations);
2140444c061aSmrg}
2141444c061aSmrg
2142444c061aSmrg/*  The spec is not clear on when actions specified in accelerators are bound;
2143444c061aSmrg *  Bind them at Realize the same as translations
2144444c061aSmrg */
2145a3bd7f05Smrgvoid
2146a3bd7f05SmrgXtInstallAccelerators(Widget destination, Widget source)
2147444c061aSmrg{
2148a3bd7f05Smrg    XtTranslations aXlations;
2149a3bd7f05Smrg    _XtTranslateOp op;
2150a3bd7f05Smrg
2151444c061aSmrg    WIDGET_TO_APPCON(destination);
2152444c061aSmrg
2153444c061aSmrg    /*
2154444c061aSmrg     * test that it was parsed as an accelarator table. Even though
2155444c061aSmrg     * there doesn't need to be a distinction it makes life easier if
2156444c061aSmrg     * we honor the spec implication that aXlations is an accelerator
2157444c061aSmrg     */
2158444c061aSmrg    LOCK_APP(app);
2159444c061aSmrg    LOCK_PROCESS;
2160444c061aSmrg    if ((!XtIsWidget(source)) ||
2161a3bd7f05Smrg        ((aXlations = source->core.accelerators) == NULL) ||
2162a3bd7f05Smrg        (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) {
2163a3bd7f05Smrg        UNLOCK_PROCESS;
2164a3bd7f05Smrg        UNLOCK_APP(app);
2165a3bd7f05Smrg        return;
2166444c061aSmrg    }
2167444c061aSmrg
2168444c061aSmrg    aXlations = source->core.accelerators;
2169444c061aSmrg    op = aXlations->operation;
2170444c061aSmrg
2171444c061aSmrg    if (ComposeTranslations(destination, op, source, aXlations) &&
2172a3bd7f05Smrg        (XtClass(source)->core_class.display_accelerator != NULL)) {
2173a3bd7f05Smrg        _XtString buf = _XtPrintXlations(destination, aXlations, source, False);
2174a3bd7f05Smrg
2175a3bd7f05Smrg        (*(XtClass(source)->core_class.display_accelerator)) (source, buf);
2176a3bd7f05Smrg        XtFree(buf);
2177444c061aSmrg    }
2178444c061aSmrg    UNLOCK_PROCESS;
2179444c061aSmrg    UNLOCK_APP(app);
2180444c061aSmrg}
2181444c061aSmrg
2182a3bd7f05Smrgvoid
2183a3bd7f05SmrgXtInstallAllAccelerators(Widget destination, Widget source)
2184444c061aSmrg{
2185444c061aSmrg    Cardinal i;
2186a3bd7f05Smrg
2187444c061aSmrg    WIDGET_TO_APPCON(destination);
2188444c061aSmrg
2189444c061aSmrg    /* Recurse down normal children */
2190444c061aSmrg    LOCK_APP(app);
2191444c061aSmrg    LOCK_PROCESS;
2192444c061aSmrg    if (XtIsComposite(source)) {
21930568f49bSmrg        CompositeWidget cw = (CompositeWidget) source;
2194a3bd7f05Smrg
2195444c061aSmrg        for (i = 0; i < cw->composite.num_children; i++) {
2196a3bd7f05Smrg            XtInstallAllAccelerators(destination, cw->composite.children[i]);
2197444c061aSmrg        }
2198444c061aSmrg    }
2199444c061aSmrg
2200444c061aSmrg    /* Recurse down popup children */
2201444c061aSmrg    if (XtIsWidget(source)) {
2202444c061aSmrg        for (i = 0; i < source->core.num_popups; i++) {
2203a3bd7f05Smrg            XtInstallAllAccelerators(destination, source->core.popup_list[i]);
2204444c061aSmrg        }
2205444c061aSmrg    }
2206444c061aSmrg    /* Finally, apply procedure to this widget */
2207a3bd7f05Smrg    XtInstallAccelerators(destination, source);
2208444c061aSmrg    UNLOCK_PROCESS;
2209444c061aSmrg    UNLOCK_APP(app);
2210444c061aSmrg}
2211444c061aSmrg
2212a3bd7f05Smrg#if 0                           /* dead code */
2213a3bd7f05Smrgstatic _XtTranslateOp
2214a3bd7f05Smrg_XtGetTMOperation(XtTranslations xlations)
2215444c061aSmrg{
2216444c061aSmrg    return ((xlations->hasBindings)
2217a3bd7f05Smrg            ? ((ATranslations) xlations)->xlations->operation
2218a3bd7f05Smrg            : xlations->operation);
2219444c061aSmrg}
2220444c061aSmrg#endif
2221444c061aSmrg
2222a3bd7f05Smrgvoid
2223a3bd7f05SmrgXtAugmentTranslations(Widget widget, XtTranslations new)
2224444c061aSmrg{
2225444c061aSmrg    Widget hookobj;
2226a3bd7f05Smrg
2227444c061aSmrg    WIDGET_TO_APPCON(widget);
2228444c061aSmrg
2229444c061aSmrg    LOCK_APP(app);
2230444c061aSmrg    LOCK_PROCESS;
2231a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableAugment, (Widget) NULL, new);
2232444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2233444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2234a3bd7f05Smrg        XtChangeHookDataRec call_data;
2235444c061aSmrg
2236a3bd7f05Smrg        call_data.type = XtHaugmentTranslations;
2237a3bd7f05Smrg        call_data.widget = widget;
2238a3bd7f05Smrg        XtCallCallbackList(hookobj,
2239a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2240a3bd7f05Smrg                           (XtPointer) &call_data);
2241444c061aSmrg    }
2242444c061aSmrg    UNLOCK_PROCESS;
2243444c061aSmrg    UNLOCK_APP(app);
2244444c061aSmrg}
2245444c061aSmrg
2246a3bd7f05Smrgvoid
2247a3bd7f05SmrgXtOverrideTranslations(Widget widget, XtTranslations new)
2248444c061aSmrg{
2249444c061aSmrg    Widget hookobj;
2250a3bd7f05Smrg
2251444c061aSmrg    WIDGET_TO_APPCON(widget);
2252444c061aSmrg
2253444c061aSmrg    LOCK_APP(app);
2254444c061aSmrg    LOCK_PROCESS;
2255a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableOverride, (Widget) NULL, new);
2256444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2257444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2258a3bd7f05Smrg        XtChangeHookDataRec call_data;
2259444c061aSmrg
2260a3bd7f05Smrg        call_data.type = XtHoverrideTranslations;
2261a3bd7f05Smrg        call_data.widget = widget;
2262a3bd7f05Smrg        XtCallCallbackList(hookobj,
2263a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2264a3bd7f05Smrg                           (XtPointer) &call_data);
2265444c061aSmrg    }
2266444c061aSmrg    UNLOCK_PROCESS;
2267444c061aSmrg    UNLOCK_APP(app);
2268444c061aSmrg}
2269444c061aSmrg
2270a3bd7f05Smrgvoid
2271a3bd7f05Smrg_XtMergeTranslations(Widget widget,
2272a3bd7f05Smrg                     XtTranslations newXlations,
2273a3bd7f05Smrg                     _XtTranslateOp op)
2274444c061aSmrg{
2275a3bd7f05Smrg    if (!newXlations) {
2276a3bd7f05Smrg        if (!widget->core.tm.translations)
2277a3bd7f05Smrg            return;
2278a3bd7f05Smrg        else {
2279a3bd7f05Smrg            newXlations = widget->core.tm.translations;
2280a3bd7f05Smrg            widget->core.tm.translations = NULL;
2281a3bd7f05Smrg        }
2282a3bd7f05Smrg    }
2283a3bd7f05Smrg    (void) ComposeTranslations(widget, op, (Widget) NULL, newXlations);
2284444c061aSmrg}
2285444c061aSmrg
2286a3bd7f05Smrgvoid
2287a3bd7f05Smrg_XtUnmergeTranslations(Widget widget, XtTranslations xlations)
2288444c061aSmrg{
2289a3bd7f05Smrg    ComposeTranslations(widget, XtTableUnmerge, (Widget) NULL, xlations);
2290444c061aSmrg}
2291