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