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/Xaw/Cardinals.h>
43 #include <X11/Xaw/SimpleMenP.h>
44 #include <X11/Xaw/SmeBSBP.h>
45 #include <X11/Xaw/XawInit.h>
48 #define streq(a, b) (strcmp((a), (b)) == 0)
50 #define ForAllChildren(smw, childP) \
51 for ((childP) = (SmeObject *)(smw)->composite.children; \
52 (childP) < (SmeObject *)((smw)->composite.children \
53 + (smw)->composite.num_children); \
57 #define SMW_UNMAPPING 0x01
58 #define SMW_POPLEFT 0x02
64 static void XawSimpleMenuChangeManaged(Widget);
65 static void XawSimpleMenuClassInitialize(void);
66 static void XawSimpleMenuClassPartInitialize(WidgetClass);
67 static XtGeometryResult XawSimpleMenuGeometryManager(Widget, XtWidgetGeometry*,
69 static void XawSimpleMenuInitialize(Widget, Widget, ArgList, Cardinal*);
70 static void XawSimpleMenuRealize(Widget, XtValueMask*, XSetWindowAttributes*);
71 static void XawSimpleMenuRedisplay(Widget, XEvent*, Region);
72 static void XawSimpleMenuResize(Widget);
73 static Boolean XawSimpleMenuSetValues(Widget, Widget, Widget,
75 static Boolean XawSimpleMenuSetValuesHook(Widget, ArgList, Cardinal*);
77 static void PopupSubMenu(SimpleMenuWidget);
78 static void PopdownSubMenu(SimpleMenuWidget);
79 static void PopupCB(Widget, XtPointer, XtPointer);
85 static void AddPositionAction(XtAppContext, XPointer);
86 static void CalculateNewSize(Widget, Dimension*, Dimension*);
87 static void ChangeCursorOnGrab(Widget, XtPointer, XtPointer);
88 static void CreateLabel(Widget);
89 static SmeObject DoGetEventEntry(Widget, int, int);
90 static Widget FindMenu(Widget, String);
91 static SmeObject GetEventEntry(Widget, XEvent*);
92 static void Layout(Widget, Dimension*, Dimension*);
93 static void MakeResizeRequest(Widget);
94 static void MakeSetValuesRequest(Widget, unsigned int, unsigned int);
95 static void MoveMenu(Widget, int, int);
96 static void PositionMenu(Widget, XPoint*);
101 static void Highlight(Widget, XEvent*, String*, Cardinal*);
102 static void Notify(Widget, XEvent*, String*, Cardinal*);
104 static void Popdown(Widget, XEvent*, String*, Cardinal*);
106 static void PositionMenuAction(Widget, XEvent*, String*, Cardinal*);
107 static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
112 #define offset(field) XtOffsetOf(SimpleMenuRec, simple_menu.field)
114 static XtResource resources[] = {
121 offset(label_string),
159 offset(bottom_margin),
166 XtCHorizontalMargins,
175 XtCHorizontalMargins,
178 offset(right_margin),
190 XtOffsetOf(SimpleMenuRec, shell.allow_shell_resize),
208 offset(menu_on_screen),
226 offset(backing_store),
228 (XtPointer)(Always + WhenMapped + NotUseful)
235 sizeof(XawDisplayList*),
236 offset(display_list),
244 static char defaultTranslations[] =
245 "<Enter>:" "highlight()\n"
246 "<Leave>:" "unhighlight()\n"
247 "<BtnMotion>:" "highlight()\n"
249 "<BtnUp>:" "popdown() notify() unhighlight()\n"
251 "<BtnUp>:" "MenuPopdown() notify() unhighlight()\n"
255 static XtActionsRec actionsList[] =
258 {"highlight", Highlight},
259 {"unhighlight", Unhighlight},
261 {"popdown", Popdown},
262 {"set-values", XawSetValuesAction},
263 {"get-values", XawGetValuesAction},
264 {"declare", XawDeclareAction},
265 {"call-proc", XawCallProcAction},
269 static CompositeClassExtensionRec extension_rec = {
270 NULL, /* next_extension */
271 NULLQUARK, /* record_type */
272 XtCompositeExtensionVersion, /* version */
273 sizeof(CompositeClassExtensionRec), /* record_size */
274 True, /* accepts_objects */
277 #define Superclass (&overrideShellClassRec)
278 SimpleMenuClassRec simpleMenuClassRec = {
281 (WidgetClass)Superclass, /* superclass */
282 "SimpleMenu", /* class_name */
283 sizeof(SimpleMenuRec), /* size */
284 XawSimpleMenuClassInitialize, /* class_initialize */
285 XawSimpleMenuClassPartInitialize, /* class_part_initialize */
286 False, /* class_inited */
287 XawSimpleMenuInitialize, /* initialize */
288 NULL, /* initialize_hook */
289 XawSimpleMenuRealize, /* realize */
290 actionsList, /* actions */
291 XtNumber(actionsList), /* num_actions */
292 resources, /* resources */
293 XtNumber(resources), /* num_resources */
294 NULLQUARK, /* xrm_class */
295 True, /* compress_motion */
296 True, /* compress_exposure */
297 True, /* compress_enterleave */
298 False, /* visible_interest */
300 XawSimpleMenuResize, /* resize */
301 XawSimpleMenuRedisplay, /* expose */
302 XawSimpleMenuSetValues, /* set_values */
303 XawSimpleMenuSetValuesHook, /* set_values_hook */
304 XtInheritSetValuesAlmost, /* set_values_almost */
305 NULL, /* get_values_hook */
306 NULL, /* accept_focus */
307 XtVersion, /* intrinsics version */
308 NULL, /* callback offsets */
309 defaultTranslations, /* tm_table */
310 NULL, /* query_geometry */
311 NULL, /* display_accelerator */
312 NULL, /* extension */
316 XawSimpleMenuGeometryManager, /* geometry_manager */
317 XawSimpleMenuChangeManaged, /* change_managed */
318 XtInheritInsertChild, /* insert_child */
319 XtInheritDeleteChild, /* delete_child */
320 NULL, /* extension */
324 NULL, /* extension */
328 NULL, /* extension */
332 NULL, /* extension */
336 WidgetClass simpleMenuWidgetClass = (WidgetClass)&simpleMenuClassRec;
343 * XawSimpleMenuClassInitialize
346 * Class Initialize routine, called only once.
349 XawSimpleMenuClassInitialize(void)
351 XawInitializeWidgetSet();
352 XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
354 XtSetTypeConverter(XtRBackingStore, XtRString, XmuCvtBackingStoreToString,
355 NULL, 0, XtCacheNone, NULL);
356 XmuAddInitializer(AddPositionAction, NULL);
361 * XawSimpleMenuClassPartInitialize
362 * Arguments: wc - the widget class of the subclass.
365 * Class Part Initialize routine, called for every subclass. Makes
366 * sure that the subclasses pick up the extension record.
369 XawSimpleMenuClassPartInitialize(WidgetClass wc)
371 SimpleMenuWidgetClass smwc = (SimpleMenuWidgetClass)wc;
374 * Make sure that our subclass gets the extension rec too
376 extension_rec.next_extension = smwc->composite_class.extension;
377 smwc->composite_class.extension = (XtPointer) &extension_rec;
382 * XawSimpleMenuInitialize
385 * request - widget requested by the argument list
386 * cnew - new widget with both resource and non resource values
389 * Initializes the simple menu widget.
393 XawSimpleMenuInitialize(Widget request, Widget cnew,
394 ArgList args, Cardinal *num_args)
396 SimpleMenuWidget smw = (SimpleMenuWidget)cnew;
397 Dimension width, height;
399 XmuCallInitializers(XtWidgetToApplicationContext(cnew));
401 if (smw->simple_menu.label_class == NULL)
402 smw->simple_menu.label_class = smeBSBObjectClass;
404 smw->simple_menu.label = NULL;
405 smw->simple_menu.entry_set = NULL;
406 smw->simple_menu.recursive_set_values = False;
408 smw->simple_menu.sub_menu = NULL;
409 smw->simple_menu.state = 0;
411 XtAddCallback(cnew, XtNpopupCallback, PopupCB, NULL);
414 if (smw->simple_menu.label_string != NULL)
418 CalculateNewSize(cnew, &width, &height);
420 smw->simple_menu.menu_width = True;
422 if (XtWidth(smw) == 0) {
423 smw->simple_menu.menu_width = False;
424 XtWidth(smw) = width;
427 smw->simple_menu.menu_height = True;
429 if (XtHeight(smw) == 0) {
430 smw->simple_menu.menu_height = False;
431 XtHeight(smw) = height;
435 * Add a popup_callback routine for changing the cursor
437 XtAddCallback(cnew, XtNpopupCallback, ChangeCursorOnGrab, NULL);
442 * XawSimpleMenuRedisplay
445 * w - simple menu widget
446 * event - X event that caused this redisplay
447 * region - region the needs to be repainted
450 * Redisplays the contents of the widget.
454 XawSimpleMenuRedisplay(Widget w, XEvent *event, Region region)
456 SimpleMenuWidget smw = (SimpleMenuWidget)w;
458 SmeObjectClass cclass;
461 XClearWindow(XtDisplay(w), XtWindow(w));
464 if (smw->simple_menu.display_list)
465 XawRunDisplayList(w, smw->simple_menu.display_list, event, region);
469 * Check and Paint each of the entries - including the label
471 ForAllChildren(smw, entry) {
472 if (!XtIsManaged((Widget)*entry))
476 switch(XRectInRegion(region, XtX(*entry),XtY(*entry),
477 XtWidth(*entry), XtHeight(*entry))) {
485 cclass = (SmeObjectClass)(*entry)->object.widget_class;
487 if (cclass->rect_class.expose != NULL)
488 (cclass->rect_class.expose)((Widget)*entry, NULL, NULL);
494 * XawSimpleMenuRealize
497 * w - simple menu widget
498 * mask - value mask for the window to create
499 * attrs - attributes for the window to create
502 * Realizes the widget.
505 XawSimpleMenuRealize(Widget w, XtValueMask *mask, XSetWindowAttributes *attrs)
507 SimpleMenuWidget smw = (SimpleMenuWidget)w;
512 attrs->cursor = smw->simple_menu.cursor;
514 if (smw->simple_menu.backing_store == Always ||
515 smw->simple_menu.backing_store == NotUseful ||
516 smw->simple_menu.backing_store == WhenMapped) {
517 *mask |= CWBackingStore;
518 attrs->backing_store = smw->simple_menu.backing_store;
521 *mask &= ~CWBackingStore;
523 (*Superclass->core_class.realize)(w, mask, attrs);
526 if (w->core.background_pixmap > XtUnspecifiedPixmap) {
527 pixmap = XawPixmapFromXPixmap(w->core.background_pixmap, XtScreen(w),
528 w->core.colormap, w->core.depth);
529 if (pixmap && pixmap->mask)
530 XawReshapeWidget(w, pixmap);
537 * XawSimpleMenuResize
540 * w - simple menu widget
543 * Handle the menu being resized.
546 XawSimpleMenuResize(Widget w)
548 if (!XtIsRealized(w))
551 Layout(w, NULL, NULL);
553 XawSimpleMenuRedisplay(w, NULL, NULL);
558 * XawSimpleMenuSetValues
561 * current - current state of the widget
562 * request - what was requested
563 * cnew - what the widget will become
566 * Relayout the menu when one of the resources is changed.
570 XawSimpleMenuSetValues(Widget current, Widget request, Widget cnew,
571 ArgList args, Cardinal *num_args)
573 SimpleMenuWidget smw_old = (SimpleMenuWidget)current;
574 SimpleMenuWidget smw_new = (SimpleMenuWidget)cnew;
575 Boolean ret_val = False, layout = False;
577 if (!XtIsRealized(current))
580 if (!smw_new->simple_menu.recursive_set_values) {
581 if (XtWidth(smw_new) != XtWidth(smw_old)) {
582 smw_new->simple_menu.menu_width = XtWidth(smw_new) != 0;
585 if (XtHeight(smw_new) != XtHeight(smw_old)) {
586 smw_new->simple_menu.menu_height = XtHeight(smw_new) != 0;
591 if (smw_old->simple_menu.cursor != smw_new->simple_menu.cursor)
592 XDefineCursor(XtDisplay(cnew), XtWindow(cnew),
593 smw_new->simple_menu.cursor);
595 if (smw_old->simple_menu.label_string !=smw_new->simple_menu.label_string) {
596 if (smw_new->simple_menu.label_string == NULL) /* Destroy */
597 XtDestroyWidget((Widget)smw_old->simple_menu.label);
598 else if (smw_old->simple_menu.label_string == NULL) /* Create */
603 XtSetArg(arglist[0], XtNlabel, smw_new->simple_menu.label_string);
604 XtSetValues((Widget)smw_new->simple_menu.label, arglist, ONE);
608 if (smw_old->simple_menu.label_class != smw_new->simple_menu.label_class)
609 XtAppWarning(XtWidgetToApplicationContext(cnew),
610 "No Dynamic class change of the SimpleMenu Label.");
612 if (smw_old->simple_menu.top_margin != smw_new->simple_menu.top_margin
613 || smw_old->simple_menu.bottom_margin
614 != smw_new->simple_menu.bottom_margin) {
620 if (smw_old->core.background_pixmap != smw_new->core.background_pixmap) {
621 XawPixmap *opix, *npix;
623 opix = XawPixmapFromXPixmap(smw_old->core.background_pixmap,
624 XtScreen(smw_old), smw_old->core.colormap,
625 smw_old->core.depth);
626 npix = XawPixmapFromXPixmap(smw_new->core.background_pixmap,
627 XtScreen(smw_new), smw_new->core.colormap,
628 smw_new->core.depth);
629 if ((npix && npix->mask) || (opix && opix->mask))
630 XawReshapeWidget(cnew, npix);
635 Layout(cnew, NULL, NULL);
642 * XawSimpleMenuSetValuesHook
646 * arglist - argument list passed to XtSetValues
647 * num_args - number of args
650 * To handle a special case, this is passed the actual arguments.
653 XawSimpleMenuSetValuesHook(Widget w, ArgList arglist, Cardinal *num_args)
656 Dimension width, height;
659 height = XtHeight(w);
661 for (i = 0 ; i < *num_args ; i++) {
662 if (streq(arglist[i].name, XtNwidth))
663 width = (Dimension)arglist[i].value;
664 if (streq(arglist[i].name, XtNheight))
665 height = (Dimension) arglist[i].value;
668 if (width != XtWidth(w) || height != XtHeight(w))
669 MakeSetValuesRequest(w, width, height);
675 * Geometry Management routines
679 * XawSimpleMenuGeometryManager
682 * w - Menu Entry making the request
683 * request - requested new geometry
684 * reply - the allowed geometry.
687 * This is the SimpleMenu Widget's Geometry Manager.
690 * XtGeometry{Yes, No, Almost}
692 static XtGeometryResult
693 XawSimpleMenuGeometryManager(Widget w, XtWidgetGeometry *request,
694 XtWidgetGeometry *reply)
696 SimpleMenuWidget smw = (SimpleMenuWidget)XtParent(w);
697 SmeObject entry = (SmeObject)w;
698 XtGeometryMask mode = request->request_mode;
699 XtGeometryResult answer;
700 Dimension old_height, old_width;
702 if (!(mode & CWWidth) && !(mode & CWHeight))
703 return (XtGeometryNo);
705 reply->width = request->width;
706 reply->height = request->height;
708 old_width = XtWidth(entry);
709 old_height = XtHeight(entry);
711 Layout(w, &reply->width, &reply->height);
714 * Since we are an override shell and have no parent there is no one to
715 * ask to see if this geom change is okay, so I am just going to assume
716 * we can do whatever we want. If you subclass be very careful with this
717 * assumption, it could bite you.
719 * Chris D. Peterson - Sept. 1989.
721 if ((!(mode & CWWidth) || reply->width == request->width)
722 && (!(mode & CWHeight) || reply->height == request->height)) {
723 if (mode & XtCWQueryOnly) { /* Actually perform the layout */
724 XtWidth(entry) = old_width;
725 XtHeight(entry) = old_height;
728 Layout((Widget)smw, NULL, NULL);
729 answer = XtGeometryDone;
732 XtWidth(entry) = old_width;
733 XtHeight(entry) = old_height;
735 if ((reply->width == request->width && !(mode & CWHeight))
736 || (reply->height == request->height && !(mode & CWWidth))
737 || (reply->width == request->width
738 && reply->height == request->height))
739 answer = XtGeometryNo;
741 answer = XtGeometryAlmost;
742 reply->request_mode = 0;
743 if (reply->width != request->width)
744 reply->request_mode |= CWWidth;
745 if (reply->height != request->height)
746 reply->request_mode |= CWHeight;
755 * XawSimpleMenuChangeManaged
758 * w - simple menu widget
761 * Called whenever a new child is managed.
764 XawSimpleMenuChangeManaged(Widget w)
766 Layout(w, NULL, NULL);
770 * Global Action Routines
772 * These actions routines will be added to the application's
780 * w - a widget (no the simple menu widget)
781 * event - the event that caused this action
782 * params - parameters passed to the routine.
783 * we expect the name of the menu here.
787 * Positions the simple menu widget.
791 PositionMenuAction(Widget w, XEvent *event,
792 String *params, Cardinal *num_params)
797 if (*num_params != 1) {
798 XtAppWarning(XtWidgetToApplicationContext(w),
799 "SimpleMenuWidget: position menu action expects "
800 "only one parameter which is the name of the menu.");
804 if ((menu = FindMenu(w, params[0])) == NULL) {
805 char error_buf[BUFSIZ];
807 snprintf(error_buf, sizeof(error_buf),
808 "SimpleMenuWidget: could not find menu named %s.",
810 XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
814 switch (event->type) {
817 loc.x = event->xbutton.x_root;
818 loc.y = event->xbutton.y_root;
819 PositionMenu(menu, &loc);
823 loc.x = event->xcrossing.x_root;
824 loc.y = event->xcrossing.y_root;
825 PositionMenu(menu, &loc);
828 loc.x = event->xmotion.x_root;
829 loc.y = event->xmotion.y_root;
830 PositionMenu(menu, &loc);
833 PositionMenu(menu, NULL);
839 * Widget Action Routines
846 * w - simple menu widget
847 * event - event that caused this action
852 * Unhighlights current entry.
856 Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
858 SimpleMenuWidget smw = (SimpleMenuWidget)w;
859 SmeObject entry = smw->simple_menu.entry_set;
865 if (!smw->simple_menu.sub_menu)
868 SmeObjectClass cclass;
870 smw->simple_menu.entry_set = NULL;
871 cclass = (SmeObjectClass)entry->object.widget_class;
872 (cclass->sme_class.unhighlight)((Widget)entry);
881 * w - simple menu widget
882 * event - event that caused this action
887 * Highlights current entry.
891 Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
893 SimpleMenuWidget smw = (SimpleMenuWidget)w;
896 if (!XtIsSensitive(w))
899 entry = GetEventEntry(w, event);
901 if (entry == smw->simple_menu.entry_set)
905 if (!smw->simple_menu.sub_menu)
907 Unhighlight(w, event, params, num_params);
912 if (!XtIsSensitive((Widget)entry))
916 if (smw->simple_menu.sub_menu)
920 Unhighlight(w, event, params, num_params);
923 if (!(smw->simple_menu.state & SMW_UNMAPPING))
926 SmeObjectClass cclass;
928 smw->simple_menu.entry_set = entry;
929 cclass = (SmeObjectClass)entry->object.widget_class;
931 (cclass->sme_class.highlight)((Widget)entry);
934 if (XtIsSubclass((Widget)entry, smeBSBObjectClass))
945 * w - simple menu widget
946 * event - event that caused this action
951 * Notify user of current entry.
955 Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
958 SmeObjectClass cclass;
960 /* may be a propagated event from a sub menu, need to check it */
961 if (XtWindow(w) != event->xany.window)
963 entry = GetEventEntry(w, event);
964 if (entry == NULL || !XtIsSensitive((Widget)entry))
967 cclass = (SmeObjectClass) entry->object.widget_class;
968 (cclass->sme_class.notify)((Widget)entry);
976 * XawSimpleMenuAddGlobalActions
979 * app_con - appcontext
982 * Adds the global actions to the simple menu widget.
985 XawSimpleMenuAddGlobalActions(XtAppContext app_con)
987 XtInitializeWidgetClass(simpleMenuWidgetClass);
988 XmuCallInitializers(app_con);
993 * XawSimpleMenuGetActiveEntry
999 * Gets the currently active (set) entry.
1002 * The currently set entry or NULL if none is set
1005 XawSimpleMenuGetActiveEntry(Widget w)
1007 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1009 return ((Widget)smw->simple_menu.entry_set);
1014 * XawSimpleMenuClearActiveEntry
1020 * Unsets the currently active (set) entry.
1023 XawSimpleMenuClearActiveEntry(Widget w)
1025 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1027 smw->simple_menu.entry_set = NULL;
1041 * Creates the label object and makes sure it is the first child in
1045 CreateLabel(Widget w)
1047 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1048 Widget *child, *next_child;
1052 if (smw->simple_menu.label_string == NULL ||
1053 smw->simple_menu.label != NULL) {
1054 XtAppWarning(XtWidgetToApplicationContext(w),
1055 "Xaw Simple Menu Widget: label string is NULL or "
1056 "label already exists, no label is being created.");
1060 XtSetArg(args[0], XtNlabel, smw->simple_menu.label_string);
1061 XtSetArg(args[1], XtNjustify, XtJustifyCenter);
1062 smw->simple_menu.label = (SmeObject)
1063 XtCreateManagedWidget("menuLabel",
1064 smw->simple_menu.label_class, w, args, TWO);
1067 for (child = smw->composite.children + smw->composite.num_children,
1068 i = smw->composite.num_children; i > 0; i--, child--) {
1069 if (next_child != NULL)
1070 *next_child = *child;
1073 *child = (Widget)smw->simple_menu.label;
1082 * width_ret - returned width
1083 * height_ret - returned height
1086 * if width == NULL || height == NULL then it assumes the you do not care
1087 * about the return values, and just want a relayout.
1089 * if this is not the case then it will set width_ret and height_ret
1090 * to be width and height that the child would get if it were layed out
1093 * "w" can be the simple menu widget or any of its object children.
1096 Layout(Widget w, Dimension *width_ret, Dimension *height_ret)
1098 SmeObject current_entry;
1099 SimpleMenuWidget smw;
1100 Dimension width, height;
1101 Boolean allow_change_size;
1103 Cardinal i, count, n;
1104 int width_kid, height_kid, tmp_w, tmp_h;
1105 short vadd, hadd, x_ins, y_ins;
1110 if (XtIsSubclass(w, simpleMenuWidgetClass)) {
1111 smw = (SimpleMenuWidget)w;
1112 current_entry = NULL;
1115 smw = (SimpleMenuWidget)XtParent(w);
1116 current_entry = (SmeObject)w;
1119 allow_change_size = (!XtIsRealized((Widget)smw)
1120 || smw->shell.allow_shell_resize);
1122 for (i = smw->simple_menu.label ? 1 : 0;
1123 i < smw->composite.num_children;
1125 XtWidgetGeometry preferred;
1127 kid = smw->composite.children[i];
1128 if (!XtIsManaged(kid))
1130 if (smw->simple_menu.row_height != 0)
1131 XtHeight(kid) = smw->simple_menu.row_height;
1132 XtQueryGeometry(kid, NULL, &preferred);
1133 if (preferred.request_mode & CWWidth)
1134 XtWidth(kid) = preferred.width;
1137 if (smw->simple_menu.label
1138 && XtIsManaged((Widget)smw->simple_menu.label)) {
1139 XtWidgetGeometry preferred;
1141 kid = (Widget)smw->simple_menu.label;
1142 XtQueryGeometry(kid, NULL, &preferred);
1143 if (preferred.request_mode & CWWidth)
1144 XtWidth(kid) = preferred.width;
1145 if (preferred.request_mode & CWHeight)
1146 XtHeight(kid) = preferred.height;
1150 if (!smw->simple_menu.menu_width)
1152 if (!smw->simple_menu.menu_height)
1154 if (!XtWidth(smw) || !XtHeight(smw))
1155 MakeResizeRequest((Widget)smw);
1157 widths = (Dimension *)XtMalloc(sizeof(Dimension));
1159 hadd = smw->simple_menu.left_margin;
1163 vadd = smw->simple_menu.top_margin;
1164 if (smw->simple_menu.label)
1165 vadd += XtHeight(smw->simple_menu.label);
1168 width = tmp_w = tmp_h = n = 0;
1171 for (i = smw->simple_menu.label ? 1 : 0;
1172 i < smw->composite.num_children;
1174 kid = smw->composite.children[i];
1175 if (!XtIsManaged(kid))
1177 width_kid = XtWidth(kid);
1178 height_kid = XtHeight(kid);
1180 if (n && (height + height_kid + smw->simple_menu.bottom_margin
1183 widths = (Dimension *)XtRealloc((char *)widths,
1184 sizeof(Dimension) * count);
1185 widths[count - 1] = width_kid;
1188 height = height_kid + vadd;
1191 height += height_kid;
1194 if (width_kid > tmp_w)
1195 widths[count - 1] = tmp_w = width_kid;
1199 height = tmp_h + smw->simple_menu.bottom_margin;
1202 if (smw->simple_menu.label && width < XtWidth(smw->simple_menu.label)) {
1205 inc = (XtWidth(smw->simple_menu.label) - width) / (float)count;
1206 width = XtWidth(smw->simple_menu.label);
1207 for (n = 0; n < count; n++)
1212 width += hadd + smw->simple_menu.right_margin;
1215 x_ins = n = count = 0;
1219 for (i = smw->simple_menu.label ? 1 : 0;
1220 i < smw->composite.num_children;
1222 kid = smw->composite.children[i];
1223 if (!XtIsManaged(kid))
1226 height_kid = XtHeight(kid);
1228 if (n && (tmp_h + height_kid + smw->simple_menu.bottom_margin
1233 tmp_w += widths[count];
1234 tmp_h = height_kid + vadd;
1238 tmp_h += height_kid;
1242 XtX(kid) = x_ins + hadd;
1244 XtWidth(kid) = widths[count];
1247 XtFree((char *)widths);
1249 if (allow_change_size)
1250 MakeSetValuesRequest((Widget) smw, width, height);
1252 if (smw->simple_menu.label) {
1253 XtX(smw->simple_menu.label) = 0;
1254 XtY(smw->simple_menu.label) = smw->simple_menu.top_margin;
1255 XtWidth(smw->simple_menu.label) = XtWidth(smw)
1257 - (smw->simple_menu.left_margin + smw->simple_menu.right_margin)
1261 if (current_entry) {
1263 *width_ret = XtWidth(current_entry);
1265 *height_ret = XtHeight(current_entry);
1274 * app_con - application context
1278 * Adds the XawPositionSimpleMenu action to the global
1279 * action list for this appcon.
1283 AddPositionAction(XtAppContext app_con, XPointer data)
1285 static XtActionsRec pos_action[] = {
1286 {"XawPositionSimpleMenu", PositionMenuAction},
1289 XtAppAddActions(app_con, pos_action, XtNumber(pos_action));
1297 * widget - reference widget
1298 * name - menu widget's name
1301 * Find the menu give a name and reference widget
1304 * The menu widget or NULL.
1307 FindMenu(Widget widget, String name)
1311 for (w = widget; w != NULL; w = XtParent(w))
1312 if ((menu = XtNameToWidget(w, name)) != NULL)
1323 * w - simple menu widget
1324 * location - pointer the the position or NULL
1330 PositionMenu(Widget w, XPoint *location)
1332 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1336 if (location == NULL) {
1337 Window temp1, temp2;
1338 int root_x, root_y, tempX, tempY;
1341 location = &t_point;
1342 if (XQueryPointer(XtDisplay(w), XtWindow(w), &temp1, &temp2,
1343 &root_x, &root_y, &tempX, &tempY, &tempM) == False) {
1344 XtAppWarning(XtWidgetToApplicationContext(w),
1345 "Xaw Simple Menu Widget: "
1346 "Could not find location of mouse pointer");
1349 location->x = (short) root_x;
1350 location->y = (short) root_y;
1354 * The width will not be correct unless it is realized
1358 location->x -= XtWidth(w) >> 1;
1360 if (smw->simple_menu.popup_entry == NULL)
1361 entry = smw->simple_menu.label;
1363 entry = smw->simple_menu.popup_entry;
1366 location->y -= XtY(entry) + (XtHeight(entry) >> 1);
1368 MoveMenu(w, location->x, location->y);
1376 * w - simple menu widget
1377 * x - current location of the widget
1381 * Actually moves the menu, may force it to
1382 * to be fully visable if menu_on_screen is True.
1385 MoveMenu(Widget w, int x, int y)
1388 Cardinal num_args = 0;
1389 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1391 if (smw->simple_menu.menu_on_screen) {
1392 int width = XtWidth(w) + (XtBorderWidth(w) << 1);
1393 int height = XtHeight(w) + (XtBorderWidth(w) << 1);
1396 int scr_width = WidthOfScreen(XtScreen(w));
1398 if (x + width > scr_width)
1399 x = scr_width - width;
1405 int scr_height = HeightOfScreen(XtScreen(w));
1407 if (y + height > scr_height)
1408 y = scr_height - height;
1414 XtSetArg(arglist[num_args], XtNx, x); num_args++;
1415 XtSetArg(arglist[num_args], XtNy, y); num_args++;
1416 XtSetValues(w, arglist, num_args);
1421 * ChangeCursorOnGrab
1429 * Changes the cursor on the active grab to the one
1430 * specified in out resource list.
1434 ChangeCursorOnGrab(Widget w, XtPointer temp1, XtPointer temp2)
1436 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1439 * The event mask here is what is currently in the MIT implementation.
1440 * There really needs to be a way to get the value of the mask out
1441 * of the toolkit (CDP 5/26/89).
1443 XChangeActivePointerGrab(XtDisplay(w), ButtonPressMask | ButtonReleaseMask,
1444 smw->simple_menu.cursor,
1445 XtLastTimestampProcessed(XtDisplay(w)));
1450 * MakeSetValuesRequest
1453 * w - simple menu widget
1454 * width - size requested
1458 MakeSetValuesRequest(Widget w, unsigned int width, unsigned int height)
1460 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1462 Cardinal num_args = 0;
1464 if (!smw->simple_menu.recursive_set_values) {
1465 if (XtWidth(smw) != width || XtHeight(smw) != height) {
1466 smw->simple_menu.recursive_set_values = True;
1467 XtSetArg(arglist[num_args], XtNwidth, width); num_args++;
1468 XtSetArg(arglist[num_args], XtNheight, height); num_args++;
1469 XtSetValues(w, arglist, num_args);
1471 else if (XtIsRealized((Widget)smw))
1472 XawSimpleMenuRedisplay((Widget)smw, NULL, NULL);
1474 smw->simple_menu.recursive_set_values = False;
1478 DoGetEventEntry(Widget w, int x_loc, int y_loc)
1480 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1483 ForAllChildren(smw, entry) {
1484 if (!XtIsManaged((Widget)*entry))
1487 if (x_loc > XtX(*entry)
1488 && x_loc <= XtX(*entry) + XtWidth(*entry)
1489 && y_loc > XtY(*entry)
1490 && y_loc <= XtY(*entry) + XtHeight(*entry)) {
1491 if (*entry == smw->simple_menu.label)
1492 return (NULL); /* cannot select the label */
1506 * w - simple menu widget
1510 * Gets an entry given an event that has X and Y coords.
1513 * The entry that this point is in
1516 GetEventEntry(Widget w, XEvent *event)
1518 int x_loc, y_loc, x_root;
1519 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1523 switch (event->type) {
1525 x_loc = event->xmotion.x;
1526 y_loc = event->xmotion.y;
1527 x_root = event->xmotion.x_root;
1531 x_loc = event->xcrossing.x;
1532 y_loc = event->xcrossing.y;
1533 x_root = event->xcrossing.x_root;
1537 x_loc = event->xbutton.x;
1538 y_loc = event->xbutton.y;
1539 x_root = event->xbutton.x_root;
1542 XtAppError(XtWidgetToApplicationContext(w),
1543 "Unknown event type in GetEventEntry().");
1547 if (x_loc < 0 || x_loc >= XtWidth(smw) ||
1548 y_loc < 0 || y_loc >= XtHeight(smw))
1551 /* Move the menu if it's outside the screen, does not check
1552 * smw->simple_menu.menu_on_screen because menus is bigger than screen
1554 if (x_root == WidthOfScreen(XtScreen(w)) - 1 &&
1555 XtX(w) + XtWidth(w) + (XtBorderWidth(w)) > x_root) {
1557 if (smw->simple_menu.entry_set) {
1558 entry = DoGetEventEntry(w,
1559 XtX(smw->simple_menu.entry_set)
1560 + XtWidth(smw->simple_menu.entry_set) + 1,
1562 Unhighlight(w, event, NULL, NULL);
1564 warp = -(int)XtWidth(entry) >> 1;
1565 move = x_loc - XtWidth(entry) - XtX(entry) + XtBorderWidth(w);
1569 move = WidthOfScreen(XtScreen(w)) -
1570 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1575 move = WidthOfScreen(XtScreen(w)) -
1576 (XtX(w) + XtWidth(w) + (XtBorderWidth(w) << 1));
1579 else if (x_root == 0 && XtX(w) < 0) {
1581 if (smw->simple_menu.entry_set) {
1582 entry = DoGetEventEntry(w, XtX(smw->simple_menu.entry_set) - 1,
1584 Unhighlight(w, event, NULL, NULL);
1586 warp = XtWidth(entry) >> 1;
1587 move = x_loc - XtX(entry);
1590 move = x_loc + XtBorderWidth(w);
1593 move = x_loc + XtBorderWidth(w);
1599 XtMoveWidget(w, XtX(w) + move, XtY(w));
1601 XWarpPointer(XtDisplay(w), None, None, 0, 0, 0, 0, warp, 0);
1603 return (DoGetEventEntry(w, x_loc, y_loc));
1607 CalculateNewSize(Widget w, Dimension *width_return, Dimension *height_return)
1609 SimpleMenuWidget xaw = (SimpleMenuWidget)w;
1612 int width_kid, height_kid;
1613 int width, height, tmp_w, tmp_h, max_dim;
1615 int n, columns, test_h, num_children = 0;
1616 Boolean try_layout = False;
1619 hadd = xaw->simple_menu.left_margin + xaw->simple_menu.right_margin;
1623 vadd = xaw->simple_menu.top_margin + xaw->simple_menu.bottom_margin;
1624 if (xaw->simple_menu.label)
1625 vadd += XtHeight(xaw->simple_menu.label);
1628 max_dim = *height_return;
1629 else if (!XtHeight(w)) {
1630 max_dim = HeightOfScreen(XtScreen(w));
1634 max_dim = XtHeight(w);
1637 width = height = tmp_w = tmp_h = n = test_h = 0;
1639 for (i = xaw->simple_menu.label ? 1 : 0;
1640 i < xaw->composite.num_children;
1642 kid = xaw->composite.children[i];
1643 if (!XtIsManaged(kid))
1646 width_kid = XtWidth(kid);
1647 height_kid = XtHeight(kid);
1651 test_h = height_kid;
1652 else if (test_h != height_kid)
1656 if (n && (height + height_kid > max_dim)) {
1660 height = height_kid;
1663 height += height_kid;
1666 if (width_kid > tmp_w)
1671 height = tmp_h + vadd;
1672 width += tmp_w + hadd;
1674 if (xaw->simple_menu.label)
1675 width = XawMax(width, XtWidth(xaw->simple_menu.label) + hadd);
1677 *width_return = width;
1678 *height_return = height;
1680 if (try_layout && columns > 1 && num_children > 2) {
1683 height = test_h * (xaw->simple_menu.label ?
1687 max_dim -= max_dim % test_h;
1688 space = max_dim - (height % max_dim);
1689 if (space >= test_h * columns) {
1690 height = max_dim - space / columns;
1691 if (height % test_h)
1692 height += test_h - (height % test_h);
1693 *height_return = height + vadd;
1694 CalculateNewSize(w, width_return, height_return);
1700 MakeResizeRequest(Widget w)
1703 Dimension width, height;
1706 height = XtHeight(w);
1708 for (tries = 0; tries < 100; tries++) {
1709 CalculateNewSize(w, &width, &height);
1710 if (width == XtWidth(w) && height == XtHeight(w))
1712 if (XtMakeResizeRequest(w, width, height, &width, &height) ==
1720 Popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
1722 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1724 while (XtParent(w) &&
1725 XtIsSubclass(XtParent(w), simpleMenuWidgetClass)) {
1726 if (((SimpleMenuWidget)XtParent(w))->simple_menu.sub_menu == (Widget)w) {
1728 smw = (SimpleMenuWidget)w;
1729 smw->simple_menu.entry_set = NULL;
1735 smw->simple_menu.state |= SMW_UNMAPPING;
1736 if (smw->simple_menu.sub_menu)
1737 PopdownSubMenu(smw);
1738 XtCallActionProc(w, "XtMenuPopdown", event, params, *num_params);
1742 PopupSubMenu(SimpleMenuWidget smw)
1747 SmeBSBObject entry = (SmeBSBObject)smw->simple_menu.entry_set;
1748 Position menu_x, menu_y;
1751 if (entry->sme_bsb.menu_name == NULL)
1754 if ((menu = FindMenu((Widget)smw, entry->sme_bsb.menu_name)) == NULL)
1757 smw->simple_menu.sub_menu = menu;
1759 if (!XtIsRealized(menu))
1760 XtRealizeWidget(menu);
1762 popleft = (smw->simple_menu.state & SMW_POPLEFT) != 0;
1765 XtTranslateCoords((Widget)smw, -(int)XtWidth(menu),
1766 XtY(entry) - XtBorderWidth(menu), &menu_x, &menu_y);
1768 XtTranslateCoords((Widget)smw, XtWidth(smw), XtY(entry)
1769 - XtBorderWidth(menu), &menu_x, &menu_y);
1771 if (!popleft && menu_x >= 0) {
1772 int scr_width = WidthOfScreen(XtScreen(menu));
1774 if (menu_x + XtWidth(menu) > scr_width) {
1775 menu_x -= XtWidth(menu) + XtWidth(smw);
1779 else if (popleft && menu_x < 0) {
1784 int scr_height = HeightOfScreen(XtScreen(menu));
1786 if (menu_y + XtHeight(menu) > scr_height)
1787 menu_y = scr_height - XtHeight(menu) - XtBorderWidth(menu);
1793 XtSetArg(args[num_args], XtNx, menu_x); num_args++;
1794 XtSetArg(args[num_args], XtNy, menu_y); num_args++;
1795 XtSetValues(menu, args, num_args);
1798 ((SimpleMenuWidget)menu)->simple_menu.state |= SMW_POPLEFT;
1800 ((SimpleMenuWidget)menu)->simple_menu.state &= ~SMW_POPLEFT;
1802 XtPopup(menu, XtGrabNone);
1806 PopdownSubMenu(SimpleMenuWidget smw)
1808 SimpleMenuWidget menu = (SimpleMenuWidget)smw->simple_menu.sub_menu;
1813 menu->simple_menu.state |= SMW_UNMAPPING;
1814 PopdownSubMenu(menu);
1816 XtPopdown((Widget)menu);
1818 smw->simple_menu.sub_menu = NULL;
1823 PopupCB(Widget w, XtPointer client_data, XtPointer call_data)
1825 SimpleMenuWidget smw = (SimpleMenuWidget)w;
1827 smw->simple_menu.state &= ~(SMW_UNMAPPING | SMW_POPLEFT);