TMstate.c revision 0568f49b
1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved. 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the "Software"), 6to deal in the Software without restriction, including without limitation 7the rights to use, copy, modify, merge, publish, distribute, sublicense, 8and/or sell copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice (including the next 12paragraph) shall be included in all copies or substantial portions of the 13Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21DEALINGS IN THE SOFTWARE. 22 23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27Permission to use, copy, modify, and distribute this software and its 28documentation for any purpose and without fee is hereby granted, 29provided that the above copyright notice appear in all copies and that 30both that copyright notice and this permission notice appear in 31supporting documentation, and that the name of Digital not be 32used in advertising or publicity pertaining to distribution of the 33software without specific, written prior permission. 34 35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41SOFTWARE. 42 43******************************************************************/ 44 45/* 46 47Copyright 1987, 1988, 1994, 1998 The Open Group 48 49Permission to use, copy, modify, distribute, and sell this software and its 50documentation for any purpose is hereby granted without fee, provided that 51the above copyright notice appear in all copies and that both that 52copyright notice and this permission notice appear in supporting 53documentation. 54 55The above copyright notice and this permission notice shall be included in 56all copies or substantial portions of the Software. 57 58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65Except as contained in this notice, the name of The Open Group shall not be 66used in advertising or otherwise to promote the sale, use or other dealings 67in this Software without prior written authorization from The Open Group. 68 69*/ 70 71/* TMstate.c -- maintains the state table of actions for the translation 72 * manager. 73 */ 74/*LINTLIBRARY*/ 75 76#ifdef HAVE_CONFIG_H 77#include <config.h> 78#endif 79#include "IntrinsicI.h" 80 81#ifndef TM_NO_MATCH 82#define TM_NO_MATCH (-2) 83#endif /* TM_NO_MATCH */ 84 85/* forward definitions */ 86static StatePtr NewState(TMParseStateTree, TMShortCard, TMShortCard); 87 88 89static String XtNtranslationError = "translationError"; 90 91#ifndef __EMX__ 92TMGlobalRec _XtGlobalTM; /* initialized to zero K&R */ 93#else 94TMGlobalRec _XtGlobalTM = {0}; 95#endif 96 97#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \ 98 (typeMatch->eventType == tmEvent->event.eventType && \ 99 (typeMatch->matchEvent != NULL) && \ 100 (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent)) 101 102 103#define NumStateTrees(xlations) \ 104 ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees) 105 106static TMShortCard GetBranchHead( 107 TMParseStateTree parseTree, 108 TMShortCard typeIndex, 109 TMShortCard modIndex, 110 Boolean isDummy) 111{ 112#define TM_BRANCH_HEAD_TBL_ALLOC 8 113#define TM_BRANCH_HEAD_TBL_REALLOC 8 114 115 TMBranchHead branchHead = parseTree->branchHeadTbl; 116 /* 117 * dummy is used as a place holder for later matching in old-style 118 * matching behavior. If there's already an entry we don't need 119 * another dummy. 120 */ 121 if (isDummy) { 122 TMShortCard i; 123 124 for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) { 125 if ((branchHead->typeIndex == typeIndex) && 126 (branchHead->modIndex == modIndex)) 127 return i; 128 } 129 } 130 if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) 131 { 132 TMShortCard newSize; 133 134 if (parseTree->branchHeadTblSize == 0) 135 parseTree->branchHeadTblSize = (TMShortCard) (parseTree->branchHeadTblSize + TM_BRANCH_HEAD_TBL_ALLOC); 136 else 137 parseTree->branchHeadTblSize = (TMShortCard) (parseTree->branchHeadTblSize + 138 TM_BRANCH_HEAD_TBL_REALLOC); 139 newSize = (TMShortCard) (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec)); 140 if (parseTree->isStackBranchHeads) { 141 TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl; 142 parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize); 143 XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize); 144 parseTree->isStackBranchHeads = False; 145 } 146 else { 147 parseTree->branchHeadTbl = (TMBranchHead) 148 XtRealloc((char *)parseTree->branchHeadTbl, 149 (Cardinal)(parseTree->branchHeadTblSize * 150 sizeof(TMBranchHeadRec))); 151 } 152 } 153#ifdef TRACE_TM 154 LOCK_PROCESS; 155 _XtGlobalTM.numBranchHeads++; 156 UNLOCK_PROCESS; 157#endif /* TRACE_TM */ 158 branchHead = 159 &parseTree->branchHeadTbl[parseTree->numBranchHeads++]; 160 branchHead->typeIndex = typeIndex; 161 branchHead->modIndex = modIndex; 162 branchHead->more = 0; 163 branchHead->isSimple = True; 164 branchHead->hasActions = False; 165 branchHead->hasCycles = False; 166 return (TMShortCard) (parseTree->numBranchHeads - 1); 167} 168 169TMShortCard _XtGetQuarkIndex( 170 TMParseStateTree parseTree, 171 XrmQuark quark) 172{ 173#define TM_QUARK_TBL_ALLOC 16 174#define TM_QUARK_TBL_REALLOC 16 175 TMShortCard i; 176 177 for (i=0; i < parseTree->numQuarks; i++) 178 if (parseTree->quarkTbl[i] == quark) 179 break; 180 181 if (i == parseTree->numQuarks) 182 { 183 if (parseTree->numQuarks == parseTree->quarkTblSize) 184 { 185 TMShortCard newSize; 186 187 if (parseTree->quarkTblSize == 0) 188 parseTree->quarkTblSize = (TMShortCard) (parseTree->quarkTblSize + TM_QUARK_TBL_ALLOC); 189 else 190 parseTree->quarkTblSize = (TMShortCard) (parseTree->quarkTblSize + TM_QUARK_TBL_REALLOC); 191 newSize = (TMShortCard) (parseTree->quarkTblSize * sizeof(XrmQuark)); 192 193 if (parseTree->isStackQuarks) { 194 XrmQuark *oldquarkTbl = parseTree->quarkTbl; 195 parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize); 196 XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize); 197 parseTree->isStackQuarks = False; 198 } 199 else { 200 parseTree->quarkTbl = (XrmQuark *) 201 XtRealloc((char *)parseTree->quarkTbl, 202 (Cardinal)(parseTree->quarkTblSize * 203 sizeof(XrmQuark))); 204 } 205 } 206 parseTree->quarkTbl[parseTree->numQuarks++] = quark; 207 } 208 return i; 209} 210 211/* 212 * Get an entry from the parseTrees complex branchHead tbl. If there's none 213 * there then allocate one 214 */ 215/*ARGSUSED*/ 216static TMShortCard GetComplexBranchIndex( 217 TMParseStateTree parseTree, 218 TMShortCard typeIndex, 219 TMShortCard modIndex) 220{ 221#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8 222#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4 223 224 if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) { 225 TMShortCard newSize; 226 227 if (parseTree->complexBranchHeadTblSize == 0) 228 parseTree->complexBranchHeadTblSize = (TMShortCard) (parseTree->complexBranchHeadTblSize + TM_COMPLEXBRANCH_HEAD_TBL_ALLOC); 229 else 230 parseTree->complexBranchHeadTblSize = (TMShortCard) (parseTree->complexBranchHeadTblSize + TM_COMPLEXBRANCH_HEAD_TBL_REALLOC); 231 232 newSize = (TMShortCard) (parseTree->complexBranchHeadTblSize * sizeof(StatePtr)); 233 234 if (parseTree->isStackComplexBranchHeads) { 235 StatePtr *oldcomplexBranchHeadTbl 236 = parseTree->complexBranchHeadTbl; 237 parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize); 238 XtMemmove(parseTree->complexBranchHeadTbl, 239 oldcomplexBranchHeadTbl, newSize); 240 parseTree->isStackComplexBranchHeads = False; 241 } 242 else { 243 parseTree->complexBranchHeadTbl = (StatePtr *) 244 XtRealloc((char *)parseTree->complexBranchHeadTbl, 245 (Cardinal)(parseTree->complexBranchHeadTblSize * 246 sizeof(StatePtr))); 247 } 248 } 249 parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL; 250 return (TMShortCard) (parseTree->numComplexBranchHeads - 1); 251} 252 253TMShortCard _XtGetTypeIndex( 254 Event *event) 255{ 256 TMShortCard i, j = TM_TYPE_SEGMENT_SIZE; 257 TMShortCard typeIndex = 0; 258 TMTypeMatch typeMatch; 259 TMTypeMatch segment = NULL; 260 261 LOCK_PROCESS; 262 for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) { 263 segment = _XtGlobalTM.typeMatchSegmentTbl[i]; 264 for (j = 0; 265 typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE; 266 j++, typeIndex++) 267 { 268 typeMatch = &(segment[j]); 269 if (event->eventType == typeMatch->eventType && 270 event->eventCode == typeMatch->eventCode && 271 event->eventCodeMask == typeMatch->eventCodeMask && 272 event->matchEvent == typeMatch->matchEvent) { 273 UNLOCK_PROCESS; 274 return typeIndex; 275 } 276 } 277 } 278 279 if (j == TM_TYPE_SEGMENT_SIZE) { 280 if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) { 281 _XtGlobalTM.typeMatchSegmentTblSize = (TMShortCard) (_XtGlobalTM.typeMatchSegmentTblSize + 4); 282 _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *) 283 XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl, 284 (Cardinal)(_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch))); 285 } 286 _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] = 287 segment = (TMTypeMatch) 288 __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec)); 289 j = 0; 290 } 291 typeMatch = &segment[j]; 292 typeMatch->eventType = event->eventType; 293 typeMatch->eventCode = event->eventCode; 294 typeMatch->eventCodeMask = event->eventCodeMask; 295 typeMatch->matchEvent = event->matchEvent; 296 _XtGlobalTM.numTypeMatches++; 297 UNLOCK_PROCESS; 298 return typeIndex; 299} 300 301static Boolean CompareLateModifiers( 302 LateBindingsPtr lateBind1P, 303 LateBindingsPtr lateBind2P) 304{ 305 LateBindingsPtr late1P = lateBind1P; 306 LateBindingsPtr late2P = lateBind2P; 307 308 if (late1P != NULL || late2P != NULL) { 309 int i = 0; 310 int j = 0; 311 if (late1P != NULL) 312 for (; late1P->keysym != NoSymbol; i++) late1P++; 313 if (late2P != NULL) 314 for (; late2P->keysym != NoSymbol; j++) late2P++; 315 if (i != j) return FALSE; 316 late1P--; 317 while (late1P >= lateBind1P) { 318 Boolean last = True; 319 for (late2P = lateBind2P + i - 1; 320 late2P >= lateBind2P; 321 late2P--) { 322 if (late1P->keysym == late2P->keysym 323 && late1P->knot == late2P->knot) { 324 j--; 325 if (last) i--; 326 break; 327 } 328 last = False; 329 } 330 late1P--; 331 } 332 if (j != 0) return FALSE; 333 } 334 return TRUE; 335} 336 337TMShortCard _XtGetModifierIndex( 338 Event *event) 339{ 340 TMShortCard i, j = TM_MOD_SEGMENT_SIZE; 341 TMShortCard modIndex = 0; 342 TMModifierMatch modMatch; 343 TMModifierMatch segment = NULL; 344 345 LOCK_PROCESS; 346 for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) { 347 segment = _XtGlobalTM.modMatchSegmentTbl[i]; 348 for (j = 0; 349 modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE; 350 j++, modIndex++) { 351 modMatch = &(segment[j]); 352 if (event->modifiers == modMatch->modifiers && 353 event->modifierMask == modMatch->modifierMask && 354 event->standard == modMatch->standard && 355 ((!event->lateModifiers && !modMatch->lateModifiers) || 356 CompareLateModifiers(event->lateModifiers, 357 modMatch->lateModifiers))) { 358 /* 359 * if we found a match then we can free the parser's 360 * late modifiers. If there isn't a match we use the 361 * parser's copy 362 */ 363 if (event->lateModifiers && 364 --event->lateModifiers->ref_count == 0) { 365 XtFree((char *)event->lateModifiers); 366 event->lateModifiers = NULL; 367 } 368 UNLOCK_PROCESS; 369 return modIndex; 370 } 371 } 372 } 373 374 if (j == TM_MOD_SEGMENT_SIZE) { 375 if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) { 376 _XtGlobalTM.modMatchSegmentTblSize = (TMShortCard) (_XtGlobalTM.modMatchSegmentTblSize + 4); 377 _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *) 378 XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl, 379 (Cardinal)(_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch))); 380 } 381 _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] = 382 segment = (TMModifierMatch) 383 __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec)); 384 j = 0; 385 } 386 modMatch = &segment[j]; 387 modMatch->modifiers = event->modifiers; 388 modMatch->modifierMask = event->modifierMask; 389 modMatch->standard = event->standard; 390 /* 391 * We use the parser's copy of the late binding array 392 */ 393#ifdef TRACE_TM 394 if (event->lateModifiers) 395 _XtGlobalTM.numLateBindings++; 396#endif /* TRACE_TM */ 397 modMatch->lateModifiers = event->lateModifiers; 398 _XtGlobalTM.numModMatches++; 399 UNLOCK_PROCESS; 400 return modIndex; 401} 402 403 404/* 405 * This is called from the SimpleStateHandler to match a stateTree 406 * entry to the event coming in 407 */ 408static int MatchBranchHead( 409 TMSimpleStateTree stateTree, 410 int startIndex, 411 TMEventPtr event) 412{ 413 TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex]; 414 int i; 415 416 LOCK_PROCESS; 417 for (i = startIndex; 418 i < (int)stateTree->numBranchHeads; 419 i++, branchHead++) 420 { 421 TMTypeMatch typeMatch; 422 TMModifierMatch modMatch; 423 424 typeMatch = TMGetTypeMatch(branchHead->typeIndex); 425 modMatch = TMGetModifierMatch(branchHead->modIndex); 426 427 if (MatchIncomingEvent(event, typeMatch, modMatch)) { 428 UNLOCK_PROCESS; 429 return i; 430 } 431 } 432 UNLOCK_PROCESS; 433 return (TM_NO_MATCH); 434} 435 436Boolean _XtRegularMatch( 437 TMTypeMatch typeMatch, 438 TMModifierMatch modMatch, 439 TMEventPtr eventSeq) 440{ 441 Modifiers computed =0; 442 Modifiers computedMask =0; 443 Boolean resolved = TRUE; 444 if (typeMatch->eventCode != (eventSeq->event.eventCode & 445 typeMatch->eventCodeMask)) return FALSE; 446 if (modMatch->lateModifiers != NULL) 447 resolved = _XtComputeLateBindings(eventSeq->xev->xany.display, 448 modMatch->lateModifiers, 449 &computed, &computedMask); 450 if (!resolved) return FALSE; 451 computed = (Modifiers) (computed | modMatch->modifiers); 452 computedMask = (Modifiers) (computedMask | modMatch->modifierMask); 453 454 return ( (computed & computedMask) == 455 (eventSeq->event.modifiers & computedMask)); 456} 457 458/*ARGSUSED*/ 459Boolean _XtMatchAtom( 460 TMTypeMatch typeMatch, 461 TMModifierMatch modMatch, 462 TMEventPtr eventSeq) 463{ 464 Atom atom; 465 466 atom = XInternAtom(eventSeq->xev->xany.display, 467 XrmQuarkToString((XrmQuark)(typeMatch->eventCode)), 468 False); 469 return (atom == eventSeq->event.eventCode); 470} 471 472#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7))) 473 474/* 475 * there are certain cases where you want to ignore the event and stay 476 * in the same state. 477 */ 478static Boolean Ignore( 479 TMEventPtr event) 480{ 481 Display *dpy; 482 XtPerDisplay pd; 483 484 if (event->event.eventType == MotionNotify) 485 return TRUE; 486 if (!(event->event.eventType == KeyPress || 487 event->event.eventType == KeyRelease)) 488 return FALSE; 489 dpy = event->xev->xany.display; 490 pd = _XtGetPerDisplay(dpy); 491 _InitializeKeysymTables(dpy, pd); 492 return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE; 493} 494 495 496static void XEventToTMEvent( 497 XEvent *event, 498 TMEventPtr tmEvent) 499{ 500 tmEvent->xev = event; 501 tmEvent->event.eventCodeMask = 0; 502 tmEvent->event.modifierMask = 0; 503 tmEvent->event.eventType = (TMLongCard) event->type; 504 tmEvent->event.lateModifiers = NULL; 505 tmEvent->event.matchEvent = NULL; 506 tmEvent->event.standard = FALSE; 507 508 switch (event->type) { 509 510 case KeyPress: 511 case KeyRelease: 512 tmEvent->event.eventCode = event->xkey.keycode; 513 tmEvent->event.modifiers = event->xkey.state; 514 break; 515 516 case ButtonPress: 517 case ButtonRelease: 518 tmEvent->event.eventCode = event->xbutton.button; 519 tmEvent->event.modifiers = event->xbutton.state; 520 break; 521 522 case MotionNotify: 523 tmEvent->event.eventCode = (TMLongCard) event->xmotion.is_hint; 524 tmEvent->event.modifiers = event->xmotion.state; 525 break; 526 527 case EnterNotify: 528 case LeaveNotify: 529 tmEvent->event.eventCode = (TMLongCard) event->xcrossing.mode; 530 tmEvent->event.modifiers = event->xcrossing.state; 531 break; 532 533 case PropertyNotify: 534 tmEvent->event.eventCode = event->xproperty.atom; 535 tmEvent->event.modifiers = 0; 536 break; 537 538 case SelectionClear: 539 tmEvent->event.eventCode = event->xselectionclear.selection; 540 tmEvent->event.modifiers = 0; 541 break; 542 543 case SelectionRequest: 544 tmEvent->event.eventCode = event->xselectionrequest.selection; 545 tmEvent->event.modifiers = 0; 546 break; 547 548 case SelectionNotify: 549 tmEvent->event.eventCode = event->xselection.selection; 550 tmEvent->event.modifiers = 0; 551 break; 552 553 case ClientMessage: 554 tmEvent->event.eventCode = event->xclient.message_type; 555 tmEvent->event.modifiers = 0; 556 break; 557 558 case MappingNotify: 559 tmEvent->event.eventCode = (TMLongCard) event->xmapping.request; 560 tmEvent->event.modifiers = 0; 561 break; 562 563 case FocusIn: 564 case FocusOut: 565 tmEvent->event.eventCode = (TMLongCard) event->xfocus.mode; 566 tmEvent->event.modifiers = 0; 567 break; 568 569 default: 570 tmEvent->event.eventCode = 0; 571 tmEvent->event.modifiers = 0; 572 break; 573 } 574} 575 576 577static unsigned long GetTime( 578 XtTM tm, 579 XEvent *event) 580{ 581 switch (event->type) { 582 583 case KeyPress: 584 case KeyRelease: 585 return event->xkey.time; 586 587 case ButtonPress: 588 case ButtonRelease: 589 return event->xbutton.time; 590 591 default: 592 return tm->lastEventTime; 593 594 } 595 596} 597 598static void HandleActions( 599 Widget w, 600 XEvent *event, 601 TMSimpleStateTree stateTree, 602 Widget accelWidget, 603 XtActionProc *procs, 604 ActionRec *actions) 605{ 606 ActionHook actionHookList; 607 Widget bindWidget; 608 609 bindWidget = accelWidget ? accelWidget : w; 610 if (accelWidget && !XtIsSensitive(accelWidget) && 611 (event->type == KeyPress || event->type == KeyRelease || 612 event->type == ButtonPress || event->type == ButtonRelease || 613 event->type == MotionNotify || event->type == EnterNotify || 614 event->type == LeaveNotify || event->type == FocusIn || 615 event->type == FocusOut)) 616 return; 617 618 actionHookList = XtWidgetToApplicationContext(w)->action_hook_list; 619 620 while (actions != NULL) { 621 /* perform any actions */ 622 if (procs[actions->idx] != NULL) { 623 if (actionHookList) { 624 ActionHook hook; 625 ActionHook next_hook; 626 String procName = 627 XrmQuarkToString(stateTree->quarkTbl[actions->idx] ); 628 629 for (hook = actionHookList; hook != NULL; ) { 630 /* 631 * Need to cache hook->next because the following action 632 * proc may free hook via XtRemoveActionHook making 633 * hook->next invalid upon return from the action proc. 634 */ 635 next_hook = hook->next; 636 (*hook->proc)(bindWidget, 637 hook->closure, 638 procName, 639 event, 640 actions->params, 641 &actions->num_params 642 ); 643 hook = next_hook; 644 } 645 } 646 (*(procs[actions->idx])) 647 (bindWidget, event, 648 actions->params, &actions->num_params ); 649 } 650 actions = actions->next; 651 } 652} 653 654typedef struct { 655 unsigned int isCycleStart:1; 656 unsigned int isCycleEnd:1; 657 TMShortCard typeIndex; 658 TMShortCard modIndex; 659}MatchPairRec, *MatchPair; 660 661typedef struct TMContextRec{ 662 TMShortCard numMatches; 663 TMShortCard maxMatches; 664 MatchPair matches; 665}TMContextRec, *TMContext; 666 667static TMContextRec contextCache[2]; 668 669#define GetContextPtr(tm) ((TMContext *)&(tm->current_state)) 670 671#define TM_CONTEXT_MATCHES_ALLOC 4 672#define TM_CONTEXT_MATCHES_REALLOC 2 673 674static void PushContext( 675 TMContext *contextPtr, 676 StatePtr newState) 677{ 678 TMContext context = *contextPtr; 679 680 LOCK_PROCESS; 681 if (context == NULL) 682 { 683 if (contextCache[0].numMatches == 0) 684 context = &contextCache[0]; 685 else if (contextCache[1].numMatches == 0) 686 context = &contextCache[1]; 687 if (!context) 688 { 689 context = XtNew(TMContextRec); 690 context->matches = NULL; 691 context->numMatches = 692 context->maxMatches = 0; 693 } 694 } 695 if (context->numMatches && 696 context->matches[context->numMatches-1].isCycleEnd) 697 { 698 TMShortCard i; 699 for (i = 0; 700 i < context->numMatches && 701 !(context->matches[i].isCycleStart); 702 i++){}; 703 if (i < context->numMatches) 704 context->numMatches = (TMShortCard) (i + 1); 705#ifdef DEBUG 706 else 707 XtWarning("pushing cycle end with no cycle start"); 708#endif /* DEBUG */ 709 } 710 else 711 { 712 if (context->numMatches == context->maxMatches) 713 { 714 if (context->maxMatches == 0) 715 context->maxMatches = (TMShortCard) (context->maxMatches + TM_CONTEXT_MATCHES_ALLOC); 716 else 717 context->maxMatches = (TMShortCard) (context->maxMatches + TM_CONTEXT_MATCHES_REALLOC); 718 context->matches = (MatchPairRec *) 719 XtRealloc((char *)context->matches, 720 (Cardinal)(context->maxMatches * sizeof(MatchPairRec))); 721 } 722 context->matches[context->numMatches].isCycleStart = newState->isCycleStart; 723 context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd; 724 context->matches[context->numMatches].typeIndex = newState->typeIndex; 725 context->matches[context->numMatches++].modIndex = newState->modIndex; 726 *contextPtr = context; 727 } 728 UNLOCK_PROCESS; 729} 730 731static void FreeContext( 732 TMContext *contextPtr) 733{ 734 TMContext context = NULL; 735 736 LOCK_PROCESS; 737 738 if (&contextCache[0] == *contextPtr) 739 context = &contextCache[0]; 740 else if (&contextCache[1] == *contextPtr) 741 context = &contextCache[1]; 742 743 if (context) 744 context->numMatches = 0; 745 else if (*contextPtr) 746 { 747 XtFree ((char *) ((*contextPtr)->matches)); 748 XtFree((char *)*contextPtr); 749 } 750 751 *contextPtr = NULL; 752 UNLOCK_PROCESS; 753} 754 755static int MatchExact( 756 TMSimpleStateTree stateTree, 757 int startIndex, 758 TMShortCard typeIndex, 759 TMShortCard modIndex) 760{ 761 TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]); 762 int i; 763 764 for (i = startIndex; 765 i < (int)stateTree->numBranchHeads; 766 i++, branchHead++) 767 { 768 if ((branchHead->typeIndex == typeIndex) && 769 (branchHead->modIndex == modIndex)) 770 return i; 771 } 772 return (TM_NO_MATCH); 773} 774 775 776 777static void HandleSimpleState( 778 Widget w, 779 XtTM tmRecPtr, 780 TMEventRec *curEventPtr) 781{ 782 XtTranslations xlations = tmRecPtr->translations; 783 TMContext *contextPtr = GetContextPtr(tmRecPtr); 784 TMShortCard i; 785 ActionRec *actions = NULL; 786 Boolean matchExact = False; 787 Boolean match = False; 788 StatePtr complexMatchState = NULL; 789 TMShortCard typeIndex = 0, modIndex = 0; 790 int matchTreeIndex = TM_NO_MATCH; 791 792 LOCK_PROCESS; 793 for (i = 0; 794 ((!match || !complexMatchState) && (i < xlations->numStateTrees)); 795 i++){ 796 int currIndex = -1; 797 TMSimpleStateTree stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; 798 799 /* 800 * don't process this tree if we're only looking for a 801 * complexMatchState and there are no complex states 802 */ 803 while (!(match && stateTree->isSimple) && 804 ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) { 805 currIndex++; 806 if (matchExact) 807 currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex); 808 else 809 currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr); 810 if (currIndex != TM_NO_MATCH) { 811 TMBranchHead branchHead; 812 StatePtr currState; 813 814 branchHead = &stateTree->branchHeadTbl[currIndex]; 815 if (branchHead->isSimple) 816 currState = NULL; 817 else 818 currState = ((TMComplexStateTree)stateTree) 819 ->complexBranchHeadTbl[TMBranchMore(branchHead)]; 820 821 /* 822 * first check for a complete match 823 */ 824 if (!match) { 825 if (branchHead->hasActions) { 826 if (branchHead->isSimple) { 827 static ActionRec dummyAction; 828 829 dummyAction.idx = TMBranchMore(branchHead); 830 actions = &dummyAction; 831 } 832 else 833 actions = currState->actions; 834 tmRecPtr->lastEventTime = 835 GetTime(tmRecPtr, curEventPtr->xev); 836 FreeContext((TMContext 837 *)&tmRecPtr->current_state); 838 match = True; 839 matchTreeIndex = i; 840 } 841 /* 842 * if it doesn't have actions and 843 * it's bc mode then it's a potential match node that is 844 * used to match later sequences. 845 */ 846 if (!TMNewMatchSemantics() && !matchExact) { 847 matchExact = True; 848 typeIndex = branchHead->typeIndex; 849 modIndex = branchHead->modIndex; 850 } 851 } 852 /* 853 * check for it being an event sequence which can be 854 * a future match 855 */ 856 if (!branchHead->isSimple && 857 !branchHead->hasActions && 858 !complexMatchState) 859 complexMatchState = currState; 860 } 861 } 862 } 863 if (match) 864 { 865 TMBindData bindData = (TMBindData) tmRecPtr->proc_table; 866 XtActionProc *procs; 867 Widget accelWidget; 868 869 if (bindData->simple.isComplex) { 870 TMComplexBindProcs bindProcs = 871 TMGetComplexBindEntry(bindData, matchTreeIndex); 872 procs = bindProcs->procs; 873 accelWidget = bindProcs->widget; 874 } 875 else { 876 TMSimpleBindProcs bindProcs = 877 TMGetSimpleBindEntry(bindData, matchTreeIndex); 878 procs = bindProcs->procs; 879 accelWidget = NULL; 880 } 881 HandleActions 882 (w, 883 curEventPtr->xev, 884 (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex], 885 accelWidget, 886 procs, 887 actions); 888 } 889 if (complexMatchState) 890 PushContext(contextPtr, complexMatchState); 891 UNLOCK_PROCESS; 892} 893 894static int MatchComplexBranch( 895 TMComplexStateTree stateTree, 896 int startIndex, 897 TMContext context, 898 StatePtr *leafStateRtn) 899{ 900 TMShortCard i; 901 902 LOCK_PROCESS; 903 for (i = (TMShortCard) startIndex; i < stateTree->numComplexBranchHeads; i++) 904 { 905 StatePtr candState; 906 TMShortCard numMatches = context->numMatches; 907 MatchPair statMatch = context->matches; 908 909 for (candState = stateTree->complexBranchHeadTbl[i]; 910 numMatches && candState; 911 numMatches--, statMatch++, candState = candState->nextLevel) 912 { 913 if ((statMatch->typeIndex != candState->typeIndex) || 914 (statMatch->modIndex != candState->modIndex)) 915 break; 916 } 917 if (numMatches == 0) { 918 *leafStateRtn = candState; 919 UNLOCK_PROCESS; 920 return i; 921 } 922 } 923 *leafStateRtn = NULL; 924 UNLOCK_PROCESS; 925 return (TM_NO_MATCH); 926} 927 928static StatePtr TryCurrentTree( 929 TMComplexStateTree *stateTreePtr, 930 XtTM tmRecPtr, 931 TMEventRec *curEventPtr) 932{ 933 StatePtr candState = NULL, matchState = NULL; 934 TMContext *contextPtr = GetContextPtr(tmRecPtr); 935 TMTypeMatch typeMatch; 936 TMModifierMatch modMatch; 937 int currIndex = -1; 938 939 /* 940 * we want the first sequence that both matches and has actions. 941 * we keep on looking till we find both 942 */ 943 LOCK_PROCESS; 944 while ((currIndex = 945 MatchComplexBranch(*stateTreePtr, 946 ++currIndex, 947 (*contextPtr), 948 &candState)) 949 != TM_NO_MATCH) { 950 if (candState != NULL) { 951 typeMatch = TMGetTypeMatch(candState->typeIndex); 952 modMatch = TMGetModifierMatch(candState->modIndex); 953 954 /* does this state's index match? --> done */ 955 if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) 956 { 957 if (candState->actions) { 958 UNLOCK_PROCESS; 959 return candState; 960 } 961 else 962 matchState = candState; 963 } 964 /* is this an event timer? */ 965 if (typeMatch->eventType == _XtEventTimerEventType) { 966 StatePtr nextState = candState->nextLevel; 967 968 /* does the succeeding state match? */ 969 if (nextState != NULL) { 970 TMTypeMatch nextTypeMatch; 971 TMModifierMatch nextModMatch; 972 973 nextTypeMatch = TMGetTypeMatch(nextState->typeIndex); 974 nextModMatch = TMGetModifierMatch(nextState->modIndex); 975 976 /* is it within the timeout? */ 977 if (MatchIncomingEvent(curEventPtr, 978 nextTypeMatch, 979 nextModMatch)) { 980 XEvent *xev = curEventPtr->xev; 981 unsigned long time = GetTime(tmRecPtr, xev); 982 XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display); 983 unsigned long delta = (unsigned long) pd->multi_click_time; 984 985 if ((tmRecPtr->lastEventTime + delta) >= time) { 986 if (nextState->actions) { 987 UNLOCK_PROCESS; 988 return candState; 989 } 990 else 991 matchState = candState; 992 } 993 } 994 } 995 } 996 } 997 } 998 UNLOCK_PROCESS; 999 return matchState; 1000} 1001 1002static void HandleComplexState( 1003 Widget w, 1004 XtTM tmRecPtr, 1005 TMEventRec *curEventPtr) 1006{ 1007 XtTranslations xlations = tmRecPtr->translations; 1008 TMContext *contextPtr = GetContextPtr(tmRecPtr); 1009 TMShortCard i, matchTreeIndex = 0; 1010 StatePtr matchState = NULL, candState; 1011 TMComplexStateTree *stateTreePtr = 1012 (TMComplexStateTree *)&xlations->stateTreeTbl[0]; 1013 1014 LOCK_PROCESS; 1015 for (i = 0; 1016 i < xlations->numStateTrees; 1017 i++, stateTreePtr++) { 1018 /* 1019 * some compilers sign extend Boolean bit fields so test for 1020 * false ||| 1021 */ 1022 if (((*stateTreePtr)->isSimple == False) && 1023 (candState = TryCurrentTree(stateTreePtr, 1024 tmRecPtr, 1025 curEventPtr))) { 1026 if (!matchState || candState->actions) { 1027 matchTreeIndex = i; 1028 matchState = candState; 1029 if (candState->actions) 1030 break; 1031 } 1032 } 1033 } 1034 if (matchState == NULL){ 1035 /* couldn't find it... */ 1036 if (!Ignore(curEventPtr)) 1037 { 1038 FreeContext(contextPtr); 1039 HandleSimpleState(w, tmRecPtr, curEventPtr); 1040 } 1041 } 1042 else { 1043 TMBindData bindData = (TMBindData) tmRecPtr->proc_table; 1044 XtActionProc *procs; 1045 Widget accelWidget; 1046 TMTypeMatch typeMatch; 1047 1048 typeMatch = TMGetTypeMatch(matchState->typeIndex); 1049 1050 PushContext(contextPtr, matchState); 1051 if (typeMatch->eventType == _XtEventTimerEventType) { 1052 matchState = matchState->nextLevel; 1053 PushContext(contextPtr, matchState); 1054 } 1055 tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev); 1056 1057 if (bindData->simple.isComplex) { 1058 TMComplexBindProcs bindProcs = 1059 TMGetComplexBindEntry(bindData, matchTreeIndex); 1060 procs = bindProcs->procs; 1061 accelWidget = bindProcs->widget; 1062 } 1063 else { 1064 TMSimpleBindProcs bindProcs = 1065 TMGetSimpleBindEntry(bindData, matchTreeIndex); 1066 procs = bindProcs->procs; 1067 accelWidget = NULL; 1068 } 1069 HandleActions(w, 1070 curEventPtr->xev, 1071 (TMSimpleStateTree) 1072 xlations->stateTreeTbl[matchTreeIndex], 1073 accelWidget, 1074 procs, 1075 matchState->actions); 1076 } 1077 UNLOCK_PROCESS; 1078} 1079 1080 1081void _XtTranslateEvent ( 1082 Widget w, 1083 XEvent * event) 1084{ 1085 XtTM tmRecPtr = &w->core.tm; 1086 TMEventRec curEvent; 1087 StatePtr current_state = tmRecPtr->current_state; 1088 1089 XEventToTMEvent (event, &curEvent); 1090 1091 if (! tmRecPtr->translations) { 1092 XtAppWarningMsg(XtWidgetToApplicationContext(w), 1093 XtNtranslationError,"nullTable",XtCXtToolkitError, 1094 "Can't translate event through NULL table", 1095 NULL, NULL); 1096 return ; 1097 } 1098 if (current_state == NULL) 1099 HandleSimpleState(w, tmRecPtr, &curEvent); 1100 else 1101 HandleComplexState(w, tmRecPtr, &curEvent); 1102} 1103 1104 1105/*ARGSUSED*/ 1106static StatePtr NewState( 1107 TMParseStateTree stateTree, 1108 TMShortCard typeIndex, 1109 TMShortCard modIndex) 1110{ 1111 StatePtr state = XtNew(StateRec); 1112 1113#ifdef TRACE_TM 1114 LOCK_PROCESS; 1115 _XtGlobalTM.numComplexStates++; 1116 UNLOCK_PROCESS; 1117#endif /* TRACE_TM */ 1118 state->typeIndex = typeIndex; 1119 state->modIndex = modIndex; 1120 state->nextLevel = NULL; 1121 state->actions = NULL; 1122 state->isCycleStart = state->isCycleEnd = False; 1123 return state; 1124} 1125 1126/* 1127 * This routine is an iterator for state trees. If the func returns 1128 * true then iteration is over. 1129 */ 1130void _XtTraverseStateTree( 1131 TMStateTree tree, 1132 _XtTraversalProc func, 1133 XtPointer data) 1134{ 1135 TMComplexStateTree stateTree = (TMComplexStateTree)tree; 1136 TMBranchHead currBH; 1137 TMShortCard i; 1138 StateRec dummyStateRec, *dummyState = &dummyStateRec; 1139 ActionRec dummyActionRec, *dummyAction = &dummyActionRec; 1140 Boolean firstSimple = True; 1141 StatePtr currState; 1142 1143 /* first traverse the complex states */ 1144 if (stateTree->isSimple == False) 1145 for (i = 0; i < stateTree->numComplexBranchHeads; i++) { 1146 currState = stateTree->complexBranchHeadTbl[i]; 1147 for (; currState; currState = currState->nextLevel) { 1148 if (func(currState, data)) 1149 return; 1150 if (currState->isCycleEnd) 1151 break; 1152 } 1153 } 1154 1155 /* now traverse the simple ones */ 1156 for (i = 0, currBH = stateTree->branchHeadTbl; 1157 i < stateTree->numBranchHeads; 1158 i++, currBH++) 1159 { 1160 if (currBH->isSimple && currBH->hasActions) 1161 { 1162 if (firstSimple) 1163 { 1164 XtBZero((char *) dummyState, sizeof(StateRec)); 1165 XtBZero((char *) dummyAction, sizeof(ActionRec)); 1166 dummyState->actions = dummyAction; 1167 firstSimple = False; 1168 } 1169 dummyState->typeIndex = currBH->typeIndex; 1170 dummyState->modIndex = currBH->modIndex; 1171 dummyAction->idx = currBH->more; 1172 if (func(dummyState, data)) 1173 return; 1174 } 1175 } 1176} 1177 1178static EventMask EventToMask( 1179 TMTypeMatch typeMatch, 1180 TMModifierMatch modMatch) 1181{ 1182 EventMask returnMask; 1183 unsigned long eventType = typeMatch->eventType; 1184 1185 if (eventType == MotionNotify) { 1186 Modifiers modifierMask = (Modifiers) modMatch->modifierMask; 1187 Modifiers tempMask; 1188 1189 returnMask = 0; 1190 if (modifierMask == 0) { 1191 if (modMatch->modifiers == AnyButtonMask) 1192 return ButtonMotionMask; 1193 else 1194 return PointerMotionMask; 1195 } 1196 tempMask = modifierMask & 1197 (Button1Mask | Button2Mask | Button3Mask 1198 | Button4Mask | Button5Mask); 1199 if (tempMask == 0) 1200 return PointerMotionMask; 1201 if (tempMask & Button1Mask) 1202 returnMask |= Button1MotionMask; 1203 if (tempMask & Button2Mask) 1204 returnMask |= Button2MotionMask; 1205 if (tempMask & Button3Mask) 1206 returnMask |= Button3MotionMask; 1207 if (tempMask & Button4Mask) 1208 returnMask |= Button4MotionMask; 1209 if (tempMask & Button5Mask) 1210 returnMask |= Button5MotionMask; 1211 return returnMask; 1212 } 1213 returnMask = _XtConvertTypeToMask((int)eventType); 1214 if (returnMask == (StructureNotifyMask|SubstructureNotifyMask)) 1215 returnMask = StructureNotifyMask; 1216 return returnMask; 1217} 1218 1219/*ARGSUSED*/ 1220static void DispatchMappingNotify( 1221 Widget widget, /* will be NULL from _RefreshMapping */ 1222 XtPointer closure, /* real Widget */ 1223 XtPointer call_data) /* XEvent* */ 1224{ 1225 _XtTranslateEvent( (Widget)closure, (XEvent*)call_data); 1226} 1227 1228 1229/*ARGSUSED*/ 1230static void RemoveFromMappingCallbacks( 1231 Widget widget, 1232 XtPointer closure, /* target widget */ 1233 XtPointer call_data) 1234{ 1235 _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks, 1236 DispatchMappingNotify, 1237 closure 1238 ); 1239} 1240 1241static Boolean AggregateEventMask( 1242 StatePtr state, 1243 XtPointer data) 1244{ 1245 LOCK_PROCESS; 1246 *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex), 1247 TMGetModifierMatch(state->modIndex)); 1248 UNLOCK_PROCESS; 1249 return False; 1250} 1251 1252void _XtInstallTranslations( 1253 Widget widget) 1254{ 1255 XtTranslations xlations; 1256 Cardinal i; 1257 Boolean mappingNotifyInterest = False; 1258 1259 xlations = widget->core.tm.translations; 1260 if (xlations == NULL) return; 1261 1262 /* 1263 * check for somebody stuffing the translations directly into the 1264 * instance structure. We will end up being called again out of 1265 * ComposeTranslations but we *should* have bindings by then 1266 */ 1267 if (widget->core.tm.proc_table == NULL) { 1268 _XtMergeTranslations(widget, NULL, XtTableReplace); 1269 /* 1270 * if we're realized then we'll be called out of 1271 * ComposeTranslations 1272 */ 1273 if (XtIsRealized(widget)) 1274 return; 1275 } 1276 1277 xlations->eventMask = 0; 1278 for (i = 0; 1279 i < xlations->numStateTrees; 1280 i++) 1281 { 1282 TMStateTree stateTree = xlations->stateTreeTbl[i]; 1283 _XtTraverseStateTree(stateTree, 1284 AggregateEventMask, 1285 (XtPointer)&xlations->eventMask); 1286 mappingNotifyInterest = (Boolean) (mappingNotifyInterest | stateTree->simple.mappingNotifyInterest); 1287 } 1288 /* double click needs to make sure that you have selected on both 1289 button down and up. */ 1290 1291 if (xlations->eventMask & ButtonPressMask) 1292 xlations->eventMask |= ButtonReleaseMask; 1293 if (xlations->eventMask & ButtonReleaseMask) 1294 xlations->eventMask |= ButtonPressMask; 1295 1296 if (mappingNotifyInterest) { 1297 XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget)); 1298 if (pd->mapping_callbacks) 1299 _XtAddCallbackOnce(&(pd->mapping_callbacks), 1300 DispatchMappingNotify, 1301 (XtPointer)widget); 1302 else 1303 _XtAddCallback(&(pd->mapping_callbacks), 1304 DispatchMappingNotify, 1305 (XtPointer)widget); 1306 1307 if (widget->core.destroy_callbacks != NULL) 1308 _XtAddCallbackOnce( (InternalCallbackList *) 1309 &widget->core.destroy_callbacks, 1310 RemoveFromMappingCallbacks, 1311 (XtPointer)widget 1312 ); 1313 else 1314 _XtAddCallback((InternalCallbackList *) 1315 &widget->core.destroy_callbacks, 1316 RemoveFromMappingCallbacks, 1317 (XtPointer)widget 1318 ); 1319 } 1320 _XtBindActions(widget, (XtTM)&widget->core.tm); 1321 _XtRegisterGrabs(widget); 1322} 1323 1324void _XtRemoveTranslations( 1325 Widget widget) 1326{ 1327 Cardinal i; 1328 Boolean mappingNotifyInterest = False; 1329 XtTranslations xlations = widget->core.tm.translations; 1330 1331 if (xlations == NULL) 1332 return; 1333 1334 for (i = 0; 1335 i < xlations->numStateTrees; 1336 i++) 1337 { 1338 TMSimpleStateTree stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; 1339 mappingNotifyInterest = (Boolean) (mappingNotifyInterest | stateTree->mappingNotifyInterest); 1340 } 1341 if (mappingNotifyInterest) 1342 RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL); 1343} 1344 1345static void _XtUninstallTranslations( 1346 Widget widget) 1347{ 1348 XtTranslations xlations = widget->core.tm.translations; 1349 1350 _XtUnbindActions(widget, 1351 xlations, 1352 (TMBindData)widget->core.tm.proc_table); 1353 _XtRemoveTranslations(widget); 1354 widget->core.tm.translations = NULL; 1355 FreeContext((TMContext *)&widget->core.tm.current_state); 1356} 1357 1358void _XtDestroyTMData( 1359 Widget widget) 1360{ 1361 TMComplexBindData cBindData; 1362 1363 _XtUninstallTranslations(widget); 1364 1365 if ((cBindData = (TMComplexBindData)widget->core.tm.proc_table)) { 1366 if (cBindData->isComplex) { 1367 ATranslations nXlations = (ATranslations) cBindData->accel_context; 1368 while (nXlations){ 1369 ATranslations aXlations = nXlations; 1370 nXlations = nXlations->next; 1371 XtFree((char *)aXlations); 1372 } 1373 } 1374 XtFree((char *)cBindData); 1375 } 1376} 1377 1378/*** Public procedures ***/ 1379 1380 1381void XtUninstallTranslations( 1382 Widget widget) 1383{ 1384 EventMask oldMask; 1385 Widget hookobj; 1386 WIDGET_TO_APPCON(widget); 1387 1388 LOCK_APP(app); 1389 if (! widget->core.tm.translations) { 1390 UNLOCK_APP(app); 1391 return; 1392 } 1393 oldMask = widget->core.tm.translations->eventMask; 1394 _XtUninstallTranslations(widget); 1395 if (XtIsRealized(widget) && oldMask) 1396 XSelectInput(XtDisplay(widget), XtWindow(widget), 1397 (long) XtBuildEventMask(widget)); 1398 hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 1399 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 1400 XtChangeHookDataRec call_data; 1401 1402 call_data.type = XtHuninstallTranslations; 1403 call_data.widget = widget; 1404 XtCallCallbackList(hookobj, 1405 ((HookObject)hookobj)->hooks.changehook_callbacks, 1406 (XtPointer)&call_data); 1407 } 1408 UNLOCK_APP(app); 1409} 1410 1411XtTranslations _XtCreateXlations( 1412 TMStateTree *stateTrees, 1413 TMShortCard numStateTrees, 1414 XtTranslations first, 1415 XtTranslations second) 1416{ 1417 XtTranslations xlations; 1418 TMShortCard i; 1419 1420 xlations = (XtTranslations) 1421 __XtMalloc((Cardinal)(sizeof(TranslationData) + 1422 (size_t)(numStateTrees - 1) * sizeof(TMStateTree))); 1423#ifdef TRACE_TM 1424 LOCK_PROCESS; 1425 if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) { 1426 _XtGlobalTM.tmTblSize = (TMShortCard)(_XtGlobalTM.tmTblSize + 16); 1427 _XtGlobalTM.tmTbl = (XtTranslations *) 1428 XtRealloc((char *)_XtGlobalTM.tmTbl, 1429 (Cardinal)(_XtGlobalTM.tmTblSize * sizeof(XtTranslations))); 1430 } 1431 _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations; 1432 UNLOCK_PROCESS; 1433#endif /* TRACE_TM */ 1434 1435 xlations->composers[0] = first; 1436 xlations->composers[1] = second; 1437 xlations->hasBindings = False; 1438 xlations->operation = XtTableReplace; 1439 1440 for (i = 0;i < numStateTrees; i++) 1441 { 1442 xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i]; 1443 stateTrees[i]->simple.refCount++; 1444 } 1445 xlations->numStateTrees = numStateTrees; 1446 xlations->eventMask = 0; 1447 return xlations; 1448} 1449 1450TMStateTree _XtParseTreeToStateTree( 1451 TMParseStateTree parseTree) 1452{ 1453 TMSimpleStateTree simpleTree; 1454 unsigned int tableSize; 1455 1456 if (parseTree->numComplexBranchHeads) { 1457 TMComplexStateTree complexTree; 1458 1459 complexTree = XtNew(TMComplexStateTreeRec); 1460 complexTree->isSimple = False; 1461 tableSize = (unsigned) (parseTree->numComplexBranchHeads * sizeof(StatePtr)); 1462 complexTree->complexBranchHeadTbl = (StatePtr *) 1463 __XtMalloc(tableSize); 1464 XtMemmove(complexTree->complexBranchHeadTbl, 1465 parseTree->complexBranchHeadTbl, tableSize); 1466 complexTree->numComplexBranchHeads = 1467 parseTree->numComplexBranchHeads; 1468 simpleTree = (TMSimpleStateTree)complexTree; 1469 } 1470 else { 1471 simpleTree = XtNew(TMSimpleStateTreeRec); 1472 simpleTree->isSimple = True; 1473 } 1474 simpleTree->isAccelerator = parseTree->isAccelerator; 1475 simpleTree->refCount = 0; 1476 simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest; 1477 1478 tableSize = (unsigned) (parseTree->numBranchHeads * sizeof(TMBranchHeadRec)); 1479 simpleTree->branchHeadTbl = (TMBranchHead) 1480 __XtMalloc(tableSize); 1481 XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize); 1482 simpleTree->numBranchHeads = parseTree->numBranchHeads; 1483 1484 tableSize = (unsigned) (parseTree->numQuarks * sizeof(XrmQuark)); 1485 simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize); 1486 XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize); 1487 simpleTree->numQuarks = parseTree->numQuarks; 1488 1489 return (TMStateTree)simpleTree; 1490} 1491 1492static void FreeActions( 1493 ActionPtr actions) 1494{ 1495 ActionPtr action; 1496 TMShortCard i; 1497 for (action = actions; action;) { 1498 ActionPtr nextAction = action->next; 1499 for (i = (TMShortCard) action->num_params; i;) { 1500 XtFree( (_XtString)action->params[--i] ); 1501 } 1502 XtFree( (char*)action->params ); 1503 XtFree((char*) action); 1504 action = nextAction; 1505 } 1506} 1507 1508/*ARGSUSED*/ 1509static void AmbigActions( 1510 EventSeqPtr initialEvent, 1511 StatePtr *state, 1512 TMParseStateTree stateTree) 1513{ 1514 String params[3]; 1515 Cardinal numParams = 0; 1516 1517 params[numParams++] = _XtPrintEventSeq(initialEvent, NULL); 1518 params[numParams++] = _XtPrintActions((*state)->actions, 1519 stateTree->quarkTbl); 1520 XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError, 1521 "Previous entry was: %s %s", params, &numParams); 1522 XtFree((char *)params[0]); 1523 XtFree((char *)params[1]); 1524 numParams = 0; 1525 params[numParams++] = _XtPrintActions(initialEvent->actions, 1526 stateTree->quarkTbl); 1527 XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError, 1528 "New actions are:%s", params, &numParams); 1529 XtFree((char *)params[0]); 1530 XtWarningMsg (XtNtranslationError,"ambiguousActions", 1531 XtCXtToolkitError, 1532 "Overriding earlier translation manager actions.", 1533 NULL, NULL); 1534 1535 FreeActions((*state)->actions); 1536 (*state)->actions = NULL; 1537} 1538 1539 1540void _XtAddEventSeqToStateTree( 1541 EventSeqPtr eventSeq, 1542 TMParseStateTree stateTree) 1543{ 1544 StatePtr *state; 1545 EventSeqPtr initialEvent = eventSeq; 1546 TMBranchHead branchHead; 1547 TMShortCard idx, modIndex, typeIndex; 1548 1549 if (eventSeq == NULL) return; 1550 1551 /* note that all states in the event seq passed in start out null */ 1552 /* we fill them in with the matching state as we traverse the list */ 1553 1554 /* 1555 * We need to free the parser data structures !!! 1556 */ 1557 1558 typeIndex = _XtGetTypeIndex(&eventSeq->event); 1559 modIndex = _XtGetModifierIndex(&eventSeq->event); 1560 idx = GetBranchHead(stateTree, typeIndex, modIndex, False); 1561 branchHead = &stateTree->branchHeadTbl[idx]; 1562 1563 /* 1564 * Need to check for pre-existing actions with same lhs ||| 1565 */ 1566 1567 /* 1568 * Check for optimized case. Don't assume that the eventSeq has actions. 1569 */ 1570 if (!eventSeq->next && 1571 eventSeq->actions && 1572 !eventSeq->actions->next && 1573 !eventSeq->actions->num_params) 1574 { 1575 if (eventSeq->event.eventType == MappingNotify) 1576 stateTree->mappingNotifyInterest = True; 1577 branchHead->hasActions = True; 1578 XtSetBits(branchHead->more, eventSeq->actions->idx, 13); 1579 FreeActions(eventSeq->actions); 1580 eventSeq->actions = NULL; 1581 return; 1582 } 1583 1584 branchHead->isSimple = False; 1585 if (!eventSeq->next) 1586 branchHead->hasActions = True; 1587 XtSetBits(branchHead->more, GetComplexBranchIndex(stateTree, typeIndex, modIndex), 13); 1588 state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)]; 1589 1590 for (;;) { 1591 *state = NewState(stateTree, typeIndex, modIndex); 1592 1593 if (eventSeq->event.eventType == MappingNotify) 1594 stateTree->mappingNotifyInterest = True; 1595 1596 /* *state now points at state record matching event */ 1597 eventSeq->state = *state; 1598 1599 if (eventSeq->actions != NULL) { 1600 if ((*state)->actions != NULL) 1601 AmbigActions(initialEvent, state, stateTree); 1602 (*state)->actions = eventSeq->actions; 1603#ifdef TRACE_TM 1604 LOCK_PROCESS; 1605 _XtGlobalTM.numComplexActions++; 1606 UNLOCK_PROCESS; 1607#endif /* TRACE_TM */ 1608 } 1609 1610 if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state)) 1611 break; 1612 1613 state = &(*state)->nextLevel; 1614 typeIndex = _XtGetTypeIndex(&eventSeq->event); 1615 modIndex = _XtGetModifierIndex(&eventSeq->event); 1616 LOCK_PROCESS; 1617 if (!TMNewMatchSemantics()) { 1618 /* 1619 * force a potential empty entry into the branch head 1620 * table in order to emulate old matching behavior 1621 */ 1622 (void) GetBranchHead(stateTree, typeIndex, modIndex, True); 1623 } 1624 UNLOCK_PROCESS; 1625 } 1626 1627 if (eventSeq && eventSeq->state) { 1628 /* we've been here before... must be a cycle in the event seq. */ 1629 branchHead->hasCycles = True; 1630 (*state)->nextLevel = eventSeq->state; 1631 eventSeq->state->isCycleStart = True; 1632 (*state)->isCycleEnd = TRUE; 1633 } 1634} 1635 1636 1637/* 1638 * Internal Converter for merging. Old and New must both be valid xlations 1639 */ 1640 1641/*ARGSUSED*/ 1642Boolean _XtCvtMergeTranslations( 1643 Display *dpy, 1644 XrmValuePtr args, 1645 Cardinal *num_args, 1646 XrmValuePtr from, 1647 XrmValuePtr to, 1648 XtPointer *closure_ret) 1649{ 1650 XtTranslations first, second, xlations; 1651 TMStateTree *stateTrees, stackStateTrees[16]; 1652 TMShortCard numStateTrees, i; 1653 1654 if (*num_args != 0) 1655 XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError, 1656 "MergeTM to TranslationTable needs no extra arguments", 1657 NULL, NULL); 1658 1659 if (to->addr != NULL && to->size < sizeof(XtTranslations)) { 1660 to->size = sizeof(XtTranslations); 1661 return False; 1662 } 1663 1664 first = ((TMConvertRec*)from->addr)->old; 1665 second = ((TMConvertRec*)from->addr)->new; 1666 1667 numStateTrees = (TMShortCard) (first->numStateTrees + second->numStateTrees); 1668 1669 stateTrees = (TMStateTree *) 1670 XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees); 1671 1672 for (i = 0; i < first->numStateTrees; i++) 1673 stateTrees[i] = first->stateTreeTbl[i]; 1674 for (i = 0; i < second->numStateTrees; i++) 1675 stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i]; 1676 1677 xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second); 1678 1679 if (to->addr != NULL) { 1680 *(XtTranslations*)to->addr = xlations; 1681 } 1682 else { 1683 static XtTranslations staticStateTable; 1684 staticStateTable = xlations; 1685 to->addr= (XPointer)&staticStateTable; 1686 to->size = sizeof(XtTranslations); 1687 } 1688 1689 XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees); 1690 return True; 1691} 1692 1693 1694static XtTranslations MergeThem( 1695 Widget dest, 1696 XtTranslations first, 1697 XtTranslations second) 1698{ 1699 XtCacheRef cache_ref; 1700 static XrmQuark from_type = NULLQUARK, to_type; 1701 XrmValue from, to; 1702 TMConvertRec convert_rec; 1703 XtTranslations newTable; 1704 1705 LOCK_PROCESS; 1706 if (from_type == NULLQUARK) { 1707 from_type = XrmPermStringToQuark(_XtRStateTablePair); 1708 to_type = XrmPermStringToQuark(XtRTranslationTable); 1709 } 1710 UNLOCK_PROCESS; 1711 from.addr = (XPointer)&convert_rec; 1712 from.size = sizeof(TMConvertRec); 1713 to.addr = (XPointer)&newTable; 1714 to.size = sizeof(XtTranslations); 1715 convert_rec.old = first; 1716 convert_rec.new = second; 1717 1718 LOCK_PROCESS; 1719 if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) { 1720 UNLOCK_PROCESS; 1721 return NULL; 1722 } 1723 UNLOCK_PROCESS; 1724 1725#ifndef REFCNT_TRANSLATIONS 1726 1727 if (cache_ref) 1728 XtAddCallback(dest, XtNdestroyCallback, 1729 XtCallbackReleaseCacheRef, (XtPointer)cache_ref); 1730 1731#endif 1732 1733 return newTable; 1734} 1735 1736/* 1737 * Unmerge will recursively traverse the xlation compose tree and 1738 * generate a new xlation that is the result of all instances of 1739 * xlations being removed. It currently doesn't differentiate between 1740 * the potential that an xlation will be both an accelerator and 1741 * normal. This is not supported by the spec anyway. 1742 */ 1743static XtTranslations UnmergeTranslations( 1744 Widget widget, 1745 XtTranslations xlations, 1746 XtTranslations unmergeXlations, 1747 TMShortCard currIndex, 1748 TMComplexBindProcs oldBindings, 1749 TMShortCard numOldBindings, 1750 TMComplexBindProcs newBindings, 1751 TMShortCard *numNewBindingsRtn) 1752 1753{ 1754 XtTranslations first, second, result; 1755 1756 if (!xlations || (xlations == unmergeXlations)) 1757 return NULL; 1758 1759 if (xlations->composers[0]) { 1760 first = UnmergeTranslations(widget, xlations->composers[0], 1761 unmergeXlations, currIndex, 1762 oldBindings, numOldBindings, 1763 newBindings, numNewBindingsRtn); 1764 } 1765 else 1766 first = NULL; 1767 1768 if (xlations->composers[0] 1769 && xlations->composers[1]) { 1770 second = UnmergeTranslations(widget, xlations->composers[1], 1771 unmergeXlations, 1772 (TMShortCard)(currIndex + 1773 xlations->composers[0]->numStateTrees), 1774 oldBindings, numOldBindings, 1775 newBindings, numNewBindingsRtn); 1776 } 1777 else 1778 second = NULL; 1779 1780 if (first || second) { 1781 if (first && second) { 1782 if ((first != xlations->composers[0]) || 1783 (second != xlations->composers[1])) 1784 result = MergeThem(widget, first, second); 1785 else result = xlations; 1786 } 1787 else { 1788 if (first) 1789 result = first; 1790 else 1791 result = second; 1792 } 1793 } else { /* only update for leaf nodes */ 1794 if (numOldBindings) { 1795 Cardinal i; 1796 for (i = 0; i < xlations->numStateTrees; i++) { 1797 if (xlations->stateTreeTbl[i]->simple.isAccelerator) 1798 newBindings[*numNewBindingsRtn] = 1799 oldBindings[currIndex + i]; 1800 (*numNewBindingsRtn)++; 1801 } 1802 } 1803 result = xlations; 1804 } 1805 return result; 1806} 1807 1808typedef struct { 1809 XtTranslations xlations; 1810 TMComplexBindProcs bindings; 1811}MergeBindRec, *MergeBind; 1812 1813static XtTranslations MergeTranslations( 1814 Widget widget, 1815 XtTranslations oldXlations, 1816 XtTranslations newXlations, 1817 _XtTranslateOp operation, 1818 Widget source, 1819 TMComplexBindProcs oldBindings, 1820 TMComplexBindProcs newBindings, 1821 TMShortCard *numNewRtn) 1822{ 1823 XtTranslations newTable = NULL, xlations; 1824 TMComplexBindProcs bindings; 1825 TMShortCard i, j; 1826 TMStateTree *treePtr; 1827 TMShortCard numNew; 1828 MergeBindRec bindPair[2]; 1829 1830 /* If the new translation has an accelerator context then pull it 1831 * off and pass it and the real xlations in to the caching merge 1832 * routine. 1833 */ 1834 if (newXlations->hasBindings) { 1835 xlations = ((ATranslations) newXlations)->xlations; 1836 bindings = (TMComplexBindProcs) 1837 &((ATranslations) newXlations)->bindTbl[0]; 1838 } 1839 else { 1840 xlations = newXlations; 1841 bindings = NULL; 1842 } 1843 switch(operation) { 1844 case XtTableReplace: 1845 newTable = bindPair[0].xlations = xlations; 1846 bindPair[0].bindings = bindings; 1847 bindPair[1].xlations = NULL; 1848 bindPair[1].bindings = NULL; 1849 break; 1850 case XtTableAugment: 1851 bindPair[0].xlations = oldXlations; 1852 bindPair[0].bindings = oldBindings; 1853 bindPair[1].xlations = xlations; 1854 bindPair[1].bindings = bindings; 1855 newTable = NULL; 1856 break; 1857 case XtTableOverride: 1858 bindPair[0].xlations = xlations; 1859 bindPair[0].bindings = bindings; 1860 bindPair[1].xlations = oldXlations; 1861 bindPair[1].bindings = oldBindings; 1862 newTable = NULL; 1863 break; 1864 } 1865 if (!newTable) 1866 newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations); 1867 1868 for (i = 0, numNew = 0; i < 2; i++) { 1869 if (bindPair[i].xlations) 1870 for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) { 1871 if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) { 1872 if (bindPair[i].bindings) 1873 newBindings[numNew] = bindPair[i].bindings[j]; 1874 else { 1875 newBindings[numNew].widget = source; 1876 newBindings[numNew].aXlations = 1877 bindPair[i].xlations; 1878 } 1879 } 1880 } 1881 } 1882 *numNewRtn = numNew; 1883 treePtr = &newTable->stateTreeTbl[0]; 1884 for (i = 0; i < newTable->numStateTrees; i++, treePtr++) 1885 (*treePtr)->simple.refCount++; 1886 return newTable; 1887} 1888 1889static TMBindData MakeBindData( 1890 TMComplexBindProcs bindings, 1891 TMShortCard numBindings, 1892 TMBindData oldBindData) 1893{ 1894 TMLongCard bytes; 1895 TMShortCard i; 1896 Boolean isComplex; 1897 TMBindData bindData; 1898 1899 if (numBindings == 0) 1900 return NULL; 1901 for (i = 0; i < numBindings; i++) 1902 if (bindings[i].widget) 1903 break; 1904 isComplex = (i < numBindings); 1905 if (isComplex) 1906 bytes = (sizeof(TMComplexBindDataRec) + 1907 ((TMLongCard)(numBindings - 1) * 1908 sizeof(TMComplexBindProcsRec))); 1909 else 1910 bytes = (sizeof(TMSimpleBindDataRec) + 1911 ((TMLongCard)(numBindings - 1) * 1912 sizeof(TMSimpleBindProcsRec))); 1913 1914 bindData = (TMBindData) __XtCalloc((Cardinal) sizeof(char), (Cardinal) bytes); 1915 XtSetBit(bindData->simple.isComplex, isComplex); 1916 if (isComplex) { 1917 TMComplexBindData cBindData = (TMComplexBindData)bindData; 1918 /* 1919 * If there were any accelerator contexts in the old bindData 1920 * then propagate them to the new one. 1921 */ 1922 if (oldBindData && oldBindData->simple.isComplex) 1923 cBindData->accel_context = 1924 ((TMComplexBindData) oldBindData)->accel_context; 1925 XtMemmove((char *)&cBindData->bindTbl[0], (char *)bindings, 1926 numBindings * sizeof(TMComplexBindProcsRec)); 1927 } 1928 return bindData; 1929} 1930 1931/* 1932 * This routine is the central clearinghouse for merging translations 1933 * into a widget. It takes care of preping the action bindings for 1934 * realize time and calling the converter or doing a straight merge if 1935 * the destination is empty. 1936 */ 1937static Boolean ComposeTranslations( 1938 Widget dest, 1939 _XtTranslateOp operation, 1940 Widget source, 1941 XtTranslations newXlations) 1942{ 1943 XtTranslations newTable, oldXlations; 1944 XtTranslations accNewXlations; 1945 EventMask oldMask = 0; 1946 TMBindData bindData; 1947 TMComplexBindProcs oldBindings = NULL; 1948 TMShortCard numOldBindings = 0, numNewBindings = 0, numBytes; 1949 TMComplexBindProcsRec stackBindings[16], *newBindings; 1950 1951 /* 1952 * how should we be handling the refcount decrement for the 1953 * replaced translation table ??? 1954 */ 1955 if (!newXlations) 1956 { 1957 XtAppWarningMsg(XtWidgetToApplicationContext(dest), 1958 XtNtranslationError,"nullTable",XtCXtToolkitError, 1959 "table to (un)merge must not be null", 1960 NULL, NULL); 1961 return False; 1962 } 1963 1964 accNewXlations = newXlations; 1965 newXlations = ((newXlations->hasBindings) 1966 ? ((ATranslations)newXlations)->xlations 1967 : newXlations); 1968 1969 if (!(oldXlations = dest->core.tm.translations)) 1970 operation = XtTableReplace; 1971 1972 /* 1973 * try to avoid generation of duplicate state trees. If the source 1974 * isn't simple (1 state Tree) then it's too much hassle 1975 */ 1976 if (((operation == XtTableAugment) || 1977 (operation == XtTableOverride)) && 1978 (newXlations->numStateTrees == 1)) { 1979 Cardinal i; 1980 for (i = 0; i < oldXlations->numStateTrees; i++) 1981 if (oldXlations->stateTreeTbl[i] == 1982 newXlations->stateTreeTbl[0]) 1983 break; 1984 if (i < oldXlations->numStateTrees) { 1985 if (operation == XtTableAugment) { 1986 /* 1987 * we don't need to do anything since it's already 1988 * there 1989 */ 1990 return True; 1991 } 1992 else {/* operation == XtTableOverride */ 1993 /* 1994 * We'll get rid of the duplicate trees throughout the 1995 * and leave it with a pruned translation table. This 1996 * will only work if the same table has been merged 1997 * into this table (or one of it's composers 1998 */ 1999 _XtUnmergeTranslations(dest, newXlations); 2000 /* 2001 * reset oldXlations so we're back in sync 2002 */ 2003 if (!(oldXlations = dest->core.tm.translations)) 2004 operation = XtTableReplace; 2005 } 2006 } 2007 } 2008 2009 bindData = (TMBindData) dest->core.tm.proc_table; 2010 if (bindData) { 2011 numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0); 2012 if (bindData->simple.isComplex) 2013 oldBindings = &((TMComplexBindData)bindData)->bindTbl[0]; 2014 else 2015 oldBindings = (TMComplexBindProcs) 2016 (&((TMSimpleBindData)bindData)->bindTbl[0]); 2017 } 2018 2019 numBytes =(TMShortCard) ((size_t)((oldXlations ? oldXlations->numStateTrees : 0) 2020 + newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec)); 2021 newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings); 2022 XtBZero((char *)newBindings, numBytes); 2023 2024 if (operation == XtTableUnmerge) { 2025 newTable = UnmergeTranslations(dest, 2026 oldXlations, 2027 newXlations, 2028 0, 2029 oldBindings, numOldBindings, 2030 newBindings, &numNewBindings); 2031#ifdef DEBUG 2032 /* check for no match for unmerge */ 2033 if (newTable == oldXlations) { 2034 XtWarning("attempt to unmerge invalid table"); 2035 XtStackFree((char *)newBindings, (char *)stackBindings); 2036 return(newTable != NULL); 2037 } 2038#endif /* DEBUG */ 2039 } 2040 else { 2041 newTable = MergeTranslations(dest, 2042 oldXlations, 2043 accNewXlations, 2044 operation, 2045 source, 2046 oldBindings, 2047 newBindings, 2048 &numNewBindings); 2049 } 2050 if (XtIsRealized(dest)) { 2051 oldMask = 0; 2052 if (oldXlations) 2053 oldMask = oldXlations->eventMask; 2054 _XtUninstallTranslations(dest); 2055 } 2056 2057 dest->core.tm.proc_table = 2058 (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData); 2059 2060 XtFree((char *)bindData); 2061 2062 dest->core.tm.translations = newTable; 2063 2064 if (XtIsRealized(dest)) { 2065 EventMask mask = 0; 2066 _XtInstallTranslations(dest); 2067 if (newTable) 2068 mask = newTable->eventMask; 2069 if (mask != oldMask) 2070 XSelectInput(XtDisplay(dest), XtWindow(dest), 2071 (long) XtBuildEventMask(dest)); 2072 } 2073 XtStackFree((XtPointer)newBindings, (XtPointer)stackBindings); 2074 return(newTable != NULL); 2075} 2076 2077/* 2078 * If a GetValues is done on a translation resource that contains 2079 * accelerators we need to return the accelerator context in addition 2080 * to the pure translations. Since this means returning memory that 2081 * the client controlls but we still own, we will track the "headers" 2082 * that we return (via a linked list pointed to from the bindData) and 2083 * free it at destroy time. 2084 */ 2085XtTranslations _XtGetTranslationValue( 2086 Widget w) 2087{ 2088 XtTM tmRecPtr = (XtTM) &w->core.tm; 2089 ATranslations *aXlationsPtr; 2090 TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table; 2091 XtTranslations xlations = tmRecPtr->translations; 2092 2093 if (!xlations || !cBindData || !cBindData->isComplex) 2094 return xlations; 2095 2096 /* Walk the list looking to see if we already have generated a 2097 * header for the currently installed translations. If we have, 2098 * just return that header. Otherwise create a new header. 2099 */ 2100 for (aXlationsPtr = (ATranslations *) &cBindData->accel_context; 2101 *aXlationsPtr && (*aXlationsPtr)->xlations != xlations; 2102 aXlationsPtr = &(*aXlationsPtr)->next) 2103 ; 2104 if (*aXlationsPtr) 2105 return (XtTranslations) *aXlationsPtr; 2106 else { 2107 /* create a new aXlations context */ 2108 ATranslations aXlations; 2109 Cardinal numBindings = xlations->numStateTrees; 2110 2111 (*aXlationsPtr) = aXlations = (ATranslations) 2112 __XtMalloc((Cardinal) (sizeof(ATranslationData) + 2113 (numBindings - 1) * sizeof(TMComplexBindProcsRec))); 2114 2115 aXlations->hasBindings = True; 2116 aXlations->xlations = xlations; 2117 aXlations->next = NULL; 2118 XtMemmove((char *) &aXlations->bindTbl[0], 2119 (char *) &cBindData->bindTbl[0], 2120 numBindings * sizeof(TMComplexBindProcsRec)); 2121 return (XtTranslations) aXlations; 2122 } 2123} 2124 2125 2126/*ARGSUSED*/ 2127static void RemoveStateTree( 2128 TMStateTree tree) 2129{ 2130#ifdef REFCNT_TRANSLATIONS 2131 TMComplexStateTree stateTree = (TMComplexStateTree)tree; 2132 2133 if (--stateTree->refCount == 0) { 2134 /* 2135 * should we free/refcount the match recs ? 2136 */ 2137 if (!stateTree->isSimple) { 2138 StatePtr currState, nextState; 2139 TMShortCard i; 2140 for (i = 0; i < stateTree->numComplexBranchHeads; i++) { 2141 currState = 2142 nextState = 2143 stateTree->complexBranchHeadTbl[i]; 2144 for (; nextState;){ 2145 FreeActions(currState->actions); 2146 currState->actions = NULL; 2147 if (!currState->isCycleEnd) 2148 nextState = currState->nextLevel; 2149 else 2150 nextState = NULL; 2151 XtFree( (char*)currState ); 2152 } 2153 } 2154 XtFree((char*)stateTree->complexBranchHeadTbl); 2155 } 2156 XtFree((char*)stateTree->branchHeadTbl); 2157 XtFree((char*)stateTree); 2158 } 2159#endif /* REFCNT_TRANSLATIONS */ 2160} 2161 2162void _XtRemoveStateTreeByIndex( 2163 XtTranslations xlations, 2164 TMShortCard i) 2165{ 2166 TMStateTree *stateTrees = xlations->stateTreeTbl; 2167 2168 RemoveStateTree(stateTrees[i]); 2169 xlations->numStateTrees--; 2170 2171 for (; i < xlations->numStateTrees; i++) 2172 { 2173 stateTrees[i] = stateTrees[i+1]; 2174 } 2175} 2176 2177/* ARGSUSED */ 2178void _XtFreeTranslations( 2179 XtAppContext app, 2180 XrmValuePtr toVal, 2181 XtPointer closure, 2182 XrmValuePtr args, 2183 Cardinal *num_args) 2184{ 2185 XtTranslations xlations; 2186 int i; 2187 2188 if (*num_args != 0) 2189 XtAppWarningMsg(app, 2190 "invalidParameters","freeTranslations",XtCXtToolkitError, 2191 "Freeing XtTranslations requires no extra arguments", 2192 NULL, NULL); 2193 2194 xlations = *(XtTranslations*)toVal->addr; 2195 for (i = 0; i < (int)xlations->numStateTrees; i++) 2196 RemoveStateTree(xlations->stateTreeTbl[i]); 2197 XtFree((char *)xlations); 2198} 2199 2200/* The spec is not clear on when actions specified in accelerators are bound; 2201 * Bind them at Realize the same as translations 2202 */ 2203void XtInstallAccelerators( 2204 Widget destination, Widget source) 2205{ 2206 XtTranslations aXlations; 2207 _XtTranslateOp op; 2208 WIDGET_TO_APPCON(destination); 2209 2210 /* 2211 * test that it was parsed as an accelarator table. Even though 2212 * there doesn't need to be a distinction it makes life easier if 2213 * we honor the spec implication that aXlations is an accelerator 2214 */ 2215 LOCK_APP(app); 2216 LOCK_PROCESS; 2217 if ((!XtIsWidget(source)) || 2218 ((aXlations = source->core.accelerators) == NULL) || 2219 (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) { 2220 UNLOCK_PROCESS; 2221 UNLOCK_APP(app); 2222 return; 2223 } 2224 2225 aXlations = source->core.accelerators; 2226 op = aXlations->operation; 2227 2228 if (ComposeTranslations(destination, op, source, aXlations) && 2229 (XtClass(source)->core_class.display_accelerator != NULL)) { 2230 _XtString buf = _XtPrintXlations(destination, aXlations, source, False); 2231 (*(XtClass(source)->core_class.display_accelerator))(source,buf); 2232 XtFree(buf); 2233 } 2234 UNLOCK_PROCESS; 2235 UNLOCK_APP(app); 2236} 2237 2238void XtInstallAllAccelerators( 2239 Widget destination, 2240 Widget source) 2241{ 2242 Cardinal i; 2243 WIDGET_TO_APPCON(destination); 2244 2245 /* Recurse down normal children */ 2246 LOCK_APP(app); 2247 LOCK_PROCESS; 2248 if (XtIsComposite(source)) { 2249 CompositeWidget cw = (CompositeWidget) source; 2250 for (i = 0; i < cw->composite.num_children; i++) { 2251 XtInstallAllAccelerators(destination,cw->composite.children[i]); 2252 } 2253 } 2254 2255 /* Recurse down popup children */ 2256 if (XtIsWidget(source)) { 2257 for (i = 0; i < source->core.num_popups; i++) { 2258 XtInstallAllAccelerators(destination,source->core.popup_list[i]); 2259 } 2260 } 2261 /* Finally, apply procedure to this widget */ 2262 XtInstallAccelerators(destination,source); 2263 UNLOCK_PROCESS; 2264 UNLOCK_APP(app); 2265} 2266 2267#if 0 /* dead code */ 2268static _XtTranslateOp _XtGetTMOperation( 2269 XtTranslations xlations) 2270{ 2271 return ((xlations->hasBindings) 2272 ? ((ATranslations)xlations)->xlations->operation 2273 : xlations->operation); 2274} 2275#endif 2276 2277void XtAugmentTranslations( 2278 Widget widget, 2279 XtTranslations new) 2280{ 2281 Widget hookobj; 2282 WIDGET_TO_APPCON(widget); 2283 2284 LOCK_APP(app); 2285 LOCK_PROCESS; 2286 (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new); 2287 hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 2288 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 2289 XtChangeHookDataRec call_data; 2290 2291 call_data.type = XtHaugmentTranslations; 2292 call_data.widget = widget; 2293 XtCallCallbackList(hookobj, 2294 ((HookObject)hookobj)->hooks.changehook_callbacks, 2295 (XtPointer)&call_data); 2296 } 2297 UNLOCK_PROCESS; 2298 UNLOCK_APP(app); 2299} 2300 2301void XtOverrideTranslations( 2302 Widget widget, 2303 XtTranslations new) 2304{ 2305 Widget hookobj; 2306 WIDGET_TO_APPCON(widget); 2307 2308 LOCK_APP(app); 2309 LOCK_PROCESS; 2310 (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new); 2311 hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 2312 if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { 2313 XtChangeHookDataRec call_data; 2314 2315 call_data.type = XtHoverrideTranslations; 2316 call_data.widget = widget; 2317 XtCallCallbackList(hookobj, 2318 ((HookObject)hookobj)->hooks.changehook_callbacks, 2319 (XtPointer)&call_data); 2320 } 2321 UNLOCK_PROCESS; 2322 UNLOCK_APP(app); 2323} 2324 2325void _XtMergeTranslations( 2326 Widget widget, 2327 XtTranslations newXlations, 2328 _XtTranslateOp op) 2329{ 2330 if (!newXlations){ 2331 if (!widget->core.tm.translations) 2332 return; 2333 else { 2334 newXlations = widget->core.tm.translations; 2335 widget->core.tm.translations = NULL; 2336 } 2337 } 2338 (void) ComposeTranslations(widget, 2339 op, 2340 (Widget)NULL, 2341 newXlations); 2342} 2343 2344void _XtUnmergeTranslations( 2345 Widget widget, 2346 XtTranslations xlations) 2347{ 2348 ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations); 2349} 2350