+;;; menu-bar.el --- define a default menu bar.
+
+;; Author: RMS
+;; Keywords: internals
+
+;; Copyright (C) 1993 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Code:
+
(define-key global-map [menu-bar] (make-sparse-keymap "menu-bar"))
-(setq menu-bar-file-menu (make-sparse-keymap "File"))
-(define-key global-map [menu-bar file] menu-bar-file-menu)
-(setq menu-bar-edit-menu (make-sparse-keymap "Edit"))
-(define-key global-map [menu-bar edit] menu-bar-edit-menu)
-(setq menu-bar-buffer-menu (make-sparse-keymap "Buffer"))
-(define-key global-map [menu-bar buffer] menu-bar-buffer-menu)
-(setq menu-bar-help-menu (make-sparse-keymap "Help"))
-(define-key global-map [menu-bar help] menu-bar-help-menu)
-
-(define-key menu-bar-file-map [new-frame] '("New Frame" . new-frame))
-(define-key menu-bar-file-map [open-file] '("Open File..." . find-file))
-(define-key menu-bar-file-map [save-buffer] '("Save Buffer" . save-buffer))
-(define-key menu-bar-file-map [write-file]
- '("Save Buffer As..." . write-file))
-(define-key menu-bar-file-map [revert-buffer]
- '("Revert Buffer" . revert-buffer))
-(define-key menu-bar-file-map [print-buffer] '("Print Buffer" . print-buffer))
-(define-key menu-bar-file-map [delete-frame] '("Delete Frame" . delete-frame))
-(define-key menu-bar-file-map [kill-buffer]
- '("Kill Buffer" . kill-this-buffer))
-(define-key menu-bar-file-map [exit-emacs]
+(defvar menu-bar-help-menu (make-sparse-keymap "Help"))
+;; Put Help item in help-menu-bar-map so it always goes last.
+(setq help-menu-bar-map (make-sparse-keymap))
+(define-key help-menu-bar-map [help] (cons "Help" menu-bar-help-menu))
+(defvar menu-bar-edit-menu (make-sparse-keymap "Edit"))
+(define-key global-map [menu-bar edit] (cons "Edit" menu-bar-edit-menu))
+(defvar menu-bar-file-menu (make-sparse-keymap "File"))
+(define-key global-map [menu-bar file] (cons "File" menu-bar-file-menu))
+
+(define-key menu-bar-file-menu [exit-emacs]
'("Exit Emacs" . save-buffers-kill-emacs))
+(define-key menu-bar-file-menu [kill-buffer]
+ '("Kill Buffer" . kill-this-buffer))
+(define-key menu-bar-file-menu [delete-frame] '("Delete Frame" . delete-frame))
+(define-key menu-bar-file-menu [print-buffer] '("Print Buffer" . print-buffer))
+(define-key menu-bar-file-menu [revert-buffer]
+ '("Revert Buffer" . revert-buffer))
+(define-key menu-bar-file-menu [write-file]
+ '("Save Buffer As..." . write-file))
+(define-key menu-bar-file-menu [save-buffer] '("Save Buffer" . save-buffer))
+(define-key menu-bar-file-menu [dired] '("Open Directory..." . dired))
+(define-key menu-bar-file-menu [open-file] '("Open File..." . find-file))
+(define-key menu-bar-file-menu [new-frame] '("New Frame" . new-frame))
-(define-key menu-bar-edit-map [undo] '("Undo" . advertised-undo))
-(define-key menu-bar-edit-map [cut] '("Cut" . x-kill-primary-selection))
-(define-key menu-bar-edit-map [copy] '("Copy" . x-copy-primary-selection))
-(define-key menu-bar-edit-map [paste] '("Paste" . x-yank-clipboard-selection))
-(define-key menu-bar-edit-map [clear] '("Clear" . x-delete-primary-selection))
-(define-key menu-bar-help-map [info] '("Info" . info))
-(define-key menu-bar-help-map [describe-mode]
- '("Describe Mode" . describe-mode))
-(define-key menu-bar-help-map [command-apropos]
- '("Command Apropos..." . command-apropos))
-(define-key menu-bar-help-map [list-keybindings]
- '("List Keybindings" . describe-bindings))
-(define-key menu-bar-help-map [describe-key]
- '("Describe Key..." . describe-key))
-(define-key menu-bar-help-map [describe-function]
- '("Describe Function..." . describe-function))
-(define-key menu-bar-help-map [describe-variable]
- '("Describe Variable..." . describe-variable))
-(define-key menu-bar-help-map [man] '("Man..." . manual-entry))
-(define-key menu-bar-help-map [emacs-tutorial]
- '("Emacs Tutorial" . help-with-tutorial))
-(define-key menu-bar-help-map [emacs-news] '("Emacs News" . view-emacs-news))
+(define-key menu-bar-edit-menu [spell] '("Spell..." . ispell-menu-map))
+(define-key menu-bar-edit-menu [fill] '("Fill" . fill-region))
+(define-key menu-bar-edit-menu [clear] '("Clear" . delete-region))
+(define-key menu-bar-edit-menu [choose-next-paste]
+ '("Choose Next Paste" . mouse-menu-choose-yank))
+(define-key menu-bar-edit-menu [paste] '("Paste" . yank))
+(define-key menu-bar-edit-menu [copy] '("Copy" . kill-ring-save))
+(define-key menu-bar-edit-menu [cut] '("Cut" . kill-region))
+(define-key menu-bar-edit-menu [undo] '("Undo" . undo))
+
+(put 'fill-region 'menu-enable 'mark-active)
+(put 'kill-region 'menu-enable 'mark-active)
+(put 'kill-ring-save 'menu-enable 'mark-active)
+(put 'yank 'menu-enable '(x-selection-exists-p))
+(put 'delete-region 'menu-enable 'mark-active)
+(put 'undo 'menu-enable '(if (eq last-command 'undo)
+ pending-undo-list
+ (consp buffer-undo-list)))
+(autoload 'ispell-menu-map "ispell" nil t 'keymap)
+(define-key menu-bar-help-menu [emacs-tutorial]
+ '("Emacs Tutorial" . help-with-tutorial))
+(define-key menu-bar-help-menu [man] '("Man..." . manual-entry))
+(define-key menu-bar-help-menu [describe-variable]
+ '("Describe Variable..." . describe-variable))
+(define-key menu-bar-help-menu [describe-function]
+ '("Describe Function..." . describe-function))
+(define-key menu-bar-help-menu [describe-key]
+ '("Describe Key..." . describe-key))
+(define-key menu-bar-help-menu [list-keybindings]
+ '("List Keybindings" . describe-bindings))
+(define-key menu-bar-help-menu [command-apropos]
+ '("Command Apropos..." . command-apropos))
+(define-key menu-bar-help-menu [describe-mode]
+ '("Describe Mode" . describe-mode))
+(define-key menu-bar-help-menu [info] '("Info" . info))
+
+(define-key menu-bar-help-menu [emacs-news] '("Emacs News" . view-emacs-news))
(defun kill-this-buffer () ; for the menubar
"Kills the current buffer."
(interactive)
(kill-buffer (current-buffer)))
+(defun kill-this-buffer-enabled-p ()
+ (let ((count 0)
+ (buffers (buffer-list)))
+ (while buffers
+ (or (string-match "^ " (buffer-name (car buffers)))
+ (setq count (1+ count)))
+ (setq buffers (cdr buffers)))
+ (> count 1)))
+
(put 'save-buffer 'menu-enable '(buffer-modified-p))
-(put 'revert-buffer 'menu-enable 'buffer-file-name)
-(put 'delete-frame 'menu-enable '(null (cdr (visible-frame-list)))))
-(put 'x-kill-primary-selection 'menu-enable '(x-selection-owner-p))
-(put 'x-copy-primary-selection 'menu-enable '(x-selection-owner-p))
-(put 'x-yank-clipboard-selection 'menu-enable '(x-selection-owner-p))
-(put 'x-delete-primary-selection 'menu-enable
- '(x-selection-exists-p 'CLIPBOARD))
+(put 'revert-buffer 'menu-enable '(and (buffer-modified-p) (buffer-file-name)))
+(put 'delete-frame 'menu-enable '(cdr (visible-frame-list)))
+(put 'kill-this-buffer 'menu-enable '(kill-this-buffer-enabled-p))
+
(put 'advertised-undo 'menu-enable
'(and (not (eq t buffer-undo-list))
(if (eq last-command 'undo)
- (setq undoing-more
- (and (boundp 'pending-undo-list)
- pending-undo-list)
- buffer-undo-list))))
\ No newline at end of file
+ (and (boundp 'pending-undo-list)
+ pending-undo-list)
+ buffer-undo-list)))
+
+(defvar yank-menu-length 100
+ "*Maximum length of an item in the menu for \
+\\[mouse-menu-choose-yank].")
+
+(defun mouse-menu-choose-yank (event)
+ "Pop up a menu of the kill-ring for selection with the mouse.
+The kill-ring-yank-pointer is moved to the selected element.
+A subsequent \\[yank] yanks the choice just selected."
+ (interactive "e")
+ (let* ((count 0)
+ (menu (mapcar (lambda (string)
+ (if (> (length string) yank-menu-length)
+ (setq string (substring string
+ 0 yank-menu-length)))
+ (prog1 (cons string count)
+ (setq count (1+ count))))
+ kill-ring))
+ (arg (x-popup-menu event
+ (list "Yank Menu"
+ (cons "Choose Next Yank" menu)))))
+ ;; A mouse click outside the menu returns nil.
+ ;; Avoid a confusing error from passing nil to rotate-yank-pointer.
+ ;; XXX should this perhaps do something other than simply return? -rm
+ (if arg
+ (progn
+ (rotate-yank-pointer arg)
+ (if (interactive-p)
+ (message "The next yank will insert the selected text.")
+ (current-kill 0))))))
+(put 'mouse-menu-choose-yank 'menu-enable 'kill-ring)
+\f
+(define-key global-map [menu-bar buffer] '("Buffers" . mouse-menu-bar-buffers))
+
+(defvar complex-buffers-menu-p nil
+ "*Non-nil says, offer a choice of actions after you pick a buffer.
+This applies to the Buffers menu from the menu bar.")
+
+(defvar buffers-menu-max-size 10
+ "*Maximum number of entries which may appear on the Buffers menu.
+If this is 10, then only the ten most-recently-selected buffers are shown.
+If this is nil, then all buffers are shown.
+A large number or nil slows down menu responsiveness.")
+
+(defun mouse-menu-bar-buffers (event)
+ "Pop up a menu of buffers for selection with the mouse.
+This switches buffers in the window that you clicked on,
+and selects that window."
+ (interactive "e")
+ (let ((buffers (buffer-list))
+ menu)
+ ;; If requested, list only the N most recently selected buffers.
+ (if (and (integerp buffers-menu-max-size)
+ (> buffers-menu-max-size 1))
+ (if (> (length buffers) buffers-menu-max-size)
+ (setcdr (nthcdr buffers-menu-max-size buffers) nil)))
+ (setq menu
+ (list "Buffer Menu"
+ (cons "Select Buffer"
+ (let ((tail buffers)
+ (maxbuf 0)
+ (maxlen 0)
+ head)
+ (while tail
+ (or (eq ?\ (aref (buffer-name (car tail)) 0))
+ (setq maxbuf
+ (max maxbuf
+ (length (buffer-name (car tail))))))
+ (setq tail (cdr tail)))
+ (setq tail buffers)
+ (while tail
+ (let ((elt (car tail)))
+ (if (not (string-match "^ "
+ (buffer-name elt)))
+ (setq head (cons
+ (cons
+ (format
+ (format "%%%ds %%s%%s %%s"
+ maxbuf)
+ (buffer-name elt)
+ (if (buffer-modified-p elt) "*" " ")
+ (save-excursion
+ (set-buffer elt)
+ (if buffer-read-only "%" " "))
+ (or (buffer-file-name elt) ""))
+ elt)
+ head)))
+ (and head (> (length (car (car head))) maxlen)
+ (setq maxlen (length (car (car head))))))
+ (setq tail (cdr tail)))
+ (nconc (reverse head)
+ (list (cons (concat (make-string (max 0 (- (/ maxlen 2) 8)) ?\ )
+ "List All Buffers")
+ 'list-buffers)))))))
+
+
+ (let ((buf (x-popup-menu (if (listp event) event
+ (cons '(0 0) (selected-frame)))
+ menu))
+ (window (and (listp event) (posn-window (event-start event)))))
+ (if (eq buf 'list-buffers)
+ (list-buffers)
+ (if buf
+ (if complex-buffers-menu-p
+ (let ((action (x-popup-menu (if (listp event) event
+ (cons '(0 0) (selected-frame)))
+ '("Buffer Action"
+ (""
+ ("Save Buffer" . save-buffer)
+ ("Kill Buffer" . kill-buffer)
+ ("Select Buffer" . switch-to-buffer))))))
+ (if (eq action 'save-buffer)
+ (save-excursion
+ (set-buffer buf)
+ (save-buffer))
+ (funcall action buf)))
+ (and (windowp window)
+ (select-window window))
+ (switch-to-buffer buf)))))))
+
+;; this version is too slow
+;;;(defun format-buffers-menu-line (buffer)
+;;; "Returns a string to represent the given buffer in the Buffer menu.
+;;;nil means the buffer shouldn't be listed. You can redefine this."
+;;; (if (string-match "\\` " (buffer-name buffer))
+;;; nil
+;;; (save-excursion
+;;; (set-buffer buffer)
+;;; (let ((size (buffer-size)))
+;;; (format "%s%s %-19s %6s %-15s %s"
+;;; (if (buffer-modified-p) "*" " ")
+;;; (if buffer-read-only "%" " ")
+;;; (buffer-name)
+;;; size
+;;; mode-name
+;;; (or (buffer-file-name) ""))))))
+\f
+(defvar menu-bar-mode nil)
+
+(defun menu-bar-mode (flag)
+ "Toggle display of a menu bar on each frame.
+This command applies to all frames that exist and frames to be
+created in the future.
+With a numeric argument, if the argument is negative,
+turn off menu bars; otherwise, turn on menu bars."
+ (interactive "P")
+ (setq menu-bar-mode (if (null flag) (not menu-bar-mode)
+ (or (not (numberp flag)) (>= flag 0))))
+ (let ((parameter (assq 'menu-bar-lines default-frame-alist)))
+ (if (consp parameter)
+ (setcdr parameter (if menu-bar-mode 1 0))
+ (setq default-frame-alist
+ (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
+ default-frame-alist))))
+ (let ((frames (frame-list)))
+ (while frames
+ ;; Turn menu bar on or off in existing frames.
+ ;; (Except for minibuffer-only frames.)
+ (or (eq 'only (cdr (assq 'minibuffer (frame-parameters (car frames)))))
+ (modify-frame-parameters
+ (car frames)
+ (list (if menu-bar-mode
+ '(menu-bar-lines . 1)
+ '(menu-bar-lines . 0)))))
+ (setq frames (cdr frames)))))
+
+;; Make frames created from now on have a menu bar.
+(if window-system
+ (menu-bar-mode t))
+
+(provide 'menu-bar)
+
+;;; menu-bar.el ends here