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 (at) 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 #ifndef OLDXAW 133 NULL, 134 #endif 135 }, 136 /* label */ 137 { 138 NULL, /* extension */ 139 }, 140 /* command */ 141 { 142 NULL, /* extension */ 143 }, 144 /* menu_button */ 145 { 146 NULL, /* extension */ 147 }, 148 }; 149 150 WidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec; 151 152 /* 153 * Implementation 154 */ 155 static void 156 XawMenuButtonClassInitialize(void) 157 { 158 XawInitializeWidgetSet(); 159 XtRegisterGrabAction(PopupMenu, True, 160 ButtonPressMask | ButtonReleaseMask, 161 GrabModeAsync, GrabModeAsync); 162 } 163 164 /*ARGSUSED*/ 165 static void 166 XawMenuButtonInitialize(Widget request _X_UNUSED, Widget cnew, 167 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 168 { 169 MenuButtonWidget mbw = (MenuButtonWidget)cnew; 170 171 if (mbw->menu_button.menu_name != default_menu_name) 172 mbw->menu_button.menu_name = XtNewString(mbw->menu_button.menu_name); 173 } 174 175 static void 176 XawMenuButtonDestroy(Widget w) 177 { 178 MenuButtonWidget mbw = (MenuButtonWidget)w; 179 180 if (mbw->menu_button.menu_name != default_menu_name) 181 XtFree(mbw->menu_button.menu_name); 182 } 183 184 /*ARGSUSED*/ 185 static Boolean 186 XawMenuButtonSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 187 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 188 { 189 MenuButtonWidget mbw_old = (MenuButtonWidget)current; 190 MenuButtonWidget mbw_new = (MenuButtonWidget)cnew; 191 192 if (mbw_old->menu_button.menu_name != mbw_new->menu_button.menu_name) { 193 if (mbw_old->menu_button.menu_name != default_menu_name) 194 XtFree(mbw_old->menu_button.menu_name); 195 if (mbw_new->menu_button.menu_name != default_menu_name) 196 mbw_new->menu_button.menu_name = 197 XtNewString(mbw_new->menu_button.menu_name); 198 } 199 200 return (False); 201 } 202 203 /*ARGSUSED*/ 204 static void 205 PopupMenu(Widget w, XEvent *event _X_UNUSED, String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 206 { 207 MenuButtonWidget mbw = (MenuButtonWidget)w; 208 Widget menu = NULL, temp; 209 Arg arglist[2]; 210 Cardinal num_args; 211 int menu_x, menu_y, menu_width, menu_height, button_height; 212 Position button_x, button_y; 213 214 if ((temp = w) == NULL) 215 return; 216 217 while(temp != NULL) { 218 menu = XtNameToWidget(temp, mbw->menu_button.menu_name); 219 if (menu == NULL) 220 temp = XtParent(temp); 221 else 222 break; 223 } 224 225 if (menu == NULL) { 226 char error_buf[BUFSIZ]; 227 228 snprintf(error_buf, sizeof(error_buf), 229 "MenuButton: Could not find menu widget named %s.", 230 mbw->menu_button.menu_name); 231 XtAppWarning(XtWidgetToApplicationContext(w), error_buf); 232 return; 233 } 234 235 if (!XtIsRealized(menu)) 236 XtRealizeWidget(menu); 237 238 menu_width = XtWidth(menu) + (XtBorderWidth(menu) << 1); 239 button_height = XtHeight(w) + (XtBorderWidth(w) << 1); 240 menu_height = XtHeight(menu) + (XtBorderWidth(menu) << 1); 241 242 XtTranslateCoords(w, 0, 0, &button_x, &button_y); 243 menu_x = button_x; 244 menu_y = button_y + button_height; 245 246 if (menu_y >= 0) { 247 int scr_height = HeightOfScreen(XtScreen(menu)); 248 249 if (menu_y + menu_height > scr_height) 250 menu_y = button_y - menu_height; 251 if (menu_y < 0) { 252 menu_y = scr_height - menu_height; 253 menu_x = button_x + XtWidth(w) + (XtBorderWidth(w) << 1); 254 if (menu_x + menu_width > WidthOfScreen(XtScreen(menu))) 255 menu_x = button_x - menu_width; 256 } 257 } 258 if (menu_y < 0) 259 menu_y = 0; 260 261 if (menu_x >= 0) { 262 int scr_width = WidthOfScreen(XtScreen(menu)); 263 264 if (menu_x + menu_width > scr_width) 265 menu_x = scr_width - menu_width; 266 } 267 if (menu_x < 0) 268 menu_x = 0; 269 270 num_args = 0; 271 XtSetArg(arglist[num_args], XtNx, menu_x); num_args++; 272 XtSetArg(arglist[num_args], XtNy, menu_y); num_args++; 273 XtSetValues(menu, arglist, num_args); 274 275 XtPopupSpringLoaded(menu); 276 } 277