TMstate.c revision a3bd7f05
1444c061aSmrg/***********************************************************
2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg/* TMstate.c -- maintains the state table of actions for the translation
72444c061aSmrg *              manager.
73444c061aSmrg */
74444c061aSmrg#ifdef HAVE_CONFIG_H
75444c061aSmrg#include <config.h>
76444c061aSmrg#endif
77444c061aSmrg#include "IntrinsicI.h"
78444c061aSmrg#ifndef TM_NO_MATCH
79444c061aSmrg#define TM_NO_MATCH (-2)
80a3bd7f05Smrg#endif                          /* TM_NO_MATCH */
81444c061aSmrg/* forward definitions */
82444c061aSmrgstatic StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard);
83444c061aSmrg
84444c061aSmrgstatic String XtNtranslationError = "translationError";
85444c061aSmrg
86444c061aSmrg#ifndef __EMX__
87a3bd7f05SmrgTMGlobalRec _XtGlobalTM;        /* initialized to zero K&R */
88444c061aSmrg#else
89a3bd7f05SmrgTMGlobalRec _XtGlobalTM = { 0 };
90444c061aSmrg#endif
91444c061aSmrg
92444c061aSmrg#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \
93444c061aSmrg  (typeMatch->eventType == tmEvent->event.eventType && \
94444c061aSmrg   (typeMatch->matchEvent != NULL) && \
95444c061aSmrg   (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent))
96444c061aSmrg
97444c061aSmrg#define NumStateTrees(xlations) \
98444c061aSmrg  ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees)
99444c061aSmrg
100a3bd7f05Smrgstatic TMShortCard
101a3bd7f05SmrgGetBranchHead(TMParseStateTree parseTree,
102a3bd7f05Smrg              TMShortCard typeIndex,
103a3bd7f05Smrg              TMShortCard modIndex,
104a3bd7f05Smrg              Boolean isDummy)
105444c061aSmrg{
106a3bd7f05Smrg#define TM_BRANCH_HEAD_TBL_ALLOC        8
107a3bd7f05Smrg#define TM_BRANCH_HEAD_TBL_REALLOC      8
108444c061aSmrg
109444c061aSmrg    TMBranchHead branchHead = parseTree->branchHeadTbl;
110a3bd7f05Smrg
111444c061aSmrg    /*
112444c061aSmrg     * dummy is used as a place holder for later matching in old-style
113444c061aSmrg     * matching behavior. If there's already an entry we don't need
114444c061aSmrg     * another dummy.
115444c061aSmrg     */
116444c061aSmrg    if (isDummy) {
117a3bd7f05Smrg        TMShortCard i;
118a3bd7f05Smrg
119a3bd7f05Smrg        for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) {
120a3bd7f05Smrg            if ((branchHead->typeIndex == typeIndex) &&
121a3bd7f05Smrg                (branchHead->modIndex == modIndex))
122a3bd7f05Smrg                return i;
123a3bd7f05Smrg        }
124a3bd7f05Smrg    }
125a3bd7f05Smrg    if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) {
126a3bd7f05Smrg        TMShortCard newSize;
127a3bd7f05Smrg
128a3bd7f05Smrg        if (parseTree->branchHeadTblSize == 0)
129a3bd7f05Smrg            parseTree->branchHeadTblSize =
130a3bd7f05Smrg                (TMShortCard) (parseTree->branchHeadTblSize +
131a3bd7f05Smrg                               TM_BRANCH_HEAD_TBL_ALLOC);
132a3bd7f05Smrg        else
133a3bd7f05Smrg            parseTree->branchHeadTblSize =
134a3bd7f05Smrg                (TMShortCard) (parseTree->branchHeadTblSize +
135a3bd7f05Smrg                               TM_BRANCH_HEAD_TBL_REALLOC);
136a3bd7f05Smrg        newSize =
137a3bd7f05Smrg            (TMShortCard) (parseTree->branchHeadTblSize *
138a3bd7f05Smrg                           sizeof(TMBranchHeadRec));
139a3bd7f05Smrg        if (parseTree->isStackBranchHeads) {
140a3bd7f05Smrg            TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl;
141a3bd7f05Smrg
142a3bd7f05Smrg            parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize);
143a3bd7f05Smrg            XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize);
144a3bd7f05Smrg            parseTree->isStackBranchHeads = False;
145a3bd7f05Smrg        }
146a3bd7f05Smrg        else {
147a3bd7f05Smrg            parseTree->branchHeadTbl = (TMBranchHead)
148a3bd7f05Smrg                XtRealloc((char *) parseTree->branchHeadTbl,
149a3bd7f05Smrg                          (Cardinal) (parseTree->branchHeadTblSize *
150a3bd7f05Smrg                                      sizeof(TMBranchHeadRec)));
151a3bd7f05Smrg        }
152a3bd7f05Smrg    }
153444c061aSmrg#ifdef TRACE_TM
154444c061aSmrg    LOCK_PROCESS;
155444c061aSmrg    _XtGlobalTM.numBranchHeads++;
156444c061aSmrg    UNLOCK_PROCESS;
157a3bd7f05Smrg#endif                          /* TRACE_TM */
158a3bd7f05Smrg    branchHead = &parseTree->branchHeadTbl[parseTree->numBranchHeads++];
159444c061aSmrg    branchHead->typeIndex = typeIndex;
160444c061aSmrg    branchHead->modIndex = modIndex;
161444c061aSmrg    branchHead->more = 0;
162444c061aSmrg    branchHead->isSimple = True;
163444c061aSmrg    branchHead->hasActions = False;
164444c061aSmrg    branchHead->hasCycles = False;
1650568f49bSmrg    return (TMShortCard) (parseTree->numBranchHeads - 1);
166444c061aSmrg}
167444c061aSmrg
168a3bd7f05SmrgTMShortCard
169a3bd7f05Smrg_XtGetQuarkIndex(TMParseStateTree parseTree, XrmQuark quark)
170444c061aSmrg{
171a3bd7f05Smrg#define TM_QUARK_TBL_ALLOC      16
172a3bd7f05Smrg#define TM_QUARK_TBL_REALLOC    16
1730568f49bSmrg    TMShortCard i;
174444c061aSmrg
175a3bd7f05Smrg    for (i = 0; i < parseTree->numQuarks; i++)
176a3bd7f05Smrg        if (parseTree->quarkTbl[i] == quark)
177a3bd7f05Smrg            break;
178a3bd7f05Smrg
179a3bd7f05Smrg    if (i == parseTree->numQuarks) {
180a3bd7f05Smrg        if (parseTree->numQuarks == parseTree->quarkTblSize) {
181a3bd7f05Smrg            TMShortCard newSize;
182a3bd7f05Smrg
183a3bd7f05Smrg            if (parseTree->quarkTblSize == 0)
184a3bd7f05Smrg                parseTree->quarkTblSize =
185a3bd7f05Smrg                    (TMShortCard) (parseTree->quarkTblSize +
186a3bd7f05Smrg                                   TM_QUARK_TBL_ALLOC);
187a3bd7f05Smrg            else
188a3bd7f05Smrg                parseTree->quarkTblSize =
189a3bd7f05Smrg                    (TMShortCard) (parseTree->quarkTblSize +
190a3bd7f05Smrg                                   TM_QUARK_TBL_REALLOC);
191a3bd7f05Smrg            newSize =
192a3bd7f05Smrg                (TMShortCard) (parseTree->quarkTblSize * sizeof(XrmQuark));
193a3bd7f05Smrg
194a3bd7f05Smrg            if (parseTree->isStackQuarks) {
195a3bd7f05Smrg                XrmQuark *oldquarkTbl = parseTree->quarkTbl;
196a3bd7f05Smrg
197a3bd7f05Smrg                parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize);
198a3bd7f05Smrg                XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize);
199a3bd7f05Smrg                parseTree->isStackQuarks = False;
200a3bd7f05Smrg            }
201a3bd7f05Smrg            else {
202a3bd7f05Smrg                parseTree->quarkTbl = (XrmQuark *)
203a3bd7f05Smrg                    XtRealloc((char *) parseTree->quarkTbl,
204a3bd7f05Smrg                              (Cardinal) (parseTree->quarkTblSize *
205a3bd7f05Smrg                                          sizeof(XrmQuark)));
206a3bd7f05Smrg            }
207a3bd7f05Smrg        }
208a3bd7f05Smrg        parseTree->quarkTbl[parseTree->numQuarks++] = quark;
209a3bd7f05Smrg    }
210444c061aSmrg    return i;
211444c061aSmrg}
212444c061aSmrg
213444c061aSmrg/*
214444c061aSmrg * Get an entry from the parseTrees complex branchHead tbl. If there's none
215444c061aSmrg * there then allocate one
216444c061aSmrg */
217a3bd7f05Smrgstatic TMShortCard
218a3bd7f05SmrgGetComplexBranchIndex(TMParseStateTree parseTree,
219a3bd7f05Smrg                      TMShortCard typeIndex _X_UNUSED,
220a3bd7f05Smrg                      TMShortCard modIndex _X_UNUSED)
221444c061aSmrg{
222444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8
223444c061aSmrg#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4
224444c061aSmrg
225444c061aSmrg    if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) {
226a3bd7f05Smrg        TMShortCard newSize;
227a3bd7f05Smrg
228a3bd7f05Smrg        if (parseTree->complexBranchHeadTblSize == 0)
229a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
230a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
231a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_ALLOC);
232a3bd7f05Smrg        else
233a3bd7f05Smrg            parseTree->complexBranchHeadTblSize =
234a3bd7f05Smrg                (TMShortCard) (parseTree->complexBranchHeadTblSize +
235a3bd7f05Smrg                               TM_COMPLEXBRANCH_HEAD_TBL_REALLOC);
236a3bd7f05Smrg
237a3bd7f05Smrg        newSize =
238a3bd7f05Smrg            (TMShortCard) (parseTree->complexBranchHeadTblSize *
239a3bd7f05Smrg                           sizeof(StatePtr));
240a3bd7f05Smrg
241a3bd7f05Smrg        if (parseTree->isStackComplexBranchHeads) {
242a3bd7f05Smrg            StatePtr *oldcomplexBranchHeadTbl = parseTree->complexBranchHeadTbl;
243a3bd7f05Smrg
244a3bd7f05Smrg            parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize);
245a3bd7f05Smrg            XtMemmove(parseTree->complexBranchHeadTbl,
246a3bd7f05Smrg                      oldcomplexBranchHeadTbl, newSize);
247a3bd7f05Smrg            parseTree->isStackComplexBranchHeads = False;
248a3bd7f05Smrg        }
249a3bd7f05Smrg        else {
250a3bd7f05Smrg            parseTree->complexBranchHeadTbl = (StatePtr *)
251a3bd7f05Smrg                XtRealloc((char *) parseTree->complexBranchHeadTbl,
252a3bd7f05Smrg                          (Cardinal) (parseTree->complexBranchHeadTblSize *
253a3bd7f05Smrg                                      sizeof(StatePtr)));
254a3bd7f05Smrg        }
255444c061aSmrg    }
256444c061aSmrg    parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL;
2570568f49bSmrg    return (TMShortCard) (parseTree->numComplexBranchHeads - 1);
258444c061aSmrg}
259444c061aSmrg
260a3bd7f05SmrgTMShortCard
261a3bd7f05Smrg_XtGetTypeIndex(Event *event)
262444c061aSmrg{
263a3bd7f05Smrg    TMShortCard i, j = TM_TYPE_SEGMENT_SIZE;
264a3bd7f05Smrg    TMShortCard typeIndex = 0;
265a3bd7f05Smrg    TMTypeMatch typeMatch;
266a3bd7f05Smrg    TMTypeMatch segment = NULL;
267444c061aSmrg
268444c061aSmrg    LOCK_PROCESS;
269444c061aSmrg    for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) {
270a3bd7f05Smrg        segment = _XtGlobalTM.typeMatchSegmentTbl[i];
271a3bd7f05Smrg        for (j = 0;
272a3bd7f05Smrg             typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE;
273a3bd7f05Smrg             j++, typeIndex++) {
274a3bd7f05Smrg            typeMatch = &(segment[j]);
275a3bd7f05Smrg            if (event->eventType == typeMatch->eventType &&
276a3bd7f05Smrg                event->eventCode == typeMatch->eventCode &&
277a3bd7f05Smrg                event->eventCodeMask == typeMatch->eventCodeMask &&
278a3bd7f05Smrg                event->matchEvent == typeMatch->matchEvent) {
279a3bd7f05Smrg                UNLOCK_PROCESS;
280a3bd7f05Smrg                return typeIndex;
281a3bd7f05Smrg            }
282a3bd7f05Smrg        }
283444c061aSmrg    }
284444c061aSmrg
285444c061aSmrg    if (j == TM_TYPE_SEGMENT_SIZE) {
286a3bd7f05Smrg        if (_XtGlobalTM.numTypeMatchSegments ==
287a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize) {
288a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTblSize =
289a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.typeMatchSegmentTblSize + 4);
290a3bd7f05Smrg            _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *)
291a3bd7f05Smrg                XtRealloc((char *) _XtGlobalTM.typeMatchSegmentTbl,
292a3bd7f05Smrg                          (Cardinal) (_XtGlobalTM.typeMatchSegmentTblSize *
293a3bd7f05Smrg                                      sizeof(TMTypeMatch)));
294a3bd7f05Smrg        }
295a3bd7f05Smrg        _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] =
296a3bd7f05Smrg            segment = (TMTypeMatch)
297a3bd7f05Smrg            __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec));
298a3bd7f05Smrg        j = 0;
299444c061aSmrg    }
300444c061aSmrg    typeMatch = &segment[j];
301444c061aSmrg    typeMatch->eventType = event->eventType;
302444c061aSmrg    typeMatch->eventCode = event->eventCode;
303444c061aSmrg    typeMatch->eventCodeMask = event->eventCodeMask;
304444c061aSmrg    typeMatch->matchEvent = event->matchEvent;
305444c061aSmrg    _XtGlobalTM.numTypeMatches++;
306444c061aSmrg    UNLOCK_PROCESS;
307444c061aSmrg    return typeIndex;
308444c061aSmrg}
309444c061aSmrg
310a3bd7f05Smrgstatic Boolean
311a3bd7f05SmrgCompareLateModifiers(LateBindingsPtr lateBind1P, LateBindingsPtr lateBind2P)
312444c061aSmrg{
313444c061aSmrg    LateBindingsPtr late1P = lateBind1P;
314444c061aSmrg    LateBindingsPtr late2P = lateBind2P;
315444c061aSmrg
316444c061aSmrg    if (late1P != NULL || late2P != NULL) {
317a3bd7f05Smrg        int i = 0;
318a3bd7f05Smrg        int j = 0;
319a3bd7f05Smrg
320a3bd7f05Smrg        if (late1P != NULL)
321a3bd7f05Smrg            for (; late1P->keysym != NoSymbol; i++)
322a3bd7f05Smrg                late1P++;
323a3bd7f05Smrg        if (late2P != NULL)
324a3bd7f05Smrg            for (; late2P->keysym != NoSymbol; j++)
325a3bd7f05Smrg                late2P++;
326a3bd7f05Smrg        if (i != j)
327a3bd7f05Smrg            return FALSE;
328a3bd7f05Smrg        late1P--;
329a3bd7f05Smrg        while (late1P >= lateBind1P) {
330a3bd7f05Smrg            Boolean last = True;
331a3bd7f05Smrg
332a3bd7f05Smrg            for (late2P = lateBind2P + i - 1; late2P >= lateBind2P; late2P--) {
333a3bd7f05Smrg                if (late1P->keysym == late2P->keysym
334a3bd7f05Smrg                    && late1P->knot == late2P->knot) {
335a3bd7f05Smrg                    j--;
336a3bd7f05Smrg                    if (last)
337a3bd7f05Smrg                        i--;
338a3bd7f05Smrg                    break;
339a3bd7f05Smrg                }
340a3bd7f05Smrg                last = False;
341a3bd7f05Smrg            }
342a3bd7f05Smrg            late1P--;
343a3bd7f05Smrg        }
344a3bd7f05Smrg        if (j != 0)
345a3bd7f05Smrg            return FALSE;
346444c061aSmrg    }
347444c061aSmrg    return TRUE;
348444c061aSmrg}
349444c061aSmrg
350a3bd7f05SmrgTMShortCard
351a3bd7f05Smrg_XtGetModifierIndex(Event *event)
352444c061aSmrg{
353a3bd7f05Smrg    TMShortCard i, j = TM_MOD_SEGMENT_SIZE;
354a3bd7f05Smrg    TMShortCard modIndex = 0;
355a3bd7f05Smrg    TMModifierMatch modMatch;
356a3bd7f05Smrg    TMModifierMatch segment = NULL;
357444c061aSmrg
358444c061aSmrg    LOCK_PROCESS;
359444c061aSmrg    for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) {
360a3bd7f05Smrg        segment = _XtGlobalTM.modMatchSegmentTbl[i];
361a3bd7f05Smrg        for (j = 0;
362a3bd7f05Smrg             modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE;
363a3bd7f05Smrg             j++, modIndex++) {
364a3bd7f05Smrg            modMatch = &(segment[j]);
365a3bd7f05Smrg            if (event->modifiers == modMatch->modifiers &&
366a3bd7f05Smrg                event->modifierMask == modMatch->modifierMask &&
367a3bd7f05Smrg                event->standard == modMatch->standard &&
368a3bd7f05Smrg                ((!event->lateModifiers && !modMatch->lateModifiers) ||
369a3bd7f05Smrg                 CompareLateModifiers(event->lateModifiers,
370a3bd7f05Smrg                                      modMatch->lateModifiers))) {
371a3bd7f05Smrg                /*
372a3bd7f05Smrg                 * if we found a match then we can free the parser's
373a3bd7f05Smrg                 * late modifiers. If there isn't a match we use the
374a3bd7f05Smrg                 * parser's copy
375a3bd7f05Smrg                 */
376a3bd7f05Smrg                if (event->lateModifiers &&
377a3bd7f05Smrg                    --event->lateModifiers->ref_count == 0) {
378a3bd7f05Smrg                    XtFree((char *) event->lateModifiers);
379a3bd7f05Smrg                    event->lateModifiers = NULL;
380a3bd7f05Smrg                }
381a3bd7f05Smrg                UNLOCK_PROCESS;
382a3bd7f05Smrg                return modIndex;
383a3bd7f05Smrg            }
384a3bd7f05Smrg        }
385444c061aSmrg    }
386444c061aSmrg
387444c061aSmrg    if (j == TM_MOD_SEGMENT_SIZE) {
388a3bd7f05Smrg        if (_XtGlobalTM.numModMatchSegments ==
389a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize) {
390a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTblSize =
391a3bd7f05Smrg                (TMShortCard) (_XtGlobalTM.modMatchSegmentTblSize + 4);
392a3bd7f05Smrg            _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *)
393a3bd7f05Smrg                XtRealloc((char *) _XtGlobalTM.modMatchSegmentTbl,
394a3bd7f05Smrg                          (Cardinal) (_XtGlobalTM.modMatchSegmentTblSize *
395a3bd7f05Smrg                                      sizeof(TMModifierMatch)));
396a3bd7f05Smrg        }
397a3bd7f05Smrg        _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] =
398a3bd7f05Smrg            segment = (TMModifierMatch)
399a3bd7f05Smrg            __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec));
400a3bd7f05Smrg        j = 0;
401444c061aSmrg    }
402444c061aSmrg    modMatch = &segment[j];
4030568f49bSmrg    modMatch->modifiers = event->modifiers;
404444c061aSmrg    modMatch->modifierMask = event->modifierMask;
405444c061aSmrg    modMatch->standard = event->standard;
406444c061aSmrg    /*
407444c061aSmrg     * We use the parser's copy of the late binding array
408444c061aSmrg     */
409444c061aSmrg#ifdef TRACE_TM
410444c061aSmrg    if (event->lateModifiers)
411a3bd7f05Smrg        _XtGlobalTM.numLateBindings++;
412a3bd7f05Smrg#endif                          /* TRACE_TM */
413444c061aSmrg    modMatch->lateModifiers = event->lateModifiers;
414444c061aSmrg    _XtGlobalTM.numModMatches++;
415444c061aSmrg    UNLOCK_PROCESS;
416444c061aSmrg    return modIndex;
417444c061aSmrg}
418444c061aSmrg
419444c061aSmrg/*
420444c061aSmrg * This is called from the SimpleStateHandler to match a stateTree
421444c061aSmrg * entry to the event coming in
422444c061aSmrg */
423a3bd7f05Smrgstatic int
424a3bd7f05SmrgMatchBranchHead(TMSimpleStateTree stateTree, int startIndex, TMEventPtr event)
425444c061aSmrg{
426444c061aSmrg    TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex];
427444c061aSmrg    int i;
428444c061aSmrg
429444c061aSmrg    LOCK_PROCESS;
430a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
431a3bd7f05Smrg        TMTypeMatch typeMatch;
432a3bd7f05Smrg        TMModifierMatch modMatch;
433a3bd7f05Smrg
434a3bd7f05Smrg        typeMatch = TMGetTypeMatch(branchHead->typeIndex);
435a3bd7f05Smrg        modMatch = TMGetModifierMatch(branchHead->modIndex);
436a3bd7f05Smrg
437a3bd7f05Smrg        if (MatchIncomingEvent(event, typeMatch, modMatch)) {
438a3bd7f05Smrg            UNLOCK_PROCESS;
439a3bd7f05Smrg            return i;
440a3bd7f05Smrg        }
441a3bd7f05Smrg    }
442444c061aSmrg    UNLOCK_PROCESS;
443444c061aSmrg    return (TM_NO_MATCH);
444444c061aSmrg}
445444c061aSmrg
446a3bd7f05SmrgBoolean
447a3bd7f05Smrg_XtRegularMatch(TMTypeMatch typeMatch,
448a3bd7f05Smrg                TMModifierMatch modMatch,
449a3bd7f05Smrg                TMEventPtr eventSeq)
450444c061aSmrg{
451a3bd7f05Smrg    Modifiers computed = 0;
452a3bd7f05Smrg    Modifiers computedMask = 0;
453444c061aSmrg    Boolean resolved = TRUE;
454a3bd7f05Smrg
455444c061aSmrg    if (typeMatch->eventCode != (eventSeq->event.eventCode &
456a3bd7f05Smrg                                 typeMatch->eventCodeMask))
457a3bd7f05Smrg        return FALSE;
458444c061aSmrg    if (modMatch->lateModifiers != NULL)
459a3bd7f05Smrg        resolved = _XtComputeLateBindings(eventSeq->xev->xany.display,
460a3bd7f05Smrg                                          modMatch->lateModifiers,
461a3bd7f05Smrg                                          &computed, &computedMask);
462a3bd7f05Smrg    if (!resolved)
463a3bd7f05Smrg        return FALSE;
4640568f49bSmrg    computed = (Modifiers) (computed | modMatch->modifiers);
4650568f49bSmrg    computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
466444c061aSmrg
467a3bd7f05Smrg    return ((computed & computedMask) ==
468a3bd7f05Smrg            (eventSeq->event.modifiers & computedMask));
469444c061aSmrg}
470444c061aSmrg
471a3bd7f05SmrgBoolean
472a3bd7f05Smrg_XtMatchAtom(TMTypeMatch typeMatch,
473a3bd7f05Smrg             TMModifierMatch modMatch _X_UNUSED,
474a3bd7f05Smrg             TMEventPtr eventSeq)
475444c061aSmrg{
476a3bd7f05Smrg    Atom atom;
477444c061aSmrg
478444c061aSmrg    atom = XInternAtom(eventSeq->xev->xany.display,
479a3bd7f05Smrg                       XrmQuarkToString((XrmQuark) (typeMatch->eventCode)),
480a3bd7f05Smrg                       False);
481444c061aSmrg    return (atom == eventSeq->event.eventCode);
482444c061aSmrg}
483444c061aSmrg
484444c061aSmrg#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7)))
485444c061aSmrg
486444c061aSmrg/*
487444c061aSmrg * there are certain cases where you want to ignore the event and stay
488444c061aSmrg * in the same state.
489444c061aSmrg */
490a3bd7f05Smrgstatic Boolean
491a3bd7f05SmrgIgnore(TMEventPtr event)
492444c061aSmrg{
493444c061aSmrg    Display *dpy;
494444c061aSmrg    XtPerDisplay pd;
495444c061aSmrg
496444c061aSmrg    if (event->event.eventType == MotionNotify)
497a3bd7f05Smrg        return TRUE;
498444c061aSmrg    if (!(event->event.eventType == KeyPress ||
499a3bd7f05Smrg          event->event.eventType == KeyRelease))
500a3bd7f05Smrg        return FALSE;
501444c061aSmrg    dpy = event->xev->xany.display;
502a3bd7f05Smrg
503444c061aSmrg    pd = _XtGetPerDisplay(dpy);
504444c061aSmrg    _InitializeKeysymTables(dpy, pd);
505444c061aSmrg    return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE;
506444c061aSmrg}
507444c061aSmrg
508a3bd7f05Smrgstatic void
509a3bd7f05SmrgXEventToTMEvent(XEvent *event, TMEventPtr tmEvent)
510444c061aSmrg{
511444c061aSmrg    tmEvent->xev = event;
512444c061aSmrg    tmEvent->event.eventCodeMask = 0;
513444c061aSmrg    tmEvent->event.modifierMask = 0;
5140568f49bSmrg    tmEvent->event.eventType = (TMLongCard) event->type;
515444c061aSmrg    tmEvent->event.lateModifiers = NULL;
516444c061aSmrg    tmEvent->event.matchEvent = NULL;
517444c061aSmrg    tmEvent->event.standard = FALSE;
518444c061aSmrg
519444c061aSmrg    switch (event->type) {
520444c061aSmrg
521a3bd7f05Smrg    case KeyPress:
522a3bd7f05Smrg    case KeyRelease:
523a3bd7f05Smrg        tmEvent->event.eventCode = event->xkey.keycode;
524a3bd7f05Smrg        tmEvent->event.modifiers = event->xkey.state;
525a3bd7f05Smrg        break;
526a3bd7f05Smrg
527a3bd7f05Smrg    case ButtonPress:
528a3bd7f05Smrg    case ButtonRelease:
529a3bd7f05Smrg        tmEvent->event.eventCode = event->xbutton.button;
530a3bd7f05Smrg        tmEvent->event.modifiers = event->xbutton.state;
531a3bd7f05Smrg        break;
532a3bd7f05Smrg
533a3bd7f05Smrg    case MotionNotify:
534a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmotion.is_hint;
535a3bd7f05Smrg        tmEvent->event.modifiers = event->xmotion.state;
536a3bd7f05Smrg        break;
537a3bd7f05Smrg
538a3bd7f05Smrg    case EnterNotify:
539a3bd7f05Smrg    case LeaveNotify:
540a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xcrossing.mode;
541a3bd7f05Smrg        tmEvent->event.modifiers = event->xcrossing.state;
542a3bd7f05Smrg        break;
543a3bd7f05Smrg
544a3bd7f05Smrg    case PropertyNotify:
545a3bd7f05Smrg        tmEvent->event.eventCode = event->xproperty.atom;
546a3bd7f05Smrg        tmEvent->event.modifiers = 0;
547a3bd7f05Smrg        break;
548a3bd7f05Smrg
549a3bd7f05Smrg    case SelectionClear:
550a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionclear.selection;
551a3bd7f05Smrg        tmEvent->event.modifiers = 0;
552a3bd7f05Smrg        break;
553a3bd7f05Smrg
554a3bd7f05Smrg    case SelectionRequest:
555a3bd7f05Smrg        tmEvent->event.eventCode = event->xselectionrequest.selection;
556a3bd7f05Smrg        tmEvent->event.modifiers = 0;
557a3bd7f05Smrg        break;
558a3bd7f05Smrg
559a3bd7f05Smrg    case SelectionNotify:
560a3bd7f05Smrg        tmEvent->event.eventCode = event->xselection.selection;
561a3bd7f05Smrg        tmEvent->event.modifiers = 0;
562a3bd7f05Smrg        break;
563a3bd7f05Smrg
564a3bd7f05Smrg    case ClientMessage:
565a3bd7f05Smrg        tmEvent->event.eventCode = event->xclient.message_type;
566a3bd7f05Smrg        tmEvent->event.modifiers = 0;
567a3bd7f05Smrg        break;
568a3bd7f05Smrg
569a3bd7f05Smrg    case MappingNotify:
570a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xmapping.request;
571a3bd7f05Smrg        tmEvent->event.modifiers = 0;
572a3bd7f05Smrg        break;
573a3bd7f05Smrg
574a3bd7f05Smrg    case FocusIn:
575a3bd7f05Smrg    case FocusOut:
576a3bd7f05Smrg        tmEvent->event.eventCode = (TMLongCard) event->xfocus.mode;
577a3bd7f05Smrg        tmEvent->event.modifiers = 0;
578a3bd7f05Smrg        break;
579a3bd7f05Smrg
580a3bd7f05Smrg    default:
581a3bd7f05Smrg        tmEvent->event.eventCode = 0;
582a3bd7f05Smrg        tmEvent->event.modifiers = 0;
583a3bd7f05Smrg        break;
584444c061aSmrg    }
585444c061aSmrg}
586444c061aSmrg
587a3bd7f05Smrgstatic unsigned long
588a3bd7f05SmrgGetTime(XtTM tm, XEvent *event)
589444c061aSmrg{
590444c061aSmrg    switch (event->type) {
591444c061aSmrg
592a3bd7f05Smrg    case KeyPress:
593a3bd7f05Smrg    case KeyRelease:
594a3bd7f05Smrg        return event->xkey.time;
595444c061aSmrg
596a3bd7f05Smrg    case ButtonPress:
597a3bd7f05Smrg    case ButtonRelease:
598a3bd7f05Smrg        return event->xbutton.time;
599444c061aSmrg
600a3bd7f05Smrg    default:
601a3bd7f05Smrg        return tm->lastEventTime;
602444c061aSmrg
603444c061aSmrg    }
604444c061aSmrg
605444c061aSmrg}
606444c061aSmrg
607a3bd7f05Smrgstatic void
608a3bd7f05SmrgHandleActions(Widget w,
609a3bd7f05Smrg              XEvent *event,
610a3bd7f05Smrg              TMSimpleStateTree stateTree,
611a3bd7f05Smrg              Widget accelWidget,
612a3bd7f05Smrg              XtActionProc *procs,
613a3bd7f05Smrg              ActionRec *actions)
614444c061aSmrg{
615a3bd7f05Smrg    ActionHook actionHookList;
616a3bd7f05Smrg    Widget bindWidget;
617444c061aSmrg
618444c061aSmrg    bindWidget = accelWidget ? accelWidget : w;
619444c061aSmrg    if (accelWidget && !XtIsSensitive(accelWidget) &&
620a3bd7f05Smrg        (event->type == KeyPress || event->type == KeyRelease ||
621a3bd7f05Smrg         event->type == ButtonPress || event->type == ButtonRelease ||
622a3bd7f05Smrg         event->type == MotionNotify || event->type == EnterNotify ||
623a3bd7f05Smrg         event->type == LeaveNotify || event->type == FocusIn ||
624a3bd7f05Smrg         event->type == FocusOut))
625a3bd7f05Smrg        return;
626444c061aSmrg
627444c061aSmrg    actionHookList = XtWidgetToApplicationContext(w)->action_hook_list;
628444c061aSmrg
629444c061aSmrg    while (actions != NULL) {
630a3bd7f05Smrg        /* perform any actions */
631a3bd7f05Smrg        if (procs[actions->idx] != NULL) {
632a3bd7f05Smrg            if (actionHookList) {
633a3bd7f05Smrg                ActionHook hook;
634a3bd7f05Smrg                ActionHook next_hook;
635a3bd7f05Smrg                String procName =
636a3bd7f05Smrg                    XrmQuarkToString(stateTree->quarkTbl[actions->idx]);
637a3bd7f05Smrg
638a3bd7f05Smrg                for (hook = actionHookList; hook != NULL;) {
639a3bd7f05Smrg                    /*
640a3bd7f05Smrg                     * Need to cache hook->next because the following action
641a3bd7f05Smrg                     * proc may free hook via XtRemoveActionHook making
642a3bd7f05Smrg                     * hook->next invalid upon return from the action proc.
643a3bd7f05Smrg                     */
644a3bd7f05Smrg                    next_hook = hook->next;
645a3bd7f05Smrg                    (*hook->proc) (bindWidget,
646a3bd7f05Smrg                                   hook->closure,
647a3bd7f05Smrg                                   procName,
648a3bd7f05Smrg                                   event,
649a3bd7f05Smrg                                   actions->params, &actions->num_params);
650a3bd7f05Smrg                    hook = next_hook;
651a3bd7f05Smrg                }
652a3bd7f05Smrg            }
653a3bd7f05Smrg            (*(procs[actions->idx]))
654a3bd7f05Smrg                (bindWidget, event, actions->params, &actions->num_params);
655a3bd7f05Smrg        }
656a3bd7f05Smrg        actions = actions->next;
657444c061aSmrg    }
658444c061aSmrg}
659444c061aSmrg
660444c061aSmrgtypedef struct {
661444c061aSmrg    unsigned int isCycleStart:1;
662444c061aSmrg    unsigned int isCycleEnd:1;
663444c061aSmrg    TMShortCard typeIndex;
664444c061aSmrg    TMShortCard modIndex;
665a3bd7f05Smrg} MatchPairRec, *MatchPair;
666444c061aSmrg
667a3bd7f05Smrgtypedef struct TMContextRec {
668a3bd7f05Smrg    TMShortCard numMatches;
669a3bd7f05Smrg    TMShortCard maxMatches;
670a3bd7f05Smrg    MatchPair matches;
671a3bd7f05Smrg} TMContextRec, *TMContext;
672444c061aSmrg
673a3bd7f05Smrgstatic TMContextRec contextCache[2];
674444c061aSmrg
675444c061aSmrg#define GetContextPtr(tm) ((TMContext *)&(tm->current_state))
676444c061aSmrg
677444c061aSmrg#define TM_CONTEXT_MATCHES_ALLOC 4
678444c061aSmrg#define TM_CONTEXT_MATCHES_REALLOC 2
679444c061aSmrg
680a3bd7f05Smrgstatic void
681a3bd7f05SmrgPushContext(TMContext *contextPtr, StatePtr newState)
682444c061aSmrg{
683a3bd7f05Smrg    TMContext context = *contextPtr;
684444c061aSmrg
685444c061aSmrg    LOCK_PROCESS;
686a3bd7f05Smrg    if (context == NULL) {
687a3bd7f05Smrg        if (contextCache[0].numMatches == 0)
688a3bd7f05Smrg            context = &contextCache[0];
689a3bd7f05Smrg        else if (contextCache[1].numMatches == 0)
690a3bd7f05Smrg            context = &contextCache[1];
691a3bd7f05Smrg        if (!context) {
692a3bd7f05Smrg            context = XtNew(TMContextRec);
693a3bd7f05Smrg            context->matches = NULL;
694a3bd7f05Smrg            context->numMatches = context->maxMatches = 0;
695a3bd7f05Smrg        }
696a3bd7f05Smrg    }
697444c061aSmrg    if (context->numMatches &&
698a3bd7f05Smrg        context->matches[context->numMatches - 1].isCycleEnd) {
699a3bd7f05Smrg        TMShortCard i;
700a3bd7f05Smrg
701a3bd7f05Smrg        for (i = 0;
702a3bd7f05Smrg             i < context->numMatches &&
703a3bd7f05Smrg             !(context->matches[i].isCycleStart); i++) {
704a3bd7f05Smrg        };
705a3bd7f05Smrg        if (i < context->numMatches)
706a3bd7f05Smrg            context->numMatches = (TMShortCard) (i + 1);
707444c061aSmrg#ifdef DEBUG
708a3bd7f05Smrg        else
709a3bd7f05Smrg            XtWarning("pushing cycle end with no cycle start");
710a3bd7f05Smrg#endif                          /* DEBUG */
711a3bd7f05Smrg    }
712a3bd7f05Smrg    else {
713a3bd7f05Smrg        if (context->numMatches == context->maxMatches) {
714a3bd7f05Smrg            if (context->maxMatches == 0)
715a3bd7f05Smrg                context->maxMatches =
716a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
717a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_ALLOC);
718a3bd7f05Smrg            else
719a3bd7f05Smrg                context->maxMatches =
720a3bd7f05Smrg                    (TMShortCard) (context->maxMatches +
721a3bd7f05Smrg                                   TM_CONTEXT_MATCHES_REALLOC);
722a3bd7f05Smrg            context->matches = (MatchPairRec *)
723a3bd7f05Smrg                XtRealloc((char *) context->matches,
724a3bd7f05Smrg                          (Cardinal) (context->maxMatches *
725a3bd7f05Smrg                                      sizeof(MatchPairRec)));
726a3bd7f05Smrg        }
727a3bd7f05Smrg        context->matches[context->numMatches].isCycleStart =
728a3bd7f05Smrg            newState->isCycleStart;
729a3bd7f05Smrg        context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd;
730a3bd7f05Smrg        context->matches[context->numMatches].typeIndex = newState->typeIndex;
731a3bd7f05Smrg        context->matches[context->numMatches++].modIndex = newState->modIndex;
732a3bd7f05Smrg        *contextPtr = context;
733a3bd7f05Smrg    }
734a3bd7f05Smrg    UNLOCK_PROCESS;
735444c061aSmrg}
736444c061aSmrg
737a3bd7f05Smrgstatic void
738a3bd7f05SmrgFreeContext(TMContext *contextPtr)
739444c061aSmrg{
740a3bd7f05Smrg    TMContext context = NULL;
741444c061aSmrg
742444c061aSmrg    LOCK_PROCESS;
743444c061aSmrg
744444c061aSmrg    if (&contextCache[0] == *contextPtr)
745a3bd7f05Smrg        context = &contextCache[0];
746444c061aSmrg    else if (&contextCache[1] == *contextPtr)
747a3bd7f05Smrg        context = &contextCache[1];
748444c061aSmrg
749444c061aSmrg    if (context)
750a3bd7f05Smrg        context->numMatches = 0;
751a3bd7f05Smrg    else if (*contextPtr) {
752a3bd7f05Smrg        XtFree((char *) ((*contextPtr)->matches));
753a3bd7f05Smrg        XtFree((char *) *contextPtr);
754444c061aSmrg    }
755444c061aSmrg
756444c061aSmrg    *contextPtr = NULL;
757444c061aSmrg    UNLOCK_PROCESS;
758444c061aSmrg}
759444c061aSmrg
760a3bd7f05Smrgstatic int
761a3bd7f05SmrgMatchExact(TMSimpleStateTree stateTree,
762a3bd7f05Smrg           int startIndex,
763a3bd7f05Smrg           TMShortCard typeIndex,
764a3bd7f05Smrg           TMShortCard modIndex)
765444c061aSmrg{
766444c061aSmrg    TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]);
767444c061aSmrg    int i;
768444c061aSmrg
769a3bd7f05Smrg    for (i = startIndex; i < (int) stateTree->numBranchHeads; i++, branchHead++) {
770a3bd7f05Smrg        if ((branchHead->typeIndex == typeIndex) &&
771a3bd7f05Smrg            (branchHead->modIndex == modIndex))
772a3bd7f05Smrg            return i;
773a3bd7f05Smrg    }
774444c061aSmrg    return (TM_NO_MATCH);
775444c061aSmrg}
776444c061aSmrg
777a3bd7f05Smrgstatic void
778a3bd7f05SmrgHandleSimpleState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
779444c061aSmrg{
780a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
781a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
782a3bd7f05Smrg    TMShortCard i;
783a3bd7f05Smrg    ActionRec *actions = NULL;
784a3bd7f05Smrg    Boolean matchExact = False;
785a3bd7f05Smrg    Boolean match = False;
786a3bd7f05Smrg    StatePtr complexMatchState = NULL;
787a3bd7f05Smrg    TMShortCard typeIndex = 0, modIndex = 0;
788a3bd7f05Smrg    int matchTreeIndex = TM_NO_MATCH;
789444c061aSmrg
790444c061aSmrg    LOCK_PROCESS;
791444c061aSmrg    for (i = 0;
792a3bd7f05Smrg         ((!match || !complexMatchState) && (i < xlations->numStateTrees));
793a3bd7f05Smrg         i++) {
794a3bd7f05Smrg        int currIndex = -1;
795a3bd7f05Smrg        TMSimpleStateTree stateTree =
796a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
797a3bd7f05Smrg
798a3bd7f05Smrg        /*
799a3bd7f05Smrg         * don't process this tree if we're only looking for a
800a3bd7f05Smrg         * complexMatchState and there are no complex states
801a3bd7f05Smrg         */
802a3bd7f05Smrg        while (!(match && stateTree->isSimple) &&
803a3bd7f05Smrg               ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) {
804a3bd7f05Smrg            currIndex++;
805a3bd7f05Smrg            if (matchExact)
806a3bd7f05Smrg                currIndex =
807a3bd7f05Smrg                    MatchExact(stateTree, currIndex, typeIndex, modIndex);
808a3bd7f05Smrg            else
809a3bd7f05Smrg                currIndex = MatchBranchHead(stateTree, currIndex, curEventPtr);
810a3bd7f05Smrg            if (currIndex != TM_NO_MATCH) {
811a3bd7f05Smrg                TMBranchHead branchHead;
812a3bd7f05Smrg                StatePtr currState;
813a3bd7f05Smrg
814a3bd7f05Smrg                branchHead = &stateTree->branchHeadTbl[currIndex];
815a3bd7f05Smrg                if (branchHead->isSimple)
816a3bd7f05Smrg                    currState = NULL;
817a3bd7f05Smrg                else
818a3bd7f05Smrg                    currState = ((TMComplexStateTree) stateTree)
819a3bd7f05Smrg                        ->complexBranchHeadTbl[TMBranchMore(branchHead)];
820a3bd7f05Smrg
821a3bd7f05Smrg                /*
822a3bd7f05Smrg                 * first check for a complete match
823a3bd7f05Smrg                 */
824a3bd7f05Smrg                if (!match) {
825a3bd7f05Smrg                    if (branchHead->hasActions) {
826a3bd7f05Smrg                        if (branchHead->isSimple) {
827a3bd7f05Smrg                            static ActionRec dummyAction;
828a3bd7f05Smrg
829a3bd7f05Smrg                            dummyAction.idx = TMBranchMore(branchHead);
830a3bd7f05Smrg                            actions = &dummyAction;
831a3bd7f05Smrg                        }
832a3bd7f05Smrg                        else
833a3bd7f05Smrg                            actions = currState->actions;
834a3bd7f05Smrg                        tmRecPtr->lastEventTime =
835a3bd7f05Smrg                            GetTime(tmRecPtr, curEventPtr->xev);
836a3bd7f05Smrg                        FreeContext((TMContext *) &tmRecPtr->current_state);
837a3bd7f05Smrg                        match = True;
838a3bd7f05Smrg                        matchTreeIndex = i;
839a3bd7f05Smrg                    }
840a3bd7f05Smrg                    /*
841a3bd7f05Smrg                     * if it doesn't have actions and
842a3bd7f05Smrg                     * it's bc mode then it's a potential match node that is
843a3bd7f05Smrg                     * used to match later sequences.
844a3bd7f05Smrg                     */
845a3bd7f05Smrg                    if (!TMNewMatchSemantics() && !matchExact) {
846a3bd7f05Smrg                        matchExact = True;
847a3bd7f05Smrg                        typeIndex = branchHead->typeIndex;
848a3bd7f05Smrg                        modIndex = branchHead->modIndex;
849a3bd7f05Smrg                    }
850a3bd7f05Smrg                }
851a3bd7f05Smrg                /*
852a3bd7f05Smrg                 * check for it being an event sequence which can be
853a3bd7f05Smrg                 * a future match
854a3bd7f05Smrg                 */
855a3bd7f05Smrg                if (!branchHead->isSimple &&
856a3bd7f05Smrg                    !branchHead->hasActions && !complexMatchState)
857a3bd7f05Smrg                    complexMatchState = currState;
858a3bd7f05Smrg            }
859a3bd7f05Smrg        }
860a3bd7f05Smrg    }
861a3bd7f05Smrg    if (match) {
862a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
863a3bd7f05Smrg        XtActionProc *procs;
864a3bd7f05Smrg        Widget accelWidget;
865a3bd7f05Smrg
866a3bd7f05Smrg        if (bindData->simple.isComplex) {
867a3bd7f05Smrg            TMComplexBindProcs bindProcs =
868a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
869a3bd7f05Smrg            procs = bindProcs->procs;
870a3bd7f05Smrg            accelWidget = bindProcs->widget;
871a3bd7f05Smrg        }
872a3bd7f05Smrg        else {
873a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
874a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
875a3bd7f05Smrg            procs = bindProcs->procs;
876a3bd7f05Smrg            accelWidget = NULL;
877a3bd7f05Smrg        }
878a3bd7f05Smrg        HandleActions
879a3bd7f05Smrg            (w,
880a3bd7f05Smrg             curEventPtr->xev,
881a3bd7f05Smrg             (TMSimpleStateTree) xlations->stateTreeTbl[matchTreeIndex],
882a3bd7f05Smrg             accelWidget, procs, actions);
883a3bd7f05Smrg    }
884444c061aSmrg    if (complexMatchState)
885a3bd7f05Smrg        PushContext(contextPtr, complexMatchState);
886444c061aSmrg    UNLOCK_PROCESS;
887444c061aSmrg}
888444c061aSmrg
889a3bd7f05Smrgstatic int
890a3bd7f05SmrgMatchComplexBranch(TMComplexStateTree stateTree,
891a3bd7f05Smrg                   int startIndex,
892a3bd7f05Smrg                   TMContext context,
893a3bd7f05Smrg                   StatePtr *leafStateRtn)
894444c061aSmrg{
895a3bd7f05Smrg    TMShortCard i;
896444c061aSmrg
897444c061aSmrg    LOCK_PROCESS;
898a3bd7f05Smrg    for (i = (TMShortCard) startIndex; i < stateTree->numComplexBranchHeads;
899a3bd7f05Smrg         i++) {
900a3bd7f05Smrg        StatePtr candState;
901a3bd7f05Smrg        TMShortCard numMatches = context->numMatches;
902a3bd7f05Smrg        MatchPair statMatch = context->matches;
903a3bd7f05Smrg
904a3bd7f05Smrg        for (candState = stateTree->complexBranchHeadTbl[i];
905a3bd7f05Smrg             numMatches && candState;
906a3bd7f05Smrg             numMatches--, statMatch++, candState = candState->nextLevel) {
907a3bd7f05Smrg            if ((statMatch->typeIndex != candState->typeIndex) ||
908a3bd7f05Smrg                (statMatch->modIndex != candState->modIndex))
909a3bd7f05Smrg                break;
910a3bd7f05Smrg        }
911a3bd7f05Smrg        if (numMatches == 0) {
912a3bd7f05Smrg            *leafStateRtn = candState;
913a3bd7f05Smrg            UNLOCK_PROCESS;
914a3bd7f05Smrg            return i;
915a3bd7f05Smrg        }
916a3bd7f05Smrg    }
917444c061aSmrg    *leafStateRtn = NULL;
918444c061aSmrg    UNLOCK_PROCESS;
919444c061aSmrg    return (TM_NO_MATCH);
920444c061aSmrg}
921444c061aSmrg
922a3bd7f05Smrgstatic StatePtr
923a3bd7f05SmrgTryCurrentTree(TMComplexStateTree *stateTreePtr,
924a3bd7f05Smrg               XtTM tmRecPtr,
925a3bd7f05Smrg               TMEventRec *curEventPtr)
926444c061aSmrg{
927a3bd7f05Smrg    StatePtr candState = NULL, matchState = NULL;
928a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
929a3bd7f05Smrg    TMTypeMatch typeMatch;
930a3bd7f05Smrg    TMModifierMatch modMatch;
931a3bd7f05Smrg    int currIndex = -1;
932444c061aSmrg
933444c061aSmrg    /*
934444c061aSmrg     * we want the first sequence that both matches and has actions.
935444c061aSmrg     * we keep on looking till we find both
936444c061aSmrg     */
937444c061aSmrg    LOCK_PROCESS;
938444c061aSmrg    while ((currIndex =
939a3bd7f05Smrg            MatchComplexBranch(*stateTreePtr,
940a3bd7f05Smrg                               ++currIndex, (*contextPtr), &candState))
941a3bd7f05Smrg           != TM_NO_MATCH) {
942a3bd7f05Smrg        if (candState != NULL) {
943a3bd7f05Smrg            typeMatch = TMGetTypeMatch(candState->typeIndex);
944a3bd7f05Smrg            modMatch = TMGetModifierMatch(candState->modIndex);
945a3bd7f05Smrg
946a3bd7f05Smrg            /* does this state's index match? --> done */
947a3bd7f05Smrg            if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) {
948a3bd7f05Smrg                if (candState->actions) {
949a3bd7f05Smrg                    UNLOCK_PROCESS;
950a3bd7f05Smrg                    return candState;
951a3bd7f05Smrg                }
952a3bd7f05Smrg                else
953a3bd7f05Smrg                    matchState = candState;
954a3bd7f05Smrg            }
955a3bd7f05Smrg            /* is this an event timer? */
956a3bd7f05Smrg            if (typeMatch->eventType == _XtEventTimerEventType) {
957a3bd7f05Smrg                StatePtr nextState = candState->nextLevel;
958a3bd7f05Smrg
959a3bd7f05Smrg                /* does the succeeding state match? */
960a3bd7f05Smrg                if (nextState != NULL) {
961a3bd7f05Smrg                    TMTypeMatch nextTypeMatch;
962a3bd7f05Smrg                    TMModifierMatch nextModMatch;
963a3bd7f05Smrg
964a3bd7f05Smrg                    nextTypeMatch = TMGetTypeMatch(nextState->typeIndex);
965a3bd7f05Smrg                    nextModMatch = TMGetModifierMatch(nextState->modIndex);
966a3bd7f05Smrg
967a3bd7f05Smrg                    /* is it within the timeout? */
968a3bd7f05Smrg                    if (MatchIncomingEvent(curEventPtr,
969a3bd7f05Smrg                                           nextTypeMatch, nextModMatch)) {
970a3bd7f05Smrg                        XEvent *xev = curEventPtr->xev;
971a3bd7f05Smrg                        unsigned long time = GetTime(tmRecPtr, xev);
972a3bd7f05Smrg                        XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display);
973a3bd7f05Smrg                        unsigned long delta =
974a3bd7f05Smrg                            (unsigned long) pd->multi_click_time;
975a3bd7f05Smrg
976a3bd7f05Smrg                        if ((tmRecPtr->lastEventTime + delta) >= time) {
977a3bd7f05Smrg                            if (nextState->actions) {
978a3bd7f05Smrg                                UNLOCK_PROCESS;
979a3bd7f05Smrg                                return candState;
980a3bd7f05Smrg                            }
981a3bd7f05Smrg                            else
982a3bd7f05Smrg                                matchState = candState;
983a3bd7f05Smrg                        }
984a3bd7f05Smrg                    }
985a3bd7f05Smrg                }
986a3bd7f05Smrg            }
987a3bd7f05Smrg        }
988444c061aSmrg    }
989444c061aSmrg    UNLOCK_PROCESS;
990444c061aSmrg    return matchState;
991444c061aSmrg}
992444c061aSmrg
993a3bd7f05Smrgstatic void
994a3bd7f05SmrgHandleComplexState(Widget w, XtTM tmRecPtr, TMEventRec *curEventPtr)
995444c061aSmrg{
996a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
997a3bd7f05Smrg    TMContext *contextPtr = GetContextPtr(tmRecPtr);
998a3bd7f05Smrg    TMShortCard i, matchTreeIndex = 0;
999a3bd7f05Smrg    StatePtr matchState = NULL, candState;
1000a3bd7f05Smrg    TMComplexStateTree *stateTreePtr =
1001a3bd7f05Smrg        (TMComplexStateTree *) &xlations->stateTreeTbl[0];
1002444c061aSmrg
1003444c061aSmrg    LOCK_PROCESS;
1004a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) {
1005a3bd7f05Smrg        /*
1006a3bd7f05Smrg         * some compilers sign extend Boolean bit fields so test for
1007a3bd7f05Smrg         * false |||
1008a3bd7f05Smrg         */
1009a3bd7f05Smrg        if (((*stateTreePtr)->isSimple == False) &&
1010a3bd7f05Smrg            (candState = TryCurrentTree(stateTreePtr, tmRecPtr, curEventPtr))) {
1011a3bd7f05Smrg            if (!matchState || candState->actions) {
1012a3bd7f05Smrg                matchTreeIndex = i;
1013a3bd7f05Smrg                matchState = candState;
1014a3bd7f05Smrg                if (candState->actions)
1015a3bd7f05Smrg                    break;
1016a3bd7f05Smrg            }
1017a3bd7f05Smrg        }
1018a3bd7f05Smrg    }
1019a3bd7f05Smrg    if (matchState == NULL) {
1020a3bd7f05Smrg        /* couldn't find it... */
1021a3bd7f05Smrg        if (!Ignore(curEventPtr)) {
1022a3bd7f05Smrg            FreeContext(contextPtr);
1023a3bd7f05Smrg            HandleSimpleState(w, tmRecPtr, curEventPtr);
1024a3bd7f05Smrg        }
1025444c061aSmrg    }
1026444c061aSmrg    else {
1027a3bd7f05Smrg        TMBindData bindData = (TMBindData) tmRecPtr->proc_table;
1028a3bd7f05Smrg        XtActionProc *procs;
1029a3bd7f05Smrg        Widget accelWidget;
1030a3bd7f05Smrg        TMTypeMatch typeMatch;
1031a3bd7f05Smrg
1032a3bd7f05Smrg        typeMatch = TMGetTypeMatch(matchState->typeIndex);
1033a3bd7f05Smrg
1034a3bd7f05Smrg        PushContext(contextPtr, matchState);
1035a3bd7f05Smrg        if (typeMatch->eventType == _XtEventTimerEventType) {
1036a3bd7f05Smrg            matchState = matchState->nextLevel;
1037a3bd7f05Smrg            PushContext(contextPtr, matchState);
1038a3bd7f05Smrg        }
1039a3bd7f05Smrg        tmRecPtr->lastEventTime = GetTime(tmRecPtr, curEventPtr->xev);
1040a3bd7f05Smrg
1041a3bd7f05Smrg        if (bindData->simple.isComplex) {
1042a3bd7f05Smrg            TMComplexBindProcs bindProcs =
1043a3bd7f05Smrg                TMGetComplexBindEntry(bindData, matchTreeIndex);
1044a3bd7f05Smrg            procs = bindProcs->procs;
1045a3bd7f05Smrg            accelWidget = bindProcs->widget;
1046a3bd7f05Smrg        }
1047a3bd7f05Smrg        else {
1048a3bd7f05Smrg            TMSimpleBindProcs bindProcs =
1049a3bd7f05Smrg                TMGetSimpleBindEntry(bindData, matchTreeIndex);
1050a3bd7f05Smrg            procs = bindProcs->procs;
1051a3bd7f05Smrg            accelWidget = NULL;
1052a3bd7f05Smrg        }
1053a3bd7f05Smrg        HandleActions(w, curEventPtr->xev, (TMSimpleStateTree)
1054a3bd7f05Smrg                      xlations->stateTreeTbl[matchTreeIndex],
1055a3bd7f05Smrg                      accelWidget, procs, matchState->actions);
1056444c061aSmrg    }
1057444c061aSmrg    UNLOCK_PROCESS;
1058444c061aSmrg}
1059444c061aSmrg
1060a3bd7f05Smrgvoid
1061a3bd7f05Smrg_XtTranslateEvent(Widget w, XEvent *event)
1062444c061aSmrg{
1063a3bd7f05Smrg    XtTM tmRecPtr = &w->core.tm;
1064a3bd7f05Smrg    TMEventRec curEvent;
1065a3bd7f05Smrg    StatePtr current_state = tmRecPtr->current_state;
1066444c061aSmrg
1067a3bd7f05Smrg    XEventToTMEvent(event, &curEvent);
1068444c061aSmrg
1069a3bd7f05Smrg    if (!tmRecPtr->translations) {
1070444c061aSmrg        XtAppWarningMsg(XtWidgetToApplicationContext(w),
1071a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1072a3bd7f05Smrg                        "Can't translate event through NULL table", NULL, NULL);
1073a3bd7f05Smrg        return;
1074444c061aSmrg    }
1075444c061aSmrg    if (current_state == NULL)
1076a3bd7f05Smrg        HandleSimpleState(w, tmRecPtr, &curEvent);
1077444c061aSmrg    else
1078a3bd7f05Smrg        HandleComplexState(w, tmRecPtr, &curEvent);
1079444c061aSmrg}
1080444c061aSmrg
1081a3bd7f05Smrgstatic StatePtr
1082a3bd7f05SmrgNewState(TMParseStateTree stateTree _X_UNUSED,
1083a3bd7f05Smrg         TMShortCard typeIndex,
1084a3bd7f05Smrg         TMShortCard modIndex)
1085444c061aSmrg{
1086444c061aSmrg    StatePtr state = XtNew(StateRec);
1087444c061aSmrg
1088444c061aSmrg#ifdef TRACE_TM
1089444c061aSmrg    LOCK_PROCESS;
1090444c061aSmrg    _XtGlobalTM.numComplexStates++;
1091444c061aSmrg    UNLOCK_PROCESS;
1092a3bd7f05Smrg#endif                          /* TRACE_TM */
1093444c061aSmrg    state->typeIndex = typeIndex;
1094444c061aSmrg    state->modIndex = modIndex;
1095444c061aSmrg    state->nextLevel = NULL;
1096444c061aSmrg    state->actions = NULL;
1097444c061aSmrg    state->isCycleStart = state->isCycleEnd = False;
1098444c061aSmrg    return state;
1099444c061aSmrg}
1100444c061aSmrg
1101444c061aSmrg/*
1102444c061aSmrg * This routine is an iterator for state trees. If the func returns
1103444c061aSmrg * true then iteration is over.
1104444c061aSmrg */
1105a3bd7f05Smrgvoid
1106a3bd7f05Smrg_XtTraverseStateTree(TMStateTree tree, _XtTraversalProc func, XtPointer data)
1107444c061aSmrg{
1108a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
1109a3bd7f05Smrg    TMBranchHead currBH;
1110a3bd7f05Smrg    TMShortCard i;
1111a3bd7f05Smrg    StateRec dummyStateRec, *dummyState = &dummyStateRec;
1112a3bd7f05Smrg    ActionRec dummyActionRec, *dummyAction = &dummyActionRec;
1113a3bd7f05Smrg    Boolean firstSimple = True;
1114a3bd7f05Smrg    StatePtr currState;
1115444c061aSmrg
1116444c061aSmrg    /* first traverse the complex states */
1117444c061aSmrg    if (stateTree->isSimple == False)
1118a3bd7f05Smrg        for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
1119a3bd7f05Smrg            currState = stateTree->complexBranchHeadTbl[i];
1120a3bd7f05Smrg            for (; currState; currState = currState->nextLevel) {
1121a3bd7f05Smrg                if (func(currState, data))
1122a3bd7f05Smrg                    return;
1123a3bd7f05Smrg                if (currState->isCycleEnd)
1124a3bd7f05Smrg                    break;
1125a3bd7f05Smrg            }
1126a3bd7f05Smrg        }
1127444c061aSmrg
1128444c061aSmrg    /* now traverse the simple ones */
1129444c061aSmrg    for (i = 0, currBH = stateTree->branchHeadTbl;
1130a3bd7f05Smrg         i < stateTree->numBranchHeads; i++, currBH++) {
1131a3bd7f05Smrg        if (currBH->isSimple && currBH->hasActions) {
1132a3bd7f05Smrg            if (firstSimple) {
1133a3bd7f05Smrg                XtBZero((char *) dummyState, sizeof(StateRec));
1134a3bd7f05Smrg                XtBZero((char *) dummyAction, sizeof(ActionRec));
1135a3bd7f05Smrg                dummyState->actions = dummyAction;
1136a3bd7f05Smrg                firstSimple = False;
1137a3bd7f05Smrg            }
1138a3bd7f05Smrg            dummyState->typeIndex = currBH->typeIndex;
1139a3bd7f05Smrg            dummyState->modIndex = currBH->modIndex;
1140a3bd7f05Smrg            dummyAction->idx = currBH->more;
1141a3bd7f05Smrg            if (func(dummyState, data))
1142a3bd7f05Smrg                return;
1143a3bd7f05Smrg        }
1144a3bd7f05Smrg    }
1145444c061aSmrg}
1146444c061aSmrg
1147a3bd7f05Smrgstatic EventMask
1148a3bd7f05SmrgEventToMask(TMTypeMatch typeMatch, TMModifierMatch modMatch)
1149444c061aSmrg{
1150444c061aSmrg    EventMask returnMask;
1151444c061aSmrg    unsigned long eventType = typeMatch->eventType;
1152444c061aSmrg
1153444c061aSmrg    if (eventType == MotionNotify) {
11540568f49bSmrg        Modifiers modifierMask = (Modifiers) modMatch->modifierMask;
1155444c061aSmrg        Modifiers tempMask;
1156444c061aSmrg
1157a3bd7f05Smrg        returnMask = 0;
1158444c061aSmrg        if (modifierMask == 0) {
1159a3bd7f05Smrg            if (modMatch->modifiers == AnyButtonMask)
1160a3bd7f05Smrg                return ButtonMotionMask;
1161a3bd7f05Smrg            else
1162a3bd7f05Smrg                return PointerMotionMask;
1163a3bd7f05Smrg        }
1164444c061aSmrg        tempMask = modifierMask &
1165a3bd7f05Smrg            (Button1Mask | Button2Mask | Button3Mask
1166a3bd7f05Smrg             | Button4Mask | Button5Mask);
1167444c061aSmrg        if (tempMask == 0)
1168a3bd7f05Smrg            return PointerMotionMask;
1169444c061aSmrg        if (tempMask & Button1Mask)
1170444c061aSmrg            returnMask |= Button1MotionMask;
1171444c061aSmrg        if (tempMask & Button2Mask)
1172444c061aSmrg            returnMask |= Button2MotionMask;
1173444c061aSmrg        if (tempMask & Button3Mask)
1174444c061aSmrg            returnMask |= Button3MotionMask;
1175444c061aSmrg        if (tempMask & Button4Mask)
1176444c061aSmrg            returnMask |= Button4MotionMask;
1177444c061aSmrg        if (tempMask & Button5Mask)
1178444c061aSmrg            returnMask |= Button5MotionMask;
1179444c061aSmrg        return returnMask;
1180444c061aSmrg    }
1181a3bd7f05Smrg    returnMask = _XtConvertTypeToMask((int) eventType);
1182a3bd7f05Smrg    if (returnMask == (StructureNotifyMask | SubstructureNotifyMask))
1183a3bd7f05Smrg        returnMask = StructureNotifyMask;
1184444c061aSmrg    return returnMask;
1185444c061aSmrg}
1186444c061aSmrg
1187a3bd7f05Smrgstatic void
1188a3bd7f05SmrgDispatchMappingNotify(Widget widget _X_UNUSED,  /* will be NULL from _RefreshMapping */
1189a3bd7f05Smrg                      XtPointer closure,        /* real Widget */
1190a3bd7f05Smrg                      XtPointer call_data)      /* XEvent* */
1191444c061aSmrg{
1192a3bd7f05Smrg    _XtTranslateEvent((Widget) closure, (XEvent *) call_data);
1193444c061aSmrg}
1194444c061aSmrg
1195a3bd7f05Smrgstatic void
1196a3bd7f05SmrgRemoveFromMappingCallbacks(Widget widget,
1197a3bd7f05Smrg                           XtPointer closure,    /* target widget */
1198a3bd7f05Smrg                           XtPointer call_data _X_UNUSED)
1199444c061aSmrg{
1200a3bd7f05Smrg    _XtRemoveCallback(&_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks,
1201a3bd7f05Smrg                      DispatchMappingNotify, closure);
1202444c061aSmrg}
1203444c061aSmrg
1204a3bd7f05Smrgstatic Boolean
1205a3bd7f05SmrgAggregateEventMask(StatePtr state, XtPointer data)
1206444c061aSmrg{
1207444c061aSmrg    LOCK_PROCESS;
1208a3bd7f05Smrg    *((EventMask *) data) |= EventToMask(TMGetTypeMatch(state->typeIndex),
1209a3bd7f05Smrg                                         TMGetModifierMatch(state->modIndex));
1210444c061aSmrg    UNLOCK_PROCESS;
1211444c061aSmrg    return False;
1212444c061aSmrg}
1213444c061aSmrg
1214a3bd7f05Smrgvoid
1215a3bd7f05Smrg_XtInstallTranslations(Widget widget)
1216444c061aSmrg{
1217444c061aSmrg    XtTranslations xlations;
1218a3bd7f05Smrg    Cardinal i;
1219a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1220444c061aSmrg
1221444c061aSmrg    xlations = widget->core.tm.translations;
1222a3bd7f05Smrg    if (xlations == NULL)
1223a3bd7f05Smrg        return;
1224444c061aSmrg
1225444c061aSmrg    /*
1226444c061aSmrg     * check for somebody stuffing the translations directly into the
1227444c061aSmrg     * instance structure. We will end up being called again out of
1228444c061aSmrg     * ComposeTranslations but we *should* have bindings by then
1229444c061aSmrg     */
1230444c061aSmrg    if (widget->core.tm.proc_table == NULL) {
1231a3bd7f05Smrg        _XtMergeTranslations(widget, NULL, XtTableReplace);
1232a3bd7f05Smrg        /*
1233a3bd7f05Smrg         * if we're realized then we'll be called out of
1234a3bd7f05Smrg         * ComposeTranslations
1235a3bd7f05Smrg         */
1236a3bd7f05Smrg        if (XtIsRealized(widget))
1237a3bd7f05Smrg            return;
1238444c061aSmrg    }
1239444c061aSmrg
1240444c061aSmrg    xlations->eventMask = 0;
1241a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1242a3bd7f05Smrg        TMStateTree stateTree = xlations->stateTreeTbl[i];
1243a3bd7f05Smrg
1244a3bd7f05Smrg        _XtTraverseStateTree(stateTree,
1245a3bd7f05Smrg                             AggregateEventMask,
1246a3bd7f05Smrg                             (XtPointer) &xlations->eventMask);
1247a3bd7f05Smrg        mappingNotifyInterest =
1248a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1249a3bd7f05Smrg                       stateTree->simple.mappingNotifyInterest);
1250a3bd7f05Smrg    }
1251444c061aSmrg    /* double click needs to make sure that you have selected on both
1252a3bd7f05Smrg       button down and up. */
1253444c061aSmrg
1254444c061aSmrg    if (xlations->eventMask & ButtonPressMask)
1255a3bd7f05Smrg        xlations->eventMask |= ButtonReleaseMask;
1256444c061aSmrg    if (xlations->eventMask & ButtonReleaseMask)
1257a3bd7f05Smrg        xlations->eventMask |= ButtonPressMask;
1258444c061aSmrg
1259444c061aSmrg    if (mappingNotifyInterest) {
1260a3bd7f05Smrg        XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget));
1261a3bd7f05Smrg
1262a3bd7f05Smrg        if (pd->mapping_callbacks)
1263a3bd7f05Smrg            _XtAddCallbackOnce(&(pd->mapping_callbacks),
1264a3bd7f05Smrg                               DispatchMappingNotify, (XtPointer) widget);
1265a3bd7f05Smrg        else
1266a3bd7f05Smrg            _XtAddCallback(&(pd->mapping_callbacks),
1267a3bd7f05Smrg                           DispatchMappingNotify, (XtPointer) widget);
1268a3bd7f05Smrg
1269a3bd7f05Smrg        if (widget->core.destroy_callbacks != NULL)
1270a3bd7f05Smrg            _XtAddCallbackOnce((InternalCallbackList *)
1271a3bd7f05Smrg                               &widget->core.destroy_callbacks,
1272a3bd7f05Smrg                               RemoveFromMappingCallbacks, (XtPointer) widget);
1273a3bd7f05Smrg        else
1274a3bd7f05Smrg            _XtAddCallback((InternalCallbackList *)
1275a3bd7f05Smrg                           &widget->core.destroy_callbacks,
1276a3bd7f05Smrg                           RemoveFromMappingCallbacks, (XtPointer) widget);
1277a3bd7f05Smrg    }
1278a3bd7f05Smrg    _XtBindActions(widget, (XtTM) &widget->core.tm);
1279444c061aSmrg    _XtRegisterGrabs(widget);
1280444c061aSmrg}
1281444c061aSmrg
1282a3bd7f05Smrgvoid
1283a3bd7f05Smrg_XtRemoveTranslations(Widget widget)
1284444c061aSmrg{
1285a3bd7f05Smrg    Cardinal i;
1286a3bd7f05Smrg    Boolean mappingNotifyInterest = False;
1287a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1288444c061aSmrg
1289444c061aSmrg    if (xlations == NULL)
1290a3bd7f05Smrg        return;
1291a3bd7f05Smrg
1292a3bd7f05Smrg    for (i = 0; i < xlations->numStateTrees; i++) {
1293a3bd7f05Smrg        TMSimpleStateTree stateTree =
1294a3bd7f05Smrg            (TMSimpleStateTree) xlations->stateTreeTbl[i];
1295a3bd7f05Smrg        mappingNotifyInterest =
1296a3bd7f05Smrg            (Boolean) (mappingNotifyInterest |
1297a3bd7f05Smrg                       stateTree->mappingNotifyInterest);
1298a3bd7f05Smrg    }
1299444c061aSmrg    if (mappingNotifyInterest)
1300a3bd7f05Smrg        RemoveFromMappingCallbacks(widget, (XtPointer) widget, NULL);
1301444c061aSmrg}
1302444c061aSmrg
1303a3bd7f05Smrgstatic void
1304a3bd7f05Smrg_XtUninstallTranslations(Widget widget)
1305444c061aSmrg{
1306a3bd7f05Smrg    XtTranslations xlations = widget->core.tm.translations;
1307444c061aSmrg
1308a3bd7f05Smrg    _XtUnbindActions(widget, xlations, (TMBindData) widget->core.tm.proc_table);
1309444c061aSmrg    _XtRemoveTranslations(widget);
1310444c061aSmrg    widget->core.tm.translations = NULL;
1311a3bd7f05Smrg    FreeContext((TMContext *) &widget->core.tm.current_state);
1312444c061aSmrg}
1313444c061aSmrg
1314a3bd7f05Smrgvoid
1315a3bd7f05Smrg_XtDestroyTMData(Widget widget)
1316444c061aSmrg{
1317a3bd7f05Smrg    TMComplexBindData cBindData;
1318444c061aSmrg
1319444c061aSmrg    _XtUninstallTranslations(widget);
1320444c061aSmrg
1321a3bd7f05Smrg    if ((cBindData = (TMComplexBindData) widget->core.tm.proc_table)) {
1322a3bd7f05Smrg        if (cBindData->isComplex) {
1323a3bd7f05Smrg            ATranslations nXlations = (ATranslations) cBindData->accel_context;
1324a3bd7f05Smrg
1325a3bd7f05Smrg            while (nXlations) {
1326a3bd7f05Smrg                ATranslations aXlations = nXlations;
1327a3bd7f05Smrg
1328a3bd7f05Smrg                nXlations = nXlations->next;
1329a3bd7f05Smrg                XtFree((char *) aXlations);
1330a3bd7f05Smrg            }
1331a3bd7f05Smrg        }
1332a3bd7f05Smrg        XtFree((char *) cBindData);
1333444c061aSmrg    }
1334444c061aSmrg}
1335444c061aSmrg
1336444c061aSmrg/*** Public procedures ***/
1337444c061aSmrg
1338a3bd7f05Smrgvoid
1339a3bd7f05SmrgXtUninstallTranslations(Widget widget)
1340444c061aSmrg{
1341a3bd7f05Smrg    EventMask oldMask;
1342444c061aSmrg    Widget hookobj;
1343a3bd7f05Smrg
1344444c061aSmrg    WIDGET_TO_APPCON(widget);
1345444c061aSmrg
1346444c061aSmrg    LOCK_APP(app);
1347a3bd7f05Smrg    if (!widget->core.tm.translations) {
1348a3bd7f05Smrg        UNLOCK_APP(app);
1349a3bd7f05Smrg        return;
1350444c061aSmrg    }
1351444c061aSmrg    oldMask = widget->core.tm.translations->eventMask;
1352444c061aSmrg    _XtUninstallTranslations(widget);
1353444c061aSmrg    if (XtIsRealized(widget) && oldMask)
1354a3bd7f05Smrg        XSelectInput(XtDisplay(widget), XtWindow(widget),
1355a3bd7f05Smrg                     (long) XtBuildEventMask(widget));
1356444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
1357444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
1358a3bd7f05Smrg        XtChangeHookDataRec call_data;
1359444c061aSmrg
1360a3bd7f05Smrg        call_data.type = XtHuninstallTranslations;
1361a3bd7f05Smrg        call_data.widget = widget;
1362a3bd7f05Smrg        XtCallCallbackList(hookobj,
1363a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
1364a3bd7f05Smrg                           (XtPointer) &call_data);
1365444c061aSmrg    }
1366444c061aSmrg    UNLOCK_APP(app);
1367444c061aSmrg}
1368444c061aSmrg
1369a3bd7f05SmrgXtTranslations
1370a3bd7f05Smrg_XtCreateXlations(TMStateTree *stateTrees,
1371a3bd7f05Smrg                  TMShortCard numStateTrees,
1372a3bd7f05Smrg                  XtTranslations first,
1373a3bd7f05Smrg                  XtTranslations second)
1374444c061aSmrg{
1375a3bd7f05Smrg    XtTranslations xlations;
1376444c061aSmrg    TMShortCard i;
1377444c061aSmrg
1378444c061aSmrg    xlations = (XtTranslations)
1379a3bd7f05Smrg        __XtMalloc((Cardinal) (sizeof(TranslationData) +
1380a3bd7f05Smrg                               (size_t) (numStateTrees -
1381a3bd7f05Smrg                                         1) * sizeof(TMStateTree)));
1382444c061aSmrg#ifdef TRACE_TM
1383444c061aSmrg    LOCK_PROCESS;
1384444c061aSmrg    if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) {
1385a3bd7f05Smrg        _XtGlobalTM.tmTblSize = (TMShortCard) (_XtGlobalTM.tmTblSize + 16);
1386a3bd7f05Smrg        _XtGlobalTM.tmTbl = (XtTranslations *)
1387a3bd7f05Smrg            XtRealloc((char *) _XtGlobalTM.tmTbl,
1388a3bd7f05Smrg                      (Cardinal) (_XtGlobalTM.tmTblSize *
1389a3bd7f05Smrg                                  sizeof(XtTranslations)));
1390444c061aSmrg    }
1391444c061aSmrg    _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations;
1392444c061aSmrg    UNLOCK_PROCESS;
1393a3bd7f05Smrg#endif                          /* TRACE_TM */
1394444c061aSmrg
1395444c061aSmrg    xlations->composers[0] = first;
1396444c061aSmrg    xlations->composers[1] = second;
1397444c061aSmrg    xlations->hasBindings = False;
1398444c061aSmrg    xlations->operation = XtTableReplace;
1399444c061aSmrg
1400a3bd7f05Smrg    for (i = 0; i < numStateTrees; i++) {
1401a3bd7f05Smrg        xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i];
1402a3bd7f05Smrg        stateTrees[i]->simple.refCount++;
1403a3bd7f05Smrg    }
1404444c061aSmrg    xlations->numStateTrees = numStateTrees;
1405444c061aSmrg    xlations->eventMask = 0;
1406444c061aSmrg    return xlations;
1407444c061aSmrg}
1408444c061aSmrg
1409a3bd7f05SmrgTMStateTree
1410a3bd7f05Smrg_XtParseTreeToStateTree(TMParseStateTree parseTree)
1411444c061aSmrg{
1412a3bd7f05Smrg    TMSimpleStateTree simpleTree;
1413a3bd7f05Smrg    unsigned int tableSize;
1414444c061aSmrg
1415444c061aSmrg    if (parseTree->numComplexBranchHeads) {
1416a3bd7f05Smrg        TMComplexStateTree complexTree;
1417a3bd7f05Smrg
1418a3bd7f05Smrg        complexTree = XtNew(TMComplexStateTreeRec);
1419a3bd7f05Smrg        complexTree->isSimple = False;
1420a3bd7f05Smrg        tableSize =
1421a3bd7f05Smrg            (unsigned) (parseTree->numComplexBranchHeads * sizeof(StatePtr));
1422a3bd7f05Smrg        complexTree->complexBranchHeadTbl = (StatePtr *)
1423a3bd7f05Smrg            __XtMalloc(tableSize);
1424a3bd7f05Smrg        XtMemmove(complexTree->complexBranchHeadTbl,
1425a3bd7f05Smrg                  parseTree->complexBranchHeadTbl, tableSize);
1426a3bd7f05Smrg        complexTree->numComplexBranchHeads = parseTree->numComplexBranchHeads;
1427a3bd7f05Smrg        simpleTree = (TMSimpleStateTree) complexTree;
1428444c061aSmrg    }
1429444c061aSmrg    else {
1430a3bd7f05Smrg        simpleTree = XtNew(TMSimpleStateTreeRec);
1431a3bd7f05Smrg        simpleTree->isSimple = True;
1432444c061aSmrg    }
1433444c061aSmrg    simpleTree->isAccelerator = parseTree->isAccelerator;
1434444c061aSmrg    simpleTree->refCount = 0;
1435444c061aSmrg    simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest;
1436444c061aSmrg
1437a3bd7f05Smrg    tableSize =
1438a3bd7f05Smrg        (unsigned) (parseTree->numBranchHeads * sizeof(TMBranchHeadRec));
1439444c061aSmrg    simpleTree->branchHeadTbl = (TMBranchHead)
1440a3bd7f05Smrg        __XtMalloc(tableSize);
1441444c061aSmrg    XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize);
1442444c061aSmrg    simpleTree->numBranchHeads = parseTree->numBranchHeads;
1443444c061aSmrg
14440568f49bSmrg    tableSize = (unsigned) (parseTree->numQuarks * sizeof(XrmQuark));
1445444c061aSmrg    simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize);
1446444c061aSmrg    XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize);
1447444c061aSmrg    simpleTree->numQuarks = parseTree->numQuarks;
1448444c061aSmrg
1449a3bd7f05Smrg    return (TMStateTree) simpleTree;
1450444c061aSmrg}
1451444c061aSmrg
1452a3bd7f05Smrgstatic void
1453a3bd7f05SmrgFreeActions(ActionPtr actions)
1454444c061aSmrg{
1455444c061aSmrg    ActionPtr action;
1456444c061aSmrg    TMShortCard i;
1457a3bd7f05Smrg
1458444c061aSmrg    for (action = actions; action;) {
1459a3bd7f05Smrg        ActionPtr nextAction = action->next;
1460a3bd7f05Smrg
1461a3bd7f05Smrg        for (i = (TMShortCard) action->num_params; i;) {
1462a3bd7f05Smrg            XtFree((_XtString) action->params[--i]);
1463a3bd7f05Smrg        }
1464a3bd7f05Smrg        XtFree((char *) action->params);
1465a3bd7f05Smrg        XtFree((char *) action);
1466a3bd7f05Smrg        action = nextAction;
1467444c061aSmrg    }
1468444c061aSmrg}
1469444c061aSmrg
1470a3bd7f05Smrgstatic void
1471a3bd7f05SmrgAmbigActions(EventSeqPtr initialEvent,
1472a3bd7f05Smrg             StatePtr *state,
1473a3bd7f05Smrg             TMParseStateTree stateTree)
1474444c061aSmrg{
1475a3bd7f05Smrg    String params[3];
1476a3bd7f05Smrg    Cardinal numParams = 0;
1477444c061aSmrg
1478444c061aSmrg    params[numParams++] = _XtPrintEventSeq(initialEvent, NULL);
1479444c061aSmrg    params[numParams++] = _XtPrintActions((*state)->actions,
1480a3bd7f05Smrg                                          stateTree->quarkTbl);
1481a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "oldActions", XtCXtToolkitError,
1482a3bd7f05Smrg                 "Previous entry was: %s %s", params, &numParams);
1483a3bd7f05Smrg    XtFree((char *) params[0]);
1484a3bd7f05Smrg    XtFree((char *) params[1]);
1485444c061aSmrg    numParams = 0;
1486a3bd7f05Smrg    params[numParams++] = _XtPrintActions(initialEvent->actions,
1487a3bd7f05Smrg                                          stateTree->quarkTbl);
1488a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "newActions", XtCXtToolkitError,
1489a3bd7f05Smrg                 "New actions are:%s", params, &numParams);
1490a3bd7f05Smrg    XtFree((char *) params[0]);
1491a3bd7f05Smrg    XtWarningMsg(XtNtranslationError, "ambiguousActions",
1492a3bd7f05Smrg                 XtCXtToolkitError,
1493a3bd7f05Smrg                 "Overriding earlier translation manager actions.", NULL, NULL);
1494444c061aSmrg
1495444c061aSmrg    FreeActions((*state)->actions);
1496444c061aSmrg    (*state)->actions = NULL;
1497444c061aSmrg}
1498444c061aSmrg
1499a3bd7f05Smrgvoid
1500a3bd7f05Smrg_XtAddEventSeqToStateTree(EventSeqPtr eventSeq, TMParseStateTree stateTree)
1501444c061aSmrg{
1502a3bd7f05Smrg    StatePtr *state;
1503a3bd7f05Smrg    EventSeqPtr initialEvent = eventSeq;
1504a3bd7f05Smrg    TMBranchHead branchHead;
1505a3bd7f05Smrg    TMShortCard idx, modIndex, typeIndex;
1506444c061aSmrg
1507a3bd7f05Smrg    if (eventSeq == NULL)
1508a3bd7f05Smrg        return;
1509444c061aSmrg
1510444c061aSmrg    /* note that all states in the event seq passed in start out null */
1511444c061aSmrg    /* we fill them in with the matching state as we traverse the list */
1512444c061aSmrg
1513444c061aSmrg    /*
1514444c061aSmrg     * We need to free the parser data structures !!!
1515444c061aSmrg     */
1516444c061aSmrg
1517444c061aSmrg    typeIndex = _XtGetTypeIndex(&eventSeq->event);
1518444c061aSmrg    modIndex = _XtGetModifierIndex(&eventSeq->event);
1519444c061aSmrg    idx = GetBranchHead(stateTree, typeIndex, modIndex, False);
1520444c061aSmrg    branchHead = &stateTree->branchHeadTbl[idx];
1521444c061aSmrg
1522444c061aSmrg    /*
1523444c061aSmrg     * Need to check for pre-existing actions with same lhs |||
1524444c061aSmrg     */
1525444c061aSmrg
1526444c061aSmrg    /*
1527444c061aSmrg     * Check for optimized case. Don't assume that the eventSeq has actions.
1528444c061aSmrg     */
1529444c061aSmrg    if (!eventSeq->next &&
1530a3bd7f05Smrg        eventSeq->actions &&
1531a3bd7f05Smrg        !eventSeq->actions->next && !eventSeq->actions->num_params) {
1532a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1533a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1534a3bd7f05Smrg        branchHead->hasActions = True;
1535a3bd7f05Smrg        XtSetBits(branchHead->more, eventSeq->actions->idx, 13);
1536a3bd7f05Smrg        FreeActions(eventSeq->actions);
1537a3bd7f05Smrg        eventSeq->actions = NULL;
1538a3bd7f05Smrg        return;
1539a3bd7f05Smrg    }
1540444c061aSmrg
1541444c061aSmrg    branchHead->isSimple = False;
1542444c061aSmrg    if (!eventSeq->next)
1543a3bd7f05Smrg        branchHead->hasActions = True;
1544a3bd7f05Smrg    XtSetBits(branchHead->more,
1545a3bd7f05Smrg              GetComplexBranchIndex(stateTree, typeIndex, modIndex), 13);
1546444c061aSmrg    state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)];
1547444c061aSmrg
1548444c061aSmrg    for (;;) {
1549a3bd7f05Smrg        *state = NewState(stateTree, typeIndex, modIndex);
1550444c061aSmrg
1551a3bd7f05Smrg        if (eventSeq->event.eventType == MappingNotify)
1552a3bd7f05Smrg            stateTree->mappingNotifyInterest = True;
1553444c061aSmrg
1554a3bd7f05Smrg        /* *state now points at state record matching event */
1555a3bd7f05Smrg        eventSeq->state = *state;
1556444c061aSmrg
1557a3bd7f05Smrg        if (eventSeq->actions != NULL) {
1558a3bd7f05Smrg            if ((*state)->actions != NULL)
1559a3bd7f05Smrg                AmbigActions(initialEvent, state, stateTree);
1560a3bd7f05Smrg            (*state)->actions = eventSeq->actions;
1561444c061aSmrg#ifdef TRACE_TM
1562a3bd7f05Smrg            LOCK_PROCESS;
1563a3bd7f05Smrg            _XtGlobalTM.numComplexActions++;
1564a3bd7f05Smrg            UNLOCK_PROCESS;
1565a3bd7f05Smrg#endif                          /* TRACE_TM */
1566a3bd7f05Smrg        }
1567a3bd7f05Smrg
1568a3bd7f05Smrg        if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state))
1569a3bd7f05Smrg            break;
1570a3bd7f05Smrg
1571a3bd7f05Smrg        state = &(*state)->nextLevel;
1572a3bd7f05Smrg        typeIndex = _XtGetTypeIndex(&eventSeq->event);
1573a3bd7f05Smrg        modIndex = _XtGetModifierIndex(&eventSeq->event);
1574a3bd7f05Smrg        LOCK_PROCESS;
1575a3bd7f05Smrg        if (!TMNewMatchSemantics()) {
1576a3bd7f05Smrg            /*
1577a3bd7f05Smrg             * force a potential empty entry into the branch head
1578a3bd7f05Smrg             * table in order to emulate old matching behavior
1579a3bd7f05Smrg             */
1580a3bd7f05Smrg            (void) GetBranchHead(stateTree, typeIndex, modIndex, True);
1581a3bd7f05Smrg        }
1582a3bd7f05Smrg        UNLOCK_PROCESS;
1583444c061aSmrg    }
1584444c061aSmrg
1585444c061aSmrg    if (eventSeq && eventSeq->state) {
1586a3bd7f05Smrg        /* we've been here before... must be a cycle in the event seq. */
1587a3bd7f05Smrg        branchHead->hasCycles = True;
1588a3bd7f05Smrg        (*state)->nextLevel = eventSeq->state;
1589a3bd7f05Smrg        eventSeq->state->isCycleStart = True;
1590a3bd7f05Smrg        (*state)->isCycleEnd = TRUE;
1591444c061aSmrg    }
1592444c061aSmrg}
1593444c061aSmrg
1594444c061aSmrg/*
1595444c061aSmrg * Internal Converter for merging. Old and New must both be valid xlations
1596444c061aSmrg */
1597a3bd7f05SmrgBoolean
1598a3bd7f05Smrg_XtCvtMergeTranslations(Display *dpy _X_UNUSED,
1599a3bd7f05Smrg                        XrmValuePtr args _X_UNUSED,
1600a3bd7f05Smrg                        Cardinal *num_args,
1601a3bd7f05Smrg                        XrmValuePtr from,
1602a3bd7f05Smrg                        XrmValuePtr to,
1603a3bd7f05Smrg                        XtPointer *closure_ret _X_UNUSED)
1604444c061aSmrg{
1605a3bd7f05Smrg    XtTranslations first, second, xlations;
1606a3bd7f05Smrg    TMStateTree *stateTrees, stackStateTrees[16];
1607a3bd7f05Smrg    TMShortCard numStateTrees, i;
1608444c061aSmrg
1609444c061aSmrg    if (*num_args != 0)
1610a3bd7f05Smrg        XtWarningMsg("invalidParameters", "mergeTranslations",
1611a3bd7f05Smrg                     XtCXtToolkitError,
1612a3bd7f05Smrg                     "MergeTM to TranslationTable needs no extra arguments",
1613a3bd7f05Smrg                     NULL, NULL);
1614444c061aSmrg
1615444c061aSmrg    if (to->addr != NULL && to->size < sizeof(XtTranslations)) {
1616a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1617a3bd7f05Smrg        return False;
1618444c061aSmrg    }
1619444c061aSmrg
1620a3bd7f05Smrg    first = ((TMConvertRec *) from->addr)->old;
1621a3bd7f05Smrg    second = ((TMConvertRec *) from->addr)->new;
1622444c061aSmrg
1623a3bd7f05Smrg    numStateTrees =
1624a3bd7f05Smrg        (TMShortCard) (first->numStateTrees + second->numStateTrees);
1625444c061aSmrg
1626444c061aSmrg    stateTrees = (TMStateTree *)
1627a3bd7f05Smrg        XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees);
1628444c061aSmrg
1629444c061aSmrg    for (i = 0; i < first->numStateTrees; i++)
1630a3bd7f05Smrg        stateTrees[i] = first->stateTreeTbl[i];
1631444c061aSmrg    for (i = 0; i < second->numStateTrees; i++)
1632a3bd7f05Smrg        stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i];
1633444c061aSmrg
1634444c061aSmrg    xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second);
1635444c061aSmrg
1636444c061aSmrg    if (to->addr != NULL) {
1637a3bd7f05Smrg        *(XtTranslations *) to->addr = xlations;
1638444c061aSmrg    }
1639444c061aSmrg    else {
1640a3bd7f05Smrg        static XtTranslations staticStateTable;
1641a3bd7f05Smrg
1642a3bd7f05Smrg        staticStateTable = xlations;
1643a3bd7f05Smrg        to->addr = (XPointer) &staticStateTable;
1644a3bd7f05Smrg        to->size = sizeof(XtTranslations);
1645444c061aSmrg    }
1646444c061aSmrg
1647a3bd7f05Smrg    XtStackFree((XtPointer) stateTrees, (XtPointer) stackStateTrees);
1648444c061aSmrg    return True;
1649444c061aSmrg}
1650444c061aSmrg
1651a3bd7f05Smrgstatic XtTranslations
1652a3bd7f05SmrgMergeThem(Widget dest, XtTranslations first, XtTranslations second)
1653444c061aSmrg{
1654a3bd7f05Smrg    XtCacheRef cache_ref;
1655a3bd7f05Smrg    static XrmQuark from_type = NULLQUARK, to_type;
1656a3bd7f05Smrg    XrmValue from, to;
1657a3bd7f05Smrg    TMConvertRec convert_rec;
1658a3bd7f05Smrg    XtTranslations newTable;
1659444c061aSmrg
1660444c061aSmrg    LOCK_PROCESS;
1661444c061aSmrg    if (from_type == NULLQUARK) {
1662a3bd7f05Smrg        from_type = XrmPermStringToQuark(_XtRStateTablePair);
1663a3bd7f05Smrg        to_type = XrmPermStringToQuark(XtRTranslationTable);
1664444c061aSmrg    }
1665444c061aSmrg    UNLOCK_PROCESS;
1666a3bd7f05Smrg    from.addr = (XPointer) &convert_rec;
1667444c061aSmrg    from.size = sizeof(TMConvertRec);
1668a3bd7f05Smrg    to.addr = (XPointer) &newTable;
1669444c061aSmrg    to.size = sizeof(XtTranslations);
1670444c061aSmrg    convert_rec.old = first;
1671444c061aSmrg    convert_rec.new = second;
1672444c061aSmrg
1673444c061aSmrg    LOCK_PROCESS;
1674a3bd7f05Smrg    if (!_XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) {
1675a3bd7f05Smrg        UNLOCK_PROCESS;
1676a3bd7f05Smrg        return NULL;
1677444c061aSmrg    }
1678444c061aSmrg    UNLOCK_PROCESS;
1679444c061aSmrg
1680444c061aSmrg#ifndef REFCNT_TRANSLATIONS
1681444c061aSmrg
1682444c061aSmrg    if (cache_ref)
1683a3bd7f05Smrg        XtAddCallback(dest, XtNdestroyCallback,
1684a3bd7f05Smrg                      XtCallbackReleaseCacheRef, (XtPointer) cache_ref);
1685444c061aSmrg
1686444c061aSmrg#endif
1687444c061aSmrg
1688444c061aSmrg    return newTable;
1689444c061aSmrg}
1690444c061aSmrg
1691444c061aSmrg/*
1692444c061aSmrg * Unmerge will recursively traverse the xlation compose tree and
1693444c061aSmrg * generate a new xlation that is the result of all instances of
1694444c061aSmrg * xlations being removed. It currently doesn't differentiate between
1695444c061aSmrg * the potential that an xlation will be both an accelerator and
1696444c061aSmrg * normal. This is not supported by the spec anyway.
1697444c061aSmrg */
1698a3bd7f05Smrgstatic XtTranslations
1699a3bd7f05SmrgUnmergeTranslations(Widget widget,
1700a3bd7f05Smrg                    XtTranslations xlations,
1701a3bd7f05Smrg                    XtTranslations unmergeXlations,
1702a3bd7f05Smrg                    TMShortCard currIndex,
1703a3bd7f05Smrg                    TMComplexBindProcs oldBindings,
1704a3bd7f05Smrg                    TMShortCard numOldBindings,
1705a3bd7f05Smrg                    TMComplexBindProcs newBindings,
1706a3bd7f05Smrg                    TMShortCard *numNewBindingsRtn)
1707444c061aSmrg{
1708444c061aSmrg    XtTranslations first, second, result;
1709444c061aSmrg
1710444c061aSmrg    if (!xlations || (xlations == unmergeXlations))
1711a3bd7f05Smrg        return NULL;
1712444c061aSmrg
1713444c061aSmrg    if (xlations->composers[0]) {
1714a3bd7f05Smrg        first = UnmergeTranslations(widget, xlations->composers[0],
1715a3bd7f05Smrg                                    unmergeXlations, currIndex,
1716a3bd7f05Smrg                                    oldBindings, numOldBindings,
1717a3bd7f05Smrg                                    newBindings, numNewBindingsRtn);
1718444c061aSmrg    }
1719444c061aSmrg    else
1720a3bd7f05Smrg        first = NULL;
1721444c061aSmrg
17220568f49bSmrg    if (xlations->composers[0]
1723a3bd7f05Smrg        && xlations->composers[1]) {
1724a3bd7f05Smrg        second = UnmergeTranslations(widget, xlations->composers[1],
1725a3bd7f05Smrg                                     unmergeXlations, (TMShortCard)
1726a3bd7f05Smrg                                     (currIndex +
1727a3bd7f05Smrg                                      xlations->composers[0]->numStateTrees),
1728a3bd7f05Smrg                                     oldBindings,
1729a3bd7f05Smrg                                     numOldBindings, newBindings,
1730a3bd7f05Smrg                                     numNewBindingsRtn);
1731444c061aSmrg    }
1732444c061aSmrg    else
1733a3bd7f05Smrg        second = NULL;
1734444c061aSmrg
1735444c061aSmrg    if (first || second) {
1736a3bd7f05Smrg        if (first && second) {
1737a3bd7f05Smrg            if ((first != xlations->composers[0]) ||
1738a3bd7f05Smrg                (second != xlations->composers[1]))
1739a3bd7f05Smrg                result = MergeThem(widget, first, second);
1740a3bd7f05Smrg            else
1741a3bd7f05Smrg                result = xlations;
1742a3bd7f05Smrg        }
1743a3bd7f05Smrg        else {
1744a3bd7f05Smrg            if (first)
1745a3bd7f05Smrg                result = first;
1746a3bd7f05Smrg            else
1747a3bd7f05Smrg                result = second;
1748a3bd7f05Smrg        }
1749a3bd7f05Smrg    }
1750a3bd7f05Smrg    else {                      /* only update for leaf nodes */
1751a3bd7f05Smrg        if (numOldBindings) {
1752a3bd7f05Smrg            Cardinal i;
1753a3bd7f05Smrg
1754a3bd7f05Smrg            for (i = 0; i < xlations->numStateTrees; i++) {
1755a3bd7f05Smrg                if (xlations->stateTreeTbl[i]->simple.isAccelerator)
1756a3bd7f05Smrg                    newBindings[*numNewBindingsRtn] =
1757a3bd7f05Smrg                        oldBindings[currIndex + i];
1758a3bd7f05Smrg                (*numNewBindingsRtn)++;
1759a3bd7f05Smrg            }
1760a3bd7f05Smrg        }
1761a3bd7f05Smrg        result = xlations;
1762444c061aSmrg    }
1763444c061aSmrg    return result;
1764444c061aSmrg}
1765444c061aSmrg
1766444c061aSmrgtypedef struct {
1767444c061aSmrg    XtTranslations xlations;
1768444c061aSmrg    TMComplexBindProcs bindings;
1769a3bd7f05Smrg} MergeBindRec, *MergeBind;
1770a3bd7f05Smrg
1771a3bd7f05Smrgstatic XtTranslations
1772a3bd7f05SmrgMergeTranslations(Widget widget,
1773a3bd7f05Smrg                  XtTranslations oldXlations,
1774a3bd7f05Smrg                  XtTranslations newXlations,
1775a3bd7f05Smrg                  _XtTranslateOp operation,
1776a3bd7f05Smrg                  Widget source,
1777a3bd7f05Smrg                  TMComplexBindProcs oldBindings,
1778a3bd7f05Smrg                  TMComplexBindProcs newBindings,
1779a3bd7f05Smrg                  TMShortCard *numNewRtn)
1780444c061aSmrg{
1781a3bd7f05Smrg    XtTranslations newTable = NULL, xlations;
1782a3bd7f05Smrg    TMComplexBindProcs bindings;
1783a3bd7f05Smrg    TMShortCard i, j;
1784a3bd7f05Smrg    TMStateTree *treePtr;
1785a3bd7f05Smrg    TMShortCard numNew;
1786a3bd7f05Smrg    MergeBindRec bindPair[2];
1787444c061aSmrg
1788444c061aSmrg    /* If the new translation has an accelerator context then pull it
1789444c061aSmrg     * off and pass it and the real xlations in to the caching merge
1790444c061aSmrg     * routine.
1791444c061aSmrg     */
1792444c061aSmrg    if (newXlations->hasBindings) {
1793a3bd7f05Smrg        xlations = ((ATranslations) newXlations)->xlations;
1794a3bd7f05Smrg        bindings = (TMComplexBindProcs)
1795a3bd7f05Smrg            &((ATranslations) newXlations)->bindTbl[0];
1796444c061aSmrg    }
1797444c061aSmrg    else {
1798a3bd7f05Smrg        xlations = newXlations;
1799a3bd7f05Smrg        bindings = NULL;
1800a3bd7f05Smrg    }
1801a3bd7f05Smrg    switch (operation) {
1802a3bd7f05Smrg    case XtTableReplace:
1803a3bd7f05Smrg        newTable = bindPair[0].xlations = xlations;
1804a3bd7f05Smrg        bindPair[0].bindings = bindings;
1805a3bd7f05Smrg        bindPair[1].xlations = NULL;
1806a3bd7f05Smrg        bindPair[1].bindings = NULL;
1807a3bd7f05Smrg        break;
1808a3bd7f05Smrg    case XtTableAugment:
1809a3bd7f05Smrg        bindPair[0].xlations = oldXlations;
1810a3bd7f05Smrg        bindPair[0].bindings = oldBindings;
1811a3bd7f05Smrg        bindPair[1].xlations = xlations;
1812a3bd7f05Smrg        bindPair[1].bindings = bindings;
1813a3bd7f05Smrg        newTable = NULL;
1814a3bd7f05Smrg        break;
1815a3bd7f05Smrg    case XtTableOverride:
1816a3bd7f05Smrg        bindPair[0].xlations = xlations;
1817a3bd7f05Smrg        bindPair[0].bindings = bindings;
1818a3bd7f05Smrg        bindPair[1].xlations = oldXlations;
1819a3bd7f05Smrg        bindPair[1].bindings = oldBindings;
1820a3bd7f05Smrg        newTable = NULL;
1821a3bd7f05Smrg        break;
1822444c061aSmrg    }
1823444c061aSmrg    if (!newTable)
1824a3bd7f05Smrg        newTable =
1825a3bd7f05Smrg            MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations);
1826444c061aSmrg
1827444c061aSmrg    for (i = 0, numNew = 0; i < 2; i++) {
1828a3bd7f05Smrg        if (bindPair[i].xlations)
1829a3bd7f05Smrg            for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) {
1830a3bd7f05Smrg                if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) {
1831a3bd7f05Smrg                    if (bindPair[i].bindings)
1832a3bd7f05Smrg                        newBindings[numNew] = bindPair[i].bindings[j];
1833a3bd7f05Smrg                    else {
1834a3bd7f05Smrg                        newBindings[numNew].widget = source;
1835a3bd7f05Smrg                        newBindings[numNew].aXlations = bindPair[i].xlations;
1836a3bd7f05Smrg                    }
1837a3bd7f05Smrg                }
1838a3bd7f05Smrg            }
1839444c061aSmrg    }
1840444c061aSmrg    *numNewRtn = numNew;
1841444c061aSmrg    treePtr = &newTable->stateTreeTbl[0];
1842444c061aSmrg    for (i = 0; i < newTable->numStateTrees; i++, treePtr++)
1843a3bd7f05Smrg        (*treePtr)->simple.refCount++;
1844444c061aSmrg    return newTable;
1845444c061aSmrg}
1846444c061aSmrg
1847a3bd7f05Smrgstatic TMBindData
1848a3bd7f05SmrgMakeBindData(TMComplexBindProcs bindings,
1849a3bd7f05Smrg             TMShortCard numBindings,
1850a3bd7f05Smrg             TMBindData oldBindData)
1851444c061aSmrg{
1852a3bd7f05Smrg    TMLongCard bytes;
1853a3bd7f05Smrg    TMShortCard i;
1854a3bd7f05Smrg    Boolean isComplex;
1855a3bd7f05Smrg    TMBindData bindData;
1856444c061aSmrg
1857444c061aSmrg    if (numBindings == 0)
1858a3bd7f05Smrg        return NULL;
1859444c061aSmrg    for (i = 0; i < numBindings; i++)
1860a3bd7f05Smrg        if (bindings[i].widget)
1861a3bd7f05Smrg            break;
1862444c061aSmrg    isComplex = (i < numBindings);
1863444c061aSmrg    if (isComplex)
1864a3bd7f05Smrg        bytes = (sizeof(TMComplexBindDataRec) +
1865a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1866a3bd7f05Smrg                  sizeof(TMComplexBindProcsRec)));
1867444c061aSmrg    else
1868a3bd7f05Smrg        bytes = (sizeof(TMSimpleBindDataRec) +
1869a3bd7f05Smrg                 ((TMLongCard) (numBindings - 1) *
1870a3bd7f05Smrg                  sizeof(TMSimpleBindProcsRec)));
1871444c061aSmrg
1872a3bd7f05Smrg    bindData =
1873a3bd7f05Smrg        (TMBindData) __XtCalloc((Cardinal) sizeof(char), (Cardinal) bytes);
18740568f49bSmrg    XtSetBit(bindData->simple.isComplex, isComplex);
1875444c061aSmrg    if (isComplex) {
1876a3bd7f05Smrg        TMComplexBindData cBindData = (TMComplexBindData) bindData;
1877a3bd7f05Smrg
1878a3bd7f05Smrg        /*
1879a3bd7f05Smrg         * If there were any accelerator contexts in the old bindData
1880a3bd7f05Smrg         * then propagate them to the new one.
1881a3bd7f05Smrg         */
1882a3bd7f05Smrg        if (oldBindData && oldBindData->simple.isComplex)
1883a3bd7f05Smrg            cBindData->accel_context =
1884a3bd7f05Smrg                ((TMComplexBindData) oldBindData)->accel_context;
1885a3bd7f05Smrg        XtMemmove((char *) &cBindData->bindTbl[0], (char *) bindings,
1886a3bd7f05Smrg                  numBindings * sizeof(TMComplexBindProcsRec));
1887444c061aSmrg    }
1888444c061aSmrg    return bindData;
1889444c061aSmrg}
1890444c061aSmrg
1891444c061aSmrg/*
1892444c061aSmrg * This routine is the central clearinghouse for merging translations
1893444c061aSmrg * into a widget. It takes care of preping the action bindings for
1894444c061aSmrg * realize time and calling the converter or doing a straight merge if
1895444c061aSmrg * the destination is empty.
1896444c061aSmrg */
1897a3bd7f05Smrgstatic Boolean
1898a3bd7f05SmrgComposeTranslations(Widget dest,
1899a3bd7f05Smrg                    _XtTranslateOp operation,
1900a3bd7f05Smrg                    Widget source,
1901a3bd7f05Smrg                    XtTranslations newXlations)
1902444c061aSmrg{
1903a3bd7f05Smrg    XtTranslations newTable, oldXlations;
1904a3bd7f05Smrg    XtTranslations accNewXlations;
1905a3bd7f05Smrg    EventMask oldMask = 0;
1906a3bd7f05Smrg    TMBindData bindData;
1907a3bd7f05Smrg    TMComplexBindProcs oldBindings = NULL;
1908a3bd7f05Smrg    TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes;
1909444c061aSmrg    TMComplexBindProcsRec stackBindings[16], *newBindings;
1910444c061aSmrg
1911444c061aSmrg    /*
1912444c061aSmrg     * how should we be handling the refcount decrement for the
1913444c061aSmrg     * replaced translation table ???
1914444c061aSmrg     */
1915a3bd7f05Smrg    if (!newXlations) {
1916a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(dest),
1917a3bd7f05Smrg                        XtNtranslationError, "nullTable", XtCXtToolkitError,
1918a3bd7f05Smrg                        "table to (un)merge must not be null", NULL, NULL);
1919a3bd7f05Smrg        return False;
1920a3bd7f05Smrg    }
1921444c061aSmrg
1922444c061aSmrg    accNewXlations = newXlations;
1923444c061aSmrg    newXlations = ((newXlations->hasBindings)
1924a3bd7f05Smrg                   ? ((ATranslations) newXlations)->xlations : newXlations);
1925444c061aSmrg
1926444c061aSmrg    if (!(oldXlations = dest->core.tm.translations))
1927a3bd7f05Smrg        operation = XtTableReplace;
1928444c061aSmrg
1929444c061aSmrg    /*
1930444c061aSmrg     * try to avoid generation of duplicate state trees. If the source
1931444c061aSmrg     * isn't simple (1 state Tree) then it's too much hassle
1932444c061aSmrg     */
1933444c061aSmrg    if (((operation == XtTableAugment) ||
1934a3bd7f05Smrg         (operation == XtTableOverride)) && (newXlations->numStateTrees == 1)) {
1935a3bd7f05Smrg        Cardinal i;
1936a3bd7f05Smrg
1937a3bd7f05Smrg        for (i = 0; i < oldXlations->numStateTrees; i++)
1938a3bd7f05Smrg            if (oldXlations->stateTreeTbl[i] == newXlations->stateTreeTbl[0])
1939a3bd7f05Smrg                break;
1940a3bd7f05Smrg        if (i < oldXlations->numStateTrees) {
1941a3bd7f05Smrg            if (operation == XtTableAugment) {
1942a3bd7f05Smrg                /*
1943a3bd7f05Smrg                 * we don't need to do anything since it's already
1944a3bd7f05Smrg                 * there
1945a3bd7f05Smrg                 */
1946a3bd7f05Smrg                return True;
1947a3bd7f05Smrg            }
1948a3bd7f05Smrg            else {              /* operation == XtTableOverride */
1949a3bd7f05Smrg                /*
1950a3bd7f05Smrg                 * We'll get rid of the duplicate trees throughout the
1951a3bd7f05Smrg                 * and leave it with a pruned translation table. This
1952a3bd7f05Smrg                 * will only work if the same table has been merged
1953a3bd7f05Smrg                 * into this table (or one of it's composers
1954a3bd7f05Smrg                 */
1955a3bd7f05Smrg                _XtUnmergeTranslations(dest, newXlations);
1956a3bd7f05Smrg                /*
1957a3bd7f05Smrg                 * reset oldXlations so we're back in sync
1958a3bd7f05Smrg                 */
1959a3bd7f05Smrg                if (!(oldXlations = dest->core.tm.translations))
1960a3bd7f05Smrg                    operation = XtTableReplace;
1961a3bd7f05Smrg            }
1962a3bd7f05Smrg        }
1963444c061aSmrg    }
1964444c061aSmrg
1965444c061aSmrg    bindData = (TMBindData) dest->core.tm.proc_table;
1966444c061aSmrg    if (bindData) {
1967a3bd7f05Smrg        numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0);
1968a3bd7f05Smrg        if (bindData->simple.isComplex)
1969a3bd7f05Smrg            oldBindings = &((TMComplexBindData) bindData)->bindTbl[0];
1970a3bd7f05Smrg        else
1971a3bd7f05Smrg            oldBindings = (TMComplexBindProcs)
1972a3bd7f05Smrg                (&((TMSimpleBindData) bindData)->bindTbl[0]);
1973444c061aSmrg    }
1974444c061aSmrg
1975a3bd7f05Smrg    numBytes =
1976a3bd7f05Smrg        (TMShortCard) ((size_t) ((oldXlations ? oldXlations->numStateTrees : 0)
1977a3bd7f05Smrg                                 +
1978a3bd7f05Smrg                                 newXlations->numStateTrees) *
1979a3bd7f05Smrg                       sizeof(TMComplexBindProcsRec));
1980a3bd7f05Smrg    newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings);
1981a3bd7f05Smrg    XtBZero((char *) newBindings, numBytes);
1982444c061aSmrg
1983444c061aSmrg    if (operation == XtTableUnmerge) {
1984a3bd7f05Smrg        newTable = UnmergeTranslations(dest,
1985a3bd7f05Smrg                                       oldXlations,
1986a3bd7f05Smrg                                       newXlations,
1987a3bd7f05Smrg                                       0,
1988a3bd7f05Smrg                                       oldBindings, numOldBindings,
1989a3bd7f05Smrg                                       newBindings, &numNewBindings);
1990444c061aSmrg#ifdef DEBUG
1991a3bd7f05Smrg        /* check for no match for unmerge */
1992a3bd7f05Smrg        if (newTable == oldXlations) {
1993a3bd7f05Smrg            XtWarning("attempt to unmerge invalid table");
1994a3bd7f05Smrg            XtStackFree((char *) newBindings, (char *) stackBindings);
1995a3bd7f05Smrg            return (newTable != NULL);
1996a3bd7f05Smrg        }
1997a3bd7f05Smrg#endif                          /* DEBUG */
1998444c061aSmrg    }
1999444c061aSmrg    else {
2000a3bd7f05Smrg        newTable = MergeTranslations(dest,
2001a3bd7f05Smrg                                     oldXlations,
2002a3bd7f05Smrg                                     accNewXlations,
2003a3bd7f05Smrg                                     operation,
2004a3bd7f05Smrg                                     source,
2005a3bd7f05Smrg                                     oldBindings, newBindings, &numNewBindings);
2006444c061aSmrg    }
2007444c061aSmrg    if (XtIsRealized(dest)) {
2008a3bd7f05Smrg        oldMask = 0;
2009a3bd7f05Smrg        if (oldXlations)
2010a3bd7f05Smrg            oldMask = oldXlations->eventMask;
2011a3bd7f05Smrg        _XtUninstallTranslations(dest);
2012444c061aSmrg    }
2013444c061aSmrg
2014444c061aSmrg    dest->core.tm.proc_table =
2015a3bd7f05Smrg        (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData);
2016444c061aSmrg
2017a3bd7f05Smrg    XtFree((char *) bindData);
2018444c061aSmrg
2019444c061aSmrg    dest->core.tm.translations = newTable;
2020444c061aSmrg
2021444c061aSmrg    if (XtIsRealized(dest)) {
2022a3bd7f05Smrg        EventMask mask = 0;
2023a3bd7f05Smrg
2024a3bd7f05Smrg        _XtInstallTranslations(dest);
2025a3bd7f05Smrg        if (newTable)
2026a3bd7f05Smrg            mask = newTable->eventMask;
2027a3bd7f05Smrg        if (mask != oldMask)
2028a3bd7f05Smrg            XSelectInput(XtDisplay(dest), XtWindow(dest),
2029a3bd7f05Smrg                         (long) XtBuildEventMask(dest));
2030a3bd7f05Smrg    }
2031a3bd7f05Smrg    XtStackFree((XtPointer) newBindings, (XtPointer) stackBindings);
2032a3bd7f05Smrg    return (newTable != NULL);
2033444c061aSmrg}
2034444c061aSmrg
2035444c061aSmrg/*
2036444c061aSmrg * If a GetValues is done on a translation resource that contains
2037444c061aSmrg * accelerators we need to return the accelerator context in addition
2038444c061aSmrg * to the pure translations.  Since this means returning memory that
2039444c061aSmrg * the client controlls but we still own, we will track the "headers"
2040444c061aSmrg * that we return (via a linked list pointed to from the bindData) and
2041444c061aSmrg * free it at destroy time.
2042444c061aSmrg */
2043a3bd7f05SmrgXtTranslations
2044a3bd7f05Smrg_XtGetTranslationValue(Widget w)
2045444c061aSmrg{
2046a3bd7f05Smrg    XtTM tmRecPtr = (XtTM) &w->core.tm;
2047a3bd7f05Smrg    ATranslations *aXlationsPtr;
2048a3bd7f05Smrg    TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table;
2049a3bd7f05Smrg    XtTranslations xlations = tmRecPtr->translations;
2050444c061aSmrg
2051444c061aSmrg    if (!xlations || !cBindData || !cBindData->isComplex)
2052a3bd7f05Smrg        return xlations;
2053444c061aSmrg
2054444c061aSmrg    /* Walk the list looking to see if we already have generated a
2055444c061aSmrg     * header for the currently installed translations.  If we have,
2056444c061aSmrg     * just return that header.  Otherwise create a new header.
2057444c061aSmrg     */
2058444c061aSmrg    for (aXlationsPtr = (ATranslations *) &cBindData->accel_context;
2059a3bd7f05Smrg         *aXlationsPtr && (*aXlationsPtr)->xlations != xlations;
2060a3bd7f05Smrg         aXlationsPtr = &(*aXlationsPtr)->next);
2061444c061aSmrg    if (*aXlationsPtr)
2062a3bd7f05Smrg        return (XtTranslations) *aXlationsPtr;
2063444c061aSmrg    else {
2064a3bd7f05Smrg        /* create a new aXlations context */
2065a3bd7f05Smrg        ATranslations aXlations;
2066a3bd7f05Smrg        Cardinal numBindings = xlations->numStateTrees;
2067a3bd7f05Smrg
2068a3bd7f05Smrg        (*aXlationsPtr) = aXlations = (ATranslations)
2069a3bd7f05Smrg            __XtMalloc((Cardinal) (sizeof(ATranslationData) +
2070a3bd7f05Smrg                                   (numBindings -
2071a3bd7f05Smrg                                    1) * sizeof(TMComplexBindProcsRec)));
2072a3bd7f05Smrg
2073a3bd7f05Smrg        aXlations->hasBindings = True;
2074a3bd7f05Smrg        aXlations->xlations = xlations;
2075a3bd7f05Smrg        aXlations->next = NULL;
2076a3bd7f05Smrg        XtMemmove((char *) &aXlations->bindTbl[0],
2077a3bd7f05Smrg                  (char *) &cBindData->bindTbl[0],
2078a3bd7f05Smrg                  numBindings * sizeof(TMComplexBindProcsRec));
2079a3bd7f05Smrg        return (XtTranslations) aXlations;
2080444c061aSmrg    }
2081444c061aSmrg}
2082444c061aSmrg
2083a3bd7f05Smrgstatic void
2084a3bd7f05SmrgRemoveStateTree(TMStateTree tree _X_UNUSED)
2085444c061aSmrg{
2086444c061aSmrg#ifdef REFCNT_TRANSLATIONS
2087a3bd7f05Smrg    TMComplexStateTree stateTree = (TMComplexStateTree) tree;
2088444c061aSmrg
2089444c061aSmrg    if (--stateTree->refCount == 0) {
2090a3bd7f05Smrg        /*
2091a3bd7f05Smrg         * should we free/refcount the match recs ?
2092a3bd7f05Smrg         */
2093a3bd7f05Smrg        if (!stateTree->isSimple) {
2094a3bd7f05Smrg            StatePtr currState, nextState;
2095a3bd7f05Smrg            TMShortCard i;
2096a3bd7f05Smrg
2097a3bd7f05Smrg            for (i = 0; i < stateTree->numComplexBranchHeads; i++) {
2098a3bd7f05Smrg                currState = nextState = stateTree->complexBranchHeadTbl[i];
2099a3bd7f05Smrg                for (; nextState;) {
2100a3bd7f05Smrg                    FreeActions(currState->actions);
2101a3bd7f05Smrg                    currState->actions = NULL;
2102a3bd7f05Smrg                    if (!currState->isCycleEnd)
2103a3bd7f05Smrg                        nextState = currState->nextLevel;
2104a3bd7f05Smrg                    else
2105a3bd7f05Smrg                        nextState = NULL;
2106a3bd7f05Smrg                    XtFree((char *) currState);
2107a3bd7f05Smrg                }
2108a3bd7f05Smrg            }
2109a3bd7f05Smrg            XtFree((char *) stateTree->complexBranchHeadTbl);
2110a3bd7f05Smrg        }
2111a3bd7f05Smrg        XtFree((char *) stateTree->branchHeadTbl);
2112a3bd7f05Smrg        XtFree((char *) stateTree);
2113a3bd7f05Smrg    }
2114a3bd7f05Smrg#endif                          /* REFCNT_TRANSLATIONS */
2115444c061aSmrg}
2116444c061aSmrg
2117a3bd7f05Smrgvoid
2118a3bd7f05Smrg_XtRemoveStateTreeByIndex(XtTranslations xlations, TMShortCard i)
2119444c061aSmrg{
2120a3bd7f05Smrg    TMStateTree *stateTrees = xlations->stateTreeTbl;
2121444c061aSmrg
2122444c061aSmrg    RemoveStateTree(stateTrees[i]);
2123444c061aSmrg    xlations->numStateTrees--;
2124444c061aSmrg
2125a3bd7f05Smrg    for (; i < xlations->numStateTrees; i++) {
2126a3bd7f05Smrg        stateTrees[i] = stateTrees[i + 1];
2127a3bd7f05Smrg    }
2128444c061aSmrg}
2129444c061aSmrg
2130a3bd7f05Smrgvoid
2131a3bd7f05Smrg_XtFreeTranslations(XtAppContext app,
2132a3bd7f05Smrg                    XrmValuePtr toVal,
2133a3bd7f05Smrg                    XtPointer closure _X_UNUSED,
2134a3bd7f05Smrg                    XrmValuePtr args _X_UNUSED,
2135a3bd7f05Smrg                    Cardinal *num_args)
2136444c061aSmrg{
2137a3bd7f05Smrg    XtTranslations xlations;
2138a3bd7f05Smrg    int i;
2139444c061aSmrg
2140444c061aSmrg    if (*num_args != 0)
2141a3bd7f05Smrg        XtAppWarningMsg(app,
2142a3bd7f05Smrg                        "invalidParameters", "freeTranslations",
2143a3bd7f05Smrg                        XtCXtToolkitError,
2144a3bd7f05Smrg                        "Freeing XtTranslations requires no extra arguments",
2145a3bd7f05Smrg                        NULL, NULL);
2146a3bd7f05Smrg
2147a3bd7f05Smrg    xlations = *(XtTranslations *) toVal->addr;
2148a3bd7f05Smrg    for (i = 0; i < (int) xlations->numStateTrees; i++)
2149a3bd7f05Smrg        RemoveStateTree(xlations->stateTreeTbl[i]);
2150a3bd7f05Smrg    XtFree((char *) xlations);
2151444c061aSmrg}
2152444c061aSmrg
2153444c061aSmrg/*  The spec is not clear on when actions specified in accelerators are bound;
2154444c061aSmrg *  Bind them at Realize the same as translations
2155444c061aSmrg */
2156a3bd7f05Smrgvoid
2157a3bd7f05SmrgXtInstallAccelerators(Widget destination, Widget source)
2158444c061aSmrg{
2159a3bd7f05Smrg    XtTranslations aXlations;
2160a3bd7f05Smrg    _XtTranslateOp op;
2161a3bd7f05Smrg
2162444c061aSmrg    WIDGET_TO_APPCON(destination);
2163444c061aSmrg
2164444c061aSmrg    /*
2165444c061aSmrg     * test that it was parsed as an accelarator table. Even though
2166444c061aSmrg     * there doesn't need to be a distinction it makes life easier if
2167444c061aSmrg     * we honor the spec implication that aXlations is an accelerator
2168444c061aSmrg     */
2169444c061aSmrg    LOCK_APP(app);
2170444c061aSmrg    LOCK_PROCESS;
2171444c061aSmrg    if ((!XtIsWidget(source)) ||
2172a3bd7f05Smrg        ((aXlations = source->core.accelerators) == NULL) ||
2173a3bd7f05Smrg        (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) {
2174a3bd7f05Smrg        UNLOCK_PROCESS;
2175a3bd7f05Smrg        UNLOCK_APP(app);
2176a3bd7f05Smrg        return;
2177444c061aSmrg    }
2178444c061aSmrg
2179444c061aSmrg    aXlations = source->core.accelerators;
2180444c061aSmrg    op = aXlations->operation;
2181444c061aSmrg
2182444c061aSmrg    if (ComposeTranslations(destination, op, source, aXlations) &&
2183a3bd7f05Smrg        (XtClass(source)->core_class.display_accelerator != NULL)) {
2184a3bd7f05Smrg        _XtString buf = _XtPrintXlations(destination, aXlations, source, False);
2185a3bd7f05Smrg
2186a3bd7f05Smrg        (*(XtClass(source)->core_class.display_accelerator)) (source, buf);
2187a3bd7f05Smrg        XtFree(buf);
2188444c061aSmrg    }
2189444c061aSmrg    UNLOCK_PROCESS;
2190444c061aSmrg    UNLOCK_APP(app);
2191444c061aSmrg}
2192444c061aSmrg
2193a3bd7f05Smrgvoid
2194a3bd7f05SmrgXtInstallAllAccelerators(Widget destination, Widget source)
2195444c061aSmrg{
2196444c061aSmrg    Cardinal i;
2197a3bd7f05Smrg
2198444c061aSmrg    WIDGET_TO_APPCON(destination);
2199444c061aSmrg
2200444c061aSmrg    /* Recurse down normal children */
2201444c061aSmrg    LOCK_APP(app);
2202444c061aSmrg    LOCK_PROCESS;
2203444c061aSmrg    if (XtIsComposite(source)) {
22040568f49bSmrg        CompositeWidget cw = (CompositeWidget) source;
2205a3bd7f05Smrg
2206444c061aSmrg        for (i = 0; i < cw->composite.num_children; i++) {
2207a3bd7f05Smrg            XtInstallAllAccelerators(destination, cw->composite.children[i]);
2208444c061aSmrg        }
2209444c061aSmrg    }
2210444c061aSmrg
2211444c061aSmrg    /* Recurse down popup children */
2212444c061aSmrg    if (XtIsWidget(source)) {
2213444c061aSmrg        for (i = 0; i < source->core.num_popups; i++) {
2214a3bd7f05Smrg            XtInstallAllAccelerators(destination, source->core.popup_list[i]);
2215444c061aSmrg        }
2216444c061aSmrg    }
2217444c061aSmrg    /* Finally, apply procedure to this widget */
2218a3bd7f05Smrg    XtInstallAccelerators(destination, source);
2219444c061aSmrg    UNLOCK_PROCESS;
2220444c061aSmrg    UNLOCK_APP(app);
2221444c061aSmrg}
2222444c061aSmrg
2223a3bd7f05Smrg#if 0                           /* dead code */
2224a3bd7f05Smrgstatic _XtTranslateOp
2225a3bd7f05Smrg_XtGetTMOperation(XtTranslations xlations)
2226444c061aSmrg{
2227444c061aSmrg    return ((xlations->hasBindings)
2228a3bd7f05Smrg            ? ((ATranslations) xlations)->xlations->operation
2229a3bd7f05Smrg            : xlations->operation);
2230444c061aSmrg}
2231444c061aSmrg#endif
2232444c061aSmrg
2233a3bd7f05Smrgvoid
2234a3bd7f05SmrgXtAugmentTranslations(Widget widget, XtTranslations new)
2235444c061aSmrg{
2236444c061aSmrg    Widget hookobj;
2237a3bd7f05Smrg
2238444c061aSmrg    WIDGET_TO_APPCON(widget);
2239444c061aSmrg
2240444c061aSmrg    LOCK_APP(app);
2241444c061aSmrg    LOCK_PROCESS;
2242a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableAugment, (Widget) NULL, new);
2243444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2244444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2245a3bd7f05Smrg        XtChangeHookDataRec call_data;
2246444c061aSmrg
2247a3bd7f05Smrg        call_data.type = XtHaugmentTranslations;
2248a3bd7f05Smrg        call_data.widget = widget;
2249a3bd7f05Smrg        XtCallCallbackList(hookobj,
2250a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2251a3bd7f05Smrg                           (XtPointer) &call_data);
2252444c061aSmrg    }
2253444c061aSmrg    UNLOCK_PROCESS;
2254444c061aSmrg    UNLOCK_APP(app);
2255444c061aSmrg}
2256444c061aSmrg
2257a3bd7f05Smrgvoid
2258a3bd7f05SmrgXtOverrideTranslations(Widget widget, XtTranslations new)
2259444c061aSmrg{
2260444c061aSmrg    Widget hookobj;
2261a3bd7f05Smrg
2262444c061aSmrg    WIDGET_TO_APPCON(widget);
2263444c061aSmrg
2264444c061aSmrg    LOCK_APP(app);
2265444c061aSmrg    LOCK_PROCESS;
2266a3bd7f05Smrg    (void) ComposeTranslations(widget, XtTableOverride, (Widget) NULL, new);
2267444c061aSmrg    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
2268444c061aSmrg    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
2269a3bd7f05Smrg        XtChangeHookDataRec call_data;
2270444c061aSmrg
2271a3bd7f05Smrg        call_data.type = XtHoverrideTranslations;
2272a3bd7f05Smrg        call_data.widget = widget;
2273a3bd7f05Smrg        XtCallCallbackList(hookobj,
2274a3bd7f05Smrg                           ((HookObject) hookobj)->hooks.changehook_callbacks,
2275a3bd7f05Smrg                           (XtPointer) &call_data);
2276444c061aSmrg    }
2277444c061aSmrg    UNLOCK_PROCESS;
2278444c061aSmrg    UNLOCK_APP(app);
2279444c061aSmrg}
2280444c061aSmrg
2281a3bd7f05Smrgvoid
2282a3bd7f05Smrg_XtMergeTranslations(Widget widget,
2283a3bd7f05Smrg                     XtTranslations newXlations,
2284a3bd7f05Smrg                     _XtTranslateOp op)
2285444c061aSmrg{
2286a3bd7f05Smrg    if (!newXlations) {
2287a3bd7f05Smrg        if (!widget->core.tm.translations)
2288a3bd7f05Smrg            return;
2289a3bd7f05Smrg        else {
2290a3bd7f05Smrg            newXlations = widget->core.tm.translations;
2291a3bd7f05Smrg            widget->core.tm.translations = NULL;
2292a3bd7f05Smrg        }
2293a3bd7f05Smrg    }
2294a3bd7f05Smrg    (void) ComposeTranslations(widget, op, (Widget) NULL, newXlations);
2295444c061aSmrg}
2296444c061aSmrg
2297a3bd7f05Smrgvoid
2298a3bd7f05Smrg_XtUnmergeTranslations(Widget widget, XtTranslations xlations)
2299444c061aSmrg{
2300a3bd7f05Smrg    ComposeTranslations(widget, XtTableUnmerge, (Widget) NULL, xlations);
2301444c061aSmrg}
2302