1 /*************************************<+>*************************************
2  *****************************************************************************
3  **
4  **   File:        PopupMgr.c
5  **
6  **   Project:     X Widgets
7  **
8  **   Description: Popup Menu Manager Widget
9  **
10  *****************************************************************************
11  **
12  **   Copyright (c) 1988 by Hewlett-Packard Company
13  **   Copyright (c) 1988 by the Massachusetts Institute of Technology
14  **
15  **   Permission to use, copy, modify, and distribute this software
16  **   and its documentation for any purpose and without fee is hereby
17  **   granted, provided that the above copyright notice appear in all
18  **   copies and that both that copyright notice and this permission
19  **   notice appear in supporting documentation, and that the names of
20  **   Hewlett-Packard or  M.I.T.  not be used in advertising or publicity
21  **   pertaining to distribution of the software without specific, written
22  **   prior permission.
23  **
24  *****************************************************************************
25  *************************************<+>*************************************/
26 
27 
28 #include <X11/IntrinsicP.h>
29 #include <X11/StringDefs.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #include <X11/Shell.h>
33 #include <X11/ShellP.h>
34 #include <Xw/Xw.h>
35 #include <Xw/XwP.h>
36 #include <Xw/MenuBtnP.h>
37 #include <Xw/MenuBtn.h>
38 #include <Xw/PopupMgrP.h>
39 #include <Xw/PopupMgr.h>
40 
41 
42 /* Standard Toolkit Routines */
43 static void Initialize();
44 static void Destroy();
45 static Boolean SetValues();
46 static void ClassPartInitialize();
47 
48 /* Global Routines */
49 static void AttachPane();
50 static void DetachPane();
51 static void AddPane();
52 static void SetSelectAccelerator();
53 static void ClearSelectAccelerator();
54 static void AddButton();
55 static void Unpost();
56 static void Post();
57 static Boolean ProcessSelect();
58 static Boolean ValidEvent();
59 static Boolean DoICascade();
60 static void ClassPost();
61 static void ClassSelect();
62 static Boolean DoYouWantThisAccelerator();
63 static Boolean DoYouWantThisPost();
64 static void SetPostMnemonic();
65 static void ClearPostMnemonic();
66 static void SetSelectMnemonic();
67 static void ClearSelectMnemonic();
68 static void SetTitleAttributes();
69 static void TraverseLeft();
70 static void TraverseRight();
71 static void TraverseNext();
72 static void TraversePrev();
73 static void TraverseHome();
74 static void TraverseUp();
75 static void TraverseDown();
76 static void TraverseNextTop();
77 static void BtnSensitivityChanged();
78 static void PaneSensitivityChanged();
79 
80 /* Action Routines */
81 static void MMPost();
82 static void MMAccelPost();
83 static void MMAccelSelect();
84 static void MMUnpost();
85 
86 /* Callback Routines */
87 static void _XwMenuPaneCleanup();
88 static void _XwMenuButtonCleanup();
89 static void _XwCascadeUnselect();
90 static void _XwCascadeSelect();
91 
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();
113 
114 
115 /****************************************************************
116  *
117  * Popup Resources
118  *
119  ****************************************************************/
120 
121 static XtResource resources[] = {
122     {XtNstickyMenus, XtCStickyMenus, XtRBoolean, sizeof(Boolean),
123        XtOffset(XwPopupMgrWidget, popup_mgr.stickyMode),XtRString,"FALSE"},
124 
125     {XtNpostAccelerator, XtCPostAccelerator, XtRString, sizeof(String),
126        XtOffset(XwPopupMgrWidget, popup_mgr.postAccelerator),XtRString,
127        NULL}
128 };
129 
130 /****************************************************************
131  *
132  * Miscellaneous Values
133  *
134  ****************************************************************/
135 
136 /* Global Action Routines */
137 static XtActionsRec XwPopupActions[] = {
138    {"PopupPostMenu",    MMPost},
139    {"PopupUnpostMenu",  MMUnpost},
140    {"PopupAccelPost",   MMAccelPost},
141    {"PopupAccelSelect", MMAccelSelect}
142 };
143 
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()";
150 
151 static char workArea[300];
152 
153 
154 /*
155  * Used when positioning a cascade such that the cursor will be
156  * in the first item of the cascade.
157  */
158 #define FUDGE_FACTOR 8
159 
160 #define SHELL_PARENT 0
161 #define ULTIMATE_PARENT 1
162 
163 /*
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.
167  */
168 #define btnMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
169 
170 /****************************************************************
171  *
172  * Full class record constant
173  *
174  ****************************************************************/
175 
176 XwPopupMgrClassRec XwpopupmgrClassRec = {
177   {
178 /* core_class fields      */
179     /* superclass         */    (WidgetClass) &XwmenumgrClassRec,
180     /* class_name         */    "XwPopupMgr",
181     /* widget_size        */    sizeof(XwPopupMgrRec),
182     /* class_initialize   */    NULL,
183     /* class_part_init    */    ClassPartInitialize,
184     /* class_inited       */	FALSE,
185     /* initialize         */    Initialize,
186     /* initialize_hook    */    NULL,
187     /* realize            */    NULL,
188     /* actions		  */	NULL,
189     /* num_actions	  */	0,
190     /* resources          */    resources,
191     /* num_resources      */    XtNumber(resources),
192     /* xrm_class          */    NULLQUARK,
193     /* compress_motion	  */	TRUE,
194     /* compress_exposure  */	TRUE,
195     /* compress_enterlv   */	TRUE,
196     /* visible_interest   */    FALSE,
197     /* destroy            */    Destroy,
198     /* resize             */    NULL,
199     /* expose             */    NULL,
200     /* set_values         */    SetValues,
201     /* set_values_hook    */    NULL,
202     /* set_values_almost  */    XtInheritSetValuesAlmost,
203     /* get_values_hook    */    NULL,
204     /* accept_focus       */    NULL,
205     /* version            */    XtVersion,
206     /* PRIVATE cb list    */    NULL,
207     /* tm_table           */    NULL,
208     /* query_geometry     */    NULL,
209     /* display_accelerator	*/	XtInheritDisplayAccelerator,
210     /* extension		*/	NULL
211   },{
212 /* composite_class fields */
213     /* geometry_manager   */    NULL,
214     /* change_managed     */    NULL,
215     /* insert_child	  */	XtInheritInsertChild,
216     /* delete_child	  */	XtInheritDeleteChild,
217 				NULL,
218   },{
219 /* constraint class fields */
220     /* resources          */    NULL,
221     /* num_resources      */    0,
222     /* constraint_size    */    0,
223     /* initialize         */    NULL,
224     /* destroy            */    NULL,
225     /* set_values         */    NULL,
226 				NULL,
227   },{
228 /* manager_class fields */
229    /* traversal handler   */    (XwTraversalProc)XtInheritTraversalProc,
230    /* translations        */    NULL,
231   },{
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,
258   },{
259 /* popup menu manager class - none */
260     /* manualPost         */    (XwPostProc) ManualPost,
261   }
262 };
263 
264 WidgetClass XwpopupmgrWidgetClass = (WidgetClass)&XwpopupmgrClassRec;
265 WidgetClass XwpopupMgrWidgetClass = (WidgetClass)&XwpopupmgrClassRec;
266 
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 /*----------------------------------------------------------------------*/
279 
XwAppInitialize(XtAppContext app)280 void XwAppInitialize(XtAppContext app)
281 {
282    /* Register the global action routines */
283    XtAppAddActions (app, XwPopupActions, XtNumber(XwPopupActions));
284 }
285 
286 
287 /*************************************<->*************************************
288  *
289  *  Initialize
290  *
291  *
292  *   Description:
293  *   -----------
294  *   Initialize the popup_mgr fields within the widget's instance structure.
295  *
296  *
297  *   Inputs:
298  *   ------
299  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
300  *
301  *   Outputs:
302  *   -------
303  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
304  *
305  *   Procedures Called
306  *   -----------------
307  *
308  *************************************<->***********************************/
309 
Initialize(request,new)310 static void Initialize (request, new)
311 
312     XwPopupMgrWidget request;
313     register XwPopupMgrWidget new;
314 
315 {
316    Widget grandparent;
317    KeySym tempKeysym;
318 
319    /*
320     * Clear the 'map when managed' flag, since this widget should
321     * never be visible.
322     */
323    new->core.mapped_when_managed = FALSE;
324 
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;
338 
339    /* Get the widget Id for the widget to which the menu is attached */
340    grandparent = (Widget) XtParent(XtParent(new));
341 
342    /*
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).
346     */
347    if ((new->popup_mgr.postAccelerator) &&
348        (strlen(new->popup_mgr.postAccelerator) > 0) &&
349        (_XwMapKeyEvent (new->popup_mgr.postAccelerator,
350                         &new->popup_mgr.accelEventType,
351                         &tempKeysym,
352                         &new->popup_mgr.accelModifiers)))
353    {
354       /* Valid accelerator string; save a copy */
355       new->popup_mgr.accelKey = XKeysymToKeycode(XtDisplay(new),
356                                      tempKeysym);
357       new->popup_mgr.postAccelerator = (String) strcpy (XtMalloc (
358          XwStrlen(new->popup_mgr. postAccelerator) + 1),
359          new->popup_mgr.postAccelerator);
360 
361       /* Set up a translation in the widget */
362       RegisterTranslation (grandparent, new->popup_mgr.postAccelerator,
363                            accelPostTemplate, new);
364    }
365    else
366    {
367       if ((new->popup_mgr.postAccelerator) &&
368           (strlen(new->popup_mgr.postAccelerator) > 0))
369       {
370          XtWarning ("PopupMgr: Invalid post accelerator; disabling feature");
371       }
372       new->popup_mgr.postAccelerator = NULL;
373       new->popup_mgr.accelEventType = 0;
374       new->popup_mgr.accelKey = 0;
375       new->popup_mgr.accelModifiers = 0;
376    }
377 
378    /* Attach a posting translation to the widget */
379    if (new->menu_mgr.postString)
380    {
381       RegisterTranslation (grandparent, new->menu_mgr.postString,
382                            postTemplate, new);
383    }
384 
385    /* Attach an unposting translation to the widget, if specified */
386    if (new->menu_mgr.unpostString)
387    {
388       RegisterTranslation (grandparent, new->menu_mgr.unpostString,
389                             unpostTemplate, new);
390    }
391 
392    /*
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.
398     */
399    if (XtIsRealized(grandparent))
400    {
401       if (new->menu_mgr.associateChildren)
402       {
403          /* Set up a grab for the post event */
404          if (new->menu_mgr.postString)
405          {
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);
411          }
412 
413          /* Set up a grab for the post accelerator */
414          if (new->popup_mgr.postAccelerator)
415          {
416             XGrabKey (XtDisplay(grandparent),
417                       new->popup_mgr.accelKey,
418                       new->popup_mgr.accelModifiers, XtWindow(grandparent),
419                       False, GrabModeAsync, GrabModeAsync);
420          }
421       }
422    }
423    else
424    {
425       XtAddEventHandler (grandparent, ExposureMask|StructureNotifyMask, False,
426                          ExposeEventHandler, new);
427    }
428 } /* Initialize */
429 
430 
431 /*************************************<->*************************************
432  *
433  *  SetValues()
434  *
435  *   Description:
436  *   -----------
437  *
438  *
439  *   Inputs:
440  *   ------
441  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
442  *
443  *   Outputs:
444  *   -------
445  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
446  *
447  *   Procedures Called
448  *   -----------------
449  *
450  *************************************<->***********************************/
451 
SetValues(current,request,new)452 static Boolean SetValues (current, request, new)
453 
454     register XwPopupMgrWidget current;
455     XwPopupMgrWidget request;
456     register XwPopupMgrWidget new;
457 
458 {
459    Widget  grandparent;
460    Boolean postGrabSet = FALSE;
461    Boolean postGrabCleared = FALSE;
462    Boolean postAccelGrabSet = FALSE;
463    Boolean postAccelGrabCleared = FALSE;
464    KeySym tempKeysym;
465    XtTranslations translation;
466    String workTemplate;
467    register int i, j, k;
468 
469    grandparent = (Widget) XtParent(XtParent(current));
470 
471    /* Process the post accelerator */
472    if (current->popup_mgr.postAccelerator != new->popup_mgr.postAccelerator)
473    {
474       if ((new->popup_mgr.postAccelerator) &&
475           (strlen(new->popup_mgr.postAccelerator) > 0))
476       {
477          if (_XwMapKeyEvent (new->popup_mgr.postAccelerator,
478                              &new->popup_mgr.accelEventType,
479                              &tempKeysym,
480                              &new->popup_mgr.accelModifiers))
481          {
482             /* Valid accelerator string; save a copy */
483             new->popup_mgr.accelKey = XKeysymToKeycode (XtDisplay(new),
484                                       tempKeysym);
485             new->popup_mgr.postAccelerator = (String) strcpy (XtMalloc (
486                XwStrlen(new->popup_mgr. postAccelerator) + 1),
487                new->popup_mgr.postAccelerator);
488          }
489          else
490          {
491             /* Invalid; revert to previous setting */
492             XtWarning
493               ("PopupMgr: Invalid post accelerator; using previous setting");
494             new->popup_mgr.postAccelerator = current->popup_mgr.postAccelerator;
495             new->popup_mgr.accelEventType = current->popup_mgr.accelEventType;
496             new->popup_mgr.accelKey = current->popup_mgr.accelKey;
497             new->popup_mgr.accelModifiers = current->popup_mgr.accelModifiers;
498          }
499       }
500       else
501       {
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;
507       }
508 
509       /*
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.
513        */
514       if (current->popup_mgr.postAccelerator != new->popup_mgr.postAccelerator)
515       {
516          /* Remove the old accelerator translation and grab */
517          if (current->popup_mgr.postAccelerator)
518          {
519             RegisterTranslation (grandparent,
520                                  current->popup_mgr.postAccelerator,
521                                  accelPostTemplate, NULL);
522 
523             if (XtIsRealized(grandparent) &&current->menu_mgr.associateChildren)
524             {
525                XUngrabKey (XtDisplay(grandparent), current->popup_mgr.accelKey,
526                     current->popup_mgr.accelModifiers, XtWindow(grandparent));
527                postAccelGrabCleared = TRUE;
528             }
529          }
530 
531          /* Set the new accelerator translation and grab */
532          if (new->popup_mgr.postAccelerator)
533          {
534             RegisterTranslation (grandparent, new->popup_mgr.postAccelerator,
535                                accelPostTemplate, new);
536 
537             if (XtIsRealized(grandparent) && new->menu_mgr.associateChildren)
538             {
539                XGrabKey (XtDisplay(grandparent), new->popup_mgr.accelKey,
540                          new->popup_mgr.accelModifiers, XtWindow(grandparent),
541                          False, GrabModeAsync, GrabModeAsync);
542                postAccelGrabSet = TRUE;
543             }
544          }
545 
546          /* Free up the buffer holding the old string */
547          XtFree (current->popup_mgr.postAccelerator);
548       }
549    }
550 
551    /* Process the post event  */
552    if (current->menu_mgr.postString != new->menu_mgr.postString)
553    {
554       /* Remove the old post translation and grab */
555       if (current->menu_mgr.postString)
556       {
557          RegisterTranslation (grandparent, current->menu_mgr.postString,
558                               postTemplate, NULL);
559 
560          if (XtIsRealized(grandparent) && current->menu_mgr.associateChildren)
561          {
562             XUngrabButton (XtDisplay(grandparent), current->menu_mgr.postButton,
563                            (current->menu_mgr.postModifiers & ~btnMask),
564                            XtWindow(grandparent));
565             postGrabCleared = TRUE;
566          }
567 
568          /* Free up the old string */
569          XtFree (current->menu_mgr.postString);
570       }
571 
572       /* Set the new post translation and grab */
573       if (new->menu_mgr.postString)
574       {
575          RegisterTranslation (grandparent, new->menu_mgr.postString,
576                             postTemplate, new);
577 
578          if (XtIsRealized(grandparent) && new->menu_mgr.associateChildren)
579          {
580             XGrabButton (XtDisplay(grandparent), new->menu_mgr.postButton,
581                          (new->menu_mgr.postModifiers & ~btnMask),
582                          XtWindow(grandparent),
583                          False, ButtonPressMask|ButtonReleaseMask,
584                          GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
585             postGrabSet = TRUE;
586          }
587       }
588    }
589 
590    /* Process the select event.  */
591    if (current->menu_mgr.selectString != new->menu_mgr.selectString)
592    {
593 
594       /*
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.
598        */
599 
600       if (new->menu_mgr.selectString)
601       {
602          /*
603           * Create the translation string of format:
604           *
605           *    "!<event>: select()"
606           */
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); */
614       }
615 
616        if (current->menu_mgr.selectString)
617          XtFree (current->menu_mgr.selectString);
618    }
619 
620    /* Process the unpost event.  */
621    if (current->menu_mgr.unpostString != new->menu_mgr.unpostString)
622    {
623       /*
624        * Each menubutton and menupane must have a new 'unpost' translation
625        * set up; no grabs are needed.  The old ones need to first be
626        * removed.
627        */
628 
629       if (current->menu_mgr.unpostString)
630       {
631          /*
632           * Create the translation string of format:
633           *
634           *    "!<event>: MMUnpost(mgrId)"
635           */
636 
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);
649       }
650 
651       if (new->menu_mgr.unpostString)
652       {
653          /*
654           * Create the translation string of format:
655           *
656           *    "!<event>: MMUnpost(mgrId)"
657           */
658 
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);
670       }
671    }
672 
673    /* Process the keyboard select event.  */
674    if (current->menu_mgr.kbdSelectString != new->menu_mgr.kbdSelectString)
675    {
676       /*
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.
680        */
681 
682       if (new->menu_mgr.kbdSelectString)
683       {
684          /*
685           * Create the translation string of format:
686           *
687           *    "!<event>: select()"
688           */
689          workTemplate = &workArea[0];
690          strcpy (workTemplate, "!");
691          strcat (workTemplate, new->menu_mgr.kbdSelectString);
692          strcat (workTemplate, selectTemplate);
693          translation = XtParseTranslationTable (workTemplate);
694 
695          /*
696           * Since the menupanes are our popup grand children, we
697           * will process them simply by traversing our popup children list.
698           */
699          SetMenuTranslations (new, translation);
700          /* XtDestroyStateTable (XtClass(new), translation); */
701       }
702 
703        if (current->menu_mgr.kbdSelectString)
704          XtFree (current->menu_mgr.kbdSelectString);
705    }
706 
707    /* Process the associateChildren flag */
708    if (current->menu_mgr.associateChildren != new->menu_mgr.associateChildren)
709    {
710       int i;
711 
712       /*
713        * If the widget is realized, then we need to set/clear button
714        * and key grabs for the post event, the post accelerator, and
715        * all menubutton accelerators; the two post grabs will only be
716        * set or cleared if they were not already done so earlier; this
717        * would have happened if either of their event strings had
718        * changed.
719        */
720       if (XtIsRealized (grandparent))
721       {
722          if (new->menu_mgr.associateChildren)
723          {
724             /* Set post grab */
725             if ((!postGrabSet) && (new->menu_mgr.postString))
726             {
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);
732             }
733 
734             /* Set post accelerator grab */
735             if ((!postAccelGrabSet) && (new->popup_mgr.postAccelerator))
736             {
737                XGrabKey (XtDisplay(grandparent), new->popup_mgr.accelKey,
738                          new->popup_mgr.accelModifiers, XtWindow(grandparent),
739                          False, GrabModeAsync, GrabModeAsync);
740             }
741 
742             /* Set menubutton accelerator grabs */
743             for (i = 0; i < new->menu_mgr.numAccels; i++)
744             {
745                XGrabKey (XtDisplay(grandparent),
746                          new->menu_mgr.menuBtnAccelTable[i].accelKey,
747                          new->menu_mgr.menuBtnAccelTable[i].accelModifiers,
748                          XtWindow(grandparent), False, GrabModeAsync,
749                          GrabModeAsync);
750             }
751          }
752          else
753          {
754             /* Clear post grab */
755             if ((!postGrabCleared) && (current->menu_mgr.postString))
756             {
757                XUngrabButton (XtDisplay(grandparent),
758                               current->menu_mgr.postButton,
759                               (current->menu_mgr.postModifiers & ~btnMask),
760                               XtWindow(grandparent));
761             }
762 
763             /* Clear post accelerator grab */
764             if ((!postAccelGrabCleared) && (current->popup_mgr.postAccelerator))
765             {
766                XUngrabKey (XtDisplay(grandparent),
767                          current->popup_mgr.accelKey,
768                          current->popup_mgr.accelModifiers,
769                          XtWindow(grandparent));
770             }
771 
772             /* Clear menubutton accelerator grabs */
773             for (i = 0; i < current->menu_mgr.numAccels; i++)
774             {
775                XUngrabKey (XtDisplay(grandparent),
776                          current->menu_mgr.menuBtnAccelTable[i].accelKey,
777                          current->menu_mgr.menuBtnAccelTable[i].accelModifiers,
778                          XtWindow(grandparent));
779             }
780          }
781       }
782    }
783 
784    /*
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).
789     */
790    if (new->manager.traversal_on != current->manager.traversal_on)
791    {
792       int traversalType;
793 
794       if (new->manager.traversal_on)
795          traversalType = XwHIGHLIGHT_TRAVERSAL;
796       else
797          traversalType = XwHIGHLIGHT_OFF;
798 
799       for (i = 0; i < current->core.num_popups; i++)
800       {
801          CompositeWidget shell;
802 
803          shell = (CompositeWidget) current->core.popup_list[i];
804 
805          for (j = 0; j < shell->composite.num_children; j++)
806          {
807             XwMenuPaneWidget menupane;
808 
809             /* Here we set the traversal flag for the menupanes */
810             menupane = (XwMenuPaneWidget)shell->composite.children[j];
811             if (XtIsSubclass ((Widget)menupane, XwmenupaneWidgetClass))
812             {
813 	       (*(((XwMenuPaneWidgetClass)
814 		XtClass(menupane))-> menu_pane_class.setTraversalFlag))
815 	         ((Widget)menupane, new->manager.traversal_on);
816             }
817 
818             for (k = 0; k < menupane->manager.num_managed_children; k++)
819             {
820                XwMenuButtonWidget mbutton;
821 
822                /* Here we set the traversal flag for the menubuttons */
823                mbutton = (XwMenuButtonWidget)menupane->composite.children[k];
824                if (XtIsSubclass ((Widget)mbutton, XwmenubuttonWidgetClass))
825                {
826 	          (*(((XwMenuButtonWidgetClass)
827 		   XtClass(mbutton))-> menubutton_class.setTraversalType))
828 	            ((Widget)mbutton, traversalType);
829                }
830             }
831          }
832       }
833    }
834 
835    /* Clear the sticky menu list, if sticky mode is disabled */
836    if (new->popup_mgr.stickyMode == False)
837       new->popup_mgr.numSavedCascades = 0;
838 
839    return (FALSE);
840 }
841 
842 
843 /*************************************<->*************************************
844  *
845  *  Destroy()
846  *
847  *   Description:
848  *   -----------
849  *
850  *
851  *   Inputs:
852  *   ------
853  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
854  *
855  *   Outputs:
856  *   -------
857  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
858  *
859  *   Procedures Called
860  *   -----------------
861  *
862  *************************************<->***********************************/
863 
Destroy(mw)864 static void Destroy (mw)
865 
866     register XwPopupMgrWidget  mw;
867 
868 {
869    Widget grandparent;
870    register int i;
871 
872    /* Get the widget Id for the widget to which the menus are attached */
873    grandparent = (Widget)XtParent(XtParent(mw));
874 
875    /* Free up any memory we allocated */
876    XtFree ((char *)(mw->popup_mgr.savedCascadeList));
877    XtFree ((char *)(mw->popup_mgr.currentCascadeList));
878 
879    /* Clean up the post and accelerated post translations */
880    if (mw->menu_mgr.postString)
881    {
882       RegisterTranslation (grandparent, mw->menu_mgr.postString,
883                            postTemplate, NULL);
884    }
885    if (mw->popup_mgr.postAccelerator)
886    {
887       RegisterTranslation (grandparent, mw->popup_mgr.postAccelerator,
888                            accelPostTemplate, NULL);
889    }
890 
891    if (mw->menu_mgr.unpostString)
892    {
893       RegisterTranslation (grandparent, mw->menu_mgr.unpostString,
894                            unpostTemplate, NULL);
895    }
896 
897    /***************
898     * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
899     * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
900     * ALREADY CLEARED.
901     *
902     * Remove translations for each menubutton accelerator
903     *
904     * for (i = 0; i < mw->menu_mgr.numAccels; i++)
905     * {
906     *  RegisterTranslation (grandparent,
907     *                       mw->menu_mgr.menuBtnAccelTable[i].accelString,
908     *                       accelSelectTemplate, NULL);
909     * }
910     ****************/
911 
912    /* Remove any grabs we have set on the widget */
913    if (XtIsRealized(grandparent))
914    {
915       if (mw->menu_mgr.associateChildren)
916       {
917          /* Remove post grab */
918          if (mw->menu_mgr.postString)
919          {
920             XUngrabButton (XtDisplay(grandparent), mw->menu_mgr.postButton,
921                            (mw->menu_mgr.postModifiers & ~btnMask),
922                            XtWindow(grandparent));
923          }
924 
925          /* Remove post accelerator grab */
926          if (mw->popup_mgr.postAccelerator)
927          {
928             XUngrabKey (XtDisplay(grandparent), mw->popup_mgr.accelKey,
929                       mw->popup_mgr.accelModifiers, XtWindow(grandparent));
930          }
931 
932          /***************
933           * THE FOLLOWING IS NOT NEEDED, SINCE BY THE TIME WE GET HERE,
934           * ALL OF OUR CHILDREN HAVE BEEN DESTROYED, AND THEIR ACCELERATORS
935           * ALREADY CLEARED.
936           *
937           * Remove grabs for each menubutton accelerator
938           * for (i = 0; i < mw->menu_mgr.numAccels; i++)
939           * {
940           *   XUngrabKey (XtDisplay(grandparent),
941           *                mw->menu_mgr.menuBtnAccelTable[i].accelKey,
942           *                mw->menu_mgr.menuBtnAccelTable[i].accelModifiers,
943           *                XtWindow(grandparent));
944           * }
945           ***************/
946       }
947    }
948    else
949    {
950       /* Simply remove the exposure handler we added at initialize time */
951       XtRemoveEventHandler (grandparent, ExposureMask|StructureNotifyMask,
952                             False, ExposeEventHandler, mw);
953    }
954 }
955 
956 
957 /*************************************<->*************************************
958  *
959  *  ClassPartInitialize(parameters)
960  *
961  *   Description:
962  *   -----------
963  *     xxxxxxxxxxxxxxxxxxxxxxx
964  *
965  *
966  *   Inputs:
967  *   ------
968  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
969  *
970  *   Outputs:
971  *   -------
972  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
973  *
974  *   Procedures Called
975  *   -----------------
976  *
977  *************************************<->***********************************/
978 
ClassPartInitialize(wc)979 static void ClassPartInitialize (wc)
980 
981    register XwPopupMgrWidgetClass wc;
982 
983 {
984    register XwPopupMgrWidgetClass super;
985 
986    super = (XwPopupMgrWidgetClass)wc->core_class.superclass;
987 
988    if (wc->menu_mgr_class.attachPane == XtInheritAttachPane)
989       wc->menu_mgr_class.attachPane = super->menu_mgr_class.attachPane;
990 
991    if (wc->menu_mgr_class.detachPane == XtInheritDetachPane)
992       wc->menu_mgr_class.detachPane = super->menu_mgr_class.detachPane;
993 
994    if (wc->menu_mgr_class.addPane == XtInheritAddPane)
995       wc->menu_mgr_class.addPane = super->menu_mgr_class.addPane;
996 
997    if (wc->menu_mgr_class.setSelectAccelerator == XtInheritSetSelectAccelerator)
998       wc->menu_mgr_class.setSelectAccelerator =
999                               super->menu_mgr_class.setSelectAccelerator;
1000 
1001    if (wc->menu_mgr_class.clearSelectAccelerator ==
1002            XtInheritClearSelectAccelerator)
1003       wc->menu_mgr_class.clearSelectAccelerator =
1004             super->menu_mgr_class.clearSelectAccelerator;
1005 
1006    if (wc->menu_mgr_class.setPostMnemonic == XtInheritSetPostMnemonic)
1007       wc->menu_mgr_class.setPostMnemonic =super->menu_mgr_class.setPostMnemonic;
1008 
1009    if (wc->menu_mgr_class.clearPostMnemonic == XtInheritClearPostMnemonic)
1010       wc->menu_mgr_class.clearPostMnemonic =
1011                                       super->menu_mgr_class.clearPostMnemonic;
1012 
1013    if (wc->menu_mgr_class.setPostMnemonic == XtInheritSetPostMnemonic)
1014       wc->menu_mgr_class.setPostMnemonic =super->menu_mgr_class.setPostMnemonic;
1015 
1016    if (wc->menu_mgr_class.clearPostMnemonic==XtInheritClearPostMnemonic)
1017       wc->menu_mgr_class.clearPostMnemonic =
1018                                     super->menu_mgr_class.clearPostMnemonic;
1019 
1020    if (wc->menu_mgr_class.addButton == XtInheritAddButton)
1021       wc->menu_mgr_class.addButton = super->menu_mgr_class.addButton;
1022 
1023    if (wc->menu_mgr_class.setSelectMnemonic == XtInheritSetSelectMnemonic)
1024       wc->menu_mgr_class.setSelectMnemonic =
1025                     super->menu_mgr_class.setSelectMnemonic;
1026 
1027    if (wc->menu_mgr_class.clearSelectMnemonic == XtInheritClearSelectMnemonic)
1028       wc->menu_mgr_class.clearSelectMnemonic =
1029                     super->menu_mgr_class.clearSelectMnemonic;
1030 
1031    if (wc->menu_mgr_class.processSelect == XtInheritProcessSelect)
1032       wc->menu_mgr_class.processSelect = super->menu_mgr_class.processSelect;
1033 
1034    if (wc->menu_mgr_class.validEvent == XtInheritValidEvent)
1035       wc->menu_mgr_class.validEvent = super->menu_mgr_class.validEvent;
1036 
1037    if (wc->menu_mgr_class.doICascade == XtInheritDoICascade)
1038       wc->menu_mgr_class.doICascade = super->menu_mgr_class.doICascade;
1039 
1040    if (wc->menu_mgr_class.paneManagedChildren == XtInheritPaneManagedChildren)
1041       wc->menu_mgr_class.paneManagedChildren =
1042                          super->menu_mgr_class.paneManagedChildren;
1043 
1044    if (wc->menu_mgr_class.setTitleAttributes == XtInheritSetTitleAttributes)
1045       wc->menu_mgr_class.setTitleAttributes =
1046                                     super->menu_mgr_class.setTitleAttributes;
1047 
1048    if (wc->menu_mgr_class.traverseLeft == XtInheritPopupTravLeft)
1049       wc->menu_mgr_class.traverseLeft = super->menu_mgr_class.traverseLeft;
1050 
1051    if (wc->menu_mgr_class.traverseRight == XtInheritPopupTravRight)
1052       wc->menu_mgr_class.traverseRight = super->menu_mgr_class.traverseRight;
1053 
1054    if (wc->menu_mgr_class.traverseNext == XtInheritPopupTravNext)
1055       wc->menu_mgr_class.traverseNext = super->menu_mgr_class.traverseNext;
1056 
1057    if (wc->menu_mgr_class.traversePrev == XtInheritPopupTravPrev)
1058       wc->menu_mgr_class.traversePrev = super->menu_mgr_class.traversePrev;
1059 
1060    if (wc->menu_mgr_class.traverseHome == XtInheritPopupTravHome)
1061       wc->menu_mgr_class.traverseHome = super->menu_mgr_class.traverseHome;
1062 
1063    if (wc->menu_mgr_class.traverseUp == XtInheritPopupTravUp)
1064       wc->menu_mgr_class.traverseUp = super->menu_mgr_class.traverseUp;
1065 
1066    if (wc->menu_mgr_class.traverseDown == XtInheritPopupTravDown)
1067       wc->menu_mgr_class.traverseDown = super->menu_mgr_class.traverseDown;
1068 
1069    if (wc->menu_mgr_class.traverseNextTop == XtInheritPopupTravNextTop)
1070       wc->menu_mgr_class.traverseNextTop=super->menu_mgr_class.traverseNextTop;
1071 
1072    if (wc->menu_mgr_class.btnSensitivityChanged==XtInheritBtnSensitivityChanged)
1073       wc->menu_mgr_class.btnSensitivityChanged =
1074                             super->menu_mgr_class.btnSensitivityChanged;
1075 
1076    if (wc->menu_mgr_class.paneSensitivityChanged ==
1077                                        XtInheritPaneSensitivityChanged)
1078       wc->menu_mgr_class.paneSensitivityChanged =
1079                             super->menu_mgr_class.paneSensitivityChanged;
1080 }
1081 
1082 /*************************************<->*************************************
1083  *
1084  *  RegisterTranslation (parameters)
1085  *
1086  *   Description:
1087  *   -----------
1088  *     xxxxxxxxxxxxxxxxxxxxxxx
1089  *
1090  *
1091  *   Inputs:
1092  *   ------
1093  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1094  *
1095  *   Outputs:
1096  *   -------
1097  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1098  *
1099  *   Procedures Called
1100  *   -----------------
1101  *
1102  *************************************<->***********************************/
1103 
RegisterTranslation(widget,event,template,menuMgrId)1104 static void RegisterTranslation (widget, event, template, menuMgrId)
1105 
1106    Widget widget;
1107    String event;
1108    String template;
1109    Widget menuMgrId;
1110 
1111 
1112 {
1113    register String workTemplate;
1114    XtTranslations translations;
1115 
1116    workTemplate = &workArea[0];
1117 
1118    /*
1119     * Construct the translation string, using the following format:
1120     *
1121     *  "!<event>: ActionProc(menuMgrId)"
1122     */
1123 
1124    strcpy (workTemplate, "!");
1125    strcat (workTemplate, event);
1126    strcat (workTemplate, template);
1127    if (menuMgrId)
1128       strcat (workTemplate, _XwMapToHex(menuMgrId->core.self));
1129    else
1130       strcat (workTemplate, _XwMapToHex(NULL));
1131    strcat (workTemplate, ")");
1132 
1133    /* Compile the translation and attach to the widget */
1134    translations = XtParseTranslationTable(workTemplate);
1135    XtOverrideTranslations (widget, translations);
1136    /* XtDestroyStateTable (XtClass(widget), translations); */
1137 }
1138 
1139 
1140 /*************************************<->*************************************
1141  *
1142  *  PositionCascade (parameters)
1143  *
1144  *   Description:
1145  *   -----------
1146  *     This routine positions a cacading submenu pane.  When the new
1147  *     menupane is posted, it will slightly overlap the previous menu
1148  *     pane (in the x direction).  In the y direction, the new menupane
1149  *     will be positioned such that its first menubutton is centered on
1150  *     the menubutton to which the menupane is attached.
1151  *
1152  *
1153  *   Inputs:
1154  *   ------
1155  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1156  *
1157  *   Outputs:
1158  *   -------
1159  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1160  *
1161  *   Procedures Called
1162  *   -----------------
1163  *
1164  *************************************<->***********************************/
1165 
PositionCascade(menubutton,menupane)1166 static void PositionCascade (menubutton, menupane)
1167 
1168    register Widget          menubutton;
1169             XwManagerWidget menupane;
1170 
1171 {
1172    Position x, y, yDelta;
1173    Widget menubuttonGrandparent;
1174    Widget menubuttonParent;
1175    Widget menupaneShell;
1176 
1177    menubuttonParent = (Widget)XtParent(menubutton);
1178    menubuttonGrandparent = (Widget)XtParent(menubuttonParent);
1179    menupaneShell = (Widget)XtParent(menupane);
1180 
1181    /*
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.
1186     */
1187    if (!XtIsRealized (menupaneShell))
1188       XtRealizeWidget (menupaneShell);
1189 
1190    /*
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.
1193     */
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);
1199 
1200    y = menubuttonGrandparent->core.y +
1201        menubuttonParent->core.border_width +
1202        menubutton->core.border_width +
1203        menubutton->core.y +
1204        (menubutton->core.height >> 1);
1205 
1206    /* Attempt to center on the first button in the new menupane */
1207    if (menupane->manager.num_managed_children > 0)
1208    {
1209       Widget firstButton = menupane->manager.managed_children[0];
1210 /*
1211       yDelta = firstButton->core.y +
1212                firstButton->core.border_width +
1213                (firstButton->core.height >> 1);
1214 */
1215       yDelta = 0;
1216    }
1217    else
1218       yDelta = menupane->core.border_width + (menupane->core.height >> 1);
1219 
1220    y -= yDelta;
1221 
1222    ForceMenuPaneOnScreen (menupane, &x, &y);
1223 
1224    XtMoveWidget (menupaneShell, x, y);
1225 }
1226 
1227 
1228 /*************************************<->*************************************
1229  *
1230  *  ExposeEventHandler (parameters)
1231  *
1232  *   Description:
1233  *   -----------
1234  *     xxxxxxxxxxxxxxxxxxxxxxx
1235  *
1236  *
1237  *   Inputs:
1238  *   ------
1239  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1240  *
1241  *   Outputs:
1242  *   -------
1243  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1244  *
1245  *   Procedures Called
1246  *   -----------------
1247  *
1248  *************************************<->***********************************/
1249 
ExposeEventHandler(w,menuMgr,event)1250 static void ExposeEventHandler (w, menuMgr, event)
1251 
1252    Widget w;
1253    register XwPopupMgrWidget menuMgr;
1254    XEvent * event;
1255 
1256 {
1257    register int i;
1258 
1259    /*
1260     * If the children inherit the menu tree, then set up grabs for
1261     * the post button, the post accelerator key, and each menubutton
1262     * accelerator.
1263     */
1264    if (menuMgr->menu_mgr.associateChildren)
1265    {
1266       if (menuMgr->menu_mgr.postString)
1267       {
1268          XGrabButton (XtDisplay(menuMgr), menuMgr->menu_mgr.postButton,
1269                       (menuMgr->menu_mgr.postModifiers & ~btnMask),
1270                       XtWindow(w), False,
1271                       ButtonPressMask|ButtonReleaseMask,
1272                       GrabModeAsync, GrabModeAsync, (Window)NULL, (Cursor)NULL);
1273       }
1274 
1275       if (menuMgr->popup_mgr.postAccelerator)
1276       {
1277          XGrabKey (XtDisplay(menuMgr), menuMgr->popup_mgr.accelKey,
1278                    menuMgr->popup_mgr.accelModifiers, XtWindow(w),
1279                    False, GrabModeAsync, GrabModeAsync);
1280       }
1281 
1282       for (i = 0; i < menuMgr->menu_mgr.numAccels; i++)
1283       {
1284          XGrabKey (XtDisplay(menuMgr),
1285                    menuMgr->menu_mgr.menuBtnAccelTable[i].accelKey,
1286                    menuMgr->menu_mgr.menuBtnAccelTable[i].accelModifiers,
1287                    XtWindow(w), False, GrabModeAsync, GrabModeAsync);
1288       }
1289    }
1290 
1291    XtRemoveEventHandler (w, ExposureMask|StructureNotifyMask, False,
1292                          (XtEventHandler)ExposeEventHandler, menuMgr);
1293 }
1294 
1295 
1296 /*************************************<->*************************************
1297  *
1298  *  _XwCascadeSelect(parameters)
1299  *
1300  *   Description:
1301  *   -----------
1302  *     xxxxxxxxxxxxxxxxxxxxxxx
1303  *
1304  *
1305  *   Inputs:
1306  *   ------
1307  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1308  *
1309  *   Outputs:
1310  *   -------
1311  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1312  *
1313  *   Procedures Called
1314  *   -----------------
1315  *
1316  *************************************<->***********************************/
1317 
_XwCascadeSelect(menubutton,menupane,data)1318 static void _XwCascadeSelect (menubutton, menupane, data)
1319 
1320    Widget menubutton;
1321    XwMenuPaneWidget  menupane;
1322    caddr_t data;       /* not used */
1323 
1324 {
1325    register int i;
1326    register XwPopupMgrWidget menuMgr;
1327 
1328    menuMgr = (XwPopupMgrWidget) XtParent(XtParent(menupane));
1329 
1330    /* If the pane is already posted, then do nothing but return */
1331    for (i = 0; i < menuMgr->popup_mgr.numCascades; i++)
1332    {
1333       if (menupane==(XwMenuPaneWidget)menuMgr->popup_mgr.currentCascadeList[i])
1334          return;
1335    }
1336 
1337    /* Position the cascading menupane */
1338    PositionCascade (menubutton, menupane);
1339 
1340    /* Post the menupane */
1341    Post (menuMgr, menupane, XtGrabNonexclusive);
1342 
1343    /* Set the traversal focus, if necessary */
1344    if (menuMgr->manager.traversal_on)
1345    {
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);
1351    }
1352    XFlush(XtDisplay(menuMgr));
1353 }
1354 
1355 
1356 /*************************************<->*************************************
1357  *
1358  *  _XwCascadeUnselect (parameters)
1359  *
1360  *   Description:
1361  *   -----------
1362  *     xxxxxxxxxxxxxxxxxxxxxxx
1363  *
1364  *
1365  *   Inputs:
1366  *   ------
1367  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1368  *
1369  *   Outputs:
1370  *   -------
1371  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1372  *
1373  *   Procedures Called
1374  *   -----------------
1375  *
1376  *************************************<->***********************************/
1377 
_XwCascadeUnselect(menubutton,menupane,params)1378 static void _XwCascadeUnselect (menubutton, menupane, params)
1379 
1380    Widget menubutton;
1381    Widget menupane;
1382    register XwunselectParams * params;
1383 
1384 {
1385    XwPopupMgrWidget menuMgr;
1386    register Widget shell;
1387 
1388    menuMgr = (XwPopupMgrWidget) XtParent(XtParent(menupane));
1389    shell = (Widget)XtParent(menupane);
1390 
1391    /*
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.
1396     *
1397     */
1398 
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))))
1404    {
1405       /* Yes, we're in the cascading menupane */
1406       params->remainHighlighted = TRUE;
1407    }
1408    else
1409    {
1410       /* No, we've left the cascade region; unpost the menupane */
1411       Unpost (menuMgr, menupane);
1412       params->remainHighlighted = FALSE;
1413    }
1414 }
1415 
1416 
1417 /*************************************<->*************************************
1418  *
1419  *  _XwMenuPaneCleanup (parameters)
1420  *
1421  *   Description:
1422  *   -----------
1423  *     xxxxxxxxxxxxxxxxxxxxxxx
1424  *
1425  *
1426  *   Inputs:
1427  *   ------
1428  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1429  *
1430  *   Outputs:
1431  *   -------
1432  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1433  *
1434  *   Procedures Called
1435  *   -----------------
1436  *
1437  *************************************<->***********************************/
1438 
_XwMenuPaneCleanup(menupane,menuMgr,data)1439 static void _XwMenuPaneCleanup (menupane, menuMgr, data)
1440 
1441    XwMenuPaneWidget menupane;
1442    Widget menuMgr;
1443    caddr_t data;   /* not used */
1444 
1445 {
1446    /*
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.
1450     */
1451    if (menupane->menu_pane.attach_to)
1452    {
1453       if (menupane->menu_pane.attachId == NULL)
1454          DetachPane (menuMgr, menupane, menupane->menu_pane.attach_to);
1455       else
1456          DoDetach (menuMgr, menupane->menu_pane.attachId, menupane);
1457    }
1458 }
1459 
1460 
1461 /*************************************<->*************************************
1462  *
1463  *  _XwMenuButtonCleanup(parameters)
1464  *
1465  *   Description:
1466  *   -----------
1467  *     xxxxxxxxxxxxxxxxxxxxxxx
1468  *
1469  *
1470  *   Inputs:
1471  *   ------
1472  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1473  *
1474  *   Outputs:
1475  *   -------
1476  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1477  *
1478  *   Procedures Called
1479  *   -----------------
1480  *
1481  *************************************<->***********************************/
1482 
_XwMenuButtonCleanup(menubutton,menuMgr,data)1483 static void _XwMenuButtonCleanup (menubutton, menuMgr, data)
1484 
1485    Widget menubutton;
1486    XwPopupMgrWidget menuMgr;
1487    caddr_t data;   /* not used */
1488 
1489 {
1490    Arg arg[1];
1491    XwMenuPaneWidget cascadeOn;
1492 
1493    /*
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.
1497     */
1498    ClearSelectAccelerator (menuMgr, menubutton);
1499 
1500    XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &cascadeOn);
1501    XtGetValues (menubutton, arg, 1);
1502 
1503    if (cascadeOn != NULL)
1504    {
1505       /* Detach, and add back into pending attach list */
1506       DoDetach (menuMgr, menubutton, cascadeOn);
1507       AddToPendingList (menuMgr, cascadeOn, cascadeOn->menu_pane.attach_to);
1508    }
1509 
1510    /*
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.
1514     */
1515    if ((menuMgr->popup_mgr.stickyMode) &&
1516        (menuMgr->popup_mgr.numSavedCascades > 0) &&
1517        (menuMgr->popup_mgr.lastSelected == menubutton->core.self))
1518    {
1519       menuMgr->popup_mgr.numSavedCascades = 0;
1520    }
1521 }
1522 
1523 
1524 /*************************************<->*************************************
1525  *
1526  *  MMPost(parameters)
1527  *
1528  *   Description:
1529  *   -----------
1530  *     xxxxxxxxxxxxxxxxxxxxxxx
1531  *
1532  *
1533  *   Inputs:
1534  *   ------
1535  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1536  *
1537  *   Outputs:
1538  *   -------
1539  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1540  *
1541  *   Procedures Called
1542  *   -----------------
1543  *
1544  *************************************<->***********************************/
1545 
MMPost(w,event,params,count)1546 static void MMPost (w, event, params, count)
1547 
1548    Widget w;
1549    XEvent * event;
1550    String * params;
1551    Cardinal count;
1552 
1553 {
1554    XwPopupMgrWidget menuMgr;
1555 
1556    /* Extract the menu manager widget id */
1557    menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1558 
1559    /*
1560     * If we have made it down here, then we know the post event is
1561     * ours to handle.
1562     */
1563    if ((menuMgr) && (menuMgr->popup_mgr.topLevelPane))
1564       ClassPost (menuMgr, event, TRUE);
1565 }
1566 
1567 
1568 /*************************************<->*************************************
1569  *
1570  *  MMUnpost(parameters)
1571  *
1572  *   Description:
1573  *   -----------
1574  *     xxxxxxxxxxxxxxxxxxxxxxx
1575  *
1576  *
1577  *   Inputs:
1578  *   ------
1579  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1580  *
1581  *   Outputs:
1582  *   -------
1583  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1584  *
1585  *   Procedures Called
1586  *   -----------------
1587  *
1588  *************************************<->***********************************/
1589 
MMUnpost(w,event,params,count)1590 static void MMUnpost (w, event, params, count)
1591 
1592    Widget w;
1593    XEvent * event;
1594    String * params;
1595    Cardinal count;
1596 
1597 {
1598    register XwPopupMgrWidget menuMgr;
1599    Boolean traversalOn;
1600 
1601    /* Extract the menu manager widget id */
1602    menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1603 
1604    /*
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.
1608     */
1609    traversalOn = menuMgr->manager.traversal_on;
1610 
1611    if ((menuMgr) && (menuMgr->menu_mgr.menuActive))
1612    {
1613       /*
1614        * Unpost the menu.
1615        * To prevent undesirable side effects, the menuActive flag must
1616        * always be cleared before bring down the menu system.
1617        */
1618       menuMgr->menu_mgr.menuActive = FALSE;
1619       Unpost (menuMgr, menuMgr->popup_mgr.topLevelPane);
1620       XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
1621 
1622       /*
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.
1626        */
1627       if (traversalOn && (menuMgr->popup_mgr.numSavedCascades == 0))
1628       {
1629          ((XwPopupMgrWidget)menuMgr->popup_mgr.topLevelPane)->
1630                           manager.active_child = NULL;
1631          XtSetKeyboardFocus (menuMgr->popup_mgr.topLevelPane, NULL);
1632       }
1633 
1634       /*
1635        * If we warped the mouse because traversal was on, then we need
1636        * to move it back to where it was.
1637        */
1638       if (traversalOn &&
1639           (menuMgr->popup_mgr.origMouseX != -1) &&
1640           (menuMgr->popup_mgr.origMouseY != -1))
1641       {
1642 	 XWarpPointer (XtDisplay (menuMgr), None,
1643 		       RootWindowOfScreen(menuMgr->core.screen),
1644 		       0, 0, 0, 0,
1645                        menuMgr->popup_mgr.origMouseX,
1646                        menuMgr->popup_mgr.origMouseY);
1647          menuMgr->popup_mgr.origMouseX = -1;
1648          menuMgr->popup_mgr.origMouseY = -1;
1649       }
1650    }
1651 }
1652 
1653 
1654 /*************************************<->*************************************
1655  *
1656  *  MMAccelPost (parameters)
1657  *
1658  *   Description:
1659  *   -----------
1660  *     xxxxxxxxxxxxxxxxxxxxxxx
1661  *
1662  *
1663  *   Inputs:
1664  *   ------
1665  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1666  *
1667  *   Outputs:
1668  *   -------
1669  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1670  *
1671  *   Procedures Called
1672  *   -----------------
1673  *
1674  *************************************<->***********************************/
1675 
MMAccelPost(w,event,params,count)1676 static void MMAccelPost (w, event, params, count)
1677 
1678    Widget w;
1679    XEvent * event;
1680    String * params;
1681    Cardinal count;
1682 
1683 {
1684    register XwPopupMgrWidget menuMgr;
1685 
1686    /* Extract the menu manager widget id */
1687    menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1688 
1689    /*
1690     * If we have made it down here, then we know the accelerator event is
1691     * ours to handle.
1692     */
1693    if ((menuMgr) && (menuMgr->popup_mgr.topLevelPane))
1694       ClassPost (menuMgr, event, FALSE);
1695 }
1696 
1697 
1698 /*************************************<->*************************************
1699  *
1700  *  MMAccelSelect (parameters)
1701  *
1702  *   Description:
1703  *   -----------
1704  *     xxxxxxxxxxxxxxxxxxxxxxx
1705  *
1706  *
1707  *   Inputs:
1708  *   ------
1709  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1710  *
1711  *   Outputs:
1712  *   -------
1713  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
1714  *
1715  *   Procedures Called
1716  *   -----------------
1717  *
1718  *************************************<->***********************************/
1719 
MMAccelSelect(w,event,params,count)1720 static void MMAccelSelect (w, event, params, count)
1721 
1722    Widget w;
1723    XEvent * event;
1724    String * params;
1725    Cardinal count;
1726 
1727 {
1728    register XwPopupMgrWidget menuMgr;
1729 
1730    /* Extract the menu manager widget id */
1731    menuMgr = (XwPopupMgrWidget) _XwMapFromHex (params[0]);
1732 
1733    if (menuMgr == NULL)
1734       return;
1735 
1736    /*
1737     * if menus are not inherited, throw out events that did occur
1738     * in the associated widget's children.  This takes care of the case
1739     * where the child does not select for key events, so they propagate
1740     * to us.
1741     */
1742    if (menuMgr->menu_mgr.associateChildren == FALSE)
1743    {
1744       if ((event->xkey.window == XtWindow (XtParent (XtParent (menuMgr)))) &&
1745           (event->xkey.subwindow != 0) &&
1746           (XtWindowToWidget (XtDisplay (menuMgr), event->xkey.subwindow)))
1747       return;
1748    }
1749 
1750    /*
1751     * If we have made it down here, then we know the accelerator event is
1752     * ours to handle.
1753     */
1754    if (menuMgr->popup_mgr.topLevelPane)
1755       ClassSelect ((XwMenuMgrWidget)menuMgr, event);
1756 }
1757 
1758 
1759 /*************************************<->*************************************
1760  *
1761  *   AttachPane(menuMgr, menupane, name)
1762  *
1763  *   Description:
1764  *   -----------
1765  *
1766  *
1767  *   Inputs:
1768  *   ------
1769  *
1770  *
1771  *   Outputs:
1772  *   -------
1773  *
1774  *
1775  *   Procedures Called
1776  *   -----------------
1777  *
1778  *************************************<->***********************************/
1779 
AttachPane(menuMgr,menupane,name)1780 static void AttachPane (menuMgr, menupane, name)
1781 
1782    register XwPopupMgrWidget   menuMgr;
1783    register XwMenuPaneWidget   menupane;
1784    String             name;
1785 
1786 {
1787    register XwMenuButtonWidget menubutton;
1788    Arg arg[1];
1789    register int i, j;
1790    CompositeWidget shell, mpane;
1791    XrmName nameQuark;
1792 
1793    if (name == NULL)
1794       return;
1795 
1796    /*
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.
1800     */
1801    menuMgr->popup_mgr.attachPane = menupane;
1802 
1803    /*
1804     * check if name is menu manager's name, then this is to be a top level
1805     */
1806    if ((strcmp (name, menuMgr->core.name) == 0) &&
1807        (XwStrlen(name) == XwStrlen(menuMgr->core.name)))
1808    {
1809       /* Remove the cascade list when the top level pane changes */
1810       menuMgr->popup_mgr.numSavedCascades = 0;
1811 
1812       if (menuMgr->popup_mgr.topLevelPane != NULL)
1813       {
1814          /* Detach the previous top level pane */
1815          XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
1816          XtSetValues (menuMgr->popup_mgr.topLevelPane, arg, 1);
1817       }
1818 
1819       /*
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.
1823        */
1824       menuMgr->popup_mgr.topLevelPane = menupane->core.self;
1825       menupane->menu_pane.attachId = NULL;
1826 
1827       SetTreeAccelerators (menuMgr, menupane);
1828    }
1829    else
1830    {
1831       /*
1832        * check if its a menubutton name in the menu system.
1833        */
1834       nameQuark = XrmStringToQuark(name);
1835 
1836       for (i = 0; i < menuMgr->core.num_popups; i++)
1837       {
1838 	 /*
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
1841 	  */
1842 	 shell = (CompositeWidget) menuMgr->core.popup_list[i];
1843 	 if ((shell->composite.num_children == 1) &&
1844 	     (XtIsSubclass(shell->composite.children[0],
1845 			   XwmenupaneWidgetClass)))
1846 	 {
1847             mpane = (CompositeWidget) shell->composite.children[0];
1848             for (j = 0; j < mpane->composite.num_children; j++)
1849 	    {
1850                menubutton = (XwMenuButtonWidget)mpane->composite.children[j];
1851                if (menubutton->core.xrm_name == nameQuark)
1852                {
1853 		  Widget dwidget = NULL;
1854                   /*
1855                    * If there is a menupane already attached to this
1856                    * button, then we need to first detach it.
1857                    */
1858 	          XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &dwidget);
1859 	          XtGetValues ((Widget)menubutton, arg, 1);
1860                   if (dwidget)
1861                   {
1862                      /* Detach the old pane */
1863                      Widget temppane = dwidget;
1864                      XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
1865                      XtSetValues (temppane, arg, 1);
1866                   }
1867 
1868 	          XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) menupane->core.self);
1869 	          XtSetValues ((Widget)menubutton, arg, 1);
1870 
1871    	          menupane->menu_pane.attachId = (Widget) menubutton;
1872 
1873 	          XtAddCallback ((Widget) menubutton,
1874 			      XtNcascadeSelect,	(XtCallbackProc)_XwCascadeSelect,
1875                               menupane->core.self);
1876 
1877 	          XtAddCallback ((Widget) menubutton,
1878 			      XtNcascadeUnselect, (XtCallbackProc)_XwCascadeUnselect,
1879 			      menupane->core.self);
1880 
1881 	          if (CompletePath(menuMgr, menupane))
1882 		      SetTreeAccelerators (menuMgr, menupane);
1883 
1884                   menuMgr->popup_mgr.attachPane = NULL;
1885 	          return;
1886                }
1887 	    }
1888 	 }
1889       }
1890       /*
1891        * Couldn't find a menubutton with this name
1892        */
1893       AddToPendingList (menuMgr, menupane, name);
1894    }
1895 
1896    /* This always needs to be cleared out when we are done */
1897    menuMgr->popup_mgr.attachPane = NULL;
1898 }
1899 
1900 /*************************************<->*************************************
1901  *
1902  *   DetachPane (menuMgr, menupane, name)
1903  *
1904  *   Description:
1905  *   -----------
1906  *
1907  *
1908  *   Inputs:
1909  *   ------
1910  *
1911  *
1912  *   Outputs:
1913  *   -------
1914  *
1915  *
1916  *   Procedures Called
1917  *   -----------------
1918  *
1919  *************************************<->***********************************/
1920 
DetachPane(menuMgr,menupane,name)1921 static void DetachPane (menuMgr, menupane, name)
1922 
1923    register XwPopupMgrWidget   menuMgr;
1924    XwMenuPaneWidget  menupane;
1925    String            name;
1926 
1927 {
1928    register int i;
1929    Arg arg;
1930    XwMenuButtonWidget menubutton;
1931    CompositeWidget shell;
1932 
1933    if (name == NULL)
1934       return;
1935 
1936    /*
1937     * if menupane is on the pending attach list, remove it and return
1938     */
1939    for (i=0; i < menuMgr->menu_mgr.numAttachReqs; i++)
1940    {
1941       if (menuMgr->menu_mgr.pendingAttachList[i].menupaneId ==
1942 	  menupane->core.self)
1943       {
1944 	 menuMgr->menu_mgr.pendingAttachList[i] =
1945 	    menuMgr->menu_mgr.pendingAttachList
1946 	       [--menuMgr->menu_mgr.numAttachReqs];
1947 	 return;
1948       }
1949    }
1950 
1951    /*
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.
1955     */
1956    menuMgr->popup_mgr.detachPane = menupane;
1957 
1958    /*
1959     * if name is the menu manager's name, removing top level
1960     */
1961    if ((strcmp (name, menuMgr->core.name) == 0) &&
1962        (XwStrlen(name) == XwStrlen(menuMgr->core.name)))
1963    {
1964       menupane->menu_pane.attachId = (Widget) NULL;
1965 
1966       if (menupane->core.self == menuMgr->popup_mgr.topLevelPane)
1967       {
1968 	 ClearTreeAccelerators (menuMgr, menupane->core.self);
1969 	 menuMgr->popup_mgr.topLevelPane = NULL;
1970       }
1971    }
1972    else
1973    {
1974       /*
1975        * detach pane from menubutton.  Look on each of the menu managers
1976        * popup children for a menupane which contains this named menubutton.
1977        */
1978       for (i = 0; i < menuMgr->core.num_popups; i++)
1979       {
1980 	 shell = (CompositeWidget) menuMgr->core.popup_list[i];
1981 	 if ((shell->composite.num_children == 1) &&
1982 	     (XtIsSubclass(shell->composite.children[0],
1983 			   XwmenupaneWidgetClass)))
1984 	 {
1985 	    if ((menubutton = (XwMenuButtonWidget)
1986 		 XtNameToWidget(shell->composite.children[0], name))
1987 		!= NULL)
1988 	    {
1989 	       /*
1990 		* Found it!  Detach it
1991 		*/
1992                DoDetach (menuMgr, menubutton, menupane);
1993                menuMgr->popup_mgr.detachPane = NULL;
1994 	       return;
1995 	    }
1996 	 }
1997       }
1998    }
1999 
2000    /* This must always be cleared when we leave */
2001    menuMgr->popup_mgr.detachPane = NULL;
2002 }
2003 
2004 
2005 /*************************************<->*************************************
2006  *
2007  *  DoDetach(parameters)
2008  *
2009  *   Description:
2010  *   -----------
2011  *     This routine does the actual work of detaching a menupane from a
2012  *     menubutton.  It has been separated out from DetachPane() due to
2013  *     a BUG in the X toolkits destroy scenario.  When the toolkit is
2014  *     destroying popup children, it replaces the widget Id entry within
2015  *     the popup list with the window Id for that widget.  DetachPane()
2016  *     attempts to traverse this list, looking for the named menubutton.
2017  *     Unfortunately, if this list contains any window Ids, then we may
2018  *     get a core dump; this only can happen when the menu is being
2019  *     destroyed.
2020  *
2021  *
2022  *   Inputs:
2023  *   ------
2024  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2025  *
2026  *   Outputs:
2027  *   -------
2028  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
2029  *
2030  *   Procedures Called
2031  *   -----------------
2032  *
2033  *************************************<->***********************************/
2034 
DoDetach(menuMgr,menubutton,menupane)2035 static void DoDetach (menuMgr, menubutton, menupane)
2036 
2037    register XwPopupMgrWidget   menuMgr;
2038    XwMenuButtonWidget menubutton;
2039    XwMenuPaneWidget   menupane;
2040 
2041 {
2042    Arg arg[1];
2043    register int i;
2044 
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);
2051 
2052    XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) NULL);
2053    XtSetValues ((Widget)menubutton, arg, 1);
2054    menupane->menu_pane.attachId = NULL;
2055 
2056    /*
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.
2060     */
2061    if ((menuMgr->popup_mgr.stickyMode) &&
2062        (menuMgr->popup_mgr.numSavedCascades > 0))
2063    {
2064       for (i = 0; i < menuMgr->popup_mgr.numSavedCascades; i++)
2065       {
2066          if (menuMgr->popup_mgr.savedCascadeList[i] ==
2067             (Widget)menupane->core.self)
2068          {
2069             menuMgr->popup_mgr.numSavedCascades = 0;
2070             break;
2071          }
2072       }
2073    }
2074 }
2075 
2076 
2077 /*************************************<->*************************************
2078  *
2079  *   AddPane(menuMgr, menupane)
2080  *
2081  *   Description:
2082  *   -----------
2083  *
2084  *
2085  *   Inputs:
2086  *   ------
2087  *
2088  *
2089  *   Outputs:
2090  *   -------
2091  *
2092  *
2093  *   Procedures Called
2094  *   -----------------
2095  *
2096  *************************************<->***********************************/
2097 
AddPane(menuMgr,menupane)2098 static void AddPane (menuMgr, menupane)
2099 
2100    register XwMenuMgrWidget  menuMgr;
2101    XwMenuPaneWidget menupane;
2102 
2103 {
2104    register int k;
2105    register int traversalType;
2106    register XwMenuButtonWidget mbutton;
2107 
2108    XtAddCallback ((Widget)menupane, XtNdestroyCallback,
2109 	(XtCallbackProc)_XwMenuPaneCleanup, menuMgr);
2110 
2111    if (menuMgr->menu_mgr.selectString)
2112    {
2113       SetUpTranslation (menupane, menuMgr->menu_mgr.selectString,
2114                         selectTemplate);
2115    }
2116 
2117    if (menuMgr->menu_mgr.unpostString)
2118    {
2119       RegisterTranslation (menupane, menuMgr->menu_mgr.unpostString,
2120                            unpostTemplate, menuMgr);
2121    }
2122 
2123    if (menuMgr->menu_mgr.kbdSelectString)
2124    {
2125       SetUpTranslation (menupane, menuMgr->menu_mgr.kbdSelectString,
2126                         selectTemplate);
2127    }
2128 
2129    /* Propogate the state of our traversal flag */
2130    if (XtIsSubclass ((Widget)menupane, XwmenupaneWidgetClass))
2131    {
2132        (*(((XwMenuPaneWidgetClass)
2133 	XtClass(menupane))-> menu_pane_class.setTraversalFlag))
2134          ((Widget)menupane, menuMgr->manager.traversal_on);
2135    }
2136 
2137    /******************
2138     * THE FOLLOWING IS NOT NEEDED, SINCE A MENUPANE CAN NEVER HAVE
2139     * ANY CHILDREN AT THIS TIME.
2140     *
2141     * traversalType = (menuMgr->manager.traversal_on) ? XwHIGHLIGHT_TRAVERSAL:
2142     *                                                   XwHIGHLIGHT_OFF;
2143     *
2144     * for (k = 0; k < menupane->manager.num_managed_children; k++)
2145     * {
2146     *    /* Here we set the traversal flag for the menubuttons
2147     *    mbutton = (XwMenuButtonWidget)menupane->composite.children[k];
2148     *    if (XtIsSubclass (mbutton, XwmenubuttonWidgetClass))
2149     *    {
2150     *       (*(((XwMenuButtonWidgetClass)
2151     *         XtClass(mbutton))-> menubutton_class.setTraversalType))
2152     *          (mbutton, traversalType);
2153     *    }
2154     * }
2155     *********************/
2156 }
2157 
2158 /*************************************<->*************************************
2159  *
2160  *   SetSelectAccelerator (menuMgr, menubutton, accelString, accelEventType,
2161  *	  	           accelKey, accelModifiers)
2162  *
2163  *   Description:
2164  *   -----------
2165  *
2166  *
2167  *   Inputs:
2168  *   ------
2169  *
2170  *
2171  *   Outputs:
2172  *   -------
2173  *
2174  *
2175  *   Procedures Called
2176  *   -----------------
2177  *
2178  *************************************<->***********************************/
2179 
SetSelectAccelerator(menuMgr,menubutton,accelString,accelEventType,accelKey,accelModifiers)2180 static void SetSelectAccelerator (menuMgr, menubutton, accelString,
2181 				  accelEventType, accelKey, accelModifiers)
2182 Widget       menuMgr;
2183 Widget       menubutton;
2184 String       accelString;
2185 unsigned int accelEventType;
2186 unsigned int accelKey;
2187 unsigned int accelModifiers;
2188 {
2189    Widget widget;
2190    XwKeyAccel * tempAccel;
2191 
2192    if (CompletePath(menuMgr, menubutton->core.parent))
2193    {
2194       ClearSelectAccelerator (menuMgr, menubutton->core.self);
2195       SetButtonAccelerators (menuMgr, menubutton->core.self, accelString,
2196                              accelEventType, accelKey, accelModifiers);
2197    }
2198 }
2199 
2200 
2201 /*************************************<->*************************************
2202  *
2203  *   ClearSelectAccelerator (menuMgr, menubutton)
2204  *
2205  *   Description:
2206  *   -----------
2207  *
2208  *
2209  *   Inputs:
2210  *   ------
2211  *
2212  *
2213  *   Outputs:
2214  *   -------
2215  *
2216  *
2217  *   Procedures Called
2218  *   -----------------
2219  *
2220  *************************************<->***********************************/
2221 
ClearSelectAccelerator(menuMgr,menubutton)2222 static void ClearSelectAccelerator (menuMgr, menubutton)
2223 
2224    register XwPopupMgrWidget menuMgr;
2225    Widget menubutton;
2226 
2227 {
2228    register int i;
2229    Widget widget;
2230 
2231    /*
2232     * search accelerator table for menubutton
2233     */
2234    for (i=0; i < menuMgr->menu_mgr.numAccels; i++)
2235    {
2236       if (menuMgr->menu_mgr.menuBtnAccelTable[i].menuBtn ==
2237             menubutton->core.self)
2238       {
2239 	 /*
2240 	  * remove translation in associated widget & toplevel pane
2241 	  * and remove grab
2242 	  */
2243 	 widget = (Widget) XtParent (XtParent (menuMgr));
2244 	 RegisterTranslation (widget,
2245 		    menuMgr->menu_mgr.menuBtnAccelTable[i].accelString,
2246 		    accelSelectTemplate, NULL);
2247 
2248 	 if (menuMgr->popup_mgr.topLevelPane)
2249          {
2250 	    RegisterTranslation (menuMgr->popup_mgr.topLevelPane,
2251 			menuMgr->menu_mgr.menuBtnAccelTable[i].accelString,
2252 			accelSelectTemplate, NULL);
2253 
2254             /*
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.
2258              */
2259             if ((menuMgr->popup_mgr.detachPane) &&
2260                (menuMgr->popup_mgr.topLevelPane ==
2261                 menuMgr->popup_mgr.detachPane->core.self))
2262             {
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;
2267             }
2268          }
2269 
2270 	 if ((menuMgr->menu_mgr.associateChildren) &&
2271 	     (XtIsRealized (widget)))
2272          {
2273 	    XUngrabKey (XtDisplay (widget),
2274 		menuMgr->menu_mgr.menuBtnAccelTable[i].accelKey,
2275 		menuMgr->menu_mgr.menuBtnAccelTable[i].accelModifiers,
2276 		XtWindow (widget));
2277          }
2278 
2279 	 /*
2280 	  * remove menubutton accelerator table entry
2281 	  */
2282 	 menuMgr->menu_mgr.menuBtnAccelTable[i] =
2283 	    menuMgr->menu_mgr.menuBtnAccelTable[--menuMgr->menu_mgr.numAccels];
2284 
2285 	 return;
2286       }
2287    }
2288 }
2289 
2290 /*************************************<->*************************************
2291  *
2292  *   AddButton(menuMgr, menubutton)
2293  *
2294  *   Description:
2295  *   -----------
2296  *
2297  *
2298  *   Inputs:
2299  *   ------
2300  *
2301  *
2302  *   Outputs:
2303  *   -------
2304  *
2305  *
2306  *   Procedures Called
2307  *   -----------------
2308  *
2309  *************************************<->***********************************/
2310 
AddButton(menuMgr,menubutton)2311 static void AddButton (menuMgr, menubutton)
2312 
2313    register XwMenuMgrWidget  menuMgr;
2314    register Widget  menubutton;
2315 
2316 {
2317    Arg args[2];
2318    Widget pending;
2319    int traversalType;
2320 
2321    if (menuMgr->menu_mgr.selectString)
2322    {
2323       SetUpTranslation (menubutton, menuMgr->menu_mgr.selectString,
2324                         selectTemplate);
2325    }
2326    if (menuMgr->menu_mgr.unpostString)
2327    {
2328       RegisterTranslation (menubutton, menuMgr->menu_mgr.unpostString,
2329                            unpostTemplate, menuMgr);
2330    }
2331    if (menuMgr->menu_mgr.kbdSelectString)
2332    {
2333       SetUpTranslation (menubutton, menuMgr->menu_mgr.kbdSelectString,
2334                         selectTemplate);
2335    }
2336 
2337    XtSetArg (args[0], XtNcascadeOn, (XtArgVal) NULL);
2338    XtSetArg (args[1], XtNmgrOverrideMnemonic, (XtArgVal) TRUE);
2339    XtSetValues (menubutton, args, XtNumber(args));
2340 
2341    XtAddCallback (menubutton, XtNdestroyCallback,
2342 		  (XtCallbackProc)_XwMenuButtonCleanup, menuMgr);
2343 
2344    /*
2345     * Accelerators are now handled when the button is managed!
2346     */
2347 
2348    /*
2349     * if this menubutton is on the pending attach list, do attach
2350     */
2351    if (pending = PendingAttach (menuMgr, menubutton))
2352        AttachPane (menuMgr, pending, menubutton->core.name);
2353 
2354    /* Propogate the our traversal state */
2355    traversalType = (menuMgr->manager.traversal_on) ? XwHIGHLIGHT_TRAVERSAL:
2356                                                      XwHIGHLIGHT_OFF;
2357 
2358    if (XtIsSubclass (menubutton, XwmenubuttonWidgetClass))
2359    {
2360       (*(((XwMenuButtonWidgetClass)
2361         XtClass(menubutton))-> menubutton_class.setTraversalType))
2362         (menubutton, traversalType);
2363    }
2364 }
2365 
2366 /*************************************<->*************************************
2367  *
2368  *   Unpost (menuMgr, menupane)
2369  *
2370  *   Description:
2371  *   -----------
2372  *
2373  *
2374  *   Inputs:
2375  *   ------
2376  *
2377  *
2378  *   Outputs:
2379  *   -------
2380  *
2381  *
2382  *   Procedures Called
2383  *   -----------------
2384  *
2385  *************************************<->***********************************/
2386 
Unpost(menuMgr,menupane)2387 static void Unpost (menuMgr, menupane)
2388 
2389    register XwPopupMgrWidget  menuMgr;
2390    XwMenuPaneWidget  menupane;
2391 
2392 {
2393    register int i,j;
2394    register XwMenuPaneWidget pane;
2395    register Widget * currentCascadeList;
2396    register WidgetList managed_children;
2397 
2398    /*
2399     * To keep all window managers happy, move the focus before we pop
2400     * down the menupane with the current focus.
2401     */
2402    if ((menupane != (XwMenuPaneWidget) menuMgr->popup_mgr.topLevelPane) &&
2403        (menuMgr->manager.traversal_on))
2404    {
2405       XwMoveFocus (XtParent(menupane->menu_pane.attachId));
2406    }
2407 
2408    currentCascadeList = menuMgr->popup_mgr.currentCascadeList;
2409 
2410    /*
2411     * popdown any cascading submenus including menupane
2412     */
2413    for (i = menuMgr->popup_mgr.numCascades - 1; i >= 0; i--)
2414    {
2415       /*
2416        * for each button in pane, unhighlight it and clear cascade flag
2417        */
2418       pane = ((XwMenuPaneWidget) currentCascadeList[i]);
2419       XtRemoveGrab ((Widget)pane);
2420       XtPopdown (XtParent (pane));
2421       managed_children = pane->manager.managed_children;
2422 
2423       for (j = 0; j < pane->manager.num_managed_children; j++)
2424       {
2425 	 if (XtIsSubclass (managed_children[j], XwmenubuttonWidgetClass))
2426 	 {
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]);
2433 	 }
2434       }
2435 
2436       --menuMgr->popup_mgr.numCascades;
2437 
2438       /*
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.
2441        */
2442       if ((pane != menupane) && (i > 0))
2443       {
2444          if (menuMgr->manager.traversal_on == FALSE)
2445          {
2446             XtRemoveEventHandler (currentCascadeList[i-1],
2447                                   EnterWindowMask, FALSE,
2448 				  (XtEventHandler)
2449                                   ((XwMenuButtonWidgetClass)
2450                                    XtClass(pane->menu_pane.attachId))->
2451                                     menubutton_class.enterParentProc,
2452                                   pane->menu_pane.attachId);
2453          }
2454          else
2455          {
2456             /* Kludge to force the grablist to get cleaned up */
2457             XtSetKeyboardFocus (XtParent(pane), None);
2458          }
2459       }
2460       else
2461       {
2462          if (menuMgr->manager.traversal_on)
2463          {
2464             /* Kludge to force the grablist to get cleaned up */
2465             XtSetKeyboardFocus (XtParent(pane), None);
2466          }
2467          XFlush (XtDisplay(menuMgr));
2468          return;
2469       }
2470    }
2471 }
2472 
2473 /*************************************<->*************************************
2474  *
2475  *   Post(menuMgr, menupane, grabtype)
2476  *
2477  *   Description:
2478  *   -----------
2479  *
2480  *
2481  *   Inputs:
2482  *   ------
2483  *
2484  *
2485  *   Outputs:
2486  *   -------
2487  *
2488  *
2489  *   Procedures Called
2490  *   -----------------
2491  *
2492  *   _XtPopup
2493  *
2494  *************************************<->***********************************/
2495 
Post(menuMgr,menupane,grabtype)2496 static void Post (menuMgr, menupane, grabtype)
2497 
2498    register XwPopupMgrWidget  menuMgr;
2499    Widget  menupane;
2500    XtGrabKind grabtype;
2501 
2502 {
2503    register int i;
2504 
2505    /*
2506     * if already posted, do nothing
2507     */
2508    for (i=0; i < menuMgr->popup_mgr.numCascades; i++)
2509       if (menuMgr->popup_mgr.currentCascadeList[i] == menupane)
2510 	 return;
2511 
2512    /*
2513     * set up grabs
2514     */
2515    if (grabtype == XtGrabNonexclusive)
2516    {
2517       _XtPopup (XtParent (menupane), grabtype, FALSE);
2518       XtAddGrab (menupane, FALSE, FALSE);
2519    }
2520    else
2521    {
2522       _XtPopup (XtParent (menupane), grabtype, TRUE);
2523       XtAddGrab (menupane, TRUE, TRUE);
2524    }
2525 
2526    /*
2527     * add menupane to current cascade list
2528     */
2529    if (menuMgr->popup_mgr.numCascades == menuMgr->popup_mgr.sizeCascadeList)
2530    {
2531       menuMgr->popup_mgr.sizeCascadeList =
2532 	 2 * menuMgr->popup_mgr.sizeCascadeList;
2533       menuMgr->popup_mgr.currentCascadeList =
2534 	 (Widget *) XtRealloc((char *)(menuMgr->popup_mgr.currentCascadeList),
2535                               menuMgr->popup_mgr.sizeCascadeList *
2536 			      sizeof (Widget));
2537    }
2538 
2539    menuMgr->popup_mgr.currentCascadeList[menuMgr->popup_mgr.numCascades++] =
2540       menupane;
2541 }
2542 
2543 /*************************************<->*************************************
2544  *
2545  *   ProcessSelect(menuMgr, widget, event)
2546  *
2547  *   Description:
2548  *   -----------
2549  *
2550  *
2551  *   Inputs:
2552  *   ------
2553  *
2554  *
2555  *   Outputs:
2556  *   -------
2557  *
2558  *
2559  *   Procedures Called
2560  *   -----------------
2561  *
2562  *************************************<->***********************************/
2563 
ProcessSelect(menuMgr,widget,event)2564 static Boolean ProcessSelect (menuMgr, widget, event)
2565 
2566    register XwPopupMgrWidget  menuMgr;
2567    Widget            widget;
2568    XEvent          * event;
2569 
2570 {
2571    register XwKeyAccel * accelerator;
2572    register int i;
2573    Boolean found = FALSE;
2574    Widget assocWidget;
2575    Boolean traversalOn;
2576 
2577    /*
2578     * If the menu manager or the associated widget is insensitive, then
2579     * ignore the select request.
2580     */
2581    assocWidget = XtParent(XtParent(menuMgr));
2582    if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
2583       return (FALSE);
2584 
2585    /*
2586     * is this a valid button event?
2587     */
2588    if ((event->xany.type==ButtonPress) || (event->xany.type==ButtonRelease))
2589    {
2590 
2591       if (_XwMatchBtnEvent (event, menuMgr->menu_mgr.selectEventType,
2592 			    menuMgr->menu_mgr.selectButton,
2593 			    menuMgr->menu_mgr.selectModifiers))
2594       {
2595          if (menuMgr->menu_mgr.menuActive == FALSE)
2596 	    return (FALSE);
2597 
2598          /*
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.
2602           */
2603          if ((menuMgr->manager.traversal_on) &&
2604              (XtIsSubclass (widget, XwmenubuttonWidgetClass)) &&
2605              (XtParent(widget) != menuMgr->popup_mgr.currentCascadeList[
2606                                menuMgr->popup_mgr.numCascades - 1]))
2607          {
2608             return (FALSE);
2609          }
2610 
2611          SetUpStickyList (menuMgr, widget);
2612       }
2613       else
2614          return (FALSE);
2615    }
2616    /*
2617     * if its not key accelerator, return false
2618     */
2619    else if ((event->xany.type == KeyPress) || (event->xany.type == KeyRelease))
2620    {
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))
2626       {
2627          SetUpStickyList (menuMgr, widget);
2628       }
2629       else
2630       {
2631          for (i=0; (i < menuMgr->menu_mgr.numAccels) && (found == FALSE); i++)
2632          {
2633             accelerator = menuMgr->menu_mgr.menuBtnAccelTable + i;
2634 	    found = _XwMatchKeyEvent (event,
2635 		       accelerator->accelEventType,
2636 		       accelerator->accelKey,
2637 		       accelerator->accelModifiers);
2638          }
2639 
2640          if (found == FALSE)
2641 	    return (FALSE);
2642 
2643          menuMgr->popup_mgr.numSavedCascades = 0;
2644          if (menuMgr->manager.traversal_on)
2645          {
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);
2650          }
2651          /* SetUpStickyList (menuMgr, widget); */
2652       }
2653    }
2654    else
2655       return (FALSE);
2656 
2657    /*
2658     * if the menu system is active, bring it down
2659     */
2660    if (menuMgr->menu_mgr.menuActive)
2661    {
2662       /*
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.
2666        */
2667       traversalOn = menuMgr->manager.traversal_on;
2668 
2669       menuMgr->menu_mgr.menuActive = FALSE;
2670 
2671       Unpost (menuMgr, menuMgr->popup_mgr.topLevelPane);
2672 
2673       /* We need to remove the grab we set in ClassPost() */
2674       XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
2675 
2676       /*
2677        * If we warped the mouse because traversal was on, then we need
2678        * to move it back to where it was.
2679        */
2680       if (traversalOn &&
2681           (menuMgr->popup_mgr.origMouseX != -1) &&
2682           (menuMgr->popup_mgr.origMouseY != -1))
2683       {
2684 	 XWarpPointer (XtDisplay (menuMgr), None,
2685 		       RootWindowOfScreen(menuMgr->core.screen),
2686 		       0, 0, 0, 0,
2687                        menuMgr->popup_mgr.origMouseX,
2688                        menuMgr->popup_mgr.origMouseY);
2689          menuMgr->popup_mgr.origMouseX = -1;
2690          menuMgr->popup_mgr.origMouseY = -1;
2691       }
2692    }
2693    return (TRUE);
2694 }
2695 
2696 /*************************************<->*************************************
2697  *
2698  *   ValidEvent(menuMgr, menubutton, event)
2699  *
2700  *   Description:
2701  *   -----------
2702  *
2703  *
2704  *   Inputs:
2705  *   ------
2706  *
2707  *
2708  *   Outputs:
2709  *   -------
2710  *
2711  *
2712  *   Procedures Called
2713  *   -----------------
2714  *
2715  *************************************<->***********************************/
2716 
ValidEvent(menuMgr,menubutton,event)2717 static Boolean ValidEvent (menuMgr, menubutton, event)
2718 
2719    XwPopupMgrWidget  menuMgr;
2720    Widget   menubutton;
2721    XEvent * event;
2722 
2723 {
2724    /* Ignore enter and leave events if traversal is active */
2725    if (menuMgr->manager.traversal_on)
2726       return (FALSE);
2727    else
2728       return (TRUE);
2729 }
2730 
2731 /*************************************<->*************************************
2732  *
2733  *   DoICascade (menuMgr)
2734  *
2735  *   Description:
2736  *   -----------
2737  *
2738  *
2739  *   Inputs:
2740  *   ------
2741  *
2742  *
2743  *   Outputs:
2744  *   -------
2745  *
2746  *
2747  *   Procedures Called
2748  *   -----------------
2749  *
2750  *************************************<->***********************************/
2751 
DoICascade(menuMgr,menuBtn)2752 static Boolean DoICascade (menuMgr, menuBtn)
2753 
2754    register XwPopupMgrWidget menuMgr;
2755    Widget menuBtn;
2756 
2757 {
2758    /* Ignore cascade events if traversal is currently active */
2759    if ((menuMgr->menu_mgr.menuActive) &&
2760       (menuMgr->manager.traversal_on == FALSE))
2761    {
2762       Widget lastCascade = menuMgr->popup_mgr.currentCascadeList[
2763           menuMgr->popup_mgr.numCascades -1];
2764 
2765       if ((XtParent(menuBtn) == lastCascade) ||
2766           (menuBtn == ((XwMenuPaneWidget)(lastCascade))->menu_pane.attachId))
2767       {
2768          return (TRUE);
2769       }
2770    }
2771 
2772    return (FALSE);
2773 }
2774 
2775 /*************************************<->*************************************
2776  *
2777  *   ClassPost(menuMgr, event, warpOn)
2778  *
2779  *   Description:
2780  *   -----------
2781  *
2782  *
2783  *   Inputs:
2784  *   ------
2785  *
2786  *
2787  *   Outputs:
2788  *   -------
2789  *
2790  *
2791  *   Procedures Called
2792  *   -----------------
2793  *
2794  *************************************<->***********************************/
2795 
ClassPost(menuMgr,event,warpOn)2796 static void ClassPost (menuMgr, event, warpOn)
2797 
2798    register XwPopupMgrWidget  menuMgr;
2799    XEvent          * event;
2800    Boolean           warpOn;
2801 
2802 {
2803    register int i;
2804    Position posx, posy;
2805    int x, y, relativeX, relativeY;
2806    int yDelta;
2807    XButtonEvent * buttonEvent = (XButtonEvent *) event;
2808    Widget assocWidget, w;
2809    Widget menuBtn;
2810    XwMenuPaneWidget tempPane;
2811    XwManagerWidget topLevelPane;
2812    XWindowChanges windowChanges;
2813    ShellWidget shell;
2814    Window root, child;
2815    int rootx, rooty, childx, childy;
2816    unsigned int returnMask;
2817 
2818    /*
2819     * If either the menu manager or the associated widget is insensitive,
2820     * then ignore the post request.
2821     */
2822    assocWidget = XtParent (XtParent (menuMgr));
2823    if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
2824       return;
2825 
2826    /*
2827     * if menus are not inherited, throw out events that did occur
2828     * in the associated widget's children.
2829     */
2830    if (menuMgr->menu_mgr.associateChildren == FALSE)
2831    {
2832       if ((event->xkey.window == XtWindow (XtParent (XtParent (menuMgr)))) &&
2833           (event->xkey.subwindow != 0) &&
2834           (XtWindowToWidget (XtDisplay (menuMgr), event->xkey.subwindow)))
2835       return;
2836    }
2837 
2838    /*
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.
2844     */
2845    /* if (menuMgr->manager.traversal_on) */
2846       SendFakeLeaveNotify(menuMgr, ULTIMATE_PARENT);
2847 
2848    /* Mark the menu system as 'active' */
2849    menuMgr->menu_mgr.menuActive = TRUE;
2850 
2851    /*
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
2855     */
2856    topLevelPane =(XwManagerWidget)menuMgr->popup_mgr.topLevelPane;
2857 
2858    /*
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.
2863     */
2864    if (!XtIsRealized (XtParent(topLevelPane )))
2865       XtRealizeWidget (XtParent (topLevelPane ));
2866 
2867    if ((event->type == ButtonPress) ||
2868        (event->type == ButtonRelease))
2869    {
2870 
2871       /*
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.
2875        */
2876       if (event->type == ButtonPress)
2877          XUngrabPointer (XtDisplay(menuMgr), CurrentTime);
2878 
2879       /*
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.
2883        */
2884       if (menuMgr->manager.traversal_on)
2885       {
2886          menuMgr->popup_mgr.origMouseX = buttonEvent->x_root;
2887          menuMgr->popup_mgr.origMouseY = buttonEvent->y_root;
2888       }
2889 
2890       x = buttonEvent->x_root - (XwCASCADEWIDTH + FUDGE_FACTOR +
2891                                  topLevelPane ->core.border_width);
2892       y = buttonEvent->y_root;
2893 
2894       /* Attempt to center on the first button in the new menupane */
2895       {
2896 
2897          if (topLevelPane->manager.num_managed_children > 0)
2898          {
2899             Widget firstButton = topLevelPane->manager.managed_children[0];
2900 
2901 /*
2902             yDelta = firstButton->core.y +
2903                      firstButton->core.border_width +
2904                      (firstButton->core.height >> 1);
2905 */
2906             yDelta = 0;
2907          }
2908          else
2909          {
2910             yDelta = topLevelPane->core.border_width +
2911                      (topLevelPane->core.height >> 1);
2912          }
2913       }
2914 
2915       y -= yDelta;
2916    }
2917    else
2918    {
2919       /*
2920        * center on the associated widget
2921        */
2922       relativeX = (assocWidget->core.width>>1);
2923       relativeY = (assocWidget->core.height>>1);
2924 
2925       /* Get our coordinates, relative to the root window */
2926       XTranslateCoordinates (XtDisplay(menuMgr),
2927                           assocWidget->core.window,
2928                           RootWindowOfScreen(XtScreen(menuMgr)),
2929                           relativeX,
2930                           relativeY,
2931                           &x, &y, &child);
2932 
2933       /*
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.
2937        */
2938       if (menuMgr->manager.traversal_on)
2939       {
2940          if (XQueryPointer(XtDisplay(menuMgr),
2941                            RootWindowOfScreen(menuMgr->core.screen),
2942                            &root, &child, &rootx, &rooty, &childx,
2943                            &childy, &returnMask))
2944          {
2945             menuMgr->popup_mgr.origMouseX = rootx;
2946             menuMgr->popup_mgr.origMouseY = rooty;
2947          }
2948       }
2949    }
2950 
2951    posx = x; posy = y;
2952    ForceMenuPaneOnScreen (topLevelPane, &posx, &posy);
2953    x = posx; y = posy;
2954    XtMoveWidget (XtParent(topLevelPane), x, y);
2955 
2956    /*
2957     * This allows us to catch all selects, and unpost the menus
2958     * regardless where the select event occurs.
2959     */
2960    XGrabPointer (XtDisplay(menuMgr), XtWindow(assocWidget), TRUE,
2961         ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|
2962         PointerMotionMask, GrabModeAsync, GrabModeAsync, None, (Cursor)NULL,
2963         CurrentTime);
2964 
2965    if ((menuMgr->popup_mgr.stickyMode) &&
2966        (menuMgr->popup_mgr.numSavedCascades))
2967    {
2968       /*
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.
2972        */
2973       for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
2974       {
2975          tempPane = (XwMenuPaneWidget)menuMgr->popup_mgr.savedCascadeList[i];
2976 
2977          if ((tempPane->menu_pane.attachId) &&
2978              (!XtIsSensitive(tempPane->menu_pane.attachId)))
2979          {
2980             /*
2981              * We are cascading from an insensitive menubutton.
2982              * Stop at the preceeding menupane.
2983              */
2984             menuMgr->popup_mgr.numSavedCascades = i;
2985             menuMgr->popup_mgr.lastSelected = tempPane->menu_pane.attachId;
2986             break;
2987          }
2988          else if (!XtIsSensitive((Widget)tempPane))
2989          {
2990             /*
2991              * If this menupane is insensitive, then stop here.
2992              */
2993             menuMgr->popup_mgr.numSavedCascades = i + 1;
2994             if (tempPane->manager.num_managed_children > 0)
2995             {
2996                menuMgr->popup_mgr.lastSelected = tempPane->manager.
2997                                                  managed_children[0];
2998             }
2999             else
3000                menuMgr->popup_mgr.lastSelected = (Widget)tempPane;
3001             break;
3002          }
3003       }
3004 
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;
3010 
3011       /*
3012        * position the menupanes on the sticky cascade list
3013        */
3014       for (i=1; i < menuMgr->popup_mgr.numSavedCascades; i++)
3015       {
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;
3022       }
3023 
3024       /*
3025        * warp the pointer to its final destination.  This must be done
3026        * AFTER the panes are positioned, but BEFORE they are posted.
3027        */
3028       if (warpOn)
3029       {
3030 	 XWarpPointer (XtDisplay (menuMgr), None,
3031 		       XtWindow(menuMgr->popup_mgr.lastSelected),
3032 		       0, 0, 0, 0, 5, 5);
3033       }
3034 
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));
3044 
3045       /*
3046        * Post and then configure the menupanes and menubuttons.
3047        * THIS MUST BE DONE AFTER THE WARP POINTER!!!
3048        */
3049       for (i= menuMgr->popup_mgr.numSavedCascades - 2; i >= 0; i--)
3050       {
3051          /*
3052           * Popup the pane and add to the grablist.
3053           * This cannot use _XtPopup() because it used XMapRaised().
3054           */
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));
3068 
3069 	 /*
3070 	  * highlight menubutton, set its cascade flag and set up event
3071           * handler on its parent
3072 	  */
3073          menuBtn = (((XwMenuPaneWidget)(menuMgr->popup_mgr.
3074                     savedCascadeList[i+1]))->menu_pane.attachId);
3075 
3076          if (menuMgr->manager.traversal_on == FALSE)
3077          {
3078 	    (*(((XwMenuButtonWidgetClass)
3079 	        XtClass(menuBtn))->menubutton_class.highlightProc)) (menuBtn);
3080          }
3081 
3082 	 (*(((XwMenuButtonWidgetClass) XtClass(menuBtn))->
3083 	                menubutton_class.setCascadeProc)) (menuBtn);
3084 
3085          if (menuMgr->manager.traversal_on == FALSE)
3086          {
3087 	    XtAddEventHandler ((Widget)tempPane, EnterWindowMask, False,
3088 				(XtEventHandler)
3089 			        ((XwMenuButtonWidgetClass) XtClass(menuBtn))->
3090 			        menubutton_class.enterParentProc,
3091 			        menuBtn);
3092          }
3093       }
3094 
3095       /*
3096        * DON'T DO THE FOLLOWING; HAVE THE ITEM HILIGHT WHEN THE CURSOR
3097        * ENTERS IT.
3098        */
3099       /********
3100        * for keyboard posts, highlight the last selected menubutton.
3101        *
3102        *if ((warpOn == FALSE) && (menuMgr->manager.traversal_on == FALSE))
3103        *{
3104        * (*(((XwMenuButtonWidgetClass)
3105        *     XtClass(menuMgr->popup_mgr.lastSelected))->
3106        *             menubutton_class.highlightProc))
3107        *    (menuMgr->popup_mgr.lastSelected);
3108        *}
3109        *******/
3110    }
3111    else
3112    {
3113       /*
3114        * post only the toplevel.
3115        * post the toplevel menupane with exclusive grabs.  All other panes
3116        * have nonexclusive grabs.
3117        */
3118       Post (menuMgr, topLevelPane, XtGrabExclusive);
3119    }
3120 
3121    /* Set the traversal focus to the last pane, if necessary */
3122    if (menuMgr->manager.traversal_on)
3123    {
3124       XwMoveFocus (menuMgr->popup_mgr.currentCascadeList [
3125                      menuMgr->popup_mgr.numCascades - 1]);
3126    }
3127 
3128    XFlush(XtDisplay(menuMgr));
3129 }
3130 
3131 /*************************************<->*************************************
3132  *
3133  *   ClassSelect(menuMgr, event)
3134  *
3135  *   Description:
3136  *   -----------
3137  *        Called only when a menubutton select accelerator is received.
3138  *
3139  *
3140  *   Inputs:
3141  *   ------
3142  *
3143  *
3144  *   Outputs:
3145  *   -------
3146  *
3147  *
3148  *   Procedures Called
3149  *   -----------------
3150  *
3151  *************************************<->***********************************/
3152 
ClassSelect(menuMgr,event)3153 static void ClassSelect (menuMgr, event)
3154 
3155    XwMenuMgrWidget  menuMgr;
3156    XEvent         * event;
3157 
3158 {
3159    register int i;
3160    Widget assocWidget;
3161    register XwKeyAccel * accelerator;
3162 
3163    /*
3164     * If either the menu manager or the associated widget is insensitive,
3165     * then ignore the select accelerator.
3166     */
3167    assocWidget = XtParent(XtParent(menuMgr));
3168    if (!XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget))
3169       return;
3170 
3171    /*
3172     * map the event into an accelerator and call the menubuttons select rtn.
3173     */
3174    for (i=0; i < menuMgr->menu_mgr.numAccels; i++)
3175    {
3176       accelerator = menuMgr->menu_mgr.menuBtnAccelTable + i;
3177 
3178       if (_XwMatchKeyEvent (event,
3179 		    accelerator->accelEventType,
3180 		    accelerator->accelKey,
3181 		    accelerator->accelModifiers))
3182       {
3183 	 if (XtIsSensitive(accelerator->menuBtn) &&
3184              _XwAllAttachesAreSensitive(accelerator->menuBtn))
3185          {
3186 	    (*(((XwMenuButtonWidgetClass)
3187 	        XtClass (accelerator->menuBtn))-> primitive_class.select_proc))
3188 	          (accelerator->menuBtn, event);
3189          }
3190 
3191 	 return;
3192       }
3193    }
3194 }
3195 
3196 
3197 /*************************************<->*************************************
3198  *
3199  *   AddToPendingList(menuMgr, menupane, name)
3200  *
3201  *   Description:
3202  *   -----------
3203  *
3204  *
3205  *   Inputs:
3206  *   ------
3207  *
3208  *
3209  *   Outputs:
3210  *   -------
3211  *
3212  *
3213  *   Procedures Called
3214  *   -----------------
3215  *
3216  *************************************<->***********************************/
3217 
AddToPendingList(menuMgr,menupane,name)3218 static void AddToPendingList (menuMgr, menupane, name)
3219 
3220    register XwMenuMgrWidget menuMgr;
3221    Widget menupane;
3222    String name;
3223 
3224 {
3225    register int nameLen;
3226    register int i;
3227    Arg arg[1];
3228    register String button;
3229 
3230    /*
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.
3233     */
3234    nameLen = XwStrlen(name);
3235    for (i = 0; i < menuMgr->menu_mgr.numAttachReqs; i++)
3236    {
3237       button = menuMgr->menu_mgr.pendingAttachList[i].menuBtnName;
3238       if ((strcmp(name, button) == 0) && (nameLen == XwStrlen(button)))
3239       {
3240          /* Detach the older request */
3241          XtSetArg (arg[0], XtNattachTo, (XtArgVal) NULL);
3242          XtSetValues (menuMgr->menu_mgr.pendingAttachList[i].menupaneId,
3243                       arg, 1);
3244          break;
3245       }
3246    }
3247 
3248    if (menuMgr->menu_mgr.numAttachReqs == menuMgr->menu_mgr.sizeAttachList)
3249    {
3250       /*
3251        * resize the list
3252        */
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));
3258    }
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;
3263 }
3264 
3265 /*************************************<->*************************************
3266  *
3267  *   SetButtonAccelerators (menuMgr, menubutton, accelString, accelEventType,
3268  * 		       	    accelKey, accelModifiers)
3269  *
3270  *   Description:
3271  *   -----------
3272  *
3273  *
3274  *   Inputs:
3275  *   ------
3276  *
3277  *
3278  *   Outputs:
3279  *   -------
3280  *
3281  *
3282  *   Procedures Called
3283  *   -----------------
3284  *
3285  *************************************<->***********************************/
3286 
SetButtonAccelerators(menuMgr,menubutton,accelString,accelEventType,accelKey,accelModifiers)3287 static void SetButtonAccelerators (menuMgr, menubutton, accelString,
3288 				   accelEventType, accelKey, accelModifiers)
3289 
3290    register XwPopupMgrWidget menuMgr;
3291    Widget           menubutton;
3292    String           accelString;
3293    unsigned int     accelEventType;
3294    unsigned int     accelKey;
3295    unsigned int     accelModifiers;
3296 
3297 {
3298    Widget widget;
3299    register XwKeyAccel * accelerator;
3300 
3301    /*
3302     * add entry to menubutton accelerator table
3303     */
3304    if (menuMgr->menu_mgr.numAccels == menuMgr->menu_mgr.sizeAccelTable)
3305    {
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));
3312    }
3313 
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++;
3322 
3323    /*
3324     * set translation in associated widget & toplevel pane for accelerator
3325     */
3326    widget =  (Widget) XtParent (XtParent (menuMgr));
3327    RegisterTranslation (widget, accelString, accelSelectTemplate, menuMgr);
3328 
3329    if (menuMgr->popup_mgr.topLevelPane)
3330    {
3331       RegisterTranslation (menuMgr->popup_mgr.topLevelPane, accelString,
3332                            accelSelectTemplate, menuMgr);
3333 
3334       /*
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.
3338        */
3339       if ((menuMgr->popup_mgr.attachPane) &&
3340          (menuMgr->popup_mgr.topLevelPane ==
3341          menuMgr->popup_mgr.attachPane->core.self))
3342       {
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;
3347       }
3348    }
3349 
3350    /*
3351     * set up key grabs if possible
3352     */
3353    if ((menuMgr->menu_mgr.associateChildren) && (XtIsRealized (widget)))
3354       XGrabKey (XtDisplay (widget), accelKey, accelModifiers,
3355 		XtWindow (widget), False, GrabModeAsync, GrabModeAsync);
3356 }
3357 
3358 /*************************************<->*************************************
3359  *
3360  *   SetTreeAccelerators (menuMgr, menupane)
3361  *
3362  *   Description:
3363  *   -----------
3364  *
3365  *
3366  *   Inputs:
3367  *   ------
3368  *
3369  *
3370  *   Outputs:
3371  *   -------
3372  *
3373  *
3374  *   Procedures Called
3375  *   -----------------
3376  *
3377  *************************************<->***********************************/
3378 
SetTreeAccelerators(menuMgr,menupane)3379 static void SetTreeAccelerators (menuMgr, menupane)
3380 
3381    XwMenuMgrWidget  menuMgr;
3382    XwMenuPaneWidget menupane;
3383 
3384 {
3385    register int i;
3386    Arg args[2];
3387    unsigned int eventType;
3388    KeyCode key;
3389    unsigned int modifiers;
3390    KeySym tempKeysym;
3391    register WidgetList managed_children;
3392 
3393    managed_children = menupane->manager.managed_children;
3394 
3395    for (i=0; i < menupane->manager.num_managed_children; i++)
3396    {
3397       if (XtIsSubclass (managed_children[i], XwmenubuttonWidgetClass))
3398       {
3399 	 String dkey = NULL;
3400 	 Widget dtree = NULL;
3401 
3402 	 XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal)(&dkey));
3403 	 XtSetArg (args[1], XtNcascadeOn, (XtArgVal)(&dtree));
3404 	 XtGetValues (managed_children[i], args, XtNumber(args));
3405 
3406 	 /*
3407 	  * set up keyboard accelerators
3408 	  */
3409 	 if (dkey)
3410 	 {
3411 	    _XwMapKeyEvent (dkey, &eventType, &tempKeysym, &modifiers);
3412             key = XKeysymToKeycode (XtDisplay (menupane), tempKeysym);
3413 	    SetButtonAccelerators (menuMgr, managed_children[i],
3414                                    dkey, eventType, key, modifiers);
3415 	 }
3416 	 /*
3417 	  * traverse any submenus
3418 	  */
3419 	 if (dtree)
3420 	    SetTreeAccelerators (menuMgr, dtree);
3421       }
3422    }
3423 }
3424 
3425 /*************************************<->*************************************
3426  *
3427  *   ClearTreeAccelerators (menuMgr, menupane)
3428  *
3429  *   Description:
3430  *   -----------
3431  *
3432  *
3433  *   Inputs:
3434  *   ------
3435  *
3436  *
3437  *   Outputs:
3438  *   -------
3439  *
3440  *
3441  *   Procedures Called
3442  *   -----------------
3443  *
3444  *************************************<->***********************************/
3445 
ClearTreeAccelerators(menuMgr,menupane)3446 static void ClearTreeAccelerators (menuMgr, menupane)
3447 
3448    Widget           menuMgr;
3449    XwMenuPaneWidget menupane;
3450 
3451 {
3452    register int i;
3453    Arg arg[1];
3454    register WidgetList managed_children;
3455 
3456    managed_children = menupane->manager.managed_children;
3457 
3458    for (i=0; i < menupane->manager.num_managed_children; i++)
3459    {
3460       if (XtIsSubclass (managed_children[i], XwmenubuttonWidgetClass))
3461       {
3462 	 Widget twidg = NULL;
3463 	 ClearSelectAccelerator(menuMgr, managed_children[i]);
3464 
3465 	 /*
3466 	  * clear accelerators from any submenu
3467 	  */
3468 	 XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &twidg);
3469 	 XtGetValues (managed_children[i], arg, 1);
3470 	 if (twidg)
3471 	    ClearTreeAccelerators (menuMgr, twidg);
3472       }
3473    }
3474 }
3475 
3476 /*************************************<->*************************************
3477  *
3478  *   CompletePath(menuMgr, menupane)
3479  *
3480  *   Description:
3481  *   -----------
3482  *
3483  *
3484  *   Inputs:
3485  *   ------
3486  *
3487  *
3488  *   Outputs:
3489  *   -------
3490  *
3491  *
3492  *   Procedures Called
3493  *   -----------------
3494  *
3495  *************************************<->***********************************/
3496 
CompletePath(menuMgr,menupane)3497 static Boolean CompletePath (menuMgr, menupane)
3498 
3499    XwPopupMgrWidget menuMgr;
3500    XwMenuPaneWidget menupane;
3501 
3502 {
3503    register XwMenuPaneWidget pane;
3504 
3505    if (menuMgr->popup_mgr.topLevelPane == FALSE)
3506       return (FALSE);
3507 
3508    for (pane = menupane; pane != NULL;
3509 	pane = (XwMenuPaneWidget) XtParent (pane->menu_pane.attachId))
3510    {
3511       if (pane == (XwMenuPaneWidget) menuMgr->popup_mgr.topLevelPane)
3512 	 return (TRUE);
3513 
3514       if (pane->menu_pane.attachId == NULL)
3515 	 return (FALSE);
3516 
3517       if (pane->core.managed == False)
3518 	 return (FALSE);
3519 
3520       if ((pane->menu_pane.attachId)->core.mapped_when_managed == FALSE)
3521 	 return (FALSE);
3522 
3523       if ((pane->menu_pane.attachId)->core.managed == FALSE)
3524 	 return (FALSE);
3525    }
3526    return (FALSE);
3527 }
3528 
3529 /*************************************<->*************************************
3530  *
3531  *   PendingAttach (menuMgr, menubutton)
3532  *
3533  *   Description:
3534  *   -----------
3535  *
3536  *
3537  *   Inputs:
3538  *   ------
3539  *
3540  *
3541  *   Outputs:
3542  *   -------
3543  *
3544  *
3545  *   Procedures Called
3546  *   -----------------
3547  *
3548  *************************************<->***********************************/
3549 
PendingAttach(menuMgr,menubutton)3550 static Widget PendingAttach (menuMgr, menubutton)
3551 
3552    XwMenuMgrWidget menuMgr;
3553    register Widget          menubutton;
3554 
3555 {
3556    register int i;
3557    Widget id;
3558    register String buttonName = menubutton->core.name;
3559    register int buttonNameLen = XwStrlen(buttonName);
3560    register XwAttachList * pendingAttachList;
3561 
3562    pendingAttachList = menuMgr->menu_mgr.pendingAttachList;
3563 
3564    for (i=0; i < menuMgr->menu_mgr.numAttachReqs; i++)
3565    {
3566       if ((strcmp (pendingAttachList[i].menuBtnName, buttonName) == 0) &&
3567           (XwStrlen(pendingAttachList[i].menuBtnName) == buttonNameLen))
3568       {
3569          id = pendingAttachList[i].menupaneId;
3570 
3571          /* Remove from pending attach list */
3572          pendingAttachList[i] = pendingAttachList[--menuMgr->menu_mgr.
3573                                                   numAttachReqs];
3574 
3575 	 return (id);
3576       }
3577    }
3578 
3579    return (NULL);
3580 }
3581 
3582 /*************************************<->*************************************
3583  *
3584  *   SetUpTranslation (widget, event, action)
3585  *
3586  *   Description:
3587  *   -----------
3588  *
3589  *   Inputs:
3590  *   ------
3591  *
3592  *
3593  *
3594  *   Outputs:
3595  *   -------
3596  *
3597  *
3598  *   Procedures Called
3599  *   -----------------
3600  *
3601  *************************************<->***********************************/
3602 
SetUpTranslation(widget,event,action)3603 static void SetUpTranslation (widget, event, action)
3604 
3605    Widget widget;
3606    String event;
3607    String action;
3608 
3609 {
3610    register String workSpace;
3611    XtTranslations translations;
3612 
3613    workSpace = &workArea[0];
3614 
3615    strcpy (workSpace, "!");
3616    strcat (workSpace, event);
3617    strcat (workSpace, action);
3618 
3619    /*
3620     * compile the translation and attach to the menupane
3621     */
3622    translations = XtParseTranslationTable(workSpace);
3623    XtOverrideTranslations (widget, translations);
3624    /* XtDestroyStateTable (XtClass(widget), translations); */
3625 }
3626 
3627 
3628 /*************************************<->*************************************
3629  *
3630  *  SetPostMnemonic (parameters)
3631  *
3632  *   Description:
3633  *   -----------
3634  *     xxxxxxxxxxxxxxxxxxxxxxx
3635  *
3636  *
3637  *   Inputs:
3638  *   ------
3639  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3640  *
3641  *   Outputs:
3642  *   -------
3643  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3644  *
3645  *   Procedures Called
3646  *   -----------------
3647  *
3648  *************************************<->***********************************/
3649 
SetPostMnemonic(menuMgr,menupane,mnemonic)3650 static void SetPostMnemonic (menuMgr, menupane, mnemonic)
3651 
3652    Widget menuMgr;
3653    Widget menupane;
3654    String mnemonic;
3655 
3656 {
3657 }
3658 
3659 
3660 /*************************************<->*************************************
3661  *
3662  *  ClearPostMnemonic (parameters)
3663  *
3664  *   Description:
3665  *   -----------
3666  *     xxxxxxxxxxxxxxxxxxxxxxx
3667  *
3668  *
3669  *   Inputs:
3670  *   ------
3671  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3672  *
3673  *   Outputs:
3674  *   -------
3675  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3676  *
3677  *   Procedures Called
3678  *   -----------------
3679  *
3680  *************************************<->***********************************/
3681 
ClearPostMnemonic(menuMgr,menupane)3682 static void ClearPostMnemonic (menuMgr, menupane)
3683 
3684    Widget menuMgr;
3685    Widget menupane;
3686 
3687 {
3688 }
3689 
3690 
3691 /*************************************<->*************************************
3692  *
3693  *  SetTitleAttributes (parameters)
3694  *
3695  *   Description:
3696  *   -----------
3697  *     xxxxxxxxxxxxxxxxxxxxxxx
3698  *
3699  *
3700  *   Inputs:
3701  *   ------
3702  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3703  *
3704  *   Outputs:
3705  *   -------
3706  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3707  *
3708  *   Procedures Called
3709  *   -----------------
3710  *
3711  *************************************<->***********************************/
3712 
SetTitleAttributes(w,x)3713 static void SetTitleAttributes(w, x)
3714   Widget w, x;
3715 {
3716 }
3717 
3718 
3719 /*************************************<->*************************************
3720  *
3721  *  ForceMenuPaneOnScreen (parameters)
3722  *
3723  *   Description:
3724  *   -----------
3725  *     xxxxxxxxxxxxxxxxxxxxxxx
3726  *
3727  *
3728  *   Inputs:
3729  *   ------
3730  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3731  *
3732  *   Outputs:
3733  *   -------
3734  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3735  *
3736  *   Procedures Called
3737  *   -----------------
3738  *
3739  *************************************<->***********************************/
3740 
ForceMenuPaneOnScreen(menupane,x,y)3741 static void ForceMenuPaneOnScreen (menupane, x, y)
3742 
3743    register Widget menupane;
3744    register Position * x;
3745    register Position * y;
3746 
3747 {
3748    int rightEdgeOfMenu, dispWidth;
3749    int bottomEdgeOfMenu, dispHeight;
3750 
3751    /*
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.
3756     */
3757    if (!XtIsRealized (XtParent(menupane)))
3758       XtRealizeWidget (XtParent (menupane));
3759 
3760    /* Force the menupane to be completely visible */
3761 
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));
3768 
3769    if (*x < 0)
3770       *x = 0;
3771 
3772    if (*y < 0)
3773       *y = 0;
3774 
3775    if (rightEdgeOfMenu >= dispWidth)
3776       *x -= (rightEdgeOfMenu - dispWidth + 1);
3777 
3778    if (bottomEdgeOfMenu >= dispHeight)
3779       *y -= (bottomEdgeOfMenu - dispHeight + 1);
3780 }
3781 
3782 
3783 /*************************************<->*************************************
3784  *
3785  *  SetSelectMnemonic (parameters)
3786  *
3787  *   Description:
3788  *   -----------
3789  *     xxxxxxxxxxxxxxxxxxxxxxx
3790  *
3791  *
3792  *   Inputs:
3793  *   ------
3794  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3795  *
3796  *   Outputs:
3797  *   -------
3798  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3799  *
3800  *   Procedures Called
3801  *   -----------------
3802  *
3803  *************************************<->***********************************/
3804 
SetSelectMnemonic(menuMgr,menubutton,mnemonic)3805 static void SetSelectMnemonic (menuMgr, menubutton, mnemonic)
3806 
3807    Widget menuMgr;
3808    Widget menubutton;
3809    String mnemonic;
3810 
3811 {
3812 }
3813 
3814 
3815 /*************************************<->*************************************
3816  *
3817  *  ClearSelectMnemonic (parameters)
3818  *
3819  *   Description:
3820  *   -----------
3821  *     xxxxxxxxxxxxxxxxxxxxxxx
3822  *
3823  *
3824  *   Inputs:
3825  *   ------
3826  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3827  *
3828  *   Outputs:
3829  *   -------
3830  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3831  *
3832  *   Procedures Called
3833  *   -----------------
3834  *
3835  *************************************<->***********************************/
3836 
ClearSelectMnemonic(menuMgr,menupane)3837 static void ClearSelectMnemonic (menuMgr, menupane)
3838 
3839    Widget menuMgr;
3840    Widget menupane;
3841 
3842 {
3843 }
3844 
3845 
3846 /*************************************<->*************************************
3847  *
3848  *  OnCascadeList(parameters)
3849  *
3850  *   Description:
3851  *   -----------
3852  *     xxxxxxxxxxxxxxxxxxxxxxx
3853  *
3854  *
3855  *   Inputs:
3856  *   ------
3857  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3858  *
3859  *   Outputs:
3860  *   -------
3861  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
3862  *
3863  *   Procedures Called
3864  *   -----------------
3865  *
3866  *************************************<->***********************************/
3867 
OnCascadeList(menuMgr,menupane)3868 static Boolean OnCascadeList (menuMgr, menupane)
3869 
3870    register XwPopupMgrWidget menuMgr;
3871    register XwMenuPaneWidget menupane;
3872 {
3873    register int i;
3874 
3875    if ((menuMgr->popup_mgr.stickyMode) &&
3876        (menuMgr->popup_mgr.numSavedCascades > 0))
3877    {
3878       for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
3879       {
3880          if ((Widget)menupane->core.self ==
3881               menuMgr->popup_mgr.savedCascadeList[i])
3882          {
3883             return (True);
3884          }
3885       }
3886    }
3887 
3888    return (False);
3889 }
3890 
3891 /*************************************<->*************************************
3892  *
3893  *   PaneManagedChildren()
3894  *
3895  *   Description:
3896  *   -----------
3897  *
3898  *
3899  *   Inputs:
3900  *   ------
3901  *
3902  *
3903  *   Outputs:
3904  *   -------
3905  *
3906  *
3907  *   Procedures Called
3908  *   -----------------
3909  *
3910  *************************************<->***********************************/
3911 
PaneManagedChildren(menuMgr,menupane)3912 static void PaneManagedChildren (menuMgr, menupane)
3913 
3914    register XwPopupMgrWidget  menuMgr;
3915    register XwMenuPaneWidget  menupane;
3916 
3917 {
3918    register Widget child;
3919    Boolean * wasManaged;
3920    Arg args[2];
3921    unsigned int event;
3922    unsigned int tempKeySym;
3923    unsigned int modifiers;
3924    KeyCode key;
3925    register int i;
3926    Boolean parentOnCascadeList;
3927    String dkey;
3928    Widget dtree;
3929 
3930 
3931    if (CompletePath (menuMgr, menupane))
3932    {
3933       /*
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.
3939        */
3940       parentOnCascadeList = OnCascadeList (menuMgr, menupane);
3941 
3942       for (i=0; i < menupane->composite.num_children; i++)
3943       {
3944 	 child = menupane->composite.children[i];
3945 	 wasManaged = (Boolean *) child->core.constraints;
3946 
3947 	 if ((*wasManaged == FALSE) && (child->core.managed == TRUE))
3948 	 {
3949 	    dkey = NULL;
3950 	    dtree = NULL;
3951 
3952 	    /*
3953 	     * child has gone from unmanaged to managed
3954 	     */
3955 	    *wasManaged = TRUE;
3956 	    XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal) &dkey);
3957 	    XtSetArg (args[1], XtNcascadeOn, (XtArgVal) &dtree);
3958 	    XtGetValues (child, args, XtNumber(args));
3959 
3960 	    /*
3961 	     * keyboard accelerator?
3962 	     */
3963 	    if (dkey)
3964 	    {
3965 	       _XwMapKeyEvent (dkey, &event, &tempKeySym, &modifiers);
3966 	       key = XKeysymToKeycode (XtDisplay(menuMgr), tempKeySym);
3967 	       SetSelectAccelerator (menuMgr, child, dkey,
3968 				     event, key, modifiers);
3969 	    }
3970 
3971 	    /*
3972 	     * Does this menubutton cascade?
3973 	     */
3974 	    if (dtree)
3975 	       SetTreeAccelerators (menuMgr, dtree);
3976 	 }
3977 	 else if ((*wasManaged == TRUE) && (child->core.managed == FALSE))
3978 	 {
3979 	    dkey = NULL;
3980 	    dtree = NULL;
3981 
3982 	    /*
3983 	     * child went from managed to unmanaged
3984 	     */
3985             *wasManaged = FALSE;
3986 	    XtSetArg (args[0], XtNkbdAccelerator, (XtArgVal) &dkey);
3987 	    XtSetArg (args[1], XtNcascadeOn, (XtArgVal) &dtree);
3988 	    XtGetValues (child, args, XtNumber(args));
3989 
3990 	    /*
3991 	     * accelerator to clear out?
3992 	     */
3993 	    if (dkey)
3994 	       ClearSelectAccelerator (menuMgr, child);
3995 
3996 	    /*
3997 	     * Does this menubutton cascade?
3998 	     */
3999 	    if (dtree)
4000 	    {
4001 	       ClearTreeAccelerators (menuMgr, dtree);
4002                if (Visible (menuMgr, dtree))
4003 	          Unpost (menuMgr, dtree);
4004 
4005                /*
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.
4009                 */
4010                if (parentOnCascadeList && OnCascadeList(menuMgr, dtree))
4011                {
4012                   parentOnCascadeList = False;
4013                   menuMgr->popup_mgr.numSavedCascades = 0;
4014                }
4015 	    }
4016 
4017             /*
4018              * If this button was the last selected item on the saved
4019              * cascade list, then we need to clean up the list.
4020              */
4021             if (parentOnCascadeList &&
4022                (child == menuMgr->popup_mgr.lastSelected))
4023             {
4024                parentOnCascadeList = False;
4025                menuMgr->popup_mgr.numSavedCascades = 0;
4026             }
4027 	 }
4028       }
4029    }
4030 }
4031 
4032 
4033 /*************************************<->*************************************
4034  *
4035  *   Visible
4036  *
4037  *   Description:
4038  *   -----------
4039  *     xxxxxxxxxxxxxxxxxxxxxxx
4040  *
4041  *
4042  *   Inputs:
4043  *   ------
4044  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4045  *
4046  *   Outputs:
4047  *   -------
4048  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4049  *
4050  *   Procedures Called
4051  *   -----------------
4052  *
4053  *************************************<->***********************************/
4054 
Visible(menuMgr,menupane)4055 static Boolean Visible (menuMgr, menupane)
4056 
4057    XwPopupMgrWidget menuMgr;
4058    Widget menupane;
4059 
4060 {
4061    register int i;
4062    register Widget * currentCascadeList =menuMgr->popup_mgr.currentCascadeList;
4063 
4064    for (i=0; i < menuMgr->popup_mgr.numCascades; i++)
4065       if (currentCascadeList[i] == menupane)
4066 	 return (TRUE);
4067 
4068    return (FALSE);
4069 }
4070 
4071 
4072 /*************************************<->*************************************
4073  *
4074  *   SetMenuTranslations
4075  *
4076  *   Description:
4077  *   -----------
4078  *     xxxxxxxxxxxxxxxxxxxxxxx
4079  *
4080  *
4081  *   Inputs:
4082  *   ------
4083  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4084  *
4085  *   Outputs:
4086  *   -------
4087  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4088  *
4089  *   Procedures Called
4090  *   -----------------
4091  *
4092  *************************************<->***********************************/
4093 
SetMenuTranslations(menuMgr,translation)4094 static void SetMenuTranslations (menuMgr, translation)
4095 
4096    XwPopupMgrWidget menuMgr;
4097    XtTranslations translation;
4098 
4099 {
4100    register int i, j, k;
4101    register CompositeWidget shell;
4102    register XwMenuPaneWidget menupane;
4103 
4104    /*
4105     * Since the menupanes are our popup grand children, we
4106     * will process them simply by traversing our popup children list.
4107     */
4108    for (i = 0; i < menuMgr->core.num_popups; i++)
4109    {
4110       shell = (CompositeWidget) menuMgr->core.popup_list[i];
4111 
4112       for (j = 0; j < shell->composite.num_children; j++)
4113       {
4114          /* Here we set the translation for the menupanes */
4115          menupane = (XwMenuPaneWidget)shell->composite.children[j];
4116          XtOverrideTranslations ((Widget)menupane, translation);
4117 
4118          for (k = 0; k < menupane->manager.num_managed_children; k++)
4119          {
4120             /* Here we set the translation for the menubuttons */
4121             XtOverrideTranslations(menupane->manager.managed_children[k],
4122                                     translation);
4123          }
4124       }
4125    }
4126 }
4127 
4128 
4129 /*************************************<->*************************************
4130  *
4131  *  TraverseRight(parameters)
4132  *
4133  *   Description:
4134  *   -----------
4135  *     xxxxxxxxxxxxxxxxxxxxxxx
4136  *
4137  *
4138  *   Inputs:
4139  *   ------
4140  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4141  *
4142  *   Outputs:
4143  *   -------
4144  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4145  *
4146  *   Procedures Called
4147  *   -----------------
4148  *
4149  *************************************<->***********************************/
4150 
TraverseRight(menuMgr,w)4151 static void TraverseRight (menuMgr, w)
4152 
4153    register XwPopupMgrWidget menuMgr;
4154    XwMenuButtonWidget w;
4155 
4156 {
4157    XwMenuPaneWidget menupane;
4158    Arg arg[1];
4159 
4160    if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4161       (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4162        menuMgr->popup_mgr.numCascades - 1]))
4163    {
4164       /* Cascade to the menupane attached to the specified menubutton */
4165       XtSetArg (arg[0], XtNcascadeOn, (XtArgVal) &menupane);
4166       XtGetValues ((Widget)w, arg, XtNumber(arg));
4167 
4168       /*
4169        * Only cascade if there is a traversable primitive widget in
4170        * the pane we would be cascading to.
4171        */
4172       if (_XwFindTraversablePrim (menupane) == FALSE)
4173          return;
4174 
4175       if (menupane)
4176          _XwCascadeSelect (w, menupane, NULL);
4177    }
4178 }
4179 
4180 
4181 /*************************************<->*************************************
4182  *
4183  *  TraverseLeft(parameters)
4184  *
4185  *   Description:
4186  *   -----------
4187  *     xxxxxxxxxxxxxxxxxxxxxxx
4188  *
4189  *
4190  *   Inputs:
4191  *   ------
4192  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4193  *
4194  *   Outputs:
4195  *   -------
4196  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4197  *
4198  *   Procedures Called
4199  *   -----------------
4200  *
4201  *************************************<->***********************************/
4202 
TraverseLeft(menuMgr,w)4203 static void TraverseLeft (menuMgr, w)
4204 
4205    register XwPopupMgrWidget menuMgr;
4206    XwMenuButtonWidget w;
4207 
4208 {
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]))
4215    {
4216       /* Unpost() will set the traversal focus, if needed */
4217       Unpost (menuMgr, menuMgr->popup_mgr.currentCascadeList[
4218                        menuMgr->popup_mgr.numCascades - 1]);
4219    }
4220 }
4221 
4222 
4223 /*************************************<->*************************************
4224  *
4225  *  TraverseUp(parameters)
4226  *
4227  *   Description:
4228  *   -----------
4229  *     xxxxxxxxxxxxxxxxxxxxxxx
4230  *
4231  *
4232  *   Inputs:
4233  *   ------
4234  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4235  *
4236  *   Outputs:
4237  *   -------
4238  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4239  *
4240  *   Procedures Called
4241  *   -----------------
4242  *
4243  *************************************<->***********************************/
4244 
TraverseUp(menuMgr,w)4245 static void TraverseUp (menuMgr, w)
4246 
4247    register XwPopupMgrWidget menuMgr;
4248    XwMenuButtonWidget w;
4249 
4250 {
4251    if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4252       (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4253        menuMgr->popup_mgr.numCascades - 1]))
4254    {
4255       XwProcessTraversal (w, XwTRAVERSE_UP, TRUE);
4256    }
4257 }
4258 
4259 
4260 /*************************************<->*************************************
4261  *
4262  *  TraverseDown(parameters)
4263  *
4264  *   Description:
4265  *   -----------
4266  *     xxxxxxxxxxxxxxxxxxxxxxx
4267  *
4268  *
4269  *   Inputs:
4270  *   ------
4271  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4272  *
4273  *   Outputs:
4274  *   -------
4275  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4276  *
4277  *   Procedures Called
4278  *   -----------------
4279  *
4280  *************************************<->***********************************/
4281 
TraverseDown(menuMgr,w)4282 static void TraverseDown (menuMgr, w)
4283 
4284    XwPopupMgrWidget menuMgr;
4285    XwMenuButtonWidget w;
4286 
4287 {
4288    if ((menuMgr->manager.traversal_on) && (menuMgr->menu_mgr.menuActive) &&
4289       (XtParent(w) == menuMgr->popup_mgr.currentCascadeList[
4290        menuMgr->popup_mgr.numCascades - 1]))
4291    {
4292       XwProcessTraversal (w, XwTRAVERSE_DOWN, TRUE);
4293    }
4294 }
4295 
4296 
4297 /*************************************<->*************************************
4298  *
4299  *  TraverseNextTop(parameters)
4300  *
4301  *   Description:
4302  *   -----------
4303  *     xxxxxxxxxxxxxxxxxxxxxxx
4304  *
4305  *
4306  *   Inputs:
4307  *   ------
4308  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4309  *
4310  *   Outputs:
4311  *   -------
4312  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4313  *
4314  *   Procedures Called
4315  *   -----------------
4316  *
4317  *************************************<->***********************************/
4318 
TraverseNextTop(menuMgr,w)4319 static void TraverseNextTop (menuMgr, w)
4320 
4321    XwPopupMgrWidget menuMgr;
4322    XwMenuButtonWidget w;
4323 
4324 {
4325 }
4326 
4327 
4328 /*************************************<->*************************************
4329  *
4330  *  TraverseNext(parameters)
4331  *
4332  *   Description:
4333  *   -----------
4334  *     xxxxxxxxxxxxxxxxxxxxxxx
4335  *
4336  *
4337  *   Inputs:
4338  *   ------
4339  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4340  *
4341  *   Outputs:
4342  *   -------
4343  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4344  *
4345  *   Procedures Called
4346  *   -----------------
4347  *
4348  *************************************<->***********************************/
4349 
TraverseNext(menuMgr,w)4350 static void TraverseNext (menuMgr, w)
4351 
4352    XwPopupMgrWidget menuMgr;
4353    XwMenuButtonWidget w;
4354 
4355 {
4356 }
4357 
4358 
4359 /*************************************<->*************************************
4360  *
4361  *  TraversePrev(parameters)
4362  *
4363  *   Description:
4364  *   -----------
4365  *     xxxxxxxxxxxxxxxxxxxxxxx
4366  *
4367  *
4368  *   Inputs:
4369  *   ------
4370  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4371  *
4372  *   Outputs:
4373  *   -------
4374  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4375  *
4376  *   Procedures Called
4377  *   -----------------
4378  *
4379  *************************************<->***********************************/
4380 
TraversePrev(menuMgr,w)4381 static void TraversePrev (menuMgr, w)
4382 
4383    XwPopupMgrWidget menuMgr;
4384    XwMenuButtonWidget w;
4385 
4386 {
4387 }
4388 
4389 
4390 /*************************************<->*************************************
4391  *
4392  *  TraverseHome(parameters)
4393  *
4394  *   Description:
4395  *   -----------
4396  *     xxxxxxxxxxxxxxxxxxxxxxx
4397  *
4398  *
4399  *   Inputs:
4400  *   ------
4401  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4402  *
4403  *   Outputs:
4404  *   -------
4405  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4406  *
4407  *   Procedures Called
4408  *   -----------------
4409  *
4410  *************************************<->***********************************/
4411 
TraverseHome(menuMgr,w)4412 static void TraverseHome (menuMgr, w)
4413 
4414    XwPopupMgrWidget menuMgr;
4415    XwMenuButtonWidget w;
4416 
4417 {
4418 }
4419 
4420 
4421 /*************************************<->*************************************
4422  *
4423  *  ManualPost(parameters)
4424  *
4425  *   Description:
4426  *   -----------
4427  *     xxxxxxxxxxxxxxxxxxxxxxx
4428  *
4429  *
4430  *   Inputs:
4431  *   ------
4432  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4433  *
4434  *   Outputs:
4435  *   -------
4436  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4437  *
4438  *   Procedures Called
4439  *   -----------------
4440  *
4441  *************************************<->***********************************/
4442 
ManualPost(menuMgr,pane,relativeTo,x,y)4443 static void ManualPost (menuMgr, pane, relativeTo, x, y)
4444 
4445    register XwPopupMgrWidget menuMgr;
4446    register Widget pane;
4447    Widget relativeTo;
4448    Position x;
4449    Position y;
4450 
4451 {
4452    int introotx, introoty, intchildx, intchildy;
4453    Position rootx, rooty;
4454    Position childx, childy;
4455    Widget assocWidget;
4456    Window root, child;
4457    unsigned int returnMask;
4458 
4459    if (pane == (Widget)NULL)
4460       pane = (Widget) menuMgr->popup_mgr.topLevelPane;
4461 
4462    /* Get the widget Id for the associated widget */
4463    assocWidget = XtParent (XtParent (menuMgr));
4464 
4465    /*
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.
4469     */
4470    if ((menuMgr->menu_mgr.menuActive == TRUE) || (pane == NULL) ||
4471       !XtIsSensitive((Widget)menuMgr) || !XtIsSensitive(assocWidget)) {
4472       return;
4473    }
4474 
4475    /*
4476     * Determine where to post the menu and translate coordinates,
4477     * if necessary.
4478     */
4479    if (relativeTo)
4480    {
4481       /*
4482        * If the coordinates are relative to a widget, then we need
4483        * to map them relative to the root window.
4484        */
4485       /* XtTranslateCoords (relativeTo, x, y, &rootx, &rooty); */
4486       XTranslateCoordinates (XtDisplay(relativeTo), XtWindow(relativeTo),
4487                              RootWindowOfScreen(XtScreen(menuMgr)),
4488                              x, y, &introotx, &introoty, &child);
4489       rootx = introotx;
4490       rooty = introoty;
4491    }
4492    else
4493    {
4494       /*
4495        * If no widget is specified, then the coordinates are assumed
4496        * to already be relative to the root window.
4497        */
4498       rootx = x;
4499       rooty = y;
4500    }
4501 
4502    /*
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.
4508     */
4509    /* if (menuMgr->manager.traversal_on) */
4510       SendFakeLeaveNotify(menuMgr, ULTIMATE_PARENT);
4511 
4512    /* Mark the menu system as active */
4513    menuMgr->menu_mgr.menuActive = TRUE;
4514 
4515    /* Position the menupane */
4516    if (!XtIsRealized (XtParent(pane)))
4517       XtRealizeWidget (XtParent(pane));
4518    ForceMenuPaneOnScreen (pane, &rootx, &rooty);
4519    XtMoveWidget (XtParent(pane), rootx, rooty);
4520 
4521    /*
4522     * Set up a pointer grab; this allows us to catch all selects and
4523     * to then unpost the menus, regardless as to where the select
4524     * occurred.
4525     */
4526    XGrabPointer (XtDisplay(menuMgr), XtWindow(assocWidget), TRUE,
4527          ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|
4528          PointerMotionMask, GrabModeAsync, GrabModeAsync, None, (Cursor)NULL,
4529          CurrentTime);
4530 
4531    /* Post the menupane */
4532    Post (menuMgr, pane, XtGrabExclusive);
4533 
4534    /*
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.
4538     */
4539    if (menuMgr->manager.traversal_on)
4540    {
4541       if (XQueryPointer(XtDisplay(menuMgr),
4542                         RootWindowOfScreen(menuMgr->core.screen),
4543                         &root, &child, &introotx, &introoty, &intchildx,
4544                         &intchildy, &returnMask))
4545       {
4546          menuMgr->popup_mgr.origMouseX = introotx;
4547          menuMgr->popup_mgr.origMouseY = introoty;
4548       }
4549 
4550       /* Set the traversal focus to the pane */
4551       XwMoveFocus (pane);
4552    }
4553 }
4554 
4555 
4556 /*************************************<->*************************************
4557  *
4558  *  XwPostPopup(parameters)
4559  *
4560  *   Description:
4561  *   -----------
4562  *     This is a utility routine which may be used by an application to
4563  *     manually post a popup menu pane.
4564  *
4565  *
4566  *   Inputs:
4567  *   ------
4568  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4569  *
4570  *   Outputs:
4571  *   -------
4572  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4573  *
4574  *   Procedures Called
4575  *   -----------------
4576  *
4577  *************************************<->***********************************/
4578 
XwPostPopup(menuMgr,pane,relativeTo,x,y)4579 void XwPostPopup (menuMgr, pane, relativeTo, x, y)
4580 
4581    Widget menuMgr, pane, relativeTo;
4582    Position x, y;
4583 
4584 {
4585    /* Only popup a menu if it is a subclass of the popup menu manager */
4586    /* Do nothing if invalid menu manager Id */
4587    if (menuMgr == NULL)
4588       return;
4589 
4590    if (XtIsSubclass (menuMgr, XwpopupmgrWidgetClass))
4591    {
4592        (*(((XwPopupMgrWidgetClass)
4593 	XtClass(menuMgr))-> popup_mgr_class.manualPost))
4594          (menuMgr, pane, relativeTo, x, y);
4595    }
4596    else
4597    {
4598       XtWarning ("PopupMgr: Widget is not a subclass of menuMgr");
4599    }
4600 }
4601 
4602 
4603 /*************************************<->*************************************
4604  *
4605  *  SendFakeLeaveNotify(parameters)
4606  *
4607  *   Description:
4608  *   -----------
4609  *     xxxxxxxxxxxxxxxxxxxxxxx
4610  *
4611  *
4612  *   Inputs:
4613  *   ------
4614  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4615  *
4616  *   Outputs:
4617  *   -------
4618  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4619  *
4620  *   Procedures Called
4621  *   -----------------
4622  *
4623  *************************************<->***********************************/
4624 
SendFakeLeaveNotify(focus_widget,mode)4625 static void SendFakeLeaveNotify (focus_widget, mode)
4626 
4627    Widget focus_widget;
4628    int mode;
4629 
4630 {
4631    XEvent event;
4632 
4633    if (mode == ULTIMATE_PARENT)
4634    {
4635       /* Search up to top level shell */
4636       while (XtParent(focus_widget) != NULL)
4637          focus_widget = XtParent(focus_widget);
4638    }
4639    else
4640    {
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);
4645    }
4646 
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;
4654 
4655    XtDispatchEvent (&event);
4656 }
4657 
4658 
4659 /*************************************<->*************************************
4660  *
4661  *  SetUpStickyList(parameters)
4662  *
4663  *   Description:
4664  *   -----------
4665  *     xxxxxxxxxxxxxxxxxxxxxxx
4666  *
4667  *
4668  *   Inputs:
4669  *   ------
4670  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4671  *
4672  *   Outputs:
4673  *   -------
4674  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4675  *
4676  *   Procedures Called
4677  *   -----------------
4678  *
4679  *************************************<->***********************************/
4680 
SetUpStickyList(menuMgr,widget)4681 static void SetUpStickyList (menuMgr, widget)
4682 
4683    XwPopupMgrWidget menuMgr;
4684    Widget widget;
4685 
4686 {
4687    int i;
4688 
4689    menuMgr->popup_mgr.numSavedCascades = 0;
4690 
4691    if ((XtIsSubclass (widget, XwmenubuttonWidgetClass)) &&
4692        (menuMgr->popup_mgr.stickyMode) &&
4693        (XtParent(widget) == menuMgr->popup_mgr.currentCascadeList
4694           [menuMgr->popup_mgr.numCascades -1]))
4695    {
4696       if (menuMgr->popup_mgr.numCascades >
4697           menuMgr->popup_mgr.sizeSavedCascadeList)
4698       {
4699           menuMgr->popup_mgr.sizeSavedCascadeList =
4700              menuMgr->popup_mgr.sizeCascadeList;
4701 	  menuMgr->popup_mgr.savedCascadeList =
4702 	     (Widget *) XtRealloc((char *)(menuMgr->popup_mgr.savedCascadeList),
4703                                   menuMgr->popup_mgr.sizeSavedCascadeList *
4704 			          sizeof (Widget));
4705        }
4706 
4707        menuMgr->popup_mgr.numSavedCascades = menuMgr->popup_mgr.numCascades;
4708        menuMgr->popup_mgr.lastSelected = widget;
4709 
4710        /* Set this widget as the traversal item */
4711        if (menuMgr->manager.traversal_on)
4712        {
4713           XwMenuPaneWidget pane;
4714 
4715           pane = ((XwMenuPaneWidget)(menuMgr->popup_mgr.currentCascadeList
4716           [menuMgr->popup_mgr.numCascades -1]));
4717           pane->manager.active_child = widget;
4718           XtSetKeyboardFocus ((Widget)pane, widget);
4719        }
4720 
4721        for (i=0; i < menuMgr->popup_mgr.numSavedCascades; i++)
4722           menuMgr->popup_mgr.savedCascadeList[i] =
4723 	          menuMgr->popup_mgr.currentCascadeList[i];
4724    }
4725    else if (menuMgr->manager.traversal_on)
4726    {
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);
4731    }
4732 }
4733 
4734 
4735 /*************************************<->*************************************
4736  *
4737  *  BtnSensitivityChanged(parameters)
4738  *
4739  *   Description:
4740  *   -----------
4741  *     xxxxxxxxxxxxxxxxxxxxxxx
4742  *
4743  *
4744  *   Inputs:
4745  *   ------
4746  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4747  *
4748  *   Outputs:
4749  *   -------
4750  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4751  *
4752  *   Procedures Called
4753  *   -----------------
4754  *
4755  *************************************<->***********************************/
4756 
BtnSensitivityChanged(menuMgr,btn)4757 static void BtnSensitivityChanged (menuMgr, btn)
4758 
4759    XwPopupMgrWidget menuMgr;
4760    Widget btn;
4761 
4762 {
4763    /* Noop */
4764 }
4765 
4766 
4767 /*************************************<->*************************************
4768  *
4769  *  PaneSensitivityChanged(parameters)
4770  *
4771  *   Description:
4772  *   -----------
4773  *     xxxxxxxxxxxxxxxxxxxxxxx
4774  *
4775  *
4776  *   Inputs:
4777  *   ------
4778  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4779  *
4780  *   Outputs:
4781  *   -------
4782  *     xxxxxxxxxxxx = xxxxxxxxxxxxx
4783  *
4784  *   Procedures Called
4785  *   -----------------
4786  *
4787  *************************************<->***********************************/
4788 
PaneSensitivityChanged(menuMgr,pane)4789 static void PaneSensitivityChanged (menuMgr, pane)
4790 
4791    XwPopupMgrWidget menuMgr;
4792    Widget pane;
4793 
4794 {
4795    /* Noop */
4796 }
4797