MenuButton.c revision 5ec34c4c
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/Xaw/MenuButtoP.h> 46#include <X11/Xaw/XawInit.h> 47#include "Private.h" 48 49/* 50 * Class Methods 51 */ 52static void XawMenuButtonClassInitialize(void); 53static void XawMenuButtonInitialize(Widget, Widget, ArgList, Cardinal*); 54static void XawMenuButtonDestroy(Widget); 55static Boolean XawMenuButtonSetValues(Widget, Widget, Widget, ArgList, Cardinal*); 56 57/* 58 * Actions 59 */ 60static void PopupMenu(Widget, XEvent*, String*, Cardinal*); 61 62/* 63 * Initialization 64 */ 65#define superclass ((CommandWidgetClass)&commandClassRec) 66 67static char defaultTranslations[] = 68"<Enter>:" "highlight()\n" 69"<Leave>:" "reset()\n" 70"Any<BtnDown>:" "reset() PopupMenu()\n"; 71 72static char default_menu_name[] = "menu"; 73 74#define offset(field) XtOffsetOf(MenuButtonRec, field) 75static 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 88static XtActionsRec actionsList[] = 89{ 90 {"PopupMenu", PopupMenu}, 91}; 92 93MenuButtonClassRec 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 147WidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec; 148 149/* 150 * Implementation 151 */ 152static void 153XawMenuButtonClassInitialize(void) 154{ 155 XawInitializeWidgetSet(); 156 XtRegisterGrabAction(PopupMenu, True, 157 ButtonPressMask | ButtonReleaseMask, 158 GrabModeAsync, GrabModeAsync); 159} 160 161/*ARGSUSED*/ 162static void 163XawMenuButtonInitialize(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 172static void 173XawMenuButtonDestroy(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*/ 182static Boolean 183XawMenuButtonSetValues(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*/ 201static void 202PopupMenu(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