comparison src/xmenu.c @ 50803:140fa7af01db

(struct skp): New struct, to pass args through map_keymap. (single_keymap_panes): Use it and map_keymap. (single_menu_item): Use skp as well.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Sun, 04 May 2003 01:27:32 +0000
parents 05ebf4266798
children 20b3d6c3c7e5
comparison
equal deleted inserted replaced
50802:fe838fc4d9a9 50803:140fa7af01db
134 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, 134 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int,
135 Lisp_Object, char **)); 135 Lisp_Object, char **));
136 static void keymap_panes P_ ((Lisp_Object *, int, int)); 136 static void keymap_panes P_ ((Lisp_Object *, int, int));
137 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, 137 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
138 int, int)); 138 int, int));
139 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object *,
140 int, int, int *));
141 static void list_of_panes P_ ((Lisp_Object)); 139 static void list_of_panes P_ ((Lisp_Object));
142 static void list_of_items P_ ((Lisp_Object)); 140 static void list_of_items P_ ((Lisp_Object));
143 141
144 extern EMACS_TIME timer_check P_ ((int)); 142 extern EMACS_TIME timer_check P_ ((int));
145 143
408 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10); 406 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
409 407
410 finish_menu_items (); 408 finish_menu_items ();
411 } 409 }
412 410
411 /* Args passed between single_keymap_panes and single_menu_item. */
412 struct skp
413 {
414 Lisp_Object pending_maps;
415 int maxdepth, notreal;
416 int notbuttons;
417 };
418
419 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
420 struct skp*));
421
413 /* This is a recursive subroutine of keymap_panes. 422 /* This is a recursive subroutine of keymap_panes.
414 It handles one keymap, KEYMAP. 423 It handles one keymap, KEYMAP.
415 The other arguments are passed along 424 The other arguments are passed along
416 or point to local variables of the previous function. 425 or point to local variables of the previous function.
417 If NOTREAL is nonzero, only check for equivalent key bindings, don't 426 If NOTREAL is nonzero, only check for equivalent key bindings, don't
425 Lisp_Object pane_name; 434 Lisp_Object pane_name;
426 Lisp_Object prefix; 435 Lisp_Object prefix;
427 int notreal; 436 int notreal;
428 int maxdepth; 437 int maxdepth;
429 { 438 {
430 Lisp_Object pending_maps = Qnil; 439 struct skp skp;
431 Lisp_Object tail, item; 440 struct gcpro gcpro1;
432 struct gcpro gcpro1, gcpro2; 441
433 int notbuttons = 0; 442 skp.pending_maps = Qnil;
443 skp.maxdepth = maxdepth;
444 skp.notreal = notreal;
445 skp.notbuttons = 0;
434 446
435 if (maxdepth <= 0) 447 if (maxdepth <= 0)
436 return; 448 return;
437 449
438 push_menu_pane (pane_name, prefix); 450 push_menu_pane (pane_name, prefix);
440 #ifndef HAVE_BOXES 452 #ifndef HAVE_BOXES
441 /* Remember index for first item in this pane so we can go back and 453 /* Remember index for first item in this pane so we can go back and
442 add a prefix when (if) we see the first button. After that, notbuttons 454 add a prefix when (if) we see the first button. After that, notbuttons
443 is set to 0, to mark that we have seen a button and all non button 455 is set to 0, to mark that we have seen a button and all non button
444 items need a prefix. */ 456 items need a prefix. */
445 notbuttons = menu_items_used; 457 skp.notbuttons = menu_items_used;
446 #endif 458 #endif
447 459
448 for (tail = keymap; CONSP (tail); tail = XCDR (tail)) 460 GCPRO1 (skp.pending_maps);
449 { 461 map_keymap (keymap, single_menu_item, Qnil, &skp, 1);
450 GCPRO2 (keymap, pending_maps); 462 UNGCPRO;
451 /* Look at each key binding, and if it is a menu item add it
452 to this menu. */
453 item = XCAR (tail);
454 if (CONSP (item))
455 single_menu_item (XCAR (item), XCDR (item),
456 &pending_maps, notreal, maxdepth, &notbuttons);
457 else if (VECTORP (item))
458 {
459 /* Loop over the char values represented in the vector. */
460 int len = XVECTOR (item)->size;
461 int c;
462 for (c = 0; c < len; c++)
463 {
464 Lisp_Object character;
465 XSETFASTINT (character, c);
466 single_menu_item (character, XVECTOR (item)->contents[c],
467 &pending_maps, notreal, maxdepth, &notbuttons);
468 }
469 }
470 UNGCPRO;
471 }
472 463
473 /* Process now any submenus which want to be panes at this level. */ 464 /* Process now any submenus which want to be panes at this level. */
474 while (!NILP (pending_maps)) 465 while (CONSP (skp.pending_maps))
475 { 466 {
476 Lisp_Object elt, eltcdr, string; 467 Lisp_Object elt, eltcdr, string;
477 elt = Fcar (pending_maps); 468 elt = XCAR (skp.pending_maps);
478 eltcdr = XCDR (elt); 469 eltcdr = XCDR (elt);
479 string = XCAR (eltcdr); 470 string = XCAR (eltcdr);
480 /* We no longer discard the @ from the beginning of the string here. 471 /* We no longer discard the @ from the beginning of the string here.
481 Instead, we do this in xmenu_show. */ 472 Instead, we do this in xmenu_show. */
482 single_keymap_panes (Fcar (elt), string, 473 single_keymap_panes (Fcar (elt), string,
483 XCDR (eltcdr), notreal, maxdepth - 1); 474 XCDR (eltcdr), notreal, maxdepth - 1);
484 pending_maps = Fcdr (pending_maps); 475 skp.pending_maps = XCDR (skp.pending_maps);
485 } 476 }
486 } 477 }
487 478
488 /* This is a subroutine of single_keymap_panes that handles one 479 /* This is a subroutine of single_keymap_panes that handles one
489 keymap entry. 480 keymap entry.
490 KEY is a key in a keymap and ITEM is its binding. 481 KEY is a key in a keymap and ITEM is its binding.
491 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into 482 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into
492 separate panes. 483 separate panes.
493 If NOTREAL is nonzero, only check for equivalent key bindings, don't 484 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't
494 evaluate expressions in menu items and don't make any menu. 485 evaluate expressions in menu items and don't make any menu.
495 If we encounter submenus deeper than MAXDEPTH levels, ignore them. 486 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them.
496 NOTBUTTONS_PTR is only used when simulating toggle boxes and radio 487 SKP->NOTBUTTONS is only used when simulating toggle boxes and radio
497 buttons. It points to variable notbuttons in single_keymap_panes, 488 buttons. It keeps track of if we have seen a button in this menu or
498 which keeps track of if we have seen a button in this menu or not. */ 489 not. */
499 490
500 static void 491 static void
501 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, 492 single_menu_item (key, item, dummy, skp)
502 notbuttons_ptr) 493 Lisp_Object key, item, dummy;
503 Lisp_Object key, item; 494 struct skp *skp;
504 Lisp_Object *pending_maps_ptr;
505 int maxdepth, notreal;
506 int *notbuttons_ptr;
507 { 495 {
508 Lisp_Object map, item_string, enabled; 496 Lisp_Object map, item_string, enabled;
509 struct gcpro gcpro1, gcpro2; 497 struct gcpro gcpro1, gcpro2;
510 int res; 498 int res;
511 499
512 /* Parse the menu item and leave the result in item_properties. */ 500 /* Parse the menu item and leave the result in item_properties. */
513 GCPRO2 (key, item); 501 GCPRO2 (key, item);
514 res = parse_menu_item (item, notreal, 0); 502 res = parse_menu_item (item, skp->notreal, 0);
515 UNGCPRO; 503 UNGCPRO;
516 if (!res) 504 if (!res)
517 return; /* Not a menu item. */ 505 return; /* Not a menu item. */
518 506
519 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; 507 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
520 508
521 if (notreal) 509 if (skp->notreal)
522 { 510 {
523 /* We don't want to make a menu, just traverse the keymaps to 511 /* We don't want to make a menu, just traverse the keymaps to
524 precompute equivalent key bindings. */ 512 precompute equivalent key bindings. */
525 if (!NILP (map)) 513 if (!NILP (map))
526 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1); 514 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
527 return; 515 return;
528 } 516 }
529 517
530 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; 518 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
531 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; 519 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
532 520
533 if (!NILP (map) && SREF (item_string, 0) == '@') 521 if (!NILP (map) && SREF (item_string, 0) == '@')
534 { 522 {
535 if (!NILP (enabled)) 523 if (!NILP (enabled))
536 /* An enabled separate pane. Remember this to handle it later. */ 524 /* An enabled separate pane. Remember this to handle it later. */
537 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)), 525 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
538 *pending_maps_ptr); 526 skp->pending_maps);
539 return; 527 return;
540 } 528 }
541 529
542 #ifndef HAVE_BOXES 530 #ifndef HAVE_BOXES
543 /* Simulate radio buttons and toggle boxes by putting a prefix in 531 /* Simulate radio buttons and toggle boxes by putting a prefix in
548 if (!NILP (type)) 536 if (!NILP (type))
549 { 537 {
550 Lisp_Object selected 538 Lisp_Object selected
551 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; 539 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
552 540
553 if (*notbuttons_ptr) 541 if (skp->notbuttons)
554 /* The first button. Line up previous items in this menu. */ 542 /* The first button. Line up previous items in this menu. */
555 { 543 {
556 int index = *notbuttons_ptr; /* Index for first item this menu. */ 544 int index = skp->notbuttons; /* Index for first item this menu. */
557 int submenu = 0; 545 int submenu = 0;
558 Lisp_Object tem; 546 Lisp_Object tem;
559 while (index < menu_items_used) 547 while (index < menu_items_used)
560 { 548 {
561 tem 549 tem
581 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] 569 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
582 = concat2 (build_string (" "), tem); 570 = concat2 (build_string (" "), tem);
583 index += MENU_ITEMS_ITEM_LENGTH; 571 index += MENU_ITEMS_ITEM_LENGTH;
584 } 572 }
585 } 573 }
586 *notbuttons_ptr = 0; 574 skp->notbuttons = 0;
587 } 575 }
588 576
589 /* Calculate prefix, if any, for this item. */ 577 /* Calculate prefix, if any, for this item. */
590 if (EQ (type, QCtoggle)) 578 if (EQ (type, QCtoggle))
591 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); 579 prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
592 else if (EQ (type, QCradio)) 580 else if (EQ (type, QCradio))
593 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); 581 prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
594 } 582 }
595 /* Not a button. If we have earlier buttons, then we need a prefix. */ 583 /* Not a button. If we have earlier buttons, then we need a prefix. */
596 else if (!*notbuttons_ptr && SREF (item_string, 0) != '\0' 584 else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
597 && SREF (item_string, 0) != '-') 585 && SREF (item_string, 0) != '-')
598 prefix = build_string (" "); 586 prefix = build_string (" ");
599 587
600 if (!NILP (prefix)) 588 if (!NILP (prefix))
601 item_string = concat2 (prefix, item_string); 589 item_string = concat2 (prefix, item_string);
618 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) 606 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
619 /* Display a submenu using the toolkit. */ 607 /* Display a submenu using the toolkit. */
620 if (! (NILP (map) || NILP (enabled))) 608 if (! (NILP (map) || NILP (enabled)))
621 { 609 {
622 push_submenu_start (); 610 push_submenu_start ();
623 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1); 611 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
624 push_submenu_end (); 612 push_submenu_end ();
625 } 613 }
626 #endif 614 #endif
627 } 615 }
628 616