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