1 /************************************************************************/
2 /* File : menu.c */
3 /* Description : Implement a Motif MenuBar into Mxvile */
4 /* Parse a File (environment variable XVILE_MENU) */
5 /* and create it at the top of the window */
6 /* Auteur : Philippe CHASSANY */
7 /* Date : 20/02/97 */
8 /************************************************************************/
9
10 /*
11 * $Id: x11menu.c,v 1.23 2021/12/08 21:24:48 tom Exp $
12 */
13
14 #define NEED_X_INCLUDES 1
15
16 /* Vile includes */
17 #include "estruct.h"
18 #include "edef.h"
19
20 #if DISP_X11
21
22 #if ATHENA_WIDGETS
23 #if defined(HAVE_LIB_XAW3DXFT)
24 #include <X11/Xaw3dxft/Form.h>
25 #include <X11/Xaw3dxft/SimpleMenu.h>
26 #include <X11/Xaw3dxft/MenuButton.h>
27 #include <X11/Xaw3dxft/SmeLine.h>
28 #include <X11/Xaw3dxft/SmeBSB.h>
29 #elif defined(HAVE_LIB_XAW3D)
30 #include <X11/Xaw3d/Form.h>
31 #include <X11/Xaw3d/SimpleMenu.h>
32 #include <X11/Xaw3d/MenuButton.h>
33 #include <X11/Xaw3d/SmeLine.h>
34 #include <X11/Xaw3d/SmeBSB.h>
35 #elif defined(HAVE_LIB_XAWPLUS)
36 #include <X11/XawPlus/Form.h>
37 #include <X11/XawPlus/SimpleMenu.h>
38 #include <X11/XawPlus/MenuButton.h>
39 #include <X11/XawPlus/SmeLine.h>
40 #include <X11/XawPlus/SmeBSB.h>
41 #elif defined(HAVE_LIB_NEXTAW)
42 #include <X11/neXtaw/Form.h>
43 #include <X11/neXtaw/SimpleMenu.h>
44 #include <X11/neXtaw/MenuButton.h>
45 #include <X11/neXtaw/SmeLine.h>
46 #include <X11/neXtaw/SmeBSB.h>
47 #elif defined(HAVE_LIB_XAW)
48 #include <X11/Xaw/Form.h>
49 #include <X11/Xaw/SimpleMenu.h>
50 #include <X11/Xaw/MenuButton.h>
51 #include <X11/Xaw/SmeLine.h>
52 #include <X11/Xaw/SmeBSB.h>
53 #endif
54 #elif MOTIF_WIDGETS
55 #include <Xm/MainW.h>
56 #include <Xm/CascadeB.h>
57 #include <Xm/SeparatoG.h>
58 #include <Xm/RowColumn.h>
59 #include <Xm/PushBG.h>
60 #include <Xm/ToggleB.h>
61 #endif
62
63 #define Nval(name,value) name, (XtArgVal)(value)
64 #define Sval(name,value) name, (value)
65
66 #define MY_MENUS struct MyMenus
67 MY_MENUS {
68 MY_MENUS *next;
69 Widget parent;
70 Widget child;
71 };
72
73 /* Locals */
74 static Widget cascade;
75 static MY_MENUS *my_menus;
76
77 /************************************************************************/
78 /* Motif function to make a cascade button into a menubar */
79 /************************************************************************/
80 void *
gui_make_menu(void * menubar,const char * nom,int the_class GCC_UNUSED)81 gui_make_menu(void *menubar, const char *nom, int the_class GCC_UNUSED)
82 {
83 MY_MENUS *remember;
84 Widget pm;
85 Widget menub = (Widget) menubar;
86 #if MOTIF_WIDGETS
87 XmString xms;
88 char str[50];
89
90 sprintf(str, "%sMenu", nom);
91 pm = (Widget) XmCreatePulldownMenu(menub, str, NULL, 0);
92 #if OPT_MENUS_COLORED
93 XtVaSetValues(pm,
94 Nval(XtNforeground, x_menu_foreground()),
95 Nval(XtNbackground, x_menu_background()),
96 NULL);
97 XtVaSetValues(menub,
98 Nval(XtNforeground, x_menu_foreground()),
99 Nval(XtNbackground, x_menu_background()),
100 NULL);
101 #endif /* OPT_MENUS_COLORED */
102
103 xms = XmStringCreateSimple(nom);
104
105 cascade = XtVaCreateManagedWidget("menuHeader",
106 xmCascadeButtonWidgetClass, menub,
107 Nval(XmNlabelString, xms),
108 Nval(XmNsubMenuId, pm),
109 #if OPT_MENUS_COLORED
110 Nval(XtNforeground, x_menu_foreground()),
111 Nval(XtNbackground, x_menu_background()),
112 #endif /* OPT_MENUS_COLORED */
113 NULL);
114 XmStringFree(xms);
115
116 if (the_class == 'H') {
117 XtVaSetValues(menub,
118 Nval(XmNmenuHelpWidget, cascade),
119 NULL);
120 }
121 #elif ATHENA_WIDGETS
122 static Widget last;
123 char *str = XtMalloc((Cardinal) strlen(nom) + 10);
124
125 sprintf(str, "%sMenu", nom);
126 pm = XtVaCreatePopupShell(str,
127 simpleMenuWidgetClass,
128 menub,
129 Nval(XtNgeometry, NULL),
130 NULL);
131
132 cascade = XtVaCreateManagedWidget("menuHeader",
133 menuButtonWidgetClass,
134 menub,
135 Nval(XtNheight, x_menu_height()),
136 Nval(XtNlabel, nom),
137 Nval(XtNfromHoriz, last),
138 Nval(XtNmenuName, str),
139 NULL);
140 #if OPT_MENUS_COLORED
141 XtVaSetValues(pm,
142 Nval(XtNforeground, x_menu_foreground()),
143 Nval(XtNbackground, x_menu_background()),
144 NULL);
145 XtVaSetValues(menub,
146 Nval(XtNforeground, x_menu_foreground()),
147 Nval(XtNbackground, x_menu_background()),
148 NULL);
149 XtVaSetValues(cascade,
150 Nval(XtNforeground, x_menu_foreground()),
151 Nval(XtNbackground, x_menu_background()),
152 NULL);
153 #endif /* OPT_MENUS_COLORED */
154 last = cascade;
155
156 #endif /* ATHENA_WIDGETS */
157
158 /* remember the widgets we created, so we can destroy them */
159 if ((remember = typecalloc(MY_MENUS)) != 0) {
160 remember->parent = pm;
161 remember->child = cascade;
162 remember->next = my_menus;
163 my_menus = remember;
164 }
165
166 return (void *) pm;
167 }
168
169 /************************************************************************/
170 /* Motif function to make a button into a cascade (with accelarator) */
171 /************************************************************************/
172 void *
gui_add_menu_item(void * pm,const char * nom,char * accel GCC_UNUSED,int the_class)173 gui_add_menu_item(void *pm, const char *nom, char *accel GCC_UNUSED, int the_class)
174 {
175 Widget w;
176 #if MOTIF_WIDGETS
177 XmString xms_accl;
178 XmString xms_name;
179 WidgetClass wc;
180
181 switch (the_class) {
182 case 'S':
183 wc = xmSeparatorGadgetClass;
184 break;
185 default:
186 /* FALLTHRU */
187 case 'B':
188 wc = xmPushButtonGadgetClass;
189 break;
190 }
191
192 if (accel != NULL)
193 xms_accl = XmStringCreateSimple(accel);
194 else
195 xms_accl = XmStringCreateSimple("");
196
197 xms_name = XmStringCreateSimple(nom);
198 w = XtVaCreateManagedWidget("menuEntry",
199 wc,
200 (Widget) pm,
201 Nval(XmNacceleratorText, xms_accl),
202 Nval(XmNlabelString, xms_name),
203 NULL);
204
205 XmStringFree(xms_accl);
206 XmStringFree(xms_name);
207
208 #elif ATHENA_WIDGETS
209 w = XtVaCreateManagedWidget("menuEntry",
210 ((the_class == 'B')
211 ? smeBSBObjectClass
212 : smeLineObjectClass),
213 (Widget) pm,
214 Nval(XtNlabel, nom),
215 NULL);
216
217 #endif /* ATHENA_WIDGETS */
218 return (void *) w;
219 }
220
221 /************************************************************************/
222 /* Function called when a buffer button is clicked into the menu */
223 /* A buffer button takes part from the list tokens (L) */
224 /************************************************************************/
225 static void
list_proc_back(Widget w GCC_UNUSED,XtPointer bname GCC_UNUSED,XtPointer call GCC_UNUSED)226 list_proc_back(Widget w GCC_UNUSED,
227 XtPointer bname GCC_UNUSED,
228 XtPointer call GCC_UNUSED)
229 {
230 int num_buff;
231 int oldflag = im_waiting(-1);
232
233 #if MOTIF_WIDGETS
234 char *accel;
235 XmString xms;
236 XtVaGetValues(w, XmNacceleratorText, &xms, NULL);
237 #ifndef XmFONTLIST_DEFAULT_TAG
238 #define XmFONTLIST_DEFAULT_TAG "XmFONTLIST_DEFAULT_TAG_STRING"
239 #endif
240 XmStringGetLtoR(xms, XmFONTLIST_DEFAULT_TAG, &accel);
241 num_buff = atoi(&accel[1]);
242 #elif ATHENA_WIDGETS
243 num_buff = (int) (long) bname;
244 #endif
245
246 if (vile_is_busy)
247 return;
248
249 (void) histbuff(TRUE, num_buff);
250 (void) im_waiting(oldflag);
251 (void) update(TRUE);
252 }
253
254 /************************************************************************/
255 /* Function called when a button is clicked into the menu */
256 /* Bind and Action are tested */
257 /************************************************************************/
258 static void
proc_back(Widget w GCC_UNUSED,XtPointer arg,XtPointer call GCC_UNUSED)259 proc_back(Widget w GCC_UNUSED, XtPointer arg, XtPointer call GCC_UNUSED)
260 {
261 char *macro_action = (char *) arg;
262 ActionFunc fact;
263 int oldflag = im_waiting(-1);
264 int exec_flag = TRUE;
265 char *s;
266
267 TRACE(("Macro/Action=%s\n", macro_action));
268
269 #if OPT_WORKING
270 if (vile_is_busy)
271 return;
272 #endif
273
274 if ((s = vlmenu_is_cmd(macro_action)) != 0) {
275 macro_action = s;
276 exec_flag = FALSE;
277 }
278
279 if (vlmenu_is_bind(macro_action)) {
280 docmd(macro_action, exec_flag, FALSE, 1);
281 } else {
282 /* Action predefined */
283 fact = vlmenu_action_func(macro_action);
284 if (fact != NULL)
285 fact(macro_action);
286 }
287
288 (void) im_waiting(oldflag);
289 (void) update(TRUE);
290 }
291
292 void
gui_add_func_callback(void * w,void * closure)293 gui_add_func_callback(void *w, void *closure)
294 {
295 #if MOTIF_WIDGETS
296 XtAddCallback((Widget) w, XmNactivateCallback, proc_back, closure);
297 #elif ATHENA_WIDGETS
298 XtAddCallback((Widget) w, XtNcallback, proc_back, closure);
299 #endif /* ATHENA_WIDGETS */
300 }
301
302 /************************************************************************/
303 /* Function called when the cascade containing the List (buffers) */
304 /* is clicked => Post the PullDown associated */
305 /* It's dirty ... */
306 /************************************************************************/
307 static void
post_buffer_list(Widget w GCC_UNUSED,XtPointer client GCC_UNUSED,XEvent * ev GCC_UNUSED,Boolean * ok GCC_UNUSED)308 post_buffer_list(Widget w GCC_UNUSED,
309 XtPointer client GCC_UNUSED,
310 XEvent * ev GCC_UNUSED,
311 Boolean *ok GCC_UNUSED)
312 {
313 static unsigned in_item_menu_list = 0; /* number allocated */
314 static unsigned nb_item_menu_list = 0; /* number in use */
315 static Widget *pm_buffer;
316
317 unsigned i, n = nb_item_menu_list;
318 BUFFER *bp;
319 char string[NBUFN + 2 + NFILEN], temp[1 + NFILEN], *p;
320 Widget pm = (Widget) client;
321
322 TRACE(("post_buffer_list\n"));
323 nb_item_menu_list = 0;
324
325 for_each_buffer(bp) {
326 if (b_is_temporary(bp)) /* cf: hist_show() */
327 continue;
328
329 p = shorten_path(vl_strncpy(temp, bp->b_fname, sizeof(temp)), FALSE);
330 sprintf(string, "%-*.*s %s", NBUFN - 1, NBUFN - 1,
331 bp->b_bname, p);
332
333 sprintf(temp, "_%d", nb_item_menu_list);
334 TRACE(("ACCEL(%s) = %s\n", temp, string));
335
336 if (nb_item_menu_list + 2 >= in_item_menu_list) {
337 unsigned m = in_item_menu_list;
338
339 in_item_menu_list = (in_item_menu_list + 3) * 2;
340
341 if (pm_buffer != 0)
342 pm_buffer = typereallocn(Widget, pm_buffer, in_item_menu_list);
343 else
344 pm_buffer = typeallocn(Widget, in_item_menu_list);
345
346 if (pm_buffer == 0) {
347 no_memory("post_buffer_list");
348 return;
349 }
350
351 while (m < in_item_menu_list)
352 pm_buffer[m++] = 0;
353 }
354
355 if (pm_buffer[nb_item_menu_list] == 0) {
356 pm_buffer[nb_item_menu_list] = (Widget) gui_add_menu_item(pm, string,
357 temp, 'B');
358 } else {
359 #if MOTIF_WIDGETS
360 XmString xms = XmStringCreateSimple(string);
361 XtVaSetValues(pm_buffer[nb_item_menu_list],
362 Nval(XmNlabelString, xms),
363 NULL);
364 XmStringFree(xms);
365 XtRemoveCallback(pm_buffer[nb_item_menu_list],
366 XmNactivateCallback, list_proc_back, NULL);
367 #elif ATHENA_WIDGETS
368 XtVaSetValues(pm_buffer[nb_item_menu_list],
369 Nval(XtNlabel, string),
370 NULL);
371 XtRemoveAllCallbacks(pm_buffer[nb_item_menu_list],
372 XtNcallback);
373 #endif
374 }
375
376 #if MOTIF_WIDGETS
377 XtAddCallback(pm_buffer[nb_item_menu_list],
378 XmNactivateCallback,
379 list_proc_back,
380 NULL);
381 #elif ATHENA_WIDGETS
382 XtAddCallback(pm_buffer[nb_item_menu_list],
383 XtNcallback,
384 list_proc_back,
385 (XtPointer) (long) nb_item_menu_list);
386 #endif
387 nb_item_menu_list++;
388 }
389 for (i = nb_item_menu_list; i < n; i++) {
390 XtDestroyWidget(pm_buffer[i]);
391 pm_buffer[i] = NULL;
392 }
393
394 #if MOTIF_WIDGETS
395 XmUpdateDisplay(pm);
396 #endif
397 }
398
399 void
gui_add_list_callback(void * pm)400 gui_add_list_callback(void *pm)
401 {
402 if (cascade != 0)
403 XtAddEventHandler(cascade,
404 ButtonPressMask,
405 False,
406 post_buffer_list,
407 (Widget) pm);
408 }
409
410 /*
411 * Hide/show menus, useful for avoiding thrashing while regenerating menus
412 */
413 int
gui_hide_menus(int f GCC_UNUSED,int n GCC_UNUSED)414 gui_hide_menus(int f GCC_UNUSED, int n GCC_UNUSED)
415 {
416 int rc = FALSE;
417 Widget w = x_menu_widget();
418
419 if (w != 0) {
420 XtUnmapWidget(w);
421 rc = TRUE;
422 }
423 TRACE(("gui_hide_menus %d\n", rc));
424 return rc;
425 }
426
427 int
gui_show_menus(int f GCC_UNUSED,int n GCC_UNUSED)428 gui_show_menus(int f GCC_UNUSED, int n GCC_UNUSED)
429 {
430 int rc = FALSE;
431 Widget w = x_menu_widget();
432
433 if (w != 0) {
434 XtMapWidget(w);
435 rc = TRUE;
436 }
437 TRACE(("gui_show_menus %d\n", rc));
438 return rc;
439 }
440
441 /*
442 * Remove children of the current menu widget, so we can regenerate them.
443 */
444 int
gui_remove_menus(int f GCC_UNUSED,int n GCC_UNUSED)445 gui_remove_menus(int f GCC_UNUSED, int n GCC_UNUSED)
446 {
447 int rc = TRUE;
448 int count = 0;
449
450 gui_hide_menus(f, n);
451 while (my_menus != 0) {
452 MY_MENUS *next = my_menus->next;
453
454 XtUnmanageChild(my_menus->parent);
455 XtDestroyWidget(my_menus->parent);
456 XtDestroyWidget(my_menus->child);
457
458 free(my_menus);
459 my_menus = next;
460 ++count;
461 }
462 TRACE(("gui_remove_menus %d\n", count));
463 return rc;
464 }
465
466 /*
467 * (Re)create the menus.
468 */
469 int
gui_create_menus(void)470 gui_create_menus(void)
471 {
472 int rc = do_menu(x_menu_widget());
473 TRACE(("gui_create_menus %d\n", rc));
474 return rc;
475 }
476
477 #endif /* DISP_X11 */
478