summaryrefslogtreecommitdiff
path: root/src/SimpleMenu.c
diff options
context:
space:
mode:
authorMatt Turner <mattst88@gmail.com>2011-08-01 21:22:31 -0400
committerMatt Turner <mattst88@gmail.com>2011-08-01 21:22:31 -0400
commit9814d1217f19449b59ff0c1de1b8e7850e95d0fa (patch)
treeb2832ae672ce14807efe23d3be12418595b5d88d /src/SimpleMenu.c
parent7bbcf240f6c6999715db6e1f4c530939cf91340e (diff)
Move sources to src/.
Signed-off-by: Matt Turner <mattst88@gmail.com>
Diffstat (limited to 'src/SimpleMenu.c')
-rw-r--r--src/SimpleMenu.c1673
1 files changed, 1673 insertions, 0 deletions
diff --git a/src/SimpleMenu.c b/src/SimpleMenu.c
new file mode 100644
index 0000000..87a3170
--- /dev/null
+++ b/src/SimpleMenu.c
@@ -0,0 +1,1673 @@
+/* $XConsortium: SimpleMenu.c,v 1.44 94/04/17 20:12:45 kaleb Exp $ */
+
+/*
+Copyright (c) 1989, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ */
+
+/*
+ * 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 <limits.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include "Xaw3dP.h"
+#include <X11/Xaw3d/XawInit.h>
+#include <X11/Xaw3d/SimpleMenP.h>
+#include <X11/Xaw3d/SmeBSBP.h>
+#include <X11/Xaw3d/SmeLine.h>
+#include <X11/Xaw3d/Cardinals.h>
+#include <X11/Xaw3d/ThreeDP.h>
+
+#include <X11/Xmu/Initer.h>
+#include <X11/Xmu/CharSet.h>
+
+#define streq(a, b) ( strcmp((a), (b)) == 0 )
+
+#define offset(field) XtOffsetOf(SimpleMenuRec, 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, (XtPointer) NULL},
+
+/*
+ * Layout Resources.
+ */
+
+ {XtNrowHeight, XtCRowHeight, XtRDimension, sizeof(Dimension),
+ offset(row_height), XtRImmediate, (XtPointer) 0},
+ {XtNtopMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(top_margin), XtRImmediate, (XtPointer) 0},
+ {XtNbottomMargin, XtCVerticalMargins, XtRDimension, sizeof(Dimension),
+ offset(bottom_margin), XtRImmediate, (XtPointer) 0},
+ {XtNleftWhitespace, XtCHorizontalWhitespace, XtRDimension, sizeof(Dimension),
+ offset(left_whitespace), XtRImmediate, (XtPointer) 0},
+ {XtNrightWhitespace, XtCHorizontalWhitespace, XtRDimension, sizeof(Dimension),
+ offset(right_whitespace), XtRImmediate, (XtPointer) 0},
+
+/*
+ * Misc. Resources
+ */
+
+ { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, sizeof(Boolean),
+ XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
+ XtRImmediate, (XtPointer) TRUE },
+ {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None},
+ {XtNmenuOnScreen, XtCMenuOnScreen, XtRBoolean, sizeof(Boolean),
+ offset(menu_on_screen), XtRImmediate, (XtPointer) TRUE},
+ {XtNpopupOnEntry, XtCPopupOnEntry, XtRWidget, sizeof(Widget),
+ offset(popup_entry), XtRWidget, NULL},
+ {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
+ offset(backing_store),
+ XtRImmediate, (XtPointer) (Always + WhenMapped + NotUseful)},
+ {XtNjumpScroll, XtCJumpScroll, XtRInt, sizeof(int),
+ offset(jump_val), XtRImmediate, (XtPointer)1},
+};
+#undef offset
+
+static char defaultTranslations[] =
+ "<EnterWindow>: highlight() \n\
+ <LeaveWindow>: unhighlight() \n\
+ <BtnMotion>: highlight() \n\
+ <BtnUp>: notify() unhighlight() popdown()";
+
+/*
+ * Semi Public function definitions.
+ */
+
+static void Redisplay(), Realize(), Resize(), ChangeManaged();
+static void Initialize(), ClassInitialize(), ClassPartInitialize();
+static Boolean SetValues(), SetValuesHook();
+static XtGeometryResult GeometryManager();
+static void PopupCB(), PopupSubMenu(), PopdownSubMenu();
+
+/*
+ * Action Routine Definitions
+ */
+
+static void Highlight(), Unhighlight(), Notify(), PositionMenuAction();
+static void Popdown();
+
+/*
+ * Private Function Definitions.
+ */
+
+static void MakeSetValuesRequest(), CreateLabel(), Layout();
+static void AddPositionAction(), PositionMenu(), ChangeCursorOnGrab();
+static void SetMarginWidths();
+static Dimension GetMenuWidth(), GetMenuHeight();
+static Widget FindMenu();
+static SmeObject GetEventEntry();
+static void MoveMenu();
+
+static XtActionsRec actionsList[] =
+{
+ {"notify", Notify},
+ {"highlight", Highlight},
+ {"unhighlight", Unhighlight},
+ {"popdown", Popdown}
+};
+
+static 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;
+
+#define SMW_ARROW_SIZE 8
+#define SMW_UNMAPPING 0x01
+#define SMW_POPLEFT 0x02
+
+#define ForAllChildren(smw, childP) \
+ for ((childP) = (SmeObject *) (smw)->composite.children; \
+ (childP) < (SmeObject *) ((smw)->composite.children + \
+ (smw)->composite.num_children); \
+ (childP)++)
+
+/************************************************************
+ *
+ * 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,
+ (XtConvertArgList)NULL, (Cardinal)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 = (XtPointer) &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, args, num_args)
+Widget request, new;
+ArgList args;
+Cardinal *num_args;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) new;
+
+ XmuCallInitializers(XtWidgetToApplicationContext(new));
+
+ smw->simple_menu.label = NULL;
+ smw->simple_menu.entry_set = NULL;
+ smw->simple_menu.recursive_set_values = FALSE;
+ smw->simple_menu.first_entry = NULL;
+ smw->simple_menu.current_first = NULL;
+ smw->simple_menu.first_y = 0;
+ smw->simple_menu.too_tall = FALSE;
+ smw->simple_menu.sub_menu = NULL;
+ smw->simple_menu.state = 0;
+
+ XtAddCallback(new, XtNpopupCallback, PopupCB, NULL);
+
+ if (smw->simple_menu.label_class == NULL)
+ smw->simple_menu.label_class = smeBSBObjectClass;
+
+ if (smw->simple_menu.label_string != NULL)
+ CreateLabel(new);
+
+ /* GetMenuHeight() needs this */
+ smw->simple_menu.threeD = XtVaCreateWidget("threeD", threeDWidgetClass,
+ new,
+ XtNx, 0, XtNy, 0, XtNwidth, /* dummy */ 10, XtNheight, /* dummy */ 10,
+ NULL);
+
+ smw->simple_menu.menu_width = TRUE;
+
+ if (smw->core.width == 0) {
+ smw->simple_menu.menu_width = FALSE;
+ smw->core.width = GetMenuWidth(new, (Widget)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, (XtPointer)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;
+ ThreeDWidget tdw = (ThreeDWidget)smw->simple_menu.threeD;
+ RectObjPart old_pos;
+ int y, max_y, new_y, dy, s = tdw->threeD.shadow_width;
+ Boolean can_paint;
+ XPoint point[3];
+
+ if (region == NULL)
+ XClearWindow(XtDisplay(w), XtWindow(w));
+
+ if (XtIsRealized((Widget)smw))
+ _ShadowSurroundedBox((Widget)smw, tdw,
+ 0, 0, smw->core.width, smw->core.height,
+ tdw->threeD.relief, True);
+
+ smw->simple_menu.didnt_fit = False;
+ y = 0;
+ max_y = HeightOfScreen(XtScreen(w)) - s;
+ new_y = -(*(SmeObject *)(smw)->composite.children)->rectangle.y;
+ can_paint = False;
+
+ /* check and paint each of the entries - including the label */
+ ForAllChildren(smw, entry)
+ {
+ if (!XtIsManaged((Widget)*entry)) continue;
+
+ if (smw->simple_menu.first_entry == NULL)
+ {
+ smw->simple_menu.first_entry = entry;
+ smw->simple_menu.current_first = entry;
+ }
+
+ if (smw->simple_menu.too_tall)
+ {
+ dy = 0;
+
+ if (entry == (smw->simple_menu.current_first))
+ {
+ new_y = (*entry)->rectangle.y - 1;
+
+ if (smw->simple_menu.current_first != smw->simple_menu.first_entry)
+ {
+ point[0].x = (*entry)->rectangle.width / 2;
+ point[0].y = s + 1;
+ point[1].x = (*entry)->rectangle.width / 2 - SMW_ARROW_SIZE / 2;
+ point[1].y = s + SMW_ARROW_SIZE;
+ point[2].x = (*entry)->rectangle.width / 2 + SMW_ARROW_SIZE / 2;
+ point[2].y = s + SMW_ARROW_SIZE;
+ XFillPolygon(XtDisplay(w), smw->core.window,
+ tdw->threeD.bot_shadow_GC, point, 3, Convex,
+ CoordModeOrigin);
+
+ new_y -= SMW_ARROW_SIZE;
+ dy = SMW_ARROW_SIZE;
+ }
+
+ smw->simple_menu.first_y = new_y;
+ can_paint = True;
+ }
+ else if (!can_paint)
+ continue;
+
+ old_pos = (*entry)->rectangle;
+ (*entry)->rectangle.y -= new_y;
+
+ if ((*entry)->rectangle.y + (*entry)->rectangle.height + dy > max_y)
+ {
+ smw->simple_menu.last_y = (*entry)->rectangle.y;
+ point[0].x = (*entry)->rectangle.width / 2;
+ point[0].y = max_y - 1;
+ point[1].x = (*entry)->rectangle.width / 2 - SMW_ARROW_SIZE / 2;
+ point[1].y = max_y - SMW_ARROW_SIZE;
+ point[2].x = (*entry)->rectangle.width / 2 + SMW_ARROW_SIZE / 2;
+ point[2].y = max_y - SMW_ARROW_SIZE;
+ XFillPolygon(XtDisplay(w), smw->core.window,
+ tdw->threeD.bot_shadow_GC, point, 3, Convex,
+ CoordModeOrigin);
+
+ smw->simple_menu.didnt_fit = True;
+ (*entry)->rectangle = old_pos;
+ break;
+ }
+ }
+
+ /*
+ 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);
+
+ if (smw->simple_menu.too_tall) (*entry)->rectangle = old_pos;
+
+ y += (*entry)->rectangle.height;
+ }
+}
+
+/* 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;
+
+ /* check if the menu is too big */
+ if (smw->core.height >= HeightOfScreen(XtScreen(w))) {
+ smw->simple_menu.too_tall = TRUE;
+ smw->core.height = HeightOfScreen(XtScreen(w));
+ }
+
+ (*superclass->core_class.realize) (w, mask, attrs);
+}
+
+/* Function Name: Resize
+ * Description: Handle the menu being resized.
+ * Arguments: w - the simple menu widget or any of its object children.
+ * Returns: none.
+ */
+
+static void
+Resize(w)
+Widget w;
+{
+ /*
+ * The sole purpose of this function is to force an initial
+ * layout by handling a call from some child widget. Ick.
+ */
+
+ if (XtIsSubclass(w, smeBSBObjectClass))
+ {
+ Widget parent = XtParent(w);
+
+ if (!XtIsRealized(parent))
+ XtRealizeWidget(parent);
+
+ Layout(w, (Dimension *)NULL, (Dimension *)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, args, num_args)
+Widget current, request, new;
+ArgList args;
+Cardinal *num_args;
+{
+ 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 arglist[1];
+
+ XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
+ XtSetValues((Widget) smw_new->simple_menu.label, arglist, 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 (smw_old->simple_menu.left_whitespace != smw_new->simple_menu.left_whitespace) {
+ layout = TRUE;
+ ret_val = TRUE;
+ }
+
+ if (smw_old->simple_menu.right_whitespace != smw_new->simple_menu.right_whitespace) {
+ layout = TRUE;
+ ret_val = TRUE;
+ }
+
+ if (layout)
+ Layout(new, (Dimension *)NULL, (Dimension *)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;
+{
+ 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 ) {
+ entry->rectangle.width = old_width;
+ entry->rectangle.height = old_height;
+ }
+ else {
+ /* Actually perform the layout */
+ Layout(( Widget) smw, (Dimension *)NULL, (Dimension *)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, (Dimension *)NULL, (Dimension *)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];
+ (void) 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];
+ (void) 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, (XPoint *)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;
+ SimpleMenuWidget sub = (SimpleMenuWidget) smw->simple_menu.sub_menu;
+ SmeObject entry = smw->simple_menu.entry_set;
+ SmeObjectClass class;
+ int old_pos;
+
+ if (entry == NULL || entry == GetEventEntry(w, event)) {
+ smw->simple_menu.entry_set = NULL;
+ PopdownSubMenu(smw);
+ return;
+ }
+
+ if (event->xcrossing.y < 0 || event->xcrossing.y >= (int)smw->core.height)
+ PopdownSubMenu(smw);
+ else if (sub &&
+ ((event->xcrossing.x < 0 &&
+ !(sub->simple_menu.state & SMW_POPLEFT)) ||
+ (event->xcrossing.x >= (int)smw->core.width &&
+ (sub->simple_menu.state & SMW_POPLEFT))))
+ PopdownSubMenu(smw);
+
+ smw->simple_menu.entry_set = NULL;
+ class = (SmeObjectClass) entry->object.widget_class;
+
+ /* backup, then restore, original entry position */
+ old_pos = entry->rectangle.y;
+ entry->rectangle.y -= smw->simple_menu.first_y;
+
+ (class->sme_class.unhighlight) ((Widget) entry);
+
+ entry->rectangle.y = old_pos;
+}
+
+/* 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;
+ int old_pos;
+
+ if (!XtIsSensitive(w)) return;
+
+ entry = GetEventEntry(w, event);
+ if (entry == smw->simple_menu.entry_set)
+ return;
+
+ PopdownSubMenu(smw);
+ Unhighlight(w, event, params, num_params);
+
+ if (entry == NULL)
+ return;
+ if (!XtIsSensitive((Widget) entry)) {
+ smw->simple_menu.entry_set = NULL;
+ return;
+ }
+
+ if (!(smw->simple_menu.state & SMW_UNMAPPING)) {
+ smw->simple_menu.entry_set = entry;
+ class = (SmeObjectClass) entry->object.widget_class;
+
+ /* backup, then restore, original entry position */
+ old_pos = entry->rectangle.y;
+ entry->rectangle.y -= smw->simple_menu.first_y;
+
+ (class->sme_class.highlight) ((Widget) entry);
+ if (XtIsSubclass((Widget)entry, smeBSBObjectClass))
+ PopupSubMenu(smw);
+
+ entry->rectangle.y = old_pos;
+ }
+}
+
+/* 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
+#if NeedFunctionPrototypes
+XawSimpleMenuAddGlobalActions(XtAppContext app_con)
+#else
+XawSimpleMenuAddGlobalActions(app_con)
+XtAppContext app_con;
+#endif
+{
+ 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
+#if NeedFunctionPrototypes
+XawSimpleMenuGetActiveEntry(Widget w)
+#else
+XawSimpleMenuGetActiveEntry(w)
+Widget w;
+#endif
+{
+ 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
+#if NeedFunctionPrototypes
+XawSimpleMenuClearActiveEntry(Widget w)
+#else
+XawSimpleMenuClearActiveEntry(w)
+Widget w;
+#endif
+{
+ 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;
+ Widget * child, * next_child;
+ int i;
+ Arg args[2];
+
+ if ( (smw->simple_menu.label_string == NULL) ||
+ (smw->simple_menu.label != NULL) ) {
+ char error_buf[BUFSIZ];
+
+ (void) 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;
+ ThreeDWidget tdw;
+ 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;
+ }
+ tdw = (ThreeDWidget)smw->simple_menu.threeD;
+
+ do_layout |= (current_entry != NULL);
+ 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 + tdw->threeD.shadow_width;
+
+ 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 + tdw->threeD.shadow_width;
+ }
+ else if (smw->simple_menu.row_height != 0 &&
+ current_entry != smw->simple_menu.label)
+ {
+ height = smw->simple_menu.row_height * smw->composite.num_children;
+ height += tdw->threeD.shadow_width * 2;
+ }
+
+ if (smw->simple_menu.menu_width)
+ width = smw->core.width;
+ else if (allow_change_size)
+ {
+ SetMarginWidths((Widget)smw);
+
+ width = GetMenuWidth((Widget)smw, (Widget)NULL);
+ }
+ 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;
+XPointer 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;
+{
+ 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;
+
+ 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];
+ (void) sprintf(error_buf, "%s %s", "Xaw Simple Menu Widget:",
+ "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;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ Arg arglist[2];
+
+ 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) {
+ int scr_width = WidthOfScreen(XtScreen(w));
+ if (x + width > scr_width)
+ x = scr_width - width;
+ }
+ if (x < 0)
+ x = 0;
+
+ if (y >= 0) {
+ int scr_height = HeightOfScreen(XtScreen(w));
+ if (y + height > scr_height)
+ y = scr_height - height;
+ }
+ if (y < 0)
+ y = 0;
+ }
+
+ XtSetArg(arglist[0], XtNx, x);
+ XtSetArg(arglist[1], XtNy, y);
+ XtSetValues(w, arglist, TWO);
+}
+
+/* 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;
+XtPointer 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,
+ XtLastTimestampProcessed(XtDisplay(w)));
+}
+
+/* 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;
+
+ if ( !smw->simple_menu.recursive_set_values ) {
+ if ( (smw->core.width != width) || (smw->core.height != height) ) {
+ Arg arglist[2];
+
+ smw->simple_menu.recursive_set_values = TRUE;
+ XtSetArg(arglist[0], XtNwidth, width);
+ XtSetArg(arglist[1], XtNheight, height);
+ XtSetValues(w, arglist, TWO);
+ }
+ else if (XtIsRealized( (Widget) smw))
+ Redisplay((Widget) smw, (XEvent *) NULL, (Region) NULL);
+ }
+ smw->simple_menu.recursive_set_values = FALSE;
+}
+
+/*
+ * Function Name: SetMarginWidths()
+ * Description: Set new margin values for all menu children.
+ * Arguments: w - the simple menu widget
+ * w_ent - the current menu entry
+ */
+static void
+SetMarginWidths(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget)w;
+ SmeObject *entry;
+ SmeBSBObject bsb_entry;
+ Dimension l_mrgn, l_bmw, r_mrgn, r_bmw;
+
+ if (smw->simple_menu.left_whitespace || smw->simple_menu.right_whitespace)
+ {
+ /* determine the widest bitmaps */
+ l_bmw = r_bmw = (Dimension)0;
+ ForAllChildren(smw, entry)
+ {
+ if (!XtIsManaged((Widget)*entry)) continue;
+ if (*entry == smw->simple_menu.label) continue;
+ if (XtIsSubclass((Widget)*entry, smeLineObjectClass))
+ continue;
+
+ bsb_entry = (SmeBSBObject)&((*entry)->object);
+ if (bsb_entry->sme_bsb.left_bitmap_width > l_bmw)
+ l_bmw = bsb_entry->sme_bsb.left_bitmap_width;
+ if (bsb_entry->sme_bsb.right_bitmap_width > r_bmw)
+ r_bmw = bsb_entry->sme_bsb.right_bitmap_width;
+ }
+
+ /* set the margin values */
+ if (smw->simple_menu.left_whitespace)
+ l_mrgn = l_bmw +
+ (smw->simple_menu.left_whitespace * ((l_bmw) ? 2 : 1));
+ if (smw->simple_menu.right_whitespace)
+ r_mrgn = r_bmw +
+ (smw->simple_menu.right_whitespace * ((r_bmw) ? 2 : 1));
+
+ /* make all the margins uniform */
+ ForAllChildren(smw, entry)
+ {
+ if (!XtIsManaged((Widget)*entry)) continue;
+ if (*entry == smw->simple_menu.label) continue;
+ if (XtIsSubclass((Widget)*entry, smeLineObjectClass))
+ continue;
+
+ bsb_entry = (SmeBSBObject)&((*entry)->object);
+ if (smw->simple_menu.left_whitespace)
+ bsb_entry->sme_bsb.left_margin = l_mrgn;
+ if (smw->simple_menu.right_whitespace)
+ bsb_entry->sme_bsb.right_margin = r_mrgn;
+ }
+ }
+}
+
+/* Function Name: GetMenuWidth
+ * Description: Sets the width to the widest entry in pixels.
+ * Arguments: w - the simple menu widget.
+ * w_ent - the current menu entry.
+ * 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, (XtWidgetGeometry *)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 height to all the entries in pixels.
+ * Arguments: w - the simple menu widget.
+ * Returns: height of menu.
+ */
+
+static Dimension
+GetMenuHeight(w)
+Widget w;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget) w;
+ ThreeDWidget tdw = (ThreeDWidget) smw->simple_menu.threeD;
+ 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;
+ height += tdw->threeD.shadow_width * 2;
+
+ 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 = 0, y_loc = 0;
+ SimpleMenuWidget smw = (SimpleMenuWidget)w;
+ SmeObject *entry;
+ static XPoint last_pos;
+ XPoint pos;
+ int s = ((ThreeDWidget)smw->simple_menu.threeD)->threeD.shadow_width;
+
+ switch (event->type) {
+ case MotionNotify:
+ x_loc = event->xmotion.x;
+ y_loc = event->xmotion.y;
+ pos.y = event->xmotion.y_root;
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ x_loc = event->xcrossing.x;
+ y_loc = event->xcrossing.y;
+ pos.y = event->xcrossing.y_root;
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ x_loc = event->xbutton.x;
+ y_loc = event->xbutton.y;
+ pos.y = event->xbutton.y_root;
+ break;
+ default:
+ XtAppError(XtWidgetToApplicationContext(w),
+ "Unknown event type in GetEventEntry().");
+ break;
+ }
+
+ if (x_loc < 0 || x_loc >= (int)smw->core.width)
+ return NULL;
+ else if (smw->simple_menu.too_tall) {
+ if (pos.y >= smw->simple_menu.last_y && smw->simple_menu.didnt_fit) {
+ if (last_pos.y && pos.y < last_pos.y) {
+ last_pos.y = pos.y;
+ return NULL;
+ }
+ smw->simple_menu.current_first += smw->simple_menu.jump_val;
+ Redisplay(w, (XEvent *)NULL, (Region)NULL);
+ last_pos.y = pos.y;
+ return NULL;
+ } else if (pos.y <= s + SMW_ARROW_SIZE &&
+ smw->simple_menu.first_entry != smw->simple_menu.current_first)
+ {
+ if (pos.y && (!last_pos.y || pos.y > last_pos.y)) {
+ last_pos.y = pos.y;
+ return NULL;
+ }
+ smw->simple_menu.current_first -= smw->simple_menu.jump_val;
+ Redisplay(w, (XEvent *)NULL, (Region)NULL);
+ last_pos.y = pos.y;
+ return NULL;
+ }
+ else
+ last_pos.y = 0;
+ } else if (y_loc < 0 || y_loc >= (int)smw->core.height)
+ return NULL;
+
+ ForAllChildren(smw, entry) {
+ int tmp_y;
+
+ if (!XtIsManaged((Widget)*entry)) continue;
+
+ tmp_y = (*entry)->rectangle.y - smw->simple_menu.first_y;
+ if (tmp_y < y_loc && tmp_y + (int)(*entry)->rectangle.height > y_loc) {
+ if (*entry == smw->simple_menu.label)
+ return NULL; /* cannot select the label */
+ else
+ return *entry;
+ }
+ }
+
+ return NULL;
+}
+
+/*ARGSUSED*/
+static void
+PopupCB(w, client_data, call_data)
+Widget w;
+XtPointer client_data, call_data;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget)w;
+
+ smw->simple_menu.state &= ~SMW_UNMAPPING;
+}
+
+static void
+PopupSubMenu(smw)
+SimpleMenuWidget smw;
+{
+ Widget menu;
+ SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set;
+ Position menu_x, menu_y;
+ Bool popleft;
+ Arg args[2];
+
+ if (entry->sme_bsb.menu_name == NULL)
+ return;
+
+ if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL)
+ return;
+
+ smw->simple_menu.sub_menu = menu;
+
+ if (!XtIsRealized(menu))
+ XtRealizeWidget(menu);
+
+ popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0;
+
+ if (popleft)
+ XtTranslateCoords((Widget)smw, -(int)XtWidth(menu),
+ XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y);
+ else
+ XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry)
+ - XtBorderWidth(menu), &menu_x, &menu_y);
+
+ if (!popleft && menu_x >= 0) {
+ int scr_width = WidthOfScreen(XtScreen(menu));
+
+ if (menu_x + XtWidth(menu) > scr_width) {
+ menu_x -= XtWidth(menu) + XtWidth(smw);
+ popleft = True;
+ }
+ }
+ else if (popleft && menu_x < 0) {
+ menu_x = 0;
+ popleft = False;
+ }
+
+ if (menu_y >= 0) {
+ ThreeDWidget tdw =
+ (ThreeDWidget)((SimpleMenuWidget)menu)->simple_menu.threeD;
+ int scr_height = HeightOfScreen(XtScreen(menu));
+
+ if (menu_y + XtHeight(menu) > scr_height)
+ menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu);
+
+ menu_y -= tdw->threeD.shadow_width;
+ }
+ if (menu_y < 0)
+ menu_y = 0;
+
+ XtSetArg(args[0], XtNx, menu_x);
+ XtSetArg(args[1], XtNy, menu_y);
+ XtSetValues(menu, args, TWO);
+
+ if (popleft)
+ ((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT;
+ else
+ ((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT;
+
+ XtPopup(menu, XtGrabNone);
+}
+
+static void
+Popdown(w, event, params, num_params)
+Widget w;
+XEvent *event;
+String *params;
+Cardinal *num_params;
+{
+ SimpleMenuWidget smw = (SimpleMenuWidget)w;
+
+ while (XtParent(w) &&
+ XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) {
+ if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w)
+ {
+ w = XtParent(w);
+ smw = (SimpleMenuWidget)w;
+ smw->simple_menu.entry_set = NULL;
+ }
+ else
+ break;
+ }
+
+ smw->simple_menu.state |= SMW_UNMAPPING;
+ PopdownSubMenu(smw);
+
+ XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params);
+}
+
+static void
+PopdownSubMenu(smw)
+SimpleMenuWidget smw;
+{
+ SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu;
+
+ if (!menu) return;
+
+ menu->simple_menu.state &= ~SMW_POPLEFT;
+ menu->simple_menu.state |= SMW_UNMAPPING;
+ PopdownSubMenu(menu);
+
+ XtPopdown((Widget)menu);
+
+ smw->simple_menu.sub_menu = NULL;
+}
+