Regenerated
[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
5c646d5a
JD
1558#if 1 /* Experimentally, we now get the right results
1559 for -geometry -0-0 without this. 24 Aug 96, rms.
1560 Maybe so, but the menu bar size is missing the pixels so the
1561 WM size hints are off by theses pixel. Jan D, oct 2009. */
5ee80bd3 1562#ifdef USE_LUCID
1d1c1567
KH
1563 if (FRAME_EXTERNAL_MENU_BAR (f))
1564 {
1565 Dimension ibw = 0;
7556890b 1566 XtVaGetValues (f->output_data.x->column_widget,
1d1c1567
KH
1567 XtNinternalBorderWidth, &ibw, NULL);
1568 menubar_size += ibw;
1569 }
5ee80bd3 1570#endif /* USE_LUCID */
5c646d5a 1571#endif /* 1 */
1d1c1567 1572
7556890b 1573 f->output_data.x->menubar_height = menubar_size;
1d1c1567 1574 }
488dd4c4 1575#endif /* not USE_GTK */
177c0ea7 1576
18686d47 1577 free_menubar_widget_value_tree (first_wv);
364cd450 1578 update_frame_menubar (f);
18686d47 1579
488dd4c4
JD
1580#ifdef USE_GTK
1581 xg_crazy_callback_abort = 0;
1582#endif
1583
18686d47
RS
1584 UNBLOCK_INPUT;
1585}
85f487d1 1586
8e6208c5 1587/* Called from Fx_create_frame to create the initial menubar of a frame
4dedbfe0
PR
1588 before it is mapped, so that the window is mapped with the menubar already
1589 there instead of us tacking it on later and thrashing the window after it
1590 is visible. */
1591
1592void
1593initialize_frame_menubar (f)
1594 FRAME_PTR f;
1595{
1596 /* This function is called before the first chance to redisplay
1597 the frame. It has to be, so the frame will have the right size. */
1598 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
88766961 1599 set_frame_menubar (f, 1, 1);
4dedbfe0
PR
1600}
1601
aba25348 1602
4dedbfe0 1603/* Get rid of the menu bar of frame F, and free its storage.
488dd4c4
JD
1604 This is used when deleting a frame, and when turning off the menu bar.
1605 For GTK this function is in gtkutil.c. */
4dedbfe0 1606
488dd4c4 1607#ifndef USE_GTK
85f487d1
FP
1608void
1609free_frame_menubar (f)
1610 FRAME_PTR f;
1611{
1612 Widget menubar_widget;
85f487d1 1613
62af879c
KL
1614 if (! FRAME_X_P (f))
1615 abort ();
1616
7556890b 1617 menubar_widget = f->output_data.x->menubar_widget;
a45bad2a
RS
1618
1619 f->output_data.x->menubar_height = 0;
177c0ea7 1620
85f487d1
FP
1621 if (menubar_widget)
1622 {
aba25348
GM
1623#ifdef USE_MOTIF
1624 /* Removing the menu bar magically changes the shell widget's x
1625 and y position of (0, 0) which, when the menu bar is turned
1626 on again, leads to pull-down menuss appearing in strange
1627 positions near the upper-left corner of the display. This
1628 happens only with some window managers like twm and ctwm,
1629 but not with other like Motif's mwm or kwm, because the
1630 latter generate ConfigureNotify events when the menu bar
1631 is switched off, which fixes the shell position. */
1632 Position x0, y0, x1, y1;
1633#endif
177c0ea7 1634
85f487d1 1635 BLOCK_INPUT;
aba25348
GM
1636
1637#ifdef USE_MOTIF
ae556422
GM
1638 if (f->output_data.x->widget)
1639 XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL);
aba25348 1640#endif
177c0ea7 1641
7556890b 1642 lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id);
0c05dcd3 1643 f->output_data.x->menubar_widget = NULL;
aba25348
GM
1644
1645#ifdef USE_MOTIF
ae556422
GM
1646 if (f->output_data.x->widget)
1647 {
1648 XtVaGetValues (f->output_data.x->widget, XtNx, &x1, XtNy, &y1, NULL);
1649 if (x1 == 0 && y1 == 0)
1650 XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL);
1651 }
aba25348 1652#endif
177c0ea7 1653
85f487d1
FP
1654 UNBLOCK_INPUT;
1655 }
1656}
488dd4c4 1657#endif /* not USE_GTK */
78589e07 1658
488dd4c4 1659#endif /* USE_X_TOOLKIT || USE_GTK */
78589e07
RS
1660\f
1661/* xmenu_show actually displays a menu using the panes and items in menu_items
1662 and returns the value selected from it.
1663 There are two versions of xmenu_show, one for Xt and one for Xlib.
1664 Both assume input is blocked by the caller. */
1665
1666/* F is the frame the menu is for.
1667 X and Y are the frame-relative specified position,
1668 relative to the inside upper left corner of the frame F.
c8b5aa3d 1669 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
78589e07
RS
1670 KEYMAPS is 1 if this menu was specified with keymaps;
1671 in that case, we return a list containing the chosen item's value
1672 and perhaps also the pane's prefix.
1673 TITLE is the specified menu title.
1674 ERROR is a place to store an error message string in case of failure.
1675 (We return nil on failure, but the value doesn't actually matter.) */
18686d47 1676
488dd4c4
JD
1677#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
1678
1679/* The item selected in the popup menu. */
1680static Lisp_Object *volatile menu_item_selection;
1681
1682#ifdef USE_GTK
1683
1684/* Used when position a popup menu. See menu_position_func and
1685 create_and_show_popup_menu below. */
1686struct next_popup_x_y
1687{
7b76ca1c 1688 FRAME_PTR f;
488dd4c4
JD
1689 int x;
1690 int y;
1691};
1692
1693/* The menu position function to use if we are not putting a popup
1694 menu where the pointer is.
1695 MENU is the menu to pop up.
1696 X and Y shall on exit contain x/y where the menu shall pop up.
1697 PUSH_IN is not documented in the GTK manual.
1698 USER_DATA is any data passed in when calling gtk_menu_popup.
1699 Here it points to a struct next_popup_x_y where the coordinates
7b76ca1c 1700 to store in *X and *Y are as well as the frame for the popup.
488dd4c4
JD
1701
1702 Here only X and Y are used. */
1703static void
1704menu_position_func (menu, x, y, push_in, user_data)
1705 GtkMenu *menu;
1706 gint *x;
1707 gint *y;
1708 gboolean *push_in;
1709 gpointer user_data;
1710{
7b76ca1c
JD
1711 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data;
1712 GtkRequisition req;
fd2f80c6
CY
1713 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (data->f);
1714 int disp_width = x_display_pixel_width (dpyinfo);
1715 int disp_height = x_display_pixel_height (dpyinfo);
b9de078a 1716
7b76ca1c
JD
1717 *x = data->x;
1718 *y = data->y;
1719
1720 /* Check if there is room for the menu. If not, adjust x/y so that
1721 the menu is fully visible. */
1722 gtk_widget_size_request (GTK_WIDGET (menu), &req);
1723 if (data->x + req.width > disp_width)
1724 *x -= data->x + req.width - disp_width;
1725 if (data->y + req.height > disp_height)
1726 *y -= data->y + req.height - disp_height;
488dd4c4
JD
1727}
1728
1729static void
1730popup_selection_callback (widget, client_data)
1731 GtkWidget *widget;
1732 gpointer client_data;
1733{
1734 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data;
1735
1736 if (xg_crazy_callback_abort) return;
1737 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data;
1738}
1739
af89e871 1740static Lisp_Object
a130b901
JD
1741pop_down_menu (arg)
1742 Lisp_Object arg;
af89e871 1743{
a130b901
JD
1744 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1745
af89e871 1746 popup_activated_flag = 0;
a130b901
JD
1747 BLOCK_INPUT;
1748 gtk_widget_destroy (GTK_WIDGET (p->pointer));
1749 UNBLOCK_INPUT;
af89e871
JD
1750 return Qnil;
1751}
1752
488dd4c4
JD
1753/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1754 menu pops down.
1755 menu_item_selection will be set to the selection. */
1756static void
1757create_and_show_popup_menu (f, first_wv, x, y, for_click)
1758 FRAME_PTR f;
1759 widget_value *first_wv;
1760 int x;
1761 int y;
1762 int for_click;
1763{
1764 int i;
1765 GtkWidget *menu;
1766 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */
1767 struct next_popup_x_y popup_x_y;
af89e871 1768 int specpdl_count = SPECPDL_INDEX ();
488dd4c4 1769
62af879c
KL
1770 if (! FRAME_X_P (f))
1771 abort ();
1772
488dd4c4
JD
1773 xg_crazy_callback_abort = 1;
1774 menu = xg_create_widget ("popup", first_wv->name, f, first_wv,
1775 G_CALLBACK (popup_selection_callback),
1776 G_CALLBACK (popup_deactivate_callback),
1777 G_CALLBACK (menu_highlight_callback));
1778 xg_crazy_callback_abort = 0;
177c0ea7 1779
488dd4c4
JD
1780 if (! for_click)
1781 {
1782 /* Not invoked by a click. pop up at x/y. */
1783 pos_func = menu_position_func;
1784
1785 /* Adjust coordinates to be root-window-relative. */
9882535b
KS
1786 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1787 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
488dd4c4
JD
1788
1789 popup_x_y.x = x;
1790 popup_x_y.y = y;
7b76ca1c 1791 popup_x_y.f = f;
488dd4c4 1792
9b85e63d
JD
1793 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */
1794 }
1795 else
1796 {
1797 for (i = 0; i < 5; i++)
1798 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1799 break;
1800 }
59cfb104 1801
488dd4c4
JD
1802 /* Display the menu. */
1803 gtk_widget_show_all (menu);
1804 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0);
177c0ea7 1805
a130b901 1806 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
af89e871 1807
ff18668f
JD
1808 if (GTK_WIDGET_MAPPED (menu))
1809 {
1810 /* Set this to one. popup_widget_loop increases it by one, so it becomes
1811 two. show_help_echo uses this to detect popup menus. */
1812 popup_activated_flag = 1;
1813 /* Process events that apply to the menu. */
1814 popup_widget_loop (1, menu);
1815 }
488dd4c4 1816
af89e871 1817 unbind_to (specpdl_count, Qnil);
177c0ea7 1818
488dd4c4
JD
1819 /* Must reset this manually because the button release event is not passed
1820 to Emacs event loop. */
1821 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
1822}
1823
1824#else /* not USE_GTK */
18686d47 1825
8ed87156 1826/* We need a unique id for each widget handled by the Lucid Widget
cc17e9bf
KH
1827 library.
1828
1829 For the main windows, and popup menus, we use this counter,
88766961 1830 which we increment each time after use. This starts from 1<<16.
cc17e9bf 1831
88766961
RS
1832 For menu bars, we use numbers starting at 0, counted in
1833 next_menubar_widget_id. */
8ed87156 1834LWLIB_ID widget_id_tick;
165e1749 1835
4dedbfe0
PR
1836static void
1837popup_selection_callback (widget, id, client_data)
1838 Widget widget;
1839 LWLIB_ID id;
1840 XtPointer client_data;
1841{
1842 menu_item_selection = (Lisp_Object *) client_data;
1843}
1844
af89e871
JD
1845/* ARG is the LWLIB ID of the dialog box, represented
1846 as a Lisp object as (HIGHPART . LOWPART). */
1847
1848static Lisp_Object
1849pop_down_menu (arg)
1850 Lisp_Object arg;
1851{
1852 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID)
1853 | XINT (XCDR (arg)));
1854
1855 BLOCK_INPUT;
1856 lw_destroy_all_widgets (id);
1857 UNBLOCK_INPUT;
1858 popup_activated_flag = 0;
1859
1860 return Qnil;
1861}
1862
488dd4c4
JD
1863/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1864 menu pops down.
1865 menu_item_selection will be set to the selection. */
1866static void
1867create_and_show_popup_menu (f, first_wv, x, y, for_click)
1868 FRAME_PTR f;
1869 widget_value *first_wv;
1870 int x;
1871 int y;
1872 int for_click;
1873{
1874 int i;
1875 Arg av[2];
1876 int ac = 0;
1877 XButtonPressedEvent dummy;
1878 LWLIB_ID menu_id;
1879 Widget menu;
488dd4c4 1880
62af879c
KL
1881 if (! FRAME_X_P (f))
1882 abort ();
1883
488dd4c4
JD
1884 menu_id = widget_id_tick++;
1885 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
1886 f->output_data.x->widget, 1, 0,
1887 popup_selection_callback,
1888 popup_deactivate_callback,
1889 menu_highlight_callback);
1890
1891 dummy.type = ButtonPress;
1892 dummy.serial = 0;
1893 dummy.send_event = 0;
1894 dummy.display = FRAME_X_DISPLAY (f);
1895 dummy.time = CurrentTime;
1896 dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window;
1897 dummy.window = dummy.root;
1898 dummy.subwindow = dummy.root;
1899 dummy.x = x;
1900 dummy.y = y;
1901
1902 /* Adjust coordinates to be root-window-relative. */
9882535b
KS
1903 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1904 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
488dd4c4
JD
1905
1906 dummy.x_root = x;
1907 dummy.y_root = y;
1908
1909 dummy.state = 0;
1910 dummy.button = 0;
1911 for (i = 0; i < 5; i++)
1912 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i))
1913 dummy.button = i;
1914
1915 /* Don't allow any geometry request from the user. */
1916 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1917 XtSetValues (menu, av, ac);
1918
1919 /* Display the menu. */
1920 lw_popup_menu (menu, (XEvent *) &dummy);
1921 popup_activated_flag = 1;
98a20c65 1922 x_activate_timeout_atimer ();
59cfb104 1923
af89e871
JD
1924 {
1925 int fact = 4 * sizeof (LWLIB_ID);
1926 int specpdl_count = SPECPDL_INDEX ();
1927 record_unwind_protect (pop_down_menu,
1928 Fcons (make_number (menu_id >> (fact)),
1929 make_number (menu_id & ~(-1 << (fact)))));
488dd4c4 1930
af89e871 1931 /* Process events that apply to the menu. */
95bdef2e 1932 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1);
488dd4c4 1933
af89e871
JD
1934 unbind_to (specpdl_count, Qnil);
1935 }
488dd4c4
JD
1936}
1937
1938#endif /* not USE_GTK */
1939
78589e07 1940static Lisp_Object
673a6211 1941xmenu_show (f, x, y, for_click, keymaps, title, error)
18686d47 1942 FRAME_PTR f;
18686d47
RS
1943 int x;
1944 int y;
9685a93f 1945 int for_click;
78589e07
RS
1946 int keymaps;
1947 Lisp_Object title;
1948 char **error;
18686d47 1949{
78589e07 1950 int i;
78589e07 1951 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
101bb4a5
RS
1952 widget_value **submenu_stack
1953 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1954 Lisp_Object *subprefix_stack
1955 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1956 int submenu_depth = 0;
4e8d3549 1957
78c8278d
RS
1958 int first_pane;
1959
62af879c
KL
1960 if (! FRAME_X_P (f))
1961 abort ();
1962
78589e07
RS
1963 *error = NULL;
1964
742f715d
KH
1965 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1966 {
1967 *error = "Empty menu";
1968 return Qnil;
1969 }
63c414df 1970
78589e07
RS
1971 /* Create a tree of widget_value objects
1972 representing the panes and their items. */
f7fab165 1973 wv = xmalloc_widget_value ();
78589e07
RS
1974 wv->name = "menu";
1975 wv->value = 0;
1976 wv->enabled = 1;
3427a3db 1977 wv->button_type = BUTTON_TYPE_NONE;
27ad7b52 1978 wv->help =Qnil;
78589e07 1979 first_wv = wv;
78c8278d 1980 first_pane = 1;
177c0ea7 1981
78589e07
RS
1982 /* Loop over all panes and items, filling in the tree. */
1983 i = 0;
1984 while (i < menu_items_used)
1985 {
101bb4a5
RS
1986 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1987 {
1988 submenu_stack[submenu_depth++] = save_wv;
1989 save_wv = prev_wv;
1990 prev_wv = 0;
78c8278d 1991 first_pane = 1;
101bb4a5
RS
1992 i++;
1993 }
1994 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1995 {
1996 prev_wv = save_wv;
1997 save_wv = submenu_stack[--submenu_depth];
78c8278d 1998 first_pane = 0;
101bb4a5
RS
1999 i++;
2000 }
2001 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
2002 && submenu_depth != 0)
2003 i += MENU_ITEMS_PANE_LENGTH;
fcaa7665
RS
2004 /* Ignore a nil in the item list.
2005 It's meaningful only for dialog boxes. */
2006 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2007 i += 1;
101bb4a5 2008 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
78589e07
RS
2009 {
2010 /* Create a new pane. */
2011 Lisp_Object pane_name, prefix;
2012 char *pane_string;
177c0ea7 2013
4c329aa8
GM
2014 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
2015 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
177c0ea7 2016
703dc2a8 2017#ifndef HAVE_MULTILINGUAL_MENU
4c329aa8
GM
2018 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
2019 {
8af9fa55 2020 pane_name = ENCODE_MENU_STRING (pane_name);
3ae565b3 2021 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
4c329aa8 2022 }
703dc2a8 2023#endif
78589e07 2024 pane_string = (NILP (pane_name)
d5db4077 2025 ? "" : (char *) SDATA (pane_name));
101bb4a5 2026 /* If there is just one top-level pane, put all its items directly
78589e07
RS
2027 under the top-level menu. */
2028 if (menu_items_n_panes == 1)
2029 pane_string = "";
2030
2031 /* If the pane has a meaningful name,
2032 make the pane a top-level menu item
2033 with its items as a submenu beneath it. */
78c8278d 2034 if (!keymaps && strcmp (pane_string, ""))
78589e07 2035 {
f7fab165 2036 wv = xmalloc_widget_value ();
78589e07
RS
2037 if (save_wv)
2038 save_wv->next = wv;
2039 else
2040 first_wv->contents = wv;
2041 wv->name = pane_string;
2042 if (keymaps && !NILP (prefix))
2043 wv->name++;
2044 wv->value = 0;
2045 wv->enabled = 1;
3427a3db 2046 wv->button_type = BUTTON_TYPE_NONE;
27ad7b52 2047 wv->help = Qnil;
78c8278d
RS
2048 save_wv = wv;
2049 prev_wv = 0;
78589e07 2050 }
78c8278d
RS
2051 else if (first_pane)
2052 {
2053 save_wv = wv;
2054 prev_wv = 0;
2055 }
2056 first_pane = 0;
78589e07
RS
2057 i += MENU_ITEMS_PANE_LENGTH;
2058 }
2059 else
2060 {
2061 /* Create a new item within current pane. */
9cd50434 2062 Lisp_Object item_name, enable, descrip, def, type, selected, help;
4c329aa8
GM
2063 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
2064 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
2065 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
2066 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
2067 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
2068 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
2069 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
3427a3db 2070
703dc2a8 2071#ifndef HAVE_MULTILINGUAL_MENU
3427a3db 2072 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
4c329aa8 2073 {
646f98ec 2074 item_name = ENCODE_MENU_STRING (item_name);
3ae565b3 2075 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
4c329aa8 2076 }
177c0ea7 2077
3427a3db 2078 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
4c329aa8 2079 {
646f98ec 2080 descrip = ENCODE_MENU_STRING (descrip);
3ae565b3 2081 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
4c329aa8
GM
2082 }
2083#endif /* not HAVE_MULTILINGUAL_MENU */
177c0ea7 2084
f7fab165 2085 wv = xmalloc_widget_value ();
177c0ea7 2086 if (prev_wv)
78589e07 2087 prev_wv->next = wv;
177c0ea7 2088 else
78589e07 2089 save_wv->contents = wv;
d5db4077 2090 wv->name = (char *) SDATA (item_name);
78589e07 2091 if (!NILP (descrip))
d5db4077 2092 wv->key = (char *) SDATA (descrip);
78589e07 2093 wv->value = 0;
a352a815
RS
2094 /* If this item has a null value,
2095 make the call_data null so that it won't display a box
2096 when the mouse is on it. */
2097 wv->call_data
2098 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
78589e07 2099 wv->enabled = !NILP (enable);
3427a3db
GM
2100
2101 if (NILP (type))
2102 wv->button_type = BUTTON_TYPE_NONE;
2103 else if (EQ (type, QCtoggle))
2104 wv->button_type = BUTTON_TYPE_TOGGLE;
2105 else if (EQ (type, QCradio))
2106 wv->button_type = BUTTON_TYPE_RADIO;
2107 else
2108 abort ();
2109
2110 wv->selected = !NILP (selected);
cc45fb40 2111
0b1f4572
RS
2112 if (! STRINGP (help))
2113 help = Qnil;
2114
2115 wv->help = help;
cc45fb40 2116
78589e07
RS
2117 prev_wv = wv;
2118
2119 i += MENU_ITEMS_ITEM_LENGTH;
2120 }
2121 }
2122
c98fcf4b 2123 /* Deal with the title, if it is non-nil. */
4dedbfe0
PR
2124 if (!NILP (title))
2125 {
f7fab165
RS
2126 widget_value *wv_title = xmalloc_widget_value ();
2127 widget_value *wv_sep1 = xmalloc_widget_value ();
2128 widget_value *wv_sep2 = xmalloc_widget_value ();
4dedbfe0
PR
2129
2130 wv_sep2->name = "--";
2131 wv_sep2->next = first_wv->contents;
27ad7b52 2132 wv_sep2->help = Qnil;
4dedbfe0
PR
2133
2134 wv_sep1->name = "--";
2135 wv_sep1->next = wv_sep2;
27ad7b52 2136 wv_sep1->help = Qnil;
4dedbfe0 2137
703dc2a8
KH
2138#ifndef HAVE_MULTILINGUAL_MENU
2139 if (STRING_MULTIBYTE (title))
646f98ec 2140 title = ENCODE_MENU_STRING (title);
703dc2a8 2141#endif
177c0ea7 2142
d5db4077 2143 wv_title->name = (char *) SDATA (title);
cc45fb40 2144 wv_title->enabled = TRUE;
3427a3db 2145 wv_title->button_type = BUTTON_TYPE_NONE;
27ad7b52 2146 wv_title->help = Qnil;
a9d8395f 2147 wv_title->next = wv_sep1;
4dedbfe0
PR
2148 first_wv->contents = wv_title;
2149 }
2150
78589e07
RS
2151 /* No selection has been chosen yet. */
2152 menu_item_selection = 0;
2153
488dd4c4
JD
2154 /* Actually create and show the menu until popped down. */
2155 create_and_show_popup_menu (f, first_wv, x, y, for_click);
18686d47 2156
488dd4c4
JD
2157 /* Free the widget_value objects we used to specify the contents. */
2158 free_menubar_widget_value_tree (first_wv);
18686d47 2159
78589e07
RS
2160 /* Find the selected item, and its pane, to return
2161 the proper value. */
2162 if (menu_item_selection != 0)
2163 {
c63f6952 2164 Lisp_Object prefix, entry;
78589e07 2165
6bbd7a29 2166 prefix = entry = Qnil;
78589e07
RS
2167 i = 0;
2168 while (i < menu_items_used)
2169 {
101bb4a5
RS
2170 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
2171 {
2172 subprefix_stack[submenu_depth++] = prefix;
2173 prefix = entry;
2174 i++;
2175 }
2176 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
2177 {
2178 prefix = subprefix_stack[--submenu_depth];
2179 i++;
2180 }
2181 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
78589e07
RS
2182 {
2183 prefix
2184 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2185 i += MENU_ITEMS_PANE_LENGTH;
2186 }
d31d42cc
RS
2187 /* Ignore a nil in the item list.
2188 It's meaningful only for dialog boxes. */
2189 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2190 i += 1;
78589e07
RS
2191 else
2192 {
2193 entry
2194 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2195 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2196 {
2197 if (keymaps != 0)
2198 {
101bb4a5
RS
2199 int j;
2200
78589e07
RS
2201 entry = Fcons (entry, Qnil);
2202 if (!NILP (prefix))
2203 entry = Fcons (prefix, entry);
101bb4a5 2204 for (j = submenu_depth - 1; j >= 0; j--)
e48087b7 2205 if (!NILP (subprefix_stack[j]))
5964e450 2206 entry = Fcons (subprefix_stack[j], entry);
78589e07
RS
2207 }
2208 return entry;
2209 }
2210 i += MENU_ITEMS_ITEM_LENGTH;
2211 }
2212 }
2213 }
be6ed24a
RS
2214 else if (!for_click)
2215 /* Make "Cancel" equivalent to C-g. */
2216 Fsignal (Qquit, Qnil);
78589e07
RS
2217
2218 return Qnil;
18686d47 2219}
4dedbfe0 2220\f
488dd4c4
JD
2221#ifdef USE_GTK
2222static void
2223dialog_selection_callback (widget, client_data)
2224 GtkWidget *widget;
2225 gpointer client_data;
2226{
2227 /* The EMACS_INT cast avoids a warning. There's no problem
2228 as long as pointers have enough bits to hold small integers. */
2229 if ((int) (EMACS_INT) client_data != -1)
2230 menu_item_selection = (Lisp_Object *) client_data;
2231
2232 popup_activated_flag = 0;
2233}
2234
2235/* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2236 dialog pops down.
2237 menu_item_selection will be set to the selection. */
2238static void
2239create_and_show_dialog (f, first_wv)
2240 FRAME_PTR f;
2241 widget_value *first_wv;
2242{
2243 GtkWidget *menu;
2244
62af879c
KL
2245 if (! FRAME_X_P (f))
2246 abort ();
2247
488dd4c4
JD
2248 menu = xg_create_widget ("dialog", first_wv->name, f, first_wv,
2249 G_CALLBACK (dialog_selection_callback),
2250 G_CALLBACK (popup_deactivate_callback),
2251 0);
2252
2253 if (menu)
2254 {
af89e871 2255 int specpdl_count = SPECPDL_INDEX ();
a130b901 2256 record_unwind_protect (pop_down_menu, make_save_value (menu, 0));
af89e871 2257
488dd4c4
JD
2258 /* Display the menu. */
2259 gtk_widget_show_all (menu);
2260
2261 /* Process events that apply to the menu. */
f1d1cd24 2262 popup_widget_loop (1, menu);
177c0ea7 2263
af89e871 2264 unbind_to (specpdl_count, Qnil);
488dd4c4
JD
2265 }
2266}
2267
2268#else /* not USE_GTK */
4dedbfe0
PR
2269static void
2270dialog_selection_callback (widget, id, client_data)
2271 Widget widget;
2272 LWLIB_ID id;
2273 XtPointer client_data;
2274{
01d5e892
RS
2275 /* The EMACS_INT cast avoids a warning. There's no problem
2276 as long as pointers have enough bits to hold small integers. */
2277 if ((int) (EMACS_INT) client_data != -1)
4dedbfe0 2278 menu_item_selection = (Lisp_Object *) client_data;
488dd4c4 2279
4dedbfe0
PR
2280 BLOCK_INPUT;
2281 lw_destroy_all_widgets (id);
2282 UNBLOCK_INPUT;
9572375b 2283 popup_activated_flag = 0;
4dedbfe0 2284}
18686d47 2285
488dd4c4 2286
488dd4c4
JD
2287/* Pop up the dialog for frame F defined by FIRST_WV and loop until the
2288 dialog pops down.
2289 menu_item_selection will be set to the selection. */
2290static void
2291create_and_show_dialog (f, first_wv)
2292 FRAME_PTR f;
2293 widget_value *first_wv;
2294{
2295 LWLIB_ID dialog_id;
2296
62af879c
KL
2297 if (!FRAME_X_P (f))
2298 abort();
2299
488dd4c4
JD
2300 dialog_id = widget_id_tick++;
2301 lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2302 f->output_data.x->widget, 1, 0,
2303 dialog_selection_callback, 0, 0);
2304 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
2305
2306 /* Display the dialog box. */
2307 lw_pop_up_all_widgets (dialog_id);
2308 popup_activated_flag = 1;
98a20c65 2309 x_activate_timeout_atimer ();
488dd4c4
JD
2310
2311 /* Process events that apply to the dialog box.
2312 Also handle timers. */
2313 {
2314 int count = SPECPDL_INDEX ();
2315 int fact = 4 * sizeof (LWLIB_ID);
177c0ea7 2316
488dd4c4 2317 /* xdialog_show_unwind is responsible for popping the dialog box down. */
af89e871 2318 record_unwind_protect (pop_down_menu,
488dd4c4
JD
2319 Fcons (make_number (dialog_id >> (fact)),
2320 make_number (dialog_id & ~(-1 << (fact)))));
2321
df470e3b 2322 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f),
95bdef2e 2323 dialog_id, 1);
488dd4c4
JD
2324
2325 unbind_to (count, Qnil);
2326 }
2327}
2328
2329#endif /* not USE_GTK */
2330
165e1749
FP
2331static char * button_names [] = {
2332 "button1", "button2", "button3", "button4", "button5",
2333 "button6", "button7", "button8", "button9", "button10" };
2334
2335static Lisp_Object
6a040d6a 2336xdialog_show (f, keymaps, title, header, error_name)
165e1749 2337 FRAME_PTR f;
165e1749 2338 int keymaps;
6a040d6a
NR
2339 Lisp_Object title, header;
2340 char **error_name;
165e1749
FP
2341{
2342 int i, nb_buttons=0;
80670155 2343 char dialog_name[6];
165e1749 2344
faa935b6 2345 widget_value *wv, *first_wv = 0, *prev_wv = 0;
165e1749 2346
fcaa7665
RS
2347 /* Number of elements seen so far, before boundary. */
2348 int left_count = 0;
2349 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
2350 int boundary_seen = 0;
2351
62af879c
KL
2352 if (! FRAME_X_P (f))
2353 abort ();
2354
6a040d6a 2355 *error_name = NULL;
165e1749 2356
80670155
RS
2357 if (menu_items_n_panes > 1)
2358 {
6a040d6a 2359 *error_name = "Multiple panes in dialog box";
80670155
RS
2360 return Qnil;
2361 }
2362
165e1749
FP
2363 /* Create a tree of widget_value objects
2364 representing the text label and buttons. */
2365 {
2366 Lisp_Object pane_name, prefix;
2367 char *pane_string;
2368 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
2369 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
2370 pane_string = (NILP (pane_name)
177c0ea7 2371 ? "" : (char *) SDATA (pane_name));
f7fab165 2372 prev_wv = xmalloc_widget_value ();
165e1749
FP
2373 prev_wv->value = pane_string;
2374 if (keymaps && !NILP (prefix))
2375 prev_wv->name++;
2376 prev_wv->enabled = 1;
2377 prev_wv->name = "message";
27ad7b52 2378 prev_wv->help = Qnil;
165e1749 2379 first_wv = prev_wv;
177c0ea7 2380
165e1749
FP
2381 /* Loop over all panes and items, filling in the tree. */
2382 i = MENU_ITEMS_PANE_LENGTH;
2383 while (i < menu_items_used)
2384 {
177c0ea7 2385
165e1749
FP
2386 /* Create a new item within current pane. */
2387 Lisp_Object item_name, enable, descrip;
2388 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2389 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2390 descrip
2391 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
177c0ea7 2392
80670155
RS
2393 if (NILP (item_name))
2394 {
2395 free_menubar_widget_value_tree (first_wv);
6a040d6a 2396 *error_name = "Submenu in dialog items";
80670155
RS
2397 return Qnil;
2398 }
fcaa7665
RS
2399 if (EQ (item_name, Qquote))
2400 {
2401 /* This is the boundary between left-side elts
2402 and right-side elts. Stop incrementing right_count. */
2403 boundary_seen = 1;
2404 i++;
2405 continue;
2406 }
86e71abf 2407 if (nb_buttons >= 9)
80670155
RS
2408 {
2409 free_menubar_widget_value_tree (first_wv);
6a040d6a 2410 *error_name = "Too many dialog items";
80670155
RS
2411 return Qnil;
2412 }
2413
f7fab165 2414 wv = xmalloc_widget_value ();
165e1749 2415 prev_wv->next = wv;
80670155 2416 wv->name = (char *) button_names[nb_buttons];
165e1749 2417 if (!NILP (descrip))
d5db4077
KR
2418 wv->key = (char *) SDATA (descrip);
2419 wv->value = (char *) SDATA (item_name);
165e1749
FP
2420 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2421 wv->enabled = !NILP (enable);
27ad7b52 2422 wv->help = Qnil;
165e1749
FP
2423 prev_wv = wv;
2424
fcaa7665
RS
2425 if (! boundary_seen)
2426 left_count++;
2427
165e1749
FP
2428 nb_buttons++;
2429 i += MENU_ITEMS_ITEM_LENGTH;
2430 }
2431
fcaa7665
RS
2432 /* If the boundary was not specified,
2433 by default put half on the left and half on the right. */
2434 if (! boundary_seen)
2435 left_count = nb_buttons - nb_buttons / 2;
2436
f7fab165 2437 wv = xmalloc_widget_value ();
80670155 2438 wv->name = dialog_name;
27ad7b52 2439 wv->help = Qnil;
6a040d6a
NR
2440
2441 /* Frame title: 'Q' = Question, 'I' = Information.
2442 Can also have 'E' = Error if, one day, we want
2443 a popup for errors. */
2444 if (NILP(header))
2445 dialog_name[0] = 'Q';
2446 else
2447 dialog_name[0] = 'I';
2448
80670155
RS
2449 /* Dialog boxes use a really stupid name encoding
2450 which specifies how many buttons to use
6a040d6a 2451 and how many buttons are on the right. */
80670155
RS
2452 dialog_name[1] = '0' + nb_buttons;
2453 dialog_name[2] = 'B';
2454 dialog_name[3] = 'R';
fcaa7665
RS
2455 /* Number of buttons to put on the right. */
2456 dialog_name[4] = '0' + nb_buttons - left_count;
80670155 2457 dialog_name[5] = 0;
165e1749
FP
2458 wv->contents = first_wv;
2459 first_wv = wv;
165e1749
FP
2460 }
2461
165e1749
FP
2462 /* No selection has been chosen yet. */
2463 menu_item_selection = 0;
2464
488dd4c4
JD
2465 /* Actually create and show the dialog. */
2466 create_and_show_dialog (f, first_wv);
f02cac82 2467
488dd4c4
JD
2468 /* Free the widget_value objects we used to specify the contents. */
2469 free_menubar_widget_value_tree (first_wv);
177c0ea7 2470
488dd4c4
JD
2471 /* Find the selected item, and its pane, to return
2472 the proper value. */
165e1749
FP
2473 if (menu_item_selection != 0)
2474 {
2475 Lisp_Object prefix;
2476
2477 prefix = Qnil;
2478 i = 0;
2479 while (i < menu_items_used)
2480 {
2481 Lisp_Object entry;
2482
2483 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2484 {
2485 prefix
2486 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2487 i += MENU_ITEMS_PANE_LENGTH;
2488 }
85996cfb
GM
2489 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2490 {
2491 /* This is the boundary between left-side elts and
2492 right-side elts. */
2493 ++i;
2494 }
165e1749
FP
2495 else
2496 {
2497 entry
2498 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2499 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2500 {
2501 if (keymaps != 0)
2502 {
2503 entry = Fcons (entry, Qnil);
2504 if (!NILP (prefix))
2505 entry = Fcons (prefix, entry);
2506 }
2507 return entry;
2508 }
2509 i += MENU_ITEMS_ITEM_LENGTH;
2510 }
2511 }
2512 }
9f6fcdc5
JD
2513 else
2514 /* Make "Cancel" equivalent to C-g. */
2515 Fsignal (Qquit, Qnil);
165e1749
FP
2516
2517 return Qnil;
2518}
ba461919 2519
488dd4c4 2520#else /* not USE_X_TOOLKIT && not USE_GTK */
78589e07 2521
3e703b25
GM
2522/* The frame of the last activated non-toolkit menu bar.
2523 Used to generate menu help events. */
2524
2525static struct frame *menu_help_frame;
2526
2527
62145073
GM
2528/* Show help HELP_STRING, or clear help if HELP_STRING is null.
2529
2530 PANE is the pane number, and ITEM is the menu item number in
2531 the menu (currently not used).
177c0ea7 2532
62145073
GM
2533 This cannot be done with generating a HELP_EVENT because
2534 XMenuActivate contains a loop that doesn't let Emacs process
2535 keyboard events. */
3e703b25
GM
2536
2537static void
62145073 2538menu_help_callback (help_string, pane, item)
3e703b25 2539 char *help_string;
62145073 2540 int pane, item;
3e703b25 2541{
62145073
GM
2542 extern Lisp_Object Qmenu_item;
2543 Lisp_Object *first_item;
2544 Lisp_Object pane_name;
2545 Lisp_Object menu_object;
177c0ea7 2546
62145073
GM
2547 first_item = XVECTOR (menu_items)->contents;
2548 if (EQ (first_item[0], Qt))
2549 pane_name = first_item[MENU_ITEMS_PANE_NAME];
2550 else if (EQ (first_item[0], Qquote))
2551 /* This shouldn't happen, see xmenu_show. */
ce33e8eb 2552 pane_name = empty_unibyte_string;
62145073
GM
2553 else
2554 pane_name = first_item[MENU_ITEMS_ITEM_NAME];
177c0ea7 2555
62145073
GM
2556 /* (menu-item MENU-NAME PANE-NUMBER) */
2557 menu_object = Fcons (Qmenu_item,
2558 Fcons (pane_name,
2559 Fcons (make_number (pane), Qnil)));
ba461919 2560 show_help_echo (help_string ? build_string (help_string) : Qnil,
62145073 2561 Qnil, menu_object, make_number (item), 1);
3e703b25 2562}
177c0ea7 2563
af89e871 2564static Lisp_Object
a130b901
JD
2565pop_down_menu (arg)
2566 Lisp_Object arg;
af89e871 2567{
a130b901
JD
2568 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
2569 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
59cfb104 2570
a130b901
JD
2571 FRAME_PTR f = p1->pointer;
2572 XMenu *menu = p2->pointer;
af89e871
JD
2573
2574 BLOCK_INPUT;
af89e871 2575#ifndef MSDOS
a130b901
JD
2576 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime);
2577 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime);
af89e871 2578#endif
a130b901 2579 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
af89e871
JD
2580
2581#ifdef HAVE_X_WINDOWS
2582 /* Assume the mouse has moved out of the X window.
2583 If it has actually moved in, we will get an EnterNotify. */
2584 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
2585
2586 /* State that no mouse buttons are now held.
2587 (The oldXMenu code doesn't track this info for us.)
2588 That is not necessarily true, but the fiction leads to reasonable
2589 results, and it is a pain to ask which are actually held now. */
2590 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
2591
2592#endif /* HAVE_X_WINDOWS */
2593
2594 UNBLOCK_INPUT;
2595
2596 return Qnil;
2597}
2598
3e703b25 2599
78589e07 2600static Lisp_Object
673a6211 2601xmenu_show (f, x, y, for_click, keymaps, title, error)
78589e07
RS
2602 FRAME_PTR f;
2603 int x, y;
9685a93f
RS
2604 int for_click;
2605 int keymaps;
78589e07
RS
2606 Lisp_Object title;
2607 char **error;
dcfdbac7 2608{
177c0ea7 2609 Window root;
78589e07
RS
2610 XMenu *menu;
2611 int pane, selidx, lpane, status;
2612 Lisp_Object entry, pane_prefix;
dcfdbac7
JB
2613 char *datap;
2614 int ulx, uly, width, height;
2615 int dispwidth, dispheight;
453a4f1b 2616 int i, j, lines, maxlines;
4e8d3549 2617 int maxwidth;
78589e07
RS
2618 int dummy_int;
2619 unsigned int dummy_uint;
af89e871 2620 int specpdl_count = SPECPDL_INDEX ();
088831f6 2621
a9e1244d 2622 if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f))
62af879c
KL
2623 abort ();
2624
07a675b7 2625 *error = 0;
78589e07
RS
2626 if (menu_items_n_panes == 0)
2627 return Qnil;
088831f6 2628
742f715d
KH
2629 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2630 {
2631 *error = "Empty menu";
2632 return Qnil;
2633 }
2634
78589e07 2635 /* Figure out which root window F is on. */
92280f67 2636 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
78589e07
RS
2637 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2638 &dummy_uint, &dummy_uint);
18686d47 2639
78589e07 2640 /* Make the menu on that window. */
92280f67 2641 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
78589e07 2642 if (menu == NULL)
dcfdbac7
JB
2643 {
2644 *error = "Can't create menu";
78589e07 2645 return Qnil;
dcfdbac7 2646 }
78589e07 2647
d130d129
RS
2648 /* Don't GC while we prepare and show the menu,
2649 because we give the oldxmenu library pointers to the
2650 contents of strings. */
2651 inhibit_garbage_collection ();
2652
87485d6f 2653#ifdef HAVE_X_WINDOWS
78589e07 2654 /* Adjust coordinates to relative to the outer (window manager) window. */
453a4f1b
JD
2655 x += FRAME_OUTER_TO_INNER_DIFF_X (f);
2656 y += FRAME_OUTER_TO_INNER_DIFF_Y (f);
87485d6f 2657#endif /* HAVE_X_WINDOWS */
78589e07
RS
2658
2659 /* Adjust coordinates to be root-window-relative. */
9882535b
KS
2660 x += f->left_pos;
2661 y += f->top_pos;
177c0ea7 2662
78589e07 2663 /* Create all the necessary panes and their items. */
453a4f1b 2664 maxlines = lines = i = 0;
78589e07 2665 while (i < menu_items_used)
dcfdbac7 2666 {
78589e07 2667 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
dcfdbac7 2668 {
78589e07
RS
2669 /* Create a new pane. */
2670 Lisp_Object pane_name, prefix;
2671 char *pane_string;
2672
453a4f1b
JD
2673 maxlines = max (maxlines, lines);
2674 lines = 0;
78589e07
RS
2675 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2676 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2677 pane_string = (NILP (pane_name)
d5db4077 2678 ? "" : (char *) SDATA (pane_name));
78589e07
RS
2679 if (keymaps && !NILP (prefix))
2680 pane_string++;
2681
92280f67 2682 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
78589e07
RS
2683 if (lpane == XM_FAILURE)
2684 {
92280f67 2685 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
78589e07
RS
2686 *error = "Can't create pane";
2687 return Qnil;
2688 }
2689 i += MENU_ITEMS_PANE_LENGTH;
4e8d3549
RS
2690
2691 /* Find the width of the widest item in this pane. */
2692 maxwidth = 0;
2693 j = i;
2694 while (j < menu_items_used)
2695 {
2696 Lisp_Object item;
2697 item = XVECTOR (menu_items)->contents[j];
2698 if (EQ (item, Qt))
2699 break;
2700 if (NILP (item))
2701 {
2702 j++;
2703 continue;
2704 }
d5db4077 2705 width = SBYTES (item);
4e8d3549
RS
2706 if (width > maxwidth)
2707 maxwidth = width;
2708
2709 j += MENU_ITEMS_ITEM_LENGTH;
2710 }
dcfdbac7 2711 }
fcaa7665
RS
2712 /* Ignore a nil in the item list.
2713 It's meaningful only for dialog boxes. */
2714 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2715 i += 1;
78589e07 2716 else
dcfdbac7 2717 {
78589e07 2718 /* Create a new item within current pane. */
3e703b25 2719 Lisp_Object item_name, enable, descrip, help;
4e8d3549 2720 unsigned char *item_data;
3e703b25 2721 char *help_string;
78589e07
RS
2722
2723 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2724 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2725 descrip
2726 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
3e703b25 2727 help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
d5db4077 2728 help_string = STRINGP (help) ? SDATA (help) : NULL;
177c0ea7 2729
78589e07 2730 if (!NILP (descrip))
4e8d3549 2731 {
d5db4077 2732 int gap = maxwidth - SBYTES (item_name);
4e8d3549
RS
2733 /* if alloca is fast, use that to make the space,
2734 to reduce gc needs. */
2735 item_data
2736 = (unsigned char *) alloca (maxwidth
d5db4077
KR
2737 + SBYTES (descrip) + 1);
2738 bcopy (SDATA (item_name), item_data,
2739 SBYTES (item_name));
2740 for (j = SCHARS (item_name); j < maxwidth; j++)
4e8d3549 2741 item_data[j] = ' ';
d5db4077
KR
2742 bcopy (SDATA (descrip), item_data + j,
2743 SBYTES (descrip));
2744 item_data[j + SBYTES (descrip)] = 0;
4e8d3549
RS
2745 }
2746 else
d5db4077 2747 item_data = SDATA (item_name);
78589e07 2748
92280f67
RS
2749 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2750 menu, lpane, 0, item_data,
3e703b25 2751 !NILP (enable), help_string)
dcfdbac7
JB
2752 == XM_FAILURE)
2753 {
92280f67 2754 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
dcfdbac7 2755 *error = "Can't add selection to menu";
78589e07 2756 return Qnil;
dcfdbac7 2757 }
78589e07 2758 i += MENU_ITEMS_ITEM_LENGTH;
453a4f1b 2759 lines++;
dcfdbac7
JB
2760 }
2761 }
4e8d3549 2762
453a4f1b
JD
2763 maxlines = max (maxlines, lines);
2764
78589e07 2765 /* All set and ready to fly. */
92280f67 2766 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
63685b9d
GM
2767 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
2768 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f));
78589e07
RS
2769 x = min (x, dispwidth);
2770 y = min (y, dispheight);
2771 x = max (x, 1);
2772 y = max (y, 1);
92280f67 2773 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
dcfdbac7
JB
2774 &ulx, &uly, &width, &height);
2775 if (ulx+width > dispwidth)
2776 {
78589e07 2777 x -= (ulx + width) - dispwidth;
dcfdbac7
JB
2778 ulx = dispwidth - width;
2779 }
2780 if (uly+height > dispheight)
2781 {
78589e07 2782 y -= (uly + height) - dispheight;
dcfdbac7
JB
2783 uly = dispheight - height;
2784 }
2de7397f
EZ
2785#ifndef HAVE_X_WINDOWS
2786 if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
2787 {
2788 /* Move the menu away of the echo area, to avoid overwriting the
2789 menu with help echo messages or vice versa. */
2790 if (BUFFERP (echo_area_buffer[0]) && WINDOWP (echo_area_window))
2791 {
2792 y -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2793 uly -= WINDOW_TOTAL_LINES (XWINDOW (echo_area_window));
2794 }
2795 else
2796 {
2797 y--;
2798 uly--;
2799 }
2800 }
2801#endif
78589e07
RS
2802 if (ulx < 0) x -= ulx;
2803 if (uly < 0) y -= uly;
121e4555 2804
453a4f1b
JD
2805 if (! for_click)
2806 {
2807 /* If position was not given by a mouse click, adjust so upper left
2808 corner of the menu as a whole ends up at given coordinates. This
2809 is what x-popup-menu says in its documentation. */
2810 x += width/2;
2811 y += 1.5*height/(maxlines+2);
2812 }
2813
121e4555 2814 XMenuSetAEQ (menu, TRUE);
78589e07
RS
2815 XMenuSetFreeze (menu, TRUE);
2816 pane = selidx = 0;
3e703b25 2817
c3438661
JD
2818#ifndef MSDOS
2819 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
2820#endif
59cfb104 2821
a130b901
JD
2822 record_unwind_protect (pop_down_menu,
2823 Fcons (make_save_value (f, 0),
2824 make_save_value (menu, 0)));
c3438661 2825
3e703b25
GM
2826 /* Help display under X won't work because XMenuActivate contains
2827 a loop that doesn't give Emacs a chance to process it. */
2828 menu_help_frame = f;
92280f67 2829 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
af89e871
JD
2830 x, y, ButtonReleaseMask, &datap,
2831 menu_help_callback);
a352a815 2832
dcfdbac7
JB
2833 switch (status)
2834 {
2835 case XM_SUCCESS:
2836#ifdef XDEBUG
2837 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2838#endif
fa6d54d9 2839
78589e07
RS
2840 /* Find the item number SELIDX in pane number PANE. */
2841 i = 0;
2842 while (i < menu_items_used)
fa6d54d9 2843 {
78589e07 2844 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
088831f6 2845 {
78589e07
RS
2846 if (pane == 0)
2847 pane_prefix
2848 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2849 pane--;
2850 i += MENU_ITEMS_PANE_LENGTH;
088831f6 2851 }
78589e07 2852 else
ab6ee1a0 2853 {
78589e07 2854 if (pane == -1)
ab6ee1a0 2855 {
78589e07 2856 if (selidx == 0)
ab6ee1a0 2857 {
78589e07
RS
2858 entry
2859 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2860 if (keymaps != 0)
ab6ee1a0 2861 {
78589e07
RS
2862 entry = Fcons (entry, Qnil);
2863 if (!NILP (pane_prefix))
2864 entry = Fcons (pane_prefix, entry);
ab6ee1a0 2865 }
78589e07 2866 break;
ab6ee1a0 2867 }
78589e07 2868 selidx--;
ab6ee1a0 2869 }
78589e07 2870 i += MENU_ITEMS_ITEM_LENGTH;
ab6ee1a0
RS
2871 }
2872 }
78589e07 2873 break;
dcfdbac7 2874
78589e07 2875 case XM_FAILURE:
78589e07
RS
2876 *error = "Can't activate menu";
2877 case XM_IA_SELECT:
9f6fcdc5
JD
2878 entry = Qnil;
2879 break;
78589e07 2880 case XM_NO_SELECT:
be6ed24a
RS
2881 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
2882 the menu was invoked with a mouse event as POSITION). */
9f6fcdc5
JD
2883 if (! for_click)
2884 Fsignal (Qquit, Qnil);
78589e07
RS
2885 entry = Qnil;
2886 break;
dcfdbac7 2887 }
a5285df3 2888
af89e871 2889 unbind_to (specpdl_count, Qnil);
a5285df3 2890
78589e07 2891 return entry;
dcfdbac7 2892}
4dedbfe0 2893
78589e07 2894#endif /* not USE_X_TOOLKIT */
1e659e4c
RS
2895
2896#endif /* HAVE_MENUS */
e3135734 2897
b79b8a1c
CY
2898/* Detect if a dialog or menu has been posted. */
2899
2900int
2901popup_activated ()
2902{
2903 return popup_activated_flag;
2904}
e3135734
CY
2905
2906/* The following is used by delayed window autoselection. */
2907
2908DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2909 doc: /* Return t if a menu or popup dialog is active. */)
2910 ()
2911{
2912#ifdef HAVE_MENUS
2913 return (popup_activated ()) ? Qt : Qnil;
2914#else
2915 return Qnil;
2916#endif /* HAVE_MENUS */
2917}
088831f6 2918\f
dfcf069d 2919void
78589e07 2920syms_of_xmenu ()
dcfdbac7 2921{
0314aacb
RS
2922 Qdebug_on_next_call = intern ("debug-on-next-call");
2923 staticpro (&Qdebug_on_next_call);
2924
8ed87156 2925#ifdef USE_X_TOOLKIT
177c0ea7 2926 widget_id_tick = (1<<16);
88766961 2927 next_menubar_widget_id = 1;
8ed87156
RS
2928#endif
2929
78589e07 2930 defsubr (&Sx_popup_menu);
508fb067 2931 defsubr (&Smenu_or_popup_active_p);
22badffe
JD
2932
2933#if defined (USE_GTK) || defined (USE_X_TOOLKIT)
12b6af5c
KL
2934 defsubr (&Sx_menu_bar_open_internal);
2935 Ffset (intern ("accelerate-menu"),
2936 intern (Sx_menu_bar_open_internal.symbol_name));
22badffe
JD
2937#endif
2938
1e659e4c 2939#ifdef HAVE_MENUS
165e1749 2940 defsubr (&Sx_popup_dialog);
1e659e4c 2941#endif
dcfdbac7 2942}
6b61353c
KH
2943
2944/* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242
2945 (do not change this comment) */