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