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