;;; menubar-items.el --- Menubar and popup-menu content for XEmacs.

;; Copyright (C) 1991-1995, 1997-1998 Free Software Foundation, Inc.
;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
;; Copyright (C) 1995 Sun Microsystems.
;; Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003 Ben Wing.
;; Copyright (C) 1997 MORIOKA Tomohiko.

;; Maintainer: XEmacs Development Team
;; Keywords: frames, extensions, internal, dumped

;; This file is part of XEmacs.

;; XEmacs 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.

;; XEmacs 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 Xmacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Authorship:

;; Created c. 1991 for Lucid Emacs.  Originally called x-menubar.el.
;;   Contained four menus -- File, Edit, Buffers, Help.
;;   Dynamic menu changes possible only through activate-menubar-hook.
;;   Also contained menu manipulation funs, e.g. find-menu-item, add-menu.
;; Options menu added for 19.9 by Jamie Zawinski, late 1993.
;; Major reorganization c. 1994 by Ben Wing; added many items and moved
;;   some items to two new menus, Apps and Tools. (for 19.10?)
;; Generic menubar functions moved to new file, menubar.el, by Ben Wing,
;;   1995, for 19.12; also, creation of current buffers menu options,
;;   and buffers menu changed from purely most-recent to sorted alphabetical,
;;   by mode.  Also added mode-popup-menu support.
;; New API (add-submenu, add-menu-button) and menu filter support added
;;   late summer 1995 by Stig, for 19.13.  Also popup-menubar-menu.
;; Renamed to menubar-items.el c. 1998, with MS Win support.
;; Options menu rewritten to use custom c. 1999 by ? (Jan Vroonhof?).
;; Major reorganization Mar. 2000 by Ben Wing; added many items and changed
;;   top-level menus to File, Edit, View, Cmds, Tools, Options, Buffers.
;; Accelerator spec functionality added Mar. 2000 by Ben Wing.

;;; Commentary:

;; This file is dumped with XEmacs (when window system and menubar support is
;; compiled in).

;;; Code:

(defun Menubar-items-truncate-history (list count label-length)
  "Truncate a history LIST to first COUNT items.
Return a list of (label value) lists with labels truncated to last
LABEL-LENGTH characters of value."
  (mapcar #'(lambda (x)
	      (if (<= (length x) label-length)
                  (list x x)
                (list
                 (concat "..." (substring x (- label-length))) x)))
	  (if (<= (length list) count)
	      list
	    (butlast list (- (length list) count)))))

(defun submenu-generate-accelerator-spec (list &optional omit-chars-list)
  "Add auto-generated accelerator specifications to a submenu.
This can be used to add accelerators to the return value of a menu filter
function.  It correctly ignores unselectable items.  It will destructively
modify the list passed to it.  If an item already has an auto-generated
accelerator spec, this will be removed before the new one is added, making
this function idempotent.

If OMIT-CHARS-LIST is given, it should be a list of lowercase characters,
which will not be used as accelerators."
  (let ((n 0))
    (dolist (item list list)
      (cond
       ((vectorp item)
	(setq n (1+ n))
	(aset item 0
	      (concat
	       (menu-item-generate-accelerator-spec n omit-chars-list)
	       (menu-item-strip-accelerator-spec (aref item 0)))))
       ((consp item)
	(setq n (1+ n))
	(setcar item
		(concat
		 (menu-item-generate-accelerator-spec n omit-chars-list)
		 (menu-item-strip-accelerator-spec (car item)))))))))

(defun menu-item-strip-accelerator-spec (item)
  "Strip an auto-generated accelerator spec off of ITEM.
ITEM should be a string.  This removes specs added by
`menu-item-generate-accelerator-spec' and `submenu-generate-accelerator-spec'."
  (if (string-match "%_. " item)
      (substring item 4)
    item))

(defun menu-item-generate-accelerator-spec (n &optional omit-chars-list)
  "Return an accelerator specification for use with auto-generated menus.
This should be concat'd onto the beginning of each menu line.  The spec
allows the Nth line to be selected by the number N.  '0' is used for the
10th line, and 'a' through 'z' are used for the following 26 lines.

If OMIT-CHARS-LIST is given, it should be a list of lowercase characters,
which will not be used as accelerators."
  (cond ((< n 10) (concat "%_" (int-to-string n) " "))
	((= n 10) "%_0 ")
	((<= n 36)
	 (setq n (- n 10))
	 (let ((m 0))
	   (while (> n 0)
	     (setq m (1+ m))
	     (while (memq (int-to-char (+ m (- (char-to-int ?a) 1)))
			  omit-chars-list)
	       (setq m (1+ m)))
	     (setq n (1- n)))
	   (if (<= m 26)
	       (concat
		"%_"
		(char-to-string (int-to-char (+ m (- (char-to-int ?a) 1))))
		" ")
	     "")))
	(t "")))

