1 /* The lwlib interface to "xlwmenu" menus.
2 
3 Copyright (C) 1992 Lucid, Inc.
4 Copyright (C) 1994, 2000-2021 Free Software Foundation, Inc.
5 
6 This file is part of the Lucid Widget Library.
7 
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 1, or (at your option)
11 any later version.
12 
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
20 
21 #include <config.h>
22 
23 #include <setjmp.h>
24 #include <lisp.h>
25 
26 #include "lwlib-Xlw.h"
27 #include <X11/StringDefs.h>
28 #include <X11/IntrinsicP.h>
29 #include <X11/ObjectP.h>
30 #include <X11/CompositeP.h>
31 #include <X11/Shell.h>
32 #include "xlwmenu.h"
33 
34 #if 0
35 
36 #include <stdio.h>
37 
38 /* Print the complete X resource name of widget WIDGET to stderr.
39    This is sometimes handy to have available.  */
40 
41 void
42 x_print_complete_resource_name (Widget widget)
43 {
44   int i;
45   String names[100];
46 
47   for (i = 0; i < 100 && widget != NULL; ++i)
48     {
49       names[i] = XtName (widget);
50       widget = XtParent (widget);
51     }
52 
53   for (--i; i >= 1; --i)
54     fprintf (stderr, "%s.", names[i]);
55   fprintf (stderr, "%s\n", names[0]);
56 }
57 
58 #endif /* 0 */
59 
60 
61 /* Menu callbacks */
62 
63 /* Callback XtNhighlightCallback for Lucid menus.  W is the menu
64    widget, CLIENT_DATA contains a pointer to the widget_instance
65    for the menu, CALL_DATA contains a pointer to the widget_value
66    structure for the highlighted menu item.  The latter may be null
67    if there isn't any highlighted menu item.  */
68 
69 static void
highlight_hook(Widget w,XtPointer client_data,XtPointer call_data)70 highlight_hook (Widget w, XtPointer client_data, XtPointer call_data)
71 {
72   widget_instance *instance = (widget_instance *) client_data;
73 
74   if (instance->info->highlight_cb
75       && !w->core.being_destroyed)
76     instance->info->highlight_cb (w, instance->info->id, call_data);
77 }
78 
79 static void
enter_hook(Widget w,XtPointer client_data,XtPointer call_data)80 enter_hook (Widget w, XtPointer client_data, XtPointer call_data)
81 {
82   highlight_hook (w, client_data, call_data);
83 }
84 
85 static void
leave_hook(Widget w,XtPointer client_data,XtPointer call_data)86 leave_hook (Widget w, XtPointer client_data, XtPointer call_data)
87 {
88   highlight_hook (w, client_data, NULL);
89 }
90 
91 
92 static void
pre_hook(Widget w,XtPointer client_data,XtPointer call_data)93 pre_hook (Widget w, XtPointer client_data, XtPointer call_data)
94 {
95   widget_instance* instance = (widget_instance*)client_data;
96   widget_value* val;
97 
98   if (w->core.being_destroyed)
99     return;
100 
101   val = lw_get_widget_value_for_widget (instance, w);
102   if (instance->info->pre_activate_cb)
103     instance->info->pre_activate_cb (w, instance->info->id,
104 				     val ? val->call_data : NULL);
105 }
106 
107 static void
pick_hook(Widget w,XtPointer client_data,XtPointer call_data)108 pick_hook (Widget w, XtPointer client_data, XtPointer call_data)
109 {
110   widget_instance* instance = (widget_instance*)client_data;
111   widget_value* contents_val = (widget_value*)call_data;
112   widget_value* widget_val;
113   XtPointer widget_arg;
114 
115   if (w->core.being_destroyed)
116     return;
117 
118   if (instance->info->selection_cb && contents_val && contents_val->enabled
119       && !contents_val->contents)
120     instance->info->selection_cb (w, instance->info->id,
121 				  contents_val->call_data);
122 
123   widget_val = lw_get_widget_value_for_widget (instance, w);
124   widget_arg = widget_val ? widget_val->call_data : NULL;
125   if (instance->info->post_activate_cb)
126     instance->info->post_activate_cb (w, instance->info->id, widget_arg);
127 
128 }
129 
130 /* creation functions */
131 
132 static Widget
xlw_create_menubar(widget_instance * instance)133 xlw_create_menubar (widget_instance *instance)
134 {
135   Widget widget;
136   Arg al[5];
137   int ac = 0;
138 
139   XtSetArg (al[ac], XtNmenu, instance->info->val); ac++;
140 #ifdef emacs
141   XtSetArg (al[ac], XtNshowGrip, 0); ac++;
142   XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
143   XtSetArg (al[ac], XtNallowResize, 1); ac++;
144 #endif
145 
146   /* This used to use XtVaCreateWidget, but an old Xt version
147      has a bug in XtVaCreateWidget that frees instance->info->name.  */
148   widget
149     = XtCreateWidget (instance->info->name, xlwMenuWidgetClass,
150 		      instance->parent, al, ac);
151 
152   XtAddCallback (widget, XtNopen, pre_hook, (XtPointer)instance);
153   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
154   XtAddCallback (widget, XtNleaveCallback, leave_hook, (XtPointer)instance);
155   XtAddCallback (widget, XtNenterCallback, enter_hook, (XtPointer)instance);
156   return widget;
157 }
158 
159 static Widget
xlw_create_popup_menu(widget_instance * instance)160 xlw_create_popup_menu (widget_instance *instance)
161 {
162   Widget popup_shell
163     = XtCreatePopupShell (instance->info->name, overrideShellWidgetClass,
164 			  instance->parent, NULL, 0);
165 
166   Widget widget;
167   Arg al[2];
168   int ac = 0;
169 
170   XtSetArg (al[ac], XtNmenu, instance->info->val); ac++;
171   XtSetArg (al[ac], XtNhorizontal, False); ac++;
172 
173   /* This used to use XtVaManagedCreateWidget, but an old Xt version
174      has a bug in XtVaManagedCreateWidget that frees instance->info->name.  */
175   widget
176     = XtCreateManagedWidget ("popup", xlwMenuWidgetClass,
177 			     popup_shell, al, ac);
178 
179   XtAddCallback (widget, XtNselect, pick_hook, (XtPointer)instance);
180   XtAddCallback (widget, XtNleaveCallback, leave_hook, (XtPointer)instance);
181   XtAddCallback (widget, XtNenterCallback, enter_hook, (XtPointer)instance);
182 
183   return popup_shell;
184 }
185 
186 widget_creation_entry
187 xlw_creation_table [] =
188 {
189   {"menubar", xlw_create_menubar},
190   {"popup", xlw_create_popup_menu},
191   {NULL, NULL}
192 };
193 
194 Boolean
lw_lucid_widget_p(Widget widget)195 lw_lucid_widget_p (Widget widget)
196 {
197   WidgetClass the_class = XtClass (widget);
198 
199   if (the_class == xlwMenuWidgetClass)
200     return True;
201   if (the_class == overrideShellWidgetClass)
202     return (XtClass (((CompositeWidget)widget)->composite.children [0])
203 	    == xlwMenuWidgetClass);
204   return False;
205 }
206 
207 void
xlw_update_one_widget(widget_instance * instance,Widget widget,widget_value * val,Boolean deep_p)208 xlw_update_one_widget (widget_instance* instance, Widget widget,
209 		       widget_value* val, Boolean deep_p)
210 {
211   Arg al[1];
212 
213   /* This used to use XtVaSetValues, but some old Xt versions
214      that have a bug in XtVaCreateWidget might have it here too.  */
215   XtSetArg (al[0], XtNmenu, instance->info->val);
216 
217   XtSetValues (widget, al, 1);
218 }
219 
220 void
xlw_update_one_value(widget_instance * instance,Widget widget,widget_value * val)221 xlw_update_one_value (widget_instance *instance,
222                       Widget widget,
223                       widget_value *val)
224 {
225   return;
226 }
227 
228 void
xlw_pop_instance(widget_instance * instance,Boolean up)229 xlw_pop_instance (widget_instance* instance, Boolean up)
230 {
231 }
232 
233 void
xlw_popup_menu(Widget widget,XEvent * event)234 xlw_popup_menu (Widget widget, XEvent *event)
235 {
236   XlwMenuWidget mw;
237 
238   if (!XtIsShell (widget))
239     return;
240 
241   mw = (XlwMenuWidget)((CompositeWidget)widget)->composite.children [0];
242 
243   if (event)
244     XtCallActionProc ((Widget) mw, "start", event, NULL, 0);
245   else
246     {
247       XEvent dummy;
248       XButtonPressedEvent *bd = &dummy.xbutton;
249 
250       bd->type = ButtonPress;
251       bd->serial = 0;
252       bd->send_event = 0;
253       bd->display = XtDisplay (widget);
254       bd->window = XtWindow (XtParent (widget));
255       bd->time = CurrentTime;
256       bd->button = 0;
257       XQueryPointer (bd->display, bd->window, &bd->root,
258 		     &bd->subwindow, &bd->x_root, &bd->y_root,
259 		     &bd->x, &bd->y, &bd->state);
260 
261       XtCallActionProc ((Widget) mw, "start", &dummy, NULL, 0);
262     }
263 }
264 
265 /* Destruction of instances */
266 void
xlw_destroy_instance(widget_instance * instance)267 xlw_destroy_instance (widget_instance *instance)
268 {
269   if (instance->widget)
270     XtDestroyWidget (instance->widget);
271 }
272