MenuButton.c revision 421c997b
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  {
131421c997bSmrg    XtInheritChangeSensitive		/* change_sensitive	  */
1327a84e134Smrg  },
1337a84e134Smrg  /* label */
1347a84e134Smrg  {
1357a84e134Smrg    NULL,				/* extension */
1367a84e134Smrg  },
1377a84e134Smrg  /* command */
1387a84e134Smrg  {
1397a84e134Smrg    NULL,				/* extension */
1407a84e134Smrg  },
1417a84e134Smrg  /* menu_button */
1427a84e134Smrg  {
1437a84e134Smrg    NULL,				/* extension */
1447a84e134Smrg  },
1457a84e134Smrg};
1467a84e134Smrg
1477a84e134SmrgWidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec;
1487a84e134Smrg
1497a84e134Smrg/*
1507a84e134Smrg * Implementation
1517a84e134Smrg */
1527a84e134Smrgstatic void
1537a84e134SmrgXawMenuButtonClassInitialize(void)
1547a84e134Smrg{
1557a84e134Smrg    XawInitializeWidgetSet();
1567a84e134Smrg    XtRegisterGrabAction(PopupMenu, True,
1577a84e134Smrg			 ButtonPressMask | ButtonReleaseMask,
1587a84e134Smrg			 GrabModeAsync, GrabModeAsync);
1597a84e134Smrg}
1607a84e134Smrg
1617a84e134Smrg/*ARGSUSED*/
1627a84e134Smrgstatic void
1637a84e134SmrgXawMenuButtonInitialize(Widget request, Widget cnew,
1647a84e134Smrg			ArgList args, Cardinal *num_args)
1657a84e134Smrg{
1667a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)cnew;
1677a84e134Smrg
1687a84e134Smrg    if (mbw->menu_button.menu_name != default_menu_name)
1697a84e134Smrg	mbw->menu_button.menu_name = XtNewString(mbw->menu_button.menu_name);
1707a84e134Smrg}
1717a84e134Smrg
1727a84e134Smrgstatic void
1737a84e134SmrgXawMenuButtonDestroy(Widget w)
1747a84e134Smrg{
1757a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)w;
1767a84e134Smrg
1777a84e134Smrg    if (mbw->menu_button.menu_name != default_menu_name)
1787a84e134Smrg	XtFree(mbw->menu_button.menu_name);
1797a84e134Smrg}
1807a84e134Smrg
1817a84e134Smrg/*ARGSUSED*/
1827a84e134Smrgstatic Boolean
1837a84e134SmrgXawMenuButtonSetValues(Widget current, Widget request, Widget cnew,
1847a84e134Smrg		       ArgList args, Cardinal *num_args)
1857a84e134Smrg{
1867a84e134Smrg    MenuButtonWidget mbw_old = (MenuButtonWidget)current;
1877a84e134Smrg    MenuButtonWidget mbw_new = (MenuButtonWidget)cnew;
1887a84e134Smrg
1897a84e134Smrg    if (mbw_old->menu_button.menu_name != mbw_new->menu_button.menu_name) {
1907a84e134Smrg	if (mbw_old->menu_button.menu_name != default_menu_name)
1917a84e134Smrg	    XtFree(mbw_old->menu_button.menu_name);
1927a84e134Smrg	if (mbw_new->menu_button.menu_name != default_menu_name)
1937a84e134Smrg	    mbw_new->menu_button.menu_name =
1947a84e134Smrg		XtNewString(mbw_new->menu_button.menu_name);
1957a84e134Smrg    }
1967a84e134Smrg
1977a84e134Smrg    return (False);
1987a84e134Smrg}
1997a84e134Smrg
2007a84e134Smrg/*ARGSUSED*/
2017a84e134Smrgstatic void
2027a84e134SmrgPopupMenu(Widget w, XEvent *event, String *params, Cardinal *num_params)
2037a84e134Smrg{
2047a84e134Smrg    MenuButtonWidget mbw = (MenuButtonWidget)w;
2057a84e134Smrg    Widget menu = NULL, temp;
2067a84e134Smrg    Arg arglist[2];
2077a84e134Smrg    Cardinal num_args;
2087a84e134Smrg    int menu_x, menu_y, menu_width, menu_height, button_height;
2097a84e134Smrg    Position button_x, button_y;
2107a84e134Smrg
2117a84e134Smrg    temp = w;
2127a84e134Smrg    while(temp != NULL) {
2137a84e134Smrg	menu = XtNameToWidget(temp, mbw->menu_button.menu_name);
214421c997bSmrg	if (menu == NULL)
2157a84e134Smrg	    temp = XtParent(temp);
2167a84e134Smrg	else
2177a84e134Smrg	    break;
2187a84e134Smrg    }
2197a84e134Smrg
2207a84e134Smrg    if (menu == NULL) {
2217a84e134Smrg	char error_buf[BUFSIZ];
2227a84e134Smrg
223421c997bSmrg	snprintf(error_buf, sizeof(error_buf),
224421c997bSmrg		 "MenuButton:  Could not find menu widget named %s.",
225421c997bSmrg		 mbw->menu_button.menu_name);
2267a84e134Smrg	XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
2277a84e134Smrg	return;
2287a84e134Smrg    }
2297a84e134Smrg
2307a84e134Smrg    if (!XtIsRealized(menu))
2317a84e134Smrg	XtRealizeWidget(menu);
232421c997bSmrg
2337a84e134Smrg    menu_width = XtWidth(menu) + (XtBorderWidth(menu) << 1);
2347a84e134Smrg    button_height = XtHeight(w) + (XtBorderWidth(w) << 1);
2357a84e134Smrg    menu_height = XtHeight(menu) + (XtBorderWidth(menu) << 1);
2367a84e134Smrg
2377a84e134Smrg    XtTranslateCoords(w, 0, 0, &button_x, &button_y);
2387a84e134Smrg    menu_x = button_x;
2397a84e134Smrg    menu_y = button_y + button_height;
2407a84e134Smrg
2417a84e134Smrg    if (menu_y >= 0) {
2427a84e134Smrg	int scr_height = HeightOfScreen(XtScreen(menu));
2437a84e134Smrg
2447a84e134Smrg	if (menu_y + menu_height > scr_height)
2457a84e134Smrg	    menu_y = button_y - menu_height;
2467a84e134Smrg	if (menu_y < 0) {
2477a84e134Smrg	    menu_y = scr_height - menu_height;
2487a84e134Smrg	    menu_x = button_x + XtWidth(w) + (XtBorderWidth(w) << 1);
2497a84e134Smrg	    if (menu_x + menu_width > WidthOfScreen(XtScreen(menu)))
2507a84e134Smrg		menu_x = button_x - menu_width;
2517a84e134Smrg	}
2527a84e134Smrg    }
2537a84e134Smrg    if (menu_y < 0)
2547a84e134Smrg	menu_y = 0;
2557a84e134Smrg
2567a84e134Smrg    if (menu_x >= 0) {
2577a84e134Smrg	int scr_width = WidthOfScreen(XtScreen(menu));
2587a84e134Smrg
2597a84e134Smrg	if (menu_x + menu_width > scr_width)
2607a84e134Smrg	    menu_x = scr_width - menu_width;
2617a84e134Smrg    }
262421c997bSmrg    if (menu_x < 0)
2637a84e134Smrg	menu_x = 0;
2647a84e134Smrg
2657a84e134Smrg    num_args = 0;
2667a84e134Smrg    XtSetArg(arglist[num_args], XtNx, menu_x); num_args++;
2677a84e134Smrg    XtSetArg(arglist[num_args], XtNy, menu_y); num_args++;
2687a84e134Smrg    XtSetValues(menu, arglist, num_args);
2697a84e134Smrg
2707a84e134Smrg    XtPopupSpringLoaded(menu);
2717a84e134Smrg}
272