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