]> code.delx.au - gnu-emacs/blobdiff - lisp/faces.el
(Info-goto-index): One register one step in the history.
[gnu-emacs] / lisp / faces.el
index 172efc5cd12490d60961441cd683d9492fbd40e6..d60d30a46f638fab873985a7ca5009a34adb20cd 100644 (file)
@@ -200,7 +200,7 @@ If NAME is already a face, it is simply returned.
 
 This function is defined for compatibility with Emacs 20.2.  It
 should not be used anymore."
-  (or (internal-find-face name frame)
+  (or (facep name)
       (check-face name)))
 (make-obsolete 'internal-get-face "See `facep' and `check-face'." "21.1")
 
@@ -302,7 +302,7 @@ If FRAME is omitted or nil, use the selected frame."
   "*List of X resources and classes for face attributes.
 Each element has the form (ATTRIBUTE ENTRY1 ENTRY2...) where ATTRIBUTE is
 the name of a face attribute, and each ENTRY is a cons of the form
-(RESOURCE . CLASS) with RESOURCE being the resource and CLASS being the
+\(RESOURCE . CLASS) with RESOURCE being the resource and CLASS being the
 X resource class for the attribute."
   :type '(repeat (cons symbol (repeat (cons string string))))
   :group 'faces)
@@ -355,45 +355,125 @@ FRAME nil or not specified means do it for all frames."
   (symbol-name (check-face face)))
 
 
-(defun face-attribute (face attribute &optional frame)
+(defun face-attribute (face attribute &optional frame inherit)
   "Return the value of FACE's ATTRIBUTE on FRAME.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (internal-get-lisp-face-attribute face attribute frame))
+If FRAME is omitted or nil, use the selected frame.
+
+If INHERIT is nil, only attributes directly defined by FACE are considered,
+  so the return value may be `unspecified', or a relative value.
+If INHERIT is non-nil, FACE's definition of ATTRIBUTE is merged with the
+  faces specified by its `:inherit' attribute; however the return value
+  may still be `unspecified' or relative.
+If INHERIT is a face or a list of faces, then the result is further merged
+  with that face (or faces), until it becomes specified and absolute.
+
+To ensure that the return value is always specified and absolute, use a
+value of `default' for INHERIT; this will resolve any unspecified or
+relative values by merging with the `default' face (which is always
+completely specified)."
+  (let ((value (internal-get-lisp-face-attribute face attribute frame)))
+    (when (and inherit (face-attribute-relative-p attribute value))
+      ;; VALUE is relative, so merge with inherited faces
+      (let ((inh-from (face-attribute face :inherit frame)))
+       (unless (or (null inh-from) (eq inh-from 'unspecified))
+         (setq value
+               (face-attribute-merged-with attribute value inh-from frame)))))
+    (when (and inherit
+              (not (eq inherit t))
+              (face-attribute-relative-p attribute value))
+       ;; We should merge with INHERIT as well
+      (setq value (face-attribute-merged-with attribute value inherit frame)))
+    value))
+
+(defun face-attribute-merged-with (attribute value faces &optional frame)
+  "Merges ATTRIBUTE, initially VALUE, with faces from FACES until absolute.
+FACES may be either a single face or a list of faces.
+\[This is an internal function]"
+  (cond ((not (face-attribute-relative-p attribute value))
+        value)
+       ((null faces)
+        value)
+       ((consp faces)
+        (face-attribute-merged-with
+         attribute
+         (face-attribute-merged-with attribute value (car faces) frame)
+         (cdr faces)
+         frame))
+       (t
+        (merge-face-attribute attribute
+                              value
+                              (face-attribute faces attribute frame t)))))
+
 
+(defmacro face-attribute-specified-or (value &rest body)
+  "Return VALUE, unless it's `unspecified', in which case evaluate BODY and return the result."
+  (let ((temp (make-symbol "value")))
+    `(let ((,temp ,value))
+       (if (not (eq ,temp 'unspecified))
+          ,temp
+        ,@body))))
 
-(defun face-foreground (face &optional frame)
+(defun face-foreground (face &optional frame inherit)
   "Return the foreground color name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (let ((value (internal-get-lisp-face-attribute face :foreground frame)))
-    (if (eq value 'unspecified)
-       nil
-      value)))
-
+If FRAME is omitted or nil, use the selected frame.
 
-(defun face-background (face &optional frame)
+If INHERIT is nil, only a foreground color directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a foreground color, then any
+  foreground color that FACE inherits through its `:inherit' attribute
+  is considered as well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified foreground color.
+
+To ensure that a valid color is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by
+merging with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :foreground frame inherit)
+                              nil))
+
+(defun face-background (face &optional frame inherit)
   "Return the background color name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (let ((value (internal-get-lisp-face-attribute face :background frame)))
-    (if (eq value 'unspecified)
-       nil
-      value)))
-
+If FRAME is omitted or nil, use the selected frame.
 
