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