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