; doc/emacs/misc.texi (Network Security): Fix typo.
[emacs.git] / src / xmenu.c
blob6477d5b0aca29327e86bae3d16632752a8656abe
1 /* X Communication module for terminals which understand the X protocol.
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2018 Free Software
4 Foundation, Inc.
6 Author: Jon Arnold
7 Roman Budzianowski
8 Robert Krawitz
10 This file is part of GNU Emacs.
12 GNU Emacs is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or (at
15 your option) any later version.
17 GNU Emacs is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
25 /* X pop-up deck-of-cards menu facility for GNU Emacs.
29 /* Modified by Fred Pierresteguy on December 93
30 to make the popup menus and menubar use the Xt. */
32 /* Rewritten for clarity and GC protection by rms in Feb 94. */
34 #include <config.h>
36 #include <stdio.h>
38 #include "lisp.h"
39 #include "keyboard.h"
40 #include "frame.h"
41 #include "systime.h"
42 #include "termhooks.h"
43 #include "window.h"
44 #include "blockinput.h"
45 #include "buffer.h"
46 #include "coding.h"
47 #include "sysselect.h"
49 #ifdef MSDOS
50 #include "msdos.h"
51 #endif
53 #ifdef HAVE_X_WINDOWS
54 /* This may include sys/types.h, and that somehow loses
55 if this is not done before the other system files. */
56 #include "xterm.h"
57 #endif
59 /* Load sys/types.h if not already loaded.
60 In some systems loading it twice is suicidal. */
61 #ifndef makedev
62 #include <sys/types.h>
63 #endif
65 #ifdef HAVE_X_WINDOWS
66 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu
67 code accepts the Emacs internal encoding. */
68 #undef HAVE_MULTILINGUAL_MENU
69 #ifdef USE_X_TOOLKIT
70 #include "widget.h"
71 #include <X11/Xlib.h>
72 #include <X11/IntrinsicP.h>
73 #include <X11/CoreP.h>
74 #include <X11/StringDefs.h>
75 #include <X11/Shell.h>
76 #ifdef USE_LUCID
77 #include "xsettings.h"
78 #include "../lwlib/xlwmenu.h"
79 #ifdef HAVE_XAW3D
80 #include <X11/Xaw3d/Paned.h>
81 #else /* !HAVE_XAW3D */
82 #include <X11/Xaw/Paned.h>
83 #endif /* HAVE_XAW3D */
84 #endif /* USE_LUCID */
85 #ifdef USE_MOTIF
86 #include "../lwlib/lwlib.h"
87 #endif
88 #else /* not USE_X_TOOLKIT */
89 #ifndef USE_GTK
90 #include "../oldXMenu/XMenu.h"
91 #endif
92 #endif /* not USE_X_TOOLKIT */
93 #endif /* HAVE_X_WINDOWS */
95 #ifdef USE_GTK
96 #include "gtkutil.h"
97 #ifdef HAVE_GTK3
98 #include "xgselect.h"
99 #endif
100 #endif
102 #include "menu.h"
105 /* Flag which when set indicates a dialog or menu has been posted by
106 Xt on behalf of one of the widget sets. */
107 static int popup_activated_flag;
110 #ifdef USE_X_TOOLKIT
112 static LWLIB_ID next_menubar_widget_id;
114 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
116 static struct frame *
117 menubar_id_to_frame (LWLIB_ID id)
119 Lisp_Object tail, frame;
120 struct frame *f;
122 FOR_EACH_FRAME (tail, frame)
124 f = XFRAME (frame);
125 if (!FRAME_WINDOW_P (f))
126 continue;
127 if (f->output_data.x->id == id)
128 return f;
130 return 0;
133 #endif
135 #ifndef MSDOS
137 #if defined USE_GTK || defined USE_MOTIF
139 /* Set menu_items_inuse so no other popup menu or dialog is created. */
141 void
142 x_menu_set_in_use (bool in_use)
144 Lisp_Object frames, frame;
146 menu_items_inuse = in_use ? Qt : Qnil;
147 popup_activated_flag = in_use;
148 #ifdef USE_X_TOOLKIT
149 if (popup_activated_flag)
150 x_activate_timeout_atimer ();
151 #endif
153 /* Don't let frames in `above' z-group obscure popups. */
154 FOR_EACH_FRAME (frames, frame)
156 struct frame *f = XFRAME (frame);
158 if (in_use && FRAME_Z_GROUP_ABOVE (f))
159 x_set_z_group (f, Qabove_suspended, Qabove);
160 else if (!in_use && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
161 x_set_z_group (f, Qabove, Qabove_suspended);
164 #endif
166 /* Wait for an X event to arrive or for a timer to expire. */
168 void
169 x_menu_wait_for_event (void *data)
171 /* Another way to do this is to register a timer callback, that can be
172 done in GTK and Xt. But we have to do it like this when using only X
173 anyway, and with callbacks we would have three variants for timer handling
174 instead of the small ifdefs below. */
176 while (
177 #ifdef USE_X_TOOLKIT
178 ! XtAppPending (Xt_app_con)
179 #elif defined USE_GTK
180 ! gtk_events_pending ()
181 #else
182 ! XPending (data)
183 #endif
186 struct timespec next_time = timer_check (), *ntp;
187 fd_set read_fds;
188 struct x_display_info *dpyinfo;
189 int n = 0;
191 FD_ZERO (&read_fds);
192 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
194 int fd = ConnectionNumber (dpyinfo->display);
195 FD_SET (fd, &read_fds);
196 if (fd > n) n = fd;
197 XFlush (dpyinfo->display);
200 if (! timespec_valid_p (next_time))
201 ntp = 0;
202 else
203 ntp = &next_time;
205 #if defined USE_GTK && defined HAVE_GTK3
206 /* Gtk3 have arrows on menus when they don't fit. When the
207 pointer is over an arrow, a timeout scrolls it a bit. Use
208 xg_select so that timeout gets triggered. */
209 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
210 #else
211 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
212 #endif
215 #endif /* ! MSDOS */
218 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
220 #ifdef USE_X_TOOLKIT
222 /* Loop in Xt until the menu pulldown or dialog popup has been
223 popped down (deactivated). This is used for x-popup-menu
224 and x-popup-dialog; it is not used for the menu bar.
226 NOTE: All calls to popup_get_selection should be protected
227 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
229 static void
230 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
231 LWLIB_ID id, bool do_timers)
233 XEvent event;
235 while (popup_activated_flag)
237 if (initial_event)
239 event = *initial_event;
240 initial_event = 0;
242 else
244 if (do_timers) x_menu_wait_for_event (0);
245 XtAppNextEvent (Xt_app_con, &event);
248 /* Make sure we don't consider buttons grabbed after menu goes.
249 And make sure to deactivate for any ButtonRelease,
250 even if XtDispatchEvent doesn't do that. */
251 if (event.type == ButtonRelease
252 && dpyinfo->display == event.xbutton.display)
254 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
255 #ifdef USE_MOTIF /* Pretending that the event came from a
256 Btn1Down seems the only way to convince Motif to
257 activate its callbacks; setting the XmNmenuPost
258 isn't working. --marcus@sysc.pdx.edu. */
259 event.xbutton.button = 1;
260 /* Motif only pops down menus when no Ctrl, Alt or Mod
261 key is pressed and the button is released. So reset key state
262 so Motif thinks this is the case. */
263 event.xbutton.state = 0;
264 #endif
266 /* Pop down on C-g and Escape. */
267 else if (event.type == KeyPress
268 && dpyinfo->display == event.xbutton.display)
270 KeySym keysym = XLookupKeysym (&event.xkey, 0);
272 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
273 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
274 popup_activated_flag = 0;
277 x_dispatch_event (&event, event.xany.display);
281 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
282 doc: /* SKIP: real doc in USE_GTK definition in xmenu.c. */)
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, false, true);
293 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
294 if (menubar)
296 Window child;
297 bool error_p = false;
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_after_check ();
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, false, true);
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 (bool 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, false, true);
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
492 show_help_echo (help, Qnil, Qnil, Qnil);
495 /* Callback called when menu items are highlighted/unhighlighted
496 while moving the mouse over them. WIDGET is the menu bar or menu
497 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
498 the data structure for the menu item, or null in case of
499 unhighlighting. */
501 #ifdef USE_GTK
502 static void
503 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
505 xg_menu_item_cb_data *cb_data;
506 Lisp_Object help;
508 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
509 if (! cb_data) return;
511 help = call_data ? cb_data->help : Qnil;
513 /* If popup_activated_flag is greater than 1 we are in a popup menu.
514 Don't pass the frame to show_help_event for those.
515 Passing frame creates an Emacs event. As we are looping in
516 popup_widget_loop, it won't be handled. Passing NULL shows the tip
517 directly without using an Emacs event. This is what the Lucid code
518 does below. */
519 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
520 widget, help);
522 #else
523 static void
524 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
526 widget_value *wv = call_data;
527 Lisp_Object help = wv ? wv->help : Qnil;
529 /* Determine the frame for the help event. */
530 struct frame *f = menubar_id_to_frame (id);
532 show_help_event (f, widget, help);
534 #endif
536 #ifdef USE_GTK
537 /* Gtk calls callbacks just because we tell it what item should be
538 selected in a radio group. If this variable is set to a non-zero
539 value, we are creating menus and don't want callbacks right now.
541 static bool xg_crazy_callback_abort;
543 /* This callback is called from the menu bar pulldown menu
544 when the user makes a selection.
545 Figure out what the user chose
546 and put the appropriate events into the keyboard buffer. */
547 static void
548 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
550 xg_menu_item_cb_data *cb_data = client_data;
552 if (xg_crazy_callback_abort)
553 return;
555 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
556 return;
558 /* For a group of radio buttons, GTK calls the selection callback first
559 for the item that was active before the selection and then for the one that
560 is active after the selection. For C-h k this means we get the help on
561 the deselected item and then the selected item is executed. Prevent that
562 by ignoring the non-active item. */
563 if (GTK_IS_RADIO_MENU_ITEM (widget)
564 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
565 return;
567 /* When a menu is popped down, X generates a focus event (i.e. focus
568 goes back to the frame below the menu). Since GTK buffers events,
569 we force it out here before the menu selection event. Otherwise
570 sit-for will exit at once if the focus event follows the menu selection
571 event. */
573 block_input ();
574 while (gtk_events_pending ())
575 gtk_main_iteration ();
576 unblock_input ();
578 find_and_call_menu_selection (cb_data->cl_data->f,
579 cb_data->cl_data->menu_bar_items_used,
580 cb_data->cl_data->menu_bar_vector,
581 cb_data->call_data);
584 #else /* not USE_GTK */
586 /* This callback is called from the menu bar pulldown menu
587 when the user makes a selection.
588 Figure out what the user chose
589 and put the appropriate events into the keyboard buffer. */
590 static void
591 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
593 struct frame *f;
595 f = menubar_id_to_frame (id);
596 if (!f)
597 return;
598 find_and_call_menu_selection (f, f->menu_bar_items_used,
599 f->menu_bar_vector, client_data);
601 #endif /* not USE_GTK */
603 /* Recompute all the widgets of frame F, when the menu bar has been
604 changed. */
606 static void
607 update_frame_menubar (struct frame *f)
609 #ifdef USE_GTK
610 xg_update_frame_menubar (f);
611 #else
612 struct x_output *x;
614 eassert (FRAME_X_P (f));
616 x = f->output_data.x;
618 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
619 return;
621 block_input ();
623 /* Do the voodoo which means "I'm changing lots of things, don't try
624 to refigure sizes until I'm done." */
625 lw_refigure_widget (x->column_widget, False);
627 /* The order in which children are managed is the top to bottom
628 order in which they are displayed in the paned window. First,
629 remove the text-area widget. */
630 XtUnmanageChild (x->edit_widget);
632 /* Remove the menubar that is there now, and put up the menubar that
633 should be there. */
634 XtManageChild (x->menubar_widget);
635 XtMapWidget (x->menubar_widget);
636 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
638 /* Re-manage the text-area widget, and then thrash the sizes. */
639 XtManageChild (x->edit_widget);
640 lw_refigure_widget (x->column_widget, True);
642 /* Force the pane widget to resize itself. */
643 adjust_frame_size (f, -1, -1, 2, false, Qupdate_frame_menubar);
644 unblock_input ();
645 #endif /* USE_GTK */
648 #ifdef USE_LUCID
649 static void
650 apply_systemfont_to_dialog (Widget w)
652 const char *fn = xsettings_get_system_normal_font ();
653 if (fn)
655 XrmDatabase db = XtDatabase (XtDisplay (w));
656 if (db)
657 XrmPutStringResource (&db, "*dialog.font", fn);
661 static void
662 apply_systemfont_to_menu (struct frame *f, Widget w)
664 const char *fn = xsettings_get_system_normal_font ();
666 if (fn)
668 XrmDatabase db = XtDatabase (XtDisplay (w));
669 if (db)
671 XrmPutStringResource (&db, "*menubar*font", fn);
672 XrmPutStringResource (&db, "*popup*font", fn);
677 #endif
679 /* Set the contents of the menubar widgets of frame F.
680 The argument FIRST_TIME is currently ignored;
681 it is set the first time this is called, from initialize_frame_menubar. */
683 void
684 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
686 xt_or_gtk_widget menubar_widget, old_widget;
687 #ifdef USE_X_TOOLKIT
688 LWLIB_ID id;
689 #endif
690 Lisp_Object items;
691 widget_value *wv, *first_wv, *prev_wv = 0;
692 int i;
693 int *submenu_start, *submenu_end;
694 bool *submenu_top_level_items;
695 int *submenu_n_panes;
697 eassert (FRAME_X_P (f));
699 menubar_widget = old_widget = f->output_data.x->menubar_widget;
701 XSETFRAME (Vmenu_updating_frame, f);
703 #ifdef USE_X_TOOLKIT
704 if (f->output_data.x->id == 0)
705 f->output_data.x->id = next_menubar_widget_id++;
706 id = f->output_data.x->id;
707 #endif
709 if (! menubar_widget)
710 deep_p = true;
711 /* Make the first call for any given frame always go deep. */
712 else if (!f->output_data.x->saved_menu_event && !deep_p)
714 deep_p = true;
715 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
716 f->output_data.x->saved_menu_event->type = 0;
719 if (deep_p)
721 /* Make a widget-value tree representing the entire menu trees. */
723 struct buffer *prev = current_buffer;
724 Lisp_Object buffer;
725 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
726 int previous_menu_items_used = f->menu_bar_items_used;
727 Lisp_Object *previous_items
728 = alloca (previous_menu_items_used * sizeof *previous_items);
729 int subitems;
731 /* If we are making a new widget, its contents are empty,
732 do always reinitialize them. */
733 if (! menubar_widget)
734 previous_menu_items_used = 0;
736 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
737 specbind (Qinhibit_quit, Qt);
738 /* Don't let the debugger step into this code
739 because it is not reentrant. */
740 specbind (Qdebug_on_next_call, Qnil);
742 record_unwind_save_match_data ();
743 if (NILP (Voverriding_local_map_menu_flag))
745 specbind (Qoverriding_terminal_local_map, Qnil);
746 specbind (Qoverriding_local_map, Qnil);
749 set_buffer_internal_1 (XBUFFER (buffer));
751 /* Run the Lucid hook. */
752 safe_run_hooks (Qactivate_menubar_hook);
754 /* If it has changed current-menubar from previous value,
755 really recompute the menubar from the value. */
756 if (! NILP (Vlucid_menu_bar_dirty_flag))
757 call0 (Qrecompute_lucid_menubar);
758 safe_run_hooks (Qmenu_bar_update_hook);
759 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
761 items = FRAME_MENU_BAR_ITEMS (f);
763 /* Save the frame's previous menu bar contents data. */
764 if (previous_menu_items_used)
765 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
766 previous_menu_items_used * word_size);
768 /* Fill in menu_items with the current menu bar contents.
769 This can evaluate Lisp code. */
770 save_menu_items ();
772 menu_items = f->menu_bar_vector;
773 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
774 subitems = ASIZE (items) / 4;
775 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
776 submenu_end = alloca (subitems * sizeof *submenu_end);
777 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
778 submenu_top_level_items = alloca (subitems
779 * sizeof *submenu_top_level_items);
780 init_menu_items ();
781 for (i = 0; i < subitems; i++)
783 Lisp_Object key, string, maps;
785 key = AREF (items, 4 * i);
786 string = AREF (items, 4 * i + 1);
787 maps = AREF (items, 4 * i + 2);
788 if (NILP (string))
789 break;
791 submenu_start[i] = menu_items_used;
793 menu_items_n_panes = 0;
794 submenu_top_level_items[i]
795 = parse_single_submenu (key, string, maps);
796 submenu_n_panes[i] = menu_items_n_panes;
798 submenu_end[i] = menu_items_used;
801 submenu_start[i] = -1;
802 finish_menu_items ();
804 /* Convert menu_items into widget_value trees
805 to display the menu. This cannot evaluate Lisp code. */
807 wv = make_widget_value ("menubar", NULL, true, Qnil);
808 wv->button_type = BUTTON_TYPE_NONE;
809 first_wv = wv;
811 for (i = 0; submenu_start[i] >= 0; i++)
813 menu_items_n_panes = submenu_n_panes[i];
814 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
815 submenu_top_level_items[i]);
816 if (prev_wv)
817 prev_wv->next = wv;
818 else
819 first_wv->contents = wv;
820 /* Don't set wv->name here; GC during the loop might relocate it. */
821 wv->enabled = true;
822 wv->button_type = BUTTON_TYPE_NONE;
823 prev_wv = wv;
826 set_buffer_internal_1 (prev);
828 /* If there has been no change in the Lisp-level contents
829 of the menu bar, skip redisplaying it. Just exit. */
831 /* Compare the new menu items with the ones computed last time. */
832 for (i = 0; i < previous_menu_items_used; i++)
833 if (menu_items_used == i
834 || (!EQ (previous_items[i], AREF (menu_items, i))))
835 break;
836 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
838 /* The menu items have not changed. Don't bother updating
839 the menus in any form, since it would be a no-op. */
840 free_menubar_widget_value_tree (first_wv);
841 discard_menu_items ();
842 unbind_to (specpdl_count, Qnil);
843 return;
846 /* The menu items are different, so store them in the frame. */
847 fset_menu_bar_vector (f, menu_items);
848 f->menu_bar_items_used = menu_items_used;
850 /* This undoes save_menu_items. */
851 unbind_to (specpdl_count, Qnil);
853 /* Now GC cannot happen during the lifetime of the widget_value,
854 so it's safe to store data from a Lisp_String. */
855 wv = first_wv->contents;
856 for (i = 0; i < ASIZE (items); i += 4)
858 Lisp_Object string;
859 string = AREF (items, i + 1);
860 if (NILP (string))
861 break;
862 wv->name = SSDATA (string);
863 update_submenu_strings (wv->contents);
864 wv = wv->next;
868 else
870 /* Make a widget-value tree containing
871 just the top level menu bar strings. */
873 wv = make_widget_value ("menubar", NULL, true, Qnil);
874 wv->button_type = BUTTON_TYPE_NONE;
875 first_wv = wv;
877 items = FRAME_MENU_BAR_ITEMS (f);
878 for (i = 0; i < ASIZE (items); i += 4)
880 Lisp_Object string;
882 string = AREF (items, i + 1);
883 if (NILP (string))
884 break;
886 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
887 wv->button_type = BUTTON_TYPE_NONE;
888 /* This prevents lwlib from assuming this
889 menu item is really supposed to be empty. */
890 /* The intptr_t cast avoids a warning.
891 This value just has to be different from small integers. */
892 wv->call_data = (void *) (intptr_t) (-1);
894 if (prev_wv)
895 prev_wv->next = wv;
896 else
897 first_wv->contents = wv;
898 prev_wv = wv;
901 /* Forget what we thought we knew about what is in the
902 detailed contents of the menu bar menus.
903 Changing the top level always destroys the contents. */
904 f->menu_bar_items_used = 0;
907 /* Create or update the menu bar widget. */
909 block_input ();
911 #ifdef USE_GTK
912 xg_crazy_callback_abort = true;
913 if (menubar_widget)
915 /* The fourth arg is DEEP_P, which says to consider the entire
916 menu trees we supply, rather than just the menu bar item names. */
917 xg_modify_menubar_widgets (menubar_widget,
919 first_wv,
920 deep_p,
921 G_CALLBACK (menubar_selection_callback),
922 G_CALLBACK (popup_deactivate_callback),
923 G_CALLBACK (menu_highlight_callback));
925 else
927 menubar_widget
928 = xg_create_widget ("menubar", "menubar", f, first_wv,
929 G_CALLBACK (menubar_selection_callback),
930 G_CALLBACK (popup_deactivate_callback),
931 G_CALLBACK (menu_highlight_callback));
933 f->output_data.x->menubar_widget = menubar_widget;
937 #else /* not USE_GTK */
938 if (menubar_widget)
940 /* Disable resizing (done for Motif!) */
941 lw_allow_resizing (f->output_data.x->widget, False);
943 /* The third arg is DEEP_P, which says to consider the entire
944 menu trees we supply, rather than just the menu bar item names. */
945 lw_modify_all_widgets (id, first_wv, deep_p);
947 /* Re-enable the edit widget to resize. */
948 lw_allow_resizing (f->output_data.x->widget, True);
950 else
952 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
953 XtTranslations override = XtParseTranslationTable (menuOverride);
955 #ifdef USE_LUCID
956 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
957 #endif
958 menubar_widget = lw_create_widget ("menubar", "menubar", id,
959 first_wv,
960 f->output_data.x->column_widget,
961 false,
962 popup_activate_callback,
963 menubar_selection_callback,
964 popup_deactivate_callback,
965 menu_highlight_callback);
966 f->output_data.x->menubar_widget = menubar_widget;
968 /* Make menu pop down on C-g. */
969 XtOverrideTranslations (menubar_widget, override);
973 int menubar_size;
974 if (f->output_data.x->menubar_widget)
975 XtRealizeWidget (f->output_data.x->menubar_widget);
977 menubar_size
978 = (f->output_data.x->menubar_widget
979 ? (f->output_data.x->menubar_widget->core.height
980 #ifndef USE_LUCID
981 /* Damn me... With Lucid I get a core.border_width of 1
982 only the first time this is called and an ibw of 1 every
983 time this is called. So the first time this is called I
984 was off by one. Fix that here by never adding
985 core.border_width for Lucid. */
986 + f->output_data.x->menubar_widget->core.border_width
987 #endif /* USE_LUCID */
989 : 0);
991 #ifdef USE_LUCID
992 /* Experimentally, we now get the right results
993 for -geometry -0-0 without this. 24 Aug 96, rms.
994 Maybe so, but the menu bar size is missing the pixels so the
995 WM size hints are off by these pixels. Jan D, oct 2009. */
996 if (FRAME_EXTERNAL_MENU_BAR (f))
998 Dimension ibw = 0;
1000 XtVaGetValues (f->output_data.x->column_widget,
1001 XtNinternalBorderWidth, &ibw, NULL);
1002 menubar_size += ibw;
1004 #endif /* USE_LUCID */
1006 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1008 #endif /* not USE_GTK */
1010 free_menubar_widget_value_tree (first_wv);
1011 update_frame_menubar (f);
1013 #ifdef USE_GTK
1014 xg_crazy_callback_abort = false;
1015 #endif
1017 unblock_input ();
1020 /* Called from Fx_create_frame to create the initial menubar of a frame
1021 before it is mapped, so that the window is mapped with the menubar already
1022 there instead of us tacking it on later and thrashing the window after it
1023 is visible. */
1025 void
1026 initialize_frame_menubar (struct frame *f)
1028 /* This function is called before the first chance to redisplay
1029 the frame. It has to be, so the frame will have the right size. */
1030 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1031 set_frame_menubar (f, true, true);
1035 /* Get rid of the menu bar of frame F, and free its storage.
1036 This is used when deleting a frame, and when turning off the menu bar.
1037 For GTK this function is in gtkutil.c. */
1039 #ifndef USE_GTK
1040 void
1041 free_frame_menubar (struct frame *f)
1043 Widget menubar_widget;
1044 #ifdef USE_MOTIF
1045 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1046 If we want to preserve the old height, calculate it now so we can
1047 restore it below. */
1048 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1049 #endif
1051 eassert (FRAME_X_P (f));
1053 menubar_widget = f->output_data.x->menubar_widget;
1055 FRAME_MENUBAR_HEIGHT (f) = 0;
1057 if (menubar_widget)
1059 #ifdef USE_MOTIF
1060 /* Removing the menu bar magically changes the shell widget's x
1061 and y position of (0, 0) which, when the menu bar is turned
1062 on again, leads to pull-down menus appearing in strange
1063 positions near the upper-left corner of the display. This
1064 happens only with some window managers like twm and ctwm,
1065 but not with other like Motif's mwm or kwm, because the
1066 latter generate ConfigureNotify events when the menu bar
1067 is switched off, which fixes the shell position. */
1068 Position x0, y0, x1, y1;
1069 #endif
1071 block_input ();
1073 #ifdef USE_MOTIF
1074 if (f->output_data.x->widget)
1075 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1076 #endif
1078 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1079 f->output_data.x->menubar_widget = NULL;
1081 if (f->output_data.x->widget)
1083 #ifdef USE_MOTIF
1084 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1085 if (x1 == 0 && y1 == 0)
1086 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1087 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1088 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_1);
1089 else
1090 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1091 #else
1092 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1093 #endif /* USE_MOTIF */
1095 else
1097 #ifdef USE_MOTIF
1098 if (WINDOWP (FRAME_ROOT_WINDOW (f))
1099 && frame_inhibit_resize (f, false, Qmenu_bar_lines))
1100 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_2);
1101 #endif
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 int max_x = -1;
1160 int max_y = -1;
1161 #ifdef HAVE_GTK3
1162 int scale;
1163 #endif
1165 Lisp_Object frame, workarea;
1167 XSETFRAME (frame, data->f);
1169 #ifdef HAVE_GTK3
1170 scale = xg_get_scale (data->f);
1171 #endif
1172 /* TODO: Get the monitor workarea directly without calculating other
1173 items in x-display-monitor-attributes-list. */
1174 workarea = call3 (Qframe_monitor_workarea,
1175 Qnil,
1176 make_number (data->x),
1177 make_number (data->y));
1179 if (CONSP (workarea))
1181 int min_x, min_y;
1183 min_x = XINT (XCAR (workarea));
1184 min_y = XINT (Fnth (make_number (1), workarea));
1185 max_x = min_x + XINT (Fnth (make_number (2), workarea));
1186 max_y = min_y + XINT (Fnth (make_number (3), workarea));
1189 if (max_x < 0 || max_y < 0)
1191 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1193 max_x = x_display_pixel_width (dpyinfo);
1194 max_y = x_display_pixel_height (dpyinfo);
1197 /* frame-monitor-workarea and {x,y}_display_pixel_width/height all
1198 return device pixels, but GTK wants scaled pixels. The positions
1199 passed in via data were already scaled for us. */
1200 #ifdef HAVE_GTK3
1201 max_x /= scale;
1202 max_y /= scale;
1203 #endif
1204 *x = data->x;
1205 *y = data->y;
1207 /* Check if there is room for the menu. If not, adjust x/y so that
1208 the menu is fully visible. gtk_widget_get_preferred_size returns
1209 scaled pixels, so there is no need to apply the scaling
1210 factor. */
1211 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1212 if (data->x + req.width > max_x)
1213 *x -= data->x + req.width - max_x;
1214 if (data->y + req.height > max_y)
1215 *y -= data->y + req.height - max_y;
1218 static void
1219 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1221 xg_menu_item_cb_data *cb_data = client_data;
1223 if (xg_crazy_callback_abort) return;
1224 if (cb_data) menu_item_selection = cb_data->call_data;
1227 static void
1228 pop_down_menu (void *arg)
1230 popup_activated_flag = 0;
1231 block_input ();
1232 gtk_widget_destroy (GTK_WIDGET (arg));
1233 unblock_input ();
1236 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1237 menu pops down.
1238 menu_item_selection will be set to the selection. */
1239 static void
1240 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1241 int x, int y, bool for_click)
1243 int i;
1244 GtkWidget *menu;
1245 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1246 struct next_popup_x_y popup_x_y;
1247 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1248 bool use_pos_func = ! for_click;
1250 #ifdef HAVE_GTK3
1251 /* Always use position function for Gtk3. Otherwise menus may become
1252 too small to show anything. */
1253 use_pos_func = true;
1254 #endif
1256 eassert (FRAME_X_P (f));
1258 xg_crazy_callback_abort = true;
1259 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1260 G_CALLBACK (popup_selection_callback),
1261 G_CALLBACK (popup_deactivate_callback),
1262 G_CALLBACK (menu_highlight_callback));
1263 xg_crazy_callback_abort = false;
1265 if (use_pos_func)
1267 Window dummy_window;
1269 /* Not invoked by a click. pop up at x/y. */
1270 pos_func = menu_position_func;
1272 /* Adjust coordinates to be root-window-relative. */
1273 block_input ();
1274 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1276 /* From-window, to-window. */
1277 FRAME_X_WINDOW (f),
1278 FRAME_DISPLAY_INFO (f)->root_window,
1280 /* From-position, to-position. */
1281 x, y, &x, &y,
1283 /* Child of win. */
1284 &dummy_window);
1285 #ifdef HAVE_GTK3
1286 /* Use window scaling factor to adjust position for hidpi screens. */
1287 x /= xg_get_scale (f);
1288 y /= xg_get_scale (f);
1289 #endif
1290 unblock_input ();
1291 popup_x_y.x = x;
1292 popup_x_y.y = y;
1293 popup_x_y.f = f;
1295 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1298 if (for_click)
1300 for (i = 0; i < 5; i++)
1301 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1302 break;
1303 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1304 if (i == 5) i = 0;
1307 /* Display the menu. */
1308 gtk_widget_show_all (menu);
1310 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1311 FRAME_DISPLAY_INFO (f)->last_user_time);
1313 record_unwind_protect_ptr (pop_down_menu, menu);
1315 if (gtk_widget_get_mapped (menu))
1317 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1318 two. show_help_echo uses this to detect popup menus. */
1319 popup_activated_flag = 1;
1320 /* Process events that apply to the menu. */
1321 popup_widget_loop (true, menu);
1324 unbind_to (specpdl_count, Qnil);
1326 /* Must reset this manually because the button release event is not passed
1327 to Emacs event loop. */
1328 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1331 #else /* not USE_GTK */
1333 /* We need a unique id for each widget handled by the Lucid Widget
1334 library.
1336 For the main windows, and popup menus, we use this counter, which we
1337 increment each time after use. This starts from WIDGET_ID_TICK_START.
1339 For menu bars, we use numbers starting at 0, counted in
1340 next_menubar_widget_id. */
1341 LWLIB_ID widget_id_tick;
1343 static void
1344 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1346 menu_item_selection = client_data;
1349 /* ID is the LWLIB ID of the dialog box. */
1351 static void
1352 pop_down_menu (int id)
1354 block_input ();
1355 lw_destroy_all_widgets ((LWLIB_ID) id);
1356 unblock_input ();
1357 popup_activated_flag = 0;
1360 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1361 menu pops down.
1362 menu_item_selection will be set to the selection. */
1363 static void
1364 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1365 int x, int y, bool for_click)
1367 int i;
1368 Arg av[2];
1369 int ac = 0;
1370 XEvent dummy;
1371 XButtonPressedEvent *event = &(dummy.xbutton);
1372 LWLIB_ID menu_id;
1373 Widget menu;
1374 Window dummy_window;
1376 eassert (FRAME_X_P (f));
1378 #ifdef USE_LUCID
1379 apply_systemfont_to_menu (f, f->output_data.x->widget);
1380 #endif
1382 menu_id = widget_id_tick++;
1383 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1384 f->output_data.x->widget, true, 0,
1385 popup_selection_callback,
1386 popup_deactivate_callback,
1387 menu_highlight_callback);
1389 event->type = ButtonPress;
1390 event->serial = 0;
1391 event->send_event = false;
1392 event->display = FRAME_X_DISPLAY (f);
1393 event->time = CurrentTime;
1394 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1395 event->window = event->subwindow = event->root;
1396 event->x = x;
1397 event->y = y;
1399 /* Adjust coordinates to be root-window-relative. */
1400 block_input ();
1401 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1402 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1404 /* From-window, to-window. */
1405 FRAME_X_WINDOW (f),
1406 FRAME_DISPLAY_INFO (f)->root_window,
1408 /* From-position, to-position. */
1409 x, y, &x, &y,
1411 /* Child of win. */
1412 &dummy_window);
1413 unblock_input ();
1415 event->x_root = x;
1416 event->y_root = y;
1418 event->state = 0;
1419 event->button = 0;
1420 for (i = 0; i < 5; i++)
1421 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1422 event->button = i;
1424 /* Don't allow any geometry request from the user. */
1425 XtSetArg (av[ac], (char *) XtNgeometry, 0); ac++;
1426 XtSetValues (menu, av, ac);
1428 /* Display the menu. */
1429 lw_popup_menu (menu, &dummy);
1430 popup_activated_flag = 1;
1431 x_activate_timeout_atimer ();
1434 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1436 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1438 /* Process events that apply to the menu. */
1439 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1441 unbind_to (specpdl_count, Qnil);
1445 #endif /* not USE_GTK */
1447 static void
1448 cleanup_widget_value_tree (void *arg)
1450 free_menubar_widget_value_tree (arg);
1453 Lisp_Object
1454 x_menu_show (struct frame *f, int x, int y, int menuflags,
1455 Lisp_Object title, const char **error_name)
1457 int i;
1458 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1459 widget_value **submenu_stack
1460 = alloca (menu_items_used * sizeof *submenu_stack);
1461 Lisp_Object *subprefix_stack
1462 = alloca (menu_items_used * sizeof *subprefix_stack);
1463 int submenu_depth = 0;
1465 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1467 eassert (FRAME_X_P (f));
1469 *error_name = NULL;
1471 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1473 *error_name = "Empty menu";
1474 return Qnil;
1477 block_input ();
1479 /* Create a tree of widget_value objects
1480 representing the panes and their items. */
1481 wv = make_widget_value ("menu", NULL, true, Qnil);
1482 wv->button_type = BUTTON_TYPE_NONE;
1483 first_wv = wv;
1484 bool first_pane = true;
1486 /* Loop over all panes and items, filling in the tree. */
1487 i = 0;
1488 while (i < menu_items_used)
1490 if (EQ (AREF (menu_items, i), Qnil))
1492 submenu_stack[submenu_depth++] = save_wv;
1493 save_wv = prev_wv;
1494 prev_wv = 0;
1495 first_pane = true;
1496 i++;
1498 else if (EQ (AREF (menu_items, i), Qlambda))
1500 prev_wv = save_wv;
1501 save_wv = submenu_stack[--submenu_depth];
1502 first_pane = false;
1503 i++;
1505 else if (EQ (AREF (menu_items, i), Qt)
1506 && submenu_depth != 0)
1507 i += MENU_ITEMS_PANE_LENGTH;
1508 /* Ignore a nil in the item list.
1509 It's meaningful only for dialog boxes. */
1510 else if (EQ (AREF (menu_items, i), Qquote))
1511 i += 1;
1512 else if (EQ (AREF (menu_items, i), Qt))
1514 /* Create a new pane. */
1515 Lisp_Object pane_name, prefix;
1516 const char *pane_string;
1518 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1519 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1521 #ifndef HAVE_MULTILINGUAL_MENU
1522 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1524 pane_name = ENCODE_MENU_STRING (pane_name);
1525 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1527 #endif
1528 pane_string = (NILP (pane_name)
1529 ? "" : SSDATA (pane_name));
1530 /* If there is just one top-level pane, put all its items directly
1531 under the top-level menu. */
1532 if (menu_items_n_panes == 1)
1533 pane_string = "";
1535 /* If the pane has a meaningful name,
1536 make the pane a top-level menu item
1537 with its items as a submenu beneath it. */
1538 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1540 wv = make_widget_value (pane_string, NULL, true, Qnil);
1541 if (save_wv)
1542 save_wv->next = wv;
1543 else
1544 first_wv->contents = wv;
1545 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1546 wv->name++;
1547 wv->button_type = BUTTON_TYPE_NONE;
1548 save_wv = wv;
1549 prev_wv = 0;
1551 else if (first_pane)
1553 save_wv = wv;
1554 prev_wv = 0;
1556 first_pane = false;
1557 i += MENU_ITEMS_PANE_LENGTH;
1559 else
1561 /* Create a new item within current pane. */
1562 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1563 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1564 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1565 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1566 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1567 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1568 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1569 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1571 #ifndef HAVE_MULTILINGUAL_MENU
1572 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1574 item_name = ENCODE_MENU_STRING (item_name);
1575 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1578 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1580 descrip = ENCODE_MENU_STRING (descrip);
1581 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1583 #endif /* not HAVE_MULTILINGUAL_MENU */
1585 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1586 STRINGP (help) ? help : Qnil);
1587 if (prev_wv)
1588 prev_wv->next = wv;
1589 else
1590 save_wv->contents = wv;
1591 if (!NILP (descrip))
1592 wv->key = SSDATA (descrip);
1593 /* If this item has a null value,
1594 make the call_data null so that it won't display a box
1595 when the mouse is on it. */
1596 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1598 if (NILP (type))
1599 wv->button_type = BUTTON_TYPE_NONE;
1600 else if (EQ (type, QCtoggle))
1601 wv->button_type = BUTTON_TYPE_TOGGLE;
1602 else if (EQ (type, QCradio))
1603 wv->button_type = BUTTON_TYPE_RADIO;
1604 else
1605 emacs_abort ();
1607 wv->selected = !NILP (selected);
1609 prev_wv = wv;
1611 i += MENU_ITEMS_ITEM_LENGTH;
1615 /* Deal with the title, if it is non-nil. */
1616 if (!NILP (title))
1618 widget_value *wv_title;
1619 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1620 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1622 wv_sep2->next = first_wv->contents;
1623 wv_sep1->next = wv_sep2;
1625 #ifndef HAVE_MULTILINGUAL_MENU
1626 if (STRING_MULTIBYTE (title))
1627 title = ENCODE_MENU_STRING (title);
1628 #endif
1630 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1631 wv_title->button_type = BUTTON_TYPE_NONE;
1632 wv_title->next = wv_sep1;
1633 first_wv->contents = wv_title;
1636 /* No selection has been chosen yet. */
1637 menu_item_selection = 0;
1639 /* Make sure to free the widget_value objects we used to specify the
1640 contents even with longjmp. */
1641 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1643 /* Actually create and show the menu until popped down. */
1644 create_and_show_popup_menu (f, first_wv, x, y,
1645 menuflags & MENU_FOR_CLICK);
1647 unbind_to (specpdl_count, Qnil);
1649 /* Find the selected item, and its pane, to return
1650 the proper value. */
1651 if (menu_item_selection != 0)
1653 Lisp_Object prefix, entry;
1655 prefix = entry = Qnil;
1656 i = 0;
1657 while (i < menu_items_used)
1659 if (EQ (AREF (menu_items, i), Qnil))
1661 subprefix_stack[submenu_depth++] = prefix;
1662 prefix = entry;
1663 i++;
1665 else if (EQ (AREF (menu_items, i), Qlambda))
1667 prefix = subprefix_stack[--submenu_depth];
1668 i++;
1670 else if (EQ (AREF (menu_items, i), Qt))
1672 prefix
1673 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1674 i += MENU_ITEMS_PANE_LENGTH;
1676 /* Ignore a nil in the item list.
1677 It's meaningful only for dialog boxes. */
1678 else if (EQ (AREF (menu_items, i), Qquote))
1679 i += 1;
1680 else
1682 entry
1683 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1684 if (menu_item_selection == aref_addr (menu_items, i))
1686 if (menuflags & MENU_KEYMAPS)
1688 int j;
1690 entry = list1 (entry);
1691 if (!NILP (prefix))
1692 entry = Fcons (prefix, entry);
1693 for (j = submenu_depth - 1; j >= 0; j--)
1694 if (!NILP (subprefix_stack[j]))
1695 entry = Fcons (subprefix_stack[j], entry);
1697 unblock_input ();
1698 return entry;
1700 i += MENU_ITEMS_ITEM_LENGTH;
1704 else if (!(menuflags & MENU_FOR_CLICK))
1706 unblock_input ();
1707 /* Make "Cancel" equivalent to C-g. */
1708 quit ();
1711 unblock_input ();
1712 return Qnil;
1715 #ifdef USE_GTK
1716 static void
1717 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1719 /* Treat the pointer as an integer. There's no problem
1720 as long as pointers have enough bits to hold small integers. */
1721 if ((intptr_t) client_data != -1)
1722 menu_item_selection = client_data;
1724 popup_activated_flag = 0;
1727 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1728 dialog pops down.
1729 menu_item_selection will be set to the selection. */
1730 static void
1731 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1733 GtkWidget *menu;
1735 eassert (FRAME_X_P (f));
1737 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1738 G_CALLBACK (dialog_selection_callback),
1739 G_CALLBACK (popup_deactivate_callback),
1742 if (menu)
1744 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1745 record_unwind_protect_ptr (pop_down_menu, menu);
1747 /* Display the menu. */
1748 gtk_widget_show_all (menu);
1750 /* Process events that apply to the menu. */
1751 popup_widget_loop (true, menu);
1753 unbind_to (specpdl_count, Qnil);
1757 #else /* not USE_GTK */
1758 static void
1759 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1761 /* Treat the pointer as an integer. There's no problem
1762 as long as pointers have enough bits to hold small integers. */
1763 if ((intptr_t) client_data != -1)
1764 menu_item_selection = client_data;
1766 block_input ();
1767 lw_destroy_all_widgets (id);
1768 unblock_input ();
1769 popup_activated_flag = 0;
1773 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1774 dialog pops down.
1775 menu_item_selection will be set to the selection. */
1776 static void
1777 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1779 LWLIB_ID dialog_id;
1781 eassert (FRAME_X_P (f));
1783 dialog_id = widget_id_tick++;
1784 #ifdef USE_LUCID
1785 apply_systemfont_to_dialog (f->output_data.x->widget);
1786 #endif
1787 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1788 f->output_data.x->widget, true, 0,
1789 dialog_selection_callback, 0, 0);
1790 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1791 /* Display the dialog box. */
1792 lw_pop_up_all_widgets (dialog_id);
1793 popup_activated_flag = 1;
1794 x_activate_timeout_atimer ();
1796 /* Process events that apply to the dialog box.
1797 Also handle timers. */
1799 ptrdiff_t count = SPECPDL_INDEX ();
1801 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1803 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1805 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1807 unbind_to (count, Qnil);
1811 #endif /* not USE_GTK */
1813 static const char * button_names [] = {
1814 "button1", "button2", "button3", "button4", "button5",
1815 "button6", "button7", "button8", "button9", "button10" };
1817 static Lisp_Object
1818 x_dialog_show (struct frame *f, Lisp_Object title,
1819 Lisp_Object header, const char **error_name)
1821 int i, nb_buttons=0;
1822 char dialog_name[6];
1824 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1826 /* Number of elements seen so far, before boundary. */
1827 int left_count = 0;
1828 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1829 bool boundary_seen = false;
1831 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1833 eassert (FRAME_X_P (f));
1835 *error_name = NULL;
1837 if (menu_items_n_panes > 1)
1839 *error_name = "Multiple panes in dialog box";
1840 return Qnil;
1843 /* Create a tree of widget_value objects
1844 representing the text label and buttons. */
1846 Lisp_Object pane_name;
1847 const char *pane_string;
1848 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1849 pane_string = (NILP (pane_name)
1850 ? "" : SSDATA (pane_name));
1851 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1852 first_wv = prev_wv;
1854 /* Loop over all panes and items, filling in the tree. */
1855 i = MENU_ITEMS_PANE_LENGTH;
1856 while (i < menu_items_used)
1859 /* Create a new item within current pane. */
1860 Lisp_Object item_name, enable, descrip;
1861 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1862 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1863 descrip
1864 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1866 if (NILP (item_name))
1868 free_menubar_widget_value_tree (first_wv);
1869 *error_name = "Submenu in dialog items";
1870 return Qnil;
1872 if (EQ (item_name, Qquote))
1874 /* This is the boundary between left-side elts
1875 and right-side elts. Stop incrementing right_count. */
1876 boundary_seen = true;
1877 i++;
1878 continue;
1880 if (nb_buttons >= 9)
1882 free_menubar_widget_value_tree (first_wv);
1883 *error_name = "Too many dialog items";
1884 return Qnil;
1887 wv = make_widget_value (button_names[nb_buttons],
1888 SSDATA (item_name),
1889 !NILP (enable), Qnil);
1890 prev_wv->next = wv;
1891 if (!NILP (descrip))
1892 wv->key = SSDATA (descrip);
1893 wv->call_data = aref_addr (menu_items, i);
1894 prev_wv = wv;
1896 if (! boundary_seen)
1897 left_count++;
1899 nb_buttons++;
1900 i += MENU_ITEMS_ITEM_LENGTH;
1903 /* If the boundary was not specified,
1904 by default put half on the left and half on the right. */
1905 if (! boundary_seen)
1906 left_count = nb_buttons - nb_buttons / 2;
1908 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1910 /* Frame title: 'Q' = Question, 'I' = Information.
1911 Can also have 'E' = Error if, one day, we want
1912 a popup for errors. */
1913 if (NILP (header))
1914 dialog_name[0] = 'Q';
1915 else
1916 dialog_name[0] = 'I';
1918 /* Dialog boxes use a really stupid name encoding
1919 which specifies how many buttons to use
1920 and how many buttons are on the right. */
1921 dialog_name[1] = '0' + nb_buttons;
1922 dialog_name[2] = 'B';
1923 dialog_name[3] = 'R';
1924 /* Number of buttons to put on the right. */
1925 dialog_name[4] = '0' + nb_buttons - left_count;
1926 dialog_name[5] = 0;
1927 wv->contents = first_wv;
1928 first_wv = wv;
1931 /* No selection has been chosen yet. */
1932 menu_item_selection = 0;
1934 /* Make sure to free the widget_value objects we used to specify the
1935 contents even with longjmp. */
1936 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1938 /* Actually create and show the dialog. */
1939 create_and_show_dialog (f, first_wv);
1941 unbind_to (specpdl_count, Qnil);
1943 /* Find the selected item, and its pane, to return
1944 the proper value. */
1945 if (menu_item_selection != 0)
1947 i = 0;
1948 while (i < menu_items_used)
1950 Lisp_Object entry;
1952 if (EQ (AREF (menu_items, i), Qt))
1953 i += MENU_ITEMS_PANE_LENGTH;
1954 else if (EQ (AREF (menu_items, i), Qquote))
1956 /* This is the boundary between left-side elts and
1957 right-side elts. */
1958 ++i;
1960 else
1962 entry
1963 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1964 if (menu_item_selection == aref_addr (menu_items, i))
1965 return entry;
1966 i += MENU_ITEMS_ITEM_LENGTH;
1970 else
1971 /* Make "Cancel" equivalent to C-g. */
1972 quit ();
1974 return Qnil;
1977 Lisp_Object
1978 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1980 Lisp_Object title;
1981 const char *error_name;
1982 Lisp_Object selection;
1983 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1985 check_window_system (f);
1987 /* Decode the dialog items from what was specified. */
1988 title = Fcar (contents);
1989 CHECK_STRING (title);
1990 record_unwind_protect_void (unuse_menu_items);
1992 if (NILP (Fcar (Fcdr (contents))))
1993 /* No buttons specified, add an "Ok" button so users can pop down
1994 the dialog. Also, the lesstif/motif version crashes if there are
1995 no buttons. */
1996 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1998 list_of_panes (list1 (contents));
2000 /* Display them in a dialog box. */
2001 block_input ();
2002 selection = x_dialog_show (f, title, header, &error_name);
2003 unblock_input ();
2005 unbind_to (specpdl_count, Qnil);
2006 discard_menu_items ();
2008 if (error_name) error ("%s", error_name);
2009 return selection;
2012 #else /* not USE_X_TOOLKIT && not USE_GTK */
2014 /* The frame of the last activated non-toolkit menu bar.
2015 Used to generate menu help events. */
2017 static struct frame *menu_help_frame;
2020 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
2022 PANE is the pane number, and ITEM is the menu item number in
2023 the menu (currently not used).
2025 This cannot be done with generating a HELP_EVENT because
2026 XMenuActivate contains a loop that doesn't let Emacs process
2027 keyboard events. */
2029 static void
2030 menu_help_callback (char const *help_string, int pane, int item)
2032 Lisp_Object *first_item;
2033 Lisp_Object pane_name;
2034 Lisp_Object menu_object;
2036 first_item = XVECTOR (menu_items)->contents;
2037 if (EQ (first_item[0], Qt))
2038 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2039 else if (EQ (first_item[0], Qquote))
2040 /* This shouldn't happen, see x_menu_show. */
2041 pane_name = empty_unibyte_string;
2042 else
2043 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
2045 /* (menu-item MENU-NAME PANE-NUMBER) */
2046 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
2047 show_help_echo (help_string ? build_string (help_string) : Qnil,
2048 Qnil, menu_object, make_number (item));
2051 struct pop_down_menu
2053 struct frame *frame;
2054 XMenu *menu;
2057 static void
2058 pop_down_menu (void *arg)
2060 union pop_down_menu *data = arg;
2061 struct frame *f = data->frame;
2062 XMenu *menu = data->menu;
2064 block_input ();
2065 #ifndef MSDOS
2066 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2067 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2068 #endif
2069 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2071 #ifdef HAVE_X_WINDOWS
2072 /* Assume the mouse has moved out of the X window.
2073 If it has actually moved in, we will get an EnterNotify. */
2074 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2076 /* State that no mouse buttons are now held.
2077 (The oldXMenu code doesn't track this info for us.)
2078 That is not necessarily true, but the fiction leads to reasonable
2079 results, and it is a pain to ask which are actually held now. */
2080 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2082 #endif /* HAVE_X_WINDOWS */
2084 unblock_input ();
2088 Lisp_Object
2089 x_menu_show (struct frame *f, int x, int y, int menuflags,
2090 Lisp_Object title, const char **error_name)
2092 Window root;
2093 XMenu *menu;
2094 int pane, selidx, lpane, status;
2095 Lisp_Object entry = Qnil;
2096 Lisp_Object pane_prefix;
2097 char *datap;
2098 int ulx, uly, width, height;
2099 int dispwidth, dispheight;
2100 int i, j, lines, maxlines;
2101 int maxwidth;
2102 int dummy_int;
2103 unsigned int dummy_uint;
2104 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2106 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2108 *error_name = 0;
2109 if (menu_items_n_panes == 0)
2110 return Qnil;
2112 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2114 *error_name = "Empty menu";
2115 return Qnil;
2118 USE_SAFE_ALLOCA;
2119 block_input ();
2121 /* Figure out which root window F is on. */
2122 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2123 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2124 &dummy_uint, &dummy_uint);
2126 /* Make the menu on that window. */
2127 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2128 if (menu == NULL)
2130 *error_name = "Can't create menu";
2131 goto return_entry;
2134 /* Don't GC while we prepare and show the menu,
2135 because we give the oldxmenu library pointers to the
2136 contents of strings. */
2137 inhibit_garbage_collection ();
2139 #ifdef HAVE_X_WINDOWS
2141 /* Adjust coordinates to relative to the outer (window manager) window. */
2142 int left_off, top_off;
2144 x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
2145 NULL, NULL, NULL, NULL, NULL);
2147 x += left_off;
2148 y += top_off;
2150 #endif /* HAVE_X_WINDOWS */
2152 x += f->left_pos;
2153 y += f->top_pos;
2155 /* Create all the necessary panes and their items. */
2156 maxwidth = maxlines = lines = i = 0;
2157 lpane = XM_FAILURE;
2158 while (i < menu_items_used)
2160 if (EQ (AREF (menu_items, i), Qt))
2162 /* Create a new pane. */
2163 Lisp_Object pane_name, prefix;
2164 const char *pane_string;
2166 maxlines = max (maxlines, lines);
2167 lines = 0;
2168 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2169 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2170 pane_string = (NILP (pane_name)
2171 ? "" : SSDATA (pane_name));
2172 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2173 pane_string++;
2175 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2176 if (lpane == XM_FAILURE)
2178 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2179 *error_name = "Can't create pane";
2180 goto return_entry;
2182 i += MENU_ITEMS_PANE_LENGTH;
2184 /* Find the width of the widest item in this pane. */
2185 j = i;
2186 while (j < menu_items_used)
2188 Lisp_Object item;
2189 item = AREF (menu_items, j);
2190 if (EQ (item, Qt))
2191 break;
2192 if (NILP (item))
2194 j++;
2195 continue;
2197 width = SBYTES (item);
2198 if (width > maxwidth)
2199 maxwidth = width;
2201 j += MENU_ITEMS_ITEM_LENGTH;
2204 /* Ignore a nil in the item list.
2205 It's meaningful only for dialog boxes. */
2206 else if (EQ (AREF (menu_items, i), Qquote))
2207 i += 1;
2208 else
2210 /* Create a new item within current pane. */
2211 Lisp_Object item_name, enable, descrip, help;
2212 char *item_data;
2213 char const *help_string;
2215 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2216 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2217 descrip
2218 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2219 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2220 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2222 if (!NILP (descrip))
2224 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2225 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2226 for (j = SCHARS (item_name); j < maxwidth; j++)
2227 item_data[j] = ' ';
2228 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2229 item_data[j + SBYTES (descrip)] = 0;
2231 else
2232 item_data = SSDATA (item_name);
2234 if (lpane == XM_FAILURE
2235 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2236 menu, lpane, 0, item_data,
2237 !NILP (enable), help_string)
2238 == XM_FAILURE))
2240 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2241 *error_name = "Can't add selection to menu";
2242 goto return_entry;
2244 i += MENU_ITEMS_ITEM_LENGTH;
2245 lines++;
2249 maxlines = max (maxlines, lines);
2251 /* All set and ready to fly. */
2252 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2253 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2254 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2255 x = min (x, dispwidth);
2256 y = min (y, dispheight);
2257 x = max (x, 1);
2258 y = max (y, 1);
2259 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2260 &ulx, &uly, &width, &height);
2261 if (ulx+width > dispwidth)
2263 x -= (ulx + width) - dispwidth;
2264 ulx = dispwidth - width;
2266 if (uly+height > dispheight)
2268 y -= (uly + height) - dispheight;
2269 uly = dispheight - height;
2271 #ifndef HAVE_X_WINDOWS
2272 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2274 /* Move the menu away of the echo area, to avoid overwriting the
2275 menu with help echo messages or vice versa. */
2276 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2278 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2279 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2281 else
2283 y--;
2284 uly--;
2287 #endif
2288 if (ulx < 0) x -= ulx;
2289 if (uly < 0) y -= uly;
2291 if (!(menuflags & MENU_FOR_CLICK))
2293 /* If position was not given by a mouse click, adjust so upper left
2294 corner of the menu as a whole ends up at given coordinates. This
2295 is what x-popup-menu says in its documentation. */
2296 x += width/2;
2297 y += 1.5*height/(maxlines+2);
2300 XMenuSetAEQ (menu, true);
2301 XMenuSetFreeze (menu, true);
2302 pane = selidx = 0;
2304 #ifndef MSDOS
2305 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2306 #endif
2308 record_unwind_protect_ptr (pop_down_menu,
2309 &(struct pop_down_menu) {f, menu});
2311 /* Help display under X won't work because XMenuActivate contains
2312 a loop that doesn't give Emacs a chance to process it. */
2313 menu_help_frame = f;
2314 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2315 x, y, ButtonReleaseMask, &datap,
2316 menu_help_callback);
2317 pane_prefix = Qnil;
2319 switch (status)
2321 case XM_SUCCESS:
2322 #ifdef XDEBUG
2323 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2324 #endif
2326 /* Find the item number SELIDX in pane number PANE. */
2327 i = 0;
2328 while (i < menu_items_used)
2330 if (EQ (AREF (menu_items, i), Qt))
2332 if (pane == 0)
2333 pane_prefix
2334 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2335 pane--;
2336 i += MENU_ITEMS_PANE_LENGTH;
2338 else
2340 if (pane == -1)
2342 if (selidx == 0)
2344 entry
2345 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2346 if (menuflags & MENU_KEYMAPS)
2348 entry = list1 (entry);
2349 if (!NILP (pane_prefix))
2350 entry = Fcons (pane_prefix, entry);
2352 break;
2354 selidx--;
2356 i += MENU_ITEMS_ITEM_LENGTH;
2359 break;
2361 case XM_FAILURE:
2362 *error_name = "Can't activate menu";
2363 case XM_IA_SELECT:
2364 break;
2365 case XM_NO_SELECT:
2366 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2367 the menu was invoked with a mouse event as POSITION). */
2368 if (!(menuflags & MENU_FOR_CLICK))
2370 unblock_input ();
2371 quit ();
2373 break;
2376 return_entry:
2377 unblock_input ();
2378 SAFE_FREE ();
2379 return unbind_to (specpdl_count, entry);
2382 #endif /* not USE_X_TOOLKIT */
2384 #ifndef MSDOS
2385 /* Detect if a dialog or menu has been posted. MSDOS has its own
2386 implementation on msdos.c. */
2389 popup_activated (void)
2391 return popup_activated_flag;
2393 #endif /* not MSDOS */
2395 /* The following is used by delayed window autoselection. */
2397 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2398 doc: /* Return t if a menu or popup dialog is active.
2399 \(On MS Windows, this refers to the selected frame.) */)
2400 (void)
2402 return (popup_activated ()) ? Qt : Qnil;
2405 void
2406 syms_of_xmenu (void)
2408 #ifdef USE_X_TOOLKIT
2409 enum { WIDGET_ID_TICK_START = 1 << 16 };
2410 widget_id_tick = WIDGET_ID_TICK_START;
2411 next_menubar_widget_id = 1;
2412 #endif
2414 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2415 defsubr (&Smenu_or_popup_active_p);
2417 #ifdef USE_GTK
2418 DEFSYM (Qframe_monitor_workarea, "frame-monitor-workarea");
2419 #endif
2421 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2422 defsubr (&Sx_menu_bar_open_internal);
2423 Ffset (intern_c_string ("accelerate-menu"),
2424 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2425 #endif