(Buffer-menu-mode-map): Add hyphen between "Buffer"
[emacs.git] / src / menu.c
blob74d455a8c0ab5c0ceff507638be96e2bce1f2b99
1 /* Platform-independent code for terminal communications.
2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
21 #include <stdio.h>
22 #include <setjmp.h>
24 #include "lisp.h"
25 #include "keyboard.h"
26 #include "keymap.h"
27 #include "frame.h"
28 #include "termhooks.h"
29 #include "blockinput.h"
30 #include "dispextern.h"
32 #ifdef USE_X_TOOLKIT
33 #include "../lwlib/lwlib.h"
34 #endif
36 #ifdef HAVE_X_WINDOWS
37 #include "xterm.h"
38 #endif
40 #ifdef HAVE_NS
41 #include "nsterm.h"
42 #endif
44 #ifdef USE_GTK
45 #include "gtkutil.h"
46 #endif
48 #ifdef HAVE_NTGUI
49 #include "w32term.h"
51 extern AppendMenuW_Proc unicode_append_menu;
53 #endif /* HAVE_NTGUI */
55 #include "menu.h"
57 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
58 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
59 #define HAVE_BOXES 1
60 #endif
62 extern Lisp_Object QCtoggle, QCradio;
64 Lisp_Object menu_items;
66 /* If non-nil, means that the global vars defined here are already in use.
67 Used to detect cases where we try to re-enter this non-reentrant code. */
68 Lisp_Object menu_items_inuse;
70 /* Number of slots currently allocated in menu_items. */
71 int menu_items_allocated;
73 /* This is the index in menu_items of the first empty slot. */
74 int menu_items_used;
76 /* The number of panes currently recorded in menu_items,
77 excluding those within submenus. */
78 int menu_items_n_panes;
80 /* Current depth within submenus. */
81 static int menu_items_submenu_depth;
83 void
84 init_menu_items ()
86 if (!NILP (menu_items_inuse))
87 error ("Trying to use a menu from within a menu-entry");
89 if (NILP (menu_items))
91 menu_items_allocated = 60;
92 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
95 menu_items_inuse = Qt;
96 menu_items_used = 0;
97 menu_items_n_panes = 0;
98 menu_items_submenu_depth = 0;
101 /* Call at the end of generating the data in menu_items. */
103 void
104 finish_menu_items ()
108 Lisp_Object
109 unuse_menu_items (dummy)
110 Lisp_Object dummy;
112 return menu_items_inuse = Qnil;
115 /* Call when finished using the data for the current menu
116 in menu_items. */
118 void
119 discard_menu_items ()
121 /* Free the structure if it is especially large.
122 Otherwise, hold on to it, to save time. */
123 if (menu_items_allocated > 200)
125 menu_items = Qnil;
126 menu_items_allocated = 0;
128 xassert (NILP (menu_items_inuse));
131 /* This undoes save_menu_items, and it is called by the specpdl unwind
132 mechanism. */
134 static Lisp_Object
135 restore_menu_items (saved)
136 Lisp_Object saved;
138 menu_items = XCAR (saved);
139 menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
140 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
141 saved = XCDR (saved);
142 menu_items_used = XINT (XCAR (saved));
143 saved = XCDR (saved);
144 menu_items_n_panes = XINT (XCAR (saved));
145 saved = XCDR (saved);
146 menu_items_submenu_depth = XINT (XCAR (saved));
147 return Qnil;
150 /* Push the whole state of menu_items processing onto the specpdl.
151 It will be restored when the specpdl is unwound. */
153 void
154 save_menu_items ()
156 Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
157 make_number (menu_items_used),
158 make_number (menu_items_n_panes),
159 make_number (menu_items_submenu_depth));
160 record_unwind_protect (restore_menu_items, saved);
161 menu_items_inuse = Qnil;
162 menu_items = Qnil;
166 /* Make the menu_items vector twice as large. */
168 static void
169 grow_menu_items ()
171 menu_items_allocated *= 2;
172 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
175 /* Begin a submenu. */
177 static void
178 push_submenu_start ()
180 if (menu_items_used + 1 > menu_items_allocated)
181 grow_menu_items ();
183 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
184 menu_items_submenu_depth++;
187 /* End a submenu. */
189 static void
190 push_submenu_end ()
192 if (menu_items_used + 1 > menu_items_allocated)
193 grow_menu_items ();
195 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
196 menu_items_submenu_depth--;
199 /* Indicate boundary between left and right. */
201 static void
202 push_left_right_boundary ()
204 if (menu_items_used + 1 > menu_items_allocated)
205 grow_menu_items ();
207 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
210 /* Start a new menu pane in menu_items.
211 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
213 static void
214 push_menu_pane (name, prefix_vec)
215 Lisp_Object name, prefix_vec;
217 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
218 grow_menu_items ();
220 if (menu_items_submenu_depth == 0)
221 menu_items_n_panes++;
222 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
223 XVECTOR (menu_items)->contents[menu_items_used++] = name;
224 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
227 /* Push one menu item into the current pane. NAME is the string to
228 display. ENABLE if non-nil means this item can be selected. KEY
229 is the key generated by choosing this item, or nil if this item
230 doesn't really have a definition. DEF is the definition of this
231 item. EQUIV is the textual description of the keyboard equivalent
232 for this item (or nil if none). TYPE is the type of this menu
233 item, one of nil, `toggle' or `radio'. */
235 static void
236 push_menu_item (name, enable, key, def, equiv, type, selected, help)
237 Lisp_Object name, enable, key, def, equiv, type, selected, help;
239 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
240 grow_menu_items ();
242 XVECTOR (menu_items)->contents[menu_items_used++] = name;
243 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
244 XVECTOR (menu_items)->contents[menu_items_used++] = key;
245 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
246 XVECTOR (menu_items)->contents[menu_items_used++] = def;
247 XVECTOR (menu_items)->contents[menu_items_used++] = type;
248 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
249 XVECTOR (menu_items)->contents[menu_items_used++] = help;
252 /* Args passed between single_keymap_panes and single_menu_item. */
253 struct skp
255 Lisp_Object pending_maps;
256 int maxdepth, notreal;
257 int notbuttons;
260 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
261 void *));
263 /* This is a recursive subroutine of keymap_panes.
264 It handles one keymap, KEYMAP.
265 The other arguments are passed along
266 or point to local variables of the previous function.
267 If NOTREAL is nonzero, only check for equivalent key bindings, don't
268 evaluate expressions in menu items and don't make any menu.
270 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
272 static void
273 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
274 Lisp_Object keymap;
275 Lisp_Object pane_name;
276 Lisp_Object prefix;
277 int notreal;
278 int maxdepth;
280 struct skp skp;
281 struct gcpro gcpro1;
283 skp.pending_maps = Qnil;
284 skp.maxdepth = maxdepth;
285 skp.notreal = notreal;
286 skp.notbuttons = 0;
288 if (maxdepth <= 0)
289 return;
291 push_menu_pane (pane_name, prefix);
293 #ifndef HAVE_BOXES
294 /* Remember index for first item in this pane so we can go back and
295 add a prefix when (if) we see the first button. After that, notbuttons
296 is set to 0, to mark that we have seen a button and all non button
297 items need a prefix. */
298 skp.notbuttons = menu_items_used;
299 #endif
301 GCPRO1 (skp.pending_maps);
302 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
303 UNGCPRO;
305 /* Process now any submenus which want to be panes at this level. */
306 while (CONSP (skp.pending_maps))
308 Lisp_Object elt, eltcdr, string;
309 elt = XCAR (skp.pending_maps);
310 eltcdr = XCDR (elt);
311 string = XCAR (eltcdr);
312 /* We no longer discard the @ from the beginning of the string here.
313 Instead, we do this in *menu_show. */
314 single_keymap_panes (Fcar (elt), string,
315 XCDR (eltcdr), notreal, maxdepth - 1);
316 skp.pending_maps = XCDR (skp.pending_maps);
320 /* This is a subroutine of single_keymap_panes that handles one
321 keymap entry.
322 KEY is a key in a keymap and ITEM is its binding.
323 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
324 separate panes.
325 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
326 evaluate expressions in menu items and don't make any menu.
327 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
329 static void
330 single_menu_item (key, item, dummy, skp_v)
331 Lisp_Object key, item, dummy;
332 void *skp_v;
334 Lisp_Object map, item_string, enabled;
335 struct gcpro gcpro1, gcpro2;
336 int res;
337 struct skp *skp = skp_v;
339 /* Parse the menu item and leave the result in item_properties. */
340 GCPRO2 (key, item);
341 res = parse_menu_item (item, skp->notreal, 0);
342 UNGCPRO;
343 if (!res)
344 return; /* Not a menu item. */
346 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
348 if (skp->notreal)
350 /* We don't want to make a menu, just traverse the keymaps to
351 precompute equivalent key bindings. */
352 if (!NILP (map))
353 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
354 return;
357 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
358 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
360 if (!NILP (map) && SREF (item_string, 0) == '@')
362 if (!NILP (enabled))
363 /* An enabled separate pane. Remember this to handle it later. */
364 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
365 skp->pending_maps);
366 return;
369 #if defined(HAVE_X_WINDOWS) || defined(MSDOS)
370 #ifndef HAVE_BOXES
371 /* Simulate radio buttons and toggle boxes by putting a prefix in
372 front of them. */
374 Lisp_Object prefix = Qnil;
375 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
376 if (!NILP (type))
378 Lisp_Object selected
379 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
381 if (skp->notbuttons)
382 /* The first button. Line up previous items in this menu. */
384 int index = skp->notbuttons; /* Index for first item this menu. */
385 int submenu = 0;
386 Lisp_Object tem;
387 while (index < menu_items_used)
390 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
391 if (NILP (tem))
393 index++;
394 submenu++; /* Skip sub menu. */
396 else if (EQ (tem, Qlambda))
398 index++;
399 submenu--; /* End sub menu. */
401 else if (EQ (tem, Qt))
402 index += 3; /* Skip new pane marker. */
403 else if (EQ (tem, Qquote))
404 index++; /* Skip a left, right divider. */
405 else
407 if (!submenu && SREF (tem, 0) != '\0'
408 && SREF (tem, 0) != '-')
409 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
410 = concat2 (build_string (" "), tem);
411 index += MENU_ITEMS_ITEM_LENGTH;
414 skp->notbuttons = 0;
417 /* Calculate prefix, if any, for this item. */
418 if (EQ (type, QCtoggle))
419 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
420 else if (EQ (type, QCradio))
421 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
423 /* Not a button. If we have earlier buttons, then we need a prefix. */
424 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
425 && SREF (item_string, 0) != '-')
426 prefix = build_string (" ");
428 if (!NILP (prefix))
429 item_string = concat2 (prefix, item_string);
431 #endif /* not HAVE_BOXES */
433 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
434 if (!NILP (map))
435 /* Indicate visually that this is a submenu. */
436 item_string = concat2 (item_string, build_string (" >"));
437 #endif
439 #endif /* HAVE_X_WINDOWS || MSDOS */
441 push_menu_item (item_string, enabled, key,
442 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
443 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
444 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
445 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
446 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
448 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
449 /* Display a submenu using the toolkit. */
450 if (! (NILP (map) || NILP (enabled)))
452 push_submenu_start ();
453 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
454 push_submenu_end ();
456 #endif
459 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
460 and generate menu panes for them in menu_items.
461 If NOTREAL is nonzero,
462 don't bother really computing whether an item is enabled. */
464 void
465 keymap_panes (keymaps, nmaps, notreal)
466 Lisp_Object *keymaps;
467 int nmaps;
468 int notreal;
470 int mapno;
472 init_menu_items ();
474 /* Loop over the given keymaps, making a pane for each map.
475 But don't make a pane that is empty--ignore that map instead.
476 P is the number of panes we have made so far. */
477 for (mapno = 0; mapno < nmaps; mapno++)
478 single_keymap_panes (keymaps[mapno],
479 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
481 finish_menu_items ();
485 /* Push the items in a single pane defined by the alist PANE. */
486 static void
487 list_of_items (pane)
488 Lisp_Object pane;
490 Lisp_Object tail, item, item1;
492 for (tail = pane; CONSP (tail); tail = XCDR (tail))
494 item = XCAR (tail);
495 if (STRINGP (item))
496 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
497 Qnil, Qnil, Qnil, Qnil);
498 else if (CONSP (item))
500 item1 = XCAR (item);
501 CHECK_STRING (item1);
502 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
503 Qt, Qnil, Qnil, Qnil, Qnil);
505 else
506 push_left_right_boundary ();
511 /* Push all the panes and items of a menu described by the
512 alist-of-alists MENU.
513 This handles old-fashioned calls to x-popup-menu. */
514 void
515 list_of_panes (menu)
516 Lisp_Object menu;
518 Lisp_Object tail;
520 init_menu_items ();
522 for (tail = menu; CONSP (tail); tail = XCDR (tail))
524 Lisp_Object elt, pane_name, pane_data;
525 elt = XCAR (tail);
526 pane_name = Fcar (elt);
527 CHECK_STRING (pane_name);
528 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
529 pane_data = Fcdr (elt);
530 CHECK_CONS (pane_data);
531 list_of_items (pane_data);
534 finish_menu_items ();
537 /* Set up data in menu_items for a menu bar item
538 whose event type is ITEM_KEY (with string ITEM_NAME)
539 and whose contents come from the list of keymaps MAPS. */
541 parse_single_submenu (item_key, item_name, maps)
542 Lisp_Object item_key, item_name, maps;
544 Lisp_Object length;
545 int len;
546 Lisp_Object *mapvec;
547 int i;
548 int top_level_items = 0;
550 length = Flength (maps);
551 len = XINT (length);
553 /* Convert the list MAPS into a vector MAPVEC. */
554 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
555 for (i = 0; i < len; i++)
557 mapvec[i] = Fcar (maps);
558 maps = Fcdr (maps);
561 /* Loop over the given keymaps, making a pane for each map.
562 But don't make a pane that is empty--ignore that map instead. */
563 for (i = 0; i < len; i++)
565 if (!KEYMAPP (mapvec[i]))
567 /* Here we have a command at top level in the menu bar
568 as opposed to a submenu. */
569 top_level_items = 1;
570 push_menu_pane (Qnil, Qnil);
571 push_menu_item (item_name, Qt, item_key, mapvec[i],
572 Qnil, Qnil, Qnil, Qnil);
574 else
576 Lisp_Object prompt;
577 prompt = Fkeymap_prompt (mapvec[i]);
578 single_keymap_panes (mapvec[i],
579 !NILP (prompt) ? prompt : item_name,
580 item_key, 0, 10);
584 return top_level_items;
588 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
590 /* Allocate a widget_value, blocking input. */
592 widget_value *
593 xmalloc_widget_value ()
595 widget_value *value;
597 BLOCK_INPUT;
598 value = malloc_widget_value ();
599 UNBLOCK_INPUT;
601 return value;
604 /* This recursively calls free_widget_value on the tree of widgets.
605 It must free all data that was malloc'ed for these widget_values.
606 In Emacs, many slots are pointers into the data of Lisp_Strings, and
607 must be left alone. */
609 void
610 free_menubar_widget_value_tree (wv)
611 widget_value *wv;
613 if (! wv) return;
615 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
617 if (wv->contents && (wv->contents != (widget_value*)1))
619 free_menubar_widget_value_tree (wv->contents);
620 wv->contents = (widget_value *) 0xDEADBEEF;
622 if (wv->next)
624 free_menubar_widget_value_tree (wv->next);
625 wv->next = (widget_value *) 0xDEADBEEF;
627 BLOCK_INPUT;
628 free_widget_value (wv);
629 UNBLOCK_INPUT;
632 /* Create a tree of widget_value objects
633 representing the panes and items
634 in menu_items starting at index START, up to index END. */
636 widget_value *
637 digest_single_submenu (start, end, top_level_items)
638 int start, end, top_level_items;
640 widget_value *wv, *prev_wv, *save_wv, *first_wv;
641 int i;
642 int submenu_depth = 0;
643 widget_value **submenu_stack;
644 int panes_seen = 0;
646 submenu_stack
647 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
648 wv = xmalloc_widget_value ();
649 wv->name = "menu";
650 wv->value = 0;
651 wv->enabled = 1;
652 wv->button_type = BUTTON_TYPE_NONE;
653 wv->help = Qnil;
654 first_wv = wv;
655 save_wv = 0;
656 prev_wv = 0;
658 /* Loop over all panes and items made by the preceding call
659 to parse_single_submenu and construct a tree of widget_value objects.
660 Ignore the panes and items used by previous calls to
661 digest_single_submenu, even though those are also in menu_items. */
662 i = start;
663 while (i < end)
665 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
667 submenu_stack[submenu_depth++] = save_wv;
668 save_wv = prev_wv;
669 prev_wv = 0;
670 i++;
672 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
674 prev_wv = save_wv;
675 save_wv = submenu_stack[--submenu_depth];
676 i++;
678 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
679 && submenu_depth != 0)
680 i += MENU_ITEMS_PANE_LENGTH;
681 /* Ignore a nil in the item list.
682 It's meaningful only for dialog boxes. */
683 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
684 i += 1;
685 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
687 /* Create a new pane. */
688 Lisp_Object pane_name, prefix;
689 char *pane_string;
691 panes_seen++;
693 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
694 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
696 #ifdef HAVE_NTGUI
697 if (STRINGP (pane_name))
699 if (unicode_append_menu)
700 /* Encode as UTF-8 for now. */
701 pane_name = ENCODE_UTF_8 (pane_name);
702 else if (STRING_MULTIBYTE (pane_name))
703 pane_name = ENCODE_SYSTEM (pane_name);
705 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
707 #elif !defined (HAVE_MULTILINGUAL_MENU)
708 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
710 pane_name = ENCODE_MENU_STRING (pane_name);
711 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
713 #endif
715 pane_string = (NILP (pane_name)
716 ? "" : (char *) SDATA (pane_name));
717 /* If there is just one top-level pane, put all its items directly
718 under the top-level menu. */
719 if (menu_items_n_panes == 1)
720 pane_string = "";
722 /* If the pane has a meaningful name,
723 make the pane a top-level menu item
724 with its items as a submenu beneath it. */
725 if (strcmp (pane_string, ""))
727 wv = xmalloc_widget_value ();
728 if (save_wv)
729 save_wv->next = wv;
730 else
731 first_wv->contents = wv;
732 wv->lname = pane_name;
733 /* Set value to 1 so update_submenu_strings can handle '@' */
734 wv->value = (char *)1;
735 wv->enabled = 1;
736 wv->button_type = BUTTON_TYPE_NONE;
737 wv->help = Qnil;
738 save_wv = wv;
740 else
741 save_wv = first_wv;
743 prev_wv = 0;
744 i += MENU_ITEMS_PANE_LENGTH;
746 else
748 /* Create a new item within current pane. */
749 Lisp_Object item_name, enable, descrip, def, type, selected;
750 Lisp_Object help;
752 /* All items should be contained in panes. */
753 if (panes_seen == 0)
754 abort ();
756 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
757 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
758 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
759 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
760 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
761 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
762 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
764 #ifdef HAVE_NTGUI
765 if (STRINGP (item_name))
767 if (unicode_append_menu)
768 item_name = ENCODE_UTF_8 (item_name);
769 else if (STRING_MULTIBYTE (item_name))
770 item_name = ENCODE_SYSTEM (item_name);
772 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
775 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
777 descrip = ENCODE_SYSTEM (descrip);
778 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
780 #elif !defined (HAVE_MULTILINGUAL_MENU)
781 if (STRING_MULTIBYTE (item_name))
783 item_name = ENCODE_MENU_STRING (item_name);
784 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
787 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
789 descrip = ENCODE_MENU_STRING (descrip);
790 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
792 #endif
794 wv = xmalloc_widget_value ();
795 if (prev_wv)
796 prev_wv->next = wv;
797 else
798 save_wv->contents = wv;
800 wv->lname = item_name;
801 if (!NILP (descrip))
802 wv->lkey = descrip;
803 wv->value = 0;
804 /* The EMACS_INT cast avoids a warning. There's no problem
805 as long as pointers have enough bits to hold small integers. */
806 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
807 wv->enabled = !NILP (enable);
809 if (NILP (type))
810 wv->button_type = BUTTON_TYPE_NONE;
811 else if (EQ (type, QCradio))
812 wv->button_type = BUTTON_TYPE_RADIO;
813 else if (EQ (type, QCtoggle))
814 wv->button_type = BUTTON_TYPE_TOGGLE;
815 else
816 abort ();
818 wv->selected = !NILP (selected);
819 if (! STRINGP (help))
820 help = Qnil;
822 wv->help = help;
824 prev_wv = wv;
826 i += MENU_ITEMS_ITEM_LENGTH;
830 /* If we have just one "menu item"
831 that was originally a button, return it by itself. */
832 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
834 wv = first_wv->contents;
835 free_widget_value (first_wv);
836 return wv;
839 return first_wv;
842 /* Walk through the widget_value tree starting at FIRST_WV and update
843 the char * pointers from the corresponding lisp values.
844 We do this after building the whole tree, since GC may happen while the
845 tree is constructed, and small strings are relocated. So we must wait
846 until no GC can happen before storing pointers into lisp values. */
847 void
848 update_submenu_strings (first_wv)
849 widget_value *first_wv;
851 widget_value *wv;
853 for (wv = first_wv; wv; wv = wv->next)
855 if (STRINGP (wv->lname))
857 wv->name = (char *) SDATA (wv->lname);
859 /* Ignore the @ that means "separate pane".
860 This is a kludge, but this isn't worth more time. */
861 if (wv->value == (char *)1)
863 if (wv->name[0] == '@')
864 wv->name++;
865 wv->value = 0;
869 if (STRINGP (wv->lkey))
870 wv->key = (char *) SDATA (wv->lkey);
872 if (wv->contents)
873 update_submenu_strings (wv->contents);
877 /* Find the menu selection and store it in the keyboard buffer.
878 F is the frame the menu is on.
879 MENU_BAR_ITEMS_USED is the length of VECTOR.
880 VECTOR is an array of menu events for the whole menu. */
882 void
883 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
884 FRAME_PTR f;
885 int menu_bar_items_used;
886 Lisp_Object vector;
887 void *client_data;
889 Lisp_Object prefix, entry;
890 Lisp_Object *subprefix_stack;
891 int submenu_depth = 0;
892 int i;
894 entry = Qnil;
895 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
896 prefix = Qnil;
897 i = 0;
899 while (i < menu_bar_items_used)
901 if (EQ (XVECTOR (vector)->contents[i], Qnil))
903 subprefix_stack[submenu_depth++] = prefix;
904 prefix = entry;
905 i++;
907 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
909 prefix = subprefix_stack[--submenu_depth];
910 i++;
912 else if (EQ (XVECTOR (vector)->contents[i], Qt))
914 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
915 i += MENU_ITEMS_PANE_LENGTH;
917 else
919 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
920 /* The EMACS_INT cast avoids a warning. There's no problem
921 as long as pointers have enough bits to hold small integers. */
922 if ((int) (EMACS_INT) client_data == i)
924 int j;
925 struct input_event buf;
926 Lisp_Object frame;
927 EVENT_INIT (buf);
929 XSETFRAME (frame, f);
930 buf.kind = MENU_BAR_EVENT;
931 buf.frame_or_window = frame;
932 buf.arg = frame;
933 kbd_buffer_store_event (&buf);
935 for (j = 0; j < submenu_depth; j++)
936 if (!NILP (subprefix_stack[j]))
938 buf.kind = MENU_BAR_EVENT;
939 buf.frame_or_window = frame;
940 buf.arg = subprefix_stack[j];
941 kbd_buffer_store_event (&buf);
944 if (!NILP (prefix))
946 buf.kind = MENU_BAR_EVENT;
947 buf.frame_or_window = frame;
948 buf.arg = prefix;
949 kbd_buffer_store_event (&buf);
952 buf.kind = MENU_BAR_EVENT;
953 buf.frame_or_window = frame;
954 buf.arg = entry;
955 kbd_buffer_store_event (&buf);
957 return;
959 i += MENU_ITEMS_ITEM_LENGTH;
964 #endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
966 #ifdef HAVE_NS
967 /* As above, but return the menu selection instead of storing in kb buffer.
968 If keymaps==1, return full prefixes to selection. */
969 Lisp_Object
970 find_and_return_menu_selection (FRAME_PTR f, int keymaps, void *client_data)
972 Lisp_Object prefix, entry;
973 int i;
974 Lisp_Object *subprefix_stack;
975 int submenu_depth = 0;
977 prefix = entry = Qnil;
978 i = 0;
979 subprefix_stack =
980 (Lisp_Object *)alloca(menu_items_used * sizeof (Lisp_Object));
982 while (i < menu_items_used)
984 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
986 subprefix_stack[submenu_depth++] = prefix;
987 prefix = entry;
988 i++;
990 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
992 prefix = subprefix_stack[--submenu_depth];
993 i++;
995 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
997 prefix
998 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
999 i += MENU_ITEMS_PANE_LENGTH;
1001 /* Ignore a nil in the item list.
1002 It's meaningful only for dialog boxes. */
1003 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1004 i += 1;
1005 else
1007 entry
1008 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
1009 if ((EMACS_INT)client_data == (EMACS_INT)(&XVECTOR (menu_items)->contents[i]))
1011 if (keymaps != 0)
1013 int j;
1015 entry = Fcons (entry, Qnil);
1016 if (!NILP (prefix))
1017 entry = Fcons (prefix, entry);
1018 for (j = submenu_depth - 1; j >= 0; j--)
1019 if (!NILP (subprefix_stack[j]))
1020 entry = Fcons (subprefix_stack[j], entry);
1022 return entry;
1024 i += MENU_ITEMS_ITEM_LENGTH;
1027 return Qnil;
1029 #endif /* HAVE_NS */
1031 void
1032 syms_of_menu ()
1034 staticpro (&menu_items);
1035 menu_items = Qnil;
1036 menu_items_inuse = Qnil;
1039 /* arch-tag: 78bbc7cf-8025-4156-aa8a-6c7fd99bf51d
1040 (do not change this comment) */