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
86a3bd7f05SmrgTMGlobalRec _XtGlobalTM;        /* initialized to zero K&R */
87444c061aSmrg
88444c061aSmrg#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
89444c061aSmrg  (typeMatch->eventType == tmEvent->event.eventType && \
90444c061aSmrg   (typeMatch->matchEvent != NULL) && \
91444c061aSmrg   (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
92444c061aSmrg
93444c061aSmrg#define NumStateTrees(xlations) \
94444c061aSmrg  ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
95444c061aSmrg
96a3bd7f05Smrgstatic TMShortCard
97a3bd7f05SmrgGetBranchHead(TMParseStateTree parseTree,
98a3bd7f05Smrg              TMShortCard typeIndex,
99a3bd7f05Smrg              TMShortCard modIndex,
100a3bd7f05Smrg              Boolean isDummy)
101444c061aSmrg{
102fdf6a26fSmrg#define TM_BRANCH_HEAD_TBL_ALLOC        ((TMShortCard) 8)
103fdf6a26fSmrg#define TM_BRANCH_HEAD_TBL_REALLOC      ((TMShortCard) 8)
104444c061aSmrg
105444c061aSmrg    TMBranchHead branchHead = parseTree->branchHeadTbl;
106a3bd7f05Smrg
107444c061aSmrg    /*
108444c061aSmrg     * dummy is used as a place holder for later matching in old-style
109444c061aSmrg     * matching behavior. If there's already an entry we don't need
110444c061aSmrg     * another dummy.
111444c061aSmrg     */
112444c061aSmrg    if (isDummy) {
113a3bd7f05Smrg        TMShortCard i;
114a3bd7f05Smrg
115a3bd7f05Smrg        for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
116a3bd7f05Smrg            if ((branchHead->typeIndex == typeIndex) &&
117a3bd7f05Smrg                (branchHead->modIndex == modIndex))
118a3bd7f05Smrg                return i;
119a3bd7f05Smrg        }
120a3bd7f05Smrg    }
121a3bd7f05Smrg    if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) {
122a3bd7f05Smrg
123a3bd7f05Smrg        if (parseTree->branchHeadTblSize == 0)
124fdf6a26fSmrg            parseTree->branchHeadTblSize = TM_BRANCH_HEAD_TBL_ALLOC;
125a3bd7f05Smrg        else
126fdf6a26fSmrg            parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_REALLOC;
127fdf6a26fSmrg
128a3bd7f05Smrg        if (parseTree->isStackBranchHeads) {
129a3bd7f05Smrg            TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl;
130a3bd7f05Smrg
131fdf6a26fSmrg            parseTree->branchHeadTbl =
132fdf6a26fSmrg                XtMallocArray((Cardinal) parseTree->branchHeadTblSize,
133fdf6a26fSmrg                              (Cardinal) sizeof(TMBranchHeadRec));
134fdf6a26fSmrg            memcpy(parseTree->branchHeadTbl, oldBranchHeadTbl,
135fdf6a26fSmrg                   parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec));
136a3bd7f05Smrg            parseTree->isStackBranchHeads = False;
137a3bd7f05Smrg        }
138a3bd7f05Smrg        else {
139a3bd7f05Smrg            parseTree->branchHeadTbl = (TMBranchHead)
140fdf6a26fSmrg                XtReallocArray(parseTree->branchHeadTbl,
141fdf6a26fSmrg                               (Cardinal) parseTree->branchHeadTblSize,
142fdf6a26fSmrg                               (Cardinal) sizeof(TMBranchHeadRec));
143a3bd7f05Smrg        }
144a3bd7f05Smrg    }
145444c061aSmrg#ifdef TRACE_TM
146444c061aSmrg    LOCK_PROCESS;
147444c061aSmrg    _XtGlobalTM.numBranchHeads++;
148444c061aSmrg    UNLOCK_PROCESS;
149a3bd7f05Smrg#endif                          /* TRACE_TM */
150a3bd7f05Smrg    branchHead = &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
151444c061aSmrg    branchHead->typeIndex = typeIndex;
152444c061aSmrg    branchHead->modIndex = modIndex;
153444c061aSmrg    branchHead->more = 0;
154444c061aSmrg    branchHead->isSimple = True;
155444c061aSmrg    branchHead->hasActions = False;
156444c061aSmrg    branchHead->hasCycles = False;
1570568f49bSmrg    return (TMShortCard) (parseTree->numBranchHeads - 1);
158444c061aSmrg}
159444c061aSmrg
160a3bd7f05SmrgTMShortCard
161a3bd7f05Smrg_XtGetQuarkIndex(TMParseStateTree parseTree, XrmQuark quark)
162444c061aSmrg{
163fdf6a26fSmrg#define TM_QUARK_TBL_ALLOC      ((TMShortCard) 16)
164fdf6a26fSmrg#define TM_QUARK_TBL_REALLOC    ((TMShortCard) 16)
1650568f49bSmrg    TMShortCard i;
166444c061aSmrg
167a3bd7f05Smrg    for (i = 0; i < parseTree->numQuarks; i++)
168a3bd7f05Smrg        if (parseTree->quarkTbl[i] == quark)
169a3bd7f05Smrg            break;
170a3bd7f05Smrg
171a3bd7f05Smrg    if (i == parseTree->numQuarks) {
172a3bd7f05Smrg        if (parseTree->numQuarks == parseTree->quarkTblSize) {
173a3bd7f05Smrg
174a3bd7f05Smrg            if (parseTree->quarkTblSize == 0)
175fdf6a26fSmrg                parseTree->quarkTblSize = TM_QUARK_TBL_ALLOC;
176a3bd7f05Smrg            else
177fdf6a26fSmrg                parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC;
178a3bd7f05Smrg
179a3bd7f05Smrg            if (parseTree->isStackQuarks) {
180a3bd7f05Smrg                XrmQuark *oldquarkTbl = parseTree->quarkTbl;
181a3bd7f05Smrg
182fdf6a26fSmrg                parseTree->quarkTbl =
183fdf6a26fSmrg                    XtMallocArray((Cardinal) parseTree->quarkTblSize,
184fdf6a26fSmrg                                  (Cardinal) sizeof(XrmQuark));
185fdf6a26fSmrg                memcpy(parseTree->quarkTbl, oldquarkTbl,
186fdf6a26fSmrg                       parseTree->quarkTblSize * sizeof(XrmQuark));
187a3bd7f05Smrg                parseTree->isStackQuarks = False;
188a3bd7f05Smrg            }
189a3bd7f05Smrg            else {
190a3bd7f05Smrg                parseTree->quarkTbl = (XrmQuark *)
191fdf6a26fSmrg                    XtReallocArray(parseTree->quarkTbl,
192fdf6a26fSmrg                                   (Cardinal) parseTree->quarkTblSize,
193fdf6a26fSmrg                                   (Cardinal) sizeof(XrmQuark));
194a3bd7f05Smrg            }
195a3bd7f05Smrg        }
196a3bd7f05Smrg        parseTree->quarkTbl[parseTree->numQuarks++] = quark;
197a3bd7f05Smrg    }
198444c061aSmrg    return i;
199444c061aSmrg}
200444c061aSmrg
201444c061aSmrg/*
202444c061aSmrg * Get an entry from the parseTrees complex branchHead tbl. If there's none
203444c061aSmrg * there then allocate one
204444c061aSmrg */
205a3bd7f05Smrgstatic TMShortCard
206a3bd7f05SmrgGetComplexBranchIndex(TMParseStateTree parseTree,
207a3bd7f05Smrg                      TMShortCard typeIndex _X_UNUSED,
208a3bd7f05Smrg                      TMShortCard modIndex _X_UNUSED)
209444c061aSmrg{
210444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
211444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
212444c061aSmrg
213444c061aSmrg    if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
214a3bd7f05Smrg        if (parseTree->complexBranchHeadTblSize == 0)
215a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
216a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
217a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_ALLOC);
218a3bd7f05Smrg        else
219a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
220a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
221a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_REALLOC);
222a3bd7f05Smrg
223a3bd7f05Smrg        if (parseTree->isStackComplexBranchHeads) {
224a3bd7f05Smrg            StatePtr *oldcomplexBranchHeadTbl = parseTree->complexBranchHeadTbl;
225a3bd7f05Smrg
226fdf6a26fSmrg            parseTree->complexBranchHeadTbl =
227fdf6a26fSmrg                XtMallocArray((Cardinal) parseTree->complexBranchHeadTblSize,
228fdf6a26fSmrg                              (Cardinal) sizeof(StatePtr));
229fdf6a26fSmrg            memcpy(parseTree->complexBranchHeadTbl, oldcomplexBranchHeadTbl,
230fdf6a26fSmrg                   parseTree->complexBranchHeadTblSize * sizeof(StatePtr));
231a3bd7f05Smrg            parseTree->isStackComplexBranchHeads = False;
232a3bd7f05Smrg        }
233a3bd7f05Smrg        else {
234a3bd7f05Smrg            parseTree->complexBranchHeadTbl = (StatePtr *)
235fdf6a26fSmrg                XtReallocArray(parseTree->complexBranchHeadTbl,
236fdf6a26fSmrg                               (Cardinal) parseTree->complexBranchHeadTblSize,
237fdf6a26fSmrg                               (Cardinal) sizeof(StatePtr));
238a3bd7f05Smrg        }
239444c061aSmrg    }
240444c061aSmrg    parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
2410568f49bSmrg    return (TMShortCard) (parseTree->numComplexBranchHeads - 1);
242444c061aSmrg}
243444c061aSmrg
244a3bd7f05SmrgTMShortCard
245a3bd7f05Smrg_XtGetTypeIndex(Event *event)
246444c061aSmrg{
247a3bd7f05Smrg    TMShortCard i, j = TM_TYPE_SEGMENT_SIZE;
248a3bd7f05Smrg    TMShortCard typeIndex = 0;
249a3bd7f05Smrg    TMTypeMatch typeMatch;
250a3bd7f05Smrg    TMTypeMatch segment = NULL;
251444c061aSmrg
252444c061aSmrg    LOCK_PROCESS;
253444c061aSmrg    for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
254a3bd7f05Smrg        segment = _XtGlobalTM.typeMatchSegmentTbl[i];
255a3bd7f05Smrg        for (j = 0;
256a3bd7f05Smrg             typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE;
257a3bd7f05Smrg             j++, typeIndex++) {
258a3bd7f05Smrg            typeMatch = &(segment[j]);
259a3bd7f05Smrg            if (event->eventType == typeMatch->eventType &&
260a3bd7f05Smrg                event->eventCode == typeMatch->eventCode &&
261a3bd7f05Smrg                event->eventCodeMask == typeMatch->eventCodeMask &&
262a3bd7f05Smrg                event->matchEvent == typeMatch->matchEvent) {
263a3bd7f05Smrg                UNLOCK_PROCESS;
264a3bd7f05Smrg                return typeIndex;
265a3bd7f05Smrg            }
266a3bd7f05Smrg        }
267444c061aSmrg    }
268444c061aSmrg
269444c061aSmrg    if (j == TM_TYPE_SEGMENT_SIZE) {
270a3bd7f05Smrg        if (_XtGlobalTM.numTypeMatchSegments ==
271a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize) {
272a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize =
273a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.typeMatchSegmentTblSize + 4);
274a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
275fdf6a26fSmrg                XtReallocArray(_XtGlobalTM.typeMatchSegmentTbl,
276fdf6a26fSmrg                               (Cardinal) _XtGlobalTM.typeMatchSegmentTblSize,
277fdf6a26fSmrg                               (Cardinal) sizeof(TMTypeMatch));
278a3bd7f05Smrg        }
279a3bd7f05Smrg        _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] =
280fdf6a26fSmrg            segment = XtMallocArray(TM_TYPE_SEGMENT_SIZE,
281fdf6a26fSmrg                                    (Cardinal) sizeof(TMTypeMatchRec));
282a3bd7f05Smrg        j = 0;
283444c061aSmrg    }
284444c061aSmrg    typeMatch = &segment[j];
285444c061aSmrg    typeMatch->eventType = event->eventType;
286444c061aSmrg    typeMatch->eventCode = event->eventCode;
287444c061aSmrg    typeMatch->eventCodeMask = event->eventCodeMask;
288444c061aSmrg    typeMatch->matchEvent = event->matchEvent;
289444c061aSmrg    _XtGlobalTM.numTypeMatches++;
290444c061aSmrg    UNLOCK_PROCESS;
291444c061aSmrg    return typeIndex;
292444c061aSmrg}
293444c061aSmrg
294a3bd7f05Smrgstatic Boolean
295a3bd7f05SmrgCompareLateModifiers(LateBindingsPtr lateBind1P, LateBindingsPtr lateBind2P)
296444c061aSmrg{
297444c061aSmrg    LateBindingsPtr late1P = lateBind1P;
298444c061aSmrg    LateBindingsPtr late2P = lateBind2P;
299444c061aSmrg
300444c061aSmrg    if (late1P != NULL || late2P != NULL) {
301a3bd7f05Smrg        int i = 0;
302a3bd7f05Smrg        int j = 0;
303a3bd7f05Smrg
304a3bd7f05Smrg        if (late1P != NULL)
305a3bd7f05Smrg            for (; late1P->keysym != NoSymbol; i++)
306a3bd7f05Smrg                late1P++;
307a3bd7f05Smrg        if (late2P != NULL)
308a3bd7f05Smrg            for (; late2P->keysym != NoSymbol; j++)
309a3bd7f05Smrg                late2P++;
310a3bd7f05Smrg        if (i != j)
311a3bd7f05Smrg            return FALSE;
312a3bd7f05Smrg        late1P--;
313a3bd7f05Smrg        while (late1P >= lateBind1P) {
314a3bd7f05Smrg            Boolean last = True;
315a3bd7f05Smrg
316a3bd7f05Smrg            for (late2P = lateBind2P + i - 1; late2P >= lateBind2P; late2P--) {
317a3bd7f05Smrg                if (late1P->keysym == late2P->keysym
318a3bd7f05Smrg                    && late1P->knot == late2P->knot) {
319a3bd7f05Smrg                    j--;
320a3bd7f05Smrg                    if (last)
321a3bd7f05Smrg                        i--;
322a3bd7f05Smrg                    break;
323a3bd7f05Smrg                }
324a3bd7f05Smrg                last = False;
325a3bd7f05Smrg            }
326a3bd7f05Smrg            late1P--;
327a3bd7f05Smrg        }
328a3bd7f05Smrg        if (j != 0)
329a3bd7f05Smrg            return FALSE;
330444c061aSmrg    }
331444c061aSmrg    return TRUE;
332444c061aSmrg}
333444c061aSmrg
334a3bd7f05SmrgTMShortCard
335a3bd7f05Smrg_XtGetModifierIndex(Event *event)
336444c061aSmrg{
337a3bd7f05Smrg    TMShortCard i, j = TM_MOD_SEGMENT_SIZE;
338a3bd7f05Smrg    TMShortCard modIndex = 0;
339a3bd7f05Smrg    TMModifierMatch modMatch;
340a3bd7f05Smrg    TMModifierMatch segment = NULL;
341444c061aSmrg
342444c061aSmrg    LOCK_PROCESS;
343444c061aSmrg    for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
344a3bd7f05Smrg        segment = _XtGlobalTM.modMatchSegmentTbl[i];
345a3bd7f05Smrg        for (j = 0;
346a3bd7f05Smrg             modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE;
347a3bd7f05Smrg             j++, modIndex++) {
348a3bd7f05Smrg            modMatch = &(segment[j]);
349a3bd7f05Smrg            if (event->modifiers == modMatch->modifiers &&
350a3bd7f05Smrg                event->modifierMask == modMatch->modifierMask &&
351a3bd7f05Smrg                event->standard == modMatch->standard &&
352a3bd7f05Smrg                ((!event->lateModifiers && !modMatch->lateModifiers) ||
353a3bd7f05Smrg                 CompareLateModifiers(event->lateModifiers,
354a3bd7f05Smrg                                      modMatch->lateModifiers))) {
355a3bd7f05Smrg                /*
356a3bd7f05Smrg                 * if we found a match then we can free the parser's
357a3bd7f05Smrg                 * late modifiers. If there isn't a match we use the
358a3bd7f05Smrg                 * parser's copy
359a3bd7f05Smrg                 */
360a3bd7f05Smrg                if (event->lateModifiers &&
361a3bd7f05Smrg                    --event->lateModifiers->ref_count == 0) {
362a3bd7f05Smrg                    XtFree((char *) event->lateModifiers);
363a3bd7f05Smrg                    event->lateModifiers = NULL;
364a3bd7f05Smrg                }
365a3bd7f05Smrg                UNLOCK_PROCESS;
366a3bd7f05Smrg                return modIndex;
367a3bd7f05Smrg            }
368a3bd7f05Smrg        }
369444c061aSmrg    }
370444c061aSmrg
371444c061aSmrg    if (j == TM_MOD_SEGMENT_SIZE) {
372a3bd7f05Smrg        if (_XtGlobalTM.numModMatchSegments ==
373a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize) {
374a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize =
375a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.modMatchSegmentTblSize + 4);
376a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
377fdf6a26fSmrg                XtReallocArray(_XtGlobalTM.modMatchSegmentTbl,
378fdf6a26fSmrg                               (Cardinal) _XtGlobalTM.modMatchSegmentTblSize,
379fdf6a26fSmrg                               (Cardinal) sizeof(TMModifierMatch));
380a3bd7f05Smrg        }
381a3bd7f05Smrg        _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] =
382fdf6a26fSmrg            segment = XtMallocArray(TM_MOD_SEGMENT_SIZE,
383fdf6a26fSmrg                                    (Cardinal) sizeof(TMModifierMatchRec));
384a3bd7f05Smrg        j = 0;
385444c061aSmrg    }
386444c061aSmrg    modMatch = &segment[j];
3870568f49bSmrg    modMatch->modifiers = event->modifiers;
388444c061aSmrg    modMatch->modifierMask = event->modifierMask;
389444c061aSmrg    modMatch->standard = event->standard;
390444c061aSmrg    /*
391444c061aSmrg     * We use the parser's copy of the late binding array
392444c061aSmrg     */
393444c061aSmrg#ifdef TRACE_TM
394444c061aSmrg    if (event->lateModifiers)
395a3bd7f05Smrg        _XtGlobalTM.numLateBindings++;
396a3bd7f05Smrg#endif                          /* TRACE_TM */
397444c061aSmrg    modMatch->lateModifiers = event->lateModifiers;
398444c061aSmrg    _XtGlobalTM.numModMatches++;
399444c061aSmrg    UNLOCK_PROCESS;
400444c061aSmrg    return modIndex;
401444c061aSmrg}
402444c061aSmrg
403444c061aSmrg/*
404444c061aSmrg * This is called from the SimpleStateHandler to match a stateTree
405444c061aSmrg * entry to the event coming in
406444c061aSmrg */
407a3bd7f05Smrgstatic int
408a3bd7f05SmrgMatchBranchHead(TMSimpleStateTree stateTree, int startIndex, TMEventPtr event)
409444c061aSmrg{
410444c061aSmrg    TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex];
411444c061aSmrg    int i;
412444c061aSmrg
413444c061aSmrg    LOCK_PROCESS;
414a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
415a3bd7f05Smrg        TMTypeMatch typeMatch;
416a3bd7f05Smrg        TMModifierMatch modMatch;
417a3bd7f05Smrg
418a3bd7f05Smrg        typeMatch = TMGetTypeMatch(branchHead->typeIndex);
419a3bd7f05Smrg        modMatch = TMGetModifierMatch(branchHead->modIndex);
420a3bd7f05Smrg
421a3bd7f05Smrg        if (MatchIncomingEvent(event, typeMatch, modMatch)) {
422a3bd7f05Smrg            UNLOCK_PROCESS;
423a3bd7f05Smrg            return i;
424a3bd7f05Smrg        }
425a3bd7f05Smrg    }
426444c061aSmrg    UNLOCK_PROCESS;
427444c061aSmrg    return (TM_NO_MATCH);
428444c061aSmrg}
429444c061aSmrg
430a3bd7f05SmrgBoolean
431a3bd7f05Smrg_XtRegularMatch(TMTypeMatch typeMatch,
432a3bd7f05Smrg                TMModifierMatch modMatch,
433a3bd7f05Smrg                TMEventPtr eventSeq)
434444c061aSmrg{
435a3bd7f05Smrg    Modifiers computed = 0;
436a3bd7f05Smrg    Modifiers computedMask = 0;
437444c061aSmrg    Boolean resolved = TRUE;
438a3bd7f05Smrg
439444c061aSmrg    if (typeMatch->eventCode != (eventSeq->event.eventCode &
440a3bd7f05Smrg                                 typeMatch->eventCodeMask))
441a3bd7f05Smrg        return FALSE;
442444c061aSmrg    if (modMatch->lateModifiers != NULL)
443a3bd7f05Smrg        resolved = _XtComputeLateBindings(eventSeq->xev->xany.display,
444a3bd7f05Smrg                                          modMatch->lateModifiers,
445a3bd7f05Smrg                                          &computed, &computedMask);
446a3bd7f05Smrg    if (!resolved)
447a3bd7f05Smrg        return FALSE;
4480568f49bSmrg    computed = (Modifiers) (computed | modMatch->modifiers);
4490568f49bSmrg    computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
450444c061aSmrg
451a3bd7f05Smrg    return ((computed & computedMask) ==
452a3bd7f05Smrg            (eventSeq->event.modifiers & computedMask));
453444c061aSmrg}
454444c061aSmrg
455a3bd7f05SmrgBoolean
456a3bd7f05Smrg_XtMatchAtom(TMTypeMatch typeMatch,
457a3bd7f05Smrg             TMModifierMatch modMatch _X_UNUSED,
458a3bd7f05Smrg             TMEventPtr eventSeq)
459444c061aSmrg{
460a3bd7f05Smrg    Atom atom;
461444c061aSmrg
462444c061aSmrg    atom = XInternAtom(eventSeq->xev->xany.display,
463a3bd7f05Smrg                       XrmQuarkToString((XrmQuark) (typeMatch->eventCode)),
464a3bd7f05Smrg                       False);
465444c061aSmrg    return (atom == eventSeq->event.eventCode);
466444c061aSmrg}
467444c061aSmrg
468444c061aSmrg#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7)))
469444c061aSmrg
470444c061aSmrg/*
471444c061aSmrg * there are certain cases where you want to ignore the event and stay
472444c061aSmrg * in the same state.
473444c061aSmrg */
474a3bd7f05Smrgstatic Boolean
475a3bd7f05SmrgIgnore(TMEventPtr event)
476444c061aSmrg{
477444c061aSmrg    Display *dpy;
478444c061aSmrg    XtPerDisplay pd;
479444c061aSmrg
480444c061aSmrg    if (event->event.eventType == MotionNotify)
481a3bd7f05Smrg        return TRUE;
482444c061aSmrg    if (!(event->event.eventType == KeyPress ||
483a3bd7f05Smrg          event->event.eventType == KeyRelease))
484a3bd7f05Smrg        return FALSE;
485444c061aSmrg    dpy = event->xev->xany.display;
486a3bd7f05Smrg
487444c061aSmrg    pd = _XtGetPerDisplay(dpy);
488444c061aSmrg    _InitializeKeysymTables(dpy, pd);
489444c061aSmrg    return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
490444c061aSmrg}
491444c061aSmrg
492a3bd7f05Smrgstatic void
493a3bd7f05SmrgXEventToTMEvent(XEvent *event, TMEventPtr tmEvent)
494444c061aSmrg{
495444c061aSmrg    tmEvent->xev = event;
496444c061aSmrg    tmEvent->event.eventCodeMask = 0;
497444c061aSmrg    tmEvent->event.modifierMask = 0;
4980568f49bSmrg    tmEvent->event.eventType = (TMLongCard) event->type;
499444c061aSmrg    tmEvent->event.lateModifiers = NULL;
500444c061aSmrg    tmEvent->event.matchEvent = NULL;
501444c061aSmrg    tmEvent->event.standard = FALSE;
502444c061aSmrg
503444c061aSmrg    switch (event->type) {
504444c061aSmrg
505a3bd7f05Smrg    case KeyPress:
506a3bd7f05Smrg    case KeyRelease:
507a3bd7f05Smrg        tmEvent->event.eventCode = event->xkey.keycode;
508a3bd7f05Smrg        tmEvent->event.modifiers = event->xkey.state;
509a3bd7f05Smrg        break;
510a3bd7f05Smrg
511a3bd7f05Smrg    case ButtonPress:
512a3bd7f05Smrg    case ButtonRelease:
513a3bd7f05Smrg        tmEvent->event.eventCode = event->xbutton.button;
514a3bd7f05Smrg        tmEvent->event.modifiers = event->xbutton.state;
515a3bd7f05Smrg        break;
516a3bd7f05Smrg
517a3bd7f05Smrg    case MotionNotify:
518a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmotion.is_hint;
519a3bd7f05Smrg        tmEvent->event.modifiers = event->xmotion.state;
520a3bd7f05Smrg        break;
521a3bd7f05Smrg
522a3bd7f05Smrg    case EnterNotify:
523a3bd7f05Smrg    case LeaveNotify:
524a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xcrossing.mode;
525a3bd7f05Smrg        tmEvent->event.modifiers = event->xcrossing.state;
526a3bd7f05Smrg        break;
527a3bd7f05Smrg
528a3bd7f05Smrg    case PropertyNotify:
529a3bd7f05Smrg        tmEvent->event.eventCode = event->xproperty.atom;
530a3bd7f05Smrg        tmEvent->event.modifiers = 0;
531a3bd7f05Smrg        break;
532a3bd7f05Smrg
533a3bd7f05Smrg    case SelectionClear:
534a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionclear.selection;
535a3bd7f05Smrg        tmEvent->event.modifiers = 0;
536a3bd7f05Smrg        break;
537a3bd7f05Smrg
538a3bd7f05Smrg    case SelectionRequest:
539a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionrequest.selection;
540a3bd7f05Smrg        tmEvent->event.modifiers = 0;
541a3bd7f05Smrg        break;
542a3bd7f05Smrg
543a3bd7f05Smrg    case SelectionNotify:
544a3bd7f05Smrg        tmEvent->event.eventCode = event->xselection.selection;
545a3bd7f05Smrg        tmEvent->event.modifiers = 0;
546a3bd7f05Smrg        break;
547a3bd7f05Smrg
548a3bd7f05Smrg    case ClientMessage:
549a3bd7f05Smrg        tmEvent->event.eventCode = event->xclient.message_type;
550a3bd7f05Smrg        tmEvent->event.modifiers = 0;
551a3bd7f05Smrg        break;
552a3bd7f05Smrg
553a3bd7f05Smrg    case MappingNotify:
554a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmapping.request;
555a3bd7f05Smrg        tmEvent->event.modifiers = 0;
556a3bd7f05Smrg        break;
557a3bd7f05Smrg
558a3bd7f05Smrg    case FocusIn:
559a3bd7f05Smrg    case FocusOut:
560a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xfocus.mode;
561a3bd7f05Smrg        tmEvent->event.modifiers = 0;
562a3bd7f05Smrg        break;
563a3bd7f05Smrg
564a3bd7f05Smrg    default:
565a3bd7f05Smrg        tmEvent->event.eventCode = 0;
566a3bd7f05Smrg        tmEvent->event.modifiers = 0;
567a3bd7f05Smrg        break;
568444c061aSmrg    }
569444c061aSmrg}
570444c061aSmrg
571a3bd7f05Smrgstatic unsigned long
572a3bd7f05SmrgGetTime(XtTM tm, XEvent *event)
573444c061aSmrg{
574444c061aSmrg    switch (event->type) {
575444c061aSmrg
576a3bd7f05Smrg    case KeyPress:
577a3bd7f05Smrg    case KeyRelease:
578a3bd7f05Smrg        return event->xkey.time;
579444c061aSmrg
580a3bd7f05Smrg    case ButtonPress:
581a3bd7f05Smrg    case ButtonRelease:
582a3bd7f05Smrg        return event->xbutton.time;
583444c061aSmrg
584a3bd7f05Smrg    default:
585a3bd7f05Smrg        return tm->lastEventTime;
586444c061aSmrg
587444c061aSmrg    }
588444c061aSmrg
589444c061aSmrg}
590444c061aSmrg
591a3bd7f05Smrgstatic void
592a3bd7f05SmrgHandleActions(Widget w,
593a3bd7f05Smrg              XEvent *event,
594a3bd7f05Smrg              TMSimpleStateTree stateTree,
595a3bd7f05Smrg              Widget accelWidget,
596a3bd7f05Smrg              XtActionProc *procs,
597a3bd7f05Smrg              ActionRec *actions)
598444c061aSmrg{
599a3bd7f05Smrg    ActionHook actionHookList;
600a3bd7f05Smrg    Widget bindWidget;
601444c061aSmrg
602444c061aSmrg    bindWidget = accelWidget ? accelWidget : w;
603444c061aSmrg    if (accelWidget && !XtIsSensitive(accelWidget) &&
604a3bd7f05Smrg        (event->type == KeyPress || event->type == KeyRelease ||
605a3bd7f05Smrg         event->type == ButtonPress || event->type == ButtonRelease ||
606a3bd7f05Smrg         event->type == MotionNotify || event->type == EnterNotify ||
607a3bd7f05Smrg         event->type == LeaveNotify || event->type == FocusIn ||
608a3bd7f05Smrg         event->type == FocusOut))
609a3bd7f05Smrg        return;
610444c061aSmrg
611444c061aSmrg    actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
612444c061aSmrg
613444c061aSmrg    while (actions != NULL) {
614a3bd7f05Smrg        /* perform any actions */
615a3bd7f05Smrg        if (procs[actions->idx] != NULL) {
616a3bd7f05Smrg            if (actionHookList) {
617a3bd7f05Smrg                ActionHook hook;
618a3bd7f05Smrg                ActionHook next_hook;
619a3bd7f05Smrg                String procName =
620a3bd7f05Smrg                    XrmQuarkToString(stateTree->quarkTbl[actions->idx]);
621a3bd7f05Smrg
622a3bd7f05Smrg                for (hook = actionHookList; hook != NULL;) {
623a3bd7f05Smrg                    /*
624a3bd7f05Smrg                     * Need to cache hook->next because the following action
625a3bd7f05Smrg                     * proc may free hook via XtRemoveActionHook making
626a3bd7f05Smrg                     * hook->next invalid upon return from the action proc.
627a3bd7f05Smrg                     */
628a3bd7f05Smrg                    next_hook = hook->next;
629a3bd7f05Smrg                    (*hook->proc) (bindWidget,
630a3bd7f05Smrg                                   hook->closure,
631a3bd7f05Smrg                                   procName,
632a3bd7f05Smrg                                   event,
633a3bd7f05Smrg                                   actions->params, &actions->num_params);
634a3bd7f05Smrg                    hook = next_hook;
635a3bd7f05Smrg                }
636a3bd7f05Smrg            }
637a3bd7f05Smrg            (*(procs[actions->idx]))
638a3bd7f05Smrg                (bindWidget, event, actions->params, &actions->num_params);
639a3bd7f05Smrg        }
640a3bd7f05Smrg        actions = actions->next;
641444c061aSmrg    }
642444c061aSmrg}
643444c061aSmrg
644444c061aSmrgtypedef struct {
645444c061aSmrg    unsigned int isCycleStart:1;
646444c061aSmrg    unsigned int isCycleEnd:1;
647444c061aSmrg    TMShortCard typeIndex;
648444c061aSmrg    TMShortCard modIndex;
649a3bd7f05Smrg} MatchPairRec, *MatchPair;
650444c061aSmrg
651a3bd7f05Smrgtypedef struct TMContextRec {
652a3bd7f05Smrg    TMShortCard numMatches;
653a3bd7f05Smrg    TMShortCard maxMatches;
654a3bd7f05Smrg    MatchPair matches;
655a3bd7f05Smrg} TMContextRec, *TMContext;
656444c061aSmrg
657a3bd7f05Smrgstatic TMContextRec contextCache[2];
658444c061aSmrg
659444c061aSmrg#define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
660444c061aSmrg
661444c061aSmrg#define TM_CONTEXT_MATCHES_ALLOC 4
662444c061aSmrg#define TM_CONTEXT_MATCHES_REALLOC 2
663444c061aSmrg
664a3bd7f05Smrgstatic void
665a3bd7f05SmrgPushContext(TMContext *contextPtr, StatePtr newState)
666444c061aSmrg{
667a3bd7f05Smrg    TMContext context = *contextPtr;
668444c061aSmrg
669444c061aSmrg    LOCK_PROCESS;
670a3bd7f05Smrg    if (context == NULL) {
671a3bd7f05Smrg        if (contextCache[0].numMatches == 0)
672a3bd7f05Smrg            context = &contextCache[0];
673a3bd7f05Smrg        else if (contextCache[1].numMatches == 0)
674a3bd7f05Smrg            context = &contextCache[1];
675a3bd7f05Smrg        if (!context) {
676a3bd7f05Smrg            context = XtNew(TMContextRec);
677a3bd7f05Smrg            context->matches = NULL;
678a3bd7f05Smrg            context->numMatches = context->maxMatches = 0;
679a3bd7f05Smrg        }
680a3bd7f05Smrg    }
681444c061aSmrg    if (context->numMatches &&
682a3bd7f05Smrg        context->matches[context->numMatches - 1].isCycleEnd) {
683a3bd7f05Smrg        TMShortCard i;
684a3bd7f05Smrg
685a3bd7f05Smrg        for (i = 0;
686a3bd7f05Smrg             i < context->numMatches &&
687a3bd7f05Smrg             !(context->matches[i].isCycleStart); i++) {
688a3bd7f05Smrg        };
689a3bd7f05Smrg        if (i < context->numMatches)
690a3bd7f05Smrg            context->numMatches = (TMShortCard) (i + 1);
691444c061aSmrg#ifdef DEBUG
692a3bd7f05Smrg        else
693a3bd7f05Smrg            XtWarning("pushing cycle end with no cycle start");
694a3bd7f05Smrg#endif                          /* DEBUG */
695a3bd7f05Smrg    }
696a3bd7f05Smrg    else {
697a3bd7f05Smrg        if (context->numMatches == context->maxMatches) {
698a3bd7f05Smrg            if (context->maxMatches == 0)
699a3bd7f05Smrg                context->maxMatches =
700a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
701a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_ALLOC);
702a3bd7f05Smrg            else
703a3bd7f05Smrg                context->maxMatches =
704a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
705a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_REALLOC);
706a3bd7f05Smrg            context->matches = (MatchPairRec *)
707fdf6a26fSmrg                XtReallocArray(context->matches,
708fdf6a26fSmrg                               (Cardinal) context->maxMatches,
709fdf6a26fSmrg                               sizeof(MatchPairRec));
710a3bd7f05Smrg        }
711a3bd7f05Smrg        context->matches[context->numMatches].isCycleStart =
712a3bd7f05Smrg            newState->isCycleStart;
713a3bd7f05Smrg        context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
714a3bd7f05Smrg        context->matches[context->numMatches].typeIndex = newState->typeIndex;
715a3bd7f05Smrg        context->matches[context->numMatches++].modIndex = newState->modIndex;
716a3bd7f05Smrg        *contextPtr = context;
717a3bd7f05Smrg    }
718a3bd7f05Smrg    UNLOCK_PROCESS;
719444c061aSmrg}
720444c061aSmrg
721a3bd7f05Smrgstatic void
722a3bd7f05SmrgFreeContext(TMContext *contextPtr)
723444c061aSmrg{
724a3bd7f05Smrg    TMContext context = NULL;
725444c061aSmrg
726444c061aSmrg    LOCK_PROCESS;
727444c061aSmrg
728444c061aSmrg    if (&contextCache[0] == *contextPtr)
729a3bd7f05Smrg        context = &contextCache[0];
730444c061aSmrg    else if (&contextCache[1] == *contextPtr)
731a3bd7f05Smrg        context = &contextCache[1];
732444c061aSmrg
733444c061aSmrg    if (context)
734a3bd7f05Smrg        context->numMatches = 0;
735a3bd7f05Smrg    else if (*contextPtr) {
736a3bd7f05Smrg        XtFree((char *) ((*contextPtr)->matches));
737a3bd7f05Smrg        XtFree((char *) *contextPtr);
738444c061aSmrg    }
739444c061aSmrg
740444c061aSmrg    *contextPtr = NULL;
741444c061aSmrg    UNLOCK_PROCESS;
742444c061aSmrg}
743444c061aSmrg
744a3bd7f05Smrgstatic int
745a3bd7f05SmrgMatchExact(TMSimpleStateTree stateTree,
746a3bd7f05Smrg           int startIndex,
747a3bd7f05Smrg           TMShortCard typeIndex,
748a3bd7f05Smrg           TMShortCard modIndex)
749444c061aSmrg{
750444c061aSmrg    TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
751444c061aSmrg    int i;
752444c061aSmrg
753a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
754a3bd7f05Smrg        if ((branchHead->typeIndex == typeIndex) &&
755a3bd7f05Smrg            (branchHead->modIndex == modIndex))
756a3bd7f05Smrg            return i;
757a3bd7f05Smrg    }
758444c061aSmrg    return (TM_NO_MATCH);
759444c061aSmrg}
760444c061aSmrg
761a3bd7f05Smrgstatic void
762a3bd7f05SmrgHandleSimpleState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
763444c061aSmrg{
764a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
765a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
766a3bd7f05Smrg    TMShortCard i;
767a3bd7f05Smrg    ActionRec *actions = NULL;
768a3bd7f05Smrg    Boolean matchExact = False;
769a3bd7f05Smrg    Boolean match = False;
770a3bd7f05Smrg    StatePtr complexMatchState = NULL;
771a3bd7f05Smrg    TMShortCard typeIndex = 0, modIndex = 0;
772a3bd7f05Smrg    int matchTreeIndex = TM_NO_MATCH;
773444c061aSmrg
774444c061aSmrg    LOCK_PROCESS;
775444c061aSmrg    for (i = 0;
776a3bd7f05Smrg         ((!match || !complexMatchState) && (i < xlations->numStateTrees));
777a3bd7f05Smrg         i++) {
778a3bd7f05Smrg        int currIndex = -1;
779a3bd7f05Smrg        TMSimpleStateTree stateTree =
780a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
781a3bd7f05Smrg
782a3bd7f05Smrg        /*
783a3bd7f05Smrg         * don't process this tree if we're only looking for a
784a3bd7f05Smrg         * complexMatchState and there are no complex states
785a3bd7f05Smrg         */
786a3bd7f05Smrg        while (!(match && stateTree->isSimple) &&
787a3bd7f05Smrg               ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
788a3bd7f05Smrg            currIndex++;
789a3bd7f05Smrg            if (matchExact)
790a3bd7f05Smrg                currIndex =
791a3bd7f05Smrg                    MatchExact(stateTree, currIndex, typeIndex, modIndex);
792a3bd7f05Smrg            else
793a3bd7f05Smrg                currIndex = MatchBranchHead(stateTree, currIndex, curEventPtr);
794a3bd7f05Smrg            if (currIndex != TM_NO_MATCH) {
795a3bd7f05Smrg                TMBranchHead branchHead;
796a3bd7f05Smrg                StatePtr currState;
797a3bd7f05Smrg
798a3bd7f05Smrg                branchHead = &stateTree->branchHeadTbl[currIndex];
799a3bd7f05Smrg                if (branchHead->isSimple)
800a3bd7f05Smrg                    currState = NULL;
801a3bd7f05Smrg                else
802a3bd7f05Smrg                    currState = ((TMComplexStateTree) stateTree)
803a3bd7f05Smrg                        ->complexBranchHeadTbl[TMBranchMore(branchHead)];
804a3bd7f05Smrg
805a3bd7f05Smrg                /*
806a3bd7f05Smrg                 * first check for a complete match
807a3bd7f05Smrg                 */
808a3bd7f05Smrg                if (!match) {
809a3bd7f05Smrg                    if (branchHead->hasActions) {
810a3bd7f05Smrg                        if (branchHead->isSimple) {
811a3bd7f05Smrg                            static ActionRec dummyAction;
812a3bd7f05Smrg
813a3bd7f05Smrg                            dummyAction.idx = TMBranchMore(branchHead);
814a3bd7f05Smrg                            actions = &dummyAction;
815a3bd7f05Smrg                        }
816a3bd7f05Smrg                        else
817a3bd7f05Smrg                            actions = currState->actions;
818a3bd7f05Smrg                        tmRecPtr->lastEventTime =
819a3bd7f05Smrg                            GetTime(tmRecPtr, curEventPtr->xev);
820a3bd7f05Smrg                        FreeContext((TMContext *) &tmRecPtr->current_state);
821a3bd7f05Smrg                        match = True;
822a3bd7f05Smrg                        matchTreeIndex = i;
823a3bd7f05Smrg                    }
824a3bd7f05Smrg                    /*
825a3bd7f05Smrg                     * if it doesn't have actions and
826a3bd7f05Smrg                     * it's bc mode then it's a potential match node that is
827a3bd7f05Smrg                     * used to match later sequences.
828a3bd7f05Smrg                     */
829a3bd7f05Smrg                    if (!TMNewMatchSemantics() && !matchExact) {
830a3bd7f05Smrg                        matchExact = True;
831a3bd7f05Smrg                        typeIndex = branchHead->typeIndex;
832a3bd7f05Smrg                        modIndex = branchHead->modIndex;
833a3bd7f05Smrg                    }
834a3bd7f05Smrg                }
835a3bd7f05Smrg                /*
836a3bd7f05Smrg                 * check for it being an event sequence which can be
837a3bd7f05Smrg                 * a future match
838a3bd7f05Smrg                 */
839a3bd7f05Smrg                if (!branchHead->isSimple &&
840a3bd7f05Smrg                    !branchHead->hasActions && !complexMatchState)
841a3bd7f05Smrg                    complexMatchState = currState;
842a3bd7f05Smrg            }
843a3bd7f05Smrg        }
844a3bd7f05Smrg    }
845a3bd7f05Smrg    if (match) {
846a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
847a3bd7f05Smrg        XtActionProc *procs;
848a3bd7f05Smrg        Widget accelWidget;
849a3bd7f05Smrg
850a3bd7f05Smrg        if (bindData->simple.isComplex) {
851a3bd7f05Smrg            TMComplexBindProcs bindProcs =
852a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
853a3bd7f05Smrg            procs = bindProcs->procs;
854a3bd7f05Smrg            accelWidget = bindProcs->widget;
855a3bd7f05Smrg        }
856a3bd7f05Smrg        else {
857a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
858a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
859a3bd7f05Smrg            procs = bindProcs->procs;
860a3bd7f05Smrg            accelWidget = NULL;
861a3bd7f05Smrg        }
862a3bd7f05Smrg        HandleActions
863a3bd7f05Smrg            (w,
864a3bd7f05Smrg             curEventPtr->xev,
865a3bd7f05Smrg             (TMSimpleStateTree) xlations->stateTreeTbl[matchTreeIndex],
866a3bd7f05Smrg             accelWidget, procs, actions);
867a3bd7f05Smrg    }
868444c061aSmrg    if (complexMatchState)
869a3bd7f05Smrg        PushContext(contextPtr, complexMatchState);
870444c061aSmrg    UNLOCK_PROCESS;
871444c061aSmrg}
872444c061aSmrg
873a3bd7f05Smrgstatic int
874a3bd7f05SmrgMatchComplexBranch(TMComplexStateTree stateTree,
875a3bd7f05Smrg                   int startIndex,
876a3bd7f05Smrg                   TMContext context,
877a3bd7f05Smrg                   StatePtr *leafStateRtn)
878444c061aSmrg{
879a3bd7f05Smrg    TMShortCard i;
880444c061aSmrg
881444c061aSmrg    LOCK_PROCESS;
882a3bd7f05Smrg    for (i = (TMShortCard) startIndex; i < stateTree->numComplexBranchHeads;
883a3bd7f05Smrg         i++) {
884a3bd7f05Smrg        StatePtr candState;
885a3bd7f05Smrg        TMShortCard numMatches = context->numMatches;
886a3bd7f05Smrg        MatchPair statMatch = context->matches;
887a3bd7f05Smrg
888a3bd7f05Smrg        for (candState = stateTree->complexBranchHeadTbl[i];
889a3bd7f05Smrg             numMatches && candState;
890a3bd7f05Smrg             numMatches--, statMatch++, candState = candState->nextLevel) {
891a3bd7f05Smrg            if ((statMatch->typeIndex != candState->typeIndex) ||
892a3bd7f05Smrg                (statMatch->modIndex != candState->modIndex))
893a3bd7f05Smrg                break;
894a3bd7f05Smrg        }
895a3bd7f05Smrg        if (numMatches == 0) {
896a3bd7f05Smrg            *leafStateRtn = candState;
897a3bd7f05Smrg            UNLOCK_PROCESS;
898a3bd7f05Smrg            return i;
899a3bd7f05Smrg        }
900a3bd7f05Smrg    }
901444c061aSmrg    *leafStateRtn = NULL;
902444c061aSmrg    UNLOCK_PROCESS;
903444c061aSmrg    return (TM_NO_MATCH);
904444c061aSmrg}
905444c061aSmrg
906a3bd7f05Smrgstatic StatePtr
907a3bd7f05SmrgTryCurrentTree(TMComplexStateTree *stateTreePtr,
908a3bd7f05Smrg               XtTM tmRecPtr,
909a3bd7f05Smrg               TMEventRec *curEventPtr)
910444c061aSmrg{
911a3bd7f05Smrg    StatePtr candState = NULL, matchState = NULL;
912a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
913a3bd7f05Smrg    TMTypeMatch typeMatch;
914a3bd7f05Smrg    TMModifierMatch modMatch;
915a3bd7f05Smrg    int currIndex = -1;
916444c061aSmrg
917444c061aSmrg    /*
918444c061aSmrg     * we want the first sequence that both matches and has actions.
919444c061aSmrg     * we keep on looking till we find both
920444c061aSmrg     */
921444c061aSmrg    LOCK_PROCESS;
922444c061aSmrg    while ((currIndex =
923a3bd7f05Smrg            MatchComplexBranch(*stateTreePtr,
924a3bd7f05Smrg                               ++currIndex, (*contextPtr), &candState))
925a3bd7f05Smrg           != TM_NO_MATCH) {
926a3bd7f05Smrg        if (candState != NULL) {
927a3bd7f05Smrg            typeMatch = TMGetTypeMatch(candState->typeIndex);
928a3bd7f05Smrg            modMatch = TMGetModifierMatch(candState->modIndex);
929a3bd7f05Smrg
930a3bd7f05Smrg            /* does this state's index match? --> done */
931a3bd7f05Smrg            if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) {
932a3bd7f05Smrg                if (candState->actions) {
933a3bd7f05Smrg                    UNLOCK_PROCESS;
934a3bd7f05Smrg                    return candState;
935a3bd7f05Smrg                }
936a3bd7f05Smrg                else
937a3bd7f05Smrg                    matchState = candState;
938a3bd7f05Smrg            }
939a3bd7f05Smrg            /* is this an event timer? */
940a3bd7f05Smrg            if (typeMatch->eventType == _XtEventTimerEventType) {
941a3bd7f05Smrg                StatePtr nextState = candState->nextLevel;
942a3bd7f05Smrg
943a3bd7f05Smrg                /* does the succeeding state match? */
944a3bd7f05Smrg                if (nextState != NULL) {
945a3bd7f05Smrg                    TMTypeMatch nextTypeMatch;
946a3bd7f05Smrg                    TMModifierMatch nextModMatch;
947a3bd7f05Smrg
948a3bd7f05Smrg                    nextTypeMatch = TMGetTypeMatch(nextState->typeIndex);
949a3bd7f05Smrg                    nextModMatch = TMGetModifierMatch(nextState->modIndex);
950a3bd7f05Smrg
951a3bd7f05Smrg                    /* is it within the timeout? */
952a3bd7f05Smrg                    if (MatchIncomingEvent(curEventPtr,
953a3bd7f05Smrg                                           nextTypeMatch, nextModMatch)) {
954a3bd7f05Smrg                        XEvent *xev = curEventPtr->xev;
955a3bd7f05Smrg                        unsigned long time = GetTime(tmRecPtr, xev);
956a3bd7f05Smrg                        XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
957a3bd7f05Smrg                        unsigned long delta =
958a3bd7f05Smrg                            (unsigned long) pd->multi_click_time;
959a3bd7f05Smrg
960a3bd7f05Smrg                        if ((tmRecPtr->lastEventTime + delta) >= time) {
961a3bd7f05Smrg                            if (nextState->actions) {
962a3bd7f05Smrg                                UNLOCK_PROCESS;
963a3bd7f05Smrg                                return candState;
964a3bd7f05Smrg                            }
965a3bd7f05Smrg                            else
966a3bd7f05Smrg                                matchState = candState;
967a3bd7f05Smrg                        }
968a3bd7f05Smrg                    }
969a3bd7f05Smrg                }
970a3bd7f05Smrg            }
971a3bd7f05Smrg        }
972444c061aSmrg    }
973444c061aSmrg    UNLOCK_PROCESS;
974444c061aSmrg    return matchState;
975444c061aSmrg}
976444c061aSmrg
977a3bd7f05Smrgstatic void
978a3bd7f05SmrgHandleComplexState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
979444c061aSmrg{
980a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
981a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
982a3bd7f05Smrg    TMShortCard i, matchTreeIndex = 0;
983a3bd7f05Smrg    StatePtr matchState = NULL, candState;
984a3bd7f05Smrg    TMComplexStateTree *stateTreePtr =
985a3bd7f05Smrg        (TMComplexStateTree *) &xlations->stateTreeTbl[0];
986444c061aSmrg
987444c061aSmrg    LOCK_PROCESS;
988a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) {
989a3bd7f05Smrg        /*
990a3bd7f05Smrg         * some compilers sign extend Boolean bit fields so test for
991a3bd7f05Smrg         * false |||
992a3bd7f05Smrg         */
993a3bd7f05Smrg        if (((*stateTreePtr)->isSimple == False) &&
994a3bd7f05Smrg            (candState = TryCurrentTree(stateTreePtr, tmRecPtr, curEventPtr))) {
995a3bd7f05Smrg            if (!matchState || candState->actions) {
996a3bd7f05Smrg                matchTreeIndex = i;
997a3bd7f05Smrg                matchState = candState;
998a3bd7f05Smrg                if (candState->actions)
999a3bd7f05Smrg                    break;
1000a3bd7f05Smrg            }
1001a3bd7f05Smrg        }
1002a3bd7f05Smrg    }
1003a3bd7f05Smrg    if (matchState == NULL) {
1004a3bd7f05Smrg        /* couldn't find it... */
1005a3bd7f05Smrg        if (!Ignore(curEventPtr)) {
1006a3bd7f05Smrg            FreeContext(contextPtr);
1007a3bd7f05Smrg            HandleSimpleState(w, tmRecPtr, curEventPtr);
1008a3bd7f05Smrg        }
1009444c061aSmrg    }
1010444c061aSmrg    else {
1011a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
1012a3bd7f05Smrg        XtActionProc *procs;
1013a3bd7f05Smrg        Widget accelWidget;
1014a3bd7f05Smrg        TMTypeMatch typeMatch;
1015a3bd7f05Smrg
1016a3bd7f05Smrg        typeMatch = TMGetTypeMatch(matchState->typeIndex);
1017a3bd7f05Smrg
1018a3bd7f05Smrg        PushContext(contextPtr, matchState);
1019a3bd7f05Smrg        if (typeMatch->eventType == _XtEventTimerEventType) {
1020a3bd7f05Smrg            matchState = matchState->nextLevel;
1021a3bd7f05Smrg            PushContext(contextPtr, matchState);
1022a3bd7f05Smrg        }
1023a3bd7f05Smrg        tmRecPtr->lastEventTime = GetTime(tmRecPtr, curEventPtr->xev);
1024a3bd7f05Smrg
1025a3bd7f05Smrg        if (bindData->simple.isComplex) {
1026a3bd7f05Smrg            TMComplexBindProcs bindProcs =
1027a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
1028a3bd7f05Smrg            procs = bindProcs->procs;
1029a3bd7f05Smrg            accelWidget = bindProcs->widget;
1030a3bd7f05Smrg        }
1031a3bd7f05Smrg        else {
1032a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
1033a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
1034a3bd7f05Smrg            procs = bindProcs->procs;
1035a3bd7f05Smrg            accelWidget = NULL;
1036a3bd7f05Smrg        }
1037a3bd7f05Smrg        HandleActions(w, curEventPtr->xev, (TMSimpleStateTree)
1038a3bd7f05Smrg                      xlations->stateTreeTbl[matchTreeIndex],
1039a3bd7f05Smrg                      accelWidget, procs, matchState->actions);
1040444c061aSmrg    }
1041444c061aSmrg    UNLOCK_PROCESS;
1042444c061aSmrg}
1043444c061aSmrg
1044a3bd7f05Smrgvoid
1045a3bd7f05Smrg_XtTranslateEvent(Widget w, XEvent *event)
1046444c061aSmrg{
1047a3bd7f05Smrg    XtTM tmRecPtr = &w->core.tm;
1048a3bd7f05Smrg    TMEventRec curEvent;
1049a3bd7f05Smrg    StatePtr current_state = tmRecPtr->current_state;
1050444c061aSmrg
1051a3bd7f05Smrg    XEventToTMEvent(event, &curEvent);
1052444c061aSmrg
1053a3bd7f05Smrg    if (!tmRecPtr->translations) {
1054444c061aSmrg        XtAppWarningMsg(XtWidgetToApplicationContext(w),
1055a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1056a3bd7f05Smrg                        "Can't translate event through NULL table", NULL, NULL);
1057a3bd7f05Smrg        return;
1058444c061aSmrg    }
1059444c061aSmrg    if (current_state == NULL)
1060a3bd7f05Smrg        HandleSimpleState(w, tmRecPtr, &curEvent);
1061444c061aSmrg    else
1062a3bd7f05Smrg        HandleComplexState(w, tmRecPtr, &curEvent);
1063444c061aSmrg}
1064444c061aSmrg
1065a3bd7f05Smrgstatic StatePtr
1066a3bd7f05SmrgNewState(TMParseStateTree stateTree _X_UNUSED,
1067a3bd7f05Smrg         TMShortCard typeIndex,
1068a3bd7f05Smrg         TMShortCard modIndex)
1069444c061aSmrg{
1070444c061aSmrg    StatePtr state = XtNew(StateRec);
1071444c061aSmrg
1072444c061aSmrg#ifdef TRACE_TM
1073444c061aSmrg    LOCK_PROCESS;
1074444c061aSmrg    _XtGlobalTM.numComplexStates++;
1075444c061aSmrg    UNLOCK_PROCESS;
1076a3bd7f05Smrg#endif                          /* TRACE_TM */
1077444c061aSmrg    state->typeIndex = typeIndex;
1078444c061aSmrg    state->modIndex = modIndex;
1079444c061aSmrg    state->nextLevel = NULL;
1080444c061aSmrg    state->actions = NULL;
1081444c061aSmrg    state->isCycleStart = state->isCycleEnd = False;
1082444c061aSmrg    return state;
1083444c061aSmrg}
1084444c061aSmrg
1085444c061aSmrg/*
1086444c061aSmrg * This routine is an iterator for state trees. If the func returns
1087444c061aSmrg * true then iteration is over.
1088444c061aSmrg */
1089a3bd7f05Smrgvoid
1090a3bd7f05Smrg_XtTraverseStateTree(TMStateTree tree, _XtTraversalProc func, XtPointer data)
1091444c061aSmrg{
1092a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
1093a3bd7f05Smrg    TMBranchHead currBH;
1094a3bd7f05Smrg    TMShortCard i;
1095a3bd7f05Smrg    StateRec dummyStateRec, *dummyState = &dummyStateRec;
1096a3bd7f05Smrg    ActionRec dummyActionRec, *dummyAction = &dummyActionRec;
1097a3bd7f05Smrg    Boolean firstSimple = True;
1098a3bd7f05Smrg    StatePtr currState;
1099444c061aSmrg
1100444c061aSmrg    /* first traverse the complex states */
1101444c061aSmrg    if (stateTree->isSimple == False)
1102a3bd7f05Smrg        for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
1103a3bd7f05Smrg            currState = stateTree->complexBranchHeadTbl[i];
1104a3bd7f05Smrg            for (; currState; currState = currState->nextLevel) {
1105a3bd7f05Smrg                if (func(currState, data))
1106a3bd7f05Smrg                    return;
1107a3bd7f05Smrg                if (currState->isCycleEnd)
1108a3bd7f05Smrg                    break;
1109a3bd7f05Smrg            }
1110a3bd7f05Smrg        }
1111444c061aSmrg
1112444c061aSmrg    /* now traverse the simple ones */
1113444c061aSmrg    for (i = 0, currBH = stateTree->branchHeadTbl;
1114a3bd7f05Smrg         i < stateTree->numBranchHeads; i++, currBH++) {
1115a3bd7f05Smrg        if (currBH->isSimple && currBH->hasActions) {
1116a3bd7f05Smrg            if (firstSimple) {
1117a3bd7f05Smrg                XtBZero((char *) dummyState, sizeof(StateRec));
1118a3bd7f05Smrg                XtBZero((char *) dummyAction, sizeof(ActionRec));
1119a3bd7f05Smrg                dummyState->actions = dummyAction;
1120a3bd7f05Smrg                firstSimple = False;
1121a3bd7f05Smrg            }
1122a3bd7f05Smrg            dummyState->typeIndex = currBH->typeIndex;
1123a3bd7f05Smrg            dummyState->modIndex = currBH->modIndex;
1124a3bd7f05Smrg            dummyAction->idx = currBH->more;
1125a3bd7f05Smrg            if (func(dummyState, data))
1126a3bd7f05Smrg                return;
1127a3bd7f05Smrg        }
1128a3bd7f05Smrg    }
1129444c061aSmrg}
1130444c061aSmrg
1131a3bd7f05Smrgstatic EventMask
1132a3bd7f05SmrgEventToMask(TMTypeMatch typeMatch, TMModifierMatch modMatch)
1133444c061aSmrg{
1134444c061aSmrg    EventMask returnMask;
1135444c061aSmrg    unsigned long eventType = typeMatch->eventType;
1136444c061aSmrg
1137444c061aSmrg    if (eventType == MotionNotify) {
11380568f49bSmrg        Modifiers modifierMask = (Modifiers) modMatch->modifierMask;
1139444c061aSmrg        Modifiers tempMask;
1140444c061aSmrg
1141a3bd7f05Smrg        returnMask = 0;
1142444c061aSmrg        if (modifierMask == 0) {
1143a3bd7f05Smrg            if (modMatch->modifiers == AnyButtonMask)
1144a3bd7f05Smrg                return ButtonMotionMask;
1145a3bd7f05Smrg            else
1146a3bd7f05Smrg                return PointerMotionMask;
1147a3bd7f05Smrg        }
1148444c061aSmrg        tempMask = modifierMask &
1149a3bd7f05Smrg            (Button1Mask | Button2Mask | Button3Mask
1150a3bd7f05Smrg             | Button4Mask | Button5Mask);
1151444c061aSmrg        if (tempMask == 0)
1152a3bd7f05Smrg            return PointerMotionMask;
1153444c061aSmrg        if (tempMask & Button1Mask)
1154444c061aSmrg            returnMask |= Button1MotionMask;
1155444c061aSmrg        if (tempMask & Button2Mask)
1156444c061aSmrg            returnMask |= Button2MotionMask;
1157444c061aSmrg        if (tempMask & Button3Mask)
1158444c061aSmrg            returnMask |= Button3MotionMask;
1159444c061aSmrg        if (tempMask & Button4Mask)
1160444c061aSmrg            returnMask |= Button4MotionMask;
1161444c061aSmrg        if (tempMask & Button5Mask)
1162444c061aSmrg            returnMask |= Button5MotionMask;
1163444c061aSmrg        return returnMask;
1164444c061aSmrg    }
1165a3bd7f05Smrg    returnMask = _XtConvertTypeToMask((int) eventType);
1166a3bd7f05Smrg    if (returnMask == (StructureNotifyMask | SubstructureNotifyMask))
1167a3bd7f05Smrg        returnMask = StructureNotifyMask;
1168444c061aSmrg    return returnMask;
1169444c061aSmrg}
1170444c061aSmrg
1171a3bd7f05Smrgstatic void
1172a3bd7f05SmrgDispatchMappingNotify(Widget widget _X_UNUSED,  /* will be NULL from _RefreshMapping */
1173a3bd7f05Smrg                      XtPointer closure,        /* real Widget */
1174a3bd7f05Smrg                      XtPointer call_data)      /* XEvent* */
1175444c061aSmrg{
1176a3bd7f05Smrg    _XtTranslateEvent((Widget) closure, (XEvent *) call_data);
1177444c061aSmrg}
1178444c061aSmrg
1179a3bd7f05Smrgstatic void
1180a3bd7f05SmrgRemoveFromMappingCallbacks(Widget widget,
1181a3bd7f05Smrg                           XtPointer closure,    /* target widget */
1182a3bd7f05Smrg                           XtPointer call_data _X_UNUSED)
1183444c061aSmrg{
1184a3bd7f05Smrg    _XtRemoveCallback(&_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
1185a3bd7f05Smrg                      DispatchMappingNotify, closure);
1186444c061aSmrg}
1187444c061aSmrg
1188a3bd7f05Smrgstatic Boolean
1189a3bd7f05SmrgAggregateEventMask(StatePtr state, XtPointer data)
1190444c061aSmrg{
1191444c061aSmrg    LOCK_PROCESS;
1192a3bd7f05Smrg    *((EventMask *) data) |= EventToMask(TMGetTypeMatch(state->typeIndex),
1193a3bd7f05Smrg                                         TMGetModifierMatch(state->modIndex));
1194444c061aSmrg    UNLOCK_PROCESS;
1195444c061aSmrg    return False;
1196444c061aSmrg}
1197444c061aSmrg
1198a3bd7f05Smrgvoid
1199a3bd7f05Smrg_XtInstallTranslations(Widget widget)
1200444c061aSmrg{
1201444c061aSmrg    XtTranslations xlations;
1202a3bd7f05Smrg    Cardinal i;
1203a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1204444c061aSmrg
1205444c061aSmrg    xlations = widget->core.tm.translations;
1206a3bd7f05Smrg    if (xlations == NULL)
1207a3bd7f05Smrg        return;
1208444c061aSmrg
1209444c061aSmrg    /*
1210444c061aSmrg     * check for somebody stuffing the translations directly into the
1211444c061aSmrg     * instance structure. We will end up being called again out of
1212444c061aSmrg     * ComposeTranslations but we *should* have bindings by then
1213444c061aSmrg     */
1214444c061aSmrg    if (widget->core.tm.proc_table == NULL) {
1215a3bd7f05Smrg        _XtMergeTranslations(widget, NULL, XtTableReplace);
1216a3bd7f05Smrg        /*
1217a3bd7f05Smrg         * if we're realized then we'll be called out of
1218a3bd7f05Smrg         * ComposeTranslations
1219a3bd7f05Smrg         */
1220a3bd7f05Smrg        if (XtIsRealized(widget))
1221a3bd7f05Smrg            return;
1222444c061aSmrg    }
1223444c061aSmrg
1224444c061aSmrg    xlations->eventMask = 0;
1225a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1226a3bd7f05Smrg        TMStateTree stateTree = xlations->stateTreeTbl[i];
1227a3bd7f05Smrg
1228a3bd7f05Smrg        _XtTraverseStateTree(stateTree,
1229a3bd7f05Smrg                             AggregateEventMask,
1230a3bd7f05Smrg                             (XtPointer) &xlations->eventMask);
1231a3bd7f05Smrg        mappingNotifyInterest =
1232a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1233a3bd7f05Smrg                       stateTree->simple.mappingNotifyInterest);
1234a3bd7f05Smrg    }
1235444c061aSmrg    /* double click needs to make sure that you have selected on both
1236a3bd7f05Smrg       button down and up. */
1237444c061aSmrg
1238444c061aSmrg    if (xlations->eventMask & ButtonPressMask)
1239a3bd7f05Smrg        xlations->eventMask |= ButtonReleaseMask;
1240444c061aSmrg    if (xlations->eventMask & ButtonReleaseMask)
1241a3bd7f05Smrg        xlations->eventMask |= ButtonPressMask;
1242444c061aSmrg
1243444c061aSmrg    if (mappingNotifyInterest) {
1244a3bd7f05Smrg        XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
1245a3bd7f05Smrg
1246a3bd7f05Smrg        if (pd->mapping_callbacks)
1247a3bd7f05Smrg            _XtAddCallbackOnce(&(pd->mapping_callbacks),
1248a3bd7f05Smrg                               DispatchMappingNotify, (XtPointer) widget);
1249a3bd7f05Smrg        else
1250a3bd7f05Smrg            _XtAddCallback(&(pd->mapping_callbacks),
1251a3bd7f05Smrg                           DispatchMappingNotify, (XtPointer) widget);
1252a3bd7f05Smrg
1253a3bd7f05Smrg        if (widget->core.destroy_callbacks != NULL)
1254a3bd7f05Smrg            _XtAddCallbackOnce((InternalCallbackList *)
1255a3bd7f05Smrg                               &widget->core.destroy_callbacks,
1256a3bd7f05Smrg                               RemoveFromMappingCallbacks, (XtPointer) widget);
1257a3bd7f05Smrg        else
1258a3bd7f05Smrg            _XtAddCallback((InternalCallbackList *)
1259a3bd7f05Smrg                           &widget->core.destroy_callbacks,
1260a3bd7f05Smrg                           RemoveFromMappingCallbacks, (XtPointer) widget);
1261a3bd7f05Smrg    }
1262a3bd7f05Smrg    _XtBindActions(widget, (XtTM) &widget->core.tm);
1263444c061aSmrg    _XtRegisterGrabs(widget);
1264444c061aSmrg}
1265444c061aSmrg
1266a3bd7f05Smrgvoid
1267a3bd7f05Smrg_XtRemoveTranslations(Widget widget)
1268444c061aSmrg{
1269a3bd7f05Smrg    Cardinal i;
1270a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1271a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1272444c061aSmrg
1273444c061aSmrg    if (xlations == NULL)
1274a3bd7f05Smrg        return;
1275a3bd7f05Smrg
1276a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1277a3bd7f05Smrg        TMSimpleStateTree stateTree =
1278a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
1279a3bd7f05Smrg        mappingNotifyInterest =
1280a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1281a3bd7f05Smrg                       stateTree->mappingNotifyInterest);
1282a3bd7f05Smrg    }
1283444c061aSmrg    if (mappingNotifyInterest)
1284a3bd7f05Smrg        RemoveFromMappingCallbacks(widget, (XtPointer) widget, NULL);
1285444c061aSmrg}
1286444c061aSmrg
1287a3bd7f05Smrgstatic void
1288a3bd7f05Smrg_XtUninstallTranslations(Widget widget)
1289444c061aSmrg{
1290a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1291444c061aSmrg
1292a3bd7f05Smrg    _XtUnbindActions(widget, xlations, (TMBindData) widget->core.tm.proc_table);
1293444c061aSmrg    _XtRemoveTranslations(widget);
1294444c061aSmrg    widget->core.tm.translations = NULL;
1295a3bd7f05Smrg    FreeContext((TMContext *) &widget->core.tm.current_state);
1296444c061aSmrg}
1297444c061aSmrg
1298a3bd7f05Smrgvoid
1299a3bd7f05Smrg_XtDestroyTMData(Widget widget)
1300444c061aSmrg{
1301a3bd7f05Smrg    TMComplexBindData cBindData;
1302444c061aSmrg
1303444c061aSmrg    _XtUninstallTranslations(widget);
1304444c061aSmrg
1305a3bd7f05Smrg    if ((cBindData = (TMComplexBindData) widget->core.tm.proc_table)) {
1306a3bd7f05Smrg        if (cBindData->isComplex) {
1307a3bd7f05Smrg            ATranslations nXlations = (ATranslations) cBindData->accel_context;
1308a3bd7f05Smrg
1309a3bd7f05Smrg            while (nXlations) {
1310a3bd7f05Smrg                ATranslations aXlations = nXlations;
1311a3bd7f05Smrg
1312a3bd7f05Smrg                nXlations = nXlations->next;
1313a3bd7f05Smrg                XtFree((char *) aXlations);
1314a3bd7f05Smrg            }
1315a3bd7f05Smrg        }
1316a3bd7f05Smrg        XtFree((char *) cBindData);
1317444c061aSmrg    }
1318444c061aSmrg}
1319444c061aSmrg
1320444c061aSmrg/*** Public procedures ***/
1321444c061aSmrg
1322a3bd7f05Smrgvoid
1323a3bd7f05SmrgXtUninstallTranslations(Widget widget)
1324444c061aSmrg{
1325a3bd7f05Smrg    EventMask oldMask;
1326444c061aSmrg    Widget hookobj;
1327a3bd7f05Smrg
1328444c061aSmrg    WIDGET_TO_APPCON(widget);
1329444c061aSmrg
1330444c061aSmrg    LOCK_APP(app);
1331a3bd7f05Smrg    if (!widget->core.tm.translations) {
1332a3bd7f05Smrg        UNLOCK_APP(app);
1333a3bd7f05Smrg        return;
1334444c061aSmrg    }
1335444c061aSmrg    oldMask = widget->core.tm.translations->eventMask;
1336444c061aSmrg    _XtUninstallTranslations(widget);
1337444c061aSmrg    if (XtIsRealized(widget) && oldMask)
1338a3bd7f05Smrg        XSelectInput(XtDisplay(widget), XtWindow(widget),
1339a3bd7f05Smrg                     (long) XtBuildEventMask(widget));
1340444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
1341444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
1342a3bd7f05Smrg        XtChangeHookDataRec call_data;
1343444c061aSmrg
1344a3bd7f05Smrg        call_data.type = XtHuninstallTranslations;
1345a3bd7f05Smrg        call_data.widget = widget;
1346a3bd7f05Smrg        XtCallCallbackList(hookobj,
1347a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
1348a3bd7f05Smrg                           (XtPointer) &call_data);
1349444c061aSmrg    }
1350444c061aSmrg    UNLOCK_APP(app);
1351444c061aSmrg}
1352444c061aSmrg
1353a3bd7f05SmrgXtTranslations
1354a3bd7f05Smrg_XtCreateXlations(TMStateTree *stateTrees,
1355a3bd7f05Smrg                  TMShortCard numStateTrees,
1356a3bd7f05Smrg                  XtTranslations first,
1357a3bd7f05Smrg                  XtTranslations second)
1358444c061aSmrg{
1359a3bd7f05Smrg    XtTranslations xlations;
1360444c061aSmrg    TMShortCard i;
1361444c061aSmrg
1362444c061aSmrg    xlations = (XtTranslations)
1363a3bd7f05Smrg        __XtMalloc((Cardinal) (sizeof(TranslationData) +
1364a3bd7f05Smrg                               (size_t) (numStateTrees -
1365a3bd7f05Smrg                                         1) * sizeof(TMStateTree)));
1366444c061aSmrg#ifdef TRACE_TM
1367444c061aSmrg    LOCK_PROCESS;
1368444c061aSmrg    if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
1369a3bd7f05Smrg        _XtGlobalTM.tmTblSize = (TMShortCard) (_XtGlobalTM.tmTblSize + 16);
1370a3bd7f05Smrg        _XtGlobalTM.tmTbl = (XtTranslations *)
1371fdf6a26fSmrg            XtReallocArray(_XtGlobalTM.tmTbl,
1372fdf6a26fSmrg                           (Cardinal) _XtGlobalTM.tmTblSize,
1373fdf6a26fSmrg                           (Cardinal) sizeof(XtTranslations));
1374444c061aSmrg    }
1375444c061aSmrg    _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
1376444c061aSmrg    UNLOCK_PROCESS;
1377a3bd7f05Smrg#endif                          /* TRACE_TM */
1378444c061aSmrg
1379444c061aSmrg    xlations->composers[0] = first;
1380444c061aSmrg    xlations->composers[1] = second;
1381444c061aSmrg    xlations->hasBindings = False;
1382444c061aSmrg    xlations->operation = XtTableReplace;
1383444c061aSmrg
1384a3bd7f05Smrg    for (i = 0; i < numStateTrees; i++) {
1385a3bd7f05Smrg        xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
1386a3bd7f05Smrg        stateTrees[i]->simple.refCount++;
1387a3bd7f05Smrg    }
1388444c061aSmrg    xlations->numStateTrees = numStateTrees;
1389444c061aSmrg    xlations->eventMask = 0;
1390444c061aSmrg    return xlations;
1391444c061aSmrg}
1392444c061aSmrg
1393a3bd7f05SmrgTMStateTree
1394a3bd7f05Smrg_XtParseTreeToStateTree(TMParseStateTree parseTree)
1395444c061aSmrg{
1396a3bd7f05Smrg    TMSimpleStateTree simpleTree;
1397444c061aSmrg
1398444c061aSmrg    if (parseTree->numComplexBranchHeads) {
1399a3bd7f05Smrg        TMComplexStateTree complexTree;
1400a3bd7f05Smrg
1401a3bd7f05Smrg        complexTree = XtNew(TMComplexStateTreeRec);
1402a3bd7f05Smrg        complexTree->isSimple = False;
1403fdf6a26fSmrg        complexTree->complexBranchHeadTbl =
1404fdf6a26fSmrg            XtMallocArray((Cardinal) parseTree->numComplexBranchHeads,
1405fdf6a26fSmrg                          (Cardinal) sizeof(StatePtr));
1406fdf6a26fSmrg        memcpy(complexTree->complexBranchHeadTbl,
1407fdf6a26fSmrg               parseTree->complexBranchHeadTbl,
1408fdf6a26fSmrg               parseTree->numComplexBranchHeads * sizeof(StatePtr));
1409a3bd7f05Smrg        complexTree->numComplexBranchHeads = parseTree->numComplexBranchHeads;
1410a3bd7f05Smrg        simpleTree = (TMSimpleStateTree) complexTree;
1411444c061aSmrg    }
1412444c061aSmrg    else {
1413a3bd7f05Smrg        simpleTree = XtNew(TMSimpleStateTreeRec);
1414a3bd7f05Smrg        simpleTree->isSimple = True;
1415444c061aSmrg    }
1416444c061aSmrg    simpleTree->isAccelerator = parseTree->isAccelerator;
1417444c061aSmrg    simpleTree->refCount = 0;
1418444c061aSmrg    simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
1419444c061aSmrg
1420fdf6a26fSmrg    simpleTree->branchHeadTbl =
1421fdf6a26fSmrg        XtMallocArray((Cardinal) parseTree->numBranchHeads,
1422fdf6a26fSmrg                      (Cardinal) sizeof(TMBranchHeadRec));
1423fdf6a26fSmrg    memcpy(simpleTree->branchHeadTbl, parseTree->branchHeadTbl,
1424fdf6a26fSmrg           parseTree->numBranchHeads * sizeof(TMBranchHeadRec));
1425444c061aSmrg    simpleTree->numBranchHeads = parseTree->numBranchHeads;
1426444c061aSmrg
1427fdf6a26fSmrg    simpleTree->quarkTbl = XtMallocArray((Cardinal) parseTree->numQuarks,
1428fdf6a26fSmrg                                         (Cardinal) sizeof(XrmQuark));
1429fdf6a26fSmrg    memcpy(simpleTree->quarkTbl, parseTree->quarkTbl,
1430fdf6a26fSmrg           parseTree->numQuarks * sizeof(XrmQuark));
1431444c061aSmrg    simpleTree->numQuarks = parseTree->numQuarks;
1432444c061aSmrg
1433a3bd7f05Smrg    return (TMStateTree) simpleTree;
1434444c061aSmrg}
1435444c061aSmrg
1436a3bd7f05Smrgstatic void
1437a3bd7f05SmrgFreeActions(ActionPtr actions)
1438444c061aSmrg{
1439444c061aSmrg    ActionPtr action;
1440444c061aSmrg    TMShortCard i;
1441a3bd7f05Smrg
1442444c061aSmrg    for (action = actions; action;) {
1443a3bd7f05Smrg        ActionPtr nextAction = action->next;
1444a3bd7f05Smrg
1445a3bd7f05Smrg        for (i = (TMShortCard) action->num_params; i;) {
1446a3bd7f05Smrg            XtFree((_XtString) action->params[--i]);
1447a3bd7f05Smrg        }
1448a3bd7f05Smrg        XtFree((char *) action->params);
1449a3bd7f05Smrg        XtFree((char *) action);
1450a3bd7f05Smrg        action = nextAction;
1451444c061aSmrg    }
1452444c061aSmrg}
1453444c061aSmrg
1454a3bd7f05Smrgstatic void
1455a3bd7f05SmrgAmbigActions(EventSeqPtr initialEvent,
1456a3bd7f05Smrg             StatePtr *state,
1457a3bd7f05Smrg             TMParseStateTree stateTree)
1458444c061aSmrg{
1459a3bd7f05Smrg    String params[3];
1460a3bd7f05Smrg    Cardinal numParams = 0;
1461444c061aSmrg
1462444c061aSmrg    params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
1463444c061aSmrg    params[numParams++] = _XtPrintActions((*state)->actions,
1464a3bd7f05Smrg                                          stateTree->quarkTbl);
1465a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "oldActions", XtCXtToolkitError,
1466a3bd7f05Smrg                 "Previous entry was: %s %s", params, &numParams);
1467a3bd7f05Smrg    XtFree((char *) params[0]);
1468a3bd7f05Smrg    XtFree((char *) params[1]);
1469444c061aSmrg    numParams = 0;
1470a3bd7f05Smrg    params[numParams++] = _XtPrintActions(initialEvent->actions,
1471a3bd7f05Smrg                                          stateTree->quarkTbl);
1472a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "newActions", XtCXtToolkitError,
1473a3bd7f05Smrg                 "New actions are:%s", params, &numParams);
1474a3bd7f05Smrg    XtFree((char *) params[0]);
1475a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "ambiguousActions",
1476a3bd7f05Smrg                 XtCXtToolkitError,
1477a3bd7f05Smrg                 "Overriding earlier translation manager actions.", NULL, NULL);
1478444c061aSmrg
1479444c061aSmrg    FreeActions((*state)->actions);
1480444c061aSmrg    (*state)->actions = NULL;
1481444c061aSmrg}
1482444c061aSmrg
1483a3bd7f05Smrgvoid
1484a3bd7f05Smrg_XtAddEventSeqToStateTree(EventSeqPtr eventSeq, TMParseStateTree stateTree)
1485444c061aSmrg{
1486a3bd7f05Smrg    StatePtr *state;
1487a3bd7f05Smrg    EventSeqPtr initialEvent = eventSeq;
1488a3bd7f05Smrg    TMBranchHead branchHead;
1489a3bd7f05Smrg    TMShortCard idx, modIndex, typeIndex;
1490444c061aSmrg
1491a3bd7f05Smrg    if (eventSeq == NULL)
1492a3bd7f05Smrg        return;
1493444c061aSmrg
1494444c061aSmrg    /* note that all states in the event seq passed in start out null */
1495444c061aSmrg    /* we fill them in with the matching state as we traverse the list */
1496444c061aSmrg
1497444c061aSmrg    /*
1498444c061aSmrg     * We need to free the parser data structures !!!
1499444c061aSmrg     */
1500444c061aSmrg
1501444c061aSmrg    typeIndex = _XtGetTypeIndex(&eventSeq->event);
1502444c061aSmrg    modIndex = _XtGetModifierIndex(&eventSeq->event);
1503444c061aSmrg    idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
1504444c061aSmrg    branchHead = &stateTree->branchHeadTbl[idx];
1505444c061aSmrg
1506444c061aSmrg    /*
1507444c061aSmrg     * Need to check for pre-existing actions with same lhs |||
1508444c061aSmrg     */
1509444c061aSmrg
1510444c061aSmrg    /*
1511444c061aSmrg     * Check for optimized case. Don't assume that the eventSeq has actions.
1512444c061aSmrg     */
1513444c061aSmrg    if (!eventSeq->next &&
1514a3bd7f05Smrg        eventSeq->actions &&
1515a3bd7f05Smrg        !eventSeq->actions->next && !eventSeq->actions->num_params) {
1516a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1517a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1518a3bd7f05Smrg        branchHead->hasActions = True;
1519a3bd7f05Smrg        XtSetBits(branchHead->more, eventSeq->actions->idx, 13);
1520a3bd7f05Smrg        FreeActions(eventSeq->actions);
1521a3bd7f05Smrg        eventSeq->actions = NULL;
1522a3bd7f05Smrg        return;
1523a3bd7f05Smrg    }
1524444c061aSmrg
1525444c061aSmrg    branchHead->isSimple = False;
1526444c061aSmrg    if (!eventSeq->next)
1527a3bd7f05Smrg        branchHead->hasActions = True;
1528a3bd7f05Smrg    XtSetBits(branchHead->more,
1529a3bd7f05Smrg              GetComplexBranchIndex(stateTree, typeIndex, modIndex), 13);
1530444c061aSmrg    state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
1531444c061aSmrg
1532444c061aSmrg    for (;;) {
1533a3bd7f05Smrg        *state = NewState(stateTree, typeIndex, modIndex);
1534444c061aSmrg
1535a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1536a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1537444c061aSmrg
1538a3bd7f05Smrg        /* *state now points at state record matching event */
1539a3bd7f05Smrg        eventSeq->state = *state;
1540444c061aSmrg
1541a3bd7f05Smrg        if (eventSeq->actions != NULL) {
1542a3bd7f05Smrg            if ((*state)->actions != NULL)
1543a3bd7f05Smrg                AmbigActions(initialEvent, state, stateTree);
1544a3bd7f05Smrg            (*state)->actions = eventSeq->actions;
1545444c061aSmrg#ifdef TRACE_TM
1546a3bd7f05Smrg            LOCK_PROCESS;
1547a3bd7f05Smrg            _XtGlobalTM.numComplexActions++;
1548a3bd7f05Smrg            UNLOCK_PROCESS;
1549a3bd7f05Smrg#endif                          /* TRACE_TM */
1550a3bd7f05Smrg        }
1551a3bd7f05Smrg
1552a3bd7f05Smrg        if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
1553a3bd7f05Smrg            break;
1554a3bd7f05Smrg
1555a3bd7f05Smrg        state = &(*state)->nextLevel;
1556a3bd7f05Smrg        typeIndex = _XtGetTypeIndex(&eventSeq->event);
1557a3bd7f05Smrg        modIndex = _XtGetModifierIndex(&eventSeq->event);
1558a3bd7f05Smrg        LOCK_PROCESS;
1559a3bd7f05Smrg        if (!TMNewMatchSemantics()) {
1560a3bd7f05Smrg            /*
1561a3bd7f05Smrg             * force a potential empty entry into the branch head
1562a3bd7f05Smrg             * table in order to emulate old matching behavior
1563a3bd7f05Smrg             */
1564a3bd7f05Smrg            (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
1565a3bd7f05Smrg        }
1566a3bd7f05Smrg        UNLOCK_PROCESS;
1567444c061aSmrg    }
1568444c061aSmrg
1569444c061aSmrg    if (eventSeq && eventSeq->state) {
1570a3bd7f05Smrg        /* we've been here before... must be a cycle in the event seq. */
1571a3bd7f05Smrg        branchHead->hasCycles = True;
1572a3bd7f05Smrg        (*state)->nextLevel = eventSeq->state;
1573a3bd7f05Smrg        eventSeq->state->isCycleStart = True;
1574a3bd7f05Smrg        (*state)->isCycleEnd = TRUE;
1575444c061aSmrg    }
1576444c061aSmrg}
1577444c061aSmrg
1578444c061aSmrg/*
1579444c061aSmrg * Internal Converter for merging. Old and New must both be valid xlations
1580444c061aSmrg */
1581a3bd7f05SmrgBoolean
1582a3bd7f05Smrg_XtCvtMergeTranslations(Display *dpy _X_UNUSED,
1583a3bd7f05Smrg                        XrmValuePtr args _X_UNUSED,
1584a3bd7f05Smrg                        Cardinal *num_args,
1585a3bd7f05Smrg                        XrmValuePtr from,
1586a3bd7f05Smrg                        XrmValuePtr to,
1587a3bd7f05Smrg                        XtPointer *closure_ret _X_UNUSED)
1588444c061aSmrg{
1589a3bd7f05Smrg    XtTranslations first, second, xlations;
1590a3bd7f05Smrg    TMStateTree *stateTrees, stackStateTrees[16];
1591a3bd7f05Smrg    TMShortCard numStateTrees, i;
1592444c061aSmrg
1593444c061aSmrg    if (*num_args != 0)
1594a3bd7f05Smrg        XtWarningMsg("invalidParameters", "mergeTranslations",
1595a3bd7f05Smrg                     XtCXtToolkitError,
1596a3bd7f05Smrg                     "MergeTM to TranslationTable needs no extra arguments",
1597a3bd7f05Smrg                     NULL, NULL);
1598444c061aSmrg
1599444c061aSmrg    if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
1600a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1601a3bd7f05Smrg        return False;
1602444c061aSmrg    }
1603444c061aSmrg
1604a3bd7f05Smrg    first = ((TMConvertRec *) from->addr)->old;
1605a3bd7f05Smrg    second = ((TMConvertRec *) from->addr)->new;
1606444c061aSmrg
1607a3bd7f05Smrg    numStateTrees =
1608a3bd7f05Smrg        (TMShortCard) (first->numStateTrees + second->numStateTrees);
1609444c061aSmrg
1610444c061aSmrg    stateTrees = (TMStateTree *)
1611a3bd7f05Smrg        XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
1612444c061aSmrg
1613444c061aSmrg    for (i = 0; i < first->numStateTrees; i++)
1614a3bd7f05Smrg        stateTrees[i] = first->stateTreeTbl[i];
1615444c061aSmrg    for (i = 0; i < second->numStateTrees; i++)
1616a3bd7f05Smrg        stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
1617444c061aSmrg
1618444c061aSmrg    xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
1619444c061aSmrg
1620444c061aSmrg    if (to->addr != NULL) {
1621a3bd7f05Smrg        *(XtTranslations *) to->addr = xlations;
1622444c061aSmrg    }
1623444c061aSmrg    else {
1624a3bd7f05Smrg        static XtTranslations staticStateTable;
1625a3bd7f05Smrg
1626a3bd7f05Smrg        staticStateTable = xlations;
1627a3bd7f05Smrg        to->addr = (XPointer) &staticStateTable;
1628a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1629444c061aSmrg    }
1630444c061aSmrg
1631a3bd7f05Smrg    XtStackFree((XtPointer) stateTrees, (XtPointer) stackStateTrees);
1632444c061aSmrg    return True;
1633444c061aSmrg}
1634444c061aSmrg
1635a3bd7f05Smrgstatic XtTranslations
1636a3bd7f05SmrgMergeThem(Widget dest, XtTranslations first, XtTranslations second)
1637444c061aSmrg{
1638a3bd7f05Smrg    XtCacheRef cache_ref;
1639a3bd7f05Smrg    static XrmQuark from_type = NULLQUARK, to_type;
1640a3bd7f05Smrg    XrmValue from, to;
1641a3bd7f05Smrg    TMConvertRec convert_rec;
1642a3bd7f05Smrg    XtTranslations newTable;
1643444c061aSmrg
1644444c061aSmrg    LOCK_PROCESS;
1645444c061aSmrg    if (from_type == NULLQUARK) {
1646a3bd7f05Smrg        from_type = XrmPermStringToQuark(_XtRStateTablePair);
1647a3bd7f05Smrg        to_type = XrmPermStringToQuark(XtRTranslationTable);
1648444c061aSmrg    }
1649444c061aSmrg    UNLOCK_PROCESS;
1650a3bd7f05Smrg    from.addr = (XPointer) &convert_rec;
1651444c061aSmrg    from.size = sizeof(TMConvertRec);
1652a3bd7f05Smrg    to.addr = (XPointer) &newTable;
1653444c061aSmrg    to.size = sizeof(XtTranslations);
1654444c061aSmrg    convert_rec.old = first;
1655444c061aSmrg    convert_rec.new = second;
1656444c061aSmrg
1657444c061aSmrg    LOCK_PROCESS;
1658a3bd7f05Smrg    if (!_XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) {
1659a3bd7f05Smrg        UNLOCK_PROCESS;
1660a3bd7f05Smrg        return NULL;
1661444c061aSmrg    }
1662444c061aSmrg    UNLOCK_PROCESS;
1663444c061aSmrg
1664444c061aSmrg#ifndef REFCNT_TRANSLATIONS
1665444c061aSmrg
1666444c061aSmrg    if (cache_ref)
1667a3bd7f05Smrg        XtAddCallback(dest, XtNdestroyCallback,
1668a3bd7f05Smrg                      XtCallbackReleaseCacheRef, (XtPointer) cache_ref);
1669444c061aSmrg
1670444c061aSmrg#endif
1671444c061aSmrg
1672444c061aSmrg    return newTable;
1673444c061aSmrg}
1674444c061aSmrg
1675444c061aSmrg/*
1676444c061aSmrg * Unmerge will recursively traverse the xlation compose tree and
1677444c061aSmrg * generate a new xlation that is the result of all instances of
1678444c061aSmrg * xlations being removed. It currently doesn't differentiate between
1679444c061aSmrg * the potential that an xlation will be both an accelerator and
1680444c061aSmrg * normal. This is not supported by the spec anyway.
1681444c061aSmrg */
1682a3bd7f05Smrgstatic XtTranslations
1683a3bd7f05SmrgUnmergeTranslations(Widget widget,
1684a3bd7f05Smrg                    XtTranslations xlations,
1685a3bd7f05Smrg                    XtTranslations unmergeXlations,
1686a3bd7f05Smrg                    TMShortCard currIndex,
1687a3bd7f05Smrg                    TMComplexBindProcs oldBindings,
1688a3bd7f05Smrg                    TMShortCard numOldBindings,
1689a3bd7f05Smrg                    TMComplexBindProcs newBindings,
1690a3bd7f05Smrg                    TMShortCard *numNewBindingsRtn)
1691444c061aSmrg{
1692444c061aSmrg    XtTranslations first, second, result;
1693444c061aSmrg
1694444c061aSmrg    if (!xlations || (xlations == unmergeXlations))
1695a3bd7f05Smrg        return NULL;
1696444c061aSmrg
1697444c061aSmrg    if (xlations->composers[0]) {
1698a3bd7f05Smrg        first = UnmergeTranslations(widget, xlations->composers[0],
1699a3bd7f05Smrg                                    unmergeXlations, currIndex,
1700a3bd7f05Smrg                                    oldBindings, numOldBindings,
1701a3bd7f05Smrg                                    newBindings, numNewBindingsRtn);
1702444c061aSmrg    }
1703444c061aSmrg    else
1704a3bd7f05Smrg        first = NULL;
1705444c061aSmrg
17060568f49bSmrg    if (xlations->composers[0]
1707a3bd7f05Smrg        && xlations->composers[1]) {
1708a3bd7f05Smrg        second = UnmergeTranslations(widget, xlations->composers[1],
1709a3bd7f05Smrg                                     unmergeXlations, (TMShortCard)
1710a3bd7f05Smrg                                     (currIndex +
1711a3bd7f05Smrg                                      xlations->composers[0]->numStateTrees),
1712a3bd7f05Smrg                                     oldBindings,
1713a3bd7f05Smrg                                     numOldBindings, newBindings,
1714a3bd7f05Smrg                                     numNewBindingsRtn);
1715444c061aSmrg    }
1716444c061aSmrg    else
1717a3bd7f05Smrg        second = NULL;
1718444c061aSmrg
1719444c061aSmrg    if (first || second) {
1720a3bd7f05Smrg        if (first && second) {
1721a3bd7f05Smrg            if ((first != xlations->composers[0]) ||
1722a3bd7f05Smrg                (second != xlations->composers[1]))
1723a3bd7f05Smrg                result = MergeThem(widget, first, second);
1724a3bd7f05Smrg            else
1725a3bd7f05Smrg                result = xlations;
1726a3bd7f05Smrg        }
1727a3bd7f05Smrg        else {
1728a3bd7f05Smrg            if (first)
1729a3bd7f05Smrg                result = first;
1730a3bd7f05Smrg            else
1731a3bd7f05Smrg                result = second;
1732a3bd7f05Smrg        }
1733a3bd7f05Smrg    }
1734a3bd7f05Smrg    else {                      /* only update for leaf nodes */
1735a3bd7f05Smrg        if (numOldBindings) {
1736a3bd7f05Smrg            Cardinal i;
1737a3bd7f05Smrg
1738a3bd7f05Smrg            for (i = 0; i < xlations->numStateTrees; i++) {
1739a3bd7f05Smrg                if (xlations->stateTreeTbl[i]->simple.isAccelerator)
1740a3bd7f05Smrg                    newBindings[*numNewBindingsRtn] =
1741a3bd7f05Smrg                        oldBindings[currIndex + i];
1742a3bd7f05Smrg                (*numNewBindingsRtn)++;
1743a3bd7f05Smrg            }
1744a3bd7f05Smrg        }
1745a3bd7f05Smrg        result = xlations;
1746444c061aSmrg    }
1747444c061aSmrg    return result;
1748444c061aSmrg}
1749444c061aSmrg
1750444c061aSmrgtypedef struct {
1751444c061aSmrg    XtTranslations xlations;
1752444c061aSmrg    TMComplexBindProcs bindings;
1753a3bd7f05Smrg} MergeBindRec, *MergeBind;
1754a3bd7f05Smrg
1755a3bd7f05Smrgstatic XtTranslations
1756a3bd7f05SmrgMergeTranslations(Widget widget,
1757a3bd7f05Smrg                  XtTranslations oldXlations,
1758a3bd7f05Smrg                  XtTranslations newXlations,
1759a3bd7f05Smrg                  _XtTranslateOp operation,
1760a3bd7f05Smrg                  Widget source,
1761a3bd7f05Smrg                  TMComplexBindProcs oldBindings,
1762a3bd7f05Smrg                  TMComplexBindProcs newBindings,
1763a3bd7f05Smrg                  TMShortCard *numNewRtn)
1764444c061aSmrg{
1765a3bd7f05Smrg    XtTranslations newTable = NULL, xlations;
1766a3bd7f05Smrg    TMComplexBindProcs bindings;
1767a3bd7f05Smrg    TMShortCard i, j;
1768a3bd7f05Smrg    TMStateTree *treePtr;
1769a3bd7f05Smrg    TMShortCard numNew;
1770a3bd7f05Smrg    MergeBindRec bindPair[2];
1771444c061aSmrg
1772444c061aSmrg    /* If the new translation has an accelerator context then pull it
1773444c061aSmrg     * off and pass it and the real xlations in to the caching merge
1774444c061aSmrg     * routine.
1775444c061aSmrg     */
1776444c061aSmrg    if (newXlations->hasBindings) {
1777a3bd7f05Smrg        xlations = ((ATranslations) newXlations)->xlations;
1778a3bd7f05Smrg        bindings = (TMComplexBindProcs)
1779a3bd7f05Smrg            &((ATranslations) newXlations)->bindTbl[0];
1780444c061aSmrg    }
1781444c061aSmrg    else {
1782a3bd7f05Smrg        xlations = newXlations;
1783a3bd7f05Smrg        bindings = NULL;
1784a3bd7f05Smrg    }
1785a3bd7f05Smrg    switch (operation) {
1786fdf6a26fSmrg    default:
1787a3bd7f05Smrg    case XtTableReplace:
1788a3bd7f05Smrg        newTable = bindPair[0].xlations = xlations;
1789a3bd7f05Smrg        bindPair[0].bindings = bindings;
1790a3bd7f05Smrg        bindPair[1].xlations = NULL;
1791a3bd7f05Smrg        bindPair[1].bindings = NULL;
1792a3bd7f05Smrg        break;
1793a3bd7f05Smrg    case XtTableAugment:
1794a3bd7f05Smrg        bindPair[0].xlations = oldXlations;
1795a3bd7f05Smrg        bindPair[0].bindings = oldBindings;
1796a3bd7f05Smrg        bindPair[1].xlations = xlations;
1797a3bd7f05Smrg        bindPair[1].bindings = bindings;
1798a3bd7f05Smrg        newTable = NULL;
1799a3bd7f05Smrg        break;
1800a3bd7f05Smrg    case XtTableOverride:
1801a3bd7f05Smrg        bindPair[0].xlations = xlations;
1802a3bd7f05Smrg        bindPair[0].bindings = bindings;
1803a3bd7f05Smrg        bindPair[1].xlations = oldXlations;
1804a3bd7f05Smrg        bindPair[1].bindings = oldBindings;
1805a3bd7f05Smrg        newTable = NULL;
1806a3bd7f05Smrg        break;
1807444c061aSmrg    }
1808444c061aSmrg    if (!newTable)
1809a3bd7f05Smrg        newTable =
1810a3bd7f05Smrg            MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
1811444c061aSmrg
1812444c061aSmrg    for (i = 0, numNew = 0; i < 2; i++) {
1813a3bd7f05Smrg        if (bindPair[i].xlations)
1814a3bd7f05Smrg            for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
1815a3bd7f05Smrg                if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
1816a3bd7f05Smrg                    if (bindPair[i].bindings)
1817a3bd7f05Smrg                        newBindings[numNew] = bindPair[i].bindings[j];
1818a3bd7f05Smrg                    else {
1819a3bd7f05Smrg                        newBindings[numNew].widget = source;
1820a3bd7f05Smrg                        newBindings[numNew].aXlations = bindPair[i].xlations;
1821a3bd7f05Smrg                    }
1822a3bd7f05Smrg                }
1823a3bd7f05Smrg            }
1824444c061aSmrg    }
1825444c061aSmrg    *numNewRtn = numNew;
1826444c061aSmrg    treePtr = &newTable->stateTreeTbl[0];
1827444c061aSmrg    for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
1828a3bd7f05Smrg        (*treePtr)->simple.refCount++;
1829444c061aSmrg    return newTable;
1830444c061aSmrg}
1831444c061aSmrg
1832a3bd7f05Smrgstatic TMBindData
1833a3bd7f05SmrgMakeBindData(TMComplexBindProcs bindings,
1834a3bd7f05Smrg             TMShortCard numBindings,
1835a3bd7f05Smrg             TMBindData oldBindData)
1836444c061aSmrg{
1837a3bd7f05Smrg    TMLongCard bytes;
1838a3bd7f05Smrg    TMShortCard i;
1839a3bd7f05Smrg    Boolean isComplex;
1840a3bd7f05Smrg    TMBindData bindData;
1841444c061aSmrg
1842444c061aSmrg    if (numBindings == 0)
1843a3bd7f05Smrg        return NULL;
1844444c061aSmrg    for (i = 0; i < numBindings; i++)
1845a3bd7f05Smrg        if (bindings[i].widget)
1846a3bd7f05Smrg            break;
1847444c061aSmrg    isComplex = (i < numBindings);
1848444c061aSmrg    if (isComplex)
1849a3bd7f05Smrg        bytes = (sizeof(TMComplexBindDataRec) +
1850a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1851a3bd7f05Smrg                  sizeof(TMComplexBindProcsRec)));
1852444c061aSmrg    else
1853a3bd7f05Smrg        bytes = (sizeof(TMSimpleBindDataRec) +
1854a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1855a3bd7f05Smrg                  sizeof(TMSimpleBindProcsRec)));
1856444c061aSmrg
1857a3bd7f05Smrg    bindData =
1858a3bd7f05Smrg        (TMBindData) __XtCalloc((Cardinal) sizeof(char), (Cardinal) bytes);
18590568f49bSmrg    XtSetBit(bindData->simple.isComplex, isComplex);
1860444c061aSmrg    if (isComplex) {
1861a3bd7f05Smrg        TMComplexBindData cBindData = (TMComplexBindData) bindData;
1862a3bd7f05Smrg
1863a3bd7f05Smrg        /*
1864a3bd7f05Smrg         * If there were any accelerator contexts in the old bindData
1865a3bd7f05Smrg         * then propagate them to the new one.
1866a3bd7f05Smrg         */
1867a3bd7f05Smrg        if (oldBindData && oldBindData->simple.isComplex)
1868a3bd7f05Smrg            cBindData->accel_context =
1869a3bd7f05Smrg                ((TMComplexBindData) oldBindData)->accel_context;
1870fdf6a26fSmrg        memcpy(&cBindData->bindTbl[0], bindings,
1871fdf6a26fSmrg               numBindings * sizeof(TMComplexBindProcsRec));
1872444c061aSmrg    }
1873444c061aSmrg    return bindData;
1874444c061aSmrg}
1875444c061aSmrg
1876444c061aSmrg/*
1877444c061aSmrg * This routine is the central clearinghouse for merging translations
1878444c061aSmrg * into a widget. It takes care of preping the action bindings for
1879444c061aSmrg * realize time and calling the converter or doing a straight merge if
1880444c061aSmrg * the destination is empty.
1881444c061aSmrg */
1882a3bd7f05Smrgstatic Boolean
1883a3bd7f05SmrgComposeTranslations(Widget dest,
1884a3bd7f05Smrg                    _XtTranslateOp operation,
1885a3bd7f05Smrg                    Widget source,
1886a3bd7f05Smrg                    XtTranslations newXlations)
1887444c061aSmrg{
1888a3bd7f05Smrg    XtTranslations newTable, oldXlations;
1889a3bd7f05Smrg    XtTranslations accNewXlations;
1890a3bd7f05Smrg    EventMask oldMask = 0;
1891a3bd7f05Smrg    TMBindData bindData;
1892a3bd7f05Smrg    TMComplexBindProcs oldBindings = NULL;
1893a3bd7f05Smrg    TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes;
1894444c061aSmrg    TMComplexBindProcsRec stackBindings[16], *newBindings;
1895444c061aSmrg
1896444c061aSmrg    /*
1897444c061aSmrg     * how should we be handling the refcount decrement for the
1898444c061aSmrg     * replaced translation table ???
1899444c061aSmrg     */
1900a3bd7f05Smrg    if (!newXlations) {
1901a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(dest),
1902a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1903a3bd7f05Smrg                        "table to (un)merge must not be null", NULL, NULL);
1904a3bd7f05Smrg        return False;
1905a3bd7f05Smrg    }
1906444c061aSmrg
1907444c061aSmrg    accNewXlations = newXlations;
1908444c061aSmrg    newXlations = ((newXlations->hasBindings)
1909a3bd7f05Smrg                   ? ((ATranslations) newXlations)->xlations : newXlations);
1910444c061aSmrg
1911444c061aSmrg    if (!(oldXlations = dest->core.tm.translations))
1912a3bd7f05Smrg        operation = XtTableReplace;
1913444c061aSmrg
1914444c061aSmrg    /*
1915444c061aSmrg     * try to avoid generation of duplicate state trees. If the source
1916444c061aSmrg     * isn't simple (1 state Tree) then it's too much hassle
1917444c061aSmrg     */
1918444c061aSmrg    if (((operation == XtTableAugment) ||
1919a3bd7f05Smrg         (operation == XtTableOverride)) && (newXlations->numStateTrees == 1)) {
1920a3bd7f05Smrg        Cardinal i;
1921a3bd7f05Smrg
1922a3bd7f05Smrg        for (i = 0; i < oldXlations->numStateTrees; i++)
1923a3bd7f05Smrg            if (oldXlations->stateTreeTbl[i] == newXlations->stateTreeTbl[0])
1924a3bd7f05Smrg                break;
1925a3bd7f05Smrg        if (i < oldXlations->numStateTrees) {
1926a3bd7f05Smrg            if (operation == XtTableAugment) {
1927a3bd7f05Smrg                /*
1928a3bd7f05Smrg                 * we don't need to do anything since it's already
1929a3bd7f05Smrg                 * there
1930a3bd7f05Smrg                 */
1931a3bd7f05Smrg                return True;
1932a3bd7f05Smrg            }
1933a3bd7f05Smrg            else {              /* operation == XtTableOverride */
1934a3bd7f05Smrg                /*
1935a3bd7f05Smrg                 * We'll get rid of the duplicate trees throughout the
1936a3bd7f05Smrg                 * and leave it with a pruned translation table. This
1937a3bd7f05Smrg                 * will only work if the same table has been merged
1938a3bd7f05Smrg                 * into this table (or one of it's composers
1939a3bd7f05Smrg                 */
1940a3bd7f05Smrg                _XtUnmergeTranslations(dest, newXlations);
1941a3bd7f05Smrg                /*
1942a3bd7f05Smrg                 * reset oldXlations so we're back in sync
1943a3bd7f05Smrg                 */
1944a3bd7f05Smrg                if (!(oldXlations = dest->core.tm.translations))
1945a3bd7f05Smrg                    operation = XtTableReplace;
1946a3bd7f05Smrg            }
1947a3bd7f05Smrg        }
1948444c061aSmrg    }
1949444c061aSmrg
1950444c061aSmrg    bindData = (TMBindData) dest->core.tm.proc_table;
1951444c061aSmrg    if (bindData) {
1952a3bd7f05Smrg        numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
1953a3bd7f05Smrg        if (bindData->simple.isComplex)
1954a3bd7f05Smrg            oldBindings = &((TMComplexBindData) bindData)->bindTbl[0];
1955a3bd7f05Smrg        else
1956a3bd7f05Smrg            oldBindings = (TMComplexBindProcs)
1957a3bd7f05Smrg                (&((TMSimpleBindData) bindData)->bindTbl[0]);
1958444c061aSmrg    }
1959444c061aSmrg
1960a3bd7f05Smrg    numBytes =
1961a3bd7f05Smrg        (TMShortCard) ((size_t) ((oldXlations ? oldXlations->numStateTrees : 0)
1962a3bd7f05Smrg                                 +
1963a3bd7f05Smrg                                 newXlations->numStateTrees) *
1964a3bd7f05Smrg                       sizeof(TMComplexBindProcsRec));
1965a3bd7f05Smrg    newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings);
1966a3bd7f05Smrg    XtBZero((char *) newBindings, numBytes);
1967444c061aSmrg
1968444c061aSmrg    if (operation == XtTableUnmerge) {
1969a3bd7f05Smrg        newTable = UnmergeTranslations(dest,
1970a3bd7f05Smrg                                       oldXlations,
1971a3bd7f05Smrg                                       newXlations,
1972a3bd7f05Smrg                                       0,
1973a3bd7f05Smrg                                       oldBindings, numOldBindings,
1974a3bd7f05Smrg                                       newBindings, &numNewBindings);
1975444c061aSmrg#ifdef DEBUG
1976a3bd7f05Smrg        /* check for no match for unmerge */
1977a3bd7f05Smrg        if (newTable == oldXlations) {
1978a3bd7f05Smrg            XtWarning("attempt to unmerge invalid table");
1979a3bd7f05Smrg            XtStackFree((char *) newBindings, (char *) stackBindings);
1980a3bd7f05Smrg            return (newTable != NULL);
1981a3bd7f05Smrg        }
1982a3bd7f05Smrg#endif                          /* DEBUG */
1983444c061aSmrg    }
1984444c061aSmrg    else {
1985a3bd7f05Smrg        newTable = MergeTranslations(dest,
1986a3bd7f05Smrg                                     oldXlations,
1987a3bd7f05Smrg                                     accNewXlations,
1988a3bd7f05Smrg                                     operation,
1989a3bd7f05Smrg                                     source,
1990a3bd7f05Smrg                                     oldBindings, newBindings, &numNewBindings);
1991444c061aSmrg    }
1992444c061aSmrg    if (XtIsRealized(dest)) {
1993a3bd7f05Smrg        oldMask = 0;
1994a3bd7f05Smrg        if (oldXlations)
1995a3bd7f05Smrg            oldMask = oldXlations->eventMask;
1996a3bd7f05Smrg        _XtUninstallTranslations(dest);
1997444c061aSmrg    }
1998444c061aSmrg
1999444c061aSmrg    dest->core.tm.proc_table =
2000a3bd7f05Smrg        (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
2001444c061aSmrg
2002a3bd7f05Smrg    XtFree((char *) bindData);
2003444c061aSmrg
2004444c061aSmrg    dest->core.tm.translations = newTable;
2005444c061aSmrg
2006444c061aSmrg    if (XtIsRealized(dest)) {
2007a3bd7f05Smrg        EventMask mask = 0;
2008a3bd7f05Smrg
2009a3bd7f05Smrg        _XtInstallTranslations(dest);
2010a3bd7f05Smrg        if (newTable)
2011a3bd7f05Smrg            mask = newTable->eventMask;
2012a3bd7f05Smrg        if (mask != oldMask)
2013a3bd7f05Smrg            XSelectInput(XtDisplay(dest), XtWindow(dest),
2014a3bd7f05Smrg                         (long) XtBuildEventMask(dest));
2015a3bd7f05Smrg    }
2016a3bd7f05Smrg    XtStackFree((XtPointer) newBindings, (XtPointer) stackBindings);
2017a3bd7f05Smrg    return (newTable != NULL);
2018444c061aSmrg}
2019444c061aSmrg
2020444c061aSmrg/*
2021444c061aSmrg * If a GetValues is done on a translation resource that contains
2022444c061aSmrg * accelerators we need to return the accelerator context in addition
2023444c061aSmrg * to the pure translations.  Since this means returning memory that
2024fdf6a26fSmrg * the client controls but we still own, we will track the "headers"
2025444c061aSmrg * that we return (via a linked list pointed to from the bindData) and
2026444c061aSmrg * free it at destroy time.
2027444c061aSmrg */
2028a3bd7f05SmrgXtTranslations
2029a3bd7f05Smrg_XtGetTranslationValue(Widget w)
2030444c061aSmrg{
2031a3bd7f05Smrg    XtTM tmRecPtr = (XtTM) &w->core.tm;
2032a3bd7f05Smrg    ATranslations *aXlationsPtr;
2033a3bd7f05Smrg    TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table;
2034a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
2035444c061aSmrg
2036444c061aSmrg    if (!xlations || !cBindData || !cBindData->isComplex)
2037a3bd7f05Smrg        return xlations;
2038444c061aSmrg
2039444c061aSmrg    /* Walk the list looking to see if we already have generated a
2040444c061aSmrg     * header for the currently installed translations.  If we have,
2041444c061aSmrg     * just return that header.  Otherwise create a new header.
2042444c061aSmrg     */
2043444c061aSmrg    for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
2044a3bd7f05Smrg         *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
2045a3bd7f05Smrg         aXlationsPtr = &(*aXlationsPtr)->next);
2046444c061aSmrg    if (*aXlationsPtr)
2047a3bd7f05Smrg        return (XtTranslations) *aXlationsPtr;
2048444c061aSmrg    else {
2049a3bd7f05Smrg        /* create a new aXlations context */
2050a3bd7f05Smrg        ATranslations aXlations;
2051a3bd7f05Smrg        Cardinal numBindings = xlations->numStateTrees;
2052a3bd7f05Smrg
2053a3bd7f05Smrg        (*aXlationsPtr) = aXlations = (ATranslations)
2054a3bd7f05Smrg            __XtMalloc((Cardinal) (sizeof(ATranslationData) +
2055a3bd7f05Smrg                                   (numBindings -
2056a3bd7f05Smrg                                    1) * sizeof(TMComplexBindProcsRec)));
2057a3bd7f05Smrg
2058a3bd7f05Smrg        aXlations->hasBindings = True;
2059a3bd7f05Smrg        aXlations->xlations = xlations;
2060a3bd7f05Smrg        aXlations->next = NULL;
2061fdf6a26fSmrg        memcpy(&aXlations->bindTbl[0],
2062fdf6a26fSmrg               &cBindData->bindTbl[0],
2063fdf6a26fSmrg               numBindings * sizeof(TMComplexBindProcsRec));
2064a3bd7f05Smrg        return (XtTranslations) aXlations;
2065444c061aSmrg    }
2066444c061aSmrg}
2067444c061aSmrg
2068a3bd7f05Smrgstatic void
2069a3bd7f05SmrgRemoveStateTree(TMStateTree tree _X_UNUSED)
2070444c061aSmrg{
2071444c061aSmrg#ifdef REFCNT_TRANSLATIONS
2072a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
2073444c061aSmrg
2074444c061aSmrg    if (--stateTree->refCount == 0) {
2075a3bd7f05Smrg        /*
2076a3bd7f05Smrg         * should we free/refcount the match recs ?
2077a3bd7f05Smrg         */
2078a3bd7f05Smrg        if (!stateTree->isSimple) {
2079a3bd7f05Smrg            StatePtr currState, nextState;
2080a3bd7f05Smrg            TMShortCard i;
2081a3bd7f05Smrg
2082a3bd7f05Smrg            for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
2083a3bd7f05Smrg                currState = nextState = stateTree->complexBranchHeadTbl[i];
2084a3bd7f05Smrg                for (; nextState;) {
2085a3bd7f05Smrg                    FreeActions(currState->actions);
2086a3bd7f05Smrg                    currState->actions = NULL;
2087a3bd7f05Smrg                    if (!currState->isCycleEnd)
2088a3bd7f05Smrg                        nextState = currState->nextLevel;
2089a3bd7f05Smrg                    else
2090a3bd7f05Smrg                        nextState = NULL;
2091a3bd7f05Smrg                    XtFree((char *) currState);
2092a3bd7f05Smrg                }
2093a3bd7f05Smrg            }
2094a3bd7f05Smrg            XtFree((char *) stateTree->complexBranchHeadTbl);
2095a3bd7f05Smrg        }
2096a3bd7f05Smrg        XtFree((char *) stateTree->branchHeadTbl);
2097a3bd7f05Smrg        XtFree((char *) stateTree);
2098a3bd7f05Smrg    }
2099a3bd7f05Smrg#endif                          /* REFCNT_TRANSLATIONS */
2100444c061aSmrg}
2101444c061aSmrg
2102a3bd7f05Smrgvoid
2103a3bd7f05Smrg_XtRemoveStateTreeByIndex(XtTranslations xlations, TMShortCard i)
2104444c061aSmrg{
2105a3bd7f05Smrg    TMStateTree *stateTrees = xlations->stateTreeTbl;
2106444c061aSmrg
2107444c061aSmrg    RemoveStateTree(stateTrees[i]);
2108444c061aSmrg    xlations->numStateTrees--;
2109444c061aSmrg
2110a3bd7f05Smrg    for (; i < xlations->numStateTrees; i++) {
2111a3bd7f05Smrg        stateTrees[i] = stateTrees[i + 1];
2112a3bd7f05Smrg    }
2113444c061aSmrg}
2114444c061aSmrg
2115a3bd7f05Smrgvoid
2116a3bd7f05Smrg_XtFreeTranslations(XtAppContext app,
2117a3bd7f05Smrg                    XrmValuePtr toVal,
2118a3bd7f05Smrg                    XtPointer closure _X_UNUSED,
2119a3bd7f05Smrg                    XrmValuePtr args _X_UNUSED,
2120a3bd7f05Smrg                    Cardinal *num_args)
2121444c061aSmrg{
2122a3bd7f05Smrg    XtTranslations xlations;
2123a3bd7f05Smrg    int i;
2124444c061aSmrg
2125444c061aSmrg    if (*num_args != 0)
2126a3bd7f05Smrg        XtAppWarningMsg(app,
2127a3bd7f05Smrg                        "invalidParameters", "freeTranslations",
2128a3bd7f05Smrg                        XtCXtToolkitError,
2129a3bd7f05Smrg                        "Freeing XtTranslations requires no extra arguments",
2130a3bd7f05Smrg                        NULL, NULL);
2131a3bd7f05Smrg
2132a3bd7f05Smrg    xlations = *(XtTranslations *) toVal->addr;
2133a3bd7f05Smrg    for (i = 0; i < (int) xlations->numStateTrees; i++)
2134a3bd7f05Smrg        RemoveStateTree(xlations->stateTreeTbl[i]);
2135a3bd7f05Smrg    XtFree((char *) xlations);
2136444c061aSmrg}
2137444c061aSmrg
2138444c061aSmrg/*  The spec is not clear on when actions specified in accelerators are bound;
2139444c061aSmrg *  Bind them at Realize the same as translations
2140444c061aSmrg */
2141a3bd7f05Smrgvoid
2142a3bd7f05SmrgXtInstallAccelerators(Widget destination, Widget source)
2143444c061aSmrg{
2144a3bd7f05Smrg    XtTranslations aXlations;
2145a3bd7f05Smrg    _XtTranslateOp op;
2146a3bd7f05Smrg
2147444c061aSmrg    WIDGET_TO_APPCON(destination);
2148444c061aSmrg
2149444c061aSmrg    /*
2150444c061aSmrg     * test that it was parsed as an accelarator table. Even though
2151444c061aSmrg     * there doesn't need to be a distinction it makes life easier if
2152444c061aSmrg     * we honor the spec implication that aXlations is an accelerator
2153444c061aSmrg     */
2154444c061aSmrg    LOCK_APP(app);
2155444c061aSmrg    LOCK_PROCESS;
2156444c061aSmrg    if ((!XtIsWidget(source)) ||
2157a3bd7f05Smrg        ((aXlations = source->core.accelerators) == NULL) ||
2158a3bd7f05Smrg        (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) {
2159a3bd7f05Smrg        UNLOCK_PROCESS;
2160a3bd7f05Smrg        UNLOCK_APP(app);
2161a3bd7f05Smrg        return;
2162444c061aSmrg    }
2163444c061aSmrg
2164444c061aSmrg    aXlations = source->core.accelerators;
2165444c061aSmrg    op = aXlations->operation;
2166444c061aSmrg
2167444c061aSmrg    if (ComposeTranslations(destination, op, source, aXlations) &&
2168a3bd7f05Smrg        (XtClass(source)->core_class.display_accelerator != NULL)) {
2169a3bd7f05Smrg        _XtString buf = _XtPrintXlations(destination, aXlations, source, False);
2170a3bd7f05Smrg
2171a3bd7f05Smrg        (*(XtClass(source)->core_class.display_accelerator)) (source, buf);
2172a3bd7f05Smrg        XtFree(buf);
2173444c061aSmrg    }
2174444c061aSmrg    UNLOCK_PROCESS;
2175444c061aSmrg    UNLOCK_APP(app);
2176444c061aSmrg}
2177444c061aSmrg
2178a3bd7f05Smrgvoid
2179a3bd7f05SmrgXtInstallAllAccelerators(Widget destination, Widget source)
2180444c061aSmrg{
2181444c061aSmrg    Cardinal i;
2182a3bd7f05Smrg
2183444c061aSmrg    WIDGET_TO_APPCON(destination);
2184444c061aSmrg
2185444c061aSmrg    /* Recurse down normal children */
2186444c061aSmrg    LOCK_APP(app);
2187444c061aSmrg    LOCK_PROCESS;
2188444c061aSmrg    if (XtIsComposite(source)) {
21890568f49bSmrg        CompositeWidget cw = (CompositeWidget) source;
2190a3bd7f05Smrg
2191444c061aSmrg        for (i = 0; i < cw->composite.num_children; i++) {
2192a3bd7f05Smrg            XtInstallAllAccelerators(destination, cw->composite.children[i]);
2193444c061aSmrg        }
2194444c061aSmrg    }
2195444c061aSmrg
2196444c061aSmrg    /* Recurse down popup children */
2197444c061aSmrg    if (XtIsWidget(source)) {
2198444c061aSmrg        for (i = 0; i < source->core.num_popups; i++) {
2199a3bd7f05Smrg            XtInstallAllAccelerators(destination, source->core.popup_list[i]);
2200444c061aSmrg        }
2201444c061aSmrg    }
2202444c061aSmrg    /* Finally, apply procedure to this widget */
2203a3bd7f05Smrg    XtInstallAccelerators(destination, source);
2204444c061aSmrg    UNLOCK_PROCESS;
2205444c061aSmrg    UNLOCK_APP(app);
2206444c061aSmrg}
2207444c061aSmrg
2208a3bd7f05Smrg#if 0                           /* dead code */
2209a3bd7f05Smrgstatic _XtTranslateOp
2210a3bd7f05Smrg_XtGetTMOperation(XtTranslations xlations)
2211444c061aSmrg{
2212444c061aSmrg    return ((xlations->hasBindings)
2213a3bd7f05Smrg            ? ((ATranslations) xlations)->xlations->operation
2214a3bd7f05Smrg            : xlations->operation);
2215444c061aSmrg}
2216444c061aSmrg#endif
2217444c061aSmrg
2218a3bd7f05Smrgvoid
2219a3bd7f05SmrgXtAugmentTranslations(Widget widget, XtTranslations new)
2220444c061aSmrg{
2221444c061aSmrg    Widget hookobj;
2222a3bd7f05Smrg
2223444c061aSmrg    WIDGET_TO_APPCON(widget);
2224444c061aSmrg
2225444c061aSmrg    LOCK_APP(app);
2226444c061aSmrg    LOCK_PROCESS;
2227a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableAugment, (Widget) NULL, new);
2228444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2229444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2230a3bd7f05Smrg        XtChangeHookDataRec call_data;
2231444c061aSmrg
2232a3bd7f05Smrg        call_data.type = XtHaugmentTranslations;
2233a3bd7f05Smrg        call_data.widget = widget;
2234a3bd7f05Smrg        XtCallCallbackList(hookobj,
2235a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2236a3bd7f05Smrg                           (XtPointer) &call_data);
2237444c061aSmrg    }
2238444c061aSmrg    UNLOCK_PROCESS;
2239444c061aSmrg    UNLOCK_APP(app);
2240444c061aSmrg}
2241444c061aSmrg
2242a3bd7f05Smrgvoid
2243a3bd7f05SmrgXtOverrideTranslations(Widget widget, XtTranslations new)
2244444c061aSmrg{
2245444c061aSmrg    Widget hookobj;
2246a3bd7f05Smrg
2247444c061aSmrg    WIDGET_TO_APPCON(widget);
2248444c061aSmrg
2249444c061aSmrg    LOCK_APP(app);
2250444c061aSmrg    LOCK_PROCESS;
2251a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableOverride, (Widget) NULL, new);
2252444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2253444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2254a3bd7f05Smrg        XtChangeHookDataRec call_data;
2255444c061aSmrg
2256a3bd7f05Smrg        call_data.type = XtHoverrideTranslations;
2257a3bd7f05Smrg        call_data.widget = widget;
2258a3bd7f05Smrg        XtCallCallbackList(hookobj,
2259a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2260a3bd7f05Smrg                           (XtPointer) &call_data);
2261444c061aSmrg    }
2262444c061aSmrg    UNLOCK_PROCESS;
2263444c061aSmrg    UNLOCK_APP(app);
2264444c061aSmrg}
2265444c061aSmrg
2266a3bd7f05Smrgvoid
2267a3bd7f05Smrg_XtMergeTranslations(Widget widget,
2268a3bd7f05Smrg                     XtTranslations newXlations,
2269a3bd7f05Smrg                     _XtTranslateOp op)
2270444c061aSmrg{
2271a3bd7f05Smrg    if (!newXlations) {
2272a3bd7f05Smrg        if (!widget->core.tm.translations)
2273a3bd7f05Smrg            return;
2274a3bd7f05Smrg        else {
2275a3bd7f05Smrg            newXlations = widget->core.tm.translations;
2276a3bd7f05Smrg            widget->core.tm.translations = NULL;
2277a3bd7f05Smrg        }
2278a3bd7f05Smrg    }
2279a3bd7f05Smrg    (void) ComposeTranslations(widget, op, (Widget) NULL, newXlations);
2280444c061aSmrg}
2281444c061aSmrg
2282a3bd7f05Smrgvoid
2283a3bd7f05Smrg_XtUnmergeTranslations(Widget widget, XtTranslations xlations)
2284444c061aSmrg{
2285a3bd7f05Smrg    ComposeTranslations(widget, XtTableUnmerge, (Widget) NULL, xlations);
2286444c061aSmrg}
2287