aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman1998-03-21 06:01:22 +0000
committerRichard M. Stallman1998-03-21 06:01:22 +0000
commitde57a39c28e6618fc3289a4102aa4762244b94bd (patch)
tree76b446c18ccdced3b1989065d8f89bb98d7882f4 /src
parenta3fc8840a3c1586b17c9d211e959571fba365af6 (diff)
downloademacs-de57a39c28e6618fc3289a4102aa4762244b94bd.tar.gz
emacs-de57a39c28e6618fc3289a4102aa4762244b94bd.zip
Don't include puresize.h any more as code that needs it
has moved to keyboard.c. (menu_item_equiv_key, menu_item_enabled_p_1, menu_item_enabled_p): Functions deleted; code moved to parse_menu_item in keyboard.c. (single_keymap_panes): Large part of code moved to single_menu_item. (single_menu_item): New function that uses parse_menu_item. (Qmenu_alias): Variable deleted. (QCtoggle, QCradio): New variables. (syms_of_xmenu): Change initializations of variables.
Diffstat (limited to 'src')
-rw-r--r--src/xmenu.c450
1 files changed, 162 insertions, 288 deletions
diff --git a/src/xmenu.c b/src/xmenu.c
index 9116030f07c..ef51f83ee3c 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -41,7 +41,6 @@ Boston, MA 02111-1307, USA. */
41#include "window.h" 41#include "window.h"
42#include "keyboard.h" 42#include "keyboard.h"
43#include "blockinput.h" 43#include "blockinput.h"
44#include "puresize.h"
45#include "buffer.h" 44#include "buffer.h"
46 45
47#ifdef MSDOS 46#ifdef MSDOS
@@ -90,13 +89,10 @@ Lisp_Object Vmenu_updating_frame;
90 89
91Lisp_Object Qdebug_on_next_call; 90Lisp_Object Qdebug_on_next_call;
92 91
93Lisp_Object Qmenu_alias;
94
95extern Lisp_Object Qmenu_enable;
96extern Lisp_Object Qmenu_bar; 92extern Lisp_Object Qmenu_bar;
97extern Lisp_Object Qmouse_click, Qevent_kind; 93extern Lisp_Object Qmouse_click, Qevent_kind;
98 94
99extern Lisp_Object Vdefine_key_rebound_commands; 95extern Lisp_Object QCtoggle, QCradio;
100 96
101extern Lisp_Object Voverriding_local_map; 97extern Lisp_Object Voverriding_local_map;
102extern Lisp_Object Voverriding_local_map_menu_flag; 98extern Lisp_Object Voverriding_local_map_menu_flag;
@@ -117,6 +113,7 @@ void popup_get_selection ();
117static Lisp_Object xmenu_show (); 113static Lisp_Object xmenu_show ();
118static void keymap_panes (); 114static void keymap_panes ();
119static void single_keymap_panes (); 115static void single_keymap_panes ();
116static void single_menu_item ();
120static void list_of_panes (); 117static void list_of_panes ();
121static void list_of_items (); 118static void list_of_items ();
122 119
@@ -339,152 +336,6 @@ push_menu_item (name, enable, key, def, equiv)
339 XVECTOR (menu_items)->contents[menu_items_used++] = def; 336 XVECTOR (menu_items)->contents[menu_items_used++] = def;
340} 337}
341 338
342/* Figure out the current keyboard equivalent of a menu item ITEM1.
343 The item string for menu display should be ITEM_STRING.
344 Store the equivalent keyboard key sequence's
345 textual description into *DESCRIP_PTR.
346 Also cache them in the item itself.
347 Return the real definition to execute. */
348
349static Lisp_Object
350menu_item_equiv_key (item_string, item1, descrip_ptr)
351 Lisp_Object item_string;
352 Lisp_Object item1;
353 Lisp_Object *descrip_ptr;
354{
355 /* This is the real definition--the function to run. */
356 Lisp_Object def;
357 /* This is the sublist that records cached equiv key data
358 so we can save time. */
359 Lisp_Object cachelist;
360 /* These are the saved equivalent keyboard key sequence
361 and its key-description. */
362 Lisp_Object savedkey, descrip;
363 Lisp_Object def1;
364 int changed = 0;
365 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
366
367 /* If a help string follows the item string, skip it. */
368 if (CONSP (XCONS (item1)->cdr)
369 && STRINGP (XCONS (XCONS (item1)->cdr)->car))
370 item1 = XCONS (item1)->cdr;
371
372 def = Fcdr (item1);
373
374 /* Get out the saved equivalent-keyboard-key info. */
375 cachelist = savedkey = descrip = Qnil;
376 if (CONSP (def) && CONSP (XCONS (def)->car)
377 && (NILP (XCONS (XCONS (def)->car)->car)
378 || VECTORP (XCONS (XCONS (def)->car)->car)))
379 {
380 cachelist = XCONS (def)->car;
381 def = XCONS (def)->cdr;
382 savedkey = XCONS (cachelist)->car;
383 descrip = XCONS (cachelist)->cdr;
384 }
385
386 GCPRO4 (def, def1, savedkey, descrip);
387
388 /* Is it still valid? */
389 def1 = Qnil;
390 if (!NILP (savedkey))
391 def1 = Fkey_binding (savedkey, Qnil);
392 /* If not, update it. */
393 if (! EQ (def1, def)
394 /* If the command is an alias for another
395 (such as easymenu.el and lmenu.el set it up),
396 check if the original command matches the cached command. */
397 && !(SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
398 && EQ (def1, XSYMBOL (def)->function))
399 /* If something had no key binding before, don't recheck it
400 because that is too slow--except if we have a list of rebound
401 commands in Vdefine_key_rebound_commands, do recheck any command
402 that appears in that list. */
403 && (NILP (cachelist) || !NILP (savedkey)
404 || (! EQ (Qt, Vdefine_key_rebound_commands)
405 && !NILP (Fmemq (def, Vdefine_key_rebound_commands)))))
406 {
407 changed = 1;
408 descrip = Qnil;
409 /* If the command is an alias for another
410 (such as easymenu.el and lmenu.el set it up),
411 see if the original command name has equivalent keys. */
412 if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
413 && ! NILP (Fget (def, Qmenu_alias)))
414 savedkey = Fwhere_is_internal (XSYMBOL (def)->function,
415 Qnil, Qt, Qnil);
416 else
417 /* Otherwise look up the specified command itself.
418 We don't try both, because that makes easymenu menus slow. */
419 savedkey = Fwhere_is_internal (def, Qnil, Qt, Qnil);
420
421 if (!NILP (savedkey))
422 {
423 descrip = Fkey_description (savedkey);
424 descrip = concat2 (make_string (" (", 3), descrip);
425 descrip = concat2 (descrip, make_string (")", 1));
426 }
427 }
428
429 /* Cache the data we just got in a sublist of the menu binding. */
430 if (NILP (cachelist))
431 {
432 CHECK_IMPURE (item1);
433 XCONS (item1)->cdr = Fcons (Fcons (savedkey, descrip), def);
434 }
435 else if (changed)
436 {
437 XCONS (cachelist)->car = savedkey;
438 XCONS (cachelist)->cdr = descrip;
439 }
440
441 UNGCPRO;
442 *descrip_ptr = descrip;
443 return def;
444}
445
446/* This is used as the handler when calling internal_condition_case_1. */
447
448static Lisp_Object
449menu_item_enabled_p_1 (arg)
450 Lisp_Object arg;
451{
452 /* If we got a quit from within the menu computation,
453 quit all the way out of it. This takes care of C-] in the debugger. */
454 if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit))
455 Fsignal (Qquit, Qnil);
456
457 return Qnil;
458}
459
460/* Return non-nil if the command DEF is enabled when used as a menu item.
461 This is based on looking for a menu-enable property.
462 If NOTREAL is set, don't bother really computing this. */
463
464static Lisp_Object
465menu_item_enabled_p (def, notreal)
466 Lisp_Object def;
467 int notreal;
468{
469 Lisp_Object enabled, tem;
470
471 enabled = Qt;
472 if (notreal)
473 return enabled;
474 if (SYMBOLP (def))
475 {
476 /* No property, or nil, means enable.
477 Otherwise, enable if value is not nil. */
478 tem = Fget (def, Qmenu_enable);
479 if (!NILP (tem))
480 /* (condition-case nil (eval tem)
481 (error nil)) */
482 enabled = internal_condition_case_1 (Feval, tem, Qerror,
483 menu_item_enabled_p_1);
484 }
485 return enabled;
486}
487
488/* Look through KEYMAPS, a vector of keymaps that is NMAPS long, 339/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
489 and generate menu panes for them in menu_items. 340 and generate menu panes for them in menu_items.
490 If NOTREAL is nonzero, 341 If NOTREAL is nonzero,
@@ -513,8 +364,8 @@ keymap_panes (keymaps, nmaps, notreal)
513 It handles one keymap, KEYMAP. 364 It handles one keymap, KEYMAP.
514 The other arguments are passed along 365 The other arguments are passed along
515 or point to local variables of the previous function. 366 or point to local variables of the previous function.
516 If NOTREAL is nonzero, 367 If NOTREAL is nonzero, only check for equivalent key bindings, don't
517 don't bother really computing whether an item is enabled. 368 evaluate expressions in menu items and don't make any menu.
518 369
519 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */ 370 If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
520 371
@@ -526,88 +377,33 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
526 int notreal; 377 int notreal;
527 int maxdepth; 378 int maxdepth;
528{ 379{
529 Lisp_Object pending_maps; 380 Lisp_Object pending_maps = Qnil;
530 Lisp_Object tail, item, item1, item_string, table; 381 Lisp_Object tail, item;
531 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; 382 struct gcpro gcpro1, gcpro2;
383 int notbuttons = 0;
532 384
533 if (maxdepth <= 0) 385 if (maxdepth <= 0)
534 return; 386 return;
535 387
536 pending_maps = Qnil;
537
538 push_menu_pane (pane_name, prefix); 388 push_menu_pane (pane_name, prefix);
539 389
390#ifndef HAVE_BOXES
391 /* Remember index for first item in this pane so we can go back and
392 add a prefix when (if) we see the first button. After that, notbuttons
393 is set to 0, to mark that we have seen a button and all non button
394 items need a prefix. */
395 notbuttons = menu_items_used;
396#endif
397
540 for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr) 398 for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
541 { 399 {
542 /* Look at each key binding, and if it has a menu string, 400 GCPRO2 (keymap, pending_maps);
543 make a menu item from it. */ 401 /* Look at each key binding, and if it is a menu item add it
402 to this menu. */
544 item = XCONS (tail)->car; 403 item = XCONS (tail)->car;
545 if (CONSP (item)) 404 if (CONSP (item))
546 { 405 single_menu_item (XCONS (item)->car, XCONS (item)->cdr,
547 item1 = XCONS (item)->cdr; 406 &pending_maps, notreal, maxdepth, &notbuttons);
548 if (CONSP (item1))
549 {
550 item_string = XCONS (item1)->car;
551 if (STRINGP (item_string))
552 {
553 /* This is the real definition--the function to run. */
554 Lisp_Object def;
555 /* These are the saved equivalent keyboard key sequence
556 and its key-description. */
557 Lisp_Object descrip;
558 Lisp_Object tem, enabled;
559
560 /* GCPRO because ...enabled_p will call eval
561 and ..._equiv_key may autoload something.
562 Protecting KEYMAP preserves everything we use;
563 aside from that, must protect whatever might be
564 a string. Since there's no GCPRO5, we refetch
565 item_string instead of protecting it. */
566 descrip = def = Qnil;
567 GCPRO4 (keymap, pending_maps, def, descrip);
568
569 def = menu_item_equiv_key (item_string, item1, &descrip);
570 enabled = menu_item_enabled_p (def, notreal);
571
572 UNGCPRO;
573
574 item_string = XCONS (item1)->car;
575
576 tem = Fkeymapp (def);
577 if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
578 pending_maps = Fcons (Fcons (def, Fcons (item_string, XCONS (item)->car)),
579 pending_maps);
580 else
581 {
582 Lisp_Object submap;
583 GCPRO4 (keymap, pending_maps, descrip, item_string);
584 submap = get_keymap_1 (def, 0, 1);
585 UNGCPRO;
586#ifndef USE_X_TOOLKIT
587 /* Indicate visually that this is a submenu. */
588 if (!NILP (submap))
589 item_string = concat2 (item_string,
590 build_string (" >"));
591#endif
592 /* If definition is nil, pass nil as the key. */
593 push_menu_item (item_string, enabled,
594 XCONS (item)->car, def,
595 descrip);
596#ifdef USE_X_TOOLKIT
597 /* Display a submenu using the toolkit. */
598 if (! NILP (submap))
599 {
600 push_submenu_start ();
601 single_keymap_panes (submap, Qnil,
602 XCONS (item)->car, notreal,
603 maxdepth - 1);
604 push_submenu_end ();
605 }
606#endif
607 }
608 }
609 }
610 }
611 else if (VECTORP (item)) 407 else if (VECTORP (item))
612 { 408 {
613 /* Loop over the char values represented in the vector. */ 409 /* Loop over the char values represented in the vector. */
@@ -617,68 +413,11 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
617 { 413 {
618 Lisp_Object character; 414 Lisp_Object character;
619 XSETFASTINT (character, c); 415 XSETFASTINT (character, c);
620 item1 = XVECTOR (item)->contents[c]; 416 single_menu_item (character, XVECTOR (item)->contents[c],
621 if (CONSP (item1)) 417 &pending_maps, notreal, maxdepth, &notbuttons);
622 {
623 item_string = XCONS (item1)->car;
624 if (STRINGP (item_string))
625 {
626 Lisp_Object def;
627
628 /* These are the saved equivalent keyboard key sequence
629 and its key-description. */
630 Lisp_Object descrip;
631 Lisp_Object tem, enabled;
632
633 /* GCPRO because ...enabled_p will call eval
634 and ..._equiv_key may autoload something.
635 Protecting KEYMAP preserves everything we use;
636 aside from that, must protect whatever might be
637 a string. Since there's no GCPRO5, we refetch
638 item_string instead of protecting it. */
639 GCPRO4 (keymap, pending_maps, def, descrip);
640 descrip = def = Qnil;
641
642 def = menu_item_equiv_key (item_string, item1, &descrip);
643 enabled = menu_item_enabled_p (def, notreal);
644
645 UNGCPRO;
646
647 item_string = XCONS (item1)->car;
648
649 tem = Fkeymapp (def);
650 if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
651 pending_maps = Fcons (Fcons (def, Fcons (item_string, character)),
652 pending_maps);
653 else
654 {
655 Lisp_Object submap;
656 GCPRO4 (keymap, pending_maps, descrip, item_string);
657 submap = get_keymap_1 (def, 0, 1);
658 UNGCPRO;
659#ifndef USE_X_TOOLKIT
660 if (!NILP (submap))
661 item_string = concat2 (item_string,
662 build_string (" >"));
663#endif
664 /* If definition is nil, pass nil as the key. */
665 push_menu_item (item_string, enabled, character,
666 def, descrip);
667#ifdef USE_X_TOOLKIT
668 if (! NILP (submap))
669 {
670 push_submenu_start ();
671 single_keymap_panes (submap, Qnil,
672 character, notreal,
673 maxdepth - 1);
674 push_submenu_end ();
675 }
676#endif
677 }
678 }
679 }
680 } 418 }
681 } 419 }
420 UNGCPRO;
682 } 421 }
683 422
684 /* Process now any submenus which want to be panes at this level. */ 423 /* Process now any submenus which want to be panes at this level. */
@@ -696,6 +435,144 @@ single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
696 } 435 }
697} 436}
698 437
438/* This is a subroutine of single_keymap_panes that handles one
439 keymap entry.
440 KEY is a key in a keymap and ITEM is its binding.
441 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into
442 separate panes.
443 If NOTREAL is nonzero, only check for equivalent key bindings, don't
444 evaluate expressions in menu items and don't make any menu.
445 If we encounter submenus deeper than MAXDEPTH levels, ignore them.
446 NOTBUTTONS_PTR is only used when simulating toggle boxes and radio
447 buttons. It points to variable notbuttons in single_keymap_panes,
448 which keeps track of if we have seen a button in this menu or not. */
449
450static void
451single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
452 notbuttons_ptr)
453 Lisp_Object key, item;
454 Lisp_Object *pending_maps_ptr;
455 int maxdepth, notreal;
456 int *notbuttons_ptr;
457{
458 Lisp_Object def, map, item_string, enabled;
459 struct gcpro gcpro1, gcpro2;
460 int res;
461
462 /* Parse the menu item and leave the result in item_properties. */
463 GCPRO2 (key, item);
464 res = parse_menu_item (item, notreal, 0);
465 UNGCPRO;
466 if (!res)
467 return; /* Not a menu item. */
468
469 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
470
471 if (notreal)
472 {
473 /* We don't want to make a menu, just traverse the keymaps to
474 precompute equivalent key bindings. */
475 if (!NILP (map))
476 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1);
477 return;
478 }
479
480 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
481 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
482
483 if (!NILP (map) && XSTRING (item_string)->data[0] == '@')
484 {
485 if (!NILP (enabled))
486 /* An enabled separate pane. Remember this to handle it later. */
487 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)),
488 *pending_maps_ptr);
489 return;
490 }
491
492#ifndef HAVE_BOXES
493 /* Simulate radio buttons and toggle boxes by putting a prefix in
494 front of them. */
495 {
496 Lisp_Object prefix = Qnil;
497 Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
498 if (!NILP (type))
499 {
500 Lisp_Object selected
501 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
502
503 if (*notbuttons_ptr)
504 /* The first button. Line up previous items in this menu. */
505 {
506 int index = *notbuttons_ptr; /* Index for first item this menu. */
507 int submenu = 0;
508 Lisp_Object tem;
509 while (index < menu_items_used)
510 {
511 tem
512 = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
513 if (NILP (tem))
514 {
515 index++;
516 submenu++; /* Skip sub menu. */
517 }
518 else if (EQ (tem, Qlambda))
519 {
520 index++;
521 submenu--; /* End sub menu. */
522 }
523 else if (EQ (tem, Qt))
524 index += 3; /* Skip new pane marker. */
525 else if (EQ (tem, Qquote))
526 index++; /* Skip a left, right divider. */
527 else
528 {
529 if (!submenu && XSTRING (tem)->data[0] != '\0'
530 && XSTRING (tem)->data[0] != '-')
531 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
532 = concat2 (build_string (" "), tem);
533 index += MENU_ITEMS_ITEM_LENGTH;
534 }
535 }
536 *notbuttons_ptr = 0;
537 }
538
539 /* Calculate prefix, if any, for this item. */
540 if (EQ (type, QCtoggle))
541 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
542 else if (EQ (type, QCradio))
543 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
544 }
545 /* Not a button. If we have earlier buttons, then we need a prefix. */
546 else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0'
547 && XSTRING (item_string)->data[0] != '-')
548 prefix = build_string (" ");
549
550 if (!NILP (prefix))
551 item_string = concat2 (prefix, item_string);
552 }
553#endif /* not HAVE_BOXES */
554
555#ifndef USE_X_TOOLKIT
556 if (!NILP(map))
557 /* Indicate visually that this is a submenu. */
558 item_string = concat2 (item_string, build_string (" >"));
559#endif
560
561 push_menu_item (item_string, enabled, key,
562 XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
563 XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]);
564
565#ifdef USE_X_TOOLKIT
566 /* Display a submenu using the toolkit. */
567 if (! (NILP (map) || NILP (enabled)))
568 {
569 push_submenu_start ();
570 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
571 push_submenu_end ();
572 }
573#endif
574}
575
699/* Push all the panes and items of a menu described by the 576/* Push all the panes and items of a menu described by the
700 alist-of-alists MENU. 577 alist-of-alists MENU.
701 This handles old-fashioned calls to x-popup-menu. */ 578 This handles old-fashioned calls to x-popup-menu. */
@@ -2730,9 +2607,6 @@ syms_of_xmenu ()
2730 staticpro (&menu_items); 2607 staticpro (&menu_items);
2731 menu_items = Qnil; 2608 menu_items = Qnil;
2732 2609
2733 Qmenu_alias = intern ("menu-alias");
2734 staticpro (&Qmenu_alias);
2735
2736 Qdebug_on_next_call = intern ("debug-on-next-call"); 2610 Qdebug_on_next_call = intern ("debug-on-next-call");
2737 staticpro (&Qdebug_on_next_call); 2611 staticpro (&Qdebug_on_next_call);
2738 2612