Home | History | Annotate | Line # | Download | only in src
      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