]> code.delx.au - gnu-emacs/blob - src/xmenu.c
Use bool for boolean in xmenu.c, xml.c
[gnu-emacs] / src / xmenu.c
1 /* X Communication module for terminals which understand the X protocol.
2
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
4 Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Emacs 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 <http://www.gnu.org/licenses/>. */
20
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 *
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
25 *
26 */
27
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
30
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
32
33 #include <config.h>
34
35 #include <stdio.h>
36
37 #include "lisp.h"
38 #include "keyboard.h"
39 #include "keymap.h"
40 #include "frame.h"
41 #include "termhooks.h"
42 #include "window.h"
43 #include "blockinput.h"
44 #include "character.h"
45 #include "buffer.h"
46 #include "charset.h"
47 #include "coding.h"
48 #include "sysselect.h"
49
50 #ifdef MSDOS
51 #include "msdos.h"
52 #endif
53
54 #ifdef HAVE_X_WINDOWS
55 /* This may include sys/types.h, and that somehow loses
56 if this is not done before the other system files. */
57 #include "xterm.h"
58 #endif
59
60 /* Load sys/types.h if not already loaded.
61 In some systems loading it twice is suicidal. */
62 #ifndef makedev
63 #include <sys/types.h>
64 #endif
65
66 #include "dispextern.h"
67
68 #ifdef HAVE_X_WINDOWS
69 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
70 code accepts the Emacs internal encoding. */
71 #undef HAVE_MULTILINGUAL_MENU
72 #ifdef USE_X_TOOLKIT
73 #include "widget.h"
74 #include <X11/Xlib.h>
75 #include <X11/IntrinsicP.h>
76 #include <X11/CoreP.h>
77 #include <X11/StringDefs.h>
78 #include <X11/Shell.h>
79 #ifdef USE_LUCID
80 #include "xsettings.h"
81 #include "../lwlib/xlwmenu.h"
82 #ifdef HAVE_XAW3D
83 #include <X11/Xaw3d/Paned.h>
84 #else /* !HAVE_XAW3D */
85 #include <X11/Xaw/Paned.h>
86 #endif /* HAVE_XAW3D */
87 #endif /* USE_LUCID */
88 #ifdef USE_MOTIF
89 #include "../lwlib/lwlib.h"
90 #endif
91 #else /* not USE_X_TOOLKIT */
92 #ifndef USE_GTK
93 #include "../oldXMenu/XMenu.h"
94 #endif
95 #endif /* not USE_X_TOOLKIT */
96 #endif /* HAVE_X_WINDOWS */
97
98 #ifdef USE_GTK
99 #include "gtkutil.h"
100 #ifdef HAVE_GTK3
101 #include "xgselect.h"
102 #endif
103 #endif
104
105 #include "menu.h"
106
107 \f
108 /* Flag which when set indicates a dialog or menu has been posted by
109 Xt on behalf of one of the widget sets. */
110 static int popup_activated_flag;
111
112 \f
113 #ifdef USE_X_TOOLKIT
114
115 static LWLIB_ID next_menubar_widget_id;
116
117 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
118
119 static struct frame *
120 menubar_id_to_frame (LWLIB_ID id)
121 {
122 Lisp_Object tail, frame;
123 struct frame *f;
124
125 FOR_EACH_FRAME (tail, frame)
126 {
127 f = XFRAME (frame);
128 if (!FRAME_WINDOW_P (f))
129 continue;
130 if (f->output_data.x->id == id)
131 return f;
132 }
133 return 0;
134 }
135
136 #endif
137
138 #ifndef MSDOS
139
140 #if defined USE_GTK || defined USE_MOTIF
141
142 /* Set menu_items_inuse so no other popup menu or dialog is created. */
143
144 void
145 x_menu_set_in_use (bool in_use)
146 {
147 menu_items_inuse = in_use ? Qt : Qnil;
148 popup_activated_flag = in_use;
149 #ifdef USE_X_TOOLKIT
150 if (popup_activated_flag)
151 x_activate_timeout_atimer ();
152 #endif
153 }
154
155 #endif
156
157 /* Wait for an X event to arrive or for a timer to expire. */
158
159 void
160 x_menu_wait_for_event (void *data)
161 {
162 /* Another way to do this is to register a timer callback, that can be
163 done in GTK and Xt. But we have to do it like this when using only X
164 anyway, and with callbacks we would have three variants for timer handling
165 instead of the small ifdefs below. */
166
167 while (
168 #ifdef USE_X_TOOLKIT
169 ! XtAppPending (Xt_app_con)
170 #elif defined USE_GTK
171 ! gtk_events_pending ()
172 #else
173 ! XPending (data)
174 #endif
175 )
176 {
177 struct timespec next_time = timer_check (), *ntp;
178 fd_set read_fds;
179 struct x_display_info *dpyinfo;
180 int n = 0;
181
182 FD_ZERO (&read_fds);
183 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
184 {
185 int fd = ConnectionNumber (dpyinfo->display);
186 FD_SET (fd, &read_fds);
187 if (fd > n) n = fd;
188 XFlush (dpyinfo->display);
189 }
190
191 if (! timespec_valid_p (next_time))
192 ntp = 0;
193 else
194 ntp = &next_time;
195
196 #if defined USE_GTK && defined HAVE_GTK3
197 /* Gtk3 have arrows on menus when they don't fit. When the
198 pointer is over an arrow, a timeout scrolls it a bit. Use
199 xg_select so that timeout gets triggered. */
200 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
201 #else
202 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
203 #endif
204 }
205 }
206 #endif /* ! MSDOS */
207
208 \f
209 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
210
211 #ifdef USE_X_TOOLKIT
212
213 /* Loop in Xt until the menu pulldown or dialog popup has been
214 popped down (deactivated). This is used for x-popup-menu
215 and x-popup-dialog; it is not used for the menu bar.
216
217 NOTE: All calls to popup_get_selection should be protected
218 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
219
220 static void
221 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
222 LWLIB_ID id, bool do_timers)
223 {
224 XEvent event;
225
226 while (popup_activated_flag)
227 {
228 if (initial_event)
229 {
230 event = *initial_event;
231 initial_event = 0;
232 }
233 else
234 {
235 if (do_timers) x_menu_wait_for_event (0);
236 XtAppNextEvent (Xt_app_con, &event);
237 }
238
239 /* Make sure we don't consider buttons grabbed after menu goes.
240 And make sure to deactivate for any ButtonRelease,
241 even if XtDispatchEvent doesn't do that. */
242 if (event.type == ButtonRelease
243 && dpyinfo->display == event.xbutton.display)
244 {
245 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
246 #ifdef USE_MOTIF /* Pretending that the event came from a
247 Btn1Down seems the only way to convince Motif to
248 activate its callbacks; setting the XmNmenuPost
249 isn't working. --marcus@sysc.pdx.edu. */
250 event.xbutton.button = 1;
251 /* Motif only pops down menus when no Ctrl, Alt or Mod
252 key is pressed and the button is released. So reset key state
253 so Motif thinks this is the case. */
254 event.xbutton.state = 0;
255 #endif
256 }
257 /* Pop down on C-g and Escape. */
258 else if (event.type == KeyPress
259 && dpyinfo->display == event.xbutton.display)
260 {
261 KeySym keysym = XLookupKeysym (&event.xkey, 0);
262
263 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
264 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
265 popup_activated_flag = 0;
266 }
267
268 x_dispatch_event (&event, event.xany.display);
269 }
270 }
271
272 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
273 doc: /* Start key navigation of the menu bar in FRAME.
274 This initially opens the first menu bar item and you can then navigate with the
275 arrow keys, select a menu entry with the return key or cancel with the
276 escape key. If FRAME has no menu bar this function does nothing.
277
278 If FRAME is nil or not given, use the selected frame. */)
279 (Lisp_Object frame)
280 {
281 XEvent ev;
282 struct frame *f = decode_window_system_frame (frame);
283 Widget menubar;
284 block_input ();
285
286 if (FRAME_EXTERNAL_MENU_BAR (f))
287 set_frame_menubar (f, false, true);
288
289 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
290 if (menubar)
291 {
292 Window child;
293 bool error_p = false;
294
295 x_catch_errors (FRAME_X_DISPLAY (f));
296 memset (&ev, 0, sizeof ev);
297 ev.xbutton.display = FRAME_X_DISPLAY (f);
298 ev.xbutton.window = XtWindow (menubar);
299 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
300 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
301 ev.xbutton.button = Button1;
302 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
303 ev.xbutton.same_screen = True;
304
305 #ifdef USE_MOTIF
306 {
307 Arg al[2];
308 WidgetList list;
309 Cardinal nr;
310 XtSetArg (al[0], XtNchildren, &list);
311 XtSetArg (al[1], XtNnumChildren, &nr);
312 XtGetValues (menubar, al, 2);
313 ev.xbutton.window = XtWindow (list[0]);
314 }
315 #endif
316
317 XTranslateCoordinates (FRAME_X_DISPLAY (f),
318 /* From-window, to-window. */
319 ev.xbutton.window, ev.xbutton.root,
320
321 /* From-position, to-position. */
322 ev.xbutton.x, ev.xbutton.y,
323 &ev.xbutton.x_root, &ev.xbutton.y_root,
324
325 /* Child of win. */
326 &child);
327 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
328 x_uncatch_errors ();
329
330 if (! error_p)
331 {
332 ev.type = ButtonPress;
333 ev.xbutton.state = 0;
334
335 XtDispatchEvent (&ev);
336 ev.xbutton.type = ButtonRelease;
337 ev.xbutton.state = Button1Mask;
338 XtDispatchEvent (&ev);
339 }
340 }
341
342 unblock_input ();
343
344 return Qnil;
345 }
346 #endif /* USE_X_TOOLKIT */
347
348
349 #ifdef USE_GTK
350 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
351 doc: /* Start key navigation of the menu bar in FRAME.
352 This initially opens the first menu bar item and you can then navigate with the
353 arrow keys, select a menu entry with the return key or cancel with the
354 escape key. If FRAME has no menu bar this function does nothing.
355
356 If FRAME is nil or not given, use the selected frame. */)
357 (Lisp_Object frame)
358 {
359 GtkWidget *menubar;
360 struct frame *f;
361
362 block_input ();
363 f = decode_window_system_frame (frame);
364
365 if (FRAME_EXTERNAL_MENU_BAR (f))
366 set_frame_menubar (f, false, true);
367
368 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
369 if (menubar)
370 {
371 /* Activate the first menu. */
372 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
373
374 if (children)
375 {
376 g_signal_emit_by_name (children->data, "activate_item");
377 popup_activated_flag = 1;
378 g_list_free (children);
379 }
380 }
381 unblock_input ();
382
383 return Qnil;
384 }
385
386 /* Loop util popup_activated_flag is set to zero in a callback.
387 Used for popup menus and dialogs. */
388
389 static void
390 popup_widget_loop (bool do_timers, GtkWidget *widget)
391 {
392 ++popup_activated_flag;
393
394 /* Process events in the Gtk event loop until done. */
395 while (popup_activated_flag)
396 {
397 if (do_timers) x_menu_wait_for_event (0);
398 gtk_main_iteration ();
399 }
400 }
401 #endif
402
403 /* Activate the menu bar of frame F.
404 This is called from keyboard.c when it gets the
405 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
406
407 To activate the menu bar, we use the X button-press event
408 that was saved in saved_menu_event.
409 That makes the toolkit do its thing.
410
411 But first we recompute the menu bar contents (the whole tree).
412
413 The reason for saving the button event until here, instead of
414 passing it to the toolkit right away, is that we can safely
415 execute Lisp code. */
416
417 void
418 x_activate_menubar (struct frame *f)
419 {
420 eassert (FRAME_X_P (f));
421
422 if (!f->output_data.x->saved_menu_event->type)
423 return;
424
425 #ifdef USE_GTK
426 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
427 f->output_data.x->saved_menu_event->xany.window))
428 return;
429 #endif
430
431 set_frame_menubar (f, false, true);
432 block_input ();
433 popup_activated_flag = 1;
434 #ifdef USE_GTK
435 XPutBackEvent (f->output_data.x->display_info->display,
436 f->output_data.x->saved_menu_event);
437 #else
438 XtDispatchEvent (f->output_data.x->saved_menu_event);
439 #endif
440 unblock_input ();
441
442 /* Ignore this if we get it a second time. */
443 f->output_data.x->saved_menu_event->type = 0;
444 }
445
446 /* This callback is invoked when the user selects a menubar cascade
447 pushbutton, but before the pulldown menu is posted. */
448
449 #ifndef USE_GTK
450 static void
451 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
452 {
453 popup_activated_flag = 1;
454 x_activate_timeout_atimer ();
455 }
456 #endif
457
458 /* This callback is invoked when a dialog or menu is finished being
459 used and has been unposted. */
460
461 static void
462 popup_deactivate_callback (
463 #ifdef USE_GTK
464 GtkWidget *widget, gpointer client_data
465 #else
466 Widget widget, LWLIB_ID id, XtPointer client_data
467 #endif
468 )
469 {
470 popup_activated_flag = 0;
471 }
472
473
474 /* Function that finds the frame for WIDGET and shows the HELP text
475 for that widget.
476 F is the frame if known, or NULL if not known. */
477 static void
478 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
479 {
480 Lisp_Object frame;
481
482 if (f)
483 {
484 XSETFRAME (frame, f);
485 kbd_buffer_store_help_event (frame, help);
486 }
487 else
488 show_help_echo (help, Qnil, Qnil, Qnil);
489 }
490
491 /* Callback called when menu items are highlighted/unhighlighted
492 while moving the mouse over them. WIDGET is the menu bar or menu
493 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
494 the data structure for the menu item, or null in case of
495 unhighlighting. */
496
497 #ifdef USE_GTK
498 static void
499 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
500 {
501 xg_menu_item_cb_data *cb_data;
502 Lisp_Object help;
503
504 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
505 if (! cb_data) return;
506
507 help = call_data ? cb_data->help : Qnil;
508
509 /* If popup_activated_flag is greater than 1 we are in a popup menu.
510 Don't pass the frame to show_help_event for those.
511 Passing frame creates an Emacs event. As we are looping in
512 popup_widget_loop, it won't be handled. Passing NULL shows the tip
513 directly without using an Emacs event. This is what the Lucid code
514 does below. */
515 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
516 widget, help);
517 }
518 #else
519 static void
520 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
521 {
522 widget_value *wv = call_data;
523 Lisp_Object help = wv ? wv->help : Qnil;
524
525 /* Determine the frame for the help event. */
526 struct frame *f = menubar_id_to_frame (id);
527
528 show_help_event (f, widget, help);
529 }
530 #endif
531
532 #ifdef USE_GTK
533 /* Gtk calls callbacks just because we tell it what item should be
534 selected in a radio group. If this variable is set to a non-zero
535 value, we are creating menus and don't want callbacks right now.
536 */
537 static bool xg_crazy_callback_abort;
538
539 /* This callback is called from the menu bar pulldown menu
540 when the user makes a selection.
541 Figure out what the user chose
542 and put the appropriate events into the keyboard buffer. */
543 static void
544 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
545 {
546 xg_menu_item_cb_data *cb_data = client_data;
547
548 if (xg_crazy_callback_abort)
549 return;
550
551 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
552 return;
553
554 /* For a group of radio buttons, GTK calls the selection callback first
555 for the item that was active before the selection and then for the one that
556 is active after the selection. For C-h k this means we get the help on
557 the deselected item and then the selected item is executed. Prevent that
558 by ignoring the non-active item. */
559 if (GTK_IS_RADIO_MENU_ITEM (widget)
560 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
561 return;
562
563 /* When a menu is popped down, X generates a focus event (i.e. focus
564 goes back to the frame below the menu). Since GTK buffers events,
565 we force it out here before the menu selection event. Otherwise
566 sit-for will exit at once if the focus event follows the menu selection
567 event. */
568
569 block_input ();
570 while (gtk_events_pending ())
571 gtk_main_iteration ();
572 unblock_input ();
573
574 find_and_call_menu_selection (cb_data->cl_data->f,
575 cb_data->cl_data->menu_bar_items_used,
576 cb_data->cl_data->menu_bar_vector,
577 cb_data->call_data);
578 }
579
580 #else /* not USE_GTK */
581
582 /* This callback is called from the menu bar pulldown menu
583 when the user makes a selection.
584 Figure out what the user chose
585 and put the appropriate events into the keyboard buffer. */
586 static void
587 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
588 {
589 struct frame *f;
590
591 f = menubar_id_to_frame (id);
592 if (!f)
593 return;
594 find_and_call_menu_selection (f, f->menu_bar_items_used,
595 f->menu_bar_vector, client_data);
596 }
597 #endif /* not USE_GTK */
598 \f
599 /* Recompute all the widgets of frame F, when the menu bar has been
600 changed. */
601
602 static void
603 update_frame_menubar (struct frame *f)
604 {
605 #ifdef USE_GTK
606 xg_update_frame_menubar (f);
607 #else
608 struct x_output *x;
609
610 eassert (FRAME_X_P (f));
611
612 x = f->output_data.x;
613
614 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
615 return;
616
617 block_input ();
618
619 /* Do the voodoo which means "I'm changing lots of things, don't try
620 to refigure sizes until I'm done." */
621 lw_refigure_widget (x->column_widget, False);
622
623 /* The order in which children are managed is the top to bottom
624 order in which they are displayed in the paned window. First,
625 remove the text-area widget. */
626 XtUnmanageChild (x->edit_widget);
627
628 /* Remove the menubar that is there now, and put up the menubar that
629 should be there. */
630 XtManageChild (x->menubar_widget);
631 XtMapWidget (x->menubar_widget);
632 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
633
634 /* Re-manage the text-area widget, and then thrash the sizes. */
635 XtManageChild (x->edit_widget);
636 lw_refigure_widget (x->column_widget, True);
637
638 /* Force the pane widget to resize itself. */
639 int new_height = -1;
640 #ifdef USE_LUCID
641 /* For reasons I don't know Lucid wants to add one pixel to the frame
642 height when adding the menu bar. Compensate that here. */
643 new_height = FRAME_TEXT_HEIGHT (f) - 1;
644 s);
645 #endif /* USE_LUCID */
646 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
647 unblock_input ();
648 #endif /* USE_GTK */
649 }
650
651 #ifdef USE_LUCID
652 static void
653 apply_systemfont_to_dialog (Widget w)
654 {
655 const char *fn = xsettings_get_system_normal_font ();
656 if (fn)
657 {
658 XrmDatabase db = XtDatabase (XtDisplay (w));
659 if (db)
660 XrmPutStringResource (&db, "*dialog.font", fn);
661 }
662 }
663
664 static void
665 apply_systemfont_to_menu (struct frame *f, Widget w)
666 {
667 const char *fn = xsettings_get_system_normal_font ();
668
669 if (fn)
670 {
671 XrmDatabase db = XtDatabase (XtDisplay (w));
672 if (db)
673 {
674 XrmPutStringResource (&db, "*menubar*font", fn);
675 XrmPutStringResource (&db, "*popup*font", fn);
676 }
677 }
678 }
679
680 #endif
681
682 /* Set the contents of the menubar widgets of frame F.
683 The argument FIRST_TIME is currently ignored;
684 it is set the first time this is called, from initialize_frame_menubar. */
685
686 void
687 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
688 {
689 xt_or_gtk_widget menubar_widget, old_widget;
690 #ifdef USE_X_TOOLKIT
691 LWLIB_ID id;
692 #endif
693 Lisp_Object items;
694 widget_value *wv, *first_wv, *prev_wv = 0;
695 int i;
696 int *submenu_start, *submenu_end;
697 bool *submenu_top_level_items;
698 int *submenu_n_panes;
699
700 eassert (FRAME_X_P (f));
701
702 menubar_widget = old_widget = f->output_data.x->menubar_widget;
703
704 XSETFRAME (Vmenu_updating_frame, f);
705
706 #ifdef USE_X_TOOLKIT
707 if (f->output_data.x->id == 0)
708 f->output_data.x->id = next_menubar_widget_id++;
709 id = f->output_data.x->id;
710 #endif
711
712 if (! menubar_widget)
713 deep_p = true;
714 /* Make the first call for any given frame always go deep. */
715 else if (!f->output_data.x->saved_menu_event && !deep_p)
716 {
717 deep_p = true;
718 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
719 f->output_data.x->saved_menu_event->type = 0;
720 }
721
722 if (deep_p)
723 {
724 /* Make a widget-value tree representing the entire menu trees. */
725
726 struct buffer *prev = current_buffer;
727 Lisp_Object buffer;
728 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
729 int previous_menu_items_used = f->menu_bar_items_used;
730 Lisp_Object *previous_items
731 = alloca (previous_menu_items_used * sizeof *previous_items);
732 int subitems;
733
734 /* If we are making a new widget, its contents are empty,
735 do always reinitialize them. */
736 if (! menubar_widget)
737 previous_menu_items_used = 0;
738
739 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
740 specbind (Qinhibit_quit, Qt);
741 /* Don't let the debugger step into this code
742 because it is not reentrant. */
743 specbind (Qdebug_on_next_call, Qnil);
744
745 record_unwind_save_match_data ();
746 if (NILP (Voverriding_local_map_menu_flag))
747 {
748 specbind (Qoverriding_terminal_local_map, Qnil);
749 specbind (Qoverriding_local_map, Qnil);
750 }
751
752 set_buffer_internal_1 (XBUFFER (buffer));
753
754 /* Run the Lucid hook. */
755 safe_run_hooks (Qactivate_menubar_hook);
756
757 /* If it has changed current-menubar from previous value,
758 really recompute the menubar from the value. */
759 if (! NILP (Vlucid_menu_bar_dirty_flag))
760 call0 (Qrecompute_lucid_menubar);
761 safe_run_hooks (Qmenu_bar_update_hook);
762 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
763
764 items = FRAME_MENU_BAR_ITEMS (f);
765
766 /* Save the frame's previous menu bar contents data. */
767 if (previous_menu_items_used)
768 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
769 previous_menu_items_used * word_size);
770
771 /* Fill in menu_items with the current menu bar contents.
772 This can evaluate Lisp code. */
773 save_menu_items ();
774
775 menu_items = f->menu_bar_vector;
776 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
777 subitems = ASIZE (items) / 4;
778 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
779 submenu_end = alloca (subitems * sizeof *submenu_end);
780 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
781 submenu_top_level_items = alloca (subitems
782 * sizeof *submenu_top_level_items);
783 init_menu_items ();
784 for (i = 0; i < subitems; i++)
785 {
786 Lisp_Object key, string, maps;
787
788 key = AREF (items, 4 * i);
789 string = AREF (items, 4 * i + 1);
790 maps = AREF (items, 4 * i + 2);
791 if (NILP (string))
792 break;
793
794 submenu_start[i] = menu_items_used;
795
796 menu_items_n_panes = 0;
797 submenu_top_level_items[i]
798 = parse_single_submenu (key, string, maps);
799 submenu_n_panes[i] = menu_items_n_panes;
800
801 submenu_end[i] = menu_items_used;
802 }
803
804 submenu_start[i] = -1;
805 finish_menu_items ();
806
807 /* Convert menu_items into widget_value trees
808 to display the menu. This cannot evaluate Lisp code. */
809
810 wv = make_widget_value ("menubar", NULL, true, Qnil);
811 wv->button_type = BUTTON_TYPE_NONE;
812 first_wv = wv;
813
814 for (i = 0; submenu_start[i] >= 0; i++)
815 {
816 menu_items_n_panes = submenu_n_panes[i];
817 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
818 submenu_top_level_items[i]);
819 if (prev_wv)
820 prev_wv->next = wv;
821 else
822 first_wv->contents = wv;
823 /* Don't set wv->name here; GC during the loop might relocate it. */
824 wv->enabled = true;
825 wv->button_type = BUTTON_TYPE_NONE;
826 prev_wv = wv;
827 }
828
829 set_buffer_internal_1 (prev);
830
831 /* If there has been no change in the Lisp-level contents
832 of the menu bar, skip redisplaying it. Just exit. */
833
834 /* Compare the new menu items with the ones computed last time. */
835 for (i = 0; i < previous_menu_items_used; i++)
836 if (menu_items_used == i
837 || (!EQ (previous_items[i], AREF (menu_items, i))))
838 break;
839 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
840 {
841 /* The menu items have not changed. Don't bother updating
842 the menus in any form, since it would be a no-op. */
843 free_menubar_widget_value_tree (first_wv);
844 discard_menu_items ();
845 unbind_to (specpdl_count, Qnil);
846 return;
847 }
848
849 /* The menu items are different, so store them in the frame. */
850 fset_menu_bar_vector (f, menu_items);
851 f->menu_bar_items_used = menu_items_used;
852
853 /* This undoes save_menu_items. */
854 unbind_to (specpdl_count, Qnil);
855
856 /* Now GC cannot happen during the lifetime of the widget_value,
857 so it's safe to store data from a Lisp_String. */
858 wv = first_wv->contents;
859 for (i = 0; i < ASIZE (items); i += 4)
860 {
861 Lisp_Object string;
862 string = AREF (items, i + 1);
863 if (NILP (string))
864 break;
865 wv->name = SSDATA (string);
866 update_submenu_strings (wv->contents);
867 wv = wv->next;
868 }
869
870 }
871 else
872 {
873 /* Make a widget-value tree containing
874 just the top level menu bar strings. */
875
876 wv = make_widget_value ("menubar", NULL, true, Qnil);
877 wv->button_type = BUTTON_TYPE_NONE;
878 first_wv = wv;
879
880 items = FRAME_MENU_BAR_ITEMS (f);
881 for (i = 0; i < ASIZE (items); i += 4)
882 {
883 Lisp_Object string;
884
885 string = AREF (items, i + 1);
886 if (NILP (string))
887 break;
888
889 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
890 wv->button_type = BUTTON_TYPE_NONE;
891 /* This prevents lwlib from assuming this
892 menu item is really supposed to be empty. */
893 /* The intptr_t cast avoids a warning.
894 This value just has to be different from small integers. */
895 wv->call_data = (void *) (intptr_t) (-1);
896
897 if (prev_wv)
898 prev_wv->next = wv;
899 else
900 first_wv->contents = wv;
901 prev_wv = wv;
902 }
903
904 /* Forget what we thought we knew about what is in the
905 detailed contents of the menu bar menus.
906 Changing the top level always destroys the contents. */
907 f->menu_bar_items_used = 0;
908 }
909
910 /* Create or update the menu bar widget. */
911
912 block_input ();
913
914 #ifdef USE_GTK
915 xg_crazy_callback_abort = true;
916 if (menubar_widget)
917 {
918 /* The fourth arg is DEEP_P, which says to consider the entire
919 menu trees we supply, rather than just the menu bar item names. */
920 xg_modify_menubar_widgets (menubar_widget,
921 f,
922 first_wv,
923 deep_p,
924 G_CALLBACK (menubar_selection_callback),
925 G_CALLBACK (popup_deactivate_callback),
926 G_CALLBACK (menu_highlight_callback));
927 }
928 else
929 {
930 menubar_widget
931 = xg_create_widget ("menubar", "menubar", f, first_wv,
932 G_CALLBACK (menubar_selection_callback),
933 G_CALLBACK (popup_deactivate_callback),
934 G_CALLBACK (menu_highlight_callback));
935
936 f->output_data.x->menubar_widget = menubar_widget;
937 }
938
939
940 #else /* not USE_GTK */
941 if (menubar_widget)
942 {
943 /* Disable resizing (done for Motif!) */
944 lw_allow_resizing (f->output_data.x->widget, False);
945
946 /* The third arg is DEEP_P, which says to consider the entire
947 menu trees we supply, rather than just the menu bar item names. */
948 lw_modify_all_widgets (id, first_wv, deep_p);
949
950 /* Re-enable the edit widget to resize. */
951 lw_allow_resizing (f->output_data.x->widget, True);
952 }
953 else
954 {
955 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
956 XtTranslations override = XtParseTranslationTable (menuOverride);
957
958 #ifdef USE_LUCID
959 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
960 #endif
961 menubar_widget = lw_create_widget ("menubar", "menubar", id,
962 first_wv,
963 f->output_data.x->column_widget,
964 false,
965 popup_activate_callback,
966 menubar_selection_callback,
967 popup_deactivate_callback,
968 menu_highlight_callback);
969 f->output_data.x->menubar_widget = menubar_widget;
970
971 /* Make menu pop down on C-g. */
972 XtOverrideTranslations (menubar_widget, override);
973 }
974
975 {
976 int menubar_size;
977 if (f->output_data.x->menubar_widget)
978 XtRealizeWidget (f->output_data.x->menubar_widget);
979
980 menubar_size
981 = (f->output_data.x->menubar_widget
982 ? (f->output_data.x->menubar_widget->core.height
983 + f->output_data.x->menubar_widget->core.border_width)
984 : 0);
985
986 #ifdef USE_LUCID
987 /* Experimentally, we now get the right results
988 for -geometry -0-0 without this. 24 Aug 96, rms.
989 Maybe so, but the menu bar size is missing the pixels so the
990 WM size hints are off by these pixels. Jan D, oct 2009. */
991 if (FRAME_EXTERNAL_MENU_BAR (f))
992 {
993 Dimension ibw = 0;
994 XtVaGetValues (f->output_data.x->column_widget,
995 XtNinternalBorderWidth, &ibw, NULL);
996 menubar_size += ibw;
997 }
998 #endif /* USE_LUCID */
999
1000 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1001 }
1002 #endif /* not USE_GTK */
1003
1004 free_menubar_widget_value_tree (first_wv);
1005 update_frame_menubar (f);
1006
1007 #ifdef USE_GTK
1008 xg_crazy_callback_abort = false;
1009 #endif
1010
1011 unblock_input ();
1012 }
1013
1014 /* Called from Fx_create_frame to create the initial menubar of a frame
1015 before it is mapped, so that the window is mapped with the menubar already
1016 there instead of us tacking it on later and thrashing the window after it
1017 is visible. */
1018
1019 void
1020 initialize_frame_menubar (struct frame *f)
1021 {
1022 /* This function is called before the first chance to redisplay
1023 the frame. It has to be, so the frame will have the right size. */
1024 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1025 set_frame_menubar (f, true, true);
1026 }
1027
1028
1029 /* Get rid of the menu bar of frame F, and free its storage.
1030 This is used when deleting a frame, and when turning off the menu bar.
1031 For GTK this function is in gtkutil.c. */
1032
1033 #ifndef USE_GTK
1034 void
1035 free_frame_menubar (struct frame *f)
1036 {
1037 Widget menubar_widget;
1038 #ifdef USE_MOTIF
1039 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1040 If we want to preserve the old height, calculate it now so we can
1041 restore it below. */
1042 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1043 #endif
1044
1045 eassert (FRAME_X_P (f));
1046
1047 menubar_widget = f->output_data.x->menubar_widget;
1048
1049 FRAME_MENUBAR_HEIGHT (f) = 0;
1050
1051 if (menubar_widget)
1052 {
1053 #ifdef USE_MOTIF
1054 /* Removing the menu bar magically changes the shell widget's x
1055 and y position of (0, 0) which, when the menu bar is turned
1056 on again, leads to pull-down menus appearing in strange
1057 positions near the upper-left corner of the display. This
1058 happens only with some window managers like twm and ctwm,
1059 but not with other like Motif's mwm or kwm, because the
1060 latter generate ConfigureNotify events when the menu bar
1061 is switched off, which fixes the shell position. */
1062 Position x0, y0, x1, y1;
1063 #endif
1064
1065 block_input ();
1066
1067 #ifdef USE_MOTIF
1068 if (f->output_data.x->widget)
1069 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1070 #endif
1071
1072 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1073 f->output_data.x->menubar_widget = NULL;
1074
1075 if (f->output_data.x->widget)
1076 {
1077 int new_height = -1;
1078 #ifdef USE_MOTIF
1079 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1080 if (x1 == 0 && y1 == 0)
1081 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1082 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1083 new_height = old_height;
1084 #endif /* USE_MOTIF */
1085 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
1086 }
1087 else
1088 {
1089 #ifdef USE_MOTIF
1090 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1091 adjust_frame_size (f, -1, old_height, 1, false, Qmenu_bar_lines);
1092 #endif
1093 }
1094
1095 unblock_input ();
1096 }
1097 }
1098 #endif /* not USE_GTK */
1099
1100 #endif /* USE_X_TOOLKIT || USE_GTK */
1101 \f
1102 /* x_menu_show actually displays a menu using the panes and items in menu_items
1103 and returns the value selected from it.
1104 There are two versions of x_menu_show, one for Xt and one for Xlib.
1105 Both assume input is blocked by the caller. */
1106
1107 /* F is the frame the menu is for.
1108 X and Y are the frame-relative specified position,
1109 relative to the inside upper left corner of the frame F.
1110 Bitfield MENUFLAGS bits are:
1111 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1112 MENU_KEYMAPS is set if this menu was specified with keymaps;
1113 in that case, we return a list containing the chosen item's value
1114 and perhaps also the pane's prefix.
1115 TITLE is the specified menu title.
1116 ERROR is a place to store an error message string in case of failure.
1117 (We return nil on failure, but the value doesn't actually matter.) */
1118
1119 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1120
1121 /* The item selected in the popup menu. */
1122 static Lisp_Object *volatile menu_item_selection;
1123
1124 #ifdef USE_GTK
1125
1126 /* Used when position a popup menu. See menu_position_func and
1127 create_and_show_popup_menu below. */
1128 struct next_popup_x_y
1129 {
1130 struct frame *f;
1131 int x;
1132 int y;
1133 };
1134
1135 /* The menu position function to use if we are not putting a popup
1136 menu where the pointer is.
1137 MENU is the menu to pop up.
1138 X and Y shall on exit contain x/y where the menu shall pop up.
1139 PUSH_IN is not documented in the GTK manual.
1140 USER_DATA is any data passed in when calling gtk_menu_popup.
1141 Here it points to a struct next_popup_x_y where the coordinates
1142 to store in *X and *Y are as well as the frame for the popup.
1143
1144 Here only X and Y are used. */
1145 static void
1146 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1147 {
1148 struct next_popup_x_y *data = user_data;
1149 GtkRequisition req;
1150 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1151 int disp_width = x_display_pixel_width (dpyinfo);
1152 int disp_height = x_display_pixel_height (dpyinfo);
1153
1154 *x = data->x;
1155 *y = data->y;
1156
1157 /* Check if there is room for the menu. If not, adjust x/y so that
1158 the menu is fully visible. */
1159 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1160 if (data->x + req.width > disp_width)
1161 *x -= data->x + req.width - disp_width;
1162 if (data->y + req.height > disp_height)
1163 *y -= data->y + req.height - disp_height;
1164 }
1165
1166 static void
1167 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1168 {
1169 xg_menu_item_cb_data *cb_data = client_data;
1170
1171 if (xg_crazy_callback_abort) return;
1172 if (cb_data) menu_item_selection = cb_data->call_data;
1173 }
1174
1175 static void
1176 pop_down_menu (void *arg)
1177 {
1178 popup_activated_flag = 0;
1179 block_input ();
1180 gtk_widget_destroy (GTK_WIDGET (arg));
1181 unblock_input ();
1182 }
1183
1184 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1185 menu pops down.
1186 menu_item_selection will be set to the selection. */
1187 static void
1188 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1189 int x, int y, bool for_click)
1190 {
1191 int i;
1192 GtkWidget *menu;
1193 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1194 struct next_popup_x_y popup_x_y;
1195 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1196 bool use_pos_func = ! for_click;
1197
1198 #ifdef HAVE_GTK3
1199 /* Always use position function for Gtk3. Otherwise menus may become
1200 too small to show anything. */
1201 use_pos_func = true;
1202 #endif
1203
1204 eassert (FRAME_X_P (f));
1205
1206 xg_crazy_callback_abort = true;
1207 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1208 G_CALLBACK (popup_selection_callback),
1209 G_CALLBACK (popup_deactivate_callback),
1210 G_CALLBACK (menu_highlight_callback));
1211 xg_crazy_callback_abort = false;
1212
1213 if (use_pos_func)
1214 {
1215 /* Not invoked by a click. pop up at x/y. */
1216 pos_func = menu_position_func;
1217
1218 /* Adjust coordinates to be root-window-relative. */
1219 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1220 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1221
1222 popup_x_y.x = x;
1223 popup_x_y.y = y;
1224 popup_x_y.f = f;
1225
1226 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1227 }
1228
1229 if (for_click)
1230 {
1231 for (i = 0; i < 5; i++)
1232 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1233 break;
1234 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1235 if (i == 5) i = 0;
1236 }
1237
1238 /* Display the menu. */
1239 gtk_widget_show_all (menu);
1240
1241 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1242 FRAME_DISPLAY_INFO (f)->last_user_time);
1243
1244 record_unwind_protect_ptr (pop_down_menu, menu);
1245
1246 if (gtk_widget_get_mapped (menu))
1247 {
1248 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1249 two. show_help_echo uses this to detect popup menus. */
1250 popup_activated_flag = 1;
1251 /* Process events that apply to the menu. */
1252 popup_widget_loop (true, menu);
1253 }
1254
1255 unbind_to (specpdl_count, Qnil);
1256
1257 /* Must reset this manually because the button release event is not passed
1258 to Emacs event loop. */
1259 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1260 }
1261
1262 #else /* not USE_GTK */
1263
1264 /* We need a unique id for each widget handled by the Lucid Widget
1265 library.
1266
1267 For the main windows, and popup menus, we use this counter, which we
1268 increment each time after use. This starts from WIDGET_ID_TICK_START.
1269
1270 For menu bars, we use numbers starting at 0, counted in
1271 next_menubar_widget_id. */
1272 LWLIB_ID widget_id_tick;
1273
1274 static void
1275 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1276 {
1277 menu_item_selection = client_data;
1278 }
1279
1280 /* ID is the LWLIB ID of the dialog box. */
1281
1282 static void
1283 pop_down_menu (int id)
1284 {
1285 block_input ();
1286 lw_destroy_all_widgets ((LWLIB_ID) id);
1287 unblock_input ();
1288 popup_activated_flag = 0;
1289 }
1290
1291 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1292 menu pops down.
1293 menu_item_selection will be set to the selection. */
1294 static void
1295 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1296 int x, int y, bool for_click)
1297 {
1298 int i;
1299 Arg av[2];
1300 int ac = 0;
1301 XEvent dummy;
1302 XButtonPressedEvent *event = &(dummy.xbutton);
1303 LWLIB_ID menu_id;
1304 Widget menu;
1305
1306 eassert (FRAME_X_P (f));
1307
1308 #ifdef USE_LUCID
1309 apply_systemfont_to_menu (f, f->output_data.x->widget);
1310 #endif
1311
1312 menu_id = widget_id_tick++;
1313 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1314 f->output_data.x->widget, true, 0,
1315 popup_selection_callback,
1316 popup_deactivate_callback,
1317 menu_highlight_callback);
1318
1319 event->type = ButtonPress;
1320 event->serial = 0;
1321 event->send_event = false;
1322 event->display = FRAME_X_DISPLAY (f);
1323 event->time = CurrentTime;
1324 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1325 event->window = event->subwindow = event->root;
1326 event->x = x;
1327 event->y = y;
1328
1329 /* Adjust coordinates to be root-window-relative. */
1330 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1331 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1332
1333 event->x_root = x;
1334 event->y_root = y;
1335
1336 event->state = 0;
1337 event->button = 0;
1338 for (i = 0; i < 5; i++)
1339 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1340 event->button = i;
1341
1342 /* Don't allow any geometry request from the user. */
1343 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1344 XtSetValues (menu, av, ac);
1345
1346 /* Display the menu. */
1347 lw_popup_menu (menu, &dummy);
1348 popup_activated_flag = 1;
1349 x_activate_timeout_atimer ();
1350
1351 {
1352 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1353
1354 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1355
1356 /* Process events that apply to the menu. */
1357 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1358
1359 unbind_to (specpdl_count, Qnil);
1360 }
1361 }
1362
1363 #endif /* not USE_GTK */
1364
1365 static void
1366 cleanup_widget_value_tree (void *arg)
1367 {
1368 free_menubar_widget_value_tree (arg);
1369 }
1370
1371 Lisp_Object
1372 x_menu_show (struct frame *f, int x, int y, int menuflags,
1373 Lisp_Object title, const char **error_name)
1374 {
1375 int i;
1376 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1377 widget_value **submenu_stack
1378 = alloca (menu_items_used * sizeof *submenu_stack);
1379 Lisp_Object *subprefix_stack
1380 = alloca (menu_items_used * sizeof *subprefix_stack);
1381 int submenu_depth = 0;
1382
1383 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1384
1385 eassert (FRAME_X_P (f));
1386
1387 *error_name = NULL;
1388
1389 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1390 {
1391 *error_name = "Empty menu";
1392 return Qnil;
1393 }
1394
1395 block_input ();
1396
1397 /* Create a tree of widget_value objects
1398 representing the panes and their items. */
1399 wv = make_widget_value ("menu", NULL, true, Qnil);
1400 wv->button_type = BUTTON_TYPE_NONE;
1401 first_wv = wv;
1402 bool first_pane = true;
1403
1404 /* Loop over all panes and items, filling in the tree. */
1405 i = 0;
1406 while (i < menu_items_used)
1407 {
1408 if (EQ (AREF (menu_items, i), Qnil))
1409 {
1410 submenu_stack[submenu_depth++] = save_wv;
1411 save_wv = prev_wv;
1412 prev_wv = 0;
1413 first_pane = true;
1414 i++;
1415 }
1416 else if (EQ (AREF (menu_items, i), Qlambda))
1417 {
1418 prev_wv = save_wv;
1419 save_wv = submenu_stack[--submenu_depth];
1420 first_pane = false;
1421 i++;
1422 }
1423 else if (EQ (AREF (menu_items, i), Qt)
1424 && submenu_depth != 0)
1425 i += MENU_ITEMS_PANE_LENGTH;
1426 /* Ignore a nil in the item list.
1427 It's meaningful only for dialog boxes. */
1428 else if (EQ (AREF (menu_items, i), Qquote))
1429 i += 1;
1430 else if (EQ (AREF (menu_items, i), Qt))
1431 {
1432 /* Create a new pane. */
1433 Lisp_Object pane_name, prefix;
1434 const char *pane_string;
1435
1436 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1437 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1438
1439 #ifndef HAVE_MULTILINGUAL_MENU
1440 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1441 {
1442 pane_name = ENCODE_MENU_STRING (pane_name);
1443 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1444 }
1445 #endif
1446 pane_string = (NILP (pane_name)
1447 ? "" : SSDATA (pane_name));
1448 /* If there is just one top-level pane, put all its items directly
1449 under the top-level menu. */
1450 if (menu_items_n_panes == 1)
1451 pane_string = "";
1452
1453 /* If the pane has a meaningful name,
1454 make the pane a top-level menu item
1455 with its items as a submenu beneath it. */
1456 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1457 {
1458 wv = make_widget_value (pane_string, NULL, true, Qnil);
1459 if (save_wv)
1460 save_wv->next = wv;
1461 else
1462 first_wv->contents = wv;
1463 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1464 wv->name++;
1465 wv->button_type = BUTTON_TYPE_NONE;
1466 save_wv = wv;
1467 prev_wv = 0;
1468 }
1469 else if (first_pane)
1470 {
1471 save_wv = wv;
1472 prev_wv = 0;
1473 }
1474 first_pane = false;
1475 i += MENU_ITEMS_PANE_LENGTH;
1476 }
1477 else
1478 {
1479 /* Create a new item within current pane. */
1480 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1481 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1482 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1483 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1484 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1485 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1486 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1487 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1488
1489 #ifndef HAVE_MULTILINGUAL_MENU
1490 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1491 {
1492 item_name = ENCODE_MENU_STRING (item_name);
1493 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1494 }
1495
1496 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1497 {
1498 descrip = ENCODE_MENU_STRING (descrip);
1499 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1500 }
1501 #endif /* not HAVE_MULTILINGUAL_MENU */
1502
1503 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1504 STRINGP (help) ? help : Qnil);
1505 if (prev_wv)
1506 prev_wv->next = wv;
1507 else
1508 save_wv->contents = wv;
1509 if (!NILP (descrip))
1510 wv->key = SSDATA (descrip);
1511 /* If this item has a null value,
1512 make the call_data null so that it won't display a box
1513 when the mouse is on it. */
1514 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1515
1516 if (NILP (type))
1517 wv->button_type = BUTTON_TYPE_NONE;
1518 else if (EQ (type, QCtoggle))
1519 wv->button_type = BUTTON_TYPE_TOGGLE;
1520 else if (EQ (type, QCradio))
1521 wv->button_type = BUTTON_TYPE_RADIO;
1522 else
1523 emacs_abort ();
1524
1525 wv->selected = !NILP (selected);
1526
1527 prev_wv = wv;
1528
1529 i += MENU_ITEMS_ITEM_LENGTH;
1530 }
1531 }
1532
1533 /* Deal with the title, if it is non-nil. */
1534 if (!NILP (title))
1535 {
1536 widget_value *wv_title;
1537 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1538 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1539
1540 wv_sep2->next = first_wv->contents;
1541 wv_sep1->next = wv_sep2;
1542
1543 #ifndef HAVE_MULTILINGUAL_MENU
1544 if (STRING_MULTIBYTE (title))
1545 title = ENCODE_MENU_STRING (title);
1546 #endif
1547
1548 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1549 wv_title->button_type = BUTTON_TYPE_NONE;
1550 wv_title->next = wv_sep1;
1551 first_wv->contents = wv_title;
1552 }
1553
1554 /* No selection has been chosen yet. */
1555 menu_item_selection = 0;
1556
1557 /* Make sure to free the widget_value objects we used to specify the
1558 contents even with longjmp. */
1559 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1560
1561 /* Actually create and show the menu until popped down. */
1562 create_and_show_popup_menu (f, first_wv, x, y,
1563 menuflags & MENU_FOR_CLICK);
1564
1565 unbind_to (specpdl_count, Qnil);
1566
1567 /* Find the selected item, and its pane, to return
1568 the proper value. */
1569 if (menu_item_selection != 0)
1570 {
1571 Lisp_Object prefix, entry;
1572
1573 prefix = entry = Qnil;
1574 i = 0;
1575 while (i < menu_items_used)
1576 {
1577 if (EQ (AREF (menu_items, i), Qnil))
1578 {
1579 subprefix_stack[submenu_depth++] = prefix;
1580 prefix = entry;
1581 i++;
1582 }
1583 else if (EQ (AREF (menu_items, i), Qlambda))
1584 {
1585 prefix = subprefix_stack[--submenu_depth];
1586 i++;
1587 }
1588 else if (EQ (AREF (menu_items, i), Qt))
1589 {
1590 prefix
1591 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1592 i += MENU_ITEMS_PANE_LENGTH;
1593 }
1594 /* Ignore a nil in the item list.
1595 It's meaningful only for dialog boxes. */
1596 else if (EQ (AREF (menu_items, i), Qquote))
1597 i += 1;
1598 else
1599 {
1600 entry
1601 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1602 if (menu_item_selection == aref_addr (menu_items, i))
1603 {
1604 if (menuflags & MENU_KEYMAPS)
1605 {
1606 int j;
1607
1608 entry = list1 (entry);
1609 if (!NILP (prefix))
1610 entry = Fcons (prefix, entry);
1611 for (j = submenu_depth - 1; j >= 0; j--)
1612 if (!NILP (subprefix_stack[j]))
1613 entry = Fcons (subprefix_stack[j], entry);
1614 }
1615 unblock_input ();
1616 return entry;
1617 }
1618 i += MENU_ITEMS_ITEM_LENGTH;
1619 }
1620 }
1621 }
1622 else if (!(menuflags & MENU_FOR_CLICK))
1623 {
1624 unblock_input ();
1625 /* Make "Cancel" equivalent to C-g. */
1626 Fsignal (Qquit, Qnil);
1627 }
1628
1629 unblock_input ();
1630 return Qnil;
1631 }
1632 \f
1633 #ifdef USE_GTK
1634 static void
1635 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1636 {
1637 /* Treat the pointer as an integer. There's no problem
1638 as long as pointers have enough bits to hold small integers. */
1639 if ((intptr_t) client_data != -1)
1640 menu_item_selection = client_data;
1641
1642 popup_activated_flag = 0;
1643 }
1644
1645 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1646 dialog pops down.
1647 menu_item_selection will be set to the selection. */
1648 static void
1649 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1650 {
1651 GtkWidget *menu;
1652
1653 eassert (FRAME_X_P (f));
1654
1655 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1656 G_CALLBACK (dialog_selection_callback),
1657 G_CALLBACK (popup_deactivate_callback),
1658 0);
1659
1660 if (menu)
1661 {
1662 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1663 record_unwind_protect_ptr (pop_down_menu, menu);
1664
1665 /* Display the menu. */
1666 gtk_widget_show_all (menu);
1667
1668 /* Process events that apply to the menu. */
1669 popup_widget_loop (true, menu);
1670
1671 unbind_to (specpdl_count, Qnil);
1672 }
1673 }
1674
1675 #else /* not USE_GTK */
1676 static void
1677 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1678 {
1679 /* Treat the pointer as an integer. There's no problem
1680 as long as pointers have enough bits to hold small integers. */
1681 if ((intptr_t) client_data != -1)
1682 menu_item_selection = client_data;
1683
1684 block_input ();
1685 lw_destroy_all_widgets (id);
1686 unblock_input ();
1687 popup_activated_flag = 0;
1688 }
1689
1690
1691 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1692 dialog pops down.
1693 menu_item_selection will be set to the selection. */
1694 static void
1695 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1696 {
1697 LWLIB_ID dialog_id;
1698
1699 eassert (FRAME_X_P (f));
1700
1701 dialog_id = widget_id_tick++;
1702 #ifdef USE_LUCID
1703 apply_systemfont_to_dialog (f->output_data.x->widget);
1704 #endif
1705 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1706 f->output_data.x->widget, true, 0,
1707 dialog_selection_callback, 0, 0);
1708 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1709 /* Display the dialog box. */
1710 lw_pop_up_all_widgets (dialog_id);
1711 popup_activated_flag = 1;
1712 x_activate_timeout_atimer ();
1713
1714 /* Process events that apply to the dialog box.
1715 Also handle timers. */
1716 {
1717 ptrdiff_t count = SPECPDL_INDEX ();
1718
1719 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1720
1721 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1722
1723 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1724
1725 unbind_to (count, Qnil);
1726 }
1727 }
1728
1729 #endif /* not USE_GTK */
1730
1731 static const char * button_names [] = {
1732 "button1", "button2", "button3", "button4", "button5",
1733 "button6", "button7", "button8", "button9", "button10" };
1734
1735 static Lisp_Object
1736 x_dialog_show (struct frame *f, Lisp_Object title,
1737 Lisp_Object header, const char **error_name)
1738 {
1739 int i, nb_buttons=0;
1740 char dialog_name[6];
1741
1742 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1743
1744 /* Number of elements seen so far, before boundary. */
1745 int left_count = 0;
1746 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1747 bool boundary_seen = false;
1748
1749 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1750
1751 eassert (FRAME_X_P (f));
1752
1753 *error_name = NULL;
1754
1755 if (menu_items_n_panes > 1)
1756 {
1757 *error_name = "Multiple panes in dialog box";
1758 return Qnil;
1759 }
1760
1761 /* Create a tree of widget_value objects
1762 representing the text label and buttons. */
1763 {
1764 Lisp_Object pane_name;
1765 const char *pane_string;
1766 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1767 pane_string = (NILP (pane_name)
1768 ? "" : SSDATA (pane_name));
1769 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1770 first_wv = prev_wv;
1771
1772 /* Loop over all panes and items, filling in the tree. */
1773 i = MENU_ITEMS_PANE_LENGTH;
1774 while (i < menu_items_used)
1775 {
1776
1777 /* Create a new item within current pane. */
1778 Lisp_Object item_name, enable, descrip;
1779 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1780 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1781 descrip
1782 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1783
1784 if (NILP (item_name))
1785 {
1786 free_menubar_widget_value_tree (first_wv);
1787 *error_name = "Submenu in dialog items";
1788 return Qnil;
1789 }
1790 if (EQ (item_name, Qquote))
1791 {
1792 /* This is the boundary between left-side elts
1793 and right-side elts. Stop incrementing right_count. */
1794 boundary_seen = true;
1795 i++;
1796 continue;
1797 }
1798 if (nb_buttons >= 9)
1799 {
1800 free_menubar_widget_value_tree (first_wv);
1801 *error_name = "Too many dialog items";
1802 return Qnil;
1803 }
1804
1805 wv = make_widget_value (button_names[nb_buttons],
1806 SSDATA (item_name),
1807 !NILP (enable), Qnil);
1808 prev_wv->next = wv;
1809 if (!NILP (descrip))
1810 wv->key = SSDATA (descrip);
1811 wv->call_data = aref_addr (menu_items, i);
1812 prev_wv = wv;
1813
1814 if (! boundary_seen)
1815 left_count++;
1816
1817 nb_buttons++;
1818 i += MENU_ITEMS_ITEM_LENGTH;
1819 }
1820
1821 /* If the boundary was not specified,
1822 by default put half on the left and half on the right. */
1823 if (! boundary_seen)
1824 left_count = nb_buttons - nb_buttons / 2;
1825
1826 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1827
1828 /* Frame title: 'Q' = Question, 'I' = Information.
1829 Can also have 'E' = Error if, one day, we want
1830 a popup for errors. */
1831 if (NILP (header))
1832 dialog_name[0] = 'Q';
1833 else
1834 dialog_name[0] = 'I';
1835
1836 /* Dialog boxes use a really stupid name encoding
1837 which specifies how many buttons to use
1838 and how many buttons are on the right. */
1839 dialog_name[1] = '0' + nb_buttons;
1840 dialog_name[2] = 'B';
1841 dialog_name[3] = 'R';
1842 /* Number of buttons to put on the right. */
1843 dialog_name[4] = '0' + nb_buttons - left_count;
1844 dialog_name[5] = 0;
1845 wv->contents = first_wv;
1846 first_wv = wv;
1847 }
1848
1849 /* No selection has been chosen yet. */
1850 menu_item_selection = 0;
1851
1852 /* Make sure to free the widget_value objects we used to specify the
1853 contents even with longjmp. */
1854 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1855
1856 /* Actually create and show the dialog. */
1857 create_and_show_dialog (f, first_wv);
1858
1859 unbind_to (specpdl_count, Qnil);
1860
1861 /* Find the selected item, and its pane, to return
1862 the proper value. */
1863 if (menu_item_selection != 0)
1864 {
1865 i = 0;
1866 while (i < menu_items_used)
1867 {
1868 Lisp_Object entry;
1869
1870 if (EQ (AREF (menu_items, i), Qt))
1871 i += MENU_ITEMS_PANE_LENGTH;
1872 else if (EQ (AREF (menu_items, i), Qquote))
1873 {
1874 /* This is the boundary between left-side elts and
1875 right-side elts. */
1876 ++i;
1877 }
1878 else
1879 {
1880 entry
1881 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1882 if (menu_item_selection == aref_addr (menu_items, i))
1883 return entry;
1884 i += MENU_ITEMS_ITEM_LENGTH;
1885 }
1886 }
1887 }
1888 else
1889 /* Make "Cancel" equivalent to C-g. */
1890 Fsignal (Qquit, Qnil);
1891
1892 return Qnil;
1893 }
1894
1895 Lisp_Object
1896 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1897 {
1898 Lisp_Object title;
1899 const char *error_name;
1900 Lisp_Object selection;
1901 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1902
1903 check_window_system (f);
1904
1905 /* Decode the dialog items from what was specified. */
1906 title = Fcar (contents);
1907 CHECK_STRING (title);
1908 record_unwind_protect_void (unuse_menu_items);
1909
1910 if (NILP (Fcar (Fcdr (contents))))
1911 /* No buttons specified, add an "Ok" button so users can pop down
1912 the dialog. Also, the lesstif/motif version crashes if there are
1913 no buttons. */
1914 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1915
1916 list_of_panes (list1 (contents));
1917
1918 /* Display them in a dialog box. */
1919 block_input ();
1920 selection = x_dialog_show (f, title, header, &error_name);
1921 unblock_input ();
1922
1923 unbind_to (specpdl_count, Qnil);
1924 discard_menu_items ();
1925
1926 if (error_name) error ("%s", error_name);
1927 return selection;
1928 }
1929
1930 #else /* not USE_X_TOOLKIT && not USE_GTK */
1931
1932 /* The frame of the last activated non-toolkit menu bar.
1933 Used to generate menu help events. */
1934
1935 static struct frame *menu_help_frame;
1936
1937
1938 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1939
1940 PANE is the pane number, and ITEM is the menu item number in
1941 the menu (currently not used).
1942
1943 This cannot be done with generating a HELP_EVENT because
1944 XMenuActivate contains a loop that doesn't let Emacs process
1945 keyboard events. */
1946
1947 static void
1948 menu_help_callback (char const *help_string, int pane, int item)
1949 {
1950 Lisp_Object *first_item;
1951 Lisp_Object pane_name;
1952 Lisp_Object menu_object;
1953
1954 first_item = XVECTOR (menu_items)->contents;
1955 if (EQ (first_item[0], Qt))
1956 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1957 else if (EQ (first_item[0], Qquote))
1958 /* This shouldn't happen, see x_menu_show. */
1959 pane_name = empty_unibyte_string;
1960 else
1961 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1962
1963 /* (menu-item MENU-NAME PANE-NUMBER) */
1964 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1965 show_help_echo (help_string ? build_string (help_string) : Qnil,
1966 Qnil, menu_object, make_number (item));
1967 }
1968
1969 static void
1970 pop_down_menu (Lisp_Object arg)
1971 {
1972 struct frame *f = XSAVE_POINTER (arg, 0);
1973 XMenu *menu = XSAVE_POINTER (arg, 1);
1974
1975 block_input ();
1976 #ifndef MSDOS
1977 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
1978 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
1979 #endif
1980 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
1981
1982 #ifdef HAVE_X_WINDOWS
1983 /* Assume the mouse has moved out of the X window.
1984 If it has actually moved in, we will get an EnterNotify. */
1985 x_mouse_leave (FRAME_DISPLAY_INFO (f));
1986
1987 /* State that no mouse buttons are now held.
1988 (The oldXMenu code doesn't track this info for us.)
1989 That is not necessarily true, but the fiction leads to reasonable
1990 results, and it is a pain to ask which are actually held now. */
1991 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1992
1993 #endif /* HAVE_X_WINDOWS */
1994
1995 unblock_input ();
1996 }
1997
1998
1999 Lisp_Object
2000 x_menu_show (struct frame *f, int x, int y, int menuflags,
2001 Lisp_Object title, const char **error_name)
2002 {
2003 Window root;
2004 XMenu *menu;
2005 int pane, selidx, lpane, status;
2006 Lisp_Object entry = Qnil;
2007 Lisp_Object pane_prefix;
2008 char *datap;
2009 int ulx, uly, width, height;
2010 int dispwidth, dispheight;
2011 int i, j, lines, maxlines;
2012 int maxwidth;
2013 int dummy_int;
2014 unsigned int dummy_uint;
2015 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2016
2017 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2018
2019 *error_name = 0;
2020 if (menu_items_n_panes == 0)
2021 return Qnil;
2022
2023 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2024 {
2025 *error_name = "Empty menu";
2026 return Qnil;
2027 }
2028
2029 USE_SAFE_ALLOCA;
2030 block_input ();
2031
2032 /* Figure out which root window F is on. */
2033 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2034 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2035 &dummy_uint, &dummy_uint);
2036
2037 /* Make the menu on that window. */
2038 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2039 if (menu == NULL)
2040 {
2041 *error_name = "Can't create menu";
2042 goto return_entry;
2043 }
2044
2045 /* Don't GC while we prepare and show the menu,
2046 because we give the oldxmenu library pointers to the
2047 contents of strings. */
2048 inhibit_garbage_collection ();
2049
2050 #ifdef HAVE_X_WINDOWS
2051 /* Adjust coordinates to relative to the outer (window manager) window. */
2052 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2053 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2054 #endif /* HAVE_X_WINDOWS */
2055
2056 /* Adjust coordinates to be root-window-relative. */
2057 x += f->left_pos;
2058 y += f->top_pos;
2059
2060 /* Create all the necessary panes and their items. */
2061 maxwidth = maxlines = lines = i = 0;
2062 lpane = XM_FAILURE;
2063 while (i < menu_items_used)
2064 {
2065 if (EQ (AREF (menu_items, i), Qt))
2066 {
2067 /* Create a new pane. */
2068 Lisp_Object pane_name, prefix;
2069 const char *pane_string;
2070
2071 maxlines = max (maxlines, lines);
2072 lines = 0;
2073 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2074 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2075 pane_string = (NILP (pane_name)
2076 ? "" : SSDATA (pane_name));
2077 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2078 pane_string++;
2079
2080 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2081 if (lpane == XM_FAILURE)
2082 {
2083 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2084 *error_name = "Can't create pane";
2085 goto return_entry;
2086 }
2087 i += MENU_ITEMS_PANE_LENGTH;
2088
2089 /* Find the width of the widest item in this pane. */
2090 j = i;
2091 while (j < menu_items_used)
2092 {
2093 Lisp_Object item;
2094 item = AREF (menu_items, j);
2095 if (EQ (item, Qt))
2096 break;
2097 if (NILP (item))
2098 {
2099 j++;
2100 continue;
2101 }
2102 width = SBYTES (item);
2103 if (width > maxwidth)
2104 maxwidth = width;
2105
2106 j += MENU_ITEMS_ITEM_LENGTH;
2107 }
2108 }
2109 /* Ignore a nil in the item list.
2110 It's meaningful only for dialog boxes. */
2111 else if (EQ (AREF (menu_items, i), Qquote))
2112 i += 1;
2113 else
2114 {
2115 /* Create a new item within current pane. */
2116 Lisp_Object item_name, enable, descrip, help;
2117 char *item_data;
2118 char const *help_string;
2119
2120 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2121 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2122 descrip
2123 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2124 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2125 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2126
2127 if (!NILP (descrip))
2128 {
2129 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2130 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2131 for (j = SCHARS (item_name); j < maxwidth; j++)
2132 item_data[j] = ' ';
2133 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2134 item_data[j + SBYTES (descrip)] = 0;
2135 }
2136 else
2137 item_data = SSDATA (item_name);
2138
2139 if (lpane == XM_FAILURE
2140 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2141 menu, lpane, 0, item_data,
2142 !NILP (enable), help_string)
2143 == XM_FAILURE))
2144 {
2145 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2146 *error_name = "Can't add selection to menu";
2147 goto return_entry;
2148 }
2149 i += MENU_ITEMS_ITEM_LENGTH;
2150 lines++;
2151 }
2152 }
2153
2154 maxlines = max (maxlines, lines);
2155
2156 /* All set and ready to fly. */
2157 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2158 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2159 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2160 x = min (x, dispwidth);
2161 y = min (y, dispheight);
2162 x = max (x, 1);
2163 y = max (y, 1);
2164 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2165 &ulx, &uly, &width, &height);
2166 if (ulx+width > dispwidth)
2167 {
2168 x -= (ulx + width) - dispwidth;
2169 ulx = dispwidth - width;
2170 }
2171 if (uly+height > dispheight)
2172 {
2173 y -= (uly + height) - dispheight;
2174 uly = dispheight - height;
2175 }
2176 #ifndef HAVE_X_WINDOWS
2177 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2178 {
2179 /* Move the menu away of the echo area, to avoid overwriting the
2180 menu with help echo messages or vice versa. */
2181 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2182 {
2183 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2184 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2185 }
2186 else
2187 {
2188 y--;
2189 uly--;
2190 }
2191 }
2192 #endif
2193 if (ulx < 0) x -= ulx;
2194 if (uly < 0) y -= uly;
2195
2196 if (!(menuflags & MENU_FOR_CLICK))
2197 {
2198 /* If position was not given by a mouse click, adjust so upper left
2199 corner of the menu as a whole ends up at given coordinates. This
2200 is what x-popup-menu says in its documentation. */
2201 x += width/2;
2202 y += 1.5*height/(maxlines+2);
2203 }
2204
2205 XMenuSetAEQ (menu, true);
2206 XMenuSetFreeze (menu, true);
2207 pane = selidx = 0;
2208
2209 #ifndef MSDOS
2210 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2211 #endif
2212
2213 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2214
2215 /* Help display under X won't work because XMenuActivate contains
2216 a loop that doesn't give Emacs a chance to process it. */
2217 menu_help_frame = f;
2218 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2219 x, y, ButtonReleaseMask, &datap,
2220 menu_help_callback);
2221 pane_prefix = Qnil;
2222
2223 switch (status)
2224 {
2225 case XM_SUCCESS:
2226 #ifdef XDEBUG
2227 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2228 #endif
2229
2230 /* Find the item number SELIDX in pane number PANE. */
2231 i = 0;
2232 while (i < menu_items_used)
2233 {
2234 if (EQ (AREF (menu_items, i), Qt))
2235 {
2236 if (pane == 0)
2237 pane_prefix
2238 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2239 pane--;
2240 i += MENU_ITEMS_PANE_LENGTH;
2241 }
2242 else
2243 {
2244 if (pane == -1)
2245 {
2246 if (selidx == 0)
2247 {
2248 entry
2249 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2250 if (menuflags & MENU_KEYMAPS)
2251 {
2252 entry = list1 (entry);
2253 if (!NILP (pane_prefix))
2254 entry = Fcons (pane_prefix, entry);
2255 }
2256 break;
2257 }
2258 selidx--;
2259 }
2260 i += MENU_ITEMS_ITEM_LENGTH;
2261 }
2262 }
2263 break;
2264
2265 case XM_FAILURE:
2266 *error_name = "Can't activate menu";
2267 case XM_IA_SELECT:
2268 break;
2269 case XM_NO_SELECT:
2270 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2271 the menu was invoked with a mouse event as POSITION). */
2272 if (!(menuflags & MENU_FOR_CLICK))
2273 {
2274 unblock_input ();
2275 Fsignal (Qquit, Qnil);
2276 }
2277 break;
2278 }
2279
2280 return_entry:
2281 unblock_input ();
2282 SAFE_FREE ();
2283 return unbind_to (specpdl_count, entry);
2284 }
2285
2286 #endif /* not USE_X_TOOLKIT */
2287
2288 #ifndef MSDOS
2289 /* Detect if a dialog or menu has been posted. MSDOS has its own
2290 implementation on msdos.c. */
2291
2292 int ATTRIBUTE_CONST
2293 popup_activated (void)
2294 {
2295 return popup_activated_flag;
2296 }
2297 #endif /* not MSDOS */
2298
2299 /* The following is used by delayed window autoselection. */
2300
2301 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2302 doc: /* Return t if a menu or popup dialog is active. */)
2303 (void)
2304 {
2305 return (popup_activated ()) ? Qt : Qnil;
2306 }
2307 \f
2308 void
2309 syms_of_xmenu (void)
2310 {
2311 #ifdef USE_X_TOOLKIT
2312 enum { WIDGET_ID_TICK_START = 1 << 16 };
2313 widget_id_tick = WIDGET_ID_TICK_START;
2314 next_menubar_widget_id = 1;
2315 #endif
2316
2317 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2318 defsubr (&Smenu_or_popup_active_p);
2319
2320 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2321 defsubr (&Sx_menu_bar_open_internal);
2322 Ffset (intern_c_string ("accelerate-menu"),
2323 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2324 #endif
2325 }