home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / SimpleMenu.c.orig < prev    next >
Encoding:
Text File  |  1991-06-22  |  34.3 KB  |  1,264 lines

  1. /* $XConsortium: SimpleMenu.c,v 1.39 91/06/22 18:03:29 rws Exp $ */
  2.  
  3. /*
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  */
  23.  
  24. /*
  25.  * SimpleMenu.c - Source code file for SimpleMenu widget.
  26.  *
  27.  * Date:    April 3, 1989
  28.  *
  29.  * By:      Chris D. Peterson
  30.  *          MIT X Consortium 
  31.  *          kit@expo.lcs.mit.edu
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <X11/IntrinsicP.h>
  36. #include <X11/StringDefs.h>
  37.  
  38. #include <X11/Xaw/XawInit.h>
  39. #include <X11/Xaw/SimpleMenP.h>
  40. #include <X11/Xaw/SmeBSB.h>
  41. #include <X11/Xaw/Cardinals.h>
  42.  
  43. #include <X11/Xmu/Initer.h>
  44. #include <X11/Xmu/CharSet.h>
  45.  
  46. #define streq(a, b)        ( strcmp((a), (b)) == 0 )
  47.  
  48. #define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field)
  49.  
  50. static XtResource resources[] = { 
  51.  
  52. /*
  53.  * Label Resources.
  54.  */
  55.  
  56.   {XtNlabel,  XtCLabel, XtRString, sizeof(String),
  57.      offset(label_string), XtRString, NULL},
  58.   {XtNlabelClass,  XtCLabelClass, XtRPointer, sizeof(WidgetClass),
  59.      offset(label_class), XtRImmediate, (XtPointer) NULL},
  60.  
  61. /*
  62.  * Layout Resources.
  63.  */
  64.  
  65.   {XtNrowHeight,  XtCRowHeight, XtRDimension, sizeof(Dimension),
  66.      offset(row_height), XtRImmediate, (XtPointer) 0},
  67.   {XtNtopMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  68.      offset(top_margin), XtRImmediate, (XtPointer) 0},
  69.   {XtNbottomMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
  70.      offset(bottom_margin), XtRImmediate, (XtPointer) 0},
  71.  
  72. /*
  73.  * Misc. Resources
  74.  */
  75.  
  76.   { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
  77.       XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
  78.       XtRImmediate, (XtPointer) TRUE },
  79.   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
  80.       offset(cursor), XtRImmediate, (XtPointer) None},
  81.   {XtNmenuOnScreen,  XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
  82.       offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
  83.   {XtNpopupOnEntry,  XtCPopupOnEntry, XtRWidget, sizeof(Widget),
  84.       offset(popup_entry), XtRWidget, NULL},
  85.   {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
  86.       offset(backing_store), 
  87.       XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
  88. };  
  89. #undef offset
  90.  
  91. static char defaultTranslations[] =
  92.     "<EnterWindow>:     highlight()             \n\
  93.      <LeaveWindow>:     unhighlight()           \n\
  94.      <BtnMotion>:       highlight()             \n\
  95.      <BtnUp>:           MenuPopdown() notify() unhighlight()"; 
  96.  
  97. /*
  98.  * Semi Public function definitions. 
  99.  */
  100.  
  101. static void Redisplay(), Realize(), Resize(), ChangeManaged();
  102. static void Initialize(), ClassInitialize(), ClassPartInitialize();
  103. static Boolean SetValues(), SetValuesHook();
  104. static XtGeometryResult GeometryManager();
  105.  
  106. /*
  107.  * Action Routine Definitions
  108.  */
  109.  
  110. static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
  111.  
  112. /* 
  113.  * Private Function Definitions.
  114.  */
  115.  
  116. static void MakeSetValuesRequest(), CreateLabel(), Layout();
  117. static void AddPositionAction(), PositionMenu(), ChangeCursorOnGrab();
  118. static Dimension GetMenuWidth(), GetMenuHeight();
  119. static Widget FindMenu();
  120. static SmeObject GetEventEntry();
  121. static void MoveMenu();
  122.  
  123. static XtActionsRec actionsList[] =
  124. {
  125.   {"notify",            Notify},
  126.   {"highlight",         Highlight},
  127.   {"unhighlight",       Unhighlight},
  128. };
  129.  
  130. static CompositeClassExtensionRec extension_rec = {
  131.     /* next_extension */  NULL,
  132.     /* record_type */     NULLQUARK,
  133.     /* version */         XtCompositeExtensionVersion,
  134.     /* record_size */     sizeof(CompositeClassExtensionRec),
  135.     /* accepts_objects */ TRUE,
  136. };
  137.  
  138. #define superclass (&overrideShellClassRec)
  139.     
  140. SimpleMenuClassRec simpleMenuClassRec = {
  141.   {
  142.     /* superclass         */    (WidgetClass) superclass,
  143.     /* class_name         */    "SimpleMenu",
  144.     /* size               */    sizeof(SimpleMenuRec),
  145.     /* class_initialize   */    ClassInitialize,
  146.     /* class_part_initialize*/    ClassPartInitialize,
  147.     /* Class init'ed      */    FALSE,
  148.     /* initialize         */    Initialize,
  149.     /* initialize_hook    */    NULL,
  150.     /* realize            */    Realize,
  151.     /* actions            */    actionsList,
  152.     /* num_actions        */    XtNumber(actionsList),
  153.     /* resources          */    resources,
  154.     /* resource_count     */    XtNumber(resources),
  155.     /* xrm_class          */    NULLQUARK,
  156.     /* compress_motion    */    TRUE, 
  157.     /* compress_exposure  */    TRUE,
  158.     /* compress_enterleave*/     TRUE,
  159.     /* visible_interest   */    FALSE,
  160.     /* destroy            */    NULL,
  161.     /* resize             */    Resize,
  162.     /* expose             */    Redisplay,
  163.     /* set_values         */    SetValues,
  164.     /* set_values_hook    */    SetValuesHook,
  165.     /* set_values_almost  */    XtInheritSetValuesAlmost,  
  166.     /* get_values_hook    */    NULL,            
  167.     /* accept_focus       */    NULL,
  168.     /* intrinsics version */    XtVersion,
  169.     /* callback offsets   */    NULL,
  170.     /* tm_table          */    defaultTranslations,
  171.     /* query_geometry      */    NULL,
  172.     /* display_accelerator*/    NULL,
  173.     /* extension      */    NULL
  174.   },{
  175.     /* geometry_manager   */    GeometryManager,
  176.     /* change_managed     */    ChangeManaged,
  177.     /* insert_child      */    XtInheritInsertChild,
  178.     /* delete_child      */    XtInheritDeleteChild,
  179.     /* extension      */    NULL
  180.   },{
  181.     /* Shell extension      */    NULL
  182.   },{
  183.     /* Override extension */    NULL
  184.   },{
  185.     /* Simple Menu extension*/  NULL
  186.   }
  187. };
  188.  
  189. WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
  190.  
  191. /************************************************************
  192.  *
  193.  * Semi-Public Functions.
  194.  *
  195.  ************************************************************/
  196.  
  197. /*      Function Name: ClassInitialize
  198.  *      Description: Class Initialize routine, called only once.
  199.  *      Arguments: none.
  200.  *      Returns: none.
  201.  */
  202.  
  203. static void
  204. ClassInitialize()
  205. {
  206.   XawInitializeWidgetSet();
  207.   XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
  208.          NULL, 0 );
  209.   XmuAddInitializer( AddPositionAction, NULL);
  210. }
  211.  
  212. /*      Function Name: ClassInitialize
  213.  *      Description: Class Part Initialize routine, called for every
  214.  *                   subclass.  Makes sure that the subclasses pick up 
  215.  *                   the extension record.
  216.  *      Arguments: wc - the widget class of the subclass.
  217.  *      Returns: none.
  218.  */
  219.  
  220. static void
  221. ClassPartInitialize(wc)
  222. WidgetClass wc;
  223. {
  224.     SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
  225.  
  226. /*
  227.  * Make sure that our subclass gets the extension rec too.
  228.  */
  229.  
  230.     extension_rec.next_extension = smwc->composite_class.extension;
  231.     smwc->composite_class.extension = (XtPointer) &extension_rec;
  232. }
  233.  
  234. /*      Function Name: Initialize
  235.  *      Description: Initializes the simple menu widget
  236.  *      Arguments: request - the widget requested by the argument list.
  237.  *                 new     - the new widget with both resource and non
  238.  *                           resource values.
  239.  *      Returns: none.
  240.  */
  241.  
  242. /* ARGSUSED */
  243. static void
  244. Initialize(request, new)
  245. Widget request, new;
  246. {
  247.   SimpleMenuWidget smw = (SimpleMenuWidget) new;
  248.  
  249.   XmuCallInitializers(XtWidgetToApplicationContext(new));
  250.  
  251.   if (smw->simple_menu.label_class == NULL) 
  252.       smw->simple_menu.label_class = smeBSBObjectClass;
  253.  
  254.   smw->simple_menu.label = NULL;
  255.   smw->simple_menu.entry_set = NULL;
  256.   smw->simple_menu.recursive_set_values = FALSE;
  257.  
  258.   if (smw->simple_menu.label_string != NULL)
  259.       CreateLabel(new);
  260.  
  261.   smw->simple_menu.menu_width = TRUE;
  262.  
  263.   if (smw->core.width == 0) {
  264.       smw->simple_menu.menu_width = FALSE;
  265.       smw->core.width = GetMenuWidth(new, NULL);
  266.   }
  267.  
  268.   smw->simple_menu.menu_height = TRUE;
  269.  
  270.   if (smw->core.height == 0) {
  271.       smw->simple_menu.menu_height = FALSE;
  272.       smw->core.height = GetMenuHeight(new);
  273.   }
  274.  
  275. /*
  276.  * Add a popup_callback routine for changing the cursor.
  277.  */
  278.   
  279.   XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
  280. }
  281.  
  282. /*      Function Name: Redisplay
  283.  *      Description: Redisplays the contents of the widget.
  284.  *      Arguments: w - the simple menu widget.
  285.  *                 event - the X event that caused this redisplay.
  286.  *                 region - the region the needs to be repainted. 
  287.  *      Returns: none.
  288.  */
  289.  
  290. /* ARGSUSED */
  291. static void
  292. Redisplay(w, event, region)
  293. Widget w;
  294. XEvent * event;
  295. Region region;
  296. {
  297.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  298.     SmeObject * entry;
  299.     SmeObjectClass class;
  300.  
  301.     if (region == NULL)
  302.     XClearWindow(XtDisplay(w), XtWindow(w));
  303.  
  304.     /*
  305.      * Check and Paint each of the entries - including the label.
  306.      */
  307.  
  308.     ForAllChildren(smw, entry) {
  309.     if (!XtIsManaged ( (Widget) *entry)) continue;
  310.  
  311.     if (region != NULL) 
  312.         switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
  313.                  (int) (*entry)->rectangle.y,
  314.                  (unsigned int) (*entry)->rectangle.width,
  315.                  (unsigned int) (*entry)->rectangle.height)) {
  316.         case RectangleIn:
  317.         case RectanglePart:
  318.         break;
  319.         default:
  320.         continue;
  321.         }
  322.     class = (SmeObjectClass) (*entry)->object.widget_class;
  323.  
  324.     if (class->rect_class.expose != NULL)
  325.         (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
  326.     }
  327. }
  328.  
  329. /*      Function Name: Realize
  330.  *      Description: Realizes the widget.
  331.  *      Arguments: w - the simple menu widget.
  332.  *                 mask - value mask for the window to create.
  333.  *                 attrs - attributes for the window to create.
  334.  *      Returns: none
  335.  */
  336.  
  337. static void
  338. Realize(w, mask, attrs)
  339. Widget w;
  340. XtValueMask * mask;
  341. XSetWindowAttributes * attrs;
  342. {
  343.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  344.  
  345.     attrs->cursor = smw->simple_menu.cursor;
  346.     *mask |= CWCursor;
  347.     if ((smw->simple_menu.backing_store == Always) ||
  348.     (smw->simple_menu.backing_store == NotUseful) ||
  349.     (smw->simple_menu.backing_store == WhenMapped) ) {
  350.     *mask |= CWBackingStore;
  351.     attrs->backing_store = smw->simple_menu.backing_store;
  352.     }
  353.     else
  354.     *mask &= ~CWBackingStore;
  355.  
  356.     (*superclass->core_class.realize) (w, mask, attrs);
  357. }
  358.  
  359. /*      Function Name: Resize
  360.  *      Description: Handle the menu being resized bigger.
  361.  *      Arguments: w - the simple menu widget.
  362.  *      Returns: none.
  363.  */
  364.  
  365. static void
  366. Resize(w)
  367. Widget w;
  368. {
  369.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  370.     SmeObject * entry;
  371.  
  372.     if ( !XtIsRealized(w) ) return;
  373.  
  374.     ForAllChildren(smw, entry)     /* reset width of all entries. */
  375.     if (XtIsManaged( (Widget) *entry))
  376.         (*entry)->rectangle.width = smw->core.width;
  377.     
  378.     Redisplay(w, (XEvent *) NULL, (Region) NULL);
  379. }
  380.  
  381. /*      Function Name: SetValues
  382.  *      Description: Relayout the menu when one of the resources is changed.
  383.  *      Arguments: current - current state of the widget.
  384.  *                 request - what was requested.
  385.  *                 new - what the widget will become.
  386.  *      Returns: none
  387.  */
  388.  
  389. /* ARGSUSED */
  390. static Boolean
  391. SetValues(current, request, new)
  392. Widget current, request, new;
  393. {
  394.     SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
  395.     SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
  396.     Boolean ret_val = FALSE, layout = FALSE;
  397.     
  398.     if (!XtIsRealized(current)) return(FALSE);
  399.     
  400.     if (!smw_new->simple_menu.recursive_set_values) {
  401.     if (smw_new->core.width != smw_old->core.width) {
  402.         smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
  403.         layout = TRUE;
  404.     }
  405.     if (smw_new->core.height != smw_old->core.height) {
  406.         smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
  407.         layout = TRUE;
  408.     }
  409.     }
  410.  
  411.     if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
  412.     XDefineCursor(XtDisplay(new),
  413.               XtWindow(new), smw_new->simple_menu.cursor);
  414.     
  415.     if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) 
  416.     if (smw_new->simple_menu.label_string == NULL)         /* Destroy. */
  417.         XtDestroyWidget((Widget) smw_old->simple_menu.label);
  418.     else if (smw_old->simple_menu.label_string == NULL)    /* Create. */
  419.         CreateLabel(new);
  420.     else {                                                 /* Change. */
  421.         Arg args[1];
  422.         
  423.         XtSetArg(args[0], XtNlabel, smw_new->simple_menu.label_string);
  424.         XtSetValues((Widget) smw_new->simple_menu.label, args, ONE);
  425.     }
  426.     
  427.     if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
  428.     XtAppWarning(XtWidgetToApplicationContext(new),
  429.              "No Dynamic class change of the SimpleMenu Label.");
  430.     
  431.     if ((smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin) ||
  432.     (smw_old->simple_menu.bottom_margin != 
  433.      smw_new->simple_menu.bottom_margin) /* filler.................  */ ) {
  434.     layout = TRUE;
  435.     ret_val = TRUE;
  436.     }
  437.  
  438.     if (layout)
  439.     Layout(new, NULL, NULL);
  440.  
  441.     return(ret_val);
  442. }
  443.  
  444. /*      Function Name: SetValuesHook
  445.  *      Description: To handle a special case, this is passed the
  446.  *                   actual arguments.
  447.  *      Arguments: w - the menu widget.
  448.  *                 arglist - the argument list passed to XtSetValues.
  449.  *                 num_args - the number of args.
  450.  *      Returns: none
  451.  */
  452.  
  453. /* 
  454.  * If the user actually passed a width and height to the widget
  455.  * then this MUST be used, rather than our newly calculated width and
  456.  * height.
  457.  */
  458.  
  459. static Boolean
  460. SetValuesHook(w, arglist, num_args)
  461. Widget w;
  462. ArgList arglist;
  463. Cardinal *num_args;
  464. {
  465.     register Cardinal i;
  466.     Dimension width, height;
  467.     
  468.     width = w->core.width;
  469.     height = w->core.height;
  470.     
  471.     for ( i = 0 ; i < *num_args ; i++) {
  472.     if ( streq(arglist[i].name, XtNwidth) )
  473.         width = (Dimension) arglist[i].value;
  474.     if ( streq(arglist[i].name, XtNheight) )
  475.         height = (Dimension) arglist[i].value;
  476.     }
  477.  
  478.     if ((width != w->core.width) || (height != w->core.height))
  479.     MakeSetValuesRequest(w, width, height);
  480.     return(FALSE);
  481. }
  482.  
  483. /************************************************************
  484.  *
  485.  * Geometry Management routines.
  486.  *
  487.  ************************************************************/
  488.  
  489. /*    Function Name: GeometryManager
  490.  *    Description: This is the SimpleMenu Widget's Geometry Manager.
  491.  *    Arguments: w - the Menu Entry making the request.
  492.  *                 request - requested new geometry.
  493.  *                 reply - the allowed geometry.
  494.  *    Returns: XtGeometry{Yes, No, Almost}.
  495.  */
  496.  
  497. static XtGeometryResult
  498. GeometryManager(w, request, reply)
  499. Widget w;
  500. XtWidgetGeometry * request, * reply;
  501. {
  502.     SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
  503.     SmeObject entry = (SmeObject) w;
  504.     XtGeometryMask mode = request->request_mode;
  505.     XtGeometryResult answer;
  506.     Dimension old_height, old_width;
  507.  
  508.     if ( !(mode & CWWidth) && !(mode & CWHeight) )
  509.     return(XtGeometryNo);
  510.  
  511.     reply->width = request->width;
  512.     reply->height = request->height;
  513.  
  514.     old_width = entry->rectangle.width;
  515.     old_height = entry->rectangle.height;
  516.  
  517.     Layout(w, &(reply->width), &(reply->height) );
  518.  
  519. /*
  520.  * Since we are an override shell and have no parent there is no one to
  521.  * ask to see if this geom change is okay, so I am just going to assume
  522.  * we can do whatever we want.  If you subclass be very careful with this
  523.  * assumption, it could bite you.
  524.  *
  525.  * Chris D. Peterson - Sept. 1989.
  526.  */
  527.  
  528.     if ( (reply->width == request->width) &&
  529.      (reply->height == request->height) ) {
  530.  
  531.     if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
  532.         entry->rectangle.width = old_width;
  533.         entry->rectangle.height = old_height;    
  534.     }
  535.     else {
  536.         Layout(( Widget) smw, NULL, NULL);
  537.     }
  538.     answer = XtGeometryDone;
  539.     }
  540.     else {
  541.     entry->rectangle.width = old_width;
  542.     entry->rectangle.height = old_height;    
  543.  
  544.     if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
  545.           ((reply->height == request->height) && !(mode & CWWidth)) ||
  546.           ((reply->width == request->width) && 
  547.            (reply->height == request->height)) )
  548.         answer = XtGeometryNo;
  549.     else {
  550.         answer = XtGeometryAlmost;
  551.         reply->request_mode = 0;
  552.         if (reply->width != request->width)
  553.         reply->request_mode |= CWWidth;
  554.         if (reply->height != request->height)
  555.         reply->request_mode |= CWHeight;
  556.     }
  557.     }
  558.     return(answer);
  559. }
  560.  
  561. /*    Function Name: ChangeManaged
  562.  *    Description: called whenever a new child is managed.
  563.  *    Arguments: w - the simple menu widget.
  564.  *    Returns: none.
  565.  */
  566.  
  567. static void
  568. ChangeManaged(w)
  569. Widget w;
  570. {
  571.     Layout(w, NULL, NULL);
  572. }
  573.  
  574. /************************************************************
  575.  *
  576.  * Global Action Routines.
  577.  * 
  578.  * These actions routines will be added to the application's
  579.  * global action list. 
  580.  * 
  581.  ************************************************************/
  582.  
  583. /*      Function Name: PositionMenuAction
  584.  *      Description: Positions the simple menu widget.
  585.  *      Arguments: w - a widget (no the simple menu widget.)
  586.  *                 event - the event that caused this action.
  587.  *                 params, num_params - parameters passed to the routine.
  588.  *                                      we expect the name of the menu here.
  589.  *      Returns: none
  590.  */
  591.  
  592. /* ARGSUSED */
  593. static void
  594. PositionMenuAction(w, event, params, num_params)
  595. Widget w;
  596. XEvent * event;
  597. String * params;
  598. Cardinal * num_params;
  599.   Widget menu;
  600.   XPoint loc;
  601.  
  602.   if (*num_params != 1) {
  603.     char error_buf[BUFSIZ];
  604.     sprintf(error_buf, "%s %s",
  605.         "Xaw - SimpleMenuWidget: position menu action expects only one",
  606.         "parameter which is the name of the menu.");
  607.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  608.     return;
  609.   }
  610.  
  611.   if ( (menu = FindMenu(w, params[0])) == NULL) {
  612.     char error_buf[BUFSIZ];
  613.     sprintf(error_buf, "%s '%s'",
  614.         "Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
  615.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  616.     return;
  617.   }
  618.   
  619.   switch (event->type) {
  620.   case ButtonPress:
  621.   case ButtonRelease:
  622.     loc.x = event->xbutton.x_root;
  623.     loc.y = event->xbutton.y_root;
  624.     PositionMenu(menu, &loc);
  625.     break;
  626.   case EnterNotify:
  627.   case LeaveNotify:
  628.     loc.x = event->xcrossing.x_root;
  629.     loc.y = event->xcrossing.y_root;
  630.     PositionMenu(menu, &loc);
  631.     break;
  632.   case MotionNotify:
  633.     loc.x = event->xmotion.x_root;
  634.     loc.y = event->xmotion.y_root;
  635.     PositionMenu(menu, &loc);
  636.     break;
  637.   default:
  638.     PositionMenu(menu, NULL);
  639.     break;
  640.   }
  641. }  
  642.  
  643. /************************************************************
  644.  *
  645.  * Widget Action Routines.
  646.  * 
  647.  ************************************************************/
  648.  
  649. /*      Function Name: Unhighlight
  650.  *      Description: Unhighlights current entry.
  651.  *      Arguments: w - the simple menu widget.
  652.  *                 event - the event that caused this action.
  653.  *                 params, num_params - ** NOT USED **
  654.  *      Returns: none
  655.  */
  656.  
  657. /* ARGSUSED */
  658. static void
  659. Unhighlight(w, event, params, num_params)
  660. Widget w;
  661. XEvent * event;
  662. String * params;
  663. Cardinal * num_params;
  664.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  665.     SmeObject entry = smw->simple_menu.entry_set;
  666.     SmeObjectClass class;
  667.  
  668.     if ( entry == NULL) return;
  669.  
  670.     smw->simple_menu.entry_set = NULL;
  671.     class = (SmeObjectClass) entry->object.widget_class;
  672.     (class->sme_class.unhighlight) ( (Widget) entry);
  673. }
  674.  
  675. /*      Function Name: Highlight
  676.  *      Description: Highlights current entry.
  677.  *      Arguments: w - the simple menu widget.
  678.  *                 event - the event that caused this action.
  679.  *                 params, num_params - ** NOT USED **
  680.  *      Returns: none
  681.  */
  682.  
  683. /* ARGSUSED */
  684. static void
  685. Highlight(w, event, params, num_params)
  686. Widget w;
  687. XEvent * event;
  688. String * params;
  689. Cardinal * num_params;
  690. {
  691.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  692.     SmeObject entry;
  693.     SmeObjectClass class;
  694.     
  695.     if ( !XtIsSensitive(w) ) return;
  696.     
  697.     entry = GetEventEntry(w, event);
  698.  
  699.     if (entry == smw->simple_menu.entry_set) return;
  700.  
  701.     Unhighlight(w, event, params, num_params);  
  702.  
  703.     if (entry == NULL) return;
  704.  
  705.     if ( !XtIsSensitive( (Widget) entry)) {
  706.     smw->simple_menu.entry_set = NULL;
  707.     return;
  708.     }
  709.  
  710.     smw->simple_menu.entry_set = entry;
  711.     class = (SmeObjectClass) entry->object.widget_class;
  712.  
  713.     (class->sme_class.highlight) ( (Widget) entry);
  714. }
  715.  
  716. /*      Function Name: Notify
  717.  *      Description: Notify user of current entry.
  718.  *      Arguments: w - the simple menu widget.
  719.  *                 event - the event that caused this action.
  720.  *                 params, num_params - ** NOT USED **
  721.  *      Returns: none
  722.  */
  723.  
  724. /* ARGSUSED */
  725. static void
  726. Notify(w, event, params, num_params)
  727. Widget w;
  728. XEvent * event;
  729. String * params;
  730. Cardinal * num_params;
  731. {
  732.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  733.     SmeObject entry = smw->simple_menu.entry_set;
  734.     SmeObjectClass class;
  735.     
  736.     if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
  737.  
  738.     class = (SmeObjectClass) entry->object.widget_class;
  739.     (class->sme_class.notify)( (Widget) entry );
  740. }
  741.  
  742. /************************************************************
  743.  *
  744.  * Public Functions.
  745.  *
  746.  ************************************************************/
  747.  
  748. /*    Function Name: XawSimpleMenuAddGlobalActions
  749.  *    Description: adds the global actions to the simple menu widget.
  750.  *    Arguments: app_con - the appcontext.
  751.  *    Returns: none.
  752.  */
  753.  
  754. void
  755. #if NeedFunctionPrototypes
  756. XawSimpleMenuAddGlobalActions(XtAppContext app_con)
  757. #else
  758. XawSimpleMenuAddGlobalActions(app_con)
  759. XtAppContext app_con;
  760. #endif
  761. {
  762.     XtInitializeWidgetClass(simpleMenuWidgetClass);
  763.     XmuCallInitializers( app_con );
  764.  
  765.  
  766. /*    Function Name: XawSimpleMenuGetActiveEntry
  767.  *    Description: Gets the currently active (set) entry.
  768.  *    Arguments: w - the smw widget.
  769.  *    Returns: the currently set entry or NULL if none is set.
  770.  */
  771.  
  772. Widget
  773. #if NeedFunctionPrototypes
  774. XawSimpleMenuGetActiveEntry(Widget w)
  775. #else
  776. XawSimpleMenuGetActiveEntry(w)
  777. Widget w;
  778. #endif
  779. {
  780.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  781.  
  782.     return( (Widget) smw->simple_menu.entry_set);
  783.  
  784. /*    Function Name: XawSimpleMenuClearActiveEntry
  785.  *    Description: Unsets the currently active (set) entry.
  786.  *    Arguments: w - the smw widget.
  787.  *    Returns: none.
  788.  */
  789.  
  790. void
  791. #if NeedFunctionPrototypes
  792. XawSimpleMenuClearActiveEntry(Widget w)
  793. #else
  794. XawSimpleMenuClearActiveEntry(w)
  795. Widget w;
  796. #endif
  797. {
  798.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  799.  
  800.     smw->simple_menu.entry_set = NULL;
  801.  
  802. /************************************************************
  803.  *
  804.  * Private Functions.
  805.  *
  806.  ************************************************************/
  807.  
  808. /*    Function Name: CreateLabel
  809.  *    Description: Creates a the menu label.
  810.  *    Arguments: w - the smw widget.
  811.  *    Returns: none.
  812.  * 
  813.  * Creates the label object and makes sure it is the first child in
  814.  * in the list.
  815.  */
  816.  
  817. static void
  818. CreateLabel(w)
  819. Widget w;
  820. {
  821.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  822.     register Widget * child, * next_child;
  823.     register int i;
  824.     Arg args[2];
  825.  
  826.     if ( (smw->simple_menu.label_string == NULL) ||
  827.      (smw->simple_menu.label != NULL) ) {
  828.     char error_buf[BUFSIZ];
  829.  
  830.     sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
  831.         "label string is NULL", "label already exists", 
  832.         "no label is being created.");
  833.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  834.     return;
  835.     }
  836.  
  837.     XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
  838.     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
  839.     smw->simple_menu.label = (SmeObject) 
  840.                           XtCreateManagedWidget("menuLabel", 
  841.                         smw->simple_menu.label_class, w,
  842.                         args, TWO);
  843.  
  844.     next_child = NULL;
  845.     for (child = smw->composite.children + smw->composite.num_children,
  846.      i = smw->composite.num_children ; i > 0 ; i--, child--) {
  847.     if (next_child != NULL)
  848.         *next_child = *child;
  849.     next_child = child;
  850.     }
  851.     *child = (Widget) smw->simple_menu.label;
  852. }
  853.  
  854. /*    Function Name: Layout
  855.  *    Description: lays the menu entries out all nice and neat.
  856.  *    Arguments: w - See below (+++)
  857.  *                 width_ret, height_ret - The returned width and 
  858.  *                                         height values.
  859.  *    Returns: none.
  860.  *
  861.  * if width == NULL || height == NULL then it assumes the you do not care
  862.  * about the return values, and just want a relayout.
  863.  *
  864.  * if this is not the case then it will set width_ret and height_ret
  865.  * to be width and height that the child would get if it were layed out
  866.  * at this time.
  867.  *
  868.  * +++ "w" can be the simple menu widget or any of its object children.
  869.  */
  870.  
  871. static void
  872. Layout(w, width_ret, height_ret)
  873. Widget w;
  874. Dimension *width_ret, *height_ret;
  875. {
  876.     SmeObject current_entry, *entry;
  877.     SimpleMenuWidget smw;
  878.     Dimension width, height;
  879.     Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
  880.     Boolean allow_change_size;
  881.     height = 0;
  882.  
  883.     if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
  884.     smw = (SimpleMenuWidget) w;
  885.     current_entry = NULL;
  886.     }
  887.     else {
  888.     smw = (SimpleMenuWidget) XtParent(w);
  889.     current_entry = (SmeObject) w;
  890.     }
  891.  
  892.     allow_change_size = (!XtIsRealized((Widget)smw) ||
  893.              (smw->shell.allow_shell_resize));
  894.  
  895.     if ( smw->simple_menu.menu_height )
  896.     height = smw->core.height;
  897.     else
  898.     if (do_layout) {
  899.         height = smw->simple_menu.top_margin;
  900.         ForAllChildren(smw, entry) {
  901.         if (!XtIsManaged( (Widget) *entry)) continue;
  902.  
  903.         if ( (smw->simple_menu.row_height != 0) && 
  904.             (*entry != smw->simple_menu.label) ) 
  905.             (*entry)->rectangle.height = smw->simple_menu.row_height;
  906.         
  907.         (*entry)->rectangle.y = height;
  908.         (*entry)->rectangle.x = 0;
  909.         height += (*entry)->rectangle.height;
  910.         }
  911.         height += smw->simple_menu.bottom_margin;
  912.     }
  913.     else {
  914.         if ((smw->simple_menu.row_height != 0) && 
  915.         (current_entry != smw->simple_menu.label) )
  916.         height = smw->simple_menu.row_height;
  917.     }
  918.     
  919.     if (smw->simple_menu.menu_width)
  920.     width = smw->core.width;
  921.     else if ( allow_change_size )
  922.     width = GetMenuWidth((Widget) smw, (Widget) current_entry);
  923.     else
  924.     width = smw->core.width;
  925.  
  926.     if (do_layout) {
  927.     ForAllChildren(smw, entry)
  928.         if (XtIsManaged( (Widget) *entry)) 
  929.         (*entry)->rectangle.width = width;
  930.  
  931.     if (allow_change_size)
  932.         MakeSetValuesRequest((Widget) smw, width, height);
  933.     }
  934.     else {
  935.     *width_ret = width;
  936.     if (height != 0)
  937.         *height_ret = height;
  938.     }
  939. }
  940.     
  941. /*    Function Name: AddPositionAction
  942.  *    Description: Adds the XawPositionSimpleMenu action to the global
  943.  *                   action list for this appcon.
  944.  *    Arguments: app_con - the application context for this app.
  945.  *                 data - NOT USED.
  946.  *    Returns: none.
  947.  */
  948.  
  949. /* ARGSUSED */
  950. static void
  951. AddPositionAction(app_con, data)
  952. XtAppContext app_con;
  953. caddr_t data;
  954. {
  955.     static XtActionsRec pos_action[] = {
  956.         { "XawPositionSimpleMenu", PositionMenuAction },
  957.     };
  958.  
  959.     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
  960. }
  961.  
  962. /*    Function Name: FindMenu
  963.  *    Description: Find the menu give a name and reference widget.
  964.  *    Arguments: widget - reference widget.
  965.  *                 name   - the menu widget's name.
  966.  *    Returns: the menu widget or NULL.
  967.  */
  968.  
  969. static Widget 
  970. FindMenu(widget, name)
  971. Widget widget;
  972. String name;
  973. {
  974.     register Widget w, menu;
  975.     
  976.     for ( w = widget ; w != NULL ; w = XtParent(w) )
  977.     if ( (menu = XtNameToWidget(w, name)) != NULL )
  978.         return(menu);
  979.     return(NULL);
  980. }
  981.  
  982. /*    Function Name: PositionMenu
  983.  *    Description: Places the menu
  984.  *    Arguments: w - the simple menu widget.
  985.  *                 location - a pointer the the position or NULL.
  986.  *    Returns: none.
  987.  */
  988.  
  989. static void
  990. PositionMenu(w, location)
  991. Widget w;
  992. XPoint * location;
  993. {
  994.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  995.     SmeObject entry;
  996.     XPoint t_point;
  997.     
  998.     if (location == NULL) {
  999.     Window junk1, junk2;
  1000.     int root_x, root_y, junkX, junkY;
  1001.     unsigned int junkM;
  1002.     
  1003.     location = &t_point;
  1004.     if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2, 
  1005.               &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
  1006.         char error_buf[BUFSIZ];
  1007.         sprintf(error_buf, "%s %s", "Xaw - SimpleMenuWidget:",
  1008.             "Could not find location of mouse pointer");
  1009.         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  1010.         return;
  1011.     }
  1012.     location->x = (short) root_x;
  1013.     location->y = (short) root_y;
  1014.     }
  1015.     
  1016.     /*
  1017.      * The width will not be correct unless it is realized.
  1018.      */
  1019.     
  1020.     XtRealizeWidget(w);
  1021.     
  1022.     location->x -= (Position) w->core.width/2;
  1023.     
  1024.     if (smw->simple_menu.popup_entry == NULL)
  1025.     entry = smw->simple_menu.label;
  1026.     else
  1027.     entry = smw->simple_menu.popup_entry;
  1028.  
  1029.     if (entry != NULL)
  1030.     location->y -= entry->rectangle.y + entry->rectangle.height/2;
  1031.  
  1032.     MoveMenu(w, (Position) location->x, (Position) location->y);
  1033. }
  1034.  
  1035. /*    Function Name: MoveMenu
  1036.  *    Description: Actually moves the menu, may force it to
  1037.  *                   to be fully visable if menu_on_screen is TRUE.
  1038.  *    Arguments: w - the simple menu widget.
  1039.  *                 x, y - the current location of the widget.
  1040.  *    Returns: none 
  1041.  */
  1042.  
  1043. static void
  1044. MoveMenu(w, x, y)
  1045. Widget w;
  1046. Position x, y;
  1047. {
  1048.     Arg arglist[2];
  1049.     Cardinal num_args = 0;
  1050.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1051.     
  1052.     if (smw->simple_menu.menu_on_screen) {
  1053.     int width = w->core.width + 2 * w->core.border_width;
  1054.     int height = w->core.height + 2 * w->core.border_width;
  1055.     
  1056.     if (x >= 0) {
  1057.         int scr_width = WidthOfScreen(XtScreen(w));
  1058.         if (x + width > scr_width)
  1059.         x = scr_width - width;
  1060.     }
  1061.     if (x < 0) 
  1062.         x = 0;
  1063.     
  1064.     if (y >= 0) {
  1065.         int scr_height = HeightOfScreen(XtScreen(w));
  1066.         if (y + height > scr_height)
  1067.         y = scr_height - height;
  1068.     }
  1069.     if (y < 0)
  1070.         y = 0;
  1071.     }
  1072.     
  1073.     XtSetArg(arglist[num_args], XtNx, x); num_args++;
  1074.     XtSetArg(arglist[num_args], XtNy, y); num_args++;
  1075.     XtSetValues(w, arglist, num_args);
  1076. }
  1077.  
  1078. /*    Function Name: ChangeCursorOnGrab
  1079.  *    Description: Changes the cursor on the active grab to the one
  1080.  *                   specified in out resource list.
  1081.  *    Arguments: w - the widget.
  1082.  *                 junk, garbage - ** NOT USED **.
  1083.  *    Returns: None.
  1084.  */
  1085.  
  1086. /* ARGSUSED */
  1087. static void
  1088. ChangeCursorOnGrab(w, junk, garbage)
  1089. Widget w;
  1090. XtPointer junk, garbage;
  1091. {
  1092.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1093.     
  1094.     /*
  1095.      * The event mask here is what is currently in the MIT implementation.
  1096.      * There really needs to be a way to get the value of the mask out
  1097.      * of the toolkit (CDP 5/26/89).
  1098.      */
  1099.     
  1100.     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
  1101.                  smw->simple_menu.cursor, 
  1102.                  XtLastTimestampProcessed(XtDisplay(w)));
  1103. }
  1104.  
  1105. /*      Function Name: MakeSetValuesRequest
  1106.  *      Description: Makes a (possibly recursive) call to SetValues,
  1107.  *                   I take great pains to not go into an infinite loop.
  1108.  *      Arguments: w - the simple menu widget.
  1109.  *                 width, height - the size of the ask for.
  1110.  *      Returns: none
  1111.  */
  1112.  
  1113. static void
  1114. MakeSetValuesRequest(w, width, height)
  1115. Widget w;
  1116. Dimension width, height;
  1117. {
  1118.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1119.     Arg arglist[2];
  1120.     Cardinal num_args = (Cardinal) 0;
  1121.     
  1122.     if ( !smw->simple_menu.recursive_set_values ) {
  1123.     if ( (smw->core.width != width) || (smw->core.height != height) ) {
  1124.         smw->simple_menu.recursive_set_values = TRUE;
  1125.         XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
  1126.         XtSetArg(arglist[num_args], XtNheight, height); num_args++;
  1127.         XtSetValues(w, arglist, num_args);
  1128.     }
  1129.     else if (XtIsRealized( (Widget) smw))
  1130.         Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
  1131.     }
  1132.     smw->simple_menu.recursive_set_values = FALSE;
  1133. }
  1134.  
  1135. /*      Function Name: GetMenuWidth
  1136.  *      Description: Sets the length of the widest entry in pixels.
  1137.  *      Arguments: w - the simple menu widget.
  1138.  *      Returns: width of menu.
  1139.  */
  1140.  
  1141. static Dimension
  1142. GetMenuWidth(w, w_ent)
  1143. Widget w, w_ent;
  1144. {
  1145.     SmeObject cur_entry = (SmeObject) w_ent;
  1146.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1147.     Dimension width, widest = (Dimension) 0;
  1148.     SmeObject * entry;
  1149.     
  1150.     if ( smw->simple_menu.menu_width ) 
  1151.     return(smw->core.width);
  1152.  
  1153.     ForAllChildren(smw, entry) {
  1154.     XtWidgetGeometry preferred;
  1155.  
  1156.     if (!XtIsManaged( (Widget) *entry)) continue;
  1157.     
  1158.     if (*entry != cur_entry) {
  1159.         XtQueryGeometry((Widget) *entry, NULL, &preferred);
  1160.         
  1161.         if (preferred.request_mode & CWWidth)
  1162.         width = preferred.width;
  1163.         else
  1164.         width = (*entry)->rectangle.width;
  1165.     }
  1166.     else
  1167.         width = (*entry)->rectangle.width;
  1168.     
  1169.     if ( width > widest )
  1170.         widest = width;
  1171.     }
  1172.     
  1173.     return(widest);
  1174. }
  1175.  
  1176. /*      Function Name: GetMenuHeight
  1177.  *      Description: Sets the length of the widest entry in pixels.
  1178.  *      Arguments: w - the simple menu widget.
  1179.  *      Returns: width of menu.
  1180.  */
  1181.  
  1182. static Dimension
  1183. GetMenuHeight(w)
  1184. Widget w;
  1185. {
  1186.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1187.     SmeObject * entry;
  1188.     Dimension height;
  1189.     
  1190.     if (smw->simple_menu.menu_height)
  1191.     return(smw->core.height);
  1192.  
  1193.     height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
  1194.     
  1195.     if (smw->simple_menu.row_height == 0) 
  1196.     ForAllChildren(smw, entry) 
  1197.         if (XtIsManaged ((Widget) *entry)) 
  1198.         height += (*entry)->rectangle.height;
  1199.     else 
  1200.     height += smw->simple_menu.row_height * smw->composite.num_children;
  1201.     
  1202.     return(height);
  1203. }
  1204.  
  1205. /*      Function Name: GetEventEntry
  1206.  *      Description: Gets an entry given an event that has X and Y coords.
  1207.  *      Arguments: w - the simple menu widget.
  1208.  *                 event - the event.
  1209.  *      Returns: the entry that this point is in.
  1210.  */
  1211.  
  1212. static SmeObject
  1213. GetEventEntry(w, event)
  1214. Widget w;
  1215. XEvent * event;
  1216. {
  1217.     Position x_loc, y_loc;
  1218.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1219.     SmeObject * entry;
  1220.     
  1221.     switch (event->type) {
  1222.     case MotionNotify:
  1223.     x_loc = event->xmotion.x;
  1224.     y_loc = event->xmotion.y;
  1225.     break;
  1226.     case EnterNotify:
  1227.     case LeaveNotify:
  1228.     x_loc = event->xcrossing.x;
  1229.     y_loc = event->xcrossing.y;
  1230.     break;
  1231.     case ButtonPress:
  1232.     case ButtonRelease:
  1233.     x_loc = event->xbutton.x;
  1234.     y_loc = event->xbutton.y;
  1235.     break;
  1236.     default:
  1237.     XtAppError(XtWidgetToApplicationContext(w),
  1238.            "Unknown event type in GetEventEntry().");
  1239.     break;
  1240.     }
  1241.     
  1242.     if ( (x_loc < 0) || (x_loc >= (int)smw->core.width) || (y_loc < 0) ||
  1243.     (y_loc >= (int)smw->core.height) )
  1244.     return(NULL);
  1245.     
  1246.     ForAllChildren(smw, entry) {
  1247.     if (!XtIsManaged ((Widget) *entry)) continue;
  1248.  
  1249.     if ( ((*entry)->rectangle.y < y_loc) &&
  1250.         ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) )
  1251.         if ( *entry == smw->simple_menu.label )
  1252.         return(NULL);    /* cannot select the label. */
  1253.         else
  1254.         return(*entry);
  1255.     }
  1256.     
  1257.     return(NULL);
  1258. }
  1259.