2732a72b3702fe9e7604f1bb5ab195743d8ba903
[framework/uifw/xorg/lib/libxaw.git] / src / MenuButton.c
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/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  */
53 static void XawMenuButtonClassInitialize(void);
54 static void XawMenuButtonInitialize(Widget, Widget, ArgList, Cardinal*);
55 static void XawMenuButtonDestroy(Widget);
56 static Boolean XawMenuButtonSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
57
58 /*
59  * Actions
60  */
61 static void PopupMenu(Widget, XEvent*, String*, Cardinal*);
62
63 /*
64  * Initialization
65  */
66 #define superclass ((CommandWidgetClass)&commandClassRec)
67
68 static char defaultTranslations[] = 
69 "<Enter>:"      "highlight()\n"
70 "<Leave>:"      "reset()\n"
71 "Any<BtnDown>:" "reset() PopupMenu()\n";
72
73 static char default_menu_name[] = "menu";
74
75 #define offset(field) XtOffsetOf(MenuButtonRec, field)
76 static 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
89 static XtActionsRec actionsList[] =
90 {
91   {"PopupMenu", PopupMenu},
92 };
93
94 MenuButtonClassRec 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
148 WidgetClass menuButtonWidgetClass = (WidgetClass)&menuButtonClassRec;
149
150 /*
151  * Implementation
152  */
153 static void
154 XawMenuButtonClassInitialize(void)
155 {
156     XawInitializeWidgetSet();
157     XtRegisterGrabAction(PopupMenu, True,
158                          ButtonPressMask | ButtonReleaseMask,
159                          GrabModeAsync, GrabModeAsync);
160 }
161
162 /*ARGSUSED*/
163 static void
164 XawMenuButtonInitialize(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
173 static void
174 XawMenuButtonDestroy(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*/
183 static Boolean
184 XawMenuButtonSetValues(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*/
202 static void
203 PopupMenu(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 }