1 /*
2 Copyright 1989, 1994, 1998 The Open Group
3
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
8 documentation.
9
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12
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.
19
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.
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/Xaw/MenuButtoP.h>
46 #include <X11/Xaw/XawInit.h>
47 #include "Private.h"
48
49 /*
50 * Class Methods
51 */
52 static void XawMenuButtonClassInitialize(void);
53 static void XawMenuButtonInitialize(Widget, Widget, ArgList, Cardinal*);
54 static void XawMenuButtonDestroy(Widget);
55 static Boolean XawMenuButtonSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
56
57 /*
58 * Actions
59 */
60 static void PopupMenu(Widget, XEvent*, String*, Cardinal*);
61
62 /*
63 * Initialization
64 */
65 #define superclass ((CommandWidgetClass)&commandClassRec)
66
67 static char defaultTranslations[] =
68 "<Enter>:" "highlight()\n"
69 "<Leave>:" "reset()\n"
70 "Any<BtnDown>:" "reset() PopupMenu()\n";
71
72 static char default_menu_name[] = "menu";
73
74 #define offset(field) XtOffsetOf(MenuButtonRec, field)
75 static XtResource resources[] = {
76 {
77 XtNmenuName,
78 XtCMenuName,
79 XtRString,
80 sizeof(String),
81 offset(menu_button.menu_name),
82 XtRString,
83 (XtPointer)default_menu_name
84 },
85 };
86 #undef offset
87
88 static XtActionsRec actionsList[] =
89 {
90 {"PopupMenu", PopupMenu},
91 };
92
93 MenuButtonClassRec menuButtonClassRec = {
94 /* core */
95 {
96 (WidgetClass)superclass, /* superclass */
97 "MenuButton", /* class_name */
98 sizeof(MenuButtonRec), /* size */
99 XawMenuButtonClassInitialize, /* class_initialize */
100 NULL, /* class_part_initialize */
101 False, /* class_inited */
102 XawMenuButtonInitialize, /* initialize */
103 NULL, /* initialize_hook */
104 XtInheritRealize, /* realize */
105 actionsList, /* actions */
106 XtNumber(actionsList), /* num_actions */
107 resources, /* resources */
108 XtNumber(resources), /* num_resources */
109 NULLQUARK, /* xrm_class */
110 False, /* compress_motion */
111 True, /* compress_exposure */
112 True, /* compress_enterleave */
113 False, /* visible_interest */
114 XawMenuButtonDestroy, /* destroy */
115 XtInheritResize, /* resize */
116 XtInheritExpose, /* expose */
117 XawMenuButtonSetValues, /* set_values */
118 NULL, /* set_values_hook */
119 XtInheritSetValuesAlmost, /* set_values_almost */
120 NULL, /* get_values_hook */
121 NULL, /* accept_focus */
122 XtVersion, /* version */
123 NULL, /* callback_private */
124 defaultTranslations, /* tm_table */
125 XtInheritQueryGeometry, /* query_geometry */
126 XtInheritDisplayAccelerator, /* display_accelerator */
127 NULL, /* extension */
128 },
129 /* simple */
130 {
131 XtInheritChangeSensitive /* change_sensitive */
132 },
133 /* label */
134 {
135 NULL, /* extension */
136 },
137 /* command */
138 {
139 NULL, /* extension */
140 },
141 /* menu_button */
142 {
143 NULL, /* extension */
144 },
145 };
146
147 WidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec;
148
149 /*
150 * Implementation
151 */
152 static void
XawMenuButtonClassInitialize(void)153 XawMenuButtonClassInitialize(void)
154 {
155 XawInitializeWidgetSet();
156 XtRegisterGrabAction(PopupMenu, True,
157 ButtonPressMask | ButtonReleaseMask,
158 GrabModeAsync, GrabModeAsync);
159 }
160
161 /*ARGSUSED*/
162 static void
XawMenuButtonInitialize(Widget request _X_UNUSED,Widget cnew,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)163 XawMenuButtonInitialize(Widget request _X_UNUSED, Widget cnew,
164 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
165 {
166 MenuButtonWidget mbw = (MenuButtonWidget)cnew;
167
168 if (mbw->menu_button.menu_name != default_menu_name)
169 mbw->menu_button.menu_name = XtNewString(mbw->menu_button.menu_name);
170 }
171
172 static void
XawMenuButtonDestroy(Widget w)173 XawMenuButtonDestroy(Widget w)
174 {
175 MenuButtonWidget mbw = (MenuButtonWidget)w;
176
177 if (mbw->menu_button.menu_name != default_menu_name)
178 XtFree(mbw->menu_button.menu_name);
179 }
180
181 /*ARGSUSED*/
182 static Boolean
XawMenuButtonSetValues(Widget current,Widget request _X_UNUSED,Widget cnew,ArgList args _X_UNUSED,Cardinal * num_args _X_UNUSED)183 XawMenuButtonSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
184 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
185 {
186 MenuButtonWidget mbw_old = (MenuButtonWidget)current;
187 MenuButtonWidget mbw_new = (MenuButtonWidget)cnew;
188
189 if (mbw_old->menu_button.menu_name != mbw_new->menu_button.menu_name) {
190 if (mbw_old->menu_button.menu_name != default_menu_name)
191 XtFree(mbw_old->menu_button.menu_name);
192 if (mbw_new->menu_button.menu_name != default_menu_name)
193 mbw_new->menu_button.menu_name =
194 XtNewString(mbw_new->menu_button.menu_name);
195 }
196
197 return (False);
198 }
199
200 /*ARGSUSED*/
201 static void
PopupMenu(Widget w,XEvent * event _X_UNUSED,String * params _X_UNUSED,Cardinal * num_params _X_UNUSED)202 PopupMenu(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED)
203 {
204 MenuButtonWidget mbw = (MenuButtonWidget)w;
205 Widget menu = NULL, temp;
206 Arg arglist[2];
207 Cardinal num_args;
208 int menu_x, menu_y, menu_width, menu_height, button_height;
209 Position button_x, button_y;
210
211 temp = w;
212 while(temp != NULL) {
213 menu = XtNameToWidget(temp, mbw->menu_button.menu_name);
214 if (menu == NULL)
215 temp = XtParent(temp);
216 else
217 break;
218 }
219
220 if (menu == NULL) {
221 char error_buf[BUFSIZ];
222
223 snprintf(error_buf, sizeof(error_buf),
224 "MenuButton: Could not find menu widget named %s.",
225 mbw->menu_button.menu_name);
226 XtAppWarning(XtWidgetToApplicationContext(w), error_buf);
227 return;
228 }
229
230 if (!XtIsRealized(menu))
231 XtRealizeWidget(menu);
232
233 menu_width = XtWidth(menu) + (XtBorderWidth(menu) << 1);
234 button_height = XtHeight(w) + (XtBorderWidth(w) << 1);
235 menu_height = XtHeight(menu) + (XtBorderWidth(menu) << 1);
236
237 XtTranslateCoords(w, 0, 0, &button_x, &button_y);
238 menu_x = button_x;
239 menu_y = button_y + button_height;
240
241 if (menu_y >= 0) {
242 int scr_height = HeightOfScreen(XtScreen(menu));
243
244 if (menu_y + menu_height > scr_height)
245 menu_y = button_y - menu_height;
246 if (menu_y < 0) {
247 menu_y = scr_height - menu_height;
248 menu_x = button_x + XtWidth(w) + (XtBorderWidth(w) << 1);
249 if (menu_x + menu_width > WidthOfScreen(XtScreen(menu)))
250 menu_x = button_x - menu_width;
251 }
252 }
253 if (menu_y < 0)
254 menu_y = 0;
255
256 if (menu_x >= 0) {
257 int scr_width = WidthOfScreen(XtScreen(menu));
258
259 if (menu_x + menu_width > scr_width)
260 menu_x = scr_width - menu_width;
261 }
262 if (menu_x < 0)
263 menu_x = 0;
264
265 num_args = 0;
266 XtSetArg(arglist[num_args], XtNx, menu_x); num_args++;
267 XtSetArg(arglist[num_args], XtNy, menu_y); num_args++;
268 XtSetValues(menu, arglist, num_args);
269
270 XtPopupSpringLoaded(menu);
271 }
272