-(defun face-stipple (face &optional frame)
+If INHERIT is nil, only a background color directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a background color, then any
+  background color that FACE inherits through its `:inherit' attribute
+  is considered as well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified background color.
+
+To ensure that a valid color is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by
+merging with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :background frame inherit)
+                              nil))
+
+(defun face-stipple (face &optional frame inherit)
  "Return the stipple pixmap name of FACE, or nil if unspecified.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
-If FRAME is omitted or nil, use the selected frame."
-  (let ((value (internal-get-lisp-face-attribute face :stipple frame)))
-    (if (eq value 'unspecified)
-       nil
-      value)))
+If FRAME is omitted or nil, use the selected frame.
+
+If INHERIT is nil, only a stipple directly defined by FACE is
+  considered, so the return value may be nil.
+If INHERIT is t, and FACE doesn't define a stipple, then any stipple
+  that FACE inherits through its `:inherit' attribute is considered as
+  well; however the return value may still be nil.
+If INHERIT is a face or a list of faces, then it is used to try to
+  resolve an unspecified stipple.
+
+To ensure that a valid stipple or nil is always returned, use a value of
+`default' for INHERIT; this will resolve any unspecified values by merging
+with the `default' face (which is always completely specified)."
+  (face-attribute-specified-or (face-attribute face :stipple frame inherit)
+                              nil))
 
 
 (defalias 'face-background-pixmap 'face-stipple)
@@ -599,7 +679,7 @@ like an underlying face would be, with higher priority than underlying faces."
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font weight."
-  (interactive (list (read-face-name "Make which face bold ")))
+  (interactive (list (read-face-name "Make which face bold")))
   (set-face-attribute face frame :weight 'bold))
 
 
@@ -607,7 +687,7 @@ Use `set-face-attribute' for finer control of the font weight."
   "Make the font of FACE be non-bold, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility."
-  (interactive (list (read-face-name "Make which face non-bold ")))
+  (interactive (list (read-face-name "Make which face non-bold")))
   (set-face-attribute face frame :weight 'normal))
 
 
@@ -616,7 +696,7 @@ Argument NOERROR is ignored and retained for compatibility."
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font slant."
-  (interactive (list (read-face-name "Make which face italic ")))
+  (interactive (list (read-face-name "Make which face italic")))
   (set-face-attribute face frame :slant 'italic))
 
 
@@ -624,7 +704,7 @@ Use `set-face-attribute' for finer control of the font slant."
   "Make the font of FACE be non-italic, if possible.
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility."
-  (interactive (list (read-face-name "Make which face non-italic ")))
+  (interactive (list (read-face-name "Make which face non-italic")))
   (set-face-attribute face frame :slant 'normal))
 
 
@@ -633,7 +713,7 @@ Argument NOERROR is ignored and retained for compatibility."
 FRAME nil or not specified means change face on all frames.
 Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of font weight and slant."
-  (interactive (list (read-face-name "Make which face bold-italic")))
+  (interactive (list (read-face-name "Make which face bold-italic")))
   (set-face-attribute face frame :weight 'bold :slant 'italic))
 
 
@@ -744,14 +824,14 @@ Use `set-face-attribute' or `modify-face' for finer control."
 
 (defun invert-face (face &optional frame)
   "Swap the foreground and background colors of FACE.
-FRAME nil or not specified means change face on all frames.
+If FRAME is omitted or nil, it means change face on all frames.
 If FACE specifies neither foreground nor background color,
 set its foreground and background to the background and foreground
 of the default face.  Value is FACE."
-  (interactive (list (read-face-name "Invert face ")))
+  (interactive (list (read-face-name "Invert face")))
   (let ((fg (face-attribute face :foreground frame))
        (bg (face-attribute face :background frame)))
-    (if (or fg bg)
+    (if (not (and (eq fg 'unspecified) (eq bg 'unspecified)))
        (set-face-attribute face frame :foreground bg :background fg)
       (set-face-attribute face frame
                          :foreground
@@ -767,6 +847,7 @@ of the default face.  Value is FACE."
 
 (defun read-face-name (prompt)
   "Read and return a face symbol, prompting with PROMPT.
+PROMPT should not end with a blank, since this function appends one.
 Value is a symbol naming a known face."
   (let ((face-list (mapcar #'(lambda (x) (cons (symbol-name x) x))
                           (face-list)))
@@ -1109,7 +1190,7 @@ If FRAME is omitted or nil, use the selected frame."
                  (:inherit . "Inherit")))
        (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x)))
                                        attrs))))
-    (require 'help-mode)
+    (help-setup-xref (list #'describe-face face) (interactive-p))
     (with-output-to-temp-buffer (help-buffer)
       (save-excursion
        (set-buffer standard-output)
@@ -1129,8 +1210,7 @@ If FRAME is omitted or nil, use the selected frame."
              (re-search-backward
               (concat "\\(" customize-label "\\)") nil t)
              (help-xref-button 1 'help-customize-face face)))))
-      (print-help-return-message)
-      (help-setup-xref (list #'describe-face face) (interactive-p)))))
+      (print-help-return-message))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1951,47 +2031,52 @@ also the same size as FACE on FRAME, or fail."
                   (substring font (match-end 1)))))))
 (make-obsolete 'x-frob-font-slant 'make-face-... "21.1")
 
+;; These aliases are here so that we don't get warnings about obsolete
+;; functions from the byte compiler.
+(defalias 'internal-frob-font-weight 'x-frob-font-weight)
+(defalias 'internal-frob-font-slant 'x-frob-font-slant)
+
 (defun x-make-font-bold (font)
   "Given an X font specification, make a bold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "bold"))
+  (internal-frob-font-weight font "bold"))
 (make-obsolete 'x-make-font-bold 'make-face-bold "21.1")
 
 (defun x-make-font-demibold (font)
   "Given an X font specification, make a demibold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "demibold"))
+  (internal-frob-font-weight font "demibold"))
 (make-obsolete 'x-make-font-demibold 'make-face-bold "21.1")
 
 (defun x-make-font-unbold (font)
   "Given an X font specification, make a non-bold version of it.
 If that can't be done, return nil."
-  (x-frob-font-weight font "medium"))
+  (internal-frob-font-weight font "medium"))
 (make-obsolete 'x-make-font-unbold 'make-face-unbold "21.1")
 
 (defun x-make-font-italic (font)
   "Given an X font specification, make an italic version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "i"))
+  (internal-frob-font-slant font "i"))
 (make-obsolete 'x-make-font-italic 'make-face-italic "21.1")
 
 (defun x-make-font-oblique (font) ; you say tomayto...
   "Given an X font specification, make an oblique version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "o"))
+  (internal-frob-font-slant font "o"))
 (make-obsolete 'x-make-font-oblique 'make-face-italic "21.1")
 
 (defun x-make-font-unitalic (font)
   "Given an X font specification, make a non-italic version of it.
 If that can't be done, return nil."
-  (x-frob-font-slant font "r"))
+  (internal-frob-font-slant font "r"))
 (make-obsolete 'x-make-font-unitalic 'make-face-unitalic "21.1")
 
 (defun x-make-font-bold-italic (font)
   "Given an X font specification, make a bold and italic version of it.
 If that can't be done, return nil."
-  (and (setq font (x-make-font-bold font))
-       (x-make-font-italic font)))
+  (and (setq font (internal-frob-font-weight font "bold"))
+       (internal-frob-font-slant font "i")))
 (make-obsolete 'x-make-font-bold-italic 'make-face-bold-italic "21.1")
 
 (provide 'faces)