1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Popup Menu Manager Widget
10 *****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
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
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>
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();
49 static void AttachPane();
50 static void DetachPane();
51 static void AddPane();
52 static void SetSelectAccelerator();
53 static void ClearSelectAccelerator();
54 static void AddButton();
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();
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 /****************************************************************
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
,
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
,
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
,
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
,
208 /* query_geometry */ NULL
,
209 /* display_accelerator */ XtInheritDisplayAccelerator
,
212 /* composite_class fields */
213 /* geometry_manager */ NULL
,
214 /* change_managed */ NULL
,
215 /* insert_child */ XtInheritInsertChild
,
216 /* delete_child */ XtInheritDeleteChild
,
219 /* constraint class fields */
220 /* resources */ NULL
,
221 /* num_resources */ 0,
222 /* constraint_size */ 0,
223 /* initialize */ NULL
,
225 /* set_values */ 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 /*************************************<->*************************************
294 * Initialize the popup_mgr fields within the widget's instance structure.
299 * xxxxxxxxxxxx = xxxxxxxxxxxxx
303 * xxxxxxxxxxxx = xxxxxxxxxxxxx
308 *************************************<->***********************************/
310 static void Initialize (request
, new)
312 XwPopupMgrWidget request
;
313 register XwPopupMgrWidget
new;
320 * Clear the 'map when managed' flag, since this widget should
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
,
352 &new->popup_mgr
.accelModifiers
)))
354 /* Valid accelerator string; save a copy */
355 new->popup_mgr
.accelKey
= XKeysymToKeycode(XtDisplay(new),
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);
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
,
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
);
425 XtAddEventHandler (grandparent
, ExposureMask
|StructureNotifyMask
, False
,
426 ExposeEventHandler
, new);
431 /*************************************<->*************************************
441 * xxxxxxxxxxxx = xxxxxxxxxxxxx
445 * xxxxxxxxxxxx = xxxxxxxxxxxxx
450 *************************************<->***********************************/
452 static Boolean
SetValues (current
, request
, new)
454 register XwPopupMgrWidget current
;
455 XwPopupMgrWidget request
;
456 register XwPopupMgrWidget
new;
460 Boolean postGrabSet
= FALSE
;
461 Boolean postGrabCleared
= FALSE
;
462 Boolean postAccelGrabSet
= FALSE
;
463 Boolean postAccelGrabCleared
= FALSE
;
465 XtTranslations translation
;
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
,
480 &new->popup_mgr
.accelModifiers
))
482 /* Valid accelerator string; save a copy */
483 new->popup_mgr
.accelKey
= XKeysymToKeycode (XtDisplay(new),
485 new->popup_mgr
.postAccelerator
= (String
) strcpy (XtMalloc (
486 XwStrlen(new->popup_mgr
. postAccelerator
) + 1),
487 new->popup_mgr
.postAccelerator
);
491 /* Invalid; revert to previous setting */
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
;
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
) &¤t
->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
,
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
,
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
);
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
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
)
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
720 if (XtIsRealized (grandparent
))
722 if (new->menu_mgr
.associateChildren
)
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
,
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
)
794 if (new->manager
.traversal_on
)
795 traversalType
= XwHIGHLIGHT_TRAVERSAL
;
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;
843 /*************************************<->*************************************
853 * xxxxxxxxxxxx = xxxxxxxxxxxxx
857 * xxxxxxxxxxxx = xxxxxxxxxxxxx
862 *************************************<->***********************************/
864 static void Destroy (mw
)
866 register XwPopupMgrWidget mw
;
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
,
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
);
898 * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
899 * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
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);
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
));
933 * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
934 * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
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));
950 /* Simply remove the exposure handler we added at initialize time */
951 XtRemoveEventHandler (grandparent
, ExposureMask
|StructureNotifyMask
,
952 False
, ExposeEventHandler
, mw
);
957 /*************************************<->*************************************
959 * ClassPartInitialize(parameters)
963 * xxxxxxxxxxxxxxxxxxxxxxx
968 * xxxxxxxxxxxx = xxxxxxxxxxxxx
972 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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)
1088 * xxxxxxxxxxxxxxxxxxxxxxx
1093 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1097 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1102 *************************************<->***********************************/
1104 static void RegisterTranslation (widget
, event
, template, 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);
1128 strcat (workTemplate
, _XwMapToHex(menuMgrId
->core
.self
));
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)
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.
1155 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1159 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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);
1218 yDelta
= menupane
->core
.border_width
+ (menupane
->core
.height
>> 1);
1222 ForceMenuPaneOnScreen (menupane
, &x
, &y
);
1224 XtMoveWidget (menupaneShell
, x
, y
);
1228 /*************************************<->*************************************
1230 * ExposeEventHandler (parameters)
1234 * xxxxxxxxxxxxxxxxxxxxxxx
1239 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1243 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1248 *************************************<->***********************************/
1250 static void ExposeEventHandler (w
, menuMgr
, event
)
1253 register XwPopupMgrWidget menuMgr
;
1260 * If the children inherit the menu tree, then set up grabs for
1261 * the post button, the post accelerator key, and each menubutton
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
),
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)
1302 * xxxxxxxxxxxxxxxxxxxxxxx
1307 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1311 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1316 *************************************<->***********************************/
1318 static void _XwCascadeSelect (menubutton
, menupane
, data
)
1321 XwMenuPaneWidget menupane
;
1322 caddr_t data
; /* not used */
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
])
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)
1362 * xxxxxxxxxxxxxxxxxxxxxxx
1367 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1371 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1376 *************************************<->***********************************/
1378 static void _XwCascadeUnselect (menubutton
, menupane
, params
)
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
;
1410 /* No, we've left the cascade region; unpost the menupane */
1411 Unpost (menuMgr
, menupane
);
1412 params
->remainHighlighted
= FALSE
;
1417 /*************************************<->*************************************
1419 * _XwMenuPaneCleanup (parameters)
1423 * xxxxxxxxxxxxxxxxxxxxxxx
1428 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1432 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1437 *************************************<->***********************************/
1439 static void _XwMenuPaneCleanup (menupane
, menuMgr
, data
)
1441 XwMenuPaneWidget menupane
;
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
);
1456 DoDetach (menuMgr
, menupane
->menu_pane
.attachId
, menupane
);
1461 /*************************************<->*************************************
1463 * _XwMenuButtonCleanup(parameters)
1467 * xxxxxxxxxxxxxxxxxxxxxxx
1472 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1476 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1481 *************************************<->***********************************/
1483 static void _XwMenuButtonCleanup (menubutton
, menuMgr
, data
)
1486 XwPopupMgrWidget menuMgr
;
1487 caddr_t data
; /* not used */
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)
1530 * xxxxxxxxxxxxxxxxxxxxxxx
1535 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1539 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1544 *************************************<->***********************************/
1546 static void MMPost (w
, event
, params
, 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
1563 if ((menuMgr
) && (menuMgr
->popup_mgr
.topLevelPane
))
1564 ClassPost (menuMgr
, event
, TRUE
);
1568 /*************************************<->*************************************
1570 * MMUnpost(parameters)
1574 * xxxxxxxxxxxxxxxxxxxxxxx
1579 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1583 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1588 *************************************<->***********************************/
1590 static void MMUnpost (w
, event
, params
, 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
))
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.
1639 (menuMgr
->popup_mgr
.origMouseX
!= -1) &&
1640 (menuMgr
->popup_mgr
.origMouseY
!= -1))
1642 XWarpPointer (XtDisplay (menuMgr
), None
,
1643 RootWindowOfScreen(menuMgr
->core
.screen
),
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)
1660 * xxxxxxxxxxxxxxxxxxxxxxx
1665 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1669 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1674 *************************************<->***********************************/
1676 static void MMAccelPost (w
, event
, params
, 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
1693 if ((menuMgr
) && (menuMgr
->popup_mgr
.topLevelPane
))
1694 ClassPost (menuMgr
, event
, FALSE
);
1698 /*************************************<->*************************************
1700 * MMAccelSelect (parameters)
1704 * xxxxxxxxxxxxxxxxxxxxxxx
1709 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1713 * xxxxxxxxxxxx = xxxxxxxxxxxxx
1718 *************************************<->***********************************/
1720 static void MMAccelSelect (w
, event
, params
, count
)
1728 register XwPopupMgrWidget menuMgr
;
1730 /* Extract the menu manager widget id */
1731 menuMgr
= (XwPopupMgrWidget
) _XwMapFromHex (params
[0]);
1733 if (menuMgr
== NULL
)
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
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
)))
1751 * If we have made it down here, then we know the accelerator event is
1754 if (menuMgr
->popup_mgr
.topLevelPane
)
1755 ClassSelect ((XwMenuMgrWidget
)menuMgr
, event
);
1759 /*************************************<->*************************************
1761 * AttachPane(menuMgr, menupane, name)
1778 *************************************<->***********************************/
1780 static void AttachPane (menuMgr
, menupane
, name
)
1782 register XwPopupMgrWidget menuMgr
;
1783 register XwMenuPaneWidget menupane
;
1787 register XwMenuButtonWidget menubutton
;
1790 CompositeWidget shell
, mpane
;
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
);
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);
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
;
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)
1919 *************************************<->***********************************/
1921 static void DetachPane (menuMgr
, menupane
, name
)
1923 register XwPopupMgrWidget menuMgr
;
1924 XwMenuPaneWidget menupane
;
1930 XwMenuButtonWidget menubutton
;
1931 CompositeWidget shell
;
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
];
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
;
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
))
1990 * Found it! Detach it
1992 DoDetach (menuMgr
, menubutton
, menupane
);
1993 menuMgr
->popup_mgr
.detachPane
= NULL
;
2000 /* This must always be cleared when we leave */
2001 menuMgr
->popup_mgr
.detachPane
= NULL
;
2005 /*************************************<->*************************************
2007 * DoDetach(parameters)
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
2024 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2028 * xxxxxxxxxxxx = xxxxxxxxxxxxx
2033 *************************************<->***********************************/
2035 static void DoDetach (menuMgr
, menubutton
, menupane
)
2037 register XwPopupMgrWidget menuMgr
;
2038 XwMenuButtonWidget menubutton
;
2039 XwMenuPaneWidget menupane
;
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;
2077 /*************************************<->*************************************
2079 * AddPane(menuMgr, menupane)
2096 *************************************<->***********************************/
2098 static void AddPane (menuMgr
, menupane
)
2100 register XwMenuMgrWidget menuMgr
;
2101 XwMenuPaneWidget menupane
;
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
,
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
,
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
);
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:
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)
2178 *************************************<->***********************************/
2180 static void SetSelectAccelerator (menuMgr
, menubutton
, accelString
,
2181 accelEventType
, accelKey
, accelModifiers
)
2185 unsigned int accelEventType
;
2186 unsigned int accelKey
;
2187 unsigned int accelModifiers
;
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)
2220 *************************************<->***********************************/
2222 static void ClearSelectAccelerator (menuMgr
, menubutton
)
2224 register XwPopupMgrWidget menuMgr
;
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
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
,
2280 * remove menubutton accelerator table entry
2282 menuMgr
->menu_mgr
.menuBtnAccelTable
[i
] =
2283 menuMgr
->menu_mgr
.menuBtnAccelTable
[--menuMgr
->menu_mgr
.numAccels
];
2290 /*************************************<->*************************************
2292 * AddButton(menuMgr, menubutton)
2309 *************************************<->***********************************/
2311 static void AddButton (menuMgr
, menubutton
)
2313 register XwMenuMgrWidget menuMgr
;
2314 register Widget menubutton
;
2321 if (menuMgr
->menu_mgr
.selectString
)
2323 SetUpTranslation (menubutton
, menuMgr
->menu_mgr
.selectString
,
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
,
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
:
2358 if (XtIsSubclass (menubutton
, XwmenubuttonWidgetClass
))
2360 (*(((XwMenuButtonWidgetClass
)
2361 XtClass(menubutton
))-> menubutton_class
.setTraversalType
))
2362 (menubutton
, traversalType
);
2366 /*************************************<->*************************************
2368 * Unpost (menuMgr, menupane)
2385 *************************************<->***********************************/
2387 static void Unpost (menuMgr
, menupane
)
2389 register XwPopupMgrWidget menuMgr
;
2390 XwMenuPaneWidget menupane
;
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
,
2449 ((XwMenuButtonWidgetClass
)
2450 XtClass(pane
->menu_pane
.attachId
))->
2451 menubutton_class
.enterParentProc
,
2452 pane
->menu_pane
.attachId
);
2456 /* Kludge to force the grablist to get cleaned up */
2457 XtSetKeyboardFocus (XtParent(pane
), None
);
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
));
2473 /*************************************<->*************************************
2475 * Post(menuMgr, menupane, grabtype)
2494 *************************************<->***********************************/
2496 static void Post (menuMgr
, menupane
, grabtype
)
2498 register XwPopupMgrWidget menuMgr
;
2500 XtGrabKind grabtype
;
2506 * if already posted, do nothing
2508 for (i
=0; i
< menuMgr
->popup_mgr
.numCascades
; i
++)
2509 if (menuMgr
->popup_mgr
.currentCascadeList
[i
] == menupane
)
2515 if (grabtype
== XtGrabNonexclusive
)
2517 _XtPopup (XtParent (menupane
), grabtype
, FALSE
);
2518 XtAddGrab (menupane
, FALSE
, FALSE
);
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
*
2539 menuMgr
->popup_mgr
.currentCascadeList
[menuMgr
->popup_mgr
.numCascades
++] =
2543 /*************************************<->*************************************
2545 * ProcessSelect(menuMgr, widget, event)
2562 *************************************<->***********************************/
2564 static Boolean
ProcessSelect (menuMgr
, widget
, event
)
2566 register XwPopupMgrWidget menuMgr
;
2571 register XwKeyAccel
* accelerator
;
2573 Boolean found
= FALSE
;
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
))
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
)
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]))
2611 SetUpStickyList (menuMgr
, widget
);
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
);
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
);
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); */
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.
2681 (menuMgr
->popup_mgr
.origMouseX
!= -1) &&
2682 (menuMgr
->popup_mgr
.origMouseY
!= -1))
2684 XWarpPointer (XtDisplay (menuMgr
), None
,
2685 RootWindowOfScreen(menuMgr
->core
.screen
),
2687 menuMgr
->popup_mgr
.origMouseX
,
2688 menuMgr
->popup_mgr
.origMouseY
);
2689 menuMgr
->popup_mgr
.origMouseX
= -1;
2690 menuMgr
->popup_mgr
.origMouseY
= -1;
2696 /*************************************<->*************************************
2698 * ValidEvent(menuMgr, menubutton, event)
2715 *************************************<->***********************************/
2717 static Boolean
ValidEvent (menuMgr
, menubutton
, event
)
2719 XwPopupMgrWidget menuMgr
;
2724 /* Ignore enter and leave events if traversal is active */
2725 if (menuMgr
->manager
.traversal_on
)
2731 /*************************************<->*************************************
2733 * DoICascade (menuMgr)
2750 *************************************<->***********************************/
2752 static Boolean
DoICascade (menuMgr
, menuBtn
)
2754 register XwPopupMgrWidget menuMgr
;
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
))
2775 /*************************************<->*************************************
2777 * ClassPost(menuMgr, event, warpOn)
2794 *************************************<->***********************************/
2796 static void ClassPost (menuMgr
, event
, warpOn
)
2798 register XwPopupMgrWidget menuMgr
;
2804 Position posx
, posy
;
2805 int x
, y
, relativeX
, relativeY
;
2807 XButtonEvent
* buttonEvent
= (XButtonEvent
*) event
;
2808 Widget assocWidget
, w
;
2810 XwMenuPaneWidget tempPane
;
2811 XwManagerWidget topLevelPane
;
2812 XWindowChanges windowChanges
;
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
))
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
)))
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);
2910 yDelta
= topLevelPane
->core
.border_width
+
2911 (topLevelPane
->core
.height
>> 1);
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
)),
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
;
2952 ForceMenuPaneOnScreen (topLevelPane
, &posx
, &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
,
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
;
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];
3000 menuMgr
->popup_mgr
.lastSelected
= (Widget
)tempPane
;
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.
3030 XWarpPointer (XtDisplay (menuMgr
), None
,
3031 XtWindow(menuMgr
->popup_mgr
.lastSelected
),
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
,
3089 ((XwMenuButtonWidgetClass
) XtClass(menuBtn
))->
3090 menubutton_class
.enterParentProc
,
3096 * DON'T DO THE FOLLOWING; HAVE THE ITEM HILIGHT WHEN THE CURSOR
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);
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)
3137 * Called only when a menubutton select accelerator is received.
3151 *************************************<->***********************************/
3153 static void ClassSelect (menuMgr
, event
)
3155 XwMenuMgrWidget menuMgr
;
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
))
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
);
3197 /*************************************<->*************************************
3199 * AddToPendingList(menuMgr, menupane, name)
3216 *************************************<->***********************************/
3218 static void AddToPendingList (menuMgr
, menupane
, name
)
3220 register XwMenuMgrWidget menuMgr
;
3225 register int nameLen
;
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
,
3248 if (menuMgr
->menu_mgr
.numAttachReqs
== menuMgr
->menu_mgr
.sizeAttachList
)
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)
3285 *************************************<->***********************************/
3287 static void SetButtonAccelerators (menuMgr
, menubutton
, accelString
,
3288 accelEventType
, accelKey
, accelModifiers
)
3290 register XwPopupMgrWidget menuMgr
;
3293 unsigned int accelEventType
;
3294 unsigned int accelKey
;
3295 unsigned int accelModifiers
;
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)
3377 *************************************<->***********************************/
3379 static void SetTreeAccelerators (menuMgr
, menupane
)
3381 XwMenuMgrWidget menuMgr
;
3382 XwMenuPaneWidget menupane
;
3387 unsigned int eventType
;
3389 unsigned int modifiers
;
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
))
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
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
3420 SetTreeAccelerators (menuMgr
, dtree
);
3425 /*************************************<->*************************************
3427 * ClearTreeAccelerators (menuMgr, menupane)
3444 *************************************<->***********************************/
3446 static void ClearTreeAccelerators (menuMgr
, menupane
)
3449 XwMenuPaneWidget menupane
;
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);
3471 ClearTreeAccelerators (menuMgr
, twidg
);
3476 /*************************************<->*************************************
3478 * CompletePath(menuMgr, menupane)
3495 *************************************<->***********************************/
3497 static Boolean
CompletePath (menuMgr
, menupane
)
3499 XwPopupMgrWidget menuMgr
;
3500 XwMenuPaneWidget menupane
;
3503 register XwMenuPaneWidget pane
;
3505 if (menuMgr
->popup_mgr
.topLevelPane
== FALSE
)
3508 for (pane
= menupane
; pane
!= NULL
;
3509 pane
= (XwMenuPaneWidget
) XtParent (pane
->menu_pane
.attachId
))
3511 if (pane
== (XwMenuPaneWidget
) menuMgr
->popup_mgr
.topLevelPane
)
3514 if (pane
->menu_pane
.attachId
== NULL
)
3517 if (pane
->core
.managed
== False
)
3520 if ((pane
->menu_pane
.attachId
)->core
.mapped_when_managed
== FALSE
)
3523 if ((pane
->menu_pane
.attachId
)->core
.managed
== FALSE
)
3529 /*************************************<->*************************************
3531 * PendingAttach (menuMgr, menubutton)
3548 *************************************<->***********************************/
3550 static Widget
PendingAttach (menuMgr
, menubutton
)
3552 XwMenuMgrWidget menuMgr
;
3553 register Widget menubutton
;
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
.
3582 /*************************************<->*************************************
3584 * SetUpTranslation (widget, event, action)
3601 *************************************<->***********************************/
3603 static void SetUpTranslation (widget
, event
, 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)
3634 * xxxxxxxxxxxxxxxxxxxxxxx
3639 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3643 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3648 *************************************<->***********************************/
3650 static void SetPostMnemonic (menuMgr
, menupane
, mnemonic
)
3660 /*************************************<->*************************************
3662 * ClearPostMnemonic (parameters)
3666 * xxxxxxxxxxxxxxxxxxxxxxx
3671 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3675 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3680 *************************************<->***********************************/
3682 static void ClearPostMnemonic (menuMgr
, menupane
)
3691 /*************************************<->*************************************
3693 * SetTitleAttributes (parameters)
3697 * xxxxxxxxxxxxxxxxxxxxxxx
3702 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3706 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3711 *************************************<->***********************************/
3713 static void SetTitleAttributes(w
, x
)
3719 /*************************************<->*************************************
3721 * ForceMenuPaneOnScreen (parameters)
3725 * xxxxxxxxxxxxxxxxxxxxxxx
3730 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3734 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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
));
3775 if (rightEdgeOfMenu
>= dispWidth
)
3776 *x
-= (rightEdgeOfMenu
- dispWidth
+ 1);
3778 if (bottomEdgeOfMenu
>= dispHeight
)
3779 *y
-= (bottomEdgeOfMenu
- dispHeight
+ 1);
3783 /*************************************<->*************************************
3785 * SetSelectMnemonic (parameters)
3789 * xxxxxxxxxxxxxxxxxxxxxxx
3794 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3798 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3803 *************************************<->***********************************/
3805 static void SetSelectMnemonic (menuMgr
, menubutton
, mnemonic
)
3815 /*************************************<->*************************************
3817 * ClearSelectMnemonic (parameters)
3821 * xxxxxxxxxxxxxxxxxxxxxxx
3826 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3830 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3835 *************************************<->***********************************/
3837 static void ClearSelectMnemonic (menuMgr
, menupane
)
3846 /*************************************<->*************************************
3848 * OnCascadeList(parameters)
3852 * xxxxxxxxxxxxxxxxxxxxxxx
3857 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3861 * xxxxxxxxxxxx = xxxxxxxxxxxxx
3866 *************************************<->***********************************/
3868 static Boolean
OnCascadeList (menuMgr
, menupane
)
3870 register XwPopupMgrWidget menuMgr
;
3871 register XwMenuPaneWidget menupane
;
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
])
3891 /*************************************<->*************************************
3893 * PaneManagedChildren()
3910 *************************************<->***********************************/
3912 static void PaneManagedChildren (menuMgr
, menupane
)
3914 register XwPopupMgrWidget menuMgr
;
3915 register XwMenuPaneWidget menupane
;
3918 register Widget child
;
3919 Boolean
* wasManaged
;
3922 unsigned int tempKeySym
;
3923 unsigned int modifiers
;
3926 Boolean parentOnCascadeList
;
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
))
3953 * child has gone from unmanaged to managed
3956 XtSetArg (args
[0], XtNkbdAccelerator
, (XtArgVal
) &dkey
);
3957 XtSetArg (args
[1], XtNcascadeOn
, (XtArgVal
) &dtree
);
3958 XtGetValues (child
, args
, XtNumber(args
));
3961 * keyboard accelerator?
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?
3975 SetTreeAccelerators (menuMgr
, dtree
);
3977 else if ((*wasManaged
== TRUE
) && (child
->core
.managed
== FALSE
))
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?
3994 ClearSelectAccelerator (menuMgr
, child
);
3997 * Does this menubutton cascade?
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 /*************************************<->*************************************
4039 * xxxxxxxxxxxxxxxxxxxxxxx
4044 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4048 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4053 *************************************<->***********************************/
4055 static Boolean
Visible (menuMgr
, menupane
)
4057 XwPopupMgrWidget menuMgr
;
4062 register Widget
* currentCascadeList
=menuMgr
->popup_mgr
.currentCascadeList
;
4064 for (i
=0; i
< menuMgr
->popup_mgr
.numCascades
; i
++)
4065 if (currentCascadeList
[i
] == menupane
)
4072 /*************************************<->*************************************
4074 * SetMenuTranslations
4078 * xxxxxxxxxxxxxxxxxxxxxxx
4083 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4087 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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
],
4129 /*************************************<->*************************************
4131 * TraverseRight(parameters)
4135 * xxxxxxxxxxxxxxxxxxxxxxx
4140 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4144 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4149 *************************************<->***********************************/
4151 static void TraverseRight (menuMgr
, w
)
4153 register XwPopupMgrWidget menuMgr
;
4154 XwMenuButtonWidget w
;
4157 XwMenuPaneWidget menupane
;
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
)
4176 _XwCascadeSelect (w
, menupane
, NULL
);
4181 /*************************************<->*************************************
4183 * TraverseLeft(parameters)
4187 * xxxxxxxxxxxxxxxxxxxxxxx
4192 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4196 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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)
4229 * xxxxxxxxxxxxxxxxxxxxxxx
4234 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4238 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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)
4266 * xxxxxxxxxxxxxxxxxxxxxxx
4271 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4275 * xxxxxxxxxxxx = xxxxxxxxxxxxx
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)
4303 * xxxxxxxxxxxxxxxxxxxxxxx
4308 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4312 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4317 *************************************<->***********************************/
4319 static void TraverseNextTop (menuMgr
, w
)
4321 XwPopupMgrWidget menuMgr
;
4322 XwMenuButtonWidget w
;
4328 /*************************************<->*************************************
4330 * TraverseNext(parameters)
4334 * xxxxxxxxxxxxxxxxxxxxxxx
4339 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4343 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4348 *************************************<->***********************************/
4350 static void TraverseNext (menuMgr
, w
)
4352 XwPopupMgrWidget menuMgr
;
4353 XwMenuButtonWidget w
;
4359 /*************************************<->*************************************
4361 * TraversePrev(parameters)
4365 * xxxxxxxxxxxxxxxxxxxxxxx
4370 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4374 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4379 *************************************<->***********************************/
4381 static void TraversePrev (menuMgr
, w
)
4383 XwPopupMgrWidget menuMgr
;
4384 XwMenuButtonWidget w
;
4390 /*************************************<->*************************************
4392 * TraverseHome(parameters)
4396 * xxxxxxxxxxxxxxxxxxxxxxx
4401 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4405 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4410 *************************************<->***********************************/
4412 static void TraverseHome (menuMgr
, w
)
4414 XwPopupMgrWidget menuMgr
;
4415 XwMenuButtonWidget w
;
4421 /*************************************<->*************************************
4423 * ManualPost(parameters)
4427 * xxxxxxxxxxxxxxxxxxxxxxx
4432 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4436 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4441 *************************************<->***********************************/
4443 static void ManualPost (menuMgr
, pane
, relativeTo
, x
, y
)
4445 register XwPopupMgrWidget menuMgr
;
4446 register Widget pane
;
4452 int introotx
, introoty
, intchildx
, intchildy
;
4453 Position rootx
, rooty
;
4454 Position childx
, childy
;
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
)) {
4476 * Determine where to post the menu and translate coordinates,
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
);
4495 * If no widget is specified, then the coordinates are assumed
4496 * to already be relative to the root window.
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
4526 XGrabPointer (XtDisplay(menuMgr
), XtWindow(assocWidget
), TRUE
,
4527 ButtonPressMask
|ButtonReleaseMask
|EnterWindowMask
|LeaveWindowMask
|
4528 PointerMotionMask
, GrabModeAsync
, GrabModeAsync
, None
, (Cursor
)NULL
,
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 */
4556 /*************************************<->*************************************
4558 * XwPostPopup(parameters)
4562 * This is a utility routine which may be used by an application to
4563 * manually post a popup menu pane.
4568 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4572 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4577 *************************************<->***********************************/
4579 void XwPostPopup (menuMgr
, pane
, relativeTo
, x
, y
)
4581 Widget menuMgr
, pane
, relativeTo
;
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
)
4590 if (XtIsSubclass (menuMgr
, XwpopupmgrWidgetClass
))
4592 (*(((XwPopupMgrWidgetClass
)
4593 XtClass(menuMgr
))-> popup_mgr_class
.manualPost
))
4594 (menuMgr
, pane
, relativeTo
, x
, y
);
4598 XtWarning ("PopupMgr: Widget is not a subclass of menuMgr");
4603 /*************************************<->*************************************
4605 * SendFakeLeaveNotify(parameters)
4609 * xxxxxxxxxxxxxxxxxxxxxxx
4614 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4618 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4623 *************************************<->***********************************/
4625 static void SendFakeLeaveNotify (focus_widget
, mode
)
4627 Widget focus_widget
;
4633 if (mode
== ULTIMATE_PARENT
)
4635 /* Search up to top level shell */
4636 while (XtParent(focus_widget
) != NULL
)
4637 focus_widget
= XtParent(focus_widget
);
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)
4665 * xxxxxxxxxxxxxxxxxxxxxxx
4670 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4674 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4679 *************************************<->***********************************/
4681 static void SetUpStickyList (menuMgr
, widget
)
4683 XwPopupMgrWidget menuMgr
;
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
*
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)
4741 * xxxxxxxxxxxxxxxxxxxxxxx
4746 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4750 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4755 *************************************<->***********************************/
4757 static void BtnSensitivityChanged (menuMgr
, btn
)
4759 XwPopupMgrWidget menuMgr
;
4767 /*************************************<->*************************************
4769 * PaneSensitivityChanged(parameters)
4773 * xxxxxxxxxxxxxxxxxxxxxxx
4778 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4782 * xxxxxxxxxxxx = xxxxxxxxxxxxx
4787 *************************************<->***********************************/
4789 static void PaneSensitivityChanged (menuMgr
, pane
)
4791 XwPopupMgrWidget menuMgr
;