2 Copyright 1989, 1994, 1998 The Open Group
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 Except as contained in this notice, the name of The Open Group shall not be
21 used in advertising or otherwise to promote the sale, use or other dealings
22 in this Software without prior written authorization from The Open Group.
26 * SimpleMenu.c - Source code file for SimpleMenu widget.
30 * By: Chris D. Peterson
32 * kit@expo.lcs.mit.edu
39 #include <X11/IntrinsicP.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xmu/Initer.h>
42 #include <X11/Xmu/SysUtil.h>
43 #include <X11/Xaw/Cardinals.h>
44 #include <X11/Xaw/SimpleMenP.h>
45 #include <X11/Xaw/SmeBSBP.h>
46 #include <X11/Xaw/XawInit.h>
49 #define streq(a, b) (strcmp((a), (b)) == 0)
51 #define ForAllChildren(smw, childP) \
52 for ((childP) = (SmeObject *)(smw)->composite.children; \
53 (childP) < (SmeObject *)((smw)->composite.children \
54 + (smw)->composite.num_children); \
58 #define SMW_UNMAPPING 0x01
59 #define SMW_POPLEFT 0x02
65 static void XawSimpleMenuChangeManaged(Widget);
66 static void XawSimpleMenuClassInitialize(void);
67 static void XawSimpleMenuClassPartInitialize(WidgetClass);
68 static XtGeometryResult XawSimpleMenuGeometryManager(Widget, XtWidgetGeometry*,
70 static void XawSimpleMenuInitialize(Widget, Widget, ArgList, Cardinal*);
71 static void XawSimpleMenuRealize(Widget, XtValueMask*, XSetWindowAttributes*);
72 static void XawSimpleMenuRedisplay(Widget, XEvent*, Region);
73 static void XawSimpleMenuResize(Widget);
74 static Boolean XawSimpleMenuSetValues(Widget, Widget, Widget,
76 static Boolean XawSimpleMenuSetValuesHook(Widget, ArgList, Cardinal*);
78 static void PopupSubMenu(SimpleMenuWidget);
79 static void PopdownSubMenu(SimpleMenuWidget);
80 static void PopupCB(Widget, XtPointer, XtPointer);
86 static void AddPositionAction(XtAppContext, XPointer);
87 static void CalculateNewSize(Widget, Dimension*, Dimension*);
88 static void ChangeCursorOnGrab(Widget, XtPointer, XtPointer);
89 static void CreateLabel(Widget);
90 static SmeObject DoGetEventEntry(Widget, int, int);
91 static Widget FindMenu(Widget, String);
92 static SmeObject GetEventEntry(Widget, XEvent*);
93 static void Layout(Widget, Dimension*, Dimension*);
94 static void MakeResizeRequest(Widget);
95 static void MakeSetValuesRequest(Widget, unsigned int, unsigned int);
96 static void MoveMenu(Widget, int, int);
97 static void PositionMenu(Widget, XPoint*);
102 static void Highlight(Widget, XEvent*, String*, Cardinal*);
103 static void Notify(Widget, XEvent*, String*, Cardinal*);
105 static void Popdown(Widget, XEvent*, String*, Cardinal*);
107 static void PositionMenuAction(Widget, XEvent*, String*, Cardinal*);
108 static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
113 #define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field)
115 static XtResource resources[] = {
122 offset(label_string),
160 offset(bottom_margin),
167 XtCHorizontalMargins,
176 XtCHorizontalMargins,
179 offset(right_margin),
191 XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
209 offset(menu_on_screen),
227 offset(backing_store),
229 (XtPointer)(Always + WhenMapped + NotUseful)
236 sizeof(XawDisplayList*),
237 offset(display_list),
245 static char defaultTranslations[] =
246 "<Enter>:" "highlight()\n"
247 "<Leave>:" "unhighlight()\n"
248 "<BtnMotion>:" "highlight()\n"
250 "<BtnUp>:" "popdown() notify() unhighlight()\n"
252 "<BtnUp>:" "MenuPopdown() notify() unhighlight()\n"
256 static XtActionsRec actionsList[] =
259 {"highlight", Highlight},
260 {"unhighlight", Unhighlight},
262 {"popdown", Popdown},
263 {"set-values", XawSetValuesAction},
264 {"get-values", XawGetValuesAction},
265 {"declare", XawDeclareAction},
266 {"call-proc", XawCallProcAction},
270 static CompositeClassExtensionRec extension_rec = {
271 NULL, /* next_extension */
272 NULLQUARK, /* record_type */
273 XtCompositeExtensionVersion, /* version */
274 sizeof(CompositeClassExtensionRec), /* record_size */
275 True, /* accepts_objects */
278 #define Superclass (&overrideShellClassRec)
279 SimpleMenuClassRec simpleMenuClassRec = {
282 (WidgetClass)Superclass, /* superclass */
283 "SimpleMenu", /* class_name */
284 sizeof(SimpleMenuRec), /* size */
285 XawSimpleMenuClassInitialize, /* class_initialize */
286 XawSimpleMenuClassPartInitialize, /* class_part_initialize */
287 False, /* class_inited */
288 XawSimpleMenuInitialize, /* initialize */
289 NULL, /* initialize_hook */
290 XawSimpleMenuRealize, /* realize */
291 actionsList, /* actions */
292 XtNumber(actionsList), /* num_actions */
293 resources, /* resources */
294 XtNumber(resources), /* num_resources */
295 NULLQUARK, /* xrm_class */
296 True, /* compress_motion */
297 True, /* compress_exposure */
298 True, /* compress_enterleave */
299 False, /* visible_interest */
301 XawSimpleMenuResize, /* resize */
302 XawSimpleMenuRedisplay, /* expose */
303 XawSimpleMenuSetValues, /* set_values */
304 XawSimpleMenuSetValuesHook, /* set_values_hook */
305 XtInheritSetValuesAlmost, /* set_values_almost */
306 NULL, /* get_values_hook */
307 NULL, /* accept_focus */
308 XtVersion, /* intrinsics version */
309 NULL, /* callback offsets */
310 defaultTranslations, /* tm_table */
311 NULL, /* query_geometry */
312 NULL, /* display_accelerator */
313 NULL, /* extension */
317 XawSimpleMenuGeometryManager, /* geometry_manager */
318 XawSimpleMenuChangeManaged, /* change_managed */
319 XtInheritInsertChild, /* insert_child */
320 XtInheritDeleteChild, /* delete_child */
321 NULL, /* extension */
325 NULL, /* extension */
329 NULL, /* extension */
333 NULL, /* extension */
337 WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
344 * XawSimpleMenuClassInitialize
347 * Class Initialize routine, called only once.
350 XawSimpleMenuClassInitialize(void)
352 XawInitializeWidgetSet();
353 XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
355 XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
356 NULL, 0, XtCacheNone, NULL);
357 XmuAddInitializer(AddPositionAction, NULL);
362 * XawSimpleMenuClassPartInitialize
363 * Arguments: wc - the widget class of the subclass.
366 * Class Part Initialize routine, called for every subclass. Makes
367 * sure that the subclasses pick up the extension record.
370 XawSimpleMenuClassPartInitialize(WidgetClass wc)
372 SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass)wc;
375 * Make sure that our subclass gets the extension rec too
377 extension_rec.next_extension = smwc->composite_class.extension;
378 smwc->composite_class.extension = (XtPointer) &extension_rec;
383 * XawSimpleMenuInitialize
386 * request - widget requested by the argument list
387 * cnew - new widget with both resource and non resource values
390 * Initializes the simple menu widget.
394 XawSimpleMenuInitialize(Widget request, Widget cnew,
395 ArgList args, Cardinal *num_args)
397 SimpleMenuWidget smw = (SimpleMenuWidget)cnew;
398 Dimension width, height;
400 XmuCallInitializers(XtWidgetToApplicationContext(cnew));
402 if (smw->simple_menu.label_class == NULL)
403 smw->simple_menu.label_class = smeBSBObjectClass;
405 smw->simple_menu.label = NULL;
406 smw->simple_menu.entry_set = NULL;
407 smw->simple_menu.recursive_set_values = False;
409 smw->simple_menu.sub_menu = NULL;
410 smw->simple_menu.state = 0;
412 XtAddCallback(cnew, XtNpopupCallback, PopupCB, NULL);
415 if (smw->simple_menu.label_string != NULL)
419 CalculateNewSize(cnew, &width, &height);
421 smw->simple_menu.menu_width = True;
423 if (XtWidth(smw) == 0) {
424 smw->simple_menu.menu_width = False;
425 XtWidth(smw) = width;
428 smw->simple_menu.menu_height = True;
430 if (XtHeight(smw) == 0) {
431 smw->simple_menu.menu_height = False;
432 XtHeight(smw) = height;
436 * Add a popup_callback routine for changing the cursor
438 XtAddCallback(cnew, XtNpopupCallback, ChangeCursorOnGrab, NULL);
443 * XawSimpleMenuRedisplay
446 * w - simple menu widget
447 * event - X event that caused this redisplay
448 * region - region the needs to be repainted
451 * Redisplays the contents of the widget.
455 XawSimpleMenuRedisplay(Widget w, XEvent *event, Region region)
457 SimpleMenuWidget smw = (SimpleMenuWidget)w;
459 SmeObjectClass cclass;
462 XClearWindow(XtDisplay(w), XtWindow(w));
465 if (smw->simple_menu.display_list)
466 XawRunDisplayList(w, smw->simple_menu.display_list, event, region);
470 * Check and Paint each of the entries - including the label
472 ForAllChildren(smw, entry) {
473 if (!XtIsManaged((Widget)*entry))
477 switch(XRectInRegion(region, XtX(*entry),XtY(*entry),
478 XtWidth(*entry), XtHeight(*entry))) {
486 cclass = (SmeObjectClass)(*entry)->object.widget_class;
488 if (cclass->rect_class.expose != NULL)
489 (cclass->rect_class.expose)((Widget)*entry, NULL, NULL);
495 * XawSimpleMenuRealize
498 * w - simple menu widget
499 * mask - value mask for the window to create
500 * attrs - attributes for the window to create
503 * Realizes the widget.
506 XawSimpleMenuRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
508 SimpleMenuWidget smw = (SimpleMenuWidget)w;
513 attrs->cursor = smw->simple_menu.cursor;
515 if (smw->simple_menu.backing_store == Always ||
516 smw->simple_menu.backing_store == NotUseful ||
517 smw->simple_menu.backing_store == WhenMapped) {
518 *mask |= CWBackingStore;
519 attrs->backing_store = smw->simple_menu.backing_store;
522 *mask &= ~CWBackingStore;
524 (*Superclass->core_class.realize)(w, mask, attrs);
527 if (w->core.background_pixmap > XtUnspecifiedPixmap) {
528 pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
529 w->core.colormap, w->core.depth);
530 if (pixmap && pixmap->mask)
531 XawReshapeWidget(w, pixmap);
538 * XawSimpleMenuResize
541 * w - simple menu widget
544 * Handle the menu being resized.
547 XawSimpleMenuResize(Widget w)
549 if (!XtIsRealized(w))
552 Layout(w, NULL, NULL);
554 XawSimpleMenuRedisplay(w, NULL, NULL);
559 * XawSimpleMenuSetValues
562 * current - current state of the widget
563 * request - what was requested
564 * cnew - what the widget will become
567 * Relayout the menu when one of the resources is changed.
571 XawSimpleMenuSetValues(Widget current, Widget request, Widget cnew,
572 ArgList args, Cardinal *num_args)
574 SimpleMenuWidget smw_old = (SimpleMenuWidget)current;
575 SimpleMenuWidget smw_new = (SimpleMenuWidget)cnew;
576 Boolean ret_val = False, layout = False;
578 if (!XtIsRealized(current))
581 if (!smw_new->simple_menu.recursive_set_values) {
582 if (XtWidth(smw_new) != XtWidth(smw_old)) {
583 smw_new->simple_menu.menu_width = XtWidth(smw_new) != 0;
586 if (XtHeight(smw_new) != XtHeight(smw_old)) {
587 smw_new->simple_menu.menu_height = XtHeight(smw_new) != 0;
592 if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
593 XDefineCursor(XtDisplay(cnew), XtWindow(cnew),
594 smw_new->simple_menu.cursor);
596 if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) {
597 if (smw_new->simple_menu.label_string == NULL) /* Destroy */
598 XtDestroyWidget((Widget)smw_old->simple_menu.label);
599 else if (smw_old->simple_menu.label_string == NULL) /* Create */
604 XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
605 XtSetValues((Widget)smw_new->simple_menu.label, arglist, ONE);
609 if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
610 XtAppWarning(XtWidgetToApplicationContext(cnew),
611 "No Dynamic class change of the SimpleMenu Label.");
613 if (smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin
614 || smw_old->simple_menu.bottom_margin
615 != smw_new->simple_menu.bottom_margin) {
621 if (smw_old->core.background_pixmap != smw_new->core.background_pixmap) {
622 XawPixmap *opix, *npix;
624 opix = XawPixmapFromXPixmap(smw_old->core.background_pixmap,
625 XtScreen(smw_old), smw_old->core.colormap,
626 smw_old->core.depth);
627 npix = XawPixmapFromXPixmap(smw_new->core.background_pixmap,
628 XtScreen(smw_new), smw_new->core.colormap,
629 smw_new->core.depth);
630 if ((npix && npix->mask) || (opix && opix->mask))
631 XawReshapeWidget(cnew, npix);
636 Layout(cnew, NULL, NULL);
643 * XawSimpleMenuSetValuesHook
647 * arglist - argument list passed to XtSetValues
648 * num_args - number of args
651 * To handle a special case, this is passed the actual arguments.
654 XawSimpleMenuSetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
657 Dimension width, height;
660 height = XtHeight(w);
662 for (i = 0 ; i < *num_args ; i++) {
663 if (streq(arglist[i].name, XtNwidth))
664 width = (Dimension)arglist[i].value;
665 if (streq(arglist[i].name, XtNheight))
666 height = (Dimension) arglist[i].value;
669 if (width != XtWidth(w) || height != XtHeight(w))
670 MakeSetValuesRequest(w, width, height);
676 * Geometry Management routines
680 * XawSimpleMenuGeometryManager
683 * w - Menu Entry making the request
684 * request - requested new geometry
685 * reply - the allowed geometry.
688 * This is the SimpleMenu Widget's Geometry Manager.
691 * XtGeometry{Yes, No, Almost}
693 static XtGeometryResult
694 XawSimpleMenuGeometryManager(Widget w, XtWidgetGeometry *request,
695 XtWidgetGeometry *reply)
697 SimpleMenuWidget smw = (SimpleMenuWidget)XtParent(w);
698 SmeObject entry = (SmeObject)w;
699 XtGeometryMask mode = request->request_mode;
700 XtGeometryResult answer;
701 Dimension old_height, old_width;
703 if (!(mode & CWWidth) && !(mode & CWHeight))
704 return (XtGeometryNo);
706 reply->width = request->width;
707 reply->height = request->height;
709 old_width = XtWidth(entry);
710 old_height = XtHeight(entry);
712 Layout(w, &reply->width, &reply->height);
715 * Since we are an override shell and have no parent there is no one to
716 * ask to see if this geom change is okay, so I am just going to assume
717 * we can do whatever we want. If you subclass be very careful with this
718 * assumption, it could bite you.
720 * Chris D. Peterson - Sept. 1989.
722 if ((!(mode & CWWidth) || reply->width == request->width)
723 && (!(mode & CWHeight) || reply->height == request->height)) {
724 if (mode & XtCWQueryOnly) { /* Actually perform the layout */
725 XtWidth(entry) = old_width;
726 XtHeight(entry) = old_height;
729 Layout((Widget)smw, NULL, NULL);
730 answer = XtGeometryDone;
733 XtWidth(entry) = old_width;
734 XtHeight(entry) = old_height;
736 if ((reply->width == request->width && !(mode & CWHeight))
737 || (reply->height == request->height && !(mode & CWWidth))
738 || (reply->width == request->width
739 && reply->height == request->height))
740 answer = XtGeometryNo;
742 answer = XtGeometryAlmost;
743 reply->request_mode = 0;
744 if (reply->width != request->width)
745 reply->request_mode |= CWWidth;
746 if (reply->height != request->height)
747 reply->request_mode |= CWHeight;
756 * XawSimpleMenuChangeManaged
759 * w - simple menu widget
762 * Called whenever a new child is managed.
765 XawSimpleMenuChangeManaged(Widget w)
767 Layout(w, NULL, NULL);
771 * Global Action Routines
773 * These actions routines will be added to the application's
781 * w - a widget (no the simple menu widget)
782 * event - the event that caused this action
783 * params - parameters passed to the routine.
784 * we expect the name of the menu here.
788 * Positions the simple menu widget.
792 PositionMenuAction(Widget w, XEvent *event,
793 String *params, Cardinal *num_params)
798 if (*num_params != 1) {
799 XtAppWarning(XtWidgetToApplicationContext(w),
800 "SimpleMenuWidget: position menu action expects "
801 "only one parameter which is the name of the menu.");
805 if ((menu = FindMenu(w, params[0])) == NULL) {
806 char error_buf[BUFSIZ];
808 (void)XmuSnprintf(error_buf, sizeof(error_buf),
809 "SimpleMenuWidget: could not find menu named %s.",
811 XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
815 switch (event->type) {
818 loc.x = event->xbutton.x_root;
819 loc.y = event->xbutton.y_root;
820 PositionMenu(menu, &loc);
824 loc.x = event->xcrossing.x_root;
825 loc.y = event->xcrossing.y_root;
826 PositionMenu(menu, &loc);
829 loc.x = event->xmotion.x_root;
830 loc.y = event->xmotion.y_root;
831 PositionMenu(menu, &loc);
834 PositionMenu(menu, NULL);
840 * Widget Action Routines
847 * w - simple menu widget
848 * event - event that caused this action
853 * Unhighlights current entry.
857 Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
859 SimpleMenuWidget smw = (SimpleMenuWidget)w;
860 SmeObject entry = smw->simple_menu.entry_set;
866 if (!smw->simple_menu.sub_menu)
869 SmeObjectClass cclass;
871 smw->simple_menu.entry_set = NULL;
872 cclass = (SmeObjectClass)entry->object.widget_class;
873 (cclass->sme_class.unhighlight)((Widget)entry);
882 * w - simple menu widget
883 * event - event that caused this action
888 * Highlights current entry.
892 Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
894 SimpleMenuWidget smw = (SimpleMenuWidget)w;
897 if (!XtIsSensitive(w))
900 entry = GetEventEntry(w, event);
902 if (entry == smw->simple_menu.entry_set)
906 if (!smw->simple_menu.sub_menu)
908 Unhighlight(w, event, params, num_params);
913 if (!XtIsSensitive((Widget)entry))
917 if (smw->simple_menu.sub_menu)
921 Unhighlight(w, event, params, num_params);
924 if (!(smw->simple_menu.state & SMW_UNMAPPING))
927 SmeObjectClass cclass;
929 smw->simple_menu.entry_set = entry;
930 cclass = (SmeObjectClass)entry->object.widget_class;
932 (cclass->sme_class.highlight)((Widget)entry);
935 if (XtIsSubclass((Widget)entry, smeBSBObjectClass))
946 * w - simple menu widget
947 * event - event that caused this action
952 * Notify user of current entry.
956 Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
959 SmeObjectClass cclass;
961 /* may be a propagated event from a sub menu, need to check it */
962 if (XtWindow(w) != event->xany.window)
964 entry = GetEventEntry(w, event);
965 if (entry == NULL || !XtIsSensitive((Widget)entry))
968 cclass = (SmeObjectClass) entry->object.widget_class;
969 (cclass->sme_class.notify)((Widget)entry);
977 * XawSimpleMenuAddGlobalActions
980 * app_con - appcontext
983 * Adds the global actions to the simple menu widget.
986 XawSimpleMenuAddGlobalActions(XtAppContext app_con)
988 XtInitializeWidgetClass(simpleMenuWidgetClass);
989 XmuCallInitializers(app_con);
994 * XawSimpleMenuGetActiveEntry
1000 * Gets the currently active (set) entry.
1003 * The currently set entry or NULL if none is set
1006 XawSimpleMenuGetActiveEntry(Widget w)
1008 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1010 return ((Widget)smw->simple_menu.entry_set);
1015 * XawSimpleMenuClearActiveEntry
1021 * Unsets the currently active (set) entry.
1024 XawSimpleMenuClearActiveEntry(Widget w)
1026 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1028 smw->simple_menu.entry_set = NULL;
1042 * Creates the label object and makes sure it is the first child in
1046 CreateLabel(Widget w)
1048 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1049 Widget *child, *next_child;
1053 if (smw->simple_menu.label_string == NULL ||
1054 smw->simple_menu.label != NULL) {
1055 XtAppWarning(XtWidgetToApplicationContext(w),
1056 "Xaw Simple Menu Widget: label string is NULL or "
1057 "label already exists, no label is being created.");
1061 XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
1062 XtSetArg(args[1], XtNjustify, XtJustifyCenter);
1063 smw->simple_menu.label = (SmeObject)
1064 XtCreateManagedWidget("menuLabel",
1065 smw->simple_menu.label_class, w, args, TWO);
1068 for (child = smw->composite.children + smw->composite.num_children,
1069 i = smw->composite.num_children; i > 0; i--, child--) {
1070 if (next_child != NULL)
1071 *next_child = *child;
1074 *child = (Widget)smw->simple_menu.label;
1083 * width_ret - returned width
1084 * height_ret - returned height
1087 * if width == NULL || height == NULL then it assumes the you do not care
1088 * about the return values, and just want a relayout.
1090 * if this is not the case then it will set width_ret and height_ret
1091 * to be width and height that the child would get if it were layed out
1094 * "w" can be the simple menu widget or any of its object children.
1097 Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
1099 SmeObject current_entry;
1100 SimpleMenuWidget smw;
1101 Dimension width, height;
1102 Boolean allow_change_size;
1104 Cardinal i, count, n;
1105 int width_kid, height_kid, tmp_w, tmp_h;
1106 short vadd, hadd, x_ins, y_ins;
1111 if (XtIsSubclass(w, simpleMenuWidgetClass)) {
1112 smw = (SimpleMenuWidget)w;
1113 current_entry = NULL;
1116 smw = (SimpleMenuWidget)XtParent(w);
1117 current_entry = (SmeObject)w;
1120 allow_change_size = (!XtIsRealized((Widget)smw)
1121 || smw->shell.allow_shell_resize);
1123 for (i = smw->simple_menu.label ? 1 : 0;
1124 i < smw->composite.num_children;
1126 XtWidgetGeometry preferred;
1128 kid = smw->composite.children[i];
1129 if (!XtIsManaged(kid))
1131 if (smw->simple_menu.row_height != 0)
1132 XtHeight(kid) = smw->simple_menu.row_height;
1133 XtQueryGeometry(kid, NULL, &preferred);
1134 if (preferred.request_mode & CWWidth)
1135 XtWidth(kid) = preferred.width;
1138 if (smw->simple_menu.label
1139 && XtIsManaged((Widget)smw->simple_menu.label)) {
1140 XtWidgetGeometry preferred;
1142 kid = (Widget)smw->simple_menu.label;
1143 XtQueryGeometry(kid, NULL, &preferred);
1144 if (preferred.request_mode & CWWidth)
1145 XtWidth(kid) = preferred.width;
1146 if (preferred.request_mode & CWHeight)
1147 XtHeight(kid) = preferred.height;
1151 if (!smw->simple_menu.menu_width)
1153 if (!smw->simple_menu.menu_height)
1155 if (!XtWidth(smw) || !XtHeight(smw))
1156 MakeResizeRequest((Widget)smw);
1158 widths = (Dimension *)XtMalloc(sizeof(Dimension));
1160 hadd = smw->simple_menu.left_margin;
1164 vadd = smw->simple_menu.top_margin;
1165 if (smw->simple_menu.label)
1166 vadd += XtHeight(smw->simple_menu.label);
1169 width = tmp_w = tmp_h = n = 0;
1172 for (i = smw->simple_menu.label ? 1 : 0;
1173 i < smw->composite.num_children;
1175 kid = smw->composite.children[i];
1176 if (!XtIsManaged(kid))
1178 width_kid = XtWidth(kid);
1179 height_kid = XtHeight(kid);
1181 if (n && (height + height_kid + smw->simple_menu.bottom_margin
1184 widths = (Dimension *)XtRealloc((char *)widths,
1185 sizeof(Dimension) * count);
1186 widths[count - 1] = width_kid;
1189 height = height_kid + vadd;
1192 height += height_kid;
1195 if (width_kid > tmp_w)
1196 widths[count - 1] = tmp_w = width_kid;
1200 height = tmp_h + smw->simple_menu.bottom_margin;
1203 if (smw->simple_menu.label && width < XtWidth(smw->simple_menu.label)) {
1206 inc = (XtWidth(smw->simple_menu.label) - width) / (float)count;
1207 width = XtWidth(smw->simple_menu.label);
1208 for (n = 0; n < count; n++)
1213 width += hadd + smw->simple_menu.right_margin;
1216 x_ins = n = count = 0;
1220 for (i = smw->simple_menu.label ? 1 : 0;
1221 i < smw->composite.num_children;
1223 kid = smw->composite.children[i];
1224 if (!XtIsManaged(kid))
1227 height_kid = XtHeight(kid);
1229 if (n && (tmp_h + height_kid + smw->simple_menu.bottom_margin
1234 tmp_w += widths[count];
1235 tmp_h = height_kid + vadd;
1239 tmp_h += height_kid;
1243 XtX(kid) = x_ins + hadd;
1245 XtWidth(kid) = widths[count];
1248 XtFree((char *)widths);
1250 if (allow_change_size)
1251 MakeSetValuesRequest((Widget) smw, width, height);
1253 if (smw->simple_menu.label) {
1254 XtX(smw->simple_menu.label) = 0;
1255 XtY(smw->simple_menu.label) = smw->simple_menu.top_margin;
1256 XtWidth(smw->simple_menu.label) = XtWidth(smw)
1258 - (smw->simple_menu.left_margin + smw->simple_menu.right_margin)
1262 if (current_entry) {
1264 *width_ret = XtWidth(current_entry);
1266 *height_ret = XtHeight(current_entry);
1275 * app_con - application context
1279 * Adds the XawPositionSimpleMenu action to the global
1280 * action list for this appcon.
1284 AddPositionAction(XtAppContext app_con, XPointer data)
1286 static XtActionsRec pos_action[] = {
1287 {"XawPositionSimpleMenu", PositionMenuAction},
1290 XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
1298 * widget - reference widget
1299 * name - menu widget's name
1302 * Find the menu give a name and reference widget
1305 * The menu widget or NULL.
1308 FindMenu(Widget widget, String name)
1312 for (w = widget; w != NULL; w = XtParent(w))
1313 if ((menu = XtNameToWidget(w, name)) != NULL)
1324 * w - simple menu widget
1325 * location - pointer the the position or NULL
1331 PositionMenu(Widget w, XPoint *location)
1333 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1337 if (location == NULL) {
1338 Window temp1, temp2;
1339 int root_x, root_y, tempX, tempY;
1342 location = &t_point;
1343 if (XQueryPointer(XtDisplay(w), XtWindow(w), &temp1, &temp2,
1344 &root_x, &root_y, &tempX, &tempY, &tempM) == False) {
1345 XtAppWarning(XtWidgetToApplicationContext(w),
1346 "Xaw Simple Menu Widget: "
1347 "Could not find location of mouse pointer");
1350 location->x = (short) root_x;
1351 location->y = (short) root_y;
1355 * The width will not be correct unless it is realized
1359 location->x -= XtWidth(w) >> 1;
1361 if (smw->simple_menu.popup_entry == NULL)
1362 entry = smw->simple_menu.label;
1364 entry = smw->simple_menu.popup_entry;
1367 location->y -= XtY(entry) + (XtHeight(entry) >> 1);
1369 MoveMenu(w, location->x, location->y);
1377 * w - simple menu widget
1378 * x - current location of the widget
1382 * Actually moves the menu, may force it to
1383 * to be fully visable if menu_on_screen is True.
1386 MoveMenu(Widget w, int x, int y)
1389 Cardinal num_args = 0;
1390 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1392 if (smw->simple_menu.menu_on_screen) {
1393 int width = XtWidth(w) + (XtBorderWidth(w) << 1);
1394 int height = XtHeight(w) + (XtBorderWidth(w) << 1);
1397 int scr_width = WidthOfScreen(XtScreen(w));
1399 if (x + width > scr_width)
1400 x = scr_width - width;
1406 int scr_height = HeightOfScreen(XtScreen(w));
1408 if (y + height > scr_height)
1409 y = scr_height - height;
1415 XtSetArg(arglist[num_args], XtNx, x); num_args++;
1416 XtSetArg(arglist[num_args], XtNy, y); num_args++;
1417 XtSetValues(w, arglist, num_args);
1422 * ChangeCursorOnGrab
1430 * Changes the cursor on the active grab to the one
1431 * specified in out resource list.
1435 ChangeCursorOnGrab(Widget w, XtPointer temp1, XtPointer temp2)
1437 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1440 * The event mask here is what is currently in the MIT implementation.
1441 * There really needs to be a way to get the value of the mask out
1442 * of the toolkit (CDP 5/26/89).
1444 XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask | ButtonReleaseMask,
1445 smw->simple_menu.cursor,
1446 XtLastTimestampProcessed(XtDisplay(w)));
1451 * MakeSetValuesRequest
1454 * w - simple menu widget
1455 * width - size requested
1459 MakeSetValuesRequest(Widget w, unsigned int width, unsigned int height)
1461 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1463 Cardinal num_args = 0;
1465 if (!smw->simple_menu.recursive_set_values) {
1466 if (XtWidth(smw) != width || XtHeight(smw) != height) {
1467 smw->simple_menu.recursive_set_values = True;
1468 XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
1469 XtSetArg(arglist[num_args], XtNheight, height); num_args++;
1470 XtSetValues(w, arglist, num_args);
1472 else if (XtIsRealized((Widget)smw))
1473 XawSimpleMenuRedisplay((Widget)smw, NULL, NULL);
1475 smw->simple_menu.recursive_set_values = False;
1479 DoGetEventEntry(Widget w, int x_loc, int y_loc)
1481 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1484 ForAllChildren(smw, entry) {
1485 if (!XtIsManaged((Widget)*entry))
1488 if (x_loc > XtX(*entry)
1489 && x_loc <= XtX(*entry) + XtWidth(*entry)
1490 && y_loc > XtY(*entry)
1491 && y_loc <= XtY(*entry) + XtHeight(*entry)) {
1492 if (*entry == smw->simple_menu.label)
1493 return (NULL); /* cannot select the label */
1507 * w - simple menu widget
1511 * Gets an entry given an event that has X and Y coords.
1514 * The entry that this point is in
1517 GetEventEntry(Widget w, XEvent *event)
1519 int x_loc, y_loc, x_root;
1520 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1524 switch (event->type) {
1526 x_loc = event->xmotion.x;
1527 y_loc = event->xmotion.y;
1528 x_root = event->xmotion.x_root;
1532 x_loc = event->xcrossing.x;
1533 y_loc = event->xcrossing.y;
1534 x_root = event->xcrossing.x_root;
1538 x_loc = event->xbutton.x;
1539 y_loc = event->xbutton.y;
1540 x_root = event->xbutton.x_root;
1543 XtAppError(XtWidgetToApplicationContext(w),
1544 "Unknown event type in GetEventEntry().");
1548 if (x_loc < 0 || x_loc >= XtWidth(smw) ||
1549 y_loc < 0 || y_loc >= XtHeight(smw))
1552 /* Move the menu if it's outside the screen, does not check
1553 * smw->simple_menu.menu_on_screen because menus is bigger than screen
1555 if (x_root == WidthOfScreen(XtScreen(w)) - 1 &&
1556 XtX(w) + XtWidth(w) + (XtBorderWidth(w)) > x_root) {
1558 if (smw->simple_menu.entry_set) {
1559 entry = DoGetEventEntry(w,
1560 XtX(smw->simple_menu.entry_set)
1561 + XtWidth(smw->simple_menu.entry_set) + 1,
1563 Unhighlight(w, event, NULL, NULL);
1565 warp = -(int)XtWidth(entry) >> 1;
1566 move = x_loc - XtWidth(entry) - XtX(entry) + XtBorderWidth(w);
1570 move = WidthOfScreen(XtScreen(w)) -
1571 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1576 move = WidthOfScreen(XtScreen(w)) -
1577 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1580 else if (x_root == 0 && XtX(w) < 0) {
1582 if (smw->simple_menu.entry_set) {
1583 entry = DoGetEventEntry(w, XtX(smw->simple_menu.entry_set) - 1,
1585 Unhighlight(w, event, NULL, NULL);
1587 warp = XtWidth(entry) >> 1;
1588 move = x_loc - XtX(entry);
1591 move = x_loc + XtBorderWidth(w);
1594 move = x_loc + XtBorderWidth(w);
1600 XtMoveWidget(w, XtX(w) + move, XtY(w));
1602 XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, warp, 0);
1604 return (DoGetEventEntry(w, x_loc, y_loc));
1608 CalculateNewSize(Widget w, Dimension *width_return, Dimension *height_return)
1610 SimpleMenuWidget xaw = (SimpleMenuWidget)w;
1613 int width_kid, height_kid;
1614 int width, height, tmp_w, tmp_h, max_dim;
1616 int n, columns, test_h, num_children = 0;
1617 Boolean try_layout = False;
1620 hadd = xaw->simple_menu.left_margin + xaw->simple_menu.right_margin;
1624 vadd = xaw->simple_menu.top_margin + xaw->simple_menu.bottom_margin;
1625 if (xaw->simple_menu.label)
1626 vadd += XtHeight(xaw->simple_menu.label);
1629 max_dim = *height_return;
1630 else if (!XtHeight(w)) {
1631 max_dim = HeightOfScreen(XtScreen(w));
1635 max_dim = XtHeight(w);
1638 width = height = tmp_w = tmp_h = n = test_h = 0;
1640 for (i = xaw->simple_menu.label ? 1 : 0;
1641 i < xaw->composite.num_children;
1643 kid = xaw->composite.children[i];
1644 if (!XtIsManaged(kid))
1647 width_kid = XtWidth(kid);
1648 height_kid = XtHeight(kid);
1652 test_h = height_kid;
1653 else if (test_h != height_kid)
1657 if (n && (height + height_kid > max_dim)) {
1661 height = height_kid;
1664 height += height_kid;
1667 if (width_kid > tmp_w)
1672 height = tmp_h + vadd;
1673 width += tmp_w + hadd;
1675 if (xaw->simple_menu.label)
1676 width = XawMax(width, XtWidth(xaw->simple_menu.label) + hadd);
1678 *width_return = width;
1679 *height_return = height;
1681 if (try_layout && columns > 1 && num_children > 2) {
1684 height = test_h * (xaw->simple_menu.label ?
1688 max_dim -= max_dim % test_h;
1689 space = max_dim - (height % max_dim);
1690 if (space >= test_h * columns) {
1691 height = max_dim - space / columns;
1692 if (height % test_h)
1693 height += test_h - (height % test_h);
1694 *height_return = height + vadd;
1695 CalculateNewSize(w, width_return, height_return);
1701 MakeResizeRequest(Widget w)
1704 Dimension width, height;
1707 height = XtHeight(w);
1709 for (tries = 0; tries < 100; tries++) {
1710 CalculateNewSize(w, &width, &height);
1711 if (width == XtWidth(w) && height == XtHeight(w))
1713 if (XtMakeResizeRequest(w, width, height, &width, &height) ==
1721 Popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
1723 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1725 while (XtParent(w) &&
1726 XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) {
1727 if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w) {
1729 smw = (SimpleMenuWidget)w;
1730 smw->simple_menu.entry_set = NULL;
1736 smw->simple_menu.state |= SMW_UNMAPPING;
1737 if (smw->simple_menu.sub_menu)
1738 PopdownSubMenu(smw);
1739 XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params);
1743 PopupSubMenu(SimpleMenuWidget smw)
1748 SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set;
1749 Position menu_x, menu_y;
1752 if (entry->sme_bsb.menu_name == NULL)
1755 if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL)
1758 smw->simple_menu.sub_menu = menu;
1760 if (!XtIsRealized(menu))
1761 XtRealizeWidget(menu);
1763 popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0;
1766 XtTranslateCoords((Widget)smw, -(int)XtWidth(menu),
1767 XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y);
1769 XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry)
1770 - XtBorderWidth(menu), &menu_x, &menu_y);
1772 if (!popleft && menu_x >= 0) {
1773 int scr_width = WidthOfScreen(XtScreen(menu));
1775 if (menu_x + XtWidth(menu) > scr_width) {
1776 menu_x -= XtWidth(menu) + XtWidth(smw);
1780 else if (popleft && menu_x < 0) {
1785 int scr_height = HeightOfScreen(XtScreen(menu));
1787 if (menu_y + XtHeight(menu) > scr_height)
1788 menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu);
1794 XtSetArg(args[num_args], XtNx, menu_x); num_args++;
1795 XtSetArg(args[num_args], XtNy, menu_y); num_args++;
1796 XtSetValues(menu, args, num_args);
1799 ((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT;
1801 ((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT;
1803 XtPopup(menu, XtGrabNone);
1807 PopdownSubMenu(SimpleMenuWidget smw)
1809 SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu;
1814 menu->simple_menu.state |= SMW_UNMAPPING;
1815 PopdownSubMenu(menu);
1817 XtPopdown((Widget)menu);
1819 smw->simple_menu.sub_menu = NULL;
1824 PopupCB(Widget w, XtPointer client_data, XtPointer call_data)
1826 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1828 smw->simple_menu.state &= ~(SMW_UNMAPPING | SMW_POPLEFT);