1 /*********************************************************** 2 Copyright (c) 1993, Oracle and/or its affiliates. 3 4 Permission is hereby granted, free of charge, to any person obtaining a 5 copy of this software and associated documentation files (the "Software"), 6 to deal in the Software without restriction, including without limitation 7 the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 and/or sell copies of the Software, and to permit persons to whom the 9 Software is furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice (including the next 12 paragraph) shall be included in all copies or substantial portions of the 13 Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 DEALINGS IN THE SOFTWARE. 22 23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27 Permission to use, copy, modify, and distribute this software and its 28 documentation for any purpose and without fee is hereby granted, 29 provided that the above copyright notice appear in all copies and that 30 both that copyright notice and this permission notice appear in 31 supporting documentation, and that the name of Digital not be 32 used in advertising or publicity pertaining to distribution of the 33 software without specific, written prior permission. 34 35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41 SOFTWARE. 42 43 ******************************************************************/ 44 45 /* 46 47 Copyright 1987, 1988, 1998 The Open Group 48 49 Permission to use, copy, modify, distribute, and sell this software and its 50 documentation for any purpose is hereby granted without fee, provided that 51 the above copyright notice appear in all copies and that both that 52 copyright notice and this permission notice appear in supporting 53 documentation. 54 55 The above copyright notice and this permission notice shall be included in 56 all copies or substantial portions of the Software. 57 58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65 Except as contained in this notice, the name of The Open Group shall not be 66 used in advertising or otherwise to promote the sale, use or other dealings 67 in this Software without prior written authorization from The Open Group. 68 69 */ 70 71 /* TMaction.c -- maintains the state table of actions for the translation 72 * manager. 73 */ 74 75 #ifdef HAVE_CONFIG_H 76 #include <config.h> 77 #endif 78 #include "IntrinsicI.h" 79 #include "StringDefs.h" 80 81 #if defined(__STDC__) && !defined(NORCONST) 82 #define RConst const 83 #else 84 #define RConst /**/ 85 #endif 86 static _Xconst _XtString XtNtranslationError = "translationError"; 87 88 typedef struct _CompiledAction { 89 XrmQuark signature; 90 XtActionProc proc; 91 } CompiledAction, *CompiledActionTable; 92 93 #define GetClassActions(wc) \ 94 ((wc->core_class.actions) \ 95 ? (((TMClassCache)wc->core_class.actions)->actions) \ 96 : NULL) 97 98 static CompiledActionTable 99 CompileActionTable(register RConst struct _XtActionsRec *actions, register Cardinal count, /* may be 0 */ 100 Boolean stat, /* if False, copy before compiling in place */ 101 Boolean perm) /* if False, use XrmStringToQuark */ 102 { 103 register CompiledActionTable cActions; 104 register int i; 105 CompiledActionTable cTableHold; 106 XrmQuark (*func) (_Xconst char *); 107 108 if (!count) 109 return (CompiledActionTable) NULL; 110 func = (perm ? XrmPermStringToQuark : XrmStringToQuark); 111 112 if (!stat) { 113 cTableHold = cActions = XtMallocArray(count, 114 (Cardinal) sizeof(CompiledAction)); 115 116 for (i = (int) count; --i >= 0; cActions++, actions++) { 117 cActions->proc = actions->proc; 118 cActions->signature = (*func) (actions->string); 119 } 120 } 121 else { 122 cTableHold = (CompiledActionTable) actions; 123 124 for (i = (int) count; --i >= 0; actions++) 125 ((CompiledActionTable) actions)->signature = 126 (*func) (actions->string); 127 } 128 cActions = cTableHold; 129 130 /* Insertion sort. Whatever sort is used, it must be stable. */ 131 for (i = 1; (Cardinal) i <= count - 1; i++) { 132 CompiledAction hold; 133 register Cardinal j; 134 135 hold = cActions[i]; 136 j = (Cardinal) i; 137 while (j && cActions[j - 1].signature > hold.signature) { 138 cActions[j] = cActions[j - 1]; 139 j--; 140 } 141 cActions[j] = hold; 142 } 143 144 return cActions; 145 } 146 147 typedef struct _ActionListRec *ActionList; 148 typedef struct _ActionListRec { 149 ActionList next; 150 CompiledActionTable table; 151 TMShortCard count; 152 } ActionListRec; 153 154 static void 155 ReportUnboundActions(XtTranslations xlations, TMBindData bindData) 156 { 157 TMSimpleStateTree stateTree; 158 Cardinal num_unbound = 0; 159 Cardinal num_params = 1; 160 char *message; 161 char messagebuf[1000]; 162 register Cardinal num_chars = 0; 163 register Cardinal i, j; 164 XtActionProc *procs; 165 166 for (i = 0; i < xlations->numStateTrees; i++) { 167 if (bindData->simple.isComplex) 168 procs = TMGetComplexBindEntry(bindData, i)->procs; 169 else 170 procs = TMGetSimpleBindEntry(bindData, i)->procs; 171 172 stateTree = (TMSimpleStateTree) xlations->stateTreeTbl[i]; 173 for (j = 0; j < stateTree->numQuarks; j++) { 174 if (procs[j] == NULL) { 175 String s = XrmQuarkToString(stateTree->quarkTbl[j]); 176 177 if (num_unbound != 0) 178 num_chars += 2; 179 num_chars += (Cardinal) strlen(s); 180 num_unbound++; 181 } 182 } 183 } 184 if (num_unbound == 0) 185 return; 186 message = XtStackAlloc(num_chars + 1, messagebuf); 187 if (message != NULL) { 188 String params[1]; 189 190 *message = '\0'; 191 num_unbound = 0; 192 for (i = 0; i < xlations->numStateTrees; i++) { 193 if (bindData->simple.isComplex) 194 procs = TMGetComplexBindEntry(bindData, i)->procs; 195 else 196 procs = TMGetSimpleBindEntry(bindData, i)->procs; 197 198 stateTree = (TMSimpleStateTree) xlations->stateTreeTbl[i]; 199 for (j = 0; j < stateTree->numQuarks; j++) { 200 if (procs[j] == NULL) { 201 String s = XrmQuarkToString(stateTree->quarkTbl[j]); 202 203 if (num_unbound != 0) 204 (void) strcat(message, ", "); 205 (void) strcat(message, s); 206 num_unbound++; 207 } 208 } 209 } 210 message[num_chars] = '\0'; 211 params[0] = message; 212 XtWarningMsg(XtNtranslationError, "unboundActions", XtCXtToolkitError, 213 "Actions not found: %s", params, &num_params); 214 XtStackFree(message, messagebuf); 215 } 216 } 217 218 static CompiledAction * 219 SearchActionTable(XrmQuark signature, 220 CompiledActionTable actionTable, 221 Cardinal numActions) 222 { 223 int left, right; 224 225 left = 0; 226 right = (int) numActions - 1; 227 while (left <= right) { 228 int i = (left + right) >> 1; 229 230 if (signature < actionTable[i].signature) 231 right = i - 1; 232 else if (signature > actionTable[i].signature) 233 left = i + 1; 234 else { 235 while (i && actionTable[i - 1].signature == signature) 236 i--; 237 return &actionTable[i]; 238 } 239 } 240 return (CompiledAction *) NULL; 241 } 242 243 static int 244 BindActions(TMSimpleStateTree stateTree, 245 XtActionProc *procs, 246 CompiledActionTable compiledActionTable, 247 TMShortCard numActions, 248 Cardinal *ndxP) 249 { 250 register int unbound = (int) (stateTree->numQuarks - *ndxP); 251 CompiledAction *action; 252 register Cardinal ndx; 253 register Boolean savedNdx = False; 254 255 for (ndx = *ndxP; ndx < stateTree->numQuarks; ndx++) { 256 if (procs[ndx] == NULL) { 257 /* attempt to bind it */ 258 XrmQuark q = stateTree->quarkTbl[ndx]; 259 260 action = SearchActionTable(q, compiledActionTable, numActions); 261 if (action) { 262 procs[ndx] = action->proc; 263 unbound--; 264 } 265 else if (!savedNdx) { 266 *ndxP = ndx; 267 savedNdx = True; 268 } 269 } 270 else { 271 /* already bound, leave it alone */ 272 unbound--; 273 } 274 } 275 return unbound; 276 } 277 278 typedef struct _TMBindCacheStatusRec { 279 unsigned int boundInClass:1; 280 unsigned int boundInHierarchy:1; 281 unsigned int boundInContext:1; 282 unsigned int notFullyBound:1; 283 unsigned int refCount:28; 284 } TMBindCacheStatusRec, *TMBindCacheStatus; 285 286 typedef struct _TMBindCacheRec { 287 struct _TMBindCacheRec *next; 288 TMBindCacheStatusRec status; 289 TMStateTree stateTree; 290 #ifdef TRACE_TM 291 WidgetClass widgetClass; 292 #endif /* TRACE_TM */ 293 XtActionProc procs[1]; /* variable length */ 294 } TMBindCacheRec, *TMBindCache; 295 296 typedef struct _TMClassCacheRec { 297 CompiledActionTable actions; 298 TMBindCacheRec *bindCache; 299 } TMClassCacheRec, *TMClassCache; 300 301 #define IsPureClassBind(bc) \ 302 (bc->status.boundInClass && \ 303 !(bc->status.boundInHierarchy || \ 304 bc->status.boundInContext || \ 305 bc->status.notFullyBound)) 306 307 #define GetClassCache(w) \ 308 ((TMClassCache)w->core.widget_class->core_class.actions) 309 310 static int 311 BindProcs(Widget widget, 312 TMSimpleStateTree stateTree, 313 XtActionProc *procs, 314 TMBindCacheStatus bindStatus) 315 { 316 register WidgetClass class; 317 register ActionList actionList; 318 int unbound = -1, newUnbound = -1; 319 Cardinal ndx = 0; 320 Widget w = widget; 321 322 LOCK_PROCESS; 323 do { 324 class = w->core.widget_class; 325 do { 326 if (class->core_class.actions != NULL) 327 unbound = 328 BindActions(stateTree, 329 procs, 330 GetClassActions(class), 331 (TMShortCard) class->core_class.num_actions, 332 &ndx); 333 class = class->core_class.superclass; 334 } while (unbound != 0 && class != NULL); 335 if (unbound < (int) stateTree->numQuarks) 336 bindStatus->boundInClass = True; 337 else 338 bindStatus->boundInClass = False; 339 if (newUnbound == -1) 340 newUnbound = unbound; 341 w = XtParent(w); 342 } while (unbound != 0 && w != NULL); 343 344 if (newUnbound > unbound) 345 bindStatus->boundInHierarchy = True; 346 else 347 bindStatus->boundInHierarchy = False; 348 349 if (unbound) { 350 XtAppContext app = XtWidgetToApplicationContext(widget); 351 352 newUnbound = unbound; 353 for (actionList = app->action_table; 354 unbound != 0 && actionList != NULL; 355 actionList = actionList->next) { 356 unbound = BindActions(stateTree, 357 procs, 358 actionList->table, actionList->count, &ndx); 359 } 360 if (newUnbound > unbound) 361 bindStatus->boundInContext = True; 362 else 363 bindStatus->boundInContext = False; 364 365 } 366 else { 367 bindStatus->boundInContext = False; 368 } 369 UNLOCK_PROCESS; 370 return unbound; 371 } 372 373 static XtActionProc * 374 TryBindCache(Widget widget, TMStateTree stateTree) 375 { 376 TMClassCache classCache; 377 378 LOCK_PROCESS; 379 classCache = GetClassCache(widget); 380 381 if (classCache == NULL) { 382 WidgetClass wc = XtClass(widget); 383 384 wc->core_class.actions = (XtActionList) 385 _XtInitializeActionData(NULL, 0, True); 386 } 387 else { 388 TMBindCache bindCache = (TMBindCache) (classCache->bindCache); 389 390 for (; bindCache; bindCache = bindCache->next) { 391 if (IsPureClassBind(bindCache) && 392 (stateTree == bindCache->stateTree)) { 393 bindCache->status.refCount++; 394 UNLOCK_PROCESS; 395 return &bindCache->procs[0]; 396 } 397 } 398 } 399 UNLOCK_PROCESS; 400 return NULL; 401 } 402 403 /* 404 * The class record actions field will point to the bind cache header 405 * after this call is made out of coreClassPartInit. 406 */ 407 XtPointer 408 _XtInitializeActionData(register struct _XtActionsRec *actions, 409 register Cardinal count, 410 _XtBoolean inPlace) 411 { 412 TMClassCache classCache; 413 414 classCache = XtNew(TMClassCacheRec); 415 classCache->actions = 416 CompileActionTable(actions, count, (Boolean) inPlace, True); 417 classCache->bindCache = NULL; 418 return (XtPointer) classCache; 419 } 420 421 #define TM_BIND_CACHE_REALLOC 2 422 423 static XtActionProc * 424 EnterBindCache(Widget w, 425 TMSimpleStateTree stateTree, 426 XtActionProc *procs, 427 TMBindCacheStatus bindStatus) 428 { 429 TMClassCache classCache; 430 TMBindCache *bindCachePtr; 431 TMShortCard procsSize; 432 TMBindCache bindCache; 433 434 LOCK_PROCESS; 435 classCache = GetClassCache(w); 436 bindCachePtr = &classCache->bindCache; 437 procsSize = (TMShortCard) (stateTree->numQuarks * sizeof(XtActionProc)); 438 439 for (bindCache = *bindCachePtr; 440 (*bindCachePtr); 441 bindCachePtr = &(*bindCachePtr)->next, bindCache = *bindCachePtr) { 442 TMBindCacheStatus cacheStatus = &bindCache->status; 443 444 if ((bindStatus->boundInClass == cacheStatus->boundInClass) && 445 (bindStatus->boundInHierarchy == cacheStatus->boundInHierarchy) && 446 (bindStatus->boundInContext == cacheStatus->boundInContext) && 447 (bindCache->stateTree == (TMStateTree) stateTree) && 448 !XtMemcmp(&bindCache->procs[0], procs, procsSize)) { 449 bindCache->status.refCount++; 450 break; 451 } 452 } 453 if (*bindCachePtr == NULL) { 454 *bindCachePtr = bindCache = (TMBindCache) 455 __XtMalloc((Cardinal) (sizeof(TMBindCacheRec) + 456 (size_t) (procsSize - 457 sizeof(XtActionProc)))); 458 bindCache->next = NULL; 459 bindCache->status = *bindStatus; 460 bindCache->status.refCount = 1; 461 bindCache->stateTree = (TMStateTree) stateTree; 462 #ifdef TRACE_TM 463 bindCache->widgetClass = XtClass(w); 464 if (_XtGlobalTM.numBindCache == _XtGlobalTM.bindCacheTblSize) { 465 _XtGlobalTM.bindCacheTblSize = 466 (TMShortCard) (_XtGlobalTM.bindCacheTblSize + 16); 467 _XtGlobalTM.bindCacheTbl = 468 XtReallocArray(_XtGlobalTM.bindCacheTbl, 469 (Cardinal) _XtGlobalTM.bindCacheTblSize, 470 (Cardinal) sizeof(TMBindCache)); 471 } 472 _XtGlobalTM.bindCacheTbl[_XtGlobalTM.numBindCache++] = bindCache; 473 #endif /* TRACE_TM */ 474 memcpy(&bindCache->procs[0], procs, procsSize); 475 } 476 UNLOCK_PROCESS; 477 return &bindCache->procs[0]; 478 } 479 480 static void 481 RemoveFromBindCache(Widget w, XtActionProc *procs) 482 { 483 TMClassCache classCache; 484 TMBindCache *bindCachePtr; 485 TMBindCache bindCache; 486 XtAppContext app = XtWidgetToApplicationContext(w); 487 488 LOCK_PROCESS; 489 classCache = GetClassCache(w); 490 bindCachePtr = (TMBindCache *) &classCache->bindCache; 491 492 for (bindCache = *bindCachePtr; 493 *bindCachePtr; 494 bindCachePtr = &(*bindCachePtr)->next, bindCache = *bindCachePtr) { 495 if (&bindCache->procs[0] == procs) { 496 if (--bindCache->status.refCount == 0) { 497 #ifdef TRACE_TM 498 TMShortCard j; 499 Boolean found = False; 500 TMBindCache *tbl = _XtGlobalTM.bindCacheTbl; 501 502 for (j = 0; j < _XtGlobalTM.numBindCache; j++) { 503 if (found) 504 tbl[j - 1] = tbl[j]; 505 if (tbl[j] == bindCache) 506 found = True; 507 } 508 if (!found) 509 XtWarning("where's the action ??? "); 510 else 511 _XtGlobalTM.numBindCache--; 512 #endif /* TRACE_TM */ 513 *bindCachePtr = bindCache->next; 514 bindCache->next = app->free_bindings; 515 app->free_bindings = bindCache; 516 } 517 break; 518 } 519 } 520 UNLOCK_PROCESS; 521 } 522 523 static void 524 RemoveAccelerators(Widget widget, XtPointer closure, XtPointer data _X_UNUSED) 525 { 526 Widget destination = (Widget) closure; 527 TMComplexBindProcs bindProcs; 528 XtTranslations stackXlations[16]; 529 XtTranslations *xlationsList, destXlations; 530 TMShortCard i, numXlations = 0; 531 532 if ((destXlations = destination->core.tm.translations) == NULL) { 533 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 534 XtNtranslationError, "nullTable", XtCXtToolkitError, 535 "Can't remove accelerators from NULL table", 536 NULL, NULL); 537 return; 538 } 539 540 xlationsList = (XtTranslations *) 541 XtStackAlloc((destXlations->numStateTrees * sizeof(XtTranslations)), 542 stackXlations); 543 544 for (i = 0, bindProcs = 545 TMGetComplexBindEntry(destination->core.tm.proc_table, i); 546 i < destXlations->numStateTrees; i++, bindProcs++) { 547 if (bindProcs->widget == widget) { 548 /* 549 * if it's being destroyed don't do all the work 550 */ 551 if (destination->core.being_destroyed) { 552 bindProcs->procs = NULL; 553 } 554 else 555 xlationsList[numXlations] = bindProcs->aXlations; 556 numXlations++; 557 } 558 } 559 560 if (numXlations == 0) 561 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 562 XtNtranslationError, "nullTable", XtCXtToolkitError, 563 "Tried to remove nonexistent accelerators", NULL, NULL); 564 else { 565 if (!destination->core.being_destroyed) 566 for (i = 0; i < numXlations; i++) 567 _XtUnmergeTranslations(destination, xlationsList[i]); 568 } 569 XtStackFree((char *) xlationsList, stackXlations); 570 } 571 572 void 573 _XtBindActions(Widget widget, XtTM tm) 574 { 575 XtTranslations xlations = tm->translations; 576 int globalUnbound = 0; 577 Cardinal i; 578 TMBindData bindData = (TMBindData) tm->proc_table; 579 TMSimpleBindProcs simpleBindProcs = NULL; 580 TMComplexBindProcs complexBindProcs = NULL; 581 XtActionProc *newProcs; 582 Widget bindWidget; 583 584 if ((xlations == NULL) || widget->core.being_destroyed) 585 return; 586 587 for (i = 0; i < xlations->numStateTrees; i++) { 588 TMSimpleStateTree stateTree; 589 590 stateTree = (TMSimpleStateTree) xlations->stateTreeTbl[i]; 591 if (bindData->simple.isComplex) { 592 complexBindProcs = TMGetComplexBindEntry(bindData, i); 593 if (complexBindProcs->widget) { 594 bindWidget = complexBindProcs->widget; 595 596 if (bindWidget->core.destroy_callbacks != NULL) 597 _XtAddCallbackOnce((InternalCallbackList *) 598 &bindWidget->core.destroy_callbacks, 599 RemoveAccelerators, (XtPointer) widget); 600 else 601 _XtAddCallback((InternalCallbackList *) 602 &bindWidget->core.destroy_callbacks, 603 RemoveAccelerators, (XtPointer) widget); 604 } 605 else 606 bindWidget = widget; 607 } 608 else { 609 simpleBindProcs = TMGetSimpleBindEntry(bindData, i); 610 bindWidget = widget; 611 } 612 if ((newProcs = 613 TryBindCache(bindWidget, (TMStateTree) stateTree)) == NULL) { 614 XtActionProc *procs, stackProcs[256]; 615 int localUnbound; 616 TMBindCacheStatusRec bcStatusRec; 617 618 procs = (XtActionProc *) 619 XtStackAlloc(stateTree->numQuarks * sizeof(XtActionProc), 620 stackProcs); 621 XtBZero((XtPointer) procs, 622 stateTree->numQuarks * sizeof(XtActionProc)); 623 624 localUnbound = BindProcs(bindWidget, 625 stateTree, procs, &bcStatusRec); 626 627 if (localUnbound) 628 bcStatusRec.notFullyBound = True; 629 else 630 bcStatusRec.notFullyBound = False; 631 632 newProcs = 633 EnterBindCache(bindWidget, stateTree, procs, &bcStatusRec); 634 XtStackFree((XtPointer) procs, (XtPointer) stackProcs); 635 globalUnbound += localUnbound; 636 } 637 if (bindData->simple.isComplex) 638 complexBindProcs->procs = newProcs; 639 else 640 simpleBindProcs->procs = newProcs; 641 } 642 if (globalUnbound) 643 ReportUnboundActions(xlations, (TMBindData) tm->proc_table); 644 } 645 646 void 647 _XtUnbindActions(Widget widget, XtTranslations xlations, TMBindData bindData) 648 { 649 Cardinal i; 650 Widget bindWidget; 651 XtActionProc *procs; 652 653 if ((xlations == NULL) || !XtIsRealized(widget)) 654 return; 655 656 for (i = 0; i < xlations->numStateTrees; i++) { 657 if (bindData->simple.isComplex) { 658 TMComplexBindProcs complexBindProcs; 659 660 complexBindProcs = TMGetComplexBindEntry(bindData, i); 661 662 if (complexBindProcs->widget) { 663 /* 664 * check for this being an accelerator binding whose 665 * source is gone ( set by RemoveAccelerators) 666 */ 667 if (complexBindProcs->procs == NULL) 668 continue; 669 670 XtRemoveCallback(complexBindProcs->widget, 671 XtNdestroyCallback, 672 RemoveAccelerators, (XtPointer) widget); 673 bindWidget = complexBindProcs->widget; 674 } 675 else 676 bindWidget = widget; 677 procs = complexBindProcs->procs; 678 complexBindProcs->procs = NULL; 679 } 680 else { 681 TMSimpleBindProcs simpleBindProcs; 682 683 simpleBindProcs = TMGetSimpleBindEntry(bindData, i); 684 procs = simpleBindProcs->procs; 685 simpleBindProcs->procs = NULL; 686 bindWidget = widget; 687 } 688 RemoveFromBindCache(bindWidget, procs); 689 } 690 } 691 692 #ifdef notdef 693 void 694 _XtRemoveBindProcsByIndex(Widget w, TMBindData bindData, TMShortCard ndx) 695 { 696 TMShortCard i = ndx; 697 TMBindProcs bindProcs = (TMBindProcs) &bindData->bindTbl[0]; 698 699 RemoveFromBindCache(bindProcs->widget ? bindProcs->widget : w, 700 bindProcs[i].procs); 701 702 for (; i < bindData->bindTblSize; i++) 703 bindProcs[i] = bindProcs[i + 1]; 704 } 705 #endif /* notdef */ 706 707 /* 708 * used to free all copied action tables, called from DestroyAppContext 709 */ 710 void 711 _XtFreeActions(ActionList actions) 712 { 713 ActionList curr, next; 714 715 for (curr = actions; curr;) { 716 next = curr->next; 717 XtFree((char *) curr->table); 718 XtFree((char *) curr); 719 curr = next; 720 } 721 } 722 723 void 724 XtAddActions(XtActionList actions, Cardinal num_actions) 725 { 726 XtAppAddActions(_XtDefaultAppContext(), actions, num_actions); 727 } 728 729 void 730 XtAppAddActions(XtAppContext app, XtActionList actions, Cardinal num_actions) 731 { 732 register ActionList rec; 733 734 LOCK_APP(app); 735 rec = XtNew(ActionListRec); 736 rec->next = app->action_table; 737 app->action_table = rec; 738 rec->table = CompileActionTable(actions, num_actions, False, False); 739 rec->count = (TMShortCard) num_actions; 740 UNLOCK_APP(app); 741 } 742 743 void 744 XtGetActionList(WidgetClass widget_class, 745 XtActionList *actions_return, 746 Cardinal *num_actions_return) 747 { 748 CompiledActionTable table; 749 750 *actions_return = NULL; 751 *num_actions_return = 0; 752 753 LOCK_PROCESS; 754 if (!widget_class->core_class.class_inited) { 755 UNLOCK_PROCESS; 756 return; 757 } 758 if (!(widget_class->core_class.class_inited & WidgetClassFlag)) { 759 UNLOCK_PROCESS; 760 return; 761 } 762 *num_actions_return = widget_class->core_class.num_actions; 763 if (*num_actions_return) { 764 XtActionList list = *actions_return = 765 XtMallocArray(*num_actions_return, (Cardinal) sizeof(XtActionsRec)); 766 767 table = GetClassActions(widget_class); 768 769 if (table != NULL) { 770 int i; 771 772 for (i = (int) (*num_actions_return); --i >= 0; list++, table++) { 773 list->string = XrmQuarkToString(table->signature); 774 list->proc = table->proc; 775 } 776 } 777 } 778 UNLOCK_PROCESS; 779 } 780 781 /*********************************************************************** 782 * 783 * Pop-up and Grab stuff 784 * 785 ***********************************************************************/ 786 787 static Widget 788 _XtFindPopup(Widget widget, String name) 789 { 790 register Cardinal i; 791 register XrmQuark q; 792 register Widget w; 793 794 q = XrmStringToQuark(name); 795 796 for (w = widget; w != NULL; w = w->core.parent) 797 for (i = 0; i < w->core.num_popups; i++) 798 if (w->core.popup_list[i]->core.xrm_name == q) 799 return w->core.popup_list[i]; 800 801 return NULL; 802 } 803 804 void 805 XtMenuPopupAction(Widget widget, 806 XEvent *event, 807 String *params, 808 Cardinal *num_params) 809 { 810 Boolean spring_loaded; 811 register Widget popup_shell; 812 XtAppContext app = XtWidgetToApplicationContext(widget); 813 814 LOCK_APP(app); 815 if (*num_params != 1) { 816 XtAppWarningMsg(app, 817 "invalidParameters", "xtMenuPopupAction", 818 XtCXtToolkitError, 819 "MenuPopup wants exactly one argument", NULL, NULL); 820 UNLOCK_APP(app); 821 return; 822 } 823 824 if (event->type == ButtonPress) 825 spring_loaded = True; 826 else if (event->type == KeyPress || event->type == EnterNotify) 827 spring_loaded = False; 828 else { 829 XtAppWarningMsg(app, 830 "invalidPopup", "unsupportedOperation", 831 XtCXtToolkitError, 832 "Pop-up menu creation is only supported on ButtonPress, KeyPress or EnterNotify events.", 833 NULL, NULL); 834 UNLOCK_APP(app); 835 return; 836 } 837 838 popup_shell = _XtFindPopup(widget, params[0]); 839 if (popup_shell == NULL) { 840 XtAppWarningMsg(app, 841 "invalidPopup", "xtMenuPopup", XtCXtToolkitError, 842 "Can't find popup widget \"%s\" in XtMenuPopup", 843 params, num_params); 844 UNLOCK_APP(app); 845 return; 846 } 847 848 if (spring_loaded) 849 _XtPopup(popup_shell, XtGrabExclusive, TRUE); 850 else 851 _XtPopup(popup_shell, XtGrabNonexclusive, FALSE); 852 UNLOCK_APP(app); 853 } 854 855 static void 856 _XtMenuPopdownAction(Widget widget, 857 XEvent *event _X_UNUSED, 858 String *params, 859 Cardinal *num_params) 860 { 861 Widget popup_shell; 862 863 if (*num_params == 0) { 864 XtPopdown(widget); 865 } 866 else if (*num_params == 1) { 867 popup_shell = _XtFindPopup(widget, params[0]); 868 if (popup_shell == NULL) { 869 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 870 "invalidPopup", "xtMenuPopdown", XtCXtToolkitError, 871 "Can't find popup widget \"%s\" in XtMenuPopdown", 872 params, num_params); 873 return; 874 } 875 XtPopdown(popup_shell); 876 } 877 else { 878 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 879 "invalidParameters", "xtMenuPopdown", XtCXtToolkitError, 880 "XtMenuPopdown called with num_params != 0 or 1", 881 NULL, NULL); 882 } 883 } 884 885 /* *INDENT-OFF* */ 886 static XtActionsRec RConst tmActions[] = { 887 {"XtMenuPopup", XtMenuPopupAction}, 888 {"XtMenuPopdown", _XtMenuPopdownAction}, 889 {"MenuPopup", XtMenuPopupAction}, /* old & obsolete */ 890 {"MenuPopdown", _XtMenuPopdownAction}, /* ditto */ 891 #ifndef NO_MIT_HACKS 892 {"XtDisplayTranslations", _XtDisplayTranslations}, 893 {"XtDisplayAccelerators", _XtDisplayAccelerators}, 894 {"XtDisplayInstalledAccelerators", _XtDisplayInstalledAccelerators}, 895 #endif 896 }; 897 /* *INDENT-ON* */ 898 899 void 900 _XtPopupInitialize(XtAppContext app) 901 { 902 register ActionList rec; 903 904 /* 905 * The _XtGlobalTM.newMatchSemantics flag determines whether 906 * we support old or new matching 907 * behavior. This is mainly an issue of whether subsequent lhs will 908 * get pushed up in the match table if a lhs containing this initial 909 * sequence has already been encountered. Currently inited to False; 910 */ 911 #ifdef NEW_TM 912 _XtGlobalTM.newMatchSemantics = True; 913 #else 914 _XtGlobalTM.newMatchSemantics = False; 915 #endif 916 917 rec = XtNew(ActionListRec); 918 rec->next = app->action_table; 919 app->action_table = rec; 920 LOCK_PROCESS; 921 rec->table = CompileActionTable(tmActions, XtNumber(tmActions), False, 922 True); 923 rec->count = XtNumber(tmActions); 924 UNLOCK_PROCESS; 925 _XtGrabInitialize(app); 926 } 927 928 void 929 XtCallActionProc(Widget widget, 930 _Xconst char *action, 931 XEvent *event, 932 String *params, 933 Cardinal num_params) 934 { 935 CompiledAction *actionP; 936 XrmQuark q = XrmStringToQuark(action); 937 Widget w = widget; 938 XtAppContext app = XtWidgetToApplicationContext(widget); 939 ActionList actionList; 940 Cardinal i; 941 942 LOCK_APP(app); 943 XtCheckSubclass(widget, coreWidgetClass, 944 "XtCallActionProc first argument is not a subclass of Core"); 945 LOCK_PROCESS; 946 do { 947 WidgetClass class = XtClass(w); 948 949 do { 950 if ((actionP = GetClassActions(class)) != NULL) 951 for (i = 0; i < class->core_class.num_actions; i++, actionP++) { 952 953 if (actionP->signature == q) { 954 ActionHook hook = app->action_hook_list; 955 956 while (hook != NULL) { 957 (*hook->proc) (widget, 958 hook->closure, 959 (String) action, 960 event, 961 params, 962 &num_params); 963 hook = hook->next; 964 } 965 (*(actionP->proc)) 966 (widget, event, params, &num_params); 967 UNLOCK_PROCESS; 968 UNLOCK_APP(app); 969 return; 970 } 971 } 972 class = class->core_class.superclass; 973 } while (class != NULL); 974 w = XtParent(w); 975 } while (w != NULL); 976 UNLOCK_PROCESS; 977 978 for (actionList = app->action_table; 979 actionList != NULL; actionList = actionList->next) { 980 981 for (i = 0, actionP = actionList->table; 982 i < actionList->count; i++, actionP++) { 983 if (actionP->signature == q) { 984 ActionHook hook = app->action_hook_list; 985 986 while (hook != NULL) { 987 (*hook->proc) (widget, 988 hook->closure, 989 (String) action, 990 event, 991 params, 992 &num_params); 993 hook = hook->next; 994 } 995 (*(actionP->proc)) 996 (widget, event, params, &num_params); 997 UNLOCK_APP(app); 998 return; 999 } 1000 } 1001 1002 } 1003 1004 { 1005 String par[2]; 1006 Cardinal num_par = 2; 1007 1008 par[0] = (String) action; 1009 par[1] = XtName(widget); 1010 XtAppWarningMsg(app, 1011 "noActionProc", "xtCallActionProc", XtCXtToolkitError, 1012 "No action proc named \"%s\" is registered for widget \"%s\"", 1013 par, &num_par); 1014 } 1015 UNLOCK_APP(app); 1016 } 1017 1018 void 1019 _XtDoFreeBindings(XtAppContext app) 1020 { 1021 TMBindCache bcp; 1022 1023 while (app->free_bindings) { 1024 bcp = app->free_bindings->next; 1025 XtFree((char *) app->free_bindings); 1026 app->free_bindings = bcp; 1027 } 1028 } 1029