Mercurial > hg > xemacs-beta
comparison lisp/menubar.el @ 442:abe6d1db359e r21-2-36
Import from CVS: tag r21-2-36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:35:02 +0200 |
parents | 3ecd8885ac67 |
children | 576fb035e263 |
comparison
equal
deleted
inserted
replaced
441:72a7cfa4a488 | 442:abe6d1db359e |
---|---|
28 | 28 |
29 ;;; Commentary: | 29 ;;; Commentary: |
30 | 30 |
31 ;; This file is dumped with XEmacs (when menubar support is compiled in). | 31 ;; This file is dumped with XEmacs (when menubar support is compiled in). |
32 | 32 |
33 ;; Some stuff in FSF menu-bar.el is in x-menubar.el | 33 ;; Some stuff in FSF menu-bar.el is in menubar-items.el |
34 | 34 |
35 ;;; Code: | 35 ;;; Code: |
36 | 36 |
37 (defgroup menu nil | 37 (defgroup menu nil |
38 "Input from the menus." | 38 "Input from the menus." |
126 (signal 'error | 126 (signal 'error |
127 (list "button descriptors must be at least 2 long" | 127 (list "button descriptors must be at least 2 long" |
128 menuitem))) | 128 menuitem))) |
129 (setq plistp (or (>= L 5) | 129 (setq plistp (or (>= L 5) |
130 (and (> L 2) (keywordp (aref menuitem 2))))) | 130 (and (> L 2) (keywordp (aref menuitem 2))))) |
131 (or (stringp (aref menuitem 0)) | |
132 (signal 'error | |
133 (list | |
134 "first element of a button must be a string (the label)" | |
135 menuitem))) | |
136 (or plistp | |
137 (< L 4) | |
138 (null (aref menuitem 3)) | |
139 (stringp (aref menuitem 3)) | |
140 (signal 'error | |
141 (list | |
142 "fourth element of a button must be a string (the label suffix)" | |
143 menuitem))) | |
144 (if plistp | 131 (if plistp |
145 (let ((i 2) | 132 (let ((i 2) |
146 selp | 133 selp |
147 style | 134 style |
148 item) | 135 item) |
472 under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the | 459 under the toplevel \"File\" menu. (\"Menu\" \"Foo\" \"Item\") means the |
473 menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"." | 460 menu item called \"Item\" under the \"Foo\" submenu of \"Menu\"." |
474 (enable-menu-item-1 path t nil)) | 461 (enable-menu-item-1 path t nil)) |
475 | 462 |
476 | 463 |
464 | |
465 ;;;;;;; popup menus | |
466 | |
467 (defvar global-popup-menu nil | |
468 "The global popup menu. This is present in all modes. | |
469 See the function `popup-menu' for a description of menu syntax.") | |
470 | |
471 (defvar mode-popup-menu nil | |
472 "The mode-specific popup menu. Automatically buffer local. | |
473 This is appended to the default items in `global-popup-menu'. | |
474 See the function `popup-menu' for a description of menu syntax.") | |
475 (make-variable-buffer-local 'mode-popup-menu) | |
476 | |
477 (defvar activate-popup-menu-hook nil | |
478 "Function or functions run before a mode-specific popup menu is made visible. | |
479 These functions are called with no arguments, and should interrogate and | |
480 modify the value of `global-popup-menu' or `mode-popup-menu' as desired. | |
481 Note: this hook is only run if you use `popup-mode-menu' for activating the | |
482 global and mode-specific commands; if you have your own binding for button3, | |
483 this hook won't be run.") | |
484 | |
485 (defvar last-popup-menu-event nil | |
486 "The mouse event that invoked the last popup menu. | |
487 NOTE: This is EXPERIMENTAL and may change at any time.") | |
488 | |
489 (defun popup-mode-menu (&optional event) | |
490 "Pop up a menu of global and mode-specific commands. | |
491 The menu is computed by combining `global-popup-menu' and `mode-popup-menu' | |
492 with any items derived from the `context-menu' property of the extent where the | |
493 button was clicked." | |
494 (interactive "_e") | |
495 (setq last-popup-menu-event | |
496 (or (and event (button-event-p event) event) | |
497 (let* ((mouse-pos (mouse-position)) | |
498 (win (car mouse-pos)) | |
499 (x (cadr mouse-pos)) | |
500 (y (cddr mouse-pos)) | |
501 (edges (window-pixel-edges win)) | |
502 (winx (first edges)) | |
503 (winy (second edges)) | |
504 (x (+ x winx)) | |
505 (y (+ y winy))) | |
506 (make-event 'button-press | |
507 `(button 3 x ,x y ,y channel ,(window-frame win) | |
508 timestamp ,(current-event-timestamp | |
509 (cdfw-console win))))))) | |
510 (run-hooks 'activate-popup-menu-hook) | |
511 (let* ((context-window (and event (event-window event))) | |
512 (context-point (and event (event-point event))) | |
513 (context-extents (and context-window | |
514 context-point | |
515 (extents-at context-point | |
516 (window-buffer context-window) | |
517 'context-menu))) | |
518 (context-menu-items | |
519 (apply 'append (mapcar #'(lambda (extent) | |
520 (extent-property extent 'context-menu)) | |
521 context-extents)))) | |
522 (popup-menu | |
523 (cond ((and global-popup-menu mode-popup-menu) | |
524 ;; Merge global-popup-menu and mode-popup-menu | |
525 (check-menu-syntax mode-popup-menu) | |
526 (let* ((title (car mode-popup-menu)) | |
527 (items (cdr mode-popup-menu)) | |
528 mode-filters) | |
529 ;; Strip keywords from local menu for attaching them at the top | |
530 (while (and items | |
531 (keywordp (car items))) | |
532 ;; Push both keyword and its argument. | |
533 (push (pop items) mode-filters) | |
534 (push (pop items) mode-filters)) | |
535 (setq mode-filters (nreverse mode-filters)) | |
536 ;; If mode-filters contains a keyword already present in | |
537 ;; `global-popup-menu', you will probably lose. | |
538 (append (list (car global-popup-menu)) | |
539 mode-filters | |
540 (cdr global-popup-menu) | |
541 '("---" "---") | |
542 (if popup-menu-titles (list title)) | |
543 (if popup-menu-titles '("---" "---")) | |
544 items | |
545 context-menu-items))) | |
546 (t | |
547 (append | |
548 (or mode-popup-menu | |
549 global-popup-menu | |
550 (error "No menu defined in this buffer")) | |
551 context-menu-items)))) | |
552 | |
553 (while (popup-up-p) | |
554 (dispatch-event (next-event))) | |
555 | |
556 )) | |
557 | |
558 (defun popup-buffer-menu (event) | |
559 "Pop up a copy of the Buffers menu (from the menubar) where the mouse is clicked." | |
560 (interactive "e") | |
561 (let ((window (and (event-over-text-area-p event) (event-window event))) | |
562 (bmenu nil)) | |
563 (or window | |
564 (error "Pointer must be in a normal window")) | |
565 (select-window window) | |
566 (if current-menubar | |
567 (setq bmenu (assoc "%_Buffers" current-menubar))) | |
568 (if (null bmenu) | |
569 (setq bmenu (assoc "%_Buffers" default-menubar))) | |
570 (if (null bmenu) | |
571 (error "Can't find the Buffers menu")) | |
572 (popup-menu bmenu))) | |
573 | |
574 (defun popup-menubar-menu (event) | |
575 "Pop up a copy of menu that also appears in the menubar." | |
576 (interactive "e") | |
577 (let ((window (and (event-over-text-area-p event) (event-window event))) | |
578 popup-menubar) | |
579 (or window | |
580 (error "Pointer must be in a normal window")) | |
581 (select-window window) | |
582 (and current-menubar (run-hooks 'activate-menubar-hook)) | |
583 ;; #### Instead of having to copy this just to safely get rid of | |
584 ;; any nil what we should really do is fix up the internal menubar | |
585 ;; code to just ignore nil if generating a popup menu | |
586 (setq popup-menubar (delete nil (copy-sequence (or current-menubar | |
587 default-menubar)))) | |
588 (popup-menu (cons "%_Menubar Menu" popup-menubar)) | |
589 )) | |
590 | |
591 (defun menu-call-at-event (form &optional event default-behavior-fallback) | |
592 "Call FORM while temporarily setting point to the position in EVENT. | |
593 NOTE: This is EXPERIMENTAL and may change at any time. | |
594 | |
595 FORM is called the way forms in menu specs are: i.e. if a symbol, it's called | |
596 with `call-interactively', otherwise with `eval'. EVENT defaults to | |
597 `last-popup-menu-event', making this function especially useful in popup | |
598 menus. The buffer and point are set temporarily within a `save-excursion'. | |
599 If EVENT is not a mouse event, or was not over a buffer, nothing | |
600 happens unless DEFAULT-BEHAVIOR-FALLBACK is non-nil, in which case the | |
601 FORM is called normally." | |
602 (or event (setq event last-popup-menu-event)) | |
603 (let ((buf (event-buffer event)) | |
604 (p (event-closest-point event))) | |
605 (cond ((and buf p (> p 0)) | |
606 (save-excursion | |
607 (set-buffer buf) | |
608 (goto-char p) | |
609 (if (symbolp form) | |
610 (call-interactively form) | |
611 (eval form)))) | |
612 (default-behavior-fallback | |
613 (if (symbolp form) | |
614 (call-interactively form) | |
615 (eval form)))))) | |
616 | |
617 (global-set-key 'button3 'popup-mode-menu) | |
618 ;; shift button3 and shift button2 are reserved for Hyperbole | |
619 (global-set-key '(meta control button3) 'popup-buffer-menu) | |
620 ;; The following command is way too dangerous with Custom. | |
621 ;; (global-set-key '(meta shift button3) 'popup-menubar-menu) | |
622 | |
623 ;; Here's a test of the cool new menu features (from Stig). | |
624 | |
625 ;;(setq mode-popup-menu | |
626 ;; '("Test Popup Menu" | |
627 ;; :filter cdr | |
628 ;; ["this item won't appear because of the menu filter" ding t] | |
629 ;; "--:singleLine" | |
630 ;; "singleLine" | |
631 ;; "--:doubleLine" | |
632 ;; "doubleLine" | |
633 ;; "--:singleDashedLine" | |
634 ;; "singleDashedLine" | |
635 ;; "--:doubleDashedLine" | |
636 ;; "doubleDashedLine" | |
637 ;; "--:noLine" | |
638 ;; "noLine" | |
639 ;; "--:shadowEtchedIn" | |
640 ;; "shadowEtchedIn" | |
641 ;; "--:shadowEtchedOut" | |
642 ;; "shadowEtchedOut" | |
643 ;; "--:shadowDoubleEtchedIn" | |
644 ;; "shadowDoubleEtchedIn" | |
645 ;; "--:shadowDoubleEtchedOut" | |
646 ;; "shadowDoubleEtchedOut" | |
647 ;; "--:shadowEtchedInDash" | |
648 ;; "shadowEtchedInDash" | |
649 ;; "--:shadowEtchedOutDash" | |
650 ;; "shadowEtchedOutDash" | |
651 ;; "--:shadowDoubleEtchedInDash" | |
652 ;; "shadowDoubleEtchedInDash" | |
653 ;; "--:shadowDoubleEtchedOutDash" | |
654 ;; "shadowDoubleEtchedOutDash" | |
655 ;; )) | |
656 | |
477 (defun get-popup-menu-response (menu-desc &optional event) | 657 (defun get-popup-menu-response (menu-desc &optional event) |
478 "Pop up the given menu and wait for a response. | 658 "Pop up the given menu and wait for a response. |
479 This blocks until the response is received, and returns the misc-user | 659 This blocks until the response is received, and returns the misc-user |
480 event that encapsulates the response. To execute it, you can do | 660 event that encapsulates the response. To execute it, you can do |
481 (funcall (event-function response) (event-object response)) | 661 (funcall (event-function response) (event-object response)) |