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