Merge from emacs--rel--22
[bpt/emacs.git] / lisp / cus-face.el
CommitLineData
e8af40ee 1;;; cus-face.el --- customization support for faces
d543e20b 2;;
0d30b337 3;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
409cc4a3 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
d543e20b
PA
5;;
6;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
7;; Keywords: help, faces
d543e20b 8
6c283d44 9;; This file is part of GNU Emacs.
d543e20b 10
6c283d44
RS
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
b4aa6026 13;; the Free Software Foundation; either version 3, or (at your option)
6c283d44 14;; any later version.
d543e20b 15
6c283d44
RS
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
d543e20b 20
6c283d44
RS
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
d543e20b 25
6c283d44
RS
26;;; Commentary:
27;;
28;; See `custom.el'.
d543e20b 29
6c283d44 30;;; Code:
d543e20b 31
da0b1f56 32(defalias 'custom-facep 'facep)
ccd0d40c 33
d543e20b
PA
34;;; Declaring a face.
35
d543e20b
PA
36(defun custom-declare-face (face spec doc &rest args)
37 "Like `defface', but FACE is evaluated as a normal argument."
6c283d44 38 (unless (get face 'face-defface-spec)
d543e20b 39 (when (fboundp 'facep)
6c283d44 40 (unless (facep face)
d543e20b
PA
41 ;; If the user has already created the face, respect that.
42 (let ((value (or (get face 'saved-face) spec))
987a3489 43 (have-window-system (memq initial-window-system '(x w32))))
d543e20b
PA
44 ;; Create global face.
45 (make-empty-face face)
b5188bcd 46 ;; Create frame-local faces
f4db5253 47 (dolist (frame (frame-list))
af4bbb69 48 (face-spec-set-2 face frame value)
6dc59f76 49 (when (memq (window-system frame) '(x w32 mac))
2246281f
KL
50 (setq have-window-system t)))
51 ;; When making a face after frames already exist
52 (if have-window-system
53 (make-face-x-resource-internal face)))))
b5188bcd
RS
54 ;; Don't record SPEC until we see it causes no errors.
55 (put face 'face-defface-spec spec)
4829145a 56 (push (cons 'defface face) current-load-list)
209ddde3 57 (when (and doc (null (face-documentation face)))
08449ec1 58 (set-face-documentation face (purecopy doc)))
d543e20b
PA
59 (custom-handle-all-keywords face args 'custom-face)
60 (run-hooks 'custom-define-hook))
61 face)
62
da0b1f56
GM
63;;; Face attributes.
64
d543e20b 65(defconst custom-face-attributes
da0b1f56 66 '((:family
c165ad40
MB
67 (string :tag "Font Family"
68 :help-echo "Font family or fontset alias name."))
a3997907 69
da0b1f56
GM
70 (:width
71 (choice :tag "Width"
72 :help-echo "Font width."
c165ad40 73 :value normal ; default
da0b1f56
GM
74 (const :tag "compressed" condensed)
75 (const :tag "condensed" condensed)
76 (const :tag "demiexpanded" semi-expanded)
77 (const :tag "expanded" expanded)
78 (const :tag "extracondensed" extra-condensed)
79 (const :tag "extraexpanded" extra-expanded)
80 (const :tag "medium" normal)
81 (const :tag "narrow" condensed)
82 (const :tag "normal" normal)
83 (const :tag "regular" normal)
84 (const :tag "semicondensed" semi-condensed)
85 (const :tag "semiexpanded" semi-expanded)
86 (const :tag "ultracondensed" ultra-condensed)
87 (const :tag "ultraexpanded" ultra-expanded)
51a1edab 88 (const :tag "wide" extra-expanded)))
71296446 89
da0b1f56
GM
90 (:height
91 (choice :tag "Height"
92 :help-echo "Face's font height."
c165ad40 93 :value 1.0 ; default
6bca3005 94 (integer :tag "Height in 1/10 pt")
51a1edab 95 (number :tag "Scale" 1.0)))
6bca3005 96
da0b1f56
GM
97 (:weight
98 (choice :tag "Weight"
99 :help-echo "Font weight."
c165ad40 100 :value normal ; default
992f7c96 101 (const :tag "black" ultra-bold)
da0b1f56
GM
102 (const :tag "bold" bold)
103 (const :tag "book" semi-light)
104 (const :tag "demibold" semi-bold)
105 (const :tag "extralight" extra-light)
106 (const :tag "extrabold" extra-bold)
107 (const :tag "heavy" extra-bold)
108 (const :tag "light" light)
109 (const :tag "medium" normal)
110 (const :tag "normal" normal)
111 (const :tag "regular" normal)
112 (const :tag "semibold" semi-bold)
113 (const :tag "semilight" semi-light)
114 (const :tag "ultralight" ultra-light)
51a1edab 115 (const :tag "ultrabold" ultra-bold)))
71296446 116
da0b1f56
GM
117 (:slant
118 (choice :tag "Slant"
119 :help-echo "Font slant."
c165ad40 120 :value normal ; default
da0b1f56
GM
121 (const :tag "italic" italic)
122 (const :tag "oblique" oblique)
43240958
CY
123 (const :tag "normal" normal)
124 (const :tag "roman" roman)))
71296446 125
da0b1f56
GM
126 (:underline
127 (choice :tag "Underline"
128 :help-echo "Control text underlining."
c165ad40 129 (const :tag "Off" nil)
da0b1f56 130 (const :tag "On" t)
51a1edab 131 (color :tag "Colored")))
71296446 132
da0b1f56
GM
133 (:overline
134 (choice :tag "Overline"
135 :help-echo "Control text overlining."
c165ad40 136 (const :tag "Off" nil)
da0b1f56 137 (const :tag "On" t)
51a1edab 138 (color :tag "Colored")))
71296446 139
da0b1f56
GM
140 (:strike-through
141 (choice :tag "Strike-through"
142 :help-echo "Control text strike-through."
c165ad40 143 (const :tag "Off" nil)
da0b1f56 144 (const :tag "On" t)
51a1edab 145 (color :tag "Colored")))
71296446 146
da0b1f56 147 (:box
1743c17a 148 ;; Fixme: this can probably be done better.
da0b1f56
GM
149 (choice :tag "Box around text"
150 :help-echo "Control box around text."
c165ad40 151 (const :tag "Off" nil)
da0b1f56 152 (list :tag "Box"
36b80a0d 153 :value (:line-width 2 :color "grey75" :style released-button)
1743c17a 154 (const :format "" :value :line-width)
da0b1f56 155 (integer :tag "Width")
1743c17a
DL
156 (const :format "" :value :color)
157 (choice :tag "Color" (const :tag "*" nil) color)
158 (const :format "" :value :style)
159 (choice :tag "Style"
160 (const :tag "Raised" released-button)
161 (const :tag "Sunken" pressed-button)
162 (const :tag "None" nil))))
51a1edab
MB
163 ;; filter to make value suitable for customize
164 (lambda (real-value)
c165ad40
MB
165 (and real-value
166 (let ((lwidth
167 (or (and (consp real-value)
168 (plist-get real-value :line-width))
169 (and (integerp real-value) real-value)
170 1))
171 (color
172 (or (and (consp real-value) (plist-get real-value :color))
173 (and (stringp real-value) real-value)
174 nil))
175 (style
176 (and (consp real-value) (plist-get real-value :style))))
177 (list :line-width lwidth :color color :style style))))
36b80a0d
MB
178 ;; filter to make customized-value suitable for storing
179 (lambda (cus-value)
c165ad40
MB
180 (and cus-value
181 (let ((lwidth (plist-get cus-value :line-width))
182 (color (plist-get cus-value :color))
183 (style (plist-get cus-value :style)))
184 (cond ((and (null color) (null style))
185 lwidth)
186 ((and (null lwidth) (null style))
187 ;; actually can't happen, because LWIDTH is always an int
188 color)
189 (t
190 ;; Keep as a plist, but remove null entries
191 (nconc (and lwidth `(:line-width ,lwidth))
192 (and color `(:color ,color))
193 (and style `(:style ,style)))))))))
71296446 194
da0b1f56
GM
195 (:inverse-video
196 (choice :tag "Inverse-video"
197 :help-echo "Control whether text should be in inverse-video."
c165ad40
MB
198 (const :tag "Off" nil)
199 (const :tag "On" t)))
71296446 200
da0b1f56 201 (:foreground
c165ad40 202 (color :tag "Foreground"
4bbe6176 203 :help-echo "Set foreground color (name or #RRGGBB hex spec)."))
71296446 204
da0b1f56 205 (:background
c165ad40 206 (color :tag "Background"
4bbe6176 207 :help-echo "Set background color (name or #RRGGBB hex spec)."))
71296446 208
da0b1f56
GM
209 (:stipple
210 (choice :tag "Stipple"
675f1fcb 211 :help-echo "Background bit-mask"
c165ad40 212 (const :tag "None" nil)
675f1fcb
MB
213 (file :tag "File"
214 :help-echo "Name of bitmap file."
215 :must-match t)))
6bca3005
MB
216
217 (:inherit
218 (repeat :tag "Inherit"
219 :help-echo "List of faces to inherit attributes from."
220 (face :Tag "Face" default))
51a1edab
MB
221 ;; filter to make value suitable for customize
222 (lambda (real-value)
223 (cond ((or (null real-value) (eq real-value 'unspecified))
224 nil)
225 ((symbolp real-value)
226 (list real-value))
227 (t
228 real-value)))
229 ;; filter to make customized-value suitable for storing
230 (lambda (cus-value)
231 (if (and (consp cus-value) (null (cdr cus-value)))
232 (car cus-value)
233 cus-value))))
71296446 234
da0b1f56
GM
235 "Alist of face attributes.
236
51a1edab
MB
237The elements are of the form (KEY TYPE PRE-FILTER POST-FILTER),
238where KEY is the name of the attribute, TYPE is a widget type for
239editing the attribute, PRE-FILTER is a function to make the attribute's
240value suitable for the customization widget, and POST-FILTER is a
241function to make the customized value suitable for storing. PRE-FILTER
242and POST-FILTER are optional.
d543e20b 243
51a1edab
MB
244The PRE-FILTER should take a single argument, the attribute value as
245stored, and should return a value for customization (using the
246customization type TYPE).
d543e20b 247
51a1edab
MB
248The POST-FILTER should also take a single argument, the value after
249being customized, and should return a value suitable for setting the
250given face attribute.")
d543e20b
PA
251
252(defun custom-face-attributes-get (face frame)
6c283d44
RS
253 "For FACE on FRAME, return an alternating list describing its attributes.
254The list has the form (KEYWORD VALUE KEYWORD VALUE...).
d543e20b
PA
255Each keyword should be listed in `custom-face-attributes'.
256
6c283d44 257If FRAME is nil, use the global defaults for FACE."
da0b1f56
GM
258 (let ((attrs custom-face-attributes)
259 plist)
260 (while attrs
261 (let* ((attribute (car (car attrs)))
262 (value (face-attribute face attribute frame)))
263 (setq attrs (cdr attrs))
6bca3005
MB
264 (unless (or (eq value 'unspecified)
265 (and (null value) (memq attribute '(:inherit))))
da0b1f56
GM
266 (setq plist (cons attribute (cons value plist))))))
267 plist))
d543e20b 268
d543e20b
PA
269;;; Initializing.
270
d543e20b
PA
271(defun custom-set-faces (&rest args)
272 "Initialize faces according to user preferences.
a3997907
RS
273This associates the settings with the `user' theme.
274The arguments should be a list where each entry has the form:
275
276 (FACE SPEC [NOW [COMMENT]])
277
278SPEC is stored as the saved value for FACE, as well as the value for the
279`user' theme. The `user' theme is one of the default themes known to Emacs.
280See `custom-known-themes' for more information on the known themes.
281See `custom-theme-set-faces' for more information on the interplay
282between themes and faces.
283See `defface' for the format of SPEC.
284
285If NOW is present and non-nil, FACE is created now, according to SPEC.
286COMMENT is a string comment about FACE."
287 (apply 'custom-theme-set-faces 'user args))
288
289(defun custom-theme-set-faces (theme &rest args)
290 "Initialize faces for theme THEME.
d543e20b
PA
291The arguments should be a list where each entry has the form:
292
1743c17a 293 (FACE SPEC [NOW [COMMENT]])
d543e20b 294
a3997907
RS
295SPEC is stored as the saved value for FACE, as well as the value for the
296`user' theme. The `user' theme is one of the default themes known to Emacs.
297See `custom-known-themes' for more information on the known themes.
298See `custom-theme-set-faces' for more information on the interplay
299between themes and faces.
300See `defface' for the format of SPEC.
301
6c283d44 302If NOW is present and non-nil, FACE is created now, according to SPEC.
1743c17a 303COMMENT is a string comment about FACE.
d543e20b 304
a3997907
RS
305Several properties of THEME and FACE are used in the process:
306
307If THEME property `theme-immediate' is non-nil, this is equivalent of
308providing the NOW argument to all faces in the argument list: FACE is
309created now. The only difference is FACE property `force-face': if NOW
310is non-nil, FACE property `force-face' is set to the symbol `rogue', else
311if THEME property `theme-immediate' is non-nil, FACE property `force-face'
312is set to the symbol `immediate'.
313
314SPEC itself is saved in FACE property `saved-face' and it is stored in
315FACE's list property `theme-face' \(using `custom-push-theme')."
316 (custom-check-theme theme)
317 (let ((immediate (get theme 'theme-immediate)))
318 (while args
319 (let ((entry (car args)))
320 (if (listp entry)
321 (let ((face (nth 0 entry))
322 (spec (nth 1 entry))
323 (now (nth 2 entry))
e335f09e
CY
324 (comment (nth 3 entry))
325 oldspec)
403546cb
LT
326 ;; If FACE is actually an alias, customize the face it
327 ;; is aliased to.
328 (if (get face 'face-alias)
329 (setq face (get face 'face-alias)))
e335f09e
CY
330
331 (setq oldspec (get face 'theme-face))
332 (when (not (and oldspec (eq 'user (caar oldspec))))
333 (put face 'saved-face spec)
334 (put face 'saved-face-comment comment))
335
a3997907
RS
336 (custom-push-theme 'theme-face face theme 'set spec)
337 (when (or now immediate)
338 (put face 'force-face (if now 'rogue 'immediate)))
339 (when (or now immediate (facep face))
340 (unless (facep face)
341 (make-empty-face face))
342 (put face 'face-comment comment)
af4bbb69
RS
343 (put face 'face-override-spec nil)
344 (face-spec-set face spec t))
578b4e9d
RS
345 (setq args (cdr args)))
346 ;; Old format, a plist of FACE SPEC pairs.
347 (let ((face (nth 0 args))
348 (spec (nth 1 args)))
349 (if (get face 'face-alias)
350 (setq face (get face 'face-alias)))
351 (put face 'saved-face spec)
352 (custom-push-theme 'theme-face face theme 'set spec))
353 (setq args (cdr (cdr args))))))))
a3997907 354
d358aa10
CY
355;; XEmacs compability function. In XEmacs, when you reset a Custom
356;; Theme, you have to specify the theme to reset it to. We just apply
357;; the next theme.
a3997907 358(defun custom-theme-reset-faces (theme &rest args)
2c9e973f
RS
359 "Reset the specs in THEME of some faces to their specs in other themes.
360Each of the arguments ARGS has this form:
a3997907 361
d358aa10 362 (FACE IGNORED)
a3997907 363
d358aa10 364This means reset FACE. The argument IGNORED is ignored."
a3997907 365 (custom-check-theme theme)
2c9e973f 366 (dolist (arg args)
d358aa10 367 (custom-push-theme 'theme-face (car arg) theme 'reset)))
a3997907 368
a3997907 369(defun custom-reset-faces (&rest args)
2c9e973f
RS
370 "Reset the specs of some faces to their specs in specified themes.
371This creates settings in the `user' theme.
372
373Each of the arguments ARGS has this form:
374
375 (FACE FROM-THEME)
a3997907 376
2c9e973f 377This means reset FACE to its value in FROM-THEME."
a3997907 378 (apply 'custom-theme-reset-faces 'user args))
d543e20b
PA
379
380;;; The End.
381
382(provide 'cus-face)
383
cbee283d 384;; arch-tag: 9a5c4b63-0d27-4c92-a5af-f2c7ed764c2b
1743c17a 385;;; cus-face.el ends here