Git init
[framework/uifw/xorg/lib/libxaw.git] / src / SimpleMenu.c
1 /*
2 Copyright 1989, 1994, 1998  The Open Group
3
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation.
9
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20 Except as contained in this notice, the name of The Open Group shall not be
21 used in advertising or otherwise to promote the sale, use or other dealings
22 in this Software without prior written authorization from The Open Group.
23  */
24
25 /*
26  * SimpleMenu.c - Source code file for SimpleMenu widget.
27  *
28  * Date:    April 3, 1989
29  *
30  * By:      Chris D. Peterson
31  *          MIT X Consortium 
32  *          kit@expo.lcs.mit.edu
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <stdio.h>
39 #include <X11/IntrinsicP.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xmu/Initer.h>
42 #include <X11/Xmu/SysUtil.h>
43 #include <X11/Xaw/Cardinals.h>
44 #include <X11/Xaw/SimpleMenP.h>
45 #include <X11/Xaw/SmeBSBP.h>
46 #include <X11/Xaw/XawInit.h>
47 #include "Private.h"
48
49 #define streq(a, b)     (strcmp((a), (b)) == 0)
50
51 #define ForAllChildren(smw, childP)                             \
52 for ((childP) = (SmeObject *)(smw)->composite.children;         \
53      (childP) < (SmeObject *)((smw)->composite.children         \
54                               + (smw)->composite.num_children); \
55      (childP)++)
56
57 #ifndef OLDXAW
58 #define SMW_UNMAPPING   0x01
59 #define SMW_POPLEFT     0x02
60 #endif
61
62 /*
63  * Class Methods
64  */
65 static void XawSimpleMenuChangeManaged(Widget);
66 static void XawSimpleMenuClassInitialize(void);
67 static void XawSimpleMenuClassPartInitialize(WidgetClass);
68 static XtGeometryResult XawSimpleMenuGeometryManager(Widget, XtWidgetGeometry*,
69                                                      XtWidgetGeometry*);
70 static void XawSimpleMenuInitialize(Widget, Widget, ArgList, Cardinal*);
71 static void XawSimpleMenuRealize(Widget, XtValueMask*, XSetWindowAttributes*);
72 static void XawSimpleMenuRedisplay(Widget, XEvent*, Region);
73 static void XawSimpleMenuResize(Widget);
74 static Boolean XawSimpleMenuSetValues(Widget, Widget, Widget,
75                                       ArgList, Cardinal*);
76 static Boolean XawSimpleMenuSetValuesHook(Widget, ArgList, Cardinal*);
77 #ifndef OLDXAW
78 static void PopupSubMenu(SimpleMenuWidget);
79 static void PopdownSubMenu(SimpleMenuWidget);
80 static void PopupCB(Widget, XtPointer, XtPointer);
81 #endif
82
83 /*
84  * Prototypes
85  */
86 static void AddPositionAction(XtAppContext, XPointer);
87 static void CalculateNewSize(Widget, Dimension*, Dimension*);
88 static void ChangeCursorOnGrab(Widget, XtPointer, XtPointer);
89 static void CreateLabel(Widget);
90 static SmeObject DoGetEventEntry(Widget, int, int);
91 static Widget FindMenu(Widget, String);
92 static SmeObject GetEventEntry(Widget, XEvent*);
93 static void Layout(Widget, Dimension*, Dimension*);
94 static void MakeResizeRequest(Widget);
95 static void MakeSetValuesRequest(Widget, unsigned int, unsigned int);
96 static void MoveMenu(Widget, int, int);
97 static void PositionMenu(Widget, XPoint*);
98
99 /*
100  * Actions
101  */
102 static void Highlight(Widget, XEvent*, String*, Cardinal*);
103 static void Notify(Widget, XEvent*, String*, Cardinal*);
104 #ifndef OLDXAW
105 static void Popdown(Widget, XEvent*, String*, Cardinal*);
106 #endif
107 static void PositionMenuAction(Widget, XEvent*, String*, Cardinal*);
108 static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
109
110 /*
111  * Initialization
112  */
113 #define offset(field)   XtOffsetOf(SimpleMenuRec, simple_menu.field)
114
115 static XtResource resources[] = {
116   /* label */
117   {
118     XtNlabel,
119     XtCLabel,
120     XtRString,
121     sizeof(String),
122     offset(label_string),
123     XtRString,
124     NULL
125   },
126   {
127     XtNlabelClass,
128     XtCLabelClass,
129     XtRPointer,
130     sizeof(WidgetClass),
131     offset(label_class),
132     XtRImmediate,
133     NULL
134   },
135
136   /* layout */
137   {
138     XtNrowHeight,
139     XtCRowHeight,
140     XtRDimension,
141     sizeof(Dimension),
142     offset(row_height),
143     XtRImmediate,
144     (XtPointer)0
145   },
146   {
147     XtNtopMargin,
148     XtCVerticalMargins,
149     XtRDimension,
150     sizeof(Dimension),
151     offset(top_margin),
152     XtRImmediate,
153     (XtPointer)0
154   },
155   {
156     XtNbottomMargin,
157     XtCVerticalMargins,
158     XtRDimension,
159     sizeof(Dimension),
160     offset(bottom_margin),
161     XtRImmediate,
162     (XtPointer)0
163   },
164 #ifndef OLDXAW
165   {
166     XtNleftMargin,
167     XtCHorizontalMargins,
168     XtRDimension,
169     sizeof(Dimension),
170     offset(left_margin),
171     XtRImmediate,
172     (XtPointer)0
173   },
174   {
175     XtNrightMargin,
176     XtCHorizontalMargins,
177     XtRDimension,
178     sizeof(Dimension),
179     offset(right_margin),
180     XtRImmediate,
181     (XtPointer)0
182   },
183 #endif
184
185   /* misc */
186   {
187     XtNallowShellResize,
188     XtCAllowShellResize,
189     XtRBoolean,
190     sizeof(Boolean),
191     XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
192     XtRImmediate,
193     (XtPointer)True
194   },
195   {
196     XtNcursor,
197     XtCCursor,
198     XtRCursor,
199     sizeof(Cursor),
200     offset(cursor),
201     XtRImmediate,
202     (XtPointer)None
203   },
204   {
205     XtNmenuOnScreen,
206     XtCMenuOnScreen,
207     XtRBoolean,
208     sizeof(Boolean),
209     offset(menu_on_screen),
210     XtRImmediate,
211     (XtPointer)True
212   },
213   {
214     XtNpopupOnEntry,
215     XtCPopupOnEntry,
216     XtRWidget,
217     sizeof(Widget),
218     offset(popup_entry),
219     XtRWidget,
220     NULL
221   },
222   {
223     XtNbackingStore,
224     XtCBackingStore,
225     XtRBackingStore,
226     sizeof(int),
227     offset(backing_store), 
228     XtRImmediate,
229     (XtPointer)(Always + WhenMapped + NotUseful)
230   },
231 #ifndef OLDXAW
232   {
233     XawNdisplayList,
234     XawCDisplayList,
235     XawRDisplayList,
236     sizeof(XawDisplayList*),
237     offset(display_list), 
238     XtRImmediate,
239     NULL
240   },
241 #endif
242 };  
243 #undef offset
244
245 static char defaultTranslations[] =
246 "<Enter>:"      "highlight()\n"
247 "<Leave>:"      "unhighlight()\n"
248 "<BtnMotion>:"  "highlight()\n"
249 #ifndef OLDXAW
250 "<BtnUp>:"      "popdown() notify() unhighlight()\n"
251 #else
252 "<BtnUp>:"      "MenuPopdown() notify() unhighlight()\n"
253 #endif
254 ;
255
256 static XtActionsRec actionsList[] =
257 {
258   {"notify",            Notify},
259   {"highlight",         Highlight},
260   {"unhighlight",       Unhighlight},
261 #ifndef OLDXAW
262   {"popdown",           Popdown},
263   {"set-values",        XawSetValuesAction},
264   {"get-values",        XawGetValuesAction},
265   {"declare",           XawDeclareAction},
266   {"call-proc",         XawCallProcAction},
267 #endif
268 };
269  
270 static CompositeClassExtensionRec extension_rec = {
271   NULL,                                 /* next_extension */
272   NULLQUARK,                            /* record_type */
273   XtCompositeExtensionVersion,          /* version */
274   sizeof(CompositeClassExtensionRec),   /* record_size */
275   True,                                 /* accepts_objects */
276 };
277
278 #define Superclass      (&overrideShellClassRec)
279 SimpleMenuClassRec simpleMenuClassRec = {
280   /* core */
281   {
282     (WidgetClass)Superclass,            /* superclass */
283     "SimpleMenu",                       /* class_name */
284     sizeof(SimpleMenuRec),              /* size */
285     XawSimpleMenuClassInitialize,       /* class_initialize */
286     XawSimpleMenuClassPartInitialize,   /* class_part_initialize */
287     False,                              /* class_inited */
288     XawSimpleMenuInitialize,            /* initialize */
289     NULL,                               /* initialize_hook */
290     XawSimpleMenuRealize,               /* realize */
291     actionsList,                        /* actions */
292     XtNumber(actionsList),              /* num_actions */
293     resources,                          /* resources */
294     XtNumber(resources),                /* num_resources */
295     NULLQUARK,                          /* xrm_class */
296     True,                               /* compress_motion */
297     True,                               /* compress_exposure */
298     True,                               /* compress_enterleave */
299     False,                              /* visible_interest */
300     NULL,                               /* destroy */
301     XawSimpleMenuResize,                /* resize */
302     XawSimpleMenuRedisplay,             /* expose */
303     XawSimpleMenuSetValues,             /* set_values */
304     XawSimpleMenuSetValuesHook,         /* set_values_hook */
305     XtInheritSetValuesAlmost,           /* set_values_almost */
306     NULL,                               /* get_values_hook */
307     NULL,                               /* accept_focus */
308     XtVersion,                          /* intrinsics version */
309     NULL,                               /* callback offsets */
310     defaultTranslations,                /* tm_table */
311     NULL,                               /* query_geometry */
312     NULL,                               /* display_accelerator */
313     NULL,                               /* extension */
314   },
315   /* composite */
316   {
317     XawSimpleMenuGeometryManager,       /* geometry_manager */
318     XawSimpleMenuChangeManaged,         /* change_managed */
319     XtInheritInsertChild,               /* insert_child */
320     XtInheritDeleteChild,               /* delete_child */
321     NULL,                               /* extension */
322   },
323   /* shell */
324   {
325     NULL,                               /* extension */
326   },
327   /* override */
328   {
329     NULL,                               /* extension */
330   },
331   /* simple_menu */
332   {
333     NULL,                               /* extension */
334   },
335 };
336
337 WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
338
339 /*
340  * Implementation
341  */
342 /*
343  * Function:
344  *      XawSimpleMenuClassInitialize
345  *
346  * Description:
347  *      Class Initialize routine, called only once.
348  */
349 static void
350 XawSimpleMenuClassInitialize(void)
351 {
352     XawInitializeWidgetSet();
353     XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
354                    NULL, 0);
355     XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
356                        NULL, 0, XtCacheNone, NULL);
357     XmuAddInitializer(AddPositionAction, NULL);
358 }
359
360 /*
361  * Function:
362  *      XawSimpleMenuClassPartInitialize
363  *      Arguments: wc - the widget class of the subclass.
364  *
365  * Description:
366  *        Class Part Initialize routine, called for every subclass.  Makes
367  *      sure that the subclasses pick up the extension record.
368  */
369 static void
370 XawSimpleMenuClassPartInitialize(WidgetClass wc)
371 {
372     SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass)wc;
373
374     /*
375      * Make sure that our subclass gets the extension rec too
376      */
377     extension_rec.next_extension = smwc->composite_class.extension;
378     smwc->composite_class.extension = (XtPointer) &extension_rec;
379 }
380
381 /*
382  *  Function:
383  *      XawSimpleMenuInitialize
384  *
385  * Parameters:
386  *      request - widget requested by the argument list
387  *      cnew    - new widget with both resource and non resource values
388  *
389  * Description:
390  *      Initializes the simple menu widget.
391  */
392 /*ARGSUSED*/
393 static void
394 XawSimpleMenuInitialize(Widget request, Widget cnew,
395                         ArgList args, Cardinal *num_args)
396 {
397     SimpleMenuWidget smw = (SimpleMenuWidget)cnew;
398     Dimension width, height;
399
400     XmuCallInitializers(XtWidgetToApplicationContext(cnew));
401
402     if (smw->simple_menu.label_class == NULL) 
403         smw->simple_menu.label_class = smeBSBObjectClass;
404
405     smw->simple_menu.label = NULL;
406     smw->simple_menu.entry_set = NULL;
407     smw->simple_menu.recursive_set_values = False;
408 #ifndef OLDXAW
409     smw->simple_menu.sub_menu = NULL;
410     smw->simple_menu.state = 0;
411
412     XtAddCallback(cnew, XtNpopupCallback, PopupCB, NULL);
413 #endif
414
415     if (smw->simple_menu.label_string != NULL)
416         CreateLabel(cnew);
417
418     width = height = 0;
419     CalculateNewSize(cnew, &width, &height);
420
421     smw->simple_menu.menu_width = True;
422
423     if (XtWidth(smw) == 0) {
424         smw->simple_menu.menu_width = False;
425         XtWidth(smw) = width;
426     }
427
428     smw->simple_menu.menu_height = True;
429
430     if (XtHeight(smw) == 0) {
431         smw->simple_menu.menu_height = False;
432         XtHeight(smw) = height;
433     }
434
435     /*
436      * Add a popup_callback routine for changing the cursor
437      */
438     XtAddCallback(cnew, XtNpopupCallback, ChangeCursorOnGrab, NULL);
439 }
440
441 /*
442  * Function:
443  *      XawSimpleMenuRedisplay
444  *
445  * Parameters:
446  *      w      - simple menu widget
447  *      event  - X event that caused this redisplay
448  *      region - region the needs to be repainted
449  *
450  * Description:
451  *      Redisplays the contents of the widget.
452  */
453 /*ARGSUSED*/
454 static void
455 XawSimpleMenuRedisplay(Widget w, XEvent *event, Region region)
456 {
457     SimpleMenuWidget smw = (SimpleMenuWidget)w;
458     SmeObject *entry;
459     SmeObjectClass cclass;
460
461     if (region == NULL)
462         XClearWindow(XtDisplay(w), XtWindow(w));
463
464 #ifndef OLDXAW
465     if (smw->simple_menu.display_list)
466       XawRunDisplayList(w, smw->simple_menu.display_list, event, region);
467 #endif
468
469     /*
470      * Check and Paint each of the entries - including the label
471      */
472     ForAllChildren(smw, entry) {
473         if (!XtIsManaged((Widget)*entry))
474             continue;
475
476         if (region != NULL) 
477             switch(XRectInRegion(region, XtX(*entry),XtY(*entry),
478                                  XtWidth(*entry), XtHeight(*entry))) {
479                 case RectangleIn:
480                 case RectanglePart:
481                     break;
482                 default:
483                     continue;
484             }
485
486         cclass = (SmeObjectClass)(*entry)->object.widget_class;
487
488         if (cclass->rect_class.expose != NULL)
489             (cclass->rect_class.expose)((Widget)*entry, NULL, NULL);
490     }
491 }
492
493 /*
494  * Function:
495  *      XawSimpleMenuRealize
496  *
497  * Parameters:
498  *      w     - simple menu widget
499  *      mask  - value mask for the window to create
500  *      attrs - attributes for the window to create
501  *
502  * Description:
503  *      Realizes the widget.
504  */
505 static void
506 XawSimpleMenuRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
507 {
508     SimpleMenuWidget smw = (SimpleMenuWidget)w;
509 #ifndef OLDXAW
510     XawPixmap *pixmap;
511 #endif
512
513     attrs->cursor = smw->simple_menu.cursor;
514     *mask |= CWCursor;
515     if (smw->simple_menu.backing_store == Always ||
516         smw->simple_menu.backing_store == NotUseful ||
517         smw->simple_menu.backing_store == WhenMapped) {
518         *mask |= CWBackingStore;
519         attrs->backing_store = smw->simple_menu.backing_store;
520     }
521     else
522         *mask &= ~CWBackingStore;
523
524     (*Superclass->core_class.realize)(w, mask, attrs);
525
526 #ifndef OLDXAW
527     if (w->core.background_pixmap > XtUnspecifiedPixmap) {
528         pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
529                                       w->core.colormap, w->core.depth);
530         if (pixmap && pixmap->mask)
531             XawReshapeWidget(w, pixmap);
532     }
533 #endif
534 }
535
536 /*
537  * Function:
538  *      XawSimpleMenuResize
539  *
540  * Parameters:
541  *      w - simple menu widget
542  *
543  * Description:
544  *      Handle the menu being resized.
545  */
546 static void
547 XawSimpleMenuResize(Widget w)
548 {
549     if (!XtIsRealized(w))
550         return;
551
552     Layout(w, NULL, NULL);
553
554     XawSimpleMenuRedisplay(w, NULL, NULL);
555 }
556
557 /*
558  * Function:
559  *      XawSimpleMenuSetValues
560  *
561  * Parameters:
562  *      current - current state of the widget
563  *      request - what was requested
564  *      cnew    - what the widget will become
565  *
566  * Description:
567  *      Relayout the menu when one of the resources is changed.
568  */
569 /*ARGSUSED*/
570 static Boolean
571 XawSimpleMenuSetValues(Widget current, Widget request, Widget cnew,
572                        ArgList args, Cardinal *num_args)
573 {
574     SimpleMenuWidget smw_old = (SimpleMenuWidget)current;
575     SimpleMenuWidget smw_new = (SimpleMenuWidget)cnew;
576     Boolean ret_val = False, layout = False;
577
578     if (!XtIsRealized(current))
579         return (False);
580
581     if (!smw_new->simple_menu.recursive_set_values) {
582         if (XtWidth(smw_new) != XtWidth(smw_old)) {
583             smw_new->simple_menu.menu_width = XtWidth(smw_new) != 0;
584             layout = True;
585         }
586         if (XtHeight(smw_new) != XtHeight(smw_old)) {
587             smw_new->simple_menu.menu_height = XtHeight(smw_new) != 0;
588             layout = True;
589         }
590     }
591
592     if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
593         XDefineCursor(XtDisplay(cnew), XtWindow(cnew),
594                       smw_new->simple_menu.cursor);
595
596     if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) {
597         if (smw_new->simple_menu.label_string == NULL)      /* Destroy */
598             XtDestroyWidget((Widget)smw_old->simple_menu.label);
599         else if (smw_old->simple_menu.label_string == NULL) /* Create */
600             CreateLabel(cnew);
601         else {                                              /* Change */
602             Arg arglist[1];
603             
604             XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
605             XtSetValues((Widget)smw_new->simple_menu.label, arglist, ONE);
606         }
607     }
608
609     if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
610         XtAppWarning(XtWidgetToApplicationContext(cnew),
611                      "No Dynamic class change of the SimpleMenu Label.");
612     
613     if (smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin
614         || smw_old->simple_menu.bottom_margin
615         != smw_new->simple_menu.bottom_margin) {
616         layout = True;
617         ret_val = True;
618     }
619
620 #ifndef OLDXAW
621     if (smw_old->core.background_pixmap != smw_new->core.background_pixmap) {
622         XawPixmap *opix, *npix;
623
624         opix = XawPixmapFromXPixmap(smw_old->core.background_pixmap,
625                                     XtScreen(smw_old), smw_old->core.colormap,
626                                     smw_old->core.depth);
627         npix = XawPixmapFromXPixmap(smw_new->core.background_pixmap,
628                                     XtScreen(smw_new), smw_new->core.colormap,
629                                     smw_new->core.depth);
630         if ((npix && npix->mask) || (opix && opix->mask))
631             XawReshapeWidget(cnew, npix);
632     }
633 #endif
634
635     if (layout)
636         Layout(cnew, NULL, NULL);
637
638     return (ret_val);
639 }
640
641 /* 
642  * Function:
643  *      XawSimpleMenuSetValuesHook
644  *
645  * Parameters:
646  *      w        - menu widget
647  *      arglist  - argument list passed to XtSetValues
648  *      num_args - number of args
649  *
650  * Description:
651  *      To handle a special case, this is passed the actual arguments.
652  */
653 static Boolean
654 XawSimpleMenuSetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
655 {
656     Cardinal i;
657     Dimension width, height;
658     
659     width = XtWidth(w);
660     height = XtHeight(w);
661     
662     for (i = 0 ; i < *num_args ; i++) {
663         if (streq(arglist[i].name, XtNwidth))
664             width = (Dimension)arglist[i].value;
665         if (streq(arglist[i].name, XtNheight))
666             height = (Dimension) arglist[i].value;
667     }
668
669     if (width != XtWidth(w) || height != XtHeight(w))
670         MakeSetValuesRequest(w, width, height);
671
672     return (False);
673 }
674
675 /*
676  * Geometry Management routines
677  */
678 /*
679  * Function:
680  *      XawSimpleMenuGeometryManager
681  *
682  * Parameters:
683  *      w       - Menu Entry making the request
684  *      request - requested new geometry
685  *                 reply - the allowed geometry.
686  *
687  * Description:
688  *      This is the SimpleMenu Widget's Geometry Manager.
689  *
690  * Returns:
691  *      XtGeometry{Yes, No, Almost}
692  */
693 static XtGeometryResult
694 XawSimpleMenuGeometryManager(Widget w, XtWidgetGeometry *request,
695                              XtWidgetGeometry *reply)
696 {
697     SimpleMenuWidget smw = (SimpleMenuWidget)XtParent(w);
698     SmeObject entry = (SmeObject)w;
699     XtGeometryMask mode = request->request_mode;
700     XtGeometryResult answer;
701     Dimension old_height, old_width;
702
703     if (!(mode & CWWidth) && !(mode & CWHeight))
704         return (XtGeometryNo);
705
706     reply->width = request->width;
707     reply->height = request->height;
708
709     old_width = XtWidth(entry);
710     old_height = XtHeight(entry);
711
712     Layout(w, &reply->width, &reply->height);
713
714     /*
715      * Since we are an override shell and have no parent there is no one to
716      * ask to see if this geom change is okay, so I am just going to assume
717      * we can do whatever we want.  If you subclass be very careful with this
718      * assumption, it could bite you.
719      *
720      * Chris D. Peterson - Sept. 1989.
721      */
722     if ((!(mode & CWWidth) || reply->width == request->width)
723         && (!(mode & CWHeight) || reply->height == request->height)) {
724         if (mode & XtCWQueryOnly) {     /* Actually perform the layout */
725             XtWidth(entry) = old_width;
726             XtHeight(entry) = old_height;
727         }
728         else
729             Layout((Widget)smw, NULL, NULL);
730         answer = XtGeometryDone;
731     }
732     else {
733         XtWidth(entry) = old_width;
734         XtHeight(entry) = old_height;
735
736         if ((reply->width == request->width && !(mode & CWHeight))
737             || (reply->height == request->height && !(mode & CWWidth))
738             || (reply->width == request->width
739             && reply->height == request->height))
740             answer = XtGeometryNo;
741         else {
742             answer = XtGeometryAlmost;
743             reply->request_mode = 0;
744             if (reply->width != request->width)
745                 reply->request_mode |= CWWidth;
746             if (reply->height != request->height)
747                 reply->request_mode |= CWHeight;
748         }
749     }
750
751     return (answer);
752 }
753
754 /*
755  * Function:
756  *      XawSimpleMenuChangeManaged
757  *
758  * Parameters:
759  *      w - simple menu widget
760  *
761  * Description:
762  *      Called whenever a new child is managed.
763  */
764 static void
765 XawSimpleMenuChangeManaged(Widget w)
766 {
767     Layout(w, NULL, NULL);
768 }
769
770 /*
771  * Global Action Routines
772  * 
773  * These actions routines will be added to the application's
774  * global action list
775  */
776 /*
777  * Function:
778  *      PositionMenuAction
779  * 
780  * Parameters:
781  *      w          - a widget (no the simple menu widget)
782  *      event      - the event that caused this action
783  *      params     - parameters passed to the routine.
784  *                                      we expect the name of the menu here.
785  *      num_params - ""
786  *
787  * Description:
788  *      Positions the simple menu widget.
789  */
790 /*ARGSUSED*/
791 static void
792 PositionMenuAction(Widget w, XEvent *event,
793                    String *params, Cardinal *num_params)
794
795     Widget menu;
796     XPoint loc;
797
798     if (*num_params != 1) {
799         XtAppWarning(XtWidgetToApplicationContext(w),
800                      "SimpleMenuWidget: position menu action expects "
801                      "only one parameter which is the name of the menu.");
802         return;
803     }
804
805     if ((menu = FindMenu(w, params[0])) == NULL) {
806         char error_buf[BUFSIZ];
807
808         (void)XmuSnprintf(error_buf, sizeof(error_buf),
809                           "SimpleMenuWidget: could not find menu named %s.",
810                           params[0]);
811         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
812         return;
813     }
814   
815     switch (event->type) {
816         case ButtonPress:
817         case ButtonRelease:
818             loc.x = event->xbutton.x_root;
819             loc.y = event->xbutton.y_root;
820             PositionMenu(menu, &loc);
821             break;
822         case EnterNotify:
823         case LeaveNotify:
824             loc.x = event->xcrossing.x_root;
825             loc.y = event->xcrossing.y_root;
826             PositionMenu(menu, &loc);
827             break;
828         case MotionNotify:
829             loc.x = event->xmotion.x_root;
830             loc.y = event->xmotion.y_root;
831             PositionMenu(menu, &loc);
832             break;
833         default:
834             PositionMenu(menu, NULL);
835             break;
836     }
837 }  
838
839 /*
840  * Widget Action Routines
841  */
842 /*
843  * Function:
844  *      Unhighlight
845  *
846  * Parameters:
847  *      w          - simple menu widget
848  *      event      - event that caused this action
849  *      params     - not used
850  *      num_params - ""
851  * 
852  * Description:
853  *      Unhighlights current entry.
854  */
855 /*ARGSUSED*/
856 static void
857 Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
858
859     SimpleMenuWidget smw = (SimpleMenuWidget)w;
860     SmeObject entry = smw->simple_menu.entry_set;
861  
862     if (entry == NULL)
863         return;
864
865 #ifndef OLDXAW
866     if (!smw->simple_menu.sub_menu)
867 #endif
868     {
869         SmeObjectClass cclass;
870
871         smw->simple_menu.entry_set = NULL;
872         cclass = (SmeObjectClass)entry->object.widget_class;
873         (cclass->sme_class.unhighlight)((Widget)entry);
874     }
875 }
876
877 /*
878  * Function:
879  *      Highlight
880  *
881  * Parameters:
882  *      w          - simple menu widget
883  *      event      - event that caused this action
884  *      params     - not used
885  *      num_params - ""
886  *
887  * Description:
888  *      Highlights current entry.
889  */
890 /*ARGSUSED*/
891 static void
892 Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
893 {
894     SimpleMenuWidget smw = (SimpleMenuWidget)w;
895     SmeObject entry;
896
897     if (!XtIsSensitive(w))
898         return;
899
900     entry = GetEventEntry(w, event);
901
902     if (entry == smw->simple_menu.entry_set)
903         return;
904
905 #ifndef OLDXAW
906     if (!smw->simple_menu.sub_menu)
907 #endif
908         Unhighlight(w, event, params, num_params);
909
910     if (entry == NULL)
911         return;
912
913     if (!XtIsSensitive((Widget)entry))
914         return;
915
916 #ifndef OLDXAW
917     if (smw->simple_menu.sub_menu)
918         PopdownSubMenu(smw);
919 #endif
920
921     Unhighlight(w, event, params, num_params);
922
923 #ifndef OLDXAW
924     if (!(smw->simple_menu.state & SMW_UNMAPPING))
925 #endif
926     {
927         SmeObjectClass cclass;
928
929         smw->simple_menu.entry_set = entry;
930         cclass = (SmeObjectClass)entry->object.widget_class;
931
932         (cclass->sme_class.highlight)((Widget)entry);
933
934 #ifndef OLDXAW
935         if (XtIsSubclass((Widget)entry, smeBSBObjectClass))
936             PopupSubMenu(smw);
937 #endif
938     }
939 }
940
941 /*
942  * Function:
943  *      Notify
944  *
945  * Parameters:
946  *      w          - simple menu widget
947  *      event      - event that caused this action
948  *      params     - not used
949  *      num_params - ""
950  *
951  * Description:
952  *      Notify user of current entry.
953  */
954 /*ARGSUSED*/
955 static void
956 Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
957 {
958     SmeObject entry;
959     SmeObjectClass cclass;
960
961     /* may be a propagated event from a sub menu, need to check it */
962     if (XtWindow(w) != event->xany.window)
963         return;
964     entry = GetEventEntry(w, event);
965     if (entry == NULL || !XtIsSensitive((Widget)entry))
966         return;
967
968     cclass = (SmeObjectClass) entry->object.widget_class;
969     (cclass->sme_class.notify)((Widget)entry);
970 }
971
972 /*
973  * Public Functions
974  */
975 /*
976  * Function:
977  *      XawSimpleMenuAddGlobalActions
978  *
979  * Arguments:
980  *      app_con - appcontext
981  *
982  * Description:
983  *      Adds the global actions to the simple menu widget.
984  */
985 void
986 XawSimpleMenuAddGlobalActions(XtAppContext app_con)
987 {
988     XtInitializeWidgetClass(simpleMenuWidgetClass);
989     XmuCallInitializers(app_con);
990
991
992 /*
993  * Function:
994  *      XawSimpleMenuGetActiveEntry
995  *
996  * Parameters:
997  *      w - smw widget
998  *
999  * Description:
1000  *      Gets the currently active (set) entry.
1001  *
1002  * Returns:
1003  *      The currently set entry or NULL if none is set
1004  */
1005 Widget
1006 XawSimpleMenuGetActiveEntry(Widget w)
1007 {
1008     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1009
1010     return ((Widget)smw->simple_menu.entry_set);
1011
1012
1013 /*
1014  * Function:
1015  *      XawSimpleMenuClearActiveEntry
1016  *
1017  * Parameters:
1018  *      w - smw widget
1019  *
1020  * Description:
1021  *      Unsets the currently active (set) entry.
1022  */
1023 void
1024 XawSimpleMenuClearActiveEntry(Widget w)
1025 {
1026     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1027
1028     smw->simple_menu.entry_set = NULL;
1029
1030
1031 /*
1032  * Private Functions
1033  */
1034 /*
1035  * Function:
1036  *      CreateLabel
1037  *
1038  * Parameters:
1039  *      w - smw widget
1040  * 
1041  * Description:
1042  * Creates the label object and makes sure it is the first child in
1043  * in the list.
1044  */
1045 static void
1046 CreateLabel(Widget w)
1047 {
1048     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1049     Widget *child, *next_child;
1050     int i;
1051     Arg args[2];
1052
1053     if (smw->simple_menu.label_string == NULL ||
1054         smw->simple_menu.label != NULL) {
1055         XtAppWarning(XtWidgetToApplicationContext(w),
1056                      "Xaw Simple Menu Widget: label string is NULL or "
1057                      "label already exists, no label is being created.");
1058         return;
1059     }
1060
1061     XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
1062     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
1063     smw->simple_menu.label = (SmeObject) 
1064         XtCreateManagedWidget("menuLabel", 
1065                               smw->simple_menu.label_class, w, args, TWO);
1066
1067     next_child = NULL;
1068     for (child = smw->composite.children + smw->composite.num_children,
1069          i = smw->composite.num_children; i > 0; i--, child--) {
1070         if (next_child != NULL)
1071             *next_child = *child;
1072         next_child = child;
1073     }
1074     *child = (Widget)smw->simple_menu.label;
1075 }
1076
1077 /*
1078  * Function:
1079  *      Layout
1080  *
1081  * Arguments:
1082  *      w          - See below
1083  *      width_ret  - returned width
1084  *      height_ret - returned height
1085  *
1086  * Note:
1087  * if width == NULL || height == NULL then it assumes the you do not care
1088  * about the return values, and just want a relayout.
1089  *
1090  * if this is not the case then it will set width_ret and height_ret
1091  * to be width and height that the child would get if it were layed out
1092  * at this time.
1093  *
1094  *      "w" can be the simple menu widget or any of its object children.
1095  */
1096 static void
1097 Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
1098 {
1099     SmeObject current_entry;
1100     SimpleMenuWidget smw;
1101     Dimension width, height;
1102     Boolean allow_change_size;
1103     Widget kid;
1104     Cardinal i, count, n;
1105     int width_kid, height_kid, tmp_w, tmp_h;
1106     short vadd, hadd, x_ins, y_ins;
1107     Dimension *widths;
1108
1109     height = 0;
1110
1111     if (XtIsSubclass(w, simpleMenuWidgetClass)) {
1112         smw = (SimpleMenuWidget)w;
1113         current_entry = NULL;
1114     }
1115     else {
1116         smw = (SimpleMenuWidget)XtParent(w);
1117         current_entry = (SmeObject)w;
1118     }
1119
1120     allow_change_size = (!XtIsRealized((Widget)smw)
1121                          || smw->shell.allow_shell_resize);
1122
1123     for (i = smw->simple_menu.label ? 1 : 0;
1124          i < smw->composite.num_children;
1125          i++) {
1126         XtWidgetGeometry preferred;
1127
1128         kid = smw->composite.children[i];
1129         if (!XtIsManaged(kid))
1130             continue;
1131         if (smw->simple_menu.row_height != 0)
1132             XtHeight(kid) = smw->simple_menu.row_height;
1133         XtQueryGeometry(kid, NULL, &preferred);
1134         if (preferred.request_mode & CWWidth)
1135             XtWidth(kid) = preferred.width;
1136     }
1137
1138     if (smw->simple_menu.label
1139         && XtIsManaged((Widget)smw->simple_menu.label)) {
1140         XtWidgetGeometry preferred;
1141
1142         kid = (Widget)smw->simple_menu.label;
1143         XtQueryGeometry(kid, NULL, &preferred);
1144         if (preferred.request_mode & CWWidth)
1145             XtWidth(kid) = preferred.width;
1146         if (preferred.request_mode & CWHeight)
1147             XtHeight(kid) = preferred.height;
1148     }
1149
1150     /* reset */
1151     if (!smw->simple_menu.menu_width)
1152         XtWidth(smw) = 0;
1153     if (!smw->simple_menu.menu_height)
1154         XtHeight(smw) = 0;
1155     if (!XtWidth(smw) || !XtHeight(smw))
1156         MakeResizeRequest((Widget)smw);
1157
1158     widths = (Dimension *)XtMalloc(sizeof(Dimension));
1159 #ifndef OLDXAW
1160     hadd = smw->simple_menu.left_margin;
1161 #else
1162     hadd = 0;
1163 #endif
1164     vadd = smw->simple_menu.top_margin;
1165     if (smw->simple_menu.label)
1166         vadd += XtHeight(smw->simple_menu.label);
1167
1168     count = 1;
1169     width = tmp_w = tmp_h = n = 0;
1170     height = vadd;
1171
1172     for (i = smw->simple_menu.label ? 1 : 0;
1173          i < smw->composite.num_children;
1174          i++) {
1175         kid = smw->composite.children[i];
1176         if (!XtIsManaged(kid))
1177             continue;
1178         width_kid = XtWidth(kid);
1179         height_kid = XtHeight(kid);
1180
1181         if (n && (height + height_kid + smw->simple_menu.bottom_margin
1182                   > XtHeight(smw))) {
1183             ++count;
1184             widths = (Dimension *)XtRealloc((char *)widths,
1185                                             sizeof(Dimension) * count);
1186             widths[count - 1] = width_kid;
1187             width += tmp_w;
1188             tmp_w = width_kid;
1189             height = height_kid + vadd;
1190         }
1191         else
1192             height += height_kid;
1193         if (height > tmp_h)
1194             tmp_h = height;
1195         if (width_kid > tmp_w)
1196             widths[count - 1] = tmp_w = width_kid;
1197         ++n;
1198     }
1199
1200     height = tmp_h + smw->simple_menu.bottom_margin;
1201     width += tmp_w;
1202
1203     if (smw->simple_menu.label && width < XtWidth(smw->simple_menu.label)) {
1204         float inc;
1205
1206         inc = (XtWidth(smw->simple_menu.label) - width) / (float)count;
1207         width = XtWidth(smw->simple_menu.label);
1208         for (n = 0; n < count; n++)
1209             widths[n] += inc;
1210     }
1211
1212 #ifndef OLDXAW
1213     width += hadd + smw->simple_menu.right_margin;
1214 #endif
1215
1216     x_ins = n = count = 0;
1217     tmp_w = widths[0];
1218     tmp_h = vadd;
1219
1220     for (i = smw->simple_menu.label ? 1 : 0;
1221          i < smw->composite.num_children;
1222          i++) {
1223         kid = smw->composite.children[i];
1224         if (!XtIsManaged(kid))
1225             continue;
1226
1227         height_kid = XtHeight(kid);
1228
1229         if (n && (tmp_h + height_kid + smw->simple_menu.bottom_margin
1230                   > XtHeight(smw))) {
1231             x_ins = tmp_w;
1232             y_ins = vadd;
1233             ++count;
1234             tmp_w += widths[count];
1235             tmp_h = height_kid + vadd;
1236         }
1237         else {
1238             y_ins = tmp_h;
1239             tmp_h += height_kid;
1240         }
1241         ++n;
1242
1243         XtX(kid) = x_ins + hadd;
1244         XtY(kid) = y_ins;
1245         XtWidth(kid) = widths[count];
1246     }
1247
1248     XtFree((char *)widths);
1249
1250     if (allow_change_size)
1251         MakeSetValuesRequest((Widget) smw, width, height);
1252
1253     if (smw->simple_menu.label) {
1254         XtX(smw->simple_menu.label) = 0;
1255         XtY(smw->simple_menu.label) = smw->simple_menu.top_margin;
1256         XtWidth(smw->simple_menu.label) = XtWidth(smw)
1257 #ifndef OLDXAW
1258             - (smw->simple_menu.left_margin + smw->simple_menu.right_margin)
1259 #endif
1260             ;
1261     }
1262     if (current_entry) {
1263         if (width_ret)
1264             *width_ret = XtWidth(current_entry);
1265         if (height_ret)
1266             *height_ret = XtHeight(current_entry);
1267     }
1268 }
1269     
1270 /*
1271  * Function:
1272  *      AddPositionAction
1273  *
1274  * Parameters:
1275  *      app_con - application context
1276  *      data    - (not used)
1277  *
1278  * Description:
1279  *        Adds the XawPositionSimpleMenu action to the global
1280  *                   action list for this appcon.
1281  */
1282 /*ARGSUSED*/
1283 static void
1284 AddPositionAction(XtAppContext app_con, XPointer data)
1285 {
1286     static XtActionsRec pos_action[] = {
1287         {"XawPositionSimpleMenu",       PositionMenuAction},
1288     };
1289
1290     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
1291 }
1292
1293 /*
1294  * Function:
1295  *      FindMenu
1296  *
1297  * Parameters:
1298  *      widget - reference widget
1299  *      name   - menu widget's name
1300  *
1301  * Description:
1302  *      Find the menu give a name and reference widget
1303  *
1304  * Returns:
1305  *      The menu widget or NULL.
1306  */
1307 static Widget 
1308 FindMenu(Widget widget, String name)
1309 {
1310     Widget w, menu;
1311     
1312     for (w = widget; w != NULL; w = XtParent(w))
1313         if ((menu = XtNameToWidget(w, name)) != NULL)
1314             return (menu);
1315
1316     return (NULL);
1317 }
1318
1319 /*
1320  * Function:
1321  *      PositionMenu
1322  *
1323  * Parameters:
1324  *      w        - simple menu widget
1325  *      location - pointer the the position or NULL
1326  *
1327  * Description:
1328  *      Places the menu
1329  */
1330 static void
1331 PositionMenu(Widget w, XPoint *location)
1332 {
1333     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1334     SmeObject entry;
1335     XPoint t_point;
1336     
1337     if (location == NULL) {
1338         Window temp1, temp2;
1339         int root_x, root_y, tempX, tempY;
1340         unsigned int tempM;
1341         
1342         location = &t_point;
1343         if (XQueryPointer(XtDisplay(w), XtWindow(w), &temp1, &temp2,
1344                           &root_x, &root_y, &tempX, &tempY, &tempM) == False) {
1345             XtAppWarning(XtWidgetToApplicationContext(w),
1346                          "Xaw Simple Menu Widget: "
1347                          "Could not find location of mouse pointer");
1348             return;
1349         }
1350         location->x = (short) root_x;
1351         location->y = (short) root_y;
1352     }
1353     
1354     /*
1355      * The width will not be correct unless it is realized
1356      */
1357     XtRealizeWidget(w);
1358     
1359     location->x -= XtWidth(w) >> 1;
1360     
1361     if (smw->simple_menu.popup_entry == NULL)
1362         entry = smw->simple_menu.label;
1363     else
1364         entry = smw->simple_menu.popup_entry;
1365
1366     if (entry != NULL)
1367       location->y -= XtY(entry) + (XtHeight(entry) >> 1);
1368
1369     MoveMenu(w, location->x, location->y);
1370 }
1371
1372 /*
1373  * Function:
1374  *      MoveMenu
1375  *
1376  * Parameters:
1377  *      w - simple menu widget
1378  *      x - current location of the widget
1379  *      y - ""
1380  *
1381  * Description:
1382  *        Actually moves the menu, may force it to
1383  *      to be fully visable if menu_on_screen is True.
1384  */
1385 static void
1386 MoveMenu(Widget w, int x, int y)
1387 {
1388     Arg arglist[2];
1389     Cardinal num_args = 0;
1390     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1391     
1392     if (smw->simple_menu.menu_on_screen) {
1393         int width = XtWidth(w) + (XtBorderWidth(w) << 1);
1394         int height = XtHeight(w) + (XtBorderWidth(w) << 1);
1395         
1396         if (x >= 0) {
1397             int scr_width = WidthOfScreen(XtScreen(w));
1398
1399             if (x + width > scr_width)
1400                 x = scr_width - width;
1401         }
1402         if (x < 0) 
1403             x = 0;
1404         
1405         if (y >= 0) {
1406             int scr_height = HeightOfScreen(XtScreen(w));
1407
1408             if (y + height > scr_height)
1409                 y = scr_height - height;
1410         }
1411         if (y < 0)
1412             y = 0;
1413     }
1414     
1415     XtSetArg(arglist[num_args], XtNx, x); num_args++;
1416     XtSetArg(arglist[num_args], XtNy, y); num_args++;
1417     XtSetValues(w, arglist, num_args);
1418 }
1419
1420 /*
1421  * Function:
1422  *      ChangeCursorOnGrab
1423  *
1424  * Parameters:
1425  *      w     - menu widget
1426  *      temp1 - not used
1427  *      temp2 - ""
1428  *
1429  * Description:
1430  *        Changes the cursor on the active grab to the one
1431  *                   specified in out resource list.
1432  */
1433 /*ARGSUSED*/
1434 static void
1435 ChangeCursorOnGrab(Widget w, XtPointer temp1, XtPointer temp2)
1436 {
1437     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1438     
1439     /*
1440      * The event mask here is what is currently in the MIT implementation.
1441      * There really needs to be a way to get the value of the mask out
1442      * of the toolkit (CDP 5/26/89).
1443      */
1444     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask | ButtonReleaseMask,
1445                              smw->simple_menu.cursor, 
1446                              XtLastTimestampProcessed(XtDisplay(w)));
1447 }
1448
1449 /*
1450  * Function:
1451  *      MakeSetValuesRequest
1452  *
1453  * Parameters:
1454  *      w      - simple menu widget
1455  *      width  - size requested
1456  *      height - ""
1457  */
1458 static void
1459 MakeSetValuesRequest(Widget w, unsigned int width, unsigned int height)
1460 {
1461     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1462     Arg arglist[2];
1463     Cardinal num_args = 0;
1464     
1465     if (!smw->simple_menu.recursive_set_values) {
1466         if (XtWidth(smw) != width || XtHeight(smw) != height) {
1467             smw->simple_menu.recursive_set_values = True;
1468             XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
1469             XtSetArg(arglist[num_args], XtNheight, height); num_args++;
1470             XtSetValues(w, arglist, num_args);
1471         }
1472         else if (XtIsRealized((Widget)smw))
1473             XawSimpleMenuRedisplay((Widget)smw, NULL, NULL);
1474     }
1475     smw->simple_menu.recursive_set_values = False;
1476 }
1477
1478 static SmeObject
1479 DoGetEventEntry(Widget w, int x_loc, int y_loc)
1480 {
1481     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1482     SmeObject *entry;
1483
1484     ForAllChildren(smw, entry) {
1485         if (!XtIsManaged((Widget)*entry))
1486             continue;
1487
1488         if (x_loc > XtX(*entry)
1489             && x_loc <= XtX(*entry) + XtWidth(*entry)
1490             && y_loc > XtY(*entry)
1491             &&  y_loc <= XtY(*entry) + XtHeight(*entry)) {
1492             if (*entry == smw->simple_menu.label)
1493                 return (NULL);  /* cannot select the label */
1494             else
1495                 return (*entry);
1496         }
1497     }
1498     
1499     return (NULL);
1500 }
1501
1502 /*
1503  * Function:
1504  *      GetEventEntry
1505  *
1506  * Parameters:
1507  *      w     - simple menu widget
1508  *      event - X event
1509  *
1510  * Description:
1511  *      Gets an entry given an event that has X and Y coords.
1512  *
1513  * Returns:
1514  *      The entry that this point is in
1515  */
1516 static SmeObject
1517 GetEventEntry(Widget w, XEvent *event)
1518 {
1519     int x_loc, y_loc, x_root;
1520     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1521     SmeObject entry;
1522     int warp, move;
1523
1524     switch (event->type) {
1525         case MotionNotify:
1526             x_loc = event->xmotion.x;
1527             y_loc = event->xmotion.y;
1528             x_root = event->xmotion.x_root;
1529             break;
1530         case EnterNotify:
1531         case LeaveNotify:
1532             x_loc = event->xcrossing.x;
1533             y_loc = event->xcrossing.y;
1534             x_root = event->xcrossing.x_root;
1535             break;
1536         case ButtonPress:
1537         case ButtonRelease:
1538             x_loc = event->xbutton.x;
1539             y_loc = event->xbutton.y;
1540             x_root = event->xbutton.x_root;
1541             break;
1542         default:
1543             XtAppError(XtWidgetToApplicationContext(w),
1544                        "Unknown event type in GetEventEntry().");
1545             return (NULL);
1546     }
1547     
1548     if (x_loc < 0 || x_loc >= XtWidth(smw) ||
1549         y_loc < 0 || y_loc >= XtHeight(smw))
1550         return (NULL);
1551
1552     /* Move the menu if it's outside the screen, does not check
1553      * smw->simple_menu.menu_on_screen because menus is bigger than screen
1554      */
1555     if (x_root == WidthOfScreen(XtScreen(w)) - 1 &&
1556         XtX(w) + XtWidth(w) + (XtBorderWidth(w)) > x_root) {
1557         warp = -8;
1558         if (smw->simple_menu.entry_set) {
1559             entry = DoGetEventEntry(w,
1560                                     XtX(smw->simple_menu.entry_set)
1561                                     + XtWidth(smw->simple_menu.entry_set) + 1,
1562                                     y_loc);
1563             Unhighlight(w, event, NULL, NULL);
1564             if (entry) {
1565                 warp = -(int)XtWidth(entry) >> 1;
1566                 move = x_loc - XtWidth(entry) - XtX(entry) + XtBorderWidth(w);
1567             }
1568             else {
1569                 warp = 0;
1570                 move = WidthOfScreen(XtScreen(w)) -
1571                        (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1572             }
1573         }
1574         else {
1575             warp = 0;
1576             move = WidthOfScreen(XtScreen(w)) -
1577                    (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1578         }
1579     }
1580     else if (x_root == 0 && XtX(w) < 0) {
1581         warp = 8;
1582         if (smw->simple_menu.entry_set) {
1583             entry = DoGetEventEntry(w, XtX(smw->simple_menu.entry_set) - 1,
1584                                     y_loc);
1585             Unhighlight(w, event, NULL, NULL);
1586             if (entry) {
1587                 warp = XtWidth(entry) >> 1;
1588                 move = x_loc - XtX(entry);
1589             }
1590             else
1591                 move = x_loc + XtBorderWidth(w);
1592         }
1593         else
1594             move = x_loc + XtBorderWidth(w);
1595     }
1596     else
1597         move = warp = 0;
1598
1599     if (move)
1600         XtMoveWidget(w, XtX(w) + move, XtY(w));
1601     if (warp)
1602         XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, warp, 0);
1603
1604     return (DoGetEventEntry(w, x_loc, y_loc));
1605 }
1606
1607 static void
1608 CalculateNewSize(Widget w, Dimension *width_return, Dimension *height_return)
1609 {
1610     SimpleMenuWidget xaw = (SimpleMenuWidget)w;
1611     Widget kid;
1612     Cardinal i;
1613     int width_kid, height_kid;
1614     int width, height, tmp_w, tmp_h, max_dim;
1615     short vadd, hadd;
1616     int n, columns, test_h, num_children = 0;
1617     Boolean try_layout = False;
1618
1619 #ifndef OLDXAW
1620     hadd = xaw->simple_menu.left_margin + xaw->simple_menu.right_margin;
1621 #else
1622     hadd = 0;
1623 #endif
1624     vadd = xaw->simple_menu.top_margin + xaw->simple_menu.bottom_margin;
1625     if (xaw->simple_menu.label)
1626         vadd += XtHeight(xaw->simple_menu.label);
1627
1628     if (*height_return)
1629         max_dim = *height_return;
1630     else if (!XtHeight(w)) {
1631         max_dim = HeightOfScreen(XtScreen(w));
1632         try_layout = True;
1633     }
1634     else
1635         max_dim = XtHeight(w);
1636     max_dim -= vadd;
1637
1638     width = height = tmp_w = tmp_h = n = test_h = 0;
1639     columns = 1;
1640     for (i = xaw->simple_menu.label ? 1 : 0;
1641          i < xaw->composite.num_children;
1642          i++) {
1643         kid = xaw->composite.children[i];
1644         if (!XtIsManaged(kid))
1645             continue;
1646         ++num_children;
1647         width_kid = XtWidth(kid);
1648         height_kid = XtHeight(kid);
1649
1650         if (try_layout) {
1651             if (!test_h)
1652                 test_h = height_kid;
1653             else if (test_h != height_kid)
1654                 try_layout = False;
1655         }
1656
1657         if (n && (height + height_kid > max_dim)) {
1658             ++columns;
1659             width += tmp_w;
1660             tmp_w = width_kid;
1661             height = height_kid;
1662         }
1663         else
1664             height += height_kid;
1665         if (height > tmp_h)
1666             tmp_h = height;
1667         if (width_kid > tmp_w)
1668             tmp_w = width_kid;
1669         ++n;
1670     }
1671
1672     height = tmp_h + vadd;
1673     width += tmp_w + hadd;
1674
1675     if (xaw->simple_menu.label)
1676         width = XawMax(width, XtWidth(xaw->simple_menu.label) + hadd);
1677
1678     *width_return = width;
1679     *height_return = height;
1680
1681     if (try_layout && columns > 1 && num_children > 2) {
1682         int space;
1683
1684         height = test_h * (xaw->simple_menu.label ?
1685                            num_children - 1 :
1686                            num_children);
1687
1688         max_dim -= max_dim % test_h;
1689         space = max_dim - (height % max_dim);
1690         if (space >= test_h * columns) {
1691             height = max_dim - space / columns;
1692             if (height % test_h)
1693                 height += test_h - (height % test_h);
1694             *height_return = height + vadd;
1695             CalculateNewSize(w, width_return, height_return);
1696         }
1697     }
1698 }
1699
1700 static void
1701 MakeResizeRequest(Widget w)
1702 {
1703     int tries;
1704     Dimension width, height;
1705   
1706     width = XtWidth(w);
1707     height = XtHeight(w);
1708
1709     for (tries = 0; tries < 100; tries++) {
1710         CalculateNewSize(w, &width, &height);
1711         if (width == XtWidth(w) && height == XtHeight(w))
1712             break;
1713         if (XtMakeResizeRequest(w, width, height, &width, &height) ==
1714             XtGeometryNo)
1715         break;
1716     }
1717 }
1718
1719 #ifndef OLDXAW
1720 static void
1721 Popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
1722 {
1723     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1724
1725     while (XtParent(w) &&
1726            XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) {
1727         if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w) {
1728             w = XtParent(w);
1729             smw = (SimpleMenuWidget)w;
1730             smw->simple_menu.entry_set = NULL;
1731         }
1732         else
1733             break;
1734     }
1735
1736     smw->simple_menu.state |= SMW_UNMAPPING;
1737     if (smw->simple_menu.sub_menu)
1738         PopdownSubMenu(smw);
1739     XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params);
1740 }
1741
1742 static void
1743 PopupSubMenu(SimpleMenuWidget smw)
1744 {
1745     Arg args[2];
1746     Cardinal num_args;
1747     Widget menu;
1748     SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set;
1749     Position menu_x, menu_y;
1750     Bool popleft;
1751
1752     if (entry->sme_bsb.menu_name == NULL)
1753         return;
1754
1755     if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL)
1756         return;
1757
1758     smw->simple_menu.sub_menu = menu;
1759
1760     if (!XtIsRealized(menu))
1761         XtRealizeWidget(menu);
1762
1763     popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0;
1764
1765     if (popleft) 
1766         XtTranslateCoords((Widget)smw, -(int)XtWidth(menu),
1767                           XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y);
1768     else
1769         XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry)
1770                           - XtBorderWidth(menu), &menu_x, &menu_y);
1771
1772     if (!popleft && menu_x >= 0) {
1773         int scr_width = WidthOfScreen(XtScreen(menu));
1774
1775         if (menu_x + XtWidth(menu) > scr_width) {
1776             menu_x -= XtWidth(menu) + XtWidth(smw);
1777             popleft = True;
1778         }
1779     }
1780     else if (popleft && menu_x < 0) {
1781         menu_x = 0;
1782         popleft = False;
1783     }
1784     if (menu_y >= 0) {
1785         int scr_height = HeightOfScreen(XtScreen(menu));
1786
1787         if (menu_y + XtHeight(menu) > scr_height)
1788             menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu);
1789     }
1790     if (menu_y < 0)
1791         menu_y = 0;
1792
1793     num_args = 0;
1794     XtSetArg(args[num_args], XtNx, menu_x);     num_args++;
1795     XtSetArg(args[num_args], XtNy, menu_y);     num_args++;
1796     XtSetValues(menu, args, num_args);
1797
1798     if (popleft)
1799         ((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT;
1800     else
1801         ((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT;
1802
1803     XtPopup(menu, XtGrabNone);
1804 }
1805
1806 static void
1807 PopdownSubMenu(SimpleMenuWidget smw)
1808 {
1809     SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu;
1810
1811     if (!menu)
1812         return;
1813
1814     menu->simple_menu.state |= SMW_UNMAPPING;
1815     PopdownSubMenu(menu);
1816
1817     XtPopdown((Widget)menu);
1818
1819     smw->simple_menu.sub_menu = NULL;
1820 }
1821
1822 /*ARGSUSED*/
1823 static void
1824 PopupCB(Widget w, XtPointer client_data, XtPointer call_data)
1825 {
1826     SimpleMenuWidget smw = (SimpleMenuWidget)w;
1827
1828     smw->simple_menu.state &= ~(SMW_UNMAPPING | SMW_POPLEFT);
1829 }
1830 #endif /* OLDXAW */