SimpleMenu.c revision 749
749N/A/* $XConsortium: SimpleMenu.c,v 1.44 94/04/17 20:12:45 kaleb Exp $ */
749N/A
749N/A/*
749N/ACopyright (c) 1989, 1994 X Consortium
749N/A
749N/APermission is hereby granted, free of charge, to any person obtaining a copy
749N/Aof this software and associated documentation files (the "Software"), to deal
749N/Ain the Software without restriction, including without limitation the rights
749N/Ato use, copy, modify, merge, publish, distribute, sublicense, and/or sell
749N/Acopies of the Software, and to permit persons to whom the Software is
749N/Afurnished to do so, subject to the following conditions:
749N/A
749N/AThe above copyright notice and this permission notice shall be included in
749N/Aall copies or substantial portions of the Software.
749N/A
749N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
749N/AIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
749N/AFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
749N/AX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
749N/AAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
749N/ACONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
749N/A
749N/AExcept as contained in this notice, the name of the X Consortium shall not be
749N/Aused in advertising or otherwise to promote the sale, use or other dealings
749N/Ain this Software without prior written authorization from the X Consortium.
749N/A */
749N/A
749N/A/*
749N/A * SimpleMenu.c - Source code file for SimpleMenu widget.
749N/A *
749N/A * Date: April 3, 1989
749N/A *
749N/A * By: Chris D. Peterson
749N/A * MIT X Consortium
749N/A * kit@expo.lcs.mit.edu
749N/A */
749N/A
749N/A#include <stdio.h>
749N/A#include <X11/IntrinsicP.h>
749N/A#include <X11/StringDefs.h>
749N/A
749N/A#include <X11/Xaw/XawInit.h>
749N/A#include <X11/Xaw/SimpleMenP.h>
749N/A#include <X11/Xaw/SmeBSB.h>
749N/A#include <X11/Xaw/Cardinals.h>
749N/A
749N/A#include <X11/Xmu/Initer.h>
749N/A#include <X11/Xmu/CharSet.h>
749N/A
749N/A#define streq(a, b) ( strcmp((a), (b)) == 0 )
749N/A
749N/A#define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field)
749N/A
749N/Astatic XtResource resources[] = {
749N/A
749N/A/*
749N/A * Label Resources.
749N/A */
749N/A
749N/A {XtNlabel, XtCLabel, XtRString, sizeof(String),
749N/A offset(label_string), XtRString, NULL},
749N/A {XtNlabelClass, XtCLabelClass, XtRPointer, sizeof(WidgetClass),
749N/A offset(label_class), XtRImmediate, (XtPointer) NULL},
749N/A
749N/A/*
749N/A * Layout Resources.
749N/A */
749N/A
749N/A {XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
749N/A offset(row_height), XtRImmediate, (XtPointer) 0},
749N/A {XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
749N/A offset(top_margin), XtRImmediate, (XtPointer) 0},
749N/A {XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
749N/A offset(bottom_margin), XtRImmediate, (XtPointer) 0},
749N/A
749N/A/*
749N/A * Misc. Resources
749N/A */
749N/A
749N/A { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
749N/A XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
749N/A XtRImmediate, (XtPointer) TRUE },
749N/A {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
749N/A offset(cursor), XtRImmediate, (XtPointer) None},
749N/A {XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
749N/A offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
749N/A {XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
749N/A offset(popup_entry), XtRWidget, NULL},
749N/A {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
749N/A offset(backing_store),
749N/A XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
749N/A};
749N/A#undef offset
749N/A
749N/Astatic char defaultTranslations[] =
749N/A "<EnterWindow>: highlight() \n\
749N/A <LeaveWindow>: unhighlight() \n\
749N/A <BtnMotion>: highlight() \n\
749N/A <BtnUp>: MenuPopdown() notify() unhighlight()";
749N/A
749N/A/*
749N/A * Semi Public function definitions.
749N/A */
749N/A
749N/Astatic void Redisplay(), Realize(), Resize(), ChangeManaged();
749N/Astatic void Initialize(), ClassInitialize(), ClassPartInitialize();
749N/Astatic Boolean SetValues(), SetValuesHook();
749N/Astatic XtGeometryResult GeometryManager();
749N/A
749N/A/*
749N/A * Action Routine Definitions
749N/A */
749N/A
749N/Astatic void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
749N/A
749N/A/*
749N/A * Private Function Definitions.
749N/A */
749N/A
749N/Astatic void MakeSetValuesRequest(), CreateLabel(), Layout();
749N/Astatic void AddPositionAction(), PositionMenu(), ChangeCursorOnGrab();
749N/Astatic Dimension GetMenuWidth(), GetMenuHeight();
749N/Astatic Widget FindMenu();
749N/Astatic SmeObject GetEventEntry();
749N/Astatic void MoveMenu();
749N/A
749N/Astatic XtActionsRec actionsList[] =
749N/A{
749N/A {"notify", Notify},
749N/A {"highlight", Highlight},
749N/A {"unhighlight", Unhighlight},
749N/A};
749N/A
749N/Astatic CompositeClassExtensionRec extension_rec = {
749N/A /* next_extension */ NULL,
749N/A /* record_type */ NULLQUARK,
749N/A /* version */ XtCompositeExtensionVersion,
749N/A /* record_size */ sizeof(CompositeClassExtensionRec),
749N/A /* accepts_objects */ TRUE,
749N/A};
749N/A
749N/A#define superclass (&overrideShellClassRec)
749N/A
749N/ASimpleMenuClassRec simpleMenuClassRec = {
749N/A {
749N/A /* superclass */ (WidgetClass) superclass,
749N/A /* class_name */ "SimpleMenu",
749N/A /* size */ sizeof(SimpleMenuRec),
749N/A /* class_initialize */ ClassInitialize,
749N/A /* class_part_initialize*/ ClassPartInitialize,
749N/A /* Class init'ed */ FALSE,
749N/A /* initialize */ Initialize,
749N/A /* initialize_hook */ NULL,
749N/A /* realize */ Realize,
749N/A /* actions */ actionsList,
749N/A /* num_actions */ XtNumber(actionsList),
749N/A /* resources */ resources,
749N/A /* resource_count */ XtNumber(resources),
749N/A /* xrm_class */ NULLQUARK,
749N/A /* compress_motion */ TRUE,
749N/A /* compress_exposure */ TRUE,
749N/A /* compress_enterleave*/ TRUE,
749N/A /* visible_interest */ FALSE,
749N/A /* destroy */ NULL,
749N/A /* resize */ Resize,
749N/A /* expose */ Redisplay,
749N/A /* set_values */ SetValues,
749N/A /* set_values_hook */ SetValuesHook,
749N/A /* set_values_almost */ XtInheritSetValuesAlmost,
749N/A /* get_values_hook */ NULL,
749N/A /* accept_focus */ NULL,
749N/A /* intrinsics version */ XtVersion,
749N/A /* callback offsets */ NULL,
749N/A /* tm_table */ defaultTranslations,
749N/A /* query_geometry */ NULL,
749N/A /* display_accelerator*/ NULL,
749N/A /* extension */ NULL
749N/A },{
749N/A /* geometry_manager */ GeometryManager,
749N/A /* change_managed */ ChangeManaged,
749N/A /* insert_child */ XtInheritInsertChild,
749N/A /* delete_child */ XtInheritDeleteChild,
749N/A /* extension */ NULL
749N/A },{
749N/A /* Shell extension */ NULL
749N/A },{
749N/A /* Override extension */ NULL
749N/A },{
749N/A /* Simple Menu extension*/ NULL
749N/A }
749N/A};
749N/A
749N/AWidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
749N/A
749N/A#define ForAllChildren(smw, childP) \
749N/A for ( (childP) = (SmeObject *) (smw)->composite.children ; \
749N/A (childP) < (SmeObject *) ( (smw)->composite.children + \
749N/A (smw)->composite.num_children ) ; \
749N/A (childP)++ )
749N/A
749N/A/************************************************************
749N/A *
749N/A * Semi-Public Functions.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: ClassInitialize
749N/A * Description: Class Initialize routine, called only once.
749N/A * Arguments: none.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AClassInitialize()
749N/A{
749N/A XawInitializeWidgetSet();
749N/A XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
749N/A (XtConvertArgList)NULL, (Cardinal)0 );
749N/A XmuAddInitializer( AddPositionAction, NULL);
749N/A}
749N/A
749N/A/* Function Name: ClassInitialize
749N/A * Description: Class Part Initialize routine, called for every
749N/A * subclass. Makes sure that the subclasses pick up
749N/A * the extension record.
749N/A * Arguments: wc - the widget class of the subclass.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AClassPartInitialize(wc)
749N/AWidgetClass wc;
749N/A{
749N/A SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass) wc;
749N/A
749N/A/*
749N/A * Make sure that our subclass gets the extension rec too.
749N/A */
749N/A
749N/A extension_rec.next_extension = smwc->composite_class.extension;
749N/A smwc->composite_class.extension = (XtPointer) &extension_rec;
749N/A}
749N/A
749N/A/* Function Name: Initialize
749N/A * Description: Initializes the simple menu widget
749N/A * Arguments: request - the widget requested by the argument list.
749N/A * new - the new widget with both resource and non
749N/A * resource values.
749N/A * Returns: none.
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AInitialize(request, new, args, num_args)
749N/AWidget request, new;
749N/AArgList args;
749N/ACardinal *num_args;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) new;
749N/A
749N/A XmuCallInitializers(XtWidgetToApplicationContext(new));
749N/A
749N/A if (smw->simple_menu.label_class == NULL)
749N/A smw->simple_menu.label_class = smeBSBObjectClass;
749N/A
749N/A smw->simple_menu.label = NULL;
749N/A smw->simple_menu.entry_set = NULL;
749N/A smw->simple_menu.recursive_set_values = FALSE;
749N/A
749N/A if (smw->simple_menu.label_string != NULL)
749N/A CreateLabel(new);
749N/A
749N/A smw->simple_menu.menu_width = TRUE;
749N/A
749N/A if (smw->core.width == 0) {
749N/A smw->simple_menu.menu_width = FALSE;
749N/A smw->core.width = GetMenuWidth(new, (Widget)NULL);
749N/A }
749N/A
749N/A smw->simple_menu.menu_height = TRUE;
749N/A
749N/A if (smw->core.height == 0) {
749N/A smw->simple_menu.menu_height = FALSE;
749N/A smw->core.height = GetMenuHeight(new);
749N/A }
749N/A
749N/A/*
749N/A * Add a popup_callback routine for changing the cursor.
749N/A */
749N/A
749N/A XtAddCallback(new, XtNpopupCallback, ChangeCursorOnGrab, (XtPointer)NULL);
749N/A}
749N/A
749N/A/* Function Name: Redisplay
749N/A * Description: Redisplays the contents of the widget.
749N/A * Arguments: w - the simple menu widget.
749N/A * event - the X event that caused this redisplay.
749N/A * region - the region the needs to be repainted.
749N/A * Returns: none.
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/ARedisplay(w, event, region)
749N/AWidget w;
749N/AXEvent * event;
749N/ARegion region;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject * entry;
749N/A SmeObjectClass class;
749N/A
749N/A if (region == NULL)
749N/A XClearWindow(XtDisplay(w), XtWindow(w));
749N/A
749N/A /*
749N/A * Check and Paint each of the entries - including the label.
749N/A */
749N/A
749N/A ForAllChildren(smw, entry) {
749N/A if (!XtIsManaged ( (Widget) *entry)) continue;
749N/A
749N/A if (region != NULL)
749N/A switch(XRectInRegion(region, (int) (*entry)->rectangle.x,
749N/A (int) (*entry)->rectangle.y,
749N/A (unsigned int) (*entry)->rectangle.width,
749N/A (unsigned int) (*entry)->rectangle.height)) {
749N/A case RectangleIn:
749N/A case RectanglePart:
749N/A break;
749N/A default:
749N/A continue;
749N/A }
749N/A class = (SmeObjectClass) (*entry)->object.widget_class;
749N/A
749N/A if (class->rect_class.expose != NULL)
749N/A (class->rect_class.expose)( (Widget) *entry, NULL, NULL);
749N/A }
749N/A}
749N/A
749N/A/* Function Name: Realize
749N/A * Description: Realizes the widget.
749N/A * Arguments: w - the simple menu widget.
749N/A * mask - value mask for the window to create.
749N/A * attrs - attributes for the window to create.
749N/A * Returns: none
749N/A */
749N/A
749N/Astatic void
749N/ARealize(w, mask, attrs)
749N/AWidget w;
749N/AXtValueMask * mask;
749N/AXSetWindowAttributes * attrs;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A
749N/A attrs->cursor = smw->simple_menu.cursor;
749N/A *mask |= CWCursor;
749N/A if ((smw->simple_menu.backing_store == Always) ||
749N/A (smw->simple_menu.backing_store == NotUseful) ||
749N/A (smw->simple_menu.backing_store == WhenMapped) ) {
749N/A *mask |= CWBackingStore;
749N/A attrs->backing_store = smw->simple_menu.backing_store;
749N/A }
749N/A else
749N/A *mask &= ~CWBackingStore;
749N/A
749N/A (*superclass->core_class.realize) (w, mask, attrs);
749N/A}
749N/A
749N/A/* Function Name: Resize
749N/A * Description: Handle the menu being resized bigger.
749N/A * Arguments: w - the simple menu widget.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AResize(w)
749N/AWidget w;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject * entry;
749N/A
749N/A if ( !XtIsRealized(w) ) return;
749N/A
749N/A ForAllChildren(smw, entry) /* reset width of all entries. */
749N/A if (XtIsManaged( (Widget) *entry))
749N/A (*entry)->rectangle.width = smw->core.width;
749N/A
749N/A Redisplay(w, (XEvent *) NULL, (Region) NULL);
749N/A}
749N/A
749N/A/* Function Name: SetValues
749N/A * Description: Relayout the menu when one of the resources is changed.
749N/A * Arguments: current - current state of the widget.
749N/A * request - what was requested.
749N/A * new - what the widget will become.
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic Boolean
749N/ASetValues(current, request, new, args, num_args)
749N/AWidget current, request, new;
749N/AArgList args;
749N/ACardinal *num_args;
749N/A{
749N/A SimpleMenuWidget smw_old = (SimpleMenuWidget) current;
749N/A SimpleMenuWidget smw_new = (SimpleMenuWidget) new;
749N/A Boolean ret_val = FALSE, layout = FALSE;
749N/A
749N/A if (!XtIsRealized(current)) return(FALSE);
749N/A
749N/A if (!smw_new->simple_menu.recursive_set_values) {
749N/A if (smw_new->core.width != smw_old->core.width) {
749N/A smw_new->simple_menu.menu_width = (smw_new->core.width != 0);
749N/A layout = TRUE;
749N/A }
749N/A if (smw_new->core.height != smw_old->core.height) {
749N/A smw_new->simple_menu.menu_height = (smw_new->core.height != 0);
749N/A layout = TRUE;
749N/A }
749N/A }
749N/A
749N/A if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
749N/A XDefineCursor(XtDisplay(new),
749N/A XtWindow(new), smw_new->simple_menu.cursor);
749N/A
749N/A if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string)
749N/A if (smw_new->simple_menu.label_string == NULL) /* Destroy. */
749N/A XtDestroyWidget((Widget) smw_old->simple_menu.label);
749N/A else if (smw_old->simple_menu.label_string == NULL) /* Create. */
749N/A CreateLabel(new);
749N/A else { /* Change. */
749N/A Arg arglist[1];
749N/A
749N/A XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
749N/A XtSetValues((Widget) smw_new->simple_menu.label, arglist, ONE);
749N/A }
749N/A
749N/A if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
749N/A XtAppWarning(XtWidgetToApplicationContext(new),
749N/A "No Dynamic class change of the SimpleMenu Label.");
749N/A
749N/A if ((smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin) ||
749N/A (smw_old->simple_menu.bottom_margin !=
749N/A smw_new->simple_menu.bottom_margin) /* filler................. */ ) {
749N/A layout = TRUE;
749N/A ret_val = TRUE;
749N/A }
749N/A
749N/A if (layout)
749N/A Layout(new, (Dimension *)NULL, (Dimension *)NULL);
749N/A
749N/A return(ret_val);
749N/A}
749N/A
749N/A/* Function Name: SetValuesHook
749N/A * Description: To handle a special case, this is passed the
749N/A * actual arguments.
749N/A * Arguments: w - the menu widget.
749N/A * arglist - the argument list passed to XtSetValues.
749N/A * num_args - the number of args.
749N/A * Returns: none
749N/A */
749N/A
749N/A/*
749N/A * If the user actually passed a width and height to the widget
749N/A * then this MUST be used, rather than our newly calculated width and
749N/A * height.
749N/A */
749N/A
749N/Astatic Boolean
749N/ASetValuesHook(w, arglist, num_args)
749N/AWidget w;
749N/AArgList arglist;
749N/ACardinal *num_args;
749N/A{
749N/A Cardinal i;
749N/A Dimension width, height;
749N/A
749N/A width = w->core.width;
749N/A height = w->core.height;
749N/A
749N/A for ( i = 0 ; i < *num_args ; i++) {
749N/A if ( streq(arglist[i].name, XtNwidth) )
749N/A width = (Dimension) arglist[i].value;
749N/A if ( streq(arglist[i].name, XtNheight) )
749N/A height = (Dimension) arglist[i].value;
749N/A }
749N/A
749N/A if ((width != w->core.width) || (height != w->core.height))
749N/A MakeSetValuesRequest(w, width, height);
749N/A return(FALSE);
749N/A}
749N/A
749N/A/************************************************************
749N/A *
749N/A * Geometry Management routines.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: GeometryManager
749N/A * Description: This is the SimpleMenu Widget's Geometry Manager.
749N/A * Arguments: w - the Menu Entry making the request.
749N/A * request - requested new geometry.
749N/A * reply - the allowed geometry.
749N/A * Returns: XtGeometry{Yes, No, Almost}.
749N/A */
749N/A
749N/Astatic XtGeometryResult
749N/AGeometryManager(w, request, reply)
749N/AWidget w;
749N/AXtWidgetGeometry * request, * reply;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) XtParent(w);
749N/A SmeObject entry = (SmeObject) w;
749N/A XtGeometryMask mode = request->request_mode;
749N/A XtGeometryResult answer;
749N/A Dimension old_height, old_width;
749N/A
749N/A if ( !(mode & CWWidth) && !(mode & CWHeight) )
749N/A return(XtGeometryNo);
749N/A
749N/A reply->width = request->width;
749N/A reply->height = request->height;
749N/A
749N/A old_width = entry->rectangle.width;
749N/A old_height = entry->rectangle.height;
749N/A
749N/A Layout(w, &(reply->width), &(reply->height) );
749N/A
749N/A/*
749N/A * Since we are an override shell and have no parent there is no one to
749N/A * ask to see if this geom change is okay, so I am just going to assume
749N/A * we can do whatever we want. If you subclass be very careful with this
749N/A * assumption, it could bite you.
749N/A *
749N/A * Chris D. Peterson - Sept. 1989.
749N/A */
749N/A
749N/A if ( (reply->width == request->width) &&
749N/A (reply->height == request->height) ) {
749N/A
749N/A if ( mode & XtCWQueryOnly ) { /* Actually perform the layout. */
749N/A entry->rectangle.width = old_width;
749N/A entry->rectangle.height = old_height;
749N/A }
749N/A else {
749N/A Layout(( Widget) smw, (Dimension *)NULL, (Dimension *)NULL);
749N/A }
749N/A answer = XtGeometryDone;
749N/A }
749N/A else {
749N/A entry->rectangle.width = old_width;
749N/A entry->rectangle.height = old_height;
749N/A
749N/A if ( ((reply->width == request->width) && !(mode & CWHeight)) ||
749N/A ((reply->height == request->height) && !(mode & CWWidth)) ||
749N/A ((reply->width == request->width) &&
749N/A (reply->height == request->height)) )
749N/A answer = XtGeometryNo;
749N/A else {
749N/A answer = XtGeometryAlmost;
749N/A reply->request_mode = 0;
749N/A if (reply->width != request->width)
749N/A reply->request_mode |= CWWidth;
749N/A if (reply->height != request->height)
749N/A reply->request_mode |= CWHeight;
749N/A }
749N/A }
749N/A return(answer);
749N/A}
749N/A
749N/A/* Function Name: ChangeManaged
749N/A * Description: called whenever a new child is managed.
749N/A * Arguments: w - the simple menu widget.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/AChangeManaged(w)
749N/AWidget w;
749N/A{
749N/A Layout(w, (Dimension *)NULL, (Dimension *)NULL);
749N/A}
749N/A
749N/A/************************************************************
749N/A *
749N/A * Global Action Routines.
749N/A *
749N/A * These actions routines will be added to the application's
749N/A * global action list.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: PositionMenuAction
749N/A * Description: Positions the simple menu widget.
749N/A * Arguments: w - a widget (no the simple menu widget.)
749N/A * event - the event that caused this action.
749N/A * params, num_params - parameters passed to the routine.
749N/A * we expect the name of the menu here.
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/APositionMenuAction(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal * num_params;
749N/A{
749N/A Widget menu;
749N/A XPoint loc;
749N/A char error_buf[BUFSIZ];
749N/A char* ebp;
749N/A int len;
749N/A char* fmt = "Xaw SimpleMenuWidget: could not find menu named: \"%s\"";
749N/A
749N/A if (*num_params != 1) {
749N/A char error_buf[BUFSIZ];
749N/A (void) sprintf(error_buf, "%s %s",
749N/A "Xaw - SimpleMenuWidget: position menu action expects only one",
749N/A "parameter which is the name of the menu.");
749N/A XtAppWarning(XtWidgetToApplicationContext(w),
749N/A "Xaw - SimpleMenuWidget: position menu action expects only one parameter which is the name of the menu.");
749N/A return;
749N/A }
749N/A
749N/A if ( (menu = FindMenu(w, params[0])) == NULL) {
749N/A if ((len = strlen (fmt) + strlen (params[0])) < sizeof error_buf)
749N/A ebp = error_buf;
749N/A else
749N/A ebp = XtMalloc (len + 1);
749N/A if (ebp == NULL) {
749N/A ebp = error_buf;
749N/A strcpy (ebp, "Xaw - SimpleMenuWidget: could not find menu");
749N/A } else
749N/A (void) sprintf(ebp, fmt, params[0]);
749N/A XtAppWarning(XtWidgetToApplicationContext(w), ebp);
749N/A if (ebp != error_buf) XtFree (ebp);
749N/A return;
749N/A }
749N/A
749N/A switch (event->type) {
749N/A case ButtonPress:
749N/A case ButtonRelease:
749N/A loc.x = event->xbutton.x_root;
749N/A loc.y = event->xbutton.y_root;
749N/A PositionMenu(menu, &loc);
749N/A break;
749N/A case EnterNotify:
749N/A case LeaveNotify:
749N/A loc.x = event->xcrossing.x_root;
749N/A loc.y = event->xcrossing.y_root;
749N/A PositionMenu(menu, &loc);
749N/A break;
749N/A case MotionNotify:
749N/A loc.x = event->xmotion.x_root;
749N/A loc.y = event->xmotion.y_root;
749N/A PositionMenu(menu, &loc);
749N/A break;
749N/A default:
749N/A PositionMenu(menu, (XPoint *)NULL);
749N/A break;
749N/A }
749N/A}
749N/A
749N/A/************************************************************
749N/A *
749N/A * Widget Action Routines.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: Unhighlight
749N/A * Description: Unhighlights current entry.
749N/A * Arguments: w - the simple menu widget.
749N/A * event - the event that caused this action.
749N/A * params, num_params - ** NOT USED **
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AUnhighlight(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal * num_params;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject entry = smw->simple_menu.entry_set;
749N/A SmeObjectClass class;
749N/A
749N/A if ( entry == NULL) return;
749N/A
749N/A smw->simple_menu.entry_set = NULL;
749N/A class = (SmeObjectClass) entry->object.widget_class;
749N/A (class->sme_class.unhighlight) ( (Widget) entry);
749N/A}
749N/A
749N/A/* Function Name: Highlight
749N/A * Description: Highlights current entry.
749N/A * Arguments: w - the simple menu widget.
749N/A * event - the event that caused this action.
749N/A * params, num_params - ** NOT USED **
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AHighlight(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal * num_params;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject entry;
749N/A SmeObjectClass class;
749N/A
749N/A if ( !XtIsSensitive(w) ) return;
749N/A
749N/A entry = GetEventEntry(w, event);
749N/A
749N/A if (entry == smw->simple_menu.entry_set) return;
749N/A
749N/A Unhighlight(w, event, params, num_params);
749N/A
749N/A if (entry == NULL) return;
749N/A
749N/A if ( !XtIsSensitive( (Widget) entry)) {
749N/A smw->simple_menu.entry_set = NULL;
749N/A return;
749N/A }
749N/A
749N/A smw->simple_menu.entry_set = entry;
749N/A class = (SmeObjectClass) entry->object.widget_class;
749N/A
749N/A (class->sme_class.highlight) ( (Widget) entry);
749N/A}
749N/A
749N/A/* Function Name: Notify
749N/A * Description: Notify user of current entry.
749N/A * Arguments: w - the simple menu widget.
749N/A * event - the event that caused this action.
749N/A * params, num_params - ** NOT USED **
749N/A * Returns: none
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/ANotify(w, event, params, num_params)
749N/AWidget w;
749N/AXEvent * event;
749N/AString * params;
749N/ACardinal * num_params;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject entry = smw->simple_menu.entry_set;
749N/A SmeObjectClass class;
749N/A
749N/A if ( (entry == NULL) || !XtIsSensitive((Widget) entry ) ) return;
749N/A
749N/A class = (SmeObjectClass) entry->object.widget_class;
749N/A (class->sme_class.notify)( (Widget) entry );
749N/A}
749N/A
749N/A/************************************************************
749N/A *
749N/A * Public Functions.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: XawSimpleMenuAddGlobalActions
749N/A * Description: adds the global actions to the simple menu widget.
749N/A * Arguments: app_con - the appcontext.
749N/A * Returns: none.
749N/A */
749N/A
749N/Avoid
749N/A#if NeedFunctionPrototypes
749N/AXawSimpleMenuAddGlobalActions(XtAppContext app_con)
749N/A#else
749N/AXawSimpleMenuAddGlobalActions(app_con)
749N/AXtAppContext app_con;
749N/A#endif
749N/A{
749N/A XtInitializeWidgetClass(simpleMenuWidgetClass);
749N/A XmuCallInitializers( app_con );
749N/A}
749N/A
749N/A
749N/A/* Function Name: XawSimpleMenuGetActiveEntry
749N/A * Description: Gets the currently active (set) entry.
749N/A * Arguments: w - the smw widget.
749N/A * Returns: the currently set entry or NULL if none is set.
749N/A */
749N/A
749N/AWidget
749N/A#if NeedFunctionPrototypes
749N/AXawSimpleMenuGetActiveEntry(Widget w)
749N/A#else
749N/AXawSimpleMenuGetActiveEntry(w)
749N/AWidget w;
749N/A#endif
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A
749N/A return( (Widget) smw->simple_menu.entry_set);
749N/A}
749N/A
749N/A/* Function Name: XawSimpleMenuClearActiveEntry
749N/A * Description: Unsets the currently active (set) entry.
749N/A * Arguments: w - the smw widget.
749N/A * Returns: none.
749N/A */
749N/A
749N/Avoid
749N/A#if NeedFunctionPrototypes
749N/AXawSimpleMenuClearActiveEntry(Widget w)
749N/A#else
749N/AXawSimpleMenuClearActiveEntry(w)
749N/AWidget w;
749N/A#endif
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A
749N/A smw->simple_menu.entry_set = NULL;
749N/A}
749N/A
749N/A/************************************************************
749N/A *
749N/A * Private Functions.
749N/A *
749N/A ************************************************************/
749N/A
749N/A/* Function Name: CreateLabel
749N/A * Description: Creates a the menu label.
749N/A * Arguments: w - the smw widget.
749N/A * Returns: none.
749N/A *
749N/A * Creates the label object and makes sure it is the first child in
749N/A * in the list.
749N/A */
749N/A
749N/Astatic void
749N/ACreateLabel(w)
749N/AWidget w;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A Widget * child, * next_child;
749N/A int i;
749N/A Arg args[2];
749N/A
749N/A if ( (smw->simple_menu.label_string == NULL) ||
749N/A (smw->simple_menu.label != NULL) ) {
749N/A char error_buf[BUFSIZ];
749N/A
749N/A (void) sprintf(error_buf, "Xaw Simple Menu Widget: %s or %s, %s",
749N/A "label string is NULL", "label already exists",
749N/A "no label is being created.");
749N/A XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
749N/A return;
749N/A }
749N/A
749N/A XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
749N/A XtSetArg(args[1], XtNjustify, XtJustifyCenter);
749N/A smw->simple_menu.label = (SmeObject)
749N/A XtCreateManagedWidget("menuLabel",
749N/A smw->simple_menu.label_class, w,
749N/A args, TWO);
749N/A
749N/A next_child = NULL;
749N/A for (child = smw->composite.children + smw->composite.num_children,
749N/A i = smw->composite.num_children ; i > 0 ; i--, child--) {
749N/A if (next_child != NULL)
749N/A *next_child = *child;
749N/A next_child = child;
749N/A }
749N/A *child = (Widget) smw->simple_menu.label;
749N/A}
749N/A
749N/A/* Function Name: Layout
749N/A * Description: lays the menu entries out all nice and neat.
749N/A * Arguments: w - See below (+++)
749N/A * width_ret, height_ret - The returned width and
749N/A * height values.
749N/A * Returns: none.
749N/A *
749N/A * if width == NULL || height == NULL then it assumes the you do not care
749N/A * about the return values, and just want a relayout.
749N/A *
749N/A * if this is not the case then it will set width_ret and height_ret
749N/A * to be width and height that the child would get if it were layed out
749N/A * at this time.
749N/A *
749N/A * +++ "w" can be the simple menu widget or any of its object children.
749N/A */
749N/A
749N/Astatic void
749N/ALayout(w, width_ret, height_ret)
749N/AWidget w;
749N/ADimension *width_ret, *height_ret;
749N/A{
749N/A SmeObject current_entry, *entry;
749N/A SimpleMenuWidget smw;
749N/A Dimension width, height;
749N/A Boolean do_layout = ((height_ret == NULL) || (width_ret == NULL));
749N/A Boolean allow_change_size;
749N/A height = 0;
749N/A
749N/A if ( XtIsSubclass(w, simpleMenuWidgetClass) ) {
749N/A smw = (SimpleMenuWidget) w;
749N/A current_entry = NULL;
749N/A }
749N/A else {
749N/A smw = (SimpleMenuWidget) XtParent(w);
749N/A current_entry = (SmeObject) w;
749N/A }
749N/A
749N/A allow_change_size = (!XtIsRealized((Widget)smw) ||
749N/A (smw->shell.allow_shell_resize));
749N/A
749N/A if ( smw->simple_menu.menu_height )
749N/A height = smw->core.height;
749N/A else
749N/A if (do_layout) {
749N/A height = smw->simple_menu.top_margin;
749N/A ForAllChildren(smw, entry) {
749N/A if (!XtIsManaged( (Widget) *entry)) continue;
749N/A
749N/A if ( (smw->simple_menu.row_height != 0) &&
749N/A (*entry != smw->simple_menu.label) )
749N/A (*entry)->rectangle.height = smw->simple_menu.row_height;
749N/A
749N/A (*entry)->rectangle.y = height;
749N/A (*entry)->rectangle.x = 0;
749N/A height += (*entry)->rectangle.height;
749N/A }
749N/A height += smw->simple_menu.bottom_margin;
749N/A }
749N/A else {
749N/A if ((smw->simple_menu.row_height != 0) &&
749N/A (current_entry != smw->simple_menu.label) )
749N/A height = smw->simple_menu.row_height;
749N/A }
749N/A
749N/A if (smw->simple_menu.menu_width)
749N/A width = smw->core.width;
749N/A else if ( allow_change_size )
749N/A width = GetMenuWidth((Widget) smw, (Widget) current_entry);
749N/A else
749N/A width = smw->core.width;
749N/A
749N/A if (do_layout) {
749N/A ForAllChildren(smw, entry)
749N/A if (XtIsManaged( (Widget) *entry))
749N/A (*entry)->rectangle.width = width;
749N/A
749N/A if (allow_change_size)
749N/A MakeSetValuesRequest((Widget) smw, width, height);
749N/A }
749N/A else {
749N/A *width_ret = width;
749N/A if (height != 0)
749N/A *height_ret = height;
749N/A }
749N/A}
749N/A
749N/A/* Function Name: AddPositionAction
749N/A * Description: Adds the XawPositionSimpleMenu action to the global
749N/A * action list for this appcon.
749N/A * Arguments: app_con - the application context for this app.
749N/A * data - NOT USED.
749N/A * Returns: none.
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AAddPositionAction(app_con, data)
749N/AXtAppContext app_con;
749N/AXPointer data;
749N/A{
749N/A static XtActionsRec pos_action[] = {
749N/A { "XawPositionSimpleMenu", PositionMenuAction },
749N/A };
749N/A
749N/A XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
749N/A}
749N/A
749N/A/* Function Name: FindMenu
749N/A * Description: Find the menu give a name and reference widget.
749N/A * Arguments: widget - reference widget.
749N/A * name - the menu widget's name.
749N/A * Returns: the menu widget or NULL.
749N/A */
749N/A
749N/Astatic Widget
749N/AFindMenu(widget, name)
749N/AWidget widget;
749N/AString name;
749N/A{
749N/A Widget w, menu;
749N/A
749N/A for ( w = widget ; w != NULL ; w = XtParent(w) )
749N/A if ( (menu = XtNameToWidget(w, name)) != NULL )
749N/A return(menu);
749N/A return(NULL);
749N/A}
749N/A
749N/A/* Function Name: PositionMenu
749N/A * Description: Places the menu
749N/A * Arguments: w - the simple menu widget.
749N/A * location - a pointer the the position or NULL.
749N/A * Returns: none.
749N/A */
749N/A
749N/Astatic void
749N/APositionMenu(w, location)
749N/AWidget w;
749N/AXPoint * location;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject entry;
749N/A XPoint t_point;
749N/A
749N/A if (location == NULL) {
749N/A Window junk1, junk2;
749N/A int root_x, root_y, junkX, junkY;
749N/A unsigned int junkM;
749N/A
749N/A location = &t_point;
749N/A if (XQueryPointer(XtDisplay(w), XtWindow(w), &junk1, &junk2,
749N/A &root_x, &root_y, &junkX, &junkY, &junkM) == FALSE) {
749N/A char error_buf[BUFSIZ];
749N/A (void) sprintf(error_buf, "%s %s", "Xaw Simple Menu Widget:",
749N/A "Could not find location of mouse pointer");
749N/A XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
749N/A return;
749N/A }
749N/A location->x = (short) root_x;
749N/A location->y = (short) root_y;
749N/A }
749N/A
749N/A /*
749N/A * The width will not be correct unless it is realized.
749N/A */
749N/A
749N/A XtRealizeWidget(w);
749N/A
749N/A location->x -= (Position) w->core.width/2;
749N/A
749N/A if (smw->simple_menu.popup_entry == NULL)
749N/A entry = smw->simple_menu.label;
749N/A else
749N/A entry = smw->simple_menu.popup_entry;
749N/A
749N/A if (entry != NULL)
749N/A location->y -= entry->rectangle.y + entry->rectangle.height/2;
749N/A
749N/A MoveMenu(w, (Position) location->x, (Position) location->y);
749N/A}
749N/A
749N/A/* Function Name: MoveMenu
749N/A * Description: Actually moves the menu, may force it to
749N/A * to be fully visable if menu_on_screen is TRUE.
749N/A * Arguments: w - the simple menu widget.
749N/A * x, y - the current location of the widget.
749N/A * Returns: none
749N/A */
749N/A
749N/Astatic void
749N/AMoveMenu(w, x, y)
749N/AWidget w;
749N/APosition x, y;
749N/A{
749N/A Arg arglist[2];
749N/A Cardinal num_args = 0;
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A
749N/A if (smw->simple_menu.menu_on_screen) {
749N/A int width = w->core.width + 2 * w->core.border_width;
749N/A int height = w->core.height + 2 * w->core.border_width;
749N/A
749N/A if (x >= 0) {
749N/A int scr_width = WidthOfScreen(XtScreen(w));
749N/A if (x + width > scr_width)
749N/A x = scr_width - width;
749N/A }
749N/A if (x < 0)
749N/A x = 0;
749N/A
749N/A if (y >= 0) {
749N/A int scr_height = HeightOfScreen(XtScreen(w));
749N/A if (y + height > scr_height)
749N/A y = scr_height - height;
749N/A }
749N/A if (y < 0)
749N/A y = 0;
749N/A }
749N/A
749N/A XtSetArg(arglist[num_args], XtNx, x); num_args++;
749N/A XtSetArg(arglist[num_args], XtNy, y); num_args++;
749N/A XtSetValues(w, arglist, num_args);
749N/A}
749N/A
749N/A/* Function Name: ChangeCursorOnGrab
749N/A * Description: Changes the cursor on the active grab to the one
749N/A * specified in out resource list.
749N/A * Arguments: w - the widget.
749N/A * junk, garbage - ** NOT USED **.
749N/A * Returns: None.
749N/A */
749N/A
749N/A/* ARGSUSED */
749N/Astatic void
749N/AChangeCursorOnGrab(w, junk, garbage)
749N/AWidget w;
749N/AXtPointer junk, garbage;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A
749N/A /*
749N/A * The event mask here is what is currently in the MIT implementation.
749N/A * There really needs to be a way to get the value of the mask out
749N/A * of the toolkit (CDP 5/26/89).
749N/A */
749N/A
749N/A XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask|ButtonReleaseMask,
749N/A smw->simple_menu.cursor,
749N/A XtLastTimestampProcessed(XtDisplay(w)));
749N/A}
749N/A
749N/A/* Function Name: MakeSetValuesRequest
749N/A * Description: Makes a (possibly recursive) call to SetValues,
749N/A * I take great pains to not go into an infinite loop.
749N/A * Arguments: w - the simple menu widget.
749N/A * width, height - the size of the ask for.
749N/A * Returns: none
749N/A */
749N/A
749N/Astatic void
749N/AMakeSetValuesRequest(w, width, height)
749N/AWidget w;
749N/ADimension width, height;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A Arg arglist[2];
749N/A Cardinal num_args = (Cardinal) 0;
749N/A
749N/A if ( !smw->simple_menu.recursive_set_values ) {
749N/A if ( (smw->core.width != width) || (smw->core.height != height) ) {
749N/A smw->simple_menu.recursive_set_values = TRUE;
749N/A XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
749N/A XtSetArg(arglist[num_args], XtNheight, height); num_args++;
749N/A XtSetValues(w, arglist, num_args);
749N/A }
749N/A else if (XtIsRealized( (Widget) smw))
749N/A Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
749N/A }
749N/A smw->simple_menu.recursive_set_values = FALSE;
749N/A}
749N/A
749N/A/* Function Name: GetMenuWidth
749N/A * Description: Sets the length of the widest entry in pixels.
749N/A * Arguments: w - the simple menu widget.
749N/A * Returns: width of menu.
749N/A */
749N/A
749N/Astatic Dimension
749N/AGetMenuWidth(w, w_ent)
749N/AWidget w, w_ent;
749N/A{
749N/A SmeObject cur_entry = (SmeObject) w_ent;
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A Dimension width, widest = (Dimension) 0;
749N/A SmeObject * entry;
749N/A
749N/A if ( smw->simple_menu.menu_width )
749N/A return(smw->core.width);
749N/A
749N/A ForAllChildren(smw, entry) {
749N/A XtWidgetGeometry preferred;
749N/A
749N/A if (!XtIsManaged( (Widget) *entry)) continue;
749N/A
749N/A if (*entry != cur_entry) {
749N/A XtQueryGeometry((Widget) *entry, (XtWidgetGeometry *)NULL, &preferred);
749N/A
749N/A if (preferred.request_mode & CWWidth)
749N/A width = preferred.width;
749N/A else
749N/A width = (*entry)->rectangle.width;
749N/A }
749N/A else
749N/A width = (*entry)->rectangle.width;
749N/A
749N/A if ( width > widest )
749N/A widest = width;
749N/A }
749N/A
749N/A return(widest);
749N/A}
749N/A
749N/A/* Function Name: GetMenuHeight
749N/A * Description: Sets the length of the widest entry in pixels.
749N/A * Arguments: w - the simple menu widget.
749N/A * Returns: width of menu.
749N/A */
749N/A
749N/Astatic Dimension
749N/AGetMenuHeight(w)
749N/AWidget w;
749N/A{
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject * entry;
749N/A Dimension height;
749N/A
749N/A if (smw->simple_menu.menu_height)
749N/A return(smw->core.height);
749N/A
749N/A height = smw->simple_menu.top_margin + smw->simple_menu.bottom_margin;
749N/A
749N/A if (smw->simple_menu.row_height == 0) {
749N/A ForAllChildren(smw, entry)
749N/A if (XtIsManaged ((Widget) *entry))
749N/A height += (*entry)->rectangle.height;
749N/A } else
749N/A height += smw->simple_menu.row_height * smw->composite.num_children;
749N/A
749N/A return(height);
749N/A}
749N/A
749N/A/* Function Name: GetEventEntry
749N/A * Description: Gets an entry given an event that has X and Y coords.
749N/A * Arguments: w - the simple menu widget.
749N/A * event - the event.
749N/A * Returns: the entry that this point is in.
749N/A */
749N/A
749N/Astatic SmeObject
749N/AGetEventEntry(w, event)
749N/AWidget w;
749N/AXEvent * event;
749N/A{
749N/A Position x_loc, y_loc;
749N/A SimpleMenuWidget smw = (SimpleMenuWidget) w;
749N/A SmeObject * entry;
749N/A
749N/A switch (event->type) {
749N/A case MotionNotify:
749N/A x_loc = event->xmotion.x;
749N/A y_loc = event->xmotion.y;
749N/A break;
749N/A case EnterNotify:
749N/A case LeaveNotify:
749N/A x_loc = event->xcrossing.x;
749N/A y_loc = event->xcrossing.y;
749N/A break;
749N/A case ButtonPress:
749N/A case ButtonRelease:
749N/A x_loc = event->xbutton.x;
749N/A y_loc = event->xbutton.y;
749N/A break;
749N/A default:
749N/A XtAppError(XtWidgetToApplicationContext(w),
749N/A "Unknown event type in GetEventEntry().");
749N/A break;
749N/A }
749N/A
749N/A if ( (x_loc < 0) || (x_loc >= (int)smw->core.width) || (y_loc < 0) ||
749N/A (y_loc >= (int)smw->core.height) )
749N/A return(NULL);
749N/A
749N/A ForAllChildren(smw, entry) {
749N/A if (!XtIsManaged ((Widget) *entry)) continue;
749N/A
749N/A if ( ((*entry)->rectangle.y < y_loc) &&
749N/A ((*entry)->rectangle.y + (int) (*entry)->rectangle.height > y_loc) )
749N/A if ( *entry == smw->simple_menu.label )
749N/A return(NULL); /* cannot select the label. */
749N/A else
749N/A return(*entry);
749N/A }
749N/A
749N/A return(NULL);
749N/A}