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