* net/eww.el (eww-mode-map): Remove mentions of `eww-quit'.
[emacs.git] / src / xmenu.c
blobeb783fe5070871d7b5e2e99bc13c7d794038cc90
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;
631 eassert (FRAME_X_P (f));
633 x = f->output_data.x;
635 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
636 return;
638 block_input ();
640 /* Do the voodoo which means "I'm changing lots of things, don't try
641 to refigure sizes until I'm done." */
642 lw_refigure_widget (x->column_widget, False);
644 /* The order in which children are managed is the top to bottom
645 order in which they are displayed in the paned window. First,
646 remove the text-area widget. */
647 XtUnmanageChild (x->edit_widget);
649 /* Remove the menubar that is there now, and put up the menubar that
650 should be there. */
651 XtManageChild (x->menubar_widget);
652 XtMapWidget (x->menubar_widget);
653 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
655 /* Re-manage the text-area widget, and then thrash the sizes. */
656 XtManageChild (x->edit_widget);
657 lw_refigure_widget (x->column_widget, True);
659 /* Force the pane widget to resize itself. */
660 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 2, 0);
661 unblock_input ();
662 #endif
665 #ifdef USE_LUCID
666 static void
667 apply_systemfont_to_dialog (Widget w)
669 const char *fn = xsettings_get_system_normal_font ();
670 if (fn)
672 XrmDatabase db = XtDatabase (XtDisplay (w));
673 if (db)
674 XrmPutStringResource (&db, "*dialog.font", fn);
678 static void
679 apply_systemfont_to_menu (struct frame *f, Widget w)
681 const char *fn = xsettings_get_system_normal_font ();
683 if (fn)
685 XrmDatabase db = XtDatabase (XtDisplay (w));
686 if (db)
688 XrmPutStringResource (&db, "*menubar*font", fn);
689 XrmPutStringResource (&db, "*popup*font", fn);
694 #endif
696 /* Set the contents of the menubar widgets of frame F.
697 The argument FIRST_TIME is currently ignored;
698 it is set the first time this is called, from initialize_frame_menubar. */
700 void
701 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
703 xt_or_gtk_widget menubar_widget, old_widget;
704 #ifdef USE_X_TOOLKIT
705 LWLIB_ID id;
706 #endif
707 Lisp_Object items;
708 widget_value *wv, *first_wv, *prev_wv = 0;
709 int i;
710 int *submenu_start, *submenu_end;
711 bool *submenu_top_level_items;
712 int *submenu_n_panes;
714 eassert (FRAME_X_P (f));
716 menubar_widget = old_widget = f->output_data.x->menubar_widget;
718 XSETFRAME (Vmenu_updating_frame, f);
720 #ifdef USE_X_TOOLKIT
721 if (f->output_data.x->id == 0)
722 f->output_data.x->id = next_menubar_widget_id++;
723 id = f->output_data.x->id;
724 #endif
726 if (! menubar_widget)
727 deep_p = 1;
728 /* Make the first call for any given frame always go deep. */
729 else if (!f->output_data.x->saved_menu_event && !deep_p)
731 deep_p = 1;
732 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
733 f->output_data.x->saved_menu_event->type = 0;
736 if (deep_p)
738 /* Make a widget-value tree representing the entire menu trees. */
740 struct buffer *prev = current_buffer;
741 Lisp_Object buffer;
742 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
743 int previous_menu_items_used = f->menu_bar_items_used;
744 Lisp_Object *previous_items
745 = alloca (previous_menu_items_used * sizeof *previous_items);
746 int subitems;
748 /* If we are making a new widget, its contents are empty,
749 do always reinitialize them. */
750 if (! menubar_widget)
751 previous_menu_items_used = 0;
753 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
754 specbind (Qinhibit_quit, Qt);
755 /* Don't let the debugger step into this code
756 because it is not reentrant. */
757 specbind (Qdebug_on_next_call, Qnil);
759 record_unwind_save_match_data ();
760 if (NILP (Voverriding_local_map_menu_flag))
762 specbind (Qoverriding_terminal_local_map, Qnil);
763 specbind (Qoverriding_local_map, Qnil);
766 set_buffer_internal_1 (XBUFFER (buffer));
768 /* Run the Lucid hook. */
769 safe_run_hooks (Qactivate_menubar_hook);
771 /* If it has changed current-menubar from previous value,
772 really recompute the menubar from the value. */
773 if (! NILP (Vlucid_menu_bar_dirty_flag))
774 call0 (Qrecompute_lucid_menubar);
775 safe_run_hooks (Qmenu_bar_update_hook);
776 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
778 items = FRAME_MENU_BAR_ITEMS (f);
780 /* Save the frame's previous menu bar contents data. */
781 if (previous_menu_items_used)
782 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
783 previous_menu_items_used * word_size);
785 /* Fill in menu_items with the current menu bar contents.
786 This can evaluate Lisp code. */
787 save_menu_items ();
789 menu_items = f->menu_bar_vector;
790 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
791 subitems = ASIZE (items) / 4;
792 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
793 submenu_end = alloca (subitems * sizeof *submenu_end);
794 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
795 submenu_top_level_items = alloca (subitems
796 * sizeof *submenu_top_level_items);
797 init_menu_items ();
798 for (i = 0; i < subitems; i++)
800 Lisp_Object key, string, maps;
802 key = AREF (items, 4 * i);
803 string = AREF (items, 4 * i + 1);
804 maps = AREF (items, 4 * i + 2);
805 if (NILP (string))
806 break;
808 submenu_start[i] = menu_items_used;
810 menu_items_n_panes = 0;
811 submenu_top_level_items[i]
812 = parse_single_submenu (key, string, maps);
813 submenu_n_panes[i] = menu_items_n_panes;
815 submenu_end[i] = menu_items_used;
818 submenu_start[i] = -1;
819 finish_menu_items ();
821 /* Convert menu_items into widget_value trees
822 to display the menu. This cannot evaluate Lisp code. */
824 wv = make_widget_value ("menubar", NULL, true, Qnil);
825 wv->button_type = BUTTON_TYPE_NONE;
826 first_wv = wv;
828 for (i = 0; submenu_start[i] >= 0; i++)
830 menu_items_n_panes = submenu_n_panes[i];
831 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
832 submenu_top_level_items[i]);
833 if (prev_wv)
834 prev_wv->next = wv;
835 else
836 first_wv->contents = wv;
837 /* Don't set wv->name here; GC during the loop might relocate it. */
838 wv->enabled = 1;
839 wv->button_type = BUTTON_TYPE_NONE;
840 prev_wv = wv;
843 set_buffer_internal_1 (prev);
845 /* If there has been no change in the Lisp-level contents
846 of the menu bar, skip redisplaying it. Just exit. */
848 /* Compare the new menu items with the ones computed last time. */
849 for (i = 0; i < previous_menu_items_used; i++)
850 if (menu_items_used == i
851 || (!EQ (previous_items[i], AREF (menu_items, i))))
852 break;
853 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
855 /* The menu items have not changed. Don't bother updating
856 the menus in any form, since it would be a no-op. */
857 free_menubar_widget_value_tree (first_wv);
858 discard_menu_items ();
859 unbind_to (specpdl_count, Qnil);
860 return;
863 /* The menu items are different, so store them in the frame. */
864 fset_menu_bar_vector (f, menu_items);
865 f->menu_bar_items_used = menu_items_used;
867 /* This undoes save_menu_items. */
868 unbind_to (specpdl_count, Qnil);
870 /* Now GC cannot happen during the lifetime of the widget_value,
871 so it's safe to store data from a Lisp_String. */
872 wv = first_wv->contents;
873 for (i = 0; i < ASIZE (items); i += 4)
875 Lisp_Object string;
876 string = AREF (items, i + 1);
877 if (NILP (string))
878 break;
879 wv->name = SSDATA (string);
880 update_submenu_strings (wv->contents);
881 wv = wv->next;
885 else
887 /* Make a widget-value tree containing
888 just the top level menu bar strings. */
890 wv = make_widget_value ("menubar", NULL, true, Qnil);
891 wv->button_type = BUTTON_TYPE_NONE;
892 first_wv = wv;
894 items = FRAME_MENU_BAR_ITEMS (f);
895 for (i = 0; i < ASIZE (items); i += 4)
897 Lisp_Object string;
899 string = AREF (items, i + 1);
900 if (NILP (string))
901 break;
903 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
904 wv->button_type = BUTTON_TYPE_NONE;
905 /* This prevents lwlib from assuming this
906 menu item is really supposed to be empty. */
907 /* The intptr_t cast avoids a warning.
908 This value just has to be different from small integers. */
909 wv->call_data = (void *) (intptr_t) (-1);
911 if (prev_wv)
912 prev_wv->next = wv;
913 else
914 first_wv->contents = wv;
915 prev_wv = wv;
918 /* Forget what we thought we knew about what is in the
919 detailed contents of the menu bar menus.
920 Changing the top level always destroys the contents. */
921 f->menu_bar_items_used = 0;
924 /* Create or update the menu bar widget. */
926 block_input ();
928 #ifdef USE_GTK
929 xg_crazy_callback_abort = 1;
930 if (menubar_widget)
932 /* The fourth arg is DEEP_P, which says to consider the entire
933 menu trees we supply, rather than just the menu bar item names. */
934 xg_modify_menubar_widgets (menubar_widget,
936 first_wv,
937 deep_p,
938 G_CALLBACK (menubar_selection_callback),
939 G_CALLBACK (popup_deactivate_callback),
940 G_CALLBACK (menu_highlight_callback));
942 else
944 menubar_widget
945 = xg_create_widget ("menubar", "menubar", f, first_wv,
946 G_CALLBACK (menubar_selection_callback),
947 G_CALLBACK (popup_deactivate_callback),
948 G_CALLBACK (menu_highlight_callback));
950 f->output_data.x->menubar_widget = menubar_widget;
954 #else /* not USE_GTK */
955 if (menubar_widget)
957 /* Disable resizing (done for Motif!) */
958 lw_allow_resizing (f->output_data.x->widget, False);
960 /* The third arg is DEEP_P, which says to consider the entire
961 menu trees we supply, rather than just the menu bar item names. */
962 lw_modify_all_widgets (id, first_wv, deep_p);
964 /* Re-enable the edit widget to resize. */
965 lw_allow_resizing (f->output_data.x->widget, True);
967 else
969 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
970 XtTranslations override = XtParseTranslationTable (menuOverride);
972 #ifdef USE_LUCID
973 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
974 #endif
975 menubar_widget = lw_create_widget ("menubar", "menubar", id,
976 first_wv,
977 f->output_data.x->column_widget,
979 popup_activate_callback,
980 menubar_selection_callback,
981 popup_deactivate_callback,
982 menu_highlight_callback);
983 f->output_data.x->menubar_widget = menubar_widget;
985 /* Make menu pop down on C-g. */
986 XtOverrideTranslations (menubar_widget, override);
990 int menubar_size;
991 if (f->output_data.x->menubar_widget)
992 XtRealizeWidget (f->output_data.x->menubar_widget);
994 menubar_size
995 = (f->output_data.x->menubar_widget
996 ? (f->output_data.x->menubar_widget->core.height
997 + f->output_data.x->menubar_widget->core.border_width)
998 : 0);
1000 #if 1 /* Experimentally, we now get the right results
1001 for -geometry -0-0 without this. 24 Aug 96, rms.
1002 Maybe so, but the menu bar size is missing the pixels so the
1003 WM size hints are off by these pixels. Jan D, oct 2009. */
1004 #ifdef USE_LUCID
1005 if (FRAME_EXTERNAL_MENU_BAR (f))
1007 Dimension ibw = 0;
1008 XtVaGetValues (f->output_data.x->column_widget,
1009 XtNinternalBorderWidth, &ibw, NULL);
1010 menubar_size += ibw;
1012 #endif /* USE_LUCID */
1013 #endif /* 1 */
1015 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1017 #endif /* not USE_GTK */
1019 free_menubar_widget_value_tree (first_wv);
1020 update_frame_menubar (f);
1022 #ifdef USE_GTK
1023 xg_crazy_callback_abort = 0;
1024 #endif
1026 unblock_input ();
1029 /* Called from Fx_create_frame to create the initial menubar of a frame
1030 before it is mapped, so that the window is mapped with the menubar already
1031 there instead of us tacking it on later and thrashing the window after it
1032 is visible. */
1034 void
1035 initialize_frame_menubar (struct frame *f)
1037 /* This function is called before the first chance to redisplay
1038 the frame. It has to be, so the frame will have the right size. */
1039 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1040 set_frame_menubar (f, 1, 1);
1044 /* Get rid of the menu bar of frame F, and free its storage.
1045 This is used when deleting a frame, and when turning off the menu bar.
1046 For GTK this function is in gtkutil.c. */
1048 #ifndef USE_GTK
1049 void
1050 free_frame_menubar (struct frame *f)
1052 Widget menubar_widget;
1054 eassert (FRAME_X_P (f));
1056 menubar_widget = f->output_data.x->menubar_widget;
1058 FRAME_MENUBAR_HEIGHT (f) = 0;
1060 if (menubar_widget)
1062 #ifdef USE_MOTIF
1063 /* Removing the menu bar magically changes the shell widget's x
1064 and y position of (0, 0) which, when the menu bar is turned
1065 on again, leads to pull-down menus appearing in strange
1066 positions near the upper-left corner of the display. This
1067 happens only with some window managers like twm and ctwm,
1068 but not with other like Motif's mwm or kwm, because the
1069 latter generate ConfigureNotify events when the menu bar
1070 is switched off, which fixes the shell position. */
1071 Position x0, y0, x1, y1;
1072 #endif
1074 block_input ();
1076 #ifdef USE_MOTIF
1077 if (f->output_data.x->widget)
1078 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1079 #endif
1081 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1082 f->output_data.x->menubar_widget = NULL;
1084 if (f->output_data.x->widget)
1086 #ifdef USE_MOTIF
1087 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1088 if (x1 == 0 && y1 == 0)
1089 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1090 #endif
1091 adjust_frame_size (f, FRAME_TEXT_WIDTH (f),
1092 FRAME_TEXT_HEIGHT (f), 2, 0);
1094 if (frame_inhibit_resize (f, 0))
1095 change_frame_size (f, 0, 0, 0, 0, 0, 1);
1096 else
1097 x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f),
1098 FRAME_TEXT_HEIGHT (f), 1);
1101 unblock_input ();
1104 #endif /* not USE_GTK */
1106 #endif /* USE_X_TOOLKIT || USE_GTK */
1108 /* x_menu_show actually displays a menu using the panes and items in menu_items
1109 and returns the value selected from it.
1110 There are two versions of x_menu_show, one for Xt and one for Xlib.
1111 Both assume input is blocked by the caller. */
1113 /* F is the frame the menu is for.
1114 X and Y are the frame-relative specified position,
1115 relative to the inside upper left corner of the frame F.
1116 Bitfield MENUFLAGS bits are:
1117 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1118 MENU_KEYMAPS is set if this menu was specified with keymaps;
1119 in that case, we return a list containing the chosen item's value
1120 and perhaps also the pane's prefix.
1121 TITLE is the specified menu title.
1122 ERROR is a place to store an error message string in case of failure.
1123 (We return nil on failure, but the value doesn't actually matter.) */
1125 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1127 /* The item selected in the popup menu. */
1128 static Lisp_Object *volatile menu_item_selection;
1130 #ifdef USE_GTK
1132 /* Used when position a popup menu. See menu_position_func and
1133 create_and_show_popup_menu below. */
1134 struct next_popup_x_y
1136 struct frame *f;
1137 int x;
1138 int y;
1141 /* The menu position function to use if we are not putting a popup
1142 menu where the pointer is.
1143 MENU is the menu to pop up.
1144 X and Y shall on exit contain x/y where the menu shall pop up.
1145 PUSH_IN is not documented in the GTK manual.
1146 USER_DATA is any data passed in when calling gtk_menu_popup.
1147 Here it points to a struct next_popup_x_y where the coordinates
1148 to store in *X and *Y are as well as the frame for the popup.
1150 Here only X and Y are used. */
1151 static void
1152 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1154 struct next_popup_x_y *data = user_data;
1155 GtkRequisition req;
1156 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1157 int disp_width = x_display_pixel_width (dpyinfo);
1158 int disp_height = x_display_pixel_height (dpyinfo);
1160 *x = data->x;
1161 *y = data->y;
1163 /* Check if there is room for the menu. If not, adjust x/y so that
1164 the menu is fully visible. */
1165 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1166 if (data->x + req.width > disp_width)
1167 *x -= data->x + req.width - disp_width;
1168 if (data->y + req.height > disp_height)
1169 *y -= data->y + req.height - disp_height;
1172 static void
1173 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1175 xg_menu_item_cb_data *cb_data = client_data;
1177 if (xg_crazy_callback_abort) return;
1178 if (cb_data) menu_item_selection = cb_data->call_data;
1181 static void
1182 pop_down_menu (void *arg)
1184 popup_activated_flag = 0;
1185 block_input ();
1186 gtk_widget_destroy (GTK_WIDGET (arg));
1187 unblock_input ();
1190 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1191 menu pops down.
1192 menu_item_selection will be set to the selection. */
1193 static void
1194 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1195 int x, int y, bool for_click)
1197 int i;
1198 GtkWidget *menu;
1199 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1200 struct next_popup_x_y popup_x_y;
1201 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1202 bool use_pos_func = ! for_click;
1204 #ifdef HAVE_GTK3
1205 /* Always use position function for Gtk3. Otherwise menus may become
1206 too small to show anything. */
1207 use_pos_func = 1;
1208 #endif
1210 eassert (FRAME_X_P (f));
1212 xg_crazy_callback_abort = 1;
1213 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1214 G_CALLBACK (popup_selection_callback),
1215 G_CALLBACK (popup_deactivate_callback),
1216 G_CALLBACK (menu_highlight_callback));
1217 xg_crazy_callback_abort = 0;
1219 if (use_pos_func)
1221 /* Not invoked by a click. pop up at x/y. */
1222 pos_func = menu_position_func;
1224 /* Adjust coordinates to be root-window-relative. */
1225 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1226 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1228 popup_x_y.x = x;
1229 popup_x_y.y = y;
1230 popup_x_y.f = f;
1232 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1235 if (for_click)
1237 for (i = 0; i < 5; i++)
1238 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1239 break;
1240 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1241 if (i == 5) i = 0;
1244 /* Display the menu. */
1245 gtk_widget_show_all (menu);
1247 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1248 FRAME_DISPLAY_INFO (f)->last_user_time);
1250 record_unwind_protect_ptr (pop_down_menu, menu);
1252 if (gtk_widget_get_mapped (menu))
1254 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1255 two. show_help_echo uses this to detect popup menus. */
1256 popup_activated_flag = 1;
1257 /* Process events that apply to the menu. */
1258 popup_widget_loop (1, menu);
1261 unbind_to (specpdl_count, Qnil);
1263 /* Must reset this manually because the button release event is not passed
1264 to Emacs event loop. */
1265 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1268 #else /* not USE_GTK */
1270 /* We need a unique id for each widget handled by the Lucid Widget
1271 library.
1273 For the main windows, and popup menus, we use this counter, which we
1274 increment each time after use. This starts from WIDGET_ID_TICK_START.
1276 For menu bars, we use numbers starting at 0, counted in
1277 next_menubar_widget_id. */
1278 LWLIB_ID widget_id_tick;
1280 static void
1281 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1283 menu_item_selection = client_data;
1286 /* ID is the LWLIB ID of the dialog box. */
1288 static void
1289 pop_down_menu (int id)
1291 block_input ();
1292 lw_destroy_all_widgets ((LWLIB_ID) id);
1293 unblock_input ();
1294 popup_activated_flag = 0;
1297 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1298 menu pops down.
1299 menu_item_selection will be set to the selection. */
1300 static void
1301 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1302 int x, int y, bool for_click)
1304 int i;
1305 Arg av[2];
1306 int ac = 0;
1307 XEvent dummy;
1308 XButtonPressedEvent *event = &(dummy.xbutton);
1309 LWLIB_ID menu_id;
1310 Widget menu;
1312 eassert (FRAME_X_P (f));
1314 #ifdef USE_LUCID
1315 apply_systemfont_to_menu (f, f->output_data.x->widget);
1316 #endif
1318 menu_id = widget_id_tick++;
1319 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1320 f->output_data.x->widget, 1, 0,
1321 popup_selection_callback,
1322 popup_deactivate_callback,
1323 menu_highlight_callback);
1325 event->type = ButtonPress;
1326 event->serial = 0;
1327 event->send_event = 0;
1328 event->display = FRAME_X_DISPLAY (f);
1329 event->time = CurrentTime;
1330 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1331 event->window = event->subwindow = event->root;
1332 event->x = x;
1333 event->y = y;
1335 /* Adjust coordinates to be root-window-relative. */
1336 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1337 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1339 event->x_root = x;
1340 event->y_root = y;
1342 event->state = 0;
1343 event->button = 0;
1344 for (i = 0; i < 5; i++)
1345 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1346 event->button = i;
1348 /* Don't allow any geometry request from the user. */
1349 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1350 XtSetValues (menu, av, ac);
1352 /* Display the menu. */
1353 lw_popup_menu (menu, &dummy);
1354 popup_activated_flag = 1;
1355 x_activate_timeout_atimer ();
1358 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1360 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1362 /* Process events that apply to the menu. */
1363 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
1365 unbind_to (specpdl_count, Qnil);
1369 #endif /* not USE_GTK */
1371 static void
1372 cleanup_widget_value_tree (void *arg)
1374 free_menubar_widget_value_tree (arg);
1377 Lisp_Object
1378 x_menu_show (struct frame *f, int x, int y, int menuflags,
1379 Lisp_Object title, const char **error_name)
1381 int i;
1382 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1383 widget_value **submenu_stack
1384 = alloca (menu_items_used * sizeof *submenu_stack);
1385 Lisp_Object *subprefix_stack
1386 = alloca (menu_items_used * sizeof *subprefix_stack);
1387 int submenu_depth = 0;
1389 int first_pane;
1391 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1393 eassert (FRAME_X_P (f));
1395 *error_name = NULL;
1397 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1399 *error_name = "Empty menu";
1400 return Qnil;
1403 block_input ();
1405 /* Create a tree of widget_value objects
1406 representing the panes and their items. */
1407 wv = make_widget_value ("menu", NULL, true, Qnil);
1408 wv->button_type = BUTTON_TYPE_NONE;
1409 first_wv = wv;
1410 first_pane = 1;
1412 /* Loop over all panes and items, filling in the tree. */
1413 i = 0;
1414 while (i < menu_items_used)
1416 if (EQ (AREF (menu_items, i), Qnil))
1418 submenu_stack[submenu_depth++] = save_wv;
1419 save_wv = prev_wv;
1420 prev_wv = 0;
1421 first_pane = 1;
1422 i++;
1424 else if (EQ (AREF (menu_items, i), Qlambda))
1426 prev_wv = save_wv;
1427 save_wv = submenu_stack[--submenu_depth];
1428 first_pane = 0;
1429 i++;
1431 else if (EQ (AREF (menu_items, i), Qt)
1432 && submenu_depth != 0)
1433 i += MENU_ITEMS_PANE_LENGTH;
1434 /* Ignore a nil in the item list.
1435 It's meaningful only for dialog boxes. */
1436 else if (EQ (AREF (menu_items, i), Qquote))
1437 i += 1;
1438 else if (EQ (AREF (menu_items, i), Qt))
1440 /* Create a new pane. */
1441 Lisp_Object pane_name, prefix;
1442 const char *pane_string;
1444 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1445 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1447 #ifndef HAVE_MULTILINGUAL_MENU
1448 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1450 pane_name = ENCODE_MENU_STRING (pane_name);
1451 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1453 #endif
1454 pane_string = (NILP (pane_name)
1455 ? "" : SSDATA (pane_name));
1456 /* If there is just one top-level pane, put all its items directly
1457 under the top-level menu. */
1458 if (menu_items_n_panes == 1)
1459 pane_string = "";
1461 /* If the pane has a meaningful name,
1462 make the pane a top-level menu item
1463 with its items as a submenu beneath it. */
1464 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1466 wv = make_widget_value (pane_string, NULL, true, Qnil);
1467 if (save_wv)
1468 save_wv->next = wv;
1469 else
1470 first_wv->contents = wv;
1471 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1472 wv->name++;
1473 wv->button_type = BUTTON_TYPE_NONE;
1474 save_wv = wv;
1475 prev_wv = 0;
1477 else if (first_pane)
1479 save_wv = wv;
1480 prev_wv = 0;
1482 first_pane = 0;
1483 i += MENU_ITEMS_PANE_LENGTH;
1485 else
1487 /* Create a new item within current pane. */
1488 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1489 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1490 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1491 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1492 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1493 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1494 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1495 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1497 #ifndef HAVE_MULTILINGUAL_MENU
1498 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1500 item_name = ENCODE_MENU_STRING (item_name);
1501 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1504 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1506 descrip = ENCODE_MENU_STRING (descrip);
1507 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1509 #endif /* not HAVE_MULTILINGUAL_MENU */
1511 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1512 STRINGP (help) ? help : Qnil);
1513 if (prev_wv)
1514 prev_wv->next = wv;
1515 else
1516 save_wv->contents = wv;
1517 if (!NILP (descrip))
1518 wv->key = SSDATA (descrip);
1519 /* If this item has a null value,
1520 make the call_data null so that it won't display a box
1521 when the mouse is on it. */
1522 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1524 if (NILP (type))
1525 wv->button_type = BUTTON_TYPE_NONE;
1526 else if (EQ (type, QCtoggle))
1527 wv->button_type = BUTTON_TYPE_TOGGLE;
1528 else if (EQ (type, QCradio))
1529 wv->button_type = BUTTON_TYPE_RADIO;
1530 else
1531 emacs_abort ();
1533 wv->selected = !NILP (selected);
1535 prev_wv = wv;
1537 i += MENU_ITEMS_ITEM_LENGTH;
1541 /* Deal with the title, if it is non-nil. */
1542 if (!NILP (title))
1544 widget_value *wv_title;
1545 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1546 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1548 wv_sep2->next = first_wv->contents;
1549 wv_sep1->next = wv_sep2;
1551 #ifndef HAVE_MULTILINGUAL_MENU
1552 if (STRING_MULTIBYTE (title))
1553 title = ENCODE_MENU_STRING (title);
1554 #endif
1556 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1557 wv_title->button_type = BUTTON_TYPE_NONE;
1558 wv_title->next = wv_sep1;
1559 first_wv->contents = wv_title;
1562 /* No selection has been chosen yet. */
1563 menu_item_selection = 0;
1565 /* Make sure to free the widget_value objects we used to specify the
1566 contents even with longjmp. */
1567 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1569 /* Actually create and show the menu until popped down. */
1570 create_and_show_popup_menu (f, first_wv, x, y,
1571 menuflags & MENU_FOR_CLICK);
1573 unbind_to (specpdl_count, Qnil);
1575 /* Find the selected item, and its pane, to return
1576 the proper value. */
1577 if (menu_item_selection != 0)
1579 Lisp_Object prefix, entry;
1581 prefix = entry = Qnil;
1582 i = 0;
1583 while (i < menu_items_used)
1585 if (EQ (AREF (menu_items, i), Qnil))
1587 subprefix_stack[submenu_depth++] = prefix;
1588 prefix = entry;
1589 i++;
1591 else if (EQ (AREF (menu_items, i), Qlambda))
1593 prefix = subprefix_stack[--submenu_depth];
1594 i++;
1596 else if (EQ (AREF (menu_items, i), Qt))
1598 prefix
1599 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1600 i += MENU_ITEMS_PANE_LENGTH;
1602 /* Ignore a nil in the item list.
1603 It's meaningful only for dialog boxes. */
1604 else if (EQ (AREF (menu_items, i), Qquote))
1605 i += 1;
1606 else
1608 entry
1609 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1610 if (menu_item_selection == aref_addr (menu_items, i))
1612 if (menuflags & MENU_KEYMAPS)
1614 int j;
1616 entry = list1 (entry);
1617 if (!NILP (prefix))
1618 entry = Fcons (prefix, entry);
1619 for (j = submenu_depth - 1; j >= 0; j--)
1620 if (!NILP (subprefix_stack[j]))
1621 entry = Fcons (subprefix_stack[j], entry);
1623 unblock_input ();
1624 return entry;
1626 i += MENU_ITEMS_ITEM_LENGTH;
1630 else if (!(menuflags & MENU_FOR_CLICK))
1632 unblock_input ();
1633 /* Make "Cancel" equivalent to C-g. */
1634 Fsignal (Qquit, Qnil);
1637 unblock_input ();
1638 return Qnil;
1641 #ifdef USE_GTK
1642 static void
1643 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1645 /* Treat the pointer as an integer. There's no problem
1646 as long as pointers have enough bits to hold small integers. */
1647 if ((intptr_t) client_data != -1)
1648 menu_item_selection = client_data;
1650 popup_activated_flag = 0;
1653 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1654 dialog pops down.
1655 menu_item_selection will be set to the selection. */
1656 static void
1657 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1659 GtkWidget *menu;
1661 eassert (FRAME_X_P (f));
1663 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1664 G_CALLBACK (dialog_selection_callback),
1665 G_CALLBACK (popup_deactivate_callback),
1668 if (menu)
1670 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1671 record_unwind_protect_ptr (pop_down_menu, menu);
1673 /* Display the menu. */
1674 gtk_widget_show_all (menu);
1676 /* Process events that apply to the menu. */
1677 popup_widget_loop (1, menu);
1679 unbind_to (specpdl_count, Qnil);
1683 #else /* not USE_GTK */
1684 static void
1685 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1687 /* Treat the pointer as an integer. There's no problem
1688 as long as pointers have enough bits to hold small integers. */
1689 if ((intptr_t) client_data != -1)
1690 menu_item_selection = client_data;
1692 block_input ();
1693 lw_destroy_all_widgets (id);
1694 unblock_input ();
1695 popup_activated_flag = 0;
1699 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1700 dialog pops down.
1701 menu_item_selection will be set to the selection. */
1702 static void
1703 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1705 LWLIB_ID dialog_id;
1707 eassert (FRAME_X_P (f));
1709 dialog_id = widget_id_tick++;
1710 #ifdef USE_LUCID
1711 apply_systemfont_to_dialog (f->output_data.x->widget);
1712 #endif
1713 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1714 f->output_data.x->widget, 1, 0,
1715 dialog_selection_callback, 0, 0);
1716 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1717 /* Display the dialog box. */
1718 lw_pop_up_all_widgets (dialog_id);
1719 popup_activated_flag = 1;
1720 x_activate_timeout_atimer ();
1722 /* Process events that apply to the dialog box.
1723 Also handle timers. */
1725 ptrdiff_t count = SPECPDL_INDEX ();
1727 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1729 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1731 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
1733 unbind_to (count, Qnil);
1737 #endif /* not USE_GTK */
1739 static const char * button_names [] = {
1740 "button1", "button2", "button3", "button4", "button5",
1741 "button6", "button7", "button8", "button9", "button10" };
1743 static Lisp_Object
1744 x_dialog_show (struct frame *f, Lisp_Object title,
1745 Lisp_Object header, const char **error_name)
1747 int i, nb_buttons=0;
1748 char dialog_name[6];
1750 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1752 /* Number of elements seen so far, before boundary. */
1753 int left_count = 0;
1754 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1755 int boundary_seen = 0;
1757 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1759 eassert (FRAME_X_P (f));
1761 *error_name = NULL;
1763 if (menu_items_n_panes > 1)
1765 *error_name = "Multiple panes in dialog box";
1766 return Qnil;
1769 /* Create a tree of widget_value objects
1770 representing the text label and buttons. */
1772 Lisp_Object pane_name;
1773 const char *pane_string;
1774 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1775 pane_string = (NILP (pane_name)
1776 ? "" : SSDATA (pane_name));
1777 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1778 first_wv = prev_wv;
1780 /* Loop over all panes and items, filling in the tree. */
1781 i = MENU_ITEMS_PANE_LENGTH;
1782 while (i < menu_items_used)
1785 /* Create a new item within current pane. */
1786 Lisp_Object item_name, enable, descrip;
1787 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1788 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1789 descrip
1790 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1792 if (NILP (item_name))
1794 free_menubar_widget_value_tree (first_wv);
1795 *error_name = "Submenu in dialog items";
1796 return Qnil;
1798 if (EQ (item_name, Qquote))
1800 /* This is the boundary between left-side elts
1801 and right-side elts. Stop incrementing right_count. */
1802 boundary_seen = 1;
1803 i++;
1804 continue;
1806 if (nb_buttons >= 9)
1808 free_menubar_widget_value_tree (first_wv);
1809 *error_name = "Too many dialog items";
1810 return Qnil;
1813 wv = make_widget_value (button_names[nb_buttons],
1814 SSDATA (item_name),
1815 !NILP (enable), Qnil);
1816 prev_wv->next = wv;
1817 if (!NILP (descrip))
1818 wv->key = SSDATA (descrip);
1819 wv->call_data = aref_addr (menu_items, i);
1820 prev_wv = wv;
1822 if (! boundary_seen)
1823 left_count++;
1825 nb_buttons++;
1826 i += MENU_ITEMS_ITEM_LENGTH;
1829 /* If the boundary was not specified,
1830 by default put half on the left and half on the right. */
1831 if (! boundary_seen)
1832 left_count = nb_buttons - nb_buttons / 2;
1834 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1836 /* Frame title: 'Q' = Question, 'I' = Information.
1837 Can also have 'E' = Error if, one day, we want
1838 a popup for errors. */
1839 if (NILP (header))
1840 dialog_name[0] = 'Q';
1841 else
1842 dialog_name[0] = 'I';
1844 /* Dialog boxes use a really stupid name encoding
1845 which specifies how many buttons to use
1846 and how many buttons are on the right. */
1847 dialog_name[1] = '0' + nb_buttons;
1848 dialog_name[2] = 'B';
1849 dialog_name[3] = 'R';
1850 /* Number of buttons to put on the right. */
1851 dialog_name[4] = '0' + nb_buttons - left_count;
1852 dialog_name[5] = 0;
1853 wv->contents = first_wv;
1854 first_wv = wv;
1857 /* No selection has been chosen yet. */
1858 menu_item_selection = 0;
1860 /* Make sure to free the widget_value objects we used to specify the
1861 contents even with longjmp. */
1862 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1864 /* Actually create and show the dialog. */
1865 create_and_show_dialog (f, first_wv);
1867 unbind_to (specpdl_count, Qnil);
1869 /* Find the selected item, and its pane, to return
1870 the proper value. */
1871 if (menu_item_selection != 0)
1873 i = 0;
1874 while (i < menu_items_used)
1876 Lisp_Object entry;
1878 if (EQ (AREF (menu_items, i), Qt))
1879 i += MENU_ITEMS_PANE_LENGTH;
1880 else if (EQ (AREF (menu_items, i), Qquote))
1882 /* This is the boundary between left-side elts and
1883 right-side elts. */
1884 ++i;
1886 else
1888 entry
1889 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1890 if (menu_item_selection == aref_addr (menu_items, i))
1891 return entry;
1892 i += MENU_ITEMS_ITEM_LENGTH;
1896 else
1897 /* Make "Cancel" equivalent to C-g. */
1898 Fsignal (Qquit, Qnil);
1900 return Qnil;
1903 Lisp_Object
1904 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1906 Lisp_Object title;
1907 const char *error_name;
1908 Lisp_Object selection;
1909 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1911 check_window_system (f);
1913 /* Decode the dialog items from what was specified. */
1914 title = Fcar (contents);
1915 CHECK_STRING (title);
1916 record_unwind_protect_void (unuse_menu_items);
1918 if (NILP (Fcar (Fcdr (contents))))
1919 /* No buttons specified, add an "Ok" button so users can pop down
1920 the dialog. Also, the lesstif/motif version crashes if there are
1921 no buttons. */
1922 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1924 list_of_panes (list1 (contents));
1926 /* Display them in a dialog box. */
1927 block_input ();
1928 selection = x_dialog_show (f, title, header, &error_name);
1929 unblock_input ();
1931 unbind_to (specpdl_count, Qnil);
1932 discard_menu_items ();
1934 if (error_name) error ("%s", error_name);
1935 return selection;
1938 #else /* not USE_X_TOOLKIT && not USE_GTK */
1940 /* The frame of the last activated non-toolkit menu bar.
1941 Used to generate menu help events. */
1943 static struct frame *menu_help_frame;
1946 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1948 PANE is the pane number, and ITEM is the menu item number in
1949 the menu (currently not used).
1951 This cannot be done with generating a HELP_EVENT because
1952 XMenuActivate contains a loop that doesn't let Emacs process
1953 keyboard events. */
1955 static void
1956 menu_help_callback (char const *help_string, int pane, int item)
1958 Lisp_Object *first_item;
1959 Lisp_Object pane_name;
1960 Lisp_Object menu_object;
1962 first_item = XVECTOR (menu_items)->contents;
1963 if (EQ (first_item[0], Qt))
1964 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1965 else if (EQ (first_item[0], Qquote))
1966 /* This shouldn't happen, see x_menu_show. */
1967 pane_name = empty_unibyte_string;
1968 else
1969 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1971 /* (menu-item MENU-NAME PANE-NUMBER) */
1972 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1973 show_help_echo (help_string ? build_string (help_string) : Qnil,
1974 Qnil, menu_object, make_number (item));
1977 static void
1978 pop_down_menu (Lisp_Object arg)
1980 struct frame *f = XSAVE_POINTER (arg, 0);
1981 XMenu *menu = XSAVE_POINTER (arg, 1);
1983 block_input ();
1984 #ifndef MSDOS
1985 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
1986 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
1987 #endif
1988 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
1990 #ifdef HAVE_X_WINDOWS
1991 /* Assume the mouse has moved out of the X window.
1992 If it has actually moved in, we will get an EnterNotify. */
1993 x_mouse_leave (FRAME_DISPLAY_INFO (f));
1995 /* State that no mouse buttons are now held.
1996 (The oldXMenu code doesn't track this info for us.)
1997 That is not necessarily true, but the fiction leads to reasonable
1998 results, and it is a pain to ask which are actually held now. */
1999 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2001 #endif /* HAVE_X_WINDOWS */
2003 unblock_input ();
2007 Lisp_Object
2008 x_menu_show (struct frame *f, int x, int y, int menuflags,
2009 Lisp_Object title, const char **error_name)
2011 Window root;
2012 XMenu *menu;
2013 int pane, selidx, lpane, status;
2014 Lisp_Object entry = Qnil;
2015 Lisp_Object pane_prefix;
2016 char *datap;
2017 int ulx, uly, width, height;
2018 int dispwidth, dispheight;
2019 int i, j, lines, maxlines;
2020 int maxwidth;
2021 int dummy_int;
2022 unsigned int dummy_uint;
2023 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2025 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2027 *error_name = 0;
2028 if (menu_items_n_panes == 0)
2029 return Qnil;
2031 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2033 *error_name = "Empty menu";
2034 return Qnil;
2037 USE_SAFE_ALLOCA;
2038 block_input ();
2040 /* Figure out which root window F is on. */
2041 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2042 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2043 &dummy_uint, &dummy_uint);
2045 /* Make the menu on that window. */
2046 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2047 if (menu == NULL)
2049 *error_name = "Can't create menu";
2050 goto return_entry;
2053 /* Don't GC while we prepare and show the menu,
2054 because we give the oldxmenu library pointers to the
2055 contents of strings. */
2056 inhibit_garbage_collection ();
2058 #ifdef HAVE_X_WINDOWS
2059 /* Adjust coordinates to relative to the outer (window manager) window. */
2060 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2061 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2062 #endif /* HAVE_X_WINDOWS */
2064 /* Adjust coordinates to be root-window-relative. */
2065 x += f->left_pos;
2066 y += f->top_pos;
2068 /* Create all the necessary panes and their items. */
2069 maxwidth = maxlines = lines = i = 0;
2070 lpane = XM_FAILURE;
2071 while (i < menu_items_used)
2073 if (EQ (AREF (menu_items, i), Qt))
2075 /* Create a new pane. */
2076 Lisp_Object pane_name, prefix;
2077 const char *pane_string;
2079 maxlines = max (maxlines, lines);
2080 lines = 0;
2081 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2082 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2083 pane_string = (NILP (pane_name)
2084 ? "" : SSDATA (pane_name));
2085 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2086 pane_string++;
2088 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2089 if (lpane == XM_FAILURE)
2091 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2092 *error_name = "Can't create pane";
2093 goto return_entry;
2095 i += MENU_ITEMS_PANE_LENGTH;
2097 /* Find the width of the widest item in this pane. */
2098 j = i;
2099 while (j < menu_items_used)
2101 Lisp_Object item;
2102 item = AREF (menu_items, j);
2103 if (EQ (item, Qt))
2104 break;
2105 if (NILP (item))
2107 j++;
2108 continue;
2110 width = SBYTES (item);
2111 if (width > maxwidth)
2112 maxwidth = width;
2114 j += MENU_ITEMS_ITEM_LENGTH;
2117 /* Ignore a nil in the item list.
2118 It's meaningful only for dialog boxes. */
2119 else if (EQ (AREF (menu_items, i), Qquote))
2120 i += 1;
2121 else
2123 /* Create a new item within current pane. */
2124 Lisp_Object item_name, enable, descrip, help;
2125 char *item_data;
2126 char const *help_string;
2128 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2129 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2130 descrip
2131 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2132 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2133 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2135 if (!NILP (descrip))
2137 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2138 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2139 for (j = SCHARS (item_name); j < maxwidth; j++)
2140 item_data[j] = ' ';
2141 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2142 item_data[j + SBYTES (descrip)] = 0;
2144 else
2145 item_data = SSDATA (item_name);
2147 if (lpane == XM_FAILURE
2148 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2149 menu, lpane, 0, item_data,
2150 !NILP (enable), help_string)
2151 == XM_FAILURE))
2153 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2154 *error_name = "Can't add selection to menu";
2155 goto return_entry;
2157 i += MENU_ITEMS_ITEM_LENGTH;
2158 lines++;
2162 maxlines = max (maxlines, lines);
2164 /* All set and ready to fly. */
2165 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2166 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2167 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2168 x = min (x, dispwidth);
2169 y = min (y, dispheight);
2170 x = max (x, 1);
2171 y = max (y, 1);
2172 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2173 &ulx, &uly, &width, &height);
2174 if (ulx+width > dispwidth)
2176 x -= (ulx + width) - dispwidth;
2177 ulx = dispwidth - width;
2179 if (uly+height > dispheight)
2181 y -= (uly + height) - dispheight;
2182 uly = dispheight - height;
2184 #ifndef HAVE_X_WINDOWS
2185 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2187 /* Move the menu away of the echo area, to avoid overwriting the
2188 menu with help echo messages or vice versa. */
2189 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2191 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2192 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2194 else
2196 y--;
2197 uly--;
2200 #endif
2201 if (ulx < 0) x -= ulx;
2202 if (uly < 0) y -= uly;
2204 if (!(menuflags & MENU_FOR_CLICK))
2206 /* If position was not given by a mouse click, adjust so upper left
2207 corner of the menu as a whole ends up at given coordinates. This
2208 is what x-popup-menu says in its documentation. */
2209 x += width/2;
2210 y += 1.5*height/(maxlines+2);
2213 XMenuSetAEQ (menu, TRUE);
2214 XMenuSetFreeze (menu, TRUE);
2215 pane = selidx = 0;
2217 #ifndef MSDOS
2218 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2219 #endif
2221 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2223 /* Help display under X won't work because XMenuActivate contains
2224 a loop that doesn't give Emacs a chance to process it. */
2225 menu_help_frame = f;
2226 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2227 x, y, ButtonReleaseMask, &datap,
2228 menu_help_callback);
2229 pane_prefix = Qnil;
2231 switch (status)
2233 case XM_SUCCESS:
2234 #ifdef XDEBUG
2235 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2236 #endif
2238 /* Find the item number SELIDX in pane number PANE. */
2239 i = 0;
2240 while (i < menu_items_used)
2242 if (EQ (AREF (menu_items, i), Qt))
2244 if (pane == 0)
2245 pane_prefix
2246 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2247 pane--;
2248 i += MENU_ITEMS_PANE_LENGTH;
2250 else
2252 if (pane == -1)
2254 if (selidx == 0)
2256 entry
2257 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2258 if (menuflags & MENU_KEYMAPS)
2260 entry = list1 (entry);
2261 if (!NILP (pane_prefix))
2262 entry = Fcons (pane_prefix, entry);
2264 break;
2266 selidx--;
2268 i += MENU_ITEMS_ITEM_LENGTH;
2271 break;
2273 case XM_FAILURE:
2274 *error_name = "Can't activate menu";
2275 case XM_IA_SELECT:
2276 break;
2277 case XM_NO_SELECT:
2278 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2279 the menu was invoked with a mouse event as POSITION). */
2280 if (!(menuflags & MENU_FOR_CLICK))
2282 unblock_input ();
2283 Fsignal (Qquit, Qnil);
2285 break;
2288 return_entry:
2289 unblock_input ();
2290 SAFE_FREE ();
2291 return unbind_to (specpdl_count, entry);
2294 #endif /* not USE_X_TOOLKIT */
2296 #ifndef MSDOS
2297 /* Detect if a dialog or menu has been posted. MSDOS has its own
2298 implementation on msdos.c. */
2300 int ATTRIBUTE_CONST
2301 popup_activated (void)
2303 return popup_activated_flag;
2305 #endif /* not MSDOS */
2307 /* The following is used by delayed window autoselection. */
2309 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2310 doc: /* Return t if a menu or popup dialog is active. */)
2311 (void)
2313 return (popup_activated ()) ? Qt : Qnil;
2316 void
2317 syms_of_xmenu (void)
2319 #ifdef USE_X_TOOLKIT
2320 enum { WIDGET_ID_TICK_START = 1 << 16 };
2321 widget_id_tick = WIDGET_ID_TICK_START;
2322 next_menubar_widget_id = 1;
2323 #endif
2325 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2326 defsubr (&Smenu_or_popup_active_p);
2328 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2329 defsubr (&Sx_menu_bar_open_internal);
2330 Ffset (intern_c_string ("accelerate-menu"),
2331 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2332 #endif