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