Use defgroup and defcustom.
[bpt/emacs.git] / lisp / menu-bar.el
CommitLineData
235aa29b
ER
1;;; menu-bar.el --- define a default menu bar.
2
b578f267
EN
3;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
4
235aa29b 5;; Author: RMS
b7f66977 6;; Keywords: internal
235aa29b 7
1db87953
RS
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b578f267
EN
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
1db87953 24
260130bb
KH
25;; Avishai Yacobi suggested some menu rearrangements.
26
b578f267
EN
27;;; Code:
28
d537086b
RS
29;;; User options:
30
31(defvar buffers-menu-max-size 10
32 "*Maximum number of entries which may appear on the Buffers menu.
33If this is 10, then only the ten most-recently-selected buffers are shown.
34If this is nil, then all buffers are shown.
35A large number or nil slows down menu responsiveness.")
36
b132f2b1
RM
37;; Don't clobber an existing menu-bar keymap, to preserve any menu-bar key
38;; definitions made in loaddefs.el.
39(or (lookup-key global-map [menu-bar])
40 (define-key global-map [menu-bar] (make-sparse-keymap "menu-bar")))
22390f50 41(defvar menu-bar-help-menu (make-sparse-keymap "Help"))
ffbdd83d
RS
42
43;; Force Help item to come last, after the major mode's own items.
0d31efcd
KH
44;; The symbol used to be called `help', but that gets confused with the
45;; help key.
46(setq menu-bar-final-items '(help-menu))
ffbdd83d 47
0d31efcd 48(define-key global-map [menu-bar help-menu] (cons "Help" menu-bar-help-menu))
ffbdd83d
RS
49(defvar menu-bar-search-menu (make-sparse-keymap "Search"))
50(define-key global-map [menu-bar search] (cons "Search" menu-bar-search-menu))
22390f50 51(defvar menu-bar-edit-menu (make-sparse-keymap "Edit"))
40954111 52(define-key global-map [menu-bar edit] (cons "Edit" menu-bar-edit-menu))
ffbdd83d
RS
53(defvar menu-bar-tools-menu (make-sparse-keymap "Tools"))
54(define-key global-map [menu-bar tools] (cons "Tools" menu-bar-tools-menu))
55(defvar menu-bar-files-menu (make-sparse-keymap "Files"))
56(define-key global-map [menu-bar files] (cons "Files" menu-bar-files-menu))
1b009b97
RS
57
58;; This alias is for compatibility with 19.28 and before.
59(defvar menu-bar-file-menu menu-bar-files-menu)
9bb8e471 60\f
9dcdc43d
RS
61(defvar vc-menu-map (make-sparse-keymap "Version Control"))
62
147f1d2a
RS
63(define-key menu-bar-tools-menu [gdb] '("Debugger..." . gdb))
64(define-key menu-bar-tools-menu [compile] '("Compile..." . compile))
65(define-key menu-bar-tools-menu [grep] '("Search Files..." . grep))
66
67(define-key menu-bar-tools-menu [separator-1]
68 '("--"))
69
e1726722 70(define-key menu-bar-tools-menu [calendar] '("Display Calendar" . calendar))
c0965058 71(define-key menu-bar-tools-menu [compose-mail] '("Send Mail" . compose-mail))
ffbdd83d 72(define-key menu-bar-tools-menu [rmail] '("Read Mail" . rmail))
96a699d0 73(define-key menu-bar-tools-menu [gnus] '("Read Net News" . gnus))
ffbdd83d
RS
74
75(define-key menu-bar-tools-menu [separator-vc]
76 '("--"))
77
fe74180c 78(define-key menu-bar-tools-menu [vc]
ffbdd83d 79 (cons "Version Control" vc-menu-map))
9bb8e471 80
ffbdd83d 81(define-key menu-bar-tools-menu [separator-compare]
9bb8e471
RS
82 '("--"))
83
ffbdd83d 84(define-key menu-bar-tools-menu [epatch]
080ac1ac 85 '("Apply Patch" . menu-bar-epatch-menu))
ffbdd83d 86(define-key menu-bar-tools-menu [ediff-merge]
5438ecd3 87 '("Merge" . menu-bar-ediff-merge-menu))
57eed34a 88(define-key menu-bar-tools-menu [compare]
40a8cde1 89 '("Compare" . menu-bar-ediff-menu))
9bb8e471 90
ffbdd83d 91(define-key menu-bar-tools-menu [separator-print]
9bb8e471
RS
92 '("--"))
93
ffbdd83d
RS
94(put 'print-region 'menu-enable 'mark-active)
95(put 'ps-print-region-with-faces 'menu-enable 'mark-active)
96
97(define-key menu-bar-tools-menu [ps-print-region]
98 '("Postscript Print Region" . ps-print-region-with-faces))
99(define-key menu-bar-tools-menu [ps-print-buffer]
100 '("Postscript Print Buffer" . ps-print-buffer-with-faces))
101(define-key menu-bar-tools-menu [print-region]
102 '("Print Region" . print-region))
103(define-key menu-bar-tools-menu [print-buffer]
104 '("Print Buffer" . print-buffer))
105\f
106(define-key menu-bar-files-menu [exit-emacs]
107 '("Exit Emacs" . save-buffers-kill-emacs))
108
109(define-key menu-bar-files-menu [separator-exit]
110 '("--"))
111
112(define-key menu-bar-files-menu [one-window]
113 '("One Window" . delete-other-windows))
114
115(define-key menu-bar-files-menu [split-window]
116 '("Split Window" . split-window-vertically))
9bb8e471 117
ca1a9692
RS
118(if (fboundp 'delete-frame)
119 (progn
a4e4b916
RS
120 ;; Don't use delete-frame as event name
121 ;; because that is a special event.
122 (define-key menu-bar-files-menu [delete-this-frame]
ca1a9692 123 '("Delete Frame" . delete-frame))
ffbdd83d
RS
124 (define-key menu-bar-files-menu [make-frame-on-display]
125 '("Open New Display..." . make-frame-on-display))
126 (define-key menu-bar-files-menu [make-frame]
ca1a9692 127 '("Make New Frame" . make-frame))))
9bb8e471 128
ffbdd83d 129(define-key menu-bar-files-menu [separator-buffers]
9bb8e471
RS
130 '("--"))
131
ffbdd83d
RS
132(define-key menu-bar-files-menu [kill-buffer]
133 '("Kill Current Buffer" . kill-this-buffer))
134(define-key menu-bar-files-menu [insert-file]
1f50590a 135 '("Insert File..." . insert-file))
ffbdd83d 136(define-key menu-bar-files-menu [revert-buffer]
2f1139a4 137 '("Revert Buffer" . revert-buffer))
ffbdd83d 138(define-key menu-bar-files-menu [write-file]
2f1139a4 139 '("Save Buffer As..." . write-file))
ffbdd83d
RS
140(define-key menu-bar-files-menu [save-buffer] '("Save Buffer" . save-buffer))
141(define-key menu-bar-files-menu [dired] '("Open Directory..." . dired))
142(define-key menu-bar-files-menu [open-file] '("Open File..." . find-file))
40a8cde1 143
9bb8e471 144\f
ffbdd83d
RS
145(defun nonincremental-search-forward (string)
146 "Read a string and search for it nonincrementally."
147 (interactive "sSearch for string: ")
148 (if (equal string "")
149 (search-forward (car search-ring))
150 (isearch-update-ring string nil)
151 (search-forward string)))
152
153(defun nonincremental-search-backward (string)
154 "Read a string and search backward for it nonincrementally."
155 (interactive "sSearch for string: ")
156 (if (equal string "")
157 (search-backward (car search-ring))
158 (isearch-update-ring string nil)
159 (search-backward string)))
160
161(defun nonincremental-re-search-forward (string)
162 "Read a regular expression and search for it nonincrementally."
163 (interactive "sSearch for regexp: ")
164 (if (equal string "")
165 (re-search-forward (car regexp-search-ring))
166 (isearch-update-ring string t)
167 (re-search-forward string)))
168
169(defun nonincremental-re-search-backward (string)
170 "Read a regular expression and search backward for it nonincrementally."
171 (interactive "sSearch for regexp: ")
172 (if (equal string "")
173 (re-search-backward (car regexp-search-ring))
174 (isearch-update-ring string t)
175 (re-search-backward string)))
176
1f50590a 177(defun nonincremental-repeat-search-forward ()
ffbdd83d
RS
178 "Search forward for the previous search string."
179 (interactive)
180 (search-forward (car search-ring)))
181
1f50590a 182(defun nonincremental-repeat-search-backward ()
ffbdd83d
RS
183 "Search backward for the previous search string."
184 (interactive)
185 (search-backward (car search-ring)))
186
1f50590a 187(defun nonincremental-repeat-re-search-forward ()
ffbdd83d
RS
188 "Search forward for the previous regular expression."
189 (interactive)
190 (re-search-forward (car regexp-search-ring)))
191
1f50590a 192(defun nonincremental-repeat-re-search-backward ()
ffbdd83d
RS
193 "Search backward for the previous regular expression."
194 (interactive)
195 (re-search-backward (car regexp-search-ring)))
196
1f50590a
RS
197(define-key menu-bar-search-menu [query-replace-regexp]
198 '("Query Replace Regexp..." . query-replace-regexp))
ffbdd83d 199(define-key menu-bar-search-menu [query-replace]
1f50590a 200 '("Query Replace..." . query-replace))
ffbdd83d 201(define-key menu-bar-search-menu [find-tag]
1f50590a 202 '("Find Tag..." . find-tag))
ffbdd83d
RS
203(define-key menu-bar-search-menu [bookmark]
204 '("Bookmarks" . menu-bar-bookmark-map))
205
206(define-key menu-bar-search-menu [separator-search]
207 '("--"))
208
fe74180c 209(define-key menu-bar-search-menu [repeat-regexp-back]
ffbdd83d 210 '("Repeat Regexp Backwards" . nonincremental-repeat-re-search-backward))
fe74180c 211(define-key menu-bar-search-menu [repeat-search-back]
ffbdd83d 212 '("Repeat Backwards" . nonincremental-repeat-search-backward))
fe74180c 213(define-key menu-bar-search-menu [repeat-regexp-fwd]
ffbdd83d 214 '("Repeat Regexp" . nonincremental-repeat-re-search-forward))
fe74180c 215(define-key menu-bar-search-menu [repeat-search-fwd]
ffbdd83d
RS
216 '("Repeat Search" . nonincremental-repeat-search-forward))
217
218(define-key menu-bar-search-menu [separator-repeat]
9bb8e471
RS
219 '("--"))
220
fe74180c 221(define-key menu-bar-search-menu [re-search-backward]
1f50590a 222 '("Regexp Search Backwards..." . nonincremental-re-search-backward))
fe74180c 223(define-key menu-bar-search-menu [search-backward]
1f50590a 224 '("Search Backwards..." . nonincremental-search-backward))
fe74180c 225(define-key menu-bar-search-menu [re-search-forward]
1f50590a 226 '("Regexp Search..." . nonincremental-re-search-forward))
fe74180c 227(define-key menu-bar-search-menu [search-forward]
1f50590a 228 '("Search..." . nonincremental-search-forward))
ffbdd83d 229\f
5b42ec2b
RS
230(if (fboundp 'start-process)
231 (define-key menu-bar-edit-menu [spell] '("Spell" . ispell-menu-map)))
9bb8e471 232(define-key menu-bar-edit-menu [fill] '("Fill" . fill-region))
6507ffb1 233(define-key menu-bar-edit-menu [props] '("Text Properties" . facemenu-menu))
9bb8e471
RS
234
235(define-key menu-bar-edit-menu [separator-edit]
236 '("--"))
237
238(define-key menu-bar-edit-menu [clear] '("Clear" . delete-region))
3dd92899 239
e1726722 240(define-key menu-bar-edit-menu [paste] '("Paste Most Recent" . yank))
3dd92899
KH
241
242(defvar yank-menu (cons "Select Yank" nil))
243(fset 'yank-menu (cons 'keymap yank-menu))
244(define-key menu-bar-edit-menu [select-paste] '("Select and Paste" . yank-menu))
4c0317b1 245(define-key menu-bar-edit-menu [copy] '("Copy" . menu-bar-kill-ring-save))
057d49d1
RS
246(define-key menu-bar-edit-menu [cut] '("Cut" . kill-region))
247(define-key menu-bar-edit-menu [undo] '("Undo" . undo))
248
4c0317b1
RS
249(defun menu-bar-kill-ring-save (beg end)
250 (interactive "r")
251 (if (mouse-region-match)
252 (message "Select a region with the mouse does `copy' automatically")
253 (kill-ring-save beg end)))
254
25b048ee
RS
255(put 'fill-region 'menu-enable '(and mark-active (not buffer-read-only)))
256(put 'kill-region 'menu-enable '(and mark-active (not buffer-read-only)))
4c0317b1 257(put 'menu-bar-kill-ring-save 'menu-enable 'mark-active)
25b048ee
RS
258(put 'yank 'menu-enable '(and (x-selection-exists-p) (not buffer-read-only)))
259(put 'yank-menu 'menu-enable '(and (cdr yank-menu) (not buffer-read-only)))
4c0317b1 260(put 'delete-region 'menu-enable '(and mark-active
25b048ee 261 (not buffer-read-only)
4c0317b1 262 (not (mouse-region-match))))
25b048ee
RS
263(put 'undo 'menu-enable '(and (not buffer-read-only)
264 (if (eq last-command 'undo)
265 pending-undo-list
266 (consp buffer-undo-list))))
3a841b0b 267(put 'query-replace 'menu-enable '(not buffer-read-only))
25b048ee 268(put 'query-replace-regexp 'menu-enable '(not buffer-read-only))
db774a16 269
9e18f0a0
RS
270(autoload 'ispell-menu-map "ispell" nil t 'keymap)
271
f9cf0be2 272;; These are alternative definitions for the cut, paste and copy
4c0317b1 273;; menu items. Use them if your system expects these to use the clipboard.
f9cf0be2 274
f9cf0be2
RS
275(put 'clipboard-kill-region 'menu-enable 'mark-active)
276(put 'clipboard-kill-ring-save 'menu-enable 'mark-active)
277(put 'clipboard-yank 'menu-enable
278 '(or (x-selection-exists-p) (x-selection-exists-p 'CLIPBOARD)))
279
280(defun clipboard-yank ()
281 "Reinsert the last stretch of killed text, or the clipboard contents."
282 (interactive)
283 (let ((x-select-enable-clipboard t))
284 (yank)))
285
286(defun clipboard-kill-ring-save (beg end)
287 "Copy region to kill ring, and save in the X clipboard."
288 (interactive "r")
289 (let ((x-select-enable-clipboard t))
290 (kill-ring-save beg end)))
291
292(defun clipboard-kill-region (beg end)
293 "Kill the region, and save it in the X clipboard."
294 (interactive "r")
295 (let ((x-select-enable-clipboard t))
296 (kill-region beg end)))
297
298(defun menu-bar-enable-clipboard ()
5cbdeb30
RS
299 "Make CUT, PASTE and COPY (keys and menu bar items) use the clipboard.
300Do the same for the keys of the same name."
f9cf0be2 301 (interactive)
5754d7f2
RS
302 ;; We can't use constant list structure here because it becomes pure,
303 ;; and because it gets modified with cache data.
304 (define-key menu-bar-edit-menu [paste]
305 (cons "Paste" 'clipboard-yank))
306 (define-key menu-bar-edit-menu [copy]
307 (cons "Copy" 'clipboard-kill-ring-save))
308 (define-key menu-bar-edit-menu [cut]
5cbdeb30
RS
309 (cons "Cut" 'clipboard-kill-region))
310
311 (define-key global-map [f20] 'clipboard-kill-region)
312 (define-key global-map [f16] 'clipboard-kill-ring-save)
313 (define-key global-map [f18] 'clipboard-yank)
314 ;; X11R6 versions
315 (define-key global-map [cut] 'clipboard-kill-region)
316 (define-key global-map [copy] 'clipboard-kill-ring-save)
317 (define-key global-map [paste] 'clipboard-yank))
f9cf0be2 318\f
a9f53ffb
RS
319
320;;; Menu support
321
322(defvar menu-bar-custom-menu (make-sparse-keymap "Customize"))
323
c9a86e71
RS
324(define-key menu-bar-custom-menu [custom-menu-update]
325 '("Update This Menu" . custom-menu-update))
a9f53ffb
RS
326(define-key menu-bar-custom-menu [customize-apropos]
327 '("Apropos..." . customize-apropos))
c9a86e71
RS
328(define-key menu-bar-custom-menu [customize-group]
329 '("Specific Group..." . customize-group))
a9f53ffb 330(define-key menu-bar-custom-menu [customize-face]
c9a86e71
RS
331 '("Specific Face..." . customize-face))
332(define-key menu-bar-custom-menu [customize-variable]
333 '("Specific Variable..." . customize-variable))
a9f53ffb 334(define-key menu-bar-custom-menu [customize]
c9a86e71 335 '("Browse Hierarchy of User Options" . customize))
a9f53ffb
RS
336
337(define-key menu-bar-help-menu [customize-menu]
338 (cons "Customize" menu-bar-custom-menu))
efb166ff
RS
339(define-key menu-bar-help-menu [emacs-version]
340 '("Show Version" . emacs-version))
48433a65 341(define-key menu-bar-help-menu [report-emacs-bug]
1c6e18f6 342 '("Send Bug Report..." . report-emacs-bug))
260130bb
KH
343(define-key menu-bar-help-menu [finder-by-keyword]
344 '("Find Lisp Packages..." . finder-by-keyword))
ca9b40a1 345(define-key menu-bar-help-menu [emacs-tutorial]
db774a16 346 '("Emacs Tutorial" . help-with-tutorial))
260130bb
KH
347(define-key menu-bar-help-menu [man]
348 '("Man..." . manual-entry))
2f1139a4
RS
349(define-key menu-bar-help-menu [describe-variable]
350 '("Describe Variable..." . describe-variable))
351(define-key menu-bar-help-menu [describe-function]
352 '("Describe Function..." . describe-function))
353(define-key menu-bar-help-menu [describe-key]
354 '("Describe Key..." . describe-key))
355(define-key menu-bar-help-menu [list-keybindings]
356 '("List Keybindings" . describe-bindings))
357(define-key menu-bar-help-menu [command-apropos]
358 '("Command Apropos..." . command-apropos))
359(define-key menu-bar-help-menu [describe-mode]
360 '("Describe Mode" . describe-mode))
e1726722 361(define-key menu-bar-help-menu [info] '("Browse Manuals" . info))
889560ed 362(define-key menu-bar-help-menu [emacs-faq] '("Emacs FAQ" . view-emacs-FAQ))
2f1139a4 363(define-key menu-bar-help-menu [emacs-news] '("Emacs News" . view-emacs-news))
889560ed 364
db774a16
RS
365(defun kill-this-buffer () ; for the menubar
366 "Kills the current buffer."
367 (interactive)
368 (kill-buffer (current-buffer)))
369
2f1139a4
RS
370(defun kill-this-buffer-enabled-p ()
371 (let ((count 0)
372 (buffers (buffer-list)))
373 (while buffers
374 (or (string-match "^ " (buffer-name (car buffers)))
375 (setq count (1+ count)))
376 (setq buffers (cdr buffers)))
a6f8cbf1 377 (and (not (window-minibuffer-p (frame-selected-window menu-updating-frame)))
1f50590a
RS
378 (> count 1))))
379
380(put 'kill-this-buffer 'menu-enable '(kill-this-buffer-enabled-p))
381
382(put 'save-buffer 'menu-enable
383 '(and (buffer-modified-p)
a6f8cbf1 384 (not (window-minibuffer-p (frame-selected-window menu-updating-frame)))))
1f50590a
RS
385
386(put 'write-file 'menu-enable
a6f8cbf1 387 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
388
389(put 'find-file 'menu-enable
a6f8cbf1 390 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
391
392(put 'dired 'menu-enable
a6f8cbf1 393 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
1f50590a
RS
394
395(put 'insert-file 'menu-enable
a6f8cbf1 396 '(not (window-minibuffer-p (frame-selected-window menu-updating-frame))))
2f1139a4 397
da183f87
RS
398(put 'revert-buffer 'menu-enable
399 '(or revert-buffer-function revert-buffer-insert-file-contents-function
400 (and (buffer-file-name)
660fa562
RM
401 (or (buffer-modified-p)
402 (not (verify-visited-file-modtime (current-buffer)))))))
82a74107 403
a0213a97
RS
404;; Permit deleting frame if it would leave a visible or iconified frame.
405(put 'delete-frame 'menu-enable
82a74107
KH
406 '(delete-frame-enabled-p))
407
408(defun delete-frame-enabled-p ()
409 "Return non-nil if `delete-frame' should be enabled in the menu bar."
410 (let ((frames (frame-list))
27aa8132
RS
411 (count 0))
412 (while frames
413 (if (frame-visible-p (car frames))
414 (setq count (1+ count)))
415 (setq frames (cdr frames)))
416 (> count 1)))
2f1139a4 417
db774a16
RS
418(put 'advertised-undo 'menu-enable
419 '(and (not (eq t buffer-undo-list))
420 (if (eq last-command 'undo)
2f1139a4
RS
421 (and (boundp 'pending-undo-list)
422 pending-undo-list)
423 buffer-undo-list)))
2877eac2 424
c3e1d435 425(defvar yank-menu-length 20
3dd92899
KH
426 "*Maximum length to display in the yank-menu.")
427
428(defun menu-bar-update-yank-menu (string old)
429 (let ((front (car (cdr yank-menu)))
430 (menu-string (if (<= (length string) yank-menu-length)
431 string
c3e1d435
RS
432 (concat
433 (substring string 0 (/ yank-menu-length 2))
434 "..."
435 (substring string (- (/ yank-menu-length 2)))))))
7c70a955
RS
436 ;; Don't let the menu string be all dashes
437 ;; because that has a special meaning in a menu.
438 (if (string-match "\\`-+\\'" menu-string)
439 (setq menu-string (concat menu-string " ")))
3dd92899
KH
440 ;; If we're supposed to be extending an existing string, and that
441 ;; string really is at the front of the menu, then update it in place.
442 (if (and old (or (eq old (car front))
443 (string= old (car front))))
dfabc98f 444 (progn
3dd92899
KH
445 (setcar front string)
446 (setcar (cdr front) menu-string))
447 (setcdr yank-menu
448 (cons
449 (cons string (cons menu-string 'menu-bar-select-yank))
450 (cdr yank-menu)))))
451 (if (> (length (cdr yank-menu)) kill-ring-max)
452 (setcdr (nthcdr kill-ring-max yank-menu) nil)))
453
454(defun menu-bar-select-yank ()
455 (interactive "*")
456 (push-mark (point))
457 (insert last-command-event))
40954111 458\f
3f557298
RS
459;; This definition is just to show what this looks like.
460;; It gets overridden below when menu-bar-update-buffers is called.
461(define-key global-map [menu-bar buffer]
462 (cons "Buffers" (make-sparse-keymap "Buffers")))
40954111 463
d0690d12
RS
464(defvar list-buffers-directory nil)
465
08e8171f
RS
466(defvar menu-bar-update-buffers-maxbuf)
467
09642d97
RS
468(defun menu-bar-select-buffer ()
469 (interactive)
470 (switch-to-buffer last-command-event))
471
472(defun menu-bar-select-frame ()
473 (interactive)
474 (make-frame-visible last-command-event)
475 (raise-frame last-command-event)
476 (select-frame last-command-event))
477
c171b42f
RS
478(defun menu-bar-update-buffers-1 (elt)
479 (cons (format
08e8171f 480 (format "%%%ds %%s%%s %%s" menu-bar-update-buffers-maxbuf)
c171b42f
RS
481 (cdr elt)
482 (if (buffer-modified-p (car elt))
483 "*" " ")
484 (save-excursion
485 (set-buffer (car elt))
486 (if buffer-read-only "%" " "))
487 (let ((file
488 (or (buffer-file-name (car elt))
489 (save-excursion
490 (set-buffer (car elt))
491 list-buffers-directory)
492 "")))
493 (setq file (or (file-name-directory file)
494 ""))
495 (if (> (length file) 20)
496 (setq file (concat "..." (substring file -17))))
497 file))
498 (car elt)))
499
06ff7539
RS
500(defvar menu-bar-buffers-menu-list-buffers-entry nil)
501
09642d97 502(defun menu-bar-update-buffers ()
29397c58 503 ;; If user discards the Buffers item, play along.
4d587a6c 504 (and (lookup-key (current-global-map) [menu-bar buffer])
29397c58
RS
505 (frame-or-buffer-changed-p)
506 (let ((buffers (buffer-list))
507 (frames (frame-list))
b3398af1 508 (maxlen 0)
29397c58
RS
509 buffers-menu frames-menu)
510 ;; If requested, list only the N most recently selected buffers.
511 (if (and (integerp buffers-menu-max-size)
512 (> buffers-menu-max-size 1))
513 (if (> (length buffers) buffers-menu-max-size)
514 (setcdr (nthcdr buffers-menu-max-size buffers) nil)))
515
516 ;; Make the menu of buffers proper.
517 (setq buffers-menu
518 (cons "Select Buffer"
c171b42f
RS
519 (let* ((buffer-list
520 (mapcar 'list buffers))
521 tail
08e8171f 522 (menu-bar-update-buffers-maxbuf 0)
c171b42f
RS
523 alist
524 head)
525 ;; Put into each element of buffer-list
526 ;; the name for actual display,
527 ;; perhaps truncated in the middle.
528 (setq tail buffer-list)
529 (while tail
530 (let ((name (buffer-name (car (car tail)))))
531 (setcdr (car tail)
532 (if (> (length name) 27)
533 (concat (substring name 0 12)
534 "..."
535 (substring name -12))
536 name)))
537 (setq tail (cdr tail)))
538 ;; Compute the maximum length of any name.
539 (setq tail buffer-list)
29397c58 540 (while tail
c171b42f 541 (or (eq ?\ (aref (cdr (car tail)) 0))
08e8171f
RS
542 (setq menu-bar-update-buffers-maxbuf
543 (max menu-bar-update-buffers-maxbuf
c171b42f 544 (length (cdr (car tail))))))
29397c58 545 (setq tail (cdr tail)))
c171b42f
RS
546 ;; Set ALIST to an alist of the form
547 ;; ITEM-STRING . BUFFER
548 (setq tail buffer-list)
29397c58
RS
549 (while tail
550 (let ((elt (car tail)))
c171b42f 551 (or (eq ?\ (aref (cdr elt) 0))
29397c58 552 (setq alist (cons
c171b42f 553 (menu-bar-update-buffers-1 elt)
29397c58
RS
554 alist)))
555 (and alist (> (length (car (car alist))) maxlen)
556 (setq maxlen (length (car (car alist))))))
557 (setq tail (cdr tail)))
558 (setq alist (nreverse alist))
06ff7539
RS
559 ;; Make the menu item for list-buffers
560 ;; or reuse the one we already have.
561 ;; The advantage in reusing one
562 ;; is that it already has the keyboard equivalent
563 ;; cached, so we save the time to look that up again.
564 (or menu-bar-buffers-menu-list-buffers-entry
565 (setq menu-bar-buffers-menu-list-buffers-entry
566 (cons
567 'list-buffers
568 (cons
569 ""
570 'list-buffers))))
571 ;; Update the item string for menu's new width.
572 (setcar (cdr menu-bar-buffers-menu-list-buffers-entry)
573 (concat (make-string (max (- (/ maxlen 2) 8) 0)
574 ?\ )
575 "List All Buffers"))
576 ;; Now make the actual list of items,
577 ;; ending with the list-buffers item.
29397c58
RS
578 (nconc (mapcar '(lambda (pair)
579 ;; This is somewhat risque, to use
580 ;; the buffer name itself as the event
581 ;; type to define, but it works.
582 ;; It would not work to use the buffer
583 ;; since a buffer as an event has its
584 ;; own meaning.
585 (nconc (list (buffer-name (cdr pair))
586 (car pair)
587 (cons nil nil))
588 'menu-bar-select-buffer))
589 alist)
06ff7539 590 (list menu-bar-buffers-menu-list-buffers-entry)))))
29397c58
RS
591
592
593 ;; Make a Frames menu if we have more than one frame.
594 (if (cdr frames)
b3398af1
RS
595 (let ((name (concat (make-string (max (- (/ maxlen 2) 3) 0)
596 ?\ )
597 "Frames"))
598 (frames-menu
599 (cons 'keymap
600 (cons "Select Frame"
601 (mapcar '(lambda (frame)
602 (nconc (list frame
603 (cdr (assq 'name
604 (frame-parameters frame)))
605 (cons nil nil))
606 'menu-bar-select-frame))
607 frames)))))
608 ;; Put it underneath the Buffers menu.
609 (setq buffers-menu (cons (cons 'frames (cons name frames-menu))
610 buffers-menu))))
29397c58
RS
611 (if buffers-menu
612 (setq buffers-menu (cons 'keymap buffers-menu)))
4d587a6c 613 (define-key (current-global-map) [menu-bar buffer]
b3398af1 614 (cons "Buffers" buffers-menu)))))
09642d97
RS
615
616(add-hook 'menu-bar-update-hook 'menu-bar-update-buffers)
2f1139a4 617
3f557298
RS
618(menu-bar-update-buffers)
619
40954111
RS
620;; this version is too slow
621;;;(defun format-buffers-menu-line (buffer)
622;;; "Returns a string to represent the given buffer in the Buffer menu.
623;;;nil means the buffer shouldn't be listed. You can redefine this."
624;;; (if (string-match "\\` " (buffer-name buffer))
625;;; nil
626;;; (save-excursion
627;;; (set-buffer buffer)
628;;; (let ((size (buffer-size)))
629;;; (format "%s%s %-19s %6s %-15s %s"
630;;; (if (buffer-modified-p) "*" " ")
631;;; (if buffer-read-only "%" " ")
632;;; (buffer-name)
633;;; size
634;;; mode-name
635;;; (or (buffer-file-name) ""))))))
636\f
25b048ee
RS
637;;; Set up a menu bar menu for the minibuffer.
638
639(mapcar
640 (function
641 (lambda (map)
642 (define-key map [menu-bar minibuf]
643 (cons "Minibuf" (make-sparse-keymap "Minibuf")))))
644 (list minibuffer-local-ns-map
645 minibuffer-local-must-match-map
646 minibuffer-local-isearch-map
647 minibuffer-local-map
648 minibuffer-local-completion-map))
649
650(mapcar
651 (function
652 (lambda (map)
653 (define-key map [menu-bar minibuf ?\?]
654 '("List Completions" . minibuffer-completion-help))
655 (define-key map [menu-bar minibuf space]
656 '("Complete Word" . minibuffer-complete-word))
657 (define-key map [menu-bar minibuf tab]
4e9d1906 658 '("Complete" . minibuffer-complete))
25b048ee
RS
659 ))
660 (list minibuffer-local-must-match-map
661 minibuffer-local-completion-map))
662
663(mapcar
664 (function
665 (lambda (map)
666 (define-key map [menu-bar minibuf quit]
667 '("Quit" . keyboard-escape-quit))
668 (define-key map [menu-bar minibuf return]
669 '("Enter" . exit-minibuffer))
670 ))
671 (list minibuffer-local-ns-map
672 minibuffer-local-must-match-map
673 minibuffer-local-isearch-map
674 minibuffer-local-map
675 minibuffer-local-completion-map))
676\f
7b7d6615
RS
677(defvar menu-bar-mode nil)
678
057d49d1 679(defun menu-bar-mode (flag)
dfd29450 680 "Toggle display of a menu bar on each frame.
057d49d1
RS
681This command applies to all frames that exist and frames to be
682created in the future.
683With a numeric argument, if the argument is negative,
dfd29450 684turn off menu bars; otherwise, turn on menu bars."
dad8e392 685 (interactive "P")
dad8e392 686
7b7d6615
RS
687 ;; Make menu-bar-mode and default-frame-alist consistent.
688 (let ((default (assq 'menu-bar-lines default-frame-alist)))
689 (if default
690 (setq menu-bar-mode (not (eq (cdr default) 0)))
691 (setq default-frame-alist
692 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
693 default-frame-alist))))
694
695 ;; Toggle or set the mode, according to FLAG.
696 (setq menu-bar-mode (if (null flag) (not menu-bar-mode)
697 (> (prefix-numeric-value flag) 0)))
698
699 ;; Apply it to default-frame-alist.
700 (let ((parameter (assq 'menu-bar-lines default-frame-alist)))
701 (if (consp parameter)
702 (setcdr parameter (if menu-bar-mode 1 0))
703 (setq default-frame-alist
704 (cons (cons 'menu-bar-lines (if menu-bar-mode 1 0))
705 default-frame-alist))))
706
707 ;; Apply it to existing frames.
708 (let ((frames (frame-list)))
709 (while frames
710 (let ((height (cdr (assq 'height (frame-parameters (car frames))))))
711 (modify-frame-parameters (car frames)
712 (list (cons 'menu-bar-lines
713 (if menu-bar-mode 1 0))))
714 (modify-frame-parameters (car frames)
715 (list (cons 'height height))))
716 (setq frames (cdr frames)))))
1db87953 717
bffa5d4d
RS
718(provide 'menu-bar)
719
235aa29b 720;;; menu-bar.el ends here