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