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