]> code.delx.au - gnu-emacs/blobdiff - lisp/faces.el
Merge from emacs--rel--22
[gnu-emacs] / lisp / faces.el
index ceadb6f764f5fd0202787209ac387be9f0cd8e6f..88b0c54039a323c181631d301a05b60406e50719 100644 (file)
@@ -222,11 +222,12 @@ Value is FACE."
 
 (defun face-id (face &optional frame)
   "Return the internal ID of face with name FACE.
+If FACE is a face-alias, return the ID of the target face.
 The optional argument FRAME is ignored, since the internal face ID
 of a face name is the same for all frames."
   (check-face face)
-  (get face 'face))
-
+  (or (get face 'face)
+      (face-id (get face 'face-alias))))
 
 (defun face-equal (face1 face2 &optional frame)
   "Non-nil if faces FACE1 and FACE2 are equal.
@@ -931,7 +932,7 @@ an integer value."
   (let ((valid
          (case attribute
            (:family
-            (if window-system
+            (if (window-system frame)
                 (mapcar #'(lambda (x) (cons (car x) (car x)))
                         (x-font-family-list))
              ;; Only one font on TTYs.
@@ -940,7 +941,7 @@ an integer value."
             (mapcar #'(lambda (x) (cons (symbol-name x) x))
                     (internal-lisp-face-attribute-values attribute)))
            ((:underline :overline :strike-through :box)
-            (if window-system
+            (if (window-system frame)
                 (nconc (mapcar #'(lambda (x) (cons (symbol-name x) x))
                                (internal-lisp-face-attribute-values attribute))
                        (mapcar #'(lambda (c) (cons c c))
@@ -953,7 +954,7 @@ an integer value."
            ((:height)
             'integerp)
            (:stipple
-            (and (memq window-system '(x w32 mac))
+            (and (memq (window-system frame) '(x w32 mac))
                  (mapcar #'list
                          (apply #'nconc
                                 (mapcar (lambda (dir)
@@ -1071,7 +1072,7 @@ of a global face.  Value is the new attribute value."
               ;; explicitly in VALID, using color approximation code
               ;; in tty-colors.el.
               (when (and (memq attribute '(:foreground :background))
-                         (not (memq window-system '(x w32 mac)))
+                         (not (memq (window-system frame) '(x w32 mac)))
                          (not (member new-value
                                       '("unspecified"
                                         "unspecified-fg" "unspecified-bg"))))
@@ -1193,7 +1194,7 @@ arg, prompt for a regular expression."
       (error "No faces matching \"%s\"" regexp))
     (setq max-length (1+ max-length)
          line-format (format "%%-%ds" max-length))
-    (with-output-to-temp-buffer "*Faces*"
+    (with-help-window "*Faces*"
       (save-excursion
        (set-buffer standard-output)
        (setq truncate-lines t)
@@ -1234,8 +1235,7 @@ arg, prompt for a regular expression."
            (while (not (eobp))
              (insert-char ?\s max-length)
              (forward-line 1))))
-       (goto-char (point-min)))
-      (print-help-return-message))
+       (goto-char (point-min))))
     ;; 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.
@@ -1280,10 +1280,11 @@ If FRAME is omitted or nil, use the selected frame."
       (setq face 'default))
     (if (not (listp face))
        (setq face (list face)))
-    (with-output-to-temp-buffer (help-buffer)
+    (with-help-window (help-buffer)
       (save-excursion
        (set-buffer standard-output)
        (dolist (f face)
+         (if (stringp f) (setq f (intern f)))
          (insert "Face: " (symbol-name f))
          (if (not (facep f))
              (insert "   undefined face.\n")
@@ -1326,8 +1327,7 @@ If FRAME is omitted or nil, use the selected frame."
                        (re-search-backward ": \\([^:]+\\)" nil t)
                        (help-xref-button 1 'help-face attr)))
                  (insert "\n")))))
-         (terpri)))
-      (print-help-return-message))))
+         (terpri))))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1367,14 +1367,14 @@ If FRAME is nil, the current FRAME is used."
            req (car conjunct)
            options (cdr conjunct)
            match (cond ((eq req 'type)
-                        (or (memq window-system options)
+                        (or (memq (window-system frame) options)
                             ;; FIXME: This should be revisited to use
                             ;; display-graphic-p, provided that the
                             ;; color selection depends on the number
                             ;; of supported colors, and all defface's
                             ;; are changed to look at number of colors
                             ;; instead of (type graphic) etc.
-                            (and (null window-system)
+                            (and (null (window-system frame))
                                  (memq 'tty options))
                             (and (memq 'motif options)
                                  (featurep 'motif))
@@ -1443,31 +1443,42 @@ If SPEC is nil, return nil."
 (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.
-If SPEC is nil, do nothing."
+do it on all frames (and change the default for new frames).
+See `defface' for information about SPEC.  If SPEC is nil, do nothing."
   (let ((attrs (face-spec-choose spec frame)))
     (when spec
-      (face-spec-reset-face face frame))
+      (face-spec-reset-face face (or frame t)))
     (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)))
-         ((:foreground :background)
-          ;; Compatibility with 20.x.  Some bogus face specs seem to
-          ;; exist containing things like `:foreground nil'.
-          (if (null value) (setq value 'unspecified)))
-         (t (unless (assq attribute face-x-resources)
-              (setq attribute nil))))
+             (:bold (setq attribute :weight value (if value 'bold 'normal)))
+             (:italic (setq attribute :slant value (if value 'italic 'normal)))
+             ((:foreground :background)
+              ;; Compatibility with 20.x.  Some bogus face specs seem to
+              ;; exist containing things like `:foreground nil'.
+              (if (null value) (setq value 'unspecified)))
+             (t (unless (assq attribute face-x-resources)
+                  (setq attribute nil))))
        (when attribute
-         (set-face-attribute face frame attribute value)))
+         ;; If frame is nil, set the default for new frames.
+         ;; Existing frames are handled below.
+         (set-face-attribute face (or frame t) attribute value)))
       (setq attrs (cdr (cdr attrs)))))
-  ;; When we reset the face based on its spec, then it is unmodified
-  ;; as far as Custom is concerned.
-  (if (null frame)
-      (put (or (get face 'face-alias) face) 'face-modified nil)))
+  (unless frame
+    ;; When we reset the face based on its spec, then it is unmodified
+    ;; as far as Custom is concerned.
+    (put (or (get face 'face-alias) face) 'face-modified nil)
+;;;     ;; Clear all the new-frame defaults for this face.
+;;;     ;; face-spec-reset-face won't do it right.
+;;;     (let ((facevec (cdr (assq face face-new-frame-defaults))))
+;;;       (dotimes (i (length facevec))
+;;;    (unless (= i 0)
+;;;      (aset facevec i 'unspecified))))
+    ;; Set each frame according to the rules implied by SPEC.
+    (dolist (frame (frame-list))
+      (face-spec-set face spec frame))))
 
 
 (defun face-attr-match-p (face attrs &optional frame)
@@ -1569,6 +1580,140 @@ If omitted or nil, that stands for the selected frame's display."
      (t
       (> (tty-color-gray-shades display) 2)))))
 
+(defun read-color (&optional prompt convert-to-RGB-p allow-empty-name-p msg-p)
+  "Read a color name or RGB hex value: #RRRRGGGGBBBB.
+Completion is available for color names, but not for RGB hex strings.
+If the user inputs an RGB hex string, it must have the form
+#XXXXXXXXXXXX or XXXXXXXXXXXX, where each X is a hex digit.  The
+number of Xs must be a multiple of 3, with the same number of Xs for
+each of red, green, and blue.  The order is red, green, blue.
+
+In addition to standard color names and RGB hex values, the following
+are available as color candidates.  In each case, the corresponding
+color is used.
+
+ * `foreground at point'   - foreground under the cursor
+ * `background at point'   - background under the cursor
+
+Checks input to be sure it represents a valid color.  If not, raises
+an error (but see exception for empty input with non-nil
+ALLOW-EMPTY-NAME-P).
+
+Optional arg PROMPT is the prompt; if nil, uses a default prompt.
+
+Interactively, or with optional arg CONVERT-TO-RGB-P non-nil, converts
+an input color name to an RGB hex string.  Returns the RGB hex string.
+
+Optional arg ALLOW-EMPTY-NAME-P controls what happens if the user
+enters an empty color name (that is, just hits `RET').  If non-nil,
+then returns an empty color name, \"\".  If nil, then raises an error.
+Programs must test for \"\" if ALLOW-EMPTY-NAME-P is non-nil.  They
+can then perform an appropriate action in case of empty input.
+
+Interactively, or with optional arg MSG-P non-nil, echoes the color in
+a message."
+  (interactive "i\np\ni\np")    ; Always convert to RGB interactively.
+  (let* ((completion-ignore-case t)
+         (colors (append '("foreground at point" "background at point")
+                        (defined-colors)))
+         (color (completing-read (or prompt "Color (name or #R+G+B+): ")
+                                colors))
+         hex-string)
+    (cond ((string= "foreground at point" color)
+          (setq color (foreground-color-at-point)))
+         ((string= "background at point" color)
+          (setq color (background-color-at-point))))
+    (unless color
+      (setq color ""))
+    (setq hex-string
+         (string-match "^#?\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color))
+    (if (and allow-empty-name-p (string= "" color))
+        ""
+      (when (and hex-string (not (eq (aref color 0) ?#)))
+        (setq color (concat "#" color))) ; No #; add it.
+      (unless hex-string
+        (when (or (string= "" color) (not (test-completion color colors)))
+          (error "No such color: %S" color))
+        (when convert-to-RGB-p
+          (let ((components (x-color-values color)))
+            (unless components (error "No such color: %S" color))
+            (unless (string-match "^#\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)+$" color)
+              (setq color (format "#%04X%04X%04X"
+                                  (logand 65535 (nth 0 components))
+                                  (logand 65535 (nth 1 components))
+                                  (logand 65535 (nth 2 components))))))))
+      (when msg-p (message "Color: `%s'" color))
+      color)))
+
+;; Commented out because I decided it is better to include the
+;; duplicates in read-color's completion list.
+
+;; (defun defined-colors-without-duplicates ()
+;;   "Return the list of defined colors, without the no-space versions.
+;; For each color name, we keep the variant that DOES have spaces."
+;;   (let ((result (copy-sequence (defined-colors)))
+;;        to-be-rejected)
+;;     (save-match-data
+;;       (dolist (this result)
+;;        (if (string-match " " this)
+;;            (push (replace-regexp-in-string " " "" 
+;;                                            this)
+;;                  to-be-rejected)))
+;;       (dolist (elt to-be-rejected)
+;;        (let ((as-found (car (member-ignore-case elt result))))
+;;          (setq result (delete as-found result)))))
+;;     result))
+
+(defun face-at-point ()
+  "Return the face of the character after point.
+If it has more than one face, return the first one.
+Return nil if it has no specified face."
+  (let* ((faceprop (or (get-char-property (point) 'read-face-name)
+                       (get-char-property (point) 'face)
+                       'default))
+         (face (cond ((symbolp faceprop) faceprop)
+                     ;; List of faces (don't treat an attribute spec).
+                     ;; Just use the first face.
+                     ((and (consp faceprop) (not (keywordp (car faceprop)))
+                           (not (memq (car faceprop)
+                                     '(foreground-color background-color))))
+                      (car faceprop))
+                     (t nil))))         ; Invalid face value.
+    (if (facep face) face nil)))
+
+(defun foreground-color-at-point ()
+  "Return the foreground color of the character after point."
+  ;; `face-at-point' alone is not sufficient.  It only gets named faces.
+  ;; Need also pick up any face properties that are not associated with named faces.
+  (let ((face (or (face-at-point)
+                 (get-char-property (point) 'read-face-name)
+                 (get-char-property (point) 'face))))
+    (cond ((and face (symbolp face))
+          (let ((value (face-foreground face nil 'default)))
+            (if (member value '("unspecified-fg" "unspecified-bg"))
+                nil
+              value)))
+         ((consp face)
+          (cond ((memq 'foreground-color face) (cdr (memq 'foreground-color face)))
+                ((memq ':foreground face) (cadr (memq ':foreground face)))))
+         (t nil))))                    ; Invalid face value.
+
+(defun background-color-at-point ()
+  "Return the background color of the character after point."
+  ;; `face-at-point' alone is not sufficient.  It only gets named faces.
+  ;; Need also pick up any face properties that are not associated with named faces.
+  (let ((face (or (face-at-point)
+                 (get-char-property (point) 'read-face-name)
+                 (get-char-property (point) 'face))))
+    (cond ((and face (symbolp face))
+          (let ((value (face-background face nil 'default)))
+            (if (member value '("unspecified-fg" "unspecified-bg"))
+                nil
+              value)))
+         ((consp face)
+          (cond ((memq 'background-color face) (cdr (memq 'background-color face)))
+                ((memq ':background face) (cadr (memq ':background face)))))
+         (t nil))))                    ; Invalid face value.
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Background mode.
@@ -1589,35 +1734,40 @@ variable with `setq'; this won't have the expected effect."
                 (const light)
                 (const :tag "automatic" nil)))
 
-(defvar default-frame-background-mode nil
-  "Internal variable for the default brightness of the background.
-Emacs sets it automatically depending on the terminal type.
-The value `nil' means `dark'.  If Emacs runs in non-windowed
-mode from `xterm' or a similar terminal emulator, the value is
-`light'.  On rxvt terminals, the value depends on the environment
-variable COLORFGBG.")
 
 (defun frame-set-background-mode (frame)
   "Set up display-dependent faces on FRAME.
 Display-dependent faces are those which have different definitions
 according to the `background-mode' and `display-type' frame parameters."
   (let* ((bg-resource
-         (and window-system
+         (and (window-system frame)
               (x-get-resource "backgroundMode" "BackgroundMode")))
         (bg-color (frame-parameter frame 'background-color))
+        (terminal-bg-mode (terminal-parameter frame 'background-mode))
+        (tty-type (tty-type frame))
         (bg-mode
          (cond (frame-background-mode)
                (bg-resource
                 (intern (downcase bg-resource)))
-               ((and (null window-system) (null bg-color))
-                ;; No way to determine this automatically (?).
-                (or default-frame-background-mode 'dark))
-               ;; Unspecified frame background color can only happen
-               ;; on tty's.
-               ((member bg-color '(unspecified "unspecified-bg"))
-                (or default-frame-background-mode 'dark))
+               (terminal-bg-mode)
+               ((and (null (window-system frame))
+                     ;; Unspecified frame background color can only
+                     ;; happen on tty's.
+                     (member bg-color '(nil unspecified "unspecified-bg")))
+                ;; There is no way to determine the background mode
+                ;; automatically, so we make a guess based on the
+                ;; terminal type.
+                (if (and tty-type
+                         (string-match "^\\(xterm\\|rxvt\\|dtterm\\|eterm\\)"
+                                       tty-type))
+                    'light
+                  'dark))
                ((equal bg-color "unspecified-fg") ; inverted colors
-                (if (eq default-frame-background-mode 'light) 'dark 'light))
+                (if (and tty-type
+                         (string-match "^\\(xterm\\|rxvt\\|dtterm\\|eterm\\)"
+                                       tty-type))
+                    'dark
+                  'light))
                ((>= (apply '+ (color-values bg-color frame))
                    ;; Just looking at the screen, colors whose
                    ;; values add up to .6 of the white total
@@ -1626,7 +1776,7 @@ according to the `background-mode' and `display-type' frame parameters."
                 'light)
                (t 'dark)))
         (display-type
-         (cond ((null window-system)
+         (cond ((null (window-system frame))
                 (if (tty-display-color-p frame) 'color 'mono))
                ((display-color-p frame)
                 'color)
@@ -1722,15 +1872,19 @@ 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)))
+       (frame (x-create-frame `((visibility . nil) . ,parameters)))
        success)
     (unwind-protect
        (progn
+         (x-setup-function-keys frame)
          (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 sure the tool-bar is ready to be enabled.  The
+         ;; `tool-bar-lines' frame parameter will not take effect
+         ;; without this call.
+         (tool-bar-setup frame)
+         (if (null visibility-spec)
              (make-frame-visible frame)
            (modify-frame-parameters frame (list visibility-spec)))
          (setq success t))
@@ -1789,7 +1943,7 @@ Initialize colors of certain faces from frame parameters."
       (condition-case ()
          (progn
            (face-spec-set face (face-user-default-spec face) frame)
-           (if (memq window-system '(x w32 mac))
+           (if (memq (window-system frame) '(x w32 mac))
                (make-face-x-resource-internal face frame))
            (internal-merge-in-global-face face frame))
        (error nil)))
@@ -1825,8 +1979,13 @@ created."
   (let ((frame (make-terminal-frame parameters))
        success)
     (unwind-protect
-       (progn
+       (with-selected-frame frame
          (tty-handle-reverse-video frame (frame-parameters frame))
+
+          (unless (terminal-parameter frame 'terminal-initted)
+            (set-terminal-parameter frame 'terminal-initted t)
+            (set-locale-environment nil frame)
+            (tty-run-terminal-initialization frame))
          (frame-set-background-mode frame)
          (face-set-after-frame-default frame)
          (setq success t))
@@ -1834,6 +1993,49 @@ created."
        (delete-frame frame)))
     frame))
 
+(defun tty-find-type (pred type)
+  "Return the longest prefix of TYPE to which PRED returns non-nil.
+TYPE should be a tty type name such as \"xterm-16color\".
+
+The function tries only those prefixes that are followed by a
+dash or underscore in the original type name, like \"xterm\" in
+the above example."
+  (let (hyphend)
+    (while (and type
+               (not (funcall pred type)))
+      ;; Strip off last hyphen and what follows, then try again
+      (setq type
+           (if (setq hyphend (string-match "[-_][^-_]+$" type))
+               (substring type 0 hyphend)
+             nil))))
+  type)
+
+(defun tty-run-terminal-initialization (frame &optional type)
+  "Run the special initialization code for the terminal type of FRAME.
+The optional TYPE parameter may be used to override the autodetected
+terminal type to a different value."
+  (setq type (or type (tty-type frame)))
+  ;; Load library for our terminal type.
+  ;; User init file can set term-file-prefix to nil to prevent this.
+  (with-selected-frame frame
+    (unless (null term-file-prefix)
+      (let* (term-init-func)
+       ;; First, load the terminal initialization file, if it is
+       ;; available and it hasn't been loaded already.
+       (tty-find-type #'(lambda (type)
+                          (let ((file (locate-library (concat term-file-prefix type))))
+                            (and file
+                                 (or (assoc file load-history)
+                                     (load file t t)))))
+                      type)
+       ;; Next, try to find a matching initialization function, and call it.
+       (tty-find-type #'(lambda (type)
+                          (fboundp (setq term-init-func
+                                         (intern (concat "terminal-init-" type)))))
+                      type)
+       (when (fboundp term-init-func)
+         (funcall term-init-func))
+       (set-terminal-parameter frame 'terminal-initted term-init-func)))))
 
 ;; Called from C function init_display to initialize faces of the
 ;; dumped terminal frame on startup.