comparison src/xmenu.c @ 95647:0f6a0e86ee24

Remove platform-independent menu definitions. (menu_items menu_items_inuse, menu_items_allocated) (menu_items_used, menu_items_n_panes) (menu_items_submenu_depth): Move to keyboard.h. (init_menu_items, finish_menu_items, unuse_menu_items) (discard_menu_items, restore_menu_items, save_menu_items) (grow_menu_items, push_submenu_start, push_submenu_end) (push_left_right_boundary, push_menu_pane, push_menu_item) (keymap_panes, single_keymap_panes, single_menu_item) (list_of_panes, list_of_items, find_and_call_menu_selection) (xmalloc_widget_value, free_menubar_widget_value_tree) (parse_single_submenu, digest_single_submenu) (update_submenu_strings): Move to menu.c.
author Chong Yidong <cyd@stupidchicken.com>
date Sun, 08 Jun 2008 04:36:46 +0000
parents 8971ddf55736
children c3a24b1a8412
comparison
equal deleted inserted replaced
95646:816ec0114c3c 95647:0f6a0e86ee24
120 120
121 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, 121 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
122 char **)); 122 char **));
123 static void popup_get_selection P_ ((XEvent *, struct x_display_info *, 123 static void popup_get_selection P_ ((XEvent *, struct x_display_info *,
124 LWLIB_ID, int)); 124 LWLIB_ID, int));
125
126 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */
127
128 #define HAVE_BOXES 1
129 #endif /* USE_X_TOOLKIT */ 125 #endif /* USE_X_TOOLKIT */
130 126
131 #ifdef USE_GTK 127 #ifdef USE_GTK
132 #include "gtkutil.h" 128 #include "gtkutil.h"
133 #define HAVE_BOXES 1
134 extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); 129 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
135 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, 130 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object,
136 char **)); 131 char **));
137 #endif 132 #endif
138 133
139 /* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
140 isn't defined. The use of HAVE_MULTILINGUAL_MENU could probably be
141 confined to an extended version of this with sections of code below
142 using it unconditionally. */
143 #ifdef USE_GTK
144 /* gtk just uses utf-8. */
145 # define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
146 #elif defined HAVE_X_I18N
147 # define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
148 #else
149 # define ENCODE_MENU_STRING(str) string_make_unibyte (str)
150 #endif
151
152 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
153 Lisp_Object, Lisp_Object, Lisp_Object,
154 Lisp_Object, Lisp_Object));
155 static int update_frame_menubar P_ ((struct frame *)); 134 static int update_frame_menubar P_ ((struct frame *));
156 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, 135 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
157 Lisp_Object, char **)); 136 Lisp_Object, char **));
158 static void keymap_panes P_ ((Lisp_Object *, int, int));
159 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
160 int, int));
161 static void list_of_panes P_ ((Lisp_Object));
162 static void list_of_items P_ ((Lisp_Object));
163
164 137
165 /* This holds a Lisp vector that holds the results of decoding
166 the keymaps or alist-of-alists that specify a menu.
167
168 It describes the panes and items within the panes.
169
170 Each pane is described by 3 elements in the vector:
171 t, the pane name, the pane's prefix key.
172 Then follow the pane's items, with 5 elements per item:
173 the item string, the enable flag, the item's value,
174 the definition, and the equivalent keyboard key's description string.
175
176 In some cases, multiple levels of menus may be described.
177 A single vector slot containing nil indicates the start of a submenu.
178 A single vector slot containing lambda indicates the end of a submenu.
179 The submenu follows a menu item which is the way to reach the submenu.
180
181 A single vector slot containing quote indicates that the
182 following items should appear on the right of a dialog box.
183
184 Using a Lisp vector to hold this information while we decode it
185 takes care of protecting all the data from GC. */
186
187 #define MENU_ITEMS_PANE_NAME 1
188 #define MENU_ITEMS_PANE_PREFIX 2
189 #define MENU_ITEMS_PANE_LENGTH 3
190
191 enum menu_item_idx
192 {
193 MENU_ITEMS_ITEM_NAME = 0,
194 MENU_ITEMS_ITEM_ENABLE,
195 MENU_ITEMS_ITEM_VALUE,
196 MENU_ITEMS_ITEM_EQUIV_KEY,
197 MENU_ITEMS_ITEM_DEFINITION,
198 MENU_ITEMS_ITEM_TYPE,
199 MENU_ITEMS_ITEM_SELECTED,
200 MENU_ITEMS_ITEM_HELP,
201 MENU_ITEMS_ITEM_LENGTH
202 };
203
204 static Lisp_Object menu_items;
205
206 /* If non-nil, means that the global vars defined here are already in use.
207 Used to detect cases where we try to re-enter this non-reentrant code. */
208 static Lisp_Object menu_items_inuse;
209
210 /* Number of slots currently allocated in menu_items. */
211 static int menu_items_allocated;
212
213 /* This is the index in menu_items of the first empty slot. */
214 static int menu_items_used;
215
216 /* The number of panes currently recorded in menu_items,
217 excluding those within submenus. */
218 static int menu_items_n_panes;
219
220 /* Current depth within submenus. */
221 static int menu_items_submenu_depth;
222
223 /* Flag which when set indicates a dialog or menu has been posted by 138 /* Flag which when set indicates a dialog or menu has been posted by
224 Xt on behalf of one of the widget sets. */ 139 Xt on behalf of one of the widget sets. */
225 static int popup_activated_flag; 140 static int popup_activated_flag;
226 141
227 static int next_menubar_widget_id; 142 static int next_menubar_widget_id;
143
144 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
145 extern widget_value *xmalloc_widget_value P_ ((void));
146 extern widget_value *digest_single_submenu P_ ((int, int, int));
147 #endif
228 148
229 /* This is set nonzero after the user activates the menu bar, and set 149 /* This is set nonzero after the user activates the menu bar, and set
230 to zero again after the menu bars are redisplayed by prepare_menu_bar. 150 to zero again after the menu bars are redisplayed by prepare_menu_bar.
231 While it is nonzero, all calls to set_frame_menubar go deep. 151 While it is nonzero, all calls to set_frame_menubar go deep.
232 152
259 } 179 }
260 return 0; 180 return 0;
261 } 181 }
262 182
263 #endif 183 #endif
264
265 /* Initialize the menu_items structure if we haven't already done so.
266 Also mark it as currently empty. */
267
268 static void
269 init_menu_items ()
270 {
271 if (!NILP (menu_items_inuse))
272 error ("Trying to use a menu from within a menu-entry");
273
274 if (NILP (menu_items))
275 {
276 menu_items_allocated = 60;
277 menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
278 }
279
280 menu_items_inuse = Qt;
281 menu_items_used = 0;
282 menu_items_n_panes = 0;
283 menu_items_submenu_depth = 0;
284 }
285
286 /* Call at the end of generating the data in menu_items. */
287
288 static void
289 finish_menu_items ()
290 {
291 }
292
293 static Lisp_Object
294 unuse_menu_items (dummy)
295 Lisp_Object dummy;
296 {
297 return menu_items_inuse = Qnil;
298 }
299
300 /* Call when finished using the data for the current menu
301 in menu_items. */
302
303 static void
304 discard_menu_items ()
305 {
306 /* Free the structure if it is especially large.
307 Otherwise, hold on to it, to save time. */
308 if (menu_items_allocated > 200)
309 {
310 menu_items = Qnil;
311 menu_items_allocated = 0;
312 }
313 xassert (NILP (menu_items_inuse));
314 }
315
316 /* This undoes save_menu_items, and it is called by the specpdl unwind
317 mechanism. */
318
319 static Lisp_Object
320 restore_menu_items (saved)
321 Lisp_Object saved;
322 {
323 menu_items = XCAR (saved);
324 menu_items_inuse = (! NILP (menu_items) ? Qt : Qnil);
325 menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
326 saved = XCDR (saved);
327 menu_items_used = XINT (XCAR (saved));
328 saved = XCDR (saved);
329 menu_items_n_panes = XINT (XCAR (saved));
330 saved = XCDR (saved);
331 menu_items_submenu_depth = XINT (XCAR (saved));
332 return Qnil;
333 }
334
335 /* Push the whole state of menu_items processing onto the specpdl.
336 It will be restored when the specpdl is unwound. */
337
338 static void
339 save_menu_items ()
340 {
341 Lisp_Object saved = list4 (!NILP (menu_items_inuse) ? menu_items : Qnil,
342 make_number (menu_items_used),
343 make_number (menu_items_n_panes),
344 make_number (menu_items_submenu_depth));
345 record_unwind_protect (restore_menu_items, saved);
346 menu_items_inuse = Qnil;
347 menu_items = Qnil;
348 }
349
350 /* Make the menu_items vector twice as large. */
351
352 static void
353 grow_menu_items ()
354 {
355 menu_items_allocated *= 2;
356 menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
357 }
358
359 /* Begin a submenu. */
360
361 static void
362 push_submenu_start ()
363 {
364 if (menu_items_used + 1 > menu_items_allocated)
365 grow_menu_items ();
366
367 XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
368 menu_items_submenu_depth++;
369 }
370
371 /* End a submenu. */
372
373 static void
374 push_submenu_end ()
375 {
376 if (menu_items_used + 1 > menu_items_allocated)
377 grow_menu_items ();
378
379 XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
380 menu_items_submenu_depth--;
381 }
382
383 /* Indicate boundary between left and right. */
384
385 static void
386 push_left_right_boundary ()
387 {
388 if (menu_items_used + 1 > menu_items_allocated)
389 grow_menu_items ();
390
391 XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
392 }
393
394 /* Start a new menu pane in menu_items.
395 NAME is the pane name. PREFIX_VEC is a prefix key for this pane. */
396
397 static void
398 push_menu_pane (name, prefix_vec)
399 Lisp_Object name, prefix_vec;
400 {
401 if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
402 grow_menu_items ();
403
404 if (menu_items_submenu_depth == 0)
405 menu_items_n_panes++;
406 XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
407 XVECTOR (menu_items)->contents[menu_items_used++] = name;
408 XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
409 }
410
411 /* Push one menu item into the current pane. NAME is the string to
412 display. ENABLE if non-nil means this item can be selected. KEY
413 is the key generated by choosing this item, or nil if this item
414 doesn't really have a definition. DEF is the definition of this
415 item. EQUIV is the textual description of the keyboard equivalent
416 for this item (or nil if none). TYPE is the type of this menu
417 item, one of nil, `toggle' or `radio'. */
418
419 static void
420 push_menu_item (name, enable, key, def, equiv, type, selected, help)
421 Lisp_Object name, enable, key, def, equiv, type, selected, help;
422 {
423 if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
424 grow_menu_items ();
425
426 XVECTOR (menu_items)->contents[menu_items_used++] = name;
427 XVECTOR (menu_items)->contents[menu_items_used++] = enable;
428 XVECTOR (menu_items)->contents[menu_items_used++] = key;
429 XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
430 XVECTOR (menu_items)->contents[menu_items_used++] = def;
431 XVECTOR (menu_items)->contents[menu_items_used++] = type;
432 XVECTOR (menu_items)->contents[menu_items_used++] = selected;
433 XVECTOR (menu_items)->contents[menu_items_used++] = help;
434 }
435
436 /* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
437 and generate menu panes for them in menu_items.
438 If NOTREAL is nonzero,
439 don't bother really computing whether an item is enabled. */
440
441 static void
442 keymap_panes (keymaps, nmaps, notreal)
443 Lisp_Object *keymaps;
444 int nmaps;
445 int notreal;
446 {
447 int mapno;
448
449 init_menu_items ();
450
451 /* Loop over the given keymaps, making a pane for each map.
452 But don't make a pane that is empty--ignore that map instead.
453 P is the number of panes we have made so far. */
454 for (mapno = 0; mapno < nmaps; mapno++)
455 single_keymap_panes (keymaps[mapno],
456 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
457
458 finish_menu_items ();
459 }
460
461 /* Args passed between single_keymap_panes and single_menu_item. */
462 struct skp
463 {
464 Lisp_Object pending_maps;
465 int maxdepth, notreal;
466 int notbuttons;
467 };
468
469 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
470 void *));
471
472 /* This is a recursive subroutine of keymap_panes.
473 It handles one keymap, KEYMAP.
474 The other arguments are passed along
475 or point to local variables of the previous function.
476 If NOTREAL is nonzero, only check for equivalent key bindings, don't
477 evaluate expressions in menu items and don't make any menu.
478
479 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
480
481 static void
482 single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
483 Lisp_Object keymap;
484 Lisp_Object pane_name;
485 Lisp_Object prefix;
486 int notreal;
487 int maxdepth;
488 {
489 struct skp skp;
490 struct gcpro gcpro1;
491
492 skp.pending_maps = Qnil;
493 skp.maxdepth = maxdepth;
494 skp.notreal = notreal;
495 skp.notbuttons = 0;
496
497 if (maxdepth <= 0)
498 return;
499
500 push_menu_pane (pane_name, prefix);
501
502 #ifndef HAVE_BOXES
503 /* Remember index for first item in this pane so we can go back and
504 add a prefix when (if) we see the first button. After that, notbuttons
505 is set to 0, to mark that we have seen a button and all non button
506 items need a prefix. */
507 skp.notbuttons = menu_items_used;
508 #endif
509
510 GCPRO1 (skp.pending_maps);
511 map_keymap_canonical (keymap, single_menu_item, Qnil, &skp);
512 UNGCPRO;
513
514 /* Process now any submenus which want to be panes at this level. */
515 while (CONSP (skp.pending_maps))
516 {
517 Lisp_Object elt, eltcdr, string;
518 elt = XCAR (skp.pending_maps);
519 eltcdr = XCDR (elt);
520 string = XCAR (eltcdr);
521 /* We no longer discard the @ from the beginning of the string here.
522 Instead, we do this in xmenu_show. */
523 single_keymap_panes (Fcar (elt), string,
524 XCDR (eltcdr), notreal, maxdepth - 1);
525 skp.pending_maps = XCDR (skp.pending_maps);
526 }
527 }
528
529 /* This is a subroutine of single_keymap_panes that handles one
530 keymap entry.
531 KEY is a key in a keymap and ITEM is its binding.
532 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
533 separate panes.
534 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
535 evaluate expressions in menu items and don't make any menu.
536 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them.
537 SKP->NOTBUTTONS is only used when simulating toggle boxes and radio
538 buttons. It keeps track of if we have seen a button in this menu or
539 not. */
540
541 static void
542 single_menu_item (key, item, dummy, skp_v)
543 Lisp_Object key, item, dummy;
544 void *skp_v;
545 {
546 Lisp_Object map, item_string, enabled;
547 struct gcpro gcpro1, gcpro2;
548 int res;
549 struct skp *skp = skp_v;
550
551 /* Parse the menu item and leave the result in item_properties. */
552 GCPRO2 (key, item);
553 res = parse_menu_item (item, skp->notreal, 0);
554 UNGCPRO;
555 if (!res)
556 return; /* Not a menu item. */
557
558 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
559
560 if (skp->notreal)
561 {
562 /* We don't want to make a menu, just traverse the keymaps to
563 precompute equivalent key bindings. */
564 if (!NILP (map))
565 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
566 return;
567 }
568
569 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
570 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
571
572 if (!NILP (map) && SREF (item_string, 0) == '@')
573 {
574 if (!NILP (enabled))
575 /* An enabled separate pane. Remember this to handle it later. */
576 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
577 skp->pending_maps);
578 return;
579 }
580
581 #ifndef HAVE_BOXES
582 /* Simulate radio buttons and toggle boxes by putting a prefix in
583 front of them. */
584 {
585 Lisp_Object prefix = Qnil;
586 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
587 if (!NILP (type))
588 {
589 Lisp_Object selected
590 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
591
592 if (skp->notbuttons)
593 /* The first button. Line up previous items in this menu. */
594 {
595 int index = skp->notbuttons; /* Index for first item this menu. */
596 int submenu = 0;
597 Lisp_Object tem;
598 while (index < menu_items_used)
599 {
600 tem
601 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
602 if (NILP (tem))
603 {
604 index++;
605 submenu++; /* Skip sub menu. */
606 }
607 else if (EQ (tem, Qlambda))
608 {
609 index++;
610 submenu--; /* End sub menu. */
611 }
612 else if (EQ (tem, Qt))
613 index += 3; /* Skip new pane marker. */
614 else if (EQ (tem, Qquote))
615 index++; /* Skip a left, right divider. */
616 else
617 {
618 if (!submenu && SREF (tem, 0) != '\0'
619 && SREF (tem, 0) != '-')
620 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
621 = concat2 (build_string (" "), tem);
622 index += MENU_ITEMS_ITEM_LENGTH;
623 }
624 }
625 skp->notbuttons = 0;
626 }
627
628 /* Calculate prefix, if any, for this item. */
629 if (EQ (type, QCtoggle))
630 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
631 else if (EQ (type, QCradio))
632 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
633 }
634 /* Not a button. If we have earlier buttons, then we need a prefix. */
635 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
636 && SREF (item_string, 0) != '-')
637 prefix = build_string (" ");
638
639 if (!NILP (prefix))
640 item_string = concat2 (prefix, item_string);
641 }
642 #endif /* not HAVE_BOXES */
643
644 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
645 if (!NILP (map))
646 /* Indicate visually that this is a submenu. */
647 item_string = concat2 (item_string, build_string (" >"));
648 #endif
649
650 push_menu_item (item_string, enabled, key,
651 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
652 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
653 XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
654 XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
655 XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
656
657 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
658 /* Display a submenu using the toolkit. */
659 if (! (NILP (map) || NILP (enabled)))
660 {
661 push_submenu_start ();
662 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
663 push_submenu_end ();
664 }
665 #endif
666 }
667
668 /* Push all the panes and items of a menu described by the
669 alist-of-alists MENU.
670 This handles old-fashioned calls to x-popup-menu. */
671
672 static void
673 list_of_panes (menu)
674 Lisp_Object menu;
675 {
676 Lisp_Object tail;
677
678 init_menu_items ();
679
680 for (tail = menu; CONSP (tail); tail = XCDR (tail))
681 {
682 Lisp_Object elt, pane_name, pane_data;
683 elt = XCAR (tail);
684 pane_name = Fcar (elt);
685 CHECK_STRING (pane_name);
686 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
687 pane_data = Fcdr (elt);
688 CHECK_CONS (pane_data);
689 list_of_items (pane_data);
690 }
691
692 finish_menu_items ();
693 }
694
695 /* Push the items in a single pane defined by the alist PANE. */
696
697 static void
698 list_of_items (pane)
699 Lisp_Object pane;
700 {
701 Lisp_Object tail, item, item1;
702
703 for (tail = pane; CONSP (tail); tail = XCDR (tail))
704 {
705 item = XCAR (tail);
706 if (STRINGP (item))
707 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
708 Qnil, Qnil, Qnil, Qnil);
709 else if (CONSP (item))
710 {
711 item1 = XCAR (item);
712 CHECK_STRING (item1);
713 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
714 Qt, Qnil, Qnil, Qnil, Qnil);
715 }
716 else
717 push_left_right_boundary ();
718
719 }
720 }
721 184
722 #ifdef HAVE_X_WINDOWS 185 #ifdef HAVE_X_WINDOWS
723 /* Return the mouse position in *X and *Y. The coordinates are window 186 /* Return the mouse position in *X and *Y. The coordinates are window
724 relative for the edit window in frame F. 187 relative for the edit window in frame F.
725 This is for Fx_popup_menu. The mouse_position_hook can not 188 This is for Fx_popup_menu. The mouse_position_hook can not
1618 1081
1619 show_help_event (f, widget, help); 1082 show_help_event (f, widget, help);
1620 } 1083 }
1621 #endif 1084 #endif
1622 1085
1623 /* Find the menu selection and store it in the keyboard buffer.
1624 F is the frame the menu is on.
1625 MENU_BAR_ITEMS_USED is the length of VECTOR.
1626 VECTOR is an array of menu events for the whole menu. */
1627
1628 static void
1629 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
1630 FRAME_PTR f;
1631 EMACS_INT menu_bar_items_used;
1632 Lisp_Object vector;
1633 void *client_data;
1634 {
1635 Lisp_Object prefix, entry;
1636 Lisp_Object *subprefix_stack;
1637 int submenu_depth = 0;
1638 int i;
1639
1640 entry = Qnil;
1641 subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
1642 prefix = Qnil;
1643 i = 0;
1644
1645 while (i < menu_bar_items_used)
1646 {
1647 if (EQ (XVECTOR (vector)->contents[i], Qnil))
1648 {
1649 subprefix_stack[submenu_depth++] = prefix;
1650 prefix = entry;
1651 i++;
1652 }
1653 else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
1654 {
1655 prefix = subprefix_stack[--submenu_depth];
1656 i++;
1657 }
1658 else if (EQ (XVECTOR (vector)->contents[i], Qt))
1659 {
1660 prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
1661 i += MENU_ITEMS_PANE_LENGTH;
1662 }
1663 else
1664 {
1665 entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
1666 /* The EMACS_INT cast avoids a warning. There's no problem
1667 as long as pointers have enough bits to hold small integers. */
1668 if ((int) (EMACS_INT) client_data == i)
1669 {
1670 int j;
1671 struct input_event buf;
1672 Lisp_Object frame;
1673 EVENT_INIT (buf);
1674
1675 XSETFRAME (frame, f);
1676 buf.kind = MENU_BAR_EVENT;
1677 buf.frame_or_window = frame;
1678 buf.arg = frame;
1679 kbd_buffer_store_event (&buf);
1680
1681 for (j = 0; j < submenu_depth; j++)
1682 if (!NILP (subprefix_stack[j]))
1683 {
1684 buf.kind = MENU_BAR_EVENT;
1685 buf.frame_or_window = frame;
1686 buf.arg = subprefix_stack[j];
1687 kbd_buffer_store_event (&buf);
1688 }
1689
1690 if (!NILP (prefix))
1691 {
1692 buf.kind = MENU_BAR_EVENT;
1693 buf.frame_or_window = frame;
1694 buf.arg = prefix;
1695 kbd_buffer_store_event (&buf);
1696 }
1697
1698 buf.kind = MENU_BAR_EVENT;
1699 buf.frame_or_window = frame;
1700 buf.arg = entry;
1701 kbd_buffer_store_event (&buf);
1702
1703 return;
1704 }
1705 i += MENU_ITEMS_ITEM_LENGTH;
1706 }
1707 }
1708 }
1709
1710
1711 #ifdef USE_GTK 1086 #ifdef USE_GTK
1712 /* Gtk calls callbacks just because we tell it what item should be 1087 /* Gtk calls callbacks just because we tell it what item should be
1713 selected in a radio group. If this variable is set to a non-zero 1088 selected in a radio group. If this variable is set to a non-zero
1714 value, we are creating menus and don't want callbacks right now. 1089 value, we are creating menus and don't want callbacks right now.
1715 */ 1090 */
1777 return; 1152 return;
1778 find_and_call_menu_selection (f, f->menu_bar_items_used, 1153 find_and_call_menu_selection (f, f->menu_bar_items_used,
1779 f->menu_bar_vector, client_data); 1154 f->menu_bar_vector, client_data);
1780 } 1155 }
1781 #endif /* not USE_GTK */ 1156 #endif /* not USE_GTK */
1782
1783 /* Allocate a widget_value, blocking input. */
1784
1785 widget_value *
1786 xmalloc_widget_value ()
1787 {
1788 widget_value *value;
1789
1790 BLOCK_INPUT;
1791 value = malloc_widget_value ();
1792 UNBLOCK_INPUT;
1793
1794 return value;
1795 }
1796
1797 /* This recursively calls free_widget_value on the tree of widgets.
1798 It must free all data that was malloc'ed for these widget_values.
1799 In Emacs, many slots are pointers into the data of Lisp_Strings, and
1800 must be left alone. */
1801
1802 void
1803 free_menubar_widget_value_tree (wv)
1804 widget_value *wv;
1805 {
1806 if (! wv) return;
1807
1808 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
1809
1810 if (wv->contents && (wv->contents != (widget_value*)1))
1811 {
1812 free_menubar_widget_value_tree (wv->contents);
1813 wv->contents = (widget_value *) 0xDEADBEEF;
1814 }
1815 if (wv->next)
1816 {
1817 free_menubar_widget_value_tree (wv->next);
1818 wv->next = (widget_value *) 0xDEADBEEF;
1819 }
1820 BLOCK_INPUT;
1821 free_widget_value (wv);
1822 UNBLOCK_INPUT;
1823 }
1824
1825 /* Set up data in menu_items for a menu bar item
1826 whose event type is ITEM_KEY (with string ITEM_NAME)
1827 and whose contents come from the list of keymaps MAPS. */
1828
1829 static int
1830 parse_single_submenu (item_key, item_name, maps)
1831 Lisp_Object item_key, item_name, maps;
1832 {
1833 Lisp_Object length;
1834 int len;
1835 Lisp_Object *mapvec;
1836 int i;
1837 int top_level_items = 0;
1838
1839 length = Flength (maps);
1840 len = XINT (length);
1841
1842 /* Convert the list MAPS into a vector MAPVEC. */
1843 mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
1844 for (i = 0; i < len; i++)
1845 {
1846 mapvec[i] = Fcar (maps);
1847 maps = Fcdr (maps);
1848 }
1849
1850 /* Loop over the given keymaps, making a pane for each map.
1851 But don't make a pane that is empty--ignore that map instead. */
1852 for (i = 0; i < len; i++)
1853 {
1854 if (!KEYMAPP (mapvec[i]))
1855 {
1856 /* Here we have a command at top level in the menu bar
1857 as opposed to a submenu. */
1858 top_level_items = 1;
1859 push_menu_pane (Qnil, Qnil);
1860 push_menu_item (item_name, Qt, item_key, mapvec[i],
1861 Qnil, Qnil, Qnil, Qnil);
1862 }
1863 else
1864 {
1865 Lisp_Object prompt;
1866 prompt = Fkeymap_prompt (mapvec[i]);
1867 single_keymap_panes (mapvec[i],
1868 !NILP (prompt) ? prompt : item_name,
1869 item_key, 0, 10);
1870 }
1871 }
1872
1873 return top_level_items;
1874 }
1875
1876 /* Create a tree of widget_value objects
1877 representing the panes and items
1878 in menu_items starting at index START, up to index END. */
1879
1880 static widget_value *
1881 digest_single_submenu (start, end, top_level_items)
1882 int start, end, top_level_items;
1883 {
1884 widget_value *wv, *prev_wv, *save_wv, *first_wv;
1885 int i;
1886 int submenu_depth = 0;
1887 widget_value **submenu_stack;
1888 int panes_seen = 0;
1889
1890 submenu_stack
1891 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
1892 wv = xmalloc_widget_value ();
1893 wv->name = "menu";
1894 wv->value = 0;
1895 wv->enabled = 1;
1896 wv->button_type = BUTTON_TYPE_NONE;
1897 wv->help = Qnil;
1898 first_wv = wv;
1899 save_wv = 0;
1900 prev_wv = 0;
1901
1902 /* Loop over all panes and items made by the preceding call
1903 to parse_single_submenu and construct a tree of widget_value objects.
1904 Ignore the panes and items used by previous calls to
1905 digest_single_submenu, even though those are also in menu_items. */
1906 i = start;
1907 while (i < end)
1908 {
1909 if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
1910 {
1911 submenu_stack[submenu_depth++] = save_wv;
1912 save_wv = prev_wv;
1913 prev_wv = 0;
1914 i++;
1915 }
1916 else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
1917 {
1918 prev_wv = save_wv;
1919 save_wv = submenu_stack[--submenu_depth];
1920 i++;
1921 }
1922 else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
1923 && submenu_depth != 0)
1924 i += MENU_ITEMS_PANE_LENGTH;
1925 /* Ignore a nil in the item list.
1926 It's meaningful only for dialog boxes. */
1927 else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
1928 i += 1;
1929 else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
1930 {
1931 /* Create a new pane. */
1932 Lisp_Object pane_name, prefix;
1933 char *pane_string;
1934
1935 panes_seen++;
1936
1937 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
1938 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
1939
1940 #ifndef HAVE_MULTILINGUAL_MENU
1941 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
1942 {
1943 pane_name = ENCODE_MENU_STRING (pane_name);
1944 ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
1945 }
1946 #endif
1947 pane_string = (NILP (pane_name)
1948 ? "" : (char *) SDATA (pane_name));
1949 /* If there is just one top-level pane, put all its items directly
1950 under the top-level menu. */
1951 if (menu_items_n_panes == 1)
1952 pane_string = "";
1953
1954 /* If the pane has a meaningful name,
1955 make the pane a top-level menu item
1956 with its items as a submenu beneath it. */
1957 if (strcmp (pane_string, ""))
1958 {
1959 wv = xmalloc_widget_value ();
1960 if (save_wv)
1961 save_wv->next = wv;
1962 else
1963 first_wv->contents = wv;
1964 wv->lname = pane_name;
1965 /* Set value to 1 so update_submenu_strings can handle '@' */
1966 wv->value = (char *)1;
1967 wv->enabled = 1;
1968 wv->button_type = BUTTON_TYPE_NONE;
1969 wv->help = Qnil;
1970 save_wv = wv;
1971 }
1972 else
1973 save_wv = first_wv;
1974
1975 prev_wv = 0;
1976 i += MENU_ITEMS_PANE_LENGTH;
1977 }
1978 else
1979 {
1980 /* Create a new item within current pane. */
1981 Lisp_Object item_name, enable, descrip, def, type, selected;
1982 Lisp_Object help;
1983
1984 /* All items should be contained in panes. */
1985 if (panes_seen == 0)
1986 abort ();
1987
1988 item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
1989 enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
1990 descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
1991 def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
1992 type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
1993 selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
1994 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
1995
1996 #ifndef HAVE_MULTILINGUAL_MENU
1997 if (STRING_MULTIBYTE (item_name))
1998 {
1999 item_name = ENCODE_MENU_STRING (item_name);
2000 ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
2001 }
2002
2003 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
2004 {
2005 descrip = ENCODE_MENU_STRING (descrip);
2006 ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
2007 }
2008 #endif /* not HAVE_MULTILINGUAL_MENU */
2009
2010 wv = xmalloc_widget_value ();
2011 if (prev_wv)
2012 prev_wv->next = wv;
2013 else
2014 save_wv->contents = wv;
2015
2016 wv->lname = item_name;
2017 if (!NILP (descrip))
2018 wv->lkey = descrip;
2019 wv->value = 0;
2020 /* The EMACS_INT cast avoids a warning. There's no problem
2021 as long as pointers have enough bits to hold small integers. */
2022 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
2023 wv->enabled = !NILP (enable);
2024
2025 if (NILP (type))
2026 wv->button_type = BUTTON_TYPE_NONE;
2027 else if (EQ (type, QCradio))
2028 wv->button_type = BUTTON_TYPE_RADIO;
2029 else if (EQ (type, QCtoggle))
2030 wv->button_type = BUTTON_TYPE_TOGGLE;
2031 else
2032 abort ();
2033
2034 wv->selected = !NILP (selected);
2035 if (! STRINGP (help))
2036 help = Qnil;
2037
2038 wv->help = help;
2039
2040 prev_wv = wv;
2041
2042 i += MENU_ITEMS_ITEM_LENGTH;
2043 }
2044 }
2045
2046 /* If we have just one "menu item"
2047 that was originally a button, return it by itself. */
2048 if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
2049 {
2050 wv = first_wv->contents;
2051 free_widget_value (first_wv);
2052 return wv;
2053 }
2054
2055 return first_wv;
2056 }
2057
2058 /* Walk through the widget_value tree starting at FIRST_WV and update
2059 the char * pointers from the corresponding lisp values.
2060 We do this after building the whole tree, since GC may happen while the
2061 tree is constructed, and small strings are relocated. So we must wait
2062 until no GC can happen before storing pointers into lisp values. */
2063 static void
2064 update_submenu_strings (first_wv)
2065 widget_value *first_wv;
2066 {
2067 widget_value *wv;
2068
2069 for (wv = first_wv; wv; wv = wv->next)
2070 {
2071 if (STRINGP (wv->lname))
2072 {
2073 wv->name = (char *) SDATA (wv->lname);
2074
2075 /* Ignore the @ that means "separate pane".
2076 This is a kludge, but this isn't worth more time. */
2077 if (wv->value == (char *)1)
2078 {
2079 if (wv->name[0] == '@')
2080 wv->name++;
2081 wv->value = 0;
2082 }
2083 }
2084
2085 if (STRINGP (wv->lkey))
2086 wv->key = (char *) SDATA (wv->lkey);
2087
2088 if (wv->contents)
2089 update_submenu_strings (wv->contents);
2090 }
2091 }
2092
2093 1157
2094 /* Recompute all the widgets of frame F, when the menu bar has been 1158 /* Recompute all the widgets of frame F, when the menu bar has been
2095 changed. Value is non-zero if widgets were updated. */ 1159 changed. Value is non-zero if widgets were updated. */
2096 1160
2097 static int 1161 static int
2328 1392
2329 /* The menu items are different, so store them in the frame. */ 1393 /* The menu items are different, so store them in the frame. */
2330 f->menu_bar_vector = menu_items; 1394 f->menu_bar_vector = menu_items;
2331 f->menu_bar_items_used = menu_items_used; 1395 f->menu_bar_items_used = menu_items_used;
2332 1396
2333 /* This calls restore_menu_items to restore menu_items, etc., 1397 /* This undoes save_menu_items. */
2334 as they were outside. */
2335 unbind_to (specpdl_count, Qnil); 1398 unbind_to (specpdl_count, Qnil);
2336 1399
2337 /* Now GC cannot happen during the lifetime of the widget_value, 1400 /* Now GC cannot happen during the lifetime of the widget_value,
2338 so it's safe to store data from a Lisp_String. */ 1401 so it's safe to store data from a Lisp_String. */
2339 wv = first_wv->contents; 1402 wv = first_wv->contents;
3816 } 2879 }
3817 2880
3818 void 2881 void
3819 syms_of_xmenu () 2882 syms_of_xmenu ()
3820 { 2883 {
3821 staticpro (&menu_items);
3822 menu_items = Qnil;
3823 menu_items_inuse = Qnil;
3824
3825 Qdebug_on_next_call = intern ("debug-on-next-call"); 2884 Qdebug_on_next_call = intern ("debug-on-next-call");
3826 staticpro (&Qdebug_on_next_call); 2885 staticpro (&Qdebug_on_next_call);
3827 2886
3828 #ifdef USE_X_TOOLKIT 2887 #ifdef USE_X_TOOLKIT
3829 widget_id_tick = (1<<16); 2888 widget_id_tick = (1<<16);