home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xt / TMaction.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  25.0 KB  |  946 lines

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