Mark face aliases with "-face" suffix as obsolete.
[bpt/emacs.git] / lisp / cus-edit.el
index 1909836..d2a3244 100644 (file)
@@ -1,7 +1,7 @@
 ;;; cus-edit.el --- tools for customizing Emacs and Lisp packages
 ;;
-;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;;   2006, 2007, 2008, 2009  Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Maintainer: FSF
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
   "Front-ends/assistants for, or emulators of, UNIX features."
   :group 'environment)
 
-(defgroup vms nil
-  "Support code for vms."
-  :group 'environment)
-
 (defgroup i18n nil
   "Internationalization and alternate character-set support."
   :link '(custom-manual "(emacs)International")
   "Debugging Emacs itself."
   :group 'development)
 
-(defgroup minibuffer nil
-  "Controlling the behavior of the minibuffer."
-  :link '(custom-manual "(emacs)Minibuffer")
-  :group 'environment)
-
 (defgroup keyboard nil
   "Input from the keyboard."
   :group 'environment)
   :link '(custom-manual "(emacs)Windows")
   :group 'environment)
 
-(defgroup mac nil
-  "Mac specific features."
-  :link '(custom-manual "(emacs)Mac OS")
-  :group 'environment
-  :version "22.1"
-  :prefix "mac-")
-
 ;;; Custom mode keymaps
 
 (defvar custom-mode-map
     (define-key map "n" 'widget-forward)
     (define-key map "p" 'widget-backward)
     map)
-  "Keymap for `custom-mode'.")
+  "Keymap for `Custom-mode'.")
 
 (defvar custom-mode-link-map
   (let ((map (make-keymap)))
     (define-key map [down-mouse-1] 'mouse-drag-region)
     (define-key map [mouse-2] 'widget-move-and-invoke)
     map)
-  "Local keymap for links in `custom-mode'.")
+  "Local keymap for links in `Custom-mode'.")
 
+(defvar custom-field-keymap
+  (let ((map (copy-keymap widget-field-keymap)))
+    (define-key map "\C-c\C-c" 'Custom-set)
+    (define-key map "\C-x\C-s" 'Custom-save)
+    map)
+  "Keymap used inside editable fields in customization buffers.")
+
+(widget-put (get 'editable-field 'widget-type) :keymap custom-field-keymap)
 
 ;;; Utilities.
 
@@ -751,8 +741,7 @@ groups after non-groups, if nil do not order groups at all."
 ;;; Custom Mode Commands.
 
 ;; This variable is used by `custom-tool-bar-map', or directly by
-;; `custom-buffer-create-internal' if the toolbar is not present and
-;; `custom-buffer-verbose-help' is non-nil.
+;; `custom-buffer-create-internal' if `custom-buffer-verbose-help' is non-nil.
 
 (defvar custom-commands
   '(("Set for current session" Custom-set t
@@ -818,16 +807,19 @@ and `yes-or-no-p' otherwise."
 
 (defun Custom-save (&rest ignore)
   "Set all edited settings, then save all settings that have been set.
-If a setting was edited and set before, this saves it.
-If a setting was merely edited before, this sets it then saves it."
+If a setting was edited and set before, this saves it.  If a
+setting was merely edited before, this sets it then saves it."
   (interactive)
-  (if (custom-command-apply
-       (lambda (child)
-        (when (memq (widget-get child :custom-state)
-                    '(modified set changed rogue))
-          (widget-apply child :custom-save)))
-       "Save all settings in this buffer? " t)
-      (custom-save-all)))
+  (when (custom-command-apply
+        (lambda (child)
+          (when (memq (widget-get child :custom-state)
+                      '(modified set changed rogue))
+            (widget-apply child :custom-mark-to-save)))
+        "Save all settings in this buffer? " t)
+    ;; Save changes to buffer and redraw.
+    (custom-save-all)
+    (dolist (child custom-options)
+      (widget-apply child :custom-state-set-and-redraw))))
 
 (defun custom-reset (widget &optional event)
   "Select item from reset menu."
@@ -857,20 +849,67 @@ This also shows the saved values in the buffer."
         (widget-apply widget :custom-reset-saved)))
    "Reset all settings (current values and buffer text) to saved values? "))
 
+;; The next two variables are bound to '(t) by `Custom-reset-standard'
+;; and `custom-group-reset-standard'.  If these variables are nil, both
+;; `custom-variable-reset-standard' and `custom-face-reset-standard'
+;; save, reset and redraw the handled widget immediately.  Otherwise,
+;; they add the widget to the corresponding list and leave it to
+;; `custom-reset-standard-save-and-update' to save, reset and redraw it.
+(defvar custom-reset-standard-variables-list nil)
+(defvar custom-reset-standard-faces-list nil)
+
+;; The next function was excerpted from `custom-variable-reset-standard'
+;; and `custom-face-reset-standard' and is used to avoid calling
+;; `custom-save-all' repeatedly (and thus saving settings to file one by
+;; one) when erasing all customizations.
+(defun custom-reset-standard-save-and-update ()
+  "Save settings and redraw after erasing customizations."
+  (when (or (and custom-reset-standard-variables-list
+                (not (eq custom-reset-standard-variables-list  '(t))))
+           (and custom-reset-standard-faces-list
+                (not (eq custom-reset-standard-faces-list '(t)))))
+    ;; Save settings to file.
+    (custom-save-all)
+    ;; Set state of and redraw variables.
+    (dolist (widget custom-reset-standard-variables-list)
+      (unless (eq widget t)
+       (widget-put widget :custom-state 'unknown)
+       (custom-redraw widget)))
+    ;; Set state of and redraw faces.
+    (dolist (widget custom-reset-standard-faces-list)
+      (unless (eq widget t)
+       (let* ((symbol (widget-value widget))
+              (child (car (widget-get widget :children)))
+              (value (get symbol 'face-defface-spec))
+              (comment-widget (widget-get widget :comment-widget)))
+         (put symbol 'face-comment nil)
+         (widget-value-set child
+                           (custom-pre-filter-face-spec
+                            (list (list t (custom-face-attributes-get
+                                           symbol nil)))))
+         ;; This call manages the comment visibility
+         (widget-value-set comment-widget "")
+         (custom-face-state-set widget)
+         (custom-redraw-magic widget))))))
+
 (defun Custom-reset-standard (&rest ignore)
-  "Erase all customization (either current or saved) for the group members.
+  "Erase all customizations (either current or saved) in current buffer.
 The immediate result is to restore them to their standard values.
 This operation eliminates any saved values for the group members,
 making them as if they had never been customized at all."
   (interactive)
-  (custom-command-apply
-   (lambda (widget)
-     (and (or (null (widget-get widget :custom-standard-value))
-             (widget-apply widget :custom-standard-value))
-         (memq (widget-get widget :custom-state)
-               '(modified set changed saved rogue))
-         (widget-apply widget :custom-reset-standard)))
-   "Erase all customizations for settings in this buffer? " t))
+  ;; Bind these temporarily.
+  (let ((custom-reset-standard-variables-list '(t))
+       (custom-reset-standard-faces-list '(t)))
+    (custom-command-apply
+     (lambda (widget)
+       (and (or (null (widget-get widget :custom-standard-value))
+               (widget-apply widget :custom-standard-value))
+           (memq (widget-get widget :custom-state)
+                 '(modified set changed saved rogue))
+           (widget-apply widget :custom-mark-to-reset-standard)))
+     "Erase all customizations for settings in this buffer? " t)
+    (custom-reset-standard-save-and-update)))
 
 ;;; The Customize Commands
 
@@ -1097,7 +1136,7 @@ Show the buffer in another window, but don't select it."
     (unless (eq symbol basevar)
       (message "`%s' is an alias for `%s'" symbol basevar))))
 
-(defvar customize-changed-options-previous-release "21.1"
+(defvar customize-changed-options-previous-release "22.1"
   "Version for `customize-changed-options' to refer back to by default.")
 
 ;; Packages will update this variable, so make it available.
@@ -1386,8 +1425,8 @@ that are not customizable options, as well as faces and groups
 ;;;###autoload
 (defun customize-apropos-options (regexp &optional arg)
   "Customize all loaded customizable options matching REGEXP.
-With prefix arg, include variables that are not customizable options
-\(but we recommend using `apropos-variable' instead)."
+With prefix ARG, include variables that are not customizable options
+\(but it is better to use `apropos-variable' if you want to find those)."
   (interactive "sCustomize options (regexp): \nP")
   (customize-apropos regexp (or arg 'options)))
 
@@ -1416,7 +1455,7 @@ links: groups have links to subgroups."
   :group 'custom-buffer)
 
 (defcustom custom-buffer-done-kill nil
-  "*Non-nil means exiting a Custom buffer should kill it."
+  "Non-nil means exiting a Custom buffer should kill it."
   :type 'boolean
   :version "22.1"
   :group 'custom-buffer)
@@ -1520,14 +1559,14 @@ Otherwise use brackets."
                 'custom-button-pressed-unraised))))
 
 (defun custom-buffer-create-internal (options &optional description)
-  (custom-mode)
+  (Custom-mode)
   (let ((init-file (or custom-file user-init-file)))
     ;; Insert verbose help at the top of the custom buffer.
     (when custom-buffer-verbose-help
       (widget-insert "Editing a setting changes only the text in this buffer."
                     (if init-file
                         "
-To set apply your changes, use the Save or Set buttons.
+To apply your changes, use the Save or Set buttons.
 Saving a change normally works by editing your init file."
                       "
 Currently, these settings cannot be saved for future Emacs sessions,
@@ -1542,37 +1581,41 @@ possibly because you started Emacs with `-q'.")
                     :help-echo "Read the Emacs manual."
                     "(emacs)Top")
       (widget-insert "."))
-    ;; Insert custom command buttons if the toolbar is not in use.
-
     (widget-insert "\n")
-    ;; tool-bar is not dumped in builds without x.
-    (when (not (and (bound-and-true-p tool-bar-mode) (display-graphic-p)))
-      (if custom-buffer-verbose-help
-         (widget-insert "\n
+    ;; The custom command buttons are also in the toolbar, so for a
+    ;; time they were not inserted in the buffer if the toolbar was in use.
+    ;; But it can be a little confusing for the buffer layout to
+    ;; change according to whether or nor the toolbar is on, not to
+    ;; mention that a custom buffer can in theory be created in a
+    ;; frame with a toolbar, then later viewed in one without.
+    ;; So now the buttons are always inserted in the buffer.  (Bug#1326)
+;;;    (when (not (and (bound-and-true-p tool-bar-mode) (display-graphic-p)))
+    (if custom-buffer-verbose-help
+       (widget-insert "\n
  Operate on all settings in this buffer that are not marked HIDDEN:\n"))
-      (let ((button (lambda (tag action active help icon)
-                     (widget-insert " ")
-                     (if (eval active)
-                         (widget-create 'push-button :tag tag
-                                        :help-echo help :action action))))
-           (commands custom-commands))
-       (apply button (pop commands)) ; Set for current session
-       (apply button (pop commands)) ; Save for future sessions
-       (if custom-reset-button-menu
-           (progn
-             (widget-insert " ")
-             (widget-create 'push-button
-                            :tag "Reset buffer"
-                            :help-echo "Show a menu with reset operations."
-                            :mouse-down-action 'ignore
-                            :action 'custom-reset))
-         (widget-insert "\n")
-         (apply button (pop commands)) ; Undo edits
-         (apply button (pop commands)) ; Reset to saved
-         (apply button (pop commands)) ; Erase customization
-         (widget-insert "  ")
-         (pop commands) ; Help (omitted)
-         (apply button (pop commands))))) ; Exit
+    (let ((button (lambda (tag action active help icon)
+                   (widget-insert " ")
+                   (if (eval active)
+                       (widget-create 'push-button :tag tag
+                                      :help-echo help :action action))))
+         (commands custom-commands))
+      (apply button (pop commands)) ; Set for current session
+      (apply button (pop commands)) ; Save for future sessions
+      (if custom-reset-button-menu
+         (progn
+           (widget-insert " ")
+           (widget-create 'push-button
+                          :tag "Reset buffer"
+                          :help-echo "Show a menu with reset operations."
+                          :mouse-down-action 'ignore
+                          :action 'custom-reset))
+       (widget-insert "\n")
+       (apply button (pop commands)) ; Undo edits
+       (apply button (pop commands)) ; Reset to saved
+       (apply button (pop commands)) ; Erase customization
+       (widget-insert "  ")
+       (pop commands) ; Help (omitted)
+       (apply button (pop commands)))) ; Exit
     (widget-insert "\n\n"))
 
   ;; Now populate the custom buffer.
@@ -1626,7 +1669,7 @@ possibly because you started Emacs with `-q'.")
     (setq group 'emacs))
   (let ((name "*Customize Browser*"))
     (pop-to-buffer (custom-get-fresh-buffer name)))
-  (custom-mode)
+  (Custom-mode)
   (widget-insert (format "\
 %s buttons; type RET or click mouse-1
 on a button to invoke its action.
@@ -1713,7 +1756,7 @@ item in another window.\n\n"))
 (defun custom-browse-insert-prefix (prefix)
   "Insert PREFIX.  On XEmacs convert it to line graphics."
   ;; Fixme: do graphics.
-  (if nil ; (string-match "XEmacs" emacs-version)
+  (if nil ; (featurep 'xemacs)
       (progn
        (insert "*")
        (while (not (string-equal prefix ""))
@@ -1729,7 +1772,7 @@ item in another window.\n\n"))
 ;;; Modification of Basic Widgets.
 ;;
 ;; We add extra properties to the basic widgets needed here.  This is
-;; fine, as long as we are careful to stay within out own namespace.
+;; fine, as long as we are careful to stay within our own namespace.
 ;;
 ;; We want simple widgets to be displayed by default, but complex
 ;; widgets to be hidden.
@@ -1770,8 +1813,7 @@ item in another window.\n\n"))
                           (:weight bold :slant italic :underline t)))
   "Face used when the customize item is invalid."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-invalid-face 'face-alias 'custom-invalid)
+(define-obsolete-face-alias 'custom-invalid-face 'custom-invalid "22.1")
 
 (defface custom-rogue '((((class color))
                         (:foreground "pink" :background "black"))
@@ -1779,8 +1821,7 @@ item in another window.\n\n"))
                         (:underline t)))
   "Face used when the customize item is not defined for customization."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-rogue-face 'face-alias 'custom-rogue)
+(define-obsolete-face-alias 'custom-rogue-face 'custom-rogue "22.1")
 
 (defface custom-modified '((((min-colors 88) (class color))
                            (:foreground "white" :background "blue1"))
@@ -1790,8 +1831,7 @@ item in another window.\n\n"))
                            (:slant italic :bold)))
   "Face used when the customize item has been modified."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-modified-face 'face-alias 'custom-modified)
+(define-obsolete-face-alias 'custom-modified-face 'custom-modified "22.1")
 
 (defface custom-set '((((min-colors 88) (class color))
                       (:foreground "blue1" :background "white"))
@@ -1801,8 +1841,7 @@ item in another window.\n\n"))
                       (:slant italic)))
   "Face used when the customize item has been set."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-set-face 'face-alias 'custom-set)
+(define-obsolete-face-alias 'custom-set-face 'custom-set "22.1")
 
 (defface custom-changed '((((min-colors 88) (class color))
                           (:foreground "white" :background "blue1"))
@@ -1812,8 +1851,7 @@ item in another window.\n\n"))
                           (:slant italic)))
   "Face used when the customize item has been changed."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-changed-face 'face-alias 'custom-changed)
+(define-obsolete-face-alias 'custom-changed-face 'custom-changed "22.1")
 
 (defface custom-themed '((((min-colors 88) (class color))
                           (:foreground "white" :background "blue1"))
@@ -1827,8 +1865,7 @@ item in another window.\n\n"))
 (defface custom-saved '((t (:underline t)))
   "Face used when the customize item has been saved."
   :group 'custom-magic-faces)
-;; backward-compatibility alias
-(put 'custom-saved-face 'face-alias 'custom-saved)
+(define-obsolete-face-alias 'custom-saved-face 'custom-saved "22.1")
 
 (defconst custom-magic-alist
   '((nil "#" underline "\
@@ -2017,7 +2054,7 @@ and `face'."
 ;;; The `custom' Widget.
 
 (defface custom-button
-  '((((type x w32 mac) (class color))          ; Like default modeline
+  '((((type x w32 ns) (class color))   ; Like default modeline
      (:box (:line-width 2 :style released-button)
           :background "lightgrey" :foreground "black"))
     (t
@@ -2025,15 +2062,17 @@ and `face'."
   "Face for custom buffer buttons if `custom-raised-buttons' is non-nil."
   :version "21.1"
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-button-face 'face-alias 'custom-button)
+(define-obsolete-face-alias 'custom-button-face 'custom-button "22.1")
 
 (defface custom-button-mouse
-  '((((type x w32 mac) (class color))
+  '((((type x w32 ns) (class color))
      (:box (:line-width 2 :style released-button)
           :background "grey90" :foreground "black"))
     (t
-     nil))
+     ;; This is for text terminals that support mouse, like GPM mouse
+     ;; or the MS-DOS terminal: inverse-video makes the button stand
+     ;; out on mouse-over.
+     (:inverse-video t)))
   "Mouse face for custom buffer buttons if `custom-raised-buttons' is non-nil."
   :version "22.1"
   :group 'custom-faces)
@@ -2051,7 +2090,7 @@ and `face'."
       (if custom-raised-buttons 'custom-button-mouse 'highlight))
 
 (defface custom-button-pressed
-  '((((type x w32 mac) (class color))
+  '((((type x w32 ns) (class color))
      (:box (:line-width 2 :style pressed-button)
           :background "lightgrey" :foreground "black"))
     (t
@@ -2059,8 +2098,8 @@ and `face'."
   "Face for pressed custom buttons if `custom-raised-buttons' is non-nil."
   :version "21.1"
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-button-pressed-face 'face-alias 'custom-button-pressed)
+(define-obsolete-face-alias 'custom-button-pressed-face
+  'custom-button-pressed "22.1")
 
 (defface custom-button-pressed-unraised
   '((default :inherit custom-button-unraised)
@@ -2078,8 +2117,8 @@ and `face'."
 (defface custom-documentation '((t nil))
   "Face used for documentation strings in customization buffers."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-documentation-face 'face-alias 'custom-documentation)
+(define-obsolete-face-alias 'custom-documentation-face
+  'custom-documentation "22.1")
 
 (defface custom-state '((((class color)
                          (background dark))
@@ -2090,8 +2129,7 @@ and `face'."
                        (t nil))
   "Face used for State descriptions in the customize buffer."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-state-face 'face-alias 'custom-state)
+(define-obsolete-face-alias 'custom-state-face 'custom-state "22.1")
 
 (defface custom-link
   '((t :inherit link))
@@ -2146,9 +2184,10 @@ and `face'."
     (when (and (>= pos from) (<= pos to))
       (condition-case nil
          (progn
-           (if (> column 0)
-               (goto-line line)
-             (goto-line (1+ line)))
+           (goto-char (point-min))
+           (forward-line (if (> column 0)
+                             (1- line)
+                           line))
            (move-to-column column))
        (error nil)))))
 
@@ -2204,8 +2243,8 @@ and `face'."
   "Toggle visibility of WIDGET."
   (custom-load-widget widget)
   (let ((state (widget-get widget :custom-state)))
-    (cond ((memq state '(invalid modified))
-          (error "There are unset changes"))
+    (cond ((memq state '(invalid modified set))
+          (error "There are unsaved changes"))
          ((eq state 'hidden)
           (widget-put widget :custom-state 'unknown))
          (t
@@ -2250,7 +2289,8 @@ Insert PREFIX first if non-nil."
               (insert ", "))))
       (widget-put widget :buttons buttons))))
 
-(defun custom-add-parent-links (widget &optional initial-string)
+(defun custom-add-parent-links (widget &optional initial-string
+                                      doc-initial-string)
   "Add \"Parent groups: ...\" to WIDGET if the group has parents.
 The value is non-nil if any parents were found.
 If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
@@ -2259,7 +2299,7 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
        (buttons (widget-get widget :buttons))
        (start (point))
        (parents nil))
-    (insert (or initial-string "Parent groups:"))
+    (insert (or initial-string "Groups:"))
     (mapatoms (lambda (symbol)
                (when (member (list name type) (get symbol 'custom-group))
                  (insert " ")
@@ -2278,23 +2318,27 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
                                         (get (car parents) 'custom-links))))
                 (many (> (length links) 2)))
            (when links
-             (insert "\nParent documentation: ")
-             (while links
-               (push (widget-create-child-and-convert
-                     widget (car links)
-                     :button-face 'custom-link
-                     :mouse-face 'highlight
-                     :pressed-face 'highlight)
-                     buttons)
-               (setq links (cdr links))
-               (cond ((null links)
-                      (insert ".\n"))
-                     ((null (cdr links))
-                      (if many
-                          (insert ", and ")
-                        (insert " and ")))
-                     (t
-                      (insert ", ")))))))
+             (let ((pt (point))
+                   (left-margin (+ left-margin 2)))
+              (insert "\n" (or doc-initial-string "Group documentation:") " ")
+              (while links
+                (push (widget-create-child-and-convert
+                       widget (car links)
+                       :button-face 'custom-link
+                       :mouse-face 'highlight
+                       :pressed-face 'highlight)
+                      buttons)
+                (setq links (cdr links))
+                (cond ((null links)
+                       (insert ".\n"))
+                      ((null (cdr links))
+                       (if many
+                           (insert ", and ")
+                         (insert " and ")))
+                      (t
+                        (insert ", "))))
+               (fill-region-as-paragraph pt (point))
+               (delete-to-left-margin (1+ pt) (+ pt 2))))))
     (if parents
         (insert "\n")
       (delete-region start (point)))
@@ -2315,11 +2359,10 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
                           :background "dim gray")
                          (t
                           :slant italic))
-  "Face used for comments on variables or faces"
+  "Face used for comments on variables or faces."
   :version "21.1"
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-comment-face 'face-alias 'custom-comment)
+(define-obsolete-face-alias 'custom-comment-face 'custom-comment "22.1")
 
 ;; like font-lock-comment-face
 (defface custom-comment-tag
@@ -2330,17 +2373,16 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
     (((class grayscale) (background dark))
      (:foreground "LightGray" :weight bold :slant italic))
     (t (:weight bold)))
-  "Face used for variables or faces comment tags"
+  "Face used for the comment tag on variables or faces."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-comment-tag-face 'face-alias 'custom-comment-tag)
+(define-obsolete-face-alias 'custom-comment-tag-face 'custom-comment-tag "22.1")
 
 (define-widget 'custom-comment 'string
   "User comment."
   :tag "Comment"
   :help-echo "Edit a comment here."
-  :sample-face 'custom-comment-tag-face
-  :value-face 'custom-comment-face
+  :sample-face 'custom-comment-tag
+  :value-face 'custom-comment
   :shown nil
   :create 'custom-comment-create)
 
@@ -2386,14 +2428,14 @@ If INITIAL-STRING is non-nil, use that rather than \"Parent groups:\"."
     (t (:weight bold)))
   "Face used for unpushable variable tags."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-variable-tag-face 'face-alias 'custom-variable-tag)
+(define-obsolete-face-alias 'custom-variable-tag-face
+  'custom-variable-tag "22.1")
 
 (defface custom-variable-button '((t (:underline t :weight bold)))
   "Face used for pushable variable tags."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-variable-button-face 'face-alias 'custom-variable-button)
+(define-obsolete-face-alias 'custom-variable-button-face
+  'custom-variable-button "22.1")
 
 (defcustom custom-variable-default-form 'edit
   "Default form of displaying variable values."
@@ -2428,11 +2470,13 @@ However, setting it through Custom sets the default value.")
   :value-create 'custom-variable-value-create
   :action 'custom-variable-action
   :custom-set 'custom-variable-set
-  :custom-save 'custom-variable-save
+  :custom-mark-to-save 'custom-variable-mark-to-save
   :custom-reset-current 'custom-redraw
   :custom-reset-saved 'custom-variable-reset-saved
   :custom-reset-standard 'custom-variable-reset-standard
-  :custom-standard-value 'custom-variable-standard-value)
+  :custom-mark-to-reset-standard 'custom-variable-mark-to-reset-standard
+  :custom-standard-value 'custom-variable-standard-value
+  :custom-state-set-and-redraw 'custom-variable-state-set-and-redraw)
 
 (defun custom-variable-type (symbol)
   "Return a widget suitable for editing the value of SYMBOL.
@@ -2494,7 +2538,7 @@ try matching its doc string against `custom-guess-doc-alist'."
           (push (widget-create-child-and-convert
                  widget 'item
                  :format "%{%t%}: "
-                 :sample-face 'custom-variable-tag-face
+                 :sample-face 'custom-variable-tag
                  :tag tag
                  :parent widget)
                 buttons)
@@ -2547,8 +2591,8 @@ try matching its doc string against `custom-guess-doc-alist'."
                    :action 'custom-tag-action
                    :help-echo "Change value of this option."
                    :mouse-down-action 'custom-tag-mouse-down-action
-                   :button-face 'custom-variable-button-face
-                   :sample-face 'custom-variable-tag-face
+                   :button-face 'custom-variable-button
+                   :sample-face 'custom-variable-tag
                    tag)
                   buttons)
             (insert " ")
@@ -2794,8 +2838,8 @@ Optional EVENT is the location for the menu."
     (custom-variable-state-set widget)
     (custom-redraw-magic widget)))
 
-(defun custom-variable-save (widget)
-  "Set and save the value for the variable being edited by WIDGET."
+(defun custom-variable-mark-to-save (widget)
+  "Set value and mark for saving the variable edited by WIDGET."
   (let* ((form (widget-get widget :custom-form))
         (state (widget-get widget :custom-state))
         (child (car (widget-get widget :children)))
@@ -2833,10 +2877,18 @@ Optional EVENT is the location for the menu."
           (put symbol 'variable-comment comment)
           (put symbol 'saved-variable-comment comment)))
     (put symbol 'customized-value nil)
-    (put symbol 'customized-variable-comment nil)
-    (custom-save-all)
-    (custom-variable-state-set widget)
-    (custom-redraw-magic widget)))
+    (put symbol 'customized-variable-comment nil)))
+
+(defsubst custom-variable-state-set-and-redraw (widget)
+  "Set state of variable widget WIDGET and redraw with current settings."
+  (custom-variable-state-set widget)
+  (custom-redraw-magic widget))
+
+(defun custom-variable-save (widget)
+  "Save value of variable edited by widget WIDGET."
+  (custom-variable-mark-to-save widget)
+  (custom-save-all)
+  (custom-variable-state-set-and-redraw widget))
 
 (defun custom-variable-reset-saved (widget)
   "Restore the saved value for the variable being edited by WIDGET.
@@ -2862,12 +2914,10 @@ becomes the backup value, so you can get it again."
     ;; This call will possibly make the comment invisible
     (custom-redraw widget)))
 
-(defun custom-variable-reset-standard (widget)
-  "Restore the standard setting for the variable being edited by WIDGET.
-This operation eliminates any saved setting for the variable,
-restoring it to the state of a variable that has never been customized.
-The value that was current before this operation
-becomes the backup value, so you can get it again."
+(defun custom-variable-mark-to-reset-standard (widget)
+  "Mark to restore standard setting for the variable edited by widget WIDGET.
+If `custom-reset-standard-variables-list' is nil, save, reset and
+redraw the widget immediately."
   (let* ((symbol (widget-value widget)))
     (if (get symbol 'standard-value)
        (custom-variable-backup-value widget)
@@ -2877,13 +2927,32 @@ becomes the backup value, so you can get it again."
     (put symbol 'customized-variable-comment nil)
     (custom-push-theme 'theme-value symbol 'user 'reset)
     (custom-theme-recalc-variable symbol)
-    (when (or (get symbol 'saved-value) (get symbol 'saved-variable-comment))
-      (put symbol 'saved-value nil)
-      (put symbol 'saved-variable-comment nil)
-      (custom-save-all))
-    (widget-put widget :custom-state 'unknown)
-    ;; This call will possibly make the comment invisible
-    (custom-redraw widget)))
+    (if (and custom-reset-standard-variables-list
+            (or (get symbol 'saved-value) (get symbol 'saved-variable-comment)))
+       (progn
+         (put symbol 'saved-value nil)
+         (put symbol 'saved-variable-comment nil)
+         ;; Append this to `custom-reset-standard-variables-list' to
+         ;; have `custom-reset-standard-save-and-update' save setting
+         ;; to the file, update the widget's state, and redraw it.
+         (setq custom-reset-standard-variables-list
+               (cons widget custom-reset-standard-variables-list)))
+      (when (or (get symbol 'saved-value) (get symbol 'saved-variable-comment))
+       (put symbol 'saved-value nil)
+       (put symbol 'saved-variable-comment nil)
+       (custom-save-all))
+      (widget-put widget :custom-state 'unknown)
+      ;; This call will possibly make the comment invisible
+      (custom-redraw widget))))
+
+(defun custom-variable-reset-standard (widget)
+  "Restore standard setting for the variable edited by WIDGET.
+This operation eliminates any saved setting for the variable,
+restoring it to the state of a variable that has never been customized.
+The value that was current before this operation
+becomes the backup value, so you can get it again."
+  (let (custom-reset-standard-variables-list)
+    (custom-variable-mark-to-reset-standard widget)))
 
 (defun custom-variable-backup-value (widget)
   "Back up the current value for WIDGET's variable.
@@ -3040,7 +3109,7 @@ Also change :reverse-video to :inverse-video."
 
 
 (defun custom-face-edit-attribute-tag (widget)
-  "Returns the first :tag property in WIDGET or one of its children."
+  "Return the first :tag property in WIDGET or one of its children."
   (let ((tag (widget-get widget :tag)))
     (or (and (not (equal tag "")) tag)
        (let ((children (widget-get widget :children)))
@@ -3078,10 +3147,10 @@ OS/2 Presentation Manager.")
                                           :sibling-args (:help-echo "\
 Windows NT/9X.")
                                           w32)
-                                   (const :format "MAC "
+                                   (const :format "NS "
                                           :sibling-args (:help-echo "\
-Macintosh OS.")
-                                          mac)
+GNUstep or Macintosh OS Cocoa interface.")
+                                          ns)
                                    (const :format "DOS "
                                           :sibling-args (:help-echo "\
 Plain MS-DOS.")
@@ -3135,11 +3204,10 @@ Only match frames that support the specified face attributes.")
 ;;; The `custom-face' Widget.
 
 (defface custom-face-tag
-  `((t (:weight bold :height 1.2 :inherit variable-pitch)))
+  `((t :inherit custom-variable-tag))
   "Face used for face tags."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-face-tag-face 'face-alias 'custom-face-tag)
+(define-obsolete-face-alias 'custom-face-tag-face 'custom-face-tag "22.1")
 
 (defcustom custom-face-default-form 'selected
   "Default form of displaying face definition."
@@ -3151,7 +3219,7 @@ Only match frames that support the specified face attributes.")
 
 (define-widget 'custom-face 'custom
   "Customize face."
-  :sample-face 'custom-face-tag-face
+  :sample-face 'custom-face-tag
   :help-echo "Set or reset this face."
   :documentation-property #'face-doc-string
   :value-create 'custom-face-value-create
@@ -3159,11 +3227,13 @@ Only match frames that support the specified face attributes.")
   :custom-category 'face
   :custom-form nil ; defaults to value of `custom-face-default-form'
   :custom-set 'custom-face-set
-  :custom-save 'custom-face-save
+  :custom-mark-to-save 'custom-face-mark-to-save
   :custom-reset-current 'custom-redraw
   :custom-reset-saved 'custom-face-reset-saved
   :custom-reset-standard 'custom-face-reset-standard
+  :custom-mark-to-reset-standard 'custom-face-mark-to-reset-standard
   :custom-standard-value 'custom-face-standard-value
+  :custom-state-set-and-redraw 'custom-face-state-set-and-redraw
   :custom-menu 'custom-face-menu-create)
 
 (define-widget 'custom-face-all 'editable-list
@@ -3308,6 +3378,7 @@ SPEC must be a full face spec."
           ;; Update buttons.
           (widget-put widget :buttons buttons)
           ;; Insert documentation.
+          (widget-put widget :documentation-indent 3)
           (widget-add-documentation-string-button
            widget :visibility-widget 'custom-visibility)
 
@@ -3488,17 +3559,17 @@ Optional EVENT is the location for the menu."
     (put symbol 'customized-face value)
     (custom-push-theme 'theme-face symbol 'user 'set value)
     (if (face-spec-choose value)
-       (face-spec-set symbol value)
+       (face-spec-set symbol value t)
       ;; face-set-spec ignores empty attribute lists, so just give it
       ;; something harmless instead.
-      (face-spec-set symbol '((t :foreground unspecified))))
+      (face-spec-set symbol '((t :foreground unspecified)) t))
     (put symbol 'customized-face-comment comment)
     (put symbol 'face-comment comment)
     (custom-face-state-set widget)
     (custom-redraw-magic widget)))
 
-(defun custom-face-save (widget)
-  "Save in `.emacs' the face attributes in WIDGET."
+(defun custom-face-mark-to-save (widget)
+  "Mark for saving the face edited by WIDGET."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
         (value (custom-post-filter-face-spec (widget-value child)))
@@ -3510,19 +3581,27 @@ Optional EVENT is the location for the menu."
       (custom-comment-hide comment-widget))
     (custom-push-theme 'theme-face symbol 'user 'set value)
     (if (face-spec-choose value)
-       (face-spec-set symbol value)
+       (face-spec-set symbol value t)
       ;; face-set-spec ignores empty attribute lists, so just give it
       ;; something harmless instead.
-      (face-spec-set symbol '((t :foreground unspecified))))
+      (face-spec-set symbol '((t :foreground unspecified)) t))
     (unless (eq (widget-get widget :custom-state) 'standard)
       (put symbol 'saved-face value))
     (put symbol 'customized-face nil)
     (put symbol 'face-comment comment)
     (put symbol 'customized-face-comment nil)
-    (put symbol 'saved-face-comment comment)
-    (custom-save-all)
-    (custom-face-state-set widget)
-    (custom-redraw-magic widget)))
+    (put symbol 'saved-face-comment comment)))
+
+(defsubst custom-face-state-set-and-redraw (widget)
+  "Set state of face widget WIDGET and redraw with current settings."
+  (custom-face-state-set widget)
+  (custom-redraw-magic widget))
+
+(defun custom-face-save (widget)
+  "Save the face edited by WIDGET."
+  (custom-face-mark-to-save widget)
+  (custom-save-all)
+  (custom-face-state-set-and-redraw widget))
 
 ;; For backward compatibility.
 (define-obsolete-function-alias 'custom-face-save-command 'custom-face-save
@@ -3540,7 +3619,7 @@ Optional EVENT is the location for the menu."
     (put symbol 'customized-face nil)
     (put symbol 'customized-face-comment nil)
     (custom-push-theme 'theme-face symbol 'user 'set value)
-    (face-spec-set symbol value)
+    (face-spec-set symbol value t)
     (put symbol 'face-comment comment)
     (widget-value-set child value)
     ;; This call manages the comment visibility
@@ -3551,10 +3630,10 @@ Optional EVENT is the location for the menu."
 (defun custom-face-standard-value (widget)
   (get (widget-value widget) 'face-defface-spec))
 
-(defun custom-face-reset-standard (widget)
-  "Restore WIDGET to the face's standard attribute values.
-This operation eliminates any saved attributes for the face,
-restoring it to the state of a face that has never been customized."
+(defun custom-face-mark-to-reset-standard (widget)
+  "Restore widget WIDGET to the face's standard attribute values.
+If `custom-reset-standard-faces-list' is nil, save, reset and
+redraw the widget immediately."
   (let* ((symbol (widget-value widget))
         (child (car (widget-get widget :children)))
         (value (get symbol 'face-defface-spec))
@@ -3564,21 +3643,39 @@ restoring it to the state of a face that has never been customized."
     (put symbol 'customized-face nil)
     (put symbol 'customized-face-comment nil)
     (custom-push-theme 'theme-face symbol 'user 'reset)
-    (face-spec-set symbol value)
+    (face-spec-set symbol value t)
     (custom-theme-recalc-face symbol)
-    (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
-      (put symbol 'saved-face nil)
-      (put symbol 'saved-face-comment nil)
-      (custom-save-all))
-    (put symbol 'face-comment nil)
-    (widget-value-set child
-                     (custom-pre-filter-face-spec
-                      (list (list t (custom-face-attributes-get
-                                     symbol nil)))))
-    ;; This call manages the comment visibility
-    (widget-value-set comment-widget "")
-    (custom-face-state-set widget)
-    (custom-redraw-magic widget)))
+    (if (and custom-reset-standard-faces-list
+            (or (get symbol 'saved-face) (get symbol 'saved-face-comment)))
+       ;; Do this later.
+       (progn
+         (put symbol 'saved-face nil)
+         (put symbol 'saved-face-comment nil)
+         ;; Append this to `custom-reset-standard-faces-list' and have
+         ;; `custom-reset-standard-save-and-update' save setting to the
+         ;; file, update the widget's state, and redraw it.
+         (setq custom-reset-standard-faces-list
+               (cons widget custom-reset-standard-faces-list)))
+      (when (or (get symbol 'saved-face) (get symbol 'saved-face-comment))
+       (put symbol 'saved-face nil)
+       (put symbol 'saved-face-comment nil)
+       (custom-save-all))
+      (put symbol 'face-comment nil)
+      (widget-value-set child
+                       (custom-pre-filter-face-spec
+                        (list (list t (custom-face-attributes-get
+                                       symbol nil)))))
+      ;; This call manages the comment visibility
+      (widget-value-set comment-widget "")
+      (custom-face-state-set widget)
+      (custom-redraw-magic widget))))
+
+(defun custom-face-reset-standard (widget)
+  "Restore WIDGET to the face's standard attribute values.
+This operation eliminates any saved attributes for the face,
+restoring it to the state of a face that has never been customized."
+  (let (custom-reset-standard-faces-list)
+    (custom-face-mark-to-reset-standard widget)))
 
 ;;; The `face' Widget.
 
@@ -3694,8 +3791,7 @@ and so forth.  The remaining group tags are shown with `custom-group-tag'."
     (t (:weight bold)))
   "Face used for group tags."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-group-tag-face-1 'face-alias 'custom-group-tag-1)
+(define-obsolete-face-alias 'custom-group-tag-face-1 'custom-group-tag-1 "22.1")
 
 (defface custom-group-tag
   `((((class color)
@@ -3710,8 +3806,7 @@ and so forth.  The remaining group tags are shown with `custom-group-tag'."
     (t (:weight bold)))
   "Face used for low level group tags."
   :group 'custom-faces)
-;; backward-compatibility alias
-(put 'custom-group-tag-face 'face-alias 'custom-group-tag)
+(define-obsolete-face-alias 'custom-group-tag-face 'custom-group-tag "22.1")
 
 (define-widget 'custom-group 'custom
   "Customize group."
@@ -3723,10 +3818,12 @@ and so forth.  The remaining group tags are shown with `custom-group-tag'."
   :action 'custom-group-action
   :custom-category 'group
   :custom-set 'custom-group-set
-  :custom-save 'custom-group-save
+  :custom-mark-to-save 'custom-group-mark-to-save
   :custom-reset-current 'custom-group-reset-current
   :custom-reset-saved 'custom-group-reset-saved
   :custom-reset-standard 'custom-group-reset-standard
+  :custom-mark-to-reset-standard 'custom-group-mark-to-reset-standard
+  :custom-state-set-and-redraw 'custom-group-state-set-and-redraw
   :custom-menu 'custom-group-menu-create)
 
 (defun custom-group-sample-face-get (widget)
@@ -3768,7 +3865,8 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
         (symbol (widget-value widget))
         (members (custom-group-members symbol
                                        (and (eq custom-buffer-style 'tree)
-                                            custom-browse-only-groups))))
+                                            custom-browse-only-groups)))
+        (doc (widget-docstring widget)))
     (cond ((and (eq custom-buffer-style 'tree)
                (eq state 'hidden)
                (or members (custom-unloaded-widget-p widget)))
@@ -3886,7 +3984,8 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
                    ;;; was made to display a group.
               (when (eq level 1)
                 (if (custom-add-parent-links widget
-                                             "Parent groups:")
+                                             "Parent groups:"
+                                             "Parent group documentation:")
                     (insert "\n"))))
           ;; Create level indicator.
           (insert-char ?\  (* custom-buffer-indent (1- level)))
@@ -3895,7 +3994,11 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           (let ((start (point)))
             (insert tag " group: ")
             (widget-specify-sample widget start (point)))
-          (insert (widget-docstring widget))
+          (cond
+           ((not doc)
+            (insert " Group definition missing. "))
+           ((< (length doc) 50)
+            (insert doc)))
           ;; Create visibility indicator.
           (unless (eq custom-buffer-style 'links)
             (insert "--------")
@@ -3922,8 +4025,9 @@ If GROUPS-ONLY non-nil, return only those members that are groups."
           ;; Update buttons.
           (widget-put widget :buttons buttons)
           ;; Insert documentation.
-          (widget-add-documentation-string-button
-           widget :visibility-widget 'custom-visibility)
+          (when (and doc (>= (length doc) 50))
+            (widget-add-documentation-string-button
+             widget :visibility-widget 'custom-visibility))
 
           ;; Parent groups.
           (if nil  ;;; This should test that the buffer
@@ -4020,11 +4124,23 @@ Optional EVENT is the location for the menu."
     (when (eq (widget-get child :custom-state) 'modified)
       (widget-apply child :custom-set))))
 
-(defun custom-group-save (widget)
-  "Save all modified group members."
+(defun custom-group-mark-to-save (widget)
+  "Mark all modified group members for saving."
   (dolist (child (widget-get widget :children))
     (when (memq (widget-get child :custom-state) '(modified set))
-      (widget-apply child :custom-save))))
+      (widget-apply child :custom-mark-to-save))))
+
+(defsubst custom-group-state-set-and-redraw (widget)
+  "Set state of group widget WIDGET and redraw with current settings."
+  (dolist (child (widget-get widget :children))
+    (when (memq (widget-get child :custom-state) '(modified set))
+      (widget-apply child :custom-state-set-and-redraw))))
+
+(defun custom-group-save (widget)
+  "Save all modified group members."
+  (custom-group-mark-to-save widget)
+  (custom-save-all)
+  (custom-group-state-set-and-redraw widget))
 
 (defun custom-group-reset-current (widget)
   "Reset all modified group members."
@@ -4040,10 +4156,17 @@ Optional EVENT is the location for the menu."
 
 (defun custom-group-reset-standard (widget)
   "Reset all modified, set, or saved group members."
+  (let ((custom-reset-standard-variables-list '(t))
+       (custom-reset-standard-faces-list '(t)))
+    (custom-group-mark-to-reset-standard widget)
+    (custom-reset-standard-save-and-update)))
+
+(defun custom-group-mark-to-reset-standard (widget)
+  "Mark to reset all modified, set, or saved group members."
   (dolist (child (widget-get widget :children))
     (when (memq (widget-get child :custom-state)
                '(modified set saved))
-      (widget-apply child :custom-reset-standard))))
+      (widget-apply child :custom-mark-to-reset-standard))))
 
 (defun custom-group-state-update (widget)
   "Update magic."
@@ -4104,7 +4227,7 @@ and hence will not set `custom-file' to that file either."
                       :doc
                       "Please read entire docstring below before setting \
 this through Custom.
-Click om \"More\" \(or position point there and press RETURN)
+Click on \"More\" \(or position point there and press RETURN)
 if only the first line of the docstring is shown."))
   :group 'customize)
 
@@ -4126,6 +4249,9 @@ if only the first line of the docstring is shown."))
           (setq user-init-file default-init-file))
         user-init-file))))
 
+;; If recentf-mode is non-nil, this is defined.
+(declare-function recentf-expand-file-name "recentf" (name))
+
 ;;;###autoload
 (defun custom-save-all ()
   "Save all customizations in `custom-file'."
@@ -4139,9 +4265,18 @@ if only the first line of the docstring is shown."))
                             (recentf-expand-file-name (custom-file)))
                            "\\'")
                    recentf-exclude)))
-        (old-buffer (find-buffer-visiting filename)))
+        (old-buffer (find-buffer-visiting filename))
+        old-buffer-name)
+
     (with-current-buffer (let ((find-file-visit-truename t))
                           (or old-buffer (find-file-noselect filename)))
+      ;; We'll save using file-precious-flag, so avoid destroying
+      ;; symlinks.  (If we're not already visiting the buffer, this is
+      ;; handled by find-file-visit-truename, above.)
+      (when old-buffer
+       (setq old-buffer-name (buffer-file-name))
+       (set-visited-file-name (file-chase-links filename)))
+
       (unless (eq major-mode 'emacs-lisp-mode)
        (emacs-lisp-mode))
       (let ((inhibit-read-only t))
@@ -4149,7 +4284,10 @@ if only the first line of the docstring is shown."))
        (custom-save-faces))
       (let ((file-precious-flag t))
        (save-buffer))
-      (unless old-buffer
+      (if old-buffer
+         (progn
+           (set-visited-file-name old-buffer-name)
+           (set-buffer-modified-p nil))
        (kill-buffer (current-buffer))))))
 
 ;;;###autoload
@@ -4435,7 +4573,7 @@ The format is suitable for use with `easy-menu-define'."
 ;;; Toolbar and menubar support
 
 (easy-menu-define
-  Custom-mode-menu custom-mode-map
+  Custom-mode-menu (list custom-mode-map custom-field-keymap)
   "Menu used in customization buffers."
   (nconc (list "Custom"
               (customize-menu-create 'customize))
@@ -4448,15 +4586,12 @@ The format is suitable for use with `easy-menu-define'."
                 custom-commands)))
 
 (defvar tool-bar-map)
-(defvar custom-tool-bar-map
-  (if (display-graphic-p)
-      (let ((map (make-sparse-keymap)))
-       (mapc
-        (lambda (arg)
-          (tool-bar-local-item-from-menu
-           (nth 1 arg) (nth 4 arg) map custom-mode-map))
-        custom-commands)
-       map)))
+
+;;; `custom-tool-bar-map' used to be set up here.  This will fail to
+;;; DTRT when `display-graphic-p' returns nil during compilation.  Hence
+;;; we set this up lazily in `Custom-mode'.
+(defvar custom-tool-bar-map nil
+  "Keymap for toolbar in Custom mode.")
 
 ;;; The Custom Mode.
 
@@ -4473,15 +4608,6 @@ The format is suitable for use with `easy-menu-define'."
        (widget-apply-action button event)
       (error "You can't edit this part of the Custom buffer"))))
 
-(defvar custom-field-keymap
-  (let ((map (copy-keymap widget-field-keymap)))
-    (define-key map "\C-c\C-c" 'Custom-set)
-    (define-key map "\C-x\C-s" 'Custom-save)
-    map)
-  "Keymap used inside editable fields in customization buffers.")
-
-(widget-put (get 'editable-field 'widget-type) :keymap custom-field-keymap)
-
 (defun Custom-goto-parent ()
   "Go to the parent group listed at the top of this buffer.
 If several parents are listed, go to the first of them."
@@ -4493,16 +4619,16 @@ If several parents are listed, go to the first of them."
               (parent (downcase (widget-get  button :tag))))
          (customize-group parent)))))
 
-(defcustom custom-mode-hook nil
+(defcustom Custom-mode-hook nil
   "Hook called when entering Custom mode."
   :type 'hook
-  :group 'custom-buffer )
+  :group 'custom-buffer)
 
 (defun custom-state-buffer-message (widget)
   (if (eq (widget-get (widget-get widget :parent) :custom-state) 'modified)
       (message "To install your edits, invoke [State] and choose the Set operation")))
 
-(defun custom-mode ()
+(define-derived-mode Custom-mode nil "Custom"
   "Major mode for editing customization buffers.
 
 The following commands are available:
@@ -4522,20 +4648,27 @@ Reset options to permanent settings.       \\[Custom-reset-saved]
 Erase customizations; set options
   and buffer text to the standard values.  \\[Custom-reset-standard]
 
-Entry to this mode calls the value of `custom-mode-hook'
+Entry to this mode calls the value of `Custom-mode-hook'
 if that value is non-nil."
-  (kill-all-local-variables)
-  (setq major-mode 'custom-mode
-       mode-name "Custom")
   (use-local-map custom-mode-map)
   (easy-menu-add Custom-mode-menu)
-  (set (make-local-variable 'tool-bar-map) custom-tool-bar-map)
+  (set (make-local-variable 'tool-bar-map)
+       (or custom-tool-bar-map
+          ;; Set up `custom-tool-bar-map'.
+          (let ((map (make-sparse-keymap)))
+            (mapc
+             (lambda (arg)
+               (tool-bar-local-item-from-menu
+                (nth 1 arg) (nth 4 arg) map custom-mode-map))
+             custom-commands)
+            (setq custom-tool-bar-map map))))
   (make-local-variable 'custom-options)
   (make-local-variable 'custom-local-buffer)
   (make-local-variable 'widget-documentation-face)
   (setq widget-documentation-face 'custom-documentation)
   (make-local-variable 'widget-button-face)
   (setq widget-button-face custom-button)
+  (setq show-trailing-whitespace nil)
 
   ;; We need this because of the "More" button on docstrings.
   ;; Otherwise clicking on "More" can push point offscreen, which
@@ -4553,10 +4686,17 @@ if that value is non-nil."
     (set (make-local-variable 'widget-push-button-suffix) "")
     (set (make-local-variable 'widget-link-prefix) "")
     (set (make-local-variable 'widget-link-suffix) ""))
-  (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t)
-  (run-mode-hooks 'custom-mode-hook))
+  (add-hook 'widget-edit-functions 'custom-state-buffer-message nil t))
+
+(put 'Custom-mode 'mode-class 'special)
 
+;; backward-compatibility
+(defun custom-mode ()
+  "Non-interactive variant of `Custom-mode'."
+  (Custom-mode))
+(make-obsolete 'custom-mode 'Custom-mode "23.1")
 (put 'custom-mode 'mode-class 'special)
+(define-obsolete-variable-alias 'custom-mode-hook 'Custom-mode-hook "23.1")
 
 (dolist (regexp
         '("^No user option defaults have been changed since Emacs "