]> code.delx.au - gnu-emacs/blob - src/xmenu.c
Allow setting frame pixel sizes from frame parameters (Bug#21415)
[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_after_check ();
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 adjust_frame_size (f, -1, -1, 2, false, Qupdate_frame_menubar);
640 unblock_input ();
641 #endif /* USE_GTK */
642 }
643
644 #ifdef USE_LUCID
645 static void
646 apply_systemfont_to_dialog (Widget w)
647 {
648 const char *fn = xsettings_get_system_normal_font ();
649 if (fn)
650 {
651 XrmDatabase db = XtDatabase (XtDisplay (w));
652 if (db)
653 XrmPutStringResource (&db, "*dialog.font", fn);
654 }
655 }
656
657 static void
658 apply_systemfont_to_menu (struct frame *f, Widget w)
659 {
660 const char *fn = xsettings_get_system_normal_font ();
661
662 if (fn)
663 {
664 XrmDatabase db = XtDatabase (XtDisplay (w));
665 if (db)
666 {
667 XrmPutStringResource (&db, "*menubar*font", fn);
668 XrmPutStringResource (&db, "*popup*font", fn);
669 }
670 }
671 }
672
673 #endif
674
675 /* Set the contents of the menubar widgets of frame F.
676 The argument FIRST_TIME is currently ignored;
677 it is set the first time this is called, from initialize_frame_menubar. */
678
679 void
680 set_frame_menubar (struct frame *f, bool first_time, bool deep_p)
681 {
682 xt_or_gtk_widget menubar_widget, old_widget;
683 #ifdef USE_X_TOOLKIT
684 LWLIB_ID id;
685 #endif
686 Lisp_Object items;
687 widget_value *wv, *first_wv, *prev_wv = 0;
688 int i;
689 int *submenu_start, *submenu_end;
690 bool *submenu_top_level_items;
691 int *submenu_n_panes;
692
693 eassert (FRAME_X_P (f));
694
695 menubar_widget = old_widget = f->output_data.x->menubar_widget;
696
697 XSETFRAME (Vmenu_updating_frame, f);
698
699 #ifdef USE_X_TOOLKIT
700 if (f->output_data.x->id == 0)
701 f->output_data.x->id = next_menubar_widget_id++;
702 id = f->output_data.x->id;
703 #endif
704
705 if (! menubar_widget)
706 deep_p = true;
707 /* Make the first call for any given frame always go deep. */
708 else if (!f->output_data.x->saved_menu_event && !deep_p)
709 {
710 deep_p = true;
711 f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent));
712 f->output_data.x->saved_menu_event->type = 0;
713 }
714
715 if (deep_p)
716 {
717 /* Make a widget-value tree representing the entire menu trees. */
718
719 struct buffer *prev = current_buffer;
720 Lisp_Object buffer;
721 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
722 int previous_menu_items_used = f->menu_bar_items_used;
723 Lisp_Object *previous_items
724 = alloca (previous_menu_items_used * sizeof *previous_items);
725 int subitems;
726
727 /* If we are making a new widget, its contents are empty,
728 do always reinitialize them. */
729 if (! menubar_widget)
730 previous_menu_items_used = 0;
731
732 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
733 specbind (Qinhibit_quit, Qt);
734 /* Don't let the debugger step into this code
735 because it is not reentrant. */
736 specbind (Qdebug_on_next_call, Qnil);
737
738 record_unwind_save_match_data ();
739 if (NILP (Voverriding_local_map_menu_flag))
740 {
741 specbind (Qoverriding_terminal_local_map, Qnil);
742 specbind (Qoverriding_local_map, Qnil);
743 }
744
745 set_buffer_internal_1 (XBUFFER (buffer));
746
747 /* Run the Lucid hook. */
748 safe_run_hooks (Qactivate_menubar_hook);
749
750 /* If it has changed current-menubar from previous value,
751 really recompute the menubar from the value. */
752 if (! NILP (Vlucid_menu_bar_dirty_flag))
753 call0 (Qrecompute_lucid_menubar);
754 safe_run_hooks (Qmenu_bar_update_hook);
755 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
756
757 items = FRAME_MENU_BAR_ITEMS (f);
758
759 /* Save the frame's previous menu bar contents data. */
760 if (previous_menu_items_used)
761 memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
762 previous_menu_items_used * word_size);
763
764 /* Fill in menu_items with the current menu bar contents.
765 This can evaluate Lisp code. */
766 save_menu_items ();
767
768 menu_items = f->menu_bar_vector;
769 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
770 subitems = ASIZE (items) / 4;
771 submenu_start = alloca ((subitems + 1) * sizeof *submenu_start);
772 submenu_end = alloca (subitems * sizeof *submenu_end);
773 submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes);
774 submenu_top_level_items = alloca (subitems
775 * sizeof *submenu_top_level_items);
776 init_menu_items ();
777 for (i = 0; i < subitems; i++)
778 {
779 Lisp_Object key, string, maps;
780
781 key = AREF (items, 4 * i);
782 string = AREF (items, 4 * i + 1);
783 maps = AREF (items, 4 * i + 2);
784 if (NILP (string))
785 break;
786
787 submenu_start[i] = menu_items_used;
788
789 menu_items_n_panes = 0;
790 submenu_top_level_items[i]
791 = parse_single_submenu (key, string, maps);
792 submenu_n_panes[i] = menu_items_n_panes;
793
794 submenu_end[i] = menu_items_used;
795 }
796
797 submenu_start[i] = -1;
798 finish_menu_items ();
799
800 /* Convert menu_items into widget_value trees
801 to display the menu. This cannot evaluate Lisp code. */
802
803 wv = make_widget_value ("menubar", NULL, true, Qnil);
804 wv->button_type = BUTTON_TYPE_NONE;
805 first_wv = wv;
806
807 for (i = 0; submenu_start[i] >= 0; i++)
808 {
809 menu_items_n_panes = submenu_n_panes[i];
810 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
811 submenu_top_level_items[i]);
812 if (prev_wv)
813 prev_wv->next = wv;
814 else
815 first_wv->contents = wv;
816 /* Don't set wv->name here; GC during the loop might relocate it. */
817 wv->enabled = true;
818 wv->button_type = BUTTON_TYPE_NONE;
819 prev_wv = wv;
820 }
821
822 set_buffer_internal_1 (prev);
823
824 /* If there has been no change in the Lisp-level contents
825 of the menu bar, skip redisplaying it. Just exit. */
826
827 /* Compare the new menu items with the ones computed last time. */
828 for (i = 0; i < previous_menu_items_used; i++)
829 if (menu_items_used == i
830 || (!EQ (previous_items[i], AREF (menu_items, i))))
831 break;
832 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
833 {
834 /* The menu items have not changed. Don't bother updating
835 the menus in any form, since it would be a no-op. */
836 free_menubar_widget_value_tree (first_wv);
837 discard_menu_items ();
838 unbind_to (specpdl_count, Qnil);
839 return;
840 }
841
842 /* The menu items are different, so store them in the frame. */
843 fset_menu_bar_vector (f, menu_items);
844 f->menu_bar_items_used = menu_items_used;
845
846 /* This undoes save_menu_items. */
847 unbind_to (specpdl_count, Qnil);
848
849 /* Now GC cannot happen during the lifetime of the widget_value,
850 so it's safe to store data from a Lisp_String. */
851 wv = first_wv->contents;
852 for (i = 0; i < ASIZE (items); i += 4)
853 {
854 Lisp_Object string;
855 string = AREF (items, i + 1);
856 if (NILP (string))
857 break;
858 wv->name = SSDATA (string);
859 update_submenu_strings (wv->contents);
860 wv = wv->next;
861 }
862
863 }
864 else
865 {
866 /* Make a widget-value tree containing
867 just the top level menu bar strings. */
868
869 wv = make_widget_value ("menubar", NULL, true, Qnil);
870 wv->button_type = BUTTON_TYPE_NONE;
871 first_wv = wv;
872
873 items = FRAME_MENU_BAR_ITEMS (f);
874 for (i = 0; i < ASIZE (items); i += 4)
875 {
876 Lisp_Object string;
877
878 string = AREF (items, i + 1);
879 if (NILP (string))
880 break;
881
882 wv = make_widget_value (SSDATA (string), NULL, true, Qnil);
883 wv->button_type = BUTTON_TYPE_NONE;
884 /* This prevents lwlib from assuming this
885 menu item is really supposed to be empty. */
886 /* The intptr_t cast avoids a warning.
887 This value just has to be different from small integers. */
888 wv->call_data = (void *) (intptr_t) (-1);
889
890 if (prev_wv)
891 prev_wv->next = wv;
892 else
893 first_wv->contents = wv;
894 prev_wv = wv;
895 }
896
897 /* Forget what we thought we knew about what is in the
898 detailed contents of the menu bar menus.
899 Changing the top level always destroys the contents. */
900 f->menu_bar_items_used = 0;
901 }
902
903 /* Create or update the menu bar widget. */
904
905 block_input ();
906
907 #ifdef USE_GTK
908 xg_crazy_callback_abort = true;
909 if (menubar_widget)
910 {
911 /* The fourth arg is DEEP_P, which says to consider the entire
912 menu trees we supply, rather than just the menu bar item names. */
913 xg_modify_menubar_widgets (menubar_widget,
914 f,
915 first_wv,
916 deep_p,
917 G_CALLBACK (menubar_selection_callback),
918 G_CALLBACK (popup_deactivate_callback),
919 G_CALLBACK (menu_highlight_callback));
920 }
921 else
922 {
923 menubar_widget
924 = xg_create_widget ("menubar", "menubar", f, first_wv,
925 G_CALLBACK (menubar_selection_callback),
926 G_CALLBACK (popup_deactivate_callback),
927 G_CALLBACK (menu_highlight_callback));
928
929 f->output_data.x->menubar_widget = menubar_widget;
930 }
931
932
933 #else /* not USE_GTK */
934 if (menubar_widget)
935 {
936 /* Disable resizing (done for Motif!) */
937 lw_allow_resizing (f->output_data.x->widget, False);
938
939 /* The third arg is DEEP_P, which says to consider the entire
940 menu trees we supply, rather than just the menu bar item names. */
941 lw_modify_all_widgets (id, first_wv, deep_p);
942
943 /* Re-enable the edit widget to resize. */
944 lw_allow_resizing (f->output_data.x->widget, True);
945 }
946 else
947 {
948 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()";
949 XtTranslations override = XtParseTranslationTable (menuOverride);
950
951 #ifdef USE_LUCID
952 apply_systemfont_to_menu (f, f->output_data.x->column_widget);
953 #endif
954 menubar_widget = lw_create_widget ("menubar", "menubar", id,
955 first_wv,
956 f->output_data.x->column_widget,
957 false,
958 popup_activate_callback,
959 menubar_selection_callback,
960 popup_deactivate_callback,
961 menu_highlight_callback);
962 f->output_data.x->menubar_widget = menubar_widget;
963
964 /* Make menu pop down on C-g. */
965 XtOverrideTranslations (menubar_widget, override);
966 }
967
968 {
969 int menubar_size;
970 if (f->output_data.x->menubar_widget)
971 XtRealizeWidget (f->output_data.x->menubar_widget);
972
973 menubar_size
974 = (f->output_data.x->menubar_widget
975 ? (f->output_data.x->menubar_widget->core.height
976 #ifndef USE_LUCID
977 /* Damn me... With Lucid I get a core.border_width of 1
978 only the first time this is called and an ibw of 1 every
979 time this is called. So the first time this is called I
980 was off by one. Fix that here by never adding
981 core.border_width for Lucid. */
982 + f->output_data.x->menubar_widget->core.border_width
983 #endif /* USE_LUCID */
984 )
985 : 0);
986
987 #ifdef USE_LUCID
988 /* Experimentally, we now get the right results
989 for -geometry -0-0 without this. 24 Aug 96, rms.
990 Maybe so, but the menu bar size is missing the pixels so the
991 WM size hints are off by these pixels. Jan D, oct 2009. */
992 if (FRAME_EXTERNAL_MENU_BAR (f))
993 {
994 Dimension ibw = 0;
995
996 XtVaGetValues (f->output_data.x->column_widget,
997 XtNinternalBorderWidth, &ibw, NULL);
998 menubar_size += ibw;
999 }
1000 #endif /* USE_LUCID */
1001
1002 FRAME_MENUBAR_HEIGHT (f) = menubar_size;
1003 }
1004 #endif /* not USE_GTK */
1005
1006 free_menubar_widget_value_tree (first_wv);
1007 update_frame_menubar (f);
1008
1009 #ifdef USE_GTK
1010 xg_crazy_callback_abort = false;
1011 #endif
1012
1013 unblock_input ();
1014 }
1015
1016 /* Called from Fx_create_frame to create the initial menubar of a frame
1017 before it is mapped, so that the window is mapped with the menubar already
1018 there instead of us tacking it on later and thrashing the window after it
1019 is visible. */
1020
1021 void
1022 initialize_frame_menubar (struct frame *f)
1023 {
1024 /* This function is called before the first chance to redisplay
1025 the frame. It has to be, so the frame will have the right size. */
1026 fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
1027 set_frame_menubar (f, true, true);
1028 }
1029
1030
1031 /* Get rid of the menu bar of frame F, and free its storage.
1032 This is used when deleting a frame, and when turning off the menu bar.
1033 For GTK this function is in gtkutil.c. */
1034
1035 #ifndef USE_GTK
1036 void
1037 free_frame_menubar (struct frame *f)
1038 {
1039 Widget menubar_widget;
1040 #ifdef USE_MOTIF
1041 /* Motif automatically shrinks the frame in lw_destroy_all_widgets.
1042 If we want to preserve the old height, calculate it now so we can
1043 restore it below. */
1044 int old_height = FRAME_TEXT_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
1045 #endif
1046
1047 eassert (FRAME_X_P (f));
1048
1049 menubar_widget = f->output_data.x->menubar_widget;
1050
1051 FRAME_MENUBAR_HEIGHT (f) = 0;
1052
1053 if (menubar_widget)
1054 {
1055 #ifdef USE_MOTIF
1056 /* Removing the menu bar magically changes the shell widget's x
1057 and y position of (0, 0) which, when the menu bar is turned
1058 on again, leads to pull-down menus appearing in strange
1059 positions near the upper-left corner of the display. This
1060 happens only with some window managers like twm and ctwm,
1061 but not with other like Motif's mwm or kwm, because the
1062 latter generate ConfigureNotify events when the menu bar
1063 is switched off, which fixes the shell position. */
1064 Position x0, y0, x1, y1;
1065 #endif
1066
1067 block_input ();
1068
1069 #ifdef USE_MOTIF
1070 if (f->output_data.x->widget)
1071 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
1072 #endif
1073
1074 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
1075 f->output_data.x->menubar_widget = NULL;
1076
1077 if (f->output_data.x->widget)
1078 {
1079 #ifdef USE_MOTIF
1080 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1081 if (x1 == 0 && y1 == 0)
1082 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1083 if (frame_inhibit_resize (f, false, Qmenu_bar_lines))
1084 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_1);
1085 else
1086 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1087 #else
1088 adjust_frame_size (f, -1, -1, 2, false, Qfree_frame_menubar_1);
1089 #endif /* USE_MOTIF */
1090 }
1091 else
1092 {
1093 #ifdef USE_MOTIF
1094 if (WINDOWP (FRAME_ROOT_WINDOW (f))
1095 && frame_inhibit_resize (f, false, Qmenu_bar_lines))
1096 adjust_frame_size (f, -1, old_height, 1, false, Qfree_frame_menubar_2);
1097 #endif
1098 }
1099
1100 unblock_input ();
1101 }
1102 }
1103 #endif /* not USE_GTK */
1104
1105 #endif /* USE_X_TOOLKIT || USE_GTK */
1106 \f
1107 /* x_menu_show actually displays a menu using the panes and items in menu_items
1108 and returns the value selected from it.
1109 There are two versions of x_menu_show, one for Xt and one for Xlib.
1110 Both assume input is blocked by the caller. */
1111
1112 /* F is the frame the menu is for.
1113 X and Y are the frame-relative specified position,
1114 relative to the inside upper left corner of the frame F.
1115 Bitfield MENUFLAGS bits are:
1116 MENU_FOR_CLICK is set if this menu was invoked for a mouse click.
1117 MENU_KEYMAPS is set if this menu was specified with keymaps;
1118 in that case, we return a list containing the chosen item's value
1119 and perhaps also the pane's prefix.
1120 TITLE is the specified menu title.
1121 ERROR is a place to store an error message string in case of failure.
1122 (We return nil on failure, but the value doesn't actually matter.) */
1123
1124 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1125
1126 /* The item selected in the popup menu. */
1127 static Lisp_Object *volatile menu_item_selection;
1128
1129 #ifdef USE_GTK
1130
1131 /* Used when position a popup menu. See menu_position_func and
1132 create_and_show_popup_menu below. */
1133 struct next_popup_x_y
1134 {
1135 struct frame *f;
1136 int x;
1137 int y;
1138 };
1139
1140 /* The menu position function to use if we are not putting a popup
1141 menu where the pointer is.
1142 MENU is the menu to pop up.
1143 X and Y shall on exit contain x/y where the menu shall pop up.
1144 PUSH_IN is not documented in the GTK manual.
1145 USER_DATA is any data passed in when calling gtk_menu_popup.
1146 Here it points to a struct next_popup_x_y where the coordinates
1147 to store in *X and *Y are as well as the frame for the popup.
1148
1149 Here only X and Y are used. */
1150 static void
1151 menu_position_func (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
1152 {
1153 struct next_popup_x_y *data = user_data;
1154 GtkRequisition req;
1155 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (data->f);
1156 int disp_width = x_display_pixel_width (dpyinfo);
1157 int disp_height = x_display_pixel_height (dpyinfo);
1158
1159 *x = data->x;
1160 *y = data->y;
1161
1162 /* Check if there is room for the menu. If not, adjust x/y so that
1163 the menu is fully visible. */
1164 gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &req);
1165 if (data->x + req.width > disp_width)
1166 *x -= data->x + req.width - disp_width;
1167 if (data->y + req.height > disp_height)
1168 *y -= data->y + req.height - disp_height;
1169 }
1170
1171 static void
1172 popup_selection_callback (GtkWidget *widget, gpointer client_data)
1173 {
1174 xg_menu_item_cb_data *cb_data = client_data;
1175
1176 if (xg_crazy_callback_abort) return;
1177 if (cb_data) menu_item_selection = cb_data->call_data;
1178 }
1179
1180 static void
1181 pop_down_menu (void *arg)
1182 {
1183 popup_activated_flag = 0;
1184 block_input ();
1185 gtk_widget_destroy (GTK_WIDGET (arg));
1186 unblock_input ();
1187 }
1188
1189 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1190 menu pops down.
1191 menu_item_selection will be set to the selection. */
1192 static void
1193 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1194 int x, int y, bool for_click)
1195 {
1196 int i;
1197 GtkWidget *menu;
1198 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1199 struct next_popup_x_y popup_x_y;
1200 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1201 bool use_pos_func = ! for_click;
1202
1203 #ifdef HAVE_GTK3
1204 /* Always use position function for Gtk3. Otherwise menus may become
1205 too small to show anything. */
1206 use_pos_func = true;
1207 #endif
1208
1209 eassert (FRAME_X_P (f));
1210
1211 xg_crazy_callback_abort = true;
1212 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1213 G_CALLBACK (popup_selection_callback),
1214 G_CALLBACK (popup_deactivate_callback),
1215 G_CALLBACK (menu_highlight_callback));
1216 xg_crazy_callback_abort = false;
1217
1218 if (use_pos_func)
1219 {
1220 Window dummy_window;
1221
1222 /* Not invoked by a click. pop up at x/y. */
1223 pos_func = menu_position_func;
1224
1225 /* Adjust coordinates to be root-window-relative. */
1226 block_input ();
1227 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1228
1229 /* From-window, to-window. */
1230 FRAME_X_WINDOW (f),
1231 FRAME_DISPLAY_INFO (f)->root_window,
1232
1233 /* From-position, to-position. */
1234 x, y, &x, &y,
1235
1236 /* Child of win. */
1237 &dummy_window);
1238 unblock_input ();
1239 popup_x_y.x = x;
1240 popup_x_y.y = y;
1241 popup_x_y.f = f;
1242
1243 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1244 }
1245
1246 if (for_click)
1247 {
1248 for (i = 0; i < 5; i++)
1249 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1250 break;
1251 /* If keys aren't grabbed (i.e., a mouse up event), use 0. */
1252 if (i == 5) i = 0;
1253 }
1254
1255 /* Display the menu. */
1256 gtk_widget_show_all (menu);
1257
1258 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i,
1259 FRAME_DISPLAY_INFO (f)->last_user_time);
1260
1261 record_unwind_protect_ptr (pop_down_menu, menu);
1262
1263 if (gtk_widget_get_mapped (menu))
1264 {
1265 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1266 two. show_help_echo uses this to detect popup menus. */
1267 popup_activated_flag = 1;
1268 /* Process events that apply to the menu. */
1269 popup_widget_loop (true, menu);
1270 }
1271
1272 unbind_to (specpdl_count, Qnil);
1273
1274 /* Must reset this manually because the button release event is not passed
1275 to Emacs event loop. */
1276 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1277 }
1278
1279 #else /* not USE_GTK */
1280
1281 /* We need a unique id for each widget handled by the Lucid Widget
1282 library.
1283
1284 For the main windows, and popup menus, we use this counter, which we
1285 increment each time after use. This starts from WIDGET_ID_TICK_START.
1286
1287 For menu bars, we use numbers starting at 0, counted in
1288 next_menubar_widget_id. */
1289 LWLIB_ID widget_id_tick;
1290
1291 static void
1292 popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1293 {
1294 menu_item_selection = client_data;
1295 }
1296
1297 /* ID is the LWLIB ID of the dialog box. */
1298
1299 static void
1300 pop_down_menu (int id)
1301 {
1302 block_input ();
1303 lw_destroy_all_widgets ((LWLIB_ID) id);
1304 unblock_input ();
1305 popup_activated_flag = 0;
1306 }
1307
1308 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1309 menu pops down.
1310 menu_item_selection will be set to the selection. */
1311 static void
1312 create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1313 int x, int y, bool for_click)
1314 {
1315 int i;
1316 Arg av[2];
1317 int ac = 0;
1318 XEvent dummy;
1319 XButtonPressedEvent *event = &(dummy.xbutton);
1320 LWLIB_ID menu_id;
1321 Widget menu;
1322 Window dummy_window;
1323
1324 eassert (FRAME_X_P (f));
1325
1326 #ifdef USE_LUCID
1327 apply_systemfont_to_menu (f, f->output_data.x->widget);
1328 #endif
1329
1330 menu_id = widget_id_tick++;
1331 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1332 f->output_data.x->widget, true, 0,
1333 popup_selection_callback,
1334 popup_deactivate_callback,
1335 menu_highlight_callback);
1336
1337 event->type = ButtonPress;
1338 event->serial = 0;
1339 event->send_event = false;
1340 event->display = FRAME_X_DISPLAY (f);
1341 event->time = CurrentTime;
1342 event->root = FRAME_DISPLAY_INFO (f)->root_window;
1343 event->window = event->subwindow = event->root;
1344 event->x = x;
1345 event->y = y;
1346
1347 /* Adjust coordinates to be root-window-relative. */
1348 block_input ();
1349 x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
1350 XTranslateCoordinates (FRAME_X_DISPLAY (f),
1351
1352 /* From-window, to-window. */
1353 FRAME_X_WINDOW (f),
1354 FRAME_DISPLAY_INFO (f)->root_window,
1355
1356 /* From-position, to-position. */
1357 x, y, &x, &y,
1358
1359 /* Child of win. */
1360 &dummy_window);
1361 unblock_input ();
1362
1363 event->x_root = x;
1364 event->y_root = y;
1365
1366 event->state = 0;
1367 event->button = 0;
1368 for (i = 0; i < 5; i++)
1369 if (FRAME_DISPLAY_INFO (f)->grabbed & (1 << i))
1370 event->button = i;
1371
1372 /* Don't allow any geometry request from the user. */
1373 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1374 XtSetValues (menu, av, ac);
1375
1376 /* Display the menu. */
1377 lw_popup_menu (menu, &dummy);
1378 popup_activated_flag = 1;
1379 x_activate_timeout_atimer ();
1380
1381 {
1382 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1383
1384 record_unwind_protect_int (pop_down_menu, (int) menu_id);
1385
1386 /* Process events that apply to the menu. */
1387 popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
1388
1389 unbind_to (specpdl_count, Qnil);
1390 }
1391 }
1392
1393 #endif /* not USE_GTK */
1394
1395 static void
1396 cleanup_widget_value_tree (void *arg)
1397 {
1398 free_menubar_widget_value_tree (arg);
1399 }
1400
1401 Lisp_Object
1402 x_menu_show (struct frame *f, int x, int y, int menuflags,
1403 Lisp_Object title, const char **error_name)
1404 {
1405 int i;
1406 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1407 widget_value **submenu_stack
1408 = alloca (menu_items_used * sizeof *submenu_stack);
1409 Lisp_Object *subprefix_stack
1410 = alloca (menu_items_used * sizeof *subprefix_stack);
1411 int submenu_depth = 0;
1412
1413 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1414
1415 eassert (FRAME_X_P (f));
1416
1417 *error_name = NULL;
1418
1419 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1420 {
1421 *error_name = "Empty menu";
1422 return Qnil;
1423 }
1424
1425 block_input ();
1426
1427 /* Create a tree of widget_value objects
1428 representing the panes and their items. */
1429 wv = make_widget_value ("menu", NULL, true, Qnil);
1430 wv->button_type = BUTTON_TYPE_NONE;
1431 first_wv = wv;
1432 bool first_pane = true;
1433
1434 /* Loop over all panes and items, filling in the tree. */
1435 i = 0;
1436 while (i < menu_items_used)
1437 {
1438 if (EQ (AREF (menu_items, i), Qnil))
1439 {
1440 submenu_stack[submenu_depth++] = save_wv;
1441 save_wv = prev_wv;
1442 prev_wv = 0;
1443 first_pane = true;
1444 i++;
1445 }
1446 else if (EQ (AREF (menu_items, i), Qlambda))
1447 {
1448 prev_wv = save_wv;
1449 save_wv = submenu_stack[--submenu_depth];
1450 first_pane = false;
1451 i++;
1452 }
1453 else if (EQ (AREF (menu_items, i), Qt)
1454 && submenu_depth != 0)
1455 i += MENU_ITEMS_PANE_LENGTH;
1456 /* Ignore a nil in the item list.
1457 It's meaningful only for dialog boxes. */
1458 else if (EQ (AREF (menu_items, i), Qquote))
1459 i += 1;
1460 else if (EQ (AREF (menu_items, i), Qt))
1461 {
1462 /* Create a new pane. */
1463 Lisp_Object pane_name, prefix;
1464 const char *pane_string;
1465
1466 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1467 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1468
1469 #ifndef HAVE_MULTILINGUAL_MENU
1470 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1471 {
1472 pane_name = ENCODE_MENU_STRING (pane_name);
1473 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1474 }
1475 #endif
1476 pane_string = (NILP (pane_name)
1477 ? "" : SSDATA (pane_name));
1478 /* If there is just one top-level pane, put all its items directly
1479 under the top-level menu. */
1480 if (menu_items_n_panes == 1)
1481 pane_string = "";
1482
1483 /* If the pane has a meaningful name,
1484 make the pane a top-level menu item
1485 with its items as a submenu beneath it. */
1486 if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, ""))
1487 {
1488 wv = make_widget_value (pane_string, NULL, true, Qnil);
1489 if (save_wv)
1490 save_wv->next = wv;
1491 else
1492 first_wv->contents = wv;
1493 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
1494 wv->name++;
1495 wv->button_type = BUTTON_TYPE_NONE;
1496 save_wv = wv;
1497 prev_wv = 0;
1498 }
1499 else if (first_pane)
1500 {
1501 save_wv = wv;
1502 prev_wv = 0;
1503 }
1504 first_pane = false;
1505 i += MENU_ITEMS_PANE_LENGTH;
1506 }
1507 else
1508 {
1509 /* Create a new item within current pane. */
1510 Lisp_Object item_name, enable, descrip, def, type, selected, help;
1511 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1512 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1513 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1514 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1515 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1516 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1517 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1518
1519 #ifndef HAVE_MULTILINGUAL_MENU
1520 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1521 {
1522 item_name = ENCODE_MENU_STRING (item_name);
1523 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
1524 }
1525
1526 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
1527 {
1528 descrip = ENCODE_MENU_STRING (descrip);
1529 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
1530 }
1531 #endif /* not HAVE_MULTILINGUAL_MENU */
1532
1533 wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable),
1534 STRINGP (help) ? help : Qnil);
1535 if (prev_wv)
1536 prev_wv->next = wv;
1537 else
1538 save_wv->contents = wv;
1539 if (!NILP (descrip))
1540 wv->key = SSDATA (descrip);
1541 /* If this item has a null value,
1542 make the call_data null so that it won't display a box
1543 when the mouse is on it. */
1544 wv->call_data = !NILP (def) ? aref_addr (menu_items, i) : 0;
1545
1546 if (NILP (type))
1547 wv->button_type = BUTTON_TYPE_NONE;
1548 else if (EQ (type, QCtoggle))
1549 wv->button_type = BUTTON_TYPE_TOGGLE;
1550 else if (EQ (type, QCradio))
1551 wv->button_type = BUTTON_TYPE_RADIO;
1552 else
1553 emacs_abort ();
1554
1555 wv->selected = !NILP (selected);
1556
1557 prev_wv = wv;
1558
1559 i += MENU_ITEMS_ITEM_LENGTH;
1560 }
1561 }
1562
1563 /* Deal with the title, if it is non-nil. */
1564 if (!NILP (title))
1565 {
1566 widget_value *wv_title;
1567 widget_value *wv_sep1 = make_widget_value ("--", NULL, false, Qnil);
1568 widget_value *wv_sep2 = make_widget_value ("--", NULL, false, Qnil);
1569
1570 wv_sep2->next = first_wv->contents;
1571 wv_sep1->next = wv_sep2;
1572
1573 #ifndef HAVE_MULTILINGUAL_MENU
1574 if (STRING_MULTIBYTE (title))
1575 title = ENCODE_MENU_STRING (title);
1576 #endif
1577
1578 wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil);
1579 wv_title->button_type = BUTTON_TYPE_NONE;
1580 wv_title->next = wv_sep1;
1581 first_wv->contents = wv_title;
1582 }
1583
1584 /* No selection has been chosen yet. */
1585 menu_item_selection = 0;
1586
1587 /* Make sure to free the widget_value objects we used to specify the
1588 contents even with longjmp. */
1589 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1590
1591 /* Actually create and show the menu until popped down. */
1592 create_and_show_popup_menu (f, first_wv, x, y,
1593 menuflags & MENU_FOR_CLICK);
1594
1595 unbind_to (specpdl_count, Qnil);
1596
1597 /* Find the selected item, and its pane, to return
1598 the proper value. */
1599 if (menu_item_selection != 0)
1600 {
1601 Lisp_Object prefix, entry;
1602
1603 prefix = entry = Qnil;
1604 i = 0;
1605 while (i < menu_items_used)
1606 {
1607 if (EQ (AREF (menu_items, i), Qnil))
1608 {
1609 subprefix_stack[submenu_depth++] = prefix;
1610 prefix = entry;
1611 i++;
1612 }
1613 else if (EQ (AREF (menu_items, i), Qlambda))
1614 {
1615 prefix = subprefix_stack[--submenu_depth];
1616 i++;
1617 }
1618 else if (EQ (AREF (menu_items, i), Qt))
1619 {
1620 prefix
1621 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
1622 i += MENU_ITEMS_PANE_LENGTH;
1623 }
1624 /* Ignore a nil in the item list.
1625 It's meaningful only for dialog boxes. */
1626 else if (EQ (AREF (menu_items, i), Qquote))
1627 i += 1;
1628 else
1629 {
1630 entry
1631 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1632 if (menu_item_selection == aref_addr (menu_items, i))
1633 {
1634 if (menuflags & MENU_KEYMAPS)
1635 {
1636 int j;
1637
1638 entry = list1 (entry);
1639 if (!NILP (prefix))
1640 entry = Fcons (prefix, entry);
1641 for (j = submenu_depth - 1; j >= 0; j--)
1642 if (!NILP (subprefix_stack[j]))
1643 entry = Fcons (subprefix_stack[j], entry);
1644 }
1645 unblock_input ();
1646 return entry;
1647 }
1648 i += MENU_ITEMS_ITEM_LENGTH;
1649 }
1650 }
1651 }
1652 else if (!(menuflags & MENU_FOR_CLICK))
1653 {
1654 unblock_input ();
1655 /* Make "Cancel" equivalent to C-g. */
1656 Fsignal (Qquit, Qnil);
1657 }
1658
1659 unblock_input ();
1660 return Qnil;
1661 }
1662 \f
1663 #ifdef USE_GTK
1664 static void
1665 dialog_selection_callback (GtkWidget *widget, gpointer client_data)
1666 {
1667 /* Treat the pointer as an integer. There's no problem
1668 as long as pointers have enough bits to hold small integers. */
1669 if ((intptr_t) client_data != -1)
1670 menu_item_selection = client_data;
1671
1672 popup_activated_flag = 0;
1673 }
1674
1675 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1676 dialog pops down.
1677 menu_item_selection will be set to the selection. */
1678 static void
1679 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1680 {
1681 GtkWidget *menu;
1682
1683 eassert (FRAME_X_P (f));
1684
1685 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
1686 G_CALLBACK (dialog_selection_callback),
1687 G_CALLBACK (popup_deactivate_callback),
1688 0);
1689
1690 if (menu)
1691 {
1692 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1693 record_unwind_protect_ptr (pop_down_menu, menu);
1694
1695 /* Display the menu. */
1696 gtk_widget_show_all (menu);
1697
1698 /* Process events that apply to the menu. */
1699 popup_widget_loop (true, menu);
1700
1701 unbind_to (specpdl_count, Qnil);
1702 }
1703 }
1704
1705 #else /* not USE_GTK */
1706 static void
1707 dialog_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
1708 {
1709 /* Treat the pointer as an integer. There's no problem
1710 as long as pointers have enough bits to hold small integers. */
1711 if ((intptr_t) client_data != -1)
1712 menu_item_selection = client_data;
1713
1714 block_input ();
1715 lw_destroy_all_widgets (id);
1716 unblock_input ();
1717 popup_activated_flag = 0;
1718 }
1719
1720
1721 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
1722 dialog pops down.
1723 menu_item_selection will be set to the selection. */
1724 static void
1725 create_and_show_dialog (struct frame *f, widget_value *first_wv)
1726 {
1727 LWLIB_ID dialog_id;
1728
1729 eassert (FRAME_X_P (f));
1730
1731 dialog_id = widget_id_tick++;
1732 #ifdef USE_LUCID
1733 apply_systemfont_to_dialog (f->output_data.x->widget);
1734 #endif
1735 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1736 f->output_data.x->widget, true, 0,
1737 dialog_selection_callback, 0, 0);
1738 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
1739 /* Display the dialog box. */
1740 lw_pop_up_all_widgets (dialog_id);
1741 popup_activated_flag = 1;
1742 x_activate_timeout_atimer ();
1743
1744 /* Process events that apply to the dialog box.
1745 Also handle timers. */
1746 {
1747 ptrdiff_t count = SPECPDL_INDEX ();
1748
1749 /* xdialog_show_unwind is responsible for popping the dialog box down. */
1750
1751 record_unwind_protect_int (pop_down_menu, (int) dialog_id);
1752
1753 popup_get_selection (0, FRAME_DISPLAY_INFO (f), dialog_id, true);
1754
1755 unbind_to (count, Qnil);
1756 }
1757 }
1758
1759 #endif /* not USE_GTK */
1760
1761 static const char * button_names [] = {
1762 "button1", "button2", "button3", "button4", "button5",
1763 "button6", "button7", "button8", "button9", "button10" };
1764
1765 static Lisp_Object
1766 x_dialog_show (struct frame *f, Lisp_Object title,
1767 Lisp_Object header, const char **error_name)
1768 {
1769 int i, nb_buttons=0;
1770 char dialog_name[6];
1771
1772 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1773
1774 /* Number of elements seen so far, before boundary. */
1775 int left_count = 0;
1776 /* Whether we've seen the boundary between left-hand elts and right-hand. */
1777 bool boundary_seen = false;
1778
1779 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1780
1781 eassert (FRAME_X_P (f));
1782
1783 *error_name = NULL;
1784
1785 if (menu_items_n_panes > 1)
1786 {
1787 *error_name = "Multiple panes in dialog box";
1788 return Qnil;
1789 }
1790
1791 /* Create a tree of widget_value objects
1792 representing the text label and buttons. */
1793 {
1794 Lisp_Object pane_name;
1795 const char *pane_string;
1796 pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME);
1797 pane_string = (NILP (pane_name)
1798 ? "" : SSDATA (pane_name));
1799 prev_wv = make_widget_value ("message", (char *) pane_string, true, Qnil);
1800 first_wv = prev_wv;
1801
1802 /* Loop over all panes and items, filling in the tree. */
1803 i = MENU_ITEMS_PANE_LENGTH;
1804 while (i < menu_items_used)
1805 {
1806
1807 /* Create a new item within current pane. */
1808 Lisp_Object item_name, enable, descrip;
1809 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1810 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1811 descrip
1812 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1813
1814 if (NILP (item_name))
1815 {
1816 free_menubar_widget_value_tree (first_wv);
1817 *error_name = "Submenu in dialog items";
1818 return Qnil;
1819 }
1820 if (EQ (item_name, Qquote))
1821 {
1822 /* This is the boundary between left-side elts
1823 and right-side elts. Stop incrementing right_count. */
1824 boundary_seen = true;
1825 i++;
1826 continue;
1827 }
1828 if (nb_buttons >= 9)
1829 {
1830 free_menubar_widget_value_tree (first_wv);
1831 *error_name = "Too many dialog items";
1832 return Qnil;
1833 }
1834
1835 wv = make_widget_value (button_names[nb_buttons],
1836 SSDATA (item_name),
1837 !NILP (enable), Qnil);
1838 prev_wv->next = wv;
1839 if (!NILP (descrip))
1840 wv->key = SSDATA (descrip);
1841 wv->call_data = aref_addr (menu_items, i);
1842 prev_wv = wv;
1843
1844 if (! boundary_seen)
1845 left_count++;
1846
1847 nb_buttons++;
1848 i += MENU_ITEMS_ITEM_LENGTH;
1849 }
1850
1851 /* If the boundary was not specified,
1852 by default put half on the left and half on the right. */
1853 if (! boundary_seen)
1854 left_count = nb_buttons - nb_buttons / 2;
1855
1856 wv = make_widget_value (dialog_name, NULL, false, Qnil);
1857
1858 /* Frame title: 'Q' = Question, 'I' = Information.
1859 Can also have 'E' = Error if, one day, we want
1860 a popup for errors. */
1861 if (NILP (header))
1862 dialog_name[0] = 'Q';
1863 else
1864 dialog_name[0] = 'I';
1865
1866 /* Dialog boxes use a really stupid name encoding
1867 which specifies how many buttons to use
1868 and how many buttons are on the right. */
1869 dialog_name[1] = '0' + nb_buttons;
1870 dialog_name[2] = 'B';
1871 dialog_name[3] = 'R';
1872 /* Number of buttons to put on the right. */
1873 dialog_name[4] = '0' + nb_buttons - left_count;
1874 dialog_name[5] = 0;
1875 wv->contents = first_wv;
1876 first_wv = wv;
1877 }
1878
1879 /* No selection has been chosen yet. */
1880 menu_item_selection = 0;
1881
1882 /* Make sure to free the widget_value objects we used to specify the
1883 contents even with longjmp. */
1884 record_unwind_protect_ptr (cleanup_widget_value_tree, first_wv);
1885
1886 /* Actually create and show the dialog. */
1887 create_and_show_dialog (f, first_wv);
1888
1889 unbind_to (specpdl_count, Qnil);
1890
1891 /* Find the selected item, and its pane, to return
1892 the proper value. */
1893 if (menu_item_selection != 0)
1894 {
1895 i = 0;
1896 while (i < menu_items_used)
1897 {
1898 Lisp_Object entry;
1899
1900 if (EQ (AREF (menu_items, i), Qt))
1901 i += MENU_ITEMS_PANE_LENGTH;
1902 else if (EQ (AREF (menu_items, i), Qquote))
1903 {
1904 /* This is the boundary between left-side elts and
1905 right-side elts. */
1906 ++i;
1907 }
1908 else
1909 {
1910 entry
1911 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
1912 if (menu_item_selection == aref_addr (menu_items, i))
1913 return entry;
1914 i += MENU_ITEMS_ITEM_LENGTH;
1915 }
1916 }
1917 }
1918 else
1919 /* Make "Cancel" equivalent to C-g. */
1920 Fsignal (Qquit, Qnil);
1921
1922 return Qnil;
1923 }
1924
1925 Lisp_Object
1926 xw_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
1927 {
1928 Lisp_Object title;
1929 const char *error_name;
1930 Lisp_Object selection;
1931 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
1932
1933 check_window_system (f);
1934
1935 /* Decode the dialog items from what was specified. */
1936 title = Fcar (contents);
1937 CHECK_STRING (title);
1938 record_unwind_protect_void (unuse_menu_items);
1939
1940 if (NILP (Fcar (Fcdr (contents))))
1941 /* No buttons specified, add an "Ok" button so users can pop down
1942 the dialog. Also, the lesstif/motif version crashes if there are
1943 no buttons. */
1944 contents = list2 (title, Fcons (build_string ("Ok"), Qt));
1945
1946 list_of_panes (list1 (contents));
1947
1948 /* Display them in a dialog box. */
1949 block_input ();
1950 selection = x_dialog_show (f, title, header, &error_name);
1951 unblock_input ();
1952
1953 unbind_to (specpdl_count, Qnil);
1954 discard_menu_items ();
1955
1956 if (error_name) error ("%s", error_name);
1957 return selection;
1958 }
1959
1960 #else /* not USE_X_TOOLKIT && not USE_GTK */
1961
1962 /* The frame of the last activated non-toolkit menu bar.
1963 Used to generate menu help events. */
1964
1965 static struct frame *menu_help_frame;
1966
1967
1968 /* Show help HELP_STRING, or clear help if HELP_STRING is null.
1969
1970 PANE is the pane number, and ITEM is the menu item number in
1971 the menu (currently not used).
1972
1973 This cannot be done with generating a HELP_EVENT because
1974 XMenuActivate contains a loop that doesn't let Emacs process
1975 keyboard events. */
1976
1977 static void
1978 menu_help_callback (char const *help_string, int pane, int item)
1979 {
1980 Lisp_Object *first_item;
1981 Lisp_Object pane_name;
1982 Lisp_Object menu_object;
1983
1984 first_item = XVECTOR (menu_items)->contents;
1985 if (EQ (first_item[0], Qt))
1986 pane_name = first_item[MENU_ITEMS_PANE_NAME];
1987 else if (EQ (first_item[0], Qquote))
1988 /* This shouldn't happen, see x_menu_show. */
1989 pane_name = empty_unibyte_string;
1990 else
1991 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
1992
1993 /* (menu-item MENU-NAME PANE-NUMBER) */
1994 menu_object = list3 (Qmenu_item, pane_name, make_number (pane));
1995 show_help_echo (help_string ? build_string (help_string) : Qnil,
1996 Qnil, menu_object, make_number (item));
1997 }
1998
1999 static void
2000 pop_down_menu (Lisp_Object arg)
2001 {
2002 struct frame *f = XSAVE_POINTER (arg, 0);
2003 XMenu *menu = XSAVE_POINTER (arg, 1);
2004
2005 block_input ();
2006 #ifndef MSDOS
2007 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2008 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
2009 #endif
2010 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2011
2012 #ifdef HAVE_X_WINDOWS
2013 /* Assume the mouse has moved out of the X window.
2014 If it has actually moved in, we will get an EnterNotify. */
2015 x_mouse_leave (FRAME_DISPLAY_INFO (f));
2016
2017 /* State that no mouse buttons are now held.
2018 (The oldXMenu code doesn't track this info for us.)
2019 That is not necessarily true, but the fiction leads to reasonable
2020 results, and it is a pain to ask which are actually held now. */
2021 FRAME_DISPLAY_INFO (f)->grabbed = 0;
2022
2023 #endif /* HAVE_X_WINDOWS */
2024
2025 unblock_input ();
2026 }
2027
2028
2029 Lisp_Object
2030 x_menu_show (struct frame *f, int x, int y, int menuflags,
2031 Lisp_Object title, const char **error_name)
2032 {
2033 Window root;
2034 XMenu *menu;
2035 int pane, selidx, lpane, status;
2036 Lisp_Object entry = Qnil;
2037 Lisp_Object pane_prefix;
2038 char *datap;
2039 int ulx, uly, width, height;
2040 int dispwidth, dispheight;
2041 int i, j, lines, maxlines;
2042 int maxwidth;
2043 int dummy_int;
2044 unsigned int dummy_uint;
2045 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
2046
2047 eassert (FRAME_X_P (f) || FRAME_MSDOS_P (f));
2048
2049 *error_name = 0;
2050 if (menu_items_n_panes == 0)
2051 return Qnil;
2052
2053 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2054 {
2055 *error_name = "Empty menu";
2056 return Qnil;
2057 }
2058
2059 USE_SAFE_ALLOCA;
2060 block_input ();
2061
2062 /* Figure out which root window F is on. */
2063 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
2064 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2065 &dummy_uint, &dummy_uint);
2066
2067 /* Make the menu on that window. */
2068 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
2069 if (menu == NULL)
2070 {
2071 *error_name = "Can't create menu";
2072 goto return_entry;
2073 }
2074
2075 /* Don't GC while we prepare and show the menu,
2076 because we give the oldxmenu library pointers to the
2077 contents of strings. */
2078 inhibit_garbage_collection ();
2079
2080 #ifdef HAVE_X_WINDOWS
2081 {
2082 /* Adjust coordinates to relative to the outer (window manager) window. */
2083 int left_off, top_off;
2084
2085 x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
2086 NULL, NULL, NULL, NULL, NULL);
2087
2088 x += left_off;
2089 y += top_off;
2090 }
2091 #endif /* HAVE_X_WINDOWS */
2092
2093 x += f->left_pos;
2094 y += f->top_pos;
2095
2096 /* Create all the necessary panes and their items. */
2097 maxwidth = maxlines = lines = i = 0;
2098 lpane = XM_FAILURE;
2099 while (i < menu_items_used)
2100 {
2101 if (EQ (AREF (menu_items, i), Qt))
2102 {
2103 /* Create a new pane. */
2104 Lisp_Object pane_name, prefix;
2105 const char *pane_string;
2106
2107 maxlines = max (maxlines, lines);
2108 lines = 0;
2109 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2110 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2111 pane_string = (NILP (pane_name)
2112 ? "" : SSDATA (pane_name));
2113 if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
2114 pane_string++;
2115
2116 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, true);
2117 if (lpane == XM_FAILURE)
2118 {
2119 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2120 *error_name = "Can't create pane";
2121 goto return_entry;
2122 }
2123 i += MENU_ITEMS_PANE_LENGTH;
2124
2125 /* Find the width of the widest item in this pane. */
2126 j = i;
2127 while (j < menu_items_used)
2128 {
2129 Lisp_Object item;
2130 item = AREF (menu_items, j);
2131 if (EQ (item, Qt))
2132 break;
2133 if (NILP (item))
2134 {
2135 j++;
2136 continue;
2137 }
2138 width = SBYTES (item);
2139 if (width > maxwidth)
2140 maxwidth = width;
2141
2142 j += MENU_ITEMS_ITEM_LENGTH;
2143 }
2144 }
2145 /* Ignore a nil in the item list.
2146 It's meaningful only for dialog boxes. */
2147 else if (EQ (AREF (menu_items, i), Qquote))
2148 i += 1;
2149 else
2150 {
2151 /* Create a new item within current pane. */
2152 Lisp_Object item_name, enable, descrip, help;
2153 char *item_data;
2154 char const *help_string;
2155
2156 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2157 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2158 descrip
2159 = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2160 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
2161 help_string = STRINGP (help) ? SSDATA (help) : NULL;
2162
2163 if (!NILP (descrip))
2164 {
2165 item_data = SAFE_ALLOCA (maxwidth + SBYTES (descrip) + 1);
2166 memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
2167 for (j = SCHARS (item_name); j < maxwidth; j++)
2168 item_data[j] = ' ';
2169 memcpy (item_data + j, SSDATA (descrip), SBYTES (descrip));
2170 item_data[j + SBYTES (descrip)] = 0;
2171 }
2172 else
2173 item_data = SSDATA (item_name);
2174
2175 if (lpane == XM_FAILURE
2176 || (XMenuAddSelection (FRAME_X_DISPLAY (f),
2177 menu, lpane, 0, item_data,
2178 !NILP (enable), help_string)
2179 == XM_FAILURE))
2180 {
2181 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
2182 *error_name = "Can't add selection to menu";
2183 goto return_entry;
2184 }
2185 i += MENU_ITEMS_ITEM_LENGTH;
2186 lines++;
2187 }
2188 }
2189
2190 maxlines = max (maxlines, lines);
2191
2192 /* All set and ready to fly. */
2193 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2194 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2195 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2196 x = min (x, dispwidth);
2197 y = min (y, dispheight);
2198 x = max (x, 1);
2199 y = max (y, 1);
2200 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
2201 &ulx, &uly, &width, &height);
2202 if (ulx+width > dispwidth)
2203 {
2204 x -= (ulx + width) - dispwidth;
2205 ulx = dispwidth - width;
2206 }
2207 if (uly+height > dispheight)
2208 {
2209 y -= (uly + height) - dispheight;
2210 uly = dispheight - height;
2211 }
2212 #ifndef HAVE_X_WINDOWS
2213 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2214 {
2215 /* Move the menu away of the echo area, to avoid overwriting the
2216 menu with help echo messages or vice versa. */
2217 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2218 {
2219 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2220 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2221 }
2222 else
2223 {
2224 y--;
2225 uly--;
2226 }
2227 }
2228 #endif
2229 if (ulx < 0) x -= ulx;
2230 if (uly < 0) y -= uly;
2231
2232 if (!(menuflags & MENU_FOR_CLICK))
2233 {
2234 /* If position was not given by a mouse click, adjust so upper left
2235 corner of the menu as a whole ends up at given coordinates. This
2236 is what x-popup-menu says in its documentation. */
2237 x += width/2;
2238 y += 1.5*height/(maxlines+2);
2239 }
2240
2241 XMenuSetAEQ (menu, true);
2242 XMenuSetFreeze (menu, true);
2243 pane = selidx = 0;
2244
2245 #ifndef MSDOS
2246 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2247 #endif
2248
2249 record_unwind_protect (pop_down_menu, make_save_ptr_ptr (f, menu));
2250
2251 /* Help display under X won't work because XMenuActivate contains
2252 a loop that doesn't give Emacs a chance to process it. */
2253 menu_help_frame = f;
2254 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
2255 x, y, ButtonReleaseMask, &datap,
2256 menu_help_callback);
2257 pane_prefix = Qnil;
2258
2259 switch (status)
2260 {
2261 case XM_SUCCESS:
2262 #ifdef XDEBUG
2263 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2264 #endif
2265
2266 /* Find the item number SELIDX in pane number PANE. */
2267 i = 0;
2268 while (i < menu_items_used)
2269 {
2270 if (EQ (AREF (menu_items, i), Qt))
2271 {
2272 if (pane == 0)
2273 pane_prefix
2274 = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
2275 pane--;
2276 i += MENU_ITEMS_PANE_LENGTH;
2277 }
2278 else
2279 {
2280 if (pane == -1)
2281 {
2282 if (selidx == 0)
2283 {
2284 entry
2285 = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
2286 if (menuflags & MENU_KEYMAPS)
2287 {
2288 entry = list1 (entry);
2289 if (!NILP (pane_prefix))
2290 entry = Fcons (pane_prefix, entry);
2291 }
2292 break;
2293 }
2294 selidx--;
2295 }
2296 i += MENU_ITEMS_ITEM_LENGTH;
2297 }
2298 }
2299 break;
2300
2301 case XM_FAILURE:
2302 *error_name = "Can't activate menu";
2303 case XM_IA_SELECT:
2304 break;
2305 case XM_NO_SELECT:
2306 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2307 the menu was invoked with a mouse event as POSITION). */
2308 if (!(menuflags & MENU_FOR_CLICK))
2309 {
2310 unblock_input ();
2311 Fsignal (Qquit, Qnil);
2312 }
2313 break;
2314 }
2315
2316 return_entry:
2317 unblock_input ();
2318 SAFE_FREE ();
2319 return unbind_to (specpdl_count, entry);
2320 }
2321
2322 #endif /* not USE_X_TOOLKIT */
2323
2324 #ifndef MSDOS
2325 /* Detect if a dialog or menu has been posted. MSDOS has its own
2326 implementation on msdos.c. */
2327
2328 int
2329 popup_activated (void)
2330 {
2331 return popup_activated_flag;
2332 }
2333 #endif /* not MSDOS */
2334
2335 /* The following is used by delayed window autoselection. */
2336
2337 DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2338 doc: /* Return t if a menu or popup dialog is active. */)
2339 (void)
2340 {
2341 return (popup_activated ()) ? Qt : Qnil;
2342 }
2343 \f
2344 void
2345 syms_of_xmenu (void)
2346 {
2347 #ifdef USE_X_TOOLKIT
2348 enum { WIDGET_ID_TICK_START = 1 << 16 };
2349 widget_id_tick = WIDGET_ID_TICK_START;
2350 next_menubar_widget_id = 1;
2351 #endif
2352
2353 DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
2354 defsubr (&Smenu_or_popup_active_p);
2355
2356 #if defined (USE_GTK) || defined (USE_X_TOOLKIT)
2357 defsubr (&Sx_menu_bar_open_internal);
2358 Ffset (intern_c_string ("accelerate-menu"),
2359 intern_c_string (Sx_menu_bar_open_internal.symbol_name));
2360 #endif
2361 }