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