1 ;;; cus-face.el --- customization support for faces
3 ;; Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
6 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
7 ;; Keywords: help, faces
9 ;; This file is part of GNU Emacs.
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
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
30 (defalias 'custom-facep
'facep
)
34 (defun custom-declare-face (face spec doc
&rest args
)
35 "Like `defface', but FACE is evaluated as a normal argument."
36 (unless (get face
'face-defface-spec
)
37 (when (fboundp 'facep
)
39 ;; If the user has already created the face, respect that.
40 (let ((value (or (get face
'saved-face
) spec
))
41 (have-window-system (memq initial-window-system
'(x w32
))))
42 ;; Create global face.
43 (make-empty-face face
)
44 ;; Create frame-local faces
45 (dolist (frame (frame-list))
46 (face-spec-set-2 face frame value
)
47 (when (memq (window-system frame
) '(x w32 ns
))
48 (setq have-window-system t
)))
49 ;; When making a face after frames already exist
50 (if have-window-system
51 (make-face-x-resource-internal face
)))))
52 ;; Don't record SPEC until we see it causes no errors.
53 (put face
'face-defface-spec
(purecopy spec
))
54 (push (cons 'defface face
) current-load-list
)
55 (when (and doc
(null (face-documentation face
)))
56 (set-face-documentation face
(purecopy doc
)))
57 (custom-handle-all-keywords face args
'custom-face
)
58 (run-hooks 'custom-define-hook
))
63 (defconst custom-face-attributes
65 (string :tag
"Font Family"
66 :help-echo
"Font family or fontset alias name."))
69 (string :tag
"Font Foundry"
70 :help-echo
"Font foundry name."))
74 :help-echo
"Font width."
75 :value normal
; default
76 (const :tag
"compressed" condensed
)
77 (const :tag
"condensed" condensed
)
78 (const :tag
"demiexpanded" semi-expanded
)
79 (const :tag
"expanded" expanded
)
80 (const :tag
"extracondensed" extra-condensed
)
81 (const :tag
"extraexpanded" extra-expanded
)
82 (const :tag
"medium" normal
)
83 (const :tag
"narrow" condensed
)
84 (const :tag
"normal" normal
)
85 (const :tag
"regular" normal
)
86 (const :tag
"semicondensed" semi-condensed
)
87 (const :tag
"semiexpanded" semi-expanded
)
88 (const :tag
"ultracondensed" ultra-condensed
)
89 (const :tag
"ultraexpanded" ultra-expanded
)
90 (const :tag
"wide" extra-expanded
)))
94 :help-echo
"Face's font height."
96 (integer :tag
"Height in 1/10 pt")
97 (number :tag
"Scale" 1.0)))
100 (choice :tag
"Weight"
101 :help-echo
"Font weight."
102 :value normal
; default
103 (const :tag
"black" ultra-bold
)
104 (const :tag
"bold" bold
)
105 (const :tag
"book" semi-light
)
106 (const :tag
"demibold" semi-bold
)
107 (const :tag
"extralight" extra-light
)
108 (const :tag
"extrabold" extra-bold
)
109 (const :tag
"heavy" extra-bold
)
110 (const :tag
"light" light
)
111 (const :tag
"medium" normal
)
112 (const :tag
"normal" normal
)
113 (const :tag
"regular" normal
)
114 (const :tag
"semibold" semi-bold
)
115 (const :tag
"semilight" semi-light
)
116 (const :tag
"ultralight" ultra-light
)
117 (const :tag
"ultrabold" ultra-bold
)
118 (const :tag
"thin" thin
)))
122 :help-echo
"Font slant."
123 :value normal
; default
124 (const :tag
"italic" italic
)
125 (const :tag
"oblique" oblique
)
126 (const :tag
"normal" normal
)
127 (const :tag
"roman" roman
)))
130 (choice :tag
"Underline"
131 :help-echo
"Control text underlining."
132 (const :tag
"Off" nil
)
134 (color :tag
"Colored")))
137 (choice :tag
"Overline"
138 :help-echo
"Control text overlining."
139 (const :tag
"Off" nil
)
141 (color :tag
"Colored")))
144 (choice :tag
"Strike-through"
145 :help-echo
"Control text strike-through."
146 (const :tag
"Off" nil
)
148 (color :tag
"Colored")))
151 ;; Fixme: this can probably be done better.
152 (choice :tag
"Box around text"
153 :help-echo
"Control box around text."
154 (const :tag
"Off" nil
)
156 :value
(:line-width
2 :color
"grey75" :style released-button
)
157 (const :format
"" :value
:line-width
)
158 (integer :tag
"Width")
159 (const :format
"" :value
:color
)
160 (choice :tag
"Color" (const :tag
"*" nil
) color
)
161 (const :format
"" :value
:style
)
163 (const :tag
"Raised" released-button
)
164 (const :tag
"Sunken" pressed-button
)
165 (const :tag
"None" nil
))))
166 ;; filter to make value suitable for customize
170 (or (and (consp real-value
)
171 (plist-get real-value
:line-width
))
172 (and (integerp real-value
) real-value
)
175 (or (and (consp real-value
) (plist-get real-value
:color
))
176 (and (stringp real-value
) real-value
)
179 (and (consp real-value
) (plist-get real-value
:style
))))
180 (list :line-width lwidth
:color color
:style style
))))
181 ;; filter to make customized-value suitable for storing
184 (let ((lwidth (plist-get cus-value
:line-width
))
185 (color (plist-get cus-value
:color
))
186 (style (plist-get cus-value
:style
)))
187 (cond ((and (null color
) (null style
))
189 ((and (null lwidth
) (null style
))
190 ;; actually can't happen, because LWIDTH is always an int
193 ;; Keep as a plist, but remove null entries
194 (nconc (and lwidth
`(:line-width
,lwidth
))
195 (and color
`(:color
,color
))
196 (and style
`(:style
,style
)))))))))
199 (choice :tag
"Inverse-video"
200 :help-echo
"Control whether text should be in inverse-video."
201 (const :tag
"Off" nil
)
202 (const :tag
"On" t
)))
205 (color :tag
"Foreground"
206 :help-echo
"Set foreground color (name or #RRGGBB hex spec)."))
209 (color :tag
"Background"
210 :help-echo
"Set background color (name or #RRGGBB hex spec)."))
213 (choice :tag
"Stipple"
214 :help-echo
"Background bit-mask"
215 (const :tag
"None" nil
)
217 :help-echo
"Name of bitmap file."
221 (repeat :tag
"Inherit"
222 :help-echo
"List of faces to inherit attributes from."
223 (face :Tag
"Face" default
))
224 ;; filter to make value suitable for customize
226 (cond ((or (null real-value
) (eq real-value
'unspecified
))
228 ((symbolp real-value
)
232 ;; filter to make customized-value suitable for storing
234 (if (and (consp cus-value
) (null (cdr cus-value
)))
238 "Alist of face attributes.
240 The elements are of the form (KEY TYPE PRE-FILTER POST-FILTER),
241 where KEY is the name of the attribute, TYPE is a widget type for
242 editing the attribute, PRE-FILTER is a function to make the attribute's
243 value suitable for the customization widget, and POST-FILTER is a
244 function to make the customized value suitable for storing. PRE-FILTER
245 and POST-FILTER are optional.
247 The PRE-FILTER should take a single argument, the attribute value as
248 stored, and should return a value for customization (using the
249 customization type TYPE).
251 The POST-FILTER should also take a single argument, the value after
252 being customized, and should return a value suitable for setting the
253 given face attribute.")
255 (defun custom-face-attributes-get (face frame
)
256 "For FACE on FRAME, return an alternating list describing its attributes.
257 The list has the form (KEYWORD VALUE KEYWORD VALUE...).
258 Each keyword should be listed in `custom-face-attributes'.
260 If FRAME is nil, use the global defaults for FACE."
261 (let ((attrs custom-face-attributes
)
264 (let* ((attribute (car (car attrs
)))
265 (value (face-attribute face attribute frame
)))
266 (setq attrs
(cdr attrs
))
267 (unless (or (eq value
'unspecified
)
268 (and (null value
) (memq attribute
'(:inherit
))))
269 (setq plist
(cons attribute
(cons value plist
))))))
274 (defun custom-set-faces (&rest args
)
275 "Initialize faces according to user preferences.
276 This associates the settings with the `user' theme.
277 The arguments should be a list where each entry has the form:
279 (FACE SPEC [NOW [COMMENT]])
281 SPEC is stored as the saved value for FACE, as well as the value for the
282 `user' theme. The `user' theme is one of the default themes known to Emacs.
283 See `custom-known-themes' for more information on the known themes.
284 See `custom-theme-set-faces' for more information on the interplay
285 between themes and faces.
286 See `defface' for the format of SPEC.
288 If NOW is present and non-nil, FACE is created now, according to SPEC.
289 COMMENT is a string comment about FACE."
290 (apply 'custom-theme-set-faces
'user args
))
292 (defun custom-theme-set-faces (theme &rest args
)
293 "Initialize faces for theme THEME.
294 The arguments should be a list where each entry has the form:
296 (FACE SPEC [NOW [COMMENT]])
298 SPEC is stored as the saved value for FACE, as well as the value for the
299 `user' theme. The `user' theme is one of the default themes known to Emacs.
300 See `custom-known-themes' for more information on the known themes.
301 See `custom-theme-set-faces' for more information on the interplay
302 between themes and faces.
303 See `defface' for the format of SPEC.
305 If NOW is present and non-nil, FACE is created now, according to SPEC.
306 COMMENT is a string comment about FACE.
308 Several properties of THEME and FACE are used in the process:
310 If THEME property `theme-immediate' is non-nil, this is equivalent of
311 providing the NOW argument to all faces in the argument list: FACE is
312 created now. The only difference is FACE property `force-face': if NOW
313 is non-nil, FACE property `force-face' is set to the symbol `rogue', else
314 if THEME property `theme-immediate' is non-nil, FACE property `force-face'
315 is set to the symbol `immediate'.
317 SPEC itself is saved in FACE property `saved-face' and it is stored in
318 FACE's list property `theme-face' \(using `custom-push-theme')."
319 (custom-check-theme theme
)
320 (let ((immediate (get theme
'theme-immediate
)))
322 (let ((entry (car args
)))
324 (let ((face (nth 0 entry
))
327 (comment (nth 3 entry
))
329 ;; If FACE is actually an alias, customize the face it
331 (if (get face
'face-alias
)
332 (setq face
(get face
'face-alias
)))
334 (setq oldspec
(get face
'theme-face
))
335 (when (not (and oldspec
(eq 'user
(caar oldspec
))))
336 (put face
'saved-face spec
)
337 (put face
'saved-face-comment comment
))
339 (custom-push-theme 'theme-face face theme
'set spec
)
340 (when (or now immediate
)
341 (put face
'force-face
(if now
'rogue
'immediate
)))
342 (when (or now immediate
(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
))
348 (setq args
(cdr args
)))
349 ;; Old format, a plist of FACE SPEC pairs.
350 (let ((face (nth 0 args
))
352 (if (get face
'face-alias
)
353 (setq face
(get face
'face-alias
)))
354 (put face
'saved-face spec
)
355 (custom-push-theme 'theme-face face theme
'set spec
))
356 (setq args
(cdr (cdr args
))))))))
358 ;; XEmacs compability function. In XEmacs, when you reset a Custom
359 ;; Theme, you have to specify the theme to reset it to. We just apply
361 (defun custom-theme-reset-faces (theme &rest args
)
362 "Reset the specs in THEME of some faces to their specs in other themes.
363 Each of the arguments ARGS has this form:
367 This means reset FACE. The argument IGNORED is ignored."
368 (custom-check-theme theme
)
370 (custom-push-theme 'theme-face
(car arg
) theme
'reset
)))
372 (defun custom-reset-faces (&rest args
)
373 "Reset the specs of some faces to their specs in specified themes.
374 This creates settings in the `user' theme.
376 Each of the arguments ARGS has this form:
380 This means reset FACE to its value in FROM-THEME."
381 (apply 'custom-theme-reset-faces
'user args
))
387 ;; arch-tag: 9a5c4b63-0d27-4c92-a5af-f2c7ed764c2b
388 ;;; cus-face.el ends here