In update_frame_menubar remove garbaged code.
[emacs.git] / src / xmenu.c
blob9063a8a2a52dc7399479ffe631af0d2c4a0db500
1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 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
11 (at 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 <http://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 "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"
50 #ifdef MSDOS
51 #include "msdos.h"
52 #endif
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
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
66 #include "dispextern.h"
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 */
98 #ifdef USE_GTK
99 #include "gtkutil.h"
100 #ifdef HAVE_GTK3
101 #include "xgselect.h"
102 #endif
103 #endif
105 #include "menu.h"
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;
113 #ifdef USE_X_TOOLKIT
115 static LWLIB_ID next_menubar_widget_id;
117 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
119 static struct frame *
120 menubar_id_to_frame (LWLIB_ID id)
122 Lisp_Object tail, frame;
123 struct frame *f;
125 FOR_EACH_FRAME (tail, frame)
127 f = XFRAME (frame);
128 if (!FRAME_WINDOW_P (f))
129 continue;
130 if (f->output_data.x->id == id)
131 return f;
133 return 0;
136 #endif
138 #ifndef MSDOS
140 #if defined USE_GTK || defined USE_MOTIF
142 /* Set menu_items_inuse so no other popup menu or dialog is created. */
144 void
145 x_menu_set_in_use (bool in_use)
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
155 #endif
157 /* Wait for an X event to arrive or for a timer to expire. */
159 void
160 x_menu_wait_for_event (void *data)
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. */
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
177 struct timespec next_time = timer_check (), *ntp;
178 fd_set read_fds;
179 struct x_display_info *dpyinfo;
180 int n = 0;
182 FD_ZERO (&read_fds);
183 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
185 int fd = ConnectionNumber (dpyinfo->display);
186 FD_SET (fd, &read_fds);
187 if (fd > n) n = fd;
188 XFlush (dpyinfo->display);
191 if (! timespec_valid_p (next_time))
192 ntp = 0;
193 else
194 ntp = &next_time;
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
206 #endif /* ! MSDOS */
209 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
211 #ifdef USE_X_TOOLKIT
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.
217 NOTE: All calls to popup_get_selection should be protected
218 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
220 static void
221 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
222 LWLIB_ID id, bool do_timers)
224 XEvent event;
226 while (popup_activated_flag)
228 if (initial_event)
230 event = *initial_event;
231 initial_event = 0;
233 else
235 if (do_timers) x_menu_wait_for_event (0);
236 XtAppNextEvent (Xt_app_con, &event);
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)
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
257 /* Pop down on C-g and Escape. */
258 else if (event.type == KeyPress
259 && dpyinfo->display == event.xbutton.display)
261 KeySym keysym = XLookupKeysym (&event.xkey, 0);
263 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
264 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
265 popup_activated_flag = 0;
268 x_dispatch_event (&event, event.xany.display);
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.
278 If FRAME is nil or not given, use the selected frame. */)
279 (Lisp_Object frame)
281 XEvent ev;
282 struct frame *f = decode_window_system_frame (frame);
283 Widget menubar;
284 block_input ();
286 if (FRAME_EXTERNAL_MENU_BAR (f))
287 set_frame_menubar (f, false, true);
289 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
290 if (menubar)
292 Window child;
293 bool error_p = false;
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;
305 #ifdef USE_MOTIF
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]);
315 #endif
317 XTranslateCoordinates (FRAME_X_DISPLAY (f),
318 /* From-window, to-window. */
319 ev.xbutton.window, ev.xbutton.root,
321 /* From-position, to-position. */
322 ev.xbutton.x, ev.xbutton.y,
323 &ev.xbutton.x_root, &ev.xbutton.y_root,
325 /* Child of win. */
326 &child);
327 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
328 x_uncatch_errors ();
330 if (! error_p)
332 ev.type = ButtonPress;
333 ev.xbutton.state = 0;
335 XtDispatchEvent (&ev);
336 ev.xbutton.type = ButtonRelease;
337 ev.xbutton.state = Button1Mask;
338 XtDispatchEvent (&ev);
342 unblock_input ();
344 return Qnil;
346 #endif /* USE_X_TOOLKIT */
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.
356 If FRAME is nil or not given, use the selected frame. */)
357 (Lisp_Object frame)
359 GtkWidget *menubar;
360 struct frame *f;
362 block_input ();
363 f = decode_window_system_frame (frame);
365 if (FRAME_EXTERNAL_MENU_BAR (f))
366 set_frame_menubar (f, false, true);
368 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
369 if (menubar)
371 /* Activate the first menu. */
372 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
374 if (children)
376 g_signal_emit_by_name (children->data, "activate_item");
377 popup_activated_flag = 1;
378 g_list_free (children);
381 unblock_input ();
383 return Qnil;
386 /* Loop util popup_activated_flag is set to zero in a callback.
387 Used for popup menus and dialogs. */
389 static void
390 popup_widget_loop (bool do_timers, GtkWidget *widget)
392 ++popup_activated_flag;
394 /* Process events in the Gtk event loop until done. */
395 while (popup_activated_flag)
397 if (do_timers) x_menu_wait_for_event (0);
398 gtk_main_iteration ();
401 #endif
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.
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.
411 But first we recompute the menu bar contents (the whole tree).
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. */
417 void
418 x_activate_menubar (struct frame *f)
420 eassert (FRAME_X_P (f));
422 if (!f->output_data.x->saved_menu_event->type)
423 return;
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
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 ();
442 /* Ignore this if we get it a second time. */
443 f->output_data.x->saved_menu_event->type = 0;
446 /* This callback is invoked when the user selects a menubar cascade
447 pushbutton, but before the pulldown menu is posted. */
449 #ifndef USE_GTK
450 static void
451 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
453 popup_activated_flag = 1;
454 x_activate_timeout_atimer ();
456 #endif
458 /* This callback is invoked when a dialog or menu is finished being
459 used and has been unposted. */
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
470 popup_activated_flag = 0;
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)
480 Lisp_Object frame;
482 if (f)
484 XSETFRAME (frame, f);
485 kbd_buffer_store_help_event (frame, help);
487 else
488 show_help_echo (help, Qnil, Qnil, Qnil);
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. */
497 #ifdef USE_GTK
498 static void
499 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
501 xg_menu_item_cb_data *cb_data;
502 Lisp_Object help;
504 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
505 if (! cb_data) return;
507 help = call_data ? cb_data->help : Qnil;
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);
518 #else
519 static void
520 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
522 widget_value *wv = call_data;
523 Lisp_Object help = wv ? wv->help : Qnil;
525 /* Determine the frame for the help event. */
526 struct frame *f = menubar_id_to_frame (id);
528 show_help_event (f, widget, help);
530 #endif
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.
537 static bool xg_crazy_callback_abort;
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)
546 xg_menu_item_cb_data *cb_data = client_data;
548 if (xg_crazy_callback_abort)
549 return;
551 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
552 return;
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;
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. */
569 block_input ();
570 while (gtk_events_pending ())
571 gtk_main_iteration ();
572 unblock_input ();
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);
580 #else /* not USE_GTK */
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)
589 struct frame *f;
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);
597 #endif /* not USE_GTK */
599 /* Recompute all the widgets of frame F, when the menu bar has been
600 changed. */
602 static void
603 update_frame_menubar (struct frame *f)
605 #ifdef USE_GTK
606 xg_update_frame_menubar (f);
607 #else
608 struct x_output *x;
610 eassert (FRAME_X_P (f));
612 x = f->output_data.x;
614 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
615 return;
617 block_input ();
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);
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);
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);
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);
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 #endif /* USE_LUCID */
645 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
646 unblock_input ();
647 #endif /* USE_GTK */
650 #ifdef USE_LUCID
651 static void
652 apply_systemfont_to_dialog (Widget w)
654 const char *fn = xsettings_get_system_normal_font ();
655 if (fn)
657 XrmDatabase db = XtDatabase (XtDisplay (w));
658 if (db)
659 XrmPutStringResource (&db, "*dialog.font", fn);
663 static void
664 apply_systemfont_to_menu (struct frame *f, Widget w)
666 const char *fn = xsettings_get_system_normal_font ();
668 if (fn)
670 XrmDatabase db = XtDatabase (XtDisplay (w));
671 if (db)
673 XrmPutStringResource (&db, "*menubar*font", fn);
674 XrmPutStringResource (&db, "*popup*font", fn);
679 #endif
681 /* Set the contents of the menubar widgets of frame F.
682 The argument FIRST_TIME is currently ignored;
683 it is set the first time this is called, from initialize_frame_menubar. */
685 void
686 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
688 xt_or_gtk_widget menubar_widget, old_widget;
689 #ifdef USE_X_TOOLKIT
690 LWLIB_ID id;
691 #endif
692 Lisp_Object items;
693 widget_value *wv, *first_wv, *prev_wv = 0;
694 int i;
695 int *submenu_start, *submenu_end;
696 bool *submenu_top_level_items;
697 int *submenu_n_panes;
699 eassert (FRAME_X_P (f));
701 menubar_widget = old_widget = f->output_data.x->menubar_widget;
703 XSETFRAME (Vmenu_updating_frame, f);
705 #ifdef USE_X_TOOLKIT
706 if (f->output_data.x->id == 0)
707 f->output_data.x->id = next_menubar_widget_id++;
708 id = f->output_data.x->id;
709 #endif
711 if (! menubar_widget)
712 deep_p = true;
713 /* Make the first call for any given frame always go deep. */
714 else if (!f->output_data.x->saved_menu_event && !deep_p)
716 deep_p = true;
717 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
718 f->output_data.x->saved_menu_event->type = 0;
721 if (deep_p)
723 /* Make a widget-value tree representing the entire menu trees. */
725 struct buffer *prev = current_buffer;
726 Lisp_Object buffer;
727 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
728 int previous_menu_items_used = f->menu_bar_items_used;
729 Lisp_Object *previous_items
730 = alloca (previous_menu_items_used * sizeof *previous_items);
731 int subitems;
733 /* If we are making a new widget, its contents are empty,
734 do always reinitialize them. */
735 if (! menubar_widget)
736 previous_menu_items_used = 0;
738 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
739 specbind (Qinhibit_quit, Qt);
740 /* Don't let the debugger step into this code
741 because it is not reentrant. */
742 specbind (Qdebug_on_next_call, Qnil);
744 record_unwind_save_match_data ();
745 if (NILP (Voverriding_local_map_menu_flag))
747 specbind (Qoverriding_terminal_local_map, Qnil);
748 specbind (Qoverriding_local_map, Qnil);
751 set_buffer_internal_1 (XBUFFER (buffer));
753 /* Run the Lucid hook. */
754 safe_run_hooks (Qactivate_menubar_hook);
756 /* If it has changed current-menubar from previous value,
757 really recompute the menubar from the value. */
758 if (! NILP (Vlucid_menu_bar_dirty_flag))
759 call0 (Qrecompute_lucid_menubar);
760 safe_run_hooks (Qmenu_bar_update_hook);
761 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
763 items = FRAME_MENU_BAR_ITEMS (f);
765 /* Save the frame's previous menu bar contents data. */
766 if (previous_menu_items_used)
767 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
768 previous_menu_items_used * word_size);
770 /* Fill in menu_items with the current menu bar contents.
771 This can evaluate Lisp code. */
772 save_menu_items ();
774 menu_items = f->menu_bar_vector;
775 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
776 subitems = ASIZE (items) / 4;
777 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
778 submenu_end = alloca (subitems * sizeof *submenu_end);
779 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
780 submenu_top_level_items = alloca (subitems
781 * sizeof *submenu_top_level_items);
782 init_menu_items ();
783 for (i = 0; i < subitems; i++)
785 Lisp_Object key, string, maps;
787 key = AREF (items, 4 * i);
788 string = AREF (items, 4 * i + 1);
789 maps = AREF (items, 4 * i + 2);
790 if (NILP (string))
791 break;
793 submenu_start[i] = menu_items_used;
795 menu_items_n_panes = 0;
796 submenu_top_level_items[i]
797 = parse_single_submenu (key, string, maps);
798 submenu_n_panes[i] = menu_items_n_panes;
800 submenu_end[i] = menu_items_used;
803 submenu_start[i] = -1;
804 finish_menu_items ();
806 /* Convert menu_items into widget_value trees
807 to display the menu. This cannot evaluate Lisp code. */
809 wv = make_widget_value ("menubar", NULL, true, Qnil);
810 wv->button_type = BUTTON_TYPE_NONE;
811 first_wv = wv;
813 for (i = 0; submenu_start[i] >= 0; i++)
815 menu_items_n_panes = submenu_n_panes[i];
816 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
817 submenu_top_level_items[i]);
818 if (prev_wv)
819 prev_wv->next = wv;
820 else
821 first_wv->contents = wv;
822 /* Don't set wv->name here; GC during the loop might relocate it. */
823 wv->enabled = true;
824 wv->button_type = BUTTON_TYPE_NONE;
825 prev_wv = wv;
828 set_buffer_internal_1 (prev);
830 /* If there has been no change in the Lisp-level contents
831 of the menu bar, skip redisplaying it. Just exit. */
833 /* Compare the new menu items with the ones computed last time. */
834 for (i = 0; i < previous_menu_items_used; i++)
835 if (menu_items_used == i
836 || (!EQ (previous_items[i], AREF (menu_items, i))))
837 break;
838 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
840 /* The menu items have not changed. Don't bother updating
841 the menus in any form, since it would be a no-op. */
842 free_menubar_widget_value_tree (first_wv);
843 discard_menu_items ();
844 unbind_to (specpdl_count, Qnil);
845 return;
848 /* The menu items are different, so store them in the frame. */
849 fset_menu_bar_vector (f, menu_items);
850 f->menu_bar_items_used = menu_items_used;
852 /* This undoes save_menu_items. */
853 unbind_to (specpdl_count, Qnil);
855 /* Now GC cannot happen during the lifetime of the widget_value,
856 so it's safe to store data from a Lisp_String. */
857 wv = first_wv->contents;
858 for (i = 0; i < ASIZE (items); i += 4)
860 Lisp_Object string;
861 string = AREF (items, i + 1);
862 if (NILP (string))
863 break;
864 wv->name = SSDATA (string);
865 update_submenu_strings (wv->contents);
866 wv = wv->next;
870 else
872 /* Make a widget-value tree containing
873 just the top level menu bar strings. */
875 wv = make_widget_value ("menubar", NULL, true, Qnil);
876 wv->button_type = BUTTON_TYPE_NONE;
877 first_wv = wv;
879 items = FRAME_MENU_BAR_ITEMS (f);
880 for (i = 0; i < ASIZE (items); i += 4)
882 Lisp_Object string;
884 string = AREF (items, i + 1);
885 if (NILP (string))
886 break;
888 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
889 wv->button_type = BUTTON_TYPE_NONE;
890 /* This prevents lwlib from assuming this
891 menu item is really supposed to be empty. */
892 /* The intptr_t cast avoids a warning.
893 This value just has to be different from small integers. */
894 wv->call_data = (void *) (intptr_t) (-1);
896 if (prev_wv)
897 prev_wv->next = wv;
898 else
899 first_wv->contents = wv;
900 prev_wv = wv;
903 /* Forget what we thought we knew about what is in the
904 detailed contents of the menu bar menus.
905 Changing the top level always destroys the contents. */
906 f->menu_bar_items_used = 0;
909 /* Create or update the menu bar widget. */
911 block_input ();
913 #ifdef USE_GTK
914 xg_crazy_callback_abort = true;
915 if (menubar_widget)
917 /* The fourth arg is DEEP_P, which says to consider the entire
918 menu trees we supply, rather than just the menu bar item names. */
919 xg_modify_menubar_widgets (menubar_widget,
921 first_wv,
922 deep_p,
923 G_CALLBACK (menubar_selection_callback),
924 G_CALLBACK (popup_deactivate_callback),
925 G_CALLBACK (menu_highlight_callback));
927 else
929 menubar_widget
930 = xg_create_widget ("menubar", "menubar", f, first_wv,
931 G_CALLBACK (menubar_selection_callback),
932 G_CALLBACK (popup_deactivate_callback),
933 G_CALLBACK (menu_highlight_callback));
935 f->output_data.x->menubar_widget = menubar_widget;
939 #else /* not USE_GTK */
940 if (menubar_widget)
942 /* Disable resizing (done for Motif!) */
943 lw_allow_resizing (f->output_data.x->widget, False);
945 /* The third arg is DEEP_P, which says to consider the entire
946 menu trees we supply, rather than just the menu bar item names. */
947 lw_modify_all_widgets (id, first_wv, deep_p);
949 /* Re-enable the edit widget to resize. */
950 lw_allow_resizing (f->output_data.x->widget, True);
952 else
954 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
955 XtTranslations override = XtParseTranslationTable (menuOverride);
957 #ifdef USE_LUCID
958 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
959 #endif
960 menubar_widget = lw_create_widget ("menubar", "menubar", id,
961 first_wv,
962 f->output_data.x->column_widget,
963 false,
964 popup_activate_callback,
965 menubar_selection_callback,
966 popup_deactivate_callback,
967 menu_highlight_callback);
968 f->output_data.x->menubar_widget = menubar_widget;
970 /* Make menu pop down on C-g. */
971 XtOverrideTranslations (menubar_widget, override);
975 int menubar_size;
976 if (f->output_data.x->menubar_widget)
977 XtRealizeWidget (f->output_data.x->menubar_widget);
979 menubar_size
980 = (f->output_data.x->menubar_widget
981 ? (f->output_data.x->menubar_widget->core.height
982 + f->output_data.x->menubar_widget->core.border_width)
983 : 0);
985 #ifdef USE_LUCID
986 /* Experimentally, we now get the right results
987 for -geometry -0-0 without this. 24 Aug 96, rms.
988 Maybe so, but the menu bar size is missing the pixels so the
989 WM size hints are off by these pixels. Jan D, oct 2009. */
990 if (FRAME_EXTERNAL_MENU_BAR (f))
992 Dimension ibw = 0;
993 XtVaGetValues (f->output_data.x->column_widget,
994 XtNinternalBorderWidth, &ibw, NULL);
995 menubar_size += ibw;
997 #endif /* USE_LUCID */
999 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1001 #endif /* not USE_GTK */
1003 free_menubar_widget_value_tree (first_wv);
1004 update_frame_menubar (f);
1006 #ifdef USE_GTK
1007 xg_crazy_callback_abort = false;
1008 #endif
1010 unblock_input ();
1013 /* Called from Fx_create_frame to create the initial menubar of a frame
1014 before it is mapped, so that the window is mapped with the menubar already
1015 there instead of us tacking it on later and thrashing the window after it
1016 is visible. */
1018 void
1019 initialize_frame_menubar (struct frame *f)
1021 /* This function is called before the first chance to redisplay
1022 the frame. It has to be, so the frame will have the right size. */
1023 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1024 set_frame_menubar (f, true, true);
1028 /* Get rid of the menu bar of frame F, and free its storage.
1029 This is used when deleting a frame, and when turning off the menu bar.
1030 For GTK this function is in gtkutil.c. */
1032 #ifndef USE_GTK
1033 void
1034 free_frame_menubar (struct frame *f)
1036 Widget menubar_widget;
1037 #ifdef USE_MOTIF
1038 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1039 If we want to preserve the old height, calculate it now so we can
1040 restore it below. */
1041 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1042 #endif
1044 eassert (FRAME_X_P (f));
1046 menubar_widget = f->output_data.x->menubar_widget;
1048 FRAME_MENUBAR_HEIGHT (f) = 0;
1050 if (menubar_widget)
1052 #ifdef USE_MOTIF
1053 /* Removing the menu bar magically changes the shell widget's x
1054 and y position of (0, 0) which, when the menu bar is turned
1055 on again, leads to pull-down menus appearing in strange
1056 positions near the upper-left corner of the display. This
1057 happens only with some window managers like twm and ctwm,
1058 but not with other like Motif's mwm or kwm, because the
1059 latter generate ConfigureNotify events when the menu bar
1060 is switched off, which fixes the shell position. */
1061 Position x0, y0, x1, y1;
1062 #endif
1064 block_input ();
1066 #ifdef USE_MOTIF
1067 if (f->output_data.x->widget)
1068 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1069 #endif
1071 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1072 f->output_data.x->menubar_widget = NULL;
1074 if (f->output_data.x->widget)
1076 int new_height = -1;
1077 #ifdef USE_MOTIF
1078 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1079 if (x1 == 0 && y1 == 0)
1080 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1081 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1082 new_height = old_height;
1083 #endif /* USE_MOTIF */
1084 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
1086 else
1088 #ifdef USE_MOTIF
1089 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1090 adjust_frame_size (f, -1, old_height, 1, false, Qmenu_bar_lines);
1091 #endif
1094 unblock_input ();
1097 #endif /* not USE_GTK */
1099 #endif /* USE_X_TOOLKIT || USE_GTK */
1101 /* x_menu_show actually displays a menu using the panes and items in menu_items
1102 and returns the value selected from it.
1103 There are two versions of x_menu_show, one for Xt and one for Xlib.
1104 Both assume input is blocked by the caller. */
1106 /* F is the frame the menu is for.
1107 X and Y are the frame-relative specified position,
1108 relative to the inside upper left corner of the frame F.
1109 Bitfield MENUFLAGS bits are:
1110 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1111 MENU_KEYMAPS is set if this menu was specified with keymaps;
1112 in that case, we return a list containing the chosen item's value
1113 and perhaps also the pane's prefix.
1114 TITLE is the specified menu title.
1115 ERROR is a place to store an error message string in case of failure.
1116 (We return nil on failure, but the value doesn't actually matter.) */
1118 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1120 /* The item selected in the popup menu. */
1121 static Lisp_Object *volatile menu_item_selection;
1123 #ifdef USE_GTK
1125 /* Used when position a popup menu. See menu_position_func and
1126 create_and_show_popup_menu below. */
1127 struct next_popup_x_y
1129 struct frame *f;
1130 int x;
1131 int y;
1134 /* The menu position function to use if we are not putting a popup
1135 menu where the pointer is.
1136 MENU is the menu to pop up.
1137 X and Y shall on exit contain x/y where the menu shall pop up.
1138 PUSH_IN is not documented in the GTK manual.
1139 USER_DATA is any data passed in when calling gtk_menu_popup.
1140 Here it points to a struct next_popup_x_y where the coordinates
1141 to store in *X and *Y are as well as the frame for the popup.
1143 Here only X and Y are used. */
1144 static void
1145 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1147 struct next_popup_x_y *data = user_data;
1148 GtkRequisition req;
1149 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1150 int disp_width = x_display_pixel_width (dpyinfo);
1151 int disp_height = x_display_pixel_height (dpyinfo);
1153 *x = data->x;
1154 *y = data->y;
1156 /* Check if there is room for the menu. If not, adjust x/y so that
1157 the menu is fully visible. */
1158 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1159 if (data->x + req.width > disp_width)
1160 *x -= data->x + req.width - disp_width;
1161 if (data->y + req.height > disp_height)
1162 *y -= data->y + req.height - disp_height;
1165 static void
1166 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1168 xg_menu_item_cb_data *cb_data = client_data;
1170 if (xg_crazy_callback_abort) return;
1171 if (cb_data) menu_item_selection = cb_data->call_data;
1174 static void
1175 pop_down_menu (void *arg)
1177 popup_activated_flag = 0;
1178 block_input ();
1179 gtk_widget_destroy (GTK_WIDGET (arg));
1180 unblock_input ();
1183 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1184 menu pops down.
1185 menu_item_selection will be set to the selection. */
1186 static void
1187 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1188 int x, int y, bool for_click)
1190 int i;
1191 GtkWidget *menu;
1192 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1193 struct next_popup_x_y popup_x_y;
1194 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1195 bool use_pos_func = ! for_click;
1197 #ifdef HAVE_GTK3
1198 /* Always use position function for Gtk3. Otherwise menus may become
1199 too small to show anything. */
1200 use_pos_func = true;
1201 #endif
1203 eassert (FRAME_X_P (f));
1205 xg_crazy_callback_abort = true;
1206 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1207 G_CALLBACK (popup_selection_callback),
1208 G_CALLBACK (popup_deactivate_callback),
1209 G_CALLBACK (menu_highlight_callback));
1210 xg_crazy_callback_abort = false;
1212 if (use_pos_func)
1214 /* Not invoked by a click. pop up at x/y. */
1215 pos_func = menu_position_func;
1217 /* Adjust coordinates to be root-window-relative. */
1218 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1219 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1221 popup_x_y.x = x;
1222 popup_x_y.y = y;
1223 popup_x_y.f = f;
1225 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1228 if (for_click)
1230 for (i = 0; i < 5; i++)
1231 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1232 break;
1233 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1234 if (i == 5) i = 0;
1237 /* Display the menu. */
1238 gtk_widget_show_all (menu);
1240 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1241 FRAME_DISPLAY_INFO (f)->last_user_time);
1243 record_unwind_protect_ptr (pop_down_menu, menu);
1245 if (gtk_widget_get_mapped (menu))
1247 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1248 two. show_help_echo uses this to detect popup menus. */
1249 popup_activated_flag = 1;
1250 /* Process events that apply to the menu. */
1251 popup_widget_loop (true, menu);
1254 unbind_to (specpdl_count, Qnil);
1256 /* Must reset this manually because the button release event is not passed
1257 to Emacs event loop. */
1258 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1261 #else /* not USE_GTK */
1263 /* We need a unique id for each widget handled by the Lucid Widget
1264 library.
1266 For the main windows, and popup menus, we use this counter, which we
1267 increment each time after use. This starts from WIDGET_ID_TICK_START.
1269 For menu bars, we use numbers starting at 0, counted in
1270 next_menubar_widget_id. */
1271 LWLIB_ID widget_id_tick;
1273 static void
1274 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1276 menu_item_selection = client_data;
1279 /* ID is the LWLIB ID of the dialog box. */
1281 static void
1282 pop_down_menu (int id)
1284 block_input ();
1285 lw_destroy_all_widgets ((LWLIB_ID) id);
1286 unblock_input ();
1287 popup_activated_flag = 0;
1290 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1291 menu pops down.
1292 menu_item_selection will be set to the selection. */
1293 static void
1294 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1295 int x, int y, bool for_click)
1297 int i;
1298 Arg av[2];
1299 int ac = 0;
1300 XEvent dummy;
1301 XButtonPressedEvent *event = &(dummy.xbutton);
1302 LWLIB_ID menu_id;
1303 Widget menu;
1305 eassert (FRAME_X_P (f));
1307 #ifdef USE_LUCID
1308 apply_systemfont_to_menu (f, f->output_data.x->widget);
1309 #endif
1311 menu_id = widget_id_tick++;
1312 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1313 f->output_data.x->widget, true, 0,
1314 popup_selection_callback,
1315 popup_deactivate_callback,
1316 menu_highlight_callback);
1318 event->type = ButtonPress;
1319 event->serial = 0;
1320 event->send_event = false;
1321 event->display = FRAME_X_DISPLAY (f);
1322 event->time = CurrentTime;
1323 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1324 event->window = event->subwindow = event->root;
1325 event->x = x;
1326 event->y = y;
1328 /* Adjust coordinates to be root-window-relative. */
1329 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1330 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1332 event->x_root = x;
1333 event->y_root = y;
1335 event->state = 0;
1336 event->button = 0;
1337 for (i = 0; i < 5; i++)
1338 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1339 event->button = i;
1341 /* Don't allow any geometry request from the user. */
1342 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1343 XtSetValues (menu, av, ac);
1345 /* Display the menu. */
1346 lw_popup_menu (menu, &dummy);
1347 popup_activated_flag = 1;
1348 x_activate_timeout_atimer ();
1351 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1353 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1355 /* Process events that apply to the menu. */
1356 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1358 unbind_to (specpdl_count, Qnil);
1362 #endif /* not USE_GTK */
1364 static void
1365 cleanup_widget_value_tree (void *arg)
1367 free_menubar_widget_value_tree (arg);
1370 Lisp_Object
1371 x_menu_show (struct frame *f, int x, int y, int menuflags,
1372 Lisp_Object title, const char **error_name)
1374 int i;
1375 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1376 widget_value **submenu_stack
1377 = alloca (menu_items_used * sizeof *submenu_stack);
1378 Lisp_Object *subprefix_stack
1379 = alloca (menu_items_used * sizeof *subprefix_stack);
1380 int submenu_depth = 0;
1382 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1384 eassert (FRAME_X_P (f));
1386 *error_name = NULL;
1388 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1390 *error_name = "Empty menu";
1391 return Qnil;
1394 block_input ();
1396 /* Create a tree of widget_value objects
1397 representing the panes and their items. */
1398 wv = make_widget_value ("menu", NULL, true, Qnil);
1399 wv->button_type = BUTTON_TYPE_NONE;
1400 first_wv = wv;
1401 bool first_pane = true;
1403 /* Loop over all panes and items, filling in the tree. */
1404 i = 0;
1405 while (i < menu_items_used)
1407 if (EQ (AREF (menu_items, i), Qnil))
1409 submenu_stack[submenu_depth++] = save_wv;
1410 save_wv = prev_wv;
1411 prev_wv = 0;
1412 first_pane = true;
1413 i++;
1415 else if (EQ (AREF (menu_items, i), Qlambda))
1417 prev_wv = save_wv;
1418 save_wv = submenu_stack[--submenu_depth];
1419 first_pane = false;
1420 i++;
1422 else if (EQ (AREF (menu_items, i), Qt)
1423 && submenu_depth != 0)
1424 i += MENU_ITEMS_PANE_LENGTH;
1425 /* Ignore a nil in the item list.
1426 It's meaningful only for dialog boxes. */
1427 else if (EQ (AREF (menu_items, i), Qquote))
1428 i += 1;
1429 else if (EQ (AREF (menu_items, i), Qt))
1431 /* Create a new pane. */
1432 Lisp_Object pane_name, prefix;
1433 const char *pane_string;
1435 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1436 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1438 #ifndef HAVE_MULTILINGUAL_MENU
1439 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1441 pane_name = ENCODE_MENU_STRING (pane_name);
1442 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1444 #endif
1445 pane_string = (NILP (pane_name)
1446 ? "" : SSDATA (pane_name));
1447 /* If there is just one top-level pane, put all its items directly
1448 under the top-level menu. */
1449 if (menu_items_n_panes == 1)
1450 pane_string = "";
1452 /* If the pane has a meaningful name,
1453 make the pane a top-level menu item
1454 with its items as a submenu beneath it. */
1455 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1457 wv = make_widget_value (pane_string, NULL, true, Qnil);
1458 if (save_wv)
1459 save_wv->next = wv;
1460 else
1461 first_wv->contents = wv;
1462 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1463 wv->name++;
1464 wv->button_type = BUTTON_TYPE_NONE;
1465 save_wv = wv;
1466 prev_wv = 0;
1468 else if (first_pane)
1470 save_wv = wv;
1471 prev_wv = 0;
1473 first_pane = false;
1474 i += MENU_ITEMS_PANE_LENGTH;
1476 else
1478 /* Create a new item within current pane. */
1479 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1480 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1481 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1482 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1483 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1484 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1485 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1486 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1488 #ifndef HAVE_MULTILINGUAL_MENU
1489 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1491 item_name = ENCODE_MENU_STRING (item_name);
1492 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1495 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1497 descrip = ENCODE_MENU_STRING (descrip);
1498 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1500 #endif /* not HAVE_MULTILINGUAL_MENU */
1502 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1503 STRINGP (help) ? help : Qnil);
1504 if (prev_wv)
1505 prev_wv->next = wv;
1506 else
1507 save_wv->contents = wv;
1508 if (!NILP (descrip))
1509 wv->key = SSDATA (descrip);
1510 /* If this item has a null value,
1511 make the call_data null so that it won't display a box
1512 when the mouse is on it. */
1513 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1515 if (NILP (type))
1516 wv->button_type = BUTTON_TYPE_NONE;
1517 else if (EQ (type, QCtoggle))
1518 wv->button_type = BUTTON_TYPE_TOGGLE;
1519 else if (EQ (type, QCradio))
1520 wv->button_type = BUTTON_TYPE_RADIO;
1521 else
1522 emacs_abort ();
1524 wv->selected = !NILP (selected);
1526 prev_wv = wv;
1528 i += MENU_ITEMS_ITEM_LENGTH;
1532 /* Deal with the title, if it is non-nil. */
1533 if (!NILP (title))
1535 widget_value *wv_title;
1536 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1537 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1539 wv_sep2->next = first_wv->contents;
1540 wv_sep1->next = wv_sep2;
1542 #ifndef HAVE_MULTILINGUAL_MENU
1543 if (STRING_MULTIBYTE (title))
1544 title = ENCODE_MENU_STRING (title);
1545 #endif
1547 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1548 wv_title->button_type = BUTTON_TYPE_NONE;
1549 wv_title->next = wv_sep1;
1550 first_wv->contents = wv_title;
1553 /* No selection has been chosen yet. */
1554 menu_item_selection = 0;
1556 /* Make sure to free the widget_value objects we used to specify the
1557 contents even with longjmp. */
1558 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1560 /* Actually create and show the menu until popped down. */
1561 create_and_show_popup_menu (f, first_wv, x, y,
1562 menuflags & MENU_FOR_CLICK);
1564 unbind_to (specpdl_count, Qnil);
1566 /* Find the selected item, and its pane, to return
1567 the proper value. */
1568 if (menu_item_selection != 0)
1570 Lisp_Object prefix, entry;
1572 prefix = entry = Qnil;
1573 i = 0;
1574 while (i < menu_items_used)
1576 if (EQ (AREF (menu_items, i), Qnil))
1578 subprefix_stack[submenu_depth++] = prefix;
1579 prefix = entry;
1580 i++;
1582 else if (EQ (AREF (menu_items, i), Qlambda))
1584 prefix = subprefix_stack[--submenu_depth];
1585 i++;
1587 else if (EQ (AREF (menu_items, i), Qt))
1589 prefix
1590 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1591 i += MENU_ITEMS_PANE_LENGTH;
1593 /* Ignore a nil in the item list.
1594 It's meaningful only for dialog boxes. */
1595 else if (EQ (AREF (menu_items, i), Qquote))
1596 i += 1;
1597 else
1599 entry
1600 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1601 if (menu_item_selection == aref_addr (menu_items, i))
1603 if (menuflags & MENU_KEYMAPS)
1605 int j;
1607 entry = list1 (entry);
1608 if (!NILP (prefix))
1609 entry = Fcons (prefix, entry);
1610 for (j = submenu_depth - 1; j >= 0; j--)
1611 if (!NILP (subprefix_stack[j]))
1612 entry = Fcons (subprefix_stack[j], entry);
1614 unblock_input ();
1615 return entry;
1617 i += MENU_ITEMS_ITEM_LENGTH;
1621 else if (!(menuflags & MENU_FOR_CLICK))
1623 unblock_input ();
1624 /* Make "Cancel" equivalent to C-g. */
1625 Fsignal (Qquit, Qnil);
1628 unblock_input ();
1629 return Qnil;
1632 #ifdef USE_GTK
1633 static void
1634 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1636 /* Treat the pointer as an integer. There's no problem
1637 as long as pointers have enough bits to hold small integers. */
1638 if ((intptr_t) client_data != -1)
1639 menu_item_selection = client_data;
1641 popup_activated_flag = 0;
1644 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1645 dialog pops down.
1646 menu_item_selection will be set to the selection. */
1647 static void
1648 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1650 GtkWidget *menu;
1652 eassert (FRAME_X_P (f));
1654 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1655 G_CALLBACK (dialog_selection_callback),
1656 G_CALLBACK (popup_deactivate_callback),
1659 if (menu)
1661 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1662 record_unwind_protect_ptr (pop_down_menu, menu);
1664 /* Display the menu. */
1665 gtk_widget_show_all (menu);
1667 /* Process events that apply to the menu. */
1668 popup_widget_loop (true, menu);
1670 unbind_to (specpdl_count, Qnil);
1674 #else /* not USE_GTK */
1675 static void
1676 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1678 /* Treat the pointer as an integer. There's no problem
1679 as long as pointers have enough bits to hold small integers. */
1680 if ((intptr_t) client_data != -1)
1681 menu_item_selection = client_data;
1683 block_input ();
1684 lw_destroy_all_widgets (id);
1685 unblock_input ();
1686 popup_activated_flag = 0;
1690 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1691 dialog pops down.
1692 menu_item_selection will be set to the selection. */
1693 static void
1694 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1696 LWLIB_ID dialog_id;
1698 eassert (FRAME_X_P (f));
1700 dialog_id = widget_id_tick++;
1701 #ifdef USE_LUCID
1702 apply_systemfont_to_dialog (f->output_data.x->widget);
1703 #endif
1704 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1705 f->output_data.x->widget, true, 0,
1706 dialog_selection_callback, 0, 0);
1707 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1708 /* Display the dialog box. */
1709 lw_pop_up_all_widgets (dialog_id);
1710 popup_activated_flag = 1;
1711 x_activate_timeout_atimer ();
1713 /* Process events that apply to the dialog box.
1714 Also handle timers. */
1716 ptrdiff_t count = SPECPDL_INDEX ();
1718 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1720 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1722 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1724 unbind_to (count, Qnil);
1728 #endif /* not USE_GTK */
1730 static const char * button_names [] = {
1731 "button1", "button2", "button3", "button4", "button5",
1732 "button6", "button7", "button8", "button9", "button10" };
1734 static Lisp_Object
1735 x_dialog_show (struct frame *f, Lisp_Object title,
1736 Lisp_Object header, const char **error_name)
1738 int i, nb_buttons=0;
1739 char dialog_name[6];
1741 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1743 /* Number of elements seen so far, before boundary. */
1744 int left_count = 0;
1745 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1746 bool boundary_seen = false;
1748 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1750 eassert (FRAME_X_P (f));
1752 *error_name = NULL;
1754 if (menu_items_n_panes > 1)
1756 *error_name = "Multiple panes in dialog box";
1757 return Qnil;
1760 /* Create a tree of widget_value objects
1761 representing the text label and buttons. */
1763 Lisp_Object pane_name;
1764 const char *pane_string;
1765 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1766 pane_string = (NILP (pane_name)
1767 ? "" : SSDATA (pane_name));
1768 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1769 first_wv = prev_wv;
1771 /* Loop over all panes and items, filling in the tree. */
1772 i = MENU_ITEMS_PANE_LENGTH;
1773 while (i < menu_items_used)
1776 /* Create a new item within current pane. */
1777 Lisp_Object item_name, enable, descrip;
1778 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1779 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1780 descrip
1781 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1783 if (NILP (item_name))
1785 free_menubar_widget_value_tree (first_wv);
1786 *error_name = "Submenu in dialog items";
1787 return Qnil;
1789 if (EQ (item_name, Qquote))
1791 /* This is the boundary between left-side elts
1792 and right-side elts. Stop incrementing right_count. */
1793 boundary_seen = true;
1794 i++;
1795 continue;
1797 if (nb_buttons >= 9)
1799 free_menubar_widget_value_tree (first_wv);
1800 *error_name = "Too many dialog items";
1801 return Qnil;
1804 wv = make_widget_value (button_names[nb_buttons],
1805 SSDATA (item_name),
1806 !NILP (enable), Qnil);
1807 prev_wv->next = wv;
1808 if (!NILP (descrip))
1809 wv->key = SSDATA (descrip);
1810 wv->call_data = aref_addr (menu_items, i);
1811 prev_wv = wv;
1813 if (! boundary_seen)
1814 left_count++;
1816 nb_buttons++;
1817 i += MENU_ITEMS_ITEM_LENGTH;
1820 /* If the boundary was not specified,
1821 by default put half on the left and half on the right. */
1822 if (! boundary_seen)
1823 left_count = nb_buttons - nb_buttons / 2;
1825 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1827 /* Frame title: 'Q' = Question, 'I' = Information.
1828 Can also have 'E' = Error if, one day, we want
1829 a popup for errors. */
1830 if (NILP (header))
1831 dialog_name[0] = 'Q';
1832 else
1833 dialog_name[0] = 'I';
1835 /* Dialog boxes use a really stupid name encoding
1836 which specifies how many buttons to use
1837 and how many buttons are on the right. */
1838 dialog_name[1] = '0' + nb_buttons;
1839 dialog_name[2] = 'B';
1840 dialog_name[3] = 'R';
1841 /* Number of buttons to put on the right. */
1842 dialog_name[4] = '0' + nb_buttons - left_count;
1843 dialog_name[5] = 0;
1844 wv->contents = first_wv;
1845 first_wv = wv;
1848 /* No selection has been chosen yet. */
1849 menu_item_selection = 0;
1851 /* Make sure to free the widget_value objects we used to specify the
1852 contents even with longjmp. */
1853 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1855 /* Actually create and show the dialog. */
1856 create_and_show_dialog (f, first_wv);
1858 unbind_to (specpdl_count, Qnil);
1860 /* Find the selected item, and its pane, to return
1861 the proper value. */
1862 if (menu_item_selection != 0)
1864 i = 0;
1865 while (i < menu_items_used)
1867 Lisp_Object entry;
1869 if (EQ (AREF (menu_items, i), Qt))
1870 i += MENU_ITEMS_PANE_LENGTH;
1871 else if (EQ (AREF (menu_items, i), Qquote))
1873 /* This is the boundary between left-side elts and
1874 right-side elts. */
1875 ++i;
1877 else
1879 entry
1880 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1881 if (menu_item_selection == aref_addr (menu_items, i))
1882 return entry;
1883 i += MENU_ITEMS_ITEM_LENGTH;
1887 else
1888 /* Make "Cancel" equivalent to C-g. */
1889 Fsignal (Qquit, Qnil);
1891 return Qnil;
1894 Lisp_Object
1895 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1897 Lisp_Object title;
1898 const char *error_name;
1899 Lisp_Object selection;
1900 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1902 check_window_system (f);
1904 /* Decode the dialog items from what was specified. */
1905 title = Fcar (contents);
1906 CHECK_STRING (title);
1907 record_unwind_protect_void (unuse_menu_items);
1909 if (NILP (Fcar (Fcdr (contents))))
1910 /* No buttons specified, add an "Ok" button so users can pop down
1911 the dialog. Also, the lesstif/motif version crashes if there are
1912 no buttons. */
1913 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1915 list_of_panes (list1 (contents));
1917 /* Display them in a dialog box. */
1918 block_input ();
1919 selection = x_dialog_show (f, title, header, &error_name);
1920 unblock_input ();
1922 unbind_to (specpdl_count, Qnil);
1923 discard_menu_items ();
1925 if (error_name) error ("%s", error_name);
1926 return selection;
1929 #else /* not USE_X_TOOLKIT && not USE_GTK */
1931 /* The frame of the last activated non-toolkit menu bar.
1932 Used to generate menu help events. */
1934 static struct frame *menu_help_frame;
1937 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1939 PANE is the pane number, and ITEM is the menu item number in
1940 the menu (currently not used).
1942 This cannot be done with generating a HELP_EVENT because
1943 XMenuActivate contains a loop that doesn't let Emacs process
1944 keyboard events. */
1946 static void
1947 menu_help_callback (char const *help_string, int pane, int item)
1949 Lisp_Object *first_item;
1950 Lisp_Object pane_name;
1951 Lisp_Object menu_object;
1953 first_item = XVECTOR (menu_items)->contents;
1954 if (EQ (first_item[0], Qt))
1955 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1956 else if (EQ (first_item[0], Qquote))
1957 /* This shouldn't happen, see x_menu_show. */
1958 pane_name = empty_unibyte_string;
1959 else
1960 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1962 /* (menu-item MENU-NAME PANE-NUMBER) */
1963 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1964 show_help_echo (help_string ? build_string (help_string) : Qnil,
1965 Qnil, menu_object, make_number (item));
1968 static void
1969 pop_down_menu (Lisp_Object arg)
1971 struct frame *f = XSAVE_POINTER (arg, 0);
1972 XMenu *menu = XSAVE_POINTER (arg, 1);
1974 block_input ();
1975 #ifndef MSDOS
1976 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
1977 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
1978 #endif
1979 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
1981 #ifdef HAVE_X_WINDOWS
1982 /* Assume the mouse has moved out of the X window.
1983 If it has actually moved in, we will get an EnterNotify. */
1984 x_mouse_leave (FRAME_DISPLAY_INFO (f));
1986 /* State that no mouse buttons are now held.
1987 (The oldXMenu code doesn't track this info for us.)
1988 That is not necessarily true, but the fiction leads to reasonable
1989 results, and it is a pain to ask which are actually held now. */
1990 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1992 #endif /* HAVE_X_WINDOWS */
1994 unblock_input ();
1998 Lisp_Object
1999 x_menu_show (struct frame *f, int x, int y, int menuflags,
2000 Lisp_Object title, const char **error_name)
2002 Window root;
2003 XMenu *menu;
2004 int pane, selidx, lpane, status;
2005 Lisp_Object entry = Qnil;
2006 Lisp_Object pane_prefix;
2007 char *datap;
2008 int ulx, uly, width, height;
2009 int dispwidth, dispheight;
2010 int i, j, lines, maxlines;
2011 int maxwidth;
2012 int dummy_int;
2013 unsigned int dummy_uint;
2014 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2016 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2018 *error_name = 0;
2019 if (menu_items_n_panes == 0)
2020 return Qnil;
2022 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2024 *error_name = "Empty menu";
2025 return Qnil;
2028 USE_SAFE_ALLOCA;
2029 block_input ();
2031 /* Figure out which root window F is on. */
2032 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2033 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2034 &dummy_uint, &dummy_uint);
2036 /* Make the menu on that window. */
2037 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2038 if (menu == NULL)
2040 *error_name = "Can't create menu";
2041 goto return_entry;
2044 /* Don't GC while we prepare and show the menu,
2045 because we give the oldxmenu library pointers to the
2046 contents of strings. */
2047 inhibit_garbage_collection ();
2049 #ifdef HAVE_X_WINDOWS
2050 /* Adjust coordinates to relative to the outer (window manager) window. */
2051 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2052 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2053 #endif /* HAVE_X_WINDOWS */
2055 /* Adjust coordinates to be root-window-relative. */
2056 x += f->left_pos;
2057 y += f->top_pos;
2059 /* Create all the necessary panes and their items. */
2060 maxwidth = maxlines = lines = i = 0;
2061 lpane = XM_FAILURE;
2062 while (i < menu_items_used)
2064 if (EQ (AREF (menu_items, i), Qt))
2066 /* Create a new pane. */
2067 Lisp_Object pane_name, prefix;
2068 const char *pane_string;
2070 maxlines = max (maxlines, lines);
2071 lines = 0;
2072 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2073 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2074 pane_string = (NILP (pane_name)
2075 ? "" : SSDATA (pane_name));
2076 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2077 pane_string++;
2079 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2080 if (lpane == XM_FAILURE)
2082 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2083 *error_name = "Can't create pane";
2084 goto return_entry;
2086 i += MENU_ITEMS_PANE_LENGTH;
2088 /* Find the width of the widest item in this pane. */
2089 j = i;
2090 while (j < menu_items_used)
2092 Lisp_Object item;
2093 item = AREF (menu_items, j);
2094 if (EQ (item, Qt))
2095 break;
2096 if (NILP (item))
2098 j++;
2099 continue;
2101 width = SBYTES (item);
2102 if (width > maxwidth)
2103 maxwidth = width;
2105 j += MENU_ITEMS_ITEM_LENGTH;
2108 /* Ignore a nil in the item list.
2109 It's meaningful only for dialog boxes. */
2110 else if (EQ (AREF (menu_items, i), Qquote))
2111 i += 1;
2112 else
2114 /* Create a new item within current pane. */
2115 Lisp_Object item_name, enable, descrip, help;
2116 char *item_data;
2117 char const *help_string;
2119 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2120 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2121 descrip
2122 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2123 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2124 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2126 if (!NILP (descrip))
2128 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2129 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2130 for (j = SCHARS (item_name); j < maxwidth; j++)
2131 item_data[j] = ' ';
2132 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2133 item_data[j + SBYTES (descrip)] = 0;
2135 else
2136 item_data = SSDATA (item_name);
2138 if (lpane == XM_FAILURE
2139 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2140 menu, lpane, 0, item_data,
2141 !NILP (enable), help_string)
2142 == XM_FAILURE))
2144 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2145 *error_name = "Can't add selection to menu";
2146 goto return_entry;
2148 i += MENU_ITEMS_ITEM_LENGTH;
2149 lines++;
2153 maxlines = max (maxlines, lines);
2155 /* All set and ready to fly. */
2156 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2157 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2158 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2159 x = min (x, dispwidth);
2160 y = min (y, dispheight);
2161 x = max (x, 1);
2162 y = max (y, 1);
2163 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2164 &ulx, &uly, &width, &height);
2165 if (ulx+width > dispwidth)
2167 x -= (ulx + width) - dispwidth;
2168 ulx = dispwidth - width;
2170 if (uly+height > dispheight)
2172 y -= (uly + height) - dispheight;
2173 uly = dispheight - height;
2175 #ifndef HAVE_X_WINDOWS
2176 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2178 /* Move the menu away of the echo area, to avoid overwriting the
2179 menu with help echo messages or vice versa. */
2180 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2182 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2183 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2185 else
2187 y--;
2188 uly--;
2191 #endif
2192 if (ulx < 0) x -= ulx;
2193 if (uly < 0) y -= uly;
2195 if (!(menuflags & MENU_FOR_CLICK))
2197 /* If position was not given by a mouse click, adjust so upper left
2198 corner of the menu as a whole ends up at given coordinates. This
2199 is what x-popup-menu says in its documentation. */
2200 x += width/2;
2201 y += 1.5*height/(maxlines+2);
2204 XMenuSetAEQ (menu, true);
2205 XMenuSetFreeze (menu, true);
2206 pane = selidx = 0;
2208 #ifndef MSDOS
2209 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2210 #endif
2212 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2214 /* Help display under X won't work because XMenuActivate contains
2215 a loop that doesn't give Emacs a chance to process it. */
2216 menu_help_frame = f;
2217 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2218 x, y, ButtonReleaseMask, &datap,
2219 menu_help_callback);
2220 pane_prefix = Qnil;
2222 switch (status)
2224 case XM_SUCCESS:
2225 #ifdef XDEBUG
2226 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2227 #endif
2229 /* Find the item number SELIDX in pane number PANE. */
2230 i = 0;
2231 while (i < menu_items_used)
2233 if (EQ (AREF (menu_items, i), Qt))
2235 if (pane == 0)
2236 pane_prefix
2237 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2238 pane--;
2239 i += MENU_ITEMS_PANE_LENGTH;
2241 else
2243 if (pane == -1)
2245 if (selidx == 0)
2247 entry
2248 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2249 if (menuflags & MENU_KEYMAPS)
2251 entry = list1 (entry);
2252 if (!NILP (pane_prefix))
2253 entry = Fcons (pane_prefix, entry);
2255 break;
2257 selidx--;
2259 i += MENU_ITEMS_ITEM_LENGTH;
2262 break;
2264 case XM_FAILURE:
2265 *error_name = "Can't activate menu";
2266 case XM_IA_SELECT:
2267 break;
2268 case XM_NO_SELECT:
2269 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2270 the menu was invoked with a mouse event as POSITION). */
2271 if (!(menuflags & MENU_FOR_CLICK))
2273 unblock_input ();
2274 Fsignal (Qquit, Qnil);
2276 break;
2279 return_entry:
2280 unblock_input ();
2281 SAFE_FREE ();
2282 return unbind_to (specpdl_count, entry);
2285 #endif /* not USE_X_TOOLKIT */
2287 #ifndef MSDOS
2288 /* Detect if a dialog or menu has been posted. MSDOS has its own
2289 implementation on msdos.c. */
2291 int ATTRIBUTE_CONST
2292 popup_activated (void)
2294 return popup_activated_flag;
2296 #endif /* not MSDOS */
2298 /* The following is used by delayed window autoselection. */
2300 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2301 doc: /* Return t if a menu or popup dialog is active. */)
2302 (void)
2304 return (popup_activated ()) ? Qt : Qnil;
2307 void
2308 syms_of_xmenu (void)
2310 #ifdef USE_X_TOOLKIT
2311 enum { WIDGET_ID_TICK_START = 1 << 16 };
2312 widget_id_tick = WIDGET_ID_TICK_START;
2313 next_menubar_widget_id = 1;
2314 #endif
2316 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2317 defsubr (&Smenu_or_popup_active_p);
2319 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2320 defsubr (&Sx_menu_bar_open_internal);
2321 Ffset (intern_c_string ("accelerate-menu"),
2322 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2323 #endif