(XTread_socket): Turn off meta, super, hyper and alt bits
[bpt/emacs.git] / src / xmenu.c
CommitLineData
dcfdbac7 1/* X Communication module for terminals which understand the X protocol.
b5b4d636 2 Copyright (C) 1986, 1988, 1993, 1994 Free Software Foundation, Inc.
dcfdbac7
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
774910eb 8the Free Software Foundation; either version 2, or (at your option)
dcfdbac7
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* X pop-up deck-of-cards menu facility for gnuemacs.
21 *
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
24 *
25 */
26
18686d47
RS
27/* Modified by Fred Pierresteguy on December 93
28 to make the popup menus and menubar use the Xt. */
29
78589e07
RS
30/* Rewritten for clarity and GC protection by rms in Feb 94. */
31
dcfdbac7
JB
32/* On 4.3 this loses if it comes after xterm.h. */
33#include <signal.h>
18160b98 34#include <config.h>
565620a5
RS
35
36#include <stdio.h>
dcfdbac7 37#include "lisp.h"
18686d47 38#include "termhooks.h"
7708e9bd 39#include "frame.h"
dcfdbac7 40#include "window.h"
031b0e31 41#include "keyboard.h"
9ac0d9e0 42#include "blockinput.h"
62010a73 43#include "puresize.h"
dcfdbac7 44
eeee3112
RS
45#ifdef MSDOS
46#include "msdos.h"
47#endif
48
87485d6f 49#ifdef HAVE_X_WINDOWS
dcfdbac7
JB
50/* This may include sys/types.h, and that somehow loses
51 if this is not done before the other system files. */
52#include "xterm.h"
87485d6f 53#endif
dcfdbac7
JB
54
55/* Load sys/types.h if not already loaded.
56 In some systems loading it twice is suicidal. */
57#ifndef makedev
58#include <sys/types.h>
59#endif
60
61#include "dispextern.h"
62
87485d6f 63#ifdef HAVE_X_WINDOWS
18686d47
RS
64#ifdef USE_X_TOOLKIT
65#include <X11/Xlib.h>
66#include <X11/IntrinsicP.h>
67#include <X11/CoreP.h>
68#include <X11/StringDefs.h>
60f312e2 69#include <X11/Shell.h>
1d1c1567 70#include <X11/Xaw/Paned.h>
18686d47 71#include "../lwlib/lwlib.h"
a352a815
RS
72#else /* not USE_X_TOOLKIT */
73#include "../oldXMenu/XMenu.h"
74#endif /* not USE_X_TOOLKIT */
75#endif /* HAVE_X_WINDOWS */
18686d47 76
dcfdbac7
JB
77#define min(x,y) (((x) < (y)) ? (x) : (y))
78#define max(x,y) (((x) > (y)) ? (x) : (y))
79
dcfdbac7
JB
80#ifndef TRUE
81#define TRUE 1
82#define FALSE 0
78589e07 83#endif /* no TRUE */
dcfdbac7 84
6904bdcd 85extern Lisp_Object Qmenu_enable;
18686d47 86extern Lisp_Object Qmenu_bar;
92280f67 87extern Lisp_Object Qmouse_click, Qevent_kind;
78589e07 88
8fbc986d
RS
89extern Lisp_Object Vdefine_key_rebound_commands;
90
18686d47 91#ifdef USE_X_TOOLKIT
78589e07
RS
92extern void process_expose_from_menu ();
93extern XtAppContext Xt_app_con;
94
165e1749 95static Lisp_Object xdialog_show ();
4dedbfe0 96void popup_get_selection ();
18686d47
RS
97#endif
98
78589e07
RS
99static Lisp_Object xmenu_show ();
100static void keymap_panes ();
101static void single_keymap_panes ();
102static void list_of_panes ();
103static void list_of_items ();
104\f
105/* This holds a Lisp vector that holds the results of decoding
106 the keymaps or alist-of-alists that specify a menu.
dcfdbac7 107
78589e07 108 It describes the panes and items within the panes.
dcfdbac7 109
78589e07
RS
110 Each pane is described by 3 elements in the vector:
111 t, the pane name, the pane's prefix key.
a352a815 112 Then follow the pane's items, with 5 elements per item:
78589e07 113 the item string, the enable flag, the item's value,
a352a815 114 the definition, and the equivalent keyboard key's description string.
dcfdbac7 115
101bb4a5
RS
116 In some cases, multiple levels of menus may be described.
117 A single vector slot containing nil indicates the start of a submenu.
118 A single vector slot containing lambda indicates the end of a submenu.
119 The submenu follows a menu item which is the way to reach the submenu.
120
fcaa7665
RS
121 A single vector slot containing quote indicates that the
122 following items should appear on the right of a dialog box.
123
78589e07
RS
124 Using a Lisp vector to hold this information while we decode it
125 takes care of protecting all the data from GC. */
dcfdbac7 126
78589e07
RS
127#define MENU_ITEMS_PANE_NAME 1
128#define MENU_ITEMS_PANE_PREFIX 2
129#define MENU_ITEMS_PANE_LENGTH 3
088831f6 130
78589e07
RS
131#define MENU_ITEMS_ITEM_NAME 0
132#define MENU_ITEMS_ITEM_ENABLE 1
133#define MENU_ITEMS_ITEM_VALUE 2
134#define MENU_ITEMS_ITEM_EQUIV_KEY 3
a352a815
RS
135#define MENU_ITEMS_ITEM_DEFINITION 4
136#define MENU_ITEMS_ITEM_LENGTH 5
7da99777 137
78589e07 138static Lisp_Object menu_items;
18686d47 139
78589e07
RS
140/* Number of slots currently allocated in menu_items. */
141static int menu_items_allocated;
18686d47 142
78589e07
RS
143/* This is the index in menu_items of the first empty slot. */
144static int menu_items_used;
18686d47 145
101bb4a5
RS
146/* The number of panes currently recorded in menu_items,
147 excluding those within submenus. */
78589e07 148static int menu_items_n_panes;
18686d47 149
101bb4a5
RS
150/* Current depth within submenus. */
151static int menu_items_submenu_depth;
152
4dedbfe0 153/* Flag which when set indicates a dialog or menu has been posted by
c98fcf4b 154 Xt on behalf of one of the widget sets. */
4dedbfe0
PR
155static int popup_activated_flag;
156
bd3a4da2
RS
157/* This holds a Lisp vector
158 which contains frames that have menu bars.
159 Each frame that has a menu bar is found at some index in this vector
160 and the menu bar widget refers to the frame through that index. */
161static Lisp_Object frame_vector;
162\f
163/* Return the index of FRAME in frame_vector.
164 If FRAME isn't in frame_vector yet, put it in,
165 lengthening the vector if necessary. */
166
167static int
168frame_vector_add_frame (f)
169 FRAME_PTR *f;
170{
171 int length = XVECTOR (frame_vector)->size;
172 int i, empty = -1;
173 Lisp_Object new, frame;
174
175 XSETFRAME (frame, f);
176
177 for (i = 0; i < length; i++)
178 {
179 if (EQ (frame, XVECTOR (frame_vector)->contents[i]))
180 return i;
181 if (NILP (XVECTOR (frame_vector)->contents[i]))
182 empty = i;
183 }
184
185 if (empty >= 0)
186 {
187 XVECTOR (frame_vector)->contents[empty] = frame;
188 return empty;
189 }
190
191 new = Fmake_vector (make_number (length * 2), Qnil);
192 bcopy (XVECTOR (frame_vector)->contents,
193 XVECTOR (new)->contents, sizeof (Lisp_Object) * length);
194
8a442858 195 frame_vector = new;
bd3a4da2
RS
196 XVECTOR (frame_vector)->contents[length] = frame;
197 return length;
198}
4dedbfe0 199\f
78589e07
RS
200/* Initialize the menu_items structure if we haven't already done so.
201 Also mark it as currently empty. */
202
203static void
204init_menu_items ()
205{
206 if (NILP (menu_items))
207 {
208 menu_items_allocated = 60;
209 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
18686d47
RS
210 }
211
78589e07
RS
212 menu_items_used = 0;
213 menu_items_n_panes = 0;
101bb4a5 214 menu_items_submenu_depth = 0;
78589e07 215}
18686d47 216
78589e07
RS
217/* Call at the end of generating the data in menu_items.
218 This fills in the number of items in the last pane. */
1658603c 219
78589e07
RS
220static void
221finish_menu_items ()
222{
223}
1658603c 224
78589e07
RS
225/* Call when finished using the data for the current menu
226 in menu_items. */
1658603c 227
78589e07
RS
228static void
229discard_menu_items ()
230{
231 /* Free the structure if it is especially large.
232 Otherwise, hold on to it, to save time. */
233 if (menu_items_allocated > 200)
234 {
235 menu_items = Qnil;
236 menu_items_allocated = 0;
237 }
238}
1658603c 239
101bb4a5
RS
240/* Make the menu_items vector twice as large. */
241
242static void
243grow_menu_items ()
244{
245 Lisp_Object old;
246 int old_size = menu_items_allocated;
247 old = menu_items;
248
249 menu_items_allocated *= 2;
250 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
251 bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
252 old_size * sizeof (Lisp_Object));
253}
254
255/* Begin a submenu. */
256
257static void
258push_submenu_start ()
259{
260 if (menu_items_used + 1 > menu_items_allocated)
261 grow_menu_items ();
262
263 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
264 menu_items_submenu_depth++;
265}
266
267/* End a submenu. */
268
269static void
270push_submenu_end ()
271{
272 if (menu_items_used + 1 > menu_items_allocated)
273 grow_menu_items ();
274
275 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
276 menu_items_submenu_depth--;
277}
278
fcaa7665
RS
279/* Indicate boundary between left and right. */
280
281static void
282push_left_right_boundary ()
283{
284 if (menu_items_used + 1 > menu_items_allocated)
285 grow_menu_items ();
286
287 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
288}
289
78589e07
RS
290/* Start a new menu pane in menu_items..
291 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
1658603c 292
78589e07
RS
293static void
294push_menu_pane (name, prefix_vec)
295 Lisp_Object name, prefix_vec;
296{
297 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
101bb4a5 298 grow_menu_items ();
dcfdbac7 299
101bb4a5
RS
300 if (menu_items_submenu_depth == 0)
301 menu_items_n_panes++;
78589e07
RS
302 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
303 XVECTOR (menu_items)->contents[menu_items_used++] = name;
304 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
305}
dcfdbac7 306
78589e07
RS
307/* Push one menu item into the current pane.
308 NAME is the string to display. ENABLE if non-nil means
309 this item can be selected. KEY is the key generated by
a352a815
RS
310 choosing this item, or nil if this item doesn't really have a definition.
311 DEF is the definition of this item.
312 EQUIV is the textual description of the keyboard equivalent for
313 this item (or nil if none). */
18686d47 314
78589e07 315static void
a352a815
RS
316push_menu_item (name, enable, key, def, equiv)
317 Lisp_Object name, enable, key, def, equiv;
78589e07
RS
318{
319 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
101bb4a5 320 grow_menu_items ();
088831f6 321
78589e07
RS
322 XVECTOR (menu_items)->contents[menu_items_used++] = name;
323 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
324 XVECTOR (menu_items)->contents[menu_items_used++] = key;
325 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
a352a815 326 XVECTOR (menu_items)->contents[menu_items_used++] = def;
78589e07
RS
327}
328\f
329/* Figure out the current keyboard equivalent of a menu item ITEM1.
330 The item string for menu display should be ITEM_STRING.
331 Store the equivalent keyboard key sequence's
332 textual description into *DESCRIP_PTR.
333 Also cache them in the item itself.
334 Return the real definition to execute. */
088831f6 335
78589e07
RS
336static Lisp_Object
337menu_item_equiv_key (item_string, item1, descrip_ptr)
338 Lisp_Object item_string;
339 Lisp_Object item1;
340 Lisp_Object *descrip_ptr;
341{
342 /* This is the real definition--the function to run. */
343 Lisp_Object def;
344 /* This is the sublist that records cached equiv key data
345 so we can save time. */
346 Lisp_Object cachelist;
347 /* These are the saved equivalent keyboard key sequence
348 and its key-description. */
349 Lisp_Object savedkey, descrip;
350 Lisp_Object def1;
351 int changed = 0;
8c512fcb 352 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
088831f6 353
78589e07
RS
354 /* If a help string follows the item string, skip it. */
355 if (CONSP (XCONS (item1)->cdr)
356 && STRINGP (XCONS (XCONS (item1)->cdr)->car))
357 item1 = XCONS (item1)->cdr;
088831f6 358
78589e07 359 def = Fcdr (item1);
088831f6 360
78589e07
RS
361 /* Get out the saved equivalent-keyboard-key info. */
362 cachelist = savedkey = descrip = Qnil;
363 if (CONSP (def) && CONSP (XCONS (def)->car)
364 && (NILP (XCONS (XCONS (def)->car)->car)
365 || VECTORP (XCONS (XCONS (def)->car)->car)))
088831f6 366 {
78589e07
RS
367 cachelist = XCONS (def)->car;
368 def = XCONS (def)->cdr;
369 savedkey = XCONS (cachelist)->car;
370 descrip = XCONS (cachelist)->cdr;
088831f6 371 }
78589e07 372
8c512fcb
RS
373 GCPRO4 (def, def1, savedkey, descrip);
374
78589e07
RS
375 /* Is it still valid? */
376 def1 = Qnil;
377 if (!NILP (savedkey))
378 def1 = Fkey_binding (savedkey, Qnil);
379 /* If not, update it. */
380 if (! EQ (def1, def)
cc1032b3
RS
381 /* If the command is an alias for another
382 (such as easymenu.el and lmenu.el set it up),
c98fcf4b 383 check if the original command matches the cached command. */
cc1032b3
RS
384 && !(SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
385 && EQ (def1, XSYMBOL (def)->function))
8fbc986d
RS
386 /* If something had no key binding before, don't recheck it
387 because that is too slow--except if we have a list of rebound
388 commands in Vdefine_key_rebound_commands, do recheck any command
389 that appears in that list. */
390 && (NILP (cachelist) || !NILP (savedkey)
391 || (! EQ (Qt, Vdefine_key_rebound_commands)
392 && !NILP (Fmemq (def, Vdefine_key_rebound_commands)))))
088831f6 393 {
78589e07
RS
394 changed = 1;
395 descrip = Qnil;
10bba266
RS
396 /* If the command is an alias for another
397 (such as easymenu.el and lmenu.el set it up),
398 see if the original command name has equivalent keys. */
399 if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function))
400 savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
401 Qnil, Qt, Qnil);
86e00a8a
RS
402 else
403 /* Otherwise look up the specified command itself.
404 We don't try both, because that makes easymenu menus slow. */
405 savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
406
78589e07
RS
407 if (!NILP (savedkey))
408 {
409 descrip = Fkey_description (savedkey);
410 descrip = concat2 (make_string (" (", 3), descrip);
411 descrip = concat2 (descrip, make_string (")", 1));
412 }
dcfdbac7 413 }
18686d47 414
78589e07
RS
415 /* Cache the data we just got in a sublist of the menu binding. */
416 if (NILP (cachelist))
62010a73
RS
417 {
418 CHECK_IMPURE (item1);
419 XCONS (item1)->cdr = Fcons (Fcons (savedkey, descrip), def);
420 }
78589e07 421 else if (changed)
dcfdbac7 422 {
78589e07
RS
423 XCONS (cachelist)->car = savedkey;
424 XCONS (cachelist)->cdr = descrip;
dcfdbac7 425 }
18686d47 426
8c512fcb 427 UNGCPRO;
78589e07
RS
428 *descrip_ptr = descrip;
429 return def;
18686d47
RS
430}
431
78589e07
RS
432/* This is used as the handler when calling internal_condition_case_1. */
433
434static Lisp_Object
435menu_item_enabled_p_1 (arg)
436 Lisp_Object arg;
18686d47 437{
37a98547
RS
438 /* If we got a quit from within the menu computation,
439 quit all the way out of it. This takes care of C-] in the debugger. */
440 if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit))
441 Fsignal (Qquit, Qnil);
442
78589e07 443 return Qnil;
dcfdbac7
JB
444}
445
78589e07 446/* Return non-nil if the command DEF is enabled when used as a menu item.
101bb4a5
RS
447 This is based on looking for a menu-enable property.
448 If NOTREAL is set, don't bother really computing this. */
78589e07
RS
449
450static Lisp_Object
101bb4a5 451menu_item_enabled_p (def, notreal)
78589e07 452 Lisp_Object def;
0f5e911d 453 int notreal;
18686d47 454{
78589e07 455 Lisp_Object enabled, tem;
18686d47 456
78589e07 457 enabled = Qt;
101bb4a5
RS
458 if (notreal)
459 return enabled;
b5bb2705 460 if (SYMBOLP (def))
78589e07
RS
461 {
462 /* No property, or nil, means enable.
463 Otherwise, enable if value is not nil. */
464 tem = Fget (def, Qmenu_enable);
465 if (!NILP (tem))
466 /* (condition-case nil (eval tem)
467 (error nil)) */
468 enabled = internal_condition_case_1 (Feval, tem, Qerror,
469 menu_item_enabled_p_1);
470 }
471 return enabled;
472}
473\f
474/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
101bb4a5
RS
475 and generate menu panes for them in menu_items.
476 If NOTREAL is nonzero,
477 don't bother really computing whether an item is enabled. */
18686d47 478
78589e07 479static void
101bb4a5 480keymap_panes (keymaps, nmaps, notreal)
78589e07
RS
481 Lisp_Object *keymaps;
482 int nmaps;
101bb4a5 483 int notreal;
18686d47 484{
78589e07 485 int mapno;
18686d47 486
78589e07 487 init_menu_items ();
18686d47 488
78589e07
RS
489 /* Loop over the given keymaps, making a pane for each map.
490 But don't make a pane that is empty--ignore that map instead.
491 P is the number of panes we have made so far. */
492 for (mapno = 0; mapno < nmaps; mapno++)
101bb4a5 493 single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal);
78589e07
RS
494
495 finish_menu_items ();
496}
497
498/* This is a recursive subroutine of keymap_panes.
499 It handles one keymap, KEYMAP.
500 The other arguments are passed along
101bb4a5
RS
501 or point to local variables of the previous function.
502 If NOTREAL is nonzero,
503 don't bother really computing whether an item is enabled. */
78589e07
RS
504
505static void
101bb4a5 506single_keymap_panes (keymap, pane_name, prefix, notreal)
78589e07
RS
507 Lisp_Object keymap;
508 Lisp_Object pane_name;
509 Lisp_Object prefix;
101bb4a5 510 int notreal;
78589e07
RS
511{
512 Lisp_Object pending_maps;
513 Lisp_Object tail, item, item1, item_string, table;
514 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
515
516 pending_maps = Qnil;
517
518 push_menu_pane (pane_name, prefix);
519
b5bb2705 520 for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
18686d47 521 {
78589e07
RS
522 /* Look at each key binding, and if it has a menu string,
523 make a menu item from it. */
524 item = XCONS (tail)->car;
b5bb2705 525 if (CONSP (item))
18686d47 526 {
78589e07 527 item1 = XCONS (item)->cdr;
b5bb2705 528 if (CONSP (item1))
78589e07
RS
529 {
530 item_string = XCONS (item1)->car;
b5bb2705 531 if (STRINGP (item_string))
78589e07
RS
532 {
533 /* This is the real definition--the function to run. */
534 Lisp_Object def;
535 /* These are the saved equivalent keyboard key sequence
536 and its key-description. */
537 Lisp_Object descrip;
538 Lisp_Object tem, enabled;
539
8c512fcb
RS
540 /* GCPRO because ...enabled_p will call eval
541 and ..._equiv_key may autoload something.
78589e07
RS
542 Protecting KEYMAP preserves everything we use;
543 aside from that, must protect whatever might be
544 a string. Since there's no GCPRO5, we refetch
545 item_string instead of protecting it. */
8c512fcb 546 descrip = def = Qnil;
78589e07 547 GCPRO4 (keymap, pending_maps, def, descrip);
8c512fcb
RS
548
549 def = menu_item_equiv_key (item_string, item1, &descrip);
101bb4a5
RS
550 enabled = menu_item_enabled_p (def, notreal);
551
78589e07
RS
552 UNGCPRO;
553
554 item_string = XCONS (item1)->car;
555
556 tem = Fkeymapp (def);
557 if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
558 pending_maps = Fcons (Fcons (def, Fcons (item_string, XCONS (item)->car)),
559 pending_maps);
560 else
101bb4a5
RS
561 {
562 Lisp_Object submap;
bc28c440 563 GCPRO4 (keymap, pending_maps, descrip, item_string);
101bb4a5 564 submap = get_keymap_1 (def, 0, 1);
bc28c440 565 UNGCPRO;
101bb4a5
RS
566#ifndef USE_X_TOOLKIT
567 /* Indicate visually that this is a submenu. */
568 if (!NILP (submap))
569 item_string = concat2 (item_string,
570 build_string (" >"));
571#endif
a352a815
RS
572 /* If definition is nil, pass nil as the key. */
573 push_menu_item (item_string, enabled,
574 XCONS (item)->car, def,
101bb4a5
RS
575 descrip);
576#ifdef USE_X_TOOLKIT
577 /* Display a submenu using the toolkit. */
578 if (! NILP (submap))
579 {
580 push_submenu_start ();
581 single_keymap_panes (submap, Qnil,
582 XCONS (item)->car, notreal);
583 push_submenu_end ();
584 }
585#endif
586 }
78589e07
RS
587 }
588 }
589 }
b5bb2705 590 else if (VECTORP (item))
78589e07
RS
591 {
592 /* Loop over the char values represented in the vector. */
593 int len = XVECTOR (item)->size;
594 int c;
595 for (c = 0; c < len; c++)
596 {
597 Lisp_Object character;
33b43fa6 598 XSETFASTINT (character, c);
78589e07 599 item1 = XVECTOR (item)->contents[c];
b5bb2705 600 if (CONSP (item1))
78589e07
RS
601 {
602 item_string = XCONS (item1)->car;
b5bb2705 603 if (STRINGP (item_string))
78589e07
RS
604 {
605 Lisp_Object def;
606
607 /* These are the saved equivalent keyboard key sequence
608 and its key-description. */
609 Lisp_Object descrip;
610 Lisp_Object tem, enabled;
611
8c512fcb
RS
612 /* GCPRO because ...enabled_p will call eval
613 and ..._equiv_key may autoload something.
78589e07
RS
614 Protecting KEYMAP preserves everything we use;
615 aside from that, must protect whatever might be
616 a string. Since there's no GCPRO5, we refetch
617 item_string instead of protecting it. */
618 GCPRO4 (keymap, pending_maps, def, descrip);
8c512fcb
RS
619 descrip = def = Qnil;
620
621 def = menu_item_equiv_key (item_string, item1, &descrip);
101bb4a5 622 enabled = menu_item_enabled_p (def, notreal);
8c512fcb 623
78589e07
RS
624 UNGCPRO;
625
626 item_string = XCONS (item1)->car;
627
628 tem = Fkeymapp (def);
629 if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
630 pending_maps = Fcons (Fcons (def, Fcons (item_string, character)),
631 pending_maps);
632 else
101bb4a5
RS
633 {
634 Lisp_Object submap;
bc28c440 635 GCPRO4 (keymap, pending_maps, descrip, item_string);
101bb4a5 636 submap = get_keymap_1 (def, 0, 1);
bc28c440 637 UNGCPRO;
101bb4a5
RS
638#ifndef USE_X_TOOLKIT
639 if (!NILP (submap))
640 item_string = concat2 (item_string,
641 build_string (" >"));
642#endif
a352a815 643 /* If definition is nil, pass nil as the key. */
101bb4a5 644 push_menu_item (item_string, enabled, character,
a352a815 645 def, descrip);
101bb4a5
RS
646#ifdef USE_X_TOOLKIT
647 if (! NILP (submap))
648 {
649 push_submenu_start ();
650 single_keymap_panes (submap, Qnil,
651 character, notreal);
652 push_submenu_end ();
653 }
654#endif
655 }
78589e07
RS
656 }
657 }
658 }
18686d47
RS
659 }
660 }
78589e07
RS
661
662 /* Process now any submenus which want to be panes at this level. */
663 while (!NILP (pending_maps))
664 {
101bb4a5 665 Lisp_Object elt, eltcdr, string;
78589e07
RS
666 elt = Fcar (pending_maps);
667 eltcdr = XCONS (elt)->cdr;
101bb4a5
RS
668 string = XCONS (eltcdr)->car;
669 /* We no longer discard the @ from the beginning of the string here.
670 Instead, we do this in xmenu_show. */
671 single_keymap_panes (Fcar (elt), string,
672 XCONS (eltcdr)->cdr, notreal);
78589e07
RS
673 pending_maps = Fcdr (pending_maps);
674 }
18686d47 675}
78589e07
RS
676\f
677/* Push all the panes and items of a menu decsribed by the
678 alist-of-alists MENU.
679 This handles old-fashioned calls to x-popup-menu. */
18686d47 680
78589e07
RS
681static void
682list_of_panes (menu)
18686d47 683 Lisp_Object menu;
18686d47 684{
78589e07
RS
685 Lisp_Object tail;
686
687 init_menu_items ();
688
689 for (tail = menu; !NILP (tail); tail = Fcdr (tail))
690 {
691 Lisp_Object elt, pane_name, pane_data;
692 elt = Fcar (tail);
693 pane_name = Fcar (elt);
694 CHECK_STRING (pane_name, 0);
695 push_menu_pane (pane_name, Qnil);
696 pane_data = Fcdr (elt);
697 CHECK_CONS (pane_data, 0);
698 list_of_items (pane_data);
699 }
700
701 finish_menu_items ();
702}
703
704/* Push the items in a single pane defined by the alist PANE. */
705
706static void
707list_of_items (pane)
708 Lisp_Object pane;
709{
710 Lisp_Object tail, item, item1;
711
712 for (tail = pane; !NILP (tail); tail = Fcdr (tail))
713 {
714 item = Fcar (tail);
715 if (STRINGP (item))
a352a815 716 push_menu_item (item, Qnil, Qnil, Qt, Qnil);
fcaa7665
RS
717 else if (NILP (item))
718 push_left_right_boundary ();
78589e07
RS
719 else
720 {
721 CHECK_CONS (item, 0);
722 item1 = Fcar (item);
723 CHECK_STRING (item1, 1);
a352a815 724 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil);
78589e07
RS
725 }
726 }
727}
728\f
540e52d1 729DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
78589e07
RS
730 "Pop up a deck-of-cards menu and return user's selection.\n\
731POSITION is a position specification. This is either a mouse button event\n\
732or a list ((XOFFSET YOFFSET) WINDOW)\n\
748a0e1f 733where XOFFSET and YOFFSET are positions in pixels from the top left\n\
78589e07
RS
734corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
735This controls the position of the center of the first line\n\
736in the first pane of the menu, not the top left of the menu as a whole.\n\
737If POSITION is t, it means to use the current mouse position.\n\
738\n\
739MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
740The menu items come from key bindings that have a menu string as well as\n\
741a definition; actually, the \"definition\" in such a key binding looks like\n\
742\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
743the keymap as a top-level element.\n\n\
744You can also use a list of keymaps as MENU.\n\
745 Then each keymap makes a separate pane.\n\
746When MENU is a keymap or a list of keymaps, the return value\n\
747is a list of events.\n\n\
748Alternatively, you can specify a menu of multiple panes\n\
749 with a list of the form (TITLE PANE1 PANE2...),\n\
750where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
751Each ITEM is normally a cons cell (STRING . VALUE);\n\
752but a string can appear as an item--that makes a nonselectable line\n\
753in the menu.\n\
754With this form of menu, the return value is VALUE from the chosen item.\n\
755\n\
756If POSITION is nil, don't display the menu at all, just precalculate the\n\
757cached information about equivalent key sequences.")
758 (position, menu)
759 Lisp_Object position, menu;
760{
761 int number_of_panes, panes;
18686d47 762 Lisp_Object keymap, tem;
78589e07
RS
763 int xpos, ypos;
764 Lisp_Object title;
765 char *error_name;
766 Lisp_Object selection;
18686d47 767 int i, j;
78589e07
RS
768 FRAME_PTR f;
769 Lisp_Object x, y, window;
770 int keymaps = 0;
9685a93f 771 int for_click = 0;
78589e07
RS
772 struct gcpro gcpro1;
773
78589e07
RS
774 if (! NILP (position))
775 {
101bb4a5
RS
776 check_x ();
777
78589e07 778 /* Decode the first argument: find the window and the coordinates. */
9572375b
KH
779 if (EQ (position, Qt)
780 || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
78589e07
RS
781 {
782 /* Use the mouse's current position. */
ac8f8f7d 783 FRAME_PTR new_f = selected_frame;
78589e07
RS
784 Lisp_Object bar_window;
785 int part;
786 unsigned long time;
787
b137c582 788 if (mouse_position_hook)
46b657e2
RS
789 (*mouse_position_hook) (&new_f, 1, &bar_window,
790 &part, &x, &y, &time);
5ca2ef64 791 if (new_f != 0)
a39f0477 792 XSETFRAME (window, new_f);
5ca2ef64
RS
793 else
794 {
795 window = selected_window;
33b43fa6
KH
796 XSETFASTINT (x, 0);
797 XSETFASTINT (y, 0);
5ca2ef64 798 }
78589e07
RS
799 }
800 else
801 {
802 tem = Fcar (position);
b5bb2705 803 if (CONSP (tem))
78589e07
RS
804 {
805 window = Fcar (Fcdr (position));
806 x = Fcar (tem);
807 y = Fcar (Fcdr (tem));
808 }
809 else
810 {
9685a93f 811 for_click = 1;
78589e07
RS
812 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
813 window = Fcar (tem); /* POSN_WINDOW (tem) */
814 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
815 x = Fcar (tem);
816 y = Fcdr (tem);
78589e07
RS
817 }
818 }
819
820 CHECK_NUMBER (x, 0);
821 CHECK_NUMBER (y, 0);
822
823 /* Decode where to put the menu. */
824
b5bb2705 825 if (FRAMEP (window))
78589e07
RS
826 {
827 f = XFRAME (window);
78589e07
RS
828 xpos = 0;
829 ypos = 0;
830 }
b5bb2705 831 else if (WINDOWP (window))
78589e07
RS
832 {
833 CHECK_LIVE_WINDOW (window, 0);
834 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
835
836 xpos = (FONT_WIDTH (f->display.x->font) * XWINDOW (window)->left);
a8097b6c 837 ypos = (f->display.x->line_height * XWINDOW (window)->top);
78589e07
RS
838 }
839 else
840 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
841 but I don't want to make one now. */
842 CHECK_WINDOW (window, 0);
843
844 xpos += XINT (x);
845 ypos += XINT (y);
846 }
847
848 title = Qnil;
849 GCPRO1 (title);
850
851 /* Decode the menu items from what was specified. */
18686d47
RS
852
853 keymap = Fkeymapp (menu);
854 tem = Qnil;
b5bb2705 855 if (CONSP (menu))
18686d47
RS
856 tem = Fkeymapp (Fcar (menu));
857 if (!NILP (keymap))
858 {
859 /* We were given a keymap. Extract menu info from the keymap. */
860 Lisp_Object prompt;
861 keymap = get_keymap (menu);
862
78589e07 863 /* Extract the detailed info to make one pane. */
101bb4a5 864 keymap_panes (&menu, 1, NILP (position));
78589e07 865
18686d47
RS
866 /* Search for a string appearing directly as an element of the keymap.
867 That string is the title of the menu. */
868 prompt = map_prompt (keymap);
18686d47 869
78589e07
RS
870 /* Make that be the pane title of the first pane. */
871 if (!NILP (prompt) && menu_items_n_panes >= 0)
872 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
873
874 keymaps = 1;
18686d47
RS
875 }
876 else if (!NILP (tem))
877 {
878 /* We were given a list of keymaps. */
18686d47
RS
879 int nmaps = XFASTINT (Flength (menu));
880 Lisp_Object *maps
881 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
882 int i;
78589e07
RS
883
884 title = Qnil;
18686d47
RS
885
886 /* The first keymap that has a prompt string
887 supplies the menu title. */
b5bb2705 888 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem))
18686d47 889 {
78589e07
RS
890 Lisp_Object prompt;
891
18686d47
RS
892 maps[i++] = keymap = get_keymap (Fcar (tem));
893
894 prompt = map_prompt (keymap);
78589e07
RS
895 if (NILP (title) && !NILP (prompt))
896 title = prompt;
18686d47
RS
897 }
898
899 /* Extract the detailed info to make one pane. */
101bb4a5 900 keymap_panes (maps, nmaps, NILP (position));
78589e07
RS
901
902 /* Make the title be the pane title of the first pane. */
903 if (!NILP (title) && menu_items_n_panes >= 0)
904 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
905
906 keymaps = 1;
18686d47
RS
907 }
908 else
909 {
910 /* We were given an old-fashioned menu. */
78589e07
RS
911 title = Fcar (menu);
912 CHECK_STRING (title, 1);
18686d47 913
78589e07 914 list_of_panes (Fcdr (menu));
18686d47 915
78589e07
RS
916 keymaps = 0;
917 }
18686d47 918
78589e07 919 if (NILP (position))
18686d47 920 {
78589e07
RS
921 discard_menu_items ();
922 UNGCPRO;
923 return Qnil;
18686d47
RS
924 }
925
78589e07
RS
926 /* Display them in a menu. */
927 BLOCK_INPUT;
18686d47 928
673a6211 929 selection = xmenu_show (f, xpos, ypos, for_click,
78589e07
RS
930 keymaps, title, &error_name);
931 UNBLOCK_INPUT;
18686d47 932
78589e07 933 discard_menu_items ();
18686d47 934
78589e07 935 UNGCPRO;
18686d47 936
78589e07
RS
937 if (error_name) error (error_name);
938 return selection;
18686d47 939}
165e1749 940
540e52d1 941DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
165e1749 942 "Pop up a dialog box and return user's selection.\n\
99fe880d
RS
943POSITION specifies which frame to use.\n\
944This is normally a mouse button event or a window or frame.\n\
945If POSITION is t, it means to use the frame the mouse is on.\n\
946The dialog box appears in the middle of the specified frame.\n\
165e1749 947\n\
99fe880d
RS
948CONTENTS specifies the alternatives to display in the dialog box.\n\
949It is a list of the form (TITLE ITEM1 ITEM2...).\n\
950Each ITEM is a cons cell (STRING . VALUE).\n\
fcaa7665
RS
951The return value is VALUE from the chosen item.\n\n\
952An ITEM may also be just a string--that makes a nonselectable item.\n\
953An ITEM may also be nil--that means to put all preceding items\n\
954on the left of the dialog box and all following items on the right.\n\
955\(By default, approximately half appear on each side.)")
99fe880d
RS
956 (position, contents)
957 Lisp_Object position, contents;
165e1749 958{
165e1749 959 FRAME_PTR f;
99fe880d 960 Lisp_Object window;
165e1749
FP
961
962 check_x ();
963
99fe880d 964 /* Decode the first argument: find the window or frame to use. */
88d4f6ec
KH
965 if (EQ (position, Qt)
966 || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
165e1749 967 {
b14db4d7 968#if 0 /* Using the frame the mouse is on may not be right. */
99fe880d 969 /* Use the mouse's current position. */
ac8f8f7d 970 FRAME_PTR new_f = selected_frame;
99fe880d
RS
971 Lisp_Object bar_window;
972 int part;
973 unsigned long time;
974 Lisp_Object x, y;
165e1749 975
46b657e2 976 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
5ca2ef64 977
99fe880d 978 if (new_f != 0)
a39f0477 979 XSETFRAME (window, new_f);
99fe880d
RS
980 else
981 window = selected_window;
b14db4d7 982#endif
88d4f6ec 983 window = selected_window;
99fe880d
RS
984 }
985 else if (CONSP (position))
986 {
987 Lisp_Object tem;
988 tem = Fcar (position);
b5bb2705 989 if (CONSP (tem))
99fe880d 990 window = Fcar (Fcdr (position));
80670155
RS
991 else
992 {
99fe880d
RS
993 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
994 window = Fcar (tem); /* POSN_WINDOW (tem) */
165e1749 995 }
165e1749 996 }
99fe880d
RS
997 else if (WINDOWP (position) || FRAMEP (position))
998 window = position;
165e1749 999
99fe880d 1000 /* Decode where to put the menu. */
165e1749 1001
b5bb2705 1002 if (FRAMEP (window))
99fe880d 1003 f = XFRAME (window);
b5bb2705 1004 else if (WINDOWP (window))
165e1749 1005 {
99fe880d
RS
1006 CHECK_LIVE_WINDOW (window, 0);
1007 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
165e1749 1008 }
99fe880d
RS
1009 else
1010 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
1011 but I don't want to make one now. */
1012 CHECK_WINDOW (window, 0);
165e1749 1013
99fe880d
RS
1014#ifndef USE_X_TOOLKIT
1015 /* Display a menu with these alternatives
1016 in the middle of frame F. */
1017 {
1018 Lisp_Object x, y, frame, newpos;
a39f0477
KH
1019 XSETFRAME (frame, f);
1020 XSETINT (x, x_pixel_width (f) / 2);
1021 XSETINT (y, x_pixel_height (f) / 2);
99fe880d
RS
1022 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
1023
1024 return Fx_popup_menu (newpos,
1025 Fcons (Fcar (contents), Fcons (contents, Qnil)));
1026 }
1027#else
1028 {
1029 Lisp_Object title;
1030 char *error_name;
1031 Lisp_Object selection;
165e1749 1032
99fe880d
RS
1033 /* Decode the dialog items from what was specified. */
1034 title = Fcar (contents);
1035 CHECK_STRING (title, 1);
165e1749 1036
99fe880d 1037 list_of_panes (Fcons (contents, Qnil));
165e1749 1038
99fe880d
RS
1039 /* Display them in a dialog box. */
1040 BLOCK_INPUT;
f8c2630d 1041 selection = xdialog_show (f, 0, title, &error_name);
99fe880d 1042 UNBLOCK_INPUT;
165e1749 1043
99fe880d
RS
1044 discard_menu_items ();
1045
1046 if (error_name) error (error_name);
1047 return selection;
1048 }
7464b131 1049#endif
392d3f4b 1050}
78589e07
RS
1051\f
1052#ifdef USE_X_TOOLKIT
18686d47 1053
4dedbfe0 1054/* Loop in Xt until the menu pulldown or dialog popup has been
c98fcf4b
PR
1055 popped down (deactivated).
1056
2e2b8e22 1057 NOTE: All calls to popup_get_selection should be protected
c98fcf4b 1058 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */
aa669def 1059
4dedbfe0 1060void
2e2b8e22 1061popup_get_selection (initial_event, dpyinfo, id)
4dedbfe0 1062 XEvent *initial_event;
aa669def 1063 struct x_display_info *dpyinfo;
2e2b8e22 1064 LWLIB_ID id;
78589e07 1065{
4dedbfe0 1066 XEvent event;
78589e07 1067
aa669def
RS
1068 /* Define a queue to save up for later unreading
1069 all X events that don't pertain to the menu. */
1070 struct event_queue
1071 {
1072 XEvent event;
1073 struct event_queue *next;
1074 };
1075
1076 struct event_queue *queue = NULL;
1077 struct event_queue *queue_tmp;
1078
4dedbfe0
PR
1079 if (initial_event)
1080 event = *initial_event;
1081 else
1082 XtAppNextEvent (Xt_app_con, &event);
78589e07 1083
4dedbfe0 1084 while (1)
78589e07 1085 {
aa669def
RS
1086 /* Handle expose events for editor frames right away. */
1087 if (event.type == Expose)
1088 process_expose_from_menu (event);
1089 /* Make sure we don't consider buttons grabbed after menu goes. */
1090 else if (event.type == ButtonRelease
1091 && dpyinfo->display == event.xbutton.display)
1092 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
2e2b8e22
KH
1093 /* If the user presses a key, deactivate the menu.
1094 The user is likely to do that if we get wedged. */
1095 else if (event.type == KeyPress
1096 && dpyinfo->display == event.xbutton.display)
1097 {
2e2b8e22
KH
1098 popup_activated_flag = 0;
1099 break;
1100 }
aa669def
RS
1101
1102 /* Queue all events not for this popup,
9572375b
KH
1103 except for Expose, which we've already handled.
1104 Note that the X window is associated with the frame if this
1105 is a menu bar popup, but not if it's a dialog box. So we use
1106 x_non_menubar_window_to_frame, not x_any_window_to_frame. */
aa669def
RS
1107 if (event.type != Expose
1108 && (event.xany.display != dpyinfo->display
9572375b 1109 || x_non_menubar_window_to_frame (dpyinfo, event.xany.window)))
aa669def 1110 {
aa669def
RS
1111 queue_tmp = (struct event_queue *) malloc (sizeof (struct event_queue));
1112
1113 if (queue_tmp != NULL)
1114 {
1115 queue_tmp->event = event;
1116 queue_tmp->next = queue;
1117 queue = queue_tmp;
1118 }
1119 }
9572375b
KH
1120 else
1121 XtDispatchEvent (&event);
aa669def
RS
1122
1123 if (!popup_activated ())
4dedbfe0
PR
1124 break;
1125 XtAppNextEvent (Xt_app_con, &event);
78589e07 1126 }
aa669def
RS
1127
1128 /* Unread any events that we got but did not handle. */
1129 while (queue != NULL)
1130 {
1131 queue_tmp = queue;
1132 XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event);
1133 queue = queue_tmp->next;
1134 free ((char *)queue_tmp);
1135 /* Cause these events to get read as soon as we UNBLOCK_INPUT. */
1136 interrupt_input_pending = 1;
1137 }
78589e07
RS
1138}
1139
c98fcf4b 1140/* Detect if a dialog or menu has been posted. */
aa669def 1141
4dedbfe0
PR
1142int
1143popup_activated ()
1144{
1145 return popup_activated_flag;
1146}
1147
1148
1149/* This callback is invoked when the user selects a menubar cascade
1150 pushbutton, but before the pulldown menu is posted. */
78589e07
RS
1151
1152static void
4dedbfe0 1153popup_activate_callback (widget, id, client_data)
78589e07
RS
1154 Widget widget;
1155 LWLIB_ID id;
1156 XtPointer client_data;
1157{
4dedbfe0 1158 popup_activated_flag = 1;
78589e07
RS
1159}
1160
4dedbfe0
PR
1161/* This callback is called from the menu bar pulldown menu
1162 when the user makes a selection.
1163 Figure out what the user chose
1164 and put the appropriate events into the keyboard buffer. */
1165
78589e07 1166static void
4dedbfe0 1167menubar_selection_callback (widget, id, client_data)
78589e07
RS
1168 Widget widget;
1169 LWLIB_ID id;
1170 XtPointer client_data;
1171{
c63f6952 1172 Lisp_Object prefix, entry;
bd3a4da2 1173 FRAME_PTR f = XFRAME (XVECTOR (frame_vector)->contents[id]);
4dedbfe0
PR
1174 Lisp_Object vector;
1175 Lisp_Object *subprefix_stack;
1176 int submenu_depth = 0;
1177 int i;
1178
1179 if (!f)
1180 return;
1181 subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
1182 vector = f->menu_bar_vector;
1183 prefix = Qnil;
1184 i = 0;
1185 while (i < f->menu_bar_items_used)
1186 {
4dedbfe0
PR
1187 if (EQ (XVECTOR (vector)->contents[i], Qnil))
1188 {
1189 subprefix_stack[submenu_depth++] = prefix;
1190 prefix = entry;
1191 i++;
1192 }
1193 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
1194 {
1195 prefix = subprefix_stack[--submenu_depth];
1196 i++;
1197 }
1198 else if (EQ (XVECTOR (vector)->contents[i], Qt))
1199 {
4cb35c39 1200 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
4dedbfe0
PR
1201 i += MENU_ITEMS_PANE_LENGTH;
1202 }
1203 else
1204 {
4cb35c39 1205 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
01d5e892
RS
1206 /* The EMACS_INT cast avoids a warning. There's no problem
1207 as long as pointers have enough bits to hold small integers. */
1208 if ((int) (EMACS_INT) client_data == i)
4dedbfe0
PR
1209 {
1210 int j;
1211 struct input_event buf;
4cb35c39 1212 Lisp_Object frame;
4dedbfe0 1213
4cb35c39 1214 XSETFRAME (frame, f);
4dedbfe0 1215 buf.kind = menu_bar_event;
9572375b 1216 buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
4dedbfe0
PR
1217 kbd_buffer_store_event (&buf);
1218
1219 for (j = 0; j < submenu_depth; j++)
1220 if (!NILP (subprefix_stack[j]))
1221 {
1222 buf.kind = menu_bar_event;
4cb35c39 1223 buf.frame_or_window = Fcons (frame, subprefix_stack[j]);
4dedbfe0
PR
1224 kbd_buffer_store_event (&buf);
1225 }
1226
1227 if (!NILP (prefix))
1228 {
1229 buf.kind = menu_bar_event;
4cb35c39 1230 buf.frame_or_window = Fcons (frame, prefix);
4dedbfe0
PR
1231 kbd_buffer_store_event (&buf);
1232 }
1233
1234 buf.kind = menu_bar_event;
4cb35c39 1235 buf.frame_or_window = Fcons (frame, entry);
4dedbfe0
PR
1236 kbd_buffer_store_event (&buf);
1237
1238 return;
1239 }
1240 i += MENU_ITEMS_ITEM_LENGTH;
1241 }
1242 }
18686d47
RS
1243}
1244
4dedbfe0 1245/* This callback is invoked when a dialog or menu is finished being
c98fcf4b 1246 used and has been unposted. */
4dedbfe0 1247
165e1749 1248static void
4dedbfe0 1249popup_deactivate_callback (widget, id, client_data)
165e1749
FP
1250 Widget widget;
1251 LWLIB_ID id;
1252 XtPointer client_data;
1253{
4dedbfe0 1254 popup_activated_flag = 0;
165e1749
FP
1255}
1256
4dedbfe0
PR
1257
1258/* This recursively calls free_widget_value on the tree of widgets.
18686d47 1259 It must free all data that was malloc'ed for these widget_values.
78589e07
RS
1260 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1261 must be left alone. */
1262
18686d47
RS
1263void
1264free_menubar_widget_value_tree (wv)
1265 widget_value *wv;
1266{
1267 if (! wv) return;
18686d47
RS
1268
1269 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1270
1271 if (wv->contents && (wv->contents != (widget_value*)1))
1272 {
1273 free_menubar_widget_value_tree (wv->contents);
1274 wv->contents = (widget_value *) 0xDEADBEEF;
1275 }
1276 if (wv->next)
1277 {
1278 free_menubar_widget_value_tree (wv->next);
1279 wv->next = (widget_value *) 0xDEADBEEF;
1280 }
1281 BLOCK_INPUT;
1282 free_widget_value (wv);
1283 UNBLOCK_INPUT;
1284}
4dedbfe0
PR
1285\f
1286/* Return a tree of widget_value structures for a menu bar item
1287 whose event type is ITEM_KEY (with string ITEM_NAME)
1288 and whose contents come from the list of keymaps MAPS. */
1289
1290static widget_value *
1291single_submenu (item_key, item_name, maps)
1292 Lisp_Object item_key, item_name, maps;
1293{
1294 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1295 int i;
1296 int submenu_depth = 0;
1297 Lisp_Object length;
1298 int len;
1299 Lisp_Object *mapvec;
1300 widget_value **submenu_stack;
1301 int mapno;
1302 int previous_items = menu_items_used;
1303
1304 length = Flength (maps);
1305 len = XINT (length);
1306
1307 /* Convert the list MAPS into a vector MAPVEC. */
1308 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1309 for (i = 0; i < len; i++)
1310 {
1311 mapvec[i] = Fcar (maps);
1312 maps = Fcdr (maps);
1313 }
1314
1315 menu_items_n_panes = 0;
1316
1317 /* Loop over the given keymaps, making a pane for each map.
1318 But don't make a pane that is empty--ignore that map instead. */
1319 for (i = 0; i < len; i++)
1320 single_keymap_panes (mapvec[i], item_name, item_key, 0);
1321
1322 /* Create a tree of widget_value objects
1323 representing the panes and their items. */
1324
1325 submenu_stack
1326 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1327 wv = malloc_widget_value ();
1328 wv->name = "menu";
1329 wv->value = 0;
1330 wv->enabled = 1;
1331 first_wv = wv;
1332 save_wv = 0;
1333
1334 /* Loop over all panes and items made during this call
1335 and construct a tree of widget_value objects.
1336 Ignore the panes and items made by previous calls to
1337 single_submenu, even though those are also in menu_items. */
1338 i = previous_items;
1339 while (i < menu_items_used)
1340 {
1341 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1342 {
1343 submenu_stack[submenu_depth++] = save_wv;
1344 save_wv = prev_wv;
1345 prev_wv = 0;
1346 i++;
1347 }
1348 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1349 {
1350 prev_wv = save_wv;
1351 save_wv = submenu_stack[--submenu_depth];
1352 i++;
1353 }
1354 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1355 && submenu_depth != 0)
1356 i += MENU_ITEMS_PANE_LENGTH;
1357 /* Ignore a nil in the item list.
1358 It's meaningful only for dialog boxes. */
1359 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1360 i += 1;
1361 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1362 {
1363 /* Create a new pane. */
1364 Lisp_Object pane_name, prefix;
1365 char *pane_string;
1366 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1367 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1368 pane_string = (NILP (pane_name)
1369 ? "" : (char *) XSTRING (pane_name)->data);
1370 /* If there is just one top-level pane, put all its items directly
1371 under the top-level menu. */
1372 if (menu_items_n_panes == 1)
1373 pane_string = "";
1374
1375 /* If the pane has a meaningful name,
1376 make the pane a top-level menu item
1377 with its items as a submenu beneath it. */
1378 if (strcmp (pane_string, ""))
1379 {
1380 wv = malloc_widget_value ();
1381 if (save_wv)
1382 save_wv->next = wv;
1383 else
1384 first_wv->contents = wv;
1385 wv->name = pane_string;
1386 if (!NILP (prefix))
1387 wv->name++;
1388 wv->value = 0;
1389 wv->enabled = 1;
1390 }
1391 save_wv = wv;
1392 prev_wv = 0;
1393 i += MENU_ITEMS_PANE_LENGTH;
1394 }
1395 else
1396 {
1397 /* Create a new item within current pane. */
a352a815 1398 Lisp_Object item_name, enable, descrip, def;
4dedbfe0
PR
1399 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1400 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1401 descrip
1402 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
a352a815 1403 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
18686d47 1404
4dedbfe0
PR
1405 wv = malloc_widget_value ();
1406 if (prev_wv)
1407 prev_wv->next = wv;
1408 else
1409 save_wv->contents = wv;
1410 wv->name = (char *) XSTRING (item_name)->data;
1411 if (!NILP (descrip))
1412 wv->key = (char *) XSTRING (descrip)->data;
1413 wv->value = 0;
01d5e892
RS
1414 /* The EMACS_INT cast avoids a warning. There's no problem
1415 as long as pointers have enough bits to hold small integers. */
1416 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
4dedbfe0
PR
1417 wv->enabled = !NILP (enable);
1418 prev_wv = wv;
1419
1420 i += MENU_ITEMS_ITEM_LENGTH;
1421 }
1422 }
1423
1424 return first_wv;
1425}
1426\f
cffa74ea
FP
1427extern void EmacsFrameSetCharSize ();
1428
4bcdbab1
KH
1429/* Recompute all the widgets of frame F, when the menu bar
1430 has been changed. */
4dedbfe0 1431
18686d47 1432static void
6af6cbb5 1433update_frame_menubar (f)
18686d47
RS
1434 FRAME_PTR f;
1435{
1436 struct x_display *x = f->display.x;
cffa74ea 1437 int columns, rows;
18686d47
RS
1438 int menubar_changed;
1439
4dedbfe0
PR
1440 Dimension shell_height;
1441
1442 /* We assume the menubar contents has changed if the global flag is set,
1443 or if the current buffer has changed, or if the menubar has never
1444 been updated before.
1445 */
18686d47
RS
1446 menubar_changed = (x->menubar_widget
1447 && !XtIsManaged (x->menubar_widget));
1448
1449 if (! (menubar_changed))
1450 return;
1451
1452 BLOCK_INPUT;
cffa74ea
FP
1453 /* Save the size of the frame because the pane widget doesn't accept to
1454 resize itself. So force it. */
1455 columns = f->width;
1456 rows = f->height;
1457
4dedbfe0
PR
1458 /* Do the voodoo which means "I'm changing lots of things, don't try to
1459 refigure sizes until I'm done." */
1460 lw_refigure_widget (x->column_widget, False);
cffa74ea 1461
18686d47
RS
1462 /* the order in which children are managed is the top to
1463 bottom order in which they are displayed in the paned window.
1464 First, remove the text-area widget.
1465 */
1466 XtUnmanageChild (x->edit_widget);
1467
1468 /* remove the menubar that is there now, and put up the menubar that
1469 should be there.
1470 */
1471 if (menubar_changed)
1472 {
1473 XtManageChild (x->menubar_widget);
1474 XtMapWidget (x->menubar_widget);
1475 XtVaSetValues (x->menubar_widget, XtNmappedWhenManaged, 1, 0);
1476 }
1477
c98fcf4b 1478 /* Re-manage the text-area widget, and then thrash the sizes. */
18686d47 1479 XtManageChild (x->edit_widget);
4dedbfe0 1480 lw_refigure_widget (x->column_widget, True);
cffa74ea
FP
1481
1482 /* Force the pane widget to resize itself with the right values. */
1483 EmacsFrameSetCharSize (x->edit_widget, columns, rows);
1484
18686d47
RS
1485 UNBLOCK_INPUT;
1486}
1487
4bcdbab1
KH
1488/* Set the contents of the menubar widgets of frame F.
1489 The argument FIRST_TIME is currently ignored;
1490 it is set the first time this is called, from initialize_frame_menubar. */
1491
18686d47 1492void
706aa2f2 1493set_frame_menubar (f, first_time)
18686d47 1494 FRAME_PTR f;
706aa2f2 1495 int first_time;
18686d47
RS
1496{
1497 Widget menubar_widget = f->display.x->menubar_widget;
bd3a4da2 1498 Lisp_Object tail, items, frame;
4d19cb8e 1499 widget_value *wv, *first_wv, *prev_wv = 0;
5b3557df 1500 int i;
bd3a4da2 1501 int id;
aa669def 1502 int count;
37a98547 1503 int specpdl_count = specpdl_ptr - specpdl;
bd3a4da2 1504
aa669def 1505 count = inhibit_garbage_collection ();
18686d47 1506
37a98547
RS
1507 specbind (Qinhibit_quit, Qt);
1508
aa669def 1509 id = frame_vector_add_frame (f);
18686d47
RS
1510
1511 wv = malloc_widget_value ();
1512 wv->name = "menubar";
1513 wv->value = 0;
1514 wv->enabled = 1;
4d19cb8e 1515 first_wv = wv;
4dedbfe0
PR
1516 items = FRAME_MENU_BAR_ITEMS (f);
1517 menu_items = f->menu_bar_vector;
1518 menu_items_allocated = XVECTOR (menu_items)->size;
1519 init_menu_items ();
18686d47 1520
5b3557df 1521 for (i = 0; i < XVECTOR (items)->size; i += 3)
18686d47 1522 {
4dedbfe0 1523 Lisp_Object key, string, maps;
18686d47 1524
4dedbfe0 1525 key = XVECTOR (items)->contents[i];
5b3557df 1526 string = XVECTOR (items)->contents[i + 1];
4dedbfe0 1527 maps = XVECTOR (items)->contents[i + 2];
5b3557df
RS
1528 if (NILP (string))
1529 break;
18686d47 1530
4dedbfe0 1531 wv = single_submenu (key, string, maps);
18686d47
RS
1532 if (prev_wv)
1533 prev_wv->next = wv;
4d19cb8e
KH
1534 else
1535 first_wv->contents = wv;
1536 /* Don't set wv->name here; GC during the loop might relocate it. */
18686d47
RS
1537 wv->enabled = 1;
1538 prev_wv = wv;
1539 }
1540
4d19cb8e
KH
1541 /* Now GC cannot happen during the lifetime of the widget_value,
1542 so it's safe to store data from a Lisp_String. */
1543 wv = first_wv->contents;
1544 for (i = 0; i < XVECTOR (items)->size; i += 3)
1545 {
1546 Lisp_Object string;
1547 string = XVECTOR (items)->contents[i + 1];
1548 if (NILP (string))
1549 break;
1550 wv->name = (char *) XSTRING (string)->data;
1551 wv = wv->next;
1552 }
1553
4dedbfe0
PR
1554 finish_menu_items ();
1555
1556 f->menu_bar_vector = menu_items;
1557 f->menu_bar_items_used = menu_items_used;
1558 menu_items = Qnil;
1559
aa669def
RS
1560 unbind_to (count, Qnil);
1561
1562 BLOCK_INPUT;
1563
18686d47 1564 if (menubar_widget)
4dedbfe0
PR
1565 {
1566 /* Disable resizing (done for Motif!) */
1567 lw_allow_resizing (f->display.x->widget, False);
1568
1569 /* The third arg is DEEP_P, which says to consider the entire
1570 menu trees we supply, rather than just the menu bar item names. */
cc17e9bf 1571 lw_modify_all_widgets ((LWLIB_ID) id, first_wv, 1);
4dedbfe0 1572
c98fcf4b 1573 /* Re-enable the edit widget to resize. */
4dedbfe0
PR
1574 lw_allow_resizing (f->display.x->widget, True);
1575 }
18686d47
RS
1576 else
1577 {
1578 menubar_widget = lw_create_widget ("menubar", "menubar",
cc17e9bf 1579 (LWLIB_ID) id, first_wv,
4dedbfe0
PR
1580 f->display.x->column_widget,
1581 0,
1582 popup_activate_callback,
1583 menubar_selection_callback,
1584 popup_deactivate_callback);
18686d47 1585 f->display.x->menubar_widget = menubar_widget;
18686d47 1586 }
1d1c1567
KH
1587
1588 {
1589 int menubar_size
1590 = (f->display.x->menubar_widget
1591 ? (f->display.x->menubar_widget->core.height
1592 + f->display.x->menubar_widget->core.border_width)
1593 : 0);
1594
1595 if (FRAME_EXTERNAL_MENU_BAR (f))
1596 {
1597 Dimension ibw = 0;
1598 XtVaGetValues (f->display.x->column_widget,
1599 XtNinternalBorderWidth, &ibw, NULL);
1600 menubar_size += ibw;
1601 }
1602
1603 f->display.x->menubar_height = menubar_size;
1604 }
18686d47
RS
1605
1606 free_menubar_widget_value_tree (first_wv);
1607
4bcdbab1 1608 update_frame_menubar (f);
18686d47 1609
37a98547
RS
1610 unbind_to (specpdl_count, Qnil);
1611
18686d47
RS
1612 UNBLOCK_INPUT;
1613}
85f487d1 1614
4dedbfe0
PR
1615/* Called from Fx_create_frame to create the inital menubar of a frame
1616 before it is mapped, so that the window is mapped with the menubar already
1617 there instead of us tacking it on later and thrashing the window after it
1618 is visible. */
1619
1620void
1621initialize_frame_menubar (f)
1622 FRAME_PTR f;
1623{
1624 /* This function is called before the first chance to redisplay
1625 the frame. It has to be, so the frame will have the right size. */
1626 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1627 set_frame_menubar (f, 1);
1628}
1629
1630/* Get rid of the menu bar of frame F, and free its storage.
1631 This is used when deleting a frame, and when turning off the menu bar. */
1632
85f487d1
FP
1633void
1634free_frame_menubar (f)
1635 FRAME_PTR f;
1636{
1637 Widget menubar_widget;
1638 int id;
1639
1640 menubar_widget = f->display.x->menubar_widget;
85f487d1
FP
1641
1642 if (menubar_widget)
1643 {
bd3a4da2 1644 id = frame_vector_add_frame (f);
85f487d1 1645 BLOCK_INPUT;
cc17e9bf 1646 lw_destroy_all_widgets ((LWLIB_ID) id);
bd3a4da2 1647 XVECTOR (frame_vector)->contents[id] = Qnil;
85f487d1
FP
1648 UNBLOCK_INPUT;
1649 }
1650}
78589e07 1651
78589e07
RS
1652#endif /* USE_X_TOOLKIT */
1653\f
1654/* xmenu_show actually displays a menu using the panes and items in menu_items
1655 and returns the value selected from it.
1656 There are two versions of xmenu_show, one for Xt and one for Xlib.
1657 Both assume input is blocked by the caller. */
1658
1659/* F is the frame the menu is for.
1660 X and Y are the frame-relative specified position,
1661 relative to the inside upper left corner of the frame F.
9685a93f 1662 FOR_CLICK if this menu was invoked for a mouse click.
78589e07
RS
1663 KEYMAPS is 1 if this menu was specified with keymaps;
1664 in that case, we return a list containing the chosen item's value
1665 and perhaps also the pane's prefix.
1666 TITLE is the specified menu title.
1667 ERROR is a place to store an error message string in case of failure.
1668 (We return nil on failure, but the value doesn't actually matter.) */
18686d47
RS
1669
1670#ifdef USE_X_TOOLKIT
18686d47 1671
8ed87156 1672/* We need a unique id for each widget handled by the Lucid Widget
cc17e9bf
KH
1673 library.
1674
1675 For the main windows, and popup menus, we use this counter,
1676 which we increment each time after use.
1677
1678 For menu bars, we use the index of the frame in frame_vector
1679 as the id. */
8ed87156 1680LWLIB_ID widget_id_tick;
165e1749 1681
4dedbfe0
PR
1682#ifdef __STDC__
1683static Lisp_Object *volatile menu_item_selection;
1684#else
1685static Lisp_Object *menu_item_selection;
1686#endif
1687
1688static void
1689popup_selection_callback (widget, id, client_data)
1690 Widget widget;
1691 LWLIB_ID id;
1692 XtPointer client_data;
1693{
1694 menu_item_selection = (Lisp_Object *) client_data;
1695}
1696
78589e07 1697static Lisp_Object
673a6211 1698xmenu_show (f, x, y, for_click, keymaps, title, error)
18686d47 1699 FRAME_PTR f;
18686d47
RS
1700 int x;
1701 int y;
9685a93f 1702 int for_click;
78589e07
RS
1703 int keymaps;
1704 Lisp_Object title;
1705 char **error;
18686d47 1706{
78589e07 1707 int i;
cc17e9bf 1708 LWLIB_ID menu_id;
18686d47 1709 Widget menu;
60f312e2
RS
1710 Arg av [2];
1711 int ac = 0;
78589e07 1712 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
101bb4a5
RS
1713 widget_value **submenu_stack
1714 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1715 Lisp_Object *subprefix_stack
1716 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1717 int submenu_depth = 0;
78589e07 1718
4e8d3549
RS
1719 Position root_x, root_y;
1720
78c8278d 1721 int first_pane;
a51b963c 1722 int next_release_must_exit = 0;
78c8278d 1723
78589e07
RS
1724 *error = NULL;
1725
742f715d
KH
1726 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1727 {
1728 *error = "Empty menu";
1729 return Qnil;
1730 }
63c414df 1731
78589e07
RS
1732 /* Create a tree of widget_value objects
1733 representing the panes and their items. */
1734 wv = malloc_widget_value ();
1735 wv->name = "menu";
1736 wv->value = 0;
1737 wv->enabled = 1;
1738 first_wv = wv;
78c8278d 1739 first_pane = 1;
78589e07
RS
1740
1741 /* Loop over all panes and items, filling in the tree. */
1742 i = 0;
1743 while (i < menu_items_used)
1744 {
101bb4a5
RS
1745 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1746 {
1747 submenu_stack[submenu_depth++] = save_wv;
1748 save_wv = prev_wv;
1749 prev_wv = 0;
78c8278d 1750 first_pane = 1;
101bb4a5
RS
1751 i++;
1752 }
1753 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1754 {
1755 prev_wv = save_wv;
1756 save_wv = submenu_stack[--submenu_depth];
78c8278d 1757 first_pane = 0;
101bb4a5
RS
1758 i++;
1759 }
1760 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1761 && submenu_depth != 0)
1762 i += MENU_ITEMS_PANE_LENGTH;
fcaa7665
RS
1763 /* Ignore a nil in the item list.
1764 It's meaningful only for dialog boxes. */
1765 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1766 i += 1;
101bb4a5 1767 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
78589e07
RS
1768 {
1769 /* Create a new pane. */
1770 Lisp_Object pane_name, prefix;
1771 char *pane_string;
1772 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1773 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1774 pane_string = (NILP (pane_name)
1775 ? "" : (char *) XSTRING (pane_name)->data);
101bb4a5 1776 /* If there is just one top-level pane, put all its items directly
78589e07
RS
1777 under the top-level menu. */
1778 if (menu_items_n_panes == 1)
1779 pane_string = "";
1780
1781 /* If the pane has a meaningful name,
1782 make the pane a top-level menu item
1783 with its items as a submenu beneath it. */
78c8278d 1784 if (!keymaps && strcmp (pane_string, ""))
78589e07
RS
1785 {
1786 wv = malloc_widget_value ();
1787 if (save_wv)
1788 save_wv->next = wv;
1789 else
1790 first_wv->contents = wv;
1791 wv->name = pane_string;
1792 if (keymaps && !NILP (prefix))
1793 wv->name++;
1794 wv->value = 0;
1795 wv->enabled = 1;
78c8278d
RS
1796 save_wv = wv;
1797 prev_wv = 0;
78589e07 1798 }
78c8278d
RS
1799 else if (first_pane)
1800 {
1801 save_wv = wv;
1802 prev_wv = 0;
1803 }
1804 first_pane = 0;
78589e07
RS
1805 i += MENU_ITEMS_PANE_LENGTH;
1806 }
1807 else
1808 {
1809 /* Create a new item within current pane. */
a352a815 1810 Lisp_Object item_name, enable, descrip, def;
78589e07
RS
1811 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1812 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1813 descrip
1814 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
a352a815 1815 def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
78589e07
RS
1816
1817 wv = malloc_widget_value ();
1818 if (prev_wv)
1819 prev_wv->next = wv;
1820 else
1821 save_wv->contents = wv;
4e8d3549 1822 wv->name = (char *) XSTRING (item_name)->data;
78589e07 1823 if (!NILP (descrip))
4e8d3549 1824 wv->key = (char *) XSTRING (descrip)->data;
78589e07 1825 wv->value = 0;
a352a815
RS
1826 /* If this item has a null value,
1827 make the call_data null so that it won't display a box
1828 when the mouse is on it. */
1829 wv->call_data
1830 = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0);
78589e07
RS
1831 wv->enabled = !NILP (enable);
1832 prev_wv = wv;
1833
1834 i += MENU_ITEMS_ITEM_LENGTH;
1835 }
1836 }
1837
c98fcf4b 1838 /* Deal with the title, if it is non-nil. */
4dedbfe0
PR
1839 if (!NILP (title))
1840 {
1841 widget_value *wv_title = malloc_widget_value ();
1842 widget_value *wv_sep1 = malloc_widget_value ();
1843 widget_value *wv_sep2 = malloc_widget_value ();
1844
1845 wv_sep2->name = "--";
1846 wv_sep2->next = first_wv->contents;
1847
1848 wv_sep1->name = "--";
1849 wv_sep1->next = wv_sep2;
1850
1851 wv_title->name = (char *) XSTRING (title)->data;
1852 wv_title->enabled = True;
1853 wv_title->next = wv_sep1;
1854 first_wv->contents = wv_title;
1855 }
1856
78589e07 1857 /* Actually create the menu. */
cc17e9bf 1858 menu_id = widget_id_tick++;
78589e07 1859 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv,
18686d47 1860 f->display.x->widget, 1, 0,
4dedbfe0
PR
1861 popup_selection_callback,
1862 popup_deactivate_callback);
60f312e2
RS
1863
1864 /* Don't allow any geometry request from the user. */
1865 XtSetArg (av[ac], XtNgeometry, 0); ac++;
1866 XtSetValues (menu, av, ac);
1867
78589e07
RS
1868 /* Free the widget_value objects we used to specify the contents. */
1869 free_menubar_widget_value_tree (first_wv);
1870
1871 /* No selection has been chosen yet. */
1872 menu_item_selection = 0;
1873
78589e07 1874 /* Display the menu. */
4dedbfe0
PR
1875 lw_popup_menu (menu);
1876 popup_activated_flag = 1;
18686d47 1877
78589e07 1878 /* Process events that apply to the menu. */
2e2b8e22 1879 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id);
78589e07 1880
a9c90b7c
RS
1881 /* fp turned off the following statement and wrote a comment
1882 that it is unnecessary--that the menu has already disappeared.
21af8a68
KH
1883 Nowadays the menu disappears ok, all right, but
1884 we need to delete the widgets or multiple ones will pile up. */
78589e07 1885 lw_destroy_all_widgets (menu_id);
18686d47 1886
78589e07
RS
1887 /* Find the selected item, and its pane, to return
1888 the proper value. */
1889 if (menu_item_selection != 0)
1890 {
c63f6952 1891 Lisp_Object prefix, entry;
78589e07
RS
1892
1893 prefix = Qnil;
1894 i = 0;
1895 while (i < menu_items_used)
1896 {
101bb4a5
RS
1897 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1898 {
1899 subprefix_stack[submenu_depth++] = prefix;
1900 prefix = entry;
1901 i++;
1902 }
1903 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1904 {
1905 prefix = subprefix_stack[--submenu_depth];
1906 i++;
1907 }
1908 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
78589e07
RS
1909 {
1910 prefix
1911 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1912 i += MENU_ITEMS_PANE_LENGTH;
1913 }
1914 else
1915 {
1916 entry
1917 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1918 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
1919 {
1920 if (keymaps != 0)
1921 {
101bb4a5
RS
1922 int j;
1923
78589e07
RS
1924 entry = Fcons (entry, Qnil);
1925 if (!NILP (prefix))
1926 entry = Fcons (prefix, entry);
101bb4a5 1927 for (j = submenu_depth - 1; j >= 0; j--)
e48087b7 1928 if (!NILP (subprefix_stack[j]))
5964e450 1929 entry = Fcons (subprefix_stack[j], entry);
78589e07
RS
1930 }
1931 return entry;
1932 }
1933 i += MENU_ITEMS_ITEM_LENGTH;
1934 }
1935 }
1936 }
1937
1938 return Qnil;
18686d47 1939}
4dedbfe0
PR
1940\f
1941static void
1942dialog_selection_callback (widget, id, client_data)
1943 Widget widget;
1944 LWLIB_ID id;
1945 XtPointer client_data;
1946{
01d5e892
RS
1947 /* The EMACS_INT cast avoids a warning. There's no problem
1948 as long as pointers have enough bits to hold small integers. */
1949 if ((int) (EMACS_INT) client_data != -1)
4dedbfe0
PR
1950 menu_item_selection = (Lisp_Object *) client_data;
1951 BLOCK_INPUT;
1952 lw_destroy_all_widgets (id);
1953 UNBLOCK_INPUT;
9572375b 1954 popup_activated_flag = 0;
4dedbfe0 1955}
18686d47 1956
165e1749
FP
1957static char * button_names [] = {
1958 "button1", "button2", "button3", "button4", "button5",
1959 "button6", "button7", "button8", "button9", "button10" };
1960
1961static Lisp_Object
673a6211 1962xdialog_show (f, keymaps, title, error)
165e1749 1963 FRAME_PTR f;
165e1749
FP
1964 int keymaps;
1965 Lisp_Object title;
1966 char **error;
1967{
1968 int i, nb_buttons=0;
cc17e9bf 1969 LWLIB_ID dialog_id;
165e1749 1970 Widget menu;
80670155 1971 char dialog_name[6];
165e1749 1972
165e1749
FP
1973 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1974
fcaa7665
RS
1975 /* Number of elements seen so far, before boundary. */
1976 int left_count = 0;
1977 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1978 int boundary_seen = 0;
1979
165e1749
FP
1980 *error = NULL;
1981
80670155
RS
1982 if (menu_items_n_panes > 1)
1983 {
1984 *error = "Multiple panes in dialog box";
1985 return Qnil;
1986 }
1987
165e1749
FP
1988 /* Create a tree of widget_value objects
1989 representing the text label and buttons. */
1990 {
1991 Lisp_Object pane_name, prefix;
1992 char *pane_string;
1993 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
1994 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
1995 pane_string = (NILP (pane_name)
1996 ? "" : (char *) XSTRING (pane_name)->data);
1997 prev_wv = malloc_widget_value ();
1998 prev_wv->value = pane_string;
1999 if (keymaps && !NILP (prefix))
2000 prev_wv->name++;
2001 prev_wv->enabled = 1;
2002 prev_wv->name = "message";
2003 first_wv = prev_wv;
2004
2005 /* Loop over all panes and items, filling in the tree. */
2006 i = MENU_ITEMS_PANE_LENGTH;
2007 while (i < menu_items_used)
2008 {
2009
2010 /* Create a new item within current pane. */
2011 Lisp_Object item_name, enable, descrip;
2012 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2013 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2014 descrip
2015 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2016
80670155
RS
2017 if (NILP (item_name))
2018 {
2019 free_menubar_widget_value_tree (first_wv);
2020 *error = "Submenu in dialog items";
2021 return Qnil;
2022 }
fcaa7665
RS
2023 if (EQ (item_name, Qquote))
2024 {
2025 /* This is the boundary between left-side elts
2026 and right-side elts. Stop incrementing right_count. */
2027 boundary_seen = 1;
2028 i++;
2029 continue;
2030 }
80670155
RS
2031 if (nb_buttons >= 10)
2032 {
2033 free_menubar_widget_value_tree (first_wv);
2034 *error = "Too many dialog items";
2035 return Qnil;
2036 }
2037
165e1749
FP
2038 wv = malloc_widget_value ();
2039 prev_wv->next = wv;
80670155 2040 wv->name = (char *) button_names[nb_buttons];
165e1749 2041 if (!NILP (descrip))
4e8d3549
RS
2042 wv->key = (char *) XSTRING (descrip)->data;
2043 wv->value = (char *) XSTRING (item_name)->data;
165e1749
FP
2044 wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
2045 wv->enabled = !NILP (enable);
2046 prev_wv = wv;
2047
fcaa7665
RS
2048 if (! boundary_seen)
2049 left_count++;
2050
165e1749
FP
2051 nb_buttons++;
2052 i += MENU_ITEMS_ITEM_LENGTH;
2053 }
2054
fcaa7665
RS
2055 /* If the boundary was not specified,
2056 by default put half on the left and half on the right. */
2057 if (! boundary_seen)
2058 left_count = nb_buttons - nb_buttons / 2;
2059
165e1749 2060 wv = malloc_widget_value ();
80670155
RS
2061 wv->name = dialog_name;
2062
2063 /* Dialog boxes use a really stupid name encoding
2064 which specifies how many buttons to use
2065 and how many buttons are on the right.
2066 The Q means something also. */
2067 dialog_name[0] = 'Q';
2068 dialog_name[1] = '0' + nb_buttons;
2069 dialog_name[2] = 'B';
2070 dialog_name[3] = 'R';
fcaa7665
RS
2071 /* Number of buttons to put on the right. */
2072 dialog_name[4] = '0' + nb_buttons - left_count;
80670155 2073 dialog_name[5] = 0;
165e1749
FP
2074 wv->contents = first_wv;
2075 first_wv = wv;
165e1749
FP
2076 }
2077
2078 /* Actually create the dialog. */
cc17e9bf 2079 dialog_id = widget_id_tick++;
165e1749
FP
2080 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
2081 f->display.x->widget, 1, 0,
2082 dialog_selection_callback, 0);
b5587215 2083 lw_modify_all_widgets (dialog_id, first_wv->contents, True);
165e1749
FP
2084 /* Free the widget_value objects we used to specify the contents. */
2085 free_menubar_widget_value_tree (first_wv);
2086
2087 /* No selection has been chosen yet. */
2088 menu_item_selection = 0;
2089
165e1749
FP
2090 /* Display the menu. */
2091 lw_pop_up_all_widgets (dialog_id);
aa669def 2092 popup_activated_flag = 1;
165e1749
FP
2093
2094 /* Process events that apply to the menu. */
2e2b8e22 2095 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
165e1749 2096
21af8a68
KH
2097 lw_destroy_all_widgets (dialog_id);
2098
165e1749
FP
2099 /* Find the selected item, and its pane, to return
2100 the proper value. */
2101 if (menu_item_selection != 0)
2102 {
2103 Lisp_Object prefix;
2104
2105 prefix = Qnil;
2106 i = 0;
2107 while (i < menu_items_used)
2108 {
2109 Lisp_Object entry;
2110
2111 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2112 {
2113 prefix
2114 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2115 i += MENU_ITEMS_PANE_LENGTH;
2116 }
2117 else
2118 {
2119 entry
2120 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2121 if (menu_item_selection == &XVECTOR (menu_items)->contents[i])
2122 {
2123 if (keymaps != 0)
2124 {
2125 entry = Fcons (entry, Qnil);
2126 if (!NILP (prefix))
2127 entry = Fcons (prefix, entry);
2128 }
2129 return entry;
2130 }
2131 i += MENU_ITEMS_ITEM_LENGTH;
2132 }
2133 }
2134 }
2135
2136 return Qnil;
2137}
18686d47 2138#else /* not USE_X_TOOLKIT */
78589e07
RS
2139
2140static Lisp_Object
673a6211 2141xmenu_show (f, x, y, for_click, keymaps, title, error)
78589e07
RS
2142 FRAME_PTR f;
2143 int x, y;
9685a93f
RS
2144 int for_click;
2145 int keymaps;
78589e07
RS
2146 Lisp_Object title;
2147 char **error;
dcfdbac7 2148{
78589e07
RS
2149 Window root;
2150 XMenu *menu;
2151 int pane, selidx, lpane, status;
2152 Lisp_Object entry, pane_prefix;
dcfdbac7
JB
2153 char *datap;
2154 int ulx, uly, width, height;
2155 int dispwidth, dispheight;
4e8d3549
RS
2156 int i, j;
2157 int maxwidth;
78589e07
RS
2158 int dummy_int;
2159 unsigned int dummy_uint;
088831f6 2160
07a675b7 2161 *error = 0;
78589e07
RS
2162 if (menu_items_n_panes == 0)
2163 return Qnil;
088831f6 2164
742f715d
KH
2165 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2166 {
2167 *error = "Empty menu";
2168 return Qnil;
2169 }
2170
78589e07 2171 /* Figure out which root window F is on. */
92280f67 2172 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &root,
78589e07
RS
2173 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
2174 &dummy_uint, &dummy_uint);
18686d47 2175
78589e07 2176 /* Make the menu on that window. */
92280f67 2177 menu = XMenuCreate (FRAME_X_DISPLAY (f), root, "emacs");
78589e07 2178 if (menu == NULL)
dcfdbac7
JB
2179 {
2180 *error = "Can't create menu";
78589e07 2181 return Qnil;
dcfdbac7 2182 }
78589e07 2183
87485d6f 2184#ifdef HAVE_X_WINDOWS
78589e07 2185 /* Adjust coordinates to relative to the outer (window manager) window. */
78589e07
RS
2186 {
2187 Window child;
2188 int win_x = 0, win_y = 0;
2189
2190 /* Find the position of the outside upper-left corner of
2191 the inner window, with respect to the outer window. */
f1847de3 2192 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
78589e07
RS
2193 {
2194 BLOCK_INPUT;
92280f67 2195 XTranslateCoordinates (FRAME_X_DISPLAY (f),
78589e07
RS
2196
2197 /* From-window, to-window. */
2198 f->display.x->window_desc,
2199 f->display.x->parent_desc,
2200
2201 /* From-position, to-position. */
2202 0, 0, &win_x, &win_y,
2203
2204 /* Child of window. */
2205 &child);
2206 UNBLOCK_INPUT;
2207 x += win_x;
2208 y += win_y;
2209 }
2210 }
87485d6f 2211#endif /* HAVE_X_WINDOWS */
78589e07
RS
2212
2213 /* Adjust coordinates to be root-window-relative. */
2214 x += f->display.x->left_pos;
2215 y += f->display.x->top_pos;
18686d47 2216
78589e07
RS
2217 /* Create all the necessary panes and their items. */
2218 i = 0;
2219 while (i < menu_items_used)
dcfdbac7 2220 {
78589e07 2221 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
dcfdbac7 2222 {
78589e07
RS
2223 /* Create a new pane. */
2224 Lisp_Object pane_name, prefix;
2225 char *pane_string;
2226
2227 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
2228 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2229 pane_string = (NILP (pane_name)
2230 ? "" : (char *) XSTRING (pane_name)->data);
2231 if (keymaps && !NILP (prefix))
2232 pane_string++;
2233
92280f67 2234 lpane = XMenuAddPane (FRAME_X_DISPLAY (f), menu, pane_string, TRUE);
78589e07
RS
2235 if (lpane == XM_FAILURE)
2236 {
92280f67 2237 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
78589e07
RS
2238 *error = "Can't create pane";
2239 return Qnil;
2240 }
2241 i += MENU_ITEMS_PANE_LENGTH;
4e8d3549
RS
2242
2243 /* Find the width of the widest item in this pane. */
2244 maxwidth = 0;
2245 j = i;
2246 while (j < menu_items_used)
2247 {
2248 Lisp_Object item;
2249 item = XVECTOR (menu_items)->contents[j];
2250 if (EQ (item, Qt))
2251 break;
2252 if (NILP (item))
2253 {
2254 j++;
2255 continue;
2256 }
2257 width = XSTRING (item)->size;
2258 if (width > maxwidth)
2259 maxwidth = width;
2260
2261 j += MENU_ITEMS_ITEM_LENGTH;
2262 }
dcfdbac7 2263 }
fcaa7665
RS
2264 /* Ignore a nil in the item list.
2265 It's meaningful only for dialog boxes. */
2266 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2267 i += 1;
78589e07 2268 else
dcfdbac7 2269 {
78589e07
RS
2270 /* Create a new item within current pane. */
2271 Lisp_Object item_name, enable, descrip;
4e8d3549 2272 unsigned char *item_data;
78589e07
RS
2273
2274 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
2275 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
2276 descrip
2277 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
2278 if (!NILP (descrip))
4e8d3549
RS
2279 {
2280 int gap = maxwidth - XSTRING (item_name)->size;
2281#ifdef C_ALLOCA
2282 Lisp_Object spacer;
2283 spacer = Fmake_string (make_number (gap), make_number (' '));
2284 item_name = concat2 (item_name, spacer);
2285 item_name = concat2 (item_name, descrip);
2286 item_data = XSTRING (item_name)->data;
2287#else
2288 /* if alloca is fast, use that to make the space,
2289 to reduce gc needs. */
2290 item_data
2291 = (unsigned char *) alloca (maxwidth
2292 + XSTRING (descrip)->size + 1);
2293 bcopy (XSTRING (item_name)->data, item_data,
2294 XSTRING (item_name)->size);
2295 for (j = XSTRING (item_name)->size; j < maxwidth; j++)
2296 item_data[j] = ' ';
2297 bcopy (XSTRING (descrip)->data, item_data + j,
2298 XSTRING (descrip)->size);
2299 item_data[j + XSTRING (descrip)->size] = 0;
2300#endif
2301 }
2302 else
2303 item_data = XSTRING (item_name)->data;
78589e07 2304
92280f67
RS
2305 if (XMenuAddSelection (FRAME_X_DISPLAY (f),
2306 menu, lpane, 0, item_data,
78589e07 2307 !NILP (enable))
dcfdbac7
JB
2308 == XM_FAILURE)
2309 {
92280f67 2310 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
dcfdbac7 2311 *error = "Can't add selection to menu";
78589e07 2312 return Qnil;
dcfdbac7 2313 }
78589e07 2314 i += MENU_ITEMS_ITEM_LENGTH;
dcfdbac7
JB
2315 }
2316 }
4e8d3549 2317
78589e07 2318 /* All set and ready to fly. */
92280f67
RS
2319 XMenuRecompute (FRAME_X_DISPLAY (f), menu);
2320 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f),
f1847de3 2321 XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
92280f67 2322 dispheight = DisplayHeight (FRAME_X_DISPLAY (f),
f1847de3 2323 XScreenNumberOfScreen (FRAME_X_SCREEN (f)));
78589e07
RS
2324 x = min (x, dispwidth);
2325 y = min (y, dispheight);
2326 x = max (x, 1);
2327 y = max (y, 1);
92280f67 2328 XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
dcfdbac7
JB
2329 &ulx, &uly, &width, &height);
2330 if (ulx+width > dispwidth)
2331 {
78589e07 2332 x -= (ulx + width) - dispwidth;
dcfdbac7
JB
2333 ulx = dispwidth - width;
2334 }
2335 if (uly+height > dispheight)
2336 {
78589e07 2337 y -= (uly + height) - dispheight;
dcfdbac7
JB
2338 uly = dispheight - height;
2339 }
78589e07
RS
2340 if (ulx < 0) x -= ulx;
2341 if (uly < 0) y -= uly;
121e4555
KH
2342
2343 XMenuSetAEQ (menu, TRUE);
78589e07
RS
2344 XMenuSetFreeze (menu, TRUE);
2345 pane = selidx = 0;
dcfdbac7 2346
92280f67 2347 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx,
78589e07 2348 x, y, ButtonReleaseMask, &datap);
a352a815
RS
2349
2350
f1df80a8 2351#ifdef HAVE_X_WINDOWS
a352a815
RS
2352 /* Assume the mouse has moved out of the X window.
2353 If it has actually moved in, we will get an EnterNotify. */
29e460bd 2354 x_mouse_leave (FRAME_X_DISPLAY_INFO (f));
f1df80a8 2355#endif
a352a815 2356
dcfdbac7
JB
2357 switch (status)
2358 {
2359 case XM_SUCCESS:
2360#ifdef XDEBUG
2361 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
2362#endif
fa6d54d9 2363
78589e07
RS
2364 /* Find the item number SELIDX in pane number PANE. */
2365 i = 0;
2366 while (i < menu_items_used)
fa6d54d9 2367 {
78589e07 2368 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
088831f6 2369 {
78589e07
RS
2370 if (pane == 0)
2371 pane_prefix
2372 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2373 pane--;
2374 i += MENU_ITEMS_PANE_LENGTH;
088831f6 2375 }
78589e07 2376 else
ab6ee1a0 2377 {
78589e07 2378 if (pane == -1)
ab6ee1a0 2379 {
78589e07 2380 if (selidx == 0)
ab6ee1a0 2381 {
78589e07
RS
2382 entry
2383 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2384 if (keymaps != 0)
ab6ee1a0 2385 {
78589e07
RS
2386 entry = Fcons (entry, Qnil);
2387 if (!NILP (pane_prefix))
2388 entry = Fcons (pane_prefix, entry);
ab6ee1a0 2389 }
78589e07 2390 break;
ab6ee1a0 2391 }
78589e07 2392 selidx--;
ab6ee1a0 2393 }
78589e07 2394 i += MENU_ITEMS_ITEM_LENGTH;
ab6ee1a0
RS
2395 }
2396 }
78589e07 2397 break;
dcfdbac7 2398
78589e07 2399 case XM_FAILURE:
78589e07
RS
2400 *error = "Can't activate menu";
2401 case XM_IA_SELECT:
2402 case XM_NO_SELECT:
2403 entry = Qnil;
2404 break;
dcfdbac7 2405 }
92280f67 2406 XMenuDestroy (FRAME_X_DISPLAY (f), menu);
a5285df3 2407
87485d6f 2408#ifdef HAVE_X_WINDOWS
a5285df3
RS
2409 /* State that no mouse buttons are now held.
2410 (The oldXMenu code doesn't track this info for us.)
2411 That is not necessarily true, but the fiction leads to reasonable
2412 results, and it is a pain to ask which are actually held now. */
e9a79fb2 2413 FRAME_X_DISPLAY_INFO (f)->grabbed = 0;
87485d6f 2414#endif
a5285df3 2415
78589e07 2416 return entry;
dcfdbac7 2417}
4dedbfe0 2418
78589e07 2419#endif /* not USE_X_TOOLKIT */
088831f6 2420\f
78589e07 2421syms_of_xmenu ()
dcfdbac7 2422{
78589e07
RS
2423 staticpro (&menu_items);
2424 menu_items = Qnil;
dcfdbac7 2425
8ed87156 2426#ifdef USE_X_TOOLKIT
4dedbfe0 2427 widget_id_tick = (1<<16);
8ed87156
RS
2428#endif
2429
bd3a4da2
RS
2430 staticpro (&frame_vector);
2431 frame_vector = Fmake_vector (make_number (10), Qnil);
2432
78589e07 2433 defsubr (&Sx_popup_menu);
165e1749 2434 defsubr (&Sx_popup_dialog);
dcfdbac7 2435}