MenuButton.c revision 994689c1
1/*
2Copyright 1989, 1994, 1998  The Open Group
3
4Permission to use, copy, modify, distribute, and sell this software and its
5documentation for any purpose is hereby granted without fee, provided that
6the above copyright notice appear in all copies and that both that
7copyright notice and this permission notice appear in supporting
8documentation.
9
10The above copyright notice and this permission notice shall be included in
11all copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20Except as contained in this notice, the name of The Open Group shall not be
21used in advertising or otherwise to promote the sale, use or other dealings
22in this Software without prior written authorization from The Open Group.
23 *
24 */
25
26/*
27 * MenuButton.c - Source code for MenuButton widget.
28 *
29 * This is the source code for the Athena MenuButton widget.
30 * It is intended to provide an easy method of activating pulldown menus.
31 *
32 * Date:    May 2, 1989
33 *
34 * By:      Chris D. Peterson
35 *          MIT X Consortium
36 *          kit@expo.lcs.mit.edu
37 */
38
39#ifdef HAVE_CONFIG_H
40#include <config.h>
41#endif
42#include <stdio.h>
43#include <X11/IntrinsicP.h>
44#include <X11/StringDefs.h>
45#include <X11/Xmu/SysUtil.h>
46#include <X11/Xaw/MenuButtoP.h>
47#include <X11/Xaw/XawInit.h>
48#include "Private.h"
49
50/*
51 * Class Methods
52 */
53static void XawMenuButtonClassInitialize(void);
54static void XawMenuButtonInitialize(Widget, Widget, ArgList, Cardinal*);
55static void XawMenuButtonDestroy(Widget);
56static Boolean XawMenuButtonSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
57
58/*
59 * Actions
60 */
61static void PopupMenu(Widget, XEvent*, String*, Cardinal*);
62
63/*
64 * Initialization
65 */
66#define superclass ((CommandWidgetClass)&commandClassRec)
67
68static char defaultTranslations[] =
69"<Enter>:"	"highlight()\n"
70"<Leave>:"	"reset()\n"
71"Any<BtnDown>:"	"reset() PopupMenu()\n";
72
73static char default_menu_name[] = "menu";
74
75#define offset(field) XtOffsetOf(MenuButtonRec, field)
76static XtResource resources[] = {
77  {
78    XtNmenuName,
79    XtCMenuName,
80    XtRString,
81    sizeof(String),
82    offset(menu_button.menu_name),
83    XtRString,
84    (XtPointer)default_menu_name
85  },
86};
87#undef offset
88
89static XtActionsRec actionsList[] =
90{
91  {"PopupMenu",	PopupMenu},
92};
93
94MenuButtonClassRec menuButtonClassRec = {
95  /* core */
96  {
97    (WidgetClass)superclass,		/* superclass		  */
98    "MenuButton",			/* class_name		  */
99    sizeof(MenuButtonRec),       	/* size			  */
100    XawMenuButtonClassInitialize,	/* class_initialize	  */
101    NULL,				/* class_part_initialize  */
102    False,				/* class_inited		  */
103    XawMenuButtonInitialize,		/* initialize		  */
104    NULL,				/* initialize_hook	  */
105    XtInheritRealize,			/* realize		  */
106    actionsList,			/* actions		  */
107    XtNumber(actionsList),		/* num_actions		  */
108    resources,				/* resources		  */
109    XtNumber(resources),		/* num_resources	  */
110    NULLQUARK,				/* xrm_class		  */
111    False,				/* compress_motion	  */
112    True,				/* compress_exposure	  */
113    True,				/* compress_enterleave	  */
114    False,				/* visible_interest	  */
115    XawMenuButtonDestroy,		/* destroy		  */
116    XtInheritResize,			/* resize		  */
117    XtInheritExpose,			/* expose		  */
118    XawMenuButtonSetValues,		/* set_values		  */
119    NULL,				/* set_values_hook	  */
120    XtInheritSetValuesAlmost,		/* set_values_almost	  */
121    NULL,				/* get_values_hook	  */
122    NULL,				/* accept_focus		  */
123    XtVersion,				/* version		  */
124    NULL,				/* callback_private	  */
125    defaultTranslations,               	/* tm_table		  */
126    XtInheritQueryGeometry,		/* query_geometry	  */
127    XtInheritDisplayAccelerator,	/* display_accelerator	  */
128    NULL,				/* extension */
129  },
130  /* simple */
131  {
132    XtInheritChangeSensitive		/* change_sensitive	  */
133  },
134  /* label */
135  {
136    NULL,				/* extension */
137  },
138  /* command */
139  {
140    NULL,				/* extension */
141  },
142  /* menu_button */
143  {
144    NULL,				/* extension */
145  },
146};
147
148WidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec;
149
150/*
151 * Implementation
152 */
153static void
154XawMenuButtonClassInitialize(void)
155{
156    XawInitializeWidgetSet();
157    XtRegisterGrabAction(PopupMenu, True,
158			 ButtonPressMask | ButtonReleaseMask,
159			 GrabModeAsync, GrabModeAsync);
160}
161
162/*ARGSUSED*/
163static void
164XawMenuButtonInitialize(Widget request, Widget cnew,
165			ArgList args, Cardinal *num_args)
166{
167    MenuButtonWidget mbw = (MenuButtonWidget)cnew;
168
169    if (mbw->menu_button.menu_name != default_menu_name)
170	mbw->menu_button.menu_name = XtNewString(mbw->menu_button.menu_name);
171}
172
173static void
174XawMenuButtonDestroy(Widget w)
175{
176    MenuButtonWidget mbw = (MenuButtonWidget)w;
177
178    if (mbw->menu_button.menu_name != default_menu_name)
179	XtFree(mbw->menu_button.menu_name);
180}
181
182/*ARGSUSED*/
183static Boolean
184XawMenuButtonSetValues(Widget current, Widget request, Widget cnew,
185		       ArgList args, Cardinal *num_args)
186{
187    MenuButtonWidget mbw_old = (MenuButtonWidget)current;
188    MenuButtonWidget mbw_new = (MenuButtonWidget)cnew;
189
190    if (mbw_old->menu_button.menu_name != mbw_new->menu_button.menu_name) {
191	if (mbw_old->menu_button.menu_name != default_menu_name)
192	    XtFree(mbw_old->menu_button.menu_name);
193	if (mbw_new->menu_button.menu_name != default_menu_name)
194	    mbw_new->menu_button.menu_name =
195		XtNewString(mbw_new->menu_button.menu_name);
196    }
197
198    return (False);
199}
200
201/*ARGSUSED*/
202static void
203PopupMenu(Widget w, XEvent *event, String *params, Cardinal *num_params)
204{
205    MenuButtonWidget mbw = (MenuButtonWidget)w;
206    Widget menu = NULL, temp;
207    Arg arglist[2];
208    Cardinal num_args;
209    int menu_x, menu_y, menu_width, menu_height, button_height;
210    Position button_x, button_y;
211
212    temp = w;
213    while(temp != NULL) {
214	menu = XtNameToWidget(temp, mbw->menu_button.menu_name);
215	if (menu == NULL)
216	    temp = XtParent(temp);
217	else
218	    break;
219    }
220
221    if (menu == NULL) {
222	char error_buf[BUFSIZ];
223
224	(void)XmuSnprintf(error_buf, sizeof(error_buf),
225			  "MenuButton:  Could not find menu widget named %s.",
226			  mbw->menu_button.menu_name);
227	XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
228	return;
229    }
230
231    if (!XtIsRealized(menu))
232	XtRealizeWidget(menu);
233
234    menu_width = XtWidth(menu) + (XtBorderWidth(menu) << 1);
235    button_height = XtHeight(w) + (XtBorderWidth(w) << 1);
236    menu_height = XtHeight(menu) + (XtBorderWidth(menu) << 1);
237
238    XtTranslateCoords(w, 0, 0, &button_x, &button_y);
239    menu_x = button_x;
240    menu_y = button_y + button_height;
241
242    if (menu_y >= 0) {
243	int scr_height = HeightOfScreen(XtScreen(menu));
244
245	if (menu_y + menu_height > scr_height)
246	    menu_y = button_y - menu_height;
247	if (menu_y < 0) {
248	    menu_y = scr_height - menu_height;
249	    menu_x = button_x + XtWidth(w) + (XtBorderWidth(w) << 1);
250	    if (menu_x + menu_width > WidthOfScreen(XtScreen(menu)))
251		menu_x = button_x - menu_width;
252	}
253    }
254    if (menu_y < 0)
255	menu_y = 0;
256
257    if (menu_x >= 0) {
258	int scr_width = WidthOfScreen(XtScreen(menu));
259
260	if (menu_x + menu_width > scr_width)
261	    menu_x = scr_width - menu_width;
262    }
263    if (menu_x < 0)
264	menu_x = 0;
265
266    num_args = 0;
267    XtSetArg(arglist[num_args], XtNx, menu_x); num_args++;
268    XtSetArg(arglist[num_args], XtNy, menu_y); num_args++;
269    XtSetValues(menu, arglist, num_args);
270
271    XtPopupSpringLoaded(menu);
272}
273