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