(defcustom menu-max-items 25
  "*Maximum number of items in generated menus.
If number of entries in such a menu is larger than this value, split menu
into submenus of nearly equal length (see `menu-submenu-max-items').  If
nil, never split menu into submenus."
  :group 'menu
  :type '(choice (const :tag "no submenus" nil)
		 (integer)))

(defcustom menu-submenu-max-items 20
  "*Maximum number of items in submenus when splitting menus.
We split large menus into submenus of this many items, and then balance
them out as much as possible (otherwise the last submenu may have very few
items)."
  :group 'menu
  :type 'integer)

(defcustom menu-submenu-name-format "%-12.12s ... %.12s"
  "*Format specification of the submenu name when splitting menus.
Used by `menu-split-long-menu' if the number of entries in a menu is
larger than `menu-menu-max-items'.
This string should contain one %s for the name of the first entry and
one %s for the name of the last entry in the submenu.
If the value is a function, it should return the submenu name.  The
function is be called with two arguments, the names of the first and
the last entry in the menu."
  :group 'menu
  :type '(choice (string :tag "Format string")
		 (function)))

(defun menu-split-long-menu (menu)
  "Split MENU according to `menu-max-items' and add accelerator specs.

You should normally use the idiom

\(menu-split-long-menu (menu-sort-menu menu))

See also `menu-sort-menu'."
  (let ((len (length menu)))
    (if (or (null menu-max-items)
	    (<= len menu-max-items))
	(submenu-generate-accelerator-spec menu)
      (let* ((outer (/ (+ len (1- menu-submenu-max-items))
		       menu-submenu-max-items))
	     (inner (/ (+ len (1- outer)) outer))
	     (result nil))
	(while menu
	  (let ((sub nil)
		(from (car menu)))
	    (dotimes (foo (min inner len))
	      (setq sub  (cons (car menu) sub)
		    menu (cdr menu)))
	    (setq len (- len inner))
	    (let ((to (car sub)))
	      (setq sub (nreverse sub))
	      (setq result
		    (cons (cons (if (stringp menu-submenu-name-format)
				    (format menu-submenu-name-format
					    (menu-item-strip-accelerator-spec
					     (aref from 0))
					    (menu-item-strip-accelerator-spec
					     (aref to 0)))
				  (funcall menu-submenu-name-format
					   (menu-item-strip-accelerator-spec
					    (aref from 0))
					   (menu-item-strip-accelerator-spec
					    (aref to 0))))
				(submenu-generate-accelerator-spec sub))
			  result)))))
	(submenu-generate-accelerator-spec (nreverse result))))))

(defun menu-sort-menu (menu)
  "Sort MENU alphabetically.

You should normally use the idiom

\(menu-split-long-menu (menu-sort-menu menu))

See also `menu-split-long-menu'."
  (sort menu
	#'(lambda (a b) (string-lessp (aref a 0) (aref b 0)))))

(defun coding-system-menu-filter (fun active &optional dots)
  "Filter for menu entries with a submenu listing all coding systems.
This is for operations that take a coding system as an argument.  FUN
should be a function of one argument, which will be a coding system symbol.
ACTIVE should be a function one argument (again, a coding system symbol),
indicating whether the entry is active.  If DOTS is given, the menu entries
will have three dots appended.

Write your filter like this:

:filter
  (lambda (menu)
    (lambda (entry) ...)
    (lambda (entry) ...))
"
  (menu-split-long-menu
   (menu-sort-menu
    (mapcar
     #'(lambda (_csmf_entry)
	 `[ ,(concat (coding-system-description _csmf_entry)
		     (if dots "..." ""))
	    (funcall ,fun ',_csmf_entry)
	    :active (funcall ,active ',_csmf_entry)
	    ])
     (delete-if
      #'(lambda (name)
	  (or (coding-system-alias-p name)
	      (not (eq name (coding-system-name
			     (coding-system-base name))))))
      (coding-system-list))))))

(defconst default-menubar
; (purecopy-menubar ;purespace is dead
   ;; note backquote.
   `(
     ("%_File"
      ["%_Open..." find-file]
      ["Open in Other %_Window..." find-file-other-window]
      ["Open in New %_Frame..." find-file-other-frame]
      ("Open with Specified %_Encoding"
       :filter
       (lambda (menu)
	 (coding-system-menu-filter
	  (lambda (entry)
	    (let ((coding-system-for-read entry))
	      (call-interactively 'find-file)))
	  (lambda (entry) t)
	  t))
       )
      ["%_Hex Edit File..." hexl-find-file
       :active (fboundp 'hexl-find-file)]
      ["%_Insert File..." insert-file]
      ["%_View File..." view-file]
      "------"
      ["%_New Frame" make-frame]
      ["Frame on Other %_Display..." make-frame-on-display
       :active (fboundp 'make-frame-on-display)]
      ["%_Close Frame" delete-frame
       :active (not (eq (next-frame (selected-frame) 'nomini 'window-system)
			(selected-frame)))]
      "-----"
      ["%_Save" save-buffer
       :active (buffer-modified-p)
       :suffix (if put-buffer-names-in-file-menu (buffer-name) "")]
      ["Save %_As..." write-file]
      ["Save So%_me Buffers" save-some-buffers]
      "-----"
      ,@(if (valid-specifier-tag-p 'msprinter)
	  '(["Page Set%_up..." generic-page-setup]))
      ["%_Print" generic-print-buffer
       :active (or (valid-specifier-tag-p 'msprinter)
		   (and (not (eq system-type 'windows-nt))
			(fboundp 'lpr-region)))
       :suffix (if (region-active-p) "Selection..."
		 (if put-buffer-names-in-file-menu (concat (buffer-name) "...")
		   "..."))]
      ,@(unless (valid-specifier-tag-p 'msprinter)
	  '(["Prett%_y-Print" ps-print-buffer-with-faces
	     :active (fboundp 'ps-print-buffer-with-faces)
	     :suffix (if put-buffer-names-in-file-menu (buffer-name) "")]))
      "-----"
      ["%_Revert Buffer" revert-buffer
       :active (or buffer-file-name revert-buffer-function)
       :suffix (if put-buffer-names-in-file-menu (buffer-name) "")]
      ("Rever%_t/Recover"
      ("Revert Buffer with Specified %_Encoding"
       :filter
       (lambda (menu)
	 (coding-system-menu-filter
	  (lambda (entry)
	    (let ((coding-system-for-read entry))
	      (revert-buffer)))
	  (lambda (entry) (or buffer-file-name revert-buffer-function))
	  t))
       )
      ["Re%_cover Buffer from Autosave" (recover-file buffer-file-name)
       :active buffer-file-name
       :suffix (if put-buffer-names-in-file-menu (buffer-name) "")]
      ["Recover %_Session..." recover-session]
      )
      "-----"
      ["E%_xit XEmacs" save-buffers-kill-emacs]
      )

     ("%_Edit"
      ["%_Undo" undo
       :active (and (not (eq buffer-undo-list t))
		    (or buffer-undo-list pending-undo-list))
       :suffix (if (eq last-command 'undo) "More" "")]
      ["%_Redo" redo
       :included (fboundp 'redo)
       :active (not (or (eq buffer-undo-list t)
			(eq last-buffer-undo-list nil)
			(not (or (eq last-buffer-undo-list buffer-undo-list)
				 (and (null (car-safe buffer-undo-list))
				      (eq last-buffer-undo-list
					  (cdr-safe buffer-undo-list)))))
			(or (eq buffer-undo-list pending-undo-list)
			    (eq (cdr buffer-undo-list) pending-undo-list))))
       :suffix (if (eq last-command 'redo) "More" "")]
      "----"
      ["Cu%_t" kill-primary-selection
       :active (selection-owner-p)]
      ["%_Copy" copy-primary-selection
       :active (selection-owner-p)]
      ["%_Paste" yank-clipboard-selection
       :active (selection-exists-p 'CLIPBOARD)]
      ["%_Delete" delete-primary-selection
       :active (selection-owner-p)]
      "----"
      ["Select %_All" mark-whole-buffer]
      ["Select Pa%_ge" mark-page]
      ["Select Paragrap%_h" mark-paragraph]
      ["Re%_select Region" activate-region :active (mark t)]
      "----"
      ["%_Find..." make-search-dialog]
      ["R%_eplace..." query-replace]
      ["Replace (Rege%_xp)..." query-replace-regexp]
      ["List %_Matching Lines..." list-matching-lines]
      )

     ("%_View"
      ["%_Split Window" split-window-vertically]
      ["S%_plit Window (Side by Side)" split-window-horizontally]
      ["%_Un-Split (Keep This)" delete-other-windows
       :active (not (one-window-p t))]
      ["Un-Split (Keep %_Others)" delete-window
       :active (not (one-window-p t))]
      ["Balance %_Windows" balance-windows
       :active (not (one-window-p t))]
      ["Shrink Window to %_Fit" shrink-window-if-larger-than-buffer]
      "----"
      ("N%_arrow"
       ["%_Narrow to Region" narrow-to-region :active (region-exists-p)]
       ["Narrow to %_Page" narrow-to-page]
       ["Narrow to %_Defun" narrow-to-defun]
      "----"
       ["%_Widen" widen :active (or (/= (point-min) 1)
				    (/= (point-max) (1+ (buffer-size))))]
       )
      "----"
      ["%_Goto Line..." goto-line]
      ["Beginning of %_Defun" beginning-of-defun]
      ["%_End of Defun" end-of-defun]
      ["%_Count Lines in Buffer" count-lines-buffer
       :included (not (region-active-p))]
      ["%_Count Lines in Region" count-lines-region
       :included (region-active-p)]
      "----"
      ["%_Jump to Previous Mark" (set-mark-command t)
       :active (mark t)]
      ["Se%_t Bookmark" bookmark-set
       :active (fboundp 'bookmark-set)]
      ("%_Bookmarks"
       :filter
       (lambda (menu)
	 (let ((alist (and-boundp 'bookmark-alist
			bookmark-alist)))
	   (if (not alist)
	       menu
	     (let ((items
		    (submenu-generate-accelerator-spec
		     (mapcar #'(lambda (bmk)
				 `[,bmk (bookmark-jump ',bmk)])
			     (bookmark-all-names)))))
	       (append menu '("---") items)))))
       "---"
       ["Insert %_Contents" bookmark-menu-insert
	:active (fboundp 'bookmark-menu-insert)]
       ["Insert L%_ocation" bookmark-menu-locate
	:active (fboundp 'bookmark-menu-locate)]
       "---"
       ["%_Rename Bookmark" bookmark-menu-rename
	:active (fboundp 'bookmark-menu-rename)]
       ("%_Delete Bookmark"
	 :filter (lambda (menu)
		   (submenu-generate-accelerator-spec
		    (mapcar #'(lambda (bmk)
				`[,bmk (bookmark-delete ',bmk)])
			    (bookmark-all-names)))))
       ["%_Edit Bookmark List" bookmark-bmenu-list
	:active (and-boundp 'bookmark-alist bookmark-alist)]
       "---"
       ["%_Save Bookmarks"        bookmark-save
	:active (and-boundp 'bookmark-alist bookmark-alist)]
       ["Save Bookmarks %_As..."  bookmark-write
	:active (and-boundp 'bookmark-alist bookmark-alist)]
       ["%_Load a Bookmark File" bookmark-load
	:active (fboundp 'bookmark-load)]
       )
      )


     ("C%_mds"
      ["Repeat Last Comple%_x Command..." repeat-complex-command]
      ["E%_valuate Lisp Expression..." eval-expression]
      ["Execute %_Named Command..." execute-extended-command]
      "----"
      ["Start %_Defining Macro" start-kbd-macro
       :included (not defining-kbd-macro)]
      ["Stop %_Defining Macro" end-kbd-macro
       :included defining-kbd-macro]
      ["%_Execute Last Macro" call-last-kbd-macro
       :active last-kbd-macro]
      ("Other %_Macro"
       ["Edit %_Last Macro" edit-last-kbd-macro
	:active last-kbd-macro]
       ["%_Edit Macro..." edit-kbd-macro]
       ["%_Append to Last Macro" (start-kbd-macro t)
	:active (and (not defining-kbd-macro) last-kbd-macro)]
       "---"
       ["%_Name Last Macro..." name-last-kbd-macro
	:active last-kbd-macro]
       ["Assign Last Macro to %_Key..." assign-last-kbd-macro-to-key
	:active (and last-kbd-macro
		     (fboundp 'assign-last-kbd-macro-to-key))]
       "---"
       ["E%_xecute Last Macro on Region Lines"
	:active (and last-kbd-macro (region-exists-p))]
       "---"
       ["%_Query User During Macro" kbd-macro-query
	:active defining-kbd-macro]
       ["Enter %_Recursive Edit During Macro" (kbd-macro-query t)
	:active defining-kbd-macro]
       "---"
       ["%_Insert Named Macro into Buffer..." insert-kbd-macro]
       ["Read Macro from Re%_gion" read-kbd-macro
	:active (region-exists-p)]
       )
      "----"
       ["D%_ynamic Abbrev Expand" dabbrev-expand]
       ["Define %_Global Abbrev for " add-global-abbrev
	:suffix	(truncate-string-to-width (abbrev-string-to-be-defined nil)
					  40 nil nil t)]
      ("Other %_Abbrev"
       ["Dynamic Abbrev %_Complete" dabbrev-completion]
       ["Dynamic Abbrev Complete in %_All Buffers" (dabbrev-completion 16)]
       "----"
       "----"
       ["%_Define Global Abbrev for " add-global-abbrev
	:suffix	(truncate-string-to-width (abbrev-string-to-be-defined nil)
					  40 nil nil t)]
       ["Define %_Mode-Specific Abbrev for " add-mode-abbrev
	:suffix	(truncate-string-to-width (abbrev-string-to-be-defined nil)
					  40 nil nil t)]
       ["Define Global Ex%_pansion for " inverse-add-global-abbrev
	:suffix	(truncate-string-to-width
		 (inverse-abbrev-string-to-be-defined 1)
		 40 nil nil t)]
       ["Define Mode-Specific Expa%_nsion for " inverse-add-mode-abbrev
	:suffix	(truncate-string-to-width
		 (inverse-abbrev-string-to-be-defined 1)
		 40 nil nil t)]
       "---"
       ["E%_xpand Abbrev" expand-abbrev]
       ["Expand Abbrevs in Re%_gion" expand-region-abbrevs
	:active (region-exists-p)]
       ["%_Unexpand Last Abbrev" unexpand-abbrev
	:active (and (stringp last-abbrev-text)
		     (> last-abbrev-location 0))]
       "---"
       ["%_Kill All Abbrevs" kill-all-abbrevs]
       ["%_Insert All Abbrevs into Buffer" insert-abbrevs]
       ["%_List Abbrevs" list-abbrevs]
       "---"
       ["%_Edit Abbrevs" edit-abbrevs]
       ["%_Redefine Abbrevs from Buffer" edit-abbrevs-redefine
	:active (eq major-mode 'edit-abbrevs-mode)]
       "---"
       ["%_Save Abbrevs As..." write-abbrev-file]
       ["L%_oad Abbrevs..." read-abbrev-file]
       )
	"---"
      ["%_Cut Rectangle" kill-rectangle]
      ("Other %_Rectangles/Register"
       ["%_Yank Rectangle" yank-rectangle]
       ["Rectangle %_to Register" copy-rectangle-to-register]
       ["Rectangle %_from Register" insert-register]
       ["%_Delete Rectangle" clear-rectangle]
       ["%_Open Rectangle" open-rectangle]
       ["%_Prefix Rectangle..." string-rectangle]
       ["Rectangle %_Mousing"
	(customize-set-variable	'mouse-track-rectangle-p
				(not mouse-track-rectangle-p))
	:style toggle :selected mouse-track-rectangle-p]
       "---"
       ["%_Copy to Register..." copy-to-register :active (region-exists-p)]
       ["%_Append to Register..." append-register :active (region-exists-p)]
       ["%_Insert Register..." insert-register]
       "---"
       ["%_Save Point to Register" point-to-register]
       ["%_Jump to Register"  register-to-point]
       )
	"---"
       ["%_Sort Lines in Region" sort-lines :active (region-exists-p)]
       ["%_Uppercase Region or Word" upcase-region-or-word]
       ["%_Lowercase Region or Word" downcase-region-or-word]
       ["%_Indent Region or Balanced Expression"
	indent-region-or-balanced-expression]
       ["%_Fill Paragraph or Region" fill-paragraph-or-region]
       ("Other %_Text Commands"
	["Sort %_Paragraphs in Region" sort-paragraphs :active (region-exists-p)]
	["Sort Pa%_ges in Region" sort-pages :active (region-exists-p)]
	["Sort C%_olumns in Region" sort-columns :active (region-exists-p)]
	["Sort %_Regexp..." sort-regexp-fields :active (region-exists-p)]
	"---"
	["%_Capitalize Region" capitalize-region :active (region-exists-p)]
	["Title-C%_ase Region" capitalize-region-as-title
	 :active (region-exists-p)]
	"----"
	["C%_enter Region or Paragraph"
	 (if (region-active-p) (center-region) (center-line))]
	["Center %_Line" center-line]
	"---"
	["%_Indent Region Rigidly" indent-rigidly :active (region-exists-p)]
	["In%_dent To Column..." indent-to-column]
	"---"
	["%_Untabify (Tabs to Spaces)" untabify :active (and (region-exists-p)
							  (fboundp 'untabify))]
	["%_Tabify (Spaces to Tabs)" tabify :active (and (region-exists-p)
							(fboundp 'tabify))]
	["Tab to Tab %_Stop" tab-to-tab-stop]
	["Edit Ta%_b Stops" edit-tab-stops]
	)
	"---"
       ("S%_pell-Check"
	["%_Buffer" ispell-buffer
	 :active (fboundp 'ispell-buffer)]
	"---"
	["%_Word" ispell-word]
	["%_Complete Word" ispell-complete-word]
	["%_Region" ispell-region]
	)
       )
     
     ("%_Tools"
      ("%_Packages"
       ("%_Set Download Site"
	("%_Official Releases"
	 :filter (lambda (&rest junk)
		   (menu-split-long-menu
		    (submenu-generate-accelerator-spec
		     (package-ui-download-menu)))))
	("%_Pre-Releases"
	 :filter (lambda (&rest junk)
		   (menu-split-long-menu
		    (submenu-generate-accelerator-spec
		     (package-ui-pre-release-download-menu)))))
	("%_Site Releases"
	 :filter (lambda (&rest junk)
		   (menu-split-long-menu
		    (submenu-generate-accelerator-spec
		     (package-ui-site-release-download-menu))))))
       "--:shadowEtchedIn"
       ["%_Update Package Index" package-get-update-base]
       ["%_List and Install" pui-list-packages]
       ["U%_pdate Installed Packages" package-get-update-all]
       ["%_Help" (Info-goto-node "(xemacs)Packages")])
      ("%_Internet"
       ["Read Mail %_1 (VM)..." vm
	:active (fboundp 'vm)]
       ["Read Mail %_2 (MH)..." (mh-rmail t)
	:active (fboundp 'mh-rmail)]
       ["Send %_Mail..." compose-mail
	:active (fboundp 'compose-mail)]
       ["Usenet %_News" gnus
	:active (fboundp 'gnus)]
       ["Browse the %_Web" w3
	:active (fboundp 'w3)])
      "---"
      ("%_Grep"
       :filter
       (lambda (menu)
	 (if (or (not (boundp 'grep-history)) (null grep-history))
	     menu
	   (let ((items
		  (submenu-generate-accelerator-spec
                   (mapcar #'(lambda (label-value)
			       (vector (first label-value)
				       (list 'grep (second label-value))))
			   (Menubar-items-truncate-history
                            grep-history 10 50)))))
	     (append menu '("---") items))))
       ["%_Grep..." grep :active (fboundp 'grep)]
       ["%_Kill Grep" kill-compilation
	:active (and (fboundp 'kill-compilation)
		     (fboundp 'compilation-find-buffer)
		     (let ((buffer (condition-case nil
				       (compilation-find-buffer)
				     (error nil))))
		       (and buffer (get-buffer-process buffer))))]
       "---"
       ["Grep %_All Files in Current Directory..."
	grep-all-files-in-current-directory
	:active (fboundp 'grep-all-files-in-current-directory)]
       ["Grep All Files in Current Directory %_Recursively..."
	grep-all-files-in-current-directory-and-below
	:active (fboundp 'grep-all-files-in-current-directory-and-below)]
       "---"
       ["Grep %_C and C Header Files in Current Directory..."
	(progn
	  (require 'compile)
	  (let ((grep-command
		 (cons (concat grep-command " *.[chCH]"
					; i wanted to also use *.cc and *.hh.
					; see long comment below under Perl.
			       )
		       (length grep-command))))
	    (call-interactively 'grep)))
	:active (fboundp 'grep)]
       ["Grep C Hea%_der Files in Current Directory..."
	(progn
	  (require 'compile)
	  (let ((grep-command
		 (cons (concat grep-command " *.[hH]"
					; i wanted to also use *.hh.
					; see long comment below under Perl.
			       )
		       (length grep-command))))
	    (call-interactively 'grep)))
	:active (fboundp 'grep)]
       ["Grep %_E-Lisp Files in Current Directory..."
	(progn
	  (require 'compile)
	  (let ((grep-command
		 (cons (concat grep-command " *.el")
		       (length grep-command))))
	    (call-interactively 'grep)))
	:active (fboundp 'grep)]
       ["Grep %_Perl Files in Current Directory..."
	(progn
	  (require 'compile)
	  (let ((grep-command
		 (cons (concat grep-command " *.pl"
					; i wanted to use this:
					; " *.pl *.pm *.am"
					; but grep complains if it can't
					; match anything in a glob, and
					; that screws other things up.
					; perhaps we need to first scan
					; each separate glob in the directory
					; to see if there are any files in
					; that glob, and if not, omit it.
			       )
		       (length grep-command))))
	    (call-interactively 'grep)))
	:active (fboundp 'grep)]
       ["Grep %_HTML Files in Current Directory..."
	(progn
	  (require 'compile)
	  (let ((grep-command
		 (cons (concat grep-command " *.*htm*")
		       (length grep-command))))
	    (call-interactively 'grep)))
	:active (fboundp 'grep)]
       "---"
       ["%_Next Match" next-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["Pre%_vious Match" previous-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["%_First Match" first-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["G%_oto Match" compile-goto-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       "---"
       ["%_Set Grep Command..."
	(progn
	  (require 'compile)
	  (customize-set-variable
	   'grep-command
	   (read-shell-command "Default Grep Command: " grep-command)))
	:active (fboundp 'grep)
	]
       )
      ("%_Compile"
       :filter
       (lambda (menu)
	 (if (or (not (boundp 'compile-history)) (null compile-history))
	     menu
	   (let ((items
		  (submenu-generate-accelerator-spec
		   (mapcar #'(lambda (label-value)
			       (vector (first label-value)
				       (list 'compile (second label-value))))
			   (Menubar-items-truncate-history
                            compile-history 10 50)))))
	     (append menu '("---") items))))
       ["%_Compile..." compile :active (fboundp 'compile)]
       ["%_Repeat Compilation" recompile :active (fboundp 'recompile)]
       ["%_Kill Compilation" kill-compilation
	:active (and (fboundp 'kill-compilation)
		     (fboundp 'compilation-find-buffer)
		     (let ((buffer (condition-case nil
				       (compilation-find-buffer)
				     (error nil))))
		       (and buffer (get-buffer-process buffer))))]
       "---"
       ["%_Next Error" next-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["Pre%_vious Error" previous-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["%_First Error" first-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       ["G%_oto Error" compile-goto-error
	:active (and (fboundp 'compilation-errors-exist-p)
		     (compilation-errors-exist-p))]
       )
      ("%_Debug"
       ["%_GDB..." gdb
	:active (fboundp 'gdb)]
       ["%_DBX..." dbx
	:active (fboundp 'dbx)])
      ("%_Shell"
       ["%_Shell" shell
	:active (fboundp 'shell)]
       ["S%_hell Command..." shell-command
	:active (fboundp 'shell-command)]
       ["Shell Command on %_Region..." shell-command-on-region
       :active (and (fboundp 'shell-command-on-region) (region-exists-p))])

      ("%_Tags"
       ["%_Find Tag..." find-tag]
       ["Find %_Other Window..." find-tag-other-window]
       ["%_Next Tag..." (find-tag nil)]
       ["N%_ext Other Window..." (find-tag-other-window nil)]
       ["Next %_File" next-file]
       "-----"
       ["Tags %_Search..." tags-search]
       ["Tags %_Replace..." tags-query-replace]
       ["%_Continue Search/Replace" tags-loop-continue]
       "-----"
       ["%_Pop stack" pop-tag-mark]
       ["%_Apropos..." tags-apropos]
       "-----"
       ["%_Set Tags Table File..." visit-tags-table]
       )

      "----"

      ("Ca%_lendar"
       ["%_3-Month Calendar" calendar
	:active (fboundp 'calendar)]
       ["%_Diary" diary
	:active (fboundp 'diary)]
       ["%_Holidays" holidays
	:active (fboundp 'holidays)]
       ;; we're all pagans at heart ...
       ["%_Phases of the Moon" phases-of-moon
	:active (fboundp 'phases-of-moon)]
       ["%_Sunrise/Sunset" sunrise-sunset
	:active (fboundp 'sunrise-sunset)])

      ("Ga%_mes"
       ["%_Mine Game" xmine
	:active (fboundp 'xmine)]
       ["%_Tetris" tetris
	:active (fboundp 'tetris)]
       ["%_Sokoban" sokoban
	:active (fboundp 'sokoban)]
       ["Quote from %_Zippy" yow
	:active (fboundp 'yow)]
       ["%_Psychoanalyst" doctor
	:active (fboundp 'doctor)]
       ["Ps%_ychoanalyze Zippy!" psychoanalyze-pinhead
	:active (fboundp 'psychoanalyze-pinhead)]
       ["%_Random Flames" flame
	:active (fboundp 'flame)]
       ["%_Dunnet (Adventure)" dunnet
	:active (fboundp 'dunnet)]
       ["Towers of %_Hanoi" hanoi
	:active (fboundp 'hanoi)]
       ["Game of %_Life" life
	:active (fboundp 'life)]
       ["M%_ultiplication Puzzle" mpuz
	:active (fboundp 'mpuz)])

      "----"
      )

     ("%_Options"
      ("%_Behaviors"
       :filter 
       (lambda (menu)
	 (menu-split-long-menu
	  (menu-sort-menu
	   (loop for behavior being the hash-keys in behavior-hash-table
	     using (hash-value plist)
	     collect (vector (format "%s (%s)" behavior
				     (getf plist :short-doc))
			     `(if (memq ',behavior enabled-behavior-list)
				  (disable-behavior ',behavior)
				(enable-behavior ',behavior))
			     :style 'toggle
			     :selected `(memq ',behavior
					      enabled-behavior-list))
	     )))))

      ("%_Advanced (Customize)"
       ("%_Emacs" :filter (lambda (&rest junk)
			    (cdr (custom-menu-create 'emacs))))
       ["%_Group..." customize-group]
       ["%_Variable..." customize-variable]
       ["%_Face..." customize-face]
       ["%_Saved..." customize-saved]
       ["Se%_t..." customize-customized]
       ["%_Apropos..." customize-apropos]
       ["%_Browse..." customize-browse])
      "---"
      ("%_Editing"
       ["This Buffer %_Read Only" (toggle-read-only)
	:style toggle :selected buffer-read-only]
       ["%_Yank/Kill Interact With Clipboard"
	(if (eq interprogram-cut-function 'own-clipboard)
	    (progn
	      (customize-set-variable 'interprogram-cut-function nil)
	      (customize-set-variable 'interprogram-paste-function nil))
	  (customize-set-variable 'interprogram-cut-function 'own-clipboard)
	  (customize-set-variable 'interprogram-paste-function 'get-clipboard))
	:style toggle
	:selected (eq interprogram-cut-function 'own-clipboard)]
       ["%_Overstrike"
	(progn
	  (setq overwrite-mode (if overwrite-mode nil 'overwrite-mode-textual))
	  (customize-set-variable 'overwrite-mode overwrite-mode))
	:style toggle :selected overwrite-mode]
       ["%_Abbrev Mode"
	(customize-set-variable 'abbrev-mode
				(not (default-value 'abbrev-mode)))
	:style toggle
	:selected (default-value 'abbrev-mode)]
       ["Active Re%_gions"
	(customize-set-variable 'zmacs-regions (not zmacs-regions))
	:style toggle :selected zmacs-regions]
       "---"
       ["%_Case Sensitive Search"
	(customize-set-variable 'case-fold-search
				(setq case-fold-search (not case-fold-search)))
	:style toggle :selected (not case-fold-search)]
       ["Case %_Matching Replace"
	(customize-set-variable 'case-replace (not case-replace))
	:style toggle :selected case-replace]
       "---"
       ("%_Newline at End of File..."
	["%_Don't Require"
	 (customize-set-variable 'require-final-newline nil)
	 :style radio :selected (not require-final-newline)]
	["%_Require"
	 (customize-set-variable 'require-final-newline t)
	 :style radio :selected (eq require-final-newline t)]
	["%_Ask"
	 (customize-set-variable 'require-final-newline 'ask)
	 :style radio :selected (and require-final-newline
				     (not (eq require-final-newline t)))])
       ["Add Newline When Moving Past %_End"
	(customize-set-variable 'next-line-add-newlines
				(not next-line-add-newlines))
	:style toggle :selected next-line-add-newlines])
      ("%_Keyboard and Mouse"
       ["%_Delete Key Deletes Selection"
	(customize-set-variable 'pending-delete-mode (not pending-delete-mode))
	:style toggle
	:selected (and (boundp 'pending-delete-mode) pending-delete-mode)
	:active (boundp 'pending-delete-mode)]
       ["`kill-%_word' Stores in Clipboard"
	(customize-set-variable 'kill-word-into-kill-ring
				(not kill-word-into-kill-ring))
	:style toggle
	:selected kill-word-into-kill-ring]
       ["`kill-%_line' Kills Whole Line at Beg"
	 (customize-set-variable 'kill-whole-line (not kill-whole-line))
	 :style toggle
	 :selected kill-whole-line]
       ["Size for %_Block-Movement Commands..."
	(customize-set-variable 'block-movement-size
				(read-number "Block Movement Size: "
					      t block-movement-size))]
       ["%_VI Emulation"
	(progn
	  (toggle-viper-mode)
	  (customize-set-variable 'viper-mode viper-mode))
	:style toggle :selected (and (boundp 'viper-mode) viper-mode)
	:active (fboundp 'toggle-viper-mode)]
       "----"
       ["S%_hifted Motion Keys Select Region"
	 (customize-set-variable 'shifted-motion-keys-select-region
				 (not shifted-motion-keys-select-region))
	 :style toggle
	 :selected shifted-motion-keys-select-region]
       ["%_After Shifted Motion, Unshifted Motion Keys Deselect"
	 (customize-set-variable 'unshifted-motion-keys-deselect-region
				 (not unshifted-motion-keys-deselect-region))
	 :style toggle
	 :selected unshifted-motion-keys-deselect-region]
       "----"
       ["%_Set Key..." global-set-key]
       ["%_Unset Key..." global-unset-key]
       "---"
       ["%_Mouse Paste at Text Cursor (not Clicked Location)"
	(customize-set-variable 'mouse-yank-at-point (not mouse-yank-at-point))
	:style toggle :selected mouse-yank-at-point]
       "---"
       ["%_Teach Extended Commands"
	(customize-set-variable 'teach-extended-commands-p
				(not teach-extended-commands-p))
	:style toggle :selected teach-extended-commands-p]
       )
      ("%_Printing"
       ["Set Printer %_Name for Generic Print Support..."
	(customize-set-variable
	 'printer-name
	 (read-string "Set printer name: " printer-name))]
       "---"
       ["Command-Line %_Switches for `lpr'/`lp'..."
	;; better to directly open a customization buffer, since the value
	;; must be a list of strings, which is somewhat complex to prompt for.
	(customize-variable 'lpr-switches)
	(boundp 'lpr-switches)]
       ("%_Pretty-Print Paper Size"
	["%_Letter"
	 (customize-set-variable 'ps-paper-type 'letter)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'letter))
	 :active (boundp 'ps-paper-type)]
	["Lette%_r-Small"
	 (customize-set-variable 'ps-paper-type 'letter-small)
	 :style radio
	 :selected (and (boundp 'ps-paper-type)
			(eq ps-paper-type 'letter-small))
	 :active (boundp 'ps-paper-type)]
	["Le%_gal"
	 (customize-set-variable 'ps-paper-type 'legal)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'legal))
	 :active (boundp 'ps-paper-type)]
	["%_Statement"
	 (customize-set-variable 'ps-paper-type 'statement)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'statement))
	 :active (boundp 'ps-paper-type)]
	["%_Executive"
	 (customize-set-variable 'ps-paper-type 'executive)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'executive))
	 :active (boundp 'ps-paper-type)]
	["%_Tabloid"
	 (customize-set-variable 'ps-paper-type 'tabloid)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'tabloid))
	 :active (boundp 'ps-paper-type)]
	["Le%_dger"
	 (customize-set-variable 'ps-paper-type 'ledger)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'ledger))
	 :active (boundp 'ps-paper-type)]
	["A%_3"
	 (customize-set-variable 'ps-paper-type 'a3)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'a3))
	 :active (boundp 'ps-paper-type)]
	["%_A4"
	 (customize-set-variable 'ps-paper-type 'a4)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'a4))
	 :active (boundp 'ps-paper-type)]
	["A4s%_mall"
	 (customize-set-variable 'ps-paper-type 'a4small)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'a4small))
	 :active (boundp 'ps-paper-type)]
	["B%_4"
	 (customize-set-variable 'ps-paper-type 'b4)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'b4))
	 :active (boundp 'ps-paper-type)]
	["%_B5"
	 (customize-set-variable 'ps-paper-type 'b5)
	 :style radio
	 :selected (and (boundp 'ps-paper-type) (eq ps-paper-type 'b5))
	 :active (boundp 'ps-paper-type)]
	)
       ["%_Color Printing"
	(cond (ps-print-color-p
	       (customize-set-variable 'ps-print-color-p nil)
	       ;; I'm wondering whether all this muck is useful.
	       (and (boundp 'original-face-background)
		    original-face-background
		    (set-face-background 'default original-face-background)))
	      (t
	       (customize-set-variable 'ps-print-color-p t)
	       (setq original-face-background
		     (face-background-instance 'default))
	       (set-face-background 'default "white")))
	:style toggle
	:selected (and (boundp 'ps-print-color-p) ps-print-color-p)
	:active (boundp 'ps-print-color-p)])
      ("%_Internet"
       ("%_Compose Mail With"
	["Default Emacs Mailer"
	 (customize-set-variable 'mail-user-agent 'sendmail-user-agent)
	 :style radio
	 :selected (eq mail-user-agent 'sendmail-user-agent)]
	["MH"
	 (customize-set-variable 'mail-user-agent 'mh-e-user-agent)
	 :style radio
	 :selected (eq mail-user-agent 'mh-e-user-agent)
	 :active (get 'mh-e-user-agent 'composefunc)]
	["GNUS"
	 (customize-set-variable 'mail-user-agent 'message-user-agent)
	 :style radio
	 :selected (eq mail-user-agent 'message-user-agent)
	 :active (get 'message-user-agent 'composefunc)]
	)
       ["Set My %_Email Address..."
	(customize-set-variable
	 'user-mail-address
	 (read-string "Set email address: " user-mail-address))]
       ["Set %_Machine Email Name..."
	(customize-set-variable
	 'mail-host-address
	 (read-string "Set machine email name: " mail-host-address))]
       ["Set %_SMTP Server..."
	(progn
	  (require 'smtpmail)
	  (customize-set-variable
	   'smtpmail-smtp-server
	   (read-string "Set SMTP server: " smtpmail-smtp-server)))
	:active (and (boundp 'send-mail-function)
		     (eq send-mail-function 'smtpmail-send-it))]
       ["SMTP %_Debug Info"
	(progn
	  (require 'smtpmail)
	  (customize-set-variable 'smtpmail-debug-info
				  (not smtpmail-debug-info)))
	:style toggle
	:selected (and (boundp 'smtpmail-debug-info) smtpmail-debug-info)
	:active (and (boundp 'send-mail-function)
		     (eq send-mail-function 'smtpmail-send-it))])
      ("%_Troubleshooting"
       ["%_Debug on Error [not saved]"
	(setq debug-on-error (not debug-on-error))
	:style toggle :selected debug-on-error]
       ["Debug on %_Quit [not saved]"
	(setq debug-on-quit (not debug-on-quit))
	:style toggle :selected debug-on-quit]
       ["Debug on S%_ignal [not saved]"
	(setq debug-on-signal (not debug-on-signal))
	:style toggle :selected debug-on-signal]
       ["%_Stack Trace on Error [not saved]"
	(setq stack-trace-on-error (not stack-trace-on-error))
	:style toggle :selected stack-trace-on-error]
       ["Stack Trace on Si%_gnal [not saved]"
	(setq stack-trace-on-signal (not stack-trace-on-signal))
	:style toggle :selected stack-trace-on-signal]
       )
      ("Encodin%_g"
       ["Automatic %_EOL Detection"
	(customize-set-variable 'eol-detection-enabled-p
				(not eol-detection-enabled-p))
	:style toggle
	:selected eol-detection-enabled-p
	:included (not (memq system-type '(windows-nt cygwin32)))]
       ("Set Coding System of %_Buffer File"
	:filter
	(lambda (menu)
	  (coding-system-menu-filter
	   (lambda (entry)
	     (set-buffer-file-coding-system entry))
	   (lambda (entry) t)
	   ))
	)
       ;; not implemented yet
       ("Set Coding System of %_Terminal"
	:filter
	(lambda (menu)
	  (coding-system-menu-filter
	   (lambda (entry)
	     (set-terminal-coding-system entry))
	   (lambda (entry) nil)
	   ))
	)
       ;; not implemented yet
       ("Set Coding System of %_Keyboard"
	:filter
	(lambda (menu)
	  (coding-system-menu-filter
	   (lambda (entry)
	     (set-keyboard-coding-system entry))
	   (lambda (entry) nil)
	   ))
	)
       ("Set Coding System of %_Process"
	:filter
	(lambda (menu)
	  (coding-system-menu-filter
	   (lambda (entry)
	     (set-buffer-process-coding-system entry))
	   (lambda (entry) (get-buffer-process (current-buffer)))
	   ))
	)
       )
      ,@(when (featurep 'mule)
	  '(("Internationa%_l"
	     ("Set %_Language Environment"
	      :filter
	      (lambda (menu)
		(menu-split-long-menu
		 (menu-sort-menu
		  (mapcar #'(lambda (entry)
			      `[ ,(car entry)
				 (set-language-environment ',(car entry))
				 :style radio
				 :selected
				 ,(equal (car entry)
					 current-language-environment)])
			  language-info-alist)
		  ))))
	     ["%_Toggle Input Method" toggle-input-method]
	     ["Select %_Input Method" set-input-method]
	     )))
      "-----"
      ("%_Display"
       ,@(if (featurep 'scrollbar)
	     '(["%_Scrollbars"
		(customize-set-variable 'scrollbars-visible-p
					(not scrollbars-visible-p))
		:style toggle
		:selected scrollbars-visible-p]))
       ["%_Wrap Long Lines"
	(progn;; becomes buffer-local
	  (setq truncate-lines (not truncate-lines))
	  (customize-set-variable 'truncate-lines truncate-lines))
	:style toggle
	:selected (not truncate-lines)]
       "----"
       ["%_3D Modeline"
	(customize-set-variable 'modeline-3d-p
				(not modeline-3d-p))
	:style toggle
	:selected modeline-3d-p]
       ("Modeline %_Horizontal Scrolling"
	["%_None"
	 (customize-set-variable 'modeline-scrolling-method nil)
	 :style radio
	 :selected (not modeline-scrolling-method)]
	["As %_Text"
	 (customize-set-variable 'modeline-scrolling-method t)
	 :style radio
	 :selected (eq modeline-scrolling-method t)]
	["As %_Scrollbar"
	 (customize-set-variable 'modeline-scrolling-method 'scrollbar)
	 :style radio
	 :selected (eq modeline-scrolling-method 'scrollbar)]
	)
       ,@(if (featurep 'toolbar)
	     '("---"
	       ["%_Toolbars Visible"
		(customize-set-variable 'toolbar-visible-p
					(not toolbar-visible-p))
		:style toggle
		:selected toolbar-visible-p]
	       ["Toolbars Ca%_ptioned"
		(customize-set-variable 'toolbar-captioned-p
					(not toolbar-captioned-p))
		:style toggle
		:active toolbar-visible-p
		:selected toolbar-captioned-p]
	       ("Default Toolba%_r Location"
		["%_Top"
		 (customize-set-variable 'default-toolbar-position 'top)
		 :style radio
		 :active toolbar-visible-p
		 :selected (eq default-toolbar-position 'top)]
		["%_Bottom"
		 (customize-set-variable 'default-toolbar-position 'bottom)
		 :style radio
		 :active toolbar-visible-p
		 :selected (eq default-toolbar-position 'bottom)]
		["%_Left"
		 (customize-set-variable 'default-toolbar-position 'left)
		 :style radio
		 :active toolbar-visible-p
		 :selected (eq default-toolbar-position 'left)]
		["%_Right"
		 (customize-set-variable 'default-toolbar-position 'right)
		 :style radio
		 :active toolbar-visible-p
		 :selected (eq default-toolbar-position 'right)]
		)
	       ))
       ,@(if (featurep 'gutter)
	     '("---"
	       ["B%_uffers Tab Visible"
		(customize-set-variable 'gutter-buffers-tab-visible-p
					(not gutter-buffers-tab-visible-p))
		:style toggle
		:selected gutter-buffers-tab-visible-p]
	       ("Default %_Gutter Location"
		["%_Top"
		 (customize-set-variable 'default-gutter-position 'top)
		 :style radio
		 :selected (eq default-gutter-position 'top)]
		["%_Bottom"
		 (customize-set-variable 'default-gutter-position 'bottom)
		 :style radio
		 :selected (eq default-gutter-position 'bottom)]
		["%_Left"
		 (customize-set-variable 'default-gutter-position 'left)
		 :style radio
		 :selected (eq default-gutter-position 'left)]
		["%_Right"
		 (customize-set-variable 'default-gutter-position 'right)
		 :style radio
		 :selected (eq default-gutter-position 'right)]
		)
	       ))
       "-----"
       ["%_Blinking Cursor"
	(customize-set-variable 'blink-cursor-mode (not blink-cursor-mode))
	:style toggle
	:selected (and (boundp 'blink-cursor-mode) blink-cursor-mode)
	:active (boundp 'blink-cursor-mode)]
       ["Bl%_ock Cursor"
	(progn
	  (customize-set-variable 'bar-cursor nil)
	  (force-cursor-redisplay))
	:style radio
	:selected (null bar-cursor)]
       ["Bar Cursor (%_1 Pixel)"
	(progn
	  (customize-set-variable 'bar-cursor t)
	  (force-cursor-redisplay))
	:style radio
	:selected (eq bar-cursor t)]
       ["Bar Cursor (%_2 Pixels)"
	(progn
	  (customize-set-variable 'bar-cursor 2)
	  (force-cursor-redisplay))
	:style radio
	:selected (and bar-cursor (not (eq bar-cursor t)))]
       "----"
       ("Pa%_ren Highlighting"
       ["%_None"
	(customize-set-variable 'paren-mode nil)
	:style radio
	:selected (and (boundp 'paren-mode) (not paren-mode))
	:active (boundp 'paren-mode)]
       ["%_Blinking Paren"
	(customize-set-variable 'paren-mode 'blink-paren)
	:style radio
	:selected (and (boundp 'paren-mode) (eq paren-mode 'blink-paren))
	:active (boundp 'paren-mode)]
       ["%_Steady Paren"
	(customize-set-variable 'paren-mode 'paren)
	:style radio
	:selected (and (boundp 'paren-mode) (eq paren-mode 'paren))
	:active (boundp 'paren-mode)]
       ["%_Expression"
	(customize-set-variable 'paren-mode 'sexp)
	:style radio
	:selected (and (boundp 'paren-mode) (eq paren-mode 'sexp))
	:active (boundp 'paren-mode)]
       ;;	 ["Nes%_ted Shading"
       ;;	  (customize-set-variable 'paren-mode 'nested)
       ;;	  :style radio
       ;;	  :selected (and (boundp 'paren-mode) (eq paren-mode 'nested))
       ;;	  :active (boundp 'paren-mode)]
       )
       "------"
       ["%_Line Numbers"
	(progn
	  (customize-set-variable 'line-number-mode (not line-number-mode))
	  (redraw-modeline))
	:style toggle :selected line-number-mode]
       ["%_Column Numbers"
	(progn
	  (customize-set-variable 'column-number-mode
				  (not column-number-mode))
	  (redraw-modeline))
	:style toggle :selected column-number-mode]

       ("\"Other %_Window\" Location"
	["%_Always in Same Frame"
	 (customize-set-variable
	  'get-frame-for-buffer-default-instance-limit nil)
	 :style radio
	 :selected (null get-frame-for-buffer-default-instance-limit)]
	["Other Frame (%_2 Frames Max)"
	 (customize-set-variable 'get-frame-for-buffer-default-instance-limit
				 2)
	 :style radio
	 :selected (eq 2 get-frame-for-buffer-default-instance-limit)]
	["Other Frame (%_3 Frames Max)"
	 (customize-set-variable 'get-frame-for-buffer-default-instance-limit
				 3)
	 :style radio
	 :selected (eq 3 get-frame-for-buffer-default-instance-limit)]
	["Other Frame (%_4 Frames Max)"
	 (customize-set-variable 'get-frame-for-buffer-default-instance-limit
				 4)
	 :style radio
	 :selected (eq 4 get-frame-for-buffer-default-instance-limit)]
	["Other Frame (%_5 Frames Max)"
	 (customize-set-variable 'get-frame-for-buffer-default-instance-limit
				 5)
	 :style radio
	 :selected (eq 5 get-frame-for-buffer-default-instance-limit)]
	["Always Create %_New Frame"
	 (customize-set-variable 'get-frame-for-buffer-default-instance-limit
				 0)
	 :style radio
	 :selected (eq 0 get-frame-for-buffer-default-instance-limit)]
	"-----"
	["%_Temp Buffers Always in Same Frame"
	 (customize-set-variable 'temp-buffer-show-function
				 'show-temp-buffer-in-current-frame)
	 :style radio
	 :selected (eq temp-buffer-show-function
		       'show-temp-buffer-in-current-frame)]
	["Temp Buffers %_Like Other Buffers"
	 (customize-set-variable 'temp-buffer-show-function nil)
	 :style radio
	 :selected (null temp-buffer-show-function)]
	"-----"
	["%_Make Current Frame Gnuserv Target"
	 (customize-set-variable 'gnuserv-frame (if (eq gnuserv-frame t) nil
						  t))
	 :style toggle
	 :selected (and (boundp 'gnuserv-frame) (eq gnuserv-frame t))
	 :active (boundp 'gnuserv-frame)]
	)
       )
      ("%_Menubars"
       ["%_Frame-Local Font Menu"
	(customize-set-variable 'font-menu-this-frame-only-p
				(not font-menu-this-frame-only-p))
	:style toggle
	:selected (and (boundp 'font-menu-this-frame-only-p)
		       font-menu-this-frame-only-p)]
       ["%_Alt/Meta Selects Menu Items"
	(if (eq menu-accelerator-enabled 'menu-force)
	    (customize-set-variable 'menu-accelerator-enabled nil)
	  (customize-set-variable 'menu-accelerator-enabled 'menu-force))
	:style toggle
	:selected (eq menu-accelerator-enabled 'menu-force)]
       "----"
       ["Buffers Menu %_Length..."
	(customize-set-variable
	 'buffers-menu-max-size
	 ;; would it be better to open a customization buffer ?
	 (let ((val
		(read-number
		 "Enter number of buffers to display (or 0 for unlimited): ")))
	   (if (eq val 0) nil val)))]
       ["%_Multi-Operation Buffers Sub-Menus"
	(customize-set-variable 'complex-buffers-menu-p
				(not complex-buffers-menu-p))
	:style toggle
	:selected complex-buffers-menu-p]
       ["S%_ubmenus for Buffer Groups"
	(customize-set-variable 'buffers-menu-submenus-for-groups-p
				(not buffers-menu-submenus-for-groups-p))
	:style toggle
	:selected buffers-menu-submenus-for-groups-p]
       ["%_Verbose Buffer Menu Entries"
	(if (eq buffers-menu-format-buffer-line-function
		'slow-format-buffers-menu-line)
	    (customize-set-variable 'buffers-menu-format-buffer-line-function
				    'format-buffers-menu-line)
	  (customize-set-variable 'buffers-menu-format-buffer-line-function
				  'slow-format-buffers-menu-line))
	:style toggle
	:selected (eq buffers-menu-format-buffer-line-function
		      'slow-format-buffers-menu-line)]
       ("Buffers Menu %_Sorting"
	["%_Most Recently Used"
	 (progn
	   (customize-set-variable 'buffers-menu-sort-function nil)
	   (customize-set-variable 'buffers-menu-grouping-function nil))
	 :style radio
	 :selected (null buffers-menu-sort-function)]
	["%_Alphabetically"
	 (progn
	   (customize-set-variable 'buffers-menu-sort-function
				   'sort-buffers-menu-alphabetically)
	   (customize-set-variable 'buffers-menu-grouping-function nil))
	 :style radio
	 :selected (eq 'sort-buffers-menu-alphabetically
		       buffers-menu-sort-function)]
	["%_By Major Mode, Then Alphabetically"
	 (progn
	   (customize-set-variable
	    'buffers-menu-sort-function
	    'sort-buffers-menu-by-mode-then-alphabetically)
	   (customize-set-variable
	    'buffers-menu-grouping-function
	    'group-buffers-menu-by-mode-then-alphabetically))
	 :style radio
	 :selected (eq 'sort-buffers-menu-by-mode-then-alphabetically
		       buffers-menu-sort-function)])
       "---"
       ["%_Ignore Scaled Fonts"
	(customize-set-variable 'font-menu-ignore-scaled-fonts
				(not font-menu-ignore-scaled-fonts))
	:style toggle
	:selected (and (boundp 'font-menu-ignore-scaled-fonts)
		       font-menu-ignore-scaled-fonts)]
       )
      ("S%_yntax Highlighting"
       ["%_In This Buffer"
	(progn;; becomes buffer local
	  (font-lock-mode)
	  (customize-set-variable 'font-lock-mode font-lock-mode))
	:style toggle
	:selected (and (boundp 'font-lock-mode) font-lock-mode)
	:active (boundp 'font-lock-mode)]
       ["%_Automatic"
	(customize-set-variable 'font-lock-auto-fontify
				(not font-lock-auto-fontify))
	:style toggle
	:selected (and (boundp 'font-lock-auto-fontify) font-lock-auto-fontify)
	:active (fboundp 'font-lock-mode)]
       "-----"
       ["Force %_Rehighlight in this Buffer"
	(customize-set-variable 'font-lock-auto-fontify
				(not font-lock-auto-fontify))
	:style toggle
	:selected (and (boundp 'font-lock-auto-fontify) font-lock-auto-fontify)
	:active (fboundp 'font-lock-mode)]
       "-----"
       ["%_Fonts"
	(progn
	  (require 'font-lock)
	  (font-lock-use-default-fonts)
	  (customize-set-variable 'font-lock-use-fonts t)
	  (customize-set-variable 'font-lock-use-colors nil)
	  (font-lock-mode 1))
	:style radio
	:selected (and (boundp 'font-lock-use-fonts) font-lock-use-fonts)
	:active (fboundp 'font-lock-mode)]
       ["%_Colors"
	(progn
	  (require 'font-lock)
	  (font-lock-use-default-colors)
	  (customize-set-variable 'font-lock-use-colors t)
	  (customize-set-variable 'font-lock-use-fonts nil)
	  (font-lock-mode 1))
	:style radio
	:selected (and (boundp 'font-lock-use-colors) font-lock-use-colors)
	:active (boundp 'font-lock-mode)]
       "-----"
       ["%_1 Least"
	(progn
	  (require 'font-lock)
	  (if (or (and (not (integerp font-lock-maximum-decoration))
		       (not (eq t font-lock-maximum-decoration)))
		  (and (integerp font-lock-maximum-decoration)
		       (<= font-lock-maximum-decoration 0)))
	      nil
	    (customize-set-variable 'font-lock-maximum-decoration nil)
	    (font-lock-recompute-variables)))
	:style radio
	:active (fboundp 'font-lock-mode)
	:selected (and (boundp 'font-lock-maximum-decoration)
		       (or (and (not (integerp font-lock-maximum-decoration))
				(not (eq t font-lock-maximum-decoration)))
			   (and (integerp font-lock-maximum-decoration)
				(<= font-lock-maximum-decoration 0))))]
       ["%_2 More"
	(progn
	  (require 'font-lock)
	  (if (and (integerp font-lock-maximum-decoration)
		   (= 1 font-lock-maximum-decoration))
	      nil
	    (customize-set-variable 'font-lock-maximum-decoration 1)
	    (font-lock-recompute-variables)))
	:style radio
	:active (fboundp 'font-lock-mode)
	:selected (and (boundp 'font-lock-maximum-decoration)
		       (integerp font-lock-maximum-decoration)
		       (= 1 font-lock-maximum-decoration))]
       ["%_3 Even More"
	(progn
	  (require 'font-lock)
	  (if (and (integerp font-lock-maximum-decoration)
		   (= 2 font-lock-maximum-decoration))
	      nil
	    (customize-set-variable 'font-lock-maximum-decoration 2)
	    (font-lock-recompute-variables)))
	:style radio
	:active (fboundp 'font-lock-mode)
	:selected (and (boundp 'font-lock-maximum-decoration)
		       (integerp font-lock-maximum-decoration)
		       (= 2 font-lock-maximum-decoration))]
       ["%_4 Most"
	(progn
	  (require 'font-lock)
	  (if (or (eq font-lock-maximum-decoration t)
		  (and (integerp font-lock-maximum-decoration)
		       (>= font-lock-maximum-decoration 3)))
	      nil
	    (customize-set-variable 'font-lock-maximum-decoration t)
	    (font-lock-recompute-variables)))
	:style radio
	:active (fboundp 'font-lock-mode)
	:selected (and (boundp 'font-lock-maximum-decoration)
		       (or (eq font-lock-maximum-decoration t)
			   (and (integerp font-lock-maximum-decoration)
				(>= font-lock-maximum-decoration 3))))]
       "-----"
       ["Lazy %_Lock"
	(progn;; becomes buffer local
	  (lazy-lock-mode)
	  (customize-set-variable 'lazy-lock-mode lazy-lock-mode)
	  ;; this shouldn't be necessary so there has to
	  ;; be a redisplay bug lurking somewhere (or
	  ;; possibly another event handler bug)
	  (redraw-modeline))
	:active (and (boundp 'font-lock-mode) (boundp 'lazy-lock-mode)
		     font-lock-mode)
	:style toggle
	:selected (and (boundp 'lazy-lock-mode) lazy-lock-mode)]
       ["Lazy %_Shot"
	(progn;; becomes buffer local
	  (lazy-shot-mode)
	  (customize-set-variable 'lazy-shot-mode lazy-shot-mode)
	  ;; this shouldn't be necessary so there has to
	  ;; be a redisplay bug lurking somewhere (or
	  ;; possibly another event handler bug)
	  (redraw-modeline))
	:active (and (boundp 'font-lock-mode) (boundp 'lazy-shot-mode)
		     font-lock-mode)
	:style toggle
	:selected (and (boundp 'lazy-shot-mode) lazy-shot-mode)]
       ["Cac%_hing"
	(progn;; becomes buffer local
	  (fast-lock-mode)
	  (customize-set-variable 'fast-lock-mode fast-lock-mode)
	  ;; this shouldn't be necessary so there has to
	  ;; be a redisplay bug lurking somewhere (or
	  ;; possibly another event handler bug)
	  (redraw-modeline))
	:active (and (boundp 'font-lock-mode) (boundp 'fast-lock-mode)
		     font-lock-mode)
	:style toggle
	:selected (and (boundp 'fast-lock-mode) fast-lock-mode)]
       )
      ("%_Font" :filter font-menu-family-constructor)
      ("Font Si%_ze" :filter font-menu-size-constructor)
      ;;      ("Font Weig%_ht" :filter font-menu-weight-constructor)
      ["Edit Fa%_ces..." (customize-face nil)]
      "-----"
      ["Edit I%_nit File"
       ;; #### there should be something that holds the name that the init
       ;; file should be created as, when it's not present.
       (let ((el-file (or user-init-file "~/.xemacs/init.el")))
	 (if (string-match "\\.elc$" el-file)
	     (setq el-file
		   (substring user-init-file 0 (1- (length el-file)))))
	 (find-file el-file)
	 (or (eq major-mode 'emacs-lisp-mode)
	     (emacs-lisp-mode)))]
      ["%_Save Options to Init File" customize-save-customized]
      )

     ("%_Buffers"
      :filter buffers-menu-filter
      ["Go To %_Previous Buffer" switch-to-other-buffer]
      ["Go To %_Buffer..." switch-to-buffer]
      "----"
      ["%_List All Buffers" list-all-buffers]
      ["%_Delete Buffer" kill-this-buffer
       :suffix (if put-buffer-names-in-file-menu (buffer-name) "")]
      "----"
      )

     nil	; the partition: menus after this are flushright

     ("%_Help"
      ["%_About XEmacs..." about-xemacs]
      ["%_Home Page (www.xemacs.org)" xemacs-www-page
       :active (fboundp 'browse-url)]
      ["What's %_New in XEmacs" view-emacs-news]
      "-----"
      ("%_Info (Online Docs)"
       ["%_Info Contents" (Info-goto-node "(dir)")]
       "-----"
       ["XEmacs %_User's Manual" (Info-goto-node "(XEmacs)")]
       ["XEmacs %_Lisp Reference Manual" (Info-goto-node "(Lispref)")]
       ["All About %_Packages" (Info-goto-node "(xemacs)Packages")]
       ["%_Getting Started with XEmacs" (Info-goto-node "(New-Users-Guide)")]
       ["%_XEmacs Internals Manual" (Info-goto-node "(Internals)")]
       ["%_How to Use Info" (Info-goto-node "(Info)")]
       "-----"
       ["Lookup %_Key Sequence in User's Manual..."
	Info-goto-emacs-key-command-node]
       ["Lookup %_Command in User's Manual..." Info-goto-emacs-command-node]
       ["Lookup %_Function in Lisp Reference..." Info-elisp-ref]
       "-----"
       ["Find %_Topic in User's Manual/Lispref..."
	Info-search-index-in-xemacs-and-lispref]
       ["%_Search Text in User's Manual..." Info-search-text-in-xemacs]
       ["S%_earch Text in Lisp Reference..."
	Info-search-text-in-lispref]
       )
      ("XEmacs %_FAQ"
       ["%_FAQ (local)" xemacs-local-faq]
       ["FAQ via %_WWW" xemacs-www-faq
	:active (fboundp 'browse-url)])
      ("%_Tutorials"
       :filter tutorials-menu-filter)
      ("%_Samples"
       ["View Sample %_init.el" view-sample-init-el
	:active (locate-data-file "sample.init.el")]
       ["View Sample .%_gtkrc"
	(Help-find-file (locate-data-file "sample.gtkrc"))
	:included (featurep 'gtk)
	:active (locate-data-file "sample.gtkrc")]
       ["View Sample .%_Xresources"
	(Help-find-file (locate-data-file "sample.Xresources"))
	:included (featurep 'x)
	:active (locate-data-file "sample.Xresources")]
       ["View Sample %_enriched.doc"
	(Help-find-file (locate-data-file "enriched.doc"))
	:active (locate-data-file "enriched.doc")])
      ("%_Commands, Variables, Keys"
       ["Describe %_Mode" describe-mode]
       ["%_Apropos..." hyper-apropos]
       ["%_Command-Only Apropos..." command-hyper-apropos]
       ["Apropos %_Docs..." apropos-documentation]
       "-----"
       ["Describe %_Key..." describe-key]
       ["Show %_Bindings" describe-bindings]
       ["Show M%_ouse Bindings" describe-pointer]
       "-----"
       ["Describe %_Function..." describe-function]
       ["Describe %_Variable..." describe-variable]
       ["%_Locate Command in Keymap..." where-is])
      ,@(when (featurep 'mule)
	  '(("Internationa%_l"
	     ("Describe %_Language Support"
	      :filter
	      (lambda (menu)
		(menu-split-long-menu
		 (menu-sort-menu
		  (mapcar #'(lambda (entry)
			      `[ ,(car entry)
				 (describe-language-environment
				  ',(car entry))
				:style radio
				:selected
				,(equal (car entry)
					current-language-environment)])
			  language-info-alist)
		  ))))
	     ["Describe %_Input Method" describe-input-method]
	     ["Describe Current %_Coding Systems"
	      describe-current-coding-system]
	     ["Show Character %_Table" view-charset-by-menu]
	     ;; not implemented yet
	     ["Show %_Diagnosis for MULE" mule-diag :active nil]
	     ["Show \"%_hello\" in Many Languages" view-hello-file]
	     )))
      ("%_Other"
       ["%_Current Installation Info" describe-installation
	:active (boundp 'Installation-string)]
       ["%_No Warranty" describe-no-warranty]
       ["XEmacs %_License" describe-copying]
       ["Find %_Packages" finder-by-keyword]
       ["View %_Splash Screen" xemacs-splash-buffer]
       ["%_Unix Manual..." manual-entry])
      "-----"
      ["Recent %_Messages" (view-lossage t)]
      ["Recent %_Keystrokes" view-lossage]
      ["Recent %_Warnings" view-warnings]
      ["Send %_Bug Report..." report-xemacs-bug
       :active (fboundp 'report-xemacs-bug)])))


(defun init-menubar-at-startup ()
  "Don't call this.
Adds `Load .emacs' button to menubar when starting up with -q."
  (when (and (not load-user-init-file-p)
	     (file-exists-p (expand-file-name ".emacs" "~")))
    (add-menu-button
     nil
     ["%_Load .emacs"
      (progn
	(mapc #'(lambda (buf)
		 (with-current-buffer buf
		   (delete-menu-item '("Load .emacs"))))
	      (buffer-list))
	(load-user-init-file))
      ]
     "Help")))


;;; The File menu

(defvar put-buffer-names-in-file-menu t)

;;; The Buffers menu

(defgroup buffers-menu nil
  "Customization of `Buffers' menu."
  :group 'menu)

(defvar buffers-menu-omit-chars-list '(?b ?p ?l ?d))

(defcustom buffers-menu-max-size 25
  "*Maximum number of entries which may appear on the \"Buffers\" menu.
If this is 10, then only the ten most-recently-selected buffers will be
shown.  If this is nil, then all buffers will be shown.  Setting this to
a large number or nil will slow down menu responsiveness."
  :type '(choice (const :tag "Show all" nil)
		 (integer 10))
  :group 'buffers-menu)

(defcustom complex-buffers-menu-p nil
  "*If non-nil, the buffers menu will contain several commands.
Commands will be presented as submenus of each buffer line.  If this
is false, then there will be only one command: select that buffer."
  :type 'boolean
  :group 'buffers-menu)

(defcustom buffers-menu-submenus-for-groups-p nil
  "*If non-nil, the buffers menu will contain one submenu per group of buffers.
The grouping function is specified in `buffers-menu-grouping-function'.
If this is an integer, do not build submenus if the number of buffers
is not larger than this value."
  :type '(choice (const :tag "No Subgroups" nil)
		 (integer :tag "Max. submenus" 10)
		 (sexp :format "%t\n" :tag "Allow Subgroups" :value t))
  :group 'buffers-menu)

(defcustom buffers-menu-switch-to-buffer-function 'switch-to-buffer
  "*The function to call to select a buffer from the buffers menu.
`switch-to-buffer' is a good choice, as is `pop-to-buffer'."
  :type '(radio (function-item switch-to-buffer)
		(function-item pop-to-buffer)
		(function :tag "Other"))
  :group 'buffers-menu)

(defcustom buffers-menu-omit-function 'buffers-menu-omit-invisible-buffers
  "*If non-nil, a function specifying the buffers to omit from the buffers menu.
This is passed a buffer and should return non-nil if the buffer should be
omitted.  The default value `buffers-menu-omit-invisible-buffers' omits
buffers that are normally considered \"invisible\" (those whose name
begins with a space)."
  :type '(choice (const :tag "None" nil)
		 function)
  :group 'buffers-menu)

(defcustom buffers-menu-format-buffer-line-function 'format-buffers-menu-line
  "*The function to call to return a string to represent a buffer in
the buffers menu.  The function is passed a buffer and a number
(starting with 1) indicating which buffer line in the menu is being
processed and should return a string containing an accelerator
spec. (Check out `menu-item-generate-accelerator-spec' as a convenient
way of generating the accelerator specs.) The default value
`format-buffers-menu-line' just returns the name of the buffer and
uses the number as the accelerator.  Also check out
`slow-format-buffers-menu-line' which returns a whole bunch of info
about a buffer.

Note: Gross Compatibility Hack: Older versions of this function prototype
only expected one argument, not two.  We deal gracefully with such
functions by simply calling them with one argument and leaving out the
line number.  However, this may go away at any time, so make sure to
update all of your functions of this type."
  :type 'function
  :group 'buffers-menu)

(defcustom buffers-menu-sort-function
  'sort-buffers-menu-by-mode-then-alphabetically
  "*If non-nil, a function to sort the list of buffers in the buffers menu.
It will be passed two arguments (two buffers to compare) and should return
t if the first is \"less\" than the second.  One possible value is
`sort-buffers-menu-alphabetically'; another is
`sort-buffers-menu-by-mode-then-alphabetically'."
  :type '(choice (const :tag "None" nil)
		 function)
  :group 'buffers-menu)

(defcustom buffers-menu-grouping-function
  'group-buffers-menu-by-mode-then-alphabetically
  "*If non-nil, a function to group buffers in the buffers menu together.
It will be passed two arguments, successive members of the sorted buffers
list after being passed through `buffers-menu-sort-function'.  It should
return non-nil if the second buffer begins a new group.  The return value
should be the name of the old group, which may be used in hierarchical
buffers menus.  The last invocation of the function contains nil as the
second argument, so that the name of the last group can be determined.

The sensible values of this function are dependent on the value specified
for `buffers-menu-sort-function'."
  :type '(choice (const :tag "None" nil)
		 function)
  :group 'buffers-menu)

(defcustom list-all-buffers-function 'list-buffers
  "*Function that `list-all-buffers' calls."
  :type '(choice (const list-buffers)
		 (const ibuffer)
		 (const ibuffer-other-window)
		 function)
  :group 'buffers-menu)

(defun sort-buffers-menu-alphabetically (buf1 buf2)
  "For use as a value of `buffers-menu-sort-function'.
Sorts the buffers in alphabetical order by name, but puts buffers beginning
with a star at the end of the list."
  (let* ((nam1 (buffer-name buf1))
	 (nam2 (buffer-name buf2))
	 (inv1p (not (null (string-match "\\` " nam1))))
	 (inv2p (not (null (string-match "\\` " nam2))))
	 (star1p (not (null (string-match "\\`*" nam1))))
	 (star2p (not (null (string-match "\\`*" nam2)))))
    (cond ((not (eq inv1p inv2p))
	   (not inv1p))
	  ((not (eq star1p star2p))
	   (not star1p))
	  (t
	   (string-lessp nam1 nam2)))))

(defun sort-buffers-menu-by-mode-then-alphabetically (buf1 buf2)
  "For use as a value of `buffers-menu-sort-function'.
Sorts first by major mode and then alphabetically by name, but puts buffers
beginning with a star at the end of the list."
  (let* ((nam1 (buffer-name buf1))
	 (nam2 (buffer-name buf2))
	 (inv1p (not (null (string-match "\\` " nam1))))
	 (inv2p (not (null (string-match "\\` " nam2))))
	 (star1p (not (null (string-match "\\`*" nam1))))
	 (star2p (not (null (string-match "\\`*" nam2))))
	 (mode1 (symbol-value-in-buffer 'major-mode buf1))
	 (mode2 (symbol-value-in-buffer 'major-mode buf2)))
    (cond ((not (eq inv1p inv2p))
	   (not inv1p))
	  ((not (eq star1p star2p))
	   (not star1p))
	  ((and star1p star2p (string-lessp nam1 nam2)))
	  ((string-lessp mode1 mode2)
	   t)
	  ((string-lessp mode2 mode1)
	   nil)
	  (t
	   (string-lessp nam1 nam2)))))

;; this version is too slow on some machines.
;; (vintage 1990, that is)
(defun slow-format-buffers-menu-line (buffer n)
  "For use as a value of `buffers-menu-format-buffer-line-function'.
This returns a string containing a bunch of info about the buffer."
  (concat (menu-item-generate-accelerator-spec n buffers-menu-omit-chars-list)
	  (format "%s%s %-19s %6s %-15s %s"
		  (if (buffer-modified-p buffer) "*" " ")
		  (if (symbol-value-in-buffer 'buffer-read-only buffer)
		      "%" " ")
		  (buffer-name buffer)
		  (buffer-size buffer)
		  (symbol-value-in-buffer 'mode-name buffer)
		  (or (buffer-file-name buffer) ""))))

(defun format-buffers-menu-line (buffer n)
  "For use as a value of `buffers-menu-format-buffer-line-function'.
This just returns the buffer's name."
  (concat (menu-item-generate-accelerator-spec n buffers-menu-omit-chars-list)
	  (buffer-name buffer)))

(defun group-buffers-menu-by-mode-then-alphabetically (buf1 buf2)
  "For use as a value of `buffers-menu-grouping-function'.
This groups buffers by major mode.  It only really makes sense if
`buffers-menu-sorting-function' is
`sort-buffers-menu-by-mode-then-alphabetically'."
  (cond ((string-match "\\`*" (buffer-name buf1))
	 (and (null buf2) "*Misc*"))
	((or (null buf2)
	     (string-match "\\`*" (buffer-name buf2))
	     (not (eq (symbol-value-in-buffer 'major-mode buf1)
		      (symbol-value-in-buffer 'major-mode buf2))))
	 (symbol-value-in-buffer 'mode-name buf1))
	(t nil)))

(defun buffer-menu-save-buffer (buffer)
  (save-excursion
    (set-buffer buffer)
    (save-buffer)))

(defun buffer-menu-write-file (buffer)
  (save-excursion
    (set-buffer buffer)
    (write-file (read-file-name
		 (format "Write %s to file: "
			 (buffer-name (current-buffer)))))))

(defsubst build-buffers-menu-internal (buffers)
  (let (name line (n 0))
    (mapcar
     #'(lambda (buffer)
	 (if (eq buffer t)
	     "---"
	   (setq n (1+ n))
	   (setq line
		 ; #### a truly Kyle-friendly hack.
		 (let ((fn buffers-menu-format-buffer-line-function))
		   (if (= (function-max-args fn) 1)
		       (funcall fn buffer)
		     (funcall fn buffer n))))
	   (if complex-buffers-menu-p
	       (delq nil
		     (list line
			   (vector "S%_witch to Buffer"
				   (list buffers-menu-switch-to-buffer-function
					 (setq name (buffer-name buffer)))
				   t)
			   (if (eq buffers-menu-switch-to-buffer-function
				   'switch-to-buffer)
			       (vector "Switch to Buffer, Other %_Frame"
				       (list 'switch-to-buffer-other-frame
					     (setq name (buffer-name buffer)))
				       t)
			     nil)
			   (if (and (buffer-modified-p buffer)
				    (buffer-file-name buffer))
			       (vector "%_Save Buffer"
				       (list 'buffer-menu-save-buffer name) t)
			     ["%_Save Buffer" nil nil]
			     )
			   (vector "Save %_As..."
				   (list 'buffer-menu-write-file name) t)
			   (vector "%_Delete Buffer" (list 'kill-buffer name)
				   t)))
	     ;; #### We don't want buffer names to be translated,
	     ;; #### so we put the buffer name in the suffix.
	     ;; #### Also, avoid losing with non-ASCII buffer names.
	     ;; #### We still lose, however, if complex-buffers-menu-p. --mrb
	     (vector ""
		     (list buffers-menu-switch-to-buffer-function
			   (buffer-name buffer))
		     t line))))
     buffers)))

(defun buffers-menu-filter (menu)
  "This is the menu filter for the top-level buffers \"Buffers\" menu.
It dynamically creates a list of buffers to use as the contents of the menu.
Only the most-recently-used few buffers will be listed on the menu, for
efficiency reasons.  You can control how many buffers will be shown by
setting `buffers-menu-max-size'.  You can control the text of the menu
items by redefining the function `format-buffers-menu-line'."
  (let ((buffers (delete-if buffers-menu-omit-function (buffer-list))))
    (and (integerp buffers-menu-max-size)
	 (> buffers-menu-max-size 1)
	 (> (length buffers) buffers-menu-max-size)
	 ;; shorten list of buffers (not with submenus!)
	 (not (and buffers-menu-grouping-function
		   buffers-menu-submenus-for-groups-p))
	 (setcdr (nthcdr buffers-menu-max-size buffers) nil))
    (if buffers-menu-sort-function
	(setq buffers (sort buffers buffers-menu-sort-function)))
    (if (and buffers-menu-grouping-function
	     buffers-menu-submenus-for-groups-p
	     (or (not (integerp buffers-menu-submenus-for-groups-p))
		 (> (length buffers) buffers-menu-submenus-for-groups-p)))
	(let (groups groupnames current-group)
	  (mapl
	   #'(lambda (sublist)
	       (let ((groupname (funcall buffers-menu-grouping-function
					 (car sublist) (cadr sublist))))
		 (setq current-group (cons (car sublist) current-group))
		 (if groupname
		     (progn
		       (setq groups (cons (nreverse current-group)
					  groups))
		       (setq groupnames (cons groupname groupnames))
		       (setq current-group nil)))))
	   buffers)
	  (setq buffers
		(mapcar*
		 #'(lambda (groupname group)
		     (cons groupname (build-buffers-menu-internal group)))
		 (nreverse groupnames)
		 (nreverse groups))))
      (if buffers-menu-grouping-function
	  (progn
	    (setq buffers
		  (mapcon
		   #'(lambda (sublist)
		       (cond ((funcall buffers-menu-grouping-function
				       (car sublist) (cadr sublist))
			      (list (car sublist) t))
			     (t (list (car sublist)))))
		   buffers))
	    ;; remove a trailing separator.
	    (and (>= (length buffers) 2)
		 (let ((lastcdr (nthcdr (- (length buffers) 2) buffers)))
		   (if (eq t (cadr lastcdr))
		       (setcdr lastcdr nil))))))
      (setq buffers (build-buffers-menu-internal buffers)))
    (append menu buffers)
    ))

(defun list-all-buffers ()
  "Display a list of buffers.  Calls `list-all-buffers-function'."
  (interactive)
  (funcall (if (fboundp list-all-buffers-function)
	       list-all-buffers-function
	     'list-buffers)))


;;; The Options menu

;; We'll keep those variables here for a while, in order to provide a
;; function for porting the old options file that a user may own to Custom.

(defvar options-save-faces nil
  "*Non-nil value means save-options will save information about faces.
A nil value means save-options will not save face information.
Set this non-nil only if you use M-x edit-faces to change face
settings.  If you use M-x customize-face or the \"Browse Faces...\"
menu entry, you will see a button in the Customize Face buffer that you
can use to permanently save your face changes.

M-x edit-faces is deprecated.  Support for it and this variable will
be discontinued in a future release.")

(defvar save-options-init-file nil
  "File into which to save forms to load the options file (nil for .emacs).
Normally this is nil, which means save into your .emacs file (the value
of `user-init-file'.")

(defvar save-options-file ".xemacs-options"
  "File to save options into.
This file is loaded from your .emacs file.
If this is a relative filename, it is put into the same directory as your
.emacs file.")



;;; The Help menu

(defun tutorials-menu-filter (menu-items)
  (declare (special language-info-alist
		    current-language-environment
		    tutorial-supported-languages))
  (append
   (if (featurep 'mule)
       (if (assq 'tutorial
		 (assoc current-language-environment language-info-alist))
	   `([,(concat "%_Default (" current-language-environment ")")
	      help-with-tutorial]))
     '(["%_English" help-with-tutorial]))
   (submenu-generate-accelerator-spec
    (if (featurep 'mule)
	;; Mule tutorials.
	(mapcan #'(lambda (lang)
		    (let ((tut (assq 'tutorial lang)))
		      (and tut
			   (not (string= (car lang) "ASCII"))
			   ;; skip current language, since we already
			   ;; included it first
			   (not (string= (car lang)
					 current-language-environment))
			   `([,(car lang)
			      (help-with-tutorial nil ,(car lang))]))))
		language-info-alist)
      ;; Non mule tutorials.
      (mapcar #'(lambda (lang)
		  `[,(car lang)
		    (help-with-tutorial nil ,(car lang))])
	      tutorial-supported-languages)))))

(set-menubar default-menubar)

(when (featurep 'menubar-items)
  (loop for buf being the buffers do
    (or (eq default-menubar (symbol-value-in-buffer 'current-menubar buf))
	(with-current-buffer buf
	  (condition-case nil
	      (funcall major-mode)
	    (error (setq current-menubar default-menubar)))))))


;;; Popup menus.

(defconst default-popup-menu
  '("XEmacs Commands"
    ["%_Split Window" split-window-vertically]
    ["S%_plit Window (Side by Side)" split-window-horizontally]
    ["%_Un-Split (Keep This)" delete-other-windows
     :active (not (one-window-p t))]
    ["Un-Split (Keep %_Others)" delete-window
     :active (not (one-window-p t))]
    ))

;; In an effort to avoid massive menu clutter, this mostly worthless menu is
;; superseded by any local popup menu...
(setq-default mode-popup-menu default-popup-menu)


;; misc

(defun xemacs-splash-buffer ()
  "Redisplay XEmacs splash screen in a buffer."
  (interactive)
  (let ((buffer (get-buffer-create "*Splash*"))
	tmout)
    (set-buffer buffer)
    (setq buffer-read-only t)
    (erase-buffer buffer)
    (setq tmout (display-splash-frame))
    (when tmout
      (make-local-hook 'kill-buffer-hook)
      (add-hook 'kill-buffer-hook
		`(lambda ()
		   (disable-timeout ,tmout))
		nil t))
    (pop-to-buffer buffer)
    (delete-other-windows)))


;;; backwards compatibility
(provide 'x-menubar)
(provide 'menubar-items)

;;; menubar-items.el ends here.
