Fix last commit in w32term.c.
[emacs.git] / src / xmenu.c
blobf4d0921762cbbcbfc3557d5c8d9cffb680b56b6d
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 unblock_input ();
667 #endif
670 #ifdef USE_LUCID
671 static void
672 apply_systemfont_to_dialog (Widget w)
674 const char *fn = xsettings_get_system_normal_font ();
675 if (fn)
677 XrmDatabase db = XtDatabase (XtDisplay (w));
678 if (db)
679 XrmPutStringResource (&db, "*dialog.font", fn);
683 static void
684 apply_systemfont_to_menu (struct frame *f, Widget w)
686 const char *fn = xsettings_get_system_normal_font ();
688 if (fn)
690 XrmDatabase db = XtDatabase (XtDisplay (w));
691 if (db)
693 XrmPutStringResource (&db, "*menubar*font", fn);
694 XrmPutStringResource (&db, "*popup*font", fn);
699 #endif
701 /* Set the contents of the menubar widgets of frame F.
702 The argument FIRST_TIME is currently ignored;
703 it is set the first time this is called, from initialize_frame_menubar. */
705 void
706 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
708 xt_or_gtk_widget menubar_widget;
709 #ifdef USE_X_TOOLKIT
710 LWLIB_ID id;
711 #endif
712 Lisp_Object items;
713 widget_value *wv, *first_wv, *prev_wv = 0;
714 int i;
715 int *submenu_start, *submenu_end;
716 bool *submenu_top_level_items;
717 int *submenu_n_panes;
719 eassert (FRAME_X_P (f));
721 menubar_widget = f->output_data.x->menubar_widget;
723 XSETFRAME (Vmenu_updating_frame, f);
725 #ifdef USE_X_TOOLKIT
726 if (f->output_data.x->id == 0)
727 f->output_data.x->id = next_menubar_widget_id++;
728 id = f->output_data.x->id;
729 #endif
731 if (! menubar_widget)
732 deep_p = 1;
733 /* Make the first call for any given frame always go deep. */
734 else if (!f->output_data.x->saved_menu_event && !deep_p)
736 deep_p = 1;
737 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
738 f->output_data.x->saved_menu_event->type = 0;
741 #ifdef USE_GTK
742 /* If we have detached menus, we must update deep so detached menus
743 also gets updated. */
744 deep_p = deep_p || xg_have_tear_offs (f);
745 #endif
747 if (deep_p)
749 /* Make a widget-value tree representing the entire menu trees. */
751 struct buffer *prev = current_buffer;
752 Lisp_Object buffer;
753 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
754 int previous_menu_items_used = f->menu_bar_items_used;
755 Lisp_Object *previous_items
756 = alloca (previous_menu_items_used * sizeof *previous_items);
757 int subitems;
759 /* If we are making a new widget, its contents are empty,
760 do always reinitialize them. */
761 if (! menubar_widget)
762 previous_menu_items_used = 0;
764 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
765 specbind (Qinhibit_quit, Qt);
766 /* Don't let the debugger step into this code
767 because it is not reentrant. */
768 specbind (Qdebug_on_next_call, Qnil);
770 record_unwind_save_match_data ();
771 if (NILP (Voverriding_local_map_menu_flag))
773 specbind (Qoverriding_terminal_local_map, Qnil);
774 specbind (Qoverriding_local_map, Qnil);
777 set_buffer_internal_1 (XBUFFER (buffer));
779 /* Run the Lucid hook. */
780 safe_run_hooks (Qactivate_menubar_hook);
782 /* If it has changed current-menubar from previous value,
783 really recompute the menubar from the value. */
784 if (! NILP (Vlucid_menu_bar_dirty_flag))
785 call0 (Qrecompute_lucid_menubar);
786 safe_run_hooks (Qmenu_bar_update_hook);
787 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
789 items = FRAME_MENU_BAR_ITEMS (f);
791 /* Save the frame's previous menu bar contents data. */
792 if (previous_menu_items_used)
793 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
794 previous_menu_items_used * word_size);
796 /* Fill in menu_items with the current menu bar contents.
797 This can evaluate Lisp code. */
798 save_menu_items ();
800 menu_items = f->menu_bar_vector;
801 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
802 subitems = ASIZE (items) / 4;
803 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
804 submenu_end = alloca (subitems * sizeof *submenu_end);
805 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
806 submenu_top_level_items = alloca (subitems
807 * sizeof *submenu_top_level_items);
808 init_menu_items ();
809 for (i = 0; i < subitems; i++)
811 Lisp_Object key, string, maps;
813 key = AREF (items, 4 * i);
814 string = AREF (items, 4 * i + 1);
815 maps = AREF (items, 4 * i + 2);
816 if (NILP (string))
817 break;
819 submenu_start[i] = menu_items_used;
821 menu_items_n_panes = 0;
822 submenu_top_level_items[i]
823 = parse_single_submenu (key, string, maps);
824 submenu_n_panes[i] = menu_items_n_panes;
826 submenu_end[i] = menu_items_used;
829 submenu_start[i] = -1;
830 finish_menu_items ();
832 /* Convert menu_items into widget_value trees
833 to display the menu. This cannot evaluate Lisp code. */
835 wv = make_widget_value ("menubar", NULL, true, Qnil);
836 wv->button_type = BUTTON_TYPE_NONE;
837 first_wv = wv;
839 for (i = 0; submenu_start[i] >= 0; i++)
841 menu_items_n_panes = submenu_n_panes[i];
842 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
843 submenu_top_level_items[i]);
844 if (prev_wv)
845 prev_wv->next = wv;
846 else
847 first_wv->contents = wv;
848 /* Don't set wv->name here; GC during the loop might relocate it. */
849 wv->enabled = 1;
850 wv->button_type = BUTTON_TYPE_NONE;
851 prev_wv = wv;
854 set_buffer_internal_1 (prev);
856 /* If there has been no change in the Lisp-level contents
857 of the menu bar, skip redisplaying it. Just exit. */
859 /* Compare the new menu items with the ones computed last time. */
860 for (i = 0; i < previous_menu_items_used; i++)
861 if (menu_items_used == i
862 || (!EQ (previous_items[i], AREF (menu_items, i))))
863 break;
864 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
866 /* The menu items have not changed. Don't bother updating
867 the menus in any form, since it would be a no-op. */
868 free_menubar_widget_value_tree (first_wv);
869 discard_menu_items ();
870 unbind_to (specpdl_count, Qnil);
871 return;
874 /* The menu items are different, so store them in the frame. */
875 fset_menu_bar_vector (f, menu_items);
876 f->menu_bar_items_used = menu_items_used;
878 /* This undoes save_menu_items. */
879 unbind_to (specpdl_count, Qnil);
881 /* Now GC cannot happen during the lifetime of the widget_value,
882 so it's safe to store data from a Lisp_String. */
883 wv = first_wv->contents;
884 for (i = 0; i < ASIZE (items); i += 4)
886 Lisp_Object string;
887 string = AREF (items, i + 1);
888 if (NILP (string))
889 break;
890 wv->name = SSDATA (string);
891 update_submenu_strings (wv->contents);
892 wv = wv->next;
896 else
898 /* Make a widget-value tree containing
899 just the top level menu bar strings. */
901 wv = make_widget_value ("menubar", NULL, true, Qnil);
902 wv->button_type = BUTTON_TYPE_NONE;
903 first_wv = wv;
905 items = FRAME_MENU_BAR_ITEMS (f);
906 for (i = 0; i < ASIZE (items); i += 4)
908 Lisp_Object string;
910 string = AREF (items, i + 1);
911 if (NILP (string))
912 break;
914 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
915 wv->button_type = BUTTON_TYPE_NONE;
916 /* This prevents lwlib from assuming this
917 menu item is really supposed to be empty. */
918 /* The intptr_t cast avoids a warning.
919 This value just has to be different from small integers. */
920 wv->call_data = (void *) (intptr_t) (-1);
922 if (prev_wv)
923 prev_wv->next = wv;
924 else
925 first_wv->contents = wv;
926 prev_wv = wv;
929 /* Forget what we thought we knew about what is in the
930 detailed contents of the menu bar menus.
931 Changing the top level always destroys the contents. */
932 f->menu_bar_items_used = 0;
935 /* Create or update the menu bar widget. */
937 block_input ();
939 #ifdef USE_GTK
940 xg_crazy_callback_abort = 1;
941 if (menubar_widget)
943 /* The fourth arg is DEEP_P, which says to consider the entire
944 menu trees we supply, rather than just the menu bar item names. */
945 xg_modify_menubar_widgets (menubar_widget,
947 first_wv,
948 deep_p,
949 G_CALLBACK (menubar_selection_callback),
950 G_CALLBACK (popup_deactivate_callback),
951 G_CALLBACK (menu_highlight_callback));
953 else
955 menubar_widget
956 = xg_create_widget ("menubar", "menubar", f, first_wv,
957 G_CALLBACK (menubar_selection_callback),
958 G_CALLBACK (popup_deactivate_callback),
959 G_CALLBACK (menu_highlight_callback));
961 f->output_data.x->menubar_widget = menubar_widget;
965 #else /* not USE_GTK */
966 if (menubar_widget)
968 /* Disable resizing (done for Motif!) */
969 lw_allow_resizing (f->output_data.x->widget, False);
971 /* The third arg is DEEP_P, which says to consider the entire
972 menu trees we supply, rather than just the menu bar item names. */
973 lw_modify_all_widgets (id, first_wv, deep_p);
975 /* Re-enable the edit widget to resize. */
976 lw_allow_resizing (f->output_data.x->widget, True);
978 else
980 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
981 XtTranslations override = XtParseTranslationTable (menuOverride);
983 #ifdef USE_LUCID
984 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
985 #endif
986 menubar_widget = lw_create_widget ("menubar", "menubar", id,
987 first_wv,
988 f->output_data.x->column_widget,
990 popup_activate_callback,
991 menubar_selection_callback,
992 popup_deactivate_callback,
993 menu_highlight_callback);
994 f->output_data.x->menubar_widget = menubar_widget;
996 /* Make menu pop down on C-g. */
997 XtOverrideTranslations (menubar_widget, override);
1001 int menubar_size;
1002 if (f->output_data.x->menubar_widget)
1003 XtRealizeWidget (f->output_data.x->menubar_widget);
1005 menubar_size
1006 = (f->output_data.x->menubar_widget
1007 ? (f->output_data.x->menubar_widget->core.height
1008 + f->output_data.x->menubar_widget->core.border_width)
1009 : 0);
1011 #if 1 /* Experimentally, we now get the right results
1012 for -geometry -0-0 without this. 24 Aug 96, rms.
1013 Maybe so, but the menu bar size is missing the pixels so the
1014 WM size hints are off by these pixels. Jan D, oct 2009. */
1015 #ifdef USE_LUCID
1016 if (FRAME_EXTERNAL_MENU_BAR (f))
1018 Dimension ibw = 0;
1019 XtVaGetValues (f->output_data.x->column_widget,
1020 XtNinternalBorderWidth, &ibw, NULL);
1021 menubar_size += ibw;
1023 #endif /* USE_LUCID */
1024 #endif /* 1 */
1026 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1028 #endif /* not USE_GTK */
1030 free_menubar_widget_value_tree (first_wv);
1031 update_frame_menubar (f);
1033 #ifdef USE_GTK
1034 xg_crazy_callback_abort = 0;
1035 #endif
1037 unblock_input ();
1040 /* Called from Fx_create_frame to create the initial menubar of a frame
1041 before it is mapped, so that the window is mapped with the menubar already
1042 there instead of us tacking it on later and thrashing the window after it
1043 is visible. */
1045 void
1046 initialize_frame_menubar (struct frame *f)
1048 /* This function is called before the first chance to redisplay
1049 the frame. It has to be, so the frame will have the right size. */
1050 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1051 set_frame_menubar (f, 1, 1);
1055 /* Get rid of the menu bar of frame F, and free its storage.
1056 This is used when deleting a frame, and when turning off the menu bar.
1057 For GTK this function is in gtkutil.c. */
1059 #ifndef USE_GTK
1060 void
1061 free_frame_menubar (struct frame *f)
1063 Widget menubar_widget;
1065 eassert (FRAME_X_P (f));
1067 menubar_widget = f->output_data.x->menubar_widget;
1069 FRAME_MENUBAR_HEIGHT (f) = 0;
1071 if (menubar_widget)
1073 #ifdef USE_MOTIF
1074 /* Removing the menu bar magically changes the shell widget's x
1075 and y position of (0, 0) which, when the menu bar is turned
1076 on again, leads to pull-down menus appearing in strange
1077 positions near the upper-left corner of the display. This
1078 happens only with some window managers like twm and ctwm,
1079 but not with other like Motif's mwm or kwm, because the
1080 latter generate ConfigureNotify events when the menu bar
1081 is switched off, which fixes the shell position. */
1082 Position x0, y0, x1, y1;
1083 #endif
1085 block_input ();
1087 #ifdef USE_MOTIF
1088 if (f->output_data.x->widget)
1089 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1090 #endif
1092 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1093 f->output_data.x->menubar_widget = NULL;
1095 if (f->output_data.x->widget)
1097 #ifdef USE_MOTIF
1098 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1099 if (x1 == 0 && y1 == 0)
1100 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1101 #endif
1102 x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
1104 unblock_input ();
1107 #endif /* not USE_GTK */
1109 #endif /* USE_X_TOOLKIT || USE_GTK */
1111 /* x_menu_show actually displays a menu using the panes and items in menu_items
1112 and returns the value selected from it.
1113 There are two versions of x_menu_show, one for Xt and one for Xlib.
1114 Both assume input is blocked by the caller. */
1116 /* F is the frame the menu is for.
1117 X and Y are the frame-relative specified position,
1118 relative to the inside upper left corner of the frame F.
1119 Bitfield MENUFLAGS bits are:
1120 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1121 MENU_KEYMAPS is set if this menu was specified with keymaps;
1122 in that case, we return a list containing the chosen item's value
1123 and perhaps also the pane's prefix.
1124 TITLE is the specified menu title.
1125 ERROR is a place to store an error message string in case of failure.
1126 (We return nil on failure, but the value doesn't actually matter.) */
1128 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1130 /* The item selected in the popup menu. */
1131 static Lisp_Object *volatile menu_item_selection;
1133 #ifdef USE_GTK
1135 /* Used when position a popup menu. See menu_position_func and
1136 create_and_show_popup_menu below. */
1137 struct next_popup_x_y
1139 struct frame *f;
1140 int x;
1141 int y;
1144 /* The menu position function to use if we are not putting a popup
1145 menu where the pointer is.
1146 MENU is the menu to pop up.
1147 X and Y shall on exit contain x/y where the menu shall pop up.
1148 PUSH_IN is not documented in the GTK manual.
1149 USER_DATA is any data passed in when calling gtk_menu_popup.
1150 Here it points to a struct next_popup_x_y where the coordinates
1151 to store in *X and *Y are as well as the frame for the popup.
1153 Here only X and Y are used. */
1154 static void
1155 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1157 struct next_popup_x_y *data = user_data;
1158 GtkRequisition req;
1159 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1160 int disp_width = x_display_pixel_width (dpyinfo);
1161 int disp_height = x_display_pixel_height (dpyinfo);
1163 *x = data->x;
1164 *y = data->y;
1166 /* Check if there is room for the menu. If not, adjust x/y so that
1167 the menu is fully visible. */
1168 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1169 if (data->x + req.width > disp_width)
1170 *x -= data->x + req.width - disp_width;
1171 if (data->y + req.height > disp_height)
1172 *y -= data->y + req.height - disp_height;
1175 static void
1176 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1178 xg_menu_item_cb_data *cb_data = client_data;
1180 if (xg_crazy_callback_abort) return;
1181 if (cb_data) menu_item_selection = cb_data->call_data;
1184 static void
1185 pop_down_menu (void *arg)
1187 popup_activated_flag = 0;
1188 block_input ();
1189 gtk_widget_destroy (GTK_WIDGET (arg));
1190 unblock_input ();
1193 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1194 menu pops down.
1195 menu_item_selection will be set to the selection. */
1196 static void
1197 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1198 int x, int y, bool for_click)
1200 int i;
1201 GtkWidget *menu;
1202 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1203 struct next_popup_x_y popup_x_y;
1204 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1205 bool use_pos_func = ! for_click;
1207 #ifdef HAVE_GTK3
1208 /* Always use position function for Gtk3. Otherwise menus may become
1209 too small to show anything. */
1210 use_pos_func = 1;
1211 #endif
1213 eassert (FRAME_X_P (f));
1215 xg_crazy_callback_abort = 1;
1216 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1217 G_CALLBACK (popup_selection_callback),
1218 G_CALLBACK (popup_deactivate_callback),
1219 G_CALLBACK (menu_highlight_callback));
1220 xg_crazy_callback_abort = 0;
1222 if (use_pos_func)
1224 /* Not invoked by a click. pop up at x/y. */
1225 pos_func = menu_position_func;
1227 /* Adjust coordinates to be root-window-relative. */
1228 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1229 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1231 popup_x_y.x = x;
1232 popup_x_y.y = y;
1233 popup_x_y.f = f;
1235 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1238 if (for_click)
1240 for (i = 0; i < 5; i++)
1241 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1242 break;
1243 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1244 if (i == 5) i = 0;
1247 /* Display the menu. */
1248 gtk_widget_show_all (menu);
1250 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1251 FRAME_DISPLAY_INFO (f)->last_user_time);
1253 record_unwind_protect_ptr (pop_down_menu, menu);
1255 if (gtk_widget_get_mapped (menu))
1257 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1258 two. show_help_echo uses this to detect popup menus. */
1259 popup_activated_flag = 1;
1260 /* Process events that apply to the menu. */
1261 popup_widget_loop (1, menu);
1264 unbind_to (specpdl_count, Qnil);
1266 /* Must reset this manually because the button release event is not passed
1267 to Emacs event loop. */
1268 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1271 #else /* not USE_GTK */
1273 /* We need a unique id for each widget handled by the Lucid Widget
1274 library.
1276 For the main windows, and popup menus, we use this counter, which we
1277 increment each time after use. This starts from WIDGET_ID_TICK_START.
1279 For menu bars, we use numbers starting at 0, counted in
1280 next_menubar_widget_id. */
1281 LWLIB_ID widget_id_tick;
1283 static void
1284 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1286 menu_item_selection = client_data;
1289 /* ID is the LWLIB ID of the dialog box. */
1291 static void
1292 pop_down_menu (int id)
1294 block_input ();
1295 lw_destroy_all_widgets ((LWLIB_ID) id);
1296 unblock_input ();
1297 popup_activated_flag = 0;
1300 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1301 menu pops down.
1302 menu_item_selection will be set to the selection. */
1303 static void
1304 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1305 int x, int y, bool for_click)
1307 int i;
1308 Arg av[2];
1309 int ac = 0;
1310 XEvent dummy;
1311 XButtonPressedEvent *event = &(dummy.xbutton);
1312 LWLIB_ID menu_id;
1313 Widget menu;
1315 eassert (FRAME_X_P (f));
1317 #ifdef USE_LUCID
1318 apply_systemfont_to_menu (f, f->output_data.x->widget);
1319 #endif
1321 menu_id = widget_id_tick++;
1322 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1323 f->output_data.x->widget, 1, 0,
1324 popup_selection_callback,
1325 popup_deactivate_callback,
1326 menu_highlight_callback);
1328 event->type = ButtonPress;
1329 event->serial = 0;
1330 event->send_event = 0;
1331 event->display = FRAME_X_DISPLAY (f);
1332 event->time = CurrentTime;
1333 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1334 event->window = event->subwindow = event->root;
1335 event->x = x;
1336 event->y = y;
1338 /* Adjust coordinates to be root-window-relative. */
1339 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1340 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1342 event->x_root = x;
1343 event->y_root = y;
1345 event->state = 0;
1346 event->button = 0;
1347 for (i = 0; i < 5; i++)
1348 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1349 event->button = i;
1351 /* Don't allow any geometry request from the user. */
1352 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1353 XtSetValues (menu, av, ac);
1355 /* Display the menu. */
1356 lw_popup_menu (menu, &dummy);
1357 popup_activated_flag = 1;
1358 x_activate_timeout_atimer ();
1361 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1363 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1365 /* Process events that apply to the menu. */
1366 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, 1);
1368 unbind_to (specpdl_count, Qnil);
1372 #endif /* not USE_GTK */
1374 static void
1375 cleanup_widget_value_tree (void *arg)
1377 free_menubar_widget_value_tree (arg);
1380 Lisp_Object
1381 x_menu_show (struct frame *f, int x, int y, int menuflags,
1382 Lisp_Object title, const char **error_name)
1384 int i;
1385 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1386 widget_value **submenu_stack
1387 = alloca (menu_items_used * sizeof *submenu_stack);
1388 Lisp_Object *subprefix_stack
1389 = alloca (menu_items_used * sizeof *subprefix_stack);
1390 int submenu_depth = 0;
1392 int first_pane;
1394 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1396 eassert (FRAME_X_P (f));
1398 *error_name = NULL;
1400 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1402 *error_name = "Empty menu";
1403 return Qnil;
1406 block_input ();
1408 /* Create a tree of widget_value objects
1409 representing the panes and their items. */
1410 wv = make_widget_value ("menu", NULL, true, Qnil);
1411 wv->button_type = BUTTON_TYPE_NONE;
1412 first_wv = wv;
1413 first_pane = 1;
1415 /* Loop over all panes and items, filling in the tree. */
1416 i = 0;
1417 while (i < menu_items_used)
1419 if (EQ (AREF (menu_items, i), Qnil))
1421 submenu_stack[submenu_depth++] = save_wv;
1422 save_wv = prev_wv;
1423 prev_wv = 0;
1424 first_pane = 1;
1425 i++;
1427 else if (EQ (AREF (menu_items, i), Qlambda))
1429 prev_wv = save_wv;
1430 save_wv = submenu_stack[--submenu_depth];
1431 first_pane = 0;
1432 i++;
1434 else if (EQ (AREF (menu_items, i), Qt)
1435 && submenu_depth != 0)
1436 i += MENU_ITEMS_PANE_LENGTH;
1437 /* Ignore a nil in the item list.
1438 It's meaningful only for dialog boxes. */
1439 else if (EQ (AREF (menu_items, i), Qquote))
1440 i += 1;
1441 else if (EQ (AREF (menu_items, i), Qt))
1443 /* Create a new pane. */
1444 Lisp_Object pane_name, prefix;
1445 const char *pane_string;
1447 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1448 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1450 #ifndef HAVE_MULTILINGUAL_MENU
1451 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1453 pane_name = ENCODE_MENU_STRING (pane_name);
1454 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1456 #endif
1457 pane_string = (NILP (pane_name)
1458 ? "" : SSDATA (pane_name));
1459 /* If there is just one top-level pane, put all its items directly
1460 under the top-level menu. */
1461 if (menu_items_n_panes == 1)
1462 pane_string = "";
1464 /* If the pane has a meaningful name,
1465 make the pane a top-level menu item
1466 with its items as a submenu beneath it. */
1467 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1469 wv = make_widget_value (pane_string, NULL, true, Qnil);
1470 if (save_wv)
1471 save_wv->next = wv;
1472 else
1473 first_wv->contents = wv;
1474 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1475 wv->name++;
1476 wv->button_type = BUTTON_TYPE_NONE;
1477 save_wv = wv;
1478 prev_wv = 0;
1480 else if (first_pane)
1482 save_wv = wv;
1483 prev_wv = 0;
1485 first_pane = 0;
1486 i += MENU_ITEMS_PANE_LENGTH;
1488 else
1490 /* Create a new item within current pane. */
1491 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1492 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1493 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1494 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1495 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1496 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1497 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1498 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1500 #ifndef HAVE_MULTILINGUAL_MENU
1501 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1503 item_name = ENCODE_MENU_STRING (item_name);
1504 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1507 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1509 descrip = ENCODE_MENU_STRING (descrip);
1510 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1512 #endif /* not HAVE_MULTILINGUAL_MENU */
1514 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1515 STRINGP (help) ? help : Qnil);
1516 if (prev_wv)
1517 prev_wv->next = wv;
1518 else
1519 save_wv->contents = wv;
1520 if (!NILP (descrip))
1521 wv->key = SSDATA (descrip);
1522 /* If this item has a null value,
1523 make the call_data null so that it won't display a box
1524 when the mouse is on it. */
1525 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1527 if (NILP (type))
1528 wv->button_type = BUTTON_TYPE_NONE;
1529 else if (EQ (type, QCtoggle))
1530 wv->button_type = BUTTON_TYPE_TOGGLE;
1531 else if (EQ (type, QCradio))
1532 wv->button_type = BUTTON_TYPE_RADIO;
1533 else
1534 emacs_abort ();
1536 wv->selected = !NILP (selected);
1538 prev_wv = wv;
1540 i += MENU_ITEMS_ITEM_LENGTH;
1544 /* Deal with the title, if it is non-nil. */
1545 if (!NILP (title))
1547 widget_value *wv_title;
1548 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1549 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1551 wv_sep2->next = first_wv->contents;
1552 wv_sep1->next = wv_sep2;
1554 #ifndef HAVE_MULTILINGUAL_MENU
1555 if (STRING_MULTIBYTE (title))
1556 title = ENCODE_MENU_STRING (title);
1557 #endif
1559 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1560 wv_title->button_type = BUTTON_TYPE_NONE;
1561 wv_title->next = wv_sep1;
1562 first_wv->contents = wv_title;
1565 /* No selection has been chosen yet. */
1566 menu_item_selection = 0;
1568 /* Make sure to free the widget_value objects we used to specify the
1569 contents even with longjmp. */
1570 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1572 /* Actually create and show the menu until popped down. */
1573 create_and_show_popup_menu (f, first_wv, x, y,
1574 menuflags & MENU_FOR_CLICK);
1576 unbind_to (specpdl_count, Qnil);
1578 /* Find the selected item, and its pane, to return
1579 the proper value. */
1580 if (menu_item_selection != 0)
1582 Lisp_Object prefix, entry;
1584 prefix = entry = Qnil;
1585 i = 0;
1586 while (i < menu_items_used)
1588 if (EQ (AREF (menu_items, i), Qnil))
1590 subprefix_stack[submenu_depth++] = prefix;
1591 prefix = entry;
1592 i++;
1594 else if (EQ (AREF (menu_items, i), Qlambda))
1596 prefix = subprefix_stack[--submenu_depth];
1597 i++;
1599 else if (EQ (AREF (menu_items, i), Qt))
1601 prefix
1602 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1603 i += MENU_ITEMS_PANE_LENGTH;
1605 /* Ignore a nil in the item list.
1606 It's meaningful only for dialog boxes. */
1607 else if (EQ (AREF (menu_items, i), Qquote))
1608 i += 1;
1609 else
1611 entry
1612 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1613 if (menu_item_selection == aref_addr (menu_items, i))
1615 if (menuflags & MENU_KEYMAPS)
1617 int j;
1619 entry = list1 (entry);
1620 if (!NILP (prefix))
1621 entry = Fcons (prefix, entry);
1622 for (j = submenu_depth - 1; j >= 0; j--)
1623 if (!NILP (subprefix_stack[j]))
1624 entry = Fcons (subprefix_stack[j], entry);
1626 unblock_input ();
1627 return entry;
1629 i += MENU_ITEMS_ITEM_LENGTH;
1633 else if (!(menuflags & MENU_FOR_CLICK))
1635 unblock_input ();
1636 /* Make "Cancel" equivalent to C-g. */
1637 Fsignal (Qquit, Qnil);
1640 unblock_input ();
1641 return Qnil;
1644 #ifdef USE_GTK
1645 static void
1646 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1648 /* Treat the pointer as an integer. There's no problem
1649 as long as pointers have enough bits to hold small integers. */
1650 if ((intptr_t) client_data != -1)
1651 menu_item_selection = client_data;
1653 popup_activated_flag = 0;
1656 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1657 dialog pops down.
1658 menu_item_selection will be set to the selection. */
1659 static void
1660 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1662 GtkWidget *menu;
1664 eassert (FRAME_X_P (f));
1666 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1667 G_CALLBACK (dialog_selection_callback),
1668 G_CALLBACK (popup_deactivate_callback),
1671 if (menu)
1673 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1674 record_unwind_protect_ptr (pop_down_menu, menu);
1676 /* Display the menu. */
1677 gtk_widget_show_all (menu);
1679 /* Process events that apply to the menu. */
1680 popup_widget_loop (1, menu);
1682 unbind_to (specpdl_count, Qnil);
1686 #else /* not USE_GTK */
1687 static void
1688 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1690 /* Treat the pointer as an integer. There's no problem
1691 as long as pointers have enough bits to hold small integers. */
1692 if ((intptr_t) client_data != -1)
1693 menu_item_selection = client_data;
1695 block_input ();
1696 lw_destroy_all_widgets (id);
1697 unblock_input ();
1698 popup_activated_flag = 0;
1702 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1703 dialog pops down.
1704 menu_item_selection will be set to the selection. */
1705 static void
1706 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1708 LWLIB_ID dialog_id;
1710 eassert (FRAME_X_P (f));
1712 dialog_id = widget_id_tick++;
1713 #ifdef USE_LUCID
1714 apply_systemfont_to_dialog (f->output_data.x->widget);
1715 #endif
1716 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1717 f->output_data.x->widget, 1, 0,
1718 dialog_selection_callback, 0, 0);
1719 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1720 /* Display the dialog box. */
1721 lw_pop_up_all_widgets (dialog_id);
1722 popup_activated_flag = 1;
1723 x_activate_timeout_atimer ();
1725 /* Process events that apply to the dialog box.
1726 Also handle timers. */
1728 ptrdiff_t count = SPECPDL_INDEX ();
1730 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1732 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1734 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, 1);
1736 unbind_to (count, Qnil);
1740 #endif /* not USE_GTK */
1742 static const char * button_names [] = {
1743 "button1", "button2", "button3", "button4", "button5",
1744 "button6", "button7", "button8", "button9", "button10" };
1746 static Lisp_Object
1747 x_dialog_show (struct frame *f, Lisp_Object title,
1748 Lisp_Object header, const char **error_name)
1750 int i, nb_buttons=0;
1751 char dialog_name[6];
1753 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1755 /* Number of elements seen so far, before boundary. */
1756 int left_count = 0;
1757 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1758 int boundary_seen = 0;
1760 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1762 eassert (FRAME_X_P (f));
1764 *error_name = NULL;
1766 if (menu_items_n_panes > 1)
1768 *error_name = "Multiple panes in dialog box";
1769 return Qnil;
1772 /* Create a tree of widget_value objects
1773 representing the text label and buttons. */
1775 Lisp_Object pane_name;
1776 const char *pane_string;
1777 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1778 pane_string = (NILP (pane_name)
1779 ? "" : SSDATA (pane_name));
1780 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1781 first_wv = prev_wv;
1783 /* Loop over all panes and items, filling in the tree. */
1784 i = MENU_ITEMS_PANE_LENGTH;
1785 while (i < menu_items_used)
1788 /* Create a new item within current pane. */
1789 Lisp_Object item_name, enable, descrip;
1790 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1791 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1792 descrip
1793 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1795 if (NILP (item_name))
1797 free_menubar_widget_value_tree (first_wv);
1798 *error_name = "Submenu in dialog items";
1799 return Qnil;
1801 if (EQ (item_name, Qquote))
1803 /* This is the boundary between left-side elts
1804 and right-side elts. Stop incrementing right_count. */
1805 boundary_seen = 1;
1806 i++;
1807 continue;
1809 if (nb_buttons >= 9)
1811 free_menubar_widget_value_tree (first_wv);
1812 *error_name = "Too many dialog items";
1813 return Qnil;
1816 wv = make_widget_value (button_names[nb_buttons],
1817 SSDATA (item_name),
1818 !NILP (enable), Qnil);
1819 prev_wv->next = wv;
1820 if (!NILP (descrip))
1821 wv->key = SSDATA (descrip);
1822 wv->call_data = aref_addr (menu_items, i);
1823 prev_wv = wv;
1825 if (! boundary_seen)
1826 left_count++;
1828 nb_buttons++;
1829 i += MENU_ITEMS_ITEM_LENGTH;
1832 /* If the boundary was not specified,
1833 by default put half on the left and half on the right. */
1834 if (! boundary_seen)
1835 left_count = nb_buttons - nb_buttons / 2;
1837 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1839 /* Frame title: 'Q' = Question, 'I' = Information.
1840 Can also have 'E' = Error if, one day, we want
1841 a popup for errors. */
1842 if (NILP (header))
1843 dialog_name[0] = 'Q';
1844 else
1845 dialog_name[0] = 'I';
1847 /* Dialog boxes use a really stupid name encoding
1848 which specifies how many buttons to use
1849 and how many buttons are on the right. */
1850 dialog_name[1] = '0' + nb_buttons;
1851 dialog_name[2] = 'B';
1852 dialog_name[3] = 'R';
1853 /* Number of buttons to put on the right. */
1854 dialog_name[4] = '0' + nb_buttons - left_count;
1855 dialog_name[5] = 0;
1856 wv->contents = first_wv;
1857 first_wv = wv;
1860 /* No selection has been chosen yet. */
1861 menu_item_selection = 0;
1863 /* Make sure to free the widget_value objects we used to specify the
1864 contents even with longjmp. */
1865 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1867 /* Actually create and show the dialog. */
1868 create_and_show_dialog (f, first_wv);
1870 unbind_to (specpdl_count, Qnil);
1872 /* Find the selected item, and its pane, to return
1873 the proper value. */
1874 if (menu_item_selection != 0)
1876 i = 0;
1877 while (i < menu_items_used)
1879 Lisp_Object entry;
1881 if (EQ (AREF (menu_items, i), Qt))
1882 i += MENU_ITEMS_PANE_LENGTH;
1883 else if (EQ (AREF (menu_items, i), Qquote))
1885 /* This is the boundary between left-side elts and
1886 right-side elts. */
1887 ++i;
1889 else
1891 entry
1892 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1893 if (menu_item_selection == aref_addr (menu_items, i))
1894 return entry;
1895 i += MENU_ITEMS_ITEM_LENGTH;
1899 else
1900 /* Make "Cancel" equivalent to C-g. */
1901 Fsignal (Qquit, Qnil);
1903 return Qnil;
1906 Lisp_Object
1907 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1909 Lisp_Object title;
1910 const char *error_name;
1911 Lisp_Object selection;
1912 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1914 check_window_system (f);
1916 /* Decode the dialog items from what was specified. */
1917 title = Fcar (contents);
1918 CHECK_STRING (title);
1919 record_unwind_protect_void (unuse_menu_items);
1921 if (NILP (Fcar (Fcdr (contents))))
1922 /* No buttons specified, add an "Ok" button so users can pop down
1923 the dialog. Also, the lesstif/motif version crashes if there are
1924 no buttons. */
1925 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1927 list_of_panes (list1 (contents));
1929 /* Display them in a dialog box. */
1930 block_input ();
1931 selection = x_dialog_show (f, title, header, &error_name);
1932 unblock_input ();
1934 unbind_to (specpdl_count, Qnil);
1935 discard_menu_items ();
1937 if (error_name) error ("%s", error_name);
1938 return selection;
1941 #else /* not USE_X_TOOLKIT && not USE_GTK */
1943 /* The frame of the last activated non-toolkit menu bar.
1944 Used to generate menu help events. */
1946 static struct frame *menu_help_frame;
1949 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1951 PANE is the pane number, and ITEM is the menu item number in
1952 the menu (currently not used).
1954 This cannot be done with generating a HELP_EVENT because
1955 XMenuActivate contains a loop that doesn't let Emacs process
1956 keyboard events. */
1958 static void
1959 menu_help_callback (char const *help_string, int pane, int item)
1961 Lisp_Object *first_item;
1962 Lisp_Object pane_name;
1963 Lisp_Object menu_object;
1965 first_item = XVECTOR (menu_items)->contents;
1966 if (EQ (first_item[0], Qt))
1967 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1968 else if (EQ (first_item[0], Qquote))
1969 /* This shouldn't happen, see x_menu_show. */
1970 pane_name = empty_unibyte_string;
1971 else
1972 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1974 /* (menu-item MENU-NAME PANE-NUMBER) */
1975 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1976 show_help_echo (help_string ? build_string (help_string) : Qnil,
1977 Qnil, menu_object, make_number (item));
1980 static void
1981 pop_down_menu (Lisp_Object arg)
1983 struct frame *f = XSAVE_POINTER (arg, 0);
1984 XMenu *menu = XSAVE_POINTER (arg, 1);
1986 block_input ();
1987 #ifndef MSDOS
1988 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
1989 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
1990 #endif
1991 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
1993 #ifdef HAVE_X_WINDOWS
1994 /* Assume the mouse has moved out of the X window.
1995 If it has actually moved in, we will get an EnterNotify. */
1996 x_mouse_leave (FRAME_DISPLAY_INFO (f));
1998 /* State that no mouse buttons are now held.
1999 (The oldXMenu code doesn't track this info for us.)
2000 That is not necessarily true, but the fiction leads to reasonable
2001 results, and it is a pain to ask which are actually held now. */
2002 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2004 #endif /* HAVE_X_WINDOWS */
2006 unblock_input ();
2010 Lisp_Object
2011 x_menu_show (struct frame *f, int x, int y, int menuflags,
2012 Lisp_Object title, const char **error_name)
2014 Window root;
2015 XMenu *menu;
2016 int pane, selidx, lpane, status;
2017 Lisp_Object entry, pane_prefix;
2018 char *datap;
2019 int ulx, uly, width, height;
2020 int dispwidth, dispheight;
2021 int i, j, lines, maxlines;
2022 int maxwidth;
2023 int dummy_int;
2024 unsigned int dummy_uint;
2025 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2027 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2029 *error_name = 0;
2030 if (menu_items_n_panes == 0)
2031 return Qnil;
2033 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2035 *error_name = "Empty menu";
2036 return Qnil;
2039 block_input ();
2041 /* Figure out which root window F is on. */
2042 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2043 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2044 &dummy_uint, &dummy_uint);
2046 /* Make the menu on that window. */
2047 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2048 if (menu == NULL)
2050 *error_name = "Can't create menu";
2051 unblock_input ();
2052 return Qnil;
2055 /* Don't GC while we prepare and show the menu,
2056 because we give the oldxmenu library pointers to the
2057 contents of strings. */
2058 inhibit_garbage_collection ();
2060 #ifdef HAVE_X_WINDOWS
2061 /* Adjust coordinates to relative to the outer (window manager) window. */
2062 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2063 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
2064 #endif /* HAVE_X_WINDOWS */
2066 /* Adjust coordinates to be root-window-relative. */
2067 x += f->left_pos;
2068 y += f->top_pos;
2070 /* Create all the necessary panes and their items. */
2071 maxwidth = maxlines = lines = i = 0;
2072 lpane = XM_FAILURE;
2073 while (i < menu_items_used)
2075 if (EQ (AREF (menu_items, i), Qt))
2077 /* Create a new pane. */
2078 Lisp_Object pane_name, prefix;
2079 const char *pane_string;
2081 maxlines = max (maxlines, lines);
2082 lines = 0;
2083 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2084 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2085 pane_string = (NILP (pane_name)
2086 ? "" : SSDATA (pane_name));
2087 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2088 pane_string++;
2090 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
2091 if (lpane == XM_FAILURE)
2093 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2094 *error_name = "Can't create pane";
2095 unblock_input ();
2096 return Qnil;
2098 i += MENU_ITEMS_PANE_LENGTH;
2100 /* Find the width of the widest item in this pane. */
2101 j = i;
2102 while (j < menu_items_used)
2104 Lisp_Object item;
2105 item = AREF (menu_items, j);
2106 if (EQ (item, Qt))
2107 break;
2108 if (NILP (item))
2110 j++;
2111 continue;
2113 width = SBYTES (item);
2114 if (width > maxwidth)
2115 maxwidth = width;
2117 j += MENU_ITEMS_ITEM_LENGTH;
2120 /* Ignore a nil in the item list.
2121 It's meaningful only for dialog boxes. */
2122 else if (EQ (AREF (menu_items, i), Qquote))
2123 i += 1;
2124 else
2126 /* Create a new item within current pane. */
2127 Lisp_Object item_name, enable, descrip, help;
2128 char *item_data;
2129 char const *help_string;
2131 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2132 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2133 descrip
2134 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2135 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2136 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2138 if (!NILP (descrip))
2140 /* if alloca is fast, use that to make the space,
2141 to reduce gc needs. */
2142 item_data = alloca (maxwidth + SBYTES (descrip) + 1);
2143 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2144 for (j = SCHARS (item_name); j < maxwidth; j++)
2145 item_data[j] = ' ';
2146 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2147 item_data[j + SBYTES (descrip)] = 0;
2149 else
2150 item_data = SSDATA (item_name);
2152 if (lpane == XM_FAILURE
2153 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2154 menu, lpane, 0, item_data,
2155 !NILP (enable), help_string)
2156 == XM_FAILURE))
2158 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2159 *error_name = "Can't add selection to menu";
2160 unblock_input ();
2161 return Qnil;
2163 i += MENU_ITEMS_ITEM_LENGTH;
2164 lines++;
2168 maxlines = max (maxlines, lines);
2170 /* All set and ready to fly. */
2171 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2172 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2173 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2174 x = min (x, dispwidth);
2175 y = min (y, dispheight);
2176 x = max (x, 1);
2177 y = max (y, 1);
2178 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2179 &ulx, &uly, &width, &height);
2180 if (ulx+width > dispwidth)
2182 x -= (ulx + width) - dispwidth;
2183 ulx = dispwidth - width;
2185 if (uly+height > dispheight)
2187 y -= (uly + height) - dispheight;
2188 uly = dispheight - height;
2190 #ifndef HAVE_X_WINDOWS
2191 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2193 /* Move the menu away of the echo area, to avoid overwriting the
2194 menu with help echo messages or vice versa. */
2195 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2197 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2198 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2200 else
2202 y--;
2203 uly--;
2206 #endif
2207 if (ulx < 0) x -= ulx;
2208 if (uly < 0) y -= uly;
2210 if (!(menuflags & MENU_FOR_CLICK))
2212 /* If position was not given by a mouse click, adjust so upper left
2213 corner of the menu as a whole ends up at given coordinates. This
2214 is what x-popup-menu says in its documentation. */
2215 x += width/2;
2216 y += 1.5*height/(maxlines+2);
2219 XMenuSetAEQ (menu, TRUE);
2220 XMenuSetFreeze (menu, TRUE);
2221 pane = selidx = 0;
2223 #ifndef MSDOS
2224 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2225 #endif
2227 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2229 /* Help display under X won't work because XMenuActivate contains
2230 a loop that doesn't give Emacs a chance to process it. */
2231 menu_help_frame = f;
2232 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2233 x, y, ButtonReleaseMask, &datap,
2234 menu_help_callback);
2235 entry = pane_prefix = Qnil;
2237 switch (status)
2239 case XM_SUCCESS:
2240 #ifdef XDEBUG
2241 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2242 #endif
2244 /* Find the item number SELIDX in pane number PANE. */
2245 i = 0;
2246 while (i < menu_items_used)
2248 if (EQ (AREF (menu_items, i), Qt))
2250 if (pane == 0)
2251 pane_prefix
2252 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2253 pane--;
2254 i += MENU_ITEMS_PANE_LENGTH;
2256 else
2258 if (pane == -1)
2260 if (selidx == 0)
2262 entry
2263 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2264 if (menuflags & MENU_KEYMAPS)
2266 entry = list1 (entry);
2267 if (!NILP (pane_prefix))
2268 entry = Fcons (pane_prefix, entry);
2270 break;
2272 selidx--;
2274 i += MENU_ITEMS_ITEM_LENGTH;
2277 break;
2279 case XM_FAILURE:
2280 *error_name = "Can't activate menu";
2281 case XM_IA_SELECT:
2282 break;
2283 case XM_NO_SELECT:
2284 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2285 the menu was invoked with a mouse event as POSITION). */
2286 if (!(menuflags & MENU_FOR_CLICK))
2288 unblock_input ();
2289 Fsignal (Qquit, Qnil);
2291 break;
2294 unblock_input ();
2295 unbind_to (specpdl_count, Qnil);
2297 return entry;
2300 #endif /* not USE_X_TOOLKIT */
2302 #ifndef MSDOS
2303 /* Detect if a dialog or menu has been posted. MSDOS has its own
2304 implementation on msdos.c. */
2306 int ATTRIBUTE_CONST
2307 popup_activated (void)
2309 return popup_activated_flag;
2311 #endif /* not MSDOS */
2313 /* The following is used by delayed window autoselection. */
2315 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2316 doc: /* Return t if a menu or popup dialog is active. */)
2317 (void)
2319 return (popup_activated ()) ? Qt : Qnil;
2322 void
2323 syms_of_xmenu (void)
2325 #ifdef USE_X_TOOLKIT
2326 enum { WIDGET_ID_TICK_START = 1 << 16 };
2327 widget_id_tick = WIDGET_ID_TICK_START;
2328 next_menubar_widget_id = 1;
2329 #endif
2331 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2332 defsubr (&Smenu_or_popup_active_p);
2334 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2335 defsubr (&Sx_menu_bar_open_internal);
2336 Ffset (intern_c_string ("accelerate-menu"),
2337 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2338 #endif