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