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