Comment fix for rms.
[emacs.git] / src / menu.c
blob52c721891f7a6e728970002943d44009963dfe00
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 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>
23 #include "lisp.h"
24 #include "keyboard.h"
25 #include "keymap.h"
26 #include "frame.h"
27 #include "termhooks.h"
28 #include "blockinput.h"
29 #include "dispextern.h"
31 #ifdef USE_X_TOOLKIT
32 #include "../lwlib/lwlib.h"
33 #endif
35 #ifdef HAVE_X_WINDOWS
36 #include "xterm.h"
37 #endif
39 #ifdef USE_GTK
40 #include "gtkutil.h"
41 #endif
43 #ifdef HAVE_NTGUI
44 #include "w32term.h"
46 extern AppendMenuW_Proc unicode_append_menu;
48 #endif /* HAVE_NTGUI */
51 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
52 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
53 #define HAVE_BOXES 1
54 #endif
56 extern Lisp_Object QCtoggle, QCradio;
58 Lisp_Object menu_items;
60 /* If non-nil, means that the global vars defined here are already in use.
61 Used to detect cases where we try to re-enter this non-reentrant code. */
62 Lisp_Object menu_items_inuse;
64 /* Number of slots currently allocated in menu_items. */
65 int menu_items_allocated;
67 /* This is the index in menu_items of the first empty slot. */
68 int menu_items_used;
70 /* The number of panes currently recorded in menu_items,
71 excluding those within submenus. */
72 int menu_items_n_panes;
74 /* Current depth within submenus. */
75 static int menu_items_submenu_depth;
77 void
78 init_menu_items ()
80 if (!NILP (menu_items_inuse))
81 error ("Trying to use a menu from within a menu-entry");
83 if (NILP (menu_items))
85 menu_items_allocated = 60;
86 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
89 menu_items_inuse = Qt;
90 menu_items_used = 0;
91 menu_items_n_panes = 0;
92 menu_items_submenu_depth = 0;
95 /* Call at the end of generating the data in menu_items. */
97 void
98 finish_menu_items ()
102 Lisp_Object
103 unuse_menu_items (dummy)
104 Lisp_Object dummy;
106 return menu_items_inuse = Qnil;
109 /* Call when finished using the data for the current menu
110 in menu_items. */
112 void
113 discard_menu_items ()
115 /* Free the structure if it is especially large.
116 Otherwise, hold on to it, to save time. */
117 if (menu_items_allocated > 200)
119 menu_items = Qnil;
120 menu_items_allocated = 0;
122 xassert (NILP (menu_items_inuse));
125 /* This undoes save_menu_items, and it is called by the specpdl unwind
126 mechanism. */
128 static Lisp_Object
129 restore_menu_items (saved)
130 Lisp_Object saved;
132 menu_items = XCAR (saved);
133 menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
134 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
135 saved = XCDR (saved);
136 menu_items_used = XINT (XCAR (saved));
137 saved = XCDR (saved);
138 menu_items_n_panes = XINT (XCAR (saved));
139 saved = XCDR (saved);
140 menu_items_submenu_depth = XINT (XCAR (saved));
141 return Qnil;
144 /* Push the whole state of menu_items processing onto the specpdl.
145 It will be restored when the specpdl is unwound. */
147 void
148 save_menu_items ()
150 Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
151 make_number (menu_items_used),
152 make_number (menu_items_n_panes),
153 make_number (menu_items_submenu_depth));
154 record_unwind_protect (restore_menu_items, saved);
155 menu_items_inuse = Qnil;
156 menu_items = Qnil;
160 /* Make the menu_items vector twice as large. */
162 static void
163 grow_menu_items ()
165 menu_items_allocated *= 2;
166 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
169 /* Begin a submenu. */
171 static void
172 push_submenu_start ()
174 if (menu_items_used + 1 > menu_items_allocated)
175 grow_menu_items ();
177 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
178 menu_items_submenu_depth++;
181 /* End a submenu. */
183 static void
184 push_submenu_end ()
186 if (menu_items_used + 1 > menu_items_allocated)
187 grow_menu_items ();
189 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
190 menu_items_submenu_depth--;
193 /* Indicate boundary between left and right. */
195 static void
196 push_left_right_boundary ()
198 if (menu_items_used + 1 > menu_items_allocated)
199 grow_menu_items ();
201 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
204 /* Start a new menu pane in menu_items.
205 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
207 static void
208 push_menu_pane (name, prefix_vec)
209 Lisp_Object name, prefix_vec;
211 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
212 grow_menu_items ();
214 if (menu_items_submenu_depth == 0)
215 menu_items_n_panes++;
216 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
217 XVECTOR (menu_items)->contents[menu_items_used++] = name;
218 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
221 /* Push one menu item into the current pane. NAME is the string to
222 display. ENABLE if non-nil means this item can be selected. KEY
223 is the key generated by choosing this item, or nil if this item
224 doesn't really have a definition. DEF is the definition of this
225 item. EQUIV is the textual description of the keyboard equivalent
226 for this item (or nil if none). TYPE is the type of this menu
227 item, one of nil, `toggle' or `radio'. */
229 static void
230 push_menu_item (name, enable, key, def, equiv, type, selected, help)
231 Lisp_Object name, enable, key, def, equiv, type, selected, help;
233 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
234 grow_menu_items ();
236 XVECTOR (menu_items)->contents[menu_items_used++] = name;
237 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
238 XVECTOR (menu_items)->contents[menu_items_used++] = key;
239 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
240 XVECTOR (menu_items)->contents[menu_items_used++] = def;
241 XVECTOR (menu_items)->contents[menu_items_used++] = type;
242 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
243 XVECTOR (menu_items)->contents[menu_items_used++] = help;
246 /* Args passed between single_keymap_panes and single_menu_item. */
247 struct skp
249 Lisp_Object pending_maps;
250 int maxdepth, notreal;
251 int notbuttons;
254 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
255 void *));
257 /* This is a recursive subroutine of keymap_panes.
258 It handles one keymap, KEYMAP.
259 The other arguments are passed along
260 or point to local variables of the previous function.
261 If NOTREAL is nonzero, only check for equivalent key bindings, don't
262 evaluate expressions in menu items and don't make any menu.
264 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
266 static void
267 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
268 Lisp_Object keymap;
269 Lisp_Object pane_name;
270 Lisp_Object prefix;
271 int notreal;
272 int maxdepth;
274 struct skp skp;
275 struct gcpro gcpro1;
277 skp.pending_maps = Qnil;
278 skp.maxdepth = maxdepth;
279 skp.notreal = notreal;
280 skp.notbuttons = 0;
282 if (maxdepth <= 0)
283 return;
285 push_menu_pane (pane_name, prefix);
287 #ifndef HAVE_BOXES
288 /* Remember index for first item in this pane so we can go back and
289 add a prefix when (if) we see the first button. After that, notbuttons
290 is set to 0, to mark that we have seen a button and all non button
291 items need a prefix. */
292 skp.notbuttons = menu_items_used;
293 #endif
295 GCPRO1 (skp.pending_maps);
296 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
297 UNGCPRO;
299 /* Process now any submenus which want to be panes at this level. */
300 while (CONSP (skp.pending_maps))
302 Lisp_Object elt, eltcdr, string;
303 elt = XCAR (skp.pending_maps);
304 eltcdr = XCDR (elt);
305 string = XCAR (eltcdr);
306 /* We no longer discard the @ from the beginning of the string here.
307 Instead, we do this in *menu_show. */
308 single_keymap_panes (Fcar (elt), string,
309 XCDR (eltcdr), notreal, maxdepth - 1);
310 skp.pending_maps = XCDR (skp.pending_maps);
314 /* This is a subroutine of single_keymap_panes that handles one
315 keymap entry.
316 KEY is a key in a keymap and ITEM is its binding.
317 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
318 separate panes.
319 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
320 evaluate expressions in menu items and don't make any menu.
321 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. */
323 static void
324 single_menu_item (key, item, dummy, skp_v)
325 Lisp_Object key, item, dummy;
326 void *skp_v;
328 Lisp_Object map, item_string, enabled;
329 struct gcpro gcpro1, gcpro2;
330 int res;
331 struct skp *skp = skp_v;
333 /* Parse the menu item and leave the result in item_properties. */
334 GCPRO2 (key, item);
335 res = parse_menu_item (item, skp->notreal, 0);
336 UNGCPRO;
337 if (!res)
338 return; /* Not a menu item. */
340 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
342 if (skp->notreal)
344 /* We don't want to make a menu, just traverse the keymaps to
345 precompute equivalent key bindings. */
346 if (!NILP (map))
347 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
348 return;
351 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
352 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
354 if (!NILP (map) && SREF (item_string, 0) == '@')
356 if (!NILP (enabled))
357 /* An enabled separate pane. Remember this to handle it later. */
358 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
359 skp->pending_maps);
360 return;
363 #ifdef HAVE_X_WINDOWS
364 #ifndef HAVE_BOXES
365 /* Simulate radio buttons and toggle boxes by putting a prefix in
366 front of them. */
368 Lisp_Object prefix = Qnil;
369 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
370 if (!NILP (type))
372 Lisp_Object selected
373 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
375 if (skp->notbuttons)
376 /* The first button. Line up previous items in this menu. */
378 int index = skp->notbuttons; /* Index for first item this menu. */
379 int submenu = 0;
380 Lisp_Object tem;
381 while (index < menu_items_used)
384 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
385 if (NILP (tem))
387 index++;
388 submenu++; /* Skip sub menu. */
390 else if (EQ (tem, Qlambda))
392 index++;
393 submenu--; /* End sub menu. */
395 else if (EQ (tem, Qt))
396 index += 3; /* Skip new pane marker. */
397 else if (EQ (tem, Qquote))
398 index++; /* Skip a left, right divider. */
399 else
401 if (!submenu && SREF (tem, 0) != '\0'
402 && SREF (tem, 0) != '-')
403 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
404 = concat2 (build_string (" "), tem);
405 index += MENU_ITEMS_ITEM_LENGTH;
408 skp->notbuttons = 0;
411 /* Calculate prefix, if any, for this item. */
412 if (EQ (type, QCtoggle))
413 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
414 else if (EQ (type, QCradio))
415 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
417 /* Not a button. If we have earlier buttons, then we need a prefix. */
418 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
419 && SREF (item_string, 0) != '-')
420 prefix = build_string (" ");
422 if (!NILP (prefix))
423 item_string = concat2 (prefix, item_string);
425 #endif /* not HAVE_BOXES */
427 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
428 if (!NILP (map))
429 /* Indicate visually that this is a submenu. */
430 item_string = concat2 (item_string, build_string (" >"));
431 #endif
433 #endif /* HAVE_X_WINDOWS */
435 push_menu_item (item_string, enabled, key,
436 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
437 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
438 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
439 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
440 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
442 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
443 /* Display a submenu using the toolkit. */
444 if (! (NILP (map) || NILP (enabled)))
446 push_submenu_start ();
447 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
448 push_submenu_end ();
450 #endif
453 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
454 and generate menu panes for them in menu_items.
455 If NOTREAL is nonzero,
456 don't bother really computing whether an item is enabled. */
458 void
459 keymap_panes (keymaps, nmaps, notreal)
460 Lisp_Object *keymaps;
461 int nmaps;
462 int notreal;
464 int mapno;
466 init_menu_items ();
468 /* Loop over the given keymaps, making a pane for each map.
469 But don't make a pane that is empty--ignore that map instead.
470 P is the number of panes we have made so far. */
471 for (mapno = 0; mapno < nmaps; mapno++)
472 single_keymap_panes (keymaps[mapno],
473 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
475 finish_menu_items ();
479 /* Push the items in a single pane defined by the alist PANE. */
480 static void
481 list_of_items (pane)
482 Lisp_Object pane;
484 Lisp_Object tail, item, item1;
486 for (tail = pane; CONSP (tail); tail = XCDR (tail))
488 item = XCAR (tail);
489 if (STRINGP (item))
490 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
491 Qnil, Qnil, Qnil, Qnil);
492 else if (CONSP (item))
494 item1 = XCAR (item);
495 CHECK_STRING (item1);
496 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
497 Qt, Qnil, Qnil, Qnil, Qnil);
499 else
500 push_left_right_boundary ();
505 /* Push all the panes and items of a menu described by the
506 alist-of-alists MENU.
507 This handles old-fashioned calls to x-popup-menu. */
508 void
509 list_of_panes (menu)
510 Lisp_Object menu;
512 Lisp_Object tail;
514 init_menu_items ();
516 for (tail = menu; CONSP (tail); tail = XCDR (tail))
518 Lisp_Object elt, pane_name, pane_data;
519 elt = XCAR (tail);
520 pane_name = Fcar (elt);
521 CHECK_STRING (pane_name);
522 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
523 pane_data = Fcdr (elt);
524 CHECK_CONS (pane_data);
525 list_of_items (pane_data);
528 finish_menu_items ();
531 /* Set up data in menu_items for a menu bar item
532 whose event type is ITEM_KEY (with string ITEM_NAME)
533 and whose contents come from the list of keymaps MAPS. */
535 parse_single_submenu (item_key, item_name, maps)
536 Lisp_Object item_key, item_name, maps;
538 Lisp_Object length;
539 int len;
540 Lisp_Object *mapvec;
541 int i;
542 int top_level_items = 0;
544 length = Flength (maps);
545 len = XINT (length);
547 /* Convert the list MAPS into a vector MAPVEC. */
548 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
549 for (i = 0; i < len; i++)
551 mapvec[i] = Fcar (maps);
552 maps = Fcdr (maps);
555 /* Loop over the given keymaps, making a pane for each map.
556 But don't make a pane that is empty--ignore that map instead. */
557 for (i = 0; i < len; i++)
559 if (!KEYMAPP (mapvec[i]))
561 /* Here we have a command at top level in the menu bar
562 as opposed to a submenu. */
563 top_level_items = 1;
564 push_menu_pane (Qnil, Qnil);
565 push_menu_item (item_name, Qt, item_key, mapvec[i],
566 Qnil, Qnil, Qnil, Qnil);
568 else
570 Lisp_Object prompt;
571 prompt = Fkeymap_prompt (mapvec[i]);
572 single_keymap_panes (mapvec[i],
573 !NILP (prompt) ? prompt : item_name,
574 item_key, 0, 10);
578 return top_level_items;
582 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
584 /* Allocate a widget_value, blocking input. */
586 widget_value *
587 xmalloc_widget_value ()
589 widget_value *value;
591 BLOCK_INPUT;
592 value = malloc_widget_value ();
593 UNBLOCK_INPUT;
595 return value;
598 /* This recursively calls free_widget_value on the tree of widgets.
599 It must free all data that was malloc'ed for these widget_values.
600 In Emacs, many slots are pointers into the data of Lisp_Strings, and
601 must be left alone. */
603 void
604 free_menubar_widget_value_tree (wv)
605 widget_value *wv;
607 if (! wv) return;
609 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
611 if (wv->contents && (wv->contents != (widget_value*)1))
613 free_menubar_widget_value_tree (wv->contents);
614 wv->contents = (widget_value *) 0xDEADBEEF;
616 if (wv->next)
618 free_menubar_widget_value_tree (wv->next);
619 wv->next = (widget_value *) 0xDEADBEEF;
621 BLOCK_INPUT;
622 free_widget_value (wv);
623 UNBLOCK_INPUT;
626 /* Create a tree of widget_value objects
627 representing the panes and items
628 in menu_items starting at index START, up to index END. */
630 widget_value *
631 digest_single_submenu (start, end, top_level_items)
632 int start, end, top_level_items;
634 widget_value *wv, *prev_wv, *save_wv, *first_wv;
635 int i;
636 int submenu_depth = 0;
637 widget_value **submenu_stack;
638 int panes_seen = 0;
640 submenu_stack
641 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
642 wv = xmalloc_widget_value ();
643 wv->name = "menu";
644 wv->value = 0;
645 wv->enabled = 1;
646 wv->button_type = BUTTON_TYPE_NONE;
647 wv->help = Qnil;
648 first_wv = wv;
649 save_wv = 0;
650 prev_wv = 0;
652 /* Loop over all panes and items made by the preceding call
653 to parse_single_submenu and construct a tree of widget_value objects.
654 Ignore the panes and items used by previous calls to
655 digest_single_submenu, even though those are also in menu_items. */
656 i = start;
657 while (i < end)
659 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
661 submenu_stack[submenu_depth++] = save_wv;
662 save_wv = prev_wv;
663 prev_wv = 0;
664 i++;
666 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
668 prev_wv = save_wv;
669 save_wv = submenu_stack[--submenu_depth];
670 i++;
672 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
673 && submenu_depth != 0)
674 i += MENU_ITEMS_PANE_LENGTH;
675 /* Ignore a nil in the item list.
676 It's meaningful only for dialog boxes. */
677 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
678 i += 1;
679 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
681 /* Create a new pane. */
682 Lisp_Object pane_name, prefix;
683 char *pane_string;
685 panes_seen++;
687 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
688 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
690 #ifdef HAVE_NTGUI
691 if (STRINGP (pane_name))
693 if (unicode_append_menu)
694 /* Encode as UTF-8 for now. */
695 pane_name = ENCODE_UTF_8 (pane_name);
696 else if (STRING_MULTIBYTE (pane_name))
697 pane_name = ENCODE_SYSTEM (pane_name);
699 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
701 #elif !defined (HAVE_MULTILINGUAL_MENU)
702 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
704 pane_name = ENCODE_MENU_STRING (pane_name);
705 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
707 #endif
709 pane_string = (NILP (pane_name)
710 ? "" : (char *) SDATA (pane_name));
711 /* If there is just one top-level pane, put all its items directly
712 under the top-level menu. */
713 if (menu_items_n_panes == 1)
714 pane_string = "";
716 /* If the pane has a meaningful name,
717 make the pane a top-level menu item
718 with its items as a submenu beneath it. */
719 if (strcmp (pane_string, ""))
721 wv = xmalloc_widget_value ();
722 if (save_wv)
723 save_wv->next = wv;
724 else
725 first_wv->contents = wv;
726 wv->lname = pane_name;
727 /* Set value to 1 so update_submenu_strings can handle '@' */
728 wv->value = (char *)1;
729 wv->enabled = 1;
730 wv->button_type = BUTTON_TYPE_NONE;
731 wv->help = Qnil;
732 save_wv = wv;
734 else
735 save_wv = first_wv;
737 prev_wv = 0;
738 i += MENU_ITEMS_PANE_LENGTH;
740 else
742 /* Create a new item within current pane. */
743 Lisp_Object item_name, enable, descrip, def, type, selected;
744 Lisp_Object help;
746 /* All items should be contained in panes. */
747 if (panes_seen == 0)
748 abort ();
750 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
751 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
752 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
753 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
754 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
755 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
756 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
758 #ifdef HAVE_NTGUI
759 if (STRINGP (item_name))
761 if (unicode_append_menu)
762 item_name = ENCODE_UTF_8 (item_name);
763 else if (STRING_MULTIBYTE (item_name))
764 item_name = ENCODE_SYSTEM (item_name);
766 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
769 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
771 descrip = ENCODE_SYSTEM (descrip);
772 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
774 #elif !defined (HAVE_MULTILINGUAL_MENU)
775 if (STRING_MULTIBYTE (item_name))
777 item_name = ENCODE_MENU_STRING (item_name);
778 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
781 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
783 descrip = ENCODE_MENU_STRING (descrip);
784 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
786 #endif
788 wv = xmalloc_widget_value ();
789 if (prev_wv)
790 prev_wv->next = wv;
791 else
792 save_wv->contents = wv;
794 wv->lname = item_name;
795 if (!NILP (descrip))
796 wv->lkey = descrip;
797 wv->value = 0;
798 /* The EMACS_INT cast avoids a warning. There's no problem
799 as long as pointers have enough bits to hold small integers. */
800 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
801 wv->enabled = !NILP (enable);
803 if (NILP (type))
804 wv->button_type = BUTTON_TYPE_NONE;
805 else if (EQ (type, QCradio))
806 wv->button_type = BUTTON_TYPE_RADIO;
807 else if (EQ (type, QCtoggle))
808 wv->button_type = BUTTON_TYPE_TOGGLE;
809 else
810 abort ();
812 wv->selected = !NILP (selected);
813 if (! STRINGP (help))
814 help = Qnil;
816 wv->help = help;
818 prev_wv = wv;
820 i += MENU_ITEMS_ITEM_LENGTH;
824 /* If we have just one "menu item"
825 that was originally a button, return it by itself. */
826 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
828 wv = first_wv->contents;
829 free_widget_value (first_wv);
830 return wv;
833 return first_wv;
836 /* Walk through the widget_value tree starting at FIRST_WV and update
837 the char * pointers from the corresponding lisp values.
838 We do this after building the whole tree, since GC may happen while the
839 tree is constructed, and small strings are relocated. So we must wait
840 until no GC can happen before storing pointers into lisp values. */
841 void
842 update_submenu_strings (first_wv)
843 widget_value *first_wv;
845 widget_value *wv;
847 for (wv = first_wv; wv; wv = wv->next)
849 if (STRINGP (wv->lname))
851 wv->name = (char *) SDATA (wv->lname);
853 /* Ignore the @ that means "separate pane".
854 This is a kludge, but this isn't worth more time. */
855 if (wv->value == (char *)1)
857 if (wv->name[0] == '@')
858 wv->name++;
859 wv->value = 0;
863 if (STRINGP (wv->lkey))
864 wv->key = (char *) SDATA (wv->lkey);
866 if (wv->contents)
867 update_submenu_strings (wv->contents);
871 /* Find the menu selection and store it in the keyboard buffer.
872 F is the frame the menu is on.
873 MENU_BAR_ITEMS_USED is the length of VECTOR.
874 VECTOR is an array of menu events for the whole menu. */
876 void
877 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
878 FRAME_PTR f;
879 EMACS_INT menu_bar_items_used;
880 Lisp_Object vector;
881 void *client_data;
883 Lisp_Object prefix, entry;
884 Lisp_Object *subprefix_stack;
885 int submenu_depth = 0;
886 int i;
888 entry = Qnil;
889 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
890 prefix = Qnil;
891 i = 0;
893 while (i < menu_bar_items_used)
895 if (EQ (XVECTOR (vector)->contents[i], Qnil))
897 subprefix_stack[submenu_depth++] = prefix;
898 prefix = entry;
899 i++;
901 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
903 prefix = subprefix_stack[--submenu_depth];
904 i++;
906 else if (EQ (XVECTOR (vector)->contents[i], Qt))
908 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
909 i += MENU_ITEMS_PANE_LENGTH;
911 else
913 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
914 /* The EMACS_INT cast avoids a warning. There's no problem
915 as long as pointers have enough bits to hold small integers. */
916 if ((int) (EMACS_INT) client_data == i)
918 int j;
919 struct input_event buf;
920 Lisp_Object frame;
921 EVENT_INIT (buf);
923 XSETFRAME (frame, f);
924 buf.kind = MENU_BAR_EVENT;
925 buf.frame_or_window = frame;
926 buf.arg = frame;
927 kbd_buffer_store_event (&buf);
929 for (j = 0; j < submenu_depth; j++)
930 if (!NILP (subprefix_stack[j]))
932 buf.kind = MENU_BAR_EVENT;
933 buf.frame_or_window = frame;
934 buf.arg = subprefix_stack[j];
935 kbd_buffer_store_event (&buf);
938 if (!NILP (prefix))
940 buf.kind = MENU_BAR_EVENT;
941 buf.frame_or_window = frame;
942 buf.arg = prefix;
943 kbd_buffer_store_event (&buf);
946 buf.kind = MENU_BAR_EVENT;
947 buf.frame_or_window = frame;
948 buf.arg = entry;
949 kbd_buffer_store_event (&buf);
951 return;
953 i += MENU_ITEMS_ITEM_LENGTH;
958 #endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NTGUI */
960 void
961 syms_of_menu ()
963 staticpro (&menu_items);
964 menu_items = Qnil;
965 menu_items_inuse = Qnil;
968 /* arch-tag: 78bbc7cf-8025-4156-aa8a-6c7fd99bf51d
969 (do not change this comment) */