Document reserved keys
[emacs.git] / src / xmenu.c
blobe7ef31ac5649ff8b3f2e8abeaaa151c56216b0a1
1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2018 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
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 (at
11 your option) any later version.
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.
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/>. */
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
33 #include <config.h>
35 #include <stdio.h>
37 #include "lisp.h"
38 #include "keyboard.h"
39 #include "frame.h"
40 #include "systime.h"
41 #include "termhooks.h"
42 #include "window.h"
43 #include "blockinput.h"
44 #include "buffer.h"
45 #include "coding.h"
46 #include "sysselect.h"
48 #ifdef MSDOS
49 #include "msdos.h"
50 #endif
52 #ifdef HAVE_X_WINDOWS
53 /* This may include sys/types.h, and that somehow loses
54 if this is not done before the other system files. */
55 #include "xterm.h"
56 #endif
58 /* Load sys/types.h if not already loaded.
59 In some systems loading it twice is suicidal. */
60 #ifndef makedev
61 #include <sys/types.h>
62 #endif
64 #ifdef HAVE_X_WINDOWS
65 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
66 code accepts the Emacs internal encoding. */
67 #undef HAVE_MULTILINGUAL_MENU
68 #ifdef USE_X_TOOLKIT
69 #include "widget.h"
70 #include <X11/Xlib.h>
71 #include <X11/IntrinsicP.h>
72 #include <X11/CoreP.h>
73 #include <X11/StringDefs.h>
74 #include <X11/Shell.h>
75 #ifdef USE_LUCID
76 #include "xsettings.h"
77 #include "../lwlib/xlwmenu.h"
78 #ifdef HAVE_XAW3D
79 #include <X11/Xaw3d/Paned.h>
80 #else /* !HAVE_XAW3D */
81 #include <X11/Xaw/Paned.h>
82 #endif /* HAVE_XAW3D */
83 #endif /* USE_LUCID */
84 #ifdef USE_MOTIF
85 #include "../lwlib/lwlib.h"
86 #endif
87 #else /* not USE_X_TOOLKIT */
88 #ifndef USE_GTK
89 #include "../oldXMenu/XMenu.h"
90 #endif
91 #endif /* not USE_X_TOOLKIT */
92 #endif /* HAVE_X_WINDOWS */
94 #ifdef USE_GTK
95 #include "gtkutil.h"
96 #ifdef HAVE_GTK3
97 #include "xgselect.h"
98 #endif
99 #endif
101 #include "menu.h"
104 /* Flag which when set indicates a dialog or menu has been posted by
105 Xt on behalf of one of the widget sets. */
106 static int popup_activated_flag;
109 #ifdef USE_X_TOOLKIT
111 static LWLIB_ID next_menubar_widget_id;
113 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
115 static struct frame *
116 menubar_id_to_frame (LWLIB_ID id)
118 Lisp_Object tail, frame;
119 struct frame *f;
121 FOR_EACH_FRAME (tail, frame)
123 f = XFRAME (frame);
124 if (!FRAME_WINDOW_P (f))
125 continue;
126 if (f->output_data.x->id == id)
127 return f;
129 return 0;
132 #endif
134 #ifndef MSDOS
136 #if defined USE_GTK || defined USE_MOTIF
138 /* Set menu_items_inuse so no other popup menu or dialog is created. */
140 void
141 x_menu_set_in_use (bool in_use)
143 Lisp_Object frames, frame;
145 menu_items_inuse = in_use ? Qt : Qnil;
146 popup_activated_flag = in_use;
147 #ifdef USE_X_TOOLKIT
148 if (popup_activated_flag)
149 x_activate_timeout_atimer ();
150 #endif
152 /* Don't let frames in `above' z-group obscure popups. */
153 FOR_EACH_FRAME (frames, frame)
155 struct frame *f = XFRAME (frame);
157 if (in_use && FRAME_Z_GROUP_ABOVE (f))
158 x_set_z_group (f, Qabove_suspended, Qabove);
159 else if (!in_use && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
160 x_set_z_group (f, Qabove, Qabove_suspended);
163 #endif
165 /* Wait for an X event to arrive or for a timer to expire. */
167 void
168 x_menu_wait_for_event (void *data)
170 /* Another way to do this is to register a timer callback, that can be
171 done in GTK and Xt. But we have to do it like this when using only X
172 anyway, and with callbacks we would have three variants for timer handling
173 instead of the small ifdefs below. */
175 while (
176 #ifdef USE_X_TOOLKIT
177 ! XtAppPending (Xt_app_con)
178 #elif defined USE_GTK
179 ! gtk_events_pending ()
180 #else
181 ! XPending (data)
182 #endif
185 struct timespec next_time = timer_check (), *ntp;
186 fd_set read_fds;
187 struct x_display_info *dpyinfo;
188 int n = 0;
190 FD_ZERO (&read_fds);
191 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
193 int fd = ConnectionNumber (dpyinfo->display);
194 FD_SET (fd, &read_fds);
195 if (fd > n) n = fd;
196 XFlush (dpyinfo->display);
199 if (! timespec_valid_p (next_time))
200 ntp = 0;
201 else
202 ntp = &next_time;
204 #if defined USE_GTK && defined HAVE_GTK3
205 /* Gtk3 have arrows on menus when they don't fit. When the
206 pointer is over an arrow, a timeout scrolls it a bit. Use
207 xg_select so that timeout gets triggered. */
208 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
209 #else
210 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
211 #endif
214 #endif /* ! MSDOS */
217 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
219 #ifdef USE_X_TOOLKIT
221 /* Loop in Xt until the menu pulldown or dialog popup has been
222 popped down (deactivated). This is used for x-popup-menu
223 and x-popup-dialog; it is not used for the menu bar.
225 NOTE: All calls to popup_get_selection should be protected
226 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
228 static void
229 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
230 LWLIB_ID id, bool do_timers)
232 XEvent event;
234 while (popup_activated_flag)
236 if (initial_event)
238 event = *initial_event;
239 initial_event = 0;
241 else
243 if (do_timers) x_menu_wait_for_event (0);
244 XtAppNextEvent (Xt_app_con, &event);
247 /* Make sure we don't consider buttons grabbed after menu goes.
248 And make sure to deactivate for any ButtonRelease,
249 even if XtDispatchEvent doesn't do that. */
250 if (event.type == ButtonRelease
251 && dpyinfo->display == event.xbutton.display)
253 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
254 #ifdef USE_MOTIF /* Pretending that the event came from a
255 Btn1Down seems the only way to convince Motif to
256 activate its callbacks; setting the XmNmenuPost
257 isn't working. --marcus@sysc.pdx.edu. */
258 event.xbutton.button = 1;
259 /* Motif only pops down menus when no Ctrl, Alt or Mod
260 key is pressed and the button is released. So reset key state
261 so Motif thinks this is the case. */
262 event.xbutton.state = 0;
263 #endif
265 /* Pop down on C-g and Escape. */
266 else if (event.type == KeyPress
267 && dpyinfo->display == event.xbutton.display)
269 KeySym keysym = XLookupKeysym (&event.xkey, 0);
271 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
272 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
273 popup_activated_flag = 0;
276 x_dispatch_event (&event, event.xany.display);
280 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
281 doc: /* Start key navigation of the menu bar in FRAME.
282 This initially opens the first menu bar item and you can then navigate with the
283 arrow keys, select a menu entry with the return key or cancel with the
284 escape key. If FRAME has no menu bar this function does nothing.
286 If FRAME is nil or not given, use the selected frame. */)
287 (Lisp_Object frame)
289 XEvent ev;
290 struct frame *f = decode_window_system_frame (frame);
291 Widget menubar;
292 block_input ();
294 if (FRAME_EXTERNAL_MENU_BAR (f))
295 set_frame_menubar (f, false, true);
297 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
298 if (menubar)
300 Window child;
301 bool error_p = false;
303 x_catch_errors (FRAME_X_DISPLAY (f));
304 memset (&ev, 0, sizeof ev);
305 ev.xbutton.display = FRAME_X_DISPLAY (f);
306 ev.xbutton.window = XtWindow (menubar);
307 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
308 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
309 ev.xbutton.button = Button1;
310 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
311 ev.xbutton.same_screen = True;
313 #ifdef USE_MOTIF
315 Arg al[2];
316 WidgetList list;
317 Cardinal nr;
318 XtSetArg (al[0], XtNchildren, &list);
319 XtSetArg (al[1], XtNnumChildren, &nr);
320 XtGetValues (menubar, al, 2);
321 ev.xbutton.window = XtWindow (list[0]);
323 #endif
325 XTranslateCoordinates (FRAME_X_DISPLAY (f),
326 /* From-window, to-window. */
327 ev.xbutton.window, ev.xbutton.root,
329 /* From-position, to-position. */
330 ev.xbutton.x, ev.xbutton.y,
331 &ev.xbutton.x_root, &ev.xbutton.y_root,
333 /* Child of win. */
334 &child);
335 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
336 x_uncatch_errors_after_check ();
338 if (! error_p)
340 ev.type = ButtonPress;
341 ev.xbutton.state = 0;
343 XtDispatchEvent (&ev);
344 ev.xbutton.type = ButtonRelease;
345 ev.xbutton.state = Button1Mask;
346 XtDispatchEvent (&ev);
350 unblock_input ();
352 return Qnil;
354 #endif /* USE_X_TOOLKIT */
357 #ifdef USE_GTK
358 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
359 doc: /* Start key navigation of the menu bar in FRAME.
360 This initially opens the first menu bar item and you can then navigate with the
361 arrow keys, select a menu entry with the return key or cancel with the
362 escape key. If FRAME has no menu bar this function does nothing.
364 If FRAME is nil or not given, use the selected frame. */)
365 (Lisp_Object frame)
367 GtkWidget *menubar;
368 struct frame *f;
370 block_input ();
371 f = decode_window_system_frame (frame);
373 if (FRAME_EXTERNAL_MENU_BAR (f))
374 set_frame_menubar (f, false, true);
376 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
377 if (menubar)
379 /* Activate the first menu. */
380 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
382 if (children)
384 g_signal_emit_by_name (children->data, "activate_item");
385 popup_activated_flag = 1;
386 g_list_free (children);
389 unblock_input ();
391 return Qnil;
394 /* Loop util popup_activated_flag is set to zero in a callback.
395 Used for popup menus and dialogs. */
397 static void
398 popup_widget_loop (bool do_timers, GtkWidget *widget)
400 ++popup_activated_flag;
402 /* Process events in the Gtk event loop until done. */
403 while (popup_activated_flag)
405 if (do_timers) x_menu_wait_for_event (0);
406 gtk_main_iteration ();
409 #endif
411 /* Activate the menu bar of frame F.
412 This is called from keyboard.c when it gets the
413 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
415 To activate the menu bar, we use the X button-press event
416 that was saved in saved_menu_event.
417 That makes the toolkit do its thing.
419 But first we recompute the menu bar contents (the whole tree).
421 The reason for saving the button event until here, instead of
422 passing it to the toolkit right away, is that we can safely
423 execute Lisp code. */
425 void
426 x_activate_menubar (struct frame *f)
428 eassert (FRAME_X_P (f));
430 if (!f->output_data.x->saved_menu_event->type)
431 return;
433 #ifdef USE_GTK
434 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
435 f->output_data.x->saved_menu_event->xany.window))
436 return;
437 #endif
439 set_frame_menubar (f, false, true);
440 block_input ();
441 popup_activated_flag = 1;
442 #ifdef USE_GTK
443 XPutBackEvent (f->output_data.x->display_info->display,
444 f->output_data.x->saved_menu_event);
445 #else
446 XtDispatchEvent (f->output_data.x->saved_menu_event);
447 #endif
448 unblock_input ();
450 /* Ignore this if we get it a second time. */
451 f->output_data.x->saved_menu_event->type = 0;
454 /* This callback is invoked when the user selects a menubar cascade
455 pushbutton, but before the pulldown menu is posted. */
457 #ifndef USE_GTK
458 static void
459 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
461 popup_activated_flag = 1;
462 x_activate_timeout_atimer ();
464 #endif
466 /* This callback is invoked when a dialog or menu is finished being
467 used and has been unposted. */
469 static void
470 popup_deactivate_callback (
471 #ifdef USE_GTK
472 GtkWidget *widget, gpointer client_data
473 #else
474 Widget widget, LWLIB_ID id, XtPointer client_data
475 #endif
478 popup_activated_flag = 0;
482 /* Function that finds the frame for WIDGET and shows the HELP text
483 for that widget.
484 F is the frame if known, or NULL if not known. */
485 static void
486 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
488 Lisp_Object frame;
490 if (f)
492 XSETFRAME (frame, f);
493 kbd_buffer_store_help_event (frame, help);
495 else
496 show_help_echo (help, Qnil, Qnil, Qnil);
499 /* Callback called when menu items are highlighted/unhighlighted
500 while moving the mouse over them. WIDGET is the menu bar or menu
501 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
502 the data structure for the menu item, or null in case of
503 unhighlighting. */
505 #ifdef USE_GTK
506 static void
507 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
509 xg_menu_item_cb_data *cb_data;
510 Lisp_Object help;
512 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
513 if (! cb_data) return;
515 help = call_data ? cb_data->help : Qnil;
517 /* If popup_activated_flag is greater than 1 we are in a popup menu.
518 Don't pass the frame to show_help_event for those.
519 Passing frame creates an Emacs event. As we are looping in
520 popup_widget_loop, it won't be handled. Passing NULL shows the tip
521 directly without using an Emacs event. This is what the Lucid code
522 does below. */
523 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
524 widget, help);
526 #else
527 static void
528 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
530 widget_value *wv = call_data;
531 Lisp_Object help = wv ? wv->help : Qnil;
533 /* Determine the frame for the help event. */
534 struct frame *f = menubar_id_to_frame (id);
536 show_help_event (f, widget, help);
538 #endif
540 #ifdef USE_GTK
541 /* Gtk calls callbacks just because we tell it what item should be
542 selected in a radio group. If this variable is set to a non-zero
543 value, we are creating menus and don't want callbacks right now.
545 static bool xg_crazy_callback_abort;
547 /* This callback is called from the menu bar pulldown menu
548 when the user makes a selection.
549 Figure out what the user chose
550 and put the appropriate events into the keyboard buffer. */
551 static void
552 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
554 xg_menu_item_cb_data *cb_data = client_data;
556 if (xg_crazy_callback_abort)
557 return;
559 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
560 return;
562 /* For a group of radio buttons, GTK calls the selection callback first
563 for the item that was active before the selection and then for the one that
564 is active after the selection. For C-h k this means we get the help on
565 the deselected item and then the selected item is executed. Prevent that
566 by ignoring the non-active item. */
567 if (GTK_IS_RADIO_MENU_ITEM (widget)
568 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
569 return;
571 /* When a menu is popped down, X generates a focus event (i.e. focus
572 goes back to the frame below the menu). Since GTK buffers events,
573 we force it out here before the menu selection event. Otherwise
574 sit-for will exit at once if the focus event follows the menu selection
575 event. */
577 block_input ();
578 while (gtk_events_pending ())
579 gtk_main_iteration ();
580 unblock_input ();
582 find_and_call_menu_selection (cb_data->cl_data->f,
583 cb_data->cl_data->menu_bar_items_used,
584 cb_data->cl_data->menu_bar_vector,
585 cb_data->call_data);
588 #else /* not USE_GTK */
590 /* This callback is called from the menu bar pulldown menu
591 when the user makes a selection.
592 Figure out what the user chose
593 and put the appropriate events into the keyboard buffer. */
594 static void
595 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
597 struct frame *f;
599 f = menubar_id_to_frame (id);
600 if (!f)
601 return;
602 find_and_call_menu_selection (f, f->menu_bar_items_used,
603 f->menu_bar_vector, client_data);
605 #endif /* not USE_GTK */
607 /* Recompute all the widgets of frame F, when the menu bar has been
608 changed. */
610 static void
611 update_frame_menubar (struct frame *f)
613 #ifdef USE_GTK
614 xg_update_frame_menubar (f);
615 #else
616 struct x_output *x;
618 eassert (FRAME_X_P (f));
620 x = f->output_data.x;
622 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
623 return;
625 block_input ();
627 /* Do the voodoo which means "I'm changing lots of things, don't try
628 to refigure sizes until I'm done." */
629 lw_refigure_widget (x->column_widget, False);
631 /* The order in which children are managed is the top to bottom
632 order in which they are displayed in the paned window. First,
633 remove the text-area widget. */
634 XtUnmanageChild (x->edit_widget);
636 /* Remove the menubar that is there now, and put up the menubar that
637 should be there. */
638 XtManageChild (x->menubar_widget);
639 XtMapWidget (x->menubar_widget);
640 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
642 /* Re-manage the text-area widget, and then thrash the sizes. */
643 XtManageChild (x->edit_widget);
644 lw_refigure_widget (x->column_widget, True);
646 /* Force the pane widget to resize itself. */
647 adjust_frame_size (f, -1, -1, 2, false, Qupdate_frame_menubar);
648 unblock_input ();
649 #endif /* USE_GTK */
652 #ifdef USE_LUCID
653 static void
654 apply_systemfont_to_dialog (Widget w)
656 const char *fn = xsettings_get_system_normal_font ();
657 if (fn)
659 XrmDatabase db = XtDatabase (XtDisplay (w));
660 if (db)
661 XrmPutStringResource (&db, "*dialog.font", fn);
665 static void
666 apply_systemfont_to_menu (struct frame *f, Widget w)
668 const char *fn = xsettings_get_system_normal_font ();
670 if (fn)
672 XrmDatabase db = XtDatabase (XtDisplay (w));
673 if (db)
675 XrmPutStringResource (&db, "*menubar*font", fn);
676 XrmPutStringResource (&db, "*popup*font", fn);
681 #endif
683 /* Set the contents of the menubar widgets of frame F.
684 The argument FIRST_TIME is currently ignored;
685 it is set the first time this is called, from initialize_frame_menubar. */
687 void
688 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
690 xt_or_gtk_widget menubar_widget, old_widget;
691 #ifdef USE_X_TOOLKIT
692 LWLIB_ID id;
693 #endif
694 Lisp_Object items;
695 widget_value *wv, *first_wv, *prev_wv = 0;
696 int i;
697 int *submenu_start, *submenu_end;
698 bool *submenu_top_level_items;
699 int *submenu_n_panes;
701 eassert (FRAME_X_P (f));
703 menubar_widget = old_widget = f->output_data.x->menubar_widget;
705 XSETFRAME (Vmenu_updating_frame, f);
707 #ifdef USE_X_TOOLKIT
708 if (f->output_data.x->id == 0)
709 f->output_data.x->id = next_menubar_widget_id++;
710 id = f->output_data.x->id;
711 #endif
713 if (! menubar_widget)
714 deep_p = true;
715 /* Make the first call for any given frame always go deep. */
716 else if (!f->output_data.x->saved_menu_event && !deep_p)
718 deep_p = true;
719 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
720 f->output_data.x->saved_menu_event->type = 0;
723 if (deep_p)
725 /* Make a widget-value tree representing the entire menu trees. */
727 struct buffer *prev = current_buffer;
728 Lisp_Object buffer;
729 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
730 int previous_menu_items_used = f->menu_bar_items_used;
731 Lisp_Object *previous_items
732 = alloca (previous_menu_items_used * sizeof *previous_items);
733 int subitems;
735 /* If we are making a new widget, its contents are empty,
736 do always reinitialize them. */
737 if (! menubar_widget)
738 previous_menu_items_used = 0;
740 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
741 specbind (Qinhibit_quit, Qt);
742 /* Don't let the debugger step into this code
743 because it is not reentrant. */
744 specbind (Qdebug_on_next_call, Qnil);
746 record_unwind_save_match_data ();
747 if (NILP (Voverriding_local_map_menu_flag))
749 specbind (Qoverriding_terminal_local_map, Qnil);
750 specbind (Qoverriding_local_map, Qnil);
753 set_buffer_internal_1 (XBUFFER (buffer));
755 /* Run the Lucid hook. */
756 safe_run_hooks (Qactivate_menubar_hook);
758 /* If it has changed current-menubar from previous value,
759 really recompute the menubar from the value. */
760 if (! NILP (Vlucid_menu_bar_dirty_flag))
761 call0 (Qrecompute_lucid_menubar);
762 safe_run_hooks (Qmenu_bar_update_hook);
763 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
765 items = FRAME_MENU_BAR_ITEMS (f);
767 /* Save the frame's previous menu bar contents data. */
768 if (previous_menu_items_used)
769 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
770 previous_menu_items_used * word_size);
772 /* Fill in menu_items with the current menu bar contents.
773 This can evaluate Lisp code. */
774 save_menu_items ();
776 menu_items = f->menu_bar_vector;
777 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
778 subitems = ASIZE (items) / 4;
779 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
780 submenu_end = alloca (subitems * sizeof *submenu_end);
781 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
782 submenu_top_level_items = alloca (subitems
783 * sizeof *submenu_top_level_items);
784 init_menu_items ();
785 for (i = 0; i < subitems; i++)
787 Lisp_Object key, string, maps;
789 key = AREF (items, 4 * i);
790 string = AREF (items, 4 * i + 1);
791 maps = AREF (items, 4 * i + 2);
792 if (NILP (string))
793 break;
795 submenu_start[i] = menu_items_used;
797 menu_items_n_panes = 0;
798 submenu_top_level_items[i]
799 = parse_single_submenu (key, string, maps);
800 submenu_n_panes[i] = menu_items_n_panes;
802 submenu_end[i] = menu_items_used;
805 submenu_start[i] = -1;
806 finish_menu_items ();
808 /* Convert menu_items into widget_value trees
809 to display the menu. This cannot evaluate Lisp code. */
811 wv = make_widget_value ("menubar", NULL, true, Qnil);
812 wv->button_type = BUTTON_TYPE_NONE;
813 first_wv = wv;
815 for (i = 0; submenu_start[i] >= 0; i++)
817 menu_items_n_panes = submenu_n_panes[i];
818 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
819 submenu_top_level_items[i]);
820 if (prev_wv)
821 prev_wv->next = wv;
822 else
823 first_wv->contents = wv;
824 /* Don't set wv->name here; GC during the loop might relocate it. */
825 wv->enabled = true;
826 wv->button_type = BUTTON_TYPE_NONE;
827 prev_wv = wv;
830 set_buffer_internal_1 (prev);
832 /* If there has been no change in the Lisp-level contents
833 of the menu bar, skip redisplaying it. Just exit. */
835 /* Compare the new menu items with the ones computed last time. */
836 for (i = 0; i < previous_menu_items_used; i++)
837 if (menu_items_used == i
838 || (!EQ (previous_items[i], AREF (menu_items, i))))
839 break;
840 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
842 /* The menu items have not changed. Don't bother updating
843 the menus in any form, since it would be a no-op. */
844 free_menubar_widget_value_tree (first_wv);
845 discard_menu_items ();
846 unbind_to (specpdl_count, Qnil);
847 return;
850 /* The menu items are different, so store them in the frame. */
851 fset_menu_bar_vector (f, menu_items);
852 f->menu_bar_items_used = menu_items_used;
854 /* This undoes save_menu_items. */
855 unbind_to (specpdl_count, Qnil);
857 /* Now GC cannot happen during the lifetime of the widget_value,
858 so it's safe to store data from a Lisp_String. */
859 wv = first_wv->contents;
860 for (i = 0; i < ASIZE (items); i += 4)
862 Lisp_Object string;
863 string = AREF (items, i + 1);
864 if (NILP (string))
865 break;
866 wv->name = SSDATA (string);
867 update_submenu_strings (wv->contents);
868 wv = wv->next;
872 else
874 /* Make a widget-value tree containing
875 just the top level menu bar strings. */
877 wv = make_widget_value ("menubar", NULL, true, Qnil);
878 wv->button_type = BUTTON_TYPE_NONE;
879 first_wv = wv;
881 items = FRAME_MENU_BAR_ITEMS (f);
882 for (i = 0; i < ASIZE (items); i += 4)
884 Lisp_Object string;
886 string = AREF (items, i + 1);
887 if (NILP (string))
888 break;
890 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
891 wv->button_type = BUTTON_TYPE_NONE;
892 /* This prevents lwlib from assuming this
893 menu item is really supposed to be empty. */
894 /* The intptr_t cast avoids a warning.
895 This value just has to be different from small integers. */
896 wv->call_data = (void *) (intptr_t) (-1);
898 if (prev_wv)
899 prev_wv->next = wv;
900 else
901 first_wv->contents = wv;
902 prev_wv = wv;
905 /* Forget what we thought we knew about what is in the
906 detailed contents of the menu bar menus.
907 Changing the top level always destroys the contents. */
908 f->menu_bar_items_used = 0;
911 /* Create or update the menu bar widget. */
913 block_input ();
915 #ifdef USE_GTK
916 xg_crazy_callback_abort = true;
917 if (menubar_widget)
919 /* The fourth arg is DEEP_P, which says to consider the entire
920 menu trees we supply, rather than just the menu bar item names. */
921 xg_modify_menubar_widgets (menubar_widget,
923 first_wv,
924 deep_p,
925 G_CALLBACK (menubar_selection_callback),
926 G_CALLBACK (popup_deactivate_callback),
927 G_CALLBACK (menu_highlight_callback));
929 else
931 menubar_widget
932 = xg_create_widget ("menubar", "menubar", f, first_wv,
933 G_CALLBACK (menubar_selection_callback),
934 G_CALLBACK (popup_deactivate_callback),
935 G_CALLBACK (menu_highlight_callback));
937 f->output_data.x->menubar_widget = menubar_widget;
941 #else /* not USE_GTK */
942 if (menubar_widget)
944 /* Disable resizing (done for Motif!) */
945 lw_allow_resizing (f->output_data.x->widget, False);
947 /* The third arg is DEEP_P, which says to consider the entire
948 menu trees we supply, rather than just the menu bar item names. */
949 lw_modify_all_widgets (id, first_wv, deep_p);
951 /* Re-enable the edit widget to resize. */
952 lw_allow_resizing (f->output_data.x->widget, True);
954 else
956 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
957 XtTranslations override = XtParseTranslationTable (menuOverride);
959 #ifdef USE_LUCID
960 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
961 #endif
962 menubar_widget = lw_create_widget ("menubar", "menubar", id,
963 first_wv,
964 f->output_data.x->column_widget,
965 false,
966 popup_activate_callback,
967 menubar_selection_callback,
968 popup_deactivate_callback,
969 menu_highlight_callback);
970 f->output_data.x->menubar_widget = menubar_widget;
972 /* Make menu pop down on C-g. */
973 XtOverrideTranslations (menubar_widget, override);
977 int menubar_size;
978 if (f->output_data.x->menubar_widget)
979 XtRealizeWidget (f->output_data.x->menubar_widget);
981 menubar_size
982 = (f->output_data.x->menubar_widget
983 ? (f->output_data.x->menubar_widget->core.height
984 #ifndef USE_LUCID
985 /* Damn me... With Lucid I get a core.border_width of 1
986 only the first time this is called and an ibw of 1 every
987 time this is called. So the first time this is called I
988 was off by one. Fix that here by never adding
989 core.border_width for Lucid. */
990 + f->output_data.x->menubar_widget->core.border_width
991 #endif /* USE_LUCID */
993 : 0);
995 #ifdef USE_LUCID
996 /* Experimentally, we now get the right results
997 for -geometry -0-0 without this. 24 Aug 96, rms.
998 Maybe so, but the menu bar size is missing the pixels so the
999 WM size hints are off by these pixels. Jan D, oct 2009. */
1000 if (FRAME_EXTERNAL_MENU_BAR (f))
1002 Dimension ibw = 0;
1004 XtVaGetValues (f->output_data.x->column_widget,
1005 XtNinternalBorderWidth, &ibw, NULL);
1006 menubar_size += ibw;
1008 #endif /* USE_LUCID */
1010 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1012 #endif /* not USE_GTK */
1014 free_menubar_widget_value_tree (first_wv);
1015 update_frame_menubar (f);
1017 #ifdef USE_GTK
1018 xg_crazy_callback_abort = false;
1019 #endif
1021 unblock_input ();
1024 /* Called from Fx_create_frame to create the initial menubar of a frame
1025 before it is mapped, so that the window is mapped with the menubar already
1026 there instead of us tacking it on later and thrashing the window after it
1027 is visible. */
1029 void
1030 initialize_frame_menubar (struct frame *f)
1032 /* This function is called before the first chance to redisplay
1033 the frame. It has to be, so the frame will have the right size. */
1034 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1035 set_frame_menubar (f, true, true);
1039 /* Get rid of the menu bar of frame F, and free its storage.
1040 This is used when deleting a frame, and when turning off the menu bar.
1041 For GTK this function is in gtkutil.c. */
1043 #ifndef USE_GTK
1044 void
1045 free_frame_menubar (struct frame *f)
1047 Widget menubar_widget;
1048 #ifdef USE_MOTIF
1049 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1050 If we want to preserve the old height, calculate it now so we can
1051 restore it below. */
1052 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1053 #endif
1055 eassert (FRAME_X_P (f));
1057 menubar_widget = f->output_data.x->menubar_widget;
1059 FRAME_MENUBAR_HEIGHT (f) = 0;
1061 if (menubar_widget)
1063 #ifdef USE_MOTIF
1064 /* Removing the menu bar magically changes the shell widget's x
1065 and y position of (0, 0) which, when the menu bar is turned
1066 on again, leads to pull-down menus appearing in strange
1067 positions near the upper-left corner of the display. This
1068 happens only with some window managers like twm and ctwm,
1069 but not with other like Motif's mwm or kwm, because the
1070 latter generate ConfigureNotify events when the menu bar
1071 is switched off, which fixes the shell position. */
1072 Position x0, y0, x1, y1;
1073 #endif
1075 block_input ();
1077 #ifdef USE_MOTIF
1078 if (f->output_data.x->widget)
1079 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1080 #endif
1082 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1083 f->output_data.x->menubar_widget = NULL;
1085 if (f->output_data.x->widget)
1087 #ifdef USE_MOTIF
1088 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1089 if (x1 == 0 && y1 == 0)
1090 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1091 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1092 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_1);
1093 else
1094 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1095 #else
1096 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1097 #endif /* USE_MOTIF */
1099 else
1101 #ifdef USE_MOTIF
1102 if (WINDOWP (FRAME_ROOT_WINDOW (f))
1103 && frame_inhibit_resize (f, false, Qmenu_bar_lines))
1104 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_2);
1105 #endif
1108 unblock_input ();
1111 #endif /* not USE_GTK */
1113 #endif /* USE_X_TOOLKIT || USE_GTK */
1115 /* x_menu_show actually displays a menu using the panes and items in menu_items
1116 and returns the value selected from it.
1117 There are two versions of x_menu_show, one for Xt and one for Xlib.
1118 Both assume input is blocked by the caller. */
1120 /* F is the frame the menu is for.
1121 X and Y are the frame-relative specified position,
1122 relative to the inside upper left corner of the frame F.
1123 Bitfield MENUFLAGS bits are:
1124 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1125 MENU_KEYMAPS is set if this menu was specified with keymaps;
1126 in that case, we return a list containing the chosen item's value
1127 and perhaps also the pane's prefix.
1128 TITLE is the specified menu title.
1129 ERROR is a place to store an error message string in case of failure.
1130 (We return nil on failure, but the value doesn't actually matter.) */
1132 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1134 /* The item selected in the popup menu. */
1135 static Lisp_Object *volatile menu_item_selection;
1137 #ifdef USE_GTK
1139 /* Used when position a popup menu. See menu_position_func and
1140 create_and_show_popup_menu below. */
1141 struct next_popup_x_y
1143 struct frame *f;
1144 int x;
1145 int y;
1148 /* The menu position function to use if we are not putting a popup
1149 menu where the pointer is.
1150 MENU is the menu to pop up.
1151 X and Y shall on exit contain x/y where the menu shall pop up.
1152 PUSH_IN is not documented in the GTK manual.
1153 USER_DATA is any data passed in when calling gtk_menu_popup.
1154 Here it points to a struct next_popup_x_y where the coordinates
1155 to store in *X and *Y are as well as the frame for the popup.
1157 Here only X and Y are used. */
1158 static void
1159 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1161 struct next_popup_x_y *data = user_data;
1162 GtkRequisition req;
1163 int max_x = -1;
1164 int max_y = -1;
1166 Lisp_Object frame, workarea;
1168 XSETFRAME (frame, data->f);
1170 /* TODO: Get the monitor workarea directly without calculating other
1171 items in x-display-monitor-attributes-list. */
1172 workarea = call3 (Qframe_monitor_workarea,
1173 Qnil,
1174 make_number (data->x),
1175 make_number (data->y));
1177 if (CONSP (workarea))
1179 int min_x, min_y;
1181 min_x = XINT (XCAR (workarea));
1182 min_y = XINT (Fnth (make_number (1), workarea));
1183 max_x = min_x + XINT (Fnth (make_number (2), workarea));
1184 max_y = min_y + XINT (Fnth (make_number (3), workarea));
1187 if (max_x < 0 || max_y < 0)
1189 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1191 max_x = x_display_pixel_width (dpyinfo);
1192 max_y = x_display_pixel_height (dpyinfo);
1195 *x = data->x;
1196 *y = data->y;
1198 /* Check if there is room for the menu. If not, adjust x/y so that
1199 the menu is fully visible. */
1200 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1201 if (data->x + req.width > max_x)
1202 *x -= data->x + req.width - max_x;
1203 if (data->y + req.height > max_y)
1204 *y -= data->y + req.height - max_y;
1207 static void
1208 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1210 xg_menu_item_cb_data *cb_data = client_data;
1212 if (xg_crazy_callback_abort) return;
1213 if (cb_data) menu_item_selection = cb_data->call_data;
1216 static void
1217 pop_down_menu (void *arg)
1219 popup_activated_flag = 0;
1220 block_input ();
1221 gtk_widget_destroy (GTK_WIDGET (arg));
1222 unblock_input ();
1225 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1226 menu pops down.
1227 menu_item_selection will be set to the selection. */
1228 static void
1229 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1230 int x, int y, bool for_click)
1232 int i;
1233 GtkWidget *menu;
1234 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1235 struct next_popup_x_y popup_x_y;
1236 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1237 bool use_pos_func = ! for_click;
1239 #ifdef HAVE_GTK3
1240 /* Always use position function for Gtk3. Otherwise menus may become
1241 too small to show anything. */
1242 use_pos_func = true;
1243 #endif
1245 eassert (FRAME_X_P (f));
1247 xg_crazy_callback_abort = true;
1248 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1249 G_CALLBACK (popup_selection_callback),
1250 G_CALLBACK (popup_deactivate_callback),
1251 G_CALLBACK (menu_highlight_callback));
1252 xg_crazy_callback_abort = false;
1254 if (use_pos_func)
1256 Window dummy_window;
1258 /* Not invoked by a click. pop up at x/y. */
1259 pos_func = menu_position_func;
1261 /* Adjust coordinates to be root-window-relative. */
1262 block_input ();
1263 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1265 /* From-window, to-window. */
1266 FRAME_X_WINDOW (f),
1267 FRAME_DISPLAY_INFO (f)->root_window,
1269 /* From-position, to-position. */
1270 x, y, &x, &y,
1272 /* Child of win. */
1273 &dummy_window);
1274 #ifdef HAVE_GTK3
1275 /* Use window scaling factor to adjust position for hidpi screens. */
1276 x /= xg_get_scale (f);
1277 y /= xg_get_scale (f);
1278 #endif
1279 unblock_input ();
1280 popup_x_y.x = x;
1281 popup_x_y.y = y;
1282 popup_x_y.f = f;
1284 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1287 if (for_click)
1289 for (i = 0; i < 5; i++)
1290 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1291 break;
1292 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1293 if (i == 5) i = 0;
1296 /* Display the menu. */
1297 gtk_widget_show_all (menu);
1299 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1300 FRAME_DISPLAY_INFO (f)->last_user_time);
1302 record_unwind_protect_ptr (pop_down_menu, menu);
1304 if (gtk_widget_get_mapped (menu))
1306 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1307 two. show_help_echo uses this to detect popup menus. */
1308 popup_activated_flag = 1;
1309 /* Process events that apply to the menu. */
1310 popup_widget_loop (true, menu);
1313 unbind_to (specpdl_count, Qnil);
1315 /* Must reset this manually because the button release event is not passed
1316 to Emacs event loop. */
1317 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1320 #else /* not USE_GTK */
1322 /* We need a unique id for each widget handled by the Lucid Widget
1323 library.
1325 For the main windows, and popup menus, we use this counter, which we
1326 increment each time after use. This starts from WIDGET_ID_TICK_START.
1328 For menu bars, we use numbers starting at 0, counted in
1329 next_menubar_widget_id. */
1330 LWLIB_ID widget_id_tick;
1332 static void
1333 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1335 menu_item_selection = client_data;
1338 /* ID is the LWLIB ID of the dialog box. */
1340 static void
1341 pop_down_menu (int id)
1343 block_input ();
1344 lw_destroy_all_widgets ((LWLIB_ID) id);
1345 unblock_input ();
1346 popup_activated_flag = 0;
1349 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1350 menu pops down.
1351 menu_item_selection will be set to the selection. */
1352 static void
1353 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1354 int x, int y, bool for_click)
1356 int i;
1357 Arg av[2];
1358 int ac = 0;
1359 XEvent dummy;
1360 XButtonPressedEvent *event = &(dummy.xbutton);
1361 LWLIB_ID menu_id;
1362 Widget menu;
1363 Window dummy_window;
1365 eassert (FRAME_X_P (f));
1367 #ifdef USE_LUCID
1368 apply_systemfont_to_menu (f, f->output_data.x->widget);
1369 #endif
1371 menu_id = widget_id_tick++;
1372 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1373 f->output_data.x->widget, true, 0,
1374 popup_selection_callback,
1375 popup_deactivate_callback,
1376 menu_highlight_callback);
1378 event->type = ButtonPress;
1379 event->serial = 0;
1380 event->send_event = false;
1381 event->display = FRAME_X_DISPLAY (f);
1382 event->time = CurrentTime;
1383 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1384 event->window = event->subwindow = event->root;
1385 event->x = x;
1386 event->y = y;
1388 /* Adjust coordinates to be root-window-relative. */
1389 block_input ();
1390 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1391 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1393 /* From-window, to-window. */
1394 FRAME_X_WINDOW (f),
1395 FRAME_DISPLAY_INFO (f)->root_window,
1397 /* From-position, to-position. */
1398 x, y, &x, &y,
1400 /* Child of win. */
1401 &dummy_window);
1402 unblock_input ();
1404 event->x_root = x;
1405 event->y_root = y;
1407 event->state = 0;
1408 event->button = 0;
1409 for (i = 0; i < 5; i++)
1410 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1411 event->button = i;
1413 /* Don't allow any geometry request from the user. */
1414 XtSetArg (av[ac], (char *) XtNgeometry, 0); ac++;
1415 XtSetValues (menu, av, ac);
1417 /* Display the menu. */
1418 lw_popup_menu (menu, &dummy);
1419 popup_activated_flag = 1;
1420 x_activate_timeout_atimer ();
1423 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1425 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1427 /* Process events that apply to the menu. */
1428 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1430 unbind_to (specpdl_count, Qnil);
1434 #endif /* not USE_GTK */
1436 static void
1437 cleanup_widget_value_tree (void *arg)
1439 free_menubar_widget_value_tree (arg);
1442 Lisp_Object
1443 x_menu_show (struct frame *f, int x, int y, int menuflags,
1444 Lisp_Object title, const char **error_name)
1446 int i;
1447 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1448 widget_value **submenu_stack
1449 = alloca (menu_items_used * sizeof *submenu_stack);
1450 Lisp_Object *subprefix_stack
1451 = alloca (menu_items_used * sizeof *subprefix_stack);
1452 int submenu_depth = 0;
1454 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1456 eassert (FRAME_X_P (f));
1458 *error_name = NULL;
1460 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1462 *error_name = "Empty menu";
1463 return Qnil;
1466 block_input ();
1468 /* Create a tree of widget_value objects
1469 representing the panes and their items. */
1470 wv = make_widget_value ("menu", NULL, true, Qnil);
1471 wv->button_type = BUTTON_TYPE_NONE;
1472 first_wv = wv;
1473 bool first_pane = true;
1475 /* Loop over all panes and items, filling in the tree. */
1476 i = 0;
1477 while (i < menu_items_used)
1479 if (EQ (AREF (menu_items, i), Qnil))
1481 submenu_stack[submenu_depth++] = save_wv;
1482 save_wv = prev_wv;
1483 prev_wv = 0;
1484 first_pane = true;
1485 i++;
1487 else if (EQ (AREF (menu_items, i), Qlambda))
1489 prev_wv = save_wv;
1490 save_wv = submenu_stack[--submenu_depth];
1491 first_pane = false;
1492 i++;
1494 else if (EQ (AREF (menu_items, i), Qt)
1495 && submenu_depth != 0)
1496 i += MENU_ITEMS_PANE_LENGTH;
1497 /* Ignore a nil in the item list.
1498 It's meaningful only for dialog boxes. */
1499 else if (EQ (AREF (menu_items, i), Qquote))
1500 i += 1;
1501 else if (EQ (AREF (menu_items, i), Qt))
1503 /* Create a new pane. */
1504 Lisp_Object pane_name, prefix;
1505 const char *pane_string;
1507 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1508 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1510 #ifndef HAVE_MULTILINGUAL_MENU
1511 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1513 pane_name = ENCODE_MENU_STRING (pane_name);
1514 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1516 #endif
1517 pane_string = (NILP (pane_name)
1518 ? "" : SSDATA (pane_name));
1519 /* If there is just one top-level pane, put all its items directly
1520 under the top-level menu. */
1521 if (menu_items_n_panes == 1)
1522 pane_string = "";
1524 /* If the pane has a meaningful name,
1525 make the pane a top-level menu item
1526 with its items as a submenu beneath it. */
1527 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1529 wv = make_widget_value (pane_string, NULL, true, Qnil);
1530 if (save_wv)
1531 save_wv->next = wv;
1532 else
1533 first_wv->contents = wv;
1534 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1535 wv->name++;
1536 wv->button_type = BUTTON_TYPE_NONE;
1537 save_wv = wv;
1538 prev_wv = 0;
1540 else if (first_pane)
1542 save_wv = wv;
1543 prev_wv = 0;
1545 first_pane = false;
1546 i += MENU_ITEMS_PANE_LENGTH;
1548 else
1550 /* Create a new item within current pane. */
1551 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1552 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1553 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1554 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1555 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1556 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1557 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1558 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1560 #ifndef HAVE_MULTILINGUAL_MENU
1561 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1563 item_name = ENCODE_MENU_STRING (item_name);
1564 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1567 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1569 descrip = ENCODE_MENU_STRING (descrip);
1570 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1572 #endif /* not HAVE_MULTILINGUAL_MENU */
1574 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1575 STRINGP (help) ? help : Qnil);
1576 if (prev_wv)
1577 prev_wv->next = wv;
1578 else
1579 save_wv->contents = wv;
1580 if (!NILP (descrip))
1581 wv->key = SSDATA (descrip);
1582 /* If this item has a null value,
1583 make the call_data null so that it won't display a box
1584 when the mouse is on it. */
1585 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1587 if (NILP (type))
1588 wv->button_type = BUTTON_TYPE_NONE;
1589 else if (EQ (type, QCtoggle))
1590 wv->button_type = BUTTON_TYPE_TOGGLE;
1591 else if (EQ (type, QCradio))
1592 wv->button_type = BUTTON_TYPE_RADIO;
1593 else
1594 emacs_abort ();
1596 wv->selected = !NILP (selected);
1598 prev_wv = wv;
1600 i += MENU_ITEMS_ITEM_LENGTH;
1604 /* Deal with the title, if it is non-nil. */
1605 if (!NILP (title))
1607 widget_value *wv_title;
1608 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1609 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1611 wv_sep2->next = first_wv->contents;
1612 wv_sep1->next = wv_sep2;
1614 #ifndef HAVE_MULTILINGUAL_MENU
1615 if (STRING_MULTIBYTE (title))
1616 title = ENCODE_MENU_STRING (title);
1617 #endif
1619 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1620 wv_title->button_type = BUTTON_TYPE_NONE;
1621 wv_title->next = wv_sep1;
1622 first_wv->contents = wv_title;
1625 /* No selection has been chosen yet. */
1626 menu_item_selection = 0;
1628 /* Make sure to free the widget_value objects we used to specify the
1629 contents even with longjmp. */
1630 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1632 /* Actually create and show the menu until popped down. */
1633 create_and_show_popup_menu (f, first_wv, x, y,
1634 menuflags & MENU_FOR_CLICK);
1636 unbind_to (specpdl_count, Qnil);
1638 /* Find the selected item, and its pane, to return
1639 the proper value. */
1640 if (menu_item_selection != 0)
1642 Lisp_Object prefix, entry;
1644 prefix = entry = Qnil;
1645 i = 0;
1646 while (i < menu_items_used)
1648 if (EQ (AREF (menu_items, i), Qnil))
1650 subprefix_stack[submenu_depth++] = prefix;
1651 prefix = entry;
1652 i++;
1654 else if (EQ (AREF (menu_items, i), Qlambda))
1656 prefix = subprefix_stack[--submenu_depth];
1657 i++;
1659 else if (EQ (AREF (menu_items, i), Qt))
1661 prefix
1662 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1663 i += MENU_ITEMS_PANE_LENGTH;
1665 /* Ignore a nil in the item list.
1666 It's meaningful only for dialog boxes. */
1667 else if (EQ (AREF (menu_items, i), Qquote))
1668 i += 1;
1669 else
1671 entry
1672 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1673 if (menu_item_selection == aref_addr (menu_items, i))
1675 if (menuflags & MENU_KEYMAPS)
1677 int j;
1679 entry = list1 (entry);
1680 if (!NILP (prefix))
1681 entry = Fcons (prefix, entry);
1682 for (j = submenu_depth - 1; j >= 0; j--)
1683 if (!NILP (subprefix_stack[j]))
1684 entry = Fcons (subprefix_stack[j], entry);
1686 unblock_input ();
1687 return entry;
1689 i += MENU_ITEMS_ITEM_LENGTH;
1693 else if (!(menuflags & MENU_FOR_CLICK))
1695 unblock_input ();
1696 /* Make "Cancel" equivalent to C-g. */
1697 quit ();
1700 unblock_input ();
1701 return Qnil;
1704 #ifdef USE_GTK
1705 static void
1706 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1708 /* Treat the pointer as an integer. There's no problem
1709 as long as pointers have enough bits to hold small integers. */
1710 if ((intptr_t) client_data != -1)
1711 menu_item_selection = client_data;
1713 popup_activated_flag = 0;
1716 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1717 dialog pops down.
1718 menu_item_selection will be set to the selection. */
1719 static void
1720 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1722 GtkWidget *menu;
1724 eassert (FRAME_X_P (f));
1726 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1727 G_CALLBACK (dialog_selection_callback),
1728 G_CALLBACK (popup_deactivate_callback),
1731 if (menu)
1733 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1734 record_unwind_protect_ptr (pop_down_menu, menu);
1736 /* Display the menu. */
1737 gtk_widget_show_all (menu);
1739 /* Process events that apply to the menu. */
1740 popup_widget_loop (true, menu);
1742 unbind_to (specpdl_count, Qnil);
1746 #else /* not USE_GTK */
1747 static void
1748 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1750 /* Treat the pointer as an integer. There's no problem
1751 as long as pointers have enough bits to hold small integers. */
1752 if ((intptr_t) client_data != -1)
1753 menu_item_selection = client_data;
1755 block_input ();
1756 lw_destroy_all_widgets (id);
1757 unblock_input ();
1758 popup_activated_flag = 0;
1762 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1763 dialog pops down.
1764 menu_item_selection will be set to the selection. */
1765 static void
1766 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1768 LWLIB_ID dialog_id;
1770 eassert (FRAME_X_P (f));
1772 dialog_id = widget_id_tick++;
1773 #ifdef USE_LUCID
1774 apply_systemfont_to_dialog (f->output_data.x->widget);
1775 #endif
1776 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1777 f->output_data.x->widget, true, 0,
1778 dialog_selection_callback, 0, 0);
1779 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1780 /* Display the dialog box. */
1781 lw_pop_up_all_widgets (dialog_id);
1782 popup_activated_flag = 1;
1783 x_activate_timeout_atimer ();
1785 /* Process events that apply to the dialog box.
1786 Also handle timers. */
1788 ptrdiff_t count = SPECPDL_INDEX ();
1790 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1792 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1794 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1796 unbind_to (count, Qnil);
1800 #endif /* not USE_GTK */
1802 static const char * button_names [] = {
1803 "button1", "button2", "button3", "button4", "button5",
1804 "button6", "button7", "button8", "button9", "button10" };
1806 static Lisp_Object
1807 x_dialog_show (struct frame *f, Lisp_Object title,
1808 Lisp_Object header, const char **error_name)
1810 int i, nb_buttons=0;
1811 char dialog_name[6];
1813 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1815 /* Number of elements seen so far, before boundary. */
1816 int left_count = 0;
1817 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1818 bool boundary_seen = false;
1820 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1822 eassert (FRAME_X_P (f));
1824 *error_name = NULL;
1826 if (menu_items_n_panes > 1)
1828 *error_name = "Multiple panes in dialog box";
1829 return Qnil;
1832 /* Create a tree of widget_value objects
1833 representing the text label and buttons. */
1835 Lisp_Object pane_name;
1836 const char *pane_string;
1837 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1838 pane_string = (NILP (pane_name)
1839 ? "" : SSDATA (pane_name));
1840 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1841 first_wv = prev_wv;
1843 /* Loop over all panes and items, filling in the tree. */
1844 i = MENU_ITEMS_PANE_LENGTH;
1845 while (i < menu_items_used)
1848 /* Create a new item within current pane. */
1849 Lisp_Object item_name, enable, descrip;
1850 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1851 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1852 descrip
1853 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1855 if (NILP (item_name))
1857 free_menubar_widget_value_tree (first_wv);
1858 *error_name = "Submenu in dialog items";
1859 return Qnil;
1861 if (EQ (item_name, Qquote))
1863 /* This is the boundary between left-side elts
1864 and right-side elts. Stop incrementing right_count. */
1865 boundary_seen = true;
1866 i++;
1867 continue;
1869 if (nb_buttons >= 9)
1871 free_menubar_widget_value_tree (first_wv);
1872 *error_name = "Too many dialog items";
1873 return Qnil;
1876 wv = make_widget_value (button_names[nb_buttons],
1877 SSDATA (item_name),
1878 !NILP (enable), Qnil);
1879 prev_wv->next = wv;
1880 if (!NILP (descrip))
1881 wv->key = SSDATA (descrip);
1882 wv->call_data = aref_addr (menu_items, i);
1883 prev_wv = wv;
1885 if (! boundary_seen)
1886 left_count++;
1888 nb_buttons++;
1889 i += MENU_ITEMS_ITEM_LENGTH;
1892 /* If the boundary was not specified,
1893 by default put half on the left and half on the right. */
1894 if (! boundary_seen)
1895 left_count = nb_buttons - nb_buttons / 2;
1897 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1899 /* Frame title: 'Q' = Question, 'I' = Information.
1900 Can also have 'E' = Error if, one day, we want
1901 a popup for errors. */
1902 if (NILP (header))
1903 dialog_name[0] = 'Q';
1904 else
1905 dialog_name[0] = 'I';
1907 /* Dialog boxes use a really stupid name encoding
1908 which specifies how many buttons to use
1909 and how many buttons are on the right. */
1910 dialog_name[1] = '0' + nb_buttons;
1911 dialog_name[2] = 'B';
1912 dialog_name[3] = 'R';
1913 /* Number of buttons to put on the right. */
1914 dialog_name[4] = '0' + nb_buttons - left_count;
1915 dialog_name[5] = 0;
1916 wv->contents = first_wv;
1917 first_wv = wv;
1920 /* No selection has been chosen yet. */
1921 menu_item_selection = 0;
1923 /* Make sure to free the widget_value objects we used to specify the
1924 contents even with longjmp. */
1925 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1927 /* Actually create and show the dialog. */
1928 create_and_show_dialog (f, first_wv);
1930 unbind_to (specpdl_count, Qnil);
1932 /* Find the selected item, and its pane, to return
1933 the proper value. */
1934 if (menu_item_selection != 0)
1936 i = 0;
1937 while (i < menu_items_used)
1939 Lisp_Object entry;
1941 if (EQ (AREF (menu_items, i), Qt))
1942 i += MENU_ITEMS_PANE_LENGTH;
1943 else if (EQ (AREF (menu_items, i), Qquote))
1945 /* This is the boundary between left-side elts and
1946 right-side elts. */
1947 ++i;
1949 else
1951 entry
1952 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1953 if (menu_item_selection == aref_addr (menu_items, i))
1954 return entry;
1955 i += MENU_ITEMS_ITEM_LENGTH;
1959 else
1960 /* Make "Cancel" equivalent to C-g. */
1961 quit ();
1963 return Qnil;
1966 Lisp_Object
1967 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1969 Lisp_Object title;
1970 const char *error_name;
1971 Lisp_Object selection;
1972 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1974 check_window_system (f);
1976 /* Decode the dialog items from what was specified. */
1977 title = Fcar (contents);
1978 CHECK_STRING (title);
1979 record_unwind_protect_void (unuse_menu_items);
1981 if (NILP (Fcar (Fcdr (contents))))
1982 /* No buttons specified, add an "Ok" button so users can pop down
1983 the dialog. Also, the lesstif/motif version crashes if there are
1984 no buttons. */
1985 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1987 list_of_panes (list1 (contents));
1989 /* Display them in a dialog box. */
1990 block_input ();
1991 selection = x_dialog_show (f, title, header, &error_name);
1992 unblock_input ();
1994 unbind_to (specpdl_count, Qnil);
1995 discard_menu_items ();
1997 if (error_name) error ("%s", error_name);
1998 return selection;
2001 #else /* not USE_X_TOOLKIT && not USE_GTK */
2003 /* The frame of the last activated non-toolkit menu bar.
2004 Used to generate menu help events. */
2006 static struct frame *menu_help_frame;
2009 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2011 PANE is the pane number, and ITEM is the menu item number in
2012 the menu (currently not used).
2014 This cannot be done with generating a HELP_EVENT because
2015 XMenuActivate contains a loop that doesn't let Emacs process
2016 keyboard events. */
2018 static void
2019 menu_help_callback (char const *help_string, int pane, int item)
2021 Lisp_Object *first_item;
2022 Lisp_Object pane_name;
2023 Lisp_Object menu_object;
2025 first_item = XVECTOR (menu_items)->contents;
2026 if (EQ (first_item[0], Qt))
2027 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2028 else if (EQ (first_item[0], Qquote))
2029 /* This shouldn't happen, see x_menu_show. */
2030 pane_name = empty_unibyte_string;
2031 else
2032 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2034 /* (menu-item MENU-NAME PANE-NUMBER) */
2035 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
2036 show_help_echo (help_string ? build_string (help_string) : Qnil,
2037 Qnil, menu_object, make_number (item));
2040 static void
2041 pop_down_menu (Lisp_Object arg)
2043 struct frame *f = XSAVE_POINTER (arg, 0);
2044 XMenu *menu = XSAVE_POINTER (arg, 1);
2046 block_input ();
2047 #ifndef MSDOS
2048 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2049 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2050 #endif
2051 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2053 #ifdef HAVE_X_WINDOWS
2054 /* Assume the mouse has moved out of the X window.
2055 If it has actually moved in, we will get an EnterNotify. */
2056 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2058 /* State that no mouse buttons are now held.
2059 (The oldXMenu code doesn't track this info for us.)
2060 That is not necessarily true, but the fiction leads to reasonable
2061 results, and it is a pain to ask which are actually held now. */
2062 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2064 #endif /* HAVE_X_WINDOWS */
2066 unblock_input ();
2070 Lisp_Object
2071 x_menu_show (struct frame *f, int x, int y, int menuflags,
2072 Lisp_Object title, const char **error_name)
2074 Window root;
2075 XMenu *menu;
2076 int pane, selidx, lpane, status;
2077 Lisp_Object entry = Qnil;
2078 Lisp_Object pane_prefix;
2079 char *datap;
2080 int ulx, uly, width, height;
2081 int dispwidth, dispheight;
2082 int i, j, lines, maxlines;
2083 int maxwidth;
2084 int dummy_int;
2085 unsigned int dummy_uint;
2086 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2088 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2090 *error_name = 0;
2091 if (menu_items_n_panes == 0)
2092 return Qnil;
2094 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2096 *error_name = "Empty menu";
2097 return Qnil;
2100 USE_SAFE_ALLOCA;
2101 block_input ();
2103 /* Figure out which root window F is on. */
2104 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2105 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2106 &dummy_uint, &dummy_uint);
2108 /* Make the menu on that window. */
2109 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2110 if (menu == NULL)
2112 *error_name = "Can't create menu";
2113 goto return_entry;
2116 /* Don't GC while we prepare and show the menu,
2117 because we give the oldxmenu library pointers to the
2118 contents of strings. */
2119 inhibit_garbage_collection ();
2121 #ifdef HAVE_X_WINDOWS
2123 /* Adjust coordinates to relative to the outer (window manager) window. */
2124 int left_off, top_off;
2126 x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
2127 NULL, NULL, NULL, NULL, NULL);
2129 x += left_off;
2130 y += top_off;
2132 #endif /* HAVE_X_WINDOWS */
2134 x += f->left_pos;
2135 y += f->top_pos;
2137 /* Create all the necessary panes and their items. */
2138 maxwidth = maxlines = lines = i = 0;
2139 lpane = XM_FAILURE;
2140 while (i < menu_items_used)
2142 if (EQ (AREF (menu_items, i), Qt))
2144 /* Create a new pane. */
2145 Lisp_Object pane_name, prefix;
2146 const char *pane_string;
2148 maxlines = max (maxlines, lines);
2149 lines = 0;
2150 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2151 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2152 pane_string = (NILP (pane_name)
2153 ? "" : SSDATA (pane_name));
2154 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2155 pane_string++;
2157 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2158 if (lpane == XM_FAILURE)
2160 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2161 *error_name = "Can't create pane";
2162 goto return_entry;
2164 i += MENU_ITEMS_PANE_LENGTH;
2166 /* Find the width of the widest item in this pane. */
2167 j = i;
2168 while (j < menu_items_used)
2170 Lisp_Object item;
2171 item = AREF (menu_items, j);
2172 if (EQ (item, Qt))
2173 break;
2174 if (NILP (item))
2176 j++;
2177 continue;
2179 width = SBYTES (item);
2180 if (width > maxwidth)
2181 maxwidth = width;
2183 j += MENU_ITEMS_ITEM_LENGTH;
2186 /* Ignore a nil in the item list.
2187 It's meaningful only for dialog boxes. */
2188 else if (EQ (AREF (menu_items, i), Qquote))
2189 i += 1;
2190 else
2192 /* Create a new item within current pane. */
2193 Lisp_Object item_name, enable, descrip, help;
2194 char *item_data;
2195 char const *help_string;
2197 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2198 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2199 descrip
2200 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2201 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2202 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2204 if (!NILP (descrip))
2206 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2207 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2208 for (j = SCHARS (item_name); j < maxwidth; j++)
2209 item_data[j] = ' ';
2210 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2211 item_data[j + SBYTES (descrip)] = 0;
2213 else
2214 item_data = SSDATA (item_name);
2216 if (lpane == XM_FAILURE
2217 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2218 menu, lpane, 0, item_data,
2219 !NILP (enable), help_string)
2220 == XM_FAILURE))
2222 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2223 *error_name = "Can't add selection to menu";
2224 goto return_entry;
2226 i += MENU_ITEMS_ITEM_LENGTH;
2227 lines++;
2231 maxlines = max (maxlines, lines);
2233 /* All set and ready to fly. */
2234 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2235 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2236 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2237 x = min (x, dispwidth);
2238 y = min (y, dispheight);
2239 x = max (x, 1);
2240 y = max (y, 1);
2241 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2242 &ulx, &uly, &width, &height);
2243 if (ulx+width > dispwidth)
2245 x -= (ulx + width) - dispwidth;
2246 ulx = dispwidth - width;
2248 if (uly+height > dispheight)
2250 y -= (uly + height) - dispheight;
2251 uly = dispheight - height;
2253 #ifndef HAVE_X_WINDOWS
2254 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2256 /* Move the menu away of the echo area, to avoid overwriting the
2257 menu with help echo messages or vice versa. */
2258 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2260 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2261 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2263 else
2265 y--;
2266 uly--;
2269 #endif
2270 if (ulx < 0) x -= ulx;
2271 if (uly < 0) y -= uly;
2273 if (!(menuflags & MENU_FOR_CLICK))
2275 /* If position was not given by a mouse click, adjust so upper left
2276 corner of the menu as a whole ends up at given coordinates. This
2277 is what x-popup-menu says in its documentation. */
2278 x += width/2;
2279 y += 1.5*height/(maxlines+2);
2282 XMenuSetAEQ (menu, true);
2283 XMenuSetFreeze (menu, true);
2284 pane = selidx = 0;
2286 #ifndef MSDOS
2287 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2288 #endif
2290 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2292 /* Help display under X won't work because XMenuActivate contains
2293 a loop that doesn't give Emacs a chance to process it. */
2294 menu_help_frame = f;
2295 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2296 x, y, ButtonReleaseMask, &datap,
2297 menu_help_callback);
2298 pane_prefix = Qnil;
2300 switch (status)
2302 case XM_SUCCESS:
2303 #ifdef XDEBUG
2304 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2305 #endif
2307 /* Find the item number SELIDX in pane number PANE. */
2308 i = 0;
2309 while (i < menu_items_used)
2311 if (EQ (AREF (menu_items, i), Qt))
2313 if (pane == 0)
2314 pane_prefix
2315 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2316 pane--;
2317 i += MENU_ITEMS_PANE_LENGTH;
2319 else
2321 if (pane == -1)
2323 if (selidx == 0)
2325 entry
2326 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2327 if (menuflags & MENU_KEYMAPS)
2329 entry = list1 (entry);
2330 if (!NILP (pane_prefix))
2331 entry = Fcons (pane_prefix, entry);
2333 break;
2335 selidx--;
2337 i += MENU_ITEMS_ITEM_LENGTH;
2340 break;
2342 case XM_FAILURE:
2343 *error_name = "Can't activate menu";
2344 case XM_IA_SELECT:
2345 break;
2346 case XM_NO_SELECT:
2347 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2348 the menu was invoked with a mouse event as POSITION). */
2349 if (!(menuflags & MENU_FOR_CLICK))
2351 unblock_input ();
2352 quit ();
2354 break;
2357 return_entry:
2358 unblock_input ();
2359 SAFE_FREE ();
2360 return unbind_to (specpdl_count, entry);
2363 #endif /* not USE_X_TOOLKIT */
2365 #ifndef MSDOS
2366 /* Detect if a dialog or menu has been posted. MSDOS has its own
2367 implementation on msdos.c. */
2370 popup_activated (void)
2372 return popup_activated_flag;
2374 #endif /* not MSDOS */
2376 /* The following is used by delayed window autoselection. */
2378 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2379 doc: /* Return t if a menu or popup dialog is active. */)
2380 (void)
2382 return (popup_activated ()) ? Qt : Qnil;
2385 void
2386 syms_of_xmenu (void)
2388 #ifdef USE_X_TOOLKIT
2389 enum { WIDGET_ID_TICK_START = 1 << 16 };
2390 widget_id_tick = WIDGET_ID_TICK_START;
2391 next_menubar_widget_id = 1;
2392 #endif
2394 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2395 defsubr (&Smenu_or_popup_active_p);
2397 #ifdef USE_GTK
2398 DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
2399 #endif
2401 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2402 defsubr (&Sx_menu_bar_open_internal);
2403 Ffset (intern_c_string ("accelerate-menu"),
2404 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2405 #endif