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