#if ( !defined(lint) && !defined(SABER) )
static char Xrcsid[] = "$XConsortium: SimpleMenu.c,v 1.32 89/12/11 15:01:50 kit Exp $";
#endif
/*
* Copyright 1989 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. M.I.T. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* SimpleMenu.c - Source code file for SimpleMenu widget.
*
* Date: April 3, 1989
*
* By: Chris D. Peterson
* MIT X Consortium
* kit@expo.lcs.mit.edu
*/
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <./Xaw3_1XawInit.h>
#include <./Xaw3_1SimpleMenP.h>
#include <./Xaw3_1SmeBSB.h>
#include <./Xaw3_1Cardinals.h>
#include <X11/Xmu/Initer.h>
#include <X11/Xmu/CharSet.h>
#define streq(a, b) ( strcmp((a), (b)) == 0 )
#define offset(field) XtOffset(SimpleMenuWidget, simple_menu.field)
static XtResource resources[] = {
/*
* Label Resources.
*/
{XtNlabel, XtCLabel, XtRString, sizeof(String),
offset(label_string), XtRString, NULL},
{XtNlabelClass, XtCLabelClass, XtRPointer, sizeof(WidgetClass),
offset(label_class), XtRImmediate, (caddr_t) NULL},
/*
* Layout Resources.
*/
{XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
offset(row_height), XtRImmediate, (caddr_t) 0},
{XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
offset(top_margin), XtRImmediate, (caddr_t) 0},
{XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
offset(bottom_margin), XtRImmediate, (caddr_t) 0},
/*
* Misc. Resources
*/
{ XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
XtOffset(SimpleMenuWidget, shell.allow_shell_resize),
XtRImmediate, (XtPointer) TRUE },
{XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
offset(cursor), XtRImmediate, (caddr_t) None},
{XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
offset(menu_on_screen), XtRImmediate, (caddr_t) TRUE},
{XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
offset(popup_entry), XtRWidget, NULL},
{XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
offset(backing_store),
XtRImmediate, (caddr_t) (Always + WhenMapped + NotUseful)},
};
#undef offset
static char defaultTranslations[] =
"<EnterWindow>: highlight() \n\
<LeaveWindow>: unhighlight() \n\
<BtnMotion>: highlight() \n\
<BtnUp>: MenuPopdown() notify() unhighlight()";
/*
* Semi Public function definitions.
*/
static void Redisplay(), Realize(), Resize(), ChangeManaged();
static void Initialize(), ClassInitialize(), ClassPartInitialize();
static Boolean SetValues(), SetValuesHook();
static XtGeometryResult GeometryManager();
/*
* Action Routine Definitions
*/
static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
/*
* Private Function Definitions.
*/
static void MakeSetValuesRequest(), CreateLabel(), Layout();
static void AddPositionAction(), PositionMenu(), ChangeCursorOnGrab();
static Dimension GetMenuWidth(), GetMenuHeight();
static Widget FindMenu();
static SmeObject GetEventEntry();
static XtActionsRec actionsList[] =
{
{"notify", Notify},
{"highlight", Highlight},
{"unhighlight", Unhighlight},
};
CompositeClassExtensionRec extension_rec = {
/* next_extension */ NULL,
/* record_type */ NULLQUARK,
/* version */ XtCompositeExtensionVersion,
/* record_size */ sizeof(CompositeClassExtensionRec),
/* accepts_objects */ TRUE,
};
#define superclass (&overrideShellClassRec)
SimpleMenuClassRec simpleMenuClassRec = {
{
/* superclass */ (WidgetClass) superclass,
/* class_name */ "SimpleMenu",
/* size */ sizeof(SimpleMenuRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize*/ ClassPartInitialize,
/* Class init'ed */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ resources,
/* resource_count */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave*/ TRUE,
/* visible_interest */ FALSE,
/* destroy */ NULL,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ SetValuesHook,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* intrinsics version */ XtVersion,
/* callback offsets */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ NULL,
/* display_accelerator*/ NULL,
/* extension */ NULL
},{
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ XtInheritInsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
},{
/* Shell extension */ NULL
},{
/* Override extension */ NULL
},{
/* Simple Menu extension*/ NULL
}
};
WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
/************************************************************
*
* Semi-Public Functions.
*
************************************************************/
/* Function Name: ClassInitialize
* Description: Class Initialize routine, called only once.
* Arguments: none.
* Returns: none.
*/
static void
ClassInitialize()
{
XawInitializeWidgetSet();
XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
NULL, 0 );
XmuAddInitializer( AddPositionAction, NULL);
}
/* Function Name: ClassInitialize
* Description: Class Part Initialize routine, called for every
* subclass. Makes sure that the subclasses pick up
* the extension record.
* Arguments: wc - the widget class of the subclass.
* Returns: none.
*/
static void
ClassPartInitialize(wc)
WidgetClass wc;
{
SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
/*
* Make sure that our subclass gets the extension rec too.
*/
extension_rec.next_extension = smwc->composite_class.extension;
smwc->composite_class.extension = (caddr_t) &extension_rec;
}
/* Function Name: Initialize
* Description: Initializes the simple menu widget
* Arguments: request - the widget requested by the argument list.
* new - the new widget with both resource and non
* resource values.
* Returns: none.
*/
/* ARGSUSED */
static void
Initialize(request, new)
Widget request, new;
{
SimpleMenuWidget smw = (SimpleMenuWidget) new;
XmuCallInitializers(XtWidgetToApplicationContext(new));
if (smw->simple_menu.label_class == NULL)
smw->simple_menu.label_class = smeBSBObjectClass;
smw->simple_menu.label = NULL;
smw->simple_menu.entry_set = NULL;
smw->simple_menu.recursive_set_values = FALSE;
if (smw->simple_menu.label_string != NULL)
CreateLabel(new);
smw->simple_menu.menu_width = TRUE;
if (smw->core.width == 0) {
smw->simple_menu.menu_width = FALSE;
smw->core.width = GetMenuWidth(new, NULL);
}
smw->simple_menu.menu_height = TRUE;
if (smw->core.height == 0) {
smw->simple_menu.menu_height = FALSE;
smw->core.height = GetMenuHeight(new);
}
/*
* Add a popup_callback routine for changing the cursor.
*/
XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, NULL);
}
/* Function Name: Redisplay
* Description: Redisplays the contents of the widget.
* Arguments: w - the simple menu widget.
* event - the X event that caused this redisplay.
* region - the region the needs to be repainted.
* Returns: none.
*/
/* ARGSUSED */
static void
Redisplay(w, event, region)
Widget w;
XEvent * event;
Region region;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject * entry;
SmeObjectClass class;
if (region == NULL)
XClearWindow(XtDisplay(w), XtWindow(w));
/*
* Check and Paint each of the entries - including the label.
*/
ForAllChildren(smw, entry) {
if (!XtIsManaged ( (Widget) *entry)) continue;
if (region != NULL)
switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
(int) (*entry)->rectangle.y,
(unsigned int) (*entry)->rectangle.width,
(unsigned int) (*entry)->rectangle.height)) {
case RectangleIn:
case RectanglePart:
break;
default:
continue;
}
class = (SmeObjectClass) (*entry)->object.widget_class;
if (class->rect_class.expose != NULL)
(class->rect_class.expose)( (Widget) *entry, NULL, NULL);
}
}
/* Function Name: Realize
* Description: Realizes the widget.
* Arguments: w - the simple menu widget.
* mask - value mask for the window to create.
* attrs - attributes for the window to create.
* Returns: none
*/
static void
Realize(w, mask, attrs)
Widget w;
XtValueMask * mask;
XSetWindowAttributes * attrs;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
attrs->cursor = smw->simple_menu.cursor;
*mask |= CWCursor;
if ((smw->simple_menu.backing_store == Always) ||
(smw->simple_menu.backing_store == NotUseful) ||
(smw->simple_menu.backing_store == WhenMapped) ) {
*mask |= CWBackingStore;
attrs->backing_store = smw->simple_menu.backing_store;
}
else
*mask &= ~CWBackingStore;
(*superclass->core_class.realize) (w, mask, attrs);
}
/* Function Name: Resize
* Description: Handle the menu being resized bigger.
* Arguments: w - the simple menu widget.
* Returns: none.
*/
static void
Resize(w)
Widget w;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject * entry;
if ( !XtIsRealized(w) ) return;
ForAllChildren(smw, entry) /* reset width of all entries. */
if (XtIsManaged( (Widget) *entry))
(*entry)->rectangle.width = smw->core.width;
Redisplay(w, (XEvent *) NULL, (Region) NULL);
}
/* Function Name: SetValues
* Description: Relayout the menu when one of the resources is changed.
* Arguments: current - current state of the widget.
* request - what was requested.
* new - what the widget will become.
* Returns: none
*/
/* ARGSUSED */
static Boolean
SetValues(current, request, new)
Widget current, request, new;
{
SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
Boolean ret_val = FALSE, layout = FALSE;
if (!XtIsRealized(current)) return(FALSE);
if (!smw_new->simple_menu.recursive_set_values) {
if (smw_new->core.width != smw_old->core.width) {
smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
layout = TRUE;
}
if (smw_new->core.height != smw_old->core.height) {
smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
layout = TRUE;
}
}
if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
XDefineCursor(XtDisplay(new),
XtWindow(new), smw_new->simple_menu.cursor);
if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string)
if (smw_new->simple_menu.label_string == NULL) /* Destroy. */
XtDestroyWidget((Widget)smw_old->simple_menu.label);
else if (smw_old->simple_menu.label_string == NULL) /* Create. */
CreateLabel(new);
else { /* Change. */
Arg args[1];
XtSetArg(args[0], XtNlabel, smw_new->simple_menu.label_string);
XtSetValues((Widget)smw_new->simple_menu.label, args, ONE);
}
if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
XtAppWarning(XtWidgetToApplicationContext(new),
"No Dynamic class change of the SimpleMenu Label.");
if ((smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin) ||
(smw_old->simple_menu.bottom_margin !=
smw_new->simple_menu.bottom_margin) /* filler................. */ ) {
layout = TRUE;
ret_val = TRUE;
}
if (layout)
Layout(new, NULL, NULL);
return(ret_val);
}
/* Function Name: SetValuesHook
* Description: To handle a special case, this is passed the
* actual arguments.
* Arguments: w - the menu widget.
* arglist - the argument list passed to XtSetValues.
* num_args - the number of args.
* Returns: none
*/
/*
* If the user actually passed a width and height to the widget
* then this MUST be used, rather than our newly calculated width and
* height.
*/
static Boolean
SetValuesHook(w, arglist, num_args)
Widget w;
ArgList arglist;
Cardinal *num_args;
{
register Cardinal i;
Dimension width, height;
width = w->core.width;
height = w->core.height;
for ( i = 0 ; i < *num_args ; i++) {
if ( streq(arglist[i].name, XtNwidth) )
width = (Dimension) arglist[i].value;
if ( streq(arglist[i].name, XtNheight) )
height = (Dimension) arglist[i].value;
}
if ((width != w->core.width) || (height != w->core.height))
MakeSetValuesRequest(w, width, height);
return(FALSE);
}
/************************************************************
*
* Geometry Management routines.
*
************************************************************/
/* Function Name: GeometryManager
* Description: This is the SimpleMenu Widget's Geometry Manager.
* Arguments: w - the Menu Entry making the request.
* request - requested new geometry.
* reply - the allowed geometry.
* Returns: XtGeometry{Yes, No, Almost}.
*/
static XtGeometryResult
GeometryManager(w, request, reply)
Widget w;
XtWidgetGeometry * request, * reply;
{
SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
SmeObject entry = (SmeObject) w;
XtGeometryMask mode = request->request_mode;
XtGeometryResult answer;
Dimension old_height, old_width;
if ( !(mode & CWWidth) && !(mode & CWHeight) )
return(XtGeometryNo);
reply->width = request->width;
reply->height = request->height;
old_width = entry->rectangle.width;
old_height = entry->rectangle.height;
Layout(w, &(reply->width), &(reply->height) );
/*
* Since we are an override shell and have no parent there is no one to
* ask to see if this geom change is okay, so I am just going to assume
* we can do whatever we want. If you subclass be very careful with this
* assumption, it could bite you.
*
* Chris D. Peterson - Sept. 1989.
*/
if ( (reply->width == request->width) &&
(reply->height == request->height) ) {
if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
entry->rectangle.width = old_width;
entry->rectangle.height = old_height;
}
else {
Layout(( Widget) smw, NULL, NULL);
}
answer = XtGeometryDone;
}
else {
entry->rectangle.width = old_width;
entry->rectangle.height = old_height;
if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
((reply->height == request->height) && !(mode & CWWidth)) ||
((reply->width == request->width) &&
(reply->height == request->height)) )
answer = XtGeometryNo;
else {
answer = XtGeometryAlmost;
reply->request_mode = 0;
if (reply->width != request->width)
reply->request_mode |= CWWidth;
if (reply->height != request->height)
reply->request_mode |= CWHeight;
}
}
return(answer);
}
/* Function Name: ChangeManaged
* Description: called whenever a new child is managed.
* Arguments: w - the simple menu widget.
* Returns: none.
*/
static void
ChangeManaged(w)
Widget w;
{
Layout(w, NULL, NULL);
}
/************************************************************
*
* Global Action Routines.
*
* These actions routines will be added to the application's
* global action list.
*
************************************************************/
/* Function Name: PositionMenuAction
* Description: Positions the simple menu widget.
* Arguments: w - a widget (no the simple menu widget.)
* event - the event that caused this action.
* params, num_params - parameters passed to the routine.
* we expect the name of the menu here.
* Returns: none
*/
/* ARGSUSED */
static void
PositionMenuAction(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
Widget menu;
XPoint loc;
if (*num_params != 1) {
char error_buf[BUFSIZ];
sprintf(error_buf, "%s %s",
"Xaw - SimpleMenuWidget: position menu action expects only one",
"parameter which is the name of the menu.");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
if ( (menu = FindMenu(w, params[0])) == NULL) {
char error_buf[BUFSIZ];
sprintf(error_buf, "%s '%s'",
"Xaw - SimpleMenuWidget: could not find menu named: ", params[0]);
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
switch (event->type) {
case ButtonPress:
case ButtonRelease:
loc.x = event->xbutton.x_root;
loc.y = event->xbutton.y_root;
PositionMenu(menu, &loc);
break;
case EnterNotify:
case LeaveNotify:
loc.x = event->xcrossing.x_root;
loc.y = event->xcrossing.y_root;
PositionMenu(menu, &loc);
break;
case MotionNotify:
loc.x = event->xmotion.x_root;
loc.y = event->xmotion.y_root;
PositionMenu(menu, &loc);
break;
default:
PositionMenu(menu, NULL);
break;
}
}
/************************************************************
*
* Widget Action Routines.
*
************************************************************/
/* Function Name: Unhighlight
* Description: Unhighlights current entry.
* Arguments: w - the simple menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
/* ARGSUSED */
static void
Unhighlight(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject entry = smw->simple_menu.entry_set;
SmeObjectClass class;
if ( entry == NULL) return;
smw->simple_menu.entry_set = NULL;
class = (SmeObjectClass) entry->object.widget_class;
(class->sme_class.unhighlight) ( (Widget) entry);
}
/* Function Name: Highlight
* Description: Highlights current entry.
* Arguments: w - the simple menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
/* ARGSUSED */
static void
Highlight(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject entry;
SmeObjectClass class;
if ( !XtIsSensitive(w) ) return;
entry = GetEventEntry(w, event);
if (entry == smw->simple_menu.entry_set) return;
Unhighlight(w, event, params, num_params);
if (entry == NULL) return;
if ( !XtIsSensitive( (Widget) entry)) {
smw->simple_menu.entry_set = NULL;
return;
}
smw->simple_menu.entry_set = entry;
class = (SmeObjectClass) entry->object.widget_class;
(class->sme_class.highlight) ( (Widget) entry);
}
/* Function Name: Notify
* Description: Notify user of current entry.
* Arguments: w - the simple menu widget.
* event - the event that caused this action.
* params, num_params - ** NOT USED **
* Returns: none
*/
/* ARGSUSED */
static void
Notify(w, event, params, num_params)
Widget w;
XEvent * event;
String * params;
Cardinal * num_params;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject entry = smw->simple_menu.entry_set;
SmeObjectClass class;
if ( (entry == NULL) || !XtIsSensitive((Widget) entry) ) return;
class = (SmeObjectClass) entry->object.widget_class;
(class->sme_class.notify)( (Widget) entry );
}
/************************************************************
*
* Public Functions.
*
************************************************************/
/* Function Name: XawSimpleMenuAddGlobalActions
* Description: adds the global actions to the simple menu widget.
* Arguments: app_con - the appcontext.
* Returns: none.
*/
void
XawSimpleMenuAddGlobalActions(app_con)
XtAppContext app_con;
{
XtInitializeWidgetClass(simpleMenuWidgetClass);
XmuCallInitializers( app_con );
}
/* Function Name: XawSimpleMenuGetActiveEntry
* Description: Gets the currently active (set) entry.
* Arguments: w - the smw widget.
* Returns: the currently set entry or NULL if none is set.
*/
Widget
XawSimpleMenuGetActiveEntry(w)
Widget w;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
return( (Widget) smw->simple_menu.entry_set);
}
/* Function Name: XawSimpleMenuClearActiveEntry
* Description: Unsets the currently active (set) entry.
* Arguments: w - the smw widget.
* Returns: none.
*/
void
XawSimpleMenuClearActiveEntry(w)
Widget w;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
smw->simple_menu.entry_set = NULL;
}
/************************************************************
*
* Private Functions.
*
************************************************************/
/* Function Name: CreateLabel
* Description: Creates a the menu label.
* Arguments: w - the smw widget.
* Returns: none.
*
* Creates the label object and makes sure it is the first child in
* in the list.
*/
static void
CreateLabel(w)
Widget w;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
register Widget * child, * next_child;
register int i;
Arg args[2];
if ( (smw->simple_menu.label_string == NULL) ||
(smw->simple_menu.label != NULL) ) {
char error_buf[BUFSIZ];
sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
"label string is NULL", "label already exists",
"no label is being created.");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
XtSetArg(args[1], XtNjustify, XtJustifyCenter);
smw->simple_menu.label = (SmeObject)
XtCreateManagedWidget("menuLabel",
smw->simple_menu.label_class, w,
args, TWO);
next_child = NULL;
for (child = smw->composite.children + smw->composite.num_children,
i = smw->composite.num_children ; i > 0 ; i--, child--) {
if (next_child != NULL)
*next_child = *child;
next_child = child;
}
*child = (Widget) smw->simple_menu.label;
}
/* Function Name: Layout
* Description: lays the menu entries out all nice and neat.
* Arguments: w - See below (+++)
* width_ret, height_ret - The returned width and
* height values.
* Returns: none.
*
* if width == NULL || height == NULL then it assumes the you do not care
* about the return values, and just want a relayout.
*
* if this is not the case then it will set width_ret and height_ret
* to be width and height that the child would get if it were layed out
* at this time.
*
* +++ "w" can be the simple menu widget or any of its object children.
*/
static void
Layout(w, width_ret, height_ret)
Widget w;
Dimension *width_ret, *height_ret;
{
SmeObject current_entry, *entry;
SimpleMenuWidget smw;
Dimension width, height;
Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
Boolean allow_change_size;
height = 0;
if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
smw = (SimpleMenuWidget) w;
current_entry = NULL;
}
else {
smw = (SimpleMenuWidget) XtParent(w);
current_entry = (SmeObject) w;
}
allow_change_size = (!XtIsRealized((Widget)smw) ||
(smw->shell.allow_shell_resize));
if ( smw->simple_menu.menu_height )
height = smw->core.height;
else
if (do_layout) {
height = smw->simple_menu.top_margin;
ForAllChildren(smw, entry) {
if (!XtIsManaged( (Widget) *entry)) continue;
if ( (smw->simple_menu.row_height != 0) &&
(*entry != smw->simple_menu.label) )
(*entry)->rectangle.height = smw->simple_menu.row_height;
(*entry)->rectangle.y = height;
(*entry)->rectangle.x = 0;
height += (*entry)->rectangle.height;
}
height += smw->simple_menu.bottom_margin;
}
else {
if ((smw->simple_menu.row_height != 0) &&
(current_entry != smw->simple_menu.label) )
height = smw->simple_menu.row_height;
}
if (smw->simple_menu.menu_width)
width = smw->core.width;
else if ( allow_change_size )
width = GetMenuWidth((Widget) smw, (Widget) current_entry);
else
width = smw->core.width;
if (do_layout) {
ForAllChildren(smw, entry)
if (XtIsManaged( (Widget) *entry))
(*entry)->rectangle.width = width;
if (allow_change_size)
MakeSetValuesRequest((Widget) smw, width, height);
}
else {
*width_ret = width;
if (height != 0)
*height_ret = height;
}
}
/* Function Name: AddPositionAction
* Description: Adds the XawPositionSimpleMenu action to the global
* action list for this appcon.
* Arguments: app_con - the application context for this app.
* data - NOT USED.
* Returns: none.
*/
/* ARGSUSED */
static void
AddPositionAction(app_con, data)
XtAppContext app_con;
caddr_t data;
{
static XtActionsRec pos_action[] = {
{ "XawPositionSimpleMenu", PositionMenuAction },
};
XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
}
/* Function Name: FindMenu
* Description: Find the menu give a name and reference widget.
* Arguments: widget - reference widget.
* name - the menu widget's name.
* Returns: the menu widget or NULL.
*/
static Widget
FindMenu(widget, name)
Widget widget;
String name;
{
register Widget w, menu;
for ( w = widget ; w != NULL ; w = XtParent(w) )
if ( (menu = XtNameToWidget(w, name)) != NULL )
return(menu);
return(NULL);
}
/* Function Name: PositionMenu
* Description: Places the menu
* Arguments: w - the simple menu widget.
* location - a pointer the the position or NULL.
* Returns: none.
*/
static void
PositionMenu(w, location)
Widget w;
XPoint * location;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject entry;
XPoint t_point;
static void MoveMenu();
if (location == NULL) {
Window junk1, junk2;
int root_x, root_y, junkX, junkY;
unsigned int junkM;
location = &t_point;
if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2,
&root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
char error_buf[BUFSIZ];
sprintf(error_buf, "%s %s", "Xaw - SimpleMenuWidget:",
"Could not find location of mouse pointer");
XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
return;
}
location->x = (short) root_x;
location->y = (short) root_y;
}
/*
* The width will not be correct unless it is realized.
*/
XtRealizeWidget(w);
location->x -= (Position) w->core.width/2;
if (smw->simple_menu.popup_entry == NULL)
entry = smw->simple_menu.label;
else
entry = smw->simple_menu.popup_entry;
if (entry != NULL)
location->y -= entry->rectangle.y + entry->rectangle.height/2;
MoveMenu(w, (Position) location->x, (Position) location->y);
}
/* Function Name: MoveMenu
* Description: Actually moves the menu, may force it to
* to be fully visable if menu_on_screen is TRUE.
* Arguments: w - the simple menu widget.
* x, y - the current location of the widget.
* Returns: none
*/
static void
MoveMenu(w, x, y)
Widget w;
Position x, y;
{
Arg arglist[2];
Cardinal num_args = 0;
SimpleMenuWidget smw = (SimpleMenuWidget) w;
if (smw->simple_menu.menu_on_screen) {
int width = w->core.width + 2 * w->core.border_width;
int height = w->core.height + 2 * w->core.border_width;
if (x < 0)
x = 0;
else {
int scr_width = WidthOfScreen(XtScreen(w));
if (x + width > scr_width)
x = scr_width - width;
}
if (y < 0)
y = 0;
else {
int scr_height = HeightOfScreen(XtScreen(w));
if (y + height > scr_height)
y = scr_height - height;
}
}
XtSetArg(arglist[num_args], XtNx, x); num_args++;
XtSetArg(arglist[num_args], XtNy, y); num_args++;
XtSetValues(w, arglist, num_args);
}
/* Function Name: ChangeCursorOnGrab
* Description: Changes the cursor on the active grab to the one
* specified in out resource list.
* Arguments: w - the widget.
* junk, garbage - ** NOT USED **.
* Returns: None.
*/
/* ARGSUSED */
static void
ChangeCursorOnGrab(w, junk, garbage)
Widget w;
caddr_t junk, garbage;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
/*
* The event mask here is what is currently in the MIT implementation.
* There really needs to be a way to get the value of the mask out
* of the toolkit (CDP 5/26/89).
*/
XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
smw->simple_menu.cursor, CurrentTime);
}
/* Function Name: MakeSetValuesRequest
* Description: Makes a (possibly recursive) call to SetValues,
* I take great pains to not go into an infinite loop.
* Arguments: w - the simple menu widget.
* width, height - the size of the ask for.
* Returns: none
*/
static void
MakeSetValuesRequest(w, width, height)
Widget w;
Dimension width, height;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
Arg arglist[2];
Cardinal num_args = (Cardinal) 0;
if ( !smw->simple_menu.recursive_set_values ) {
if ( (smw->core.width != width) || (smw->core.height != height) ) {
smw->simple_menu.recursive_set_values = TRUE;
XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
XtSetArg(arglist[num_args], XtNheight, height); num_args++;
XtSetValues(w, arglist, num_args);
}
else if (XtIsRealized( (Widget) smw))
Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
}
smw->simple_menu.recursive_set_values = FALSE;
}
/* Function Name: GetMenuWidth
* Description: Sets the length of the widest entry in pixels.
* Arguments: w - the simple menu widget.
* Returns: width of menu.
*/
static Dimension
GetMenuWidth(w, w_ent)
Widget w, w_ent;
{
SmeObject cur_entry = (SmeObject) w_ent;
SimpleMenuWidget smw = (SimpleMenuWidget) w;
Dimension width, widest = (Dimension) 0;
SmeObject * entry;
if ( smw->simple_menu.menu_width )
return(smw->core.width);
ForAllChildren(smw, entry) {
XtWidgetGeometry preferred;
if (!XtIsManaged( (Widget) *entry)) continue;
if (*entry != cur_entry) {
XtQueryGeometry((Widget)*entry, NULL, &preferred);
if (preferred.request_mode & CWWidth)
width = preferred.width;
else
width = (*entry)->rectangle.width;
}
else
width = (*entry)->rectangle.width;
if ( width > widest )
widest = width;
}
return(widest);
}
/* Function Name: GetMenuHeight
* Description: Sets the length of the widest entry in pixels.
* Arguments: w - the simple menu widget.
* Returns: width of menu.
*/
static Dimension
GetMenuHeight(w)
Widget w;
{
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject * entry;
Dimension height;
if (smw->simple_menu.menu_height)
return(smw->core.height);
height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
if (smw->simple_menu.row_height == 0)
ForAllChildren(smw, entry)
if (XtIsManaged ((Widget) *entry))
height += (*entry)->rectangle.height;
else
height += smw->simple_menu.row_height * smw->composite.num_children;
return(height);
}
/* Function Name: GetEventEntry
* Description: Gets an entry given an event that has X and Y coords.
* Arguments: w - the simple menu widget.
* event - the event.
* Returns: the entry that this point is in.
*/
static SmeObject
GetEventEntry(w, event)
Widget w;
XEvent * event;
{
Position x_loc, y_loc;
SimpleMenuWidget smw = (SimpleMenuWidget) w;
SmeObject * entry;
switch (event->type) {
case MotionNotify:
x_loc = event->xmotion.x;
y_loc = event->xmotion.y;
break;
case EnterNotify:
case LeaveNotify:
x_loc = event->xcrossing.x;
y_loc = event->xcrossing.y;
break;
case ButtonPress:
case ButtonRelease:
x_loc = event->xbutton.x;
y_loc = event->xbutton.y;
break;
default:
XtAppError(XtWidgetToApplicationContext(w),
"Unknown event type in GetEventEntry().");
break;
}
if ( (x_loc < 0) || (x_loc >= smw->core.width) || (y_loc < 0) ||
(y_loc >= smw->core.height) )
return(NULL);
ForAllChildren(smw, entry) {
if (!XtIsManaged ((Widget) *entry)) continue;
if ( ((*entry)->rectangle.y < y_loc) &&
((*entry)->rectangle.y + (*entry)->rectangle.height > y_loc) )
if ( *entry == smw->simple_menu.label )
return(NULL); /* cannot select the label. */
else
return(*entry);
}
return(NULL);
}