home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / SimpleMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  34.4 KB  |  1,268 lines

  1. /* $XConsortium: SimpleMenu.c,v 1.41 92/09/10 16:25:07 converse 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, args, num_args)
  245. Widget request, new;
  246. ArgList args;
  247. Cardinal *num_args;
  248. {
  249.   SimpleMenuWidget smw = (SimpleMenuWidget) new;
  250.  
  251.   XmuCallInitializers(XtWidgetToApplicationContext(new));
  252.  
  253.   if (smw->simple_menu.label_class == NULL) 
  254.       smw->simple_menu.label_class = smeBSBObjectClass;
  255.  
  256.   smw->simple_menu.label = NULL;
  257.   smw->simple_menu.entry_set = NULL;
  258.   smw->simple_menu.recursive_set_values = FALSE;
  259.  
  260.   if (smw->simple_menu.label_string != NULL)
  261.       CreateLabel(new);
  262.  
  263.   smw->simple_menu.menu_width = TRUE;
  264.  
  265.   if (smw->core.width == 0) {
  266.       smw->simple_menu.menu_width = FALSE;
  267.       smw->core.width = GetMenuWidth(new, NULL);
  268.   }
  269.  
  270.   smw->simple_menu.menu_height = TRUE;
  271.  
  272.   if (smw->core.height == 0) {
  273.       smw->simple_menu.menu_height = FALSE;
  274.       smw->core.height = GetMenuHeight(new);
  275.   }
  276.  
  277. /*
  278.  * Add a popup_callback routine for changing the cursor.
  279.  */
  280.   
  281.   XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
  282. }
  283.  
  284. /*      Function Name: Redisplay
  285.  *      Description: Redisplays the contents of the widget.
  286.  *      Arguments: w - the simple menu widget.
  287.  *                 event - the X event that caused this redisplay.
  288.  *                 region - the region the needs to be repainted. 
  289.  *      Returns: none.
  290.  */
  291.  
  292. /* ARGSUSED */
  293. static void
  294. Redisplay(w, event, region)
  295. Widget w;
  296. XEvent * event;
  297. Region region;
  298. {
  299.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  300.     SmeObject * entry;
  301.     SmeObjectClass class;
  302.  
  303.     if (region == NULL)
  304.     XClearWindow(XtDisplay(w), XtWindow(w));
  305.  
  306.     /*
  307.      * Check and Paint each of the entries - including the label.
  308.      */
  309.  
  310.     ForAllChildren(smw, entry) {
  311.     if (!XtIsManaged ( (Widget) *entry)) continue;
  312.  
  313.     if (region != NULL) 
  314.         switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
  315.                  (int) (*entry)->rectangle.y,
  316.                  (unsigned int) (*entry)->rectangle.width,
  317.                  (unsigned int) (*entry)->rectangle.height)) {
  318.         case RectangleIn:
  319.         case RectanglePart:
  320.         break;
  321.         default:
  322.         continue;
  323.         }
  324.     class = (SmeObjectClass) (*entry)->object.widget_class;
  325.  
  326.     if (class->rect_class.expose != NULL)
  327.         (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
  328.     }
  329. }
  330.  
  331. /*      Function Name: Realize
  332.  *      Description: Realizes the widget.
  333.  *      Arguments: w - the simple menu widget.
  334.  *                 mask - value mask for the window to create.
  335.  *                 attrs - attributes for the window to create.
  336.  *      Returns: none
  337.  */
  338.  
  339. static void
  340. Realize(w, mask, attrs)
  341. Widget w;
  342. XtValueMask * mask;
  343. XSetWindowAttributes * attrs;
  344. {
  345.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  346.  
  347.     attrs->cursor = smw->simple_menu.cursor;
  348.     *mask |= CWCursor;
  349.     if ((smw->simple_menu.backing_store == Always) ||
  350.     (smw->simple_menu.backing_store == NotUseful) ||
  351.     (smw->simple_menu.backing_store == WhenMapped) ) {
  352.     *mask |= CWBackingStore;
  353.     attrs->backing_store = smw->simple_menu.backing_store;
  354.     }
  355.     else
  356.     *mask &= ~CWBackingStore;
  357.  
  358.     (*superclass->core_class.realize) (w, mask, attrs);
  359. }
  360.  
  361. /*      Function Name: Resize
  362.  *      Description: Handle the menu being resized bigger.
  363.  *      Arguments: w - the simple menu widget.
  364.  *      Returns: none.
  365.  */
  366.  
  367. static void
  368. Resize(w)
  369. Widget w;
  370. {
  371.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  372.     SmeObject * entry;
  373.  
  374.     if ( !XtIsRealized(w) ) return;
  375.  
  376.     ForAllChildren(smw, entry)     /* reset width of all entries. */
  377.     if (XtIsManaged( (Widget) *entry))
  378.         (*entry)->rectangle.width = smw->core.width;
  379.     
  380.     Redisplay(w, (XEvent *) NULL, (Region) NULL);
  381. }
  382.  
  383. /*      Function Name: SetValues
  384.  *      Description: Relayout the menu when one of the resources is changed.
  385.  *      Arguments: current - current state of the widget.
  386.  *                 request - what was requested.
  387.  *                 new - what the widget will become.
  388.  *      Returns: none
  389.  */
  390.  
  391. /* ARGSUSED */
  392. static Boolean
  393. SetValues(current, request, new, args, num_args)
  394. Widget current, request, new;
  395. ArgList args;
  396. Cardinal *num_args;
  397. {
  398.     SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
  399.     SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
  400.     Boolean ret_val = FALSE, layout = FALSE;
  401.     
  402.     if (!XtIsRealized(current)) return(FALSE);
  403.     
  404.     if (!smw_new->simple_menu.recursive_set_values) {
  405.     if (smw_new->core.width != smw_old->core.width) {
  406.         smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
  407.         layout = TRUE;
  408.     }
  409.     if (smw_new->core.height != smw_old->core.height) {
  410.         smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
  411.         layout = TRUE;
  412.     }
  413.     }
  414.  
  415.     if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
  416.     XDefineCursor(XtDisplay(new),
  417.               XtWindow(new), smw_new->simple_menu.cursor);
  418.     
  419.     if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) 
  420.     if (smw_new->simple_menu.label_string == NULL)         /* Destroy. */
  421.         XtDestroyWidget((Widget) smw_old->simple_menu.label);
  422.     else if (smw_old->simple_menu.label_string == NULL)    /* Create. */
  423.         CreateLabel(new);
  424.     else {                                                 /* Change. */
  425.         Arg arglist[1];
  426.         
  427.         XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
  428.         XtSetValues((Widget) smw_new->simple_menu.label, arglist, ONE);
  429.     }
  430.     
  431.     if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
  432.     XtAppWarning(XtWidgetToApplicationContext(new),
  433.              "No Dynamic class change of the SimpleMenu Label.");
  434.     
  435.     if ((smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin) ||
  436.     (smw_old->simple_menu.bottom_margin != 
  437.      smw_new->simple_menu.bottom_margin) /* filler.................  */ ) {
  438.     layout = TRUE;
  439.     ret_val = TRUE;
  440.     }
  441.  
  442.     if (layout)
  443.     Layout(new, NULL, NULL);
  444.  
  445.     return(ret_val);
  446. }
  447.  
  448. /*      Function Name: SetValuesHook
  449.  *      Description: To handle a special case, this is passed the
  450.  *                   actual arguments.
  451.  *      Arguments: w - the menu widget.
  452.  *                 arglist - the argument list passed to XtSetValues.
  453.  *                 num_args - the number of args.
  454.  *      Returns: none
  455.  */
  456.  
  457. /* 
  458.  * If the user actually passed a width and height to the widget
  459.  * then this MUST be used, rather than our newly calculated width and
  460.  * height.
  461.  */
  462.  
  463. static Boolean
  464. SetValuesHook(w, arglist, num_args)
  465. Widget w;
  466. ArgList arglist;
  467. Cardinal *num_args;
  468. {
  469.     register Cardinal i;
  470.     Dimension width, height;
  471.     
  472.     width = w->core.width;
  473.     height = w->core.height;
  474.     
  475.     for ( i = 0 ; i < *num_args ; i++) {
  476.     if ( streq(arglist[i].name, XtNwidth) )
  477.         width = (Dimension) arglist[i].value;
  478.     if ( streq(arglist[i].name, XtNheight) )
  479.         height = (Dimension) arglist[i].value;
  480.     }
  481.  
  482.     if ((width != w->core.width) || (height != w->core.height))
  483.     MakeSetValuesRequest(w, width, height);
  484.     return(FALSE);
  485. }
  486.  
  487. /************************************************************
  488.  *
  489.  * Geometry Management routines.
  490.  *
  491.  ************************************************************/
  492.  
  493. /*    Function Name: GeometryManager
  494.  *    Description: This is the SimpleMenu Widget's Geometry Manager.
  495.  *    Arguments: w - the Menu Entry making the request.
  496.  *                 request - requested new geometry.
  497.  *                 reply - the allowed geometry.
  498.  *    Returns: XtGeometry{Yes, No, Almost}.
  499.  */
  500.  
  501. static XtGeometryResult
  502. GeometryManager(w, request, reply)
  503. Widget w;
  504. XtWidgetGeometry * request, * reply;
  505. {
  506.     SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
  507.     SmeObject entry = (SmeObject) w;
  508.     XtGeometryMask mode = request->request_mode;
  509.     XtGeometryResult answer;
  510.     Dimension old_height, old_width;
  511.  
  512.     if ( !(mode & CWWidth) && !(mode & CWHeight) )
  513.     return(XtGeometryNo);
  514.  
  515.     reply->width = request->width;
  516.     reply->height = request->height;
  517.  
  518.     old_width = entry->rectangle.width;
  519.     old_height = entry->rectangle.height;
  520.  
  521.     Layout(w, &(reply->width), &(reply->height) );
  522.  
  523. /*
  524.  * Since we are an override shell and have no parent there is no one to
  525.  * ask to see if this geom change is okay, so I am just going to assume
  526.  * we can do whatever we want.  If you subclass be very careful with this
  527.  * assumption, it could bite you.
  528.  *
  529.  * Chris D. Peterson - Sept. 1989.
  530.  */
  531.  
  532.     if ( (reply->width == request->width) &&
  533.      (reply->height == request->height) ) {
  534.  
  535.     if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
  536.         entry->rectangle.width = old_width;
  537.         entry->rectangle.height = old_height;    
  538.     }
  539.     else {
  540.         Layout(( Widget) smw, NULL, NULL);
  541.     }
  542.     answer = XtGeometryDone;
  543.     }
  544.     else {
  545.     entry->rectangle.width = old_width;
  546.     entry->rectangle.height = old_height;    
  547.  
  548.     if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
  549.           ((reply->height == request->height) && !(mode & CWWidth)) ||
  550.           ((reply->width == request->width) && 
  551.            (reply->height == request->height)) )
  552.         answer = XtGeometryNo;
  553.     else {
  554.         answer = XtGeometryAlmost;
  555.         reply->request_mode = 0;
  556.         if (reply->width != request->width)
  557.         reply->request_mode |= CWWidth;
  558.         if (reply->height != request->height)
  559.         reply->request_mode |= CWHeight;
  560.     }
  561.     }
  562.     return(answer);
  563. }
  564.  
  565. /*    Function Name: ChangeManaged
  566.  *    Description: called whenever a new child is managed.
  567.  *    Arguments: w - the simple menu widget.
  568.  *    Returns: none.
  569.  */
  570.  
  571. static void
  572. ChangeManaged(w)
  573. Widget w;
  574. {
  575.     Layout(w, NULL, NULL);
  576. }
  577.  
  578. /************************************************************
  579.  *
  580.  * Global Action Routines.
  581.  * 
  582.  * These actions routines will be added to the application's
  583.  * global action list. 
  584.  * 
  585.  ************************************************************/
  586.  
  587. /*      Function Name: PositionMenuAction
  588.  *      Description: Positions the simple menu widget.
  589.  *      Arguments: w - a widget (no the simple menu widget.)
  590.  *                 event - the event that caused this action.
  591.  *                 params, num_params - parameters passed to the routine.
  592.  *                                      we expect the name of the menu here.
  593.  *      Returns: none
  594.  */
  595.  
  596. /* ARGSUSED */
  597. static void
  598. PositionMenuAction(w, event, params, num_params)
  599. Widget w;
  600. XEvent * event;
  601. String * params;
  602. Cardinal * num_params;
  603.   Widget menu;
  604.   XPoint loc;
  605.  
  606.   if (*num_params != 1) {
  607.     char error_buf[BUFSIZ];
  608.     sprintf(error_buf, "%s %s",
  609.         "Xaw - SimpleMenuWidget: position menu action expects only one",
  610.         "parameter which is the name of the menu.");
  611.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  612.     return;
  613.   }
  614.  
  615.   if ( (menu = FindMenu(w, params[0])) == NULL) {
  616.     char error_buf[BUFSIZ];
  617.     sprintf(error_buf, "%s '%s'",
  618.         "Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
  619.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  620.     return;
  621.   }
  622.   
  623.   switch (event->type) {
  624.   case ButtonPress:
  625.   case ButtonRelease:
  626.     loc.x = event->xbutton.x_root;
  627.     loc.y = event->xbutton.y_root;
  628.     PositionMenu(menu, &loc);
  629.     break;
  630.   case EnterNotify:
  631.   case LeaveNotify:
  632.     loc.x = event->xcrossing.x_root;
  633.     loc.y = event->xcrossing.y_root;
  634.     PositionMenu(menu, &loc);
  635.     break;
  636.   case MotionNotify:
  637.     loc.x = event->xmotion.x_root;
  638.     loc.y = event->xmotion.y_root;
  639.     PositionMenu(menu, &loc);
  640.     break;
  641.   default:
  642.     PositionMenu(menu, NULL);
  643.     break;
  644.   }
  645. }  
  646.  
  647. /************************************************************
  648.  *
  649.  * Widget Action Routines.
  650.  * 
  651.  ************************************************************/
  652.  
  653. /*      Function Name: Unhighlight
  654.  *      Description: Unhighlights current entry.
  655.  *      Arguments: w - the simple menu widget.
  656.  *                 event - the event that caused this action.
  657.  *                 params, num_params - ** NOT USED **
  658.  *      Returns: none
  659.  */
  660.  
  661. /* ARGSUSED */
  662. static void
  663. Unhighlight(w, event, params, num_params)
  664. Widget w;
  665. XEvent * event;
  666. String * params;
  667. Cardinal * num_params;
  668.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  669.     SmeObject entry = smw->simple_menu.entry_set;
  670.     SmeObjectClass class;
  671.  
  672.     if ( entry == NULL) return;
  673.  
  674.     smw->simple_menu.entry_set = NULL;
  675.     class = (SmeObjectClass) entry->object.widget_class;
  676.     (class->sme_class.unhighlight) ( (Widget) entry);
  677. }
  678.  
  679. /*      Function Name: Highlight
  680.  *      Description: Highlights current entry.
  681.  *      Arguments: w - the simple menu widget.
  682.  *                 event - the event that caused this action.
  683.  *                 params, num_params - ** NOT USED **
  684.  *      Returns: none
  685.  */
  686.  
  687. /* ARGSUSED */
  688. static void
  689. Highlight(w, event, params, num_params)
  690. Widget w;
  691. XEvent * event;
  692. String * params;
  693. Cardinal * num_params;
  694. {
  695.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  696.     SmeObject entry;
  697.     SmeObjectClass class;
  698.     
  699.     if ( !XtIsSensitive(w) ) return;
  700.     
  701.     entry = GetEventEntry(w, event);
  702.  
  703.     if (entry == smw->simple_menu.entry_set) return;
  704.  
  705.     Unhighlight(w, event, params, num_params);  
  706.  
  707.     if (entry == NULL) return;
  708.  
  709.     if ( !XtIsSensitive( (Widget) entry)) {
  710.     smw->simple_menu.entry_set = NULL;
  711.     return;
  712.     }
  713.  
  714.     smw->simple_menu.entry_set = entry;
  715.     class = (SmeObjectClass) entry->object.widget_class;
  716.  
  717.     (class->sme_class.highlight) ( (Widget) entry);
  718. }
  719.  
  720. /*      Function Name: Notify
  721.  *      Description: Notify user of current entry.
  722.  *      Arguments: w - the simple menu widget.
  723.  *                 event - the event that caused this action.
  724.  *                 params, num_params - ** NOT USED **
  725.  *      Returns: none
  726.  */
  727.  
  728. /* ARGSUSED */
  729. static void
  730. Notify(w, event, params, num_params)
  731. Widget w;
  732. XEvent * event;
  733. String * params;
  734. Cardinal * num_params;
  735. {
  736.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  737.     SmeObject entry = smw->simple_menu.entry_set;
  738.     SmeObjectClass class;
  739.     
  740.     if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
  741.  
  742.     class = (SmeObjectClass) entry->object.widget_class;
  743.     (class->sme_class.notify)( (Widget) entry );
  744. }
  745.  
  746. /************************************************************
  747.  *
  748.  * Public Functions.
  749.  *
  750.  ************************************************************/
  751.  
  752. /*    Function Name: XawSimpleMenuAddGlobalActions
  753.  *    Description: adds the global actions to the simple menu widget.
  754.  *    Arguments: app_con - the appcontext.
  755.  *    Returns: none.
  756.  */
  757.  
  758. void
  759. #if NeedFunctionPrototypes
  760. XawSimpleMenuAddGlobalActions(XtAppContext app_con)
  761. #else
  762. XawSimpleMenuAddGlobalActions(app_con)
  763. XtAppContext app_con;
  764. #endif
  765. {
  766.     XtInitializeWidgetClass(simpleMenuWidgetClass);
  767.     XmuCallInitializers( app_con );
  768.  
  769.  
  770. /*    Function Name: XawSimpleMenuGetActiveEntry
  771.  *    Description: Gets the currently active (set) entry.
  772.  *    Arguments: w - the smw widget.
  773.  *    Returns: the currently set entry or NULL if none is set.
  774.  */
  775.  
  776. Widget
  777. #if NeedFunctionPrototypes
  778. XawSimpleMenuGetActiveEntry(Widget w)
  779. #else
  780. XawSimpleMenuGetActiveEntry(w)
  781. Widget w;
  782. #endif
  783. {
  784.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  785.  
  786.     return( (Widget) smw->simple_menu.entry_set);
  787.  
  788. /*    Function Name: XawSimpleMenuClearActiveEntry
  789.  *    Description: Unsets the currently active (set) entry.
  790.  *    Arguments: w - the smw widget.
  791.  *    Returns: none.
  792.  */
  793.  
  794. void
  795. #if NeedFunctionPrototypes
  796. XawSimpleMenuClearActiveEntry(Widget w)
  797. #else
  798. XawSimpleMenuClearActiveEntry(w)
  799. Widget w;
  800. #endif
  801. {
  802.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  803.  
  804.     smw->simple_menu.entry_set = NULL;
  805.  
  806. /************************************************************
  807.  *
  808.  * Private Functions.
  809.  *
  810.  ************************************************************/
  811.  
  812. /*    Function Name: CreateLabel
  813.  *    Description: Creates a the menu label.
  814.  *    Arguments: w - the smw widget.
  815.  *    Returns: none.
  816.  * 
  817.  * Creates the label object and makes sure it is the first child in
  818.  * in the list.
  819.  */
  820.  
  821. static void
  822. CreateLabel(w)
  823. Widget w;
  824. {
  825.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  826.     register Widget * child, * next_child;
  827.     register int i;
  828.     Arg args[2];
  829.  
  830.     if ( (smw->simple_menu.label_string == NULL) ||
  831.      (smw->simple_menu.label != NULL) ) {
  832.     char error_buf[BUFSIZ];
  833.  
  834.     sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
  835.         "label string is NULL", "label already exists", 
  836.         "no label is being created.");
  837.     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  838.     return;
  839.     }
  840.  
  841.     XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
  842.     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
  843.     smw->simple_menu.label = (SmeObject) 
  844.                           XtCreateManagedWidget("menuLabel", 
  845.                         smw->simple_menu.label_class, w,
  846.                         args, TWO);
  847.  
  848.     next_child = NULL;
  849.     for (child = smw->composite.children + smw->composite.num_children,
  850.      i = smw->composite.num_children ; i > 0 ; i--, child--) {
  851.     if (next_child != NULL)
  852.         *next_child = *child;
  853.     next_child = child;
  854.     }
  855.     *child = (Widget) smw->simple_menu.label;
  856. }
  857.  
  858. /*    Function Name: Layout
  859.  *    Description: lays the menu entries out all nice and neat.
  860.  *    Arguments: w - See below (+++)
  861.  *                 width_ret, height_ret - The returned width and 
  862.  *                                         height values.
  863.  *    Returns: none.
  864.  *
  865.  * if width == NULL || height == NULL then it assumes the you do not care
  866.  * about the return values, and just want a relayout.
  867.  *
  868.  * if this is not the case then it will set width_ret and height_ret
  869.  * to be width and height that the child would get if it were layed out
  870.  * at this time.
  871.  *
  872.  * +++ "w" can be the simple menu widget or any of its object children.
  873.  */
  874.  
  875. static void
  876. Layout(w, width_ret, height_ret)
  877. Widget w;
  878. Dimension *width_ret, *height_ret;
  879. {
  880.     SmeObject current_entry, *entry;
  881.     SimpleMenuWidget smw;
  882.     Dimension width, height;
  883.     Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
  884.     Boolean allow_change_size;
  885.     height = 0;
  886.  
  887.     if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
  888.     smw = (SimpleMenuWidget) w;
  889.     current_entry = NULL;
  890.     }
  891.     else {
  892.     smw = (SimpleMenuWidget) XtParent(w);
  893.     current_entry = (SmeObject) w;
  894.     }
  895.  
  896.     allow_change_size = (!XtIsRealized((Widget)smw) ||
  897.              (smw->shell.allow_shell_resize));
  898.  
  899.     if ( smw->simple_menu.menu_height )
  900.     height = smw->core.height;
  901.     else
  902.     if (do_layout) {
  903.         height = smw->simple_menu.top_margin;
  904.         ForAllChildren(smw, entry) {
  905.         if (!XtIsManaged( (Widget) *entry)) continue;
  906.  
  907.         if ( (smw->simple_menu.row_height != 0) && 
  908.             (*entry != smw->simple_menu.label) ) 
  909.             (*entry)->rectangle.height = smw->simple_menu.row_height;
  910.         
  911.         (*entry)->rectangle.y = height;
  912.         (*entry)->rectangle.x = 0;
  913.         height += (*entry)->rectangle.height;
  914.         }
  915.         height += smw->simple_menu.bottom_margin;
  916.     }
  917.     else {
  918.         if ((smw->simple_menu.row_height != 0) && 
  919.         (current_entry != smw->simple_menu.label) )
  920.         height = smw->simple_menu.row_height;
  921.     }
  922.     
  923.     if (smw->simple_menu.menu_width)
  924.     width = smw->core.width;
  925.     else if ( allow_change_size )
  926.     width = GetMenuWidth((Widget) smw, (Widget) current_entry);
  927.     else
  928.     width = smw->core.width;
  929.  
  930.     if (do_layout) {
  931.     ForAllChildren(smw, entry)
  932.         if (XtIsManaged( (Widget) *entry)) 
  933.         (*entry)->rectangle.width = width;
  934.  
  935.     if (allow_change_size)
  936.         MakeSetValuesRequest((Widget) smw, width, height);
  937.     }
  938.     else {
  939.     *width_ret = width;
  940.     if (height != 0)
  941.         *height_ret = height;
  942.     }
  943. }
  944.     
  945. /*    Function Name: AddPositionAction
  946.  *    Description: Adds the XawPositionSimpleMenu action to the global
  947.  *                   action list for this appcon.
  948.  *    Arguments: app_con - the application context for this app.
  949.  *                 data - NOT USED.
  950.  *    Returns: none.
  951.  */
  952.  
  953. /* ARGSUSED */
  954. static void
  955. AddPositionAction(app_con, data)
  956. XtAppContext app_con;
  957. caddr_t data;
  958. {
  959.     static XtActionsRec pos_action[] = {
  960.         { "XawPositionSimpleMenu", PositionMenuAction },
  961.     };
  962.  
  963.     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
  964. }
  965.  
  966. /*    Function Name: FindMenu
  967.  *    Description: Find the menu give a name and reference widget.
  968.  *    Arguments: widget - reference widget.
  969.  *                 name   - the menu widget's name.
  970.  *    Returns: the menu widget or NULL.
  971.  */
  972.  
  973. static Widget 
  974. FindMenu(widget, name)
  975. Widget widget;
  976. String name;
  977. {
  978.     register Widget w, menu;
  979.     
  980.     for ( w = widget ; w != NULL ; w = XtParent(w) )
  981.     if ( (menu = XtNameToWidget(w, name)) != NULL )
  982.         return(menu);
  983.     return(NULL);
  984. }
  985.  
  986. /*    Function Name: PositionMenu
  987.  *    Description: Places the menu
  988.  *    Arguments: w - the simple menu widget.
  989.  *                 location - a pointer the the position or NULL.
  990.  *    Returns: none.
  991.  */
  992.  
  993. static void
  994. PositionMenu(w, location)
  995. Widget w;
  996. XPoint * location;
  997. {
  998.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  999.     SmeObject entry;
  1000.     XPoint t_point;
  1001.     
  1002.     if (location == NULL) {
  1003.     Window junk1, junk2;
  1004.     int root_x, root_y, junkX, junkY;
  1005.     unsigned int junkM;
  1006.     
  1007.     location = &t_point;
  1008.     if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2, 
  1009.               &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
  1010.         char error_buf[BUFSIZ];
  1011.         sprintf(error_buf, "%s %s", "Xaw - SimpleMenuWidget:",
  1012.             "Could not find location of mouse pointer");
  1013.         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
  1014.         return;
  1015.     }
  1016.     location->x = (short) root_x;
  1017.     location->y = (short) root_y;
  1018.     }
  1019.     
  1020.     /*
  1021.      * The width will not be correct unless it is realized.
  1022.      */
  1023.     
  1024.     XtRealizeWidget(w);
  1025.     
  1026.     location->x -= (Position) w->core.width/2;
  1027.     
  1028.     if (smw->simple_menu.popup_entry == NULL)
  1029.     entry = smw->simple_menu.label;
  1030.     else
  1031.     entry = smw->simple_menu.popup_entry;
  1032.  
  1033.     if (entry != NULL)
  1034.     location->y -= entry->rectangle.y + entry->rectangle.height/2;
  1035.  
  1036.     MoveMenu(w, (Position) location->x, (Position) location->y);
  1037. }
  1038.  
  1039. /*    Function Name: MoveMenu
  1040.  *    Description: Actually moves the menu, may force it to
  1041.  *                   to be fully visable if menu_on_screen is TRUE.
  1042.  *    Arguments: w - the simple menu widget.
  1043.  *                 x, y - the current location of the widget.
  1044.  *    Returns: none 
  1045.  */
  1046.  
  1047. static void
  1048. MoveMenu(w, x, y)
  1049. Widget w;
  1050. Position x, y;
  1051. {
  1052.     Arg arglist[2];
  1053.     Cardinal num_args = 0;
  1054.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1055.     
  1056.     if (smw->simple_menu.menu_on_screen) {
  1057.     int width = w->core.width + 2 * w->core.border_width;
  1058.     int height = w->core.height + 2 * w->core.border_width;
  1059.     
  1060.     if (x >= 0) {
  1061.         int scr_width = WidthOfScreen(XtScreen(w));
  1062.         if (x + width > scr_width)
  1063.         x = scr_width - width;
  1064.     }
  1065.     if (x < 0) 
  1066.         x = 0;
  1067.     
  1068.     if (y >= 0) {
  1069.         int scr_height = HeightOfScreen(XtScreen(w));
  1070.         if (y + height > scr_height)
  1071.         y = scr_height - height;
  1072.     }
  1073.     if (y < 0)
  1074.         y = 0;
  1075.     }
  1076.     
  1077.     XtSetArg(arglist[num_args], XtNx, x); num_args++;
  1078.     XtSetArg(arglist[num_args], XtNy, y); num_args++;
  1079.     XtSetValues(w, arglist, num_args);
  1080. }
  1081.  
  1082. /*    Function Name: ChangeCursorOnGrab
  1083.  *    Description: Changes the cursor on the active grab to the one
  1084.  *                   specified in out resource list.
  1085.  *    Arguments: w - the widget.
  1086.  *                 junk, garbage - ** NOT USED **.
  1087.  *    Returns: None.
  1088.  */
  1089.  
  1090. /* ARGSUSED */
  1091. static void
  1092. ChangeCursorOnGrab(w, junk, garbage)
  1093. Widget w;
  1094. XtPointer junk, garbage;
  1095. {
  1096.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1097.     
  1098.     /*
  1099.      * The event mask here is what is currently in the MIT implementation.
  1100.      * There really needs to be a way to get the value of the mask out
  1101.      * of the toolkit (CDP 5/26/89).
  1102.      */
  1103.     
  1104.     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
  1105.                  smw->simple_menu.cursor, 
  1106.                  XtLastTimestampProcessed(XtDisplay(w)));
  1107. }
  1108.  
  1109. /*      Function Name: MakeSetValuesRequest
  1110.  *      Description: Makes a (possibly recursive) call to SetValues,
  1111.  *                   I take great pains to not go into an infinite loop.
  1112.  *      Arguments: w - the simple menu widget.
  1113.  *                 width, height - the size of the ask for.
  1114.  *      Returns: none
  1115.  */
  1116.  
  1117. static void
  1118. MakeSetValuesRequest(w, width, height)
  1119. Widget w;
  1120. Dimension width, height;
  1121. {
  1122.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1123.     Arg arglist[2];
  1124.     Cardinal num_args = (Cardinal) 0;
  1125.     
  1126.     if ( !smw->simple_menu.recursive_set_values ) {
  1127.     if ( (smw->core.width != width) || (smw->core.height != height) ) {
  1128.         smw->simple_menu.recursive_set_values = TRUE;
  1129.         XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
  1130.         XtSetArg(arglist[num_args], XtNheight, height); num_args++;
  1131.         XtSetValues(w, arglist, num_args);
  1132.     }
  1133.     else if (XtIsRealized( (Widget) smw))
  1134.         Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
  1135.     }
  1136.     smw->simple_menu.recursive_set_values = FALSE;
  1137. }
  1138.  
  1139. /*      Function Name: GetMenuWidth
  1140.  *      Description: Sets the length of the widest entry in pixels.
  1141.  *      Arguments: w - the simple menu widget.
  1142.  *      Returns: width of menu.
  1143.  */
  1144.  
  1145. static Dimension
  1146. GetMenuWidth(w, w_ent)
  1147. Widget w, w_ent;
  1148. {
  1149.     SmeObject cur_entry = (SmeObject) w_ent;
  1150.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1151.     Dimension width, widest = (Dimension) 0;
  1152.     SmeObject * entry;
  1153.     
  1154.     if ( smw->simple_menu.menu_width ) 
  1155.     return(smw->core.width);
  1156.  
  1157.     ForAllChildren(smw, entry) {
  1158.     XtWidgetGeometry preferred;
  1159.  
  1160.     if (!XtIsManaged( (Widget) *entry)) continue;
  1161.     
  1162.     if (*entry != cur_entry) {
  1163.         XtQueryGeometry((Widget) *entry, NULL, &preferred);
  1164.         
  1165.         if (preferred.request_mode & CWWidth)
  1166.         width = preferred.width;
  1167.         else
  1168.         width = (*entry)->rectangle.width;
  1169.     }
  1170.     else
  1171.         width = (*entry)->rectangle.width;
  1172.     
  1173.     if ( width > widest )
  1174.         widest = width;
  1175.     }
  1176.     
  1177.     return(widest);
  1178. }
  1179.  
  1180. /*      Function Name: GetMenuHeight
  1181.  *      Description: Sets the length of the widest entry in pixels.
  1182.  *      Arguments: w - the simple menu widget.
  1183.  *      Returns: width of menu.
  1184.  */
  1185.  
  1186. static Dimension
  1187. GetMenuHeight(w)
  1188. Widget w;
  1189. {
  1190.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1191.     SmeObject * entry;
  1192.     Dimension height;
  1193.     
  1194.     if (smw->simple_menu.menu_height)
  1195.     return(smw->core.height);
  1196.  
  1197.     height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
  1198.     
  1199.     if (smw->simple_menu.row_height == 0) {
  1200.     ForAllChildren(smw, entry) 
  1201.         if (XtIsManaged ((Widget) *entry)) 
  1202.         height += (*entry)->rectangle.height;
  1203.     } else 
  1204.     height += smw->simple_menu.row_height * smw->composite.num_children;
  1205.     
  1206.     return(height);
  1207. }
  1208.  
  1209. /*      Function Name: GetEventEntry
  1210.  *      Description: Gets an entry given an event that has X and Y coords.
  1211.  *      Arguments: w - the simple menu widget.
  1212.  *                 event - the event.
  1213.  *      Returns: the entry that this point is in.
  1214.  */
  1215.  
  1216. static SmeObject
  1217. GetEventEntry(w, event)
  1218. Widget w;
  1219. XEvent * event;
  1220. {
  1221.     Position x_loc, y_loc;
  1222.     SimpleMenuWidget smw = (SimpleMenuWidget) w;
  1223.     SmeObject * entry;
  1224.     
  1225.     switch (event->type) {
  1226.     case MotionNotify:
  1227.     x_loc = event->xmotion.x;
  1228.     y_loc = event->xmotion.y;
  1229.     break;
  1230.     case EnterNotify:
  1231.     case LeaveNotify:
  1232.     x_loc = event->xcrossing.x;
  1233.     y_loc = event->xcrossing.y;
  1234.     break;
  1235.     case ButtonPress:
  1236.     case ButtonRelease:
  1237.     x_loc = event->xbutton.x;
  1238.     y_loc = event->xbutton.y;
  1239.     break;
  1240.     default:
  1241.     XtAppError(XtWidgetToApplicationContext(w),
  1242.            "Unknown event type in GetEventEntry().");
  1243.     break;
  1244.     }
  1245.     
  1246.     if ( (x_loc < 0) || (x_loc >= (int)smw->core.width) || (y_loc < 0) ||
  1247.     (y_loc >= (int)smw->core.height) )
  1248.     return(NULL);
  1249.     
  1250.     ForAllChildren(smw, entry) {
  1251.     if (!XtIsManaged ((Widget) *entry)) continue;
  1252.  
  1253.     if ( ((*entry)->rectangle.y < y_loc) &&
  1254.         ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) )
  1255.         if ( *entry == smw->simple_menu.label )
  1256.         return(NULL);    /* cannot select the label. */
  1257.         else
  1258.         return(*entry);
  1259.     }
  1260.     
  1261.     return(NULL);
  1262. }
  1263.