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