(texinfo-insert-menu): specify previously free variable `level' in a
[bpt/emacs.git] / lisp / faces.el
index 89c3bf7..fda5cdb 100644 (file)
@@ -1,8 +1,10 @@
 ;;; faces.el --- Lisp faces
 
-;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
 ;;   Free Software Foundation, Inc.
 
+;; Maintainer: FSF
+
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
@@ -58,12 +60,13 @@ a font height that isn't optimal."
           (set-default symbol value)
           (internal-set-font-selection-order value)))
 
-;; This is defined originally in {w32,x}faces.c.
+
+;; This is defined originally in xfaces.c.
 (defcustom face-font-family-alternatives
   '(("courier" "fixed")
     ("helv" "helvetica" "arial" "fixed"))
   "*Alist of alternative font family names.
-Each element has the the form (FAMILY ALTERNATIVE1 ALTERNATIVE2 ...).
+Each element has the form (FAMILY ALTERNATIVE1 ALTERNATIVE2 ...).
 If fonts of family FAMILY can't be loaded, try ALTERNATIVE1, then
 ALTERNATIVE2 etc."
   :tag "Alternative font families to try."
@@ -74,6 +77,32 @@ ALTERNATIVE2 etc."
           (internal-set-alternative-font-family-alist value)))
 
 
+;; This is defined originally in xfaces.c.
+(defcustom face-font-registry-alternatives
+  (if (eq system-type 'windows-nt)
+      '(("iso8859-1" "ms-oemlatin")
+       ("gb2312.1980" "gb2312")
+       ("jisx0208.1990" "jisx0208.1983" "jisx0208.1978")
+       ("ksc5601.1989" "ksx1001.1992" "ksc5601.1987")
+       ("muletibetan-2" "muletibetan-0"))
+    '(("gb2312.1980" "gb2312.80&gb8565.88" "gbk*")
+      ("jisx0208.1990" "jisx0208.1983" "jisx0208.1978")
+      ("ksc5601.1989" "ksx1001.1992" "ksc5601.1987")
+      ("muletibetan-2" "muletibetan-0")))
+  "*Alist of alternative font registry names.
+Each element has the form (REGISTRY ALTERNATIVE1 ALTERNATIVE2 ...).
+If fonts of registry REGISTRY can be loaded, font selection
+tries to find a best matching font among all fonts of registry
+REGISTRY, ALTERNATIVE1, ALTERNATIVE2, and etc."
+  :tag "Alternative font registries to try."
+  :type '(repeat (repeat string))
+  :version "21.1"
+  :group 'font-selection
+  :set #'(lambda (symbol value)
+          (set-default symbol value)
+          (internal-set-alternative-font-registry-alist value)))
+
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Creation, copying.
@@ -172,7 +201,7 @@ If NAME is already a face, it is simply returned.
 
 This function is defined for compatibility with Emacs 20.2.  It
 should not be used anymore."
-  (or (internal-find-face name frame)
+  (or (facep name)
       (check-face name)))
 (make-obsolete 'internal-get-face "See `facep' and `check-face'." "21.1")
 
@@ -274,7 +303,7 @@ If FRAME is omitted or nil, use the selected frame."
   "*List of X resources and classes for face attributes.
 Each element has the form (ATTRIBUTE ENTRY1 ENTRY2...) where ATTRIBUTE is
 the name of a face attribute, and each ENTRY is a cons of the form
-(RESOURCE . CLASS) with RESOURCE being the resource and CLASS being the
+\(RESOURCE . CLASS) with RESOURCE being the resource and CLASS being the
 X resource class for the attribute."
   :type '(repeat (cons symbol (repeat (cons string string))))
   :group 'faces)
@@ -300,14 +329,14 @@ specifies an invalid attribute."
 
 (defun set-face-attributes-from-resources (face frame)
   "Set attributes of FACE from X resources for FRAME."
-  (when (memq (framep frame) '(x w32))
+  (when (memq (framep frame) '(x w32 mac))
     (dolist (definition face-x-resources)
       (let ((attribute (car definition)))
        (dolist (entry (cdr definition))
          (set-face-attribute-from-resource face attribute (car entry)
                                            (cdr entry) frame))))))
-    
-  
+
+
 (defun make-face-x-resource-internal (face &optional frame)
   "Fill frame-local FACE on FRAME from X resources.
 FRAME nil or not specified means do it for all frames."
@@ -327,36 +356,125 @@ FRAME nil or not specified means do it for all frames."
   (symbol-name (check-face face)))
 
 
-(defun face-attribute (face attribute &optional frame)
+(defun face-attribute (face attribute &optional frame inherit)
   "Return the value of FACE's ATTRIBUTE on FRAME.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (internal-get-lisp-face-attribute face attribute frame))
+If FRAME is omitted or nil, use the selected frame.
+
+If INHERIT is nil, only attributes directly defined by FACE are considered,
+  so the return value may be `unspecified', or a relative value.
+If INHERIT is non-nil, FACE's definition of ATTRIBUTE is merged with the
+  faces specified by its `:inherit' attribute; however the return value
+  may still be `unspecified' or relative.
+If INHERIT is a face or a list of faces, then the result is further merged
+  with that face (or faces), until it becomes specified and absolute.
+
+To ensure that the return value is always specified and absolute, use a
+value of `default' for INHERIT; this will resolve any unspecified or
+relative values by merging with the `default' face (which is always
+completely specified)."
+  (let ((value (internal-get-lisp-face-attribute face attribute frame)))
+    (when (and inherit (face-attribute-relative-p attribute value))
+      ;; VALUE is relative, so merge with inherited faces
+      (let ((inh-from (face-attribute face :inherit frame)))
+       (unless (or (null inh-from) (eq inh-from 'unspecified))
+         (setq value
+               (face-attribute-merged-with attribute value inh-from frame)))))
+    (when (and inherit
+              (not (eq inherit t))
+              (face-attribute-relative-p attribute value))
+       ;; We should merge with INHERIT as well
+      (setq value (face-attribute-merged-with attribute value inherit frame)))
+    value))
+
+(defun face-attribute-merged-with (attribute value faces &optional frame)
+  "Merges ATTRIBUTE, initially VALUE, with faces from FACES until absolute.
+FACES may be either a single face or a list of faces.
+\[This is an internal function]"
+  (cond ((not (face-attribute-relative-p attribute value))
+        value)
+       ((null faces)
+        value)
+       ((consp faces)
+        (face-attribute-merged-with
+         attribute
+         (face-attribute-merged-with attribute value (car faces) frame)
+         (cdr faces)
+         frame))
+       (t
+        (merge-face-attribute attribute
+                              value
+                              (face-attribute faces attribute frame t)))))
 
 
-(defun face-foreground (face &optional frame)
+(defmacro face-attribute-specified-or (value &rest body)
+  "Return VALUE, unless it's `unspecified', in which case evaluate BODY and return the result."
+  (let ((temp (make-symbol "value")))
+    `(let ((,temp ,value))
+       (if (not (eq ,temp 'unspecified))
+          ,temp
+        ,@body))))
+
+(defun face-foreground (face &optional frame inherit)
   "Return the foreground color name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (internal-get-lisp-face-attribute face :foreground frame))
-
+If FRAME is omitted or nil, use the selected frame.
 
-(defun face-background (face &optional frame)
+If INHERIT is nil, only a foreground color directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a foreground color, then any
+  foreground color that FACE inherits through its `:inherit' attribute
+  is considered as well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified foreground color.
+
+To ensure that a valid color is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by
+merging with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :foreground frame inherit)
+                              nil))
+
+(defun face-background (face &optional frame inherit)
   "Return the background color name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (internal-get-lisp-face-attribute face :background frame))
-
+If FRAME is omitted or nil, use the selected frame.
 
-(defun face-stipple (face &optional frame)
+If INHERIT is nil, only a background color directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a background color, then any
+  background color that FACE inherits through its `:inherit' attribute
+  is considered as well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified background color.
+
+To ensure that a valid color is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by
+merging with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :background frame inherit)
+                              nil))
+
+(defun face-stipple (face &optional frame inherit)
  "Return the stipple pixmap name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (internal-get-lisp-face-attribute face :stipple frame))
+If FRAME is omitted or nil, use the selected frame.
+
+If INHERIT is nil, only a stipple directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a stipple, then any stipple
+  that FACE inherits through its `:inherit' attribute is considered as
+  well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified stipple.
+
+To ensure that a valid stipple or nil is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by merging
+with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :stipple frame inherit)
+                              nil))
 
 
 (defalias 'face-background-pixmap 'face-stipple)
@@ -396,8 +514,6 @@ If FRAME is omitted or nil, use the selected frame.
 Use `face-attribute' for finer control."
   (let ((italic (face-attribute face :slant frame)))
     (memq italic '(italic oblique))))
-    
-
 
 
 \f
@@ -507,7 +623,9 @@ VALUE must be a property list of the form `(:line-width WIDTH
 :color COLOR :style STYLE)'.  If a keyword/value pair is missing from
 the property list, a default value will be used for the value, as
 specified below.  WIDTH specifies the width of the lines to draw; it
-defaults to 1.  COLOR is the name of the color to draw in, default is
+defaults to 1.  If WIDTH is negative, the absolute value is the width
+of the lines, and draw top/bottom lines inside the characters area,
+not around it.  COLOR is the name of the color to draw in, default is
 the foreground color of the face for simple boxes, and the background
 color of the face for 3D boxes.  STYLE specifies whether a 3D box
 should be draw.  If STYLE is `released-button', draw a box looking
@@ -562,7 +680,7 @@ like an underlying face would be, with higher priority than underlying faces."
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font weight."
-  (interactive (list (read-face-name "Make which face bold ")))
+  (interactive (list (read-face-name "Make which face bold")))
   (set-face-attribute face frame :weight 'bold))
 
 
@@ -570,16 +688,16 @@ Use `set-face-attribute' for finer control of the font weight."
   "Make the font of FACE be non-bold, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility."
-  (interactive (list (read-face-name "Make which face non-bold ")))
+  (interactive (list (read-face-name "Make which face non-bold")))
   (set-face-attribute face frame :weight 'normal))
 
-  
+
 (defun make-face-italic (face &optional frame noerror)
   "Make the font of FACE be italic, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font slant."
-  (interactive (list (read-face-name "Make which face italic ")))
+  (interactive (list (read-face-name "Make which face italic")))
   (set-face-attribute face frame :slant 'italic))
 
 
@@ -587,16 +705,16 @@ Use `set-face-attribute' for finer control of the font slant."
   "Make the font of FACE be non-italic, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility."
-  (interactive (list (read-face-name "Make which face non-italic ")))
+  (interactive (list (read-face-name "Make which face non-italic")))
   (set-face-attribute face frame :slant 'normal))
 
-  
+
 (defun make-face-bold-italic (face &optional frame noerror)
   "Make the font of FACE be bold and italic, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of font weight and slant."
-  (interactive (list (read-face-name "Make which face bold-italic")))
+  (interactive (list (read-face-name "Make which face bold-italic")))
   (set-face-attribute face frame :weight 'bold :slant 'italic))
 
 
@@ -618,7 +736,7 @@ and `:slant'.  When called interactively, prompt for the face and font."
 FRAME nil or not specified means change face on all frames.
 When called interactively, prompt for the face and color."
   (interactive (read-face-and-attribute :background))
-  (set-face-attribute face frame :background color))
+  (set-face-attribute face frame :background (or color 'unspecified)))
 
 
 (defun set-face-foreground (face color &optional frame)
@@ -626,7 +744,7 @@ When called interactively, prompt for the face and color."
 FRAME nil or not specified means change face on all frames.
 When called interactively, prompt for the face and color."
   (interactive (read-face-and-attribute :foreground))
-  (set-face-attribute face frame :foreground color))
+  (set-face-attribute face frame :foreground (or color 'unspecified)))
 
 
 (defun set-face-stipple (face stipple &optional frame)
@@ -639,7 +757,7 @@ Alternatively, STIPPLE may be a list of the form (WIDTH HEIGHT DATA)
 where WIDTH and HEIGHT are the size in pixels,
 and DATA is a string, containing the raw bits of the bitmap."
   (interactive (read-face-and-attribute :stipple))
-  (set-face-attribute face frame :stipple stipple))
+  (set-face-attribute face frame :stipple (or stipple 'unspecified)))
 
 
 (defun set-face-underline (face underline &optional frame)
@@ -707,14 +825,14 @@ Use `set-face-attribute' or `modify-face' for finer control."
 
 (defun invert-face (face &optional frame)
   "Swap the foreground and background colors of FACE.
-FRAME nil or not specified means change face on all frames.
+If FRAME is omitted or nil, it means change face on all frames.
 If FACE specifies neither foreground nor background color,
 set its foreground and background to the background and foreground
 of the default face.  Value is FACE."
-  (interactive (list (read-face-name "Invert face ")))
+  (interactive (list (read-face-name "Invert face")))
   (let ((fg (face-attribute face :foreground frame))
        (bg (face-attribute face :background frame)))
-    (if (or fg bg)
+    (if (not (and (eq fg 'unspecified) (eq bg 'unspecified)))
        (set-face-attribute face frame :foreground bg :background fg)
       (set-face-attribute face frame
                          :foreground
@@ -730,6 +848,7 @@ of the default face.  Value is FACE."
 
 (defun read-face-name (prompt)
   "Read and return a face symbol, prompting with PROMPT.
+PROMPT should not end with a blank, since this function appends one.
 Value is a symbol naming a known face."
   (let ((face-list (mapcar #'(lambda (x) (cons (symbol-name x) x))
                           (face-list)))
@@ -751,50 +870,48 @@ and colors.  If it is nil or not specified, the selected frame is
 used.  Value is an alist of (NAME . VALUE) if ATTRIBUTE expects a value
 out of a set of discrete values.  Value is `integerp' if ATTRIBUTE expects
 an integer value."
-  (let (valid)
-    (setq valid
-         (case attribute
-           (:family
-            (if window-system
-                (mapcar #'(lambda (x) (cons (car x) (car x)))
-                        (x-font-family-list))
-              ;; Only one font on TTYs.
-              (list (cons "default" "default"))))
-           ((:width :weight :slant :inverse-video)
-            (mapcar #'(lambda (x) (cons (symbol-name x) x))
-                    (internal-lisp-face-attribute-values attribute)))
-           ((:underline :overline :strike-through :box)
-            (if window-system
-                (nconc (mapcar #'(lambda (x) (cons (symbol-name x) x))
-                               (internal-lisp-face-attribute-values attribute))
-                       (mapcar #'(lambda (c) (cons c c))
-                               (x-defined-colors frame)))
-              (mapcar #'(lambda (x) (cons (symbol-name x) x))
-                      (internal-lisp-face-attribute-values attribute))))
-           ((:foreground :background)
-            (mapcar #'(lambda (c) (cons c c))
-                    (defined-colors frame)))
-           ((:height)
-            'integerp)
-           (:stipple
-            (and (memq window-system '(x w32))
-                 (mapcar #'list
-                         (apply #'nconc
-                                (mapcar (lambda (dir)
-                                          (and (file-readable-p dir)
-                                               (file-directory-p dir)
-                                               (directory-files dir)))
-                                        x-bitmap-file-path)))))
-           (:inherit
-            (cons '("none" . nil)
-                  (mapcar #'(lambda (c) (cons (symbol-name c) c))
-                          (face-list))))
-           (t
-            (error "Internal error"))))
+  (let ((valid
+         (case attribute
+           (:family
+            (if window-system
+                (mapcar #'(lambda (x) (cons (car x) (car x)))
+                        (x-font-family-list))
+             ;; Only one font on TTYs.
+             (list (cons "default" "default"))))
+           ((:width :weight :slant :inverse-video)
+            (mapcar #'(lambda (x) (cons (symbol-name x) x))
+                    (internal-lisp-face-attribute-values attribute)))
+           ((:underline :overline :strike-through :box)
+            (if window-system
+                (nconc (mapcar #'(lambda (x) (cons (symbol-name x) x))
+                               (internal-lisp-face-attribute-values attribute))
+                       (mapcar #'(lambda (c) (cons c c))
+                               (x-defined-colors frame)))
+             (mapcar #'(lambda (x) (cons (symbol-name x) x))
+                     (internal-lisp-face-attribute-values attribute))))
+           ((:foreground :background)
+            (mapcar #'(lambda (c) (cons c c))
+                    (defined-colors frame)))
+           ((:height)
+            'integerp)
+           (:stipple
+            (and (memq window-system '(x w32 mac))
+                 (mapcar #'list
+                         (apply #'nconc
+                                (mapcar (lambda (dir)
+                                          (and (file-readable-p dir)
+                                               (file-directory-p dir)
+                                               (directory-files dir)))
+                                        x-bitmap-file-path)))))
+           (:inherit
+            (cons '("none" . nil)
+                  (mapcar #'(lambda (c) (cons (symbol-name c) c))
+                          (face-list))))
+           (t
+            (error "Internal error")))))
     (if (and (listp valid) (not (memq attribute '(:inherit))))
        (nconc (list (cons "unspecified" 'unspecified)) valid)
       valid)))
-              
 
 
 (defvar face-attribute-name-alist
@@ -895,13 +1012,14 @@ of a global face.  Value is the new attribute value."
               ;; Terminal frames can support colors that don't appear
               ;; explicitly in VALID, using color approximation code
               ;; in tty-colors.el.
-              (if (and (memq attribute '(:foreground :background))
-                       (not (memq window-system '(x w32 mac)))
-                       (not (member new-value
-                                    '("unspecified"
-                                      "unspecified-fg" "unspecified-bg"))))
-                  (setq new-value (car (tty-color-desc new-value frame))))
-              (setq new-value (cdr (assoc new-value valid))))))
+              (when (and (memq attribute '(:foreground :background))
+                         (not (memq window-system '(x w32 mac)))
+                         (not (member new-value
+                                      '("unspecified"
+                                        "unspecified-fg" "unspecified-bg"))))
+                (setq new-value (car (tty-color-desc new-value frame))))
+              (when (assoc new-value valid)
+                (setq new-value (cdr (assoc new-value valid)))))))
          ((eq valid 'integerp)
           (setq new-value (face-read-integer face old-value attribute-name)))
          (t (error "Internal error")))
@@ -934,23 +1052,34 @@ Value is a property list of attribute names and new values."
                         (cons (read-face-attribute face (car attribute) frame)
                               result))))))
 
-    
-(defun modify-face (&optional frame)
+(defun modify-face (&optional face foreground background stipple
+                             bold-p italic-p underline-p inverse-p frame)
   "Modify attributes of faces interactively.
 If optional argument FRAME is nil or omitted, modify the face used
-for newly created frame, i.e. the global face."
+for newly created frame, i.e. the global face.
+For non-interactive use, `set-face-attribute' is preferred.
+When called from elisp, if FACE is nil, all arguments but FRAME are ignored
+and the face and its settings are obtained by querying the user."
   (interactive)
-  (let ((face (read-face-name "Modify face")))
+  (if face
+      (set-face-attribute face frame
+                         :foreground (or foreground 'unspecified)
+                         :background (or background 'unspecified)
+                         :stipple stipple
+                         :bold bold-p
+                         :italic italic-p
+                         :underline underline-p
+                         :inverse-video inverse-p)
+    (setq face (read-face-name "Modify face"))
     (apply #'set-face-attribute face frame
           (read-all-face-attributes face frame))))
 
-
 (defun read-face-and-attribute (attribute &optional frame)
   "Read face name and face attribute value.
 ATTRIBUTE is the attribute whose new value is read.
 FRAME nil or unspecified means read attribute value of global face.
 Value is a list (FACE NEW-VALUE) where FACE is the face read
-(a symbol), and NEW-VALUE is value read."
+\(a symbol), and NEW-VALUE is value read."
   (cond ((eq attribute :font)
         (let* ((prompt "Set font-related attributes of face")
                (face (read-face-name prompt))
@@ -996,7 +1125,7 @@ The sample text is a string that comes from the variable
           "Use "
           (if (display-mouse-p) "\\[help-follow-mouse] or ")
           "\\[help-follow] on a face name to customize it\n"
-          "or on its sample text for a decription of the face.\n\n")))
+          "or on its sample text for a description of the face.\n\n")))
        (setq help-xref-stack nil)
        (while faces
          (setq face (car faces))
@@ -1008,20 +1137,14 @@ The sample text is a string that comes from the variable
          (save-excursion
            (save-match-data
              (search-backward face-name)
-             (help-xref-button 0 (lambda (f)
-                                   (if help-xref-stack
-                                       (pop help-xref-stack))
-                                   (customize-face f))
-                               face-name
-                               "mouse-2: customize this face")))
+             (help-xref-button 0 'help-customize-face face-name)))
          (let ((beg (point)))
            (insert list-faces-sample-text)
            ;; Hyperlink to a help buffer for the face.
            (save-excursion
              (save-match-data
                (search-backward list-faces-sample-text)
-               (help-xref-button 0 #'describe-face face
-                                 "mouse-2: describe this face")))
+               (help-xref-button 0 'help-face face)))
            (insert "\n")
            (put-text-property beg (1- (point)) 'face face)
            ;; If the sample text has multiple lines, line up all of them.
@@ -1068,7 +1191,8 @@ If FRAME is omitted or nil, use the selected frame."
                  (:inherit . "Inherit")))
        (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x)))
                                        attrs))))
-    (with-output-to-temp-buffer "*Help*"
+    (help-setup-xref (list #'describe-face face) (interactive-p))
+    (with-output-to-temp-buffer (help-buffer)
       (save-excursion
        (set-buffer standard-output)
        (dolist (a attrs)
@@ -1082,16 +1206,13 @@ If FRAME is omitted or nil, use the selected frame."
          (terpri)
          (terpri)
          (princ (concat "You can " customize-label " this face."))
-         (with-current-buffer "*Help*"
+         (with-current-buffer standard-output
            (save-excursion
              (re-search-backward
               (concat "\\(" customize-label "\\)") nil t)
-             (help-xref-button 1 #'customize-face face
-                               "mouse-2, RET: customize face")))))
-      (print-help-return-message)
-      (with-current-buffer "*Help*"
-       (help-setup-xref (list #'describe-face face) (interactive-p))
-       (buffer-string)))))
+             (help-xref-button 1 'help-customize-face face)))))
+      (print-help-return-message))))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Face specifications (defface).
@@ -1111,7 +1232,7 @@ VALUE is the specified value of that attribute."
             (value (face-attribute face attribute)))
        (unless (eq value 'unspecified)
          (setq result (nconc (list attribute value) result)))))))
-    
+
 
 (defun face-spec-set-match-display (display frame)
   "Non-nil if DISPLAY matches FRAME.
@@ -1131,6 +1252,12 @@ If FRAME is nil, the current FRAME is used."
            options (cdr conjunct)
            match (cond ((eq req 'type)
                         (or (memq window-system options)
+                            ;; FIXME: This should be revisited to use
+                            ;; display-graphic-p, provided that the
+                            ;; color selection depends on the number
+                            ;; of supported colors, and all defface's
+                            ;; are changed to look at number of colors
+                            ;; instead of (type graphic) etc.
                             (and (null window-system)
                                  (memq 'tty options))
                             (and (memq 'motif options)
@@ -1151,18 +1278,23 @@ If FRAME is nil, the current FRAME is used."
 
 
 (defun face-spec-choose (spec &optional frame)
-  "Choose the proper attributes for FRAME, out of SPEC."
+  "Choose the proper attributes for FRAME, out of SPEC.
+If SPEC is nil, return nil."
   (unless frame
     (setq frame (selected-frame)))
   (let ((tail spec)
        result)
     (while tail
-      (let* ((entry (car tail))
-            (display (nth 0 entry))
-            (attrs (nth 1 entry)))
-       (setq tail (cdr tail))
+      (let* ((entry (pop tail))
+            (display (car entry))
+            (attrs (cdr entry)))
        (when (face-spec-set-match-display display frame)
-         (setq result attrs tail nil))))
+         (setq result (if (listp (car attrs))
+                          ;; Old-style entry, the attribute list is the
+                          ;; first element.
+                          (car attrs)
+                        attrs)
+               tail nil))))
     result))
 
 
@@ -1178,7 +1310,8 @@ If FRAME is nil, the current FRAME is used."
 (defun face-spec-set (face spec &optional frame)
   "Set FACE's attributes according to the first matching entry in SPEC.
 FRAME is the frame whose frame-local face is set.  FRAME nil means
-do it on all frames.  See `defface' for information about SPEC."
+do it on all frames.  See `defface' for information about SPEC.
+If SPEC is nil, do nothing."
   (let ((attrs (face-spec-choose spec frame)))
     (when attrs
       (face-spec-reset-face face frame))
@@ -1189,6 +1322,10 @@ do it on all frames.  See `defface' for information about SPEC."
        (case attribute
          (:bold (setq attribute :weight value (if value 'bold 'normal)))
          (:italic (setq attribute :slant value (if value 'italic 'normal)))
+         ((:foreground :background)
+          ;; Compatibility with 20.x.  Some bogus face specs seem to
+          ;; exist containing things like `:foreground nil'.
+          (if (null value) (setq value 'unspecified)))
          (t (unless (assq attribute face-x-resources)
               (setq attribute nil))))
        (when attribute
@@ -1219,6 +1356,16 @@ is used.  If nil or omitted, use the selected frame."
   "Return t if FACE, on FRAME, matches what SPEC says it should look like."
   (face-attr-match-p face (face-spec-choose spec frame) frame))
 
+(defsubst face-default-spec (face)
+  "Return the default face-spec for FACE, ignoring any user customization.
+If there is no default for FACE, return nil."
+  (get face 'face-defface-spec))
+
+(defsubst face-user-default-spec (face)
+  "Return the user's customized face-spec for FACE, or the default if none.
+If there is neither a user setting nor a default for FACE, return nil."
+  (or (get face 'saved-face)
+      (face-default-spec face)))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1231,7 +1378,7 @@ is used.  If nil or omitted, use the selected frame."
 The argument FRAME specifies which frame to try.
 The value may be different for frames on different display types.
 If FRAME doesn't support colors, the value is nil."
-  (if (memq (framep (or frame (selected-frame))) '(x w32))
+  (if (memq (framep (or frame (selected-frame))) '(x w32 mac))
       (xw-defined-colors frame)
     (mapcar 'car (tty-color-alist frame))))
 (defalias 'x-defined-colors 'defined-colors)
@@ -1241,9 +1388,9 @@ If FRAME doesn't support colors, the value is nil."
 If FRAME is omitted or nil, use the selected frame.
 If COLOR is the symbol `unspecified' or one of the strings
 \"unspecified-fg\" or \"unspecified-bg\", the value is nil."
-  (if (memq color '(unspecified "unspecified-bg" "unspecified-fg"))
+  (if (member color '(unspecified "unspecified-bg" "unspecified-fg"))
       nil
-    (if (memq (framep (or frame (selected-frame))) '(x w32))
+    (if (member (framep (or frame (selected-frame))) '(x w32 mac))
        (xw-color-defined-p color frame)
       (numberp (tty-color-translate color frame)))))
 (defalias 'x-color-defined-p 'color-defined-p)
@@ -1256,9 +1403,9 @@ If FRAME is omitted or nil, use the selected frame.
 If FRAME cannot display COLOR, the value is nil.
 If COLOR is the symbol `unspecified' or one of the strings
 \"unspecified-fg\" or \"unspecified-bg\", the value is nil."
-  (if (memq color '(unspecified "unspecified-fg" "unspecified-bg"))
+  (if (member color '(unspecified "unspecified-fg" "unspecified-bg"))
       nil
-    (if (memq (framep (or frame (selected-frame))) '(x w32))
+    (if (memq (framep (or frame (selected-frame))) '(x w32 mac))
        (xw-color-values color frame)
       (tty-color-values color frame))))
 (defalias 'x-color-values 'color-values)
@@ -1268,7 +1415,7 @@ If COLOR is the symbol `unspecified' or one of the strings
 The optional argument DISPLAY specifies which display to ask about.
 DISPLAY should be either a frame or a display name (a string).
 If omitted or nil, that stands for the selected frame's display."
-  (if (memq (framep-on-display display) '(x w32))
+  (if (memq (framep-on-display display) '(x w32 mac))
       (xw-display-color-p display)
     (tty-display-color-p display)))
 (defalias 'x-display-color-p 'display-color-p)
@@ -1304,26 +1451,33 @@ this won't have the expected effect."
 
 
 (defun frame-set-background-mode (frame)
-  "Set up the `background-mode' and `display-type' frame parameters for FRAME."
+  "Set up display-dependent faces on FRAME.
+Display-dependent faces are those which have different definitions
+according to the `background-mode' and `display-type' frame parameters."
   (let* ((bg-resource
          (and window-system
               (x-get-resource ".backgroundMode" "BackgroundMode")))
+        (bg-color (frame-parameter frame 'background-color))
         (bg-mode
          (cond (frame-background-mode)
-               ((null window-system)
-                ;; No way to determine this automatically (?).
-                'dark)
                (bg-resource
                 (intern (downcase bg-resource)))
-               ((< (apply '+ (x-color-values
-                              (frame-parameter frame 'background-color)
-                              frame))
+               ((and (null window-system) (null bg-color))
+                ;; No way to determine this automatically (?).
+                'dark)
+               ;; Unspecified frame background color can only happen
+               ;; on tty's.
+               ((member bg-color '(unspecified "unspecified-bg"))
+                'dark)
+               ((equal bg-color "unspecified-fg") ; inverted colors
+                'light)
+               ((>= (apply '+ (x-color-values bg-color frame))
                    ;; Just looking at the screen, colors whose
                    ;; values add up to .6 of the white total
                    ;; still look dark to me.
                    (* (apply '+ (x-color-values "white" frame)) .6))
-                'dark)
-               (t 'light)))
+                'light)
+               (t 'dark)))
         (display-type
          (cond ((null window-system)
                 (if (tty-display-color-p frame) 'color 'mono))
@@ -1338,17 +1492,26 @@ this won't have the expected effect."
          (frame-parameter frame 'display-type)))
 
     (unless (and (eq bg-mode old-bg-mode) (eq display-type old-display-type))
-      (modify-frame-parameters frame
-                              (list (cons 'background-mode bg-mode)
-                                    (cons 'display-type display-type)))
-      ;; For all named faces, choose face specs matching the new frame
-      ;; parameters.
-      (dolist (face (face-list))
-       (let ((spec (or (get face 'saved-face)
-                       (get face 'face-defface-spec))))
-         (when spec
-           (face-spec-set face spec frame)))))))
-
+      (let ((locally-modified-faces nil))
+       ;; Before modifying the frame parameters, we collect a list of
+       ;; faces that don't match what their face-spec says they should
+       ;; look like; we then avoid changing these faces below.  A
+       ;; negative list is used on the assumption that most faces will
+       ;; be unmodified, so we can avoid consing in the common case.
+       (dolist (face (face-list))
+         (when (not (face-spec-match-p face
+                                       (face-user-default-spec face)
+                                       (selected-frame)))
+           (push face locally-modified-faces)))
+       ;; Now change to the new frame parameters
+       (modify-frame-parameters frame
+                                (list (cons 'background-mode bg-mode)
+                                      (cons 'display-type display-type)))
+       ;; For all named faces, choose face specs matching the new frame
+       ;; parameters, unless they have been locally modified.
+       (dolist (face (face-list))
+         (unless (memq face locally-modified-faces)
+           (face-spec-set face (face-user-default-spec face) frame)))))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1433,12 +1596,12 @@ Value is the new frame created."
   "Set frame-local faces of FRAME from face specs and resources.
 Initialize colors of certain faces from frame parameters."
   (dolist (face (face-list))
-    (let ((spec (or (get face 'saved-face)
-                   (get face 'face-defface-spec))))
-      (when spec
-       (face-spec-set face spec frame))
+    (when (not (equal face 'default))
+      (face-spec-set face (face-user-default-spec face) frame)
       (internal-merge-in-global-face face frame)
-      (when (memq window-system '(x w32))
+      (when (and (memq window-system '(x w32 mac))
+                (or (not (boundp 'inhibit-default-face-x-resources))
+                    (not (eq face 'default))))
        (make-face-x-resource-internal face frame))))
 
   ;; Initialize attributes from frame parameters.
@@ -1449,14 +1612,33 @@ Initialize colors of certain faces from frame parameters."
                  (scroll-bar-foreground scroll-bar :foreground)
                  (scroll-bar-background scroll-bar :background)
                  (mouse-color mouse :background))))
-    (while params
-      (let ((param-name (nth 0 (car params)))
-           (face (nth 1 (car params)))
-           (attr (nth 2 (car params)))
-           value)
-       (when (setq value (frame-parameter frame param-name))
-         (set-face-attribute face frame attr value)))
-      (setq params (cdr params)))))
+    (dolist (param params)
+      (let ((frame-param (frame-parameter frame (nth 0 param)))
+           (face (nth 1 param))
+           (attr (nth 2 param)))
+       (when (and frame-param
+                  ;; Don't override face attributes explicitly
+                  ;; specified for new frames.
+                  (eq (face-attribute face attr t) 'unspecified))
+         (set-face-attribute face frame attr frame-param))))))
+
+
+(defun tty-handle-reverse-video (frame parameters)
+  "Handle the reverse-video frame parameter for terminal frames."
+  (when (cdr (or (assq 'reverse parameters)
+                (assq 'reverse default-frame-alist)))
+    (let* ((params (frame-parameters frame))
+          (bg (cdr (assq 'foreground-color params)))
+          (fg (cdr (assq 'background-color params))))
+      (modify-frame-parameters frame
+                              (list (cons 'foreground-color fg)
+                                    (cons 'background-color bg)))
+      (if (equal bg (cdr (assq 'mouse-color params)))
+         (modify-frame-parameters frame
+                                  (list (cons 'mouse-color fg))))
+      (if (equal bg (cdr (assq 'cursor-color params)))
+         (modify-frame-parameters frame
+                                  (list (cons 'cursor-color fg)))))))
 
 
 (defun tty-create-frame-with-faces (&optional parameters)
@@ -1469,6 +1651,7 @@ created."
        success)
     (unwind-protect
        (progn
+         (tty-handle-reverse-video frame (frame-parameters frame))
          (frame-set-background-mode frame)
          (face-set-after-frame-default frame)
          (setq success t))
@@ -1484,7 +1667,7 @@ created."
   (let ((frame (selected-frame)))
     (frame-set-background-mode frame)
     (face-set-after-frame-default frame)))
-  
+
 
 
 \f
@@ -1520,18 +1703,38 @@ created."
 
 
 (defface mode-line
-  '((((type x w32) (class color))
-     (:box (:line-width 2 :style released-button)
+  '((((type x w32 mac) (class color))
+     (:box (:line-width -1 :style released-button)
           :background "grey75" :foreground "black"))
     (t
      (:inverse-video t)))
-  "Basic mode line face."
+  "Basic mode line face for selected window."
   :version "21.1"
   :group 'modeline
   :group 'basic-faces)
 
+(defface mode-line-inactive
+  '((((type x w32 mac) (background light) (class color))
+     :inherit mode-line
+     :weight light
+     :box (:line-width -1 :color "grey75" :style nil)
+     :foreground "grey20" :background "grey90")
+    (((type x w32 mac) (background dark) (class color))
+     :inherit mode-line
+     :weight light
+     :box (:line-width -1 :color "grey40" :style nil)
+     :foreground "grey80" :background "grey30")
+    (t
+     :inherit mode-line
+     :inverse-video t))
+  "Basic mode line face for non-selected windows."
+  :version "21.2"
+  :group 'modeline
+  :group 'basic-faces)
+
 ;; Make `modeline' an alias for `mode-line', for compatibility.
 (put 'modeline 'face-alias 'mode-line)
+(put 'modeline-inactive 'face-alias 'mode-line-inactive)
 
 (defface header-line
   '((((type tty))
@@ -1544,28 +1747,37 @@ created."
      ;; highlighting; this may be too confusing in general, although it
      ;; happens to look good with the only current use of header-lines,
      ;; the info browser. XXX
-     (:underline t))
-    (((class color) (background light))
-     (:box (:line-width 1 :style released-button)
-          :background "grey90" :foreground "grey20"
-          :inherit mode-line))
-    (((class color) (background dark))
-     (:box (:line-width 1 :style released-button)
-          :background "grey20" :foreground "grey90"
-          :inherit mode-line))
-    (((class mono))
-     (:box (:line-width 1 :style released-button)
-          :background "grey"
-          :inherit mode-line))
+     :inherit mode-line
+     :underline t)
+    (((class color grayscale) (background light))
+     :inherit mode-line
+     :background "grey90" :foreground "grey20"
+     :box nil)
+    (((class color grayscale) (background dark))
+     :inherit mode-line
+     :background "grey20" :foreground "grey90"
+     :box nil)
+    (((class mono) (background light))
+     :inherit mode-line
+     :background "white" :foreground "black"
+     :inverse-video nil
+     :box nil
+     :underline t)
+    (((class mono) (background dark))
+     :inherit mode-line
+     :background "black" :foreground "white"
+     :inverse-video nil
+     :box nil
+     :underline t)
     (t
-     (:inverse-video t)))
+     :inverse-video t))
   "Basic header-line face."
   :version "21.1"
   :group 'basic-faces)
 
 
 (defface tool-bar
-  '((((type x w32) (class color))
+  '((((type x w32 mac) (class color))
      (:box (:line-width 1 :style released-button)
           :background "grey75" :foreground "black"))
     (((type x) (class mono))
@@ -1578,6 +1790,16 @@ created."
   :group 'basic-faces)
 
 
+(defface minibuffer-prompt '((((background dark)) (:foreground "cyan"))
+                            (((type pc)) (:foreground "magenta"))
+                            (t (:foreground "dark blue")))
+  "Face for minibuffer prompts."
+  :version "21.3"
+  :group 'basic-faces)
+
+(setq minibuffer-prompt-properties
+      (append minibuffer-prompt-properties (list 'face 'minibuffer-prompt)))
+
 (defface region
   '((((type tty) (class color))
      (:background "blue" :foreground "white"))
@@ -1586,7 +1808,7 @@ created."
     (((class color) (background dark))
      (:background "blue3"))
     (((class color) (background light))
-     (:background "light goldenrod yellow"))
+     (:background "lightgoldenrod2"))
     (t (:background "gray")))
   "Basic face for highlighting the region."
   :version "21.1"
@@ -1614,9 +1836,13 @@ created."
 
 
 (defface menu
-  '((((type x-toolkit)) ())
-    (t (:inverse-video t)))
-  "Basic menu face."
+  '((((type tty))
+     :inverse-video t)
+    (((type x-toolkit))
+     )
+    (t
+     :inverse-video t))
+  "Basic face for the font and colors of the menu bar and popup menus."
   :version "21.1"
   :group 'menu
   :group 'basic-faces)
@@ -1838,47 +2064,52 @@ also the same size as FACE on FRAME, or fail."
                   (substring font (match-end 1)))))))
 (make-obsolete 'x-frob-font-slant 'make-face-... "21.1")
 
+;; These aliases are here so that we don't get warnings about obsolete
+;; functions from the byte compiler.
+(defalias 'internal-frob-font-weight 'x-frob-font-weight)
+(defalias 'internal-frob-font-slant 'x-frob-font-slant)
+
 (defun x-make-font-bold (font)
   "Given an X font specification, make a bold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "bold"))
+  (internal-frob-font-weight font "bold"))
 (make-obsolete 'x-make-font-bold 'make-face-bold "21.1")
 
 (defun x-make-font-demibold (font)
   "Given an X font specification, make a demibold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "demibold"))
+  (internal-frob-font-weight font "demibold"))
 (make-obsolete 'x-make-font-demibold 'make-face-bold "21.1")
 
 (defun x-make-font-unbold (font)
   "Given an X font specification, make a non-bold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "medium"))
+  (internal-frob-font-weight font "medium"))
 (make-obsolete 'x-make-font-unbold 'make-face-unbold "21.1")
 
 (defun x-make-font-italic (font)
   "Given an X font specification, make an italic version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "i"))
+  (internal-frob-font-slant font "i"))
 (make-obsolete 'x-make-font-italic 'make-face-italic "21.1")
 
 (defun x-make-font-oblique (font) ; you say tomayto...
   "Given an X font specification, make an oblique version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "o"))
+  (internal-frob-font-slant font "o"))
 (make-obsolete 'x-make-font-oblique 'make-face-italic "21.1")
 
 (defun x-make-font-unitalic (font)
   "Given an X font specification, make a non-italic version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "r"))
+  (internal-frob-font-slant font "r"))
 (make-obsolete 'x-make-font-unitalic 'make-face-unitalic "21.1")
 
 (defun x-make-font-bold-italic (font)
   "Given an X font specification, make a bold and italic version of it.
 If that can't be done, return nil."
-  (and (setq font (x-make-font-bold font))
-       (x-make-font-italic font)))
+  (and (setq font (internal-frob-font-weight font "bold"))
+       (internal-frob-font-slant font "i")))
 (make-obsolete 'x-make-font-bold-italic 'make-face-bold-italic "21.1")
 
 (provide 'faces)