authors.el updates and sorting change
[emacs/old-mirror.git] / src / xmenu.c
bloba7d47188ef5a755c0e902004e7f9e390f38ca3e0
1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2014 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"
107 #ifndef TRUE
108 #define TRUE 1
109 #endif /* no TRUE */
111 static Lisp_Object Qdebug_on_next_call;
113 /* Flag which when set indicates a dialog or menu has been posted by
114 Xt on behalf of one of the widget sets. */
115 static int popup_activated_flag;
118 #ifdef USE_X_TOOLKIT
120 static LWLIB_ID next_menubar_widget_id;
122 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
124 static struct frame *
125 menubar_id_to_frame (LWLIB_ID id)
127 Lisp_Object tail, frame;
128 struct frame *f;
130 FOR_EACH_FRAME (tail, frame)
132 f = XFRAME (frame);
133 if (!FRAME_WINDOW_P (f))
134 continue;
135 if (f->output_data.x->id == id)
136 return f;
138 return 0;
141 #endif
143 #ifndef MSDOS
145 #if defined USE_GTK || defined USE_MOTIF
147 /* Set menu_items_inuse so no other popup menu or dialog is created. */
149 void
150 x_menu_set_in_use (int in_use)
152 menu_items_inuse = in_use ? Qt : Qnil;
153 popup_activated_flag = in_use;
154 #ifdef USE_X_TOOLKIT
155 if (popup_activated_flag)
156 x_activate_timeout_atimer ();
157 #endif
160 #endif
162 /* Wait for an X event to arrive or for a timer to expire. */
164 void
165 x_menu_wait_for_event (void *data)
167 /* Another way to do this is to register a timer callback, that can be
168 done in GTK and Xt. But we have to do it like this when using only X
169 anyway, and with callbacks we would have three variants for timer handling
170 instead of the small ifdefs below. */
172 while (
173 #ifdef USE_X_TOOLKIT
174 ! XtAppPending (Xt_app_con)
175 #elif defined USE_GTK
176 ! gtk_events_pending ()
177 #else
178 ! XPending (data)
179 #endif
182 struct timespec next_time = timer_check (), *ntp;
183 fd_set read_fds;
184 struct x_display_info *dpyinfo;
185 int n = 0;
187 FD_ZERO (&read_fds);
188 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
190 int fd = ConnectionNumber (dpyinfo->display);
191 FD_SET (fd, &read_fds);
192 if (fd > n) n = fd;
193 XFlush (dpyinfo->display);
196 if (! timespec_valid_p (next_time))
197 ntp = 0;
198 else
199 ntp = &next_time;
201 #if defined USE_GTK && defined HAVE_GTK3
202 /* Gtk3 have arrows on menus when they don't fit. When the
203 pointer is over an arrow, a timeout scrolls it a bit. Use
204 xg_select so that timeout gets triggered. */
205 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
206 #else
207 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
208 #endif
211 #endif /* ! MSDOS */
214 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
216 #ifdef USE_X_TOOLKIT
218 /* Loop in Xt until the menu pulldown or dialog popup has been
219 popped down (deactivated). This is used for x-popup-menu
220 and x-popup-dialog; it is not used for the menu bar.
222 NOTE: All calls to popup_get_selection should be protected
223 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
225 static void
226 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo, LWLIB_ID id, int do_timers)
228 XEvent event;
230 while (popup_activated_flag)
232 if (initial_event)
234 event = *initial_event;
235 initial_event = 0;
237 else
239 if (do_timers) x_menu_wait_for_event (0);
240 XtAppNextEvent (Xt_app_con, &event);
243 /* Make sure we don't consider buttons grabbed after menu goes.
244 And make sure to deactivate for any ButtonRelease,
245 even if XtDispatchEvent doesn't do that. */
246 if (event.type == ButtonRelease
247 && dpyinfo->display == event.xbutton.display)
249 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
250 #ifdef USE_MOTIF /* Pretending that the event came from a
251 Btn1Down seems the only way to convince Motif to
252 activate its callbacks; setting the XmNmenuPost
253 isn't working. --marcus@sysc.pdx.edu. */
254 event.xbutton.button = 1;
255 /* Motif only pops down menus when no Ctrl, Alt or Mod
256 key is pressed and the button is released. So reset key state
257 so Motif thinks this is the case. */
258 event.xbutton.state = 0;
259 #endif
261 /* Pop down on C-g and Escape. */
262 else if (event.type == KeyPress
263 && dpyinfo->display == event.xbutton.display)
265 KeySym keysym = XLookupKeysym (&event.xkey, 0);
267 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
268 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
269 popup_activated_flag = 0;
272 x_dispatch_event (&event, event.xany.display);
276 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
277 doc: /* Start key navigation of the menu bar in FRAME.
278 This initially opens the first menu bar item and you can then navigate with the
279 arrow keys, select a menu entry with the return key or cancel with the
280 escape key. If FRAME has no menu bar this function does nothing.
282 If FRAME is nil or not given, use the selected frame. */)
283 (Lisp_Object frame)
285 XEvent ev;
286 struct frame *f = decode_window_system_frame (frame);
287 Widget menubar;
288 block_input ();
290 if (FRAME_EXTERNAL_MENU_BAR (f))
291 set_frame_menubar (f, 0, 1);
293 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
294 if (menubar)
296 Window child;
297 bool error_p = 0;
299 x_catch_errors (FRAME_X_DISPLAY (f));
300 memset (&ev, 0, sizeof ev);
301 ev.xbutton.display = FRAME_X_DISPLAY (f);
302 ev.xbutton.window = XtWindow (menubar);
303 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
304 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
305 ev.xbutton.button = Button1;
306 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
307 ev.xbutton.same_screen = True;
309 #ifdef USE_MOTIF
311 Arg al[2];
312 WidgetList list;
313 Cardinal nr;
314 XtSetArg (al[0], XtNchildren, &list);
315 XtSetArg (al[1], XtNnumChildren, &nr);
316 XtGetValues (menubar, al, 2);
317 ev.xbutton.window = XtWindow (list[0]);
319 #endif
321 XTranslateCoordinates (FRAME_X_DISPLAY (f),
322 /* From-window, to-window. */
323 ev.xbutton.window, ev.xbutton.root,
325 /* From-position, to-position. */
326 ev.xbutton.x, ev.xbutton.y,
327 &ev.xbutton.x_root, &ev.xbutton.y_root,
329 /* Child of win. */
330 &child);
331 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
332 x_uncatch_errors ();
334 if (! error_p)
336 ev.type = ButtonPress;
337 ev.xbutton.state = 0;
339 XtDispatchEvent (&ev);
340 ev.xbutton.type = ButtonRelease;
341 ev.xbutton.state = Button1Mask;
342 XtDispatchEvent (&ev);
346 unblock_input ();
348 return Qnil;
350 #endif /* USE_X_TOOLKIT */
353 #ifdef USE_GTK
354 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
355 doc: /* Start key navigation of the menu bar in FRAME.
356 This initially opens the first menu bar item and you can then navigate with the
357 arrow keys, select a menu entry with the return key or cancel with the
358 escape key. If FRAME has no menu bar this function does nothing.
360 If FRAME is nil or not given, use the selected frame. */)
361 (Lisp_Object frame)
363 GtkWidget *menubar;
364 struct frame *f;
366 block_input ();
367 f = decode_window_system_frame (frame);
369 if (FRAME_EXTERNAL_MENU_BAR (f))
370 set_frame_menubar (f, 0, 1);
372 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
373 if (menubar)
375 /* Activate the first menu. */
376 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
378 if (children)
380 g_signal_emit_by_name (children->data, "activate_item");
381 popup_activated_flag = 1;
382 g_list_free (children);
385 unblock_input ();
387 return Qnil;
390 /* Loop util popup_activated_flag is set to zero in a callback.
391 Used for popup menus and dialogs. */
393 static void
394 popup_widget_loop (int do_timers, GtkWidget *widget)
396 ++popup_activated_flag;
398 /* Process events in the Gtk event loop until done. */
399 while (popup_activated_flag)
401 if (do_timers) x_menu_wait_for_event (0);
402 gtk_main_iteration ();
405 #endif
407 /* Activate the menu bar of frame F.
408 This is called from keyboard.c when it gets the
409 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
411 To activate the menu bar, we use the X button-press event
412 that was saved in saved_menu_event.
413 That makes the toolkit do its thing.
415 But first we recompute the menu bar contents (the whole tree).
417 The reason for saving the button event until here, instead of
418 passing it to the toolkit right away, is that we can safely
419 execute Lisp code. */
421 void
422 x_activate_menubar (struct frame *f)
424 eassert (FRAME_X_P (f));
426 if (!f->output_data.x->saved_menu_event->type)
427 return;
429 #ifdef USE_GTK
430 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
431 f->output_data.x->saved_menu_event->xany.window))
432 return;
433 #endif
435 set_frame_menubar (f, 0, 1);
436 block_input ();
437 popup_activated_flag = 1;
438 #ifdef USE_GTK
439 XPutBackEvent (f->output_data.x->display_info->display,
440 f->output_data.x->saved_menu_event);
441 #else
442 XtDispatchEvent (f->output_data.x->saved_menu_event);
443 #endif
444 unblock_input ();
446 /* Ignore this if we get it a second time. */
447 f->output_data.x->saved_menu_event->type = 0;
450 /* This callback is invoked when the user selects a menubar cascade
451 pushbutton, but before the pulldown menu is posted. */
453 #ifndef USE_GTK
454 static void
455 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
457 popup_activated_flag = 1;
458 x_activate_timeout_atimer ();
460 #endif
462 /* This callback is invoked when a dialog or menu is finished being
463 used and has been unposted. */
465 static void
466 popup_deactivate_callback (
467 #ifdef USE_GTK
468 GtkWidget *widget, gpointer client_data
469 #else
470 Widget widget, LWLIB_ID id, XtPointer client_data
471 #endif
474 popup_activated_flag = 0;
478 /* Function that finds the frame for WIDGET and shows the HELP text
479 for that widget.
480 F is the frame if known, or NULL if not known. */
481 static void
482 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
484 Lisp_Object frame;
486 if (f)
488 XSETFRAME (frame, f);
489 kbd_buffer_store_help_event (frame, help);
491 else
493 #if 0 /* This code doesn't do anything useful. ++kfs */
494 /* WIDGET is the popup menu. It's parent is the frame's
495 widget. See which frame that is. */
496 xt_or_gtk_widget frame_widget = XtParent (widget);
497 Lisp_Object tail;
499 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
501 frame = XCAR (tail);
502 if (FRAMEP (frame)
503 && (f = XFRAME (frame),
504 FRAME_X_P (f) && f->output_data.x->widget == frame_widget))
505 break;
507 #endif
508 show_help_echo (help, Qnil, Qnil, Qnil);
512 /* Callback called when menu items are highlighted/unhighlighted
513 while moving the mouse over them. WIDGET is the menu bar or menu
514 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
515 the data structure for the menu item, or null in case of
516 unhighlighting. */
518 #ifdef USE_GTK
519 static void
520 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
522 xg_menu_item_cb_data *cb_data;
523 Lisp_Object help;
525 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
526 if (! cb_data) return;
528 help = call_data ? cb_data->help : Qnil;
530 /* If popup_activated_flag is greater than 1 we are in a popup menu.
531 Don't pass the frame to show_help_event for those.
532 Passing frame creates an Emacs event. As we are looping in
533 popup_widget_loop, it won't be handled. Passing NULL shows the tip
534 directly without using an Emacs event. This is what the Lucid code
535 does below. */
536 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
537 widget, help);
539 #else
540 static void
541 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
543 widget_value *wv = call_data;
544 Lisp_Object help = wv ? wv->help : Qnil;
546 /* Determine the frame for the help event. */
547 struct frame *f = menubar_id_to_frame (id);
549 show_help_event (f, widget, help);
551 #endif
553 #ifdef USE_GTK
554 /* Gtk calls callbacks just because we tell it what item should be
555 selected in a radio group. If this variable is set to a non-zero
556 value, we are creating menus and don't want callbacks right now.
558 static int xg_crazy_callback_abort;
560 /* This callback is called from the menu bar pulldown menu
561 when the user makes a selection.
562 Figure out what the user chose
563 and put the appropriate events into the keyboard buffer. */
564 static void
565 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
567 xg_menu_item_cb_data *cb_data = client_data;
569 if (xg_crazy_callback_abort)
570 return;
572 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
573 return;
575 /* For a group of radio buttons, GTK calls the selection callback first
576 for the item that was active before the selection and then for the one that
577 is active after the selection. For C-h k this means we get the help on
578 the deselected item and then the selected item is executed. Prevent that
579 by ignoring the non-active item. */
580 if (GTK_IS_RADIO_MENU_ITEM (widget)
581 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
582 return;
584 /* When a menu is popped down, X generates a focus event (i.e. focus
585 goes back to the frame below the menu). Since GTK buffers events,
586 we force it out here before the menu selection event. Otherwise
587 sit-for will exit at once if the focus event follows the menu selection
588 event. */
590 block_input ();
591 while (gtk_events_pending ())
592 gtk_main_iteration ();
593 unblock_input ();
595 find_and_call_menu_selection (cb_data->cl_data->f,
596 cb_data->cl_data->menu_bar_items_used,
597 cb_data->cl_data->menu_bar_vector,
598 cb_data->call_data);
601 #else /* not USE_GTK */
603 /* This callback is called from the menu bar pulldown menu
604 when the user makes a selection.
605 Figure out what the user chose
606 and put the appropriate events into the keyboard buffer. */
607 static void
608 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
610 struct frame *f;
612 f = menubar_id_to_frame (id);
613 if (!f)
614 return;
615 find_and_call_menu_selection (f, f->menu_bar_items_used,
616 f->menu_bar_vector, client_data);
618 #endif /* not USE_GTK */
620 /* Recompute all the widgets of frame F, when the menu bar has been
621 changed. */
623 static void
624 update_frame_menubar (struct frame *f)
626 #ifdef USE_GTK
627 xg_update_frame_menubar (f);
628 #else
629 struct x_output *x;
630 /** int columns, rows; **/
632 eassert (FRAME_X_P (f));
634 x = f->output_data.x;
636 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
637 return;
639 block_input ();
640 /* Save the size of the frame because the pane widget doesn't accept
641 to resize itself. So force it. */
642 /** columns = FRAME_COLS (f); **/
643 /** rows = FRAME_LINES (f); **/
645 /* Do the voodoo which means "I'm changing lots of things, don't try
646 to refigure sizes until I'm done." */
647 lw_refigure_widget (x->column_widget, False);
649 /* The order in which children are managed is the top to bottom
650 order in which they are displayed in the paned window. First,
651 remove the text-area widget. */
652 XtUnmanageChild (x->edit_widget);
654 /* Remove the menubar that is there now, and put up the menubar that
655 should be there. */
656 XtManageChild (x->menubar_widget);
657 XtMapWidget (x->menubar_widget);
658 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
660 /* Re-manage the text-area widget, and then thrash the sizes. */
661 XtManageChild (x->edit_widget);
662 lw_refigure_widget (x->column_widget, True);
664 /* Force the pane widget to resize itself with the right values. */
665 /** EmacsFrameSetCharSize (x->edit_widget, columns, rows); **/
666 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 2, 0);
667 unblock_input ();
668 #endif
671 #ifdef USE_LUCID
672 static void
673 apply_systemfont_to_dialog (Widget w)
675 const char *fn = xsettings_get_system_normal_font ();
676 if (fn)
678 XrmDatabase db = XtDatabase (XtDisplay (w));
679 if (db)
680 XrmPutStringResource (&db, "*dialog.font", fn);
684 static void
685 apply_systemfont_to_menu (struct frame *f, Widget w)
687 const char *fn = xsettings_get_system_normal_font ();
689 if (fn)
691 XrmDatabase db = XtDatabase (XtDisplay (w));
692 if (db)
694 XrmPutStringResource (&db, "*menubar*font", fn);
695 XrmPutStringResource (&db, "*popup*font", fn);
700 #endif
702 /* Set the contents of the menubar widgets of frame F.
703 The argument FIRST_TIME is currently ignored;
704 it is set the first time this is called, from initialize_frame_menubar. */
706 void
707 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
709 xt_or_gtk_widget menubar_widget, old_widget;
710 #ifdef USE_X_TOOLKIT
711 LWLIB_ID id;
712 #endif
713 Lisp_Object items;
714 widget_value *wv, *first_wv, *prev_wv = 0;
715 int i;
716 int *submenu_start, *submenu_end;
717 bool *submenu_top_level_items;
718 int *submenu_n_panes;
720 eassert (FRAME_X_P (f));
722 menubar_widget = old_widget = f->output_data.x->menubar_widget;
724 XSETFRAME (Vmenu_updating_frame, f);
726 #ifdef USE_X_TOOLKIT
727 if (f->output_data.x->id == 0)
728 f->output_data.x->id = next_menubar_widget_id++;
729 id = f->output_data.x->id;
730 #endif
732 if (! menubar_widget)
733 deep_p = 1;
734 /* Make the first call for any given frame always go deep. */
735 else if (!f->output_data.x->saved_menu_event && !deep_p)
737 deep_p = 1;
738 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
739 f->output_data.x->saved_menu_event->type = 0;
742 #ifdef USE_GTK
743 /* If we have detached menus, we must update deep so detached menus
744 also gets updated. */
745 deep_p = deep_p || xg_have_tear_offs (f);
746 #endif
748 if (deep_p)
750 /* Make a widget-value tree representing the entire menu trees. */
752 struct buffer *prev = current_buffer;
753 Lisp_Object buffer;
754 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
755 int previous_menu_items_used = f->menu_bar_items_used;
756 Lisp_Object *previous_items
757 = alloca (previous_menu_items_used * sizeof *previous_items);
758 int subitems;
760 /* If we are making a new widget, its contents are empty,
761 do always reinitialize them. */
762 if (! menubar_widget)
763 previous_menu_items_used = 0;
765 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
766 specbind (Qinhibit_quit, Qt);
767 /* Don't let the debugger step into this code
768 because it is not reentrant. */
769 specbind (Qdebug_on_next_call, Qnil);
771 record_unwind_save_match_data ();
772 if (NILP (Voverriding_local_map_menu_flag))
774 specbind (Qoverriding_terminal_local_map, Qnil);
775 specbind (Qoverriding_local_map, Qnil);
778 set_buffer_internal_1 (XBUFFER (buffer));
780 /* Run the Lucid hook. */
781 safe_run_hooks (Qactivate_menubar_hook);
783 /* If it has changed current-menubar from previous value,
784 really recompute the menubar from the value. */
785 if (! NILP (Vlucid_menu_bar_dirty_flag))
786 call0 (Qrecompute_lucid_menubar);
787 safe_run_hooks (Qmenu_bar_update_hook);
788 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
790 items = FRAME_MENU_BAR_ITEMS (f);
792 /* Save the frame's previous menu bar contents data. */
793 if (previous_menu_items_used)
794 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
795 previous_menu_items_used * word_size);
797 /* Fill in menu_items with the current menu bar contents.
798 This can evaluate Lisp code. */
799 save_menu_items ();
801 menu_items = f->menu_bar_vector;
802 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
803 subitems = ASIZE (items) / 4;
804 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
805 submenu_end = alloca (subitems * sizeof *submenu_end);
806 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
807 submenu_top_level_items = alloca (subitems
808 * sizeof *submenu_top_level_items);
809 init_menu_items ();
810 for (i = 0; i < subitems; i++)
812 Lisp_Object key, string, maps;
814 key = AREF (items, 4 * i);
815 string = AREF (items, 4 * i + 1);
816 maps = AREF (items, 4 * i + 2);
817 if (NILP (string))
818 break;
820 submenu_start[i] = menu_items_used;
822 menu_items_n_panes = 0;
823 submenu_top_level_items[i]
824 = parse_single_submenu (key, string, maps);
825 submenu_n_panes[i] = menu_items_n_panes;
827 submenu_end[i] = menu_items_used;
830 submenu_start[i] = -1;
831 finish_menu_items ();
833 /* Convert menu_items into widget_value trees
834 to display the menu. This cannot evaluate Lisp code. */
836 wv = make_widget_value ("menubar", NULL, true, Qnil);
837 wv->button_type = BUTTON_TYPE_NONE;
838 first_wv = wv;
840 for (i = 0; submenu_start[i] >= 0; i++)
842 menu_items_n_panes = submenu_n_panes[i];
843 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
844 submenu_top_level_items[i]);
845 if (prev_wv)
846 prev_wv->next = wv;
847 else
848 first_wv->contents = wv;
849 /* Don't set wv->name here; GC during the loop might relocate it. */
850 wv->enabled = 1;
851 wv->button_type = BUTTON_TYPE_NONE;
852 prev_wv = wv;
855 set_buffer_internal_1 (prev);
857 /* If there has been no change in the Lisp-level contents
858 of the menu bar, skip redisplaying it. Just exit. */
860 /* Compare the new menu items with the ones computed last time. */
861 for (i = 0; i < previous_menu_items_used; i++)
862 if (menu_items_used == i
863 || (!EQ (previous_items[i], AREF (menu_items, i))))
864 break;
865 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
867 /* The menu items have not changed. Don't bother updating
868 the menus in any form, since it would be a no-op. */
869 free_menubar_widget_value_tree (first_wv);
870 discard_menu_items ();
871 unbind_to (specpdl_count, Qnil);
872 return;
875 /* The menu items are different, so store them in the frame. */
876 fset_menu_bar_vector (f, menu_items);
877 f->menu_bar_items_used = menu_items_used;
879 /* This undoes save_menu_items. */
880 unbind_to (specpdl_count, Qnil);
882 /* Now GC cannot happen during the lifetime of the widget_value,
883 so it's safe to store data from a Lisp_String. */
884 wv = first_wv->contents;
885 for (i = 0; i < ASIZE (items); i += 4)
887 Lisp_Object string;
888 string = AREF (items, i + 1);
889 if (NILP (string))
890 break;
891 wv->name = SSDATA (string);
892 update_submenu_strings (wv->contents);
893 wv = wv->next;
897 else
899 /* Make a widget-value tree containing
900 just the top level menu bar strings. */
902 wv = make_widget_value ("menubar", NULL, true, Qnil);
903 wv->button_type = BUTTON_TYPE_NONE;
904 first_wv = wv;
906 items = FRAME_MENU_BAR_ITEMS (f);
907 for (i = 0; i < ASIZE (items); i += 4)
909 Lisp_Object string;
911 string = AREF (items, i + 1);
912 if (NILP (string))
913 break;
915 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
916 wv->button_type = BUTTON_TYPE_NONE;
917 /* This prevents lwlib from assuming this
918 menu item is really supposed to be empty. */
919 /* The intptr_t cast avoids a warning.
920 This value just has to be different from small integers. */
921 wv->call_data = (void *) (intptr_t) (-1);
923 if (prev_wv)
924 prev_wv->next = wv;
925 else
926 first_wv->contents = wv;
927 prev_wv = wv;
930 /* Forget what we thought we knew about what is in the
931 detailed contents of the menu bar menus.
932 Changing the top level always destroys the contents. */
933 f->menu_bar_items_used = 0;
936 /* Create or update the menu bar widget. */
938 block_input ();
940 #ifdef USE_GTK
941 xg_crazy_callback_abort = 1;
942 if (menubar_widget)
944 /* The fourth arg is DEEP_P, which says to consider the entire
945 menu trees we supply, rather than just the menu bar item names. */
946 xg_modify_menubar_widgets (menubar_widget,
948 first_wv,
949 deep_p,
950 G_CALLBACK (menubar_selection_callback),
951 G_CALLBACK (popup_deactivate_callback),
952 G_CALLBACK (menu_highlight_callback));
954 else
956 menubar_widget
957 = xg_create_widget ("menubar", "menubar", f, first_wv,
958 G_CALLBACK (menubar_selection_callback),
959 G_CALLBACK (popup_deactivate_callback),
960 G_CALLBACK (menu_highlight_callback));
962 f->output_data.x->menubar_widget = menubar_widget;
966 #else /* not USE_GTK */
967 if (menubar_widget)
969 /* Disable resizing (done for Motif!) */
970 lw_allow_resizing (f->output_data.x->widget, False);
972 /* The third arg is DEEP_P, which says to consider the entire
973 menu trees we supply, rather than just the menu bar item names. */
974 lw_modify_all_widgets (id, first_wv, deep_p);
976 /* Re-enable the edit widget to resize. */
977 lw_allow_resizing (f->output_data.x->widget, True);
979 else
981 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
982 XtTranslations override = XtParseTranslationTable (menuOverride);
984 #ifdef USE_LUCID
985 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
986 #endif
987 menubar_widget = lw_create_widget ("menubar", "menubar", id,
988 first_wv,
989 f->output_data.x->column_widget,
991 popup_activate_callback,
992 menubar_selection_callback,
993 popup_deactivate_callback,
994 menu_highlight_callback);
995 f->output_data.x->menubar_widget = menubar_widget;
997 /* Make menu pop down on C-g. */
998 XtOverrideTranslations (menubar_widget, override);
1002 int menubar_size;
1003 if (f->output_data.x->menubar_widget)
1004 XtRealizeWidget (f->output_data.x->menubar_widget);
1006 menubar_size
1007 = (f->output_data.x->menubar_widget
1008 ? (f->output_data.x->menubar_widget->core.height
1009 + f->output_data.x->menubar_widget->core.border_width)
1010 : 0);
1012 #if 1 /* Experimentally, we now get the right results
1013 for -geometry -0-0 without this. 24 Aug 96, rms.
1014 Maybe so, but the menu bar size is missing the pixels so the
1015 WM size hints are off by these pixels. Jan D, oct 2009. */
1016 #ifdef USE_LUCID
1017 if (FRAME_EXTERNAL_MENU_BAR (f))
1019 Dimension ibw = 0;
1020 XtVaGetValues (f->output_data.x->column_widget,
1021 XtNinternalBorderWidth, &ibw, NULL);
1022 menubar_size += ibw;
1024 #endif /* USE_LUCID */
1025 #endif /* 1 */
1027 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1029 #endif /* not USE_GTK */
1031 free_menubar_widget_value_tree (first_wv);
1032 update_frame_menubar (f);
1034 #ifdef USE_GTK
1035 xg_crazy_callback_abort = 0;
1036 #endif
1038 unblock_input ();
1041 /* Called from Fx_create_frame to create the initial menubar of a frame
1042 before it is mapped, so that the window is mapped with the menubar already
1043 there instead of us tacking it on later and thrashing the window after it
1044 is visible. */
1046 void
1047 initialize_frame_menubar (struct frame *f)
1049 /* This function is called before the first chance to redisplay
1050 the frame. It has to be, so the frame will have the right size. */
1051 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1052 set_frame_menubar (f, 1, 1);
1056 /* Get rid of the menu bar of frame F, and free its storage.
1057 This is used when deleting a frame, and when turning off the menu bar.
1058 For GTK this function is in gtkutil.c. */
1060 #ifndef USE_GTK
1061 void
1062 free_frame_menubar (struct frame *f)
1064 Widget menubar_widget;
1066 eassert (FRAME_X_P (f));
1068 menubar_widget = f->output_data.x->menubar_widget;
1070 FRAME_MENUBAR_HEIGHT (f) = 0;
1072 if (menubar_widget)
1074 #ifdef USE_MOTIF
1075 /* Removing the menu bar magically changes the shell widget's x
1076 and y position of (0, 0) which, when the menu bar is turned
1077 on again, leads to pull-down menus appearing in strange
1078 positions near the upper-left corner of the display. This
1079 happens only with some window managers like twm and ctwm,
1080 but not with other like Motif's mwm or kwm, because the
1081 latter generate ConfigureNotify events when the menu bar
1082 is switched off, which fixes the shell position. */
1083 Position x0, y0, x1, y1;
1084 #endif
1086 block_input ();
1088 #ifdef USE_MOTIF
1089 if (f->output_data.x->widget)
1090 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1091 #endif
1093 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1094 f->output_data.x->menubar_widget = NULL;
1096 if (f->output_data.x->widget)
1098 #ifdef USE_MOTIF
1099 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1100 if (x1 == 0 && y1 == 0)
1101 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1102 #endif
1103 adjust_frame_size (f, FRAME_TEXT_WIDTH (f),
1104 FRAME_TEXT_HEIGHT (f), 2, 0);
1106 if (frame_inhibit_resize (f, 0))
1107 change_frame_size (f, 0, 0, 0, 0, 0, 1);
1108 else
1109 x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f),
1110 FRAME_TEXT_HEIGHT (f), 1);
1113 unblock_input ();
1116 #endif /* not USE_GTK */
1118 #endif /* USE_X_TOOLKIT || USE_GTK */
1120 /* x_menu_show actually displays a menu using the panes and items in menu_items
1121 and returns the value selected from it.
1122 There are two versions of x_menu_show, one for Xt and one for Xlib.
1123 Both assume input is blocked by the caller. */
1125 /* F is the frame the menu is for.
1126 X and Y are the frame-relative specified position,
1127 relative to the inside upper left corner of the frame F.
1128 Bitfield MENUFLAGS bits are:
1129 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1130 MENU_KEYMAPS is set if this menu was specified with keymaps;
1131 in that case, we return a list containing the chosen item's value
1132 and perhaps also the pane's prefix.
1133 TITLE is the specified menu title.
1134 ERROR is a place to store an error message string in case of failure.
1135 (We return nil on failure, but the value doesn't actually matter.) */
1137 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1139 /* The item selected in the popup menu. */
1140 static Lisp_Object *volatile menu_item_selection;
1142 #ifdef USE_GTK
1144 /* Used when position a popup menu. See menu_position_func and
1145 create_and_show_popup_menu below. */
1146 struct next_popup_x_y
1148 struct frame *f;
1149 int x;
1150 int y;
1153 /* The menu position function to use if we are not putting a popup
1154 menu where the pointer is.
1155 MENU is the menu to pop up.
1156 X and Y shall on exit contain x/y where the menu shall pop up.
1157 PUSH_IN is not documented in the GTK manual.
1158 USER_DATA is any data passed in when calling gtk_menu_popup.
1159 Here it points to a struct next_popup_x_y where the coordinates
1160 to store in *X and *Y are as well as the frame for the popup.
1162 Here only X and Y are used. */
1163 static void
1164 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1166 struct next_popup_x_y *data = user_data;
1167 GtkRequisition req;
1168 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1169 int disp_width = x_display_pixel_width (dpyinfo);
1170 int disp_height = x_display_pixel_height (dpyinfo);
1172 *x = data->x;
1173 *y = data->y;
1175 /* Check if there is room for the menu. If not, adjust x/y so that
1176 the menu is fully visible. */
1177 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1178 if (data->x + req.width > disp_width)
1179 *x -= data->x + req.width - disp_width;
1180 if (data->y + req.height > disp_height)
1181 *y -= data->y + req.height - disp_height;
1184 static void
1185 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1187 xg_menu_item_cb_data *cb_data = client_data;
1189 if (xg_crazy_callback_abort) return;
1190 if (cb_data) menu_item_selection = cb_data->call_data;
1193 static void
1194 pop_down_menu (void *arg)
1196 popup_activated_flag = 0;
1197 block_input ();
1198 gtk_widget_destroy (GTK_WIDGET (arg));
1199 unblock_input ();
1202 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1203 menu pops down.
1204 menu_item_selection will be set to the selection. */
1205 static void
1206 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1207 int x, int y, bool for_click)
1209 int i;
1210 GtkWidget *menu;
1211 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1212 struct next_popup_x_y popup_x_y;
1213 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1214 bool use_pos_func = ! for_click;
1216 #ifdef HAVE_GTK3
1217 /* Always use position function for Gtk3. Otherwise menus may become
1218 too small to show anything. */
1219 use_pos_func = 1;
1220 #endif
1222 eassert (FRAME_X_P (f));
1224 xg_crazy_callback_abort = 1;
1225 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1226 G_CALLBACK (popup_selection_callback),
1227 G_CALLBACK (popup_deactivate_callback),
1228 G_CALLBACK (menu_highlight_callback));
1229 xg_crazy_callback_abort = 0;
1231 if (use_pos_func)
1233 /* Not invoked by a click. pop up at x/y. */
1234 pos_func = menu_position_func;
1236 /* Adjust coordinates to be root-window-relative. */
1237 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1238 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1240 popup_x_y.x = x;
1241 popup_x_y.y = y;
1242 popup_x_y.f = f;
1244 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1247 if (for_click)
1249 for (i = 0; i < 5; i++)
1250 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1251 break;
1252 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1253 if (i == 5) i = 0;
1256 /* Display the menu. */
1257 gtk_widget_show_all (menu);
1259 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1260 FRAME_DISPLAY_INFO (f)->last_user_time);
1262 record_unwind_protect_ptr (pop_down_menu, menu);
1264 if (gtk_widget_get_mapped (menu))
1266 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1267 two. show_help_echo uses this to detect popup menus. */
1268 popup_activated_flag = 1;
1269 /* Process events that apply to the menu. */
1270 popup_widget_loop (1, menu);
1273 unbind_to (specpdl_count, Qnil);
1275 /* Must reset this manually because the button release event is not passed
1276 to Emacs event loop. */
1277 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1280 #else /* not USE_GTK */
1282 /* We need a unique id for each widget handled by the Lucid Widget
1283 library.
1285 For the main windows, and popup menus, we use this counter, which we
1286 increment each time after use. This starts from WIDGET_ID_TICK_START.
1288 For menu bars, we use numbers starting at 0, counted in
1289 next_menubar_widget_id. */
1290 LWLIB_ID widget_id_tick;
1292 static void
1293 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1295 menu_item_selection = client_data;
1298 /* ID is the LWLIB ID of the dialog box. */
1300 static void
1301 pop_down_menu (int id)
1303 block_input ();
1304 lw_destroy_all_widgets ((LWLIB_ID) id);
1305 unblock_input ();
1306 popup_activated_flag = 0;
1309 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1310 menu pops down.
1311 menu_item_selection will be set to the selection. */
1312 static void
1313 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1314 int x, int y, bool for_click)
1316 int i;
1317 Arg av[2];
1318 int ac = 0;
1319 XEvent dummy;
1320 XButtonPressedEvent *event = &(dummy.xbutton);
1321 LWLIB_ID menu_id;
1322 Widget menu;
1324 eassert (FRAME_X_P (f));
1326 #ifdef USE_LUCID
1327 apply_systemfont_to_menu (f, f->output_data.x->widget);
1328 #endif
1330 menu_id = widget_id_tick++;
1331 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1332 f->output_data.x->widget, 1, 0,
1333 popup_selection_callback,
1334 popup_deactivate_callback,
1335 menu_highlight_callback);
1337 event->type = ButtonPress;
1338 event->serial = 0;
1339 event->send_event = 0;
1340 event->display = FRAME_X_DISPLAY (f);
1341 event->time = CurrentTime;
1342 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1343 event->window = event->subwindow = event->root;
1344 event->x = x;
1345 event->y = y;
1347 /* Adjust coordinates to be root-window-relative. */
1348 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1349 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1351 event->x_root = x;
1352 event->y_root = y;
1354 event->state = 0;
1355 event->button = 0;
1356 for (i = 0; i < 5; i++)
1357 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1358 event->button = i;
1360 /* Don't allow any geometry request from the user. */
1361 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1362 XtSetValues (menu, av, ac);
1364 /* Display the menu. */
1365 lw_popup_menu (menu, &dummy);
1366 popup_activated_flag = 1;
1367 x_activate_timeout_atimer ();
1370 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1372 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1374 /* Process events that apply to the menu. */
1375 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
1377 unbind_to (specpdl_count, Qnil);
1381 #endif /* not USE_GTK */
1383 static void
1384 cleanup_widget_value_tree (void *arg)
1386 free_menubar_widget_value_tree (arg);
1389 Lisp_Object
1390 x_menu_show (struct frame *f, int x, int y, int menuflags,
1391 Lisp_Object title, const char **error_name)
1393 int i;
1394 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1395 widget_value **submenu_stack
1396 = alloca (menu_items_used * sizeof *submenu_stack);
1397 Lisp_Object *subprefix_stack
1398 = alloca (menu_items_used * sizeof *subprefix_stack);
1399 int submenu_depth = 0;
1401 int first_pane;
1403 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1405 eassert (FRAME_X_P (f));
1407 *error_name = NULL;
1409 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1411 *error_name = "Empty menu";
1412 return Qnil;
1415 block_input ();
1417 /* Create a tree of widget_value objects
1418 representing the panes and their items. */
1419 wv = make_widget_value ("menu", NULL, true, Qnil);
1420 wv->button_type = BUTTON_TYPE_NONE;
1421 first_wv = wv;
1422 first_pane = 1;
1424 /* Loop over all panes and items, filling in the tree. */
1425 i = 0;
1426 while (i < menu_items_used)
1428 if (EQ (AREF (menu_items, i), Qnil))
1430 submenu_stack[submenu_depth++] = save_wv;
1431 save_wv = prev_wv;
1432 prev_wv = 0;
1433 first_pane = 1;
1434 i++;
1436 else if (EQ (AREF (menu_items, i), Qlambda))
1438 prev_wv = save_wv;
1439 save_wv = submenu_stack[--submenu_depth];
1440 first_pane = 0;
1441 i++;
1443 else if (EQ (AREF (menu_items, i), Qt)
1444 && submenu_depth != 0)
1445 i += MENU_ITEMS_PANE_LENGTH;
1446 /* Ignore a nil in the item list.
1447 It's meaningful only for dialog boxes. */
1448 else if (EQ (AREF (menu_items, i), Qquote))
1449 i += 1;
1450 else if (EQ (AREF (menu_items, i), Qt))
1452 /* Create a new pane. */
1453 Lisp_Object pane_name, prefix;
1454 const char *pane_string;
1456 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1457 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1459 #ifndef HAVE_MULTILINGUAL_MENU
1460 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1462 pane_name = ENCODE_MENU_STRING (pane_name);
1463 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1465 #endif
1466 pane_string = (NILP (pane_name)
1467 ? "" : SSDATA (pane_name));
1468 /* If there is just one top-level pane, put all its items directly
1469 under the top-level menu. */
1470 if (menu_items_n_panes == 1)
1471 pane_string = "";
1473 /* If the pane has a meaningful name,
1474 make the pane a top-level menu item
1475 with its items as a submenu beneath it. */
1476 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1478 wv = make_widget_value (pane_string, NULL, true, Qnil);
1479 if (save_wv)
1480 save_wv->next = wv;
1481 else
1482 first_wv->contents = wv;
1483 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1484 wv->name++;
1485 wv->button_type = BUTTON_TYPE_NONE;
1486 save_wv = wv;
1487 prev_wv = 0;
1489 else if (first_pane)
1491 save_wv = wv;
1492 prev_wv = 0;
1494 first_pane = 0;
1495 i += MENU_ITEMS_PANE_LENGTH;
1497 else
1499 /* Create a new item within current pane. */
1500 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1501 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1502 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1503 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1504 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1505 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1506 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1507 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1509 #ifndef HAVE_MULTILINGUAL_MENU
1510 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1512 item_name = ENCODE_MENU_STRING (item_name);
1513 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1516 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1518 descrip = ENCODE_MENU_STRING (descrip);
1519 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1521 #endif /* not HAVE_MULTILINGUAL_MENU */
1523 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1524 STRINGP (help) ? help : Qnil);
1525 if (prev_wv)
1526 prev_wv->next = wv;
1527 else
1528 save_wv->contents = wv;
1529 if (!NILP (descrip))
1530 wv->key = SSDATA (descrip);
1531 /* If this item has a null value,
1532 make the call_data null so that it won't display a box
1533 when the mouse is on it. */
1534 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1536 if (NILP (type))
1537 wv->button_type = BUTTON_TYPE_NONE;
1538 else if (EQ (type, QCtoggle))
1539 wv->button_type = BUTTON_TYPE_TOGGLE;
1540 else if (EQ (type, QCradio))
1541 wv->button_type = BUTTON_TYPE_RADIO;
1542 else
1543 emacs_abort ();
1545 wv->selected = !NILP (selected);
1547 prev_wv = wv;
1549 i += MENU_ITEMS_ITEM_LENGTH;
1553 /* Deal with the title, if it is non-nil. */
1554 if (!NILP (title))
1556 widget_value *wv_title;
1557 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1558 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1560 wv_sep2->next = first_wv->contents;
1561 wv_sep1->next = wv_sep2;
1563 #ifndef HAVE_MULTILINGUAL_MENU
1564 if (STRING_MULTIBYTE (title))
1565 title = ENCODE_MENU_STRING (title);
1566 #endif
1568 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1569 wv_title->button_type = BUTTON_TYPE_NONE;
1570 wv_title->next = wv_sep1;
1571 first_wv->contents = wv_title;
1574 /* No selection has been chosen yet. */
1575 menu_item_selection = 0;
1577 /* Make sure to free the widget_value objects we used to specify the
1578 contents even with longjmp. */
1579 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1581 /* Actually create and show the menu until popped down. */
1582 create_and_show_popup_menu (f, first_wv, x, y,
1583 menuflags & MENU_FOR_CLICK);
1585 unbind_to (specpdl_count, Qnil);
1587 /* Find the selected item, and its pane, to return
1588 the proper value. */
1589 if (menu_item_selection != 0)
1591 Lisp_Object prefix, entry;
1593 prefix = entry = Qnil;
1594 i = 0;
1595 while (i < menu_items_used)
1597 if (EQ (AREF (menu_items, i), Qnil))
1599 subprefix_stack[submenu_depth++] = prefix;
1600 prefix = entry;
1601 i++;
1603 else if (EQ (AREF (menu_items, i), Qlambda))
1605 prefix = subprefix_stack[--submenu_depth];
1606 i++;
1608 else if (EQ (AREF (menu_items, i), Qt))
1610 prefix
1611 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1612 i += MENU_ITEMS_PANE_LENGTH;
1614 /* Ignore a nil in the item list.
1615 It's meaningful only for dialog boxes. */
1616 else if (EQ (AREF (menu_items, i), Qquote))
1617 i += 1;
1618 else
1620 entry
1621 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1622 if (menu_item_selection == aref_addr (menu_items, i))
1624 if (menuflags & MENU_KEYMAPS)
1626 int j;
1628 entry = list1 (entry);
1629 if (!NILP (prefix))
1630 entry = Fcons (prefix, entry);
1631 for (j = submenu_depth - 1; j >= 0; j--)
1632 if (!NILP (subprefix_stack[j]))
1633 entry = Fcons (subprefix_stack[j], entry);
1635 unblock_input ();
1636 return entry;
1638 i += MENU_ITEMS_ITEM_LENGTH;
1642 else if (!(menuflags & MENU_FOR_CLICK))
1644 unblock_input ();
1645 /* Make "Cancel" equivalent to C-g. */
1646 Fsignal (Qquit, Qnil);
1649 unblock_input ();
1650 return Qnil;
1653 #ifdef USE_GTK
1654 static void
1655 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1657 /* Treat the pointer as an integer. There's no problem
1658 as long as pointers have enough bits to hold small integers. */
1659 if ((intptr_t) client_data != -1)
1660 menu_item_selection = client_data;
1662 popup_activated_flag = 0;
1665 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1666 dialog pops down.
1667 menu_item_selection will be set to the selection. */
1668 static void
1669 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1671 GtkWidget *menu;
1673 eassert (FRAME_X_P (f));
1675 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1676 G_CALLBACK (dialog_selection_callback),
1677 G_CALLBACK (popup_deactivate_callback),
1680 if (menu)
1682 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1683 record_unwind_protect_ptr (pop_down_menu, menu);
1685 /* Display the menu. */
1686 gtk_widget_show_all (menu);
1688 /* Process events that apply to the menu. */
1689 popup_widget_loop (1, menu);
1691 unbind_to (specpdl_count, Qnil);
1695 #else /* not USE_GTK */
1696 static void
1697 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1699 /* Treat the pointer as an integer. There's no problem
1700 as long as pointers have enough bits to hold small integers. */
1701 if ((intptr_t) client_data != -1)
1702 menu_item_selection = client_data;
1704 block_input ();
1705 lw_destroy_all_widgets (id);
1706 unblock_input ();
1707 popup_activated_flag = 0;
1711 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1712 dialog pops down.
1713 menu_item_selection will be set to the selection. */
1714 static void
1715 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1717 LWLIB_ID dialog_id;
1719 eassert (FRAME_X_P (f));
1721 dialog_id = widget_id_tick++;
1722 #ifdef USE_LUCID
1723 apply_systemfont_to_dialog (f->output_data.x->widget);
1724 #endif
1725 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1726 f->output_data.x->widget, 1, 0,
1727 dialog_selection_callback, 0, 0);
1728 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1729 /* Display the dialog box. */
1730 lw_pop_up_all_widgets (dialog_id);
1731 popup_activated_flag = 1;
1732 x_activate_timeout_atimer ();
1734 /* Process events that apply to the dialog box.
1735 Also handle timers. */
1737 ptrdiff_t count = SPECPDL_INDEX ();
1739 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1741 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1743 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
1745 unbind_to (count, Qnil);
1749 #endif /* not USE_GTK */
1751 static const char * button_names [] = {
1752 "button1", "button2", "button3", "button4", "button5",
1753 "button6", "button7", "button8", "button9", "button10" };
1755 static Lisp_Object
1756 x_dialog_show (struct frame *f, Lisp_Object title,
1757 Lisp_Object header, const char **error_name)
1759 int i, nb_buttons=0;
1760 char dialog_name[6];
1762 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1764 /* Number of elements seen so far, before boundary. */
1765 int left_count = 0;
1766 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1767 int boundary_seen = 0;
1769 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1771 eassert (FRAME_X_P (f));
1773 *error_name = NULL;
1775 if (menu_items_n_panes > 1)
1777 *error_name = "Multiple panes in dialog box";
1778 return Qnil;
1781 /* Create a tree of widget_value objects
1782 representing the text label and buttons. */
1784 Lisp_Object pane_name;
1785 const char *pane_string;
1786 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1787 pane_string = (NILP (pane_name)
1788 ? "" : SSDATA (pane_name));
1789 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1790 first_wv = prev_wv;
1792 /* Loop over all panes and items, filling in the tree. */
1793 i = MENU_ITEMS_PANE_LENGTH;
1794 while (i < menu_items_used)
1797 /* Create a new item within current pane. */
1798 Lisp_Object item_name, enable, descrip;
1799 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1800 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1801 descrip
1802 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1804 if (NILP (item_name))
1806 free_menubar_widget_value_tree (first_wv);
1807 *error_name = "Submenu in dialog items";
1808 return Qnil;
1810 if (EQ (item_name, Qquote))
1812 /* This is the boundary between left-side elts
1813 and right-side elts. Stop incrementing right_count. */
1814 boundary_seen = 1;
1815 i++;
1816 continue;
1818 if (nb_buttons >= 9)
1820 free_menubar_widget_value_tree (first_wv);
1821 *error_name = "Too many dialog items";
1822 return Qnil;
1825 wv = make_widget_value (button_names[nb_buttons],
1826 SSDATA (item_name),
1827 !NILP (enable), Qnil);
1828 prev_wv->next = wv;
1829 if (!NILP (descrip))
1830 wv->key = SSDATA (descrip);
1831 wv->call_data = aref_addr (menu_items, i);
1832 prev_wv = wv;
1834 if (! boundary_seen)
1835 left_count++;
1837 nb_buttons++;
1838 i += MENU_ITEMS_ITEM_LENGTH;
1841 /* If the boundary was not specified,
1842 by default put half on the left and half on the right. */
1843 if (! boundary_seen)
1844 left_count = nb_buttons - nb_buttons / 2;
1846 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1848 /* Frame title: 'Q' = Question, 'I' = Information.
1849 Can also have 'E' = Error if, one day, we want
1850 a popup for errors. */
1851 if (NILP (header))
1852 dialog_name[0] = 'Q';
1853 else
1854 dialog_name[0] = 'I';
1856 /* Dialog boxes use a really stupid name encoding
1857 which specifies how many buttons to use
1858 and how many buttons are on the right. */
1859 dialog_name[1] = '0' + nb_buttons;
1860 dialog_name[2] = 'B';
1861 dialog_name[3] = 'R';
1862 /* Number of buttons to put on the right. */
1863 dialog_name[4] = '0' + nb_buttons - left_count;
1864 dialog_name[5] = 0;
1865 wv->contents = first_wv;
1866 first_wv = wv;
1869 /* No selection has been chosen yet. */
1870 menu_item_selection = 0;
1872 /* Make sure to free the widget_value objects we used to specify the
1873 contents even with longjmp. */
1874 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1876 /* Actually create and show the dialog. */
1877 create_and_show_dialog (f, first_wv);
1879 unbind_to (specpdl_count, Qnil);
1881 /* Find the selected item, and its pane, to return
1882 the proper value. */
1883 if (menu_item_selection != 0)
1885 i = 0;
1886 while (i < menu_items_used)
1888 Lisp_Object entry;
1890 if (EQ (AREF (menu_items, i), Qt))
1891 i += MENU_ITEMS_PANE_LENGTH;
1892 else if (EQ (AREF (menu_items, i), Qquote))
1894 /* This is the boundary between left-side elts and
1895 right-side elts. */
1896 ++i;
1898 else
1900 entry
1901 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1902 if (menu_item_selection == aref_addr (menu_items, i))
1903 return entry;
1904 i += MENU_ITEMS_ITEM_LENGTH;
1908 else
1909 /* Make "Cancel" equivalent to C-g. */
1910 Fsignal (Qquit, Qnil);
1912 return Qnil;
1915 Lisp_Object
1916 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1918 Lisp_Object title;
1919 const char *error_name;
1920 Lisp_Object selection;
1921 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1923 check_window_system (f);
1925 /* Decode the dialog items from what was specified. */
1926 title = Fcar (contents);
1927 CHECK_STRING (title);
1928 record_unwind_protect_void (unuse_menu_items);
1930 if (NILP (Fcar (Fcdr (contents))))
1931 /* No buttons specified, add an "Ok" button so users can pop down
1932 the dialog. Also, the lesstif/motif version crashes if there are
1933 no buttons. */
1934 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1936 list_of_panes (list1 (contents));
1938 /* Display them in a dialog box. */
1939 block_input ();
1940 selection = x_dialog_show (f, title, header, &error_name);
1941 unblock_input ();
1943 unbind_to (specpdl_count, Qnil);
1944 discard_menu_items ();
1946 if (error_name) error ("%s", error_name);
1947 return selection;
1950 #else /* not USE_X_TOOLKIT && not USE_GTK */
1952 /* The frame of the last activated non-toolkit menu bar.
1953 Used to generate menu help events. */
1955 static struct frame *menu_help_frame;
1958 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1960 PANE is the pane number, and ITEM is the menu item number in
1961 the menu (currently not used).
1963 This cannot be done with generating a HELP_EVENT because
1964 XMenuActivate contains a loop that doesn't let Emacs process
1965 keyboard events. */
1967 static void
1968 menu_help_callback (char const *help_string, int pane, int item)
1970 Lisp_Object *first_item;
1971 Lisp_Object pane_name;
1972 Lisp_Object menu_object;
1974 first_item = XVECTOR (menu_items)->contents;
1975 if (EQ (first_item[0], Qt))
1976 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1977 else if (EQ (first_item[0], Qquote))
1978 /* This shouldn't happen, see x_menu_show. */
1979 pane_name = empty_unibyte_string;
1980 else
1981 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1983 /* (menu-item MENU-NAME PANE-NUMBER) */
1984 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1985 show_help_echo (help_string ? build_string (help_string) : Qnil,
1986 Qnil, menu_object, make_number (item));
1989 static void
1990 pop_down_menu (Lisp_Object arg)
1992 struct frame *f = XSAVE_POINTER (arg, 0);
1993 XMenu *menu = XSAVE_POINTER (arg, 1);
1995 block_input ();
1996 #ifndef MSDOS
1997 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
1998 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
1999 #endif
2000 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2002 #ifdef HAVE_X_WINDOWS
2003 /* Assume the mouse has moved out of the X window.
2004 If it has actually moved in, we will get an EnterNotify. */
2005 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2007 /* State that no mouse buttons are now held.
2008 (The oldXMenu code doesn't track this info for us.)
2009 That is not necessarily true, but the fiction leads to reasonable
2010 results, and it is a pain to ask which are actually held now. */
2011 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2013 #endif /* HAVE_X_WINDOWS */
2015 unblock_input ();
2019 Lisp_Object
2020 x_menu_show (struct frame *f, int x, int y, int menuflags,
2021 Lisp_Object title, const char **error_name)
2023 Window root;
2024 XMenu *menu;
2025 int pane, selidx, lpane, status;
2026 Lisp_Object entry, pane_prefix;
2027 char *datap;
2028 int ulx, uly, width, height;
2029 int dispwidth, dispheight;
2030 int i, j, lines, maxlines;
2031 int maxwidth;
2032 int dummy_int;
2033 unsigned int dummy_uint;
2034 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2036 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2038 *error_name = 0;
2039 if (menu_items_n_panes == 0)
2040 return Qnil;
2042 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2044 *error_name = "Empty menu";
2045 return Qnil;
2048 block_input ();
2050 /* Figure out which root window F is on. */
2051 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2052 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2053 &dummy_uint, &dummy_uint);
2055 /* Make the menu on that window. */
2056 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2057 if (menu == NULL)
2059 *error_name = "Can't create menu";
2060 unblock_input ();
2061 return Qnil;
2064 /* Don't GC while we prepare and show the menu,
2065 because we give the oldxmenu library pointers to the
2066 contents of strings. */
2067 inhibit_garbage_collection ();
2069 #ifdef HAVE_X_WINDOWS
2070 /* Adjust coordinates to relative to the outer (window manager) window. */
2071 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2072 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2073 #endif /* HAVE_X_WINDOWS */
2075 /* Adjust coordinates to be root-window-relative. */
2076 x += f->left_pos;
2077 y += f->top_pos;
2079 /* Create all the necessary panes and their items. */
2080 maxwidth = maxlines = lines = i = 0;
2081 lpane = XM_FAILURE;
2082 while (i < menu_items_used)
2084 if (EQ (AREF (menu_items, i), Qt))
2086 /* Create a new pane. */
2087 Lisp_Object pane_name, prefix;
2088 const char *pane_string;
2090 maxlines = max (maxlines, lines);
2091 lines = 0;
2092 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2093 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2094 pane_string = (NILP (pane_name)
2095 ? "" : SSDATA (pane_name));
2096 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2097 pane_string++;
2099 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2100 if (lpane == XM_FAILURE)
2102 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2103 *error_name = "Can't create pane";
2104 unblock_input ();
2105 return Qnil;
2107 i += MENU_ITEMS_PANE_LENGTH;
2109 /* Find the width of the widest item in this pane. */
2110 j = i;
2111 while (j < menu_items_used)
2113 Lisp_Object item;
2114 item = AREF (menu_items, j);
2115 if (EQ (item, Qt))
2116 break;
2117 if (NILP (item))
2119 j++;
2120 continue;
2122 width = SBYTES (item);
2123 if (width > maxwidth)
2124 maxwidth = width;
2126 j += MENU_ITEMS_ITEM_LENGTH;
2129 /* Ignore a nil in the item list.
2130 It's meaningful only for dialog boxes. */
2131 else if (EQ (AREF (menu_items, i), Qquote))
2132 i += 1;
2133 else
2135 /* Create a new item within current pane. */
2136 Lisp_Object item_name, enable, descrip, help;
2137 char *item_data;
2138 char const *help_string;
2140 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2141 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2142 descrip
2143 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2144 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2145 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2147 if (!NILP (descrip))
2149 /* if alloca is fast, use that to make the space,
2150 to reduce gc needs. */
2151 item_data = alloca (maxwidth + SBYTES (descrip) + 1);
2152 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2153 for (j = SCHARS (item_name); j < maxwidth; j++)
2154 item_data[j] = ' ';
2155 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2156 item_data[j + SBYTES (descrip)] = 0;
2158 else
2159 item_data = SSDATA (item_name);
2161 if (lpane == XM_FAILURE
2162 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2163 menu, lpane, 0, item_data,
2164 !NILP (enable), help_string)
2165 == XM_FAILURE))
2167 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2168 *error_name = "Can't add selection to menu";
2169 unblock_input ();
2170 return Qnil;
2172 i += MENU_ITEMS_ITEM_LENGTH;
2173 lines++;
2177 maxlines = max (maxlines, lines);
2179 /* All set and ready to fly. */
2180 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2181 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2182 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2183 x = min (x, dispwidth);
2184 y = min (y, dispheight);
2185 x = max (x, 1);
2186 y = max (y, 1);
2187 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2188 &ulx, &uly, &width, &height);
2189 if (ulx+width > dispwidth)
2191 x -= (ulx + width) - dispwidth;
2192 ulx = dispwidth - width;
2194 if (uly+height > dispheight)
2196 y -= (uly + height) - dispheight;
2197 uly = dispheight - height;
2199 #ifndef HAVE_X_WINDOWS
2200 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2202 /* Move the menu away of the echo area, to avoid overwriting the
2203 menu with help echo messages or vice versa. */
2204 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2206 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2207 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2209 else
2211 y--;
2212 uly--;
2215 #endif
2216 if (ulx < 0) x -= ulx;
2217 if (uly < 0) y -= uly;
2219 if (!(menuflags & MENU_FOR_CLICK))
2221 /* If position was not given by a mouse click, adjust so upper left
2222 corner of the menu as a whole ends up at given coordinates. This
2223 is what x-popup-menu says in its documentation. */
2224 x += width/2;
2225 y += 1.5*height/(maxlines+2);
2228 XMenuSetAEQ (menu, TRUE);
2229 XMenuSetFreeze (menu, TRUE);
2230 pane = selidx = 0;
2232 #ifndef MSDOS
2233 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2234 #endif
2236 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2238 /* Help display under X won't work because XMenuActivate contains
2239 a loop that doesn't give Emacs a chance to process it. */
2240 menu_help_frame = f;
2241 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2242 x, y, ButtonReleaseMask, &datap,
2243 menu_help_callback);
2244 entry = pane_prefix = Qnil;
2246 switch (status)
2248 case XM_SUCCESS:
2249 #ifdef XDEBUG
2250 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2251 #endif
2253 /* Find the item number SELIDX in pane number PANE. */
2254 i = 0;
2255 while (i < menu_items_used)
2257 if (EQ (AREF (menu_items, i), Qt))
2259 if (pane == 0)
2260 pane_prefix
2261 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2262 pane--;
2263 i += MENU_ITEMS_PANE_LENGTH;
2265 else
2267 if (pane == -1)
2269 if (selidx == 0)
2271 entry
2272 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2273 if (menuflags & MENU_KEYMAPS)
2275 entry = list1 (entry);
2276 if (!NILP (pane_prefix))
2277 entry = Fcons (pane_prefix, entry);
2279 break;
2281 selidx--;
2283 i += MENU_ITEMS_ITEM_LENGTH;
2286 break;
2288 case XM_FAILURE:
2289 *error_name = "Can't activate menu";
2290 case XM_IA_SELECT:
2291 break;
2292 case XM_NO_SELECT:
2293 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2294 the menu was invoked with a mouse event as POSITION). */
2295 if (!(menuflags & MENU_FOR_CLICK))
2297 unblock_input ();
2298 Fsignal (Qquit, Qnil);
2300 break;
2303 unblock_input ();
2304 unbind_to (specpdl_count, Qnil);
2306 return entry;
2309 #endif /* not USE_X_TOOLKIT */
2311 #ifndef MSDOS
2312 /* Detect if a dialog or menu has been posted. MSDOS has its own
2313 implementation on msdos.c. */
2315 int ATTRIBUTE_CONST
2316 popup_activated (void)
2318 return popup_activated_flag;
2320 #endif /* not MSDOS */
2322 /* The following is used by delayed window autoselection. */
2324 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2325 doc: /* Return t if a menu or popup dialog is active. */)
2326 (void)
2328 return (popup_activated ()) ? Qt : Qnil;
2331 void
2332 syms_of_xmenu (void)
2334 #ifdef USE_X_TOOLKIT
2335 enum { WIDGET_ID_TICK_START = 1 << 16 };
2336 widget_id_tick = WIDGET_ID_TICK_START;
2337 next_menubar_widget_id = 1;
2338 #endif
2340 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2341 defsubr (&Smenu_or_popup_active_p);
2343 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2344 defsubr (&Sx_menu_bar_open_internal);
2345 Ffset (intern_c_string ("accelerate-menu"),
2346 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2347 #endif