1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
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
CompileActionTable(register RConst struct _XtActionsRec * actions,register Cardinal count,Boolean stat,Boolean perm)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     CompiledAction hold;
106     CompiledActionTable cTableHold;
107     XrmQuark (*func) (_Xconst char *);
108 
109     if (!count)
110         return (CompiledActionTable) NULL;
111     func = (perm ? XrmPermStringToQuark : XrmStringToQuark);
112 
113     if (!stat) {
114         cTableHold = cActions = (CompiledActionTable)
115             __XtMalloc((Cardinal) ((size_t) count * sizeof(CompiledAction)));
116 
117         for (i = (int) count; --i >= 0; cActions++, actions++) {
118             cActions->proc = actions->proc;
119             cActions->signature = (*func) (actions->string);
120         }
121     }
122     else {
123         cTableHold = (CompiledActionTable) actions;
124 
125         for (i = (int) count; --i >= 0; actions++)
126             ((CompiledActionTable) actions)->signature =
127                 (*func) (actions->string);
128     }
129     cActions = cTableHold;
130 
131     /* Insertion sort.  Whatever sort is used, it must be stable. */
132     for (i = 1; (Cardinal) i <= count - 1; i++) {
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
ReportUnboundActions(XtTranslations xlations,TMBindData bindData)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 *
SearchActionTable(XrmQuark signature,CompiledActionTable actionTable,Cardinal numActions)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
BindActions(TMSimpleStateTree stateTree,XtActionProc * procs,CompiledActionTable compiledActionTable,TMShortCard numActions,Cardinal * ndxP)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
BindProcs(Widget widget,TMSimpleStateTree stateTree,XtActionProc * procs,TMBindCacheStatus bindStatus)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 *
TryBindCache(Widget widget,TMStateTree stateTree)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
_XtInitializeActionData(register struct _XtActionsRec * actions,register Cardinal count,_XtBoolean inPlace)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 *
EnterBindCache(Widget w,TMSimpleStateTree stateTree,XtActionProc * procs,TMBindCacheStatus bindStatus)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 = (TMBindCache *)
468                 XtRealloc((char *) _XtGlobalTM.bindCacheTbl,
469                           (Cardinal) ((_XtGlobalTM.bindCacheTblSize) *
470                                       sizeof(TMBindCache)));
471         }
472         _XtGlobalTM.bindCacheTbl[_XtGlobalTM.numBindCache++] = bindCache;
473 #endif                          /* TRACE_TM */
474         XtMemmove((XtPointer) &bindCache->procs[0],
475                   (XtPointer) procs, procsSize);
476     }
477     UNLOCK_PROCESS;
478     return &bindCache->procs[0];
479 }
480 
481 static void
RemoveFromBindCache(Widget w,XtActionProc * procs)482 RemoveFromBindCache(Widget w, XtActionProc *procs)
483 {
484     TMClassCache classCache;
485     TMBindCache *bindCachePtr;
486     TMBindCache bindCache;
487     XtAppContext app = XtWidgetToApplicationContext(w);
488 
489     LOCK_PROCESS;
490     classCache = GetClassCache(w);
491     bindCachePtr = (TMBindCache *) &classCache->bindCache;
492 
493     for (bindCache = *bindCachePtr;
494          *bindCachePtr;
495          bindCachePtr = &(*bindCachePtr)->next, bindCache = *bindCachePtr) {
496         if (&bindCache->procs[0] == procs) {
497             if (--bindCache->status.refCount == 0) {
498 #ifdef TRACE_TM
499                 TMShortCard j;
500                 Boolean found = False;
501                 TMBindCache *tbl = _XtGlobalTM.bindCacheTbl;
502 
503                 for (j = 0; j < _XtGlobalTM.numBindCache; j++) {
504                     if (found)
505                         tbl[j - 1] = tbl[j];
506                     if (tbl[j] == bindCache)
507                         found = True;
508                 }
509                 if (!found)
510                     XtWarning("where's the action ??? ");
511                 else
512                     _XtGlobalTM.numBindCache--;
513 #endif                          /* TRACE_TM */
514                 *bindCachePtr = bindCache->next;
515                 bindCache->next = app->free_bindings;
516                 app->free_bindings = bindCache;
517             }
518             break;
519         }
520     }
521     UNLOCK_PROCESS;
522 }
523 
524 static void
RemoveAccelerators(Widget widget,XtPointer closure,XtPointer data _X_UNUSED)525 RemoveAccelerators(Widget widget, XtPointer closure, XtPointer data _X_UNUSED)
526 {
527     Widget destination = (Widget) closure;
528     TMComplexBindProcs bindProcs;
529     XtTranslations stackXlations[16];
530     XtTranslations *xlationsList, destXlations;
531     TMShortCard i, numXlations = 0;
532 
533     if ((destXlations = destination->core.tm.translations) == NULL) {
534         XtAppWarningMsg(XtWidgetToApplicationContext(widget),
535                         XtNtranslationError, "nullTable", XtCXtToolkitError,
536                         "Can't remove accelerators from NULL table",
537                         NULL, NULL);
538         return;
539     }
540 
541     xlationsList = (XtTranslations *)
542         XtStackAlloc((destXlations->numStateTrees * sizeof(XtTranslations)),
543                      stackXlations);
544 
545     for (i = 0, bindProcs =
546          TMGetComplexBindEntry(destination->core.tm.proc_table, i);
547          i < destXlations->numStateTrees; i++, bindProcs++) {
548         if (bindProcs->widget == widget) {
549             /*
550              * if it's being destroyed don't do all the work
551              */
552             if (destination->core.being_destroyed) {
553                 bindProcs->procs = NULL;
554             }
555             else
556                 xlationsList[numXlations] = bindProcs->aXlations;
557             numXlations++;
558         }
559     }
560 
561     if (numXlations == 0)
562         XtAppWarningMsg(XtWidgetToApplicationContext(widget),
563                         XtNtranslationError, "nullTable", XtCXtToolkitError,
564                         "Tried to remove nonexistent accelerators", NULL, NULL);
565     else {
566         if (!destination->core.being_destroyed)
567             for (i = 0; i < numXlations; i++)
568                 _XtUnmergeTranslations(destination, xlationsList[i]);
569     }
570     XtStackFree((char *) xlationsList, stackXlations);
571 }
572 
573 void
_XtBindActions(Widget widget,XtTM tm)574 _XtBindActions(Widget widget, XtTM tm)
575 {
576     XtTranslations xlations = tm->translations;
577     TMSimpleStateTree stateTree;
578     int globalUnbound = 0;
579     Cardinal i;
580     TMBindData bindData = (TMBindData) tm->proc_table;
581     TMSimpleBindProcs simpleBindProcs = NULL;
582     TMComplexBindProcs complexBindProcs = NULL;
583     XtActionProc *newProcs;
584     Widget bindWidget;
585 
586     if ((xlations == NULL) || widget->core.being_destroyed)
587         return;
588 
589     for (i = 0; i < xlations->numStateTrees; i++) {
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
_XtUnbindActions(Widget widget,XtTranslations xlations,TMBindData bindData)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
_XtRemoveBindProcsByIndex(Widget w,TMBindData bindData,TMShortCard ndx)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
_XtFreeActions(ActionList actions)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
XtAddActions(XtActionList actions,Cardinal num_actions)724 XtAddActions(XtActionList actions, Cardinal num_actions)
725 {
726     XtAppAddActions(_XtDefaultAppContext(), actions, num_actions);
727 }
728 
729 void
XtAppAddActions(XtAppContext app,XtActionList actions,Cardinal num_actions)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
XtGetActionList(WidgetClass widget_class,XtActionList * actions_return,Cardinal * num_actions_return)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 = (XtActionList)
765             __XtMalloc((Cardinal)
766                        ((size_t) *num_actions_return * sizeof(XtActionsRec)));
767 
768         table = GetClassActions(widget_class);
769 
770         if (table != NULL) {
771             int i;
772 
773             for (i = (int) (*num_actions_return); --i >= 0; list++, table++) {
774                 list->string = XrmQuarkToString(table->signature);
775                 list->proc = table->proc;
776             }
777         }
778     }
779     UNLOCK_PROCESS;
780 }
781 
782 /***********************************************************************
783  *
784  * Pop-up and Grab stuff
785  *
786  ***********************************************************************/
787 
788 static Widget
_XtFindPopup(Widget widget,String name)789 _XtFindPopup(Widget widget, String name)
790 {
791     register Cardinal i;
792     register XrmQuark q;
793     register Widget w;
794 
795     q = XrmStringToQuark(name);
796 
797     for (w = widget; w != NULL; w = w->core.parent)
798         for (i = 0; i < w->core.num_popups; i++)
799             if (w->core.popup_list[i]->core.xrm_name == q)
800                 return w->core.popup_list[i];
801 
802     return NULL;
803 }
804 
805 void
XtMenuPopupAction(Widget widget,XEvent * event,String * params,Cardinal * num_params)806 XtMenuPopupAction(Widget widget,
807                   XEvent *event,
808                   String *params,
809                   Cardinal *num_params)
810 {
811     Boolean spring_loaded;
812     register Widget popup_shell;
813     XtAppContext app = XtWidgetToApplicationContext(widget);
814 
815     LOCK_APP(app);
816     if (*num_params != 1) {
817         XtAppWarningMsg(app,
818                         "invalidParameters", "xtMenuPopupAction",
819                         XtCXtToolkitError,
820                         "MenuPopup wants exactly one argument", NULL, NULL);
821         UNLOCK_APP(app);
822         return;
823     }
824 
825     if (event->type == ButtonPress)
826         spring_loaded = True;
827     else if (event->type == KeyPress || event->type == EnterNotify)
828         spring_loaded = False;
829     else {
830         XtAppWarningMsg(app,
831                         "invalidPopup", "unsupportedOperation",
832                         XtCXtToolkitError,
833                         "Pop-up menu creation is only supported on ButtonPress, KeyPress or EnterNotify events.",
834                         NULL, NULL);
835         UNLOCK_APP(app);
836         return;
837     }
838 
839     popup_shell = _XtFindPopup(widget, params[0]);
840     if (popup_shell == NULL) {
841         XtAppWarningMsg(app,
842                         "invalidPopup", "xtMenuPopup", XtCXtToolkitError,
843                         "Can't find popup widget \"%s\" in XtMenuPopup",
844                         params, num_params);
845         UNLOCK_APP(app);
846         return;
847     }
848 
849     if (spring_loaded)
850         _XtPopup(popup_shell, XtGrabExclusive, TRUE);
851     else
852         _XtPopup(popup_shell, XtGrabNonexclusive, FALSE);
853     UNLOCK_APP(app);
854 }
855 
856 static void
_XtMenuPopdownAction(Widget widget,XEvent * event _X_UNUSED,String * params,Cardinal * num_params)857 _XtMenuPopdownAction(Widget widget,
858                      XEvent *event _X_UNUSED,
859                      String *params,
860                      Cardinal *num_params)
861 {
862     Widget popup_shell;
863 
864     if (*num_params == 0) {
865         XtPopdown(widget);
866     }
867     else if (*num_params == 1) {
868         popup_shell = _XtFindPopup(widget, params[0]);
869         if (popup_shell == NULL) {
870             XtAppWarningMsg(XtWidgetToApplicationContext(widget),
871                             "invalidPopup", "xtMenuPopdown", XtCXtToolkitError,
872                             "Can't find popup widget \"%s\" in XtMenuPopdown",
873                             params, num_params);
874             return;
875         }
876         XtPopdown(popup_shell);
877     }
878     else {
879         XtAppWarningMsg(XtWidgetToApplicationContext(widget),
880                         "invalidParameters", "xtMenuPopdown", XtCXtToolkitError,
881                         "XtMenuPopdown called with num_params != 0 or 1",
882                         NULL, NULL);
883     }
884 }
885 
886 /* *INDENT-OFF* */
887 static XtActionsRec RConst tmActions[] = {
888     {"XtMenuPopup",                    XtMenuPopupAction},
889     {"XtMenuPopdown",                  _XtMenuPopdownAction},
890     {"MenuPopup",                      XtMenuPopupAction},      /* old & obsolete */
891     {"MenuPopdown",                    _XtMenuPopdownAction},   /* ditto */
892 #ifndef NO_MIT_HACKS
893     {"XtDisplayTranslations",          _XtDisplayTranslations},
894     {"XtDisplayAccelerators",          _XtDisplayAccelerators},
895     {"XtDisplayInstalledAccelerators", _XtDisplayInstalledAccelerators},
896 #endif
897 };
898 /* *INDENT-ON* */
899 
900 void
_XtPopupInitialize(XtAppContext app)901 _XtPopupInitialize(XtAppContext app)
902 {
903     register ActionList rec;
904 
905     /*
906      * The _XtGlobalTM.newMatchSemantics flag determines whether
907      * we support old or new matching
908      * behavior. This is mainly an issue of whether subsequent lhs will
909      * get pushed up in the match table if a lhs containing thier initial
910      * sequence has already been encountered. Currently inited to False;
911      */
912 #ifdef NEW_TM
913     _XtGlobalTM.newMatchSemantics = True;
914 #else
915     _XtGlobalTM.newMatchSemantics = False;
916 #endif
917 
918     rec = XtNew(ActionListRec);
919     rec->next = app->action_table;
920     app->action_table = rec;
921     LOCK_PROCESS;
922     rec->table = CompileActionTable(tmActions, XtNumber(tmActions), False,
923                                     True);
924     rec->count = XtNumber(tmActions);
925     UNLOCK_PROCESS;
926     _XtGrabInitialize(app);
927 }
928 
929 void
XtCallActionProc(Widget widget,_Xconst char * action,XEvent * event,String * params,Cardinal num_params)930 XtCallActionProc(Widget widget,
931                  _Xconst char *action,
932                  XEvent *event,
933                  String *params,
934                  Cardinal num_params)
935 {
936     CompiledAction *actionP;
937     XrmQuark q = XrmStringToQuark(action);
938     Widget w = widget;
939     XtAppContext app = XtWidgetToApplicationContext(widget);
940     ActionList actionList;
941     Cardinal i;
942 
943     LOCK_APP(app);
944     XtCheckSubclass(widget, coreWidgetClass,
945                     "XtCallActionProc first argument is not a subclass of Core");
946     LOCK_PROCESS;
947     do {
948         WidgetClass class = XtClass(w);
949 
950         do {
951             if ((actionP = GetClassActions(class)) != NULL)
952                 for (i = 0; i < class->core_class.num_actions; i++, actionP++) {
953 
954                     if (actionP->signature == q) {
955                         ActionHook hook = app->action_hook_list;
956 
957                         while (hook != NULL) {
958                             (*hook->proc) (widget,
959                                            hook->closure,
960                                            (String) action,
961                                            event,
962                                            params,
963                                            &num_params);
964                             hook = hook->next;
965                         }
966                         (*(actionP->proc))
967                             (widget, event, params, &num_params);
968                         UNLOCK_PROCESS;
969                         UNLOCK_APP(app);
970                         return;
971                     }
972                 }
973             class = class->core_class.superclass;
974         } while (class != NULL);
975         w = XtParent(w);
976     } while (w != NULL);
977     UNLOCK_PROCESS;
978 
979     for (actionList = app->action_table;
980          actionList != NULL; actionList = actionList->next) {
981 
982         for (i = 0, actionP = actionList->table;
983              i < actionList->count; i++, actionP++) {
984             if (actionP->signature == q) {
985                 ActionHook hook = app->action_hook_list;
986 
987                 while (hook != NULL) {
988                     (*hook->proc) (widget,
989                                    hook->closure,
990                                    (String) action,
991                                    event,
992                                    params,
993                                    &num_params);
994                     hook = hook->next;
995                 }
996                 (*(actionP->proc))
997                     (widget, event, params, &num_params);
998                 UNLOCK_APP(app);
999                 return;
1000             }
1001         }
1002 
1003     }
1004 
1005     {
1006         String par[2];
1007         Cardinal num_par = 2;
1008 
1009         par[0] = (String) action;
1010         par[1] = XtName(widget);
1011         XtAppWarningMsg(app,
1012                         "noActionProc", "xtCallActionProc", XtCXtToolkitError,
1013                         "No action proc named \"%s\" is registered for widget \"%s\"",
1014                         par, &num_par);
1015     }
1016     UNLOCK_APP(app);
1017 }
1018 
1019 void
_XtDoFreeBindings(XtAppContext app)1020 _XtDoFreeBindings(XtAppContext app)
1021 {
1022     TMBindCache bcp;
1023 
1024     while (app->free_bindings) {
1025         bcp = app->free_bindings->next;
1026         XtFree((char *) app->free_bindings);
1027         app->free_bindings = bcp;
1028     }
1029 }
1030