Merge branch 'master' into xcircuit-3.10
[xcircuit.git] / Xw / PopupMgr.c
blob4f7f7adccfc002989e25f99e8850e9f880c636c6
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: PopupMgr.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Popup Menu Manager Widget
9 **
10 *****************************************************************************
11 **
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
14 **
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
22 ** prior permission.
23 **
24 *****************************************************************************
25 *************************************<+>*************************************/
28 #include <X11/IntrinsicP.h>
29 #include <X11/StringDefs.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/Shell.h>
33 #include <X11/ShellP.h>
34 #include <Xw/Xw.h>
35 #include <Xw/XwP.h>
36 #include <Xw/MenuBtnP.h>
37 #include <Xw/MenuBtn.h>
38 #include <Xw/PopupMgrP.h>
39 #include <Xw/PopupMgr.h>
42 /* Standard Toolkit Routines */
43 static void Initialize();
44 static void Destroy();
45 static Boolean SetValues();
46 static void ClassPartInitialize();
48 /* Global Routines */
49 static void AttachPane();
50 static void DetachPane();
51 static void AddPane();
52 static void SetSelectAccelerator();
53 static void ClearSelectAccelerator();
54 static void AddButton();
55 static void Unpost();
56 static void Post();
57 static Boolean ProcessSelect();
58 static Boolean ValidEvent();
59 static Boolean DoICascade();
60 static void ClassPost();
61 static void ClassSelect();
62 static Boolean DoYouWantThisAccelerator();
63 static Boolean DoYouWantThisPost();
64 static void SetPostMnemonic();
65 static void ClearPostMnemonic();
66 static void SetSelectMnemonic();
67 static void ClearSelectMnemonic();
68 static void SetTitleAttributes();
69 static void TraverseLeft();
70 static void TraverseRight();
71 static void TraverseNext();
72 static void TraversePrev();
73 static void TraverseHome();
74 static void TraverseUp();
75 static void TraverseDown();
76 static void TraverseNextTop();
77 static void BtnSensitivityChanged();
78 static void PaneSensitivityChanged();
80 /* Action Routines */
81 static void MMPost();
82 static void MMAccelPost();
83 static void MMAccelSelect();
84 static void MMUnpost();
86 /* Callback Routines */
87 static void _XwMenuPaneCleanup();
88 static void _XwMenuButtonCleanup();
89 static void _XwCascadeUnselect();
90 static void _XwCascadeSelect();
92 /* Internal Support Routines */
93 static void RegisterTranslation();
94 static void ExposeEventHandler();
95 static void RegisterPostTranslation();
96 static void PositionCascade();
97 static Boolean ActionIsUsurpedByChild();
98 static void AddToPendingList();
99 static void SetButtonAccelerators();
100 static void SetTreeAccelerators();
101 static void ClearTreeAccelerators();
102 static Boolean CompletePath();
103 static Widget PendingAttach();
104 static void SetUpTranslation();
105 static void ForceMenuPaneOnScreen();
106 static void PaneManagedChildren();
107 static Boolean Visible();
108 static void SetMenuTranslations();
109 static void ManualPost();
110 static void SendFakeLeaveNotify();
111 static void SetUpStickyList();
112 static void DoDetach();
115 /****************************************************************
117 * Popup Resources
119 ****************************************************************/
121 static XtResource resources[] = {
122 {XtNstickyMenus, XtCStickyMenus, XtRBoolean, sizeof(Boolean),
123 XtOffset(XwPopupMgrWidget, popup_mgr.stickyMode),XtRString,"FALSE"},
125 {XtNpostAccelerator, XtCPostAccelerator, XtRString, sizeof(String),
126 XtOffset(XwPopupMgrWidget, popup_mgr.postAccelerator),XtRString,
127 NULL}
130 /****************************************************************
132 * Miscellaneous Values
134 ****************************************************************/
136 /* Global Action Routines */
137 static XtActionsRec XwPopupActions[] = {
138 {"PopupPostMenu", MMPost},
139 {"PopupUnpostMenu", MMUnpost},
140 {"PopupAccelPost", MMAccelPost},
141 {"PopupAccelSelect", MMAccelSelect}
144 /* Translation Template Strings */
145 static String postTemplate = ": PopupPostMenu(";
146 static String unpostTemplate = ": PopupUnpostMenu(";
147 static String accelPostTemplate = ": PopupAccelPost(";
148 static String accelSelectTemplate = ": PopupAccelSelect(";
149 static String selectTemplate = ": select()";
151 static char workArea[300];
155 * Used when positioning a cascade such that the cursor will be
156 * in the first item of the cascade.
158 #define FUDGE_FACTOR 8
160 #define SHELL_PARENT 0
161 #define ULTIMATE_PARENT 1
164 * This mask is used during the setting and clearing of button grabs.
165 * If the event being grabbed is a buttonUp event, then these bits
166 * cause the grabs to never activate; so they need to be cleared.
168 #define btnMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
170 /****************************************************************
172 * Full class record constant
174 ****************************************************************/
176 XwPopupMgrClassRec XwpopupmgrClassRec = {
178 /* core_class fields */
179 /* superclass */ (WidgetClass) &XwmenumgrClassRec,
180 /* class_name */ "XwPopupMgr",
181 /* widget_size */ sizeof(XwPopupMgrRec),
182 /* class_initialize */ NULL,
183 /* class_part_init */ ClassPartInitialize,
184 /* class_inited */ FALSE,
185 /* initialize */ Initialize,
186 /* initialize_hook */ NULL,
187 /* realize */ NULL,
188 /* actions */ NULL,
189 /* num_actions */ 0,
190 /* resources */ resources,
191 /* num_resources */ XtNumber(resources),
192 /* xrm_class */ NULLQUARK,
193 /* compress_motion */ TRUE,
194 /* compress_exposure */ TRUE,
195 /* compress_enterlv */ TRUE,
196 /* visible_interest */ FALSE,
197 /* destroy */ Destroy,
198 /* resize */ NULL,
199 /* expose */ NULL,
200 /* set_values */ SetValues,
201 /* set_values_hook */ NULL,
202 /* set_values_almost */ XtInheritSetValuesAlmost,
203 /* get_values_hook */ NULL,
204 /* accept_focus */ NULL,
205 /* version */ XtVersion,
206 /* PRIVATE cb list */ NULL,
207 /* tm_table */ NULL,
208 /* query_geometry */ NULL,
209 /* display_accelerator */ XtInheritDisplayAccelerator,
210 /* extension */ NULL
212 /* composite_class fields */
213 /* geometry_manager */ NULL,
214 /* change_managed */ NULL,
215 /* insert_child */ XtInheritInsertChild,
216 /* delete_child */ XtInheritDeleteChild,
217 NULL,
219 /* constraint class fields */
220 /* resources */ NULL,
221 /* num_resources */ 0,
222 /* constraint_size */ 0,
223 /* initialize */ NULL,
224 /* destroy */ NULL,
225 /* set_values */ NULL,
226 NULL,
228 /* manager_class fields */
229 /* traversal handler */ (XwTraversalProc)XtInheritTraversalProc,
230 /* translations */ NULL,
232 /* menu manager class */
233 /* attachPane */ AttachPane,
234 /* detachPane */ DetachPane,
235 /* addPane */ AddPane,
236 /* setSelectAccel */ SetSelectAccelerator,
237 /* clearSelectAccel */ ClearSelectAccelerator,
238 /* setPostMnemonic */ SetPostMnemonic,
239 /* clearPostMnemonic */ ClearPostMnemonic,
240 /* addButton */ AddButton,
241 /* processSelect */ (XwBooleanProc)ProcessSelect,
242 /* validEvent */ (XwBooleanProc)ValidEvent,
243 /* doIcascade */ DoICascade,
244 /* setSelectMnemonic */ SetSelectMnemonic,
245 /* clearSelectMnemon */ ClearSelectMnemonic,
246 /* setTitleAttributes */ SetTitleAttributes,
247 /* paneManagedChildren*/ PaneManagedChildren,
248 /* traverseLeft */ TraverseLeft,
249 /* traverseRight */ TraverseRight,
250 /* traverseNext */ TraverseNext,
251 /* traversePrev */ TraversePrev,
252 /* traverseHome */ TraverseHome,
253 /* traverseUp */ TraverseUp,
254 /* traverseDown */ TraverseDown,
255 /* traverseNextTop */ TraverseNextTop,
256 /* btnSensitivityChan */ BtnSensitivityChanged,
257 /* paneSensitivityCha */ PaneSensitivityChanged,
259 /* popup menu manager class - none */
260 /* manualPost */ (XwPostProc) ManualPost,
264 WidgetClass XwpopupmgrWidgetClass = (WidgetClass)&XwpopupmgrClassRec;
265 WidgetClass XwpopupMgrWidgetClass = (WidgetClass)&XwpopupmgrClassRec;
267 /*----------------------------------------------------------------------*/
268 /* I don't really know why PopupMgr needs to register its actions */
269 /* globally like this when all other widgets don't; regardless, */
270 /* running this in ClassInitialize() doesn't work because the app */
271 /* context can be destroyed and remade, and then it loses the actions, */
272 /* instead returning "Warning: Actions not found: PopupPostMenu". */
273 /* Furthermore, the "correct" implementation needs a value for "app", */
274 /* which must be declared global, which is clearly a hack. So I'm */
275 /* instead creating a world-accessible function which does what */
276 /* ClassInitialize() did, but it takes an argument "app" and must be */
277 /* called every time the application is (re)made. */
278 /*----------------------------------------------------------------------*/
280 void XwAppInitialize(XtAppContext app)
282 /* Register the global action routines */
283 XtAppAddActions (app, XwPopupActions, XtNumber(XwPopupActions));
287 /*************************************<->*************************************
289 * Initialize
292 * Description:
293 * -----------
294 * Initialize the popup_mgr fields within the widget's instance structure.
297 * Inputs:
298 * ------
299 * xxxxxxxxxxxx = xxxxxxxxxxxxx
301 * Outputs:
302 * -------
303 * xxxxxxxxxxxx = xxxxxxxxxxxxx
305 * Procedures Called
306 * -----------------
308 *************************************<->***********************************/
310 static void Initialize (request, new)
312 XwPopupMgrWidget request;
313 register XwPopupMgrWidget new;
316 Widget grandparent;
317 KeySym tempKeysym;
320 * Clear the 'map when managed' flag, since this widget should
321 * never be visible.
323 new->core.mapped_when_managed = FALSE;
325 /* Fill in our instance fields */
326 new->popup_mgr.topLevelPane = (Widget) NULL;
327 new->popup_mgr.lastSelected = (Widget) NULL;
328 new->popup_mgr.savedCascadeList = (Widget *) XtMalloc(25 * sizeof(Widget));
329 new->popup_mgr.numSavedCascades = 0;
330 new->popup_mgr.sizeSavedCascadeList = 25;
331 new->popup_mgr.currentCascadeList = (Widget *) XtMalloc(25 * sizeof(Widget));
332 new->popup_mgr.numCascades = 0;
333 new->popup_mgr.sizeCascadeList = 25;
334 new->popup_mgr.attachPane = (XwMenuPaneWidget) NULL;
335 new->popup_mgr.detachPane = (XwMenuPaneWidget) NULL;
336 new->popup_mgr.origMouseX = -1;
337 new->popup_mgr.origMouseY = -1;
339 /* Get the widget Id for the widget to which the menu is attached */
340 grandparent = (Widget) XtParent(XtParent(new));
343 * If a post accelerator is specified, then attempt to convert it to
344 * a usable format (not a string); if the accelerator specification is
345 * invalid, then use the default post accelerator (none).
347 if ((new->popup_mgr.postAccelerator) &&
348 (strlen(new->popup_mgr.postAccelerator) > 0) &&
349 (_XwMapKeyEvent (new->popup_mgr.postAccelerator,
350 &new->popup_mgr.accelEventType,
351 &tempKeysym,
352 &new->popup_mgr.accelModifiers)))
354 /* Valid accelerator string; save a copy */
355 new->popup_mgr.accelKey = XKeysymToKeycode(XtDisplay(new),
356 tempKeysym);
357 new->popup_mgr.postAccelerator = (String) strcpy (XtMalloc (
358 XwStrlen(new->popup_mgr. postAccelerator) + 1),
359 new->popup_mgr.postAccelerator);
361 /* Set up a translation in the widget */
362 RegisterTranslation (grandparent, new->popup_mgr.postAccelerator,
363 accelPostTemplate, new);
365 else
367 if ((new->popup_mgr.postAccelerator) &&
368 (strlen(new->popup_mgr.postAccelerator) > 0))
370 XtWarning ("PopupMgr: Invalid post accelerator; disabling feature");
372 new->popup_mgr.postAccelerator = NULL;
373 new->popup_mgr.accelEventType = 0;
374 new->popup_mgr.accelKey = 0;
375 new->popup_mgr.accelModifiers = 0;
378 /* Attach a posting translation to the widget */
379 if (new->menu_mgr.postString)
381 RegisterTranslation (grandparent, new->menu_mgr.postString,
382 postTemplate, new);
385 /* Attach an unposting translation to the widget, if specified */
386 if (new->menu_mgr.unpostString)
388 RegisterTranslation (grandparent, new->menu_mgr.unpostString,
389 unpostTemplate, new);
393 * If the children of the widget are to inherit this menu, then we
394 * need to set up a button grab for the posting event; if the widget
395 * is not yet realized, then we cannot set the grab, so we will
396 * attach an exposure event handler to the widget, so that when it
397 * does finally get mapped, we can set up any necessary grabs.
399 if (XtIsRealized(grandparent))
401 if (new->menu_mgr.associateChildren)
403 /* Set up a grab for the post event */
404 if (new->menu_mgr.postString)
406 XGrabButton (XtDisplay(grandparent), new->menu_mgr.postButton,
407 (new->menu_mgr.postModifiers & ~btnMask),
408 XtWindow(grandparent),
409 False, ButtonPressMask|ButtonReleaseMask,
410 GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
413 /* Set up a grab for the post accelerator */
414 if (new->popup_mgr.postAccelerator)
416 XGrabKey (XtDisplay(grandparent),
417 new->popup_mgr.accelKey,
418 new->popup_mgr.accelModifiers, XtWindow(grandparent),
419 False, GrabModeAsync, GrabModeAsync);
423 else
425 XtAddEventHandler (grandparent, ExposureMask|StructureNotifyMask, False,
426 ExposeEventHandler, new);
428 } /* Initialize */
431 /*************************************<->*************************************
433 * SetValues()
435 * Description:
436 * -----------
439 * Inputs:
440 * ------
441 * xxxxxxxxxxxx = xxxxxxxxxxxxx
443 * Outputs:
444 * -------
445 * xxxxxxxxxxxx = xxxxxxxxxxxxx
447 * Procedures Called
448 * -----------------
450 *************************************<->***********************************/
452 static Boolean SetValues (current, request, new)
454 register XwPopupMgrWidget current;
455 XwPopupMgrWidget request;
456 register XwPopupMgrWidget new;
459 Widget grandparent;
460 Boolean postGrabSet = FALSE;
461 Boolean postGrabCleared = FALSE;
462 Boolean postAccelGrabSet = FALSE;
463 Boolean postAccelGrabCleared = FALSE;
464 KeySym tempKeysym;
465 XtTranslations translation;
466 String workTemplate;
467 register int i, j, k;
469 grandparent = (Widget) XtParent(XtParent(current));
471 /* Process the post accelerator */
472 if (current->popup_mgr.postAccelerator != new->popup_mgr.postAccelerator)
474 if ((new->popup_mgr.postAccelerator) &&
475 (strlen(new->popup_mgr.postAccelerator) > 0))
477 if (_XwMapKeyEvent (new->popup_mgr.postAccelerator,
478 &new->popup_mgr.accelEventType,
479 &tempKeysym,
480 &new->popup_mgr.accelModifiers))
482 /* Valid accelerator string; save a copy */
483 new->popup_mgr.accelKey = XKeysymToKeycode (XtDisplay(new),
484 tempKeysym);
485 new->popup_mgr.postAccelerator = (String) strcpy (XtMalloc (
486 XwStrlen(new->popup_mgr. postAccelerator) + 1),
487 new->popup_mgr.postAccelerator);
489 else
491 /* Invalid; revert to previous setting */
492 XtWarning
493 ("PopupMgr: Invalid post accelerator; using previous setting");
494 new->popup_mgr.postAccelerator = current->popup_mgr.postAccelerator;
495 new->popup_mgr.accelEventType = current->popup_mgr.accelEventType;
496 new->popup_mgr.accelKey = current->popup_mgr.accelKey;
497 new->popup_mgr.accelModifiers = current->popup_mgr.accelModifiers;
500 else
502 /* None specified, so disable the feature */
503 new->popup_mgr.postAccelerator = NULL;
504 new->popup_mgr.accelEventType = 0;
505 new->popup_mgr.accelKey = 0;
506 new->popup_mgr.accelModifiers = 0;
510 * This duplicate check prevents us from doing alot of unnecessary
511 * work in the case where an invalid string was specified, and thus
512 * we reverted to the previous value.
514 if (current->popup_mgr.postAccelerator != new->popup_mgr.postAccelerator)
516 /* Remove the old accelerator translation and grab */
517 if (current->popup_mgr.postAccelerator)
519 RegisterTranslation (grandparent,
520 current->popup_mgr.postAccelerator,
521 accelPostTemplate, NULL);
523 if (XtIsRealized(grandparent) &&current->menu_mgr.associateChildren)
525 XUngrabKey (XtDisplay(grandparent), current->popup_mgr.accelKey,
526 current->popup_mgr.accelModifiers, XtWindow(grandparent));
527 postAccelGrabCleared = TRUE;
531 /* Set the new accelerator translation and grab */
532 if (new->popup_mgr.postAccelerator)
534 RegisterTranslation (grandparent, new->popup_mgr.postAccelerator,
535 accelPostTemplate, new);
537 if (XtIsRealized(grandparent) && new->menu_mgr.associateChildren)
539 XGrabKey (XtDisplay(grandparent), new->popup_mgr.accelKey,
540 new->popup_mgr.accelModifiers, XtWindow(grandparent),
541 False, GrabModeAsync, GrabModeAsync);
542 postAccelGrabSet = TRUE;
546 /* Free up the buffer holding the old string */
547 XtFree (current->popup_mgr.postAccelerator);
551 /* Process the post event */
552 if (current->menu_mgr.postString != new->menu_mgr.postString)
554 /* Remove the old post translation and grab */
555 if (current->menu_mgr.postString)
557 RegisterTranslation (grandparent, current->menu_mgr.postString,
558 postTemplate, NULL);
560 if (XtIsRealized(grandparent) && current->menu_mgr.associateChildren)
562 XUngrabButton (XtDisplay(grandparent), current->menu_mgr.postButton,
563 (current->menu_mgr.postModifiers & ~btnMask),
564 XtWindow(grandparent));
565 postGrabCleared = TRUE;
568 /* Free up the old string */
569 XtFree (current->menu_mgr.postString);
572 /* Set the new post translation and grab */
573 if (new->menu_mgr.postString)
575 RegisterTranslation (grandparent, new->menu_mgr.postString,
576 postTemplate, new);
578 if (XtIsRealized(grandparent) && new->menu_mgr.associateChildren)
580 XGrabButton (XtDisplay(grandparent), new->menu_mgr.postButton,
581 (new->menu_mgr.postModifiers & ~btnMask),
582 XtWindow(grandparent),
583 False, ButtonPressMask|ButtonReleaseMask,
584 GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
585 postGrabSet = TRUE;
590 /* Process the select event. */
591 if (current->menu_mgr.selectString != new->menu_mgr.selectString)
595 * Each menubutton and menupane must have a new 'select' translation
596 * set up; no grabs are needed. The old ones do not need to be
597 * removed, since ProcessSelect() will reject them.
600 if (new->menu_mgr.selectString)
603 * Create the translation string of format:
605 * "!<event>: select()"
607 workTemplate = &workArea[0];
608 strcpy (workTemplate, "!");
609 strcat (workTemplate, new->menu_mgr.selectString);
610 strcat (workTemplate, selectTemplate);
611 translation = XtParseTranslationTable (workTemplate);
612 SetMenuTranslations (new, translation);
613 /* XtDestroyStateTable (XtClass(new), translation); */
616 if (current->menu_mgr.selectString)
617 XtFree (current->menu_mgr.selectString);
620 /* Process the unpost event. */
621 if (current->menu_mgr.unpostString != new->menu_mgr.unpostString)
624 * Each menubutton and menupane must have a new 'unpost' translation
625 * set up; no grabs are needed. The old ones need to first be
626 * removed.
629 if (current->menu_mgr.unpostString)
632 * Create the translation string of format:
634 * "!<event>: MMUnpost(mgrId)"
637 workTemplate = &workArea[0];
638 strcpy (workTemplate, "!");
639 strcat (workTemplate, current->menu_mgr.unpostString);
640 strcat (workTemplate, unpostTemplate);
641 strcat (workTemplate, _XwMapToHex(NULL));
642 strcat (workTemplate, ")");
643 translation = XtParseTranslationTable (workTemplate);
644 SetMenuTranslations (new, translation);
645 /* XtDestroyStateTable (XtClass(new), translation); */
646 RegisterTranslation (grandparent, current->menu_mgr.unpostString,
647 unpostTemplate, NULL);
648 XtFree (current->menu_mgr.unpostString);
651 if (new->menu_mgr.unpostString)
654 * Create the translation string of format:
656 * "!<event>: MMUnpost(mgrId)"
659 workTemplate = &workArea[0];
660 strcpy (workTemplate, "!");
661 strcat (workTemplate, new->menu_mgr.unpostString);
662 strcat (workTemplate, unpostTemplate);
663 strcat (workTemplate, _XwMapToHex(new->core.self));
664 strcat (workTemplate, ")");
665 translation = XtParseTranslationTable (workTemplate);
666 SetMenuTranslations (new, translation);
667 /* XtDestroyStateTable (XtClass(new), translation); */
668 RegisterTranslation (grandparent, new->menu_mgr.unpostString,
669 unpostTemplate, new);
673 /* Process the keyboard select event. */
674 if (current->menu_mgr.kbdSelectString != new->menu_mgr.kbdSelectString)
677 * Each menubutton and menupane must have a new 'kbd select' translation
678 * set up; no grabs are needed. The old ones do not need to be
679 * removed, since ProcessSelect() will reject them.
682 if (new->menu_mgr.kbdSelectString)
685 * Create the translation string of format:
687 * "!<event>: select()"
689 workTemplate = &workArea[0];
690 strcpy (workTemplate, "!");
691 strcat (workTemplate, new->menu_mgr.kbdSelectString);
692 strcat (workTemplate, selectTemplate);
693 translation = XtParseTranslationTable (workTemplate);
696 * Since the menupanes are our popup grand children, we
697 * will process them simply by traversing our popup children list.
699 SetMenuTranslations (new, translation);
700 /* XtDestroyStateTable (XtClass(new), translation); */
703 if (current->menu_mgr.kbdSelectString)
704 XtFree (current->menu_mgr.kbdSelectString);
707 /* Process the associateChildren flag */
708 if (current->menu_mgr.associateChildren != new->menu_mgr.associateChildren)
710 int i;
713 * If the widget is realized, then we need to set/clear button
714 * and key grabs for the post event, the post accelerator, and
715 * all menubutton accelerators; the two post grabs will only be
716 * set or cleared if they were not already done so earlier; this
717 * would have happened if either of their event strings had
718 * changed.
720 if (XtIsRealized (grandparent))
722 if (new->menu_mgr.associateChildren)
724 /* Set post grab */
725 if ((!postGrabSet) && (new->menu_mgr.postString))
727 XGrabButton (XtDisplay(grandparent), new->menu_mgr.postButton,
728 (new->menu_mgr.postModifiers & ~btnMask),
729 XtWindow(grandparent),
730 False, ButtonPressMask|ButtonReleaseMask,
731 GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
734 /* Set post accelerator grab */
735 if ((!postAccelGrabSet) && (new->popup_mgr.postAccelerator))
737 XGrabKey (XtDisplay(grandparent), new->popup_mgr.accelKey,
738 new->popup_mgr.accelModifiers, XtWindow(grandparent),
739 False, GrabModeAsync, GrabModeAsync);
742 /* Set menubutton accelerator grabs */
743 for (i = 0; i < new->menu_mgr.numAccels; i++)
745 XGrabKey (XtDisplay(grandparent),
746 new->menu_mgr.menuBtnAccelTable[i].accelKey,
747 new->menu_mgr.menuBtnAccelTable[i].accelModifiers,
748 XtWindow(grandparent), False, GrabModeAsync,
749 GrabModeAsync);
752 else
754 /* Clear post grab */
755 if ((!postGrabCleared) && (current->menu_mgr.postString))
757 XUngrabButton (XtDisplay(grandparent),
758 current->menu_mgr.postButton,
759 (current->menu_mgr.postModifiers & ~btnMask),
760 XtWindow(grandparent));
763 /* Clear post accelerator grab */
764 if ((!postAccelGrabCleared) && (current->popup_mgr.postAccelerator))
766 XUngrabKey (XtDisplay(grandparent),
767 current->popup_mgr.accelKey,
768 current->popup_mgr.accelModifiers,
769 XtWindow(grandparent));
772 /* Clear menubutton accelerator grabs */
773 for (i = 0; i < current->menu_mgr.numAccels; i++)
775 XUngrabKey (XtDisplay(grandparent),
776 current->menu_mgr.menuBtnAccelTable[i].accelKey,
777 current->menu_mgr.menuBtnAccelTable[i].accelModifiers,
778 XtWindow(grandparent));
785 * Since all of the menu components inherit their traversal setting
786 * from their menu manager, anytime the menu manager's traversal
787 * state changes, we need to propogate this down to all of the other
788 * menu components (panes, buttons, separaters).
790 if (new->manager.traversal_on != current->manager.traversal_on)
792 int traversalType;
794 if (new->manager.traversal_on)
795 traversalType = XwHIGHLIGHT_TRAVERSAL;
796 else
797 traversalType = XwHIGHLIGHT_OFF;
799 for (i = 0; i < current->core.num_popups; i++)
801 CompositeWidget shell;
803 shell = (CompositeWidget) current->core.popup_list[i];
805 for (j = 0; j < shell->composite.num_children; j++)
807 XwMenuPaneWidget menupane;
809 /* Here we set the traversal flag for the menupanes */
810 menupane = (XwMenuPaneWidget)shell->composite.children[j];
811 if (XtIsSubclass ((Widget)menupane, XwmenupaneWidgetClass))
813 (*(((XwMenuPaneWidgetClass)
814 XtClass(menupane))-> menu_pane_class.setTraversalFlag))
815 ((Widget)menupane, new->manager.traversal_on);
818 for (k = 0; k < menupane->manager.num_managed_children; k++)
820 XwMenuButtonWidget mbutton;
822 /* Here we set the traversal flag for the menubuttons */
823 mbutton = (XwMenuButtonWidget)menupane->composite.children[k];
824 if (XtIsSubclass ((Widget)mbutton, XwmenubuttonWidgetClass))
826 (*(((XwMenuButtonWidgetClass)
827 XtClass(mbutton))-> menubutton_class.setTraversalType))
828 ((Widget)mbutton, traversalType);
835 /* Clear the sticky menu list, if sticky mode is disabled */
836 if (new->popup_mgr.stickyMode == False)
837 new->popup_mgr.numSavedCascades = 0;
839 return (FALSE);
843 /*************************************<->*************************************
845 * Destroy()
847 * Description:
848 * -----------
851 * Inputs:
852 * ------
853 * xxxxxxxxxxxx = xxxxxxxxxxxxx
855 * Outputs:
856 * -------
857 * xxxxxxxxxxxx = xxxxxxxxxxxxx
859 * Procedures Called
860 * -----------------
862 *************************************<->***********************************/
864 static void Destroy (mw)
866 register XwPopupMgrWidget mw;
869 Widget grandparent;
870 register int i;
872 /* Get the widget Id for the widget to which the menus are attached */
873 grandparent = (Widget)XtParent(XtParent(mw));
875 /* Free up any memory we allocated */
876 XtFree ((char *)(mw->popup_mgr.savedCascadeList));
877 XtFree ((char *)(mw->popup_mgr.currentCascadeList));
879 /* Clean up the post and accelerated post translations */
880 if (mw->menu_mgr.postString)
882 RegisterTranslation (grandparent, mw->menu_mgr.postString,
883 postTemplate, NULL);
885 if (mw->popup_mgr.postAccelerator)
887 RegisterTranslation (grandparent, mw->popup_mgr.postAccelerator,
888 accelPostTemplate, NULL);
891 if (mw->menu_mgr.unpostString)
893 RegisterTranslation (grandparent, mw->menu_mgr.unpostString,
894 unpostTemplate, NULL);
897 /***************
898 * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
899 * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
900 * ALREADY CLEARED.
902 * Remove translations for each menubutton accelerator
904 * for (i = 0; i < mw->menu_mgr.numAccels; i++)
906 * RegisterTranslation (grandparent,
907 * mw->menu_mgr.menuBtnAccelTable[i].accelString,
908 * accelSelectTemplate, NULL);
910 ****************/
912 /* Remove any grabs we have set on the widget */
913 if (XtIsRealized(grandparent))
915 if (mw->menu_mgr.associateChildren)
917 /* Remove post grab */
918 if (mw->menu_mgr.postString)
920 XUngrabButton (XtDisplay(grandparent), mw->menu_mgr.postButton,
921 (mw->menu_mgr.postModifiers & ~btnMask),
922 XtWindow(grandparent));
925 /* Remove post accelerator grab */
926 if (mw->popup_mgr.postAccelerator)
928 XUngrabKey (XtDisplay(grandparent), mw->popup_mgr.accelKey,
929 mw->popup_mgr.accelModifiers, XtWindow(grandparent));
932 /***************
933 * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
934 * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
935 * ALREADY CLEARED.
937 * Remove grabs for each menubutton accelerator
938 * for (i = 0; i < mw->menu_mgr.numAccels; i++)
940 * XUngrabKey (XtDisplay(grandparent),
941 * mw->menu_mgr.menuBtnAccelTable[i].accelKey,
942 * mw->menu_mgr.menuBtnAccelTable[i].accelModifiers,
943 * XtWindow(grandparent));
945 ***************/
948 else
950 /* Simply remove the exposure handler we added at initialize time */
951 XtRemoveEventHandler (grandparent, ExposureMask|StructureNotifyMask,
952 False, ExposeEventHandler, mw);
957 /*************************************<->*************************************
959 * ClassPartInitialize(parameters)
961 * Description:
962 * -----------
963 * xxxxxxxxxxxxxxxxxxxxxxx
966 * Inputs:
967 * ------
968 * xxxxxxxxxxxx = xxxxxxxxxxxxx
970 * Outputs:
971 * -------
972 * xxxxxxxxxxxx = xxxxxxxxxxxxx
974 * Procedures Called
975 * -----------------
977 *************************************<->***********************************/
979 static void ClassPartInitialize (wc)
981 register XwPopupMgrWidgetClass wc;
984 register XwPopupMgrWidgetClass super;
986 super = (XwPopupMgrWidgetClass)wc->core_class.superclass;
988 if (wc->menu_mgr_class.attachPane == XtInheritAttachPane)
989 wc->menu_mgr_class.attachPane = super->menu_mgr_class.attachPane;
991 if (wc->menu_mgr_class.detachPane == XtInheritDetachPane)
992 wc->menu_mgr_class.detachPane = super->menu_mgr_class.detachPane;
994 if (wc->menu_mgr_class.addPane == XtInheritAddPane)
995 wc->menu_mgr_class.addPane = super->menu_mgr_class.addPane;
997 if (wc->menu_mgr_class.setSelectAccelerator == XtInheritSetSelectAccelerator)
998 wc->menu_mgr_class.setSelectAccelerator =
999 super->menu_mgr_class.setSelectAccelerator;
1001 if (wc->menu_mgr_class.clearSelectAccelerator ==
1002 XtInheritClearSelectAccelerator)
1003 wc->menu_mgr_class.clearSelectAccelerator =
1004 super->menu_mgr_class.clearSelectAccelerator;
1006 if (wc->menu_mgr_class.setPostMnemonic == XtInheritSetPostMnemonic)
1007 wc->menu_mgr_class.setPostMnemonic =super->menu_mgr_class.setPostMnemonic;
1009 if (wc->menu_mgr_class.clearPostMnemonic == XtInheritClearPostMnemonic)
1010 wc->menu_mgr_class.clearPostMnemonic =
1011 super->menu_mgr_class.clearPostMnemonic;
1013 if (wc->menu_mgr_class.setPostMnemonic == XtInheritSetPostMnemonic)
1014 wc->menu_mgr_class.setPostMnemonic =super->menu_mgr_class.setPostMnemonic;
1016 if (wc->menu_mgr_class.clearPostMnemonic==XtInheritClearPostMnemonic)
1017 wc->menu_mgr_class.clearPostMnemonic =
1018 super->menu_mgr_class.clearPostMnemonic;
1020 if (wc->menu_mgr_class.addButton == XtInheritAddButton)
1021 wc->menu_mgr_class.addButton = super->menu_mgr_class.addButton;
1023 if (wc->menu_mgr_class.setSelectMnemonic == XtInheritSetSelectMnemonic)
1024 wc->menu_mgr_class.setSelectMnemonic =
1025 super->menu_mgr_class.setSelectMnemonic;
1027 if (wc->menu_mgr_class.clearSelectMnemonic == XtInheritClearSelectMnemonic)
1028 wc->menu_mgr_class.clearSelectMnemonic =
1029 super->menu_mgr_class.clearSelectMnemonic;
1031 if (wc->menu_mgr_class.processSelect == XtInheritProcessSelect)
1032 wc->menu_mgr_class.processSelect = super->menu_mgr_class.processSelect;
1034 if (wc->menu_mgr_class.validEvent == XtInheritValidEvent)
1035 wc->menu_mgr_class.validEvent = super->menu_mgr_class.validEvent;
1037 if (wc->menu_mgr_class.doICascade == XtInheritDoICascade)
1038 wc->menu_mgr_class.doICascade = super->menu_mgr_class.doICascade;
1040 if (wc->menu_mgr_class.paneManagedChildren == XtInheritPaneManagedChildren)
1041 wc->menu_mgr_class.paneManagedChildren =
1042 super->menu_mgr_class.paneManagedChildren;
1044 if (wc->menu_mgr_class.setTitleAttributes == XtInheritSetTitleAttributes)
1045 wc->menu_mgr_class.setTitleAttributes =
1046 super->menu_mgr_class.setTitleAttributes;
1048 if (wc->menu_mgr_class.traverseLeft == XtInheritPopupTravLeft)
1049 wc->menu_mgr_class.traverseLeft = super->menu_mgr_class.traverseLeft;
1051 if (wc->menu_mgr_class.traverseRight == XtInheritPopupTravRight)
1052 wc->menu_mgr_class.traverseRight = super->menu_mgr_class.traverseRight;
1054 if (wc->menu_mgr_class.traverseNext == XtInheritPopupTravNext)
1055 wc->menu_mgr_class.traverseNext = super->menu_mgr_class.traverseNext;
1057 if (wc->menu_mgr_class.traversePrev == XtInheritPopupTravPrev)
1058 wc->menu_mgr_class.traversePrev = super->menu_mgr_class.traversePrev;
1060 if (wc->menu_mgr_class.traverseHome == XtInheritPopupTravHome)
1061 wc->menu_mgr_class.traverseHome = super->menu_mgr_class.traverseHome;
1063 if (wc->menu_mgr_class.traverseUp == XtInheritPopupTravUp)
1064 wc->menu_mgr_class.traverseUp = super->menu_mgr_class.traverseUp;
1066 if (wc->menu_mgr_class.traverseDown == XtInheritPopupTravDown)
1067 wc->menu_mgr_class.traverseDown = super->menu_mgr_class.traverseDown;
1069 if (wc->menu_mgr_class.traverseNextTop == XtInheritPopupTravNextTop)
1070 wc->menu_mgr_class.traverseNextTop=super->menu_mgr_class.traverseNextTop;
1072 if (wc->menu_mgr_class.btnSensitivityChanged==XtInheritBtnSensitivityChanged)
1073 wc->menu_mgr_class.btnSensitivityChanged =
1074 super->menu_mgr_class.btnSensitivityChanged;
1076 if (wc->menu_mgr_class.paneSensitivityChanged ==
1077 XtInheritPaneSensitivityChanged)
1078 wc->menu_mgr_class.paneSensitivityChanged =
1079 super->menu_mgr_class.paneSensitivityChanged;
1082 /*************************************<->*************************************
1084 * RegisterTranslation (parameters)
1086 * Description:
1087 * -----------
1088 * xxxxxxxxxxxxxxxxxxxxxxx
1091 * Inputs:
1092 * ------
1093 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1095 * Outputs:
1096 * -------
1097 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1099 * Procedures Called
1100 * -----------------
1102 *************************************<->***********************************/
1104 static void RegisterTranslation (widget, event, template, menuMgrId)
1106 Widget widget;
1107 String event;
1108 String template;
1109 Widget menuMgrId;
1113 register String workTemplate;
1114 XtTranslations translations;
1116 workTemplate = &workArea[0];
1119 * Construct the translation string, using the following format:
1121 * "!<event>: ActionProc(menuMgrId)"
1124 strcpy (workTemplate, "!");
1125 strcat (workTemplate, event);
1126 strcat (workTemplate, template);
1127 if (menuMgrId)
1128 strcat (workTemplate, _XwMapToHex(menuMgrId->core.self));
1129 else
1130 strcat (workTemplate, _XwMapToHex(NULL));
1131 strcat (workTemplate, ")");
1133 /* Compile the translation and attach to the widget */
1134 translations = XtParseTranslationTable(workTemplate);
1135 XtOverrideTranslations (widget, translations);
1136 /* XtDestroyStateTable (XtClass(widget), translations); */
1140 /*************************************<->*************************************
1142 * PositionCascade (parameters)
1144 * Description:
1145 * -----------
1146 * This routine positions a cacading submenu pane. When the new
1147 * menupane is posted, it will slightly overlap the previous menu
1148 * pane (in the x direction). In the y direction, the new menupane
1149 * will be positioned such that its first menubutton is centered on
1150 * the menubutton to which the menupane is attached.
1153 * Inputs:
1154 * ------
1155 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1157 * Outputs:
1158 * -------
1159 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1161 * Procedures Called
1162 * -----------------
1164 *************************************<->***********************************/
1166 static void PositionCascade (menubutton, menupane)
1168 register Widget menubutton;
1169 XwManagerWidget menupane;
1172 Position x, y, yDelta;
1173 Widget menubuttonGrandparent;
1174 Widget menubuttonParent;
1175 Widget menupaneShell;
1177 menubuttonParent = (Widget)XtParent(menubutton);
1178 menubuttonGrandparent = (Widget)XtParent(menubuttonParent);
1179 menupaneShell = (Widget)XtParent(menupane);
1182 * In order for this algorithm to work, we need to make sure the
1183 * menupane has been realized; this is because its size is not
1184 * yet valid because it is not notified that it has any children
1185 * until it is realized.
1187 if (!XtIsRealized (menupaneShell))
1188 XtRealizeWidget (menupaneShell);
1191 * Since the x and y need to be absolute positions, we need to
1192 * use the shell widget coordinates in portions of these calculations.
1194 x = menubuttonGrandparent->core.x +
1195 menubuttonParent->core.border_width +
1196 menubutton->core.border_width +
1197 menubutton->core.width -
1198 (XwCASCADEWIDTH + FUDGE_FACTOR + menupane->core.border_width);
1200 y = menubuttonGrandparent->core.y +
1201 menubuttonParent->core.border_width +
1202 menubutton->core.border_width +
1203 menubutton->core.y +
1204 (menubutton->core.height >> 1);
1206 /* Attempt to center on the first button in the new menupane */
1207 if (menupane->manager.num_managed_children > 0)
1209 Widget firstButton = menupane->manager.managed_children[0];
1211 yDelta = firstButton->core.y +
1212 firstButton->core.border_width +
1213 (firstButton->core.height >> 1);
1215 yDelta = 0;
1217 else
1218 yDelta = menupane->core.border_width + (menupane->core.height >> 1);
1220 y -= yDelta;
1222 ForceMenuPaneOnScreen (menupane, &x, &y);
1224 XtMoveWidget (menupaneShell, x, y);
1228 /*************************************<->*************************************
1230 * ExposeEventHandler (parameters)
1232 * Description:
1233 * -----------
1234 * xxxxxxxxxxxxxxxxxxxxxxx
1237 * Inputs:
1238 * ------
1239 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1241 * Outputs:
1242 * -------
1243 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1245 * Procedures Called
1246 * -----------------
1248 *************************************<->***********************************/
1250 static void ExposeEventHandler (w, menuMgr, event)
1252 Widget w;
1253 register XwPopupMgrWidget menuMgr;
1254 XEvent * event;
1257 register int i;
1260 * If the children inherit the menu tree, then set up grabs for
1261 * the post button, the post accelerator key, and each menubutton
1262 * accelerator.
1264 if (menuMgr->menu_mgr.associateChildren)
1266 if (menuMgr->menu_mgr.postString)
1268 XGrabButton (XtDisplay(menuMgr), menuMgr->menu_mgr.postButton,
1269 (menuMgr->menu_mgr.postModifiers & ~btnMask),
1270 XtWindow(w), False,
1271 ButtonPressMask|ButtonReleaseMask,
1272 GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
1275 if (menuMgr->popup_mgr.postAccelerator)
1277 XGrabKey (XtDisplay(menuMgr), menuMgr->popup_mgr.accelKey,
1278 menuMgr->popup_mgr.accelModifiers, XtWindow(w),
1279 False, GrabModeAsync, GrabModeAsync);
1282 for (i = 0; i < menuMgr->menu_mgr.numAccels; i++)
1284 XGrabKey (XtDisplay(menuMgr),
1285 menuMgr->menu_mgr.menuBtnAccelTable[i].accelKey,
1286 menuMgr->menu_mgr.menuBtnAccelTable[i].accelModifiers,
1287 XtWindow(w), False, GrabModeAsync, GrabModeAsync);
1291 XtRemoveEventHandler (w, ExposureMask|StructureNotifyMask, False,
1292 (XtEventHandler)ExposeEventHandler, menuMgr);
1296 /*************************************<->*************************************
1298 * _XwCascadeSelect(parameters)
1300 * Description:
1301 * -----------
1302 * xxxxxxxxxxxxxxxxxxxxxxx
1305 * Inputs:
1306 * ------
1307 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1309 * Outputs:
1310 * -------
1311 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1313 * Procedures Called
1314 * -----------------
1316 *************************************<->***********************************/
1318 static void _XwCascadeSelect (menubutton, menupane, data)
1320 Widget menubutton;
1321 XwMenuPaneWidget menupane;
1322 caddr_t data; /* not used */
1325 register int i;
1326 register XwPopupMgrWidget menuMgr;
1328 menuMgr = (XwPopupMgrWidget) XtParent(XtParent(menupane));
1330 /* If the pane is already posted, then do nothing but return */
1331 for (i = 0; i < menuMgr->popup_mgr.numCascades; i++)
1333 if (menupane==(XwMenuPaneWidget)menuMgr->popup_mgr.currentCascadeList[i])
1334 return;
1337 /* Position the cascading menupane */
1338 PositionCascade (menubutton, menupane);
1340 /* Post the menupane */
1341 Post (menuMgr, menupane, XtGrabNonexclusive);
1343 /* Set the traversal focus, if necessary */
1344 if (menuMgr->manager.traversal_on)
1346 /* Force the highlight to the first item */
1347 menupane->manager.active_child = NULL;
1348 XtSetKeyboardFocus ((Widget)menupane, NULL);
1349 XwMoveFocus (menupane);
1350 SendFakeLeaveNotify(menubutton, SHELL_PARENT);
1352 XFlush(XtDisplay(menuMgr));
1356 /*************************************<->*************************************
1358 * _XwCascadeUnselect (parameters)
1360 * Description:
1361 * -----------
1362 * xxxxxxxxxxxxxxxxxxxxxxx
1365 * Inputs:
1366 * ------
1367 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1369 * Outputs:
1370 * -------
1371 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1373 * Procedures Called
1374 * -----------------
1376 *************************************<->***********************************/
1378 static void _XwCascadeUnselect (menubutton, menupane, params)
1380 Widget menubutton;
1381 Widget menupane;
1382 register XwunselectParams * params;
1385 XwPopupMgrWidget menuMgr;
1386 register Widget shell;
1388 menuMgr = (XwPopupMgrWidget) XtParent(XtParent(menupane));
1389 shell = (Widget)XtParent(menupane);
1392 * Determine if the cursor left the cascade region and entered
1393 * the cascading menupane. If this happened, then tell the menu
1394 * button to remain highlighted. If this did not happen, then we
1395 * need to unpost the menupane, and tell the menubutton to unhighlight.
1399 /* See if the cursor is in the menupane */
1400 if ((params->rootX >= shell->core.x) && (params->rootX <
1401 (shell->core.x + shell->core.width + (shell->core.border_width << 1))) &&
1402 (params->rootY >= shell->core.y) && (params->rootY <
1403 (shell->core.y + shell->core.height + (shell->core.border_width << 1))))
1405 /* Yes, we're in the cascading menupane */
1406 params->remainHighlighted = TRUE;
1408 else
1410 /* No, we've left the cascade region; unpost the menupane */
1411 Unpost (menuMgr, menupane);
1412 params->remainHighlighted = FALSE;
1417 /*************************************<->*************************************
1419 * _XwMenuPaneCleanup (parameters)
1421 * Description:
1422 * -----------
1423 * xxxxxxxxxxxxxxxxxxxxxxx
1426 * Inputs:
1427 * ------
1428 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1430 * Outputs:
1431 * -------
1432 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1434 * Procedures Called
1435 * -----------------
1437 *************************************<->***********************************/
1439 static void _XwMenuPaneCleanup (menupane, menuMgr, data)
1441 XwMenuPaneWidget menupane;
1442 Widget menuMgr;
1443 caddr_t data; /* not used */
1447 * If this menupane is currently attached to a menubutton, or if this
1448 * is the top level menupane, then we need to detach it before we
1449 * allow it to be destroyed.
1451 if (menupane->menu_pane.attach_to)
1453 if (menupane->menu_pane.attachId == NULL)
1454 DetachPane (menuMgr, menupane, menupane->menu_pane.attach_to);
1455 else
1456 DoDetach (menuMgr, menupane->menu_pane.attachId, menupane);
1461 /*************************************<->*************************************
1463 * _XwMenuButtonCleanup(parameters)
1465 * Description:
1466 * -----------
1467 * xxxxxxxxxxxxxxxxxxxxxxx
1470 * Inputs:
1471 * ------
1472 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1474 * Outputs:
1475 * -------
1476 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1478 * Procedures Called
1479 * -----------------
1481 *************************************<->***********************************/
1483 static void _XwMenuButtonCleanup (menubutton, menuMgr, data)
1485 Widget menubutton;
1486 XwPopupMgrWidget menuMgr;
1487 caddr_t data; /* not used */
1490 Arg arg[1];
1491 XwMenuPaneWidget cascadeOn;
1494 * Remove any accelerators associated with this menubutton, and if
1495 * there is a menupane cacading from us, then break that association,
1496 * and add the menupane back into the pending attach list.
1498 ClearSelectAccelerator (menuMgr, menubutton);
1500 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &cascadeOn);
1501 XtGetValues (menubutton, arg, 1);
1503 if (cascadeOn != NULL)
1505 /* Detach, and add back into pending attach list */
1506 DoDetach (menuMgr, menubutton, cascadeOn);
1507 AddToPendingList (menuMgr, cascadeOn, cascadeOn->menu_pane.attach_to);
1511 * If this menubutton had been the last item selected, and if sticky
1512 * menus is enabled, then we need to cleanup the saved cascade list,
1513 * so that we don't dump core the next time the menu is posted.
1515 if ((menuMgr->popup_mgr.stickyMode) &&
1516 (menuMgr->popup_mgr.numSavedCascades > 0) &&
1517 (menuMgr->popup_mgr.lastSelected == menubutton->core.self))
1519 menuMgr->popup_mgr.numSavedCascades = 0;
1524 /*************************************<->*************************************
1526 * MMPost(parameters)
1528 * Description:
1529 * -----------
1530 * xxxxxxxxxxxxxxxxxxxxxxx
1533 * Inputs:
1534 * ------
1535 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1537 * Outputs:
1538 * -------
1539 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1541 * Procedures Called
1542 * -----------------
1544 *************************************<->***********************************/
1546 static void MMPost (w, event, params, count)
1548 Widget w;
1549 XEvent * event;
1550 String * params;
1551 Cardinal count;
1554 XwPopupMgrWidget menuMgr;
1556 /* Extract the menu manager widget id */
1557 menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1560 * If we have made it down here, then we know the post event is
1561 * ours to handle.
1563 if ((menuMgr) && (menuMgr->popup_mgr.topLevelPane))
1564 ClassPost (menuMgr, event, TRUE);
1568 /*************************************<->*************************************
1570 * MMUnpost(parameters)
1572 * Description:
1573 * -----------
1574 * xxxxxxxxxxxxxxxxxxxxxxx
1577 * Inputs:
1578 * ------
1579 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1581 * Outputs:
1582 * -------
1583 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1585 * Procedures Called
1586 * -----------------
1588 *************************************<->***********************************/
1590 static void MMUnpost (w, event, params, count)
1592 Widget w;
1593 XEvent * event;
1594 String * params;
1595 Cardinal count;
1598 register XwPopupMgrWidget menuMgr;
1599 Boolean traversalOn;
1601 /* Extract the menu manager widget id */
1602 menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1605 * We need to use a temporary variable, because the application may
1606 * change this value from underneath us if it has attached any unpost
1607 * callbacks to any of the menupanes.
1609 traversalOn = menuMgr->manager.traversal_on;
1611 if ((menuMgr) && (menuMgr->menu_mgr.menuActive))
1614 * Unpost the menu.
1615 * To prevent undesirable side effects, the menuActive flag must
1616 * always be cleared before bring down the menu system.
1618 menuMgr->menu_mgr.menuActive = FALSE;
1619 Unpost (menuMgr, menuMgr->popup_mgr.topLevelPane);
1620 XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
1623 * If traversal is on, and there are no sticky menupanes currently
1624 * being remembered, then we need to reset the focus item to the
1625 * first item in the menupane.
1627 if (traversalOn && (menuMgr->popup_mgr.numSavedCascades == 0))
1629 ((XwPopupMgrWidget)menuMgr->popup_mgr.topLevelPane)->
1630 manager.active_child = NULL;
1631 XtSetKeyboardFocus (menuMgr->popup_mgr.topLevelPane, NULL);
1635 * If we warped the mouse because traversal was on, then we need
1636 * to move it back to where it was.
1638 if (traversalOn &&
1639 (menuMgr->popup_mgr.origMouseX != -1) &&
1640 (menuMgr->popup_mgr.origMouseY != -1))
1642 XWarpPointer (XtDisplay (menuMgr), None,
1643 RootWindowOfScreen(menuMgr->core.screen),
1644 0, 0, 0, 0,
1645 menuMgr->popup_mgr.origMouseX,
1646 menuMgr->popup_mgr.origMouseY);
1647 menuMgr->popup_mgr.origMouseX = -1;
1648 menuMgr->popup_mgr.origMouseY = -1;
1654 /*************************************<->*************************************
1656 * MMAccelPost (parameters)
1658 * Description:
1659 * -----------
1660 * xxxxxxxxxxxxxxxxxxxxxxx
1663 * Inputs:
1664 * ------
1665 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1667 * Outputs:
1668 * -------
1669 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1671 * Procedures Called
1672 * -----------------
1674 *************************************<->***********************************/
1676 static void MMAccelPost (w, event, params, count)
1678 Widget w;
1679 XEvent * event;
1680 String * params;
1681 Cardinal count;
1684 register XwPopupMgrWidget menuMgr;
1686 /* Extract the menu manager widget id */
1687 menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1690 * If we have made it down here, then we know the accelerator event is
1691 * ours to handle.
1693 if ((menuMgr) && (menuMgr->popup_mgr.topLevelPane))
1694 ClassPost (menuMgr, event, FALSE);
1698 /*************************************<->*************************************
1700 * MMAccelSelect (parameters)
1702 * Description:
1703 * -----------
1704 * xxxxxxxxxxxxxxxxxxxxxxx
1707 * Inputs:
1708 * ------
1709 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1711 * Outputs:
1712 * -------
1713 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1715 * Procedures Called
1716 * -----------------
1718 *************************************<->***********************************/
1720 static void MMAccelSelect (w, event, params, count)
1722 Widget w;
1723 XEvent * event;
1724 String * params;
1725 Cardinal count;
1728 register XwPopupMgrWidget menuMgr;
1730 /* Extract the menu manager widget id */
1731 menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1733 if (menuMgr == NULL)
1734 return;
1737 * if menus are not inherited, throw out events that did occur
1738 * in the associated widget's children. This takes care of the case
1739 * where the child does not select for key events, so they propagate
1740 * to us.
1742 if (menuMgr->menu_mgr.associateChildren == FALSE)
1744 if ((event->xkey.window == XtWindow (XtParent (XtParent (menuMgr)))) &&
1745 (event->xkey.subwindow != 0) &&
1746 (XtWindowToWidget (XtDisplay (menuMgr), event->xkey.subwindow)))
1747 return;
1751 * If we have made it down here, then we know the accelerator event is
1752 * ours to handle.
1754 if (menuMgr->popup_mgr.topLevelPane)
1755 ClassSelect ((XwMenuMgrWidget)menuMgr, event);
1759 /*************************************<->*************************************
1761 * AttachPane(menuMgr, menupane, name)
1763 * Description:
1764 * -----------
1767 * Inputs:
1768 * ------
1771 * Outputs:
1772 * -------
1775 * Procedures Called
1776 * -----------------
1778 *************************************<->***********************************/
1780 static void AttachPane (menuMgr, menupane, name)
1782 register XwPopupMgrWidget menuMgr;
1783 register XwMenuPaneWidget menupane;
1784 String name;
1787 register XwMenuButtonWidget menubutton;
1788 Arg arg[1];
1789 register int i, j;
1790 CompositeWidget shell, mpane;
1791 XrmName nameQuark;
1793 if (name == NULL)
1794 return;
1797 * Save a copy of the menupane Id, since this has been called as
1798 * a result of a SetValues being done on the menupane, and all of
1799 * our lists only contain the old widget pointer.
1801 menuMgr->popup_mgr.attachPane = menupane;
1804 * check if name is menu manager's name, then this is to be a top level
1806 if ((strcmp (name, menuMgr->core.name) == 0) &&
1807 (XwStrlen(name) == XwStrlen(menuMgr->core.name)))
1809 /* Remove the cascade list when the top level pane changes */
1810 menuMgr->popup_mgr.numSavedCascades = 0;
1812 if (menuMgr->popup_mgr.topLevelPane != NULL)
1814 /* Detach the previous top level pane */
1815 XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
1816 XtSetValues (menuMgr->popup_mgr.topLevelPane, arg, 1);
1820 * save menupane ID. Since this may be called from menupane's
1821 * SetValues routine, the widget passed may be the new structure.
1822 * Grab the self field in core to insure the right ID is used.
1824 menuMgr->popup_mgr.topLevelPane = menupane->core.self;
1825 menupane->menu_pane.attachId = NULL;
1827 SetTreeAccelerators (menuMgr, menupane);
1829 else
1832 * check if its a menubutton name in the menu system.
1834 nameQuark = XrmStringToQuark(name);
1836 for (i = 0; i < menuMgr->core.num_popups; i++)
1839 * for each shell, if its child is a menupane and the menupane
1840 * has a menubutton of the passed in name, then do the attach
1842 shell = (CompositeWidget) menuMgr->core.popup_list[i];
1843 if ((shell->composite.num_children == 1) &&
1844 (XtIsSubclass(shell->composite.children[0],
1845 XwmenupaneWidgetClass)))
1847 mpane = (CompositeWidget) shell->composite.children[0];
1848 for (j = 0; j < mpane->composite.num_children; j++)
1850 menubutton = (XwMenuButtonWidget)mpane->composite.children[j];
1851 if (menubutton->core.xrm_name == nameQuark)
1853 Widget dwidget = NULL;
1855 * If there is a menupane already attached to this
1856 * button, then we need to first detach it.
1858 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &dwidget);
1859 XtGetValues ((Widget)menubutton, arg, 1);
1860 if (dwidget)
1862 /* Detach the old pane */
1863 Widget temppane = dwidget;
1864 XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
1865 XtSetValues (temppane, arg, 1);
1868 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) menupane->core.self);
1869 XtSetValues ((Widget)menubutton, arg, 1);
1871 menupane->menu_pane.attachId = (Widget) menubutton;
1873 XtAddCallback ((Widget) menubutton,
1874 XtNcascadeSelect, (XtCallbackProc)_XwCascadeSelect,
1875 menupane->core.self);
1877 XtAddCallback ((Widget) menubutton,
1878 XtNcascadeUnselect, (XtCallbackProc)_XwCascadeUnselect,
1879 menupane->core.self);
1881 if (CompletePath(menuMgr, menupane))
1882 SetTreeAccelerators (menuMgr, menupane);
1884 menuMgr->popup_mgr.attachPane = NULL;
1885 return;
1891 * Couldn't find a menubutton with this name
1893 AddToPendingList (menuMgr, menupane, name);
1896 /* This always needs to be cleared out when we are done */
1897 menuMgr->popup_mgr.attachPane = NULL;
1900 /*************************************<->*************************************
1902 * DetachPane (menuMgr, menupane, name)
1904 * Description:
1905 * -----------
1908 * Inputs:
1909 * ------
1912 * Outputs:
1913 * -------
1916 * Procedures Called
1917 * -----------------
1919 *************************************<->***********************************/
1921 static void DetachPane (menuMgr, menupane, name)
1923 register XwPopupMgrWidget menuMgr;
1924 XwMenuPaneWidget menupane;
1925 String name;
1928 register int i;
1929 Arg arg;
1930 XwMenuButtonWidget menubutton;
1931 CompositeWidget shell;
1933 if (name == NULL)
1934 return;
1937 * if menupane is on the pending attach list, remove it and return
1939 for (i=0; i < menuMgr->menu_mgr.numAttachReqs; i++)
1941 if (menuMgr->menu_mgr.pendingAttachList[i].menupaneId ==
1942 menupane->core.self)
1944 menuMgr->menu_mgr.pendingAttachList[i] =
1945 menuMgr->menu_mgr.pendingAttachList
1946 [--menuMgr->menu_mgr.numAttachReqs];
1947 return;
1952 * Save a copy of the menupane Id, since this has been called as
1953 * a result of a SetValues being done on the menupane, and all
1954 * of our lists only contain the old widget pointer.
1956 menuMgr->popup_mgr.detachPane = menupane;
1959 * if name is the menu manager's name, removing top level
1961 if ((strcmp (name, menuMgr->core.name) == 0) &&
1962 (XwStrlen(name) == XwStrlen(menuMgr->core.name)))
1964 menupane->menu_pane.attachId = (Widget) NULL;
1966 if (menupane->core.self == menuMgr->popup_mgr.topLevelPane)
1968 ClearTreeAccelerators (menuMgr, menupane->core.self);
1969 menuMgr->popup_mgr.topLevelPane = NULL;
1972 else
1975 * detach pane from menubutton. Look on each of the menu managers
1976 * popup children for a menupane which contains this named menubutton.
1978 for (i = 0; i < menuMgr->core.num_popups; i++)
1980 shell = (CompositeWidget) menuMgr->core.popup_list[i];
1981 if ((shell->composite.num_children == 1) &&
1982 (XtIsSubclass(shell->composite.children[0],
1983 XwmenupaneWidgetClass)))
1985 if ((menubutton = (XwMenuButtonWidget)
1986 XtNameToWidget(shell->composite.children[0], name))
1987 != NULL)
1990 * Found it! Detach it
1992 DoDetach (menuMgr, menubutton, menupane);
1993 menuMgr->popup_mgr.detachPane = NULL;
1994 return;
2000 /* This must always be cleared when we leave */
2001 menuMgr->popup_mgr.detachPane = NULL;
2005 /*************************************<->*************************************
2007 * DoDetach(parameters)
2009 * Description:
2010 * -----------
2011 * This routine does the actual work of detaching a menupane from a
2012 * menubutton. It has been separated out from DetachPane() due to
2013 * a BUG in the X toolkits destroy scenario. When the toolkit is
2014 * destroying popup children, it replaces the widget Id entry within
2015 * the popup list with the window Id for that widget. DetachPane()
2016 * attempts to traverse this list, looking for the named menubutton.
2017 * Unfortunately, if this list contains any window Ids, then we may
2018 * get a core dump; this only can happen when the menu is being
2019 * destroyed.
2022 * Inputs:
2023 * ------
2024 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2026 * Outputs:
2027 * -------
2028 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2030 * Procedures Called
2031 * -----------------
2033 *************************************<->***********************************/
2035 static void DoDetach (menuMgr, menubutton, menupane)
2037 register XwPopupMgrWidget menuMgr;
2038 XwMenuButtonWidget menubutton;
2039 XwMenuPaneWidget menupane;
2042 Arg arg[1];
2043 register int i;
2045 /* Detach a menupane from a menubutton */
2046 XtRemoveCallback ((Widget)menubutton, XtNcascadeSelect,
2047 (XtCallbackProc)_XwCascadeSelect, menupane->core.self);
2048 XtRemoveCallback ((Widget)menubutton, XtNcascadeUnselect,
2049 (XtCallbackProc)_XwCascadeUnselect, menupane->core.self);
2050 ClearTreeAccelerators (menuMgr, menupane->core.self);
2052 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) NULL);
2053 XtSetValues ((Widget)menubutton, arg, 1);
2054 menupane->menu_pane.attachId = NULL;
2057 * If this menupane is on the saved cascade list (because sticky
2058 * menus are enabled), then we need to clean up the list, so that
2059 * we don't dump core the next time we post.
2061 if ((menuMgr->popup_mgr.stickyMode) &&
2062 (menuMgr->popup_mgr.numSavedCascades > 0))
2064 for (i = 0; i < menuMgr->popup_mgr.numSavedCascades; i++)
2066 if (menuMgr->popup_mgr.savedCascadeList[i] ==
2067 (Widget)menupane->core.self)
2069 menuMgr->popup_mgr.numSavedCascades = 0;
2070 break;
2077 /*************************************<->*************************************
2079 * AddPane(menuMgr, menupane)
2081 * Description:
2082 * -----------
2085 * Inputs:
2086 * ------
2089 * Outputs:
2090 * -------
2093 * Procedures Called
2094 * -----------------
2096 *************************************<->***********************************/
2098 static void AddPane (menuMgr, menupane)
2100 register XwMenuMgrWidget menuMgr;
2101 XwMenuPaneWidget menupane;
2104 register int k;
2105 register int traversalType;
2106 register XwMenuButtonWidget mbutton;
2108 XtAddCallback ((Widget)menupane, XtNdestroyCallback,
2109 (XtCallbackProc)_XwMenuPaneCleanup, menuMgr);
2111 if (menuMgr->menu_mgr.selectString)
2113 SetUpTranslation (menupane, menuMgr->menu_mgr.selectString,
2114 selectTemplate);
2117 if (menuMgr->menu_mgr.unpostString)
2119 RegisterTranslation (menupane, menuMgr->menu_mgr.unpostString,
2120 unpostTemplate, menuMgr);
2123 if (menuMgr->menu_mgr.kbdSelectString)
2125 SetUpTranslation (menupane, menuMgr->menu_mgr.kbdSelectString,
2126 selectTemplate);
2129 /* Propogate the state of our traversal flag */
2130 if (XtIsSubclass ((Widget)menupane, XwmenupaneWidgetClass))
2132 (*(((XwMenuPaneWidgetClass)
2133 XtClass(menupane))-> menu_pane_class.setTraversalFlag))
2134 ((Widget)menupane, menuMgr->manager.traversal_on);
2137 /******************
2138 * THE FOLLOWING IS NOT NEEDED, SINCE A MENUPANE CAN NEVER HAVE
2139 * ANY CHILDREN AT THIS TIME.
2141 * traversalType = (menuMgr->manager.traversal_on) ? XwHIGHLIGHT_TRAVERSAL:
2142 * XwHIGHLIGHT_OFF;
2144 * for (k = 0; k < menupane->manager.num_managed_children; k++)
2146 * /* Here we set the traversal flag for the menubuttons
2147 * mbutton = (XwMenuButtonWidget)menupane->composite.children[k];
2148 * if (XtIsSubclass (mbutton, XwmenubuttonWidgetClass))
2150 * (*(((XwMenuButtonWidgetClass)
2151 * XtClass(mbutton))-> menubutton_class.setTraversalType))
2152 * (mbutton, traversalType);
2155 *********************/
2158 /*************************************<->*************************************
2160 * SetSelectAccelerator (menuMgr, menubutton, accelString, accelEventType,
2161 * accelKey, accelModifiers)
2163 * Description:
2164 * -----------
2167 * Inputs:
2168 * ------
2171 * Outputs:
2172 * -------
2175 * Procedures Called
2176 * -----------------
2178 *************************************<->***********************************/
2180 static void SetSelectAccelerator (menuMgr, menubutton, accelString,
2181 accelEventType, accelKey, accelModifiers)
2182 Widget menuMgr;
2183 Widget menubutton;
2184 String accelString;
2185 unsigned int accelEventType;
2186 unsigned int accelKey;
2187 unsigned int accelModifiers;
2189 Widget widget;
2190 XwKeyAccel * tempAccel;
2192 if (CompletePath(menuMgr, menubutton->core.parent))
2194 ClearSelectAccelerator (menuMgr, menubutton->core.self);
2195 SetButtonAccelerators (menuMgr, menubutton->core.self, accelString,
2196 accelEventType, accelKey, accelModifiers);
2201 /*************************************<->*************************************
2203 * ClearSelectAccelerator (menuMgr, menubutton)
2205 * Description:
2206 * -----------
2209 * Inputs:
2210 * ------
2213 * Outputs:
2214 * -------
2217 * Procedures Called
2218 * -----------------
2220 *************************************<->***********************************/
2222 static void ClearSelectAccelerator (menuMgr, menubutton)
2224 register XwPopupMgrWidget menuMgr;
2225 Widget menubutton;
2228 register int i;
2229 Widget widget;
2232 * search accelerator table for menubutton
2234 for (i=0; i < menuMgr->menu_mgr.numAccels; i++)
2236 if (menuMgr->menu_mgr.menuBtnAccelTable[i].menuBtn ==
2237 menubutton->core.self)
2240 * remove translation in associated widget & toplevel pane
2241 * and remove grab
2243 widget = (Widget) XtParent (XtParent (menuMgr));
2244 RegisterTranslation (widget,
2245 menuMgr->menu_mgr.menuBtnAccelTable[i].accelString,
2246 accelSelectTemplate, NULL);
2248 if (menuMgr->popup_mgr.topLevelPane)
2250 RegisterTranslation (menuMgr->popup_mgr.topLevelPane,
2251 menuMgr->menu_mgr.menuBtnAccelTable[i].accelString,
2252 accelSelectTemplate, NULL);
2255 * Because of a short coming in the toolkit, we need to
2256 * potentially patch the top level widget's translations,
2257 * if it was in the middle of a setvalues.
2259 if ((menuMgr->popup_mgr.detachPane) &&
2260 (menuMgr->popup_mgr.topLevelPane ==
2261 menuMgr->popup_mgr.detachPane->core.self))
2263 menuMgr->popup_mgr.detachPane->core.tm =
2264 menuMgr->popup_mgr.topLevelPane->core.tm;
2265 menuMgr->popup_mgr.detachPane->core.event_table =
2266 menuMgr->popup_mgr.topLevelPane->core.event_table;
2270 if ((menuMgr->menu_mgr.associateChildren) &&
2271 (XtIsRealized (widget)))
2273 XUngrabKey (XtDisplay (widget),
2274 menuMgr->menu_mgr.menuBtnAccelTable[i].accelKey,
2275 menuMgr->menu_mgr.menuBtnAccelTable[i].accelModifiers,
2276 XtWindow (widget));
2280 * remove menubutton accelerator table entry
2282 menuMgr->menu_mgr.menuBtnAccelTable[i] =
2283 menuMgr->menu_mgr.menuBtnAccelTable[--menuMgr->menu_mgr.numAccels];
2285 return;
2290 /*************************************<->*************************************
2292 * AddButton(menuMgr, menubutton)
2294 * Description:
2295 * -----------
2298 * Inputs:
2299 * ------
2302 * Outputs:
2303 * -------
2306 * Procedures Called
2307 * -----------------
2309 *************************************<->***********************************/
2311 static void AddButton (menuMgr, menubutton)
2313 register XwMenuMgrWidget menuMgr;
2314 register Widget menubutton;
2317 Arg args[2];
2318 Widget pending;
2319 int traversalType;
2321 if (menuMgr->menu_mgr.selectString)
2323 SetUpTranslation (menubutton, menuMgr->menu_mgr.selectString,
2324 selectTemplate);
2326 if (menuMgr->menu_mgr.unpostString)
2328 RegisterTranslation (menubutton, menuMgr->menu_mgr.unpostString,
2329 unpostTemplate, menuMgr);
2331 if (menuMgr->menu_mgr.kbdSelectString)
2333 SetUpTranslation (menubutton, menuMgr->menu_mgr.kbdSelectString,
2334 selectTemplate);
2337 XtSetArg (args[0], XtNcascadeOn, (XtArgVal) NULL);
2338 XtSetArg (args[1], XtNmgrOverrideMnemonic, (XtArgVal) TRUE);
2339 XtSetValues (menubutton, args, XtNumber(args));
2341 XtAddCallback (menubutton, XtNdestroyCallback,
2342 (XtCallbackProc)_XwMenuButtonCleanup, menuMgr);
2345 * Accelerators are now handled when the button is managed!
2349 * if this menubutton is on the pending attach list, do attach
2351 if (pending = PendingAttach (menuMgr, menubutton))
2352 AttachPane (menuMgr, pending, menubutton->core.name);
2354 /* Propogate the our traversal state */
2355 traversalType = (menuMgr->manager.traversal_on) ? XwHIGHLIGHT_TRAVERSAL:
2356 XwHIGHLIGHT_OFF;
2358 if (XtIsSubclass (menubutton, XwmenubuttonWidgetClass))
2360 (*(((XwMenuButtonWidgetClass)
2361 XtClass(menubutton))-> menubutton_class.setTraversalType))
2362 (menubutton, traversalType);
2366 /*************************************<->*************************************
2368 * Unpost (menuMgr, menupane)
2370 * Description:
2371 * -----------
2374 * Inputs:
2375 * ------
2378 * Outputs:
2379 * -------
2382 * Procedures Called
2383 * -----------------
2385 *************************************<->***********************************/
2387 static void Unpost (menuMgr, menupane)
2389 register XwPopupMgrWidget menuMgr;
2390 XwMenuPaneWidget menupane;
2393 register int i,j;
2394 register XwMenuPaneWidget pane;
2395 register Widget * currentCascadeList;
2396 register WidgetList managed_children;
2399 * To keep all window managers happy, move the focus before we pop
2400 * down the menupane with the current focus.
2402 if ((menupane != (XwMenuPaneWidget) menuMgr->popup_mgr.topLevelPane) &&
2403 (menuMgr->manager.traversal_on))
2405 XwMoveFocus (XtParent(menupane->menu_pane.attachId));
2408 currentCascadeList = menuMgr->popup_mgr.currentCascadeList;
2411 * popdown any cascading submenus including menupane
2413 for (i = menuMgr->popup_mgr.numCascades - 1; i >= 0; i--)
2416 * for each button in pane, unhighlight it and clear cascade flag
2418 pane = ((XwMenuPaneWidget) currentCascadeList[i]);
2419 XtRemoveGrab ((Widget)pane);
2420 XtPopdown (XtParent (pane));
2421 managed_children = pane->manager.managed_children;
2423 for (j = 0; j < pane->manager.num_managed_children; j++)
2425 if (XtIsSubclass (managed_children[j], XwmenubuttonWidgetClass))
2427 (*(((XwMenuButtonWidgetClass)
2428 XtClass(managed_children[j]))->menubutton_class.unhighlightProc))
2429 (managed_children[j]);
2430 (*(((XwMenuButtonWidgetClass)
2431 XtClass(managed_children[j]))->menubutton_class.clearCascadeProc))
2432 (managed_children[j]);
2436 --menuMgr->popup_mgr.numCascades;
2439 * if this is not the target pane then the next one must have had an enter
2440 * window event handler added when cascaded out of it.
2442 if ((pane != menupane) && (i > 0))
2444 if (menuMgr->manager.traversal_on == FALSE)
2446 XtRemoveEventHandler (currentCascadeList[i-1],
2447 EnterWindowMask, FALSE,
2448 (XtEventHandler)
2449 ((XwMenuButtonWidgetClass)
2450 XtClass(pane->menu_pane.attachId))->
2451 menubutton_class.enterParentProc,
2452 pane->menu_pane.attachId);
2454 else
2456 /* Kludge to force the grablist to get cleaned up */
2457 XtSetKeyboardFocus (XtParent(pane), None);
2460 else
2462 if (menuMgr->manager.traversal_on)
2464 /* Kludge to force the grablist to get cleaned up */
2465 XtSetKeyboardFocus (XtParent(pane), None);
2467 XFlush (XtDisplay(menuMgr));
2468 return;
2473 /*************************************<->*************************************
2475 * Post(menuMgr, menupane, grabtype)
2477 * Description:
2478 * -----------
2481 * Inputs:
2482 * ------
2485 * Outputs:
2486 * -------
2489 * Procedures Called
2490 * -----------------
2492 * _XtPopup
2494 *************************************<->***********************************/
2496 static void Post (menuMgr, menupane, grabtype)
2498 register XwPopupMgrWidget menuMgr;
2499 Widget menupane;
2500 XtGrabKind grabtype;
2503 register int i;
2506 * if already posted, do nothing
2508 for (i=0; i < menuMgr->popup_mgr.numCascades; i++)
2509 if (menuMgr->popup_mgr.currentCascadeList[i] == menupane)
2510 return;
2513 * set up grabs
2515 if (grabtype == XtGrabNonexclusive)
2517 _XtPopup (XtParent (menupane), grabtype, FALSE);
2518 XtAddGrab (menupane, FALSE, FALSE);
2520 else
2522 _XtPopup (XtParent (menupane), grabtype, TRUE);
2523 XtAddGrab (menupane, TRUE, TRUE);
2527 * add menupane to current cascade list
2529 if (menuMgr->popup_mgr.numCascades == menuMgr->popup_mgr.sizeCascadeList)
2531 menuMgr->popup_mgr.sizeCascadeList =
2532 2 * menuMgr->popup_mgr.sizeCascadeList;
2533 menuMgr->popup_mgr.currentCascadeList =
2534 (Widget *) XtRealloc((char *)(menuMgr->popup_mgr.currentCascadeList),
2535 menuMgr->popup_mgr.sizeCascadeList *
2536 sizeof (Widget));
2539 menuMgr->popup_mgr.currentCascadeList[menuMgr->popup_mgr.numCascades++] =
2540 menupane;
2543 /*************************************<->*************************************
2545 * ProcessSelect(menuMgr, widget, event)
2547 * Description:
2548 * -----------
2551 * Inputs:
2552 * ------
2555 * Outputs:
2556 * -------
2559 * Procedures Called
2560 * -----------------
2562 *************************************<->***********************************/
2564 static Boolean ProcessSelect (menuMgr, widget, event)
2566 register XwPopupMgrWidget menuMgr;
2567 Widget widget;
2568 XEvent * event;
2571 register XwKeyAccel * accelerator;
2572 register int i;
2573 Boolean found = FALSE;
2574 Widget assocWidget;
2575 Boolean traversalOn;
2578 * If the menu manager or the associated widget is insensitive, then
2579 * ignore the select request.
2581 assocWidget = XtParent(XtParent(menuMgr));
2582 if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
2583 return (FALSE);
2586 * is this a valid button event?
2588 if ((event->xany.type==ButtonPress) || (event->xany.type==ButtonRelease))
2591 if (_XwMatchBtnEvent (event, menuMgr->menu_mgr.selectEventType,
2592 menuMgr->menu_mgr.selectButton,
2593 menuMgr->menu_mgr.selectModifiers))
2595 if (menuMgr->menu_mgr.menuActive == FALSE)
2596 return (FALSE);
2599 * During traversal, since menupanes are not unposted when
2600 * the mouse enters a different menupane, we need to ignore
2601 * selects which occur in a menubtn in one of these panes.
2603 if ((menuMgr->manager.traversal_on) &&
2604 (XtIsSubclass (widget, XwmenubuttonWidgetClass)) &&
2605 (XtParent(widget) != menuMgr->popup_mgr.currentCascadeList[
2606 menuMgr->popup_mgr.numCascades - 1]))
2608 return (FALSE);
2611 SetUpStickyList (menuMgr, widget);
2613 else
2614 return (FALSE);
2617 * if its not key accelerator, return false
2619 else if ((event->xany.type == KeyPress) || (event->xany.type == KeyRelease))
2621 /* Check for the kbd select event */
2622 if (_XwMatchKeyEvent (event,
2623 menuMgr->menu_mgr.kbdSelectEventType,
2624 menuMgr->menu_mgr.kbdSelectKey,
2625 menuMgr->menu_mgr.kbdSelectModifiers))
2627 SetUpStickyList (menuMgr, widget);
2629 else
2631 for (i=0; (i < menuMgr->menu_mgr.numAccels) && (found == FALSE); i++)
2633 accelerator = menuMgr->menu_mgr.menuBtnAccelTable + i;
2634 found = _XwMatchKeyEvent (event,
2635 accelerator->accelEventType,
2636 accelerator->accelKey,
2637 accelerator->accelModifiers);
2640 if (found == FALSE)
2641 return (FALSE);
2643 menuMgr->popup_mgr.numSavedCascades = 0;
2644 if (menuMgr->manager.traversal_on)
2646 /* Force the first item to be highlighted next time */
2647 ((XwPopupMgrWidget)menuMgr->popup_mgr.topLevelPane)->
2648 manager.active_child = NULL;
2649 XtSetKeyboardFocus (menuMgr->popup_mgr.topLevelPane, NULL);
2651 /* SetUpStickyList (menuMgr, widget); */
2654 else
2655 return (FALSE);
2658 * if the menu system is active, bring it down
2660 if (menuMgr->menu_mgr.menuActive)
2663 * We need to use a temporary variable because the application has
2664 * the chance to change this from underneath us if they have set up
2665 * an unpost callback.
2667 traversalOn = menuMgr->manager.traversal_on;
2669 menuMgr->menu_mgr.menuActive = FALSE;
2671 Unpost (menuMgr, menuMgr->popup_mgr.topLevelPane);
2673 /* We need to remove the grab we set in ClassPost() */
2674 XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
2677 * If we warped the mouse because traversal was on, then we need
2678 * to move it back to where it was.
2680 if (traversalOn &&
2681 (menuMgr->popup_mgr.origMouseX != -1) &&
2682 (menuMgr->popup_mgr.origMouseY != -1))
2684 XWarpPointer (XtDisplay (menuMgr), None,
2685 RootWindowOfScreen(menuMgr->core.screen),
2686 0, 0, 0, 0,
2687 menuMgr->popup_mgr.origMouseX,
2688 menuMgr->popup_mgr.origMouseY);
2689 menuMgr->popup_mgr.origMouseX = -1;
2690 menuMgr->popup_mgr.origMouseY = -1;
2693 return (TRUE);
2696 /*************************************<->*************************************
2698 * ValidEvent(menuMgr, menubutton, event)
2700 * Description:
2701 * -----------
2704 * Inputs:
2705 * ------
2708 * Outputs:
2709 * -------
2712 * Procedures Called
2713 * -----------------
2715 *************************************<->***********************************/
2717 static Boolean ValidEvent (menuMgr, menubutton, event)
2719 XwPopupMgrWidget menuMgr;
2720 Widget menubutton;
2721 XEvent * event;
2724 /* Ignore enter and leave events if traversal is active */
2725 if (menuMgr->manager.traversal_on)
2726 return (FALSE);
2727 else
2728 return (TRUE);
2731 /*************************************<->*************************************
2733 * DoICascade (menuMgr)
2735 * Description:
2736 * -----------
2739 * Inputs:
2740 * ------
2743 * Outputs:
2744 * -------
2747 * Procedures Called
2748 * -----------------
2750 *************************************<->***********************************/
2752 static Boolean DoICascade (menuMgr, menuBtn)
2754 register XwPopupMgrWidget menuMgr;
2755 Widget menuBtn;
2758 /* Ignore cascade events if traversal is currently active */
2759 if ((menuMgr->menu_mgr.menuActive) &&
2760 (menuMgr->manager.traversal_on == FALSE))
2762 Widget lastCascade = menuMgr->popup_mgr.currentCascadeList[
2763 menuMgr->popup_mgr.numCascades -1];
2765 if ((XtParent(menuBtn) == lastCascade) ||
2766 (menuBtn == ((XwMenuPaneWidget)(lastCascade))->menu_pane.attachId))
2768 return (TRUE);
2772 return (FALSE);
2775 /*************************************<->*************************************
2777 * ClassPost(menuMgr, event, warpOn)
2779 * Description:
2780 * -----------
2783 * Inputs:
2784 * ------
2787 * Outputs:
2788 * -------
2791 * Procedures Called
2792 * -----------------
2794 *************************************<->***********************************/
2796 static void ClassPost (menuMgr, event, warpOn)
2798 register XwPopupMgrWidget menuMgr;
2799 XEvent * event;
2800 Boolean warpOn;
2803 register int i;
2804 Position posx, posy;
2805 int x, y, relativeX, relativeY;
2806 int yDelta;
2807 XButtonEvent * buttonEvent = (XButtonEvent *) event;
2808 Widget assocWidget, w;
2809 Widget menuBtn;
2810 XwMenuPaneWidget tempPane;
2811 XwManagerWidget topLevelPane;
2812 XWindowChanges windowChanges;
2813 ShellWidget shell;
2814 Window root, child;
2815 int rootx, rooty, childx, childy;
2816 unsigned int returnMask;
2819 * If either the menu manager or the associated widget is insensitive,
2820 * then ignore the post request.
2822 assocWidget = XtParent (XtParent (menuMgr));
2823 if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
2824 return;
2827 * if menus are not inherited, throw out events that did occur
2828 * in the associated widget's children.
2830 if (menuMgr->menu_mgr.associateChildren == FALSE)
2832 if ((event->xkey.window == XtWindow (XtParent (XtParent (menuMgr)))) &&
2833 (event->xkey.subwindow != 0) &&
2834 (XtWindowToWidget (XtDisplay (menuMgr), event->xkey.subwindow)))
2835 return;
2839 * The following is a kludge fix to bypass a shortcoming within Xtk.
2840 * We need to manually inform the previous focus widget that it has
2841 * lost the cursor; this is because once we add our popups to the
2842 * grablist, the LeaveNotify will be ignored for the focus widget,
2843 * because it is not on the grablist.
2845 /* if (menuMgr->manager.traversal_on) */
2846 SendFakeLeaveNotify(menuMgr, ULTIMATE_PARENT);
2848 /* Mark the menu system as 'active' */
2849 menuMgr->menu_mgr.menuActive = TRUE;
2852 * Position the menupane's parent shell. If its a post, position to
2853 * the pointer position. If its an accelerator, position to the center
2854 * of the associated widget
2856 topLevelPane =(XwManagerWidget)menuMgr->popup_mgr.topLevelPane;
2859 * In order for this algorithm to work, we need to make sure the
2860 * menupane has been realized; this is because its size is not
2861 * yet valid because it is not notified that it has any children
2862 * until it is realized.
2864 if (!XtIsRealized (XtParent(topLevelPane )))
2865 XtRealizeWidget (XtParent (topLevelPane ));
2867 if ((event->type == ButtonPress) ||
2868 (event->type == ButtonRelease))
2872 * The server does an implicit grab, but doesn't do it in the
2873 * manner we need for menupanes and menubuttons to continue
2874 * to highlight and function.
2876 if (event->type == ButtonPress)
2877 XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
2880 * If traversal is on, then save the current mouse position,
2881 * so that we can restore the mouse to its original position
2882 * when the menu is unposted.
2884 if (menuMgr->manager.traversal_on)
2886 menuMgr->popup_mgr.origMouseX = buttonEvent->x_root;
2887 menuMgr->popup_mgr.origMouseY = buttonEvent->y_root;
2890 x = buttonEvent->x_root - (XwCASCADEWIDTH + FUDGE_FACTOR +
2891 topLevelPane ->core.border_width);
2892 y = buttonEvent->y_root;
2894 /* Attempt to center on the first button in the new menupane */
2897 if (topLevelPane->manager.num_managed_children > 0)
2899 Widget firstButton = topLevelPane->manager.managed_children[0];
2902 yDelta = firstButton->core.y +
2903 firstButton->core.border_width +
2904 (firstButton->core.height >> 1);
2906 yDelta = 0;
2908 else
2910 yDelta = topLevelPane->core.border_width +
2911 (topLevelPane->core.height >> 1);
2915 y -= yDelta;
2917 else
2920 * center on the associated widget
2922 relativeX = (assocWidget->core.width>>1);
2923 relativeY = (assocWidget->core.height>>1);
2925 /* Get our coordinates, relative to the root window */
2926 XTranslateCoordinates (XtDisplay(menuMgr),
2927 assocWidget->core.window,
2928 RootWindowOfScreen(XtScreen(menuMgr)),
2929 relativeX,
2930 relativeY,
2931 &x, &y, &child);
2934 * If traversal is on, then save the current mouse position,
2935 * so that we can restore the mouse to its original position
2936 * when the menu is unposted.
2938 if (menuMgr->manager.traversal_on)
2940 if (XQueryPointer(XtDisplay(menuMgr),
2941 RootWindowOfScreen(menuMgr->core.screen),
2942 &root, &child, &rootx, &rooty, &childx,
2943 &childy, &returnMask))
2945 menuMgr->popup_mgr.origMouseX = rootx;
2946 menuMgr->popup_mgr.origMouseY = rooty;
2951 posx = x; posy = y;
2952 ForceMenuPaneOnScreen (topLevelPane, &posx, &posy);
2953 x = posx; y = posy;
2954 XtMoveWidget (XtParent(topLevelPane), x, y);
2957 * This allows us to catch all selects, and unpost the menus
2958 * regardless where the select event occurs.
2960 XGrabPointer (XtDisplay(menuMgr), XtWindow(assocWidget), TRUE,
2961 ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|
2962 PointerMotionMask, GrabModeAsync, GrabModeAsync, None, (Cursor)NULL,
2963 CurrentTime);
2965 if ((menuMgr->popup_mgr.stickyMode) &&
2966 (menuMgr->popup_mgr.numSavedCascades))
2969 * Attempt to gracefully handle the case where one of the menupanes
2970 * or menubuttons in the current cascade list has become insensitive
2971 * since the last posting.
2973 for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
2975 tempPane = (XwMenuPaneWidget)menuMgr->popup_mgr.savedCascadeList[i];
2977 if ((tempPane->menu_pane.attachId) &&
2978 (!XtIsSensitive(tempPane->menu_pane.attachId)))
2981 * We are cascading from an insensitive menubutton.
2982 * Stop at the preceeding menupane.
2984 menuMgr->popup_mgr.numSavedCascades = i;
2985 menuMgr->popup_mgr.lastSelected = tempPane->menu_pane.attachId;
2986 break;
2988 else if (!XtIsSensitive((Widget)tempPane))
2991 * If this menupane is insensitive, then stop here.
2993 menuMgr->popup_mgr.numSavedCascades = i + 1;
2994 if (tempPane->manager.num_managed_children > 0)
2996 menuMgr->popup_mgr.lastSelected = tempPane->manager.
2997 managed_children[0];
2999 else
3000 menuMgr->popup_mgr.lastSelected = (Widget)tempPane;
3001 break;
3005 /* Set up grab for the top level menupane */
3006 XtAddGrab (XtParent(topLevelPane), TRUE, TRUE);
3007 XtAddGrab ((Widget)topLevelPane, TRUE, TRUE);
3008 menuMgr->popup_mgr.currentCascadeList[menuMgr->popup_mgr.numCascades++] =
3009 (Widget)topLevelPane;
3012 * position the menupanes on the sticky cascade list
3014 for (i=1; i < menuMgr->popup_mgr.numSavedCascades; i++)
3016 tempPane = (XwMenuPaneWidget) menuMgr->popup_mgr.savedCascadeList[i];
3017 PositionCascade (tempPane->menu_pane.attachId, tempPane);
3018 XtAddGrab (XtParent(tempPane), FALSE, FALSE);
3019 XtAddGrab ((Widget)tempPane, FALSE, FALSE);
3020 menuMgr->popup_mgr.currentCascadeList
3021 [menuMgr->popup_mgr.numCascades++] = (Widget)tempPane;
3025 * warp the pointer to its final destination. This must be done
3026 * AFTER the panes are positioned, but BEFORE they are posted.
3028 if (warpOn)
3030 XWarpPointer (XtDisplay (menuMgr), None,
3031 XtWindow(menuMgr->popup_mgr.lastSelected),
3032 0, 0, 0, 0, 5, 5);
3035 /* Post the last menupane */
3036 shell = (ShellWidget)XtParent (menuMgr->popup_mgr.savedCascadeList
3037 [menuMgr->popup_mgr.numSavedCascades - 1]);
3038 shell->shell.popped_up = TRUE;
3039 shell->shell.grab_kind = XtGrabNonexclusive;
3040 shell->shell.spring_loaded = FALSE;
3041 if (!XtIsRealized((Widget)shell))
3042 XtRealizeWidget ((Widget)shell);
3043 XMapRaised (XtDisplay(shell), XtWindow(shell));
3046 * Post and then configure the menupanes and menubuttons.
3047 * THIS MUST BE DONE AFTER THE WARP POINTER!!!
3049 for (i= menuMgr->popup_mgr.numSavedCascades - 2; i >= 0; i--)
3052 * Popup the pane and add to the grablist.
3053 * This cannot use _XtPopup() because it used XMapRaised().
3055 tempPane = (XwMenuPaneWidget) menuMgr->popup_mgr.savedCascadeList[i];
3056 shell = (ShellWidget) XtParent(tempPane);
3057 windowChanges.sibling = XtWindow(XtParent(menuMgr->popup_mgr.
3058 savedCascadeList[i+1]));
3059 windowChanges.stack_mode = Below;
3060 XConfigureWindow (XtDisplay(menuMgr), XtWindow(shell),
3061 CWSibling | CWStackMode, &windowChanges);
3062 shell->shell.popped_up = TRUE;
3063 shell->shell.grab_kind = XtGrabNonexclusive;
3064 shell->shell.spring_loaded = FALSE;
3065 if (!XtIsRealized ((Widget)shell))
3066 XtRealizeWidget ((Widget)shell);
3067 XMapWindow (XtDisplay(shell), XtWindow(shell));
3070 * highlight menubutton, set its cascade flag and set up event
3071 * handler on its parent
3073 menuBtn = (((XwMenuPaneWidget)(menuMgr->popup_mgr.
3074 savedCascadeList[i+1]))->menu_pane.attachId);
3076 if (menuMgr->manager.traversal_on == FALSE)
3078 (*(((XwMenuButtonWidgetClass)
3079 XtClass(menuBtn))->menubutton_class.highlightProc)) (menuBtn);
3082 (*(((XwMenuButtonWidgetClass) XtClass(menuBtn))->
3083 menubutton_class.setCascadeProc)) (menuBtn);
3085 if (menuMgr->manager.traversal_on == FALSE)
3087 XtAddEventHandler ((Widget)tempPane, EnterWindowMask, False,
3088 (XtEventHandler)
3089 ((XwMenuButtonWidgetClass) XtClass(menuBtn))->
3090 menubutton_class.enterParentProc,
3091 menuBtn);
3096 * DON'T DO THE FOLLOWING; HAVE THE ITEM HILIGHT WHEN THE CURSOR
3097 * ENTERS IT.
3099 /********
3100 * for keyboard posts, highlight the last selected menubutton.
3102 *if ((warpOn == FALSE) && (menuMgr->manager.traversal_on == FALSE))
3104 * (*(((XwMenuButtonWidgetClass)
3105 * XtClass(menuMgr->popup_mgr.lastSelected))->
3106 * menubutton_class.highlightProc))
3107 * (menuMgr->popup_mgr.lastSelected);
3109 *******/
3111 else
3114 * post only the toplevel.
3115 * post the toplevel menupane with exclusive grabs. All other panes
3116 * have nonexclusive grabs.
3118 Post (menuMgr, topLevelPane, XtGrabExclusive);
3121 /* Set the traversal focus to the last pane, if necessary */
3122 if (menuMgr->manager.traversal_on)
3124 XwMoveFocus (menuMgr->popup_mgr.currentCascadeList [
3125 menuMgr->popup_mgr.numCascades - 1]);
3128 XFlush(XtDisplay(menuMgr));
3131 /*************************************<->*************************************
3133 * ClassSelect(menuMgr, event)
3135 * Description:
3136 * -----------
3137 * Called only when a menubutton select accelerator is received.
3140 * Inputs:
3141 * ------
3144 * Outputs:
3145 * -------
3148 * Procedures Called
3149 * -----------------
3151 *************************************<->***********************************/
3153 static void ClassSelect (menuMgr, event)
3155 XwMenuMgrWidget menuMgr;
3156 XEvent * event;
3159 register int i;
3160 Widget assocWidget;
3161 register XwKeyAccel * accelerator;
3164 * If either the menu manager or the associated widget is insensitive,
3165 * then ignore the select accelerator.
3167 assocWidget = XtParent(XtParent(menuMgr));
3168 if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
3169 return;
3172 * map the event into an accelerator and call the menubuttons select rtn.
3174 for (i=0; i < menuMgr->menu_mgr.numAccels; i++)
3176 accelerator = menuMgr->menu_mgr.menuBtnAccelTable + i;
3178 if (_XwMatchKeyEvent (event,
3179 accelerator->accelEventType,
3180 accelerator->accelKey,
3181 accelerator->accelModifiers))
3183 if (XtIsSensitive(accelerator->menuBtn) &&
3184 _XwAllAttachesAreSensitive(accelerator->menuBtn))
3186 (*(((XwMenuButtonWidgetClass)
3187 XtClass (accelerator->menuBtn))-> primitive_class.select_proc))
3188 (accelerator->menuBtn, event);
3191 return;
3197 /*************************************<->*************************************
3199 * AddToPendingList(menuMgr, menupane, name)
3201 * Description:
3202 * -----------
3205 * Inputs:
3206 * ------
3209 * Outputs:
3210 * -------
3213 * Procedures Called
3214 * -----------------
3216 *************************************<->***********************************/
3218 static void AddToPendingList (menuMgr, menupane, name)
3220 register XwMenuMgrWidget menuMgr;
3221 Widget menupane;
3222 String name;
3225 register int nameLen;
3226 register int i;
3227 Arg arg[1];
3228 register String button;
3231 * If there is already a request in the pending list for an attach
3232 * to the same menu button, then we need to remove the older one.
3234 nameLen = XwStrlen(name);
3235 for (i = 0; i < menuMgr->menu_mgr.numAttachReqs; i++)
3237 button = menuMgr->menu_mgr.pendingAttachList[i].menuBtnName;
3238 if ((strcmp(name, button) == 0) && (nameLen == XwStrlen(button)))
3240 /* Detach the older request */
3241 XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
3242 XtSetValues (menuMgr->menu_mgr.pendingAttachList[i].menupaneId,
3243 arg, 1);
3244 break;
3248 if (menuMgr->menu_mgr.numAttachReqs == menuMgr->menu_mgr.sizeAttachList)
3251 * resize the list
3253 menuMgr->menu_mgr.sizeAttachList = 2 * menuMgr->menu_mgr.sizeAttachList;
3254 menuMgr->menu_mgr.pendingAttachList =
3255 (XwAttachList *) XtRealloc((char *)(menuMgr->menu_mgr.pendingAttachList),
3256 menuMgr->menu_mgr.sizeAttachList *
3257 sizeof(XwAttachList));
3259 menuMgr->menu_mgr.pendingAttachList
3260 [menuMgr->menu_mgr.numAttachReqs].menuBtnName = name;
3261 menuMgr->menu_mgr.pendingAttachList
3262 [menuMgr->menu_mgr.numAttachReqs++].menupaneId = menupane->core.self;
3265 /*************************************<->*************************************
3267 * SetButtonAccelerators (menuMgr, menubutton, accelString, accelEventType,
3268 * accelKey, accelModifiers)
3270 * Description:
3271 * -----------
3274 * Inputs:
3275 * ------
3278 * Outputs:
3279 * -------
3282 * Procedures Called
3283 * -----------------
3285 *************************************<->***********************************/
3287 static void SetButtonAccelerators (menuMgr, menubutton, accelString,
3288 accelEventType, accelKey, accelModifiers)
3290 register XwPopupMgrWidget menuMgr;
3291 Widget menubutton;
3292 String accelString;
3293 unsigned int accelEventType;
3294 unsigned int accelKey;
3295 unsigned int accelModifiers;
3298 Widget widget;
3299 register XwKeyAccel * accelerator;
3302 * add entry to menubutton accelerator table
3304 if (menuMgr->menu_mgr.numAccels == menuMgr->menu_mgr.sizeAccelTable)
3306 menuMgr->menu_mgr.sizeAccelTable =
3307 2 * menuMgr->menu_mgr.sizeAccelTable;
3308 menuMgr->menu_mgr.menuBtnAccelTable =
3309 (XwKeyAccel *) XtRealloc((char *)(menuMgr->menu_mgr.menuBtnAccelTable),
3310 menuMgr->menu_mgr.sizeAccelTable *
3311 sizeof(XwKeyAccel));
3314 accelerator = menuMgr->menu_mgr.menuBtnAccelTable +
3315 menuMgr->menu_mgr.numAccels;
3316 accelerator->accelString = accelString;
3317 accelerator->accelEventType = accelEventType;
3318 accelerator->accelKey = accelKey;
3319 accelerator->accelModifiers = accelModifiers;
3320 accelerator->menuBtn = menubutton->core.self;
3321 menuMgr->menu_mgr.numAccels++;
3324 * set translation in associated widget & toplevel pane for accelerator
3326 widget = (Widget) XtParent (XtParent (menuMgr));
3327 RegisterTranslation (widget, accelString, accelSelectTemplate, menuMgr);
3329 if (menuMgr->popup_mgr.topLevelPane)
3331 RegisterTranslation (menuMgr->popup_mgr.topLevelPane, accelString,
3332 accelSelectTemplate, menuMgr);
3335 * Because of a short coming in the toolkit, we need to
3336 * potentially patch the top level widget's translations,
3337 * if it was in the middle of a setvalues.
3339 if ((menuMgr->popup_mgr.attachPane) &&
3340 (menuMgr->popup_mgr.topLevelPane ==
3341 menuMgr->popup_mgr.attachPane->core.self))
3343 menuMgr->popup_mgr.attachPane->core.tm =
3344 menuMgr->popup_mgr.topLevelPane->core.tm;
3345 menuMgr->popup_mgr.attachPane->core.event_table =
3346 menuMgr->popup_mgr.topLevelPane->core.event_table;
3351 * set up key grabs if possible
3353 if ((menuMgr->menu_mgr.associateChildren) && (XtIsRealized (widget)))
3354 XGrabKey (XtDisplay (widget), accelKey, accelModifiers,
3355 XtWindow (widget), False, GrabModeAsync, GrabModeAsync);
3358 /*************************************<->*************************************
3360 * SetTreeAccelerators (menuMgr, menupane)
3362 * Description:
3363 * -----------
3366 * Inputs:
3367 * ------
3370 * Outputs:
3371 * -------
3374 * Procedures Called
3375 * -----------------
3377 *************************************<->***********************************/
3379 static void SetTreeAccelerators (menuMgr, menupane)
3381 XwMenuMgrWidget menuMgr;
3382 XwMenuPaneWidget menupane;
3385 register int i;
3386 Arg args[2];
3387 unsigned int eventType;
3388 KeyCode key;
3389 unsigned int modifiers;
3390 KeySym tempKeysym;
3391 register WidgetList managed_children;
3393 managed_children = menupane->manager.managed_children;
3395 for (i=0; i < menupane->manager.num_managed_children; i++)
3397 if (XtIsSubclass (managed_children[i], XwmenubuttonWidgetClass))
3399 String dkey = NULL;
3400 Widget dtree = NULL;
3402 XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal)(&dkey));
3403 XtSetArg (args[1], XtNcascadeOn, (XtArgVal)(&dtree));
3404 XtGetValues (managed_children[i], args, XtNumber(args));
3407 * set up keyboard accelerators
3409 if (dkey)
3411 _XwMapKeyEvent (dkey, &eventType, &tempKeysym, &modifiers);
3412 key = XKeysymToKeycode (XtDisplay (menupane), tempKeysym);
3413 SetButtonAccelerators (menuMgr, managed_children[i],
3414 dkey, eventType, key, modifiers);
3417 * traverse any submenus
3419 if (dtree)
3420 SetTreeAccelerators (menuMgr, dtree);
3425 /*************************************<->*************************************
3427 * ClearTreeAccelerators (menuMgr, menupane)
3429 * Description:
3430 * -----------
3433 * Inputs:
3434 * ------
3437 * Outputs:
3438 * -------
3441 * Procedures Called
3442 * -----------------
3444 *************************************<->***********************************/
3446 static void ClearTreeAccelerators (menuMgr, menupane)
3448 Widget menuMgr;
3449 XwMenuPaneWidget menupane;
3452 register int i;
3453 Arg arg[1];
3454 register WidgetList managed_children;
3456 managed_children = menupane->manager.managed_children;
3458 for (i=0; i < menupane->manager.num_managed_children; i++)
3460 if (XtIsSubclass (managed_children[i], XwmenubuttonWidgetClass))
3462 Widget twidg = NULL;
3463 ClearSelectAccelerator(menuMgr, managed_children[i]);
3466 * clear accelerators from any submenu
3468 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &twidg);
3469 XtGetValues (managed_children[i], arg, 1);
3470 if (twidg)
3471 ClearTreeAccelerators (menuMgr, twidg);
3476 /*************************************<->*************************************
3478 * CompletePath(menuMgr, menupane)
3480 * Description:
3481 * -----------
3484 * Inputs:
3485 * ------
3488 * Outputs:
3489 * -------
3492 * Procedures Called
3493 * -----------------
3495 *************************************<->***********************************/
3497 static Boolean CompletePath (menuMgr, menupane)
3499 XwPopupMgrWidget menuMgr;
3500 XwMenuPaneWidget menupane;
3503 register XwMenuPaneWidget pane;
3505 if (menuMgr->popup_mgr.topLevelPane == FALSE)
3506 return (FALSE);
3508 for (pane = menupane; pane != NULL;
3509 pane = (XwMenuPaneWidget) XtParent (pane->menu_pane.attachId))
3511 if (pane == (XwMenuPaneWidget) menuMgr->popup_mgr.topLevelPane)
3512 return (TRUE);
3514 if (pane->menu_pane.attachId == NULL)
3515 return (FALSE);
3517 if (pane->core.managed == False)
3518 return (FALSE);
3520 if ((pane->menu_pane.attachId)->core.mapped_when_managed == FALSE)
3521 return (FALSE);
3523 if ((pane->menu_pane.attachId)->core.managed == FALSE)
3524 return (FALSE);
3526 return (FALSE);
3529 /*************************************<->*************************************
3531 * PendingAttach (menuMgr, menubutton)
3533 * Description:
3534 * -----------
3537 * Inputs:
3538 * ------
3541 * Outputs:
3542 * -------
3545 * Procedures Called
3546 * -----------------
3548 *************************************<->***********************************/
3550 static Widget PendingAttach (menuMgr, menubutton)
3552 XwMenuMgrWidget menuMgr;
3553 register Widget menubutton;
3556 register int i;
3557 Widget id;
3558 register String buttonName = menubutton->core.name;
3559 register int buttonNameLen = XwStrlen(buttonName);
3560 register XwAttachList * pendingAttachList;
3562 pendingAttachList = menuMgr->menu_mgr.pendingAttachList;
3564 for (i=0; i < menuMgr->menu_mgr.numAttachReqs; i++)
3566 if ((strcmp (pendingAttachList[i].menuBtnName, buttonName) == 0) &&
3567 (XwStrlen(pendingAttachList[i].menuBtnName) == buttonNameLen))
3569 id = pendingAttachList[i].menupaneId;
3571 /* Remove from pending attach list */
3572 pendingAttachList[i] = pendingAttachList[--menuMgr->menu_mgr.
3573 numAttachReqs];
3575 return (id);
3579 return (NULL);
3582 /*************************************<->*************************************
3584 * SetUpTranslation (widget, event, action)
3586 * Description:
3587 * -----------
3589 * Inputs:
3590 * ------
3594 * Outputs:
3595 * -------
3598 * Procedures Called
3599 * -----------------
3601 *************************************<->***********************************/
3603 static void SetUpTranslation (widget, event, action)
3605 Widget widget;
3606 String event;
3607 String action;
3610 register String workSpace;
3611 XtTranslations translations;
3613 workSpace = &workArea[0];
3615 strcpy (workSpace, "!");
3616 strcat (workSpace, event);
3617 strcat (workSpace, action);
3620 * compile the translation and attach to the menupane
3622 translations = XtParseTranslationTable(workSpace);
3623 XtOverrideTranslations (widget, translations);
3624 /* XtDestroyStateTable (XtClass(widget), translations); */
3628 /*************************************<->*************************************
3630 * SetPostMnemonic (parameters)
3632 * Description:
3633 * -----------
3634 * xxxxxxxxxxxxxxxxxxxxxxx
3637 * Inputs:
3638 * ------
3639 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3641 * Outputs:
3642 * -------
3643 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3645 * Procedures Called
3646 * -----------------
3648 *************************************<->***********************************/
3650 static void SetPostMnemonic (menuMgr, menupane, mnemonic)
3652 Widget menuMgr;
3653 Widget menupane;
3654 String mnemonic;
3660 /*************************************<->*************************************
3662 * ClearPostMnemonic (parameters)
3664 * Description:
3665 * -----------
3666 * xxxxxxxxxxxxxxxxxxxxxxx
3669 * Inputs:
3670 * ------
3671 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3673 * Outputs:
3674 * -------
3675 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3677 * Procedures Called
3678 * -----------------
3680 *************************************<->***********************************/
3682 static void ClearPostMnemonic (menuMgr, menupane)
3684 Widget menuMgr;
3685 Widget menupane;
3691 /*************************************<->*************************************
3693 * SetTitleAttributes (parameters)
3695 * Description:
3696 * -----------
3697 * xxxxxxxxxxxxxxxxxxxxxxx
3700 * Inputs:
3701 * ------
3702 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3704 * Outputs:
3705 * -------
3706 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3708 * Procedures Called
3709 * -----------------
3711 *************************************<->***********************************/
3713 static void SetTitleAttributes(w, x)
3714 Widget w, x;
3719 /*************************************<->*************************************
3721 * ForceMenuPaneOnScreen (parameters)
3723 * Description:
3724 * -----------
3725 * xxxxxxxxxxxxxxxxxxxxxxx
3728 * Inputs:
3729 * ------
3730 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3732 * Outputs:
3733 * -------
3734 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3736 * Procedures Called
3737 * -----------------
3739 *************************************<->***********************************/
3741 static void ForceMenuPaneOnScreen (menupane, x, y)
3743 register Widget menupane;
3744 register Position * x;
3745 register Position * y;
3748 int rightEdgeOfMenu, dispWidth;
3749 int bottomEdgeOfMenu, dispHeight;
3752 * In order for this algorithm to work, we need to make sure the
3753 * menupane has been realized; this is because its size is not
3754 * yet valid because it is not notified that it has any children
3755 * until it is realized.
3757 if (!XtIsRealized (XtParent(menupane)))
3758 XtRealizeWidget (XtParent (menupane));
3760 /* Force the menupane to be completely visible */
3762 rightEdgeOfMenu = *x + (menupane->core.border_width << 1) +
3763 menupane->core.width;
3764 bottomEdgeOfMenu = *y + (menupane->core.border_width << 1) +
3765 menupane->core.height;
3766 dispWidth = WidthOfScreen (XtScreen(menupane));
3767 dispHeight = HeightOfScreen (XtScreen(menupane));
3769 if (*x < 0)
3770 *x = 0;
3772 if (*y < 0)
3773 *y = 0;
3775 if (rightEdgeOfMenu >= dispWidth)
3776 *x -= (rightEdgeOfMenu - dispWidth + 1);
3778 if (bottomEdgeOfMenu >= dispHeight)
3779 *y -= (bottomEdgeOfMenu - dispHeight + 1);
3783 /*************************************<->*************************************
3785 * SetSelectMnemonic (parameters)
3787 * Description:
3788 * -----------
3789 * xxxxxxxxxxxxxxxxxxxxxxx
3792 * Inputs:
3793 * ------
3794 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3796 * Outputs:
3797 * -------
3798 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3800 * Procedures Called
3801 * -----------------
3803 *************************************<->***********************************/
3805 static void SetSelectMnemonic (menuMgr, menubutton, mnemonic)
3807 Widget menuMgr;
3808 Widget menubutton;
3809 String mnemonic;
3815 /*************************************<->*************************************
3817 * ClearSelectMnemonic (parameters)
3819 * Description:
3820 * -----------
3821 * xxxxxxxxxxxxxxxxxxxxxxx
3824 * Inputs:
3825 * ------
3826 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3828 * Outputs:
3829 * -------
3830 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3832 * Procedures Called
3833 * -----------------
3835 *************************************<->***********************************/
3837 static void ClearSelectMnemonic (menuMgr, menupane)
3839 Widget menuMgr;
3840 Widget menupane;
3846 /*************************************<->*************************************
3848 * OnCascadeList(parameters)
3850 * Description:
3851 * -----------
3852 * xxxxxxxxxxxxxxxxxxxxxxx
3855 * Inputs:
3856 * ------
3857 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3859 * Outputs:
3860 * -------
3861 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3863 * Procedures Called
3864 * -----------------
3866 *************************************<->***********************************/
3868 static Boolean OnCascadeList (menuMgr, menupane)
3870 register XwPopupMgrWidget menuMgr;
3871 register XwMenuPaneWidget menupane;
3873 register int i;
3875 if ((menuMgr->popup_mgr.stickyMode) &&
3876 (menuMgr->popup_mgr.numSavedCascades > 0))
3878 for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
3880 if ((Widget)menupane->core.self ==
3881 menuMgr->popup_mgr.savedCascadeList[i])
3883 return (True);
3888 return (False);
3891 /*************************************<->*************************************
3893 * PaneManagedChildren()
3895 * Description:
3896 * -----------
3899 * Inputs:
3900 * ------
3903 * Outputs:
3904 * -------
3907 * Procedures Called
3908 * -----------------
3910 *************************************<->***********************************/
3912 static void PaneManagedChildren (menuMgr, menupane)
3914 register XwPopupMgrWidget menuMgr;
3915 register XwMenuPaneWidget menupane;
3918 register Widget child;
3919 Boolean * wasManaged;
3920 Arg args[2];
3921 unsigned int event;
3922 unsigned int tempKeySym;
3923 unsigned int modifiers;
3924 KeyCode key;
3925 register int i;
3926 Boolean parentOnCascadeList;
3927 String dkey;
3928 Widget dtree;
3931 if (CompletePath (menuMgr, menupane))
3934 * If the parent menupane is in the sticky menu list, then we
3935 * need to remember this, so that we can check if any of its
3936 * children which are now being unmanaged are cascading to
3937 * another entry in the sticky menu list. We will then clean
3938 * up the list, if necessary.
3940 parentOnCascadeList = OnCascadeList (menuMgr, menupane);
3942 for (i=0; i < menupane->composite.num_children; i++)
3944 child = menupane->composite.children[i];
3945 wasManaged = (Boolean *) child->core.constraints;
3947 if ((*wasManaged == FALSE) && (child->core.managed == TRUE))
3949 dkey = NULL;
3950 dtree = NULL;
3953 * child has gone from unmanaged to managed
3955 *wasManaged = TRUE;
3956 XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal) &dkey);
3957 XtSetArg (args[1], XtNcascadeOn, (XtArgVal) &dtree);
3958 XtGetValues (child, args, XtNumber(args));
3961 * keyboard accelerator?
3963 if (dkey)
3965 _XwMapKeyEvent (dkey, &event, &tempKeySym, &modifiers);
3966 key = XKeysymToKeycode (XtDisplay(menuMgr), tempKeySym);
3967 SetSelectAccelerator (menuMgr, child, dkey,
3968 event, key, modifiers);
3972 * Does this menubutton cascade?
3974 if (dtree)
3975 SetTreeAccelerators (menuMgr, dtree);
3977 else if ((*wasManaged == TRUE) && (child->core.managed == FALSE))
3979 dkey = NULL;
3980 dtree = NULL;
3983 * child went from managed to unmanaged
3985 *wasManaged = FALSE;
3986 XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal) &dkey);
3987 XtSetArg (args[1], XtNcascadeOn, (XtArgVal) &dtree);
3988 XtGetValues (child, args, XtNumber(args));
3991 * accelerator to clear out?
3993 if (dkey)
3994 ClearSelectAccelerator (menuMgr, child);
3997 * Does this menubutton cascade?
3999 if (dtree)
4001 ClearTreeAccelerators (menuMgr, dtree);
4002 if (Visible (menuMgr, dtree))
4003 Unpost (menuMgr, dtree);
4006 * If this button cascaded to a menupane which was on
4007 * the saved cascade list, then we need to clean up the
4008 * saved cascade list.
4010 if (parentOnCascadeList && OnCascadeList(menuMgr, dtree))
4012 parentOnCascadeList = False;
4013 menuMgr->popup_mgr.numSavedCascades = 0;
4018 * If this button was the last selected item on the saved
4019 * cascade list, then we need to clean up the list.
4021 if (parentOnCascadeList &&
4022 (child == menuMgr->popup_mgr.lastSelected))
4024 parentOnCascadeList = False;
4025 menuMgr->popup_mgr.numSavedCascades = 0;
4033 /*************************************<->*************************************
4035 * Visible
4037 * Description:
4038 * -----------
4039 * xxxxxxxxxxxxxxxxxxxxxxx
4042 * Inputs:
4043 * ------
4044 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4046 * Outputs:
4047 * -------
4048 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4050 * Procedures Called
4051 * -----------------
4053 *************************************<->***********************************/
4055 static Boolean Visible (menuMgr, menupane)
4057 XwPopupMgrWidget menuMgr;
4058 Widget menupane;
4061 register int i;
4062 register Widget * currentCascadeList =menuMgr->popup_mgr.currentCascadeList;
4064 for (i=0; i < menuMgr->popup_mgr.numCascades; i++)
4065 if (currentCascadeList[i] == menupane)
4066 return (TRUE);
4068 return (FALSE);
4072 /*************************************<->*************************************
4074 * SetMenuTranslations
4076 * Description:
4077 * -----------
4078 * xxxxxxxxxxxxxxxxxxxxxxx
4081 * Inputs:
4082 * ------
4083 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4085 * Outputs:
4086 * -------
4087 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4089 * Procedures Called
4090 * -----------------
4092 *************************************<->***********************************/
4094 static void SetMenuTranslations (menuMgr, translation)
4096 XwPopupMgrWidget menuMgr;
4097 XtTranslations translation;
4100 register int i, j, k;
4101 register CompositeWidget shell;
4102 register XwMenuPaneWidget menupane;
4105 * Since the menupanes are our popup grand children, we
4106 * will process them simply by traversing our popup children list.
4108 for (i = 0; i < menuMgr->core.num_popups; i++)
4110 shell = (CompositeWidget) menuMgr->core.popup_list[i];
4112 for (j = 0; j < shell->composite.num_children; j++)
4114 /* Here we set the translation for the menupanes */
4115 menupane = (XwMenuPaneWidget)shell->composite.children[j];
4116 XtOverrideTranslations ((Widget)menupane, translation);
4118 for (k = 0; k < menupane->manager.num_managed_children; k++)
4120 /* Here we set the translation for the menubuttons */
4121 XtOverrideTranslations(menupane->manager.managed_children[k],
4122 translation);
4129 /*************************************<->*************************************
4131 * TraverseRight(parameters)
4133 * Description:
4134 * -----------
4135 * xxxxxxxxxxxxxxxxxxxxxxx
4138 * Inputs:
4139 * ------
4140 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4142 * Outputs:
4143 * -------
4144 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4146 * Procedures Called
4147 * -----------------
4149 *************************************<->***********************************/
4151 static void TraverseRight (menuMgr, w)
4153 register XwPopupMgrWidget menuMgr;
4154 XwMenuButtonWidget w;
4157 XwMenuPaneWidget menupane;
4158 Arg arg[1];
4160 if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4161 (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4162 menuMgr->popup_mgr.numCascades - 1]))
4164 /* Cascade to the menupane attached to the specified menubutton */
4165 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &menupane);
4166 XtGetValues ((Widget)w, arg, XtNumber(arg));
4169 * Only cascade if there is a traversable primitive widget in
4170 * the pane we would be cascading to.
4172 if (_XwFindTraversablePrim (menupane) == FALSE)
4173 return;
4175 if (menupane)
4176 _XwCascadeSelect (w, menupane, NULL);
4181 /*************************************<->*************************************
4183 * TraverseLeft(parameters)
4185 * Description:
4186 * -----------
4187 * xxxxxxxxxxxxxxxxxxxxxxx
4190 * Inputs:
4191 * ------
4192 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4194 * Outputs:
4195 * -------
4196 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4198 * Procedures Called
4199 * -----------------
4201 *************************************<->***********************************/
4203 static void TraverseLeft (menuMgr, w)
4205 register XwPopupMgrWidget menuMgr;
4206 XwMenuButtonWidget w;
4209 /* Traverse to the previous menupane, if there is one */
4210 if ((menuMgr->menu_mgr.menuActive) &&
4211 (menuMgr->manager.traversal_on) &&
4212 (menuMgr->popup_mgr.numCascades > 1) &&
4213 (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4214 menuMgr->popup_mgr.numCascades - 1]))
4216 /* Unpost() will set the traversal focus, if needed */
4217 Unpost (menuMgr, menuMgr->popup_mgr.currentCascadeList[
4218 menuMgr->popup_mgr.numCascades - 1]);
4223 /*************************************<->*************************************
4225 * TraverseUp(parameters)
4227 * Description:
4228 * -----------
4229 * xxxxxxxxxxxxxxxxxxxxxxx
4232 * Inputs:
4233 * ------
4234 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4236 * Outputs:
4237 * -------
4238 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4240 * Procedures Called
4241 * -----------------
4243 *************************************<->***********************************/
4245 static void TraverseUp (menuMgr, w)
4247 register XwPopupMgrWidget menuMgr;
4248 XwMenuButtonWidget w;
4251 if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4252 (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4253 menuMgr->popup_mgr.numCascades - 1]))
4255 XwProcessTraversal (w, XwTRAVERSE_UP, TRUE);
4260 /*************************************<->*************************************
4262 * TraverseDown(parameters)
4264 * Description:
4265 * -----------
4266 * xxxxxxxxxxxxxxxxxxxxxxx
4269 * Inputs:
4270 * ------
4271 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4273 * Outputs:
4274 * -------
4275 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4277 * Procedures Called
4278 * -----------------
4280 *************************************<->***********************************/
4282 static void TraverseDown (menuMgr, w)
4284 XwPopupMgrWidget menuMgr;
4285 XwMenuButtonWidget w;
4288 if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4289 (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4290 menuMgr->popup_mgr.numCascades - 1]))
4292 XwProcessTraversal (w, XwTRAVERSE_DOWN, TRUE);
4297 /*************************************<->*************************************
4299 * TraverseNextTop(parameters)
4301 * Description:
4302 * -----------
4303 * xxxxxxxxxxxxxxxxxxxxxxx
4306 * Inputs:
4307 * ------
4308 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4310 * Outputs:
4311 * -------
4312 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4314 * Procedures Called
4315 * -----------------
4317 *************************************<->***********************************/
4319 static void TraverseNextTop (menuMgr, w)
4321 XwPopupMgrWidget menuMgr;
4322 XwMenuButtonWidget w;
4328 /*************************************<->*************************************
4330 * TraverseNext(parameters)
4332 * Description:
4333 * -----------
4334 * xxxxxxxxxxxxxxxxxxxxxxx
4337 * Inputs:
4338 * ------
4339 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4341 * Outputs:
4342 * -------
4343 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4345 * Procedures Called
4346 * -----------------
4348 *************************************<->***********************************/
4350 static void TraverseNext (menuMgr, w)
4352 XwPopupMgrWidget menuMgr;
4353 XwMenuButtonWidget w;
4359 /*************************************<->*************************************
4361 * TraversePrev(parameters)
4363 * Description:
4364 * -----------
4365 * xxxxxxxxxxxxxxxxxxxxxxx
4368 * Inputs:
4369 * ------
4370 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4372 * Outputs:
4373 * -------
4374 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4376 * Procedures Called
4377 * -----------------
4379 *************************************<->***********************************/
4381 static void TraversePrev (menuMgr, w)
4383 XwPopupMgrWidget menuMgr;
4384 XwMenuButtonWidget w;
4390 /*************************************<->*************************************
4392 * TraverseHome(parameters)
4394 * Description:
4395 * -----------
4396 * xxxxxxxxxxxxxxxxxxxxxxx
4399 * Inputs:
4400 * ------
4401 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4403 * Outputs:
4404 * -------
4405 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4407 * Procedures Called
4408 * -----------------
4410 *************************************<->***********************************/
4412 static void TraverseHome (menuMgr, w)
4414 XwPopupMgrWidget menuMgr;
4415 XwMenuButtonWidget w;
4421 /*************************************<->*************************************
4423 * ManualPost(parameters)
4425 * Description:
4426 * -----------
4427 * xxxxxxxxxxxxxxxxxxxxxxx
4430 * Inputs:
4431 * ------
4432 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4434 * Outputs:
4435 * -------
4436 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4438 * Procedures Called
4439 * -----------------
4441 *************************************<->***********************************/
4443 static void ManualPost (menuMgr, pane, relativeTo, x, y)
4445 register XwPopupMgrWidget menuMgr;
4446 register Widget pane;
4447 Widget relativeTo;
4448 Position x;
4449 Position y;
4452 int introotx, introoty, intchildx, intchildy;
4453 Position rootx, rooty;
4454 Position childx, childy;
4455 Widget assocWidget;
4456 Window root, child;
4457 unsigned int returnMask;
4459 if (pane == (Widget)NULL)
4460 pane = (Widget) menuMgr->popup_mgr.topLevelPane;
4462 /* Get the widget Id for the associated widget */
4463 assocWidget = XtParent (XtParent (menuMgr));
4466 * Do nothing if the menu is already active, there is no top level
4467 * menupane, the menu manager is insensitive, or the associated
4468 * widget is insensitive.
4470 if ((menuMgr->menu_mgr.menuActive == TRUE) || (pane == NULL) ||
4471 !XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget)) {
4472 return;
4476 * Determine where to post the menu and translate coordinates,
4477 * if necessary.
4479 if (relativeTo)
4482 * If the coordinates are relative to a widget, then we need
4483 * to map them relative to the root window.
4485 /* XtTranslateCoords (relativeTo, x, y, &rootx, &rooty); */
4486 XTranslateCoordinates (XtDisplay(relativeTo), XtWindow(relativeTo),
4487 RootWindowOfScreen(XtScreen(menuMgr)),
4488 x, y, &introotx, &introoty, &child);
4489 rootx = introotx;
4490 rooty = introoty;
4492 else
4495 * If no widget is specified, then the coordinates are assumed
4496 * to already be relative to the root window.
4498 rootx = x;
4499 rooty = y;
4503 * The following is a kludge fix to bypass a shortcoming within Xtk.
4504 * We need to manually inform the previous focus widget that it has
4505 * lost the cursor; this is because once we add our popups to the
4506 * grablist, the LeaveNotify will be ignored for the focus widget,
4507 * because it is not on the grablist.
4509 /* if (menuMgr->manager.traversal_on) */
4510 SendFakeLeaveNotify(menuMgr, ULTIMATE_PARENT);
4512 /* Mark the menu system as active */
4513 menuMgr->menu_mgr.menuActive = TRUE;
4515 /* Position the menupane */
4516 if (!XtIsRealized (XtParent(pane)))
4517 XtRealizeWidget (XtParent(pane));
4518 ForceMenuPaneOnScreen (pane, &rootx, &rooty);
4519 XtMoveWidget (XtParent(pane), rootx, rooty);
4522 * Set up a pointer grab; this allows us to catch all selects and
4523 * to then unpost the menus, regardless as to where the select
4524 * occurred.
4526 XGrabPointer (XtDisplay(menuMgr), XtWindow(assocWidget), TRUE,
4527 ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|
4528 PointerMotionMask, GrabModeAsync, GrabModeAsync, None, (Cursor)NULL,
4529 CurrentTime);
4531 /* Post the menupane */
4532 Post (menuMgr, pane, XtGrabExclusive);
4535 * If traversal is on, then save the current mouse position,
4536 * so that we can restore the mouse to its original position
4537 * when the menu is unposted.
4539 if (menuMgr->manager.traversal_on)
4541 if (XQueryPointer(XtDisplay(menuMgr),
4542 RootWindowOfScreen(menuMgr->core.screen),
4543 &root, &child, &introotx, &introoty, &intchildx,
4544 &intchildy, &returnMask))
4546 menuMgr->popup_mgr.origMouseX = introotx;
4547 menuMgr->popup_mgr.origMouseY = introoty;
4550 /* Set the traversal focus to the pane */
4551 XwMoveFocus (pane);
4556 /*************************************<->*************************************
4558 * XwPostPopup(parameters)
4560 * Description:
4561 * -----------
4562 * This is a utility routine which may be used by an application to
4563 * manually post a popup menu pane.
4566 * Inputs:
4567 * ------
4568 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4570 * Outputs:
4571 * -------
4572 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4574 * Procedures Called
4575 * -----------------
4577 *************************************<->***********************************/
4579 void XwPostPopup (menuMgr, pane, relativeTo, x, y)
4581 Widget menuMgr, pane, relativeTo;
4582 Position x, y;
4585 /* Only popup a menu if it is a subclass of the popup menu manager */
4586 /* Do nothing if invalid menu manager Id */
4587 if (menuMgr == NULL)
4588 return;
4590 if (XtIsSubclass (menuMgr, XwpopupmgrWidgetClass))
4592 (*(((XwPopupMgrWidgetClass)
4593 XtClass(menuMgr))-> popup_mgr_class.manualPost))
4594 (menuMgr, pane, relativeTo, x, y);
4596 else
4598 XtWarning ("PopupMgr: Widget is not a subclass of menuMgr");
4603 /*************************************<->*************************************
4605 * SendFakeLeaveNotify(parameters)
4607 * Description:
4608 * -----------
4609 * xxxxxxxxxxxxxxxxxxxxxxx
4612 * Inputs:
4613 * ------
4614 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4616 * Outputs:
4617 * -------
4618 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4620 * Procedures Called
4621 * -----------------
4623 *************************************<->***********************************/
4625 static void SendFakeLeaveNotify (focus_widget, mode)
4627 Widget focus_widget;
4628 int mode;
4631 XEvent event;
4633 if (mode == ULTIMATE_PARENT)
4635 /* Search up to top level shell */
4636 while (XtParent(focus_widget) != NULL)
4637 focus_widget = XtParent(focus_widget);
4639 else
4641 /* Search up to the shell in which this menubtn resides */
4642 while ((!XtIsSubclass (focus_widget, shellWidgetClass)) &&
4643 (XtParent(focus_widget) != NULL))
4644 focus_widget = XtParent(focus_widget);
4647 event.type = FocusOut;
4648 event.xfocus.serial = LastKnownRequestProcessed(XtDisplay(focus_widget));
4649 event.xfocus.send_event = True;
4650 event.xfocus.display = XtDisplay(focus_widget);
4651 event.xfocus.window = XtWindow(focus_widget);
4652 event.xfocus.mode = NotifyNormal;
4653 event.xfocus.detail = NotifyAncestor;
4655 XtDispatchEvent (&event);
4659 /*************************************<->*************************************
4661 * SetUpStickyList(parameters)
4663 * Description:
4664 * -----------
4665 * xxxxxxxxxxxxxxxxxxxxxxx
4668 * Inputs:
4669 * ------
4670 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4672 * Outputs:
4673 * -------
4674 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4676 * Procedures Called
4677 * -----------------
4679 *************************************<->***********************************/
4681 static void SetUpStickyList (menuMgr, widget)
4683 XwPopupMgrWidget menuMgr;
4684 Widget widget;
4687 int i;
4689 menuMgr->popup_mgr.numSavedCascades = 0;
4691 if ((XtIsSubclass (widget, XwmenubuttonWidgetClass)) &&
4692 (menuMgr->popup_mgr.stickyMode) &&
4693 (XtParent(widget) == menuMgr->popup_mgr.currentCascadeList
4694 [menuMgr->popup_mgr.numCascades -1]))
4696 if (menuMgr->popup_mgr.numCascades >
4697 menuMgr->popup_mgr.sizeSavedCascadeList)
4699 menuMgr->popup_mgr.sizeSavedCascadeList =
4700 menuMgr->popup_mgr.sizeCascadeList;
4701 menuMgr->popup_mgr.savedCascadeList =
4702 (Widget *) XtRealloc((char *)(menuMgr->popup_mgr.savedCascadeList),
4703 menuMgr->popup_mgr.sizeSavedCascadeList *
4704 sizeof (Widget));
4707 menuMgr->popup_mgr.numSavedCascades = menuMgr->popup_mgr.numCascades;
4708 menuMgr->popup_mgr.lastSelected = widget;
4710 /* Set this widget as the traversal item */
4711 if (menuMgr->manager.traversal_on)
4713 XwMenuPaneWidget pane;
4715 pane = ((XwMenuPaneWidget)(menuMgr->popup_mgr.currentCascadeList
4716 [menuMgr->popup_mgr.numCascades -1]));
4717 pane->manager.active_child = widget;
4718 XtSetKeyboardFocus ((Widget)pane, widget);
4721 for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
4722 menuMgr->popup_mgr.savedCascadeList[i] =
4723 menuMgr->popup_mgr.currentCascadeList[i];
4725 else if (menuMgr->manager.traversal_on)
4727 /* Force the first item to be highlighted next time */
4728 ((XwPopupMgrWidget)menuMgr->popup_mgr.topLevelPane)->
4729 manager.active_child = NULL;
4730 XtSetKeyboardFocus (menuMgr->popup_mgr.topLevelPane, NULL);
4735 /*************************************<->*************************************
4737 * BtnSensitivityChanged(parameters)
4739 * Description:
4740 * -----------
4741 * xxxxxxxxxxxxxxxxxxxxxxx
4744 * Inputs:
4745 * ------
4746 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4748 * Outputs:
4749 * -------
4750 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4752 * Procedures Called
4753 * -----------------
4755 *************************************<->***********************************/
4757 static void BtnSensitivityChanged (menuMgr, btn)
4759 XwPopupMgrWidget menuMgr;
4760 Widget btn;
4763 /* Noop */
4767 /*************************************<->*************************************
4769 * PaneSensitivityChanged(parameters)
4771 * Description:
4772 * -----------
4773 * xxxxxxxxxxxxxxxxxxxxxxx
4776 * Inputs:
4777 * ------
4778 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4780 * Outputs:
4781 * -------
4782 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4784 * Procedures Called
4785 * -----------------
4787 *************************************<->***********************************/
4789 static void PaneSensitivityChanged (menuMgr, pane)
4791 XwPopupMgrWidget menuMgr;
4792 Widget pane;
4795 /* Noop */