1 /**
2 *
3 * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/MenuShell.c,v 1.6 2005/03/19 10:02:25 dannybackx Exp $
4 *
5 * Copyright (C) 1996 Free Software Foundation, Inc.
6 * Copyright � 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005 LessTif Development Team
7 *
8 * This file is part of the GNU LessTif Library.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 **/
25
26 static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/MenuShell.c,v 1.6 2005/03/19 10:02:25 dannybackx Exp $";
27
28 #include <LTconfig.h>
29
30 #include <XmI/XmI.h>
31 #include <Xm/XmP.h>
32 #include <Xm/MenuShellP.h>
33 #include <Xm/MenuUtilP.h>
34 #include <Xm/RowColumnP.h>
35 #include <Xm/CascadeBP.h>
36 #include <Xm/CascadeBGP.h>
37 #include <Xm/TransltnsP.h>
38
39 #include <Xm/SpecRenderT.h>
40
41 #include <XmI/DebugUtil.h>
42
43 /* ? */
44 #undef USE_FOCUS
45
46 /* Forward Declarations */
47 static void class_initialize(void);
48 static void class_part_initialize(WidgetClass w_class);
49 static void initialize(Widget request, Widget new_w,
50 ArgList args, Cardinal *num_args);
51 static void destroy(Widget w);
52 static void realize(Widget w, XtValueMask *value_mask,
53 XSetWindowAttributes *attributes);
54
55 #if 0
56 static void expose(Widget w, XEvent *event, Region region);
57 #endif
58
59 static void resize(Widget w);
60 static Boolean set_values(Widget current, Widget request, Widget new_w,
61 ArgList args, Cardinal *num_args);
62 static XtGeometryResult geometry_manager(Widget w,
63 XtWidgetGeometry *request,
64 XtWidgetGeometry *reply);
65 static void change_managed(Widget w);
66 static void insert_child(Widget w);
67
68 #define Offset(field) XtOffsetOf(XmMenuShellRec, menu_shell.field)
69
70 /* Resources for the MenuShell class */
71 static XtResource resources[] =
72 {
73 {
74 XmNdefaultFontList, XmCDefaultFontList, XmRFontList,
75 sizeof(XmFontList), Offset(default_font_list),
76 XmRString, (XtPointer)NULL
77 },
78 {
79 XmNlabelFontList, XmCLabelFontList, XmRFontList,
80 sizeof(XmFontList), Offset(label_font_list),
81 XmRFontList, (XtPointer)NULL
82 },
83 {
84 XmNbuttonFontList, XmCButtonFontList, XmRFontList,
85 sizeof(XmFontList), Offset(button_font_list),
86 XmRFontList, (XtPointer)NULL
87 }
88 };
89
90 static void MenuShellPopdownDone(Widget w, XEvent *event, String *params, Cardinal *num_params);
91 static void MenuShellPopdownOne(Widget w, XEvent *event, String *params, Cardinal *num_params);
92 static void MenuShellPopdownEveryone(Widget w, XEvent *event, String *params, Cardinal *num_params);
93 static void _XmXtMenuPopup(Widget widget, XEvent *event, String *params, Cardinal *num_params);
94 static void _XmXtMenuPopdown(Widget widget, XEvent *event, String *params, Cardinal *num_params);
95 static void MenuShellPopupSharedMenuPane(Widget w, Widget w2, XEvent *event);
96 static XmRenderTable GetRenderTable(Widget w, XtEnum renderTableType);
97
98 static XtActionsRec actions[] =
99 {
100 {"MenuShellPopdownOne", MenuShellPopdownOne},
101 {"MenuShellPopdownDone", MenuShellPopdownDone},
102 {"XtMenuPopup", _XmXtMenuPopup},
103 {"XtMenuPopdown", _XmXtMenuPopdown},
104 {"ClearTraversal", _XmClearTraversal},
105 };
106
107 static XmBaseClassExtRec _XmMenuSCoreClassExtRec = {
108 /* next_extension */ NULL,
109 /* record_type */ NULLQUARK,
110 /* version */ XmBaseClassExtVersion,
111 /* size */ sizeof(XmBaseClassExtRec),
112 /* initialize_prehook */ NULL,
113 /* set_values_prehook */ NULL,
114 /* initialize_posthook */ NULL,
115 /* set_values_posthook */ NULL,
116 /* secondary_object_class */ NULL,
117 /* secondary_object_create */ NULL,
118 /* get_secondary_resources */ NULL,
119 /* fast_subclass */ { 0 },
120 /* get_values_prehook */ NULL,
121 /* get_values_posthook */ NULL,
122 /* class_part_init_prehook */ NULL,
123 /* class_part_init_posthook */ NULL,
124 /* ext_resources */ NULL,
125 /* compiled_ext_resources */ NULL,
126 /* num_ext_resources */ 0,
127 /* use_sub_resources */ False,
128 /* widget_navigable */ NULL,
129 /* focus_change */ NULL,
130 /* wrapper_data */ NULL
131 };
132
133
134 XmMenuShellClassRec xmMenuShellClassRec = {
135 /* Core class part */
136 {
137 /* superclass */ (WidgetClass) &overrideShellClassRec,
138 /* class_name */ "XmMenuShell",
139 /* widget_size */ sizeof(XmMenuShellRec),
140 /* class_initialize */ class_initialize,
141 /* class_part_initialize */ class_part_initialize,
142 /* class_inited */ False,
143 /* initialize */ initialize,
144 /* initialize_hook */ NULL,
145 /* realize */ realize,
146 /* actions */ actions,
147 /* num_actions */ XtNumber(actions),
148 /* resources */ resources,
149 /* num_resources */ XtNumber(resources),
150 /* xrm_class */ NULLQUARK,
151 /* compress_motion */ True,
152 /* compress_exposure */ XtExposeCompressMaximal /*XtExposeCompressMultiple*/,
153 /* compress_enterleave */ True,
154 /* visible_interest */ False,
155 /* destroy */ destroy,
156 /* resize */ resize,
157 /* expose */ XtInheritExpose /*expose*/,
158 /* set_values */ set_values,
159 /* set_values_hook */ NULL,
160 /* set_values_almost */ XtInheritSetValuesAlmost,
161 /* get_values_hook */ NULL,
162 /* accept_focus */ NULL,
163 /* version */ XtVersion,
164 /* callback offsets */ NULL,
165 /* tm_table */ _XmMenuShell_translations,
166 /* query_geometry */ NULL,
167 /* display_accelerator */ NULL,
168 /* extension */ (XtPointer)&_XmMenuSCoreClassExtRec
169 },
170 /* Composite class part */
171 {
172 /* geometry manager */ geometry_manager,
173 /* change_managed */ change_managed,
174 /* insert_child */ insert_child,
175 /* delete_child */ XtInheritDeleteChild,
176 /* extension */ NULL,
177 },
178 /* Shell class part */
179 {
180 /* extension */ NULL,
181 },
182 /* Override class part */
183 {
184 /* extension */ NULL,
185 },
186 /* XmMenuShell class part */
187 {
188 /* popdownOne */ MenuShellPopdownOne,
189 /* popdownEveryone */ MenuShellPopdownEveryone,
190 /* popdownDone */ MenuShellPopdownDone,
191 /* popupSharedMenupane */ MenuShellPopupSharedMenuPane,
192 /* extension */ NULL,
193 },
194 };
195
196 static XmSpecRenderTraitRec _XmMenuShellTraitRec = {
197 /* version */ 0,
198 /* cb */ GetRenderTable
199 };
200
201 WidgetClass xmMenuShellWidgetClass = (WidgetClass)&xmMenuShellClassRec;
202
203
204 static void
class_initialize(void)205 class_initialize(void)
206 {
207 _XmInitializeExtensions();
208 _XmMenuSCoreClassExtRec.record_type = XmQmotif;
209
210
211 if (! XmeTraitSet((XtPointer)xmMenuShellWidgetClass, XmQTspecifyRenderTable,
212 (XtPointer)&_XmMenuShellTraitRec)) {
213 _XmWarning(NULL, "XmMenuShell ClassInitialize: XmeTraitSet failed\n");
214 }
215 }
216
217
218 static void
class_part_initialize(WidgetClass widget_class)219 class_part_initialize(WidgetClass widget_class)
220 {
221 _XmFastSubclassInit(widget_class, XmMENU_SHELL_BIT);
222 }
223
224
225 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)226 initialize(Widget request, Widget new_w,
227 ArgList args, Cardinal *num_args)
228 {
229 DEBUGOUT(_LtDebug(__FILE__, new_w,
230 "%s:initialize(%d) - %i args\n"
231 "\trequest X %5i Y %5i W %5i H %5i\n"
232 "\t new_w X %5i Y %5i W %5i H %5i\n",
233 __FILE__, __LINE__,
234 *num_args,
235 XtX(request), XtY(request),
236 XtWidth(request), XtHeight(request),
237 XtX(new_w), XtY(new_w),
238 XtWidth(new_w), XtHeight(new_w)));
239 DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
240
241 if (MS_DefaultFontList(new_w) != NULL)
242 {
243 MS_DefaultFontList(new_w) = XmFontListCopy(MS_DefaultFontList(new_w));
244 }
245 else
246 {
247 MS_DefaultFontList(new_w) = _XmGetDefaultFontList(new_w, XmBUTTON_FONTLIST);
248 }
249 if (MS_ButtonFontList(new_w) == NULL)
250 {
251 if (MS_DefaultFontList(new_w) != NULL) {
252 MS_ButtonFontList(new_w) = XmFontListCopy(MS_DefaultFontList(new_w));
253 } else {
254 MS_ButtonFontList(new_w) = _XmGetDefaultFontList(new_w, XmBUTTON_FONTLIST);
255 }
256 } else {
257 MS_ButtonFontList(new_w) = XmFontListCopy(MS_ButtonFontList(new_w));
258 }
259
260 if (MS_LabelFontList(new_w) == NULL) {
261 if (MS_DefaultFontList(new_w) != NULL) {
262 MS_LabelFontList(new_w) = XmFontListCopy(MS_DefaultFontList(new_w));
263 } else {
264 MS_LabelFontList(new_w) = _XmGetDefaultFontList(new_w, XmLABEL_FONTLIST);
265 }
266 } else {
267 MS_LabelFontList(new_w) = XmFontListCopy(MS_LabelFontList(new_w));
268 }
269
270 XtBorderWidth(new_w) = 0;
271
272 /* menu shells must be given non-zero width's and height's when
273 * they are initialized, as we create the window (realize the widget) here.
274 */
275
276 if (XtWidth(new_w) == 0 || XtHeight(new_w) == 0)
277 {
278 DEBUGOUT(_LtDebug(__FILE__, new_w,
279 "Initialize: dimensions %d %d changed to 1x1",
280 XtWidth(new_w), XtHeight(new_w)));
281
282 XtWidth(new_w) = XtHeight(new_w) = 1;
283 }
284
285 MS_PrivateShell(new_w) = False;
286
287 MS_FocusData(new_w) = _XmCreateFocusData();
288 MS_FocusPolicy(new_w) = XmEXPLICIT;
289
290 XtRealizeWidget(new_w);
291 }
292
293 static void
destroy(Widget w)294 destroy(Widget w)
295 {
296 DEBUGOUT(_LtDebug(__FILE__, w, "Destroy\n"));
297 _XmDestroyFocusData(MS_FocusData(w));
298
299 XmFontListFree(MS_DefaultFontList(w));
300 XmFontListFree(MS_ButtonFontList(w));
301 XmFontListFree(MS_LabelFontList(w));
302 }
303
304 static void
resize(Widget w)305 resize(Widget w)
306 {
307 DEBUGOUT(_LtDebug(__FILE__, w, "Resize -- (%d, %d)\n",
308 XtWidth(w), XtHeight(w)));
309 }
310
311 static void
realize(Widget w,XtValueMask * value_mask,XSetWindowAttributes * attributes)312 realize(Widget w,
313 XtValueMask *value_mask,
314 XSetWindowAttributes *attributes)
315 {
316 /* Motif inherits this method */
317 *value_mask = CWBackPixmap | CWBorderPixel | CWBitGravity |
318 CWOverrideRedirect | CWEventMask | CWSaveUnder | CWColormap;
319
320 /* FIX ME: might it be that Xt passes these in attributes ? */
321 attributes->background_pixmap = None;
322 attributes->save_under = True; /* FIX ME: hardwired? */
323 attributes->bit_gravity = NorthWestGravity;
324 attributes->override_redirect = True;
325 attributes->event_mask = ButtonPressMask | ButtonReleaseMask |
326 StructureNotifyMask;
327
328 if (XtWidth(w) == 0)
329 {
330 XtWidth(w) = 1;
331 }
332 if (XtHeight(w) == 0)
333 {
334 XtHeight(w) = 1;
335 }
336
337 #define superclass (&overrideShellClassRec)
338 (*superclass->core_class.realize) (w, value_mask, attributes);
339 #undef superclass
340
341 DEBUGOUT(_LtDebug(__FILE__, w, "Realize (size %dx%d)\n",
342 XtWidth(w), XtHeight(w)));
343 }
344
345 #if 0
346 static void
347 expose(Widget w, XEvent *event, Region region)
348 {
349 DEBUGOUT(_LtDebug(__FILE__, w, "Expose\n"));
350 }
351 #endif
352
353 static Boolean
set_values(Widget current,Widget request,Widget new_w,ArgList args,Cardinal * num_args)354 set_values(Widget current, Widget request, Widget new_w,
355 ArgList args, Cardinal *num_args)
356 {
357 DEBUGOUT(_LtDebug(__FILE__, new_w, "SetValues\n"));
358 DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
359
360 if (MS_DefaultFontList(new_w) != MS_DefaultFontList(current)) {
361 XmFontListFree(MS_DefaultFontList(current));
362 MS_DefaultFontList(new_w) = XmFontListCopy(MS_DefaultFontList(new_w));
363 }
364
365 if (MS_ButtonFontList(new_w) != MS_ButtonFontList(current)) {
366 XmFontListFree(MS_ButtonFontList(current));
367 MS_ButtonFontList(new_w) = XmFontListCopy(MS_ButtonFontList(new_w));
368 }
369
370 if (MS_LabelFontList(new_w) != MS_LabelFontList(current)) {
371 XmFontListFree(MS_LabelFontList(current));
372 MS_LabelFontList(new_w) = XmFontListCopy(MS_LabelFontList(new_w));
373 }
374
375 return True;
376 }
377
378 static XtGeometryResult
geometry_manager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)379 geometry_manager(Widget w,
380 XtWidgetGeometry *request,
381 XtWidgetGeometry *reply)
382 {
383 XtGeometryResult res;
384 XtWidgetGeometry wants;
385 Widget ms = XtParent(w);
386
387 DEBUGOUT(_LtDebug2(__FILE__, ms, w,
388 "geometry_manager: request %s, allow_shell_resize %s\n",
389 _LtDebugWidgetGeometry2String(request),
390 ((XmMenuShellWidget)ms)->shell.allow_shell_resize
391 ? "True"
392 : "False"));
393
394 if ((request->request_mode & (CWWidth | CWHeight)) == 0)
395 {
396 return XtGeometryYes;
397 }
398
399 DEBUGOUT(_LtDebug(__FILE__, ms,
400 "geometry_manager: %s\n",
401 _LtDebugWidgetGeometry2String(request)));
402
403 wants = *request;
404
405 res = _XmMakeGeometryRequest(ms, &wants);
406
407 if (res == XtGeometryNo)
408 {
409 DEBUGOUT(_LtDebug(__FILE__, w,
410 "XtGeometryNo returned... THIS SHOULD NOT HAPPEN\n"));
411 }
412 *reply = wants;
413
414 if (wants.request_mode & CWWidth)
415 {
416 XtWidth(w) = wants.width;
417 }
418 if (wants.request_mode & CWHeight)
419 {
420 XtHeight(w) = wants.height;
421 }
422
423 DEBUGOUT(_LtDebug(__FILE__, w,
424 "geometry_manager: size %dx%d => Yes\n",
425 reply->width, reply->height));
426
427 return XtGeometryYes;
428 }
429
430 static void
change_managed(Widget w)431 change_managed(Widget w)
432 {
433 XtWidgetGeometry geo;
434 Widget child;
435 Cardinal i;
436
437 DEBUGOUT(_LtDebug(__FILE__, w,
438 "ChangeManaged: trying to find child to manage\n"));
439
440 /* FIX ME: isn't having no managed children perfectly valid ? */
441 child = NULL;
442 for (i = 0; i < MGR_NumChildren(w); i++)
443 {
444 DEBUGOUT(_LtDebug2(__FILE__, w,
445 MGR_Children(w)[i], "ChangeManaged [%d] %s\n",
446 i,
447 XtIsManaged(MGR_Children(w)[i])
448 ? "Managed"
449 : "Not Managed"));
450 if (XtIsManaged(MGR_Children(w)[i]))
451 {
452
453 if (!MS_PrivateShell(w))
454 {
455 child = MGR_Children(w)[i];
456 break;
457 }
458 /* I don't think this is really necessary */
459 else
460 {
461 Widget tmp = MGR_Children(w)[i];
462
463 if (RC_Type(tmp) != XmMENU_POPUP && RC_CascadeBtn(tmp))
464 {
465 if (XmIsCascadeButton(RC_CascadeBtn(tmp)) &&
466 CB_IsArmed(RC_CascadeBtn(tmp)))
467 {
468 child = tmp;
469 break;
470 }
471 else if (XmIsCascadeButtonGadget(RC_CascadeBtn(tmp)) &&
472 CBG_IsArmed(RC_CascadeBtn(tmp)))
473 {
474 child = tmp;
475 break;
476 }
477 }
478 }
479 }
480 #if 0
481 /* rws 26 Sep 1999
482 This is for http://www.bartels.de/baedform.htm. It seems that it
483 un-manages the menus somewhwhere along the line. We manage them
484 in insert_child, and expect them to stay managed.
485 */
486 /* rws 29 Sep 1999
487 However this messes up Mozilla's Go menu, sigh. So instead just
488 make sure the menu is managed in MenuShellPopupSharedMenuPane
489 */
490 else
491 {
492 if (MS_PrivateShell(w))
493 {
494 if (!XtIsManaged(MGR_Children(w)[i]))
495 {
496 XtManageChild(MGR_Children(w)[i]);
497 }
498 }
499 }
500 #endif
501 }
502
503 if (!child)
504 {
505 DEBUGOUT(_LtDebug(__FILE__, w,
506 "change_managed: no managed children so we must"
507 " be popping down\n"));
508
509 if (Shell_PoppedUp(w))
510 {
511 if (MS_PrivateShell(w))
512 {
513 DEBUGOUT(_LtDebug(__FILE__, w, " PrivateShell\n"));
514
515 _XmXtMenuPopdown(w, NULL, NULL, NULL);
516 }
517 else
518 {
519 DEBUGOUT(_LtDebug(__FILE__, w, " public shell\n"));
520 _XmRemoveGrab(w);
521
522 XtUnmapWidget(w);
523 XtCallCallbacks(w, XmNpopdownCallback, NULL);
524 Shell_PoppedUp(w) = False;
525
526 if (_XmIsActiveTearOff(MGR_Children(w)[0]))
527 {
528 Widget rc = MGR_Children(w)[0];
529
530 RCClass_MenuProcs(XtClass(rc))(XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL,
531 rc, NULL);
532 }
533 }
534 }
535
536 return;
537 }
538
539 /* MenuShell's take their height/width from the child */
540 /* MLM: either of these work, I think, but for now... */
541 geo.width = XtWidth(child) == 0 ? 1 : XtWidth(child);
542 geo.height = XtHeight(child) == 0 ? 1 : XtHeight(child);
543
544 /* FIX ME: should look at the flags */
545 _XmResizeObject(w, geo.width, geo.height, 0);
546
547 DEBUGOUT(_LtDebug2(__FILE__, w, child,
548 "ChangeManaged width %d height %d\n",
549 XtWidth(w), XtHeight(w)));
550
551 /* MenuShell children should be at 0,0 positions !
552 * Danny 17/11/96 */
553 /* Actually they are at -border_width (similiar to Vendor.c)
554 * rws 24 Feb 1197 */
555 _XmMoveObject(child, -XtBorderWidth(child), -XtBorderWidth(child));
556
557 if (RC_Type(child) == XmMENU_POPUP)
558 {
559 XmMenuState state = _XmGetMenuState(child);
560
561 DEBUGOUT(_LtDebug2(__FILE__, w, child, "Popping up\n"));
562
563 _XmPostPopupMenu(child,
564 (XEvent *)&state->RC_ButtonEventStatus.event);
565
566 state->RC_ButtonEventStatus.event.type = 0;
567 }
568 else
569 {
570 /* FIX ME: skip if shared menu shell. Children of shared menu shells
571 * do get managed upon creation. More correctly: in insert_child.
572 */
573 if (RC_Type(child) == XmMENU_PULLDOWN)
574 {
575 DEBUGOUT(_LtDebug(__FILE__, child, "Pulldown posting\n"));
576
577 if (RC_CascadeBtn(child))
578 {
579 DEBUGOUT(_LtDebug(__FILE__, child, "Child is cascade\n"));
580 if (XtIsManaged(child))
581 {
582 DEBUGOUT(_LtDebug(__FILE__, w, "Popping up\n"));
583
584 if (MS_PrivateShell(w))
585 {
586 DEBUGOUT(_LtDebug(__FILE__, w, "Popping up private shell\n"));
587 MSClass_PopupSharedMenuPane(w)(w, child, NULL);
588 }
589 else
590 {
591 DEBUGOUT(_LtDebug(__FILE__, w, "Popping up public shell\n"));
592 XtManageChild(child);
593 XMapRaised(XtDisplay(w), XtWindow(w));
594 XtCallCallbacks(w, XmNpopupCallback, NULL);
595 #ifdef NEW_MAPCALLBACK
596 /*
597 _XmCallRowColumnMapCallback(w2, event);
598 */
599 #endif
600 Shell_PoppedUp(w) = True;
601 }
602 }
603 else
604 {
605 DEBUGOUT(_LtDebug(__FILE__, w, "Popping down\n"));
606
607 if (MS_PrivateShell(w))
608 {
609 DEBUGOUT(_LtDebug(__FILE__, w, " PrivateShell\n"));
610 _XmXtMenuPopdown(w, NULL, NULL, NULL);
611 }
612 else
613 {
614 DEBUGOUT(_LtDebug(__FILE__, w, " public shell\n"));
615 if (RC_Type(child) == XmMENU_POPUP || RC_Type(child) == XmMENU_OPTION)
616 {
617 _XmRemoveGrab(w);
618 }
619
620 XtUnmapWidget(w);
621 XtCallCallbacks(w, XmNpopdownCallback, NULL);
622 XtUnmanageChild(child);
623 }
624 }
625 }
626 else
627 {
628 DEBUGOUT(_LtDebug(__FILE__, w, "Not cascade\n"));
629 /* Not attached to a cascade button. */
630 if (XtIsManaged(child))
631 {
632 /* Probably the user managed the pulldown after creation. */
633 /* FIX ME: Motif 2.0 does issue a warning here. */
634 DEBUGOUT(_LtDebug(__FILE__, child,
635 "Unmanaging in change_managed...\n"));
636 XtUnmanageChild(child);
637 }
638 }
639 }
640 }
641 }
642
643 static void
insert_child(Widget w)644 insert_child(Widget w)
645 {
646 if (!XmIsRowColumn(w))
647 {
648 _XmWarning(w,
649 "MenuShell widgets must have a xmRowColumnWidgetClass "
650 "child.");
651 return;
652 }
653 else
654 {
655 /* T. Straumann: M*TIF enforces 0 borderWidth on MenuShell's child */
656 if ( 0 != XtBorderWidth(w) )
657 {
658 XtVaSetValues(w,XmNborderWidth,0,NULL);
659 }
660 #define superclass (&overrideShellClassRec)
661 (*superclass->composite_class.insert_child) (w);
662 #undef superclass
663
664 /* this might not need to get done.
665 * Does the composite class's insert child realize
666 * a widget if the composite is realized? */
667 XtRealizeWidget(w);
668
669 if (MS_PrivateShell(XtParent(w)))
670 {
671 XtManageChild(w);
672 }
673 }
674 }
675
676
677 static void
MenuShellPopdownDone(Widget w,XEvent * event,String * params,Cardinal * num_params)678 MenuShellPopdownDone(Widget w, XEvent *event,
679 String *params, Cardinal *num_params)
680 {
681 Cardinal numparams = 0;
682 Widget rc, toplevelrc;
683 Widget menu_shell = NULL;
684 Cardinal i;
685 XmMenuState state = _XmGetMenuState(w);
686
687 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone()\n"));
688
689 /* make sure the trigger event here hasn't already been processed */
690 if (_XmMenuGetInPMMode(w) && event && event->type == ButtonRelease &&
691 event->xbutton.time <= state->RC_ButtonEventStatus.time)
692 {
693 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone(): exiting b/c already processed\n"));
694 return;
695 }
696
697 #if 0
698 /*
699 * Don't use an event that's within the multi click time.
700 * Hopefully this is an event which we can discard :-)
701 * If we get bug reports about things not disappearing when
702 * the user is fast, this is the reason.
703 * Danny 22/04/1998
704 *
705 * I also have a bad feeling about the test above. Is it meant to do
706 * what I changed it to below ?
707 */
708 if (_XmMenuGetInPMMode(w) && event && event->type == ButtonRelease &&
709 event->xbutton.time <= state->RC_ButtonEventStatus.time
710 + XtGetMultiClickTime(XtDisplay(w)))
711 {
712 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone(): exiting b/c user too fast\n"));
713 return;
714 }
715 #endif
716
717 /* must be a menu shell here:
718 assert(XmIsMenuShell(w)); */
719
720 if (MGR_NumChildren(w) == 0) {
721 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone(): exiting b/c no children\n"));
722 return;
723 }
724 /* Find a child that is managed */
725 rc = NULL;
726 for (i = 0; i < MGR_NumChildren(w); i++)
727 {
728 rc = MGR_Children(w)[i];
729 if (XmIsRowColumn(rc) && XtIsManaged(rc))
730 {
731 break;
732 }
733 }
734
735 if (!rc)
736 {
737 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone - NO RC\n"));
738 return;
739 }
740
741 DEBUGOUT(_LtDebug2(__FILE__, w, rc,
742 "MenuShellPopdownDone - found RC %s, posted: %s\n",
743 XtName(rc), RC_PopupPosted(rc) ? XtName(RC_PopupPosted(rc)) : "NULL"));
744
745 #if 1
746 /*
747 * Don't use an event that's within the multi click time.
748 * Hopefully this is an event which we can discard :-)
749 * If we get bug reports about things not disappearing when
750 * the user is fast, this is the reason.
751 * Danny 22/04/1998
752 *
753 * I also have a bad feeling about the test above. Is it meant to do
754 * what I changed it to below ?
755 */
756 /* Danny had this ifdef'd out, but it seems to be exactly what
757 * Motif does, so I put it back in. In Motif, a quick click/release
758 * causes the menu to "stick" open.
759 * -dwilliss 28-Sep-04
760 */
761 if (_XmMenuGetInPMMode(w) && event && event->type == ButtonRelease &&
762 event->xbutton.time <= state->RC_ButtonEventStatus.time
763 + XtGetMultiClickTime(XtDisplay(w)))
764 {
765 if (RC_Type(rc) != XmMENU_OPTION)
766 {
767 /* Not that this _shouldn't_ be done for option menus, but I'm
768 * not sure if this is the correct way to do it for option menus,
769 * so in that case, leave them alone for now
770 * -- dwilliss 28-Sep-04
771 */
772 _XmMenuFocus(rc, XmMENU_FOCUS_SAVE, CurrentTime);
773 RCClass_MenuTraverse(rc, XmTRAVERSE_HOME);
774 XAllowEvents(XtDisplay(rc), SyncPointer, event->xbutton.time);
775 }
776 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownDone(): exiting b/c user too fast\n"));
777 return;
778 }
779 #endif
780
781
782 _XmGetActiveTopLevelMenu(rc, &toplevelrc);
783
784 if (!toplevelrc)
785 {
786 DEBUGOUT(_LtDebug2(__FILE__, w, rc, "No toplevelrc\n"));
787
788 #if 0
789 /*
790 * This probably only happens for accelerators, and in that
791 * case there's nothing to unmanage.
792 * Removing this call fixes the problem in XmHTML's example_2.
793 * Danny 3/2/1998.
794 */
795 XtUnmanageChild(rc);
796 #endif
797 return; /* FIX ME */
798 }
799
800 if (XmIsOptionMenu(toplevelrc))
801 {
802 if (RC_PopupPosted(toplevelrc))
803 {
804 menu_shell = XtParent(RC_PopupPosted(toplevelrc));
805 }
806 else
807 {
808 DEBUGOUT(_LtDebug2(__FILE__, w, rc,
809 "No posted menu\n"));
810 return;
811 }
812 }
813 else
814 {
815 menu_shell = XtParent(toplevelrc);
816 }
817
818 if (XmIsMenuShell(menu_shell))
819 {
820 /* assert(menu_shell && XmIsMenuShell(menu_shell)); */
821
822 if (Shell_PoppedUp(menu_shell))
823 {
824 DEBUGOUT(_LtDebug(__FILE__, w,
825 "calling PopdownEveryone on toplevel menushell\n"));
826
827 MSClass_PopdownEveryone(menu_shell)(menu_shell, event, params, &numparams);
828 }
829 else
830 {
831 DEBUGOUT(_LtDebug(__FILE__, w,
832 "MenuShellPopdownDone - MenuShell is not popped up, must have been an accelerator\n"));
833 return;
834 }
835 }
836 else if (XtIsTransientShell(menu_shell))
837 {
838 MSClass_PopdownEveryone(w)(w, event, params, &numparams);
839 }
840
841 /* is a popup? */
842 if (_XmMenuGetInPMMode(w))
843 {
844 Widget msh = XtParent(rc);
845
846 if (msh && XmIsMenuShell(msh) && MS_PrivateShell(msh))
847 {
848 _XmXtMenuPopdown(msh, NULL, NULL, NULL);
849 }
850 else
851 {
852 DEBUGOUT(_LtDebug(__FILE__, rc, "Unmanaging...\n"));
853 {
854 Widget realpar;
855
856 if (XtIsShell(XtParent(rc)))
857 {
858 realpar = XtParent(XtParent(rc));
859 }
860 else
861 {
862 realpar = XtParent(rc);
863 }
864 DEBUGOUT(_LtDebug("EMACS", realpar, "%s:%s(%d) - UNGRAB %i %i\n", __FILE__, "MenuShellPopdownDone" , __LINE__,
865 RC_PostButton(rc), RC_PostModifiers(rc)));
866 XtUngrabButton(realpar,
867 RC_PostButton(rc), RC_PostModifiers(rc));
868 XtUngrabKeyboard(realpar, CurrentTime); /* XXXX 761607 */
869 }
870 XtUnmanageChild(rc);
871 if (_XmIsActiveTearOff(rc))
872 {
873 DEBUGOUT(_LtDebug(__FILE__, rc, "Unmanaging... ActiveTearOff\n"));
874 XtManageChild(rc);
875 }
876 }
877 }
878
879 /* FIX ME: this is not really elegant. */
880 if (RC_LastSelectToplevel(rc) &&
881 (XmIsMenuBar(RC_LastSelectToplevel(rc)) ||
882 XmIsOptionMenu(RC_LastSelectToplevel(rc))))
883 {
884 Widget tmp = RC_LastSelectToplevel(rc);
885
886 DEBUGOUT(_LtDebug(__FILE__, tmp,
887 " calling menuDisarm on lastSelectTopLevel\n"));
888 RCClass_MenuProcs(XtClass(tmp))(XmMENU_DISARM, tmp, NULL);
889 }
890 else if (XtParent(menu_shell) &&
891 (XmIsMenuBar(XtParent(menu_shell)) ||
892 XmIsOptionMenu(XtParent(menu_shell))))
893 {
894 Widget tmp = XtParent(menu_shell);
895
896 DEBUGOUT(_LtDebug(__FILE__, tmp,
897 " calling menuDisarm on XtParent(menu_shell)\n"));
898
899 RCClass_MenuProcs(XtClass(tmp))(XmMENU_DISARM, tmp, NULL);
900 }
901
902 _XmMenuSetInPMMode(w, False);
903
904 _XmSetInDragMode(w, False);
905 }
906
907
908 static void
MenuShellPopdownOne(Widget w,XEvent * event,String * params,Cardinal * num_params)909 MenuShellPopdownOne(Widget w, XEvent *event,
910 String *params, Cardinal *num_params)
911 {
912 Widget rc = NULL;
913
914 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownOne()\n"));
915
916 /* must be a menu shell here:
917 assert(XmIsMenuShell(w)); */
918
919 if (MGR_NumChildren(w) == 0)
920 {
921 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownOne: no children\n"));
922 return;
923 }
924
925 if (MS_PrivateShell(w) && XmIsRowColumn(XtParent(w)) &&
926 XmIsMenuBar(XtParent(w)))
927 {
928 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownOne: parent %s\n",
929 XtName(XtParent(w))));
930 rc = RC_PopupPosted(XtParent(w));
931 }
932 else
933 {
934 rc = MGR_Children(w)[0];
935 }
936
937 if (!rc || !XmIsRowColumn(rc))
938 {
939 DEBUGOUT(_LtDebug(__FILE__, w, "MenuShellPopdownOne: no RC\n"));
940 return;
941 }
942
943 DEBUGOUT(_LtDebug(__FILE__, w, " Child menu pane is %s\n", XtName(rc)));
944
945 /* unhighlight the cascade button that popped us up. */
946 if (RC_CascadeBtn(rc))
947 {
948 DEBUGOUT(_LtDebug(__FILE__, w, " Removing myself from the cascade\n"));
949
950 /* disarm the cascade button that pulled us down. */
951 if (XmIsPrimitive(RC_CascadeBtn(rc)))
952 {
953 CB_SetArmed(RC_CascadeBtn(rc), False);
954 }
955 else
956 {
957 CBG_SetArmed(RC_CascadeBtn(rc), False);
958 }
959 XmCascadeButtonHighlight(RC_CascadeBtn(rc), False);
960
961 /* clean up everything so noone thinks we're
962 popped up. */
963 RC_PopupPosted(XtParent(RC_CascadeBtn(rc))) = NULL;
964 RC_CascadeBtn(rc) = NULL;
965 }
966
967 DEBUGOUT(_LtDebug(__FILE__, w, " Popping down\n"));
968
969 if (MS_PrivateShell(w))
970 {
971 DEBUGOUT(_LtDebug(__FILE__, w, " PrivateShell\n"));
972
973 _XmXtMenuPopdown(w, NULL, NULL, NULL);
974 }
975 else
976 {
977 DEBUGOUT(_LtDebug(__FILE__, w, " public shell\n"));
978 if (RC_Type(rc) == XmMENU_POPUP || RC_Type(rc) == XmMENU_OPTION)
979 {
980 _XmRemoveGrab(w);
981 }
982
983 XtUnmapWidget(w);
984 XtCallCallbacks(w, XmNpopdownCallback, NULL);
985 XtUnmanageChild(rc);
986 }
987 _XmCallRowColumnUnmapCallback(rc, event);
988 }
989
990
991 static void
MenuShellPopdownEveryone(Widget w,XEvent * event,String * params,Cardinal * num_params)992 MenuShellPopdownEveryone(Widget w, XEvent *event,
993 String *params, Cardinal *num_params)
994 {
995 Cardinal i;
996 Widget rc;
997
998 /* must be a menu shell here:
999 assert(XmIsMenuShell(w)); */
1000
1001 DEBUGOUT(_LtDebug(__FILE__, w, "Popping down everyone - %i kids\n",
1002 MGR_NumChildren(w)));
1003
1004 if (MGR_NumChildren(w) == 0)
1005 {
1006 return;
1007 }
1008
1009 for (i = 0; i < MGR_NumChildren(w); i++)
1010 {
1011 rc = MGR_Children(w)[i];
1012
1013 DEBUGOUT(_LtDebug2(__FILE__, w, rc,"child %i\n", i));
1014 if (!rc)
1015 {
1016 continue;
1017 }
1018
1019 if (RC_PopupPosted(rc))
1020 {
1021 /* pop down our own sub tree, then ourselves. */
1022 Widget shell = XtParent(RC_PopupPosted(rc));
1023
1024 if (!shell)
1025 {
1026 continue;
1027 }
1028
1029 if (XmIsMenuShell(shell))
1030 {
1031 DEBUGOUT(_LtDebug(__FILE__, shell,
1032 " recursing in PopdownEveryone.\n"));
1033 MenuShellPopdownEveryone(shell, event, params, num_params);
1034 }
1035 }
1036 DEBUGOUT(_LtDebug(__FILE__, w, " calling popdownOne.\n"));
1037
1038 MenuShellPopdownOne(XtParent(rc), event, params, num_params);
1039 #if 0
1040 _XmCallRowColumnUnmapCallback(rc, event);
1041 #endif
1042 DEBUGOUT(_LtDebug2(__FILE__, w, rc,"child %i parent %s\n",
1043 i,
1044 XtName(XtParent(rc))));
1045 }
1046 for (i = 0; i < MGR_NumChildren(w); i++)
1047 {
1048 rc = MGR_Children(w)[i];
1049 if (_XmIsActiveTearOff(rc))
1050 {
1051 RCClass_MenuProcs(XtClass(rc))(XmMENU_RESTORE_TEAROFF_TO_TOPLEVEL_SHELL,
1052 rc, event);
1053 }
1054 }
1055 }
1056
1057
1058 static void
MenuShellPopupSharedMenuPane(Widget w,Widget w2,XEvent * event)1059 MenuShellPopupSharedMenuPane(Widget w, Widget w2, XEvent *event)
1060 {
1061 DEBUGOUT(_LtDebug(__FILE__, w, "Popping up shared pane\n"));
1062
1063 /* must be a menu shell here:
1064 assert(XmIsMenuShell(w)); */
1065
1066 XtManageChild(w2);
1067 XRaiseWindow(XtDisplay(w2), XtWindow(w2));
1068 _XmResizeObject(w, XtWidth(w2) == 0 ? 1 : XtWidth(w2), XtHeight(w2) == 0 ? 1 : XtHeight(w2), 0);
1069
1070 XtRealizeWidget(w);
1071 XMapRaised(XtDisplay(w), XtWindow(w));
1072 XtCallCallbacks(w, XmNpopupCallback, NULL);
1073 #ifdef NEW_MAPCALLBACK
1074 /*
1075 _XmCallRowColumnMapCallback(w2, event);
1076 */
1077 #endif
1078 Shell_PoppedUp(w) = True;
1079
1080 #ifdef USE_FOCUS
1081 DEBUGOUT(_LtDebug(__FILE__, w,
1082 "FOCUS SET: %s %s\n", XtName(w), XtName(w2)));
1083
1084 _XmMenuFocus(w2, XmMENU_FOCUS_SET, CurrentTime);
1085 #endif
1086
1087 XAllowEvents(XtDisplay(w2), SyncPointer/*ReplayPointer quick release problem */, CurrentTime);
1088
1089 _XmAddGrab(w, False, False);
1090 }
1091
1092
1093 static void
_XmXtMenuPopup(Widget widget,XEvent * event,String * params,Cardinal * num_params)1094 _XmXtMenuPopup(Widget widget, XEvent *event,
1095 String *params, Cardinal *num_params)
1096 {
1097 /* for popup menus */
1098 XtRealizeWidget(widget);
1099 XMapRaised(XtDisplay(widget), XtWindow(widget));
1100 XtCallCallbacks(widget, XmNpopupCallback, NULL);
1101 #ifdef NEW_MAPCALLBACK
1102 /*
1103 _XmCallRowColumnMapCallback(w2, event);
1104 */
1105 #endif
1106 Shell_PoppedUp(widget) = True;
1107
1108 XAllowEvents(XtDisplay(widget), SyncBoth, event->xbutton.time);
1109
1110 _XmGrabKeyboard(widget, True, GrabModeSync, GrabModeSync, CurrentTime);
1111
1112 _XmGrabPointer(widget, True, (ButtonPressMask | ButtonReleaseMask |
1113 EnterWindowMask | LeaveWindowMask),
1114 GrabModeSync, GrabModeSync, None,
1115 _XmGetMenuCursorByScreen(XtScreen(widget)), CurrentTime);
1116
1117 _XmAddGrab(widget, True, True);
1118
1119 XAllowEvents(XtDisplay(widget), SyncPointer, CurrentTime);
1120 }
1121
1122
1123 static void
_XmXtMenuPopdown(Widget widget,XEvent * event,String * params,Cardinal * num_params)1124 _XmXtMenuPopdown(Widget widget, XEvent *event,
1125 String *params, Cardinal *num_params)
1126 {
1127 DEBUGOUT(_LtDebug(__FILE__, widget, "_XmXtMenuPopdown()\n"));
1128 if (MS_PrivateShell(widget))
1129 {
1130 XtUnmapWidget(widget);
1131 XtCallCallbacks(widget, XmNpopdownCallback, NULL);
1132 Shell_PoppedUp(widget) = False;
1133
1134 #ifdef USE_FOCUS
1135 #if 0
1136 DEBUGOUT(_LtDebug(__FILE__, widget,
1137 "RESTORE: %s\n", XtName(widget)));
1138
1139 _XmMenuFocus(widget, XmMENU_FOCUS_RESTORE, CurrentTime);
1140 #endif
1141 #endif
1142
1143 _XmRemoveGrab(widget);
1144 }
1145 }
1146
1147
1148 extern void
_XmEnterRowColumn(Widget widget,XtPointer closure,XEvent * event,Boolean * cont)1149 _XmEnterRowColumn(Widget widget, XtPointer closure,
1150 XEvent *event, Boolean *cont)
1151 {
1152 DEBUGOUT(_LtDebug(__FILE__, widget,
1153 "_XmEnterRowColumn(not implemented)\n"));
1154 }
1155
1156
1157 extern void
_XmClearTraversal(Widget wid,XEvent * event,String * params,Cardinal * num_params)1158 _XmClearTraversal(Widget wid, XEvent *event,
1159 String *params, Cardinal *num_params)
1160 {
1161 DEBUGOUT(_LtDebug(__FILE__, wid,
1162 "_XmClearTraversal(not implemented)\n"));
1163
1164 XAllowEvents(XtDisplay(wid), SyncPointer, CurrentTime);
1165 }
1166
1167
1168 extern void
_XmSetLastManagedMenuTime(Widget wid,Time newTime)1169 _XmSetLastManagedMenuTime(Widget wid,
1170 Time newTime)
1171 {
1172 XmMenuState state = _XmGetMenuState(wid);
1173
1174 state->MS_LastManagedMenuTime = newTime;
1175 }
1176
1177
1178 extern Widget
XmCreateMenuShell(Widget parent,char * name,ArgList arglist,Cardinal argcount)1179 XmCreateMenuShell(Widget parent, char *name, ArgList arglist, Cardinal argcount)
1180 {
1181 while (parent && !XtIsComposite(parent))
1182 parent = XtParent(parent);
1183
1184 return XtCreatePopupShell(name, xmMenuShellWidgetClass, parent,
1185 arglist, argcount);
1186 }
1187
GetRenderTable(Widget w,XtEnum renderTableType)1188 static XmRenderTable GetRenderTable(Widget w, XtEnum renderTableType)
1189 {
1190 XmMenuShellWidget bb = (XmMenuShellWidget)w;
1191
1192 switch(renderTableType) {
1193 case XmLABEL_RENDER_TABLE:
1194 return bb->menu_shell.label_font_list;
1195 case XmBUTTON_RENDER_TABLE:
1196 return bb->menu_shell.button_font_list;
1197 case XmTEXT_RENDER_TABLE:
1198 return NULL; /* ?? FIX ME FIXME */
1199 #if 0
1200 return bb->menu_shell.text_font_list;
1201 #endif
1202 }
1203 return NULL;
1204 }
1205
1206