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