]> code.delx.au - gnu-emacs/blob - src/xmenu.c
Merge from origin/emacs-24
[gnu-emacs] / src / xmenu.c
1 /* X Communication module for terminals which understand the X protocol.
2
3 Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2015 Free Software
4 Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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.
12
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.
17
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/>. */
20
21 /* X pop-up deck-of-cards menu facility for GNU Emacs.
22 *
23 * Written by Jon Arnold and Roman Budzianowski
24 * Mods and rewrite by Robert Krawitz
25 *
26 */
27
28 /* Modified by Fred Pierresteguy on December 93
29 to make the popup menus and menubar use the Xt. */
30
31 /* Rewritten for clarity and GC protection by rms in Feb 94. */
32
33 #include <config.h>
34
35 #include <stdio.h>
36
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"
49
50 #ifdef MSDOS
51 #include "msdos.h"
52 #endif
53
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
59
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
65
66 #include "dispextern.h"
67
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 */
97
98 #ifdef USE_GTK
99 #include "gtkutil.h"
100 #ifdef HAVE_GTK3
101 #include "xgselect.h"
102 #endif
103 #endif
104
105 #include "menu.h"
106
107 \f
108 /* Flag which when set indicates a dialog or menu has been posted by
109 Xt on behalf of one of the widget sets. */
110 static int popup_activated_flag;
111
112 \f
113 #ifdef USE_X_TOOLKIT
114
115 static LWLIB_ID next_menubar_widget_id;
116
117 /* Return the frame whose ->output_data.x->id equals ID, or 0 if none. */
118
119 static struct frame *
120 menubar_id_to_frame (LWLIB_ID id)
121 {
122 Lisp_Object tail, frame;
123 struct frame *f;
124
125 FOR_EACH_FRAME (tail, frame)
126 {
127 f = XFRAME (frame);
128 if (!FRAME_WINDOW_P (f))
129 continue;
130 if (f->output_data.x->id == id)
131 return f;
132 }
133 return 0;
134 }
135
136 #endif
137
138 #ifndef MSDOS
139
140 #if defined USE_GTK || defined USE_MOTIF
141
142 /* Set menu_items_inuse so no other popup menu or dialog is created. */
143
144 void
145 x_menu_set_in_use (bool in_use)
146 {
147 menu_items_inuse = in_use ? Qt : Qnil;
148 popup_activated_flag = in_use;
149 #ifdef USE_X_TOOLKIT
150 if (popup_activated_flag)
151 x_activate_timeout_atimer ();
152 #endif
153 }
154
155 #endif
156
157 /* Wait for an X event to arrive or for a timer to expire. */
158
159 void
160 x_menu_wait_for_event (void *data)
161 {
162 /* Another way to do this is to register a timer callback, that can be
163 done in GTK and Xt. But we have to do it like this when using only X
164 anyway, and with callbacks we would have three variants for timer handling
165 instead of the small ifdefs below. */
166
167 while (
168 #ifdef USE_X_TOOLKIT
169 ! XtAppPending (Xt_app_con)
170 #elif defined USE_GTK
171 ! gtk_events_pending ()
172 #else
173 ! XPending (data)
174 #endif
175 )
176 {
177 struct timespec next_time = timer_check (), *ntp;
178 fd_set read_fds;
179 struct x_display_info *dpyinfo;
180 int n = 0;
181
182 FD_ZERO (&read_fds);
183 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
184 {
185 int fd = ConnectionNumber (dpyinfo->display);
186 FD_SET (fd, &read_fds);
187 if (fd > n) n = fd;
188 XFlush (dpyinfo->display);
189 }
190
191 if (! timespec_valid_p (next_time))
192 ntp = 0;
193 else
194 ntp = &next_time;
195
196 #if defined USE_GTK && defined HAVE_GTK3
197 /* Gtk3 have arrows on menus when they don't fit. When the
198 pointer is over an arrow, a timeout scrolls it a bit. Use
199 xg_select so that timeout gets triggered. */
200 xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL);
201 #else
202 pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL);
203 #endif
204 }
205 }
206 #endif /* ! MSDOS */
207
208 \f
209 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
210
211 #ifdef USE_X_TOOLKIT
212
213 /* Loop in Xt until the menu pulldown or dialog popup has been
214 popped down (deactivated). This is used for x-popup-menu
215 and x-popup-dialog; it is not used for the menu bar.
216
217 NOTE: All calls to popup_get_selection should be protected
218 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
219
220 static void
221 popup_get_selection (XEvent *initial_event, struct x_display_info *dpyinfo,
222 LWLIB_ID id, bool do_timers)
223 {
224 XEvent event;
225
226 while (popup_activated_flag)
227 {
228 if (initial_event)
229 {
230 event = *initial_event;
231 initial_event = 0;
232 }
233 else
234 {
235 if (do_timers) x_menu_wait_for_event (0);
236 XtAppNextEvent (Xt_app_con, &event);
237 }
238
239 /* Make sure we don't consider buttons grabbed after menu goes.
240 And make sure to deactivate for any ButtonRelease,
241 even if XtDispatchEvent doesn't do that. */
242 if (event.type == ButtonRelease
243 && dpyinfo->display == event.xbutton.display)
244 {
245 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
246 #ifdef USE_MOTIF /* Pretending that the event came from a
247 Btn1Down seems the only way to convince Motif to
248 activate its callbacks; setting the XmNmenuPost
249 isn't working. --marcus@sysc.pdx.edu. */
250 event.xbutton.button = 1;
251 /* Motif only pops down menus when no Ctrl, Alt or Mod
252 key is pressed and the button is released. So reset key state
253 so Motif thinks this is the case. */
254 event.xbutton.state = 0;
255 #endif
256 }
257 /* Pop down on C-g and Escape. */
258 else if (event.type == KeyPress
259 && dpyinfo->display == event.xbutton.display)
260 {
261 KeySym keysym = XLookupKeysym (&event.xkey, 0);
262
263 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0)
264 || keysym == XK_Escape) /* Any escape, ignore modifiers. */
265 popup_activated_flag = 0;
266 }
267
268 x_dispatch_event (&event, event.xany.display);
269 }
270 }
271
272 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
273 doc: /* Start key navigation of the menu bar in FRAME.
274 This initially opens the first menu bar item and you can then navigate with the
275 arrow keys, select a menu entry with the return key or cancel with the
276 escape key. If FRAME has no menu bar this function does nothing.
277
278 If FRAME is nil or not given, use the selected frame. */)
279 (Lisp_Object frame)
280 {
281 XEvent ev;
282 struct frame *f = decode_window_system_frame (frame);
283 Widget menubar;
284 block_input ();
285
286 if (FRAME_EXTERNAL_MENU_BAR (f))
287 set_frame_menubar (f, false, true);
288
289 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
290 if (menubar)
291 {
292 Window child;
293 bool error_p = false;
294
295 x_catch_errors (FRAME_X_DISPLAY (f));
296 memset (&ev, 0, sizeof ev);
297 ev.xbutton.display = FRAME_X_DISPLAY (f);
298 ev.xbutton.window = XtWindow (menubar);
299 ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
300 ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
301 ev.xbutton.button = Button1;
302 ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
303 ev.xbutton.same_screen = True;
304
305 #ifdef USE_MOTIF
306 {
307 Arg al[2];
308 WidgetList list;
309 Cardinal nr;
310 XtSetArg (al[0], XtNchildren, &list);
311 XtSetArg (al[1], XtNnumChildren, &nr);
312 XtGetValues (menubar, al, 2);
313 ev.xbutton.window = XtWindow (list[0]);
314 }
315 #endif
316
317 XTranslateCoordinates (FRAME_X_DISPLAY (f),
318 /* From-window, to-window. */
319 ev.xbutton.window, ev.xbutton.root,
320
321 /* From-position, to-position. */
322 ev.xbutton.x, ev.xbutton.y,
323 &ev.xbutton.x_root, &ev.xbutton.y_root,
324
325 /* Child of win. */
326 &child);
327 error_p = x_had_errors_p (FRAME_X_DISPLAY (f));
328 x_uncatch_errors ();
329
330 if (! error_p)
331 {
332 ev.type = ButtonPress;
333 ev.xbutton.state = 0;
334
335 XtDispatchEvent (&ev);
336 ev.xbutton.type = ButtonRelease;
337 ev.xbutton.state = Button1Mask;
338 XtDispatchEvent (&ev);
339 }
340 }
341
342 unblock_input ();
343
344 return Qnil;
345 }
346 #endif /* USE_X_TOOLKIT */
347
348
349 #ifdef USE_GTK
350 DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i",
351 doc: /* Start key navigation of the menu bar in FRAME.
352 This initially opens the first menu bar item and you can then navigate with the
353 arrow keys, select a menu entry with the return key or cancel with the
354 escape key. If FRAME has no menu bar this function does nothing.
355
356 If FRAME is nil or not given, use the selected frame. */)
357 (Lisp_Object frame)
358 {
359 GtkWidget *menubar;
360 struct frame *f;
361
362 block_input ();
363 f = decode_window_system_frame (frame);
364
365 if (FRAME_EXTERNAL_MENU_BAR (f))
366 set_frame_menubar (f, false, true);
367
368 menubar = FRAME_X_OUTPUT (f)->menubar_widget;
369 if (menubar)
370 {
371 /* Activate the first menu. */
372 GList *children = gtk_container_get_children (GTK_CONTAINER (menubar));
373
374 if (children)
375 {
376 g_signal_emit_by_name (children->data, "activate_item");
377 popup_activated_flag = 1;
378 g_list_free (children);
379 }
380 }
381 unblock_input ();
382
383 return Qnil;
384 }
385
386 /* Loop util popup_activated_flag is set to zero in a callback.
387 Used for popup menus and dialogs. */
388
389 static void
390 popup_widget_loop (bool do_timers, GtkWidget *widget)
391 {
392 ++popup_activated_flag;
393
394 /* Process events in the Gtk event loop until done. */
395 while (popup_activated_flag)
396 {
397 if (do_timers) x_menu_wait_for_event (0);
398 gtk_main_iteration ();
399 }
400 }
401 #endif
402
403 /* Activate the menu bar of frame F.
404 This is called from keyboard.c when it gets the
405 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
406
407 To activate the menu bar, we use the X button-press event
408 that was saved in saved_menu_event.
409 That makes the toolkit do its thing.
410
411 But first we recompute the menu bar contents (the whole tree).
412
413 The reason for saving the button event until here, instead of
414 passing it to the toolkit right away, is that we can safely
415 execute Lisp code. */
416
417 void
418 x_activate_menubar (struct frame *f)
419 {
420 eassert (FRAME_X_P (f));
421
422 if (!f->output_data.x->saved_menu_event->type)
423 return;
424
425 #ifdef USE_GTK
426 if (! xg_win_to_widget (FRAME_X_DISPLAY (f),
427 f->output_data.x->saved_menu_event->xany.window))
428 return;
429 #endif
430
431 set_frame_menubar (f, false, true);
432 block_input ();
433 popup_activated_flag = 1;
434 #ifdef USE_GTK
435 XPutBackEvent (f->output_data.x->display_info->display,
436 f->output_data.x->saved_menu_event);
437 #else
438 XtDispatchEvent (f->output_data.x->saved_menu_event);
439 #endif
440 unblock_input ();
441
442 /* Ignore this if we get it a second time. */
443 f->output_data.x->saved_menu_event->type = 0;
444 }
445
446 /* This callback is invoked when the user selects a menubar cascade
447 pushbutton, but before the pulldown menu is posted. */
448
449 #ifndef USE_GTK
450 static void
451 popup_activate_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
452 {
453 popup_activated_flag = 1;
454 x_activate_timeout_atimer ();
455 }
456 #endif
457
458 /* This callback is invoked when a dialog or menu is finished being
459 used and has been unposted. */
460
461 static void
462 popup_deactivate_callback (
463 #ifdef USE_GTK
464 GtkWidget *widget, gpointer client_data
465 #else
466 Widget widget, LWLIB_ID id, XtPointer client_data
467 #endif
468 )
469 {
470 popup_activated_flag = 0;
471 }
472
473
474 /* Function that finds the frame for WIDGET and shows the HELP text
475 for that widget.
476 F is the frame if known, or NULL if not known. */
477 static void
478 show_help_event (struct frame *f, xt_or_gtk_widget widget, Lisp_Object help)
479 {
480 Lisp_Object frame;
481
482 if (f)
483 {
484 XSETFRAME (frame, f);
485 kbd_buffer_store_help_event (frame, help);
486 }
487 else
488 show_help_echo (help, Qnil, Qnil, Qnil);
489 }
490
491 /* Callback called when menu items are highlighted/unhighlighted
492 while moving the mouse over them. WIDGET is the menu bar or menu
493 popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to
494 the data structure for the menu item, or null in case of
495 unhighlighting. */
496
497 #ifdef USE_GTK
498 static void
499 menu_highlight_callback (GtkWidget *widget, gpointer call_data)
500 {
501 xg_menu_item_cb_data *cb_data;
502 Lisp_Object help;
503
504 cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA);
505 if (! cb_data) return;
506
507 help = call_data ? cb_data->help : Qnil;
508
509 /* If popup_activated_flag is greater than 1 we are in a popup menu.
510 Don't pass the frame to show_help_event for those.
511 Passing frame creates an Emacs event. As we are looping in
512 popup_widget_loop, it won't be handled. Passing NULL shows the tip
513 directly without using an Emacs event. This is what the Lucid code
514 does below. */
515 show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL,
516 widget, help);
517 }
518 #else
519 static void
520 menu_highlight_callback (Widget widget, LWLIB_ID id, void *call_data)
521 {
522 widget_value *wv = call_data;
523 Lisp_Object help = wv ? wv->help : Qnil;
524
525 /* Determine the frame for the help event. */
526 struct frame *f = menubar_id_to_frame (id);
527
528 show_help_event (f, widget, help);
529 }
530 #endif
531
532 #ifdef USE_GTK
533 /* Gtk calls callbacks just because we tell it what item should be
534 selected in a radio group. If this variable is set to a non-zero
535 value, we are creating menus and don't want callbacks right now.
536 */
537 static bool xg_crazy_callback_abort;
538
539 /* This callback is called from the menu bar pulldown menu
540 when the user makes a selection.
541 Figure out what the user chose
542 and put the appropriate events into the keyboard buffer. */
543 static void
544 menubar_selection_callback (GtkWidget *widget, gpointer client_data)
545 {
546 xg_menu_item_cb_data *cb_data = client_data;
547
548 if (xg_crazy_callback_abort)
549 return;
550
551 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f)
552 return;
553
554 /* For a group of radio buttons, GTK calls the selection callback first
555 for the item that was active before the selection and then for the one that
556 is active after the selection. For C-h k this means we get the help on
557 the deselected item and then the selected item is executed. Prevent that
558 by ignoring the non-active item. */
559 if (GTK_IS_RADIO_MENU_ITEM (widget)
560 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
561 return;
562
563 /* When a menu is popped down, X generates a focus event (i.e. focus
564 goes back to the frame below the menu). Since GTK buffers events,
565 we force it out here before the menu selection event. Otherwise
566 sit-for will exit at once if the focus event follows the menu selection
567 event. */
568
569 block_input ();
570 while (gtk_events_pending ())
571 gtk_main_iteration ();
572 unblock_input ();
573
574 find_and_call_menu_selection (cb_data->cl_data->f,
575 cb_data->cl_data->menu_bar_items_used,
576 cb_data->cl_data->menu_bar_vector,
577 cb_data->call_data);
578 }
579
580 #else /* not USE_GTK */
581
582 /* This callback is called from the menu bar pulldown menu
583 when the user makes a selection.
584 Figure out what the user chose
585 and put the appropriate events into the keyboard buffer. */
586 static void
587 menubar_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
588 {
589 struct frame *f;
590
591 f = menubar_id_to_frame (id);
592 if (!f)
593 return;
594 find_and_call_menu_selection (f, f->menu_bar_items_used,
595 f->menu_bar_vector, client_data);
596 }
597 #endif /* not USE_GTK */
598 \f
599 /* Recompute all the widgets of frame F, when the menu bar has been
600 changed. */
601
602 static void
603 update_frame_menubar (struct frame *f)
604 {
605 #ifdef USE_GTK
606 xg_update_frame_menubar (f);
607 #else
608 struct x_output *x;
609
610 eassert (FRAME_X_P (f));
611
612 x = f->output_data.x;
613
614 if (!x->menubar_widget || XtIsManaged (x->menubar_widget))
615 return;
616
617 block_input ();
618
619 /* Do the voodoo which means "I'm changing lots of things, don't try
620 to refigure sizes until I'm done." */
621 lw_refigure_widget (x->column_widget, False);
622
623 /* The order in which children are managed is the top to bottom
624 order in which they are displayed in the paned window. First,
625 remove the text-area widget. */
626 XtUnmanageChild (x->edit_widget);
627
628 /* Remove the menubar that is there now, and put up the menubar that
629 should be there. */
630 XtManageChild (x->menubar_widget);
631 XtMapWidget (x->menubar_widget);
632 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, NULL);
633
634 /* Re-manage the text-area widget, and then thrash the sizes. */
635 XtManageChild (x->edit_widget);
636 lw_refigure_widget (x->column_widget, True);
637
638 /* Force the pane widget to resize itself. */
639 int new_height = -1;
640 #ifdef USE_LUCID
641 /* For reasons I don't know Lucid wants to add one pixel to the frame
642 height when adding the menu bar. Compensate that here. */
643 new_height = FRAME_TEXT_HEIGHT (f) - 1;
644 #endif /* USE_LUCID */
645 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
646 unblock_input ();
647 #endif /* USE_GTK */
648 }
649
650 #ifdef USE_LUCID
651 static void
652 apply_systemfont_to_dialog (Widget w)
653 {
654 const char *fn = xsettings_get_system_normal_font ();
655 if (fn)
656 {
657 XrmDatabase db = XtDatabase (XtDisplay (w));
658 if (db)
659 XrmPutStringResource (&db, "*dialog.font", fn);
660 }
661 }
662
663 static void
664 apply_systemfont_to_menu (struct frame *f, Widget w)
665 {
666 const char *fn = xsettings_get_system_normal_font ();
667
668 if (fn)
669 {
670 XrmDatabase db = XtDatabase (XtDisplay (w));
671 if (db)
672 {
673 XrmPutStringResource (&db, "*menubar*font", fn);
674 XrmPutStringResource (&db, "*popup*font", fn);
675 }
676 }
677 }
678
679 #endif
680
681 /* Set the contents of the menubar widgets of frame F.
682 The argument FIRST_TIME is currently ignored;
683 it is set the first time this is called, from initialize_frame_menubar. */
684
685 void
686 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
687 {
688 xt_or_gtk_widget menubar_widget, old_widget;
689 #ifdef USE_X_TOOLKIT
690 LWLIB_ID id;
691 #endif
692 Lisp_Object items;
693 widget_value *wv, *first_wv, *prev_wv = 0;
694 int i;
695 int *submenu_start, *submenu_end;
696 bool *submenu_top_level_items;
697 int *submenu_n_panes;
698
699 eassert (FRAME_X_P (f));
700
701 menubar_widget = old_widget = f->output_data.x->menubar_widget;
702
703 XSETFRAME (Vmenu_updating_frame, f);
704
705 #ifdef USE_X_TOOLKIT
706 if (f->output_data.x->id == 0)
707 f->output_data.x->id = next_menubar_widget_id++;
708 id = f->output_data.x->id;
709 #endif
710
711 if (! menubar_widget)
712 deep_p = true;
713 /* Make the first call for any given frame always go deep. */
714 else if (!f->output_data.x->saved_menu_event && !deep_p)
715 {
716 deep_p = true;
717 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
718 f->output_data.x->saved_menu_event->type = 0;
719 }
720
721 if (deep_p)
722 {
723 /* Make a widget-value tree representing the entire menu trees. */
724
725 struct buffer *prev = current_buffer;
726 Lisp_Object buffer;
727 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
728 int previous_menu_items_used = f->menu_bar_items_used;
729 Lisp_Object *previous_items
730 = alloca (previous_menu_items_used * sizeof *previous_items);
731 int subitems;
732
733 /* If we are making a new widget, its contents are empty,
734 do always reinitialize them. */
735 if (! menubar_widget)
736 previous_menu_items_used = 0;
737
738 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
739 specbind (Qinhibit_quit, Qt);
740 /* Don't let the debugger step into this code
741 because it is not reentrant. */
742 specbind (Qdebug_on_next_call, Qnil);
743
744 record_unwind_save_match_data ();
745 if (NILP (Voverriding_local_map_menu_flag))
746 {
747 specbind (Qoverriding_terminal_local_map, Qnil);
748 specbind (Qoverriding_local_map, Qnil);
749 }
750
751 set_buffer_internal_1 (XBUFFER (buffer));
752
753 /* Run the Lucid hook. */
754 safe_run_hooks (Qactivate_menubar_hook);
755
756 /* If it has changed current-menubar from previous value,
757 really recompute the menubar from the value. */
758 if (! NILP (Vlucid_menu_bar_dirty_flag))
759 call0 (Qrecompute_lucid_menubar);
760 safe_run_hooks (Qmenu_bar_update_hook);
761 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
762
763 items = FRAME_MENU_BAR_ITEMS (f);
764
765 /* Save the frame's previous menu bar contents data. */
766 if (previous_menu_items_used)
767 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
768 previous_menu_items_used * word_size);
769
770 /* Fill in menu_items with the current menu bar contents.
771 This can evaluate Lisp code. */
772 save_menu_items ();
773
774 menu_items = f->menu_bar_vector;
775 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
776 subitems = ASIZE (items) / 4;
777 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
778 submenu_end = alloca (subitems * sizeof *submenu_end);
779 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
780 submenu_top_level_items = alloca (subitems
781 * sizeof *submenu_top_level_items);
782 init_menu_items ();
783 for (i = 0; i < subitems; i++)
784 {
785 Lisp_Object key, string, maps;
786
787 key = AREF (items, 4 * i);
788 string = AREF (items, 4 * i + 1);
789 maps = AREF (items, 4 * i + 2);
790 if (NILP (string))
791 break;
792
793 submenu_start[i] = menu_items_used;
794
795 menu_items_n_panes = 0;
796 submenu_top_level_items[i]
797 = parse_single_submenu (key, string, maps);
798 submenu_n_panes[i] = menu_items_n_panes;
799
800 submenu_end[i] = menu_items_used;
801 }
802
803 submenu_start[i] = -1;
804 finish_menu_items ();
805
806 /* Convert menu_items into widget_value trees
807 to display the menu. This cannot evaluate Lisp code. */
808
809 wv = make_widget_value ("menubar", NULL, true, Qnil);
810 wv->button_type = BUTTON_TYPE_NONE;
811 first_wv = wv;
812
813 for (i = 0; submenu_start[i] >= 0; i++)
814 {
815 menu_items_n_panes = submenu_n_panes[i];
816 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
817 submenu_top_level_items[i]);
818 if (prev_wv)
819 prev_wv->next = wv;
820 else
821 first_wv->contents = wv;
822 /* Don't set wv->name here; GC during the loop might relocate it. */
823 wv->enabled = true;
824 wv->button_type = BUTTON_TYPE_NONE;
825 prev_wv = wv;
826 }
827
828 set_buffer_internal_1 (prev);
829
830 /* If there has been no change in the Lisp-level contents
831 of the menu bar, skip redisplaying it. Just exit. */
832
833 /* Compare the new menu items with the ones computed last time. */
834 for (i = 0; i < previous_menu_items_used; i++)
835 if (menu_items_used == i
836 || (!EQ (previous_items[i], AREF (menu_items, i))))
837 break;
838 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
839 {
840 /* The menu items have not changed. Don't bother updating
841 the menus in any form, since it would be a no-op. */
842 free_menubar_widget_value_tree (first_wv);
843 discard_menu_items ();
844 unbind_to (specpdl_count, Qnil);
845 return;
846 }
847
848 /* The menu items are different, so store them in the frame. */
849 fset_menu_bar_vector (f, menu_items);
850 f->menu_bar_items_used = menu_items_used;
851
852 /* This undoes save_menu_items. */
853 unbind_to (specpdl_count, Qnil);
854
855 /* Now GC cannot happen during the lifetime of the widget_value,
856 so it's safe to store data from a Lisp_String. */
857 wv = first_wv->contents;
858 for (i = 0; i < ASIZE (items); i += 4)
859 {
860 Lisp_Object string;
861 string = AREF (items, i + 1);
862 if (NILP (string))
863 break;
864 wv->name = SSDATA (string);
865 update_submenu_strings (wv->contents);
866 wv = wv->next;
867 }
868
869 }
870 else
871 {
872 /* Make a widget-value tree containing
873 just the top level menu bar strings. */
874
875 wv = make_widget_value ("menubar", NULL, true, Qnil);
876 wv->button_type = BUTTON_TYPE_NONE;
877 first_wv = wv;
878
879 items = FRAME_MENU_BAR_ITEMS (f);
880 for (i = 0; i < ASIZE (items); i += 4)
881 {
882 Lisp_Object string;
883
884 string = AREF (items, i + 1);
885 if (NILP (string))
886 break;
887
888 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
889 wv->button_type = BUTTON_TYPE_NONE;
890 /* This prevents lwlib from assuming this
891 menu item is really supposed to be empty. */
892 /* The intptr_t cast avoids a warning.
893 This value just has to be different from small integers. */
894 wv->call_data = (void *) (intptr_t) (-1);
895
896 if (prev_wv)
897 prev_wv->next = wv;
898 else
899 first_wv->contents = wv;
900 prev_wv = wv;
901 }
902
903 /* Forget what we thought we knew about what is in the
904 detailed contents of the menu bar menus.
905 Changing the top level always destroys the contents. */
906 f->menu_bar_items_used = 0;
907 }
908
909 /* Create or update the menu bar widget. */
910
911 block_input ();
912
913 #ifdef USE_GTK
914 xg_crazy_callback_abort = true;
915 if (menubar_widget)
916 {
917 /* The fourth arg is DEEP_P, which says to consider the entire
918 menu trees we supply, rather than just the menu bar item names. */
919 xg_modify_menubar_widgets (menubar_widget,
920 f,
921 first_wv,
922 deep_p,
923 G_CALLBACK (menubar_selection_callback),
924 G_CALLBACK (popup_deactivate_callback),
925 G_CALLBACK (menu_highlight_callback));
926 }
927 else
928 {
929 menubar_widget
930 = xg_create_widget ("menubar", "menubar", f, first_wv,
931 G_CALLBACK (menubar_selection_callback),
932 G_CALLBACK (popup_deactivate_callback),
933 G_CALLBACK (menu_highlight_callback));
934
935 f->output_data.x->menubar_widget = menubar_widget;
936 }
937
938
939 #else /* not USE_GTK */
940 if (menubar_widget)
941 {
942 /* Disable resizing (done for Motif!) */
943 lw_allow_resizing (f->output_data.x->widget, False);
944
945 /* The third arg is DEEP_P, which says to consider the entire
946 menu trees we supply, rather than just the menu bar item names. */
947 lw_modify_all_widgets (id, first_wv, deep_p);
948
949 /* Re-enable the edit widget to resize. */
950 lw_allow_resizing (f->output_data.x->widget, True);
951 }
952 else
953 {
954 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
955 XtTranslations override = XtParseTranslationTable (menuOverride);
956
957 #ifdef USE_LUCID
958 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
959 #endif
960 menubar_widget = lw_create_widget ("menubar", "menubar", id,
961 first_wv,
962 f->output_data.x->column_widget,
963 false,
964 popup_activate_callback,
965 menubar_selection_callback,
966 popup_deactivate_callback,
967 menu_highlight_callback);
968 f->output_data.x->menubar_widget = menubar_widget;
969
970 /* Make menu pop down on C-g. */
971 XtOverrideTranslations (menubar_widget, override);
972 }
973
974 {
975 int menubar_size;
976 if (f->output_data.x->menubar_widget)
977 XtRealizeWidget (f->output_data.x->menubar_widget);
978
979 menubar_size
980 = (f->output_data.x->menubar_widget
981 ? (f->output_data.x->menubar_widget->core.height
982 + f->output_data.x->menubar_widget->core.border_width)
983 : 0);
984
985 #ifdef USE_LUCID
986 /* Experimentally, we now get the right results
987 for -geometry -0-0 without this. 24 Aug 96, rms.
988 Maybe so, but the menu bar size is missing the pixels so the
989 WM size hints are off by these pixels. Jan D, oct 2009. */
990 if (FRAME_EXTERNAL_MENU_BAR (f))
991 {
992 Dimension ibw = 0;
993 XtVaGetValues (f->output_data.x->column_widget,
994 XtNinternalBorderWidth, &ibw, NULL);
995 menubar_size += ibw;
996 }
997 #endif /* USE_LUCID */
998
999 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1000 }
1001 #endif /* not USE_GTK */
1002
1003 free_menubar_widget_value_tree (first_wv);
1004 update_frame_menubar (f);
1005
1006 #ifdef USE_GTK
1007 xg_crazy_callback_abort = false;
1008 #endif
1009
1010 unblock_input ();
1011 }
1012
1013 /* Called from Fx_create_frame to create the initial menubar of a frame
1014 before it is mapped, so that the window is mapped with the menubar already
1015 there instead of us tacking it on later and thrashing the window after it
1016 is visible. */
1017
1018 void
1019 initialize_frame_menubar (struct frame *f)
1020 {
1021 /* This function is called before the first chance to redisplay
1022 the frame. It has to be, so the frame will have the right size. */
1023 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1024 set_frame_menubar (f, true, true);
1025 }
1026
1027
1028 /* Get rid of the menu bar of frame F, and free its storage.
1029 This is used when deleting a frame, and when turning off the menu bar.
1030 For GTK this function is in gtkutil.c. */
1031
1032 #ifndef USE_GTK
1033 void
1034 free_frame_menubar (struct frame *f)
1035 {
1036 Widget menubar_widget;
1037 #ifdef USE_MOTIF
1038 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1039 If we want to preserve the old height, calculate it now so we can
1040 restore it below. */
1041 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1042 #endif
1043
1044 eassert (FRAME_X_P (f));
1045
1046 menubar_widget = f->output_data.x->menubar_widget;
1047
1048 FRAME_MENUBAR_HEIGHT (f) = 0;
1049
1050 if (menubar_widget)
1051 {
1052 #ifdef USE_MOTIF
1053 /* Removing the menu bar magically changes the shell widget's x
1054 and y position of (0, 0) which, when the menu bar is turned
1055 on again, leads to pull-down menus appearing in strange
1056 positions near the upper-left corner of the display. This
1057 happens only with some window managers like twm and ctwm,
1058 but not with other like Motif's mwm or kwm, because the
1059 latter generate ConfigureNotify events when the menu bar
1060 is switched off, which fixes the shell position. */
1061 Position x0, y0, x1, y1;
1062 #endif
1063
1064 block_input ();
1065
1066 #ifdef USE_MOTIF
1067 if (f->output_data.x->widget)
1068 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1069 #endif
1070
1071 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1072 f->output_data.x->menubar_widget = NULL;
1073
1074 if (f->output_data.x->widget)
1075 {
1076 int new_height = -1;
1077 #ifdef USE_MOTIF
1078 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1079 if (x1 == 0 && y1 == 0)
1080 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1081 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1082 new_height = old_height;
1083 #endif /* USE_MOTIF */
1084 adjust_frame_size (f, -1, new_height, 2, false, Qmenu_bar_lines);
1085 }
1086 else
1087 {
1088 #ifdef USE_MOTIF
1089 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1090 adjust_frame_size (f, -1, old_height, 1, false, Qmenu_bar_lines);
1091 #endif
1092 }
1093
1094 unblock_input ();
1095 }
1096 }
1097 #endif /* not USE_GTK */
1098
1099 #endif /* USE_X_TOOLKIT || USE_GTK */
1100 \f
1101 /* x_menu_show actually displays a menu using the panes and items in menu_items
1102 and returns the value selected from it.
1103 There are two versions of x_menu_show, one for Xt and one for Xlib.
1104 Both assume input is blocked by the caller. */
1105
1106 /* F is the frame the menu is for.
1107 X and Y are the frame-relative specified position,
1108 relative to the inside upper left corner of the frame F.
1109 Bitfield MENUFLAGS bits are:
1110 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1111 MENU_KEYMAPS is set if this menu was specified with keymaps;
1112 in that case, we return a list containing the chosen item's value
1113 and perhaps also the pane's prefix.
1114 TITLE is the specified menu title.
1115 ERROR is a place to store an error message string in case of failure.
1116 (We return nil on failure, but the value doesn't actually matter.) */
1117
1118 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1119
1120 /* The item selected in the popup menu. */
1121 static Lisp_Object *volatile menu_item_selection;
1122
1123 #ifdef USE_GTK
1124
1125 /* Used when position a popup menu. See menu_position_func and
1126 create_and_show_popup_menu below. */
1127 struct next_popup_x_y
1128 {
1129 struct frame *f;
1130 int x;
1131 int y;
1132 };
1133
1134 /* The menu position function to use if we are not putting a popup
1135 menu where the pointer is.
1136 MENU is the menu to pop up.
1137 X and Y shall on exit contain x/y where the menu shall pop up.
1138 PUSH_IN is not documented in the GTK manual.
1139 USER_DATA is any data passed in when calling gtk_menu_popup.
1140 Here it points to a struct next_popup_x_y where the coordinates
1141 to store in *X and *Y are as well as the frame for the popup.
1142
1143 Here only X and Y are used. */
1144 static void
1145 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1146 {
1147 struct next_popup_x_y *data = user_data;
1148 GtkRequisition req;
1149 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1150 int disp_width = x_display_pixel_width (dpyinfo);
1151 int disp_height = x_display_pixel_height (dpyinfo);
1152
1153 *x = data->x;
1154 *y = data->y;
1155
1156 /* Check if there is room for the menu. If not, adjust x/y so that
1157 the menu is fully visible. */
1158 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1159 if (data->x + req.width > disp_width)
1160 *x -= data->x + req.width - disp_width;
1161 if (data->y + req.height > disp_height)
1162 *y -= data->y + req.height - disp_height;
1163 }
1164
1165 static void
1166 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1167 {
1168 xg_menu_item_cb_data *cb_data = client_data;
1169
1170 if (xg_crazy_callback_abort) return;
1171 if (cb_data) menu_item_selection = cb_data->call_data;
1172 }
1173
1174 static void
1175 pop_down_menu (void *arg)
1176 {
1177 popup_activated_flag = 0;
1178 block_input ();
1179 gtk_widget_destroy (GTK_WIDGET (arg));
1180 unblock_input ();
1181 }
1182
1183 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1184 menu pops down.
1185 menu_item_selection will be set to the selection. */
1186 static void
1187 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1188 int x, int y, bool for_click)
1189 {
1190 int i;
1191 GtkWidget *menu;
1192 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1193 struct next_popup_x_y popup_x_y;
1194 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1195 bool use_pos_func = ! for_click;
1196
1197 #ifdef HAVE_GTK3
1198 /* Always use position function for Gtk3. Otherwise menus may become
1199 too small to show anything. */
1200 use_pos_func = true;
1201 #endif
1202
1203 eassert (FRAME_X_P (f));
1204
1205 xg_crazy_callback_abort = true;
1206 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1207 G_CALLBACK (popup_selection_callback),
1208 G_CALLBACK (popup_deactivate_callback),
1209 G_CALLBACK (menu_highlight_callback));
1210 xg_crazy_callback_abort = false;
1211
1212 if (use_pos_func)
1213 {
1214 Window dummy_window;
1215
1216 /* Not invoked by a click. pop up at x/y. */
1217 pos_func = menu_position_func;
1218
1219 /* Adjust coordinates to be root-window-relative. */
1220 block_input ();
1221 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1222
1223 /* From-window, to-window. */
1224 FRAME_X_WINDOW (f),
1225 FRAME_DISPLAY_INFO (f)->root_window,
1226
1227 /* From-position, to-position. */
1228 x, y, &x, &y,
1229
1230 /* Child of win. */
1231 &dummy_window);
1232 unblock_input ();
1233 popup_x_y.x = x;
1234 popup_x_y.y = y;
1235 popup_x_y.f = f;
1236
1237 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1238 }
1239
1240 if (for_click)
1241 {
1242 for (i = 0; i < 5; i++)
1243 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1244 break;
1245 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1246 if (i == 5) i = 0;
1247 }
1248
1249 /* Display the menu. */
1250 gtk_widget_show_all (menu);
1251
1252 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1253 FRAME_DISPLAY_INFO (f)->last_user_time);
1254
1255 record_unwind_protect_ptr (pop_down_menu, menu);
1256
1257 if (gtk_widget_get_mapped (menu))
1258 {
1259 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1260 two. show_help_echo uses this to detect popup menus. */
1261 popup_activated_flag = 1;
1262 /* Process events that apply to the menu. */
1263 popup_widget_loop (true, menu);
1264 }
1265
1266 unbind_to (specpdl_count, Qnil);
1267
1268 /* Must reset this manually because the button release event is not passed
1269 to Emacs event loop. */
1270 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1271 }
1272
1273 #else /* not USE_GTK */
1274
1275 /* We need a unique id for each widget handled by the Lucid Widget
1276 library.
1277
1278 For the main windows, and popup menus, we use this counter, which we
1279 increment each time after use. This starts from WIDGET_ID_TICK_START.
1280
1281 For menu bars, we use numbers starting at 0, counted in
1282 next_menubar_widget_id. */
1283 LWLIB_ID widget_id_tick;
1284
1285 static void
1286 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1287 {
1288 menu_item_selection = client_data;
1289 }
1290
1291 /* ID is the LWLIB ID of the dialog box. */
1292
1293 static void
1294 pop_down_menu (int id)
1295 {
1296 block_input ();
1297 lw_destroy_all_widgets ((LWLIB_ID) id);
1298 unblock_input ();
1299 popup_activated_flag = 0;
1300 }
1301
1302 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1303 menu pops down.
1304 menu_item_selection will be set to the selection. */
1305 static void
1306 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1307 int x, int y, bool for_click)
1308 {
1309 int i;
1310 Arg av[2];
1311 int ac = 0;
1312 XEvent dummy;
1313 XButtonPressedEvent *event = &(dummy.xbutton);
1314 LWLIB_ID menu_id;
1315 Widget menu;
1316 Window dummy_window;
1317
1318 eassert (FRAME_X_P (f));
1319
1320 #ifdef USE_LUCID
1321 apply_systemfont_to_menu (f, f->output_data.x->widget);
1322 #endif
1323
1324 menu_id = widget_id_tick++;
1325 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1326 f->output_data.x->widget, true, 0,
1327 popup_selection_callback,
1328 popup_deactivate_callback,
1329 menu_highlight_callback);
1330
1331 event->type = ButtonPress;
1332 event->serial = 0;
1333 event->send_event = false;
1334 event->display = FRAME_X_DISPLAY (f);
1335 event->time = CurrentTime;
1336 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1337 event->window = event->subwindow = event->root;
1338 event->x = x;
1339 event->y = y;
1340
1341 /* Adjust coordinates to be root-window-relative. */
1342 block_input ();
1343 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1344 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1345
1346 /* From-window, to-window. */
1347 FRAME_X_WINDOW (f),
1348 FRAME_DISPLAY_INFO (f)->root_window,
1349
1350 /* From-position, to-position. */
1351 x, y, &x, &y,
1352
1353 /* Child of win. */
1354 &dummy_window);
1355 unblock_input ();
1356
1357 event->x_root = x;
1358 event->y_root = y;
1359
1360 event->state = 0;
1361 event->button = 0;
1362 for (i = 0; i < 5; i++)
1363 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1364 event->button = i;
1365
1366 /* Don't allow any geometry request from the user. */
1367 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1368 XtSetValues (menu, av, ac);
1369
1370 /* Display the menu. */
1371 lw_popup_menu (menu, &dummy);
1372 popup_activated_flag = 1;
1373 x_activate_timeout_atimer ();
1374
1375 {
1376 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1377
1378 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1379
1380 /* Process events that apply to the menu. */
1381 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1382
1383 unbind_to (specpdl_count, Qnil);
1384 }
1385 }
1386
1387 #endif /* not USE_GTK */
1388
1389 static void
1390 cleanup_widget_value_tree (void *arg)
1391 {
1392 free_menubar_widget_value_tree (arg);
1393 }
1394
1395 Lisp_Object
1396 x_menu_show (struct frame *f, int x, int y, int menuflags,
1397 Lisp_Object title, const char **error_name)
1398 {
1399 int i;
1400 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1401 widget_value **submenu_stack
1402 = alloca (menu_items_used * sizeof *submenu_stack);
1403 Lisp_Object *subprefix_stack
1404 = alloca (menu_items_used * sizeof *subprefix_stack);
1405 int submenu_depth = 0;
1406
1407 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1408
1409 eassert (FRAME_X_P (f));
1410
1411 *error_name = NULL;
1412
1413 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1414 {
1415 *error_name = "Empty menu";
1416 return Qnil;
1417 }
1418
1419 block_input ();
1420
1421 /* Create a tree of widget_value objects
1422 representing the panes and their items. */
1423 wv = make_widget_value ("menu", NULL, true, Qnil);
1424 wv->button_type = BUTTON_TYPE_NONE;
1425 first_wv = wv;
1426 bool first_pane = true;
1427
1428 /* Loop over all panes and items, filling in the tree. */
1429 i = 0;
1430 while (i < menu_items_used)
1431 {
1432 if (EQ (AREF (menu_items, i), Qnil))
1433 {
1434 submenu_stack[submenu_depth++] = save_wv;
1435 save_wv = prev_wv;
1436 prev_wv = 0;
1437 first_pane = true;
1438 i++;
1439 }
1440 else if (EQ (AREF (menu_items, i), Qlambda))
1441 {
1442 prev_wv = save_wv;
1443 save_wv = submenu_stack[--submenu_depth];
1444 first_pane = false;
1445 i++;
1446 }
1447 else if (EQ (AREF (menu_items, i), Qt)
1448 && submenu_depth != 0)
1449 i += MENU_ITEMS_PANE_LENGTH;
1450 /* Ignore a nil in the item list.
1451 It's meaningful only for dialog boxes. */
1452 else if (EQ (AREF (menu_items, i), Qquote))
1453 i += 1;
1454 else if (EQ (AREF (menu_items, i), Qt))
1455 {
1456 /* Create a new pane. */
1457 Lisp_Object pane_name, prefix;
1458 const char *pane_string;
1459
1460 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1461 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1462
1463 #ifndef HAVE_MULTILINGUAL_MENU
1464 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1465 {
1466 pane_name = ENCODE_MENU_STRING (pane_name);
1467 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1468 }
1469 #endif
1470 pane_string = (NILP (pane_name)
1471 ? "" : SSDATA (pane_name));
1472 /* If there is just one top-level pane, put all its items directly
1473 under the top-level menu. */
1474 if (menu_items_n_panes == 1)
1475 pane_string = "";
1476
1477 /* If the pane has a meaningful name,
1478 make the pane a top-level menu item
1479 with its items as a submenu beneath it. */
1480 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1481 {
1482 wv = make_widget_value (pane_string, NULL, true, Qnil);
1483 if (save_wv)
1484 save_wv->next = wv;
1485 else
1486 first_wv->contents = wv;
1487 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1488 wv->name++;
1489 wv->button_type = BUTTON_TYPE_NONE;
1490 save_wv = wv;
1491 prev_wv = 0;
1492 }
1493 else if (first_pane)
1494 {
1495 save_wv = wv;
1496 prev_wv = 0;
1497 }
1498 first_pane = false;
1499 i += MENU_ITEMS_PANE_LENGTH;
1500 }
1501 else
1502 {
1503 /* Create a new item within current pane. */
1504 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1505 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1506 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1507 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1508 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1509 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1510 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1511 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1512
1513 #ifndef HAVE_MULTILINGUAL_MENU
1514 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1515 {
1516 item_name = ENCODE_MENU_STRING (item_name);
1517 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1518 }
1519
1520 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1521 {
1522 descrip = ENCODE_MENU_STRING (descrip);
1523 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1524 }
1525 #endif /* not HAVE_MULTILINGUAL_MENU */
1526
1527 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1528 STRINGP (help) ? help : Qnil);
1529 if (prev_wv)
1530 prev_wv->next = wv;
1531 else
1532 save_wv->contents = wv;
1533 if (!NILP (descrip))
1534 wv->key = SSDATA (descrip);
1535 /* If this item has a null value,
1536 make the call_data null so that it won't display a box
1537 when the mouse is on it. */
1538 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1539
1540 if (NILP (type))
1541 wv->button_type = BUTTON_TYPE_NONE;
1542 else if (EQ (type, QCtoggle))
1543 wv->button_type = BUTTON_TYPE_TOGGLE;
1544 else if (EQ (type, QCradio))
1545 wv->button_type = BUTTON_TYPE_RADIO;
1546 else
1547 emacs_abort ();
1548
1549 wv->selected = !NILP (selected);
1550
1551 prev_wv = wv;
1552
1553 i += MENU_ITEMS_ITEM_LENGTH;
1554 }
1555 }
1556
1557 /* Deal with the title, if it is non-nil. */
1558 if (!NILP (title))
1559 {
1560 widget_value *wv_title;
1561 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1562 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1563
1564 wv_sep2->next = first_wv->contents;
1565 wv_sep1->next = wv_sep2;
1566
1567 #ifndef HAVE_MULTILINGUAL_MENU
1568 if (STRING_MULTIBYTE (title))
1569 title = ENCODE_MENU_STRING (title);
1570 #endif
1571
1572 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1573 wv_title->button_type = BUTTON_TYPE_NONE;
1574 wv_title->next = wv_sep1;
1575 first_wv->contents = wv_title;
1576 }
1577
1578 /* No selection has been chosen yet. */
1579 menu_item_selection = 0;
1580
1581 /* Make sure to free the widget_value objects we used to specify the
1582 contents even with longjmp. */
1583 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1584
1585 /* Actually create and show the menu until popped down. */
1586 create_and_show_popup_menu (f, first_wv, x, y,
1587 menuflags & MENU_FOR_CLICK);
1588
1589 unbind_to (specpdl_count, Qnil);
1590
1591 /* Find the selected item, and its pane, to return
1592 the proper value. */
1593 if (menu_item_selection != 0)
1594 {
1595 Lisp_Object prefix, entry;
1596
1597 prefix = entry = Qnil;
1598 i = 0;
1599 while (i < menu_items_used)
1600 {
1601 if (EQ (AREF (menu_items, i), Qnil))
1602 {
1603 subprefix_stack[submenu_depth++] = prefix;
1604 prefix = entry;
1605 i++;
1606 }
1607 else if (EQ (AREF (menu_items, i), Qlambda))
1608 {
1609 prefix = subprefix_stack[--submenu_depth];
1610 i++;
1611 }
1612 else if (EQ (AREF (menu_items, i), Qt))
1613 {
1614 prefix
1615 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1616 i += MENU_ITEMS_PANE_LENGTH;
1617 }
1618 /* Ignore a nil in the item list.
1619 It's meaningful only for dialog boxes. */
1620 else if (EQ (AREF (menu_items, i), Qquote))
1621 i += 1;
1622 else
1623 {
1624 entry
1625 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1626 if (menu_item_selection == aref_addr (menu_items, i))
1627 {
1628 if (menuflags & MENU_KEYMAPS)
1629 {
1630 int j;
1631
1632 entry = list1 (entry);
1633 if (!NILP (prefix))
1634 entry = Fcons (prefix, entry);
1635 for (j = submenu_depth - 1; j >= 0; j--)
1636 if (!NILP (subprefix_stack[j]))
1637 entry = Fcons (subprefix_stack[j], entry);
1638 }
1639 unblock_input ();
1640 return entry;
1641 }
1642 i += MENU_ITEMS_ITEM_LENGTH;
1643 }
1644 }
1645 }
1646 else if (!(menuflags & MENU_FOR_CLICK))
1647 {
1648 unblock_input ();
1649 /* Make "Cancel" equivalent to C-g. */
1650 Fsignal (Qquit, Qnil);
1651 }
1652
1653 unblock_input ();
1654 return Qnil;
1655 }
1656 \f
1657 #ifdef USE_GTK
1658 static void
1659 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1660 {
1661 /* Treat the pointer as an integer. There's no problem
1662 as long as pointers have enough bits to hold small integers. */
1663 if ((intptr_t) client_data != -1)
1664 menu_item_selection = client_data;
1665
1666 popup_activated_flag = 0;
1667 }
1668
1669 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1670 dialog pops down.
1671 menu_item_selection will be set to the selection. */
1672 static void
1673 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1674 {
1675 GtkWidget *menu;
1676
1677 eassert (FRAME_X_P (f));
1678
1679 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1680 G_CALLBACK (dialog_selection_callback),
1681 G_CALLBACK (popup_deactivate_callback),
1682 0);
1683
1684 if (menu)
1685 {
1686 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1687 record_unwind_protect_ptr (pop_down_menu, menu);
1688
1689 /* Display the menu. */
1690 gtk_widget_show_all (menu);
1691
1692 /* Process events that apply to the menu. */
1693 popup_widget_loop (true, menu);
1694
1695 unbind_to (specpdl_count, Qnil);
1696 }
1697 }
1698
1699 #else /* not USE_GTK */
1700 static void
1701 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1702 {
1703 /* Treat the pointer as an integer. There's no problem
1704 as long as pointers have enough bits to hold small integers. */
1705 if ((intptr_t) client_data != -1)
1706 menu_item_selection = client_data;
1707
1708 block_input ();
1709 lw_destroy_all_widgets (id);
1710 unblock_input ();
1711 popup_activated_flag = 0;
1712 }
1713
1714
1715 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1716 dialog pops down.
1717 menu_item_selection will be set to the selection. */
1718 static void
1719 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1720 {
1721 LWLIB_ID dialog_id;
1722
1723 eassert (FRAME_X_P (f));
1724
1725 dialog_id = widget_id_tick++;
1726 #ifdef USE_LUCID
1727 apply_systemfont_to_dialog (f->output_data.x->widget);
1728 #endif
1729 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1730 f->output_data.x->widget, true, 0,
1731 dialog_selection_callback, 0, 0);
1732 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1733 /* Display the dialog box. */
1734 lw_pop_up_all_widgets (dialog_id);
1735 popup_activated_flag = 1;
1736 x_activate_timeout_atimer ();
1737
1738 /* Process events that apply to the dialog box.
1739 Also handle timers. */
1740 {
1741 ptrdiff_t count = SPECPDL_INDEX ();
1742
1743 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1744
1745 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1746
1747 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1748
1749 unbind_to (count, Qnil);
1750 }
1751 }
1752
1753 #endif /* not USE_GTK */
1754
1755 static const char * button_names [] = {
1756 "button1", "button2", "button3", "button4", "button5",
1757 "button6", "button7", "button8", "button9", "button10" };
1758
1759 static Lisp_Object
1760 x_dialog_show (struct frame *f, Lisp_Object title,
1761 Lisp_Object header, const char **error_name)
1762 {
1763 int i, nb_buttons=0;
1764 char dialog_name[6];
1765
1766 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1767
1768 /* Number of elements seen so far, before boundary. */
1769 int left_count = 0;
1770 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1771 bool boundary_seen = false;
1772
1773 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1774
1775 eassert (FRAME_X_P (f));
1776
1777 *error_name = NULL;
1778
1779 if (menu_items_n_panes > 1)
1780 {
1781 *error_name = "Multiple panes in dialog box";
1782 return Qnil;
1783 }
1784
1785 /* Create a tree of widget_value objects
1786 representing the text label and buttons. */
1787 {
1788 Lisp_Object pane_name;
1789 const char *pane_string;
1790 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1791 pane_string = (NILP (pane_name)
1792 ? "" : SSDATA (pane_name));
1793 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1794 first_wv = prev_wv;
1795
1796 /* Loop over all panes and items, filling in the tree. */
1797 i = MENU_ITEMS_PANE_LENGTH;
1798 while (i < menu_items_used)
1799 {
1800
1801 /* Create a new item within current pane. */
1802 Lisp_Object item_name, enable, descrip;
1803 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1804 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1805 descrip
1806 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1807
1808 if (NILP (item_name))
1809 {
1810 free_menubar_widget_value_tree (first_wv);
1811 *error_name = "Submenu in dialog items";
1812 return Qnil;
1813 }
1814 if (EQ (item_name, Qquote))
1815 {
1816 /* This is the boundary between left-side elts
1817 and right-side elts. Stop incrementing right_count. */
1818 boundary_seen = true;
1819 i++;
1820 continue;
1821 }
1822 if (nb_buttons >= 9)
1823 {
1824 free_menubar_widget_value_tree (first_wv);
1825 *error_name = "Too many dialog items";
1826 return Qnil;
1827 }
1828
1829 wv = make_widget_value (button_names[nb_buttons],
1830 SSDATA (item_name),
1831 !NILP (enable), Qnil);
1832 prev_wv->next = wv;
1833 if (!NILP (descrip))
1834 wv->key = SSDATA (descrip);
1835 wv->call_data = aref_addr (menu_items, i);
1836 prev_wv = wv;
1837
1838 if (! boundary_seen)
1839 left_count++;
1840
1841 nb_buttons++;
1842 i += MENU_ITEMS_ITEM_LENGTH;
1843 }
1844
1845 /* If the boundary was not specified,
1846 by default put half on the left and half on the right. */
1847 if (! boundary_seen)
1848 left_count = nb_buttons - nb_buttons / 2;
1849
1850 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1851
1852 /* Frame title: 'Q' = Question, 'I' = Information.
1853 Can also have 'E' = Error if, one day, we want
1854 a popup for errors. */
1855 if (NILP (header))
1856 dialog_name[0] = 'Q';
1857 else
1858 dialog_name[0] = 'I';
1859
1860 /* Dialog boxes use a really stupid name encoding
1861 which specifies how many buttons to use
1862 and how many buttons are on the right. */
1863 dialog_name[1] = '0' + nb_buttons;
1864 dialog_name[2] = 'B';
1865 dialog_name[3] = 'R';
1866 /* Number of buttons to put on the right. */
1867 dialog_name[4] = '0' + nb_buttons - left_count;
1868 dialog_name[5] = 0;
1869 wv->contents = first_wv;
1870 first_wv = wv;
1871 }
1872
1873 /* No selection has been chosen yet. */
1874 menu_item_selection = 0;
1875
1876 /* Make sure to free the widget_value objects we used to specify the
1877 contents even with longjmp. */
1878 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1879
1880 /* Actually create and show the dialog. */
1881 create_and_show_dialog (f, first_wv);
1882
1883 unbind_to (specpdl_count, Qnil);
1884
1885 /* Find the selected item, and its pane, to return
1886 the proper value. */
1887 if (menu_item_selection != 0)
1888 {
1889 i = 0;
1890 while (i < menu_items_used)
1891 {
1892 Lisp_Object entry;
1893
1894 if (EQ (AREF (menu_items, i), Qt))
1895 i += MENU_ITEMS_PANE_LENGTH;
1896 else if (EQ (AREF (menu_items, i), Qquote))
1897 {
1898 /* This is the boundary between left-side elts and
1899 right-side elts. */
1900 ++i;
1901 }
1902 else
1903 {
1904 entry
1905 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1906 if (menu_item_selection == aref_addr (menu_items, i))
1907 return entry;
1908 i += MENU_ITEMS_ITEM_LENGTH;
1909 }
1910 }
1911 }
1912 else
1913 /* Make "Cancel" equivalent to C-g. */
1914 Fsignal (Qquit, Qnil);
1915
1916 return Qnil;
1917 }
1918
1919 Lisp_Object
1920 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1921 {
1922 Lisp_Object title;
1923 const char *error_name;
1924 Lisp_Object selection;
1925 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1926
1927 check_window_system (f);
1928
1929 /* Decode the dialog items from what was specified. */
1930 title = Fcar (contents);
1931 CHECK_STRING (title);
1932 record_unwind_protect_void (unuse_menu_items);
1933
1934 if (NILP (Fcar (Fcdr (contents))))
1935 /* No buttons specified, add an "Ok" button so users can pop down
1936 the dialog. Also, the lesstif/motif version crashes if there are
1937 no buttons. */
1938 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1939
1940 list_of_panes (list1 (contents));
1941
1942 /* Display them in a dialog box. */
1943 block_input ();
1944 selection = x_dialog_show (f, title, header, &error_name);
1945 unblock_input ();
1946
1947 unbind_to (specpdl_count, Qnil);
1948 discard_menu_items ();
1949
1950 if (error_name) error ("%s", error_name);
1951 return selection;
1952 }
1953
1954 #else /* not USE_X_TOOLKIT && not USE_GTK */
1955
1956 /* The frame of the last activated non-toolkit menu bar.
1957 Used to generate menu help events. */
1958
1959 static struct frame *menu_help_frame;
1960
1961
1962 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1963
1964 PANE is the pane number, and ITEM is the menu item number in
1965 the menu (currently not used).
1966
1967 This cannot be done with generating a HELP_EVENT because
1968 XMenuActivate contains a loop that doesn't let Emacs process
1969 keyboard events. */
1970
1971 static void
1972 menu_help_callback (char const *help_string, int pane, int item)
1973 {
1974 Lisp_Object *first_item;
1975 Lisp_Object pane_name;
1976 Lisp_Object menu_object;
1977
1978 first_item = XVECTOR (menu_items)->contents;
1979 if (EQ (first_item[0], Qt))
1980 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1981 else if (EQ (first_item[0], Qquote))
1982 /* This shouldn't happen, see x_menu_show. */
1983 pane_name = empty_unibyte_string;
1984 else
1985 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1986
1987 /* (menu-item MENU-NAME PANE-NUMBER) */
1988 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1989 show_help_echo (help_string ? build_string (help_string) : Qnil,
1990 Qnil, menu_object, make_number (item));
1991 }
1992
1993 static void
1994 pop_down_menu (Lisp_Object arg)
1995 {
1996 struct frame *f = XSAVE_POINTER (arg, 0);
1997 XMenu *menu = XSAVE_POINTER (arg, 1);
1998
1999 block_input ();
2000 #ifndef MSDOS
2001 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2002 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2003 #endif
2004 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2005
2006 #ifdef HAVE_X_WINDOWS
2007 /* Assume the mouse has moved out of the X window.
2008 If it has actually moved in, we will get an EnterNotify. */
2009 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2010
2011 /* State that no mouse buttons are now held.
2012 (The oldXMenu code doesn't track this info for us.)
2013 That is not necessarily true, but the fiction leads to reasonable
2014 results, and it is a pain to ask which are actually held now. */
2015 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2016
2017 #endif /* HAVE_X_WINDOWS */
2018
2019 unblock_input ();
2020 }
2021
2022
2023 Lisp_Object
2024 x_menu_show (struct frame *f, int x, int y, int menuflags,
2025 Lisp_Object title, const char **error_name)
2026 {
2027 Window root;
2028 XMenu *menu;
2029 int pane, selidx, lpane, status;
2030 Lisp_Object entry = Qnil;
2031 Lisp_Object pane_prefix;
2032 char *datap;
2033 int ulx, uly, width, height;
2034 int dispwidth, dispheight;
2035 int i, j, lines, maxlines;
2036 int maxwidth;
2037 int dummy_int;
2038 unsigned int dummy_uint;
2039 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2040
2041 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2042
2043 *error_name = 0;
2044 if (menu_items_n_panes == 0)
2045 return Qnil;
2046
2047 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2048 {
2049 *error_name = "Empty menu";
2050 return Qnil;
2051 }
2052
2053 USE_SAFE_ALLOCA;
2054 block_input ();
2055
2056 /* Figure out which root window F is on. */
2057 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2058 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2059 &dummy_uint, &dummy_uint);
2060
2061 /* Make the menu on that window. */
2062 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2063 if (menu == NULL)
2064 {
2065 *error_name = "Can't create menu";
2066 goto return_entry;
2067 }
2068
2069 /* Don't GC while we prepare and show the menu,
2070 because we give the oldxmenu library pointers to the
2071 contents of strings. */
2072 inhibit_garbage_collection ();
2073
2074 #ifdef HAVE_X_WINDOWS
2075 {
2076 /* Adjust coordinates to relative to the outer (window manager) window. */
2077 int left_off, top_off;
2078
2079 x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
2080 NULL, NULL, NULL, NULL, NULL);
2081
2082 x += left_off;
2083 y += top_off;
2084 }
2085 #endif /* HAVE_X_WINDOWS */
2086
2087 x += f->left_pos;
2088 y += f->top_pos;
2089
2090 /* Create all the necessary panes and their items. */
2091 maxwidth = maxlines = lines = i = 0;
2092 lpane = XM_FAILURE;
2093 while (i < menu_items_used)
2094 {
2095 if (EQ (AREF (menu_items, i), Qt))
2096 {
2097 /* Create a new pane. */
2098 Lisp_Object pane_name, prefix;
2099 const char *pane_string;
2100
2101 maxlines = max (maxlines, lines);
2102 lines = 0;
2103 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2104 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2105 pane_string = (NILP (pane_name)
2106 ? "" : SSDATA (pane_name));
2107 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2108 pane_string++;
2109
2110 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2111 if (lpane == XM_FAILURE)
2112 {
2113 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2114 *error_name = "Can't create pane";
2115 goto return_entry;
2116 }
2117 i += MENU_ITEMS_PANE_LENGTH;
2118
2119 /* Find the width of the widest item in this pane. */
2120 j = i;
2121 while (j < menu_items_used)
2122 {
2123 Lisp_Object item;
2124 item = AREF (menu_items, j);
2125 if (EQ (item, Qt))
2126 break;
2127 if (NILP (item))
2128 {
2129 j++;
2130 continue;
2131 }
2132 width = SBYTES (item);
2133 if (width > maxwidth)
2134 maxwidth = width;
2135
2136 j += MENU_ITEMS_ITEM_LENGTH;
2137 }
2138 }
2139 /* Ignore a nil in the item list.
2140 It's meaningful only for dialog boxes. */
2141 else if (EQ (AREF (menu_items, i), Qquote))
2142 i += 1;
2143 else
2144 {
2145 /* Create a new item within current pane. */
2146 Lisp_Object item_name, enable, descrip, help;
2147 char *item_data;
2148 char const *help_string;
2149
2150 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2151 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2152 descrip
2153 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2154 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2155 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2156
2157 if (!NILP (descrip))
2158 {
2159 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2160 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2161 for (j = SCHARS (item_name); j < maxwidth; j++)
2162 item_data[j] = ' ';
2163 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2164 item_data[j + SBYTES (descrip)] = 0;
2165 }
2166 else
2167 item_data = SSDATA (item_name);
2168
2169 if (lpane == XM_FAILURE
2170 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2171 menu, lpane, 0, item_data,
2172 !NILP (enable), help_string)
2173 == XM_FAILURE))
2174 {
2175 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2176 *error_name = "Can't add selection to menu";
2177 goto return_entry;
2178 }
2179 i += MENU_ITEMS_ITEM_LENGTH;
2180 lines++;
2181 }
2182 }
2183
2184 maxlines = max (maxlines, lines);
2185
2186 /* All set and ready to fly. */
2187 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2188 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2189 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2190 x = min (x, dispwidth);
2191 y = min (y, dispheight);
2192 x = max (x, 1);
2193 y = max (y, 1);
2194 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2195 &ulx, &uly, &width, &height);
2196 if (ulx+width > dispwidth)
2197 {
2198 x -= (ulx + width) - dispwidth;
2199 ulx = dispwidth - width;
2200 }
2201 if (uly+height > dispheight)
2202 {
2203 y -= (uly + height) - dispheight;
2204 uly = dispheight - height;
2205 }
2206 #ifndef HAVE_X_WINDOWS
2207 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2208 {
2209 /* Move the menu away of the echo area, to avoid overwriting the
2210 menu with help echo messages or vice versa. */
2211 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2212 {
2213 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2214 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2215 }
2216 else
2217 {
2218 y--;
2219 uly--;
2220 }
2221 }
2222 #endif
2223 if (ulx < 0) x -= ulx;
2224 if (uly < 0) y -= uly;
2225
2226 if (!(menuflags & MENU_FOR_CLICK))
2227 {
2228 /* If position was not given by a mouse click, adjust so upper left
2229 corner of the menu as a whole ends up at given coordinates. This
2230 is what x-popup-menu says in its documentation. */
2231 x += width/2;
2232 y += 1.5*height/(maxlines+2);
2233 }
2234
2235 XMenuSetAEQ (menu, true);
2236 XMenuSetFreeze (menu, true);
2237 pane = selidx = 0;
2238
2239 #ifndef MSDOS
2240 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2241 #endif
2242
2243 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2244
2245 /* Help display under X won't work because XMenuActivate contains
2246 a loop that doesn't give Emacs a chance to process it. */
2247 menu_help_frame = f;
2248 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2249 x, y, ButtonReleaseMask, &datap,
2250 menu_help_callback);
2251 pane_prefix = Qnil;
2252
2253 switch (status)
2254 {
2255 case XM_SUCCESS:
2256 #ifdef XDEBUG
2257 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2258 #endif
2259
2260 /* Find the item number SELIDX in pane number PANE. */
2261 i = 0;
2262 while (i < menu_items_used)
2263 {
2264 if (EQ (AREF (menu_items, i), Qt))
2265 {
2266 if (pane == 0)
2267 pane_prefix
2268 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2269 pane--;
2270 i += MENU_ITEMS_PANE_LENGTH;
2271 }
2272 else
2273 {
2274 if (pane == -1)
2275 {
2276 if (selidx == 0)
2277 {
2278 entry
2279 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2280 if (menuflags & MENU_KEYMAPS)
2281 {
2282 entry = list1 (entry);
2283 if (!NILP (pane_prefix))
2284 entry = Fcons (pane_prefix, entry);
2285 }
2286 break;
2287 }
2288 selidx--;
2289 }
2290 i += MENU_ITEMS_ITEM_LENGTH;
2291 }
2292 }
2293 break;
2294
2295 case XM_FAILURE:
2296 *error_name = "Can't activate menu";
2297 case XM_IA_SELECT:
2298 break;
2299 case XM_NO_SELECT:
2300 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2301 the menu was invoked with a mouse event as POSITION). */
2302 if (!(menuflags & MENU_FOR_CLICK))
2303 {
2304 unblock_input ();
2305 Fsignal (Qquit, Qnil);
2306 }
2307 break;
2308 }
2309
2310 return_entry:
2311 unblock_input ();
2312 SAFE_FREE ();
2313 return unbind_to (specpdl_count, entry);
2314 }
2315
2316 #endif /* not USE_X_TOOLKIT */
2317
2318 #ifndef MSDOS
2319 /* Detect if a dialog or menu has been posted. MSDOS has its own
2320 implementation on msdos.c. */
2321
2322 int
2323 popup_activated (void)
2324 {
2325 return popup_activated_flag;
2326 }
2327 #endif /* not MSDOS */
2328
2329 /* The following is used by delayed window autoselection. */
2330
2331 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2332 doc: /* Return t if a menu or popup dialog is active. */)
2333 (void)
2334 {
2335 return (popup_activated ()) ? Qt : Qnil;
2336 }
2337 \f
2338 void
2339 syms_of_xmenu (void)
2340 {
2341 #ifdef USE_X_TOOLKIT
2342 enum { WIDGET_ID_TICK_START = 1 << 16 };
2343 widget_id_tick = WIDGET_ID_TICK_START;
2344 next_menubar_widget_id = 1;
2345 #endif
2346
2347 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2348 defsubr (&Smenu_or_popup_active_p);
2349
2350 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2351 defsubr (&Sx_menu_bar_open_internal);
2352 Ffset (intern_c_string ("accelerate-menu"),
2353 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2354 #endif
2355 }