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