17a84e134Smrg/*
27a84e134SmrgCopyright 1989, 1994, 1998  The Open Group
37a84e134Smrg
47a84e134SmrgPermission to use, copy, modify, distribute, and sell this software and its
57a84e134Smrgdocumentation for any purpose is hereby granted without fee, provided that
67a84e134Smrgthe above copyright notice appear in all copies and that both that
77a84e134Smrgcopyright notice and this permission notice appear in supporting
87a84e134Smrgdocumentation.
97a84e134Smrg
107a84e134SmrgThe above copyright notice and this permission notice shall be included in
117a84e134Smrgall copies or substantial portions of the Software.
127a84e134Smrg
137a84e134SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
147a84e134SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
157a84e134SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
167a84e134SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
177a84e134SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
187a84e134SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
197a84e134Smrg
207a84e134SmrgExcept as contained in this notice, the name of The Open Group shall not be
217a84e134Smrgused in advertising or otherwise to promote the sale, use or other dealings
227a84e134Smrgin this Software without prior written authorization from The Open Group.
237a84e134Smrg *
247a84e134Smrg */
257a84e134Smrg
267a84e134Smrg/*
277a84e134Smrg * MenuButton.c - Source code for MenuButton widget.
287a84e134Smrg *
297a84e134Smrg * This is the source code for the Athena MenuButton widget.
307a84e134Smrg * It is intended to provide an easy method of activating pulldown menus.
317a84e134Smrg *
327a84e134Smrg * Date:    May 2, 1989
337a84e134Smrg *
347a84e134Smrg * By:      Chris D. Peterson
35421c997bSmrg *          MIT X Consortium
367a84e134Smrg *          kit@expo.lcs.mit.edu
377a84e134Smrg */
387a84e134Smrg
397a84e134Smrg#ifdef HAVE_CONFIG_H
407a84e134Smrg#include <config.h>
417a84e134Smrg#endif
427a84e134Smrg#include <stdio.h>
437a84e134Smrg#include <X11/IntrinsicP.h>
447a84e134Smrg#include <X11/StringDefs.h>
457a84e134Smrg#include <X11/Xaw/MenuButtoP.h>
467a84e134Smrg#include <X11/Xaw/XawInit.h>
477a84e134Smrg#include "Private.h"
487a84e134Smrg
497a84e134Smrg/*
507a84e134Smrg * Class Methods
517a84e134Smrg */
527a84e134Smrgstatic void XawMenuButtonClassInitialize(void);
537a84e134Smrgstatic void XawMenuButtonInitialize(Widget, Widget, ArgList, Cardinal*);
547a84e134Smrgstatic void XawMenuButtonDestroy(Widget);
557a84e134Smrgstatic Boolean XawMenuButtonSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
567a84e134Smrg
577a84e134Smrg/*
587a84e134Smrg * Actions
597a84e134Smrg */
607a84e134Smrgstatic void PopupMenu(Widget, XEvent*, String*, Cardinal*);
617a84e134Smrg
627a84e134Smrg/*
637a84e134Smrg * Initialization
647a84e134Smrg */
657a84e134Smrg#define superclass ((CommandWidgetClass)&commandClassRec)
667a84e134Smrg
67421c997bSmrgstatic char defaultTranslations[] =
687a84e134Smrg"<Enter>:"	"highlight()\n"
697a84e134Smrg"<Leave>:"	"reset()\n"
707a84e134Smrg"Any<BtnDown>:"	"reset() PopupMenu()\n";
717a84e134Smrg
727a84e134Smrgstatic char default_menu_name[] = "menu";
737a84e134Smrg
747a84e134Smrg#define offset(field) XtOffsetOf(MenuButtonRec, field)
757a84e134Smrgstatic XtResource resources[] = {
767a84e134Smrg  {
777a84e134Smrg    XtNmenuName,
787a84e134Smrg    XtCMenuName,
797a84e134Smrg    XtRString,
807a84e134Smrg    sizeof(String),
817a84e134Smrg    offset(menu_button.menu_name),
827a84e134Smrg    XtRString,
837a84e134Smrg    (XtPointer)default_menu_name
847a84e134Smrg  },
857a84e134Smrg};
867a84e134Smrg#undef offset
877a84e134Smrg
887a84e134Smrgstatic XtActionsRec actionsList[] =
897a84e134Smrg{
907a84e134Smrg  {"PopupMenu",	PopupMenu},
917a84e134Smrg};
927a84e134Smrg
937a84e134SmrgMenuButtonClassRec menuButtonClassRec = {
947a84e134Smrg  /* core */
957a84e134Smrg  {
967a84e134Smrg    (WidgetClass)superclass,		/* superclass		  */
977a84e134Smrg    "MenuButton",			/* class_name		  */
98421c997bSmrg    sizeof(MenuButtonRec),		/* size			  */
997a84e134Smrg    XawMenuButtonClassInitialize,	/* class_initialize	  */
1007a84e134Smrg    NULL,				/* class_part_initialize  */
1017a84e134Smrg    False,				/* class_inited		  */
1027a84e134Smrg    XawMenuButtonInitialize,		/* initialize		  */
1037a84e134Smrg    NULL,				/* initialize_hook	  */
1047a84e134Smrg    XtInheritRealize,			/* realize		  */
1057a84e134Smrg    actionsList,			/* actions		  */
1067a84e134Smrg    XtNumber(actionsList),		/* num_actions		  */
1077a84e134Smrg    resources,				/* resources		  */
1087a84e134Smrg    XtNumber(resources),		/* num_resources	  */
1097a84e134Smrg    NULLQUARK,				/* xrm_class		  */
1107a84e134Smrg    False,				/* compress_motion	  */
1117a84e134Smrg    True,				/* compress_exposure	  */
1127a84e134Smrg    True,				/* compress_enterleave	  */
1137a84e134Smrg    False,				/* visible_interest	  */
1147a84e134Smrg    XawMenuButtonDestroy,		/* destroy		  */
1157a84e134Smrg    XtInheritResize,			/* resize		  */
1167a84e134Smrg    XtInheritExpose,			/* expose		  */
1177a84e134Smrg    XawMenuButtonSetValues,		/* set_values		  */
1187a84e134Smrg    NULL,				/* set_values_hook	  */
1197a84e134Smrg    XtInheritSetValuesAlmost,		/* set_values_almost	  */
1207a84e134Smrg    NULL,				/* get_values_hook	  */
1217a84e134Smrg    NULL,				/* accept_focus		  */
1227a84e134Smrg    XtVersion,				/* version		  */
1237a84e134Smrg    NULL,				/* callback_private	  */
124421c997bSmrg    defaultTranslations,		/* tm_table		  */
1257a84e134Smrg    XtInheritQueryGeometry,		/* query_geometry	  */
1267a84e134Smrg    XtInheritDisplayAccelerator,	/* display_accelerator	  */
1277a84e134Smrg    NULL,				/* extension */
1287a84e134Smrg  },
1297a84e134Smrg  /* simple */
1307a84e134Smrg  {
131efbcb2bfSmrg    XtInheritChangeSensitive,		/* change_sensitive	  */
132efbcb2bfSmrg#ifndef OLDXAW
133efbcb2bfSmrg    NULL,
134efbcb2bfSmrg#endif
1357a84e134Smrg  },
1367a84e134Smrg  /* label */
1377a84e134Smrg  {
1387a84e134Smrg    NULL,				/* extension */
1397a84e134Smrg  },
1407a84e134Smrg  /* command */
1417a84e134Smrg  {
1427a84e134Smrg    NULL,				/* extension */
1437a84e134Smrg  },
1447a84e134Smrg  /* menu_button */
1457a84e134Smrg  {
1467a84e134Smrg    NULL,				/* extension */
1477a84e134Smrg  },
1487a84e134Smrg};
1497a84e134Smrg
1507a84e134SmrgWidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec;
1517a84e134Smrg
1527a84e134Smrg/*
1537a84e134Smrg * Implementation
1547a84e134Smrg */
1557a84e134Smrgstatic void
1567a84e134SmrgXawMenuButtonClassInitialize(void)
1577a84e134Smrg{
1587a84e134Smrg    XawInitializeWidgetSet();
1597a84e134Smrg    XtRegisterGrabAction(PopupMenu, True,
1607a84e134Smrg			 ButtonPressMask | ButtonReleaseMask,
1617a84e134Smrg			 GrabModeAsync, GrabModeAsync);
1627a84e134Smrg}
1637a84e134Smrg
1647a84e134Smrg/*ARGSUSED*/
1657a84e134Smrgstatic void
1665ec34c4cSmrgXawMenuButtonInitialize(Widget request _X_UNUSED, Widget cnew,
1675ec34c4cSmrg			ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
1687a84e134Smrg{
1697a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)cnew;
1707a84e134Smrg
1717a84e134Smrg    if (mbw->menu_button.menu_name != default_menu_name)
1727a84e134Smrg	mbw->menu_button.menu_name = XtNewString(mbw->menu_button.menu_name);
1737a84e134Smrg}
1747a84e134Smrg
1757a84e134Smrgstatic void
1767a84e134SmrgXawMenuButtonDestroy(Widget w)
1777a84e134Smrg{
1787a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)w;
1797a84e134Smrg
1807a84e134Smrg    if (mbw->menu_button.menu_name != default_menu_name)
1817a84e134Smrg	XtFree(mbw->menu_button.menu_name);
1827a84e134Smrg}
1837a84e134Smrg
1847a84e134Smrg/*ARGSUSED*/
1857a84e134Smrgstatic Boolean
1865ec34c4cSmrgXawMenuButtonSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
1875ec34c4cSmrg		       ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
1887a84e134Smrg{
1897a84e134Smrg    MenuButtonWidget mbw_old = (MenuButtonWidget)current;
1907a84e134Smrg    MenuButtonWidget mbw_new = (MenuButtonWidget)cnew;
1917a84e134Smrg
1927a84e134Smrg    if (mbw_old->menu_button.menu_name != mbw_new->menu_button.menu_name) {
1937a84e134Smrg	if (mbw_old->menu_button.menu_name != default_menu_name)
1947a84e134Smrg	    XtFree(mbw_old->menu_button.menu_name);
1957a84e134Smrg	if (mbw_new->menu_button.menu_name != default_menu_name)
1967a84e134Smrg	    mbw_new->menu_button.menu_name =
1977a84e134Smrg		XtNewString(mbw_new->menu_button.menu_name);
1987a84e134Smrg    }
1997a84e134Smrg
2007a84e134Smrg    return (False);
2017a84e134Smrg}
2027a84e134Smrg
2037a84e134Smrg/*ARGSUSED*/
2047a84e134Smrgstatic void
2055ec34c4cSmrgPopupMenu(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
2067a84e134Smrg{
2077a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)w;
2087a84e134Smrg    Widget menu = NULL, temp;
2097a84e134Smrg    Arg arglist[2];
2107a84e134Smrg    Cardinal num_args;
2117a84e134Smrg    int menu_x, menu_y, menu_width, menu_height, button_height;
2127a84e134Smrg    Position button_x, button_y;
2137a84e134Smrg
214efbcb2bfSmrg    if ((temp = w) == NULL)
215efbcb2bfSmrg	return;
216efbcb2bfSmrg
2177a84e134Smrg    while(temp != NULL) {
2187a84e134Smrg	menu = XtNameToWidget(temp, mbw->menu_button.menu_name);
219421c997bSmrg	if (menu == NULL)
2207a84e134Smrg	    temp = XtParent(temp);
2217a84e134Smrg	else
2227a84e134Smrg	    break;
2237a84e134Smrg    }
2247a84e134Smrg
2257a84e134Smrg    if (menu == NULL) {
2267a84e134Smrg	char error_buf[BUFSIZ];
2277a84e134Smrg
228421c997bSmrg	snprintf(error_buf, sizeof(error_buf),
229421c997bSmrg		 "MenuButton:  Could not find menu widget named %s.",
230421c997bSmrg		 mbw->menu_button.menu_name);
2317a84e134Smrg	XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
2327a84e134Smrg	return;
2337a84e134Smrg    }
2347a84e134Smrg
2357a84e134Smrg    if (!XtIsRealized(menu))
2367a84e134Smrg	XtRealizeWidget(menu);
237421c997bSmrg
2387a84e134Smrg    menu_width = XtWidth(menu) + (XtBorderWidth(menu) << 1);
2397a84e134Smrg    button_height = XtHeight(w) + (XtBorderWidth(w) << 1);
2407a84e134Smrg    menu_height = XtHeight(menu) + (XtBorderWidth(menu) << 1);
2417a84e134Smrg
2427a84e134Smrg    XtTranslateCoords(w, 0, 0, &button_x, &button_y);
2437a84e134Smrg    menu_x = button_x;
2447a84e134Smrg    menu_y = button_y + button_height;
2457a84e134Smrg
2467a84e134Smrg    if (menu_y >= 0) {
2477a84e134Smrg	int scr_height = HeightOfScreen(XtScreen(menu));
2487a84e134Smrg
2497a84e134Smrg	if (menu_y + menu_height > scr_height)
2507a84e134Smrg	    menu_y = button_y - menu_height;
2517a84e134Smrg	if (menu_y < 0) {
2527a84e134Smrg	    menu_y = scr_height - menu_height;
2537a84e134Smrg	    menu_x = button_x + XtWidth(w) + (XtBorderWidth(w) << 1);
2547a84e134Smrg	    if (menu_x + menu_width > WidthOfScreen(XtScreen(menu)))
2557a84e134Smrg		menu_x = button_x - menu_width;
2567a84e134Smrg	}
2577a84e134Smrg    }
2587a84e134Smrg    if (menu_y < 0)
2597a84e134Smrg	menu_y = 0;
2607a84e134Smrg
2617a84e134Smrg    if (menu_x >= 0) {
2627a84e134Smrg	int scr_width = WidthOfScreen(XtScreen(menu));
2637a84e134Smrg
2647a84e134Smrg	if (menu_x + menu_width > scr_width)
2657a84e134Smrg	    menu_x = scr_width - menu_width;
2667a84e134Smrg    }
267421c997bSmrg    if (menu_x < 0)
2687a84e134Smrg	menu_x = 0;
2697a84e134Smrg
2707a84e134Smrg    num_args = 0;
2717a84e134Smrg    XtSetArg(arglist[num_args], XtNx, menu_x); num_args++;
2727a84e134Smrg    XtSetArg(arglist[num_args], XtNy, menu_y); num_args++;
2737a84e134Smrg    XtSetValues(menu, arglist, num_args);
2747a84e134Smrg
2757a84e134Smrg    XtPopupSpringLoaded(menu);
2767a84e134Smrg}
277