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