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) &¤t->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