(custom-face-set): Don't copy an empty face,
[bpt/emacs.git] / lisp / faces.el
CommitLineData
465fceed
ER
1;;; faces.el --- Lisp interface to the c "face" structure
2
b578f267 3;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
465fceed
ER
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 2, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
b578f267
EN
18;; along with GNU Emacs; see the file COPYING. If not, write to the
19;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20;; Boston, MA 02111-1307, USA.
465fceed
ER
21
22;;; Commentary:
23
24;; Mostly derived from Lucid.
25
26;;; Code:
27
39b3b754
RS
28(eval-when-compile
29 ;; These used to be defsubsts, now they're subrs. Avoid losing if we're
30 ;; being compiled with an old Emacs that still has defsubrs in it.
31 (put 'face-name 'byte-optimizer nil)
32 (put 'face-id 'byte-optimizer nil)
33 (put 'face-font 'byte-optimizer nil)
34 (put 'face-foreground 'byte-optimizer nil)
35 (put 'face-background 'byte-optimizer nil)
36 (put 'face-stipple 'byte-optimizer nil)
37 (put 'face-underline-p 'byte-optimizer nil)
38 (put 'set-face-font 'byte-optimizer nil)
39 (put 'set-face-foreground 'byte-optimizer nil)
40 (put 'set-face-background 'byte-optimizer nil)
ca58b3ec 41 (put 'set-face-stipple 'byte-optimizer nil)
39b3b754 42 (put 'set-face-underline-p 'byte-optimizer nil))
bdda3754
JB
43\f
44;;;; Functions for manipulating face vectors.
45
46;;; A face vector is a vector of the form:
72418504 47;;; [face NAME ID FONT FOREGROUND BACKGROUND STIPPLE UNDERLINE]
bdda3754
JB
48
49;;; Type checkers.
465fceed
ER
50(defsubst internal-facep (x)
51 (and (vectorp x) (= (length x) 8) (eq (aref x 0) 'face)))
52
962a60aa
RS
53(defun facep (x)
54 "Return t if X is a face name or an internal face vector."
55 (and (or (internal-facep x)
56 (and (symbolp x) (assq x global-face-data)))
57 t))
58
465fceed 59(defmacro internal-check-face (face)
962a60aa
RS
60 (` (or (internal-facep (, face))
61 (signal 'wrong-type-argument (list 'internal-facep (, face))))))
465fceed 62
bdda3754 63;;; Accessors.
feaad827 64(defun face-name (face)
465fceed
ER
65 "Return the name of face FACE."
66 (aref (internal-get-face face) 1))
67
feaad827 68(defun face-id (face)
465fceed
ER
69 "Return the internal ID number of face FACE."
70 (aref (internal-get-face face) 2))
71
feaad827 72(defun face-font (face &optional frame)
465fceed
ER
73 "Return the font name of face FACE, or nil if it is unspecified.
74If the optional argument FRAME is given, report on face FACE in that frame.
f3f31ccf
RS
75If FRAME is t, report on the defaults for face FACE (for new frames).
76 The font default for a face is either nil, or a list
77 of the form (bold), (italic) or (bold italic).
78If FRAME is omitted or nil, use the selected frame."
465fceed
ER
79 (aref (internal-get-face face frame) 3))
80
feaad827 81(defun face-foreground (face &optional frame)
465fceed
ER
82 "Return the foreground color name of face FACE, or nil if unspecified.
83If the optional argument FRAME is given, report on face FACE in that frame.
f3f31ccf
RS
84If FRAME is t, report on the defaults for face FACE (for new frames).
85If FRAME is omitted or nil, use the selected frame."
465fceed
ER
86 (aref (internal-get-face face frame) 4))
87
feaad827 88(defun face-background (face &optional frame)
465fceed
ER
89 "Return the background color name of face FACE, or nil if unspecified.
90If the optional argument FRAME is given, report on face FACE in that frame.
f3f31ccf
RS
91If FRAME is t, report on the defaults for face FACE (for new frames).
92If FRAME is omitted or nil, use the selected frame."
465fceed
ER
93 (aref (internal-get-face face frame) 5))
94
feaad827 95(defun face-stipple (face &optional frame)
72418504
RS
96 "Return the stipple pixmap name of face FACE, or nil if unspecified.
97If the optional argument FRAME is given, report on face FACE in that frame.
98If FRAME is t, report on the defaults for face FACE (for new frames).
99If FRAME is omitted or nil, use the selected frame."
100 (aref (internal-get-face face frame) 6))
101
102(defalias 'face-background-pixmap 'face-stipple)
465fceed 103
feaad827 104(defun face-underline-p (face &optional frame)
465fceed
ER
105 "Return t if face FACE is underlined.
106If the optional argument FRAME is given, report on face FACE in that frame.
f3f31ccf
RS
107If FRAME is t, report on the defaults for face FACE (for new frames).
108If FRAME is omitted or nil, use the selected frame."
465fceed
ER
109 (aref (internal-get-face face frame) 7))
110
bdda3754
JB
111\f
112;;; Mutators.
465fceed 113
feaad827 114(defun set-face-font (face font &optional frame)
465fceed
ER
115 "Change the font of face FACE to FONT (a string).
116If the optional FRAME argument is provided, change only
117in that frame; otherwise change each frame."
118 (interactive (internal-face-interactive "font"))
3aa3a18c
KH
119 (if (stringp font)
120 (setq font (or (query-fontset font)
121 (x-resolve-font-name font 'default frame))))
10d89673 122 (internal-set-face-1 face 'font font 3 frame))
465fceed 123
feaad827 124(defun set-face-foreground (face color &optional frame)
465fceed
ER
125 "Change the foreground color of face FACE to COLOR (a string).
126If the optional FRAME argument is provided, change only
127in that frame; otherwise change each frame."
128 (interactive (internal-face-interactive "foreground"))
f0138172 129 (internal-set-face-1 face 'foreground color 4 frame))
465fceed 130
ef436392
KH
131(defvar face-default-stipple "gray3"
132 "Default stipple pattern used on monochrome displays.
133This stipple pattern is used on monochrome displays
134instead of shades of gray for a face background color.
135See `set-face-stipple' for possible values for this variable.")
136
137(defun face-color-gray-p (color &optional frame)
138 "Return t if COLOR is a shade of gray (or white or black).
139FRAME specifies the frame and thus the display for interpreting COLOR."
140 (let* ((values (x-color-values color frame))
141 (r (nth 0 values))
142 (g (nth 1 values))
143 (b (nth 2 values)))
25ae394e
RS
144 (and values
145 (< (abs (- r g)) (/ (max 1 (abs r) (abs g)) 20))
ef436392
KH
146 (< (abs (- g b)) (/ (max 1 (abs g) (abs b)) 20))
147 (< (abs (- b r)) (/ (max 1 (abs b) (abs r)) 20)))))
148
feaad827 149(defun set-face-background (face color &optional frame)
465fceed
ER
150 "Change the background color of face FACE to COLOR (a string).
151If the optional FRAME argument is provided, change only
152in that frame; otherwise change each frame."
153 (interactive (internal-face-interactive "background"))
ee09252a
RS
154 ;; For a specific frame, use gray stipple instead of gray color
155 ;; if the display does not support a gray color.
21ef90ee 156 (if (and frame (not (eq frame t)) color
a7acbbe4 157 ;; Check for support for foreground, not for background!
f1d71b2f
RS
158 ;; face-color-supported-p is smart enough to know
159 ;; that grays are "supported" as background
160 ;; because we are supposed to use stipple for them!
161 (not (face-color-supported-p frame color nil)))
ef436392 162 (set-face-stipple face face-default-stipple frame)
d0672e0d
RS
163 (if (null frame)
164 (let ((frames (frame-list)))
165 (while frames
166 (set-face-background (face-name face) color (car frames))
167 (setq frames (cdr frames)))
168 (set-face-background face color t)
169 color)
170 (internal-set-face-1 face 'background color 5 frame))))
465fceed 171
ef436392 172(defun set-face-stipple (face pixmap &optional frame)
72418504
RS
173 "Change the stipple pixmap of face FACE to PIXMAP.
174PIXMAP should be a string, the name of a file of pixmap data.
175The directories listed in the `x-bitmap-file-path' variable are searched.
465fceed 176
72418504
RS
177Alternatively, PIXMAP may be a list of the form (WIDTH HEIGHT DATA)
178where WIDTH and HEIGHT are the size in pixels,
179and DATA is a string, containing the raw bits of the bitmap.
465fceed 180
72418504
RS
181If the optional FRAME argument is provided, change only
182in that frame; otherwise change each frame."
3c5ddb48 183 (interactive (internal-face-interactive-stipple "stipple"))
ef436392 184 (internal-set-face-1 face 'background-pixmap pixmap 6 frame))
72418504
RS
185
186(defalias 'set-face-background-pixmap 'set-face-stipple)
465fceed 187
feaad827 188(defun set-face-underline-p (face underline-p &optional frame)
465fceed
ER
189 "Specify whether face FACE is underlined. (Yes if UNDERLINE-P is non-nil.)
190If the optional FRAME argument is provided, change only
191in that frame; otherwise change each frame."
192 (interactive (internal-face-interactive "underline-p" "underlined"))
f0138172 193 (internal-set-face-1 face 'underline underline-p 7 frame))
1c0a8710 194\f
2b979e14 195(defun modify-face-read-string (face default name alist)
6ffb01c4
RS
196 (let ((value
197 (completing-read
198 (if default
199 (format "Set face %s %s (default %s): "
200 face name (downcase default))
201 (format "Set face %s %s: " face name))
202 alist)))
203 (cond ((equal value "none")
204 nil)
205 ((equal value "")
206 default)
207 (t value))))
208
209(defun modify-face (face foreground background stipple
905cf8f2 210 bold-p italic-p underline-p &optional frame)
1c0a8710 211 "Change the display attributes for face FACE.
905cf8f2
SM
212If the optional FRAME argument is provided, change only
213in that frame; otherwise change each frame.
214
215FOREGROUND and BACKGROUND should be a colour name string (or list of strings to
216try) or nil. STIPPLE should be a stipple pattern name string or nil.
217If nil, means do not change the display attribute corresponding to that arg.
218
1c0a8710 219BOLD-P, ITALIC-P, and UNDERLINE-P specify whether the face should be set bold,
905cf8f2
SM
220in italic, and underlined, respectively. If neither nil or t, means do not
221change the display attribute corresponding to that arg.
222
223If called interactively, prompts for a face name and face attributes."
1c0a8710
RS
224 (interactive
225 (let* ((completion-ignore-case t)
905cf8f2
SM
226 (face (symbol-name (read-face-name "Modify face: ")))
227 (colors (mapcar 'list x-colors))
228 (stipples (mapcar 'list (apply 'nconc
229 (mapcar 'directory-files
230 x-bitmap-file-path))))
231 (foreground (modify-face-read-string
232 face (face-foreground (intern face))
233 "foreground" colors))
234 (background (modify-face-read-string
235 face (face-background (intern face))
236 "background" colors))
e5de0238
RS
237 ;; If the stipple value is a list (WIDTH HEIGHT DATA),
238 ;; represent that as a string by printing it out.
239 (old-stipple-string
240 (if (stringp (face-stipple (intern face)))
241 (face-stipple (intern face))
3c5ddb48
RS
242 (if (face-stipple (intern face))
243 (prin1-to-string (face-stipple (intern face))))))
e5de0238
RS
244 (new-stipple-string
245 (modify-face-read-string
246 face old-stipple-string
247 "stipple" stipples))
248 ;; Convert the stipple value text we read
249 ;; back to a list if it looks like one.
250 ;; This makes the assumption that a pixmap file name
251 ;; won't start with an open-paren.
252 (stipple
3c5ddb48
RS
253 (and new-stipple-string
254 (if (string-match "^(" new-stipple-string)
255 (read new-stipple-string)
256 new-stipple-string)))
257 (bold-p (y-or-n-p (concat "Should face " face " be bold ")))
258 (italic-p (y-or-n-p (concat "Should face " face " be italic ")))
259 (underline-p (y-or-n-p (concat "Should face " face " be underlined ")))
905cf8f2 260 (all-frames-p (y-or-n-p (concat "Modify face " face " in all frames "))))
1c0a8710
RS
261 (message "Face %s: %s" face
262 (mapconcat 'identity
263 (delq nil
264 (list (and foreground (concat (downcase foreground) " foreground"))
265 (and background (concat (downcase background) " background"))
e5de0238 266 (and stipple (concat (downcase new-stipple-string) " stipple"))
1c0a8710
RS
267 (and bold-p "bold") (and italic-p "italic")
268 (and underline-p "underline"))) ", "))
6ffb01c4 269 (list (intern face) foreground background stipple
905cf8f2
SM
270 bold-p italic-p underline-p
271 (if all-frames-p nil (selected-frame)))))
272 (condition-case nil
273 (face-try-color-list 'set-face-foreground face foreground frame)
274 (error nil))
275 (condition-case nil
276 (face-try-color-list 'set-face-background face background frame)
277 (error nil))
278 (condition-case nil
279 (set-face-stipple face stipple frame)
280 (error nil))
281 (cond ((eq bold-p nil) (make-face-unbold face frame t))
282 ((eq bold-p t) (make-face-bold face frame t)))
283 (cond ((eq italic-p nil) (make-face-unitalic face frame t))
284 ((eq italic-p t) (make-face-italic face frame t)))
285 (if (memq underline-p '(nil t))
286 (set-face-underline-p face underline-p frame))
1c0a8710 287 (and (interactive-p) (redraw-display)))
bdda3754
JB
288\f
289;;;; Associating face names (symbols) with their face vectors.
290
66a5c2c6
JB
291(defvar global-face-data nil
292 "Internal data for face support functions. Not for external use.
293This is an alist associating face names with the default values for
294their parameters. Newly created frames get their data from here.")
295
bdda3754
JB
296(defun face-list ()
297 "Returns a list of all defined face names."
298 (mapcar 'car global-face-data))
299
300(defun internal-find-face (name &optional frame)
301 "Retrieve the face named NAME. Return nil if there is no such face.
302If the optional argument FRAME is given, this gets the face NAME for
303that frame; otherwise, it uses the selected frame.
304If FRAME is the symbol t, then the global, non-frame face is returned.
305If NAME is already a face, it is simply returned."
306 (if (and (eq frame t) (not (symbolp name)))
307 (setq name (face-name name)))
308 (if (symbolp name)
309 (cdr (assq name
310 (if (eq frame t)
311 global-face-data
312 (frame-face-alist (or frame (selected-frame))))))
313 (internal-check-face name)
314 name))
315
316(defun internal-get-face (name &optional frame)
317 "Retrieve the face named NAME; error if there is none.
318If the optional argument FRAME is given, this gets the face NAME for
319that frame; otherwise, it uses the selected frame.
320If FRAME is the symbol t, then the global, non-frame face is returned.
321If NAME is already a face, it is simply returned."
322 (or (internal-find-face name frame)
323 (internal-check-face name)))
324
325
326(defun internal-set-face-1 (face name value index frame)
327 (let ((inhibit-quit t))
328 (if (null frame)
329 (let ((frames (frame-list)))
330 (while frames
331 (internal-set-face-1 (face-name face) name value index (car frames))
332 (setq frames (cdr frames)))
333 (aset (internal-get-face (if (symbolp face) face (face-name face)) t)
334 index value)
335 value)
336 (or (eq frame t)
337 (set-face-attribute-internal (face-id face) name value frame))
338 (aset (internal-get-face face frame) index value))))
339
340
341(defun read-face-name (prompt)
342 (let (face)
343 (while (= (length face) 0)
344 (setq face (completing-read prompt
345 (mapcar '(lambda (x) (list (symbol-name x)))
346 (face-list))
347 nil t)))
348 (intern face)))
349
350(defun internal-face-interactive (what &optional bool)
351 (let* ((fn (intern (concat "face-" what)))
352 (prompt (concat "Set " what " of face"))
353 (face (read-face-name (concat prompt ": ")))
354 (default (if (fboundp fn)
355 (or (funcall fn face (selected-frame))
356 (funcall fn 'default (selected-frame)))))
357 (value (if bool
358 (y-or-n-p (concat "Should face " (symbol-name face)
359 " be " bool "? "))
360 (read-string (concat prompt " " (symbol-name face) " to: ")
361 default))))
362 (list face (if (equal value "") nil value))))
363
3c5ddb48
RS
364(defun internal-face-interactive-stipple (what)
365 (let* ((fn (intern (concat "face-" what)))
366 (prompt (concat "Set " what " of face"))
367 (face (read-face-name (concat prompt ": ")))
368 (default (if (fboundp fn)
369 (or (funcall fn face (selected-frame))
370 (funcall fn 'default (selected-frame)))))
371 ;; If the stipple value is a list (WIDTH HEIGHT DATA),
372 ;; represent that as a string by printing it out.
373 (old-stipple-string
374 (if (stringp (face-stipple face))
375 (face-stipple face)
376 (if (null (face-stipple face))
377 nil
378 (prin1-to-string (face-stipple face)))))
379 (new-stipple-string
380 (read-string
381 (concat prompt " " (symbol-name face) " to: ")
382 old-stipple-string))
383 ;; Convert the stipple value text we read
384 ;; back to a list if it looks like one.
385 ;; This makes the assumption that a pixmap file name
386 ;; won't start with an open-paren.
387 (stipple
388 (if (string-match "^(" new-stipple-string)
389 (read new-stipple-string)
390 new-stipple-string)))
391 (list face (if (equal stipple "") nil stipple))))
465fceed 392
17b3a11b 393(defun make-face (name &optional no-resources)
465fceed
ER
394 "Define a new FACE on all frames.
395You can modify the font, color, etc of this face with the set-face- functions.
17b3a11b
RS
396If NO-RESOURCES is non-nil, then we ignore X resources
397and always make a face whose attributes are all nil.
398
465fceed 399If the face already exists, it is unmodified."
19fac299 400 (interactive "SMake face: ")
465fceed
ER
401 (or (internal-find-face name)
402 (let ((face (make-vector 8 nil)))
403 (aset face 0 'face)
404 (aset face 1 name)
405 (let* ((frames (frame-list))
406 (inhibit-quit t)
407 (id (internal-next-face-id)))
408 (make-face-internal id)
409 (aset face 2 id)
410 (while frames
411 (set-frame-face-alist (car frames)
412 (cons (cons name (copy-sequence face))
413 (frame-face-alist (car frames))))
414 (setq frames (cdr frames)))
415 (setq global-face-data (cons (cons name face) global-face-data)))
17b3a11b
RS
416 ;; When making a face after frames already exist
417 (or no-resources
418 (if (memq window-system '(x w32))
419 (make-face-x-resource-internal face)))
420 ;; Add to menu of faces.
33af44e8
BG
421 (if (fboundp 'facemenu-add-new-face)
422 (facemenu-add-new-face name))
7ee29ed8
RS
423 face))
424 name)
465fceed 425
17b3a11b
RS
426(defun make-empty-face (face)
427 "Define a new FACE on all frames, which initially reflects the defaults.
428You can modify the font, color, etc of this face with the set-face- functions.
429If the face already exists, it is unmodified."
430 (interactive "SMake empty face: ")
431 (make-face face t))
432
465fceed
ER
433;; Fill in a face by default based on X resources, for all existing frames.
434;; This has to be done when a new face is made.
435(defun make-face-x-resource-internal (face &optional frame set-anyway)
436 (cond ((null frame)
437 (let ((frames (frame-list)))
438 (while frames
b86b9918 439 (if (memq (framep (car frames)) '(x w32))
586ab698
RS
440 (make-face-x-resource-internal (face-name face)
441 (car frames) set-anyway))
465fceed
ER
442 (setq frames (cdr frames)))))
443 (t
444 (setq face (internal-get-face (face-name face) frame))
445 ;;
446 ;; These are things like "attributeForeground" instead of simply
447 ;; "foreground" because people tend to do things like "*foreground",
448 ;; which would cause all faces to be fully qualified, making faces
449 ;; inherit attributes in a non-useful way. So we've made them slightly
450 ;; less obvious to specify in order to make them work correctly in
451 ;; more random environments.
452 ;;
453 ;; I think these should be called "face.faceForeground" instead of
454 ;; "face.attributeForeground", but they're the way they are for
455 ;; hysterical reasons.
456 ;;
457 (let* ((name (symbol-name (face-name face)))
458 (fn (or (x-get-resource (concat name ".attributeFont")
459 "Face.AttributeFont")
460 (and set-anyway (face-font face))))
461 (fg (or (x-get-resource (concat name ".attributeForeground")
462 "Face.AttributeForeground")
463 (and set-anyway (face-foreground face))))
464 (bg (or (x-get-resource (concat name ".attributeBackground")
465 "Face.AttributeBackground")
466 (and set-anyway (face-background face))))
72418504
RS
467 (bgp (or (x-get-resource (concat name ".attributeStipple")
468 "Face.AttributeStipple")
469 (x-get-resource (concat name ".attributeBackgroundPixmap")
470 "Face.AttributeBackgroundPixmap")
471 (and set-anyway (face-stipple face))))
69718e9d
RS
472 (ulp (let ((resource (x-get-resource
473 (concat name ".attributeUnderline")
474 "Face.AttributeUnderline")))
475 (if resource
476 (member (downcase resource) '("on" "true"))
477 (and set-anyway (face-underline-p face)))))
465fceed
ER
478 )
479 (if fn
480 (condition-case ()
19deb21e
RS
481 (cond ((string= fn "italic")
482 (make-face-italic face))
483 ((string= fn "bold")
484 (make-face-bold face))
485 ((string= fn "bold-italic")
486 (make-face-bold-italic face))
487 (t
488 (set-face-font face fn frame)))
489 (error
490 (if (member fn '("italic" "bold" "bold-italic"))
491 (message "no %s version found for face `%s'" fn name)
492 (message "font `%s' not found for face `%s'" fn name)))))
465fceed
ER
493 (if fg
494 (condition-case ()
495 (set-face-foreground face fg frame)
496 (error (message "color `%s' not allocated for face `%s'" fg name))))
497 (if bg
498 (condition-case ()
499 (set-face-background face bg frame)
500 (error (message "color `%s' not allocated for face `%s'" bg name))))
72418504
RS
501 (if bgp
502 (condition-case ()
503 (set-face-stipple face bgp frame)
504 (error (message "pixmap `%s' not found for face `%s'" bgp name))))
465fceed
ER
505 (if (or ulp set-anyway)
506 (set-face-underline-p face ulp frame))
507 )))
508 face)
509
2f2ddd1e
RS
510(defun copy-face (old-face new-face &optional frame new-frame)
511 "Define a face just like OLD-FACE, with name NEW-FACE.
512If NEW-FACE already exists as a face, it is modified to be like OLD-FACE.
513If it doesn't already exist, it is created.
514
515If the optional argument FRAME is given as a frame,
516NEW-FACE is changed on FRAME only.
517If FRAME is t, the frame-independent default specification for OLD-FACE
518is copied to NEW-FACE.
519If FRAME is nil, copying is done for the frame-independent defaults
520and for each existing frame.
710e7005
RS
521If the optional fourth argument NEW-FRAME is given,
522copy the information from face OLD-FACE on frame FRAME
2f2ddd1e 523to NEW-FACE on frame NEW-FRAME."
710e7005 524 (or new-frame (setq new-frame frame))
da41135a 525 (let ((inhibit-quit t))
465fceed
ER
526 (if (null frame)
527 (let ((frames (frame-list)))
528 (while frames
2f2ddd1e 529 (copy-face old-face new-face (car frames))
465fceed 530 (setq frames (cdr frames)))
2f2ddd1e 531 (copy-face old-face new-face t))
da41135a
KH
532 (setq old-face (internal-get-face old-face frame))
533 (setq new-face (or (internal-find-face new-face new-frame)
534 (make-face new-face)))
52267b56
RS
535 (condition-case nil
536 ;; A face that has a global symbolic font modifier such as `bold'
537 ;; might legitimately get an error here.
538 ;; Use the frame's default font in that case.
539 (set-face-font new-face (face-font old-face frame) new-frame)
540 (error
541 (set-face-font new-face nil new-frame)))
710e7005
RS
542 (set-face-foreground new-face (face-foreground old-face frame) new-frame)
543 (set-face-background new-face (face-background old-face frame) new-frame)
72418504
RS
544 (set-face-stipple new-face
545 (face-stipple old-face frame)
546 new-frame)
465fceed 547 (set-face-underline-p new-face (face-underline-p old-face frame)
710e7005 548 new-frame))
465fceed
ER
549 new-face))
550
551(defun face-equal (face1 face2 &optional frame)
ade516a1 552 "True if the faces FACE1 and FACE2 display in the same way."
465fceed
ER
553 (setq face1 (internal-get-face face1 frame)
554 face2 (internal-get-face face2 frame))
555 (and (equal (face-foreground face1 frame) (face-foreground face2 frame))
556 (equal (face-background face1 frame) (face-background face2 frame))
557 (equal (face-font face1 frame) (face-font face2 frame))
ae0249df 558 (eq (face-underline-p face1 frame) (face-underline-p face2 frame))
72418504
RS
559 (equal (face-stipple face1 frame)
560 (face-stipple face2 frame))))
465fceed
ER
561
562(defun face-differs-from-default-p (face &optional frame)
563 "True if face FACE displays differently from the default face, on FRAME.
564A face is considered to be ``the same'' as the default face if it is
565actually specified in the same way (equivalent fonts, etc) or if it is
566fully unspecified, and thus inherits the attributes of any face it
93d6fcef
RS
567is displayed on top of.
568
569The optional argument FRAME specifies which frame to test;
570if FRAME is t, test the default for new frames.
571If FRAME is nil or omitted, test the selected frame."
465fceed
ER
572 (let ((default (internal-get-face 'default frame)))
573 (setq face (internal-get-face face frame))
574 (not (and (or (equal (face-foreground default frame)
575 (face-foreground face frame))
576 (null (face-foreground face frame)))
577 (or (equal (face-background default frame)
578 (face-background face frame))
579 (null (face-background face frame)))
fbd44116
SM
580 (or (null (face-font face frame))
581 (equal (face-font face frame)
582 (or (face-font default frame)
583 (downcase
584 (cdr (assq 'font (frame-parameters frame)))))))
72418504
RS
585 (or (equal (face-stipple default frame)
586 (face-stipple face frame))
587 (null (face-stipple face frame)))
465fceed
ER
588 (equal (face-underline-p default frame)
589 (face-underline-p face frame))
590 ))))
591
93d6fcef
RS
592(defun face-nontrivial-p (face &optional frame)
593 "True if face FACE has some non-nil attribute.
594The optional argument FRAME specifies which frame to test;
595if FRAME is t, test the default for new frames.
596If FRAME is nil or omitted, test the selected frame."
597 (setq face (internal-get-face face frame))
598 (or (face-foreground face frame)
599 (face-background face frame)
600 (face-font face frame)
601 (face-stipple face frame)
602 (face-underline-p face frame)))
603
465fceed
ER
604
605(defun invert-face (face &optional frame)
606 "Swap the foreground and background colors of face FACE.
607If the face doesn't specify both foreground and background, then
8494bbf1 608set its foreground and background to the default background and foreground."
465fceed
ER
609 (interactive (list (read-face-name "Invert face: ")))
610 (setq face (internal-get-face face frame))
611 (let ((fg (face-foreground face frame))
612 (bg (face-background face frame)))
613 (if (or fg bg)
614 (progn
615 (set-face-foreground face bg frame)
616 (set-face-background face fg frame))
c5f0b2d4
RS
617 (let* ((frame-bg (cdr (assq 'background-color (frame-parameters frame))))
618 (default-bg (or (face-background 'default frame)
619 frame-bg))
620 (frame-fg (cdr (assq 'foreground-color (frame-parameters frame))))
621 (default-fg (or (face-foreground 'default frame)
622 frame-fg)))
623 (set-face-foreground face default-bg frame)
624 (set-face-background face default-fg frame))))
465fceed
ER
625 face)
626
627
628(defun internal-try-face-font (face font &optional frame)
629 "Like set-face-font, but returns nil on failure instead of an error."
630 (condition-case ()
631 (set-face-font face font frame)
632 (error nil)))
465fceed
ER
633\f
634;; Manipulating font names.
635
d7fa5aa2
RS
636(defvar x-font-regexp nil)
637(defvar x-font-regexp-head nil)
638(defvar x-font-regexp-weight nil)
639(defvar x-font-regexp-slant nil)
465fceed 640
021ca129
KH
641(defconst x-font-regexp-weight-subnum 1)
642(defconst x-font-regexp-slant-subnum 2)
643(defconst x-font-regexp-swidth-subnum 3)
644(defconst x-font-regexp-adstyle-subnum 4)
645
465fceed
ER
646;;; Regexps matching font names in "Host Portable Character Representation."
647;;;
648(let ((- "[-?]")
649 (foundry "[^-]+")
650 (family "[^-]+")
651 (weight "\\(bold\\|demibold\\|medium\\)") ; 1
652; (weight\? "\\(\\*\\|bold\\|demibold\\|medium\\|\\)") ; 1
653 (weight\? "\\([^-]*\\)") ; 1
654 (slant "\\([ior]\\)") ; 2
655; (slant\? "\\([ior?*]?\\)") ; 2
656 (slant\? "\\([^-]?\\)") ; 2
657; (swidth "\\(\\*\\|normal\\|semicondensed\\|\\)") ; 3
658 (swidth "\\([^-]*\\)") ; 3
659; (adstyle "\\(\\*\\|sans\\|\\)") ; 4
c8787b81 660 (adstyle "\\([^-]*\\)") ; 4
465fceed
ER
661 (pixelsize "[0-9]+")
662 (pointsize "[0-9][0-9]+")
663 (resx "[0-9][0-9]+")
664 (resy "[0-9][0-9]+")
665 (spacing "[cmp?*]")
666 (avgwidth "[0-9]+")
667 (registry "[^-]+")
668 (encoding "[^-]+")
669 )
670 (setq x-font-regexp
671 (concat "\\`\\*?[-?*]"
672 foundry - family - weight\? - slant\? - swidth - adstyle -
e20d641f
RS
673 pixelsize - pointsize - resx - resy - spacing - avgwidth -
674 registry - encoding "\\*?\\'"
465fceed
ER
675 ))
676 (setq x-font-regexp-head
677 (concat "\\`[-?*]" foundry - family - weight\? - slant\?
678 "\\([-*?]\\|\\'\\)"))
679 (setq x-font-regexp-slant (concat - slant -))
680 (setq x-font-regexp-weight (concat - weight -))
681 nil)
682
281dc1c2
JB
683(defun x-resolve-font-name (pattern &optional face frame)
684 "Return a font name matching PATTERN.
685All wildcards in PATTERN become substantiated.
10d89673
JB
686If PATTERN is nil, return the name of the frame's base font, which never
687contains wildcards.
e17dbede
RS
688Given optional arguments FACE and FRAME, return a font which is
689also the same size as FACE on FRAME, or fail."
14e6867c
RS
690 (or (symbolp face)
691 (setq face (face-name face)))
692 (and (eq frame t)
693 (setq frame nil))
10d89673 694 (if pattern
8db93e45 695 ;; Note that x-list-fonts has code to handle a face with nil as its font.
abd89b80 696 (let ((fonts (x-list-fonts pattern face frame 1)))
10d89673
JB
697 (or fonts
698 (if face
962a60aa
RS
699 (if (string-match "\\*" pattern)
700 (if (null (face-font face))
701 (error "No matching fonts are the same height as the frame default font")
702 (error "No matching fonts are the same height as face `%s'" face))
703 (if (null (face-font face))
704 (error "Height of font `%s' doesn't match the frame default font"
705 pattern)
706 (error "Height of font `%s' doesn't match face `%s'"
707 pattern face)))
7cf6fac1 708 (error "No fonts match `%s'" pattern)))
10d89673
JB
709 (car fonts))
710 (cdr (assq 'font (frame-parameters (selected-frame))))))
281dc1c2 711
465fceed 712(defun x-frob-font-weight (font which)
b7ffee5f
SM
713 (let ((case-fold-search t))
714 (cond ((string-match x-font-regexp font)
715 (concat (substring font 0
716 (match-beginning x-font-regexp-weight-subnum))
717 which
718 (substring font (match-end x-font-regexp-weight-subnum)
719 (match-beginning x-font-regexp-adstyle-subnum))
720 ;; Replace the ADD_STYLE_NAME field with *
721 ;; because the info in it may not be the same
722 ;; for related fonts.
723 "*"
724 (substring font (match-end x-font-regexp-adstyle-subnum))))
528fbf51
RS
725 ((string-match x-font-regexp-head font)
726 (concat (substring font 0 (match-beginning 1)) which
727 (substring font (match-end 1))))
728 ((string-match x-font-regexp-weight font)
b7ffee5f
SM
729 (concat (substring font 0 (match-beginning 1)) which
730 (substring font (match-end 1)))))))
465fceed
ER
731
732(defun x-frob-font-slant (font which)
b7ffee5f
SM
733 (let ((case-fold-search t))
734 (cond ((string-match x-font-regexp font)
735 (concat (substring font 0
736 (match-beginning x-font-regexp-slant-subnum))
737 which
738 (substring font (match-end x-font-regexp-slant-subnum)
739 (match-beginning x-font-regexp-adstyle-subnum))
740 ;; Replace the ADD_STYLE_NAME field with *
741 ;; because the info in it may not be the same
742 ;; for related fonts.
743 "*"
744 (substring font (match-end x-font-regexp-adstyle-subnum))))
528fbf51
RS
745 ((string-match x-font-regexp-head font)
746 (concat (substring font 0 (match-beginning 2)) which
747 (substring font (match-end 2))))
748 ((string-match x-font-regexp-slant font)
b7ffee5f
SM
749 (concat (substring font 0 (match-beginning 1)) which
750 (substring font (match-end 1)))))))
465fceed
ER
751
752(defun x-make-font-bold (font)
f3f31ccf
RS
753 "Given an X font specification, make a bold version of it.
754If that can't be done, return nil."
465fceed
ER
755 (x-frob-font-weight font "bold"))
756
757(defun x-make-font-demibold (font)
f3f31ccf
RS
758 "Given an X font specification, make a demibold version of it.
759If that can't be done, return nil."
465fceed
ER
760 (x-frob-font-weight font "demibold"))
761
762(defun x-make-font-unbold (font)
f3f31ccf
RS
763 "Given an X font specification, make a non-bold version of it.
764If that can't be done, return nil."
465fceed
ER
765 (x-frob-font-weight font "medium"))
766
767(defun x-make-font-italic (font)
f3f31ccf
RS
768 "Given an X font specification, make an italic version of it.
769If that can't be done, return nil."
465fceed
ER
770 (x-frob-font-slant font "i"))
771
772(defun x-make-font-oblique (font) ; you say tomayto...
f3f31ccf
RS
773 "Given an X font specification, make an oblique version of it.
774If that can't be done, return nil."
465fceed
ER
775 (x-frob-font-slant font "o"))
776
777(defun x-make-font-unitalic (font)
f3f31ccf
RS
778 "Given an X font specification, make a non-italic version of it.
779If that can't be done, return nil."
465fceed 780 (x-frob-font-slant font "r"))
465fceed
ER
781\f
782;;; non-X-specific interface
783
bb9a81fc 784(defun make-face-bold (face &optional frame noerror)
465fceed 785 "Make the font of the given face be bold, if possible.
bb9a81fc 786If NOERROR is non-nil, return nil on failure."
465fceed 787 (interactive (list (read-face-name "Make which face bold: ")))
534dbc97 788 (if (and (eq frame t) (listp (face-font face t)))
f3f31ccf
RS
789 (set-face-font face (if (memq 'italic (face-font face t))
790 '(bold italic) '(bold))
791 t)
488bedff 792 (let (font)
f3f31ccf
RS
793 (if (null frame)
794 (let ((frames (frame-list)))
795 ;; Make this face bold in global-face-data.
796 (make-face-bold face t noerror)
797 ;; Make this face bold in each frame.
798 (while frames
799 (make-face-bold face (car frames) noerror)
800 (setq frames (cdr frames))))
801 (setq face (internal-get-face face frame))
802 (setq font (or (face-font face frame)
803 (face-font face t)))
804 (if (listp font)
805 (setq font nil))
806 (setq font (or font
807 (face-font 'default frame)
808 (cdr (assq 'font (frame-parameters frame)))))
488bedff
RS
809 (or (and font (make-face-bold-internal face frame font))
810 ;; We failed to find a bold version of the font.
811 noerror
812 (error "No bold version of %S" font))))))
f3f31ccf 813
4b3203d9
RS
814(defun make-face-bold-internal (face frame font)
815 (let (f2)
816 (or (and (setq f2 (x-make-font-bold font))
817 (internal-try-face-font face f2 frame))
818 (and (setq f2 (x-make-font-demibold font))
819 (internal-try-face-font face f2 frame)))))
bb9a81fc
JB
820
821(defun make-face-italic (face &optional frame noerror)
465fceed 822 "Make the font of the given face be italic, if possible.
bb9a81fc 823If NOERROR is non-nil, return nil on failure."
465fceed 824 (interactive (list (read-face-name "Make which face italic: ")))
534dbc97 825 (if (and (eq frame t) (listp (face-font face t)))
f3f31ccf
RS
826 (set-face-font face (if (memq 'bold (face-font face t))
827 '(bold italic) '(italic))
828 t)
488bedff 829 (let (font)
f3f31ccf
RS
830 (if (null frame)
831 (let ((frames (frame-list)))
832 ;; Make this face italic in global-face-data.
833 (make-face-italic face t noerror)
834 ;; Make this face italic in each frame.
835 (while frames
836 (make-face-italic face (car frames) noerror)
837 (setq frames (cdr frames))))
838 (setq face (internal-get-face face frame))
839 (setq font (or (face-font face frame)
840 (face-font face t)))
841 (if (listp font)
842 (setq font nil))
843 (setq font (or font
844 (face-font 'default frame)
845 (cdr (assq 'font (frame-parameters frame)))))
488bedff
RS
846 (or (and font (make-face-italic-internal face frame font))
847 ;; We failed to find an italic version of the font.
848 noerror
849 (error "No italic version of %S" font))))))
f3f31ccf 850
4b3203d9
RS
851(defun make-face-italic-internal (face frame font)
852 (let (f2)
853 (or (and (setq f2 (x-make-font-italic font))
854 (internal-try-face-font face f2 frame))
855 (and (setq f2 (x-make-font-oblique font))
856 (internal-try-face-font face f2 frame)))))
bb9a81fc
JB
857
858(defun make-face-bold-italic (face &optional frame noerror)
465fceed 859 "Make the font of the given face be bold and italic, if possible.
bb9a81fc 860If NOERROR is non-nil, return nil on failure."
465fceed 861 (interactive (list (read-face-name "Make which face bold-italic: ")))
534dbc97 862 (if (and (eq frame t) (listp (face-font face t)))
f3f31ccf 863 (set-face-font face '(bold italic) t)
488bedff 864 (let (font)
f3f31ccf
RS
865 (if (null frame)
866 (let ((frames (frame-list)))
867 ;; Make this face bold-italic in global-face-data.
868 (make-face-bold-italic face t noerror)
869 ;; Make this face bold in each frame.
870 (while frames
871 (make-face-bold-italic face (car frames) noerror)
872 (setq frames (cdr frames))))
873 (setq face (internal-get-face face frame))
874 (setq font (or (face-font face frame)
875 (face-font face t)))
876 (if (listp font)
877 (setq font nil))
878 (setq font (or font
879 (face-font 'default frame)
880 (cdr (assq 'font (frame-parameters frame)))))
488bedff
RS
881 (or (and font (make-face-bold-italic-internal face frame font))
882 ;; We failed to find a bold italic version.
883 noerror
884 (error "No bold italic version of %S" font))))))
f3f31ccf 885
4b3203d9 886(defun make-face-bold-italic-internal (face frame font)
f3f31ccf
RS
887 (let (f2 f3)
888 (or (and (setq f2 (x-make-font-italic font))
889 (not (equal font f2))
890 (setq f3 (x-make-font-bold f2))
891 (not (equal f2 f3))
892 (internal-try-face-font face f3 frame))
893 (and (setq f2 (x-make-font-oblique font))
894 (not (equal font f2))
895 (setq f3 (x-make-font-bold f2))
896 (not (equal f2 f3))
897 (internal-try-face-font face f3 frame))
898 (and (setq f2 (x-make-font-italic font))
899 (not (equal font f2))
900 (setq f3 (x-make-font-demibold f2))
901 (not (equal f2 f3))
902 (internal-try-face-font face f3 frame))
903 (and (setq f2 (x-make-font-oblique font))
904 (not (equal font f2))
905 (setq f3 (x-make-font-demibold f2))
906 (not (equal f2 f3))
907 (internal-try-face-font face f3 frame)))))
bb9a81fc
JB
908
909(defun make-face-unbold (face &optional frame noerror)
465fceed 910 "Make the font of the given face be non-bold, if possible.
bb9a81fc 911If NOERROR is non-nil, return nil on failure."
465fceed 912 (interactive (list (read-face-name "Make which face non-bold: ")))
534dbc97 913 (if (and (eq frame t) (listp (face-font face t)))
f3f31ccf
RS
914 (set-face-font face (if (memq 'italic (face-font face t))
915 '(italic) nil)
916 t)
488bedff 917 (let (font font1)
f3f31ccf
RS
918 (if (null frame)
919 (let ((frames (frame-list)))
920 ;; Make this face unbold in global-face-data.
921 (make-face-unbold face t noerror)
922 ;; Make this face unbold in each frame.
923 (while frames
924 (make-face-unbold face (car frames) noerror)
925 (setq frames (cdr frames))))
926 (setq face (internal-get-face face frame))
927 (setq font1 (or (face-font face frame)
928 (face-font face t)))
929 (if (listp font1)
930 (setq font1 nil))
931 (setq font1 (or font1
932 (face-font 'default frame)
933 (cdr (assq 'font (frame-parameters frame)))))
96616c04 934 (setq font (and font1 (x-make-font-unbold font1)))
488bedff
RS
935 (or (if font (internal-try-face-font face font frame))
936 noerror
937 (error "No unbold version of %S" font1))))))
bb9a81fc
JB
938
939(defun make-face-unitalic (face &optional frame noerror)
465fceed 940 "Make the font of the given face be non-italic, if possible.
bb9a81fc 941If NOERROR is non-nil, return nil on failure."
465fceed 942 (interactive (list (read-face-name "Make which face non-italic: ")))
534dbc97 943 (if (and (eq frame t) (listp (face-font face t)))
f3f31ccf
RS
944 (set-face-font face (if (memq 'bold (face-font face t))
945 '(bold) nil)
946 t)
488bedff 947 (let (font font1)
f3f31ccf
RS
948 (if (null frame)
949 (let ((frames (frame-list)))
950 ;; Make this face unitalic in global-face-data.
951 (make-face-unitalic face t noerror)
952 ;; Make this face unitalic in each frame.
953 (while frames
954 (make-face-unitalic face (car frames) noerror)
955 (setq frames (cdr frames))))
956 (setq face (internal-get-face face frame))
957 (setq font1 (or (face-font face frame)
958 (face-font face t)))
959 (if (listp font1)
960 (setq font1 nil))
961 (setq font1 (or font1
962 (face-font 'default frame)
963 (cdr (assq 'font (frame-parameters frame)))))
96616c04 964 (setq font (and font1 (x-make-font-unitalic font1)))
488bedff
RS
965 (or (if font (internal-try-face-font face font frame))
966 noerror
967 (error "No unitalic version of %S" font1))))))
465fceed 968\f
710e7005
RS
969(defvar list-faces-sample-text
970 "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
971 "*Text string to display as the sample text for `list-faces-display'.")
972
973;; The name list-faces would be more consistent, but let's avoid a conflict
974;; with Lucid, which uses that name differently.
975(defun list-faces-display ()
976 "List all faces, using the same sample text in each.
977The sample text is a string that comes from the variable
978`list-faces-sample-text'.
979
980It is possible to give a particular face name different appearances in
981different frames. This command shows the appearance in the
982selected frame."
983 (interactive)
984 (let ((faces (sort (face-list) (function string-lessp)))
985 (face nil)
986 (frame (selected-frame))
987 disp-frame window)
988 (with-output-to-temp-buffer "*Faces*"
989 (save-excursion
990 (set-buffer standard-output)
991 (setq truncate-lines t)
992 (while faces
993 (setq face (car faces))
994 (setq faces (cdr faces))
995 (insert (format "%25s " (symbol-name face)))
996 (let ((beg (point)))
997 (insert list-faces-sample-text)
998 (insert "\n")
23b04eac
RS
999 (put-text-property beg (1- (point)) 'face face)
1000 ;; If the sample text has multiple lines, line up all of them.
1001 (goto-char beg)
1002 (forward-line 1)
1003 (while (not (eobp))
1004 (insert " ")
1005 (forward-line 1))))
710e7005
RS
1006 (goto-char (point-min))))
1007 ;; If the *Faces* buffer appears in a different frame,
1008 ;; copy all the face definitions from FRAME,
1009 ;; so that the display will reflect the frame that was selected.
1010 (setq window (get-buffer-window (get-buffer "*Faces*") t))
1011 (setq disp-frame (if window (window-frame window)
1012 (car (frame-list))))
1013 (or (eq frame disp-frame)
1014 (let ((faces (face-list)))
1015 (while faces
1016 (copy-face (car faces) (car faces) frame disp-frame)
1017 (setq faces (cdr faces)))))))
19deb21e
RS
1018
1019(defun describe-face (face)
1020 "Display the properties of face FACE."
1021 (interactive (list (read-face-name "Describe face: ")))
1022 (with-output-to-temp-buffer "*Help*"
1023 (princ "Properties of face `")
1024 (princ (face-name face))
1025 (princ "':") (terpri)
1026 (princ "Foreground: ") (princ (face-foreground face)) (terpri)
1027 (princ "Background: ") (princ (face-background face)) (terpri)
1028 (princ " Font: ") (princ (face-font face)) (terpri)
1029 (princ "Underlined: ") (princ (if (face-underline-p face) "yes" "no")) (terpri)
1030 (princ " Stipple: ") (princ (or (face-stipple face) "none"))))
710e7005 1031\f
19ae9866
RS
1032;;; Make the standard faces.
1033;;; The C code knows the default and modeline faces as faces 0 and 1,
1034;;; so they must be the first two faces made.
e09c52a8 1035(defun face-initialize ()
465fceed 1036 (make-face 'default)
ebea97d8 1037 (make-face 'modeline)
465fceed 1038 (make-face 'highlight)
19ae9866 1039
465fceed 1040 ;; These aren't really special in any way, but they're nice to have around.
19ae9866 1041
465fceed
ER
1042 (make-face 'bold)
1043 (make-face 'italic)
1044 (make-face 'bold-italic)
578d09a6 1045 (make-face 'region)
e09c52a8 1046 (make-face 'secondary-selection)
f4b9e76b 1047 (make-face 'underline)
e09c52a8 1048
578d09a6 1049 (setq region-face (face-id 'region))
8494bbf1 1050
19ae9866
RS
1051 ;; Specify the global properties of these faces
1052 ;; so they will come out right on new frames.
1053
1054 (make-face-bold 'bold t)
1055 (make-face-italic 'italic t)
1056 (make-face-bold-italic 'bold-italic t)
1057
1058 (set-face-background 'highlight '("darkseagreen2" "green" t) t)
566b0ad2 1059 (set-face-background 'region '("gray" underline) t)
19ae9866
RS
1060 (set-face-background 'secondary-selection '("paleturquoise" "green" t) t)
1061 (set-face-background 'modeline '(t) t)
1062 (set-face-underline-p 'underline t t)
1063
1064 ;; Set up the faces of all existing X Window frames
1065 ;; from those global properties, unless already set in a given frame.
1066
e09c52a8
RS
1067 (let ((frames (frame-list)))
1068 (while frames
e17dbede 1069 (if (not (memq (framep (car frames)) '(t nil)))
19ae9866
RS
1070 (let ((frame (car frames))
1071 (rest global-face-data))
1072 (while rest
1073 (let ((face (car (car rest))))
1074 (or (face-differs-from-default-p face)
1075 (face-fill-in face (cdr (car rest)) frame)))
1076 (setq rest (cdr rest)))))
e09c52a8
RS
1077 (setq frames (cdr frames)))))
1078
465fceed 1079\f
465fceed
ER
1080;; Like x-create-frame but also set up the faces.
1081
1082(defun x-create-frame-with-faces (&optional parameters)
6e4aafdc
KH
1083 ;; Read this frame's geometry resource, if it has an explicit name,
1084 ;; and put the specs into PARAMETERS.
1085 (let* ((name (or (cdr (assq 'name parameters))
313b841c 1086 (cdr (assq 'name default-frame-alist))))
6e4aafdc 1087 (x-resource-name name)
28ceec49 1088 (res-geometry (if name (x-get-resource "geometry" "Geometry"))))
6e4aafdc 1089 (if res-geometry
28ceec49 1090 (let ((parsed (x-parse-geometry res-geometry)))
6e4aafdc
KH
1091 ;; If the resource specifies a position,
1092 ;; call the position and size "user-specified".
1093 (if (or (assq 'top parsed) (assq 'left parsed))
28ceec49
SM
1094 (setq parsed (append '((user-position . t) (user-size . t))
1095 parsed)))
313b841c
KH
1096 ;; Put the geometry parameters at the end.
1097 ;; Copy default-frame-alist so that they go after it.
28ceec49 1098 (setq parameters (append parameters default-frame-alist parsed)))))
ef436392
KH
1099 (let (frame)
1100 (if (null global-face-data)
1101 (setq frame (x-create-frame parameters))
1102 (let* ((visibility-spec (assq 'visibility parameters))
1103 (faces (copy-alist global-face-data))
1104 success
1105 (rest faces))
1106 (setq frame (x-create-frame (cons '(visibility . nil) parameters)))
1107 (unwind-protect
1108 (progn
1109 (set-frame-face-alist frame faces)
1110
1111 (if (cdr (or (assq 'reverse parameters)
1112 (assq 'reverse default-frame-alist)
1113 (let ((resource (x-get-resource "reverseVideo"
1114 "ReverseVideo")))
1115 (if resource
1116 (cons nil (member (downcase resource)
1117 '("on" "true")))))))
1118 (let* ((params (frame-parameters frame))
1119 (bg (cdr (assq 'foreground-color params)))
1120 (fg (cdr (assq 'background-color params))))
1121 (modify-frame-parameters frame
1122 (list (cons 'foreground-color fg)
1123 (cons 'background-color bg)))
1124 (if (equal bg (cdr (assq 'border-color params)))
1125 (modify-frame-parameters frame
1126 (list (cons 'border-color fg))))
1127 (if (equal bg (cdr (assq 'mouse-color params)))
1128 (modify-frame-parameters frame
1129 (list (cons 'mouse-color fg))))
1130 (if (equal bg (cdr (assq 'cursor-color params)))
1131 (modify-frame-parameters frame
1132 (list (cons 'cursor-color fg))))))
1133 ;; Copy the vectors that represent the faces.
1134 ;; Also fill them in from X resources.
1135 (while rest
1136 (let ((global (cdr (car rest))))
1137 (setcdr (car rest) (vector 'face
1138 (face-name (cdr (car rest)))
1139 (face-id (cdr (car rest)))
1140 nil nil nil nil nil))
1141 (face-fill-in (car (car rest)) global frame))
1142 (make-face-x-resource-internal (cdr (car rest)) frame t)
1143 (setq rest (cdr rest)))
1144 (if (null visibility-spec)
1145 (make-frame-visible frame)
1146 (modify-frame-parameters frame (list visibility-spec)))
1147 (setq success t))
1148 (or success
1149 (delete-frame frame)))))
1150 ;; Set up the background-mode frame parameter
1151 ;; so that programs can decide good ways of highlighting
1152 ;; on this frame.
1153 (let ((bg-resource (x-get-resource ".backgroundMode"
1154 "BackgroundMode"))
82c028e0 1155 (params (frame-parameters frame))
ef436392
KH
1156 (bg-mode))
1157 (setq bg-mode
1158 (cond (bg-resource (intern (downcase bg-resource)))
1159 ((< (apply '+ (x-color-values
82c028e0
RS
1160 (cdr (assq 'background-color params))
1161 frame))
b8c631a5
RS
1162 ;; Just looking at the screen,
1163 ;; colors whose values add up to .6 of the white total
1164 ;; still look dark to me.
1165 (* (apply '+ (x-color-values "white" frame)) .6))
ef436392
KH
1166 'dark)
1167 (t 'light)))
1168 (modify-frame-parameters frame
1169 (list (cons 'background-mode bg-mode)
1170 (cons 'display-type
1171 (cond ((x-display-color-p frame)
1172 'color)
1173 ((x-display-grayscale-p frame)
1174 'grayscale)
1175 (t 'mono))))))
1176 frame))
e09c52a8 1177
9d52c8d3
RS
1178;; Update a frame's faces when we change its default font.
1179(defun frame-update-faces (frame)
1180 (let* ((faces global-face-data)
1181 (rest faces))
1182 (while rest
1183 (let* ((face (car (car rest)))
1184 (font (face-font face t)))
1185 (if (listp font)
1186 (let ((bold (memq 'bold font))
1187 (italic (memq 'italic font)))
99fb9482
KH
1188 ;; Ignore any previous (string-valued) font, it might not even
1189 ;; be the right size anymore.
1190 (set-face-font face nil frame)
9d52c8d3
RS
1191 (cond ((and bold italic)
1192 (make-face-bold-italic face frame t))
1193 (bold
1194 (make-face-bold face frame t))
1195 (italic
1196 (make-face-italic face frame t)))))
1197 (setq rest (cdr rest)))
1198 frame)))
1199
f16c38ae
RS
1200;; Update the colors of FACE, after FRAME's own colors have been changed.
1201;; This applies only to faces with global color specifications
1202;; that are not simple constants.
1203(defun frame-update-face-colors (frame)
1204 (let ((faces global-face-data))
1205 (while faces
1206 (condition-case nil
1207 (let* ((data (cdr (car faces)))
1208 (face (car (car faces)))
1209 (foreground (face-foreground data))
1210 (background (face-background data)))
1211 ;; If the global spec is a specific color,
1212 ;; which doesn't depend on the frame's attributes,
1213 ;; we don't need to recalculate it now.
1214 (or (listp foreground)
1215 (setq foreground nil))
1216 (or (listp background)
1217 (setq background nil))
1218 ;; If we are going to frob this face at all,
1219 ;; reinitialize it first.
1220 (if (or foreground background)
1221 (progn (set-face-foreground face nil frame)
1222 (set-face-background face nil frame)))
1223 (if foreground
1224 (face-try-color-list 'set-face-foreground
1225 face foreground frame))
1226 (if background
1227 (face-try-color-list 'set-face-background
1228 face background frame)))
1229 (error nil))
1230 (setq faces (cdr faces)))))
1231
19ae9866
RS
1232;; Fill in the face FACE from frame-independent face data DATA.
1233;; DATA should be the non-frame-specific ("global") face vector
1234;; for the face. FACE should be a face name or face object.
1235;; FRAME is the frame to act on; it must be an actual frame, not nil or t.
1236(defun face-fill-in (face data frame)
1237 (condition-case nil
1238 (let ((foreground (face-foreground data))
1239 (background (face-background data))
ca58b3ec
KH
1240 (font (face-font data))
1241 (stipple (face-stipple data)))
19ae9866
RS
1242 (set-face-underline-p face (face-underline-p data) frame)
1243 (if foreground
1244 (face-try-color-list 'set-face-foreground
1245 face foreground frame))
1246 (if background
1247 (face-try-color-list 'set-face-background
1248 face background frame))
1249 (if (listp font)
1250 (let ((bold (memq 'bold font))
1251 (italic (memq 'italic font)))
1252 (cond ((and bold italic)
1253 (make-face-bold-italic face frame))
1254 (bold
1255 (make-face-bold face frame))
1256 (italic
1257 (make-face-italic face frame))))
1258 (if font
ca58b3ec
KH
1259 (set-face-font face font frame)))
1260 (if stipple
1261 (set-face-stipple face stipple frame)))
19ae9866 1262 (error nil)))
e09c52a8 1263
4099a32d
RS
1264;; Assuming COLOR is a valid color name,
1265;; return t if it can be displayed on FRAME.
1266(defun face-color-supported-p (frame color background-p)
055ff5a6
RS
1267 (and window-system
1268 (or (x-display-color-p frame)
1269 ;; A black-and-white display can implement these.
1270 (member color '("black" "white"))
1271 ;; A black-and-white display can fake gray for background.
1272 (and background-p
1273 (face-color-gray-p color frame))
1274 ;; A grayscale display can implement colors that are gray (more or less).
1275 (and (x-display-grayscale-p frame)
1276 (face-color-gray-p color frame)))))
4099a32d 1277
19ae9866
RS
1278;; Use FUNCTION to store a color in FACE on FRAME.
1279;; COLORS is either a single color or a list of colors.
1280;; If it is a list, try the colors one by one until one of them
1281;; succeeds. We signal an error only if all the colors failed.
1282;; t as COLORS or as an element of COLORS means to invert the face.
1283;; That can't fail, so any subsequent elements after the t are ignored.
1284(defun face-try-color-list (function face colors frame)
1285 (if (stringp colors)
4099a32d
RS
1286 (if (face-color-supported-p frame colors
1287 (eq function 'set-face-background))
1288 (funcall function face colors frame))
19ae9866
RS
1289 (if (eq colors t)
1290 (invert-face face frame)
1291 (let (done)
1292 (while (and colors (not done))
de52827f 1293 (if (or (memq (car colors) '(t underline))
4099a32d
RS
1294 (face-color-supported-p frame (car colors)
1295 (eq function 'set-face-background)))
1296 (if (cdr colors)
1297 ;; If there are more colors to try, catch errors
1298 ;; and set `done' if we succeed.
1299 (condition-case nil
1300 (progn
1301 (cond ((eq (car colors) t)
1302 (invert-face face frame))
1303 ((eq (car colors) 'underline)
1304 (set-face-underline-p face t frame))
1305 (t
1306 (funcall function face (car colors) frame)))
1307 (setq done t))
1308 (error nil))
1309 ;; If this is the last color, let the error get out if it fails.
1310 ;; If it succeeds, we will exit anyway after this iteration.
1311 (cond ((eq (car colors) t)
1312 (invert-face face frame))
1313 ((eq (car colors) 'underline)
1314 (set-face-underline-p face t frame))
1315 (t
1316 (funcall function face (car colors) frame)))))
19ae9866 1317 (setq colors (cdr colors)))))))
e09c52a8
RS
1318
1319;; If we are already using x-window frames, initialize faces for them.
b86b9918 1320(if (memq (framep (selected-frame)) '(x w32))
e09c52a8 1321 (face-initialize))
465fceed 1322
f0138172
JB
1323(provide 'faces)
1324
465fceed 1325;;; faces.el ends here