(font_find_for_lface): If registry is NULL, try iso8859-1 and ascii-0.
[bpt/emacs.git] / src / macmenu.c
CommitLineData
4036ffb9 1/* Menu support for GNU Emacs on Mac OS.
9ec0b715
GM
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
1a578e9b
AC
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
1a578e9b 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
1a578e9b
AC
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1a578e9b 19
e0f712ba 20/* Contributed by Andrew Choi (akochoi@mac.com). */
1a578e9b
AC
21
22#include <config.h>
1a578e9b
AC
23
24#include <stdio.h>
4036ffb9 25
1a578e9b 26#include "lisp.h"
80ca7302 27#include "frame.h"
1a578e9b 28#include "termhooks.h"
e0f712ba
AC
29#include "keyboard.h"
30#include "keymap.h"
1a578e9b 31#include "window.h"
1a578e9b
AC
32#include "blockinput.h"
33#include "buffer.h"
34#include "charset.h"
35#include "coding.h"
36
1a578e9b
AC
37/* This may include sys/types.h, and that somehow loses
38 if this is not done before the other system files. */
39#include "macterm.h"
40
41/* Load sys/types.h if not already loaded.
42 In some systems loading it twice is suicidal. */
43#ifndef makedev
44#include <sys/types.h>
45#endif
46
47#include "dispextern.h"
48
28eabd14 49#if TARGET_API_MAC_CARBON
1a578e9b 50#define HAVE_DIALOGS 1
28eabd14 51#endif
1a578e9b
AC
52
53#undef HAVE_MULTILINGUAL_MENU
54
55/******************************************************************/
1a578e9b
AC
56
57/* Assumed by other routines to zero area returned. */
58#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
59 0, (sizeof (widget_value)))
60#define free_widget_value(wv) xfree (wv)
61
62/******************************************************************/
63
1a578e9b
AC
64#ifndef TRUE
65#define TRUE 1
66#define FALSE 0
67#endif /* no TRUE */
177c0ea7 68
1a578e9b
AC
69Lisp_Object Qdebug_on_next_call;
70
0e9ffc04
YM
71extern Lisp_Object Vmenu_updating_frame;
72
4036ffb9 73extern Lisp_Object Qmenu_bar, Qmac_apple_event;
1a578e9b
AC
74
75extern Lisp_Object QCtoggle, QCradio;
76
77extern Lisp_Object Voverriding_local_map;
78extern Lisp_Object Voverriding_local_map_menu_flag;
79
80extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
81
82extern Lisp_Object Qmenu_bar_update_hook;
83
4036ffb9
YM
84void set_frame_menubar P_ ((FRAME_PTR, int, int));
85
383418e5
ST
86#if TARGET_API_MAC_CARBON
87#define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
88#else
89#define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
90#endif
91
1a578e9b
AC
92static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
93 Lisp_Object, Lisp_Object, Lisp_Object,
94 Lisp_Object, Lisp_Object));
e0f712ba 95#ifdef HAVE_DIALOGS
4036ffb9
YM
96static Lisp_Object mac_dialog_show P_ ((FRAME_PTR, int, Lisp_Object,
97 Lisp_Object, char **));
e0f712ba 98#endif
4036ffb9
YM
99static Lisp_Object mac_menu_show P_ ((struct frame *, int, int, int, int,
100 Lisp_Object, char **));
101static void keymap_panes P_ ((Lisp_Object *, int, int));
102static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
103 int, int));
104static void list_of_panes P_ ((Lisp_Object));
105static void list_of_items P_ ((Lisp_Object));
1a578e9b 106
1a578e9b
AC
107\f
108/* This holds a Lisp vector that holds the results of decoding
109 the keymaps or alist-of-alists that specify a menu.
110
111 It describes the panes and items within the panes.
112
113 Each pane is described by 3 elements in the vector:
114 t, the pane name, the pane's prefix key.
115 Then follow the pane's items, with 5 elements per item:
116 the item string, the enable flag, the item's value,
117 the definition, and the equivalent keyboard key's description string.
118
119 In some cases, multiple levels of menus may be described.
120 A single vector slot containing nil indicates the start of a submenu.
121 A single vector slot containing lambda indicates the end of a submenu.
122 The submenu follows a menu item which is the way to reach the submenu.
123
124 A single vector slot containing quote indicates that the
125 following items should appear on the right of a dialog box.
126
127 Using a Lisp vector to hold this information while we decode it
128 takes care of protecting all the data from GC. */
129
130#define MENU_ITEMS_PANE_NAME 1
131#define MENU_ITEMS_PANE_PREFIX 2
132#define MENU_ITEMS_PANE_LENGTH 3
133
134enum menu_item_idx
135{
136 MENU_ITEMS_ITEM_NAME = 0,
137 MENU_ITEMS_ITEM_ENABLE,
138 MENU_ITEMS_ITEM_VALUE,
139 MENU_ITEMS_ITEM_EQUIV_KEY,
140 MENU_ITEMS_ITEM_DEFINITION,
141 MENU_ITEMS_ITEM_TYPE,
142 MENU_ITEMS_ITEM_SELECTED,
143 MENU_ITEMS_ITEM_HELP,
144 MENU_ITEMS_ITEM_LENGTH
145};
146
147static Lisp_Object menu_items;
148
149/* Number of slots currently allocated in menu_items. */
150static int menu_items_allocated;
151
152/* This is the index in menu_items of the first empty slot. */
153static int menu_items_used;
154
155/* The number of panes currently recorded in menu_items,
156 excluding those within submenus. */
157static int menu_items_n_panes;
158
159/* Current depth within submenus. */
160static int menu_items_submenu_depth;
161
a83c3e31 162/* Nonzero means a menu is currently active. */
5aa4098e 163int popup_activated_flag;
a83c3e31 164
1a578e9b
AC
165/* This is set nonzero after the user activates the menu bar, and set
166 to zero again after the menu bars are redisplayed by prepare_menu_bar.
167 While it is nonzero, all calls to set_frame_menubar go deep.
168
169 I don't understand why this is needed, but it does seem to be
170 needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
171
172int pending_menu_activation;
173\f
174/* Initialize the menu_items structure if we haven't already done so.
175 Also mark it as currently empty. */
176
177static void
178init_menu_items ()
179{
180 if (NILP (menu_items))
181 {
182 menu_items_allocated = 60;
183 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
184 }
185
186 menu_items_used = 0;
187 menu_items_n_panes = 0;
188 menu_items_submenu_depth = 0;
189}
190
4036ffb9 191/* Call at the end of generating the data in menu_items. */
1a578e9b
AC
192
193static void
194finish_menu_items ()
195{
196}
197
198/* Call when finished using the data for the current menu
199 in menu_items. */
200
201static void
202discard_menu_items ()
203{
204 /* Free the structure if it is especially large.
205 Otherwise, hold on to it, to save time. */
206 if (menu_items_allocated > 200)
207 {
208 menu_items = Qnil;
209 menu_items_allocated = 0;
210 }
211}
212
f1d7196a
YM
213/* This undoes save_menu_items, and it is called by the specpdl unwind
214 mechanism. */
215
216static Lisp_Object
217restore_menu_items (saved)
218 Lisp_Object saved;
219{
220 menu_items = XCAR (saved);
221 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
222 saved = XCDR (saved);
223 menu_items_used = XINT (XCAR (saved));
224 saved = XCDR (saved);
225 menu_items_n_panes = XINT (XCAR (saved));
74e537fb 226 saved = XCDR (saved);
f1d7196a 227 menu_items_submenu_depth = XINT (XCAR (saved));
0e530e3b 228 return Qnil;
f1d7196a
YM
229}
230
231/* Push the whole state of menu_items processing onto the specpdl.
232 It will be restored when the specpdl is unwound. */
233
234static void
235save_menu_items ()
236{
237 Lisp_Object saved = list4 (menu_items,
238 make_number (menu_items_used),
239 make_number (menu_items_n_panes),
240 make_number (menu_items_submenu_depth));
241 record_unwind_protect (restore_menu_items, saved);
242 menu_items = Qnil;
243}
244\f
1a578e9b
AC
245/* Make the menu_items vector twice as large. */
246
247static void
248grow_menu_items ()
249{
1a578e9b 250 menu_items_allocated *= 2;
71d00ce4 251 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
1a578e9b
AC
252}
253
254/* Begin a submenu. */
255
256static void
257push_submenu_start ()
258{
259 if (menu_items_used + 1 > menu_items_allocated)
260 grow_menu_items ();
261
262 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
263 menu_items_submenu_depth++;
264}
265
266/* End a submenu. */
267
268static void
269push_submenu_end ()
270{
271 if (menu_items_used + 1 > menu_items_allocated)
272 grow_menu_items ();
273
274 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
275 menu_items_submenu_depth--;
276}
277
278/* Indicate boundary between left and right. */
279
280static void
281push_left_right_boundary ()
282{
283 if (menu_items_used + 1 > menu_items_allocated)
284 grow_menu_items ();
285
286 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
287}
288
e0f712ba 289/* Start a new menu pane in menu_items.
1a578e9b
AC
290 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
291
292static void
293push_menu_pane (name, prefix_vec)
294 Lisp_Object name, prefix_vec;
295{
296 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
297 grow_menu_items ();
298
299 if (menu_items_submenu_depth == 0)
300 menu_items_n_panes++;
301 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
302 XVECTOR (menu_items)->contents[menu_items_used++] = name;
303 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
304}
305
306/* Push one menu item into the current pane. NAME is the string to
307 display. ENABLE if non-nil means this item can be selected. KEY
308 is the key generated by choosing this item, or nil if this item
309 doesn't really have a definition. DEF is the definition of this
310 item. EQUIV is the textual description of the keyboard equivalent
311 for this item (or nil if none). TYPE is the type of this menu
312 item, one of nil, `toggle' or `radio'. */
313
314static void
315push_menu_item (name, enable, key, def, equiv, type, selected, help)
316 Lisp_Object name, enable, key, def, equiv, type, selected, help;
317{
318 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
319 grow_menu_items ();
320
321 XVECTOR (menu_items)->contents[menu_items_used++] = name;
322 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
323 XVECTOR (menu_items)->contents[menu_items_used++] = key;
324 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
325 XVECTOR (menu_items)->contents[menu_items_used++] = def;
326 XVECTOR (menu_items)->contents[menu_items_used++] = type;
327 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
328 XVECTOR (menu_items)->contents[menu_items_used++] = help;
329}
330\f
331/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
332 and generate menu panes for them in menu_items.
333 If NOTREAL is nonzero,
334 don't bother really computing whether an item is enabled. */
335
336static void
337keymap_panes (keymaps, nmaps, notreal)
338 Lisp_Object *keymaps;
339 int nmaps;
340 int notreal;
341{
342 int mapno;
343
344 init_menu_items ();
345
346 /* Loop over the given keymaps, making a pane for each map.
347 But don't make a pane that is empty--ignore that map instead.
348 P is the number of panes we have made so far. */
349 for (mapno = 0; mapno < nmaps; mapno++)
e0f712ba 350 single_keymap_panes (keymaps[mapno],
4036ffb9 351 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
1a578e9b
AC
352
353 finish_menu_items ();
354}
355
4036ffb9
YM
356/* Args passed between single_keymap_panes and single_menu_item. */
357struct skp
358 {
359 Lisp_Object pending_maps;
360 int maxdepth, notreal;
361 };
362
363static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
364 void *));
365
1a578e9b
AC
366/* This is a recursive subroutine of keymap_panes.
367 It handles one keymap, KEYMAP.
368 The other arguments are passed along
369 or point to local variables of the previous function.
370 If NOTREAL is nonzero, only check for equivalent key bindings, don't
371 evaluate expressions in menu items and don't make any menu.
372
373 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
374
375static void
376single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
377 Lisp_Object keymap;
378 Lisp_Object pane_name;
379 Lisp_Object prefix;
380 int notreal;
381 int maxdepth;
382{
4036ffb9
YM
383 struct skp skp;
384 struct gcpro gcpro1;
385
386 skp.pending_maps = Qnil;
387 skp.maxdepth = maxdepth;
388 skp.notreal = notreal;
1a578e9b
AC
389
390 if (maxdepth <= 0)
391 return;
392
393 push_menu_pane (pane_name, prefix);
394
4036ffb9
YM
395 GCPRO1 (skp.pending_maps);
396 map_keymap (keymap, single_menu_item, Qnil, &skp, 1);
397 UNGCPRO;
1a578e9b
AC
398
399 /* Process now any submenus which want to be panes at this level. */
4036ffb9 400 while (CONSP (skp.pending_maps))
1a578e9b
AC
401 {
402 Lisp_Object elt, eltcdr, string;
4036ffb9 403 elt = XCAR (skp.pending_maps);
1a578e9b
AC
404 eltcdr = XCDR (elt);
405 string = XCAR (eltcdr);
406 /* We no longer discard the @ from the beginning of the string here.
407 Instead, we do this in mac_menu_show. */
408 single_keymap_panes (Fcar (elt), string,
409 XCDR (eltcdr), notreal, maxdepth - 1);
4036ffb9 410 skp.pending_maps = XCDR (skp.pending_maps);
1a578e9b
AC
411 }
412}
413\f
414/* This is a subroutine of single_keymap_panes that handles one
415 keymap entry.
177c0ea7 416 KEY is a key in a keymap and ITEM is its binding.
4036ffb9 417 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
1a578e9b 418 separate panes.
4036ffb9 419 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
1a578e9b 420 evaluate expressions in menu items and don't make any menu.
4036ffb9 421 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
1a578e9b
AC
422
423static void
4036ffb9
YM
424single_menu_item (key, item, dummy, skp_v)
425 Lisp_Object key, item, dummy;
426 void *skp_v;
1a578e9b
AC
427{
428 Lisp_Object map, item_string, enabled;
429 struct gcpro gcpro1, gcpro2;
430 int res;
4036ffb9 431 struct skp *skp = skp_v;
177c0ea7 432
1a578e9b
AC
433 /* Parse the menu item and leave the result in item_properties. */
434 GCPRO2 (key, item);
4036ffb9 435 res = parse_menu_item (item, skp->notreal, 0);
1a578e9b
AC
436 UNGCPRO;
437 if (!res)
438 return; /* Not a menu item. */
439
440 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
177c0ea7 441
4036ffb9 442 if (skp->notreal)
1a578e9b
AC
443 {
444 /* We don't want to make a menu, just traverse the keymaps to
445 precompute equivalent key bindings. */
446 if (!NILP (map))
4036ffb9 447 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
1a578e9b
AC
448 return;
449 }
450
451 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
177c0ea7 452 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
1a578e9b 453
d5db4077 454 if (!NILP (map) && SREF (item_string, 0) == '@')
1a578e9b
AC
455 {
456 if (!NILP (enabled))
457 /* An enabled separate pane. Remember this to handle it later. */
4036ffb9
YM
458 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
459 skp->pending_maps);
1a578e9b
AC
460 return;
461 }
462
463 push_menu_item (item_string, enabled, key,
464 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
465 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
466 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
4036ffb9
YM
467 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
468 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
1a578e9b
AC
469
470 /* Display a submenu using the toolkit. */
471 if (! (NILP (map) || NILP (enabled)))
472 {
473 push_submenu_start ();
4036ffb9 474 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
1a578e9b
AC
475 push_submenu_end ();
476 }
477}
478\f
479/* Push all the panes and items of a menu described by the
480 alist-of-alists MENU.
481 This handles old-fashioned calls to x-popup-menu. */
482
483static void
484list_of_panes (menu)
485 Lisp_Object menu;
486{
487 Lisp_Object tail;
488
489 init_menu_items ();
490
4036ffb9 491 for (tail = menu; CONSP (tail); tail = XCDR (tail))
1a578e9b
AC
492 {
493 Lisp_Object elt, pane_name, pane_data;
4036ffb9 494 elt = XCAR (tail);
1a578e9b 495 pane_name = Fcar (elt);
e0f712ba 496 CHECK_STRING (pane_name);
4036ffb9 497 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
1a578e9b 498 pane_data = Fcdr (elt);
e0f712ba 499 CHECK_CONS (pane_data);
1a578e9b
AC
500 list_of_items (pane_data);
501 }
502
503 finish_menu_items ();
504}
505
506/* Push the items in a single pane defined by the alist PANE. */
507
508static void
509list_of_items (pane)
510 Lisp_Object pane;
511{
512 Lisp_Object tail, item, item1;
513
4036ffb9 514 for (tail = pane; CONSP (tail); tail = XCDR (tail))
1a578e9b 515 {
4036ffb9 516 item = XCAR (tail);
1a578e9b 517 if (STRINGP (item))
4036ffb9
YM
518 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
519 Qnil, Qnil, Qnil, Qnil);
520 else if (CONSP (item))
1a578e9b 521 {
4036ffb9 522 item1 = XCAR (item);
e0f712ba 523 CHECK_STRING (item1);
4036ffb9
YM
524 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
525 Qt, Qnil, Qnil, Qnil, Qnil);
1a578e9b 526 }
4036ffb9
YM
527 else
528 push_left_right_boundary ();
529
1a578e9b
AC
530 }
531}
532\f
b8987570
JD
533static Lisp_Object
534cleanup_popup_menu (arg)
535 Lisp_Object arg;
536{
537 discard_menu_items ();
0e530e3b 538 return Qnil;
b8987570
JD
539}
540
1a578e9b 541DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
e0f712ba 542 doc: /* Pop up a deck-of-cards menu and return user's selection.
50971a12
YM
543POSITION is a position specification. This is either a mouse button event
544or a list ((XOFFSET YOFFSET) WINDOW)
545where XOFFSET and YOFFSET are positions in pixels from the top left
546corner of WINDOW. (WINDOW may be a window or a frame object.)
547This controls the position of the top left of the menu as a whole.
548If POSITION is t, it means to use the current mouse position.
e0f712ba
AC
549
550MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
551The menu items come from key bindings that have a menu string as well as
50971a12 552a definition; actually, the "definition" in such a key binding looks like
e0f712ba
AC
553\(STRING . REAL-DEFINITION). To give the menu a title, put a string into
554the keymap as a top-level element.
555
556If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
557Otherwise, REAL-DEFINITION should be a valid key binding definition.
558
50971a12
YM
559You can also use a list of keymaps as MENU.
560 Then each keymap makes a separate pane.
e0f712ba 561
50971a12
YM
562When MENU is a keymap or a list of keymaps, the return value is the
563list of events corresponding to the user's choice. Note that
564`x-popup-menu' does not actually execute the command bound to that
565sequence of events.
566
567Alternatively, you can specify a menu of multiple panes
568 with a list of the form (TITLE PANE1 PANE2...),
569where each pane is a list of form (TITLE ITEM1 ITEM2...).
570Each ITEM is normally a cons cell (STRING . VALUE);
571but a string can appear as an item--that makes a nonselectable line
572in the menu.
e0f712ba
AC
573With this form of menu, the return value is VALUE from the chosen item.
574
575If POSITION is nil, don't display the menu at all, just precalculate the
50971a12
YM
576cached information about equivalent key sequences.
577
578If the user gets rid of the menu without making a valid choice, for
579instance by clicking the mouse away from a valid choice or by typing
580keyboard input, then this normally results in a quit and
581`x-popup-menu' does not return. But if POSITION is a mouse button
582event (indicating that the user invoked the menu with the mouse) then
583no quit occurs and `x-popup-menu' returns nil. */)
584 (position, menu)
1a578e9b
AC
585 Lisp_Object position, menu;
586{
587 Lisp_Object keymap, tem;
e0f712ba 588 int xpos = 0, ypos = 0;
1a578e9b 589 Lisp_Object title;
4036ffb9 590 char *error_name = NULL;
1a578e9b 591 Lisp_Object selection;
e0f712ba 592 FRAME_PTR f = NULL;
1a578e9b
AC
593 Lisp_Object x, y, window;
594 int keymaps = 0;
595 int for_click = 0;
b8987570 596 int specpdl_count = SPECPDL_INDEX ();
4036ffb9 597 struct gcpro gcpro1;
1a578e9b
AC
598
599#ifdef HAVE_MENUS
600 if (! NILP (position))
601 {
602 check_mac ();
603
604 /* Decode the first argument: find the window and the coordinates. */
605 if (EQ (position, Qt)
e0f712ba 606 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
4036ffb9
YM
607 || EQ (XCAR (position), Qtool_bar)
608 || EQ (XCAR (position), Qmac_apple_event))))
1a578e9b
AC
609 {
610 /* Use the mouse's current position. */
611 FRAME_PTR new_f = SELECTED_FRAME ();
612 Lisp_Object bar_window;
613 enum scroll_bar_part part;
614 unsigned long time;
615
80ca7302
DN
616 if (FRAME_TERMINAL (new_f)->mouse_position_hook)
617 (*FRAME_TERMINAL (new_f)->mouse_position_hook) (&new_f, 1, &bar_window,
1a578e9b
AC
618 &part, &x, &y, &time);
619 if (new_f != 0)
620 XSETFRAME (window, new_f);
621 else
622 {
623 window = selected_window;
624 XSETFASTINT (x, 0);
625 XSETFASTINT (y, 0);
626 }
627 }
628 else
629 {
630 tem = Fcar (position);
631 if (CONSP (tem))
632 {
633 window = Fcar (Fcdr (position));
4036ffb9
YM
634 x = XCAR (tem);
635 y = Fcar (XCDR (tem));
1a578e9b
AC
636 }
637 else
638 {
639 for_click = 1;
640 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
641 window = Fcar (tem); /* POSN_WINDOW (tem) */
642 tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
643 x = Fcar (tem);
644 y = Fcdr (tem);
645 }
646 }
647
e0f712ba
AC
648 CHECK_NUMBER (x);
649 CHECK_NUMBER (y);
1a578e9b
AC
650
651 /* Decode where to put the menu. */
652
653 if (FRAMEP (window))
654 {
655 f = XFRAME (window);
656 xpos = 0;
657 ypos = 0;
658 }
659 else if (WINDOWP (window))
660 {
e0f712ba 661 CHECK_LIVE_WINDOW (window);
1a578e9b
AC
662 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
663
90022f5a
KS
664 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
665 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
1a578e9b
AC
666 }
667 else
668 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
669 but I don't want to make one now. */
e0f712ba 670 CHECK_WINDOW (window);
1a578e9b
AC
671
672 xpos += XINT (x);
673 ypos += XINT (y);
674
675 XSETFRAME (Vmenu_updating_frame, f);
676 }
c1d9dffd
JL
677 else
678 Vmenu_updating_frame = Qnil;
1a578e9b
AC
679#endif /* HAVE_MENUS */
680
681 title = Qnil;
682 GCPRO1 (title);
683
684 /* Decode the menu items from what was specified. */
685
e0f712ba
AC
686 keymap = get_keymap (menu, 0, 0);
687 if (CONSP (keymap))
1a578e9b
AC
688 {
689 /* We were given a keymap. Extract menu info from the keymap. */
690 Lisp_Object prompt;
1a578e9b
AC
691
692 /* Extract the detailed info to make one pane. */
693 keymap_panes (&menu, 1, NILP (position));
694
695 /* Search for a string appearing directly as an element of the keymap.
696 That string is the title of the menu. */
0c5b23f8 697 prompt = Fkeymap_prompt (keymap);
1a578e9b
AC
698 if (NILP (title) && !NILP (prompt))
699 title = prompt;
700
701 /* Make that be the pane title of the first pane. */
702 if (!NILP (prompt) && menu_items_n_panes >= 0)
703 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
704
705 keymaps = 1;
706 }
e0f712ba 707 else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
1a578e9b
AC
708 {
709 /* We were given a list of keymaps. */
710 int nmaps = XFASTINT (Flength (menu));
711 Lisp_Object *maps
712 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
713 int i;
714
715 title = Qnil;
716
717 /* The first keymap that has a prompt string
718 supplies the menu title. */
4036ffb9 719 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
1a578e9b
AC
720 {
721 Lisp_Object prompt;
722
4036ffb9 723 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
1a578e9b 724
0c5b23f8 725 prompt = Fkeymap_prompt (keymap);
1a578e9b
AC
726 if (NILP (title) && !NILP (prompt))
727 title = prompt;
728 }
729
730 /* Extract the detailed info to make one pane. */
731 keymap_panes (maps, nmaps, NILP (position));
732
733 /* Make the title be the pane title of the first pane. */
734 if (!NILP (title) && menu_items_n_panes >= 0)
735 XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
736
737 keymaps = 1;
738 }
739 else
740 {
741 /* We were given an old-fashioned menu. */
742 title = Fcar (menu);
e0f712ba 743 CHECK_STRING (title);
1a578e9b
AC
744
745 list_of_panes (Fcdr (menu));
746
747 keymaps = 0;
748 }
177c0ea7 749
1a578e9b
AC
750 if (NILP (position))
751 {
752 discard_menu_items ();
753 UNGCPRO;
754 return Qnil;
755 }
756
757#ifdef HAVE_MENUS
758 /* Display them in a menu. */
b8987570 759 record_unwind_protect (cleanup_popup_menu, Qnil);
1a578e9b
AC
760 BLOCK_INPUT;
761
762 selection = mac_menu_show (f, xpos, ypos, for_click,
763 keymaps, title, &error_name);
764 UNBLOCK_INPUT;
b8987570 765 unbind_to (specpdl_count, Qnil);
1a578e9b
AC
766
767 UNGCPRO;
768#endif /* HAVE_MENUS */
769
770 if (error_name) error (error_name);
771 return selection;
772}
773
774#ifdef HAVE_MENUS
775
16b12668 776DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
e0f712ba
AC
777 doc: /* Pop up a dialog box and return user's selection.
778POSITION specifies which frame to use.
779This is normally a mouse button event or a window or frame.
780If POSITION is t, it means to use the frame the mouse is on.
781The dialog box appears in the middle of the specified frame.
782
783CONTENTS specifies the alternatives to display in the dialog box.
50971a12 784It is a list of the form (DIALOG ITEM1 ITEM2...).
e0f712ba
AC
785Each ITEM is a cons cell (STRING . VALUE).
786The return value is VALUE from the chosen item.
787
788An ITEM may also be just a string--that makes a nonselectable item.
789An ITEM may also be nil--that means to put all preceding items
790on the left of the dialog box and all following items on the right.
3f297536
NR
791\(By default, approximately half appear on each side.)
792
793If HEADER is non-nil, the frame title for the box is "Information",
50971a12
YM
794otherwise it is "Question".
795
796If the user gets rid of the dialog box without making a valid choice,
797for instance using the window manager, then this produces a quit and
798`x-popup-dialog' does not return. */)
799 (position, contents, header)
3f297536 800 Lisp_Object position, contents, header;
1a578e9b 801{
e0f712ba 802 FRAME_PTR f = NULL;
1a578e9b
AC
803 Lisp_Object window;
804
805 check_mac ();
806
807 /* Decode the first argument: find the window or frame to use. */
808 if (EQ (position, Qt)
e0f712ba 809 || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
4036ffb9
YM
810 || EQ (XCAR (position), Qtool_bar)
811 || EQ (XCAR (position), Qmac_apple_event))))
1a578e9b
AC
812 {
813#if 0 /* Using the frame the mouse is on may not be right. */
814 /* Use the mouse's current position. */
815 FRAME_PTR new_f = SELECTED_FRAME ();
816 Lisp_Object bar_window;
e0f712ba 817 enum scroll_bar_part part;
1a578e9b
AC
818 unsigned long time;
819 Lisp_Object x, y;
820
821 (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
822
823 if (new_f != 0)
824 XSETFRAME (window, new_f);
825 else
826 window = selected_window;
827#endif
828 window = selected_window;
829 }
830 else if (CONSP (position))
831 {
832 Lisp_Object tem;
833 tem = Fcar (position);
834 if (CONSP (tem))
835 window = Fcar (Fcdr (position));
836 else
837 {
838 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
839 window = Fcar (tem); /* POSN_WINDOW (tem) */
840 }
841 }
842 else if (WINDOWP (position) || FRAMEP (position))
843 window = position;
844 else
845 window = Qnil;
846
847 /* Decode where to put the menu. */
848
849 if (FRAMEP (window))
850 f = XFRAME (window);
851 else if (WINDOWP (window))
852 {
e0f712ba 853 CHECK_LIVE_WINDOW (window);
1a578e9b
AC
854 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
855 }
856 else
857 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
858 but I don't want to make one now. */
e0f712ba 859 CHECK_WINDOW (window);
1a578e9b
AC
860
861#ifndef HAVE_DIALOGS
862 /* Display a menu with these alternatives
863 in the middle of frame F. */
864 {
865 Lisp_Object x, y, frame, newpos;
866 XSETFRAME (frame, f);
867 XSETINT (x, x_pixel_width (f) / 2);
868 XSETINT (y, x_pixel_height (f) / 2);
869 newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil));
870
871 return Fx_popup_menu (newpos,
872 Fcons (Fcar (contents), Fcons (contents, Qnil)));
873 }
874#else /* HAVE_DIALOGS */
875 {
876 Lisp_Object title;
877 char *error_name;
878 Lisp_Object selection;
4036ffb9 879 int specpdl_count = SPECPDL_INDEX ();
1a578e9b
AC
880
881 /* Decode the dialog items from what was specified. */
882 title = Fcar (contents);
e0f712ba 883 CHECK_STRING (title);
1a578e9b
AC
884
885 list_of_panes (Fcons (contents, Qnil));
886
887 /* Display them in a dialog box. */
4036ffb9 888 record_unwind_protect (cleanup_popup_menu, Qnil);
1a578e9b 889 BLOCK_INPUT;
3f297536 890 selection = mac_dialog_show (f, 0, title, header, &error_name);
1a578e9b 891 UNBLOCK_INPUT;
4036ffb9 892 unbind_to (specpdl_count, Qnil);
1a578e9b
AC
893
894 if (error_name) error (error_name);
895 return selection;
896 }
897#endif /* HAVE_DIALOGS */
898}
899
b0da976d
YM
900/* Find the menu selection and store it in the keyboard buffer.
901 F is the frame the menu is on.
902 MENU_BAR_ITEMS_USED is the length of VECTOR.
903 VECTOR is an array of menu events for the whole menu. */
1a578e9b 904
5aa4098e 905void
b0da976d
YM
906find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
907 FRAME_PTR f;
908 int menu_bar_items_used;
909 Lisp_Object vector;
910 void *client_data;
1a578e9b
AC
911{
912 Lisp_Object prefix, entry;
1a578e9b
AC
913 Lisp_Object *subprefix_stack;
914 int submenu_depth = 0;
915 int i;
916
e0f712ba 917 entry = Qnil;
b0da976d 918 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
1a578e9b
AC
919 prefix = Qnil;
920 i = 0;
b0da976d
YM
921
922 while (i < menu_bar_items_used)
1a578e9b
AC
923 {
924 if (EQ (XVECTOR (vector)->contents[i], Qnil))
925 {
926 subprefix_stack[submenu_depth++] = prefix;
927 prefix = entry;
928 i++;
929 }
930 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
931 {
932 prefix = subprefix_stack[--submenu_depth];
933 i++;
934 }
935 else if (EQ (XVECTOR (vector)->contents[i], Qt))
936 {
937 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
938 i += MENU_ITEMS_PANE_LENGTH;
939 }
940 else
941 {
942 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
e0f712ba
AC
943 /* The EMACS_INT cast avoids a warning. There's no problem
944 as long as pointers have enough bits to hold small integers. */
945 if ((int) (EMACS_INT) client_data == i)
1a578e9b
AC
946 {
947 int j;
948 struct input_event buf;
949 Lisp_Object frame;
f456401b 950 EVENT_INIT (buf);
1a578e9b
AC
951
952 XSETFRAME (frame, f);
953 buf.kind = MENU_BAR_EVENT;
954 buf.frame_or_window = frame;
955 buf.arg = frame;
956 kbd_buffer_store_event (&buf);
957
958 for (j = 0; j < submenu_depth; j++)
959 if (!NILP (subprefix_stack[j]))
960 {
961 buf.kind = MENU_BAR_EVENT;
962 buf.frame_or_window = frame;
963 buf.arg = subprefix_stack[j];
964 kbd_buffer_store_event (&buf);
965 }
966
967 if (!NILP (prefix))
968 {
969 buf.kind = MENU_BAR_EVENT;
970 buf.frame_or_window = frame;
971 buf.arg = prefix;
972 kbd_buffer_store_event (&buf);
973 }
974
975 buf.kind = MENU_BAR_EVENT;
976 buf.frame_or_window = frame;
977 buf.arg = entry;
978 kbd_buffer_store_event (&buf);
979
1a578e9b
AC
980 return;
981 }
982 i += MENU_ITEMS_ITEM_LENGTH;
983 }
984 }
985}
986
987/* Allocate a widget_value, blocking input. */
988
989widget_value *
990xmalloc_widget_value ()
991{
992 widget_value *value;
993
994 BLOCK_INPUT;
995 value = malloc_widget_value ();
996 UNBLOCK_INPUT;
997
998 return value;
999}
1000
1001/* This recursively calls free_widget_value on the tree of widgets.
1002 It must free all data that was malloc'ed for these widget_values.
1003 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1004 must be left alone. */
1005
1006void
1007free_menubar_widget_value_tree (wv)
1008 widget_value *wv;
1009{
1010 if (! wv) return;
1011
1012 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1013
1014 if (wv->contents && (wv->contents != (widget_value*)1))
1015 {
1016 free_menubar_widget_value_tree (wv->contents);
1017 wv->contents = (widget_value *) 0xDEADBEEF;
1018 }
1019 if (wv->next)
1020 {
1021 free_menubar_widget_value_tree (wv->next);
1022 wv->next = (widget_value *) 0xDEADBEEF;
1023 }
1024 BLOCK_INPUT;
1025 free_widget_value (wv);
1026 UNBLOCK_INPUT;
1027}
1028\f
4036ffb9 1029/* Set up data in menu_items for a menu bar item
1a578e9b
AC
1030 whose event type is ITEM_KEY (with string ITEM_NAME)
1031 and whose contents come from the list of keymaps MAPS. */
1032
4036ffb9
YM
1033static int
1034parse_single_submenu (item_key, item_name, maps)
1a578e9b
AC
1035 Lisp_Object item_key, item_name, maps;
1036{
1a578e9b
AC
1037 Lisp_Object length;
1038 int len;
1039 Lisp_Object *mapvec;
4036ffb9 1040 int i;
1a578e9b
AC
1041 int top_level_items = 0;
1042
1043 length = Flength (maps);
1044 len = XINT (length);
1045
1046 /* Convert the list MAPS into a vector MAPVEC. */
1047 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1048 for (i = 0; i < len; i++)
1049 {
1050 mapvec[i] = Fcar (maps);
1051 maps = Fcdr (maps);
1052 }
1053
1a578e9b
AC
1054 /* Loop over the given keymaps, making a pane for each map.
1055 But don't make a pane that is empty--ignore that map instead. */
1056 for (i = 0; i < len; i++)
1057 {
4036ffb9 1058 if (!KEYMAPP (mapvec[i]))
1a578e9b
AC
1059 {
1060 /* Here we have a command at top level in the menu bar
1061 as opposed to a submenu. */
1062 top_level_items = 1;
1063 push_menu_pane (Qnil, Qnil);
1064 push_menu_item (item_name, Qt, item_key, mapvec[i],
4036ffb9 1065 Qnil, Qnil, Qnil, Qnil);
1a578e9b
AC
1066 }
1067 else
4036ffb9
YM
1068 {
1069 Lisp_Object prompt;
1070 prompt = Fkeymap_prompt (mapvec[i]);
1071 single_keymap_panes (mapvec[i],
1072 !NILP (prompt) ? prompt : item_name,
1073 item_key, 0, 10);
1074 }
1a578e9b
AC
1075 }
1076
4036ffb9
YM
1077 return top_level_items;
1078}
1079
1080/* Create a tree of widget_value objects
1081 representing the panes and items
1082 in menu_items starting at index START, up to index END. */
1083
1084static widget_value *
1085digest_single_submenu (start, end, top_level_items)
1086 int start, end, top_level_items;
1087{
1088 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1089 int i;
1090 int submenu_depth = 0;
1091 widget_value **submenu_stack;
f1d7196a 1092 int panes_seen = 0;
1a578e9b
AC
1093
1094 submenu_stack
1095 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1096 wv = xmalloc_widget_value ();
1097 wv->name = "menu";
1098 wv->value = 0;
1099 wv->enabled = 1;
1100 wv->button_type = BUTTON_TYPE_NONE;
e0f712ba 1101 wv->help = Qnil;
1a578e9b
AC
1102 first_wv = wv;
1103 save_wv = 0;
1104 prev_wv = 0;
177c0ea7 1105
4036ffb9
YM
1106 /* Loop over all panes and items made by the preceding call
1107 to parse_single_submenu and construct a tree of widget_value objects.
1108 Ignore the panes and items used by previous calls to
1109 digest_single_submenu, even though those are also in menu_items. */
1110 i = start;
1111 while (i < end)
1a578e9b
AC
1112 {
1113 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1114 {
1115 submenu_stack[submenu_depth++] = save_wv;
1116 save_wv = prev_wv;
1117 prev_wv = 0;
1118 i++;
1119 }
1120 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1121 {
1122 prev_wv = save_wv;
1123 save_wv = submenu_stack[--submenu_depth];
1124 i++;
1125 }
1126 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1127 && submenu_depth != 0)
1128 i += MENU_ITEMS_PANE_LENGTH;
1129 /* Ignore a nil in the item list.
1130 It's meaningful only for dialog boxes. */
1131 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1132 i += 1;
1133 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1134 {
1135 /* Create a new pane. */
1136 Lisp_Object pane_name, prefix;
1137 char *pane_string;
e0f712ba 1138
f1d7196a
YM
1139 panes_seen++;
1140
1a578e9b
AC
1141 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1142 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
e0f712ba 1143
1a578e9b
AC
1144#ifndef HAVE_MULTILINGUAL_MENU
1145 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
e0f712ba 1146 {
4036ffb9 1147 pane_name = ENCODE_MENU_STRING (pane_name);
e0f712ba
AC
1148 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1149 }
1a578e9b
AC
1150#endif
1151 pane_string = (NILP (pane_name)
d5db4077 1152 ? "" : (char *) SDATA (pane_name));
1a578e9b
AC
1153 /* If there is just one top-level pane, put all its items directly
1154 under the top-level menu. */
1155 if (menu_items_n_panes == 1)
1156 pane_string = "";
1157
1158 /* If the pane has a meaningful name,
1159 make the pane a top-level menu item
1160 with its items as a submenu beneath it. */
1161 if (strcmp (pane_string, ""))
1162 {
1163 wv = xmalloc_widget_value ();
1164 if (save_wv)
1165 save_wv->next = wv;
1166 else
1167 first_wv->contents = wv;
16ceacc2
JD
1168 wv->lname = pane_name;
1169 /* Set value to 1 so update_submenu_strings can handle '@' */
1170 wv->value = (char *)1;
1a578e9b
AC
1171 wv->enabled = 1;
1172 wv->button_type = BUTTON_TYPE_NONE;
e0f712ba 1173 wv->help = Qnil;
e188aa29 1174 save_wv = wv;
1a578e9b 1175 }
e188aa29
YM
1176 else
1177 save_wv = first_wv;
1178
1a578e9b
AC
1179 prev_wv = 0;
1180 i += MENU_ITEMS_PANE_LENGTH;
1181 }
1182 else
1183 {
1184 /* Create a new item within current pane. */
1185 Lisp_Object item_name, enable, descrip, def, type, selected;
4036ffb9 1186 Lisp_Object help;
1a578e9b 1187
f1d7196a
YM
1188 /* All items should be contained in panes. */
1189 if (panes_seen == 0)
1190 abort ();
1191
e0f712ba
AC
1192 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1193 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1194 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1195 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1196 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1197 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1198 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1a578e9b
AC
1199
1200#ifndef HAVE_MULTILINGUAL_MENU
4036ffb9 1201 if (STRING_MULTIBYTE (item_name))
e0f712ba 1202 {
383418e5 1203 item_name = ENCODE_MENU_STRING (item_name);
e0f712ba
AC
1204 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1205 }
1206
4036ffb9 1207 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
e0f712ba 1208 {
383418e5 1209 descrip = ENCODE_MENU_STRING (descrip);
e0f712ba
AC
1210 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1211 }
1212#endif /* not HAVE_MULTILINGUAL_MENU */
1a578e9b
AC
1213
1214 wv = xmalloc_widget_value ();
177c0ea7 1215 if (prev_wv)
1a578e9b
AC
1216 prev_wv->next = wv;
1217 else
1218 save_wv->contents = wv;
1219
16ceacc2 1220 wv->lname = item_name;
1a578e9b 1221 if (!NILP (descrip))
16ceacc2 1222 wv->lkey = descrip;
1a578e9b
AC
1223 wv->value = 0;
1224 /* The EMACS_INT cast avoids a warning. There's no problem
1225 as long as pointers have enough bits to hold small integers. */
1226 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
1227 wv->enabled = !NILP (enable);
1228
1229 if (NILP (type))
1230 wv->button_type = BUTTON_TYPE_NONE;
1231 else if (EQ (type, QCradio))
1232 wv->button_type = BUTTON_TYPE_RADIO;
1233 else if (EQ (type, QCtoggle))
1234 wv->button_type = BUTTON_TYPE_TOGGLE;
1235 else
1236 abort ();
1237
1238 wv->selected = !NILP (selected);
4036ffb9 1239 if (! STRINGP (help))
e0f712ba
AC
1240 help = Qnil;
1241
1242 wv->help = help;
1a578e9b
AC
1243
1244 prev_wv = wv;
1245
1246 i += MENU_ITEMS_ITEM_LENGTH;
1247 }
1248 }
1249
1250 /* If we have just one "menu item"
1251 that was originally a button, return it by itself. */
1252 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
1253 {
1254 wv = first_wv->contents;
1255 free_widget_value (first_wv);
1256 return wv;
1257 }
1258
1259 return first_wv;
1260}
4036ffb9 1261
16ceacc2
JD
1262/* Walk through the widget_value tree starting at FIRST_WV and update
1263 the char * pointers from the corresponding lisp values.
1264 We do this after building the whole tree, since GC may happen while the
1265 tree is constructed, and small strings are relocated. So we must wait
1266 until no GC can happen before storing pointers into lisp values. */
1267static void
1268update_submenu_strings (first_wv)
1269 widget_value *first_wv;
1270{
1271 widget_value *wv;
1272
1273 for (wv = first_wv; wv; wv = wv->next)
1274 {
bf06c82f 1275 if (STRINGP (wv->lname))
16ceacc2
JD
1276 {
1277 wv->name = SDATA (wv->lname);
1278
1279 /* Ignore the @ that means "separate pane".
1280 This is a kludge, but this isn't worth more time. */
1281 if (wv->value == (char *)1)
1282 {
1283 if (wv->name[0] == '@')
1284 wv->name++;
1285 wv->value = 0;
1286 }
1287 }
1288
bf06c82f 1289 if (STRINGP (wv->lkey))
16ceacc2
JD
1290 wv->key = SDATA (wv->lkey);
1291
1292 if (wv->contents)
1293 update_submenu_strings (wv->contents);
1294 }
1295}
1296
1a578e9b
AC
1297\f
1298/* Set the contents of the menubar widgets of frame F.
1299 The argument FIRST_TIME is currently ignored;
1300 it is set the first time this is called, from initialize_frame_menubar. */
1301
1302void
1303set_frame_menubar (f, first_time, deep_p)
1304 FRAME_PTR f;
1305 int first_time;
1306 int deep_p;
1307{
1308 int menubar_widget = f->output_data.mac->menubar_widget;
1309 Lisp_Object items;
1310 widget_value *wv, *first_wv, *prev_wv = 0;
4036ffb9
YM
1311 int i, last_i = 0;
1312 int *submenu_start, *submenu_end;
1313 int *submenu_top_level_items, *submenu_n_panes;
1a578e9b
AC
1314
1315 XSETFRAME (Vmenu_updating_frame, f);
1316
b52ee0bd
YM
1317 /* This seems to be unnecessary for Carbon. */
1318#if 0
e0f712ba
AC
1319 if (! menubar_widget)
1320 deep_p = 1;
1321 else if (pending_menu_activation && !deep_p)
1322 deep_p = 1;
b52ee0bd 1323#endif
e0f712ba 1324
e0f712ba
AC
1325 if (deep_p)
1326 {
1327 /* Make a widget-value tree representing the entire menu trees. */
1328
1329 struct buffer *prev = current_buffer;
1330 Lisp_Object buffer;
aed13378 1331 int specpdl_count = SPECPDL_INDEX ();
e0f712ba
AC
1332 int previous_menu_items_used = f->menu_bar_items_used;
1333 Lisp_Object *previous_items
1334 = (Lisp_Object *) alloca (previous_menu_items_used
1335 * sizeof (Lisp_Object));
1336
1337 /* If we are making a new widget, its contents are empty,
1338 do always reinitialize them. */
1339 if (! menubar_widget)
1340 previous_menu_items_used = 0;
1341
1342 buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
1343 specbind (Qinhibit_quit, Qt);
1344 /* Don't let the debugger step into this code
1345 because it is not reentrant. */
1346 specbind (Qdebug_on_next_call, Qnil);
1347
89f2614d 1348 record_unwind_save_match_data ();
e0f712ba
AC
1349 if (NILP (Voverriding_local_map_menu_flag))
1350 {
1351 specbind (Qoverriding_terminal_local_map, Qnil);
1352 specbind (Qoverriding_local_map, Qnil);
1353 }
1a578e9b 1354
e0f712ba 1355 set_buffer_internal_1 (XBUFFER (buffer));
1a578e9b 1356
e0f712ba
AC
1357 /* Run the Lucid hook. */
1358 safe_run_hooks (Qactivate_menubar_hook);
4036ffb9 1359
e0f712ba
AC
1360 /* If it has changed current-menubar from previous value,
1361 really recompute the menubar from the value. */
1362 if (! NILP (Vlucid_menu_bar_dirty_flag))
1363 call0 (Qrecompute_lucid_menubar);
1364 safe_run_hooks (Qmenu_bar_update_hook);
1365 FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
1a578e9b 1366
e0f712ba 1367 items = FRAME_MENU_BAR_ITEMS (f);
1a578e9b 1368
e0f712ba
AC
1369 /* Save the frame's previous menu bar contents data. */
1370 if (previous_menu_items_used)
1371 bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
1372 previous_menu_items_used * sizeof (Lisp_Object));
1a578e9b 1373
4036ffb9
YM
1374 /* Fill in menu_items with the current menu bar contents.
1375 This can evaluate Lisp code. */
f1d7196a
YM
1376 save_menu_items ();
1377
e0f712ba
AC
1378 menu_items = f->menu_bar_vector;
1379 menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
4036ffb9
YM
1380 submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1381 submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
1382 submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
1383 submenu_top_level_items
1384 = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
e0f712ba
AC
1385 init_menu_items ();
1386 for (i = 0; i < XVECTOR (items)->size; i += 4)
1387 {
1388 Lisp_Object key, string, maps;
1389
4036ffb9
YM
1390 last_i = i;
1391
e0f712ba
AC
1392 key = XVECTOR (items)->contents[i];
1393 string = XVECTOR (items)->contents[i + 1];
1394 maps = XVECTOR (items)->contents[i + 2];
1395 if (NILP (string))
1396 break;
1397
4036ffb9
YM
1398 submenu_start[i] = menu_items_used;
1399
1400 menu_items_n_panes = 0;
1401 submenu_top_level_items[i]
1402 = parse_single_submenu (key, string, maps);
1403 submenu_n_panes[i] = menu_items_n_panes;
1404
1405 submenu_end[i] = menu_items_used;
1406 }
1407
1408 finish_menu_items ();
1409
1410 /* Convert menu_items into widget_value trees
1411 to display the menu. This cannot evaluate Lisp code. */
1412
1413 wv = xmalloc_widget_value ();
1414 wv->name = "menubar";
1415 wv->value = 0;
1416 wv->enabled = 1;
1417 wv->button_type = BUTTON_TYPE_NONE;
1418 wv->help = Qnil;
1419 first_wv = wv;
1420
1421 for (i = 0; i < last_i; i += 4)
1422 {
1423 menu_items_n_panes = submenu_n_panes[i];
1424 wv = digest_single_submenu (submenu_start[i], submenu_end[i],
1425 submenu_top_level_items[i]);
177c0ea7 1426 if (prev_wv)
e0f712ba
AC
1427 prev_wv->next = wv;
1428 else
1429 first_wv->contents = wv;
1430 /* Don't set wv->name here; GC during the loop might relocate it. */
1431 wv->enabled = 1;
1432 wv->button_type = BUTTON_TYPE_NONE;
1433 prev_wv = wv;
1434 }
1435
e0f712ba 1436 set_buffer_internal_1 (prev);
e0f712ba
AC
1437
1438 /* If there has been no change in the Lisp-level contents
1439 of the menu bar, skip redisplaying it. Just exit. */
1440
f1d7196a 1441 /* Compare the new menu items with the ones computed last time. */
e0f712ba
AC
1442 for (i = 0; i < previous_menu_items_used; i++)
1443 if (menu_items_used == i
4036ffb9 1444 || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
1a578e9b 1445 break;
e0f712ba
AC
1446 if (i == menu_items_used && i == previous_menu_items_used && i != 0)
1447 {
f1d7196a
YM
1448 /* The menu items have not changed. Don't bother updating
1449 the menus in any form, since it would be a no-op. */
e0f712ba 1450 free_menubar_widget_value_tree (first_wv);
4036ffb9 1451 discard_menu_items ();
f1d7196a 1452 unbind_to (specpdl_count, Qnil);
e0f712ba
AC
1453 return;
1454 }
1a578e9b 1455
f1d7196a
YM
1456 /* The menu items are different, so store them in the frame. */
1457 f->menu_bar_vector = menu_items;
1458 f->menu_bar_items_used = menu_items_used;
1459
1460 /* This calls restore_menu_items to restore menu_items, etc.,
1461 as they were outside. */
1462 unbind_to (specpdl_count, Qnil);
1463
e0f712ba 1464 /* Now GC cannot happen during the lifetime of the widget_value,
4036ffb9 1465 so it's safe to store data from a Lisp_String. */
e0f712ba
AC
1466 wv = first_wv->contents;
1467 for (i = 0; i < XVECTOR (items)->size; i += 4)
1468 {
1469 Lisp_Object string;
1470 string = XVECTOR (items)->contents[i + 1];
1471 if (NILP (string))
1472 break;
d5db4077 1473 wv->name = (char *) SDATA (string);
16ceacc2 1474 update_submenu_strings (wv->contents);
e0f712ba
AC
1475 wv = wv->next;
1476 }
1a578e9b 1477
e0f712ba
AC
1478 }
1479 else
1480 {
1481 /* Make a widget-value tree containing
1482 just the top level menu bar strings. */
1a578e9b 1483
4036ffb9
YM
1484 wv = xmalloc_widget_value ();
1485 wv->name = "menubar";
1486 wv->value = 0;
1487 wv->enabled = 1;
1488 wv->button_type = BUTTON_TYPE_NONE;
1489 wv->help = Qnil;
1490 first_wv = wv;
1491
e0f712ba
AC
1492 items = FRAME_MENU_BAR_ITEMS (f);
1493 for (i = 0; i < XVECTOR (items)->size; i += 4)
1494 {
1495 Lisp_Object string;
1a578e9b 1496
e0f712ba
AC
1497 string = XVECTOR (items)->contents[i + 1];
1498 if (NILP (string))
1499 break;
1a578e9b 1500
e0f712ba 1501 wv = xmalloc_widget_value ();
d5db4077 1502 wv->name = (char *) SDATA (string);
e0f712ba
AC
1503 wv->value = 0;
1504 wv->enabled = 1;
1505 wv->button_type = BUTTON_TYPE_NONE;
1506 wv->help = Qnil;
1507 /* This prevents lwlib from assuming this
1508 menu item is really supposed to be empty. */
1509 /* The EMACS_INT cast avoids a warning.
1510 This value just has to be different from small integers. */
1511 wv->call_data = (void *) (EMACS_INT) (-1);
1a578e9b 1512
177c0ea7 1513 if (prev_wv)
e0f712ba
AC
1514 prev_wv->next = wv;
1515 else
1516 first_wv->contents = wv;
1517 prev_wv = wv;
1518 }
1a578e9b 1519
e0f712ba
AC
1520 /* Forget what we thought we knew about what is in the
1521 detailed contents of the menu bar menus.
1522 Changing the top level always destroys the contents. */
1523 f->menu_bar_items_used = 0;
1524 }
1a578e9b
AC
1525
1526 /* Create or update the menu bar widget. */
1527
1528 BLOCK_INPUT;
1529
e0f712ba
AC
1530 /* Non-null value to indicate menubar has already been "created". */
1531 f->output_data.mac->menubar_widget = 1;
1a578e9b 1532
5aa4098e 1533 mac_fill_menubar (first_wv->contents, deep_p);
177c0ea7 1534
1a578e9b
AC
1535 free_menubar_widget_value_tree (first_wv);
1536
1537 UNBLOCK_INPUT;
1538}
1539
1a578e9b
AC
1540/* Get rid of the menu bar of frame F, and free its storage.
1541 This is used when deleting a frame, and when turning off the menu bar. */
1542
1543void
1544free_frame_menubar (f)
1545 FRAME_PTR f;
1546{
4036ffb9 1547 f->output_data.mac->menubar_widget = 0;
1a578e9b
AC
1548}
1549
1550\f
5aa4098e
YM
1551/* The item selected in the popup menu. */
1552int menu_item_selection;
f5f870c0
JD
1553
1554/* Mac_menu_show actually displays a menu using the panes and items in
1a578e9b
AC
1555 menu_items and returns the value selected from it; we assume input
1556 is blocked by the caller. */
1557
1558/* F is the frame the menu is for.
1559 X and Y are the frame-relative specified position,
1560 relative to the inside upper left corner of the frame F.
1561 FOR_CLICK is nonzero if this menu was invoked for a mouse click.
1562 KEYMAPS is 1 if this menu was specified with keymaps;
1563 in that case, we return a list containing the chosen item's value
1564 and perhaps also the pane's prefix.
1565 TITLE is the specified menu title.
1566 ERROR is a place to store an error message string in case of failure.
1567 (We return nil on failure, but the value doesn't actually matter.) */
1568
1569static Lisp_Object
1570mac_menu_show (f, x, y, for_click, keymaps, title, error)
1571 FRAME_PTR f;
1572 int x;
1573 int y;
1574 int for_click;
1575 int keymaps;
1576 Lisp_Object title;
1577 char **error;
1578{
1579 int i;
1a578e9b
AC
1580 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
1581 widget_value **submenu_stack
1582 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1583 Lisp_Object *subprefix_stack
1584 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
1585 int submenu_depth = 0;
4036ffb9 1586
1a578e9b 1587 int first_pane;
1a578e9b
AC
1588
1589 *error = NULL;
1590
1591 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
1592 {
1593 *error = "Empty menu";
1594 return Qnil;
1595 }
1596
1597 /* Create a tree of widget_value objects
1598 representing the panes and their items. */
1599 wv = xmalloc_widget_value ();
1600 wv->name = "menu";
1601 wv->value = 0;
1602 wv->enabled = 1;
1603 wv->button_type = BUTTON_TYPE_NONE;
e0f712ba 1604 wv->help = Qnil;
1a578e9b
AC
1605 first_wv = wv;
1606 first_pane = 1;
177c0ea7 1607
1a578e9b
AC
1608 /* Loop over all panes and items, filling in the tree. */
1609 i = 0;
1610 while (i < menu_items_used)
1611 {
1612 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1613 {
1614 submenu_stack[submenu_depth++] = save_wv;
1615 save_wv = prev_wv;
1616 prev_wv = 0;
1617 first_pane = 1;
1618 i++;
1619 }
1620 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1621 {
1622 prev_wv = save_wv;
1623 save_wv = submenu_stack[--submenu_depth];
1624 first_pane = 0;
1625 i++;
1626 }
1627 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1628 && submenu_depth != 0)
1629 i += MENU_ITEMS_PANE_LENGTH;
1630 /* Ignore a nil in the item list.
1631 It's meaningful only for dialog boxes. */
1632 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1633 i += 1;
1634 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1635 {
1636 /* Create a new pane. */
1637 Lisp_Object pane_name, prefix;
1638 char *pane_string;
4036ffb9 1639
e0f712ba
AC
1640 pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
1641 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
4036ffb9 1642
1a578e9b
AC
1643#ifndef HAVE_MULTILINGUAL_MENU
1644 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
e0f712ba 1645 {
4036ffb9 1646 pane_name = ENCODE_MENU_STRING (pane_name);
e0f712ba
AC
1647 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
1648 }
1a578e9b
AC
1649#endif
1650 pane_string = (NILP (pane_name)
d5db4077 1651 ? "" : (char *) SDATA (pane_name));
1a578e9b
AC
1652 /* If there is just one top-level pane, put all its items directly
1653 under the top-level menu. */
1654 if (menu_items_n_panes == 1)
1655 pane_string = "";
1656
1657 /* If the pane has a meaningful name,
1658 make the pane a top-level menu item
1659 with its items as a submenu beneath it. */
1660 if (!keymaps && strcmp (pane_string, ""))
1661 {
1662 wv = xmalloc_widget_value ();
1663 if (save_wv)
1664 save_wv->next = wv;
1665 else
1666 first_wv->contents = wv;
1667 wv->name = pane_string;
1668 if (keymaps && !NILP (prefix))
1669 wv->name++;
1670 wv->value = 0;
1671 wv->enabled = 1;
1672 wv->button_type = BUTTON_TYPE_NONE;
e0f712ba 1673 wv->help = Qnil;
1a578e9b
AC
1674 save_wv = wv;
1675 prev_wv = 0;
1676 }
1677 else if (first_pane)
1678 {
1679 save_wv = wv;
1680 prev_wv = 0;
1681 }
1682 first_pane = 0;
1683 i += MENU_ITEMS_PANE_LENGTH;
1684 }
1685 else
1686 {
1687 /* Create a new item within current pane. */
1688 Lisp_Object item_name, enable, descrip, def, type, selected, help;
e0f712ba
AC
1689 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1690 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1691 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1692 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1693 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1694 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
4036ffb9 1695 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1a578e9b
AC
1696
1697#ifndef HAVE_MULTILINGUAL_MENU
e0f712ba
AC
1698 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
1699 {
383418e5 1700 item_name = ENCODE_MENU_STRING (item_name);
e0f712ba
AC
1701 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
1702 }
4036ffb9 1703
1a578e9b 1704 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
4036ffb9 1705 {
383418e5 1706 descrip = ENCODE_MENU_STRING (descrip);
e0f712ba
AC
1707 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
1708 }
1709#endif /* not HAVE_MULTILINGUAL_MENU */
1a578e9b
AC
1710
1711 wv = xmalloc_widget_value ();
177c0ea7 1712 if (prev_wv)
1a578e9b 1713 prev_wv->next = wv;
177c0ea7 1714 else
1a578e9b 1715 save_wv->contents = wv;
d5db4077 1716 wv->name = (char *) SDATA (item_name);
1a578e9b 1717 if (!NILP (descrip))
d5db4077 1718 wv->key = (char *) SDATA (descrip);
1a578e9b
AC
1719 wv->value = 0;
1720 /* Use the contents index as call_data, since we are
e0f712ba 1721 restricted to 16-bits. */
1a578e9b
AC
1722 wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
1723 wv->enabled = !NILP (enable);
1724
1725 if (NILP (type))
1726 wv->button_type = BUTTON_TYPE_NONE;
1727 else if (EQ (type, QCtoggle))
1728 wv->button_type = BUTTON_TYPE_TOGGLE;
1729 else if (EQ (type, QCradio))
1730 wv->button_type = BUTTON_TYPE_RADIO;
1731 else
1732 abort ();
1733
1734 wv->selected = !NILP (selected);
4036ffb9
YM
1735
1736 if (! STRINGP (help))
e0f712ba 1737 help = Qnil;
1a578e9b 1738
e0f712ba 1739 wv->help = help;
1a578e9b
AC
1740
1741 prev_wv = wv;
1742
1743 i += MENU_ITEMS_ITEM_LENGTH;
1744 }
1745 }
1746
1747 /* Deal with the title, if it is non-nil. */
1748 if (!NILP (title))
1749 {
1750 widget_value *wv_title = xmalloc_widget_value ();
1751 widget_value *wv_sep = xmalloc_widget_value ();
1752
1753 /* Maybe replace this separator with a bitmap or owner-draw item
1754 so that it looks better. Having two separators looks odd. */
1755 wv_sep->name = "--";
1756 wv_sep->next = first_wv->contents;
e0f712ba 1757 wv_sep->help = Qnil;
1a578e9b
AC
1758
1759#ifndef HAVE_MULTILINGUAL_MENU
1760 if (STRING_MULTIBYTE (title))
383418e5 1761 title = ENCODE_MENU_STRING (title);
1a578e9b 1762#endif
4036ffb9 1763
d5db4077 1764 wv_title->name = (char *) SDATA (title);
f5f870c0 1765 wv_title->enabled = FALSE;
e0f712ba 1766 wv_title->title = TRUE;
1a578e9b 1767 wv_title->button_type = BUTTON_TYPE_NONE;
e0f712ba 1768 wv_title->help = Qnil;
1a578e9b
AC
1769 wv_title->next = wv_sep;
1770 first_wv->contents = wv_title;
1771 }
1772
e0f712ba
AC
1773 /* No selection has been chosen yet. */
1774 menu_item_selection = 0;
1775
5aa4098e
YM
1776 /* Actually create and show the menu until popped down. */
1777 create_and_show_popup_menu (f, first_wv, x, y, for_click);
f5f870c0 1778
5aa4098e
YM
1779 /* Free the widget_value objects we used to specify the contents. */
1780 free_menubar_widget_value_tree (first_wv);
1a578e9b 1781
e0f712ba
AC
1782 /* Find the selected item, and its pane, to return
1783 the proper value. */
1a578e9b
AC
1784 if (menu_item_selection != 0)
1785 {
1786 Lisp_Object prefix, entry;
1787
e0f712ba 1788 prefix = entry = Qnil;
1a578e9b
AC
1789 i = 0;
1790 while (i < menu_items_used)
1791 {
1792 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1793 {
1794 subprefix_stack[submenu_depth++] = prefix;
1795 prefix = entry;
1796 i++;
1797 }
1798 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1799 {
1800 prefix = subprefix_stack[--submenu_depth];
1801 i++;
1802 }
1803 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1804 {
1805 prefix
1806 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1807 i += MENU_ITEMS_PANE_LENGTH;
1808 }
e0f712ba
AC
1809 /* Ignore a nil in the item list.
1810 It's meaningful only for dialog boxes. */
1a578e9b
AC
1811 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1812 i += 1;
1813 else
1814 {
1815 entry
1816 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
356ce658 1817 if (menu_item_selection == i)
1a578e9b
AC
1818 {
1819 if (keymaps != 0)
1820 {
1821 int j;
1822
1823 entry = Fcons (entry, Qnil);
1824 if (!NILP (prefix))
1825 entry = Fcons (prefix, entry);
1826 for (j = submenu_depth - 1; j >= 0; j--)
1827 if (!NILP (subprefix_stack[j]))
1828 entry = Fcons (subprefix_stack[j], entry);
1829 }
1830 return entry;
1831 }
1832 i += MENU_ITEMS_ITEM_LENGTH;
1833 }
1834 }
1835 }
b8987570
JD
1836 else if (!for_click)
1837 /* Make "Cancel" equivalent to C-g. */
1838 Fsignal (Qquit, Qnil);
1a578e9b
AC
1839
1840 return Qnil;
1841}
1842\f
1843
e0f712ba 1844#ifdef HAVE_DIALOGS
28eabd14
YM
1845/* Construct native Mac OS dialog based on widget_value tree. */
1846
1a578e9b
AC
1847static char * button_names [] = {
1848 "button1", "button2", "button3", "button4", "button5",
1849 "button6", "button7", "button8", "button9", "button10" };
1850
1851static Lisp_Object
4036ffb9 1852mac_dialog_show (f, keymaps, title, header, error_name)
1a578e9b
AC
1853 FRAME_PTR f;
1854 int keymaps;
3f297536 1855 Lisp_Object title, header;
4036ffb9 1856 char **error_name;
1a578e9b
AC
1857{
1858 int i, nb_buttons=0;
1859 char dialog_name[6];
1a578e9b 1860
e0f712ba 1861 widget_value *wv, *first_wv = 0, *prev_wv = 0;
1a578e9b
AC
1862
1863 /* Number of elements seen so far, before boundary. */
1864 int left_count = 0;
e0f712ba 1865 /* 1 means we've seen the boundary between left-hand elts and right-hand. */
1a578e9b
AC
1866 int boundary_seen = 0;
1867
4036ffb9 1868 *error_name = NULL;
1a578e9b
AC
1869
1870 if (menu_items_n_panes > 1)
1871 {
4036ffb9 1872 *error_name = "Multiple panes in dialog box";
1a578e9b
AC
1873 return Qnil;
1874 }
1875
e0f712ba
AC
1876 /* Create a tree of widget_value objects
1877 representing the text label and buttons. */
1a578e9b
AC
1878 {
1879 Lisp_Object pane_name, prefix;
1880 char *pane_string;
1881 pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
1882 prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
1883 pane_string = (NILP (pane_name)
177c0ea7 1884 ? "" : (char *) SDATA (pane_name));
1a578e9b
AC
1885 prev_wv = xmalloc_widget_value ();
1886 prev_wv->value = pane_string;
1887 if (keymaps && !NILP (prefix))
1888 prev_wv->name++;
1889 prev_wv->enabled = 1;
1890 prev_wv->name = "message";
e0f712ba 1891 prev_wv->help = Qnil;
1a578e9b 1892 first_wv = prev_wv;
177c0ea7 1893
1a578e9b
AC
1894 /* Loop over all panes and items, filling in the tree. */
1895 i = MENU_ITEMS_PANE_LENGTH;
1896 while (i < menu_items_used)
1897 {
177c0ea7 1898
1a578e9b 1899 /* Create a new item within current pane. */
4036ffb9 1900 Lisp_Object item_name, enable, descrip;
1a578e9b
AC
1901 item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
1902 enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
1903 descrip
1904 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
177c0ea7 1905
1a578e9b
AC
1906 if (NILP (item_name))
1907 {
1908 free_menubar_widget_value_tree (first_wv);
4036ffb9 1909 *error_name = "Submenu in dialog items";
1a578e9b
AC
1910 return Qnil;
1911 }
1912 if (EQ (item_name, Qquote))
1913 {
e0f712ba
AC
1914 /* This is the boundary between left-side elts
1915 and right-side elts. Stop incrementing right_count. */
1a578e9b
AC
1916 boundary_seen = 1;
1917 i++;
1918 continue;
1919 }
1920 if (nb_buttons >= 9)
1921 {
1922 free_menubar_widget_value_tree (first_wv);
4036ffb9 1923 *error_name = "Too many dialog items";
1a578e9b
AC
1924 return Qnil;
1925 }
1926
1927 wv = xmalloc_widget_value ();
1928 prev_wv->next = wv;
1929 wv->name = (char *) button_names[nb_buttons];
1930 if (!NILP (descrip))
d5db4077
KR
1931 wv->key = (char *) SDATA (descrip);
1932 wv->value = (char *) SDATA (item_name);
1a578e9b
AC
1933 wv->call_data = (void *) i;
1934 /* menu item is identified by its index in menu_items table */
1935 wv->enabled = !NILP (enable);
e0f712ba 1936 wv->help = Qnil;
1a578e9b
AC
1937 prev_wv = wv;
1938
1939 if (! boundary_seen)
1940 left_count++;
1941
1942 nb_buttons++;
1943 i += MENU_ITEMS_ITEM_LENGTH;
1944 }
1945
e0f712ba
AC
1946 /* If the boundary was not specified,
1947 by default put half on the left and half on the right. */
1a578e9b
AC
1948 if (! boundary_seen)
1949 left_count = nb_buttons - nb_buttons / 2;
1950
1951 wv = xmalloc_widget_value ();
1952 wv->name = dialog_name;
e0f712ba 1953 wv->help = Qnil;
1a578e9b 1954
3f297536
NR
1955 /* Frame title: 'Q' = Question, 'I' = Information.
1956 Can also have 'E' = Error if, one day, we want
1957 a popup for errors. */
1958 if (NILP(header))
1959 dialog_name[0] = 'Q';
1960 else
1961 dialog_name[0] = 'I';
1962
e0f712ba
AC
1963 /* Dialog boxes use a really stupid name encoding
1964 which specifies how many buttons to use
3f297536 1965 and how many buttons are on the right. */
1a578e9b
AC
1966 dialog_name[1] = '0' + nb_buttons;
1967 dialog_name[2] = 'B';
1968 dialog_name[3] = 'R';
1969 /* Number of buttons to put on the right. */
1970 dialog_name[4] = '0' + nb_buttons - left_count;
1971 dialog_name[5] = 0;
1972 wv->contents = first_wv;
1973 first_wv = wv;
1974 }
1975
5aa4098e
YM
1976 /* No selection has been chosen yet. */
1977 menu_item_selection = 0;
1978
b28d7564
YM
1979 /* Force a redisplay before showing the dialog. If a frame is created
1980 just before showing the dialog, its contents may not have been fully
1981 drawn. */
1982 Fredisplay (Qt);
1983
1a578e9b 1984 /* Actually create the dialog. */
28eabd14 1985#if TARGET_API_MAC_CARBON
5aa4098e 1986 create_and_show_dialog (f, first_wv);
1a578e9b 1987#else
28eabd14 1988 menu_item_selection = mac_dialog (first_wv);
1a578e9b
AC
1989#endif
1990
e0f712ba 1991 /* Free the widget_value objects we used to specify the contents. */
1a578e9b
AC
1992 free_menubar_widget_value_tree (first_wv);
1993
4036ffb9
YM
1994 /* Find the selected item, and its pane, to return
1995 the proper value. */
1a578e9b
AC
1996 if (menu_item_selection != 0)
1997 {
1998 Lisp_Object prefix;
1999
2000 prefix = Qnil;
2001 i = 0;
2002 while (i < menu_items_used)
2003 {
2004 Lisp_Object entry;
2005
2006 if (EQ (XVECTOR (menu_items)->contents[i], Qt))
2007 {
2008 prefix
2009 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
2010 i += MENU_ITEMS_PANE_LENGTH;
2011 }
4036ffb9
YM
2012 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
2013 {
2014 /* This is the boundary between left-side elts and
2015 right-side elts. */
2016 ++i;
2017 }
1a578e9b
AC
2018 else
2019 {
2020 entry
2021 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
2022 if (menu_item_selection == i)
2023 {
2024 if (keymaps != 0)
2025 {
2026 entry = Fcons (entry, Qnil);
2027 if (!NILP (prefix))
2028 entry = Fcons (prefix, entry);
2029 }
2030 return entry;
2031 }
2032 i += MENU_ITEMS_ITEM_LENGTH;
2033 }
2034 }
2035 }
4036ffb9
YM
2036 else
2037 /* Make "Cancel" equivalent to C-g. */
2038 Fsignal (Qquit, Qnil);
1a578e9b
AC
2039
2040 return Qnil;
2041}
e0f712ba 2042#endif /* HAVE_DIALOGS */
1a578e9b
AC
2043\f
2044
2045/* Is this item a separator? */
5aa4098e 2046int
1a578e9b 2047name_is_separator (name)
37a39780 2048 const char *name;
1a578e9b 2049{
37a39780 2050 const char *start = name;
e0f712ba
AC
2051
2052 /* Check if name string consists of only dashes ('-'). */
1a578e9b 2053 while (*name == '-') name++;
e0f712ba
AC
2054 /* Separators can also be of the form "--:TripleSuperMegaEtched"
2055 or "--deep-shadow". We don't implement them yet, se we just treat
2056 them like normal separators. */
2057 return (*name == '\0' || start + 2 == name);
1a578e9b 2058}
1a578e9b 2059#endif /* HAVE_MENUS */
c1f043a0 2060
a83c3e31
YM
2061/* Detect if a menu is currently active. */
2062
2063int
2064popup_activated ()
2065{
2066 return popup_activated_flag;
2067}
2068
c1f043a0
CY
2069/* The following is used by delayed window autoselection. */
2070
2071DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
2072 doc: /* Return t if a menu or popup dialog is active. */)
2073 ()
2074{
512eb161
YM
2075#if TARGET_API_MAC_CARBON
2076 return (popup_activated ()) ? Qt : Qnil;
2077#else
c1f043a0
CY
2078 /* Always return Qnil since menu selection functions do not return
2079 until a selection has been made or cancelled. */
2080 return Qnil;
512eb161 2081#endif
c1f043a0 2082}
1a578e9b
AC
2083\f
2084void
2085syms_of_macmenu ()
2086{
2087 staticpro (&menu_items);
2088 menu_items = Qnil;
2089
2090 Qdebug_on_next_call = intern ("debug-on-next-call");
2091 staticpro (&Qdebug_on_next_call);
2092
1a578e9b 2093 defsubr (&Sx_popup_menu);
0ec2e29e 2094 defsubr (&Smenu_or_popup_active_p);
1a578e9b
AC
2095#ifdef HAVE_MENUS
2096 defsubr (&Sx_popup_dialog);
2097#endif
2098}
ab5796a9
MB
2099
2100/* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce
2101 (do not change this comment) */