SimpleMenu.c

Go to the documentation of this file.
00001 /* $XConsortium: SimpleMenu.c,v 1.44 94/04/17 20:12:45 kaleb Exp $ */
00002 
00003 /*
00004 Copyright (c) 1989, 1994  X Consortium
00005 
00006 Permission is hereby granted, free of charge, to any person obtaining a copy
00007 of this software and associated documentation files (the "Software"), to deal
00008 in the Software without restriction, including without limitation the rights
00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00010 copies of the Software, and to permit persons to whom the Software is
00011 furnished to do so, subject to the following conditions:
00012 
00013 The above copyright notice and this permission notice shall be included in
00014 all copies or substantial portions of the Software.
00015 
00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00019 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00020 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 Except as contained in this notice, the name of the X Consortium shall not be
00024 used in advertising or otherwise to promote the sale, use or other dealings
00025 in this Software without prior written authorization from the X Consortium.
00026  */
00027 
00028 /*
00029  * SimpleMenu.c - Source code file for SimpleMenu widget.
00030  *
00031  * Date:    April 3, 1989
00032  *
00033  * By:      Chris D. Peterson
00034  *          MIT X Consortium 
00035  *          kit@expo.lcs.mit.edu
00036  */
00037 
00038 #include <stdio.h>
00039 #include <X11/IntrinsicP.h>
00040 #include <X11/StringDefs.h>
00041 
00042 #include <X11/Xaw3d/XawInit.h>
00043 #include <X11/Xaw3d/SimpleMenP.h>
00044 #include <X11/Xaw3d/SmeBSB.h>
00045 #include <X11/Xaw3d/Cardinals.h>
00046 
00047 #include <X11/Xmu/Initer.h>
00048 #include <X11/Xmu/CharSet.h>
00049 
00050 #define streq(a, b)        ( strcmp((a), (b)) == 0 )
00051 
00052 #define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field)
00053 
00054 static XtResource resources[] = { 
00055 
00056 /*
00057  * Label Resources.
00058  */
00059 
00060   {XtNlabel,  XtCLabel, XtRString, sizeof(String),
00061      offset(label_string), XtRString, NULL},
00062   {XtNlabelClass,  XtCLabelClass, XtRPointer, sizeof(WidgetClass),
00063      offset(label_class), XtRImmediate, (XtPointer) NULL},
00064 
00065 /*
00066  * Layout Resources.
00067  */
00068 
00069   {XtNrowHeight,  XtCRowHeight, XtRDimension, sizeof(Dimension),
00070      offset(row_height), XtRImmediate, (XtPointer) 0},
00071   {XtNtopMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
00072      offset(top_margin), XtRImmediate, (XtPointer) 0},
00073   {XtNbottomMargin,  XtCVerticalMargins, XtRDimension, sizeof(Dimension),
00074      offset(bottom_margin), XtRImmediate, (XtPointer) 0},
00075 
00076 /*
00077  * Misc. Resources
00078  */
00079 
00080   { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
00081       XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
00082       XtRImmediate, (XtPointer) TRUE },
00083   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
00084       offset(cursor), XtRImmediate, (XtPointer) None},
00085   {XtNmenuOnScreen,  XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
00086       offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
00087   {XtNpopupOnEntry,  XtCPopupOnEntry, XtRWidget, sizeof(Widget),
00088       offset(popup_entry), XtRWidget, NULL},
00089   {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
00090       offset(backing_store), 
00091       XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
00092 };  
00093 #undef offset
00094 
00095 static char defaultTranslations[] =
00096     ":<EnterWindow>:     highlight()             \n\
00097      :<LeaveWindow>:     unhighlight()           \n\
00098      :<BtnMotion>:       highlight()             \n\
00099      :<BtnUp>:           MenuPopdown() notify() unhighlight()"; 
00100 
00101 /*
00102  * Semi Public function definitions. 
00103  */
00104 
00105 static void Redisplay(), Realize(), Resize(), ChangeManaged();
00106 static void Initialize(), ClassInitialize(), ClassPartInitialize();
00107 static Boolean SetValues(), SetValuesHook();
00108 static XtGeometryResult GeometryManager();
00109 
00110 /*
00111  * Action Routine Definitions
00112  */
00113 
00114 static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
00115 
00116 /* 
00117  * Private Function Definitions.
00118  */
00119 
00120 static void MakeSetValuesRequest(), CreateLabel(), Layout();
00121 static void AddPositionAction(), PositionMenu(), ChangeCursorOnGrab();
00122 static Dimension GetMenuWidth(), GetMenuHeight();
00123 static Widget FindMenu();
00124 static SmeObject GetEventEntry();
00125 static void MoveMenu();
00126 
00127 static XtActionsRec actionsList[] =
00128 {
00129   {"notify",            Notify},
00130   {"highlight",         Highlight},
00131   {"unhighlight",       Unhighlight},
00132 };
00133  
00134 static CompositeClassExtensionRec extension_rec = {
00135     /* next_extension */  NULL,
00136     /* record_type */     NULLQUARK,
00137     /* version */         XtCompositeExtensionVersion,
00138     /* record_size */     sizeof(CompositeClassExtensionRec),
00139     /* accepts_objects */ TRUE,
00140 };
00141 
00142 #define superclass (&overrideShellClassRec)
00143     
00144 SimpleMenuClassRec simpleMenuClassRec = {
00145   {
00146     /* superclass         */    (WidgetClass) superclass,
00147     /* class_name         */    "SimpleMenu",
00148     /* size               */    sizeof(SimpleMenuRec),
00149     /* class_initialize   */    ClassInitialize,
00150     /* class_part_initialize*/  ClassPartInitialize,
00151     /* Class init'ed      */    FALSE,
00152     /* initialize         */    Initialize,
00153     /* initialize_hook    */    NULL,
00154     /* realize            */    Realize,
00155     /* actions            */    actionsList,
00156     /* num_actions        */    XtNumber(actionsList),
00157     /* resources          */    resources,
00158     /* resource_count     */    XtNumber(resources),
00159     /* xrm_class          */    NULLQUARK,
00160     /* compress_motion    */    TRUE, 
00161     /* compress_exposure  */    TRUE,
00162     /* compress_enterleave*/    TRUE,
00163     /* visible_interest   */    FALSE,
00164     /* destroy            */    NULL,
00165     /* resize             */    Resize,
00166     /* expose             */    Redisplay,
00167     /* set_values         */    SetValues,
00168     /* set_values_hook    */    SetValuesHook,
00169     /* set_values_almost  */    XtInheritSetValuesAlmost,  
00170     /* get_values_hook    */    NULL,                   
00171     /* accept_focus       */    NULL,
00172     /* intrinsics version */    XtVersion,
00173     /* callback offsets   */    NULL,
00174     /* tm_table           */    defaultTranslations,
00175     /* query_geometry     */    NULL,
00176     /* display_accelerator*/    NULL,
00177     /* extension          */    NULL
00178   },{
00179     /* geometry_manager   */    GeometryManager,
00180     /* change_managed     */    ChangeManaged,
00181     /* insert_child       */    XtInheritInsertChild,
00182     /* delete_child       */    XtInheritDeleteChild,
00183     /* extension          */    NULL
00184   },{
00185     /* Shell extension    */    NULL
00186   },{
00187     /* Override extension */    NULL
00188   },{
00189     /* Simple Menu extension*/  NULL
00190   }
00191 };
00192 
00193 WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
00194 
00195 #define ForAllChildren(smw, childP) \
00196   for ( (childP) = (SmeObject *) (smw)->composite.children ; \
00197         (childP) < (SmeObject *) ( (smw)->composite.children + \
00198                                  (smw)->composite.num_children ) ; \
00199         (childP)++ )
00200 
00201 /************************************************************
00202  *
00203  * Semi-Public Functions.
00204  *
00205  ************************************************************/
00206 
00207 /*      Function Name: ClassInitialize
00208  *      Description: Class Initialize routine, called only once.
00209  *      Arguments: none.
00210  *      Returns: none.
00211  */
00212 
00213 static void
00214 ClassInitialize()
00215 {
00216   XawInitializeWidgetSet();
00217   XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
00218                  (XtConvertArgList)NULL, (Cardinal)0 );
00219   XmuAddInitializer( AddPositionAction, NULL);
00220 }
00221 
00222 /*      Function Name: ClassInitialize
00223  *      Description: Class Part Initialize routine, called for every
00224  *                   subclass.  Makes sure that the subclasses pick up 
00225  *                   the extension record.
00226  *      Arguments: wc - the widget class of the subclass.
00227  *      Returns: none.
00228  */
00229 
00230 static void
00231 ClassPartInitialize(wc)
00232 WidgetClass wc;
00233 {
00234     SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
00235 
00236 /*
00237  * Make sure that our subclass gets the extension rec too.
00238  */
00239 
00240     extension_rec.next_extension = smwc->composite_class.extension;
00241     smwc->composite_class.extension = (XtPointer) &extension_rec;
00242 }
00243 
00244 /*      Function Name: Initialize
00245  *      Description: Initializes the simple menu widget
00246  *      Arguments: request - the widget requested by the argument list.
00247  *                 new     - the new widget with both resource and non
00248  *                           resource values.
00249  *      Returns: none.
00250  */
00251 
00252 /* ARGSUSED */
00253 static void
00254 Initialize(request, new, args, num_args)
00255 Widget request, new;
00256 ArgList args;
00257 Cardinal *num_args;
00258 {
00259   SimpleMenuWidget smw = (SimpleMenuWidget) new;
00260 
00261   XmuCallInitializers(XtWidgetToApplicationContext(new));
00262 
00263   if (smw->simple_menu.label_class == NULL) 
00264       smw->simple_menu.label_class = smeBSBObjectClass;
00265 
00266   smw->simple_menu.label = NULL;
00267   smw->simple_menu.entry_set = NULL;
00268   smw->simple_menu.recursive_set_values = FALSE;
00269 
00270   if (smw->simple_menu.label_string != NULL)
00271       CreateLabel(new);
00272 
00273   smw->simple_menu.menu_width = TRUE;
00274 
00275   if (smw->core.width == 0) {
00276       smw->simple_menu.menu_width = FALSE;
00277       smw->core.width = GetMenuWidth(new, (Widget)NULL);
00278   }
00279 
00280   smw->simple_menu.menu_height = TRUE;
00281 
00282   if (smw->core.height == 0) {
00283       smw->simple_menu.menu_height = FALSE;
00284       smw->core.height = GetMenuHeight(new);
00285   }
00286 
00287 /*
00288  * Add a popup_callback routine for changing the cursor.
00289  */
00290   
00291   XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, (XtPointer)NULL);
00292 }
00293 
00294 /*      Function Name: Redisplay
00295  *      Description: Redisplays the contents of the widget.
00296  *      Arguments: w - the simple menu widget.
00297  *                 event - the X event that caused this redisplay.
00298  *                 region - the region the needs to be repainted. 
00299  *      Returns: none.
00300  */
00301 
00302 /* ARGSUSED */
00303 static void
00304 Redisplay(w, event, region)
00305 Widget w;
00306 XEvent * event;
00307 Region region;
00308 {
00309     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00310     SmeObject * entry;
00311     SmeObjectClass class;
00312 
00313     if (region == NULL)
00314         XClearWindow(XtDisplay(w), XtWindow(w));
00315 
00316     /*
00317      * Check and Paint each of the entries - including the label.
00318      */
00319 
00320     ForAllChildren(smw, entry) {
00321         if (!XtIsManaged ( (Widget) *entry)) continue;
00322 
00323         if (region != NULL) 
00324             switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
00325                                  (int) (*entry)->rectangle.y,
00326                                  (unsigned int) (*entry)->rectangle.width,
00327                                  (unsigned int) (*entry)->rectangle.height)) {
00328             case RectangleIn:
00329             case RectanglePart:
00330                 break;
00331             default:
00332                 continue;
00333             }
00334         class = (SmeObjectClass) (*entry)->object.widget_class;
00335 
00336         if (class->rect_class.expose != NULL)
00337             (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
00338     }
00339 }
00340 
00341 /*      Function Name: Realize
00342  *      Description: Realizes the widget.
00343  *      Arguments: w - the simple menu widget.
00344  *                 mask - value mask for the window to create.
00345  *                 attrs - attributes for the window to create.
00346  *      Returns: none
00347  */
00348 
00349 static void
00350 Realize(w, mask, attrs)
00351 Widget w;
00352 XtValueMask * mask;
00353 XSetWindowAttributes * attrs;
00354 {
00355     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00356 
00357     attrs->cursor = smw->simple_menu.cursor;
00358     *mask |= CWCursor;
00359     if ((smw->simple_menu.backing_store == Always) ||
00360         (smw->simple_menu.backing_store == NotUseful) ||
00361         (smw->simple_menu.backing_store == WhenMapped) ) {
00362         *mask |= CWBackingStore;
00363         attrs->backing_store = smw->simple_menu.backing_store;
00364     }
00365     else
00366         *mask &= ~CWBackingStore;
00367 
00368     (*superclass->core_class.realize) (w, mask, attrs);
00369 }
00370 
00371 /*      Function Name: Resize
00372  *      Description: Handle the menu being resized bigger.
00373  *      Arguments: w - the simple menu widget.
00374  *      Returns: none.
00375  */
00376 
00377 static void
00378 Resize(w)
00379 Widget w;
00380 {
00381     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00382     SmeObject * entry;
00383 
00384     if ( !XtIsRealized(w) ) return;
00385 
00386     ForAllChildren(smw, entry)  /* reset width of all entries. */
00387         if (XtIsManaged( (Widget) *entry))
00388             (*entry)->rectangle.width = smw->core.width;
00389     
00390     Redisplay(w, (XEvent *) NULL, (Region) NULL);
00391 }
00392 
00393 /*      Function Name: SetValues
00394  *      Description: Relayout the menu when one of the resources is changed.
00395  *      Arguments: current - current state of the widget.
00396  *                 request - what was requested.
00397  *                 new - what the widget will become.
00398  *      Returns: none
00399  */
00400 
00401 /* ARGSUSED */
00402 static Boolean
00403 SetValues(current, request, new, args, num_args)
00404 Widget current, request, new;
00405 ArgList args;
00406 Cardinal *num_args;
00407 {
00408     SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
00409     SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
00410     Boolean ret_val = FALSE, layout = FALSE;
00411     
00412     if (!XtIsRealized(current)) return(FALSE);
00413     
00414     if (!smw_new->simple_menu.recursive_set_values) {
00415         if (smw_new->core.width != smw_old->core.width) {
00416             smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
00417             layout = TRUE;
00418         }
00419         if (smw_new->core.height != smw_old->core.height) {
00420             smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
00421             layout = TRUE;
00422         }
00423     }
00424 
00425     if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
00426         XDefineCursor(XtDisplay(new),
00427                       XtWindow(new), smw_new->simple_menu.cursor);
00428     
00429     if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) 
00430         if (smw_new->simple_menu.label_string == NULL)         /* Destroy. */
00431             XtDestroyWidget((Widget) smw_old->simple_menu.label);
00432         else if (smw_old->simple_menu.label_string == NULL)    /* Create. */
00433             CreateLabel(new);
00434         else {                                                 /* Change. */
00435             Arg arglist[1];
00436             
00437             XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
00438             XtSetValues((Widget) smw_new->simple_menu.label, arglist, ONE);
00439         }
00440     
00441     if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
00442         XtAppWarning(XtWidgetToApplicationContext(new),
00443                      "No Dynamic class change of the SimpleMenu Label.");
00444     
00445     if ((smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin) ||
00446         (smw_old->simple_menu.bottom_margin != 
00447          smw_new->simple_menu.bottom_margin) /* filler.................  */ ) {
00448         layout = TRUE;
00449         ret_val = TRUE;
00450     }
00451 
00452     if (layout)
00453         Layout(new, (Dimension *)NULL, (Dimension *)NULL);
00454 
00455     return(ret_val);
00456 }
00457 
00458 /*      Function Name: SetValuesHook
00459  *      Description: To handle a special case, this is passed the
00460  *                   actual arguments.
00461  *      Arguments: w - the menu widget.
00462  *                 arglist - the argument list passed to XtSetValues.
00463  *                 num_args - the number of args.
00464  *      Returns: none
00465  */
00466 
00467 /* 
00468  * If the user actually passed a width and height to the widget
00469  * then this MUST be used, rather than our newly calculated width and
00470  * height.
00471  */
00472 
00473 static Boolean
00474 SetValuesHook(w, arglist, num_args)
00475 Widget w;
00476 ArgList arglist;
00477 Cardinal *num_args;
00478 {
00479     Cardinal i;
00480     Dimension width, height;
00481     
00482     width = w->core.width;
00483     height = w->core.height;
00484     
00485     for ( i = 0 ; i < *num_args ; i++) {
00486         if ( streq(arglist[i].name, XtNwidth) )
00487             width = (Dimension) arglist[i].value;
00488         if ( streq(arglist[i].name, XtNheight) )
00489             height = (Dimension) arglist[i].value;
00490     }
00491 
00492     if ((width != w->core.width) || (height != w->core.height))
00493         MakeSetValuesRequest(w, width, height);
00494     return(FALSE);
00495 }
00496 
00497 /************************************************************
00498  *
00499  * Geometry Management routines.
00500  *
00501  ************************************************************/
00502 
00503 /*      Function Name: GeometryManager
00504  *      Description: This is the SimpleMenu Widget's Geometry Manager.
00505  *      Arguments: w - the Menu Entry making the request.
00506  *                 request - requested new geometry.
00507  *                 reply - the allowed geometry.
00508  *      Returns: XtGeometry{Yes, No, Almost}.
00509  */
00510 
00511 static XtGeometryResult
00512 GeometryManager(w, request, reply)
00513 Widget w;
00514 XtWidgetGeometry * request, * reply;
00515 {
00516     SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
00517     SmeObject entry = (SmeObject) w;
00518     XtGeometryMask mode = request->request_mode;
00519     XtGeometryResult answer;
00520     Dimension old_height, old_width;
00521 
00522     if ( !(mode & CWWidth) && !(mode & CWHeight) )
00523         return(XtGeometryNo);
00524 
00525     reply->width = request->width;
00526     reply->height = request->height;
00527 
00528     old_width = entry->rectangle.width;
00529     old_height = entry->rectangle.height;
00530 
00531     Layout(w, &(reply->width), &(reply->height) );
00532 
00533 /*
00534  * Since we are an override shell and have no parent there is no one to
00535  * ask to see if this geom change is okay, so I am just going to assume
00536  * we can do whatever we want.  If you subclass be very careful with this
00537  * assumption, it could bite you.
00538  *
00539  * Chris D. Peterson - Sept. 1989.
00540  */
00541 
00542     if ( (reply->width == request->width) &&
00543          (reply->height == request->height) ) {
00544 
00545         if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
00546             entry->rectangle.width = old_width;
00547             entry->rectangle.height = old_height;       
00548         }
00549         else {
00550             Layout(( Widget) smw, (Dimension *)NULL, (Dimension *)NULL);
00551         }
00552         answer = XtGeometryDone;
00553     }
00554     else {
00555         entry->rectangle.width = old_width;
00556         entry->rectangle.height = old_height;   
00557 
00558         if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
00559               ((reply->height == request->height) && !(mode & CWWidth)) ||
00560               ((reply->width == request->width) && 
00561                (reply->height == request->height)) )
00562             answer = XtGeometryNo;
00563         else {
00564             answer = XtGeometryAlmost;
00565             reply->request_mode = 0;
00566             if (reply->width != request->width)
00567                 reply->request_mode |= CWWidth;
00568             if (reply->height != request->height)
00569                 reply->request_mode |= CWHeight;
00570         }
00571     }
00572     return(answer);
00573 }
00574 
00575 /*      Function Name: ChangeManaged
00576  *      Description: called whenever a new child is managed.
00577  *      Arguments: w - the simple menu widget.
00578  *      Returns: none.
00579  */
00580 
00581 static void
00582 ChangeManaged(w)
00583 Widget w;
00584 {
00585     Layout(w, (Dimension *)NULL, (Dimension *)NULL);
00586 }
00587 
00588 /************************************************************
00589  *
00590  * Global Action Routines.
00591  * 
00592  * These actions routines will be added to the application's
00593  * global action list. 
00594  * 
00595  ************************************************************/
00596 
00597 /*      Function Name: PositionMenuAction
00598  *      Description: Positions the simple menu widget.
00599  *      Arguments: w - a widget (no the simple menu widget.)
00600  *                 event - the event that caused this action.
00601  *                 params, num_params - parameters passed to the routine.
00602  *                                      we expect the name of the menu here.
00603  *      Returns: none
00604  */
00605 
00606 /* ARGSUSED */
00607 static void
00608 PositionMenuAction(w, event, params, num_params)
00609 Widget w;
00610 XEvent * event;
00611 String * params;
00612 Cardinal * num_params;
00613 { 
00614   Widget menu;
00615   XPoint loc;
00616 
00617   if (*num_params != 1) {
00618     char error_buf[BUFSIZ];
00619     (void) sprintf(error_buf, "%s %s",
00620             "Xaw - SimpleMenuWidget: position menu action expects only one",
00621             "parameter which is the name of the menu.");
00622     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
00623     return;
00624   }
00625 
00626   if ( (menu = FindMenu(w, params[0])) == NULL) {
00627     char error_buf[BUFSIZ];
00628     (void) sprintf(error_buf, "%s '%s'",
00629             "Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
00630     XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
00631     return;
00632   }
00633   
00634   switch (event->type) {
00635   case ButtonPress:
00636   case ButtonRelease:
00637     loc.x = event->xbutton.x_root;
00638     loc.y = event->xbutton.y_root;
00639     PositionMenu(menu, &loc);
00640     break;
00641   case EnterNotify:
00642   case LeaveNotify:
00643     loc.x = event->xcrossing.x_root;
00644     loc.y = event->xcrossing.y_root;
00645     PositionMenu(menu, &loc);
00646     break;
00647   case MotionNotify:
00648     loc.x = event->xmotion.x_root;
00649     loc.y = event->xmotion.y_root;
00650     PositionMenu(menu, &loc);
00651     break;
00652   default:
00653     PositionMenu(menu, (XPoint *)NULL);
00654     break;
00655   }
00656 }  
00657 
00658 /************************************************************
00659  *
00660  * Widget Action Routines.
00661  * 
00662  ************************************************************/
00663 
00664 /*      Function Name: Unhighlight
00665  *      Description: Unhighlights current entry.
00666  *      Arguments: w - the simple menu widget.
00667  *                 event - the event that caused this action.
00668  *                 params, num_params - ** NOT USED **
00669  *      Returns: none
00670  */
00671 
00672 /* ARGSUSED */
00673 static void
00674 Unhighlight(w, event, params, num_params)
00675 Widget w;
00676 XEvent * event;
00677 String * params;
00678 Cardinal * num_params;
00679 { 
00680     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00681     SmeObject entry = smw->simple_menu.entry_set;
00682     SmeObjectClass class;
00683  
00684     if ( entry == NULL) return;
00685 
00686     smw->simple_menu.entry_set = NULL;
00687     class = (SmeObjectClass) entry->object.widget_class;
00688     (class->sme_class.unhighlight) ( (Widget) entry);
00689 }
00690 
00691 /*      Function Name: Highlight
00692  *      Description: Highlights current entry.
00693  *      Arguments: w - the simple menu widget.
00694  *                 event - the event that caused this action.
00695  *                 params, num_params - ** NOT USED **
00696  *      Returns: none
00697  */
00698 
00699 /* ARGSUSED */
00700 static void
00701 Highlight(w, event, params, num_params)
00702 Widget w;
00703 XEvent * event;
00704 String * params;
00705 Cardinal * num_params;
00706 {
00707     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00708     SmeObject entry;
00709     SmeObjectClass class;
00710     
00711     if ( !XtIsSensitive(w) ) return;
00712     
00713     entry = GetEventEntry(w, event);
00714 
00715     if (entry == smw->simple_menu.entry_set) return;
00716 
00717     Unhighlight(w, event, params, num_params);  
00718 
00719     if (entry == NULL) return;
00720 
00721     if ( !XtIsSensitive( (Widget) entry)) {
00722         smw->simple_menu.entry_set = NULL;
00723         return;
00724     }
00725 
00726     smw->simple_menu.entry_set = entry;
00727     class = (SmeObjectClass) entry->object.widget_class;
00728 
00729     (class->sme_class.highlight) ( (Widget) entry);
00730 }
00731 
00732 /*      Function Name: Notify
00733  *      Description: Notify user of current entry.
00734  *      Arguments: w - the simple menu widget.
00735  *                 event - the event that caused this action.
00736  *                 params, num_params - ** NOT USED **
00737  *      Returns: none
00738  */
00739 
00740 /* ARGSUSED */
00741 static void
00742 Notify(w, event, params, num_params)
00743 Widget w;
00744 XEvent * event;
00745 String * params;
00746 Cardinal * num_params;
00747 {
00748     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00749     SmeObject entry = smw->simple_menu.entry_set;
00750     SmeObjectClass class;
00751     
00752     if ( (entry == NULL) || !XtIsSensitive((Widget) entry ) ) return;
00753     
00754     class = (SmeObjectClass) entry->object.widget_class;
00755     (class->sme_class.notify)( (Widget) entry );
00756 }
00757 
00758 /************************************************************
00759  *
00760  * Public Functions.
00761  *
00762  ************************************************************/
00763  
00764 /*      Function Name: XawSimpleMenuAddGlobalActions
00765  *      Description: adds the global actions to the simple menu widget.
00766  *      Arguments: app_con - the appcontext.
00767  *      Returns: none.
00768  */
00769 
00770 void
00771 #if NeedFunctionPrototypes
00772 XawSimpleMenuAddGlobalActions(XtAppContext app_con)
00773 #else
00774 XawSimpleMenuAddGlobalActions(app_con)
00775 XtAppContext app_con;
00776 #endif
00777 {
00778     XtInitializeWidgetClass(simpleMenuWidgetClass);
00779     XmuCallInitializers( app_con );
00780 } 
00781 
00782  
00783 /*      Function Name: XawSimpleMenuGetActiveEntry
00784  *      Description: Gets the currently active (set) entry.
00785  *      Arguments: w - the smw widget.
00786  *      Returns: the currently set entry or NULL if none is set.
00787  */
00788 
00789 Widget
00790 #if NeedFunctionPrototypes
00791 XawSimpleMenuGetActiveEntry(Widget w)
00792 #else
00793 XawSimpleMenuGetActiveEntry(w)
00794 Widget w;
00795 #endif
00796 {
00797     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00798 
00799     return( (Widget) smw->simple_menu.entry_set);
00800 } 
00801 
00802 /*      Function Name: XawSimpleMenuClearActiveEntry
00803  *      Description: Unsets the currently active (set) entry.
00804  *      Arguments: w - the smw widget.
00805  *      Returns: none.
00806  */
00807 
00808 void
00809 #if NeedFunctionPrototypes
00810 XawSimpleMenuClearActiveEntry(Widget w)
00811 #else
00812 XawSimpleMenuClearActiveEntry(w)
00813 Widget w;
00814 #endif
00815 {
00816     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00817 
00818     smw->simple_menu.entry_set = NULL;
00819 } 
00820 
00821 /************************************************************
00822  *
00823  * Private Functions.
00824  *
00825  ************************************************************/
00826 
00827 /*      Function Name: CreateLabel
00828  *      Description: Creates a the menu label.
00829  *      Arguments: w - the smw widget.
00830  *      Returns: none.
00831  * 
00832  * Creates the label object and makes sure it is the first child in
00833  * in the list.
00834  */
00835 
00836 static void
00837 CreateLabel(w)
00838 Widget w;
00839 {
00840     SimpleMenuWidget smw = (SimpleMenuWidget) w;
00841     Widget * child, * next_child;
00842     int i;
00843     Arg args[2];
00844 
00845     if ( (smw->simple_menu.label_string == NULL) ||
00846          (smw->simple_menu.label != NULL) ) {
00847         char error_buf[BUFSIZ];
00848 
00849         (void) sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
00850                 "label string is NULL", "label already exists", 
00851                 "no label is being created.");
00852         XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
00853         return;
00854     }
00855 
00856     XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
00857     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
00858     smw->simple_menu.label = (SmeObject) 
00859                               XtCreateManagedWidget("menuLabel", 
00860                                             smw->simple_menu.label_class, w,
00861                                             args, TWO);
00862 
00863     next_child = NULL;
00864     for (child = smw->composite.children + smw->composite.num_children,
00865          i = smw->composite.num_children ; i > 0 ; i--, child--) {
00866         if (next_child != NULL)
00867             *next_child = *child;
00868         next_child = child;
00869     }
00870     *child = (Widget) smw->simple_menu.label;
00871 }
00872 
00873 /*      Function Name: Layout
00874  *      Description: lays the menu entries out all nice and neat.
00875  *      Arguments: w - See below (+++)
00876  *                 width_ret, height_ret - The returned width and 
00877  *                                         height values.
00878  *      Returns: none.
00879  *
00880  * if width == NULL || height == NULL then it assumes the you do not care
00881  * about the return values, and just want a relayout.
00882  *
00883  * if this is not the case then it will set width_ret and height_ret
00884  * to be width and height that the child would get if it were layed out
00885  * at this time.
00886  *
00887  * +++ "w" can be the simple menu widget or any of its object children.
00888  */
00889 
00890 static void
00891 Layout(w, width_ret, height_ret)
00892 Widget w;
00893 Dimension *width_ret, *height_ret;
00894 {
00895     SmeObject current_entry, *entry;
00896     SimpleMenuWidget smw;
00897     Dimension width, height;
00898     Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
00899     Boolean allow_change_size;
00900     height = 0;
00901 
00902     if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
00903         smw = (SimpleMenuWidget) w;
00904         current_entry = NULL;
00905     }
00906     else {
00907         smw = (SimpleMenuWidget) XtParent(w);
00908         current_entry = (SmeObject) w;
00909     }
00910 
00911     allow_change_size = (!XtIsRealized((Widget)smw) ||
00912                          (smw->shell.allow_shell_resize));
00913 
00914     if ( smw->simple_menu.menu_height )
00915         height = smw->core.height;
00916     else
00917         if (do_layout) {
00918             height = smw->simple_menu.top_margin;
00919             ForAllChildren(smw, entry) {
00920                 if (!XtIsManaged( (Widget) *entry)) continue;
00921 
00922                 if ( (smw->simple_menu.row_height != 0) && 
00923                     (*entry != smw->simple_menu.label) ) 
00924                     (*entry)->rectangle.height = smw->simple_menu.row_height;
00925                 
00926                 (*entry)->rectangle.y = height;
00927                 (*entry)->rectangle.x = 0;
00928                 height += (*entry)->rectangle.height;
00929             }
00930             height += smw->simple_menu.bottom_margin;
00931         }
00932         else {
00933             if ((smw->simple_menu.row_height != 0) && 
00934                 (current_entry != smw->simple_menu.label) )
00935                 height = smw->simple_menu.row_height;
00936         }
00937     
00938     if (smw->simple_menu.menu_width)
00939         width = smw->core.width;
00940     else if ( allow_change_size )
00941         width = GetMenuWidth((Widget) smw, (Widget) current_entry);
00942     else
00943         width = smw->core.width;
00944 
00945     if (do_layout) {
00946         ForAllChildren(smw, entry)
00947             if (XtIsManaged( (Widget) *entry)) 
00948                 (*entry)->rectangle.width = width;
00949 
00950         if (allow_change_size)
00951             MakeSetValuesRequest((Widget) smw, width, height);
00952     }
00953     else {
00954         *width_ret = width;
00955         if (height != 0)
00956             *height_ret = height;
00957     }
00958 }
00959     
00960 /*      Function Name: AddPositionAction
00961  *      Description: Adds the XawPositionSimpleMenu action to the global
00962  *                   action list for this appcon.
00963  *      Arguments: app_con - the application context for this app.
00964  *                 data - NOT USED.
00965  *      Returns: none.
00966  */
00967 
00968 /* ARGSUSED */
00969 static void
00970 AddPositionAction(app_con, data)
00971 XtAppContext app_con;
00972 XPointer data;
00973 {
00974     static XtActionsRec pos_action[] = {
00975         { "XawPositionSimpleMenu", PositionMenuAction },
00976     };
00977 
00978     XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
00979 }
00980 
00981 /*      Function Name: FindMenu
00982  *      Description: Find the menu give a name and reference widget.
00983  *      Arguments: widget - reference widget.
00984  *                 name   - the menu widget's name.
00985  *      Returns: the menu widget or NULL.
00986  */
00987 
00988 static Widget 
00989 FindMenu(widget, name)
00990 Widget widget;
00991 String name;
00992 {
00993     Widget w, menu;
00994     
00995     for ( w = widget ; w != NULL ; w = XtParent(w) )
00996         if ( (menu = XtNameToWidget(w, name)) != NULL )
00997             return(menu);
00998     return(NULL);
00999 }
01000 
01001 /*      Function Name: PositionMenu
01002  *      Description: Places the menu
01003  *      Arguments: w - the simple menu widget.
01004  *                 location - a pointer the the position or NULL.
01005  *      Returns: none.
01006  */
01007 
01008 static void
01009 PositionMenu(w, location)
01010 Widget w;
01011 XPoint * location;
01012 {
01013     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01014     SmeObject entry;
01015     XPoint t_point;
01016     
01017     if (location == NULL) {
01018         Window junk1, junk2;
01019         int root_x, root_y, junkX, junkY;
01020         unsigned int junkM;
01021         
01022         location = &t_point;
01023         if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2, 
01024                           &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
01025             char error_buf[BUFSIZ];
01026             (void) sprintf(error_buf, "%s %s", "Xaw Simple Menu Widget:",
01027                     "Could not find location of mouse pointer");
01028             XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
01029             return;
01030         }
01031         location->x = (short) root_x;
01032         location->y = (short) root_y;
01033     }
01034     
01035     /*
01036      * The width will not be correct unless it is realized.
01037      */
01038     
01039     XtRealizeWidget(w);
01040     
01041     location->x -= (Position) w->core.width/2;
01042     
01043     if (smw->simple_menu.popup_entry == NULL)
01044         entry = smw->simple_menu.label;
01045     else
01046         entry = smw->simple_menu.popup_entry;
01047 
01048     if (entry != NULL)
01049         location->y -= entry->rectangle.y + entry->rectangle.height/2;
01050 
01051     MoveMenu(w, (Position) location->x, (Position) location->y);
01052 }
01053 
01054 /*      Function Name: MoveMenu
01055  *      Description: Actually moves the menu, may force it to
01056  *                   to be fully visable if menu_on_screen is TRUE.
01057  *      Arguments: w - the simple menu widget.
01058  *                 x, y - the current location of the widget.
01059  *      Returns: none 
01060  */
01061 
01062 static void
01063 MoveMenu(w, x, y)
01064 Widget w;
01065 Position x, y;
01066 {
01067     Arg arglist[2];
01068     Cardinal num_args = 0;
01069     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01070     
01071     if (smw->simple_menu.menu_on_screen) {
01072         int width = w->core.width + 2 * w->core.border_width;
01073         int height = w->core.height + 2 * w->core.border_width;
01074         
01075         if (x >= 0) {
01076             int scr_width = WidthOfScreen(XtScreen(w));
01077             if (x + width > scr_width)
01078                 x = scr_width - width;
01079         }
01080         if (x < 0) 
01081             x = 0;
01082         
01083         if (y >= 0) {
01084             int scr_height = HeightOfScreen(XtScreen(w));
01085             if (y + height > scr_height)
01086                 y = scr_height - height;
01087         }
01088         if (y < 0)
01089             y = 0;
01090     }
01091     
01092     XtSetArg(arglist[num_args], XtNx, x); num_args++;
01093     XtSetArg(arglist[num_args], XtNy, y); num_args++;
01094     XtSetValues(w, arglist, num_args);
01095 }
01096 
01097 /*      Function Name: ChangeCursorOnGrab
01098  *      Description: Changes the cursor on the active grab to the one
01099  *                   specified in out resource list.
01100  *      Arguments: w - the widget.
01101  *                 junk, garbage - ** NOT USED **.
01102  *      Returns: None.
01103  */
01104 
01105 /* ARGSUSED */
01106 static void
01107 ChangeCursorOnGrab(w, junk, garbage)
01108 Widget w;
01109 XtPointer junk, garbage;
01110 {
01111     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01112     
01113     /*
01114      * The event mask here is what is currently in the MIT implementation.
01115      * There really needs to be a way to get the value of the mask out
01116      * of the toolkit (CDP 5/26/89).
01117      */
01118     
01119     XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
01120                              smw->simple_menu.cursor, 
01121                              XtLastTimestampProcessed(XtDisplay(w)));
01122 }
01123 
01124 /*      Function Name: MakeSetValuesRequest
01125  *      Description: Makes a (possibly recursive) call to SetValues,
01126  *                   I take great pains to not go into an infinite loop.
01127  *      Arguments: w - the simple menu widget.
01128  *                 width, height - the size of the ask for.
01129  *      Returns: none
01130  */
01131 
01132 static void
01133 MakeSetValuesRequest(w, width, height)
01134 Widget w;
01135 Dimension width, height;
01136 {
01137     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01138     Arg arglist[2];
01139     Cardinal num_args = (Cardinal) 0;
01140     
01141     if ( !smw->simple_menu.recursive_set_values ) {
01142         if ( (smw->core.width != width) || (smw->core.height != height) ) {
01143             smw->simple_menu.recursive_set_values = TRUE;
01144             XtSetArg(arglist[num_args], XtNwidth, width);   num_args++;
01145             XtSetArg(arglist[num_args], XtNheight, height); num_args++;
01146             XtSetValues(w, arglist, num_args);
01147         }
01148         else if (XtIsRealized( (Widget) smw))
01149             Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
01150     }
01151     smw->simple_menu.recursive_set_values = FALSE;
01152 }
01153 
01154 /*      Function Name: GetMenuWidth
01155  *      Description: Sets the length of the widest entry in pixels.
01156  *      Arguments: w - the simple menu widget.
01157  *      Returns: width of menu.
01158  */
01159 
01160 static Dimension
01161 GetMenuWidth(w, w_ent)
01162 Widget w, w_ent;
01163 {
01164     SmeObject cur_entry = (SmeObject) w_ent;
01165     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01166     Dimension width, widest = (Dimension) 0;
01167     SmeObject * entry;
01168     
01169     if ( smw->simple_menu.menu_width ) 
01170         return(smw->core.width);
01171 
01172     ForAllChildren(smw, entry) {
01173         XtWidgetGeometry preferred;
01174 
01175         if (!XtIsManaged( (Widget) *entry)) continue;
01176         
01177         if (*entry != cur_entry) {
01178             XtQueryGeometry((Widget) *entry, (XtWidgetGeometry *)NULL, &preferred);
01179             
01180             if (preferred.request_mode & CWWidth)
01181                 width = preferred.width;
01182             else
01183                 width = (*entry)->rectangle.width;
01184         }
01185         else
01186             width = (*entry)->rectangle.width;
01187         
01188         if ( width > widest )
01189             widest = width;
01190     }
01191     
01192     return(widest);
01193 }
01194 
01195 /*      Function Name: GetMenuHeight
01196  *      Description: Sets the length of the widest entry in pixels.
01197  *      Arguments: w - the simple menu widget.
01198  *      Returns: width of menu.
01199  */
01200 
01201 static Dimension
01202 GetMenuHeight(w)
01203 Widget w;
01204 {
01205     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01206     SmeObject * entry;
01207     Dimension height;
01208     
01209     if (smw->simple_menu.menu_height)
01210         return(smw->core.height);
01211 
01212     height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
01213     
01214     if (smw->simple_menu.row_height == 0) {
01215         ForAllChildren(smw, entry) 
01216             if (XtIsManaged ((Widget) *entry)) 
01217                 height += (*entry)->rectangle.height;
01218     } else 
01219         height += smw->simple_menu.row_height * smw->composite.num_children;
01220         
01221     return(height);
01222 }
01223 
01224 /*      Function Name: GetEventEntry
01225  *      Description: Gets an entry given an event that has X and Y coords.
01226  *      Arguments: w - the simple menu widget.
01227  *                 event - the event.
01228  *      Returns: the entry that this point is in.
01229  */
01230 
01231 static SmeObject
01232 GetEventEntry(w, event)
01233 Widget w;
01234 XEvent * event;
01235 {
01236     Position x_loc = 0, y_loc = 0;
01237     SimpleMenuWidget smw = (SimpleMenuWidget) w;
01238     SmeObject * entry;
01239     
01240     switch (event->type) {
01241     case MotionNotify:
01242         x_loc = event->xmotion.x;
01243         y_loc = event->xmotion.y;
01244         break;
01245     case EnterNotify:
01246     case LeaveNotify:
01247         x_loc = event->xcrossing.x;
01248         y_loc = event->xcrossing.y;
01249         break;
01250     case ButtonPress:
01251     case ButtonRelease:
01252         x_loc = event->xbutton.x;
01253         y_loc = event->xbutton.y;
01254         break;
01255     default:
01256         XtAppError(XtWidgetToApplicationContext(w),
01257                    "Unknown event type in GetEventEntry().");
01258         break;
01259     }
01260     
01261     if ( (x_loc < 0) || (x_loc >= (int)smw->core.width) || (y_loc < 0) ||
01262         (y_loc >= (int)smw->core.height) )
01263         return(NULL);
01264     
01265     ForAllChildren(smw, entry) {
01266         if (!XtIsManaged ((Widget) *entry)) continue;
01267 
01268         if ( ((*entry)->rectangle.y < y_loc) &&
01269             ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) )
01270             if ( *entry == smw->simple_menu.label )
01271                 return(NULL);   /* cannot select the label. */
01272             else
01273                 return(*entry);
01274     }
01275     
01276     return(NULL);
01277 }

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1