Home | History | Annotate | Line # | Download | only in src
      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