* alloc.c: Do not define struct catchtag.
[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, 2009 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 #include <setjmp.h>
23
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"
31
32 #ifdef USE_X_TOOLKIT
33 #include "../lwlib/lwlib.h"
34 #endif
35
36 #ifdef HAVE_X_WINDOWS
37 #include "xterm.h"
38 #endif
39
40 #ifdef HAVE_NS
41 #include "nsterm.h"
42 #endif
43
44 #ifdef USE_GTK
45 #include "gtkutil.h"
46 #endif
47
48 #ifdef HAVE_NTGUI
49 #include "w32term.h"
50
51 extern AppendMenuW_Proc unicode_append_menu;
52
53 #endif /* HAVE_NTGUI */
54
55 #include "menu.h"
56
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
61
62 extern Lisp_Object QCtoggle, QCradio;
63
64 Lisp_Object menu_items;
65
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;
69
70 /* Number of slots currently allocated in menu_items. */
71 int menu_items_allocated;
72
73 /* This is the index in menu_items of the first empty slot. */
74 int menu_items_used;
75
76 /* The number of panes currently recorded in menu_items,
77 excluding those within submenus. */
78 int menu_items_n_panes;
79
80 /* Current depth within submenus. */
81 static int menu_items_submenu_depth;
82
83 void
84 init_menu_items ()
85 {
86 if (!NILP (menu_items_inuse))
87 error ("Trying to use a menu from within a menu-entry");
88
89 if (NILP (menu_items))
90 {
91 menu_items_allocated = 60;
92 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
93 }
94
95 menu_items_inuse = Qt;
96 menu_items_used = 0;
97 menu_items_n_panes = 0;
98 menu_items_submenu_depth = 0;
99 }
100
101 /* Call at the end of generating the data in menu_items. */
102
103 void
104 finish_menu_items ()
105 {
106 }
107
108 Lisp_Object
109 unuse_menu_items (dummy)
110 Lisp_Object dummy;
111 {
112 return menu_items_inuse = Qnil;
113 }
114
115 /* Call when finished using the data for the current menu
116 in menu_items. */
117
118 void
119 discard_menu_items ()
120 {
121 /* Free the structure if it is especially large.
122 Otherwise, hold on to it, to save time. */
123 if (menu_items_allocated > 200)
124 {
125 menu_items = Qnil;
126 menu_items_allocated = 0;
127 }
128 xassert (NILP (menu_items_inuse));
129 }
130
131 /* This undoes save_menu_items, and it is called by the specpdl unwind
132 mechanism. */
133
134 static Lisp_Object
135 restore_menu_items (saved)
136 Lisp_Object saved;
137 {
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;
148 }
149
150 /* Push the whole state of menu_items processing onto the specpdl.
151 It will be restored when the specpdl is unwound. */
152
153 void
154 save_menu_items ()
155 {
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;
163 }
164
165 \f
166 /* Make the menu_items vector twice as large. */
167
168 static void
169 grow_menu_items ()
170 {
171 menu_items_allocated *= 2;
172 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
173 }
174
175 /* Begin a submenu. */
176
177 static void
178 push_submenu_start ()
179 {
180 if (menu_items_used + 1 > menu_items_allocated)
181 grow_menu_items ();
182
183 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
184 menu_items_submenu_depth++;
185 }
186
187 /* End a submenu. */
188
189 static void
190 push_submenu_end ()
191 {
192 if (menu_items_used + 1 > menu_items_allocated)
193 grow_menu_items ();
194
195 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
196 menu_items_submenu_depth--;
197 }
198
199 /* Indicate boundary between left and right. */
200
201 static void
202 push_left_right_boundary ()
203 {
204 if (menu_items_used + 1 > menu_items_allocated)
205 grow_menu_items ();
206
207 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
208 }
209
210 /* Start a new menu pane in menu_items.
211 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
212
213 static void
214 push_menu_pane (name, prefix_vec)
215 Lisp_Object name, prefix_vec;
216 {
217 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
218 grow_menu_items ();
219
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;
225 }
226
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'. */
234
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;
238 {
239 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
240 grow_menu_items ();
241
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;
250 }
251
252 /* Args passed between single_keymap_panes and single_menu_item. */
253 struct skp
254 {
255 Lisp_Object pending_maps;
256 int maxdepth, notreal;
257 int notbuttons;
258 };
259
260 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
261 void *));
262
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.
269
270 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
271
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;
279 {
280 struct skp skp;
281 struct gcpro gcpro1;
282
283 skp.pending_maps = Qnil;
284 skp.maxdepth = maxdepth;
285 skp.notreal = notreal;
286 skp.notbuttons = 0;
287
288 if (maxdepth <= 0)
289 return;
290
291 push_menu_pane (pane_name, prefix);
292
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
300
301 GCPRO1 (skp.pending_maps);
302 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
303 UNGCPRO;
304
305 /* Process now any submenus which want to be panes at this level. */
306 while (CONSP (skp.pending_maps))
307 {
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);
317 }
318 }
319
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. */
328
329 static void
330 single_menu_item (key, item, dummy, skp_v)
331 Lisp_Object key, item, dummy;
332 void *skp_v;
333 {
334 Lisp_Object map, item_string, enabled;
335 struct gcpro gcpro1, gcpro2;
336 int res;
337 struct skp *skp = skp_v;
338
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. */
345
346 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
347
348 if (skp->notreal)
349 {
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;
355 }
356
357 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
358 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
359
360 if (!NILP (map) && SREF (item_string, 0) == '@')
361 {
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;
367 }
368
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. */
373 {
374 Lisp_Object prefix = Qnil;
375 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
376 if (!NILP (type))
377 {
378 Lisp_Object selected
379 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
380
381 if (skp->notbuttons)
382 /* The first button. Line up previous items in this menu. */
383 {
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)
388 {
389 tem
390 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
391 if (NILP (tem))
392 {
393 index++;
394 submenu++; /* Skip sub menu. */
395 }
396 else if (EQ (tem, Qlambda))
397 {
398 index++;
399 submenu--; /* End sub menu. */
400 }
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
406 {
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;
412 }
413 }
414 skp->notbuttons = 0;
415 }
416
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) ? "( ) " : "(*) ");
422 }
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 (" ");
427
428 if (!NILP (prefix))
429 item_string = concat2 (prefix, item_string);
430 }
431 #endif /* not HAVE_BOXES */
432
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
438
439 #endif /* HAVE_X_WINDOWS || MSDOS */
440
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]);
447
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)))
451 {
452 push_submenu_start ();
453 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
454 push_submenu_end ();
455 }
456 #endif
457 }
458
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. */
463
464 void
465 keymap_panes (keymaps, nmaps, notreal)
466 Lisp_Object *keymaps;
467 int nmaps;
468 int notreal;
469 {
470 int mapno;
471
472 init_menu_items ();
473
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);
480
481 finish_menu_items ();
482 }
483
484
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;
489 {
490 Lisp_Object tail, item, item1;
491
492 for (tail = pane; CONSP (tail); tail = XCDR (tail))
493 {
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))
499 {
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);
504 }
505 else
506 push_left_right_boundary ();
507
508 }
509 }
510
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;
517 {
518 Lisp_Object tail;
519
520 init_menu_items ();
521
522 for (tail = menu; CONSP (tail); tail = XCDR (tail))
523 {
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);
532 }
533
534 finish_menu_items ();
535 }
536
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. */
540 int
541 parse_single_submenu (item_key, item_name, maps)
542 Lisp_Object item_key, item_name, maps;
543 {
544 Lisp_Object length;
545 int len;
546 Lisp_Object *mapvec;
547 int i;
548 int top_level_items = 0;
549
550 length = Flength (maps);
551 len = XINT (length);
552
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++)
556 {
557 mapvec[i] = Fcar (maps);
558 maps = Fcdr (maps);
559 }
560
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++)
564 {
565 if (!KEYMAPP (mapvec[i]))
566 {
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);
573 }
574 else
575 {
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);
581 }
582 }
583
584 return top_level_items;
585 }
586
587 \f
588 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
589
590 /* Allocate a widget_value, blocking input. */
591
592 widget_value *
593 xmalloc_widget_value ()
594 {
595 widget_value *value;
596
597 BLOCK_INPUT;
598 value = malloc_widget_value ();
599 UNBLOCK_INPUT;
600
601 return value;
602 }
603
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. */
608
609 void
610 free_menubar_widget_value_tree (wv)
611 widget_value *wv;
612 {
613 if (! wv) return;
614
615 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
616
617 if (wv->contents && (wv->contents != (widget_value*)1))
618 {
619 free_menubar_widget_value_tree (wv->contents);
620 wv->contents = (widget_value *) 0xDEADBEEF;
621 }
622 if (wv->next)
623 {
624 free_menubar_widget_value_tree (wv->next);
625 wv->next = (widget_value *) 0xDEADBEEF;
626 }
627 BLOCK_INPUT;
628 free_widget_value (wv);
629 UNBLOCK_INPUT;
630 }
631
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. */
635
636 widget_value *
637 digest_single_submenu (start, end, top_level_items)
638 int start, end, top_level_items;
639 {
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;
645
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;
657
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)
664 {
665 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
666 {
667 submenu_stack[submenu_depth++] = save_wv;
668 save_wv = prev_wv;
669 prev_wv = 0;
670 i++;
671 }
672 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
673 {
674 prev_wv = save_wv;
675 save_wv = submenu_stack[--submenu_depth];
676 i++;
677 }
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))
686 {
687 /* Create a new pane. */
688 Lisp_Object pane_name, prefix;
689 char *pane_string;
690
691 panes_seen++;
692
693 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
694 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
695
696 #ifdef HAVE_NTGUI
697 if (STRINGP (pane_name))
698 {
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);
704
705 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
706 }
707 #elif !defined (HAVE_MULTILINGUAL_MENU)
708 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
709 {
710 pane_name = ENCODE_MENU_STRING (pane_name);
711 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
712 }
713 #endif
714
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 = "";
721
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, ""))
726 {
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;
739 }
740 else
741 save_wv = first_wv;
742
743 prev_wv = 0;
744 i += MENU_ITEMS_PANE_LENGTH;
745 }
746 else
747 {
748 /* Create a new item within current pane. */
749 Lisp_Object item_name, enable, descrip, def, type, selected;
750 Lisp_Object help;
751
752 /* All items should be contained in panes. */
753 if (panes_seen == 0)
754 abort ();
755
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);
763
764 #ifdef HAVE_NTGUI
765 if (STRINGP (item_name))
766 {
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);
771
772 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
773 }
774
775 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
776 {
777 descrip = ENCODE_SYSTEM (descrip);
778 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
779 }
780 #elif !defined (HAVE_MULTILINGUAL_MENU)
781 if (STRING_MULTIBYTE (item_name))
782 {
783 item_name = ENCODE_MENU_STRING (item_name);
784 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
785 }
786
787 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
788 {
789 descrip = ENCODE_MENU_STRING (descrip);
790 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
791 }
792 #endif
793
794 wv = xmalloc_widget_value ();
795 if (prev_wv)
796 prev_wv->next = wv;
797 else
798 save_wv->contents = wv;
799
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);
808
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 ();
817
818 wv->selected = !NILP (selected);
819 if (! STRINGP (help))
820 help = Qnil;
821
822 wv->help = help;
823
824 prev_wv = wv;
825
826 i += MENU_ITEMS_ITEM_LENGTH;
827 }
828 }
829
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)
833 {
834 wv = first_wv->contents;
835 free_widget_value (first_wv);
836 return wv;
837 }
838
839 return first_wv;
840 }
841
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;
850 {
851 widget_value *wv;
852
853 for (wv = first_wv; wv; wv = wv->next)
854 {
855 if (STRINGP (wv->lname))
856 {
857 wv->name = (char *) SDATA (wv->lname);
858
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)
862 {
863 if (wv->name[0] == '@')
864 wv->name++;
865 wv->value = 0;
866 }
867 }
868
869 if (STRINGP (wv->lkey))
870 wv->key = (char *) SDATA (wv->lkey);
871
872 if (wv->contents)
873 update_submenu_strings (wv->contents);
874 }
875 }
876
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. */
881
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;
888 {
889 Lisp_Object prefix, entry;
890 Lisp_Object *subprefix_stack;
891 int submenu_depth = 0;
892 int i;
893
894 entry = Qnil;
895 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
896 prefix = Qnil;
897 i = 0;
898
899 while (i < menu_bar_items_used)
900 {
901 if (EQ (XVECTOR (vector)->contents[i], Qnil))
902 {
903 subprefix_stack[submenu_depth++] = prefix;
904 prefix = entry;
905 i++;
906 }
907 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
908 {
909 prefix = subprefix_stack[--submenu_depth];
910 i++;
911 }
912 else if (EQ (XVECTOR (vector)->contents[i], Qt))
913 {
914 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
915 i += MENU_ITEMS_PANE_LENGTH;
916 }
917 else
918 {
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)
923 {
924 int j;
925 struct input_event buf;
926 Lisp_Object frame;
927 EVENT_INIT (buf);
928
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);
934
935 for (j = 0; j < submenu_depth; j++)
936 if (!NILP (subprefix_stack[j]))
937 {
938 buf.kind = MENU_BAR_EVENT;
939 buf.frame_or_window = frame;
940 buf.arg = subprefix_stack[j];
941 kbd_buffer_store_event (&buf);
942 }
943
944 if (!NILP (prefix))
945 {
946 buf.kind = MENU_BAR_EVENT;
947 buf.frame_or_window = frame;
948 buf.arg = prefix;
949 kbd_buffer_store_event (&buf);
950 }
951
952 buf.kind = MENU_BAR_EVENT;
953 buf.frame_or_window = frame;
954 buf.arg = entry;
955 kbd_buffer_store_event (&buf);
956
957 return;
958 }
959 i += MENU_ITEMS_ITEM_LENGTH;
960 }
961 }
962 }
963
964 #endif /* USE_X_TOOLKIT || USE_GTK || HAVE_NS || HAVE_NTGUI */
965
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)
971 {
972 Lisp_Object prefix, entry;
973 int i;
974 Lisp_Object *subprefix_stack;
975 int submenu_depth = 0;
976
977 prefix = entry = Qnil;
978 i = 0;
979 subprefix_stack =
980 (Lisp_Object *)alloca(menu_items_used * sizeof (Lisp_Object));
981
982 while (i < menu_items_used)
983 {
984 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
985 {
986 subprefix_stack[submenu_depth++] = prefix;
987 prefix = entry;
988 i++;
989 }
990 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
991 {
992 prefix = subprefix_stack[--submenu_depth];
993 i++;
994 }
995 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
996 {
997 prefix
998 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
999 i += MENU_ITEMS_PANE_LENGTH;
1000 }
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
1006 {
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]))
1010 {
1011 if (keymaps != 0)
1012 {
1013 int j;
1014
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);
1021 }
1022 return entry;
1023 }
1024 i += MENU_ITEMS_ITEM_LENGTH;
1025 }
1026 }
1027 return Qnil;
1028 }
1029 #endif /* HAVE_NS */
1030
1031 void
1032 syms_of_menu ()
1033 {
1034 staticpro (&menu_items);
1035 menu_items = Qnil;
1036 menu_items_inuse = Qnil;
1037 }
1038
1039 /* arch-tag: 78bbc7cf-8025-4156-aa8a-6c7fd99bf51d
1040 (do not change this comment) */