text: /* $Xorg: SimpleMenu.c,v 1.4 2001/02/09 02:03:45 xorgcvs Exp $ */
  
  /*
  Copyright 1989, 1994, 1998  The Open Group
  
  Permission to use, copy, modify, distribute, and sell this software and its
  documentation for any purpose is hereby granted without fee, provided that
  the above copyright notice appear in all copies and that both that
  copyright notice and this permission notice appear in supporting
  documentation.
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  Except as contained in this notice, the name of The Open Group shall not be
  used in advertising or otherwise to promote the sale, use or other dealings
  in this Software without prior written authorization from The Open Group.
   */
  
  /* $XFree86: xc/lib/Xaw/SimpleMenu.c,v 3.21 2001/03/23 23:59:15 paulo Exp $ */
  
  /*
   * SimpleMenu.c - Source code file for SimpleMenu widget.
   *
   * Date:    April 3, 1989
   *
   * By:      Chris D. Peterson
   *          MIT X Consortium 
   *          kit@expo.lcs.mit.edu
   */
  
  #ifdef HAVE_CONFIG_H
  #include <config.h>
  #endif
  #include <stdio.h>
  #include <X11/IntrinsicP.h>
  #include <X11/StringDefs.h>
  #include <X11/Xmu/Initer.h>
  #include <X11/Xmu/SysUtil.h>
  #include <X11/Xaw/Cardinals.h>
  #include <X11/Xaw/SimpleMenP.h>
  #include <X11/Xaw/SmeBSBP.h>
  #include <X11/Xaw/XawInit.h>
  #include "Private.h"
  
  #define streq(a, b)	(strcmp((a), (b)) == 0)
  
  #define ForAllChildren(smw, childP)				\
  for ((childP) = (SmeObject *)(smw)->composite.children;		\
       (childP) < (SmeObject *)((smw)->composite.children		\
  			      + (smw)->composite.num_children);	\
       (childP)++)
  
  #ifndef OLDXAW
  #define	SMW_UNMAPPING	0x01
  #define SMW_POPLEFT	0x02
  #endif
  
  /*
   * Class Methods
   */
  static void XawSimpleMenuChangeManaged(Widget);
  static void XawSimpleMenuClassInitialize(void);
  static void XawSimpleMenuClassPartInitialize(WidgetClass);
  static XtGeometryResult XawSimpleMenuGeometryManager(Widget, XtWidgetGeometry*,
  						     XtWidgetGeometry*);
  static void XawSimpleMenuInitialize(Widget, Widget, ArgList, Cardinal*);
  static void XawSimpleMenuRealize(Widget, XtValueMask*, XSetWindowAttributes*);
  static void XawSimpleMenuRedisplay(Widget, XEvent*, Region);
  static void XawSimpleMenuResize(Widget);
  static Boolean XawSimpleMenuSetValues(Widget, Widget, Widget,
  				      ArgList, Cardinal*);
  static Boolean XawSimpleMenuSetValuesHook(Widget, ArgList, Cardinal*);
  #ifndef OLDXAW
  static void PopupSubMenu(SimpleMenuWidget);
  static void PopdownSubMenu(SimpleMenuWidget);
  static void PopupCB(Widget, XtPointer, XtPointer);
  #endif
  
  /*
   * Prototypes
   */
  static void AddPositionAction(XtAppContext, XPointer);
  static void CalculateNewSize(Widget, Dimension*, Dimension*);
  static void ChangeCursorOnGrab(Widget, XtPointer, XtPointer);
  static void CreateLabel(Widget);
  static SmeObject DoGetEventEntry(Widget, int, int);
  static Widget FindMenu(Widget, String);
  static SmeObject GetEventEntry(Widget, XEvent*);
  static void Layout(Widget, Dimension*, Dimension*);
  static void MakeResizeRequest(Widget);
  static void MakeSetValuesRequest(Widget, unsigned int, unsigned int);
  static void MoveMenu(Widget, int, int);
  static void PositionMenu(Widget, XPoint*);
  
  /*
   * Actions
   */
  static void Highlight(Widget, XEvent*, String*, Cardinal*);
  static void Notify(Widget, XEvent*, String*, Cardinal*);
  #ifndef OLDXAW
  static void Popdown(Widget, XEvent*, String*, Cardinal*);
  #endif
  static void PositionMenuAction(Widget, XEvent*, String*, Cardinal*);
  static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
  
  /*
   * Initialization
   */
  #define offset(field)	XtOffsetOf(SimpleMenuRec, simple_menu.field)
  
  static XtResource resources[] = {
    /* label */
    {
      XtNlabel,
      XtCLabel,
      XtRString,
      sizeof(String),
      offset(label_string),
      XtRString,
      NULL
    },
    {
      XtNlabelClass,
      XtCLabelClass,
      XtRPointer,
      sizeof(WidgetClass),
      offset(label_class),
      XtRImmediate,
      NULL
    },
  
    /* layout */
    {
      XtNrowHeight,
      XtCRowHeight,
      XtRDimension,
      sizeof(Dimension),
      offset(row_height),
      XtRImmediate,
      (XtPointer)0
    },
    {
      XtNtopMargin,
      XtCVerticalMargins,
      XtRDimension,
      sizeof(Dimension),
      offset(top_margin),
      XtRImmediate,
      (XtPointer)0
    },
    {
      XtNbottomMargin,
      XtCVerticalMargins,
      XtRDimension,
      sizeof(Dimension),
      offset(bottom_margin),
      XtRImmediate,
      (XtPointer)0
    },
  #ifndef OLDXAW
    {
      XtNleftMargin,
      XtCHorizontalMargins,
      XtRDimension,
      sizeof(Dimension),
      offset(left_margin),
      XtRImmediate,
      (XtPointer)0
    },
    {
      XtNrightMargin,
      XtCHorizontalMargins,
      XtRDimension,
      sizeof(Dimension),
      offset(right_margin),
      XtRImmediate,
      (XtPointer)0
    },
  #endif
  
    /* misc */
    {
      XtNallowShellResize,
      XtCAllowShellResize,
      XtRBoolean,
      sizeof(Boolean),
      XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
      XtRImmediate,
      (XtPointer)True
    },
    {
      XtNcursor,
      XtCCursor,
      XtRCursor,
      sizeof(Cursor),
      offset(cursor),
      XtRImmediate,
      (XtPointer)None
    },
    {
      XtNmenuOnScreen,
      XtCMenuOnScreen,
      XtRBoolean,
      sizeof(Boolean),
      offset(menu_on_screen),
      XtRImmediate,
      (XtPointer)True
    },
    {
      XtNpopupOnEntry,
      XtCPopupOnEntry,
      XtRWidget,
      sizeof(Widget),
      offset(popup_entry),
      XtRWidget,
      NULL
    },
    {
      XtNbackingStore,
      XtCBackingStore,
      XtRBackingStore,
      sizeof(int),
      offset(backing_store), 
      XtRImmediate,
      (XtPointer)(Always + WhenMapped + NotUseful)
    },
  #ifndef OLDXAW
    {
      XawNdisplayList,
      XawCDisplayList,
      XawRDisplayList,
      sizeof(XawDisplayList*),
      offset(display_list), 
      XtRImmediate,
      NULL
    },
  #endif
  };  
  #undef offset
  
  static char defaultTranslations[] =
  "<Enter>:"	"highlight()\n"
  "<Leave>:"	"unhighlight()\n"
  "<BtnMotion>:"	"highlight()\n"
  #ifndef OLDXAW
  "<BtnUp>:"	"popdown() notify() unhighlight()\n"
  #else
  "<BtnUp>:"	"MenuPopdown() notify() unhighlight()\n"
  #endif
  ;
  
  static XtActionsRec actionsList[] =
  {
    {"notify",            Notify},
    {"highlight",         Highlight},
    {"unhighlight",       Unhighlight},
  #ifndef OLDXAW
    {"popdown",		Popdown},
    {"set-values",	XawSetValuesAction},
    {"get-values",	XawGetValuesAction},
    {"declare",		XawDeclareAction},
    {"call-proc",		XawCallProcAction},
  #endif
  };
   
  static CompositeClassExtensionRec extension_rec = {
    NULL,					/* next_extension */
    NULLQUARK,				/* record_type */
    XtCompositeExtensionVersion,		/* version */
    sizeof(CompositeClassExtensionRec),	/* record_size */
    True,					/* accepts_objects */
  };
  
  #define Superclass	(&overrideShellClassRec)
  SimpleMenuClassRec simpleMenuClassRec = {
    /* core */
    {
      (WidgetClass)Superclass,		/* superclass */
      "SimpleMenu",			/* class_name */
      sizeof(SimpleMenuRec),		/* size */
      XawSimpleMenuClassInitialize,	/* class_initialize */
      XawSimpleMenuClassPartInitialize,	/* class_part_initialize */
      False,				/* class_inited */
      XawSimpleMenuInitialize,		/* initialize */
      NULL,				/* initialize_hook */
      XawSimpleMenuRealize,		/* realize */
      actionsList,			/* actions */
      XtNumber(actionsList),		/* num_actions */
      resources,				/* resources */
      XtNumber(resources),		/* num_resources */
      NULLQUARK,				/* xrm_class */
      True,				/* compress_motion */
      True,				/* compress_exposure */
      True,				/* compress_enterleave */
      False,				/* visible_interest */
      NULL,				/* destroy */
      XawSimpleMenuResize,		/* resize */
      XawSimpleMenuRedisplay,		/* expose */
      XawSimpleMenuSetValues,		/* set_values */
      XawSimpleMenuSetValuesHook,		/* set_values_hook */
      XtInheritSetValuesAlmost,		/* set_values_almost */
      NULL,				/* get_values_hook */
      NULL,				/* accept_focus */
      XtVersion,				/* intrinsics version */
      NULL,				/* callback offsets */
      defaultTranslations,		/* tm_table */
      NULL,				/* query_geometry */
      NULL,				/* display_accelerator */
      NULL,				/* extension */
    },
    /* composite */
    {
      XawSimpleMenuGeometryManager,	/* geometry_manager */
      XawSimpleMenuChangeManaged,		/* change_managed */
      XtInheritInsertChild,		/* insert_child */
      XtInheritDeleteChild,		/* delete_child */
      NULL,				/* extension */
    },
    /* shell */
    {
      NULL,				/* extension */
    },
    /* override */
    {
      NULL,				/* extension */
    },
    /* simple_menu */
    {
      NULL,				/* extension */
    },
  };
  
  WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
  
  /*
   * Implementation
   */
  /*
   * Function:
   *	XawSimpleMenuClassInitialize
   *
   * Description:
   *	Class Initialize routine, called only once.
   */
  static void
  XawSimpleMenuClassInitialize(void)
  {
      XawInitializeWidgetSet();
      XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
  		   NULL, 0);
      XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
  		       NULL, 0, XtCacheNone, NULL);
      XmuAddInitializer(AddPositionAction, NULL);
  }
  
  /*
   * Function:
   *	XawSimpleMenuClassPartInitialize
   *      Arguments: wc - the widget class of the subclass.
   *
   * Description:
   *	  Class Part Initialize routine, called for every subclass.  Makes
   *	sure that the subclasses pick up the extension record.
   */
  static void
  XawSimpleMenuClassPartInitialize(WidgetClass wc)
  {
      SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass)wc;
  
      /*
       * Make sure that our subclass gets the extension rec too
       */
      extension_rec.next_extension = smwc->composite_class.extension;
      smwc->composite_class.extension = (XtPointer) &extension_rec;
  }
  
  /*
   *  Function:
   *	XawSimpleMenuInitialize
   *
   * Parameters:
   *	request - widget requested by the argument list
   *	cnew	- new widget with both resource and non resource values
   *
   * Description:
   *	Initializes the simple menu widget.
   */
  /*ARGSUSED*/
  static void
  XawSimpleMenuInitialize(Widget request, Widget cnew,
  			ArgList args, Cardinal *num_args)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)cnew;
      Dimension width, height;
  
      XmuCallInitializers(XtWidgetToApplicationContext(cnew));
  
      if (smw->simple_menu.label_class == NULL) 
  	smw->simple_menu.label_class = smeBSBObjectClass;
  
      smw->simple_menu.label = NULL;
      smw->simple_menu.entry_set = NULL;
      smw->simple_menu.recursive_set_values = False;
  #ifndef OLDXAW
      smw->simple_menu.sub_menu = NULL;
      smw->simple_menu.state = 0;
  
      XtAddCallback(cnew, XtNpopupCallback, PopupCB, NULL);
  #endif
  
      if (smw->simple_menu.label_string != NULL)
  	CreateLabel(cnew);
  
      width = height = 0;
      CalculateNewSize(cnew, &width, &height);
  
      smw->simple_menu.menu_width = True;
  
      if (XtWidth(smw) == 0) {
  	smw->simple_menu.menu_width = False;
  	XtWidth(smw) = width;
      }
  
      smw->simple_menu.menu_height = True;
  
      if (XtHeight(smw) == 0) {
  	smw->simple_menu.menu_height = False;
  	XtHeight(smw) = height;
      }
  
      /*
       * Add a popup_callback routine for changing the cursor
       */
      XtAddCallback(cnew, XtNpopupCallback, ChangeCursorOnGrab, NULL);
  }
  
  /*
   * Function:
   *	XawSimpleMenuRedisplay
   *
   * Parameters:
   *	w      - simple menu widget
   *	event  - X event that caused this redisplay
   *	region - region the needs to be repainted
   *
   * Description:
   *	Redisplays the contents of the widget.
   */
  /*ARGSUSED*/
  static void
  XawSimpleMenuRedisplay(Widget w, XEvent *event, Region region)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject *entry;
      SmeObjectClass cclass;
  
      if (region == NULL)
  	XClearWindow(XtDisplay(w), XtWindow(w));
  
  #ifndef OLDXAW
      if (smw->simple_menu.display_list)
        XawRunDisplayList(w, smw->simple_menu.display_list, event, region);
  #endif
  
      /*
       * Check and Paint each of the entries - including the label
       */
      ForAllChildren(smw, entry) {
  	if (!XtIsManaged((Widget)*entry))
  	    continue;
  
  	if (region != NULL) 
  	    switch(XRectInRegion(region, XtX(*entry),XtY(*entry),
  				 XtWidth(*entry), XtHeight(*entry))) {
  		case RectangleIn:
  		case RectanglePart:
  		    break;
  		default:
  		    continue;
  	    }
  
  	cclass = (SmeObjectClass)(*entry)->object.widget_class;
  
  	if (cclass->rect_class.expose != NULL)
  	    (cclass->rect_class.expose)((Widget)*entry, NULL, NULL);
      }
  }
  
  /*
   * Function:
   *	XawSimpleMenuRealize
   *
   * Parameters:
   *	w     - simple menu widget
   *	mask  - value mask for the window to create
   *	attrs - attributes for the window to create
   *
   * Description:
   *	Realizes the widget.
   */
  static void
  XawSimpleMenuRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
  #ifndef OLDXAW
      XawPixmap *pixmap;
  #endif
  
      attrs->cursor = smw->simple_menu.cursor;
      *mask |= CWCursor;
      if (smw->simple_menu.backing_store == Always ||
  	smw->simple_menu.backing_store == NotUseful ||
  	smw->simple_menu.backing_store == WhenMapped) {
  	*mask |= CWBackingStore;
  	attrs->backing_store = smw->simple_menu.backing_store;
      }
      else
  	*mask &= ~CWBackingStore;
  
      (*Superclass->core_class.realize)(w, mask, attrs);
  
  #ifndef OLDXAW
      if (w->core.background_pixmap > XtUnspecifiedPixmap) {
  	pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
  				      w->core.colormap, w->core.depth);
  	if (pixmap && pixmap->mask)
  	    XawReshapeWidget(w, pixmap);
      }
  #endif
  }
  
  /*
   * Function:
   *	XawSimpleMenuResize
   *
   * Parameters:
   *	w - simple menu widget
   *
   * Description:
   *	Handle the menu being resized.
   */
  static void
  XawSimpleMenuResize(Widget w)
  {
      if (!XtIsRealized(w))
  	return;
  
      Layout(w, NULL, NULL);
  
      XawSimpleMenuRedisplay(w, NULL, NULL);
  }
  
  /*
   * Function:
   *	XawSimpleMenuSetValues
   *
   * Parameters:
   *	current - current state of the widget
   *	request - what was requested
   *	cnew    - what the widget will become
   *
   * Description:
   *	Relayout the menu when one of the resources is changed.
   */
  /*ARGSUSED*/
  static Boolean
  XawSimpleMenuSetValues(Widget current, Widget request, Widget cnew,
  		       ArgList args, Cardinal *num_args)
  {
      SimpleMenuWidget smw_old = (SimpleMenuWidget)current;
      SimpleMenuWidget smw_new = (SimpleMenuWidget)cnew;
      Boolean ret_val = False, layout = False;
  
      if (!XtIsRealized(current))
  	return (False);
  
      if (!smw_new->simple_menu.recursive_set_values) {
  	if (XtWidth(smw_new) != XtWidth(smw_old)) {
  	    smw_new->simple_menu.menu_width = XtWidth(smw_new) != 0;
  	    layout = True;
  	}
  	if (XtHeight(smw_new) != XtHeight(smw_old)) {
  	    smw_new->simple_menu.menu_height = XtHeight(smw_new) != 0;
  	    layout = True;
  	}
      }
  
      if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
  	XDefineCursor(XtDisplay(cnew), XtWindow(cnew),
  		      smw_new->simple_menu.cursor);
  
      if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) {
  	if (smw_new->simple_menu.label_string == NULL)	    /* Destroy */
  	    XtDestroyWidget((Widget)smw_old->simple_menu.label);
  	else if (smw_old->simple_menu.label_string == NULL) /* Create */
  	    CreateLabel(cnew);
  	else {						    /* Change */
  	    Arg arglist[1];
  	    
  	    XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
  	    XtSetValues((Widget)smw_new->simple_menu.label, arglist, ONE);
  	}
      }
  
      if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
  	XtAppWarning(XtWidgetToApplicationContext(cnew),
  		     "No Dynamic class change of the SimpleMenu Label.");
      
      if (smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin
  	|| smw_old->simple_menu.bottom_margin
  	!= smw_new->simple_menu.bottom_margin) {
  	layout = True;
  	ret_val = True;
      }
  
  #ifndef OLDXAW
      if (smw_old->core.background_pixmap != smw_new->core.background_pixmap) {
  	XawPixmap *opix, *npix;
  
  	opix = XawPixmapFromXPixmap(smw_old->core.background_pixmap,
  				    XtScreen(smw_old), smw_old->core.colormap,
  				    smw_old->core.depth);
  	npix = XawPixmapFromXPixmap(smw_new->core.background_pixmap,
  				    XtScreen(smw_new), smw_new->core.colormap,
  				    smw_new->core.depth);
  	if ((npix && npix->mask) || (opix && opix->mask))
  	    XawReshapeWidget(cnew, npix);
      }
  #endif
  
      if (layout)
  	Layout(cnew, NULL, NULL);
  
      return (ret_val);
  }
  
  /* 
   * Function:
   *	XawSimpleMenuSetValuesHook
   *
   * Parameters:
   *	w	 - menu widget
   *	arglist	 - argument list passed to XtSetValues
   *	num_args - number of args
   *
   * Description:
   *	To handle a special case, this is passed the actual arguments.
   */
  static Boolean
  XawSimpleMenuSetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
  {
      Cardinal i;
      Dimension width, height;
      
      width = XtWidth(w);
      height = XtHeight(w);
      
      for (i = 0 ; i < *num_args ; i++) {
  	if (streq(arglist[i].name, XtNwidth))
  	    width = (Dimension)arglist[i].value;
  	if (streq(arglist[i].name, XtNheight))
  	    height = (Dimension) arglist[i].value;
      }
  
      if (width != XtWidth(w) || height != XtHeight(w))
  	MakeSetValuesRequest(w, width, height);
  
      return (False);
  }
  
  /*
   * Geometry Management routines
   */
  /*
   * Function:
   *	XawSimpleMenuGeometryManager
   *
   * Parameters:
   *	w	- Menu Entry making the request
   *	request - requested new geometry
   *                 reply - the allowed geometry.
   *
   * Description:
   *	This is the SimpleMenu Widget's Geometry Manager.
   *
   * Returns:
   *	XtGeometry{Yes, No, Almost}
   */
  static XtGeometryResult
  XawSimpleMenuGeometryManager(Widget w, XtWidgetGeometry *request,
  			     XtWidgetGeometry *reply)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)XtParent(w);
      SmeObject entry = (SmeObject)w;
      XtGeometryMask mode = request->request_mode;
      XtGeometryResult answer;
      Dimension old_height, old_width;
  
      if (!(mode & CWWidth) && !(mode & CWHeight))
  	return (XtGeometryNo);
  
      reply->width = request->width;
      reply->height = request->height;
  
      old_width = XtWidth(entry);
      old_height = XtHeight(entry);
  
      Layout(w, &reply->width, &reply->height);
  
      /*
       * Since we are an override shell and have no parent there is no one to
       * ask to see if this geom change is okay, so I am just going to assume
       * we can do whatever we want.  If you subclass be very careful with this
       * assumption, it could bite you.
       *
       * Chris D. Peterson - Sept. 1989.
       */
      if ((!(mode & CWWidth) || reply->width == request->width)
  	&& (!(mode & CWHeight) || reply->height == request->height)) {
  	if (mode & XtCWQueryOnly) {	/* Actually perform the layout */
  	    XtWidth(entry) = old_width;
  	    XtHeight(entry) = old_height;
  	}
  	else
  	    Layout((Widget)smw, NULL, NULL);
  	answer = XtGeometryDone;
      }
      else {
  	XtWidth(entry) = old_width;
  	XtHeight(entry) = old_height;
  
  	if ((reply->width == request->width && !(mode & CWHeight))
  	    || (reply->height == request->height && !(mode & CWWidth))
  	    || (reply->width == request->width
  	    && reply->height == request->height))
  	    answer = XtGeometryNo;
  	else {
  	    answer = XtGeometryAlmost;
  	    reply->request_mode = 0;
  	    if (reply->width != request->width)
  		reply->request_mode |= CWWidth;
  	    if (reply->height != request->height)
  		reply->request_mode |= CWHeight;
  	}
      }
  
      return (answer);
  }
  
  /*
   * Function:
   *	XawSimpleMenuChangeManaged
   *
   * Parameters:
   *	w - simple menu widget
   *
   * Description:
   *	Called whenever a new child is managed.
   */
  static void
  XawSimpleMenuChangeManaged(Widget w)
  {
      Layout(w, NULL, NULL);
  }
  
  /*
   * Global Action Routines
   * 
   * These actions routines will be added to the application's
   * global action list
   */
  /*
   * Function:
   *	PositionMenuAction
   * 
   * Parameters:
   *	w	   - a widget (no the simple menu widget)
   *	event	   - the event that caused this action
   *	params	   - parameters passed to the routine.
   *                                      we expect the name of the menu here.
   *	num_params - ""
   *
   * Description:
   *	Positions the simple menu widget.
   */
  /*ARGSUSED*/
  static void
  PositionMenuAction(Widget w, XEvent *event,
  		   String *params, Cardinal *num_params)
  { 
      Widget menu;
      XPoint loc;
  
      if (*num_params != 1) {
  	XtAppWarning(XtWidgetToApplicationContext(w),
  		     "SimpleMenuWidget: position menu action expects "
  		     "only one parameter which is the name of the menu.");
  	return;
      }
  
      if ((menu = FindMenu(w, params[0])) == NULL) {
  	char error_buf[BUFSIZ];
  
  	(void)XmuSnprintf(error_buf, sizeof(error_buf),
  			  "SimpleMenuWidget: could not find menu named %s.",
  			  params[0]);
  	XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  	return;
      }
    
      switch (event->type) {
  	case ButtonPress:
  	case ButtonRelease:
  	    loc.x = event->xbutton.x_root;
  	    loc.y = event->xbutton.y_root;
  	    PositionMenu(menu, &loc);
  	    break;
  	case EnterNotify:
  	case LeaveNotify:
  	    loc.x = event->xcrossing.x_root;
  	    loc.y = event->xcrossing.y_root;
  	    PositionMenu(menu, &loc);
  	    break;
  	case MotionNotify:
  	    loc.x = event->xmotion.x_root;
  	    loc.y = event->xmotion.y_root;
  	    PositionMenu(menu, &loc);
  	    break;
  	default:
  	    PositionMenu(menu, NULL);
  	    break;
      }
  }  
  
  /*
   * Widget Action Routines
   */
  /*
   * Function:
   *	Unhighlight
   *
   * Parameters:
   *	w	   - simple menu widget
   *	event	   - event that caused this action
   *	params	   - not used
   *	num_params - ""
   * 
   * Description:
   *	Unhighlights current entry.
   */
  /*ARGSUSED*/
  static void
  Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
  { 
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject entry = smw->simple_menu.entry_set;
   
      if (entry == NULL)
  	return;
  
  #ifndef OLDXAW
      if (!smw->simple_menu.sub_menu)
  #endif
      {
  	SmeObjectClass cclass;
  
  	smw->simple_menu.entry_set = NULL;
  	cclass = (SmeObjectClass)entry->object.widget_class;
  	(cclass->sme_class.unhighlight)((Widget)entry);
      }
  }
  
  /*
   * Function:
   *	Highlight
   *
   * Parameters:
   *	w	   - simple menu widget
   *	event	   - event that caused this action
   *	params	   - not used
   *	num_params - ""
   *
   * Description:
   *	Highlights current entry.
   */
  /*ARGSUSED*/
  static void
  Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject entry;
  
      if (!XtIsSensitive(w))
  	return;
  
      entry = GetEventEntry(w, event);
  
      if (entry == smw->simple_menu.entry_set)
  	return;
  
  #ifndef OLDXAW
      if (!smw->simple_menu.sub_menu)
  #endif
  	Unhighlight(w, event, params, num_params);
  
      if (entry == NULL)
  	return;
  
      if (!XtIsSensitive((Widget)entry))
  	return;
  
  #ifndef OLDXAW
      if (smw->simple_menu.sub_menu)
  	PopdownSubMenu(smw);
  #endif
  
      Unhighlight(w, event, params, num_params);
  
  #ifndef OLDXAW
      if (!(smw->simple_menu.state & SMW_UNMAPPING))
  #endif
      {
  	SmeObjectClass cclass;
  
  	smw->simple_menu.entry_set = entry;
  	cclass = (SmeObjectClass)entry->object.widget_class;
  
  	(cclass->sme_class.highlight)((Widget)entry);
  
  #ifndef OLDXAW
  	if (XtIsSubclass((Widget)entry, smeBSBObjectClass))
  	    PopupSubMenu(smw);
  #endif
      }
  }
  
  /*
   * Function:
   *	Notify
   *
   * Parameters:
   *	w	   - simple menu widget
   *	event	   - event that caused this action
   *	params	   - not used
   *	num_params - ""
   *
   * Description:
   *	Notify user of current entry.
   */
  /*ARGSUSED*/
  static void
  Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      SmeObject entry;
      SmeObjectClass cclass;
  
      /* may be a propagated event from a sub menu, need to check it */
      if (XtWindow(w) != event->xany.window)
  	return;
      entry = GetEventEntry(w, event);
      if (entry == NULL || !XtIsSensitive((Widget)entry))
  	return;
  
      cclass = (SmeObjectClass) entry->object.widget_class;
      (cclass->sme_class.notify)((Widget)entry);
  }
  
  /*
   * Public Functions
   */
  /*
   * Function:
   *	XawSimpleMenuAddGlobalActions
   *
   * Arguments:
   *	app_con - appcontext
   *
   * Description:
   *	Adds the global actions to the simple menu widget.
   */
  void
  XawSimpleMenuAddGlobalActions(XtAppContext app_con)
  {
      XtInitializeWidgetClass(simpleMenuWidgetClass);
      XmuCallInitializers(app_con);
  } 
  
  /*
   * Function:
   *	XawSimpleMenuGetActiveEntry
   *
   * Parameters:
   *	w - smw widget
   *
   * Description:
   *	Gets the currently active (set) entry.
   *
   * Returns:
   *	The currently set entry or NULL if none is set
   */
  Widget
  XawSimpleMenuGetActiveEntry(Widget w)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
  
      return ((Widget)smw->simple_menu.entry_set);
  } 
  
  /*
   * Function:
   *	XawSimpleMenuClearActiveEntry
   *
   * Parameters:
   *	w - smw widget
   *
   * Description:
   *	Unsets the currently active (set) entry.
   */
  void
  XawSimpleMenuClearActiveEntry(Widget w)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
  
      smw->simple_menu.entry_set = NULL;
  } 
  
  /*
   * Private Functions
   */
  /*
   * Function:
   *	CreateLabel
   *
   * Parameters:
   *	w - smw widget
   * 
   * Description:
   * Creates the label object and makes sure it is the first child in
   * in the list.
   */
  static void
  CreateLabel(Widget w)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      Widget *child, *next_child;
      int i;
      Arg args[2];
  
      if (smw->simple_menu.label_string == NULL ||
  	smw->simple_menu.label != NULL) {
  	XtAppWarning(XtWidgetToApplicationContext(w),
  		     "Xaw Simple Menu Widget: label string is NULL or "
  		     "label already exists, no label is being created.");
  	return;
      }
  
      XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
      XtSetArg(args[1], XtNjustify, XtJustifyCenter);
      smw->simple_menu.label = (SmeObject) 
  	XtCreateManagedWidget("menuLabel", 
  			      smw->simple_menu.label_class, w, args, TWO);
  
      next_child = NULL;
      for (child = smw->composite.children + smw->composite.num_children,
  	 i = smw->composite.num_children; i > 0; i--, child--) {
  	if (next_child != NULL)
  	    *next_child = *child;
  	next_child = child;
      }
      *child = (Widget)smw->simple_menu.label;
  }
  
  /*
   * Function:
   *	Layout
   *
   * Arguments:
   *	w	   - See below
   *	width_ret  - returned width
   *	height_ret - returned height
   *
   * Note:
   * if width == NULL || height == NULL then it assumes the you do not care
   * about the return values, and just want a relayout.
   *
   * if this is not the case then it will set width_ret and height_ret
   * to be width and height that the child would get if it were layed out
   * at this time.
   *
   *	"w" can be the simple menu widget or any of its object children.
   */
  static void
  Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
  {
      SmeObject current_entry;
      SimpleMenuWidget smw;
      Dimension width, height;
      Boolean allow_change_size;
      Widget kid;
      Cardinal i, count, n;
      int width_kid, height_kid, tmp_w, tmp_h;
      short vadd, hadd, x_ins, y_ins;
      Dimension *widths;
  
      height = 0;
  
      if (XtIsSubclass(w, simpleMenuWidgetClass)) {
  	smw = (SimpleMenuWidget)w;
  	current_entry = NULL;
      }
      else {
  	smw = (SimpleMenuWidget)XtParent(w);
  	current_entry = (SmeObject)w;
      }
  
      allow_change_size = (!XtIsRealized((Widget)smw)
  			 || smw->shell.allow_shell_resize);
  
      for (i = smw->simple_menu.label ? 1 : 0;
  	 i < smw->composite.num_children;
  	 i++) {
  	XtWidgetGeometry preferred;
  
  	kid = smw->composite.children[i];
  	if (!XtIsManaged(kid))
  	    continue;
  	if (smw->simple_menu.row_height != 0)
  	    XtHeight(kid) = smw->simple_menu.row_height;
  	XtQueryGeometry(kid, NULL, &preferred);
  	if (preferred.request_mode & CWWidth)
  	    XtWidth(kid) = preferred.width;
      }
  
      if (smw->simple_menu.label
  	&& XtIsManaged((Widget)smw->simple_menu.label)) {
  	XtWidgetGeometry preferred;
  
  	kid = (Widget)smw->simple_menu.label;
  	XtQueryGeometry(kid, NULL, &preferred);
  	if (preferred.request_mode & CWWidth)
  	    XtWidth(kid) = preferred.width;
  	if (preferred.request_mode & CWHeight)
  	    XtHeight(kid) = preferred.height;
      }
  
      /* reset */
      if (!smw->simple_menu.menu_width)
  	XtWidth(smw) = 0;
      if (!smw->simple_menu.menu_height)
  	XtHeight(smw) = 0;
      if (!XtWidth(smw) || !XtHeight(smw))
  	MakeResizeRequest((Widget)smw);
  
      widths = (Dimension *)XtMalloc(sizeof(Dimension));
  #ifndef OLDXAW
      hadd = smw->simple_menu.left_margin;
  #else
      hadd = 0;
  #endif
      vadd = smw->simple_menu.top_margin;
      if (smw->simple_menu.label)
  	vadd += XtHeight(smw->simple_menu.label);
  
      count = 1;
      width = tmp_w = tmp_h = n = 0;
      height = vadd;
  
      for (i = smw->simple_menu.label ? 1 : 0;
  	 i < smw->composite.num_children;
  	 i++) {
  	kid = smw->composite.children[i];
  	if (!XtIsManaged(kid))
  	    continue;
  	width_kid = XtWidth(kid);
  	height_kid = XtHeight(kid);
  
  	if (n && (height + height_kid + smw->simple_menu.bottom_margin
  		  > XtHeight(smw))) {
  	    ++count;
  	    widths = (Dimension *)XtRealloc((char *)widths,
  					    sizeof(Dimension) * count);
  	    widths[count - 1] = width_kid;
  	    width += tmp_w;
  	    tmp_w = width_kid;
  	    height = height_kid + vadd;
  	}
  	else
  	    height += height_kid;
  	if (height > tmp_h)
  	    tmp_h = height;
  	if (width_kid > tmp_w)
  	    widths[count - 1] = tmp_w = width_kid;
  	++n;
      }
  
      height = tmp_h + smw->simple_menu.bottom_margin;
      width += tmp_w;
  
      if (smw->simple_menu.label && width < XtWidth(smw->simple_menu.label)) {
  	float inc;
  
  	inc = (XtWidth(smw->simple_menu.label) - width) / (float)count;
  	width = XtWidth(smw->simple_menu.label);
  	for (n = 0; n < count; n++)
  	    widths[n] += inc;
      }
  
  #ifndef OLDXAW
      width += hadd + smw->simple_menu.right_margin;
  #endif
  
      x_ins = n = count = 0;
      tmp_w = widths[0];
      tmp_h = vadd;
  
      for (i = smw->simple_menu.label ? 1 : 0;
  	 i < smw->composite.num_children;
  	 i++) {
  	kid = smw->composite.children[i];
  	if (!XtIsManaged(kid))
  	    continue;
  
  	height_kid = XtHeight(kid);
  
  	if (n && (tmp_h + height_kid + smw->simple_menu.bottom_margin
  		  > XtHeight(smw))) {
  	    x_ins = tmp_w;
  	    y_ins = vadd;
  	    ++count;
  	    tmp_w += widths[count];
  	    tmp_h = height_kid + vadd;
  	}
  	else {
  	    y_ins = tmp_h;
  	    tmp_h += height_kid;
  	}
  	++n;
  
  	XtX(kid) = x_ins + hadd;
  	XtY(kid) = y_ins;
  	XtWidth(kid) = widths[count];
      }
  
      XtFree((char *)widths);
  
      if (allow_change_size)
  	MakeSetValuesRequest((Widget) smw, width, height);
  
      if (smw->simple_menu.label) {
  	XtX(smw->simple_menu.label) = 0;
  	XtY(smw->simple_menu.label) = smw->simple_menu.top_margin;
  	XtWidth(smw->simple_menu.label) = XtWidth(smw)
  #ifndef OLDXAW
  	    - (smw->simple_menu.left_margin + smw->simple_menu.right_margin)
  #endif
  	    ;
      }
      if (current_entry) {
  	if (width_ret)
  	    *width_ret = XtWidth(current_entry);
  	if (height_ret)
  	    *height_ret = XtHeight(current_entry);
      }
  }
      
  /*
   * Function:
   *	AddPositionAction
   *
   * Parameters:
   *	app_con - application context
   *	data	- (not used)
   *
   * Description:
   *	  Adds the XawPositionSimpleMenu action to the global
   *                   action list for this appcon.
   */
  /*ARGSUSED*/
  static void
  AddPositionAction(XtAppContext app_con, XPointer data)
  {
      static XtActionsRec pos_action[] = {
  	{"XawPositionSimpleMenu",	PositionMenuAction},
      };
  
      XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
  }
  
  /*
   * Function:
   *	FindMenu
   *
   * Parameters:
   *	widget - reference widget
   *	name   - menu widget's name
   *
   * Description:
   *	Find the menu give a name and reference widget
   *
   * Returns:
   *	The menu widget or NULL.
   */
  static Widget 
  FindMenu(Widget widget, String name)
  {
      Widget w, menu;
      
      for (w = widget; w != NULL; w = XtParent(w))
  	if ((menu = XtNameToWidget(w, name)) != NULL)
  	    return (menu);
  
      return (NULL);
  }
  
  /*
   * Function:
   *	PositionMenu
   *
   * Parameters:
   *	w	 - simple menu widget
   *	location - pointer the the position or NULL
   *
   * Description:
   *	Places the menu
   */
  static void
  PositionMenu(Widget w, XPoint *location)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject entry;
      XPoint t_point;
      
      if (location == NULL) {
  	Window temp1, temp2;
  	int root_x, root_y, tempX, tempY;
  	unsigned int tempM;
  	
  	location = &t_point;
  	if (XQueryPointer(XtDisplay(w), XtWindow(w), &temp1, &temp2,
  			  &root_x, &root_y, &tempX, &tempY, &tempM) == False) {
  	    XtAppWarning(XtWidgetToApplicationContext(w),
  			 "Xaw Simple Menu Widget: "
  			 "Could not find location of mouse pointer");
  	    return;
  	}
  	location->x = (short) root_x;
  	location->y = (short) root_y;
      }
      
      /*
       * The width will not be correct unless it is realized
       */
      XtRealizeWidget(w);
      
      location->x -= XtWidth(w) >> 1;
      
      if (smw->simple_menu.popup_entry == NULL)
  	entry = smw->simple_menu.label;
      else
  	entry = smw->simple_menu.popup_entry;
  
      if (entry != NULL)
        location->y -= XtY(entry) + (XtHeight(entry) >> 1);
  
      MoveMenu(w, location->x, location->y);
  }
  
  /*
   * Function:
   *	MoveMenu
   *
   * Parameters:
   *	w - simple menu widget
   *	x - current location of the widget
   *	y - ""
   *
   * Description:
   *	  Actually moves the menu, may force it to
   *	to be fully visable if menu_on_screen is True.
   */
  static void
  MoveMenu(Widget w, int x, int y)
  {
      Arg arglist[2];
      Cardinal num_args = 0;
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      
      if (smw->simple_menu.menu_on_screen) {
  	int width = XtWidth(w) + (XtBorderWidth(w) << 1);
  	int height = XtHeight(w) + (XtBorderWidth(w) << 1);
  	
  	if (x >= 0) {
  	    int scr_width = WidthOfScreen(XtScreen(w));
  
  	    if (x + width > scr_width)
  		x = scr_width - width;
  	}
  	if (x < 0) 
  	    x = 0;
  	
  	if (y >= 0) {
  	    int scr_height = HeightOfScreen(XtScreen(w));
  
  	    if (y + height > scr_height)
  		y = scr_height - height;
  	}
  	if (y < 0)
  	    y = 0;
      }
      
      XtSetArg(arglist[num_args], XtNx, x); num_args++;
      XtSetArg(arglist[num_args], XtNy, y); num_args++;
      XtSetValues(w, arglist, num_args);
  }
  
  /*
   * Function:
   *	ChangeCursorOnGrab
   *
   * Parameters:
   *	w     - menu widget
   *	temp1 - not used
   *	temp2 - ""
   *
   * Description:
   *	  Changes the cursor on the active grab to the one
   *                   specified in out resource list.
   */
  /*ARGSUSED*/
  static void
  ChangeCursorOnGrab(Widget w, XtPointer temp1, XtPointer temp2)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      
      /*
       * The event mask here is what is currently in the MIT implementation.
       * There really needs to be a way to get the value of the mask out
       * of the toolkit (CDP 5/26/89).
       */
      XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask | ButtonReleaseMask,
  			     smw->simple_menu.cursor, 
  			     XtLastTimestampProcessed(XtDisplay(w)));
  }
  
  /*
   * Function:
   *	MakeSetValuesRequest
   *
   * Parameters:
   *	w      - simple menu widget
   *	width  - size requested
   *	height - ""
   */
  static void
  MakeSetValuesRequest(Widget w, unsigned int width, unsigned int height)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      Arg arglist[2];
      Cardinal num_args = 0;
      
      if (!smw->simple_menu.recursive_set_values) {
  	if (XtWidth(smw) != width || XtHeight(smw) != height) {
  	    smw->simple_menu.recursive_set_values = True;
  	    XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
  	    XtSetArg(arglist[num_args], XtNheight, height); num_args++;
  	    XtSetValues(w, arglist, num_args);
  	}
  	else if (XtIsRealized((Widget)smw))
  	    XawSimpleMenuRedisplay((Widget)smw, NULL, NULL);
      }
      smw->simple_menu.recursive_set_values = False;
  }
  
  static SmeObject
  DoGetEventEntry(Widget w, int x_loc, int y_loc)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject *entry;
  
      ForAllChildren(smw, entry) {
  	if (!XtIsManaged((Widget)*entry))
  	    continue;
  
  	if (x_loc > XtX(*entry)
  	    && x_loc <= XtX(*entry) + XtWidth(*entry)
  	    && y_loc > XtY(*entry)
  	    &&  y_loc <= XtY(*entry) + XtHeight(*entry)) {
  	    if (*entry == smw->simple_menu.label)
  		return (NULL);	/* cannot select the label */
  	    else
  		return (*entry);
  	}
      }
      
      return (NULL);
  }
  
  /*
   * Function:
   *	GetEventEntry
   *
   * Parameters:
   *	w     - simple menu widget
   *	event - X event
   *
   * Description:
   *	Gets an entry given an event that has X and Y coords.
   *
   * Returns:
   *	The entry that this point is in
   */
  static SmeObject
  GetEventEntry(Widget w, XEvent *event)
  {
      int x_loc, y_loc, x_root;
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
      SmeObject entry;
      int warp, move;
  
      switch (event->type) {
  	case MotionNotify:
  	    x_loc = event->xmotion.x;
  	    y_loc = event->xmotion.y;
  	    x_root = event->xmotion.x_root;
  	    break;
  	case EnterNotify:
  	case LeaveNotify:
  	    x_loc = event->xcrossing.x;
  	    y_loc = event->xcrossing.y;
  	    x_root = event->xcrossing.x_root;
  	    break;
  	case ButtonPress:
  	case ButtonRelease:
  	    x_loc = event->xbutton.x;
  	    y_loc = event->xbutton.y;
  	    x_root = event->xbutton.x_root;
  	    break;
  	default:
  	    XtAppError(XtWidgetToApplicationContext(w),
  		       "Unknown event type in GetEventEntry().");
  	    return (NULL);
      }
      
      if (x_loc < 0 || x_loc >= XtWidth(smw) ||
  	y_loc < 0 || y_loc >= XtHeight(smw))
  	return (NULL);
  
      /* Move the menu if it's outside the screen, does not check
       * smw->simple_menu.menu_on_screen because menus is bigger than screen
       */
      if (x_root == WidthOfScreen(XtScreen(w)) - 1 &&
  	XtX(w) + XtWidth(w) + (XtBorderWidth(w)) > x_root) {
  	warp = -8;
  	if (smw->simple_menu.entry_set) {
  	    entry = DoGetEventEntry(w,
  				    XtX(smw->simple_menu.entry_set)
  				    + XtWidth(smw->simple_menu.entry_set) + 1,
  				    y_loc);
  	    Unhighlight(w, event, NULL, NULL);
  	    if (entry) {
  		warp = -(int)XtWidth(entry) >> 1;
  		move = x_loc - XtWidth(entry) - XtX(entry) + XtBorderWidth(w);
  	    }
  	    else {
  		warp = 0;
  		move = WidthOfScreen(XtScreen(w)) -
  		       (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
  	    }
  	}
  	else {
  	    warp = 0;
  	    move = WidthOfScreen(XtScreen(w)) -
  		   (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
  	}
      }
      else if (x_root == 0 && XtX(w) < 0) {
  	warp = 8;
  	if (smw->simple_menu.entry_set) {
  	    entry = DoGetEventEntry(w, XtX(smw->simple_menu.entry_set) - 1,
  				    y_loc);
  	    Unhighlight(w, event, NULL, NULL);
  	    if (entry) {
  		warp = XtWidth(entry) >> 1;
  		move = x_loc - XtX(entry);
  	    }
  	    else
  		move = x_loc + XtBorderWidth(w);
  	}
  	else
  	    move = x_loc + XtBorderWidth(w);
      }
      else
  	move = warp = 0;
  
      if (move)
  	XtMoveWidget(w, XtX(w) + move, XtY(w));
      if (warp)
  	XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, warp, 0);
  
      return (DoGetEventEntry(w, x_loc, y_loc));
  }
  
  static void
  CalculateNewSize(Widget w, Dimension *width_return, Dimension *height_return)
  {
      SimpleMenuWidget xaw = (SimpleMenuWidget)w;
      Widget kid;
      Cardinal i;
      int width_kid, height_kid;
      int width, height, tmp_w, tmp_h, max_dim;
      short vadd, hadd;
      int n, columns, test_h, num_children = 0;
      Boolean try_layout = False;
  
  #ifndef OLDXAW
      hadd = xaw->simple_menu.left_margin + xaw->simple_menu.right_margin;
  #else
      hadd = 0;
  #endif
      vadd = xaw->simple_menu.top_margin + xaw->simple_menu.bottom_margin;
      if (xaw->simple_menu.label)
  	vadd += XtHeight(xaw->simple_menu.label);
  
      if (*height_return)
  	max_dim = *height_return;
      else if (!XtHeight(w)) {
  	max_dim = HeightOfScreen(XtScreen(w));
  	try_layout = True;
      }
      else
  	max_dim = XtHeight(w);
      max_dim -= vadd;
  
      width = height = tmp_w = tmp_h = n = test_h = 0;
      columns = 1;
      for (i = xaw->simple_menu.label ? 1 : 0;
  	 i < xaw->composite.num_children;
  	 i++) {
  	kid = xaw->composite.children[i];
  	if (!XtIsManaged(kid))
  	    continue;
  	++num_children;
  	width_kid = XtWidth(kid);
  	height_kid = XtHeight(kid);
  
  	if (try_layout) {
  	    if (!test_h)
  		test_h = height_kid;
  	    else if (test_h != height_kid)
  		try_layout = False;
  	}
  
  	if (n && (height + height_kid > max_dim)) {
  	    ++columns;
  	    width += tmp_w;
  	    tmp_w = width_kid;
  	    height = height_kid;
  	}
  	else
  	    height += height_kid;
  	if (height > tmp_h)
  	    tmp_h = height;
  	if (width_kid > tmp_w)
  	    tmp_w = width_kid;
  	++n;
      }
  
      height = tmp_h + vadd;
      width += tmp_w + hadd;
  
      if (xaw->simple_menu.label)
  	width = XawMax(width, XtWidth(xaw->simple_menu.label) + hadd);
  
      *width_return = width;
      *height_return = height;
  
      if (try_layout && columns > 1 && num_children > 2) {
  	int space;
  
  	height = test_h * (xaw->simple_menu.label ?
  			   num_children - 1 :
  			   num_children);
  
  	max_dim -= max_dim % test_h;
  	space = max_dim - (height % max_dim);
  	if (space >= test_h * columns) {
  	    height = max_dim - space / columns;
  	    if (height % test_h)
  		height += test_h - (height % test_h);
  	    *height_return = height + vadd;
  	    CalculateNewSize(w, width_return, height_return);
  	}
      }
  }
  
  static void
  MakeResizeRequest(Widget w)
  {
      int tries;
      Dimension width, height;
    
      width = XtWidth(w);
      height = XtHeight(w);
  
      for (tries = 0; tries < 100; tries++) {
  	CalculateNewSize(w, &width, &height);
  	if (width == XtWidth(w) && height == XtHeight(w))
  	    break;
  	if (XtMakeResizeRequest(w, width, height, &width, &height) ==
  	    XtGeometryNo)
  	break;
      }
  }
  
  #ifndef OLDXAW
  static void
  Popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
  
      while (XtParent(w) &&
  	   XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) {
  	if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w) {
  	    w = XtParent(w);
  	    smw = (SimpleMenuWidget)w;
  	    smw->simple_menu.entry_set = NULL;
  	}
  	else
  	    break;
      }
  
      smw->simple_menu.state |= SMW_UNMAPPING;
      if (smw->simple_menu.sub_menu)
  	PopdownSubMenu(smw);
      XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params);
  }
  
  static void
  PopupSubMenu(SimpleMenuWidget smw)
  {
      Arg args[2];
      Cardinal num_args;
      Widget menu;
      SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set;
      Position menu_x, menu_y;
      Bool popleft;
  
      if (entry->sme_bsb.menu_name == NULL)
  	return;
  
      if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL)
  	return;
  
      smw->simple_menu.sub_menu = menu;
  
      if (!XtIsRealized(menu))
  	XtRealizeWidget(menu);
  
      popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0;
  
      if (popleft) 
  	XtTranslateCoords((Widget)smw, -(int)XtWidth(menu),
  			  XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y);
      else
  	XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry)
  			  - XtBorderWidth(menu), &menu_x, &menu_y);
  
      if (!popleft && menu_x >= 0) {
  	int scr_width = WidthOfScreen(XtScreen(menu));
  
  	if (menu_x + XtWidth(menu) > scr_width) {
  	    menu_x -= XtWidth(menu) + XtWidth(smw);
  	    popleft = True;
  	}
      }
      else if (popleft && menu_x < 0) {
  	menu_x = 0;
  	popleft = False;
      }
      if (menu_y >= 0) {
  	int scr_height = HeightOfScreen(XtScreen(menu));
  
  	if (menu_y + XtHeight(menu) > scr_height)
  	    menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu);
      }
      if (menu_y < 0)
  	menu_y = 0;
  
      num_args = 0;
      XtSetArg(args[num_args], XtNx, menu_x);	num_args++;
      XtSetArg(args[num_args], XtNy, menu_y);	num_args++;
      XtSetValues(menu, args, num_args);
  
      if (popleft)
  	((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT;
      else
  	((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT;
  
      XtPopup(menu, XtGrabNone);
  }
  
  static void
  PopdownSubMenu(SimpleMenuWidget smw)
  {
      SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu;
  
      if (!menu)
  	return;
  
      menu->simple_menu.state |= SMW_UNMAPPING;
      PopdownSubMenu(menu);
  
      XtPopdown((Widget)menu);
  
      smw->simple_menu.sub_menu = NULL;
  }
  
  /*ARGSUSED*/
  static void
  PopupCB(Widget w, XtPointer client_data, XtPointer call_data)
  {
      SimpleMenuWidget smw = (SimpleMenuWidget)w;
  
      smw->simple_menu.state &= ~(SMW_UNMAPPING | SMW_POPLEFT);
  }
  #endif /* OLDXAW */
  