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