Function: popup-menu
popup-menu is a byte-compiled function defined in menu-bar.el.gz.
Signature
(popup-menu MENU &optional POSITION PREFIX FROM-MENU-BAR)
Documentation
Popup MENU and call the selected option.
MENU can be a keymap, an easymenu-style menu or a list of keymaps as for
x-popup-menu.
The menu is shown at the location specified by POSITION, which
defaults to the place of the mouse click that popped the menu.
For the form of POSITION, see popup-menu-normalize-position.
PREFIX is the prefix argument (if any) to pass to the command.
FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus.
Aliases
semantic-popup-menu (obsolete since 27.1)
Source Code
;; Defined in /usr/src/emacs/lisp/menu-bar.el.gz
(defun popup-menu (menu &optional position prefix from-menu-bar)
"Popup MENU and call the selected option.
MENU can be a keymap, an easymenu-style menu or a list of keymaps as for
`x-popup-menu'.
The menu is shown at the location specified by POSITION, which
defaults to the place of the mouse click that popped the menu.
For the form of POSITION, see `popup-menu-normalize-position'.
PREFIX is the prefix argument (if any) to pass to the command.
FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus."
(let* ((map (cond
((keymapp menu) menu)
((and (listp menu) (keymapp (car menu))) menu)
((not (listp menu)) nil)
(t (let* ((map (easy-menu-create-menu (car menu) (cdr menu)))
(filter (when (symbolp map)
(plist-get (get map 'menu-prop) :filter))))
(if filter (funcall filter (symbol-function map)) map)))))
(selected-frame (selected-frame))
(frame (if (and (eq (framep selected-frame) t) (frame-parent)
from-menu-bar
(zerop (or (frame-parameter nil 'menu-bar-lines) 0)))
;; If the selected frame is a tty child frame
;; without its own menu bar and we are called from
;; the menu bar, the menu bar must be on the root
;; frame of the selected frame.
(frame-root-frame)
(selected-frame)))
event cmd)
(with-selected-frame frame
(if from-menu-bar
(let* ((xy (posn-x-y position))
(menu-symbol (menu-bar-menu-at-x-y (car xy) (cdr xy))))
(setq position (list menu-symbol (list frame '(menu-bar)
xy 0))))
(setq position (popup-menu-normalize-position position)))
;; The looping behavior was taken from lmenu's popup-menu-popup
(while (and map (setq event
;; map could be a prefix key, in which case
;; we need to get its function cell
;; definition.
(x-popup-menu position (indirect-function map))))
;; Strangely x-popup-menu returns a list.
;; mouse-major-mode-menu was using a weird:
;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
(setq cmd
(cond
((and from-menu-bar
(consp event)
(numberp (car event))
(numberp (cdr event)))
(let ((x (car event))
(y (cdr event))
menu-symbol)
(setq menu-symbol (menu-bar-menu-at-x-y x y))
(setq position (list menu-symbol (list frame '(menu-bar)
event 0)))
(if (not (eq frame selected-frame))
;; If we are using the menu bar from the root
;; frame, look up the key binding in the keymaps
;; of the initially selected window's buffer to
;; make sure that navigating the menu bar with the
;; keyboard works as intended.
(setq map
(key-binding (vector 'menu-bar menu-symbol) nil nil
(frame-selected-window selected-frame)))
(setq map
(key-binding (vector 'menu-bar menu-symbol))))))
((and (not (keymapp map)) (listp map))
;; We were given a list of keymaps. Search them all
;; in sequence until a first binding is found.
(let ((mouse-click (apply 'vector event))
binding)
(while (and map (null binding))
(setq binding (lookup-key-ignore-too-long (car map) mouse-click))
(setq map (cdr map)))
binding))
(t
;; We were given a single keymap.
(lookup-key map (apply 'vector event)))))
;; Clear out echoing, which perhaps shows a prefix arg.
(message "")
;; Maybe try again but with the submap.
(setq map (if (keymapp cmd) cmd))))
;; If the user did not cancel by refusing to select,
;; and if the result is a command, run it.
(when (and (null map) (commandp cmd))
(setq prefix-arg prefix)
;; `setup-specified-language-environment', for instance,
;; expects this to be set from a menu keymap.
(setq last-command-event (car (last event)))
(setq from--tty-menu-p nil)
;; Signal use-dialog-box-p this command was invoked from a menu.
(let ((from--tty-menu-p t))
;; mouse-major-mode-menu was using `command-execute' instead.
(call-interactively cmd)))))