diff lisp/faces.el @ 25012:583c6bc7fe82

Complete rewrite.
author Gerd Moellmann <gerd@gnu.org>
date Wed, 21 Jul 1999 21:43:52 +0000
parents 82cf6c4c1e03
children b4b6828139fd
line wrap: on
line diff
--- a/lisp/faces.el	Wed Jul 21 21:43:52 1999 +0000
+++ b/lisp/faces.el	Wed Jul 21 21:43:52 1999 +0000
@@ -1,6 +1,7 @@
-;;; faces.el --- Lisp interface to the c "face" structure
+;;; faces.el --- Lisp faces
 
-;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998
+;;   Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -21,740 +22,1435 @@
 
 ;;; Commentary:
 
-;; Mostly derived from Lucid.
-
 ;;; Code:
 
 (eval-when-compile
- ;; These used to be defsubsts, now they're subrs.  Avoid losing if we're
- ;; being compiled with an old Emacs that still has defsubrs in it.
- (put 'face-name 'byte-optimizer nil)
- (put 'face-id 'byte-optimizer nil)
- (put 'face-font 'byte-optimizer nil)
- (put 'face-font-explicit 'byte-optimizer nil)
- (put 'face-foreground 'byte-optimizer nil)
- (put 'face-background 'byte-optimizer nil)
- (put 'face-stipple 'byte-optimizer nil)
- (put 'face-underline-p 'byte-optimizer nil)
- (put 'set-face-font 'byte-optimizer nil)
- (put 'set-face-font-auto 'byte-optimizer nil)
- (put 'set-face-foreground 'byte-optimizer nil)
- (put 'set-face-background 'byte-optimizer nil)
- (put 'set-face-stipple 'byte-optimizer nil)
- (put 'set-face-underline-p 'byte-optimizer nil))
-
-;;;; Functions for manipulating face vectors.
-
-;;; A face vector is a vector of the form:
-;;;    [face NAME ID FONT FOREGROUND BACKGROUND STIPPLE
-;;;          UNDERLINE-P INVERSE-VIDEO-P FONT-EXPLICIT-P BOLD-P ITALIC-P]
-
-;;; Type checkers.
-(defsubst internal-facep (x)
-  (and (vectorp x) (= (length x) 12) (eq (aref x 0) 'face)))
-
-(defun facep (x)
-  "Return t if X is a face name or an internal face vector."
-  (and (or (internal-facep x)
-	   (and (symbolp x) (assq x global-face-data)))
-       t))
-      
-(defmacro internal-check-face (face)
-  (` (or (internal-facep (, face))
-	 (signal 'wrong-type-argument (list 'internal-facep (, face))))))
-
-;;; Accessors.
-(defun face-name (face)
-  "Return the name of face FACE."
-  (aref (internal-get-face face) 1))
+  (require 'custom)
+  (require 'cl))
 
-(defun face-id (face)
-  "Return the internal ID number of face FACE."
-  (aref (internal-get-face face) 2))
-
-(defun face-font (face &optional frame)
-  "Return the font name of face FACE, or nil if it is 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).
-  The font default for a face is either nil, or a list
-  of the form (bold), (italic) or (bold italic).
-If FRAME is omitted or nil, use the selected frame."
-  (aref (internal-get-face face frame) 3))
-
-(defun face-foreground (face &optional frame)
-  "Return the foreground color name of face 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."
-  (aref (internal-get-face face frame) 4))
-
-(defun face-background (face &optional frame)
-  "Return the background color name of face 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."
-  (aref (internal-get-face face frame) 5))
-
-(defun face-stipple (face &optional frame)
- "Return the stipple pixmap name of face 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."
- (aref (internal-get-face face frame) 6))
-
-(defalias 'face-background-pixmap 'face-stipple)
-
-(defun face-underline-p (face &optional frame)
- "Return t if face FACE is underlined.
-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."
- (aref (internal-get-face face frame) 7))
+(require 'cus-face)
 
-(defun face-inverse-video-p (face &optional frame)
- "Return t if face FACE is in inverse video.
-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."
- (aref (internal-get-face face frame) 8))
-
-(defun face-font-explicit (face &optional frame)
-  "Return non-nil if this face's font was explicitly specified."
-  (aref (internal-get-face face frame) 9))
-
-(defun face-bold-p (face &optional frame)
-  "Return non-nil if the font of FACE is bold.
-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."
-  (aref (internal-get-face face frame) 10))
-
-(defun face-italic-p (face &optional frame)
-  "Return non-nil if the font of FACE is italic.
-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."
-  (aref (internal-get-face face frame) 11))
-
-(defalias 'face-doc-string 'face-documentation)
-(defun face-documentation (face)
-  "Get the documentation string for FACE."
-  (get face 'face-documentation))
 
-;;; Mutators.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Font selection.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun set-face-font (face font &optional frame)
-  "Change the font of face FACE to FONT (a string).
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "font"))
-  (if (stringp font)
-      (setq font (or (resolve-fontset-name font)
-		     (x-resolve-font-name font 'default frame))))
-  (internal-set-face-1 face 'font font 3 frame)
-  ;; Record that this face's font was set explicitly, not automatically,
-  ;; unless we are setting it to nil.
-  (internal-set-face-1 face nil (not (null font)) 9 frame))
-
-(defun set-face-font-auto (face font &optional frame)
-  "Change the font of face FACE to FONT (a string), for an automatic change.
-An automatic change means that we don't change the \"explicit\" flag;
-if the font was derived from the frame font before, it is now.
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "font"))
-  (if (stringp font)
-      (setq font (or (resolve-fontset-name font)
-		     (x-resolve-font-name font 'default frame))))
-  (internal-set-face-1 face 'font font 3 frame))
+(defgroup font-selection nil
+  "Influencing face font selection."
+  :group 'faces)
 
-(defun set-face-font-explicit (face flag &optional frame)
-  "Set the explicit-font flag of face FACE to FLAG.
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (internal-set-face-1 face nil flag 9 frame))
-
-(defun set-face-foreground (face color &optional frame)
-  "Change the foreground color of face FACE to COLOR (a string).
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "foreground" 'color))
-  (internal-set-face-1 face 'foreground color 4 frame))
-
-(defvar face-default-stipple "gray3" 
-  "Default stipple pattern used on monochrome displays.
-This stipple pattern is used on monochrome displays
-instead of shades of gray for a face background color.
-See `set-face-stipple' for possible values for this variable.")
-
-(defun face-color-gray-p (color &optional frame)
-  "Return t if COLOR is a shade of gray (or white or black).
-FRAME specifies the frame and thus the display for interpreting COLOR."
-  (let* ((values (x-color-values color frame))
-	 (r (nth 0 values))
-	 (g (nth 1 values))
-	 (b (nth 2 values)))
-    (and values
-	 (< (abs (- r g)) (/ (max 1 (abs r) (abs g)) 20))
-	 (< (abs (- g b)) (/ (max 1 (abs g) (abs b)) 20))
-	 (< (abs (- b r)) (/ (max 1 (abs b) (abs r)) 20)))))
 
-(defun set-face-background (face color &optional frame)
-  "Change the background color of face FACE to COLOR (a string).
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "background" 'color))
-  ;; For a specific frame, use gray stipple instead of gray color
-  ;; if the display does not support a gray color.
-  (if (and frame (not (eq frame t)) color
-	   ;; Check for support for foreground, not for background!
-	   ;; face-color-supported-p is smart enough to know
-	   ;; that grays are "supported" as background
-	   ;; because we are supposed to use stipple for them!
-	   (not (face-color-supported-p frame color nil)))
-      (set-face-stipple face face-default-stipple frame)
-    (if (null frame)
-	(let ((frames (frame-list)))
-	  (while frames
-	    (set-face-background (face-name face) color (car frames))
-	    (setq frames (cdr frames)))
-	  (set-face-background face color t)
-	  color)
-      (internal-set-face-1 face 'background color 5 frame))))
-
-(defun set-face-stipple (face pixmap &optional frame)
-  "Change the stipple pixmap of face FACE to PIXMAP.
-PIXMAP should be a string, the name of a file of pixmap data.
-The directories listed in the `x-bitmap-file-path' variable are searched.
-
-Alternatively, PIXMAP 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.  
-
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive-stipple "stipple"))
-  (internal-set-face-1 face 'background-pixmap pixmap 6 frame))
-
-(defalias 'set-face-background-pixmap 'set-face-stipple)
-
-(defun set-face-underline-p (face underline-p &optional frame)
-  "Specify whether face FACE is underlined.  (Yes if UNDERLINE-P is non-nil.)
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "underline-p" "underlined"))
-  (internal-set-face-1 face 'underline underline-p 7 frame))
+(defcustom face-font-selection-order
+  '(:width :height :weight :slant)
+  "*A list specifying how face font selection chooses fonts.
+Each of the four symbols `:width', `:height', `:weight', and `:slant'
+must appear once in the list, and the list must not contain any other
+elements.  Font selection tries to find a best matching font for
+those face attributes first that appear first in the list.  For
+example, if `:slant' appears before `:height', font selection first
+tries to find a font with a suitable slant, even if this results in
+a font height that isn't optimal."
+  :tag "Font selection order."
+  :group 'font-selection
+  :set #'(lambda (symbol value)
+	   (set-default symbol value)
+	   (internal-set-font-selection-order value)))
 
-(defun set-face-inverse-video-p (face inverse-video-p &optional frame)
-  "Specify whether face FACE is in inverse video.
-\(Yes if INVERSE-VIDEO-P is non-nil.)
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (interactive (internal-face-interactive "inverse-video-p" "inverse-video"))
-  (internal-set-face-1 face 'inverse-video inverse-video-p 8 frame))
-
-(defun set-face-bold-p (face bold-p &optional frame)
-  "Specify whether face FACE is bold.  (Yes if BOLD-P is non-nil.)
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (cond ((eq bold-p nil) (make-face-unbold face frame t))
-	(t (make-face-bold face frame t))))
-
-(defun set-face-italic-p (face italic-p &optional frame)
-  "Specify whether face FACE is italic.  (Yes if ITALIC-P is non-nil.)
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame."
-  (cond ((eq italic-p nil) (make-face-unitalic face frame t))
-	(t (make-face-italic face frame t))))
-
-(defalias 'set-face-doc-string 'set-face-documentation)
-(defun set-face-documentation (face string)
-  "Set the documentation string for FACE to STRING."
-  (put face 'face-documentation string))
-
-(defun modify-face-read-string (face default name alist)
-  (let ((value
-	 (completing-read
-	  (if default
-	      (format "Set face %s %s (default %s): "
-		      face name (downcase default))
-	    (format "Set face %s %s: " face name))
-	  alist)))
-    (cond ((equal value "none")
-	   '(nil))
-	  ((equal value "")
-	   default)
-	  (t value))))
-
-(defun modify-face (face foreground background stipple
-		    bold-p italic-p underline-p &optional inverse-p frame)
-  "Change the display attributes for face FACE.
-If the optional FRAME argument is provided, change only
-in that frame; otherwise change each frame.
-
-FOREGROUND and BACKGROUND should be a colour name string (or list of strings to
-try) or nil.  STIPPLE should be a stipple pattern name string or nil.
-If nil, means do not change the display attribute corresponding to that arg.
-If (nil), that means clear out the attribute.
 
-BOLD-P, ITALIC-P, UNDERLINE-P, and INVERSE-P specify whether
-the face should be set bold, italic, underlined or in inverse-video,
-respectively.  If one of these arguments is neither nil or t, it means do not
-change the display attribute corresponding to that argument.
+(defcustom face-font-family-alternatives
+  '(("courier" "fixed")
+    ("helv" "helvetica" "fixed"))
+  "*Alist of alternative font family names.
+Each element has the 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."
+  :group 'font-selection
+  :set #'(lambda (symbol value)
+	   (set-default symbol value)
+	   (internal-set-alternative-font-family-alist value)))
 
-If called interactively, prompts for a face name and face attributes."
-  (interactive
-   (let* ((completion-ignore-case t)
-	  (face		(symbol-name (read-face-name "Modify face: ")))
-	  (colors	(mapcar 'list x-colors))
-	  (stipples	(mapcar 'list (apply 'nconc
-					    (mapcar 'directory-files
-						    x-bitmap-file-path))))
-	  (foreground	(modify-face-read-string
-			 face (face-foreground (intern face))
-			 "foreground" colors))
-	  (background	(modify-face-read-string
-			 face (face-background (intern face))
-			 "background" colors))
-	  ;; If the stipple value is a list (WIDTH HEIGHT DATA),
-	  ;; represent that as a string by printing it out.
-	  (old-stipple-string
-	   (if (stringp (face-stipple (intern face)))
-	       (face-stipple (intern face))
-	     (if (face-stipple (intern face))
-		 (prin1-to-string (face-stipple (intern face))))))
-	  (new-stipple-string
-	   (modify-face-read-string
-	    face old-stipple-string
-	    "stipple" stipples))
-	  ;; Convert the stipple value text we read
-	  ;; back to a list if it looks like one.
-	  ;; This makes the assumption that a pixmap file name
-	  ;; won't start with an open-paren.
-	  (stipple
-	   (and new-stipple-string
-		(if (string-match "^(" new-stipple-string)
-		    (read new-stipple-string)
-		  new-stipple-string)))
-	  (bold-p	(y-or-n-p (concat "Should face " face " be bold ")))
-	  (italic-p	(y-or-n-p (concat "Should face " face " be italic ")))
-	  (underline-p	(y-or-n-p (concat "Should face " face " be underlined ")))
-	  (inverse-p	(y-or-n-p (concat "Should face " face " be inverse-video ")))
-	  (all-frames-p	(y-or-n-p (concat "Modify face " face " in all frames "))))
-     (message "Face %s: %s" face
-      (mapconcat 'identity
-       (delq nil
-	(list (if (equal foreground '(nil))
-		  " no foreground"
-		(and foreground (concat (downcase foreground) " foreground")))
-	      (if (equal background '(nil))
-		  " no background"
-		(and background (concat (downcase background) " background")))
-	      (if (equal stipple '(nil))
-		  " no stipple"
-		(and stipple (concat (downcase new-stipple-string) " stipple")))
-	      (and bold-p "bold") (and italic-p "italic")
-	      (and inverse-p "inverse")
-	      (and underline-p "underline"))) ", "))
-     (list (intern face) foreground background stipple
-	   bold-p italic-p underline-p inverse-p
-	   (if all-frames-p nil (selected-frame)))))
-  ;; Clear this before we install the new foreground and background;
-  ;; otherwise, clearing it after would swap them!
-  (when (and (or foreground background) (face-inverse-video-p face))
-    (set-face-inverse-video-p face nil frame)
-    ;; Arrange to restore it after, if we are not setting it now.
-    (or (memq inverse-p '(t nil))
-	(setq inverse-p t)))
-  (condition-case nil
-      (face-try-color-list 'set-face-foreground face foreground frame)
-    (error nil))
-  (condition-case nil
-      (face-try-color-list 'set-face-background face background frame)
-    (error nil))
-  (condition-case nil
-      (set-face-stipple face stipple frame)
-    (error nil))
-  ;; Now that we have the new colors, 
-  (if (memq inverse-p '(nil t))
-      (set-face-inverse-video-p face inverse-p frame))
-  (cond ((eq bold-p nil)
-	 (if (face-font face frame)
-	     (make-face-unbold face frame t)))
-	((eq bold-p t)
-	 (make-face-bold face frame t)))
-  (cond ((eq italic-p nil)
-	 (if (face-font face frame)
-	     (make-face-unitalic face frame t)))
-	((eq italic-p t) (make-face-italic face frame t)))
-  (if (memq underline-p '(nil t))
-      (set-face-underline-p face underline-p frame))
-  (and (interactive-p) (redraw-display)))
+
 
-;;;; Associating face names (symbols) with their face vectors.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Creation, copying.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defvar global-face-data nil
-  "Internal data for face support functions.  Not for external use.
-This is an alist associating face names with the default values for
-their parameters.  Newly created frames get their data from here.")
 
 (defun face-list ()
-  "Returns a list of all defined face names."
-  (mapcar 'car global-face-data))
+  "Return a list of all defined face names."
+  (mapcar #'car face-new-frame-defaults))
+
+
+;;; ### If not frame-local initialize by what X resources?
+
+(defun make-face (face &optional no-init-from-resources)
+  "Define a new face with name FACE, a symbol.
+NO-INIT-FROM-RESOURCES non-nil means don't initialize frame-local
+variants of FACE from X resources.  (X resources recognized are found
+in the global variable `face-x-resources'.)  If FACE is already known
+as a face, leave it unmodified.  Value is FACE."
+  (interactive "SMake face: ")
+  (unless (facep face)
+    ;; Make frame-local faces (this also makes the global one).
+    (dolist (frame (frame-list))
+      (internal-make-lisp-face face frame))
+    ;; Add the face to the face menu.
+    (when (fboundp 'facemenu-add-new-face)
+      (facemenu-add-new-face face))
+    ;; Define frame-local faces for all frames from X resources.
+    (unless no-init-from-resources
+      (make-face-x-resource-internal face)))
+  face)
+
+
+(defun make-empty-face (face)
+  "Define a new, empty face with name FACE.
+If the face already exists, it is left unmodified.  Value is FACE."
+  (interactive "SMake empty face: ")
+  (make-face face 'no-init-from-resources))
+
+
+(defun copy-face (old-face new-face &optional frame new-frame)
+  "Define a face just like OLD-FACE, with name NEW-FACE.
+
+If NEW-FACE already exists as a face, it is modified to be like
+OLD-FACE.  If it doesn't already exist, it is created.
+
+If the optional argument FRAME is given as a frame,  NEW-FACE is
+changed on FRAME only.
+If FRAME is t, the frame-independent default specification for OLD-FACE
+is copied to NEW-FACE.
+If FRAME is nil, copying is done for the frame-independent defaults
+and for each existing frame.
+
+If the optional fourth argument NEW-FRAME is given,
+copy the information from face OLD-FACE on frame FRAME
+to NEW-FACE on frame NEW-FRAME."
+  (let ((inhibit-quit t))
+    (if (null frame)
+	(progn
+	  (dolist (frame (frame-list))
+	    (copy-face old-face new-face frame))
+	  (copy-face old-face new-face t))
+      (internal-copy-lisp-face old-face new-face frame new-frame))
+    new-face))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Obsolete functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The functions in this section are defined because Lisp packages use
+;; them, despite the prefix `internal-' suggesting that they are
+;; private to the face implementation.  
 
 (defun internal-find-face (name &optional frame)
-  "Retrieve the face named NAME.  Return nil if there is no such face.
+  "Retrieve the face named NAME.
+Return nil if there is no such face.
 If the optional argument FRAME is given, this gets the face NAME for
 that frame; otherwise, it uses the selected frame.
 If FRAME is the symbol t, then the global, non-frame face is returned.
-If NAME is already a face, it is simply returned."
-  (if (and (eq frame t) (not (symbolp name)))
-      (setq name (face-name name)))
-  (if (symbolp name)
-      (cdr (assq name
-		 (if (eq frame t)
-		     global-face-data
-		   (frame-face-alist (or frame (selected-frame))))))
-    (internal-check-face name)
-    name))
+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."
+  (facep name))
+
 
 (defun internal-get-face (name &optional frame)
   "Retrieve the face named NAME; error if there is none.
 If the optional argument FRAME is given, this gets the face NAME for
 that frame; otherwise, it uses the selected frame.
 If FRAME is the symbol t, then the global, non-frame face is returned.
-If NAME is already a face, it is simply returned."
+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)
-      (internal-check-face name)))
+      (check-face name)))
 
 
-(defun internal-set-face-1 (face name value index frame)
-  (let ((inhibit-quit t))
-    (if (null frame)
-	(let ((frames (frame-list)))
-	  (while frames
-	    (internal-set-face-1 (face-name face) name value index (car frames))
-	    (setq frames (cdr frames)))
-	  (aset (internal-get-face (if (symbolp face) face (face-name face)) t)
-		index value)
-	  value)
-      (let ((internal-face (internal-get-face face frame)))
-	(or (eq frame t)
-	    (if (eq name 'inverse-video)
-		(or (eq value (aref internal-face index))
-		    (invert-face face frame))
-	      (and name (fboundp 'set-face-attribute-internal)
-		   (set-face-attribute-internal (face-id face)
-						name value frame))))
-	(aset internal-face index value)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Predicates, type checks.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun facep (face)
+  "Return non-nil if FACE is a face name."
+  (internal-lisp-face-p face))
+
+
+(defun check-face (face)
+  "Signal an error if FACE doesn't name a face.
+Value is FACE."
+  (unless (facep face)
+    (error "Not a face: %s" face))
+  face)
 
 
-(defun read-face-name (prompt)
-  (let (face)
-    (while (= (length face) 0)
-      (setq face (completing-read prompt
-				  (mapcar '(lambda (x) (list (symbol-name x)))
-					  (face-list))
-				  nil t)))
-    (intern face)))
-
-(defun internal-face-interactive (what &optional bool)
-  (let* ((fn (intern (concat "face-" what)))
-	 (prompt (concat "Set " what " of face"))
-	 (face (read-face-name (concat prompt ": ")))
-	 (default (if (fboundp fn)
-		      (or (funcall fn face (selected-frame))
-			  (funcall fn 'default (selected-frame)))))
-	 value)
-    (setq value
-	  (cond ((eq bool 'color)
-		 (completing-read (concat prompt " " (symbol-name face) " to: ")
-				  (mapcar (function (lambda (color)
-						      (cons color color)))
-					  x-colors)
-				  nil nil nil nil default))
-		(bool
-		 (y-or-n-p (concat "Should face " (symbol-name face)
-				   " be " bool "? ")))
-		(t
-		 (read-string (concat prompt " " (symbol-name face) " to: ")
-			      nil nil default))))
-    (list face (if (equal value "") nil value))))
-
-(defun internal-face-interactive-stipple (what)
-  (let* ((fn (intern (concat "face-" what)))
-	 (prompt (concat "Set " what " of face"))
-	 (face (read-face-name (concat prompt ": ")))
-	 (default (if (fboundp fn)
-		      (or (funcall fn face (selected-frame))
-			  (funcall fn 'default (selected-frame)))))
-	 ;; If the stipple value is a list (WIDTH HEIGHT DATA),
-	 ;; represent that as a string by printing it out.
-	 (old-stipple-string
-	  (if (stringp (face-stipple face))
-	      (face-stipple face)
-	    (if (null (face-stipple face))
-		nil
-	      (prin1-to-string (face-stipple face)))))
-	 (new-stipple-string
-	  (read-string
-	   (concat prompt " " (symbol-name face) " to: ")
-	   old-stipple-string))
-	 ;; Convert the stipple value text we read
-	 ;; back to a list if it looks like one.
-	 ;; This makes the assumption that a pixmap file name
-	 ;; won't start with an open-paren.
-	 (stipple
-	  (if (string-match "^(" new-stipple-string)
-	      (read new-stipple-string)
-	    new-stipple-string)))
-    (list face (if (equal stipple "") nil stipple))))
-
-(defun make-face (name &optional no-resources)
-  "Define a new FACE on all frames.  
-You can modify the font, color, etc of this face with the set-face- functions.
-If NO-RESOURCES is non-nil, then we ignore X resources
-and always make a face whose attributes are all nil.
-
-If the face already exists, it is unmodified."
-  (interactive "SMake face: ")
-  (or (internal-find-face name)
-      (let ((face (make-vector 12 nil)))
-	(aset face 0 'face)
-	(aset face 1 name)
-	(let* ((frames (frame-list))
-	       (inhibit-quit t)
-	       (id (internal-next-face-id)))
-	  (if (fboundp 'make-face-internal)
-	      (make-face-internal id))
-	  (aset face 2 id)
-	  (while frames
-	    (set-frame-face-alist (car frames)
-				  (cons (cons name (copy-sequence face))
-					(frame-face-alist (car frames))))
-	    (setq frames (cdr frames)))
-	  (setq global-face-data (cons (cons name face) global-face-data)))
-	;; When making a face after frames already exist
-	(or no-resources
-	    (if (memq window-system '(x w32))
-		(make-face-x-resource-internal face)))
-	;; Add to menu of faces.
-	(if (fboundp 'facemenu-add-new-face)
-	    (facemenu-add-new-face name))
-	face))
-  name)
-
-(defun make-empty-face (face)
-  "Define a new FACE on all frames, which initially reflects the defaults.
-You can modify the font, color, etc of this face with the set-face- functions.
-If the face already exists, it is unmodified."
-  (interactive "SMake empty face: ")
-  (make-face face t))
+;; The ID returned is not to be confused with the internally used IDs
+;; of realized faces.  The ID assigned to Lisp faces is used to
+;; support faces in display table entries.
 
-;; Fill in a face by default based on X resources, for all existing frames.
-;; This has to be done when a new face is made.
-(defun make-face-x-resource-internal (face &optional frame set-anyway)
-  (cond ((null frame)
-	 (let ((frames (frame-list)))
-	   (while frames
-	     (if (memq (framep (car frames)) '(x w32))
-		 (make-face-x-resource-internal (face-name face)
-						(car frames) set-anyway))
-	     (setq frames (cdr frames)))))
-	(t
-	 (setq face (internal-get-face (face-name face) frame))
-	 ;;
-	 ;; These are things like "attributeForeground" instead of simply
-	 ;; "foreground" because people tend to do things like "*foreground",
-	 ;; which would cause all faces to be fully qualified, making faces
-	 ;; inherit attributes in a non-useful way.  So we've made them slightly
-	 ;; less obvious to specify in order to make them work correctly in
-	 ;; more random environments.
-	 ;;
-	 ;; I think these should be called "face.faceForeground" instead of
-	 ;; "face.attributeForeground", but they're the way they are for
-	 ;; hysterical reasons.
-	 ;; 
-	 (let* ((name (symbol-name (face-name face)))
-		(fn  (or (x-get-resource (concat name ".attributeFont")
-					 "Face.AttributeFont")
-			 (and set-anyway (face-font face))))
-		(fg  (or (x-get-resource (concat name ".attributeForeground")
-					 "Face.AttributeForeground")
-			 (and set-anyway (face-foreground face))))
-		(bg  (or (x-get-resource (concat name ".attributeBackground")
-					 "Face.AttributeBackground")
-			 (and set-anyway (face-background face))))
-		(bgp (or (x-get-resource (concat name ".attributeStipple")
-					 "Face.AttributeStipple")
-			 (x-get-resource (concat name ".attributeBackgroundPixmap")
-					 "Face.AttributeBackgroundPixmap")
-			 (and set-anyway (face-stipple face))))
-		(ulp (let ((resource (x-get-resource
-				      (concat name ".attributeUnderline")
-				      "Face.AttributeUnderline")))
-		       (if resource
-			   (member (downcase resource) '("on" "true"))
-			 (and set-anyway (face-underline-p face)))))
-		)
-	   (if fn
-	       (condition-case ()
-		   (cond ((string= fn "italic")
-			  (make-face-italic face))
-			 ((string= fn "bold")
-			  (make-face-bold face))
-			 ((string= fn "bold-italic")
-			  (make-face-bold-italic face))
-			 (t
-			  (set-face-font face fn frame)))
-		 (error
-		  (if (member fn '("italic" "bold" "bold-italic"))
-		      (message "no %s version found for face `%s'" fn name)
-		    (message "font `%s' not found for face `%s'" fn name)))))
-	   (if fg
-	       (condition-case ()
-		   (set-face-foreground face fg frame)
-		 (error (message "color `%s' not allocated for face `%s'" fg name))))
-	   (if bg
-	       (condition-case ()
-		   (set-face-background face bg frame)
-		 (error (message "color `%s' not allocated for face `%s'" bg name))))
-	   (if bgp
-	       (condition-case ()
-		   (set-face-stipple face bgp frame)
-		 (error (message "pixmap `%s' not found for face `%s'" bgp name))))
-	   (if (or ulp set-anyway)
-	       (set-face-underline-p face ulp frame))
-	   )))
-  face)
+(defun face-id (face &optional frame)
+  "Return the interNal ID of face with name FACE.
+If optional argument FRAME is nil or omitted, use the selected frame."
+  (check-face face)
+  (get face 'face))
 
-(defun copy-face (old-face new-face &optional frame new-frame)
-  "Define a face just like OLD-FACE, with name NEW-FACE.
-If NEW-FACE already exists as a face, it is modified to be like OLD-FACE.
-If it doesn't already exist, it is created.
-
-If the optional argument FRAME is given as a frame,
-NEW-FACE is changed on FRAME only.
-If FRAME is t, the frame-independent default specification for OLD-FACE
-is copied to NEW-FACE.
-If FRAME is nil, copying is done for the frame-independent defaults
-and for each existing frame.
-If the optional fourth argument NEW-FRAME is given, 
-copy the information from face OLD-FACE on frame FRAME
-to NEW-FACE on frame NEW-FRAME."
-  (or new-frame (setq new-frame frame))
-  (let ((inhibit-quit t))
-    (if (null frame)
-	(let ((frames (frame-list)))
-	  (while frames
-	    (copy-face old-face new-face (car frames))
-	    (setq frames (cdr frames)))
-	  (copy-face old-face new-face t))
-      (setq old-face (internal-get-face old-face frame))
-      (setq new-face (or (internal-find-face new-face new-frame)
-			 (make-face new-face)))
-      (condition-case nil
-	  ;; A face that has a global symbolic font modifier such as `bold'
-	  ;; might legitimately get an error here.
-	  ;; Use the frame's default font in that case.
-	  (set-face-font new-face (face-font old-face frame) new-frame)
-	(error
-	 (set-face-font new-face nil new-frame)))
-      (set-face-font-explicit new-face (face-font-explicit old-face frame)
-			      new-frame)
-      (set-face-foreground new-face (face-foreground old-face frame) new-frame)
-      (set-face-background new-face (face-background old-face frame) new-frame)
-      (set-face-stipple new-face
-			(face-stipple old-face frame)
-			new-frame)
-      (set-face-underline-p new-face (face-underline-p old-face frame)
-			    new-frame))
-    new-face))
 
 (defun face-equal (face1 face2 &optional frame)
-  "True if the faces FACE1 and FACE2 display in the same way."
-  (setq face1 (internal-get-face face1 frame)
-	face2 (internal-get-face face2 frame))
-  (and (equal (face-foreground face1 frame) (face-foreground face2 frame))
-       (equal (face-background face1 frame) (face-background face2 frame))
-       (equal (face-font face1 frame) (face-font face2 frame))
-       (eq (face-underline-p face1 frame) (face-underline-p face2 frame))
-       (equal (face-stipple face1 frame)
-	      (face-stipple face2 frame))))
+  "Non-nil if faces FACE1 and FACE2 are equal.
+Faces are considered equal if all their attributes are equal.
+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-lisp-face-equal-p face1 face2 frame))
+
 
 (defun face-differs-from-default-p (face &optional frame)
-  "True if face FACE displays differently from the default face, on FRAME.
-A face is considered to be ``the same'' as the default face if it is 
-actually specified in the same way (equivalent fonts, etc) or if it is 
-fully unspecified, and thus inherits the attributes of any face it 
-is displayed on top of.
+  "Non-nil if FACE displays differently from the default face.
+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.
+A face is considered to be ``the same'' as the default face if it is
+actually specified in the same way (equal attributes) or if it is
+fully-unspecified, and thus inherits the attributes of any face it
+is displayed on top of."
+  (or (internal-lisp-face-empty-p face frame)
+      (not (internal-lisp-face-equal-p face 'default frame))))
 
-The optional argument FRAME specifies which frame to test;
-if FRAME is t, test the default for new frames.
-If FRAME is nil or omitted, test the selected frame."
-  (let ((default (internal-get-face 'default frame)))
-    (setq face (internal-get-face face frame))
-    (not (and (or (equal (face-foreground default frame)
-			 (face-foreground face frame))
-		  (null (face-foreground face frame)))
-	      (or (equal (face-background default frame)
-			 (face-background face frame))
-		  (null (face-background face frame)))
-	      (or (null (face-font face frame))
-		  (equal (face-font face frame)
-			 (or (face-font default frame)
-			     (downcase
-			      (cdr (assq 'font (frame-parameters frame)))))))
-	      (or (equal (face-stipple default frame)
-			 (face-stipple face frame))
-		  (null (face-stipple face frame)))
-	      (equal (face-underline-p default frame)
-		     (face-underline-p face frame))
-	      ))))
 
 (defun face-nontrivial-p (face &optional frame)
   "True if face FACE has some non-nil attribute.
-The optional argument FRAME specifies which frame to test;
-if FRAME is t, test the default for new frames.
-If FRAME is nil or omitted, test the selected frame."
-  (setq face (internal-get-face face frame))
-  (or (face-foreground face frame)
-      (face-background face frame)
-      (face-font face frame)
-      (face-stipple face frame)
-      (face-underline-p face 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."
+  (not (internal-lisp-face-empty-p face frame)))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Setting face attributes from X resources.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defcustom face-x-resources
+  '((:family (".attributeFamily" . "Face.AttributeFamily"))
+    (:width (".attributeWidth" . "Face.AttributeWidth"))
+    (:height (".attributeHeight" . "Face.AttributeHeight"))
+    (:weight (".attributeWeight" . "Face.AttributeWeight"))
+    (:slant (".attributeSlant" . "Face.AttributeSlant"))
+    (:foreground (".attributeForeground" . "Face.AttributeForeground"))
+    (:background (".attributeBackground" . "Face.AttributeBackground"))
+    (:overline (".attributeOverline" . "Face.AttributeOverline"))
+    (:strike-through (".attributeStrikeThrough" . "Face.AttributeStrikeThrough"))
+    (:box (".attributeBox" . "Face.AttributeBox"))
+    (:underline (".attributeUnderline" . "Face.AttributeUnderline"))
+    (:inverse-video (".attributeInverse" . "Face.AttributeInverse"))
+    (:stipple
+     (".attributeStipple" . "Face.AttributeStipple")
+     (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap"))
+    (:font (".attributeFont" . "Face.AttributeFont"))
+    (:bold (".attributeBold" . "Face.AttributeBold"))
+    (:italic (".attributeItalic" . "Face.AttributeItalic"))
+    (:font (".attributeFont" . "Face.AttributeFont")))
+  "*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
+X resource class for the attribute."
+  :type 'sexp
+  :group 'faces)
+
+
+(defun set-face-attribute-from-resource (face attribute resource class frame)
+  "Set FACE's ATTRIBUTE from X resource RESOURCE, class CLASS on FRAME.
+Value is the attribute value specified by the resource, or nil
+if not present.  This function displays a message if the resource
+specifies an invalid attribute."
+  (let* ((face-name (face-name face))
+	 (value (internal-face-x-get-resource (concat face-name resource)
+					      class frame)))
+    (when value
+      (condition-case ()
+	  (internal-set-lisp-face-attribute-from-resource
+	   face attribute (downcase value) frame)
+	(error
+	 (message "Face %s, frame %s: invalid attribute %s %s from X resource"
+		  face-name frame attribute value))))
+    value))
+
+
+(defun set-face-attributes-from-resources (face frame)
+  "Set attributes of FACE from X resources for FRAME."
+  (when (memq (framep frame) '(x w32))
+    (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."
+  (if (null frame)
+      (dolist (frame (frame-list))
+	(set-face-attributes-from-resources face frame))
+    (set-face-attributes-from-resources face frame)))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Retrieving face attributes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun face-name (face)
+  "Return the name of face FACE."
+  (symbol-name (check-face face)))
+
+
+(defun face-attribute (face attribute &optional frame)
+  "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))
+
+
+(defun face-foreground (face &optional frame)
+  "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))
+
+
+(defun face-background (face &optional frame)
+  "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))
+
+
+(defun face-stipple (face &optional frame)
+ "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))
+
+
+(defalias 'face-background-pixmap 'face-stipple)
+
+
+(defun face-underline-p (face &optional frame)
+ "Return non-nil if FACE is underlined.
+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."
+ (eq (face-attribute face :underline frame) t))
+
+
+(defun face-inverse-video-p (face &optional frame)
+ "Return non-nil if FACE is in inverse video 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."
+ (eq (face-attribute face :inverse-video frame) t))
+
+
+(defun face-bold-p (face &optional frame)
+  "Return non-nil if the font of FACE is bold 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.
+Use `face-attribute' for finer control."
+  (let ((bold (face-attribute face :weight frame)))
+    (not (memq bold '(normal unspecified)))))
+
+
+(defun face-italic-p (face &optional frame)
+  "Return non-nil if the font of FACE is italic 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.
+Use `face-attribute' for finer control."
+  (let ((italic (face-attribute face :slant frame)))
+    (not (memq italic '(normal unspecified)))))
+    
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Face documentation.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun face-documentation (face)
+  "Get the documentation string for FACE."
+  (get face 'face-documentation))
+
+
+(defun set-face-documentation (face string)
+  "Set the documentation string for FACE to STRING."
+  (put face 'face-documentation string))
+
+
+(defalias 'face-doc-string 'face-documentation)
+(defalias 'set-face-doc-string 'set-face-documentation)
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Setting face attributes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defun set-face-attribute (face frame &rest args)
+  "Set attributes of FACE on FRAME from ARGS.
+
+FRAME nil means change attributes on all frames.  FRAME t means change
+the default for new frames (this is done automatically each time an
+attribute is changed on all frames).
+
+ARGS must come in pairs ATTRIBUTE VALUE.  ATTRIBUTE must be a valid
+face attribute name.  All attributes can be set to `unspecified';
+this fact is not further mentioned below.
+
+The following attributes are recognized:
+
+`:family'
+
+VALUE must be a string specifying the font family, e.g. ``courier'',
+or a fontset alias name.  If a font family is specified, wild-cards `*'
+and `?' are allowed.
+
+`:width'
+
+VALUE specifies the relative proportionate width of the font to use.
+It must be one of the symbols `ultra-condensed', `extra-condensed',
+`condensed', `semi-condensed', `normal', `semi-expanded', `expanded',
+`extra-expanded', or `ultra-expanded'.
+
+`:height'
+
+VALUE must be an integer specifying the height of the font to use in
+1/10 pt.
+
+`:weight'
+
+VALUE specifies the weight of the font to use.  It must be one of the
+symbols `ultra-bold', `extra-bold', `bold', `semi-bold', `normal',
+`semi-light', `light', `extra-light', `ultra-light'.
+
+`:slant'
+
+VALUE specifies the slant of the font to use.  It must be one of the
+symbols `italic', `oblique', `normal', `reverse-italic', or
+`reverse-oblique'.
+
+`:foreground', `:background'
+
+VALUE must be a color name, a string.
+
+`:underline'
+
+VALUE specifies whether characters in FACE should be underlined.  If
+VALUE is t, underline with foreground color of the face.  If VALUE is
+a string, underline with that color.  If VALUE is nil, explicitly
+don't underline.
+
+`:overline'
+
+VALUE specifies whether characters in FACE should be overlined.  If
+VALUE is t, overline with foreground color of the face.  If VALUE is a
+string, overline with that color.  If VALUE is nil, explicitly don't
+overline.
+
+`:strike-through'
+
+VALUE specifies whether characters in FACE should be drawn with a line
+striking through them.  If VALUE is t, use the foreground color of the
+face.  If VALUE is a string, strike-through with that color.  If VALUE
+is nil, explicitly don't strike through.
+
+`:box'
+
+VALUE specifies whether characters in FACE should have a box drawn
+around them.  If VALUE is nil, explicitly don't draw boxes.  If
+VALUE is t, draw a box with lines of width 1 in the foreground color
+of the face.  If VALUE is a string, the string must be a color name,
+and the box is drawn in that color with a line width of 1.  Otherwise,
+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
+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
+like a released 3D button.  If STYLE is `pressed-button' draw a box
+that appears like a pressed button.  If STYLE is nil, the default if
+the property list doesn't contain a style specification, draw a 2D
+box.
+
+`:inverse-video'
+
+VALUE specifies whether characters in FACE should be displayed in
+inverse video. VALUE must be one of t or nil.
+
+`:stipple'
+
+If VALUE is a string, it must be the name of a file of pixmap data.
+The directories listed in the `x-bitmap-file-path' variable are
+searched.  Alternatively, VALUE 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.  VALUE nil means
+explicitly don't use a stipple pattern.
+
+For convenience, attributes `:family', `:width', `:height', `:weight',
+and `:slant' may also be set in one step from an X font name:
+
+`:font'
+
+Set font-related face attributes from VALUE.  VALUE must be a valid
+XLFD font name.  If it is a font name pattern, the first matching font
+will be used.
+
+For compatibility with Emacs 20, keywords `:bold' and `:italic' can
+be used to specify that a bold or italic font should be used.  VALUE
+must be t or nil in that case.  A value of `unspecified' is not allowed."
+  (cond ((null frame)
+	 ;; Change face on all frames.
+	 (dolist (frame (frame-list))
+	   (apply #'set-face-attribute face frame args))
+	 ;; Record that as a default for new frames.
+	 (apply #'set-face-attribute face t args))
+	(t
+	 (while args
+	   (internal-set-lisp-face-attribute face (car args)
+					     (car (cdr args)) frame)
+	   (setq args (cdr (cdr args)))))))
+
+
+(defun make-face-bold (face &optional frame)
+  "Make the font of FACE be bold, if possible.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' for finer control of the font weight."
+  (interactive (list (read-face-name "Make which face bold: ")))
+  (set-face-attribute face frame :weight 'bold))
+
+
+(defun make-face-unbold (face &optional frame)
+  "Make the font of FACE be non-bold, if possible.
+FRAME nil or not specified means change face on all frames."
+  (interactive (list (read-face-name "Make which face non-bold: ")))
+  (set-face-attribute face frame :weight 'normal))
+
+  
+(defun make-face-italic (face &optional frame)
+  "Make the font of FACE be italic, if possible.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' for finer control of the font slant."
+  (interactive (list (read-face-name "Make which face italic: ")))
+  (set-face-attribute face frame :slant 'italic))
+
+
+(defun make-face-unitalic (face &optional frame)
+  "Make the font of FACE be non-italic, if possible.
+FRAME nil or not specified means change face on all frames."
+  (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)
+  "Make the font of FACE be bold and italic, if possible.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' for finer control of font weight and slant."
+  (interactive (list (read-face-name "Make which face bold-italic: ")))
+  (set-face-attribute face frame :weight 'bold :slant 'italic))
+
+
+(defun set-face-font (face font &optional frame)
+  "Change font-related attributes of FACE to those of FONT (a string).
+FRAME nil or not specified means change face on all frames.
+This sets the attributes `:family', `:width', `:height', `:weight',
+and `:slant'.  When called interactively, prompt for the face and font."
+  (interactive (read-face-and-attribute :font))
+  (set-face-attribute face frame :font font))
+
+
+;; Implementation note: Emulating gray background colors with a
+;; stipple pattern is now part of the face realization process, and is
+;; done in C depending on the frame on which the face is realized.
+
+(defun set-face-background (face color &optional frame)
+  "Change the background color of face FACE to COLOR (a string).
+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))
+
+
+(defun set-face-foreground (face color &optional frame)
+  "Change the foreground color of face FACE to COLOR (a string).
+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))
+
+
+(defun set-face-stipple (face stipple &optional frame)
+  "Change the stipple pixmap of face FACE to STIPPLE.
+FRAME nil or not specified means change face on all frames.
+STIPPLE. should be a string, the name of a file of pixmap data.
+The directories listed in the `x-bitmap-file-path' variable are searched.
+
+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))
+
+
+(defun set-face-underline (face underline &optional frame)
+  "Specify whether face FACE is underlined.
+UNDERLINE nil means FACE explicitly doesn't underline.
+UNDERLINE non-nil means FACE explicitly does underlining
+with the same of the foreground color.
+If UNDERLINE is a string, underline with the color named UNDERLINE.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' to ``unspecify'' underlining."
+  (interactive
+   (let ((list (read-face-and-attribute :underline)))
+     (list (car list) (eq (car (cdr list)) t))))
+  (set-face-attribute face frame :underline underline))
+
+
+(defun set-face-underline-p (face underline-p &optional frame)
+  "Specify whether face FACE is underlined.
+UNDERLINE-P nil means FACE explicitly doesn't underline.
+UNDERLINE-P non-nil means FACE explicitly does underlining.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' to ``unspecify'' underlining."
+  (interactive
+   (let ((list (read-face-and-attribute :underline)))
+     (list (car list) (eq (car (cdr list)) t))))
+  (set-face-attribute face frame :underline underline-p))
+
+
+(defun set-face-inverse-video-p (face inverse-video-p &optional frame)
+  "Specify whether face FACE is in inverse video.
+INVERSE-VIDEO-P non-nil means FACE displays explicitly in inverse video.
+INVERSE-VIDEO-P nil means FACE explicitly is not in inverse video.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' to ``unspecify'' the inverse video attribute."
+  (interactive
+   (let ((list (read-face-and-attribute :inverse-video)))
+     (list (car list) (eq (car (cdr list)) t))))
+  (set-face-attribute face frame :inverse-video inverse-video-p))
+
+
+(defun set-face-bold-p (face bold-p &optional frame)
+  "Specify whether face FACE is bold.
+BOLD-P non-nil means FACE should explicitly display bold.
+BOLD-P nil means FACE should explicitly display non-bold.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' or `modify-face' for finer control."
+  (if (null bold-p)
+      (make-face-unbold face frame)
+    (make-face-bold face frame)))
+
+
+(defun set-face-italic-p (face italic-p &optional frame)
+  "Specify whether face FACE is italic.
+ITALIC-P non-nil means FACE should explicitly display italic.
+ITALIC-P nil means FACE should explicitly display non-italic.
+FRAME nil or not specified means change face on all frames.
+Use `set-face-attribute' or `modify-face' for finer control."
+  (if (null italic-p)
+      (make-face-unitalic face frame)
+    (make-face-italic face frame)))
+
+
+(defalias 'set-face-background-pixmap 'set-face-stipple)
 
 
 (defun invert-face (face &optional frame)
-  "Swap the foreground and background colors of face FACE.
-If the face doesn't specify both foreground and background, then
-set its foreground and background to the default background and foreground."
+  "Swap the foreground and background colors of FACE.
+FRAME nil or not specified 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: ")))
-  (setq face (internal-get-face face frame))
-  (let ((fg (face-foreground face frame))
-	(bg (face-background face frame)))
+  (let ((fg (face-attribute face :foreground frame))
+	(bg (face-attribute face :background frame)))
     (if (or fg bg)
-	(progn
-	  (set-face-foreground face bg frame)
-	  (set-face-background face fg frame))
-      (let* ((frame-bg (cdr (assq 'background-color (frame-parameters frame))))
-	     (default-bg (or (face-background 'default frame)
-			     frame-bg))
-	     (frame-fg (cdr (assq 'foreground-color (frame-parameters frame))))
-	     (default-fg (or (face-foreground 'default frame)
-			     frame-fg)))
-	(set-face-foreground face default-bg frame)
-	(set-face-background face default-fg frame))))
+	(set-face-attribute face frame :foreground bg :background fg)
+      (set-face-attribute face frame
+			  :foreground
+			  (face-attribute 'default :background frame)
+			  :background
+			  (face-attribute 'default :foreground frame))))
   face)
 
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Interactively modifying faces.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defun internal-try-face-font (face font &optional frame)
-  "Like set-face-font, but returns nil on failure instead of an error."
-  (condition-case ()
-      (set-face-font-auto face font frame)
-    (error nil)))
+(defun read-face-name (prompt)
+  "Read and return a face symbol, prompting with PROMPT.
+Value is a symbol naming a known face."
+  (let ((face-list (mapcar #'(lambda (x) (cons (symbol-name x) x))
+			   (face-list)))
+	face)
+    (while (equal "" (setq face (completing-read prompt face-list nil t))))
+    (intern face)))
+
+
+(defun face-valid-attribute-values (attribute &optional frame)
+  "Return valid values for face attribute ATTRIBUTE.
+The optional argument FRAME is used to determine available fonts
+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."
+  (case attribute
+    (:family
+     (if window-system
+	 (mapcar #'(lambda (x) (cons (car x) (car x)))
+		 (x-font-family-list))
+       ;; Only one font on TTYs.
+       (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))
+	     (or (and window-system (x-defined-colors frame))
+		 (tty-defined-colors))))
+    ((:height)
+     'integerp)
+    (:stipple
+     (and window-system
+	  (mapcar #'list
+		  (apply #'nconc (mapcar #'directory-files
+					 x-bitmap-file-path)))))
+    (t
+     (error "Internal error"))))
+
+
+(defvar face-attribute-name-alist
+  '((:family . "font family")
+    (:width . "character set width")
+    (:height . "height in 1/10 pt")
+    (:weight . "weight")
+    (:slant . "slant")
+    (:underline . "underline")
+    (:overline . "overline")
+    (:strike-through . "strike-through")
+    (:box . "box")
+    (:inverse-video . "inverse-video display")
+    (:foreground . "foreground color")
+    (:background . "background color")
+    (:stipple . "background stipple"))
+  "An alist of descriptive names for face attributes.
+Each element has the form (ATTRIBUTE-NAME . DESCRIPTION) where
+ATTRIBUTE-NAME is a face attribute name (a keyword symbol), and
+DESCRIPTION is a descriptive name for ATTRIBUTE-NAME.")
+
+
+(defun face-descriptive-attribute-name (attribute)
+  "Return a descriptive name for ATTRIBUTE."
+  (cdr (assq attribute face-attribute-name-alist)))
+
+
+(defun face-read-string (face default name &optional completion-alist)
+  "Interactively read a face attribute string value.
+FACE is the face whose attribute is read.  DEFAULT is the default
+value to return if no new value is entered.  NAME is a descriptive
+name of the attribute for prompting.  COMPLETION-ALIST is an alist
+of valid values, if non-nil.
+
+Entering ``none'' as attribute value means an unspecified attribute
+value.  Entering nothing accepts the default value DEFAULT.
+
+Value is the new attribute value."
+  (let* ((completion-ignore-case t)
+	 (value (completing-read
+		 (if default
+		     (format "Set face %s %s (default %s): "
+			     face name (downcase (if (symbolp default)
+						     (symbol-name default)
+						   default)))
+		   (format "Set face %s %s: " face name))
+		 completion-alist)))
+    (if (equal value "none")
+	nil
+      (if (equal value "") default value))))
+
+
+(defun face-read-integer (face default name)
+  "Interactively read an integer face attribute value.
+FACE is the face whose attribute is read.  DEFAULT is the default
+value to return if no new value is entered.  NAME is a descriptive
+name of the attribute for prompting.  Value is the new attribute value."
+  (let ((new-value (face-read-string face
+				     (and default (int-to-string default))
+				     name)))
+    (and new-value
+	 (string-to-int new-value))))
+
+
+(defun read-face-attribute (face attribute &optional frame)
+  "Interactively read a new value for FACE's ATTRIBUTE.
+Optional argument FRAME nil or unspecified means read an attribute value
+of a global face.  Value is the new attribute value."
+  (let* ((old-value (face-attribute face attribute frame))
+	 (attribute-name (face-descriptive-attribute-name attribute))
+	 (valid (face-valid-attribute-values attribute frame))
+	 new-value)
+    ;; Represent complex attribute values as strings by printing them
+    ;; out.  Stipple can be a vector; (WIDTH HEIGHT DATA).  Box can be
+    ;; a list `(:width WIDTH :color COLOR)' or `(:width WIDTH :shadow
+    ;; SHADOW)'.
+    (when (and (or (eq attribute :stipple)
+		   (eq attribute :box))
+	       (or (consp old-value)
+		   (vectorp old-value)))
+      (setq old-value (prin1-to-string old-value)))
+    (cond ((listp valid)
+	   (setq new-value
+		 (cdr (assoc (face-read-string face old-value
+					       attribute-name valid)
+			     valid))))
+	  ((eq valid 'integerp)
+	   (setq new-value (face-read-integer face old-value attribute-name)))
+	  (t (error "Internal error")))
+    ;; Convert stipple and box value text we read back to a list or
+    ;; vector if it looks like one.  This makes the assumption that a
+    ;; pixmap file name won't start with an open-paren.
+    (when (and (or (eq attribute :stipple)
+		   (eq attribute :box))
+	       (stringp new-value)
+	       (string-match "^[[(]" new-value))
+      (setq new-value (read new-value)))
+    new-value))
+
+
+(defun read-face-font (face &optional frame)
+  "Read the name of a font for FACE on FRAME.
+If optional argument FRAME Is nil or omitted, use the selected frame."
+  (let ((completion-ignore-case t))
+    (completing-read "Set font attributes of face %s from font: "
+		     face (x-list-fonts "*" nil frame))))
+
+
+(defun read-all-face-attributes (face &optional frame)
+  "Interactively read all attributes for FACE.
+If optional argument FRAME Is nil or omitted, use the selected frame.
+Value is a property list of attribute names and new values."
+  (let (result)
+    (dolist (attribute face-attribute-name-alist result)
+      (setq result (cons (car attribute)
+			 (cons (read-face-attribute face (car attribute) frame)
+			       result))))))
+
+    
+(defun modify-face (&optional 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."
+  (interactive)
+  (let ((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."
+  (cond ((eq attribute :font)
+	 (let* ((prompt (format "Set font-related attributes of face: "))
+		(face (read-face-name prompt))
+		(font (read-face-font face frame)))
+	   (list face font)))
+	(t
+	 (let* ((attribute-name (face-descriptive-attribute-name attribute))
+		(prompt (format "Set %s of face: " attribute-name))
+		(face (read-face-name prompt))
+		(new-value (read-face-attribute face attribute frame)))
+	   (list face new-value)))))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Listing faces.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar list-faces-sample-text
+  "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "*Text string to display as the sample text for `list-faces-display'.")
+
+
+;; The name list-faces would be more consistent, but let's avoid a
+;; conflict with Lucid, which uses that name differently.
+
+(defun list-faces-display ()
+  "List all faces, using the same sample text in each.
+The sample text is a string that comes from the variable
+`list-faces-sample-text'."
+  (interactive)
+  (let ((faces (sort (face-list) #'string-lessp))
+	(face nil)
+	(frame (selected-frame))
+	disp-frame window)
+    (with-output-to-temp-buffer "*Faces*"
+      (save-excursion
+	(set-buffer standard-output)
+	(setq truncate-lines t)
+	(while faces
+	  (setq face (car faces))
+	  (setq faces (cdr faces))
+	  (insert (format "%25s " (face-name face)))
+	  (let ((beg (point)))
+	    (insert list-faces-sample-text)
+	    (insert "\n")
+	    (put-text-property beg (1- (point)) 'face face)
+	    ;; If the sample text has multiple lines, line up all of them.
+	    (goto-char beg)
+	    (forward-line 1)
+	    (while (not (eobp))
+	      (insert "                          ")
+	      (forward-line 1))))
+	(goto-char (point-min)))
+      (print-help-return-message))
+    ;; If the *Faces* buffer appears in a different frame,
+    ;; copy all the face definitions from FRAME,
+    ;; so that the display will reflect the frame that was selected.
+    (setq window (get-buffer-window (get-buffer "*Faces*") t))
+    (setq disp-frame (if window (window-frame window)
+		       (car (frame-list))))
+    (or (eq frame disp-frame)
+	(let ((faces (face-list)))
+	  (while faces
+	    (copy-face (car faces) (car faces) frame disp-frame)
+	    (setq faces (cdr faces)))))))
+
+
+(defun describe-face (face &optional frame)
+  "Display the properties of face FACE 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."
+  (interactive (list (read-face-name "Describe face: ")))
+  (let* ((attrs '((:family . "Family")
+		  (:width . "Width")
+		  (:height . "Height")
+		  (:weight . "Weight")
+		  (:slant . "Slant")
+		  (:foreground . "Foreground")
+		  (:background . "Background")
+		  (:underline . "Underline")
+		  (:overline . "Overline")
+		  (:strike-through . "Strike-through")
+		  (:box . "Box")
+		  (:inverse-video . "Inverse")
+		  (:stipple . "Stipple")))
+	(max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x)))
+					attrs))))
+    (with-output-to-temp-buffer "*Help*"
+      (save-excursion
+	(set-buffer standard-output)
+	(dolist (a attrs)
+	  (let ((attr (face-attribute face (car a) frame)))
+	    (insert (make-string (- max-width (length (cdr a))) ?\ )
+		    (cdr a) ": " (format "%s" attr) "\n")))
+	(insert "\nDocumentation:\n\n"
+		(or (face-documentation face)
+		    "not documented as a face.")))
+      (print-help-return-message))))
+  
+
+
 
-;; Manipulating font names.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Face specifications (defface).
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Parameter FRAME Is kept for call compatibility to with previous
+;; face implementation.
+
+(defun face-attr-construct (face &optional frame)
+  "Return a defface-style attribute list for FACE on FRAME.
+Value is a property list of pairs ATTRIBUTE VALUE for all specified
+face attributes of FACE where ATTRIBUTE is the attribute name and
+VALUE is the specified value of that attribute."
+  (let (result)
+    (dolist (entry face-attribute-name-alist result)
+      (let* ((attribute (car entry))
+	     (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.
+DISPLAY is part of a spec such as can be used in `defface'.
+If FRAME is nil, the current FRAME is used."
+  (let* ((conjuncts display)
+	 conjunct req options
+	 ;; t means we have succeeded against all the conjuncts in
+	 ;; DISPLAY that have been tested so far.
+	 (match t))
+    (if (eq conjuncts t)
+	(setq conjuncts nil))
+    (while (and conjuncts match)
+      (setq conjunct (car conjuncts)
+	    conjuncts (cdr conjuncts)
+	    req (car conjunct)
+	    options (cdr conjunct)
+	    match (cond ((eq req 'type)
+			 (or (memq window-system options)
+			     (and (null window-system)
+				  (memq 'tty options))))
+			((eq req 'class)
+			 (memq (frame-parameter frame 'display-type) options))
+			((eq req 'background)
+			 (memq (frame-parameter frame 'background-mode)
+			       options))
+			(t (error "Unknown req `%S' with options `%S'" 
+				  req options)))))
+    match))
+
+
+(defun face-spec-choose (spec &optional frame)
+  "Choose the proper attributes for FRAME, out of SPEC."
+  (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))
+	(when (face-spec-set-match-display display frame)
+	  (setq result attrs tail nil))))
+    result))
+
+
+(defun face-spec-reset-face (face &optional frame)
+  "Reset all attributes of FACE on FRAME to unspecified."
+  (let ((attrs face-attribute-name-alist)
+	params)
+    (while attrs
+      (let ((attr-and-name (car attrs)))
+	(setq params (cons (car attr-and-name) (cons 'unspecified params))))
+      (setq attrs (cdr attrs)))
+    (apply #'set-face-attribute face frame params)))
+
+
+(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."
+  (let ((attrs (face-spec-choose spec frame))
+	params)
+    (while attrs
+      (let ((attribute (car attrs))
+	    (value (car (cdr attrs))))
+	;; Support some old-style attribute names and values.
+	(case attribute
+	  (:bold (setq attribute :weight value (if value 'bold 'normal)))
+	  (:italic (setq attribute :slant value (if value 'italic 'normal))))
+	(setq params (cons attribute (cons value params))))
+      (setq attrs (cdr (cdr attrs))))
+    (face-spec-reset-face face frame)
+    (apply #'set-face-attribute face frame params)))
+
+
+(defun face-attr-match-p (face attrs &optional frame)
+  "Value is non-nil if attributes of FACE match values in plist ATTRS.
+Optional parameter FRAME is the frame whose definition of FACE
+is used.  If nil or omitted, use the selected frame."
+  (unless frame
+    (setq frame (selected-frame)))
+  (let ((list face-attribute-name-alist)
+	(match t))
+    (while (and match (not (null list)))
+      (let* ((attr (car (car list)))
+	     (specified-value (plist-get attrs attr))
+	     (value-now (face-attribute face attr frame)))
+	(when specified-value
+	  (setq match (equal specified-value value-now)))
+	(setq list (cdr list))))
+    match))
+
+
+(defun face-spec-match-p (face spec &optional 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))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Background mode.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defcustom frame-background-mode nil
+  "*The brightness of the background.
+Set this to the symbol `dark' if your background color is dark, `light' if
+your background is light, or nil (default) if you want Emacs to
+examine the brightness for you."
+  :group 'faces
+  :set #'(lambda (var value)
+	   (set var value)
+	   (mapcar 'frame-set-background-mode (frame-list)))
+  :initialize 'custom-initialize-changed
+  :type '(choice (choice-item dark) 
+		 (choice-item light)
+		 (choice-item :tag "default" nil)))
+
+
+(defun frame-set-background-mode (frame)
+  "Set up the `background-mode' and `display-type' frame parameters for FRAME."
+  (let* ((bg-resource
+	  (and window-system
+	       (x-get-resource ".backgroundMode" "BackgroundMode")))
+	 (params (frame-parameters frame))
+	 (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
+				       (cdr (assq 'background-color
+						  params))
+				       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)))
+	 (display-type (cond ((null window-system)
+			      (if (tty-display-color-p) 'color 'mono))
+			     ((x-display-color-p frame)
+			      'color)
+			     ((x-display-grayscale-p frame)
+			      'grayscale)
+			     (t 'mono))))
+    (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.
+  (let ((face-list (face-list)))
+    (while face-list
+      (let* ((face (car face-list))
+	     (spec (get face 'face-defface-spec)))
+	(when spec
+	  (face-spec-set face spec frame))
+      (setq face-list (cdr face-list))))))
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Frame creation.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun x-handle-named-frame-geometry (parameters)
+  "Add geometry parameters for a named frame to parameter list PARAMETERS.
+Value is the new parameter list."
+  (let* ((name (or (cdr (assq 'name parameters))
+		   (cdr (assq 'name default-frame-alist))))
+	 (x-resource-name name)
+	 (res-geometry (if name (x-get-resource "geometry" "Geometry"))))
+    (when res-geometry
+      (let ((parsed (x-parse-geometry res-geometry)))
+	;; If the resource specifies a position, call the position
+	;; and size "user-specified".
+	(when (or (assq 'top parsed)
+		  (assq 'left parsed))
+	  (setq parsed (append '((user-position . t) (user-size . t)) parsed)))
+	;; Put the geometry parameters at the end.  Copy
+	;; default-frame-alist so that they go after it.
+	(setq parameters (append parameters default-frame-alist parsed))))
+    parameters))
+
+
+(defun x-handle-reverse-video (frame parameters)
+  "Handle the reverse-video frame parameter and X resource.
+`x-create-frame' does not handle this one."
+  (when (cdr (or (assq 'reverse parameters)
+		 (assq 'reverse default-frame-alist)
+		 (let ((resource (x-get-resource "reverseVideo"
+						 "ReverseVideo")))
+		   (if resource
+		       (cons nil (member (downcase resource)
+					 '("on" "true")))))))
+      (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 'border-color params)))
+	    (modify-frame-parameters frame
+				     (list (cons 'border-color fg))))
+	(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 x-create-frame-with-faces (&optional parameters)
+  "Create a frame from optional frame parameters PARAMETERS.
+Parameters not specified by PARAMETERS are taken from
+`default-frame-alist'.  If PARAMETERS specify a frame name,
+handle X geometry resources for that name.  If either PARAMETERS
+or `default-frame-alist' contains a `reverse' parameter, or
+the X resource ``reverseVideo'' is present, handle that.
+Value is the new frame created."
+  (setq parameters (x-handle-named-frame-geometry parameters))
+  (let ((visibility-spec (assq 'visibility parameters))
+	(frame-list (frame-list))
+	(frame (x-create-frame (cons '(visibility . nil) parameters)))
+	success)
+    (unwind-protect
+	(progn
+	  (x-handle-reverse-video frame parameters)
+	  (frame-set-background-mode frame)
+	  (face-set-after-frame-default frame)
+	  (if (or (null frame-list) (null visibility-spec))
+	      (make-frame-visible frame)
+	    (modify-frame-parameters frame (list visibility-spec)))
+	  (setq success t))
+      (unless success
+	(delete-frame frame)))
+    frame))
+
+
+(defun face-set-after-frame-default (frame)
+  "Set frame-local faces of FRAME from face specs and resources."
+  (dolist (face (face-list))
+    (let ((spec (or (get face 'saved-face)
+		    (get face 'face-defface-spec))))
+      (when spec
+	(face-spec-set face spec frame))
+      (internal-merge-in-global-face face frame)
+      (when window-system
+	(make-face-x-resource-internal face frame)))))
+
+
+(defun tty-create-frame-with-faces (&optional parameters)
+  "Create a frame from optional frame parameters PARAMETERS.
+Parameters not specified by PARAMETERS are taken from
+`default-frame-alist'.  If either PARAMETERS or `default-frame-alist'
+contains a `reverse' parameter, handle that.  Value is the new frame
+created."
+  (let ((frame (make-terminal-frame parameters))
+	success)
+    (unwind-protect
+	(progn
+	  (frame-set-background-mode frame)
+	  (face-set-after-frame-default frame)
+	  (setq success t))
+      (unless success
+	(delete-frame frame)))
+    frame))
+
+
+;; Called from C function init_display to initialize faces of the
+;; dumped terminal frame on startup.
+
+(defun tty-set-up-initial-frame-faces ()
+  (let ((frame (selected-frame)))
+    (frame-set-background-mode frame)
+    (face-set-after-frame-default frame)))
+  
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Compatiblity with 20.2
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Update a frame's faces when we change its default font.
+
+(defun frame-update-faces (frame)
+  nil)
+
+
+;; Update the colors of FACE, after FRAME's own colors have been
+;; changed.
+
+(defun frame-update-face-colors (frame)
+  (frame-set-background-mode frame))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Standard faces.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Make the standard faces.  The C code knows faces `default',
+;; `modeline', `toolbar' and `region', so they must be the first faces
+;; made.  Unspecified attributes of these three faces are filled-in
+;; from frame parameters in the C code.
+
+(defgroup basic-faces nil
+  "The standard faces of Emacs."
+  :group 'faces)
+
+
+(defface default
+  '((t nil))
+  "Basic default face."
+  :group 'basic-faces)
+
+
+(defface modeline
+  '((((type x) (class color))
+     (:box (:line-width 2 :style released-button) :background "grey75"))
+    (t
+     (:inverse-video t)))
+  "Basic mode line face."
+  :group 'basic-faces)
+
+
+(defface top-line
+  '((((type x) (class color))
+     (:box (:line-width 2 :style released-button) :background "grey75"))
+    (t
+     (:inverse-video t)))
+  "Basic top line face."
+  :group 'basic-faces)
+
+
+(defface toolbar
+  '((((type x) (class color))
+     (:box (:line-width 1 :style released-button) :background "grey75"))
+    (t
+     ()))
+  "Basic toolbar face."
+  :group 'basic-faces)
+
+
+(defface region
+  '((((type tty) (class color))
+     (:background "blue" :foreground "white"))
+    (((type tty) (class mono))
+     (:inverse-video t))
+    (((class color) (background dark))
+     (:background "blue"))
+    (((class color) (background light))
+     (:background "lightblue"))
+    (t (:background "gray")))
+  "Basic face for highlight the region."
+  :group 'basic-faces)
+
+
+(defface bitmap-area
+  '((((class color))
+     (:background "grey95"))
+    (t (:background "gray")))
+  "Basic face for bitmap areas under X."
+  :group 'basic-faces)
+
+
+(defface bold '((t (:weight bold)))
+  "Basic bold face."
+  :group 'basic-faces)
+
+
+(defface italic '((t (:slant italic)))
+  "Basic italic font."
+  :group 'basic-faces)
+
+
+(defface bold-italic '((t (:weight bold :slant italic)))
+  "Basic bold-italic face."
+  :group 'basic-faces)
+
+
+(defface underline '((t (:underline t)))
+  "Basic underlined face."
+  :group 'basic-faces)
+
+
+(defface highlight
+  '((((type tty) (class color))
+     (:background "green"))
+    (((class color) (background light))
+     (:background "darkseagreen2"))
+    (((class color) (background dark))
+     (:background "darkolivegreen"))
+    (t (:inverse-video t)))
+  "Basic face for highlighting.")
+
+
+(defface secondary-selection
+  '((((type tty) (class color))
+     (:background "cyan"))
+    (((class color) (background light))
+     (:background "paleturquoise"))
+    (((class color) (background dark))
+     (:background "darkslateblue"))
+    (t (:inverse-video t)))
+  "Basic face for displaying the secondary selection.")
+
+
+(defface fixed-pitch '((t (:family "courier*")))
+  "The basic fixed-pitch face."
+  :group 'basic-faces)
+
+
+(defface variable-pitch '((t (:family "helv*")))
+  "The basic variable-pitch face."
+  :group 'basic-faces)
+
+
+(defface trailing-whitespace
+  '((((class color) (background light))
+     (:background "red"))
+    (((class color) (background dark))
+     (:background "red"))
+    (t (:inverse-video t)))
+  "Basic face for highlighting trailing whitespace.")
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Manipulating font names.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; This is here for compatibilty with Emacs 20.2.  For example,
+;; international/fontset.el uses these functions to manipulate font
+;; names.  The following functions are not used in the face
+;; implementation itself.
 
 (defvar x-font-regexp nil)
 (defvar x-font-regexp-head nil)
@@ -803,6 +1499,7 @@
   (setq x-font-regexp-weight (concat - weight -))
   nil)	    
 
+
 (defun x-resolve-font-name (pattern &optional face frame)
   "Return a font name matching PATTERN.
 All wildcards in PATTERN become substantiated.
@@ -832,6 +1529,7 @@
 	(car fonts))
     (cdr (assq 'font (frame-parameters (selected-frame))))))
 
+
 (defun x-frob-font-weight (font which)
   (let ((case-fold-search t))
     (cond ((string-match x-font-regexp font)
@@ -852,6 +1550,7 @@
 	   (concat (substring font 0 (match-beginning 1)) which
 		   (substring font (match-end 1)))))))
 
+
 (defun x-frob-font-slant (font which)
   (let ((case-fold-search t))
     (cond ((string-match x-font-regexp font)
@@ -872,813 +1571,50 @@
 	   (concat (substring font 0 (match-beginning 1)) which
 		   (substring font (match-end 1)))))))
 
+
 (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"))
 
+
 (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"))
 
+
 (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"))
 
+
 (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"))
 
+
 (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"))
 
+
 (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"))
 
+
 (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)))
-
-;;; non-X-specific interface
 
-(defun make-face-bold (face &optional frame noerror)
-  "Make the font of the given face be bold, if possible.  
-If NOERROR is non-nil, return nil on failure."
-  (interactive (list (read-face-name "Make which face bold: ")))
-  ;; Set the bold-p flag, first of all.
-  (internal-set-face-1 face nil t 10 frame)
-  (if (and (eq frame t) (listp (face-font face t)))
-      (set-face-font face (if (memq 'italic (face-font face t))
-			      '(bold italic) '(bold))
-		     t)
-    (let (font)
-      (if (null frame)
-	  (let ((frames (frame-list)))
-	    ;; Make this face bold in global-face-data.
-	    (make-face-bold face t noerror)
-	    ;; Make this face bold in each frame.
-	    (while frames
-	      (make-face-bold face (car frames) noerror)
-	      (setq frames (cdr frames))))
-	(setq face (internal-get-face face frame))
-	(setq font (or (face-font face frame)
-		       (face-font face t)))
-	(if (listp font)
-	    (setq font nil))
-	(setq font (or font
-		       (face-font 'default frame)
-		       (cdr (assq 'font (frame-parameters frame)))))
-	(or (and font (make-face-bold-internal face frame font))
-	    ;; We failed to find a bold version of the font.
-	    noerror
-	    (error "No bold version of %S" font))))))
-
-(defun make-face-bold-internal (face frame font)
-  (let (f2)
-    (or (and (setq f2 (x-make-font-bold font))
-	     (internal-try-face-font face f2 frame))
-	(and (setq f2 (x-make-font-demibold font))
-	     (internal-try-face-font face f2 frame)))))
-
-(defun make-face-italic (face &optional frame noerror)
-  "Make the font of the given face be italic, if possible.  
-If NOERROR is non-nil, return nil on failure."
-  (interactive (list (read-face-name "Make which face italic: ")))
-  ;; Set the italic-p flag, first of all.
-  (internal-set-face-1 face nil t 11 frame)
-  (if (and (eq frame t) (listp (face-font face t)))
-      (set-face-font face (if (memq 'bold (face-font face t))
-			      '(bold italic) '(italic))
-		     t)
-    (let (font)
-      (if (null frame)
-	  (let ((frames (frame-list)))
-	    ;; Make this face italic in global-face-data.
-	    (make-face-italic face t noerror)
-	    ;; Make this face italic in each frame.
-	    (while frames
-	      (make-face-italic face (car frames) noerror)
-	      (setq frames (cdr frames))))
-	(setq face (internal-get-face face frame))
-	(setq font (or (face-font face frame)
-		       (face-font face t)))
-	(if (listp font)
-	    (setq font nil))
-	(setq font (or font
-		       (face-font 'default frame)
-		       (cdr (assq 'font (frame-parameters frame)))))
-	(or (and font (make-face-italic-internal face frame font))
-	    ;; We failed to find an italic version of the font.
-	    noerror
-	    (error "No italic version of %S" font))))))
-
-(defun make-face-italic-internal (face frame font)
-  (let (f2)
-    (or (and (setq f2 (x-make-font-italic font))
-	     (internal-try-face-font face f2 frame))
-	(and (setq f2 (x-make-font-oblique font))
-	     (internal-try-face-font face f2 frame)))))
-
-(defun make-face-bold-italic (face &optional frame noerror)
-  "Make the font of the given face be bold and italic, if possible.  
-If NOERROR is non-nil, return nil on failure."
-  (interactive (list (read-face-name "Make which face bold-italic: ")))
-  ;; Set the bold-p and italic-p flags, first of all.
-  (internal-set-face-1 face nil t 10 frame)
-  (internal-set-face-1 face nil t 11 frame)
-  (if (and (eq frame t) (listp (face-font face t)))
-      (set-face-font face '(bold italic) t)
-    (let (font)
-      (if (null frame)
-	  (let ((frames (frame-list)))
-	    ;; Make this face bold-italic in global-face-data.
-	    (make-face-bold-italic face t noerror)
-	    ;; Make this face bold in each frame.
-	    (while frames
-	      (make-face-bold-italic face (car frames) noerror)
-	      (setq frames (cdr frames))))
-	(setq face (internal-get-face face frame))
-	(setq font (or (face-font face frame)
-		       (face-font face t)))
-	(if (listp font)
-	    (setq font nil))
-	(setq font (or font
-		       (face-font 'default frame)
-		       (cdr (assq 'font (frame-parameters frame)))))
-	(or (and font (make-face-bold-italic-internal face frame font))
-	    ;; We failed to find a bold italic version.
-	    noerror
-	    (error "No bold italic version of %S" font))))))
-
-(defun make-face-bold-italic-internal (face frame font)
-  (let (f2 f3)
-    (or (and (setq f2 (x-make-font-italic font))
-	     (not (equal font f2))
-	     (setq f3 (x-make-font-bold f2))
-	     (not (equal f2 f3))
-	     (internal-try-face-font face f3 frame))
-	(and (setq f2 (x-make-font-oblique font))
-	     (not (equal font f2))
-	     (setq f3 (x-make-font-bold f2))
-	     (not (equal f2 f3))
-	     (internal-try-face-font face f3 frame))
-	(and (setq f2 (x-make-font-italic font))
-	     (not (equal font f2))
-	     (setq f3 (x-make-font-demibold f2))
-	     (not (equal f2 f3))
-	     (internal-try-face-font face f3 frame))
-	(and (setq f2 (x-make-font-oblique font))
-	     (not (equal font f2))
-	     (setq f3 (x-make-font-demibold f2))
-	     (not (equal f2 f3))
-	     (internal-try-face-font face f3 frame)))))
-
-(defun make-face-unbold (face &optional frame noerror)
-  "Make the font of the given face be non-bold, if possible.  
-If NOERROR is non-nil, return nil on failure."
-  (interactive (list (read-face-name "Make which face non-bold: ")))
-  ;; Clear the bold-p flag, first of all.
-  (internal-set-face-1 face nil nil 10 frame)
-  (if (and (eq frame t) (listp (face-font face t)))
-      (set-face-font face (if (memq 'italic (face-font face t))
-			      '(italic) nil)
-		     t)
-    (let (font font1)
-      (if (null frame)
-	  (let ((frames (frame-list)))
-	    ;; Make this face unbold in global-face-data.
-	    (make-face-unbold face t noerror)
-	    ;; Make this face unbold in each frame.
-	    (while frames
-	      (make-face-unbold face (car frames) noerror)
-	      (setq frames (cdr frames))))
-	(setq face (internal-get-face face frame))
-	(setq font1 (or (face-font face frame)
-			(face-font face t)))
-	(if (listp font1)
-	    (setq font1 nil))
-	(setq font1 (or font1
-			(face-font 'default frame)
-			(cdr (assq 'font (frame-parameters frame)))))
-	(setq font (and font1 (x-make-font-unbold font1)))
-	(or (if font (internal-try-face-font face font frame))
-	    noerror
-	    (error "No unbold version of %S" font1))))))
-
-(defun make-face-unitalic (face &optional frame noerror)
-  "Make the font of the given face be non-italic, if possible.  
-If NOERROR is non-nil, return nil on failure."
-  (interactive (list (read-face-name "Make which face non-italic: ")))
-  ;; Clear the italic-p flag, first of all.
-  (internal-set-face-1 face nil nil 11 frame)
-  (if (and (eq frame t) (listp (face-font face t)))
-      (set-face-font face (if (memq 'bold (face-font face t))
-			      '(bold) nil)
-		     t)
-    (let (font font1)
-      (if (null frame)
-	  (let ((frames (frame-list)))
-	    ;; Make this face unitalic in global-face-data.
-	    (make-face-unitalic face t noerror)
-	    ;; Make this face unitalic in each frame.
-	    (while frames
-	      (make-face-unitalic face (car frames) noerror)
-	      (setq frames (cdr frames))))
-	(setq face (internal-get-face face frame))
-	(setq font1 (or (face-font face frame)
-			(face-font face t)))
-	(if (listp font1)
-	    (setq font1 nil))
-	(setq font1 (or font1
-			(face-font 'default frame)
-			(cdr (assq 'font (frame-parameters frame)))))
-	(setq font (and font1 (x-make-font-unitalic font1)))
-	(or (if font (internal-try-face-font face font frame))
-	    noerror
-	    (error "No unitalic version of %S" font1))))))
-
-(defvar list-faces-sample-text
-  "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-  "*Text string to display as the sample text for `list-faces-display'.")
-
-;; The name list-faces would be more consistent, but let's avoid a conflict
-;; with Lucid, which uses that name differently.
-(defun list-faces-display ()
-  "List all faces, using the same sample text in each.
-The sample text is a string that comes from the variable
-`list-faces-sample-text'.
-
-It is possible to give a particular face name different appearances in
-different frames.  This command shows the appearance in the
-selected frame."
-  (interactive)
-  (let ((faces (sort (face-list) (function string-lessp)))
-	(face nil)
-	(frame (selected-frame))
-	disp-frame window
-        (face-name-max-length
-         (car (sort (mapcar (function string-width)
-			    (mapcar (function symbol-name) (face-list)))
-                    (function >)))))
-    (with-output-to-temp-buffer "*Faces*"
-      (save-excursion
-	(set-buffer standard-output)
-	(setq truncate-lines t)
-	(while faces
-	  (setq face (car faces))
-	  (setq faces (cdr faces))
-	  (insert (format 
-                   (format "%%-%ds "
-                           face-name-max-length)
-                   (symbol-name face)))
-	  (let ((beg (point)))
-	    (insert list-faces-sample-text)
-	    (insert "\n")
-	    (put-text-property beg (1- (point)) 'face face)
-	    ;; If the sample text has multiple lines, line up all of them.
-	    (goto-char beg)
-	    (forward-line 1)
-	    (while (not (eobp))
-	      (insert-char ?  (1+ face-name-max-length))
-	      (forward-line 1))))
-	(goto-char (point-min)))
-      (print-help-return-message))
-    ;; If the *Faces* buffer appears in a different frame,
-    ;; copy all the face definitions from FRAME,
-    ;; so that the display will reflect the frame that was selected.
-    (setq window (get-buffer-window (get-buffer "*Faces*") t))
-    (setq disp-frame (if window (window-frame window)
-		       (car (frame-list))))
-    (or (eq frame disp-frame)
-	(let ((faces (face-list)))
-	  (while faces
-	    (copy-face (car faces) (car faces) frame disp-frame)
-	    (setq faces (cdr faces)))))))
-
-(defun describe-face (face)
-  "Display the properties of face FACE."
-  (interactive (list (read-face-name "Describe face: ")))
-  (with-output-to-temp-buffer "*Help*"
-    (princ "Properties of face `")
-    (princ (face-name face))
-    (princ "':") (terpri)
-    (princ "Foreground: ") (princ (face-foreground face)) (terpri)
-    (princ "Background: ") (princ (face-background face)) (terpri)
-    (princ "      Font: ") (princ (face-font face)) (terpri)
-    (princ "Underlined: ") (princ (if (face-underline-p face) "yes" "no")) (terpri)
-    (princ "   Stipple: ") (princ (or (face-stipple face) "none")) (terpri)
-    (terpri)
-    (princ "Documentation:") (terpri)
-    (let ((doc (face-documentation face)))
-      (if doc
-	  (princ doc)
-	(princ "not documented as a face.")))
-    (print-help-return-message)))
-
-;;; Setting a face based on a SPEC.
-
-(defun face-attr-match-p (face attrs &optional frame)
-  (or frame (setq frame (selected-frame)))
-  (and (face-attr-match-1 face frame attrs ':inverse-video
-			  'face-inverse-video-p)
-       (if (face-inverse-video-p face frame)
-	   (and
-	    (face-attr-match-1 face frame attrs
-			       ':foreground 'face-background
-			       (cdr (assq 'foreground-color
-					  (frame-parameters frame))))
-	    (face-attr-match-1 face frame attrs
-			       ':background 'face-foreground 
-			       (cdr (assq 'background-color
-					  (frame-parameters frame)))))
-	 (and
-	  (face-attr-match-1 face frame attrs ':foreground 'face-foreground)
-	  (face-attr-match-1 face frame attrs ':background 'face-background)))
-       (face-attr-match-1 face frame attrs ':stipple 'face-stipple)
-       (face-attr-match-1 face frame attrs ':bold 'face-bold-p)
-       (face-attr-match-1 face frame attrs ':italic 'face-italic-p)
-       (face-attr-match-1 face frame attrs ':underline 'face-underline-p)
-))
-
-(defun face-attr-match-1 (face frame plist property function
-			       &optional defaultval)
-  (while (and plist (not (eq (car plist) property)))
-    (setq plist (cdr (cdr plist))))
-  (eq (funcall function face frame)
-      (if plist
-	  (nth 1 plist)
-	(or defaultval
-	    (funcall function 'default frame)))))
-
-(defun face-spec-match-p (face spec &optional 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))
-
-(defun face-attr-construct (face &optional frame)
-  "Return a defface-style attribute list for FACE, as it exists on FRAME." 
-  (let (result)
-    (if (face-inverse-video-p face frame)
-	(progn
-	  (setq result (cons ':inverse-video (cons t result)))
-	  (or (face-attr-match-1 face frame nil
-				 ':foreground 'face-background
-				 (cdr (assq 'foreground-color
-					    (frame-parameters frame))))
-	      (setq result (cons ':foreground
-				 (cons (face-foreground face frame) result))))
-	  (or (face-attr-match-1 face frame nil
-				 ':background 'face-foreground 
-				 (cdr (assq 'background-color
-					    (frame-parameters frame))))
-	      (setq result (cons ':background
-				 (cons (face-background face frame) result)))))
-      (if (face-foreground face frame)
-	  (setq result (cons ':foreground
-			     (cons (face-foreground face frame) result))))
-      (if (face-background face frame)
-	  (setq result (cons ':background
-			     (cons (face-background face frame) result)))))
-    (if (face-stipple face frame)
-	(setq result (cons ':stipple
-			   (cons (face-stipple face frame) result))))
-    (if (face-bold-p face frame)
-	(setq result (cons ':bold
-			   (cons (face-bold-p face frame) result))))
-    (if (face-italic-p face frame)
-	(setq result (cons ':italic
-			   (cons (face-italic-p face frame) result))))
-    (if (face-underline-p face frame)
-	(setq result (cons ':underline
-			   (cons (face-underline-p face frame) result))))
-    result))
-    
-;; Choose the proper attributes for FRAME, out of SPEC.
-(defun face-spec-choose (spec &optional frame)
-  (or 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))
-	(when (face-spec-set-match-display display frame)
-	  (setq result attrs tail nil))))
-    result))
-
-(defun face-spec-set (face spec &optional frame)
-  "Set FACE's face attributes according to the first matching entry in SPEC.
-If optional FRAME is non-nil, set it for that frame only.
-If it is nil, then apply SPEC to each frame individually.
-See `defface' for information about SPEC."
-  (if frame
-      (let ((attrs (face-spec-choose spec frame)))
-	(when attrs
-	  ;; If the font was set automatically, clear it out
-	  ;; to allow it to be set it again.
-	  (unless (face-font-explicit face frame)
-	    (set-face-font face nil frame))
-	  (modify-face face '(nil) '(nil) nil nil nil nil nil frame)
-	  (face-spec-set-1 face frame attrs ':foreground 'set-face-foreground)
-	  (face-spec-set-1 face frame attrs ':background 'set-face-background)
-	  (face-spec-set-1 face frame attrs ':stipple 'set-face-stipple)
-	  (face-spec-set-1 face frame attrs ':bold 'set-face-bold-p)
-	  (face-spec-set-1 face frame attrs ':italic 'set-face-italic-p)
-	  (face-spec-set-1 face frame attrs ':underline 'set-face-underline-p)
-	  (face-spec-set-1 face frame attrs ':inverse-video
-			   'set-face-inverse-video-p)))
-    (let ((frames (frame-list))
-	  frame)
-      (while frames
-	(setq frame (car frames)
-	      frames (cdr frames))
-	(face-spec-set face (or (get face 'saved-face)
-				(get face 'face-defface-spec))
-		       frame)
-	(face-spec-set face spec frame)))))
-
-(defun face-spec-set-1 (face frame plist property function)
-  (while (and plist (not (eq (car plist) property)))
-    (setq plist (cdr (cdr plist))))
-  (if plist
-      (funcall function face (nth 1 plist) frame)))
-
-(defun face-spec-set-match-display (display frame)
-  "Non-nil iff DISPLAY matches FRAME.
-DISPLAY is part of a spec such as can be used in `defface'.
-If FRAME is nil, the current FRAME is used."
-  (let* ((conjuncts display)
-	 conjunct req options
-	 ;; t means we have succeeded against all
-	 ;; the conjunts in DISPLAY that have been tested so far.
-	 (match t))
-    (if (eq conjuncts t)
-	(setq conjuncts nil))
-    (while (and conjuncts match)
-      (setq conjunct (car conjuncts)
-	    conjuncts (cdr conjuncts)
-	    req (car conjunct)
-	    options (cdr conjunct)
-	    match (cond ((eq req 'type)
-			 (memq window-system options))
-			((eq req 'class)
-			 (memq (frame-parameter frame 'display-type) options))
-			((eq req 'background)
-			 (memq (frame-parameter frame 'background-mode)
-			       options))
-			(t
-			 (error "Unknown req `%S' with options `%S'" 
-				req options)))))
-    match))
-
-;; Like x-create-frame but also set up the faces.
-
-(defun x-create-frame-with-faces (&optional parameters)
-  ;; Read this frame's geometry resource, if it has an explicit name,
-  ;; and put the specs into PARAMETERS.
-  (let* ((name (or (cdr (assq 'name parameters))
-		   (cdr (assq 'name default-frame-alist))))
-	 (x-resource-name name)
-	 (res-geometry (if name (x-get-resource "geometry" "Geometry"))))
-    (if res-geometry
-	(let ((parsed (x-parse-geometry res-geometry)))
-	  ;; If the resource specifies a position,
-	  ;; call the position and size "user-specified".
-	  (if (or (assq 'top parsed) (assq 'left parsed))
-	      (setq parsed (append '((user-position . t) (user-size . t))
-				   parsed)))
-	  ;; Put the geometry parameters at the end.
-	  ;; Copy default-frame-alist so that they go after it.
-	  (setq parameters (append parameters default-frame-alist parsed)))))
-
-  (if default-enable-multibyte-characters
-      ;; If an ASCII font is specified in PARAMETERS, we try to create
-      ;; a fontset from it, and use it for the new frame.
-      (condition-case nil
-	  (let ((font (cdr (assq 'font parameters))))
-	    (if (and font
-		     (not (query-fontset font)))
-		(setq parameters
-		      (cons (cons 'font (create-fontset-from-ascii-font font))
-			    parameters))))
-	(error nil)))
-
-  (let (frame)
-    (if (null global-face-data)
-	(progn
-	  (setq frame (x-create-frame parameters))
-	  (frame-set-background-mode frame))
-      (let* ((visibility-spec (assq 'visibility parameters))
-	     success faces rest)
-	(setq frame (x-create-frame (cons '(visibility . nil) parameters)))
-	(unwind-protect
-	    (progn
-	      ;; Copy the face alist, copying the face vectors
-	      ;; and emptying out their attributes.
-	      (setq faces
-		    (mapcar '(lambda (elt)
-			       (cons (car elt)
-				     (vector 'face
-					     (face-name (cdr elt))
-					     (face-id (cdr elt))
-					     nil
-					     nil nil nil nil
-					     nil nil nil nil)))
-			    global-face-data))
-	      (set-frame-face-alist frame faces)
-
-	      ;; Handle the reverse-video frame parameter
-	      ;; and X resource.  x-create-frame does not handle this one.
-	      (if (cdr (or (assq 'reverse parameters)
-			   (assq 'reverse default-frame-alist)
-			   (let ((resource (x-get-resource "reverseVideo"
-							   "ReverseVideo")))
-			     (if resource
-				 (cons nil (member (downcase resource)
-						   '("on" "true")))))))
-		  (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 'border-color params)))
-			(modify-frame-parameters frame
-						 (list (cons 'border-color fg))))
-		    (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))))))
-
-	      (frame-set-background-mode frame)
-
-	      (face-set-after-frame-default frame)
-
-	      ;; Make the frame visible, if desired.
-	      (if (null visibility-spec)
-		  (make-frame-visible frame)
-		(modify-frame-parameters frame (list visibility-spec)))
-	      (setq success t))
-	  (or success
-	      (delete-frame frame)))))
-    frame))
-
-;; Update a frame's faces after the frame font changes.
-;; This is called from modify-frame-parameters
-;; as well as from elsewhere in this file.
-(defun face-set-after-frame-default (frame)
-  (let ((rest (frame-face-alist frame)))
-    (while rest
-      ;; Set up each face, first from the defface information,
-      ;; then the global face data, and then the X resources.
-      (let* ((face (car (car rest)))
-	     (spec (or (get face 'customized-face)
-		       (get face 'saved-face)
-		       (get face 'face-defface-spec)))
-	     (global (cdr (assq face global-face-data)))
-	     (local (cdr (car rest))))
-	(when spec
-	  (face-spec-set face spec frame))
-	(face-fill-in face global frame)
-	(make-face-x-resource-internal local frame))
-      (setq rest (cdr rest)))))
-
-(defcustom frame-background-mode nil
-  "*The brightness of the background.
-Set this to the symbol dark if your background color is dark, light if
-your background is light, or nil (default) if you want Emacs to
-examine the brightness for you."
-  :group 'faces
-  :set #'(lambda (var value)
-	   (set var value)
-	   (mapcar 'frame-set-background-mode (frame-list)))
-  :initialize 'custom-initialize-changed
-  :type '(choice (choice-item dark) 
-		 (choice-item light)
-		 (choice-item :tag "default" nil)))
-
-(defun frame-set-background-mode (frame)
-  "Set up the `background-mode' and `display-type' frame parameters for FRAME."
-  (unless (eq (framep frame) t)
-    (let ((bg-resource (x-get-resource ".backgroundMode"
-				       "BackgroundMode"))
-	  (params (frame-parameters frame))
-	  (bg-mode))
-      (setq bg-mode
-	    (cond (frame-background-mode)
-		  (bg-resource (intern (downcase bg-resource)))
-		  ((< (apply '+ (x-color-values
-				 (cdr (assq 'background-color params))
-				 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)))
-      (modify-frame-parameters frame
-			       (list (cons 'background-mode bg-mode)
-				     (cons 'display-type
-					   (cond ((x-display-color-p frame)
-						  'color)
-						 ((x-display-grayscale-p frame)
-						  'grayscale)
-						 (t 'mono))))))))
-
-;; Update a frame's faces when we change its default font.
-(defun frame-update-faces (frame) nil)
-
-;; Update the colors of FACE, after FRAME's own colors have been changed.
-;; This applies only to faces with global color specifications
-;; that are not simple constants.
-(defun frame-update-face-colors (frame)
-  (frame-set-background-mode frame)
-  (let ((faces global-face-data))
-    (while faces
-      (condition-case nil
-	  (let* ((data (cdr (car faces)))
-		 (face (car (car faces)))
-		 (foreground (face-foreground data))
-		 (background (face-background data)))
-	    ;; If the global spec is a specific color,
-	    ;; which doesn't depend on the frame's attributes,
-	    ;; we don't need to recalculate it now.
-	    (or (listp foreground)
-		(setq foreground nil))
-	    (or (listp background)
-		(setq background nil))
-	    ;; If we are going to frob this face at all,
-	    ;; reinitialize it first.
-	    (if (or foreground background)
-		(progn (set-face-foreground face nil frame)
-		       (set-face-background face nil frame)))
-	    (if foreground
-		(face-try-color-list 'set-face-foreground
-				     face foreground frame))
-	    (if background
-		(face-try-color-list 'set-face-background
-				     face background frame)))
-	(error nil))
-      (setq faces (cdr faces)))))
-
-;; Fill in the face FACE from frame-independent face data DATA.
-;; DATA should be the non-frame-specific ("global") face vector
-;; for the face.  FACE should be a face name or face object.
-;; FRAME is the frame to act on; it must be an actual frame, not nil or t.
-(defun face-fill-in (face data frame)
-  (condition-case nil
-      (let ((foreground (face-foreground data))
-	    (background (face-background data))
-	    (font (face-font data))
-	    (stipple (face-stipple data)))
-	(if (face-underline-p data)
-	    (set-face-underline-p face (face-underline-p data) frame))
-	(if foreground
-	    (face-try-color-list 'set-face-foreground
-				 face foreground frame))
-	(if background
-	    (face-try-color-list 'set-face-background
-				 face background frame))
-	(if (listp font)
-	    (let ((bold (memq 'bold font))
-		  (italic (memq 'italic font)))
-	      (cond ((and bold italic)
-		     (make-face-bold-italic face frame))
-		    (bold
-		     (make-face-bold face frame))
-		    (italic
-		     (make-face-italic face frame))))
-	  (if font
-	      (set-face-font face font frame)))
-	(if stipple
-	    (set-face-stipple face stipple frame)))
-    (error nil)))
-
-;; Assuming COLOR is a valid color name,
-;; return t if it can be displayed on FRAME.
-(defun face-color-supported-p (frame color background-p)
-  (and window-system
-       (or (x-display-color-p frame)
-	   ;; A black-and-white display can implement these.
-	   (member color '("black" "white"))
-	   ;; A black-and-white display can fake gray for background.
-	   (and background-p
-		(face-color-gray-p color frame))
-	   ;; A grayscale display can implement colors that are gray (more or less).
-	   (and (x-display-grayscale-p frame)
-		(face-color-gray-p color frame)))))
-
-;; Use FUNCTION to store a color in FACE on FRAME.
-;; COLORS is either a single color or a list of colors.
-;; If it is a list, try the colors one by one until one of them
-;; succeeds.  We signal an error only if all the colors failed.
-;; t as COLORS or as an element of COLORS means to invert the face.
-;; That can't fail, so any subsequent elements after the t are ignored.
-(defun face-try-color-list (function face colors frame)
-  (if (stringp colors)
-      (if (face-color-supported-p frame colors
-				  (eq function 'set-face-background))
-	  (funcall function face colors frame))
-    (if (eq colors t)
-	(set-face-inverse-video-p face t frame)
-      (let (done)
-	(while (and colors (not done))
-	  (if (or (memq (car colors) '(t underline nil))
-		  (face-color-supported-p frame (car colors)
-					  (eq function 'set-face-background)))
-	      (if (cdr colors)
-		  ;; If there are more colors to try, catch errors
-		  ;; and set `done' if we succeed.
-		  (condition-case nil
-		      (progn
-			(cond ((eq (car colors) t)
-			       (set-face-inverse-video-p face t frame))
-			      ((eq (car colors) 'underline)
-			       (set-face-underline-p face t frame))
-			      (t
-			       (funcall function face (car colors) frame)))
-			(setq done t))
-		    (error nil))
-		;; If this is the last color, let the error get out if it fails.
-		;; If it succeeds, we will exit anyway after this iteration.
-		(cond ((eq (car colors) t)
-		       (set-face-inverse-video-p face t frame))
-		      ((eq (car colors) 'underline)
-		       (set-face-underline-p face t frame))
-		      (t
-		       (funcall function face (car colors) frame)))))
-	  (setq colors (cdr colors)))))))
-
-;;; Make the standard faces.
-;;; The C code knows the default and modeline faces as faces 0 and 1,
-;;; so they must be the first two faces made.
-(make-face 'default)
-(make-face 'modeline)
-(make-face 'highlight)
-
-;; These aren't really special in any way, but they're nice to have around.
-
-(make-face 'bold)
-(make-face 'italic)
-(make-face 'bold-italic)
-(make-face 'region)
-(make-face 'secondary-selection)
-(make-face 'underline)
-
-(setq region-face (face-id 'region))
-
-(defgroup basic-faces nil
-  "The standard faces of Emacs."
-  :prefix "huh"
-  :group 'faces)
-
-;; Specify how these faces look, and their documentation.
-(let ((all '((bold "Use bold font." ((t (:bold t))))
-	     (bold-italic "Use bold italic font." ((t (:bold t :italic t))))
-	     (italic "Use italic font." ((t (:italic t))))
-	     (underline "Underline text." ((t (:underline t))))
-	     (default "Used for text not covered by other faces." ((t nil)))
-	     (highlight "Highlight text in some way."
-			((((class color) (background light))
-			  (:background "darkseagreen2"))
-			 (((class color) (background dark))
-			  (:background "darkolivegreen"))
-			 (t (:inverse-video t))))
-	     (modeline "Used for displaying the modeline."
-		       ((t (:inverse-video t))))
-	     (region "Used for displaying the region."
-		     ((((class color) (background dark))
-		       (:background "blue"))
-		      (t (:background "gray"))))
-	     (secondary-selection
-	      "Used for displaying the secondary selection."
-	      ((((class color) (background light))
-		(:background "paleturquoise"))
-	       (((class color) (background dark))
-		(:background "darkslateblue"))
-	       (t (:inverse-video t))))))
-      entry symbol doc spec)
-  (while all
-    (setq entry (car all)
-	  all (cdr all)
-	  symbol (nth 0 entry)
-	  doc (nth 1 entry)
-	  spec (nth 2 entry))
-    (custom-add-to-group 'basic-faces symbol 'custom-face)
-    (put symbol 'face-documentation doc)
-    (put symbol 'face-defface-spec spec)))
 
 (provide 'faces)
 
-;;; faces.el ends here
+;;; end of faces.el