comparison lisp/x11/x-font-menu.el @ 86:364816949b59 r20-0b93

Import from CVS: tag r20-0b93
author cvs
date Mon, 13 Aug 2007 09:09:02 +0200
parents 6a378aca36af
children 821dec489c24
comparison
equal deleted inserted replaced
85:c661705957e0 86:364816949b59
1 ;; x-font-menu.el --- Managing menus of X fonts. 1 ;; x-font-menu.el --- Managing menus of X fonts.
2 2
3 ;; Copyright (C) 1994 Free Software Foundation, Inc. 3 ;; Copyright (C) 1994 Free Software Foundation, Inc.
4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp. 4 ;; Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 ;; Copyright (C) 1997 Sun Microsystems
5 6
6 ;; Author: Jamie Zawinski <jwz@lucid.com> 7 ;; Author: Jamie Zawinski <jwz@lucid.com>
7 ;; Restructured by: Jonathan Stigelman <Stig@hackvan.com> 8 ;; Restructured by: Jonathan Stigelman <Stig@hackvan.com>
9 ;; Mule-ized by: Martin Buchholz
8 10
9 ;; This file is part of XEmacs. 11 ;; This file is part of XEmacs.
10 12
11 ;; XEmacs is free software; you can redistribute it and/or modify it 13 ;; XEmacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by 14 ;; under the terms of the GNU General Public License as published by
60 ;;; XEmacs startup. At any time (i.e.: after a font-path change or 62 ;;; XEmacs startup. At any time (i.e.: after a font-path change or
61 ;;; immediately after device creation), you can call 63 ;;; immediately after device creation), you can call
62 ;;; `reset-device-font-menus' to rebuild the menus from all currently 64 ;;; `reset-device-font-menus' to rebuild the menus from all currently
63 ;;; available fonts. 65 ;;; available fonts.
64 ;;; 66 ;;;
65 ;;; There is knowledge here about the regexp match numbers in `x-font-regexp', 67 ;;; There is knowledge here about the regexp match numbers in
66 ;;; `x-font-regexp-foundry-and-family', and 68 ;;; `x-font-regexp' and `x-font-regexp-foundry-and-family' defined in
67 ;;; `x-font-regexp-registry-and-encoding' defined in x-faces.el. 69 ;;; x-faces.el.
68 ;;; 70 ;;;
69 ;;; There are at least three kinds of fonts under X11r5: 71 ;;; There are at least three kinds of fonts under X11r5:
70 ;;; 72 ;;;
71 ;;; - bitmap fonts, which can be assumed to look as good as possible; 73 ;;; - bitmap fonts, which can be assumed to look as good as possible;
72 ;;; - bitmap fonts which have been (or can be) automatically scaled to 74 ;;; - bitmap fonts which have been (or can be) automatically scaled to
95 ;;; (face-font 'default) 97 ;;; (face-font 'default)
96 ;;; (font-truename (face-font 'default)) 98 ;;; (font-truename (face-font 'default))
97 ;;; (font-properties (face-font 'default)) 99 ;;; (font-properties (face-font 'default))
98 ;;; - The values of the following variables after making a selection: 100 ;;; - The values of the following variables after making a selection:
99 ;;; font-menu-preferred-resolution 101 ;;; font-menu-preferred-resolution
100 ;;; font-menu-preferred-registry 102 ;;; font-menu-registry-encoding
101 ;;; 103 ;;;
102 ;;; There is a common misconception that "*-courier-medium-r-*-11-*", also 104 ;;; There is a common misconception that "*-courier-medium-r-*-11-*", also
103 ;;; known as "-adobe-courier-medium-r-normal--11-80-100-100-m-60-iso8859-1", 105 ;;; known as "-adobe-courier-medium-r-normal--11-80-100-100-m-60-iso8859-1",
104 ;;; is an 11-point font. It is not -- it is an 11-pixel font at 100dpi, 106 ;;; is an 11-point font. It is not -- it is an 11-pixel font at 100dpi,
105 ;;; which is an 8-point font (the number after -11- is the size in tenths 107 ;;; which is an 8-point font (the number after -11- is the size in tenths
106 ;;; of points). So if you expect to be seeing an "11" entry in the "Size" 108 ;;; of points). So if you expect to be seeing an "11" entry in the "Size"
107 ;;; menu and are not, this may be why. 109 ;;; menu and are not, this may be why.
110 ;;;
111 ;;; In the real world (aka Solaris), one has to deal with fonts that
112 ;;; appear to be medium-i but are really light-r, and fonts that
113 ;;; resolve to different resolutions depending on the charset:
114 ;;;
115 ;;; (font-instance-truename
116 ;;; (make-font-instance "-*-mincho-medium-i-normal-*-*-*-*-*-*-*-jisx0201*-*"))
117 ;;; ==>
118 ;;; "-morisawa-ryumin light kl-light-r-normal--10-100-72-72-m-50-jisx0201.1976-0"
119 ;;;
120 ;;; (list-fonts "-dt-interface user-medium-r-normal-s*-*-*-*-*-*-*-*-*")
121 ;;; ==>
122 ;;; ("-dt-interface user-medium-r-normal-s sans-12-120-72-72-m-70-iso8859-1"
123 ;;; "-dt-interface user-medium-r-normal-s-14-120-75-75-m-120-jisx0208.1983-0"
124 ;;; "-dt-interface user-medium-r-normal-s-14-120-75-75-m-60-jisx0201.1976-0")
108 125
109 ;;; Code: 126 ;;; Code:
110 127
111 ;; #### - implement these... 128 ;; #### - implement these...
112 ;; 129 ;;
124 141
125 ;; only call XListFonts (and parse) once per device. 142 ;; only call XListFonts (and parse) once per device.
126 ;; ( (device . [parsed-list-fonts family-menu size-menu weight-menu]) ...) 143 ;; ( (device . [parsed-list-fonts family-menu size-menu weight-menu]) ...)
127 (defvar device-fonts-cache nil) 144 (defvar device-fonts-cache nil)
128 145
129 (defconst font-menu-preferred-registry nil) 146 (defvar font-menu-registry-encoding nil
130 (defconst font-menu-preferred-resolution nil) 147 "Registry and encoding to use with font menu fonts.")
131 148
132 (defconst fonts-menu-junk-families 149 (defvar font-menu-preferred-resolution "*-*"
150 "Preferred horizontal and vertical font menu resolution (e.g. \"75-75\").")
151
152 (defvar fonts-menu-junk-families
133 (purecopy 153 (purecopy
134 (mapconcat 154 (mapconcat
135 #'identity 155 #'identity
136 '("cursor" "glyph" "symbol" ; Obvious losers. 156 '("cursor" "glyph" "symbol" ; Obvious losers.
137 "\\`Ax...\\'" ; FrameMaker fonts - there are just way too 157 "\\`Ax...\\'" ; FrameMaker fonts - there are just way too
140 ; "Axcor" -> "Applix Courier Roman", 160 ; "Axcor" -> "Applix Courier Roman",
141 ; "Axcob" -> "Applix Courier Bold", etc. 161 ; "Axcob" -> "Applix Courier Bold", etc.
142 ) 162 )
143 "\\|")) 163 "\\|"))
144 "A regexp matching font families which are uninteresting (e.g. cursor fonts).") 164 "A regexp matching font families which are uninteresting (e.g. cursor fonts).")
165
166 (eval-when-compile
167 (defsubst device-fonts-cache ()
168 (or (cdr (assq (selected-device) device-fonts-cache))
169 (reset-device-font-menus (selected-device)))))
145 170
146 (defun hack-font-truename (fn) 171 (defun hack-font-truename (fn)
147 "Filter the output of `font-instance-truename' to deal with Japanese fontsets." 172 "Filter the output of `font-instance-truename' to deal with Japanese fontsets."
148 (if (string-match "," (font-instance-truename fn)) 173 (if (string-match "," (font-instance-truename fn))
149 (let ((fpnt (nth 8 (split-string (font-instance-name fn) "-"))) 174 (let ((fpnt (nth 8 (split-string (font-instance-name fn) "-")))
159 184
160 ;;;###autoload 185 ;;;###autoload
161 (fset 'install-font-menus 'reset-device-font-menus) 186 (fset 'install-font-menus 'reset-device-font-menus)
162 (make-obsolete 'install-font-menus 'reset-device-font-menus) 187 (make-obsolete 'install-font-menus 'reset-device-font-menus)
163 188
164 (defvar x-font-regexp-ja nil 189 (defvar x-font-regexp-ascii nil
165 "This is used to filter out fonts that don't work in the locale. 190 "This is used to filter out font families that can't display ASCII text.
166 It must be set at run-time.") 191 It must be set at run-time.")
167 192
168 (defun vassoc (key valist) 193 (defun vassoc (key valist)
169 "Search VALIST for a vector whose first element is equal to KEY. 194 "Search VALIST for a vector whose first element is equal to KEY.
170 See also `assoc'." 195 See also `assoc'."
189 (message "Getting list of fonts from server... ") 214 (message "Getting list of fonts from server... ")
190 (if (or noninteractive 215 (if (or noninteractive
191 (not (or device (setq device (selected-device)))) 216 (not (or device (setq device (selected-device))))
192 (not (eq (device-type device) 'x))) 217 (not (eq (device-type device) 'x)))
193 nil 218 nil
194 (if (and (getenv "LANG") 219 (unless x-font-regexp-ascii
195 (string-match "^\\(ja\\|japanese\\)$" 220 (setq x-font-regexp-ascii (if (fboundp 'charset-registry)
196 (getenv "LANG"))) 221 (charset-registry 'ascii)
197 ;; #### - this is questionable behavior left over from the I18N4 code. 222 "iso8859-1")))
198 (setq x-font-regexp-ja "jisx[^-]*-[^-]*$" 223 (setq font-menu-registry-encoding
199 font-menu-preferred-registry '("*" . "*") 224 (if (featurep 'mule) "*-*" "iso8859-1"))
200 font-menu-preferred-resolution '("*" . "*"))) 225 (let ((case-fold-search t)
201 (let ((all-fonts nil) 226 family size weight entry monospaced-p
202 (case-fold-search t) 227 dev-cache cache families sizes weights)
203 name family size weight entry monospaced-p 228 (dolist (name (cond ((null debug) ; debugging kludge
204 dev-cache 229 (list-fonts "*-*-*-*-*-*-*-*-*-*-*-*-*-*" device))
205 (cache nil) 230 ((stringp debug) (split-string debug "\n"))
206 (families nil) 231 (t debug)))
207 (sizes nil) 232 (when (and (string-match x-font-regexp-ascii name)
208 (weights nil))
209 (cond ((stringp debug) ; kludge
210 (setq all-fonts (split-string debug "\n")))
211 (t
212 (setq all-fonts
213 (or debug
214 (list-fonts "*-*-*-*-*-*-*-*-*-*-*-*-*-*" device)))))
215 (while (setq name (pop all-fonts))
216 (when (and (or (not x-font-regexp-ja)
217 (string-match x-font-regexp-ja name))
218 (string-match x-font-regexp name)) 233 (string-match x-font-regexp name))
219 (setq weight (capitalize (match-string 1 name)) 234 (setq weight (capitalize (match-string 1 name))
220 size (string-to-int (match-string 6 name))) 235 size (string-to-int (match-string 6 name)))
221 (or (string-match x-font-regexp-foundry-and-family name) 236 (or (string-match x-font-regexp-foundry-and-family name)
222 (error "internal error")) 237 (error "internal error"))
227 (unless (string-match fonts-menu-junk-families family) 242 (unless (string-match fonts-menu-junk-families family)
228 (setq entry (or (vassoc family cache) 243 (setq entry (or (vassoc family cache)
229 (car (setq cache 244 (car (setq cache
230 (cons (vector family nil nil t) 245 (cons (vector family nil nil t)
231 cache))))) 246 cache)))))
232 (or (member family families) 247 (or (member family families) (push family families))
233 (setq families (cons family families))) 248 (or (member weight weights) (push weight weights))
234 (or (member weight weights) 249 (or (member size sizes) (push size sizes))
235 (setq weights (cons weight weights))) 250 (or (member weight (aref entry 1)) (push weight (aref entry 1)))
236 (or (member weight (aref entry 1)) 251 (or (member size (aref entry 2)) (push size (aref entry 2)))
237 (aset entry 1 (cons weight (aref entry 1)))) 252 (aset entry 3 (and (aref entry 3) monospaced-p)))))
238 (or (member size sizes)
239 (setq sizes (cons size sizes)))
240 (or (member size (aref entry 2))
241 (aset entry 2 (cons size (aref entry 2))))
242 (aset entry 3 (and (aref entry 3) monospaced-p))
243 )))
244 ;; 253 ;;
245 ;; Hack scalable fonts. 254 ;; Hack scalable fonts.
246 ;; Some fonts come only in scalable versions (the only size is 0) 255 ;; Some fonts come only in scalable versions (the only size is 0)
247 ;; and some fonts come in both scalable and non-scalable versions 256 ;; and some fonts come in both scalable and non-scalable versions
248 ;; (one size is 0). If there are any scalable fonts at all, make 257 ;; (one size is 0). If there are any scalable fonts at all, make
265 (setq sizes (cons (car common) sizes))) 274 (setq sizes (cons (car common) sizes)))
266 (setq common (cdr common))) 275 (setq common (cdr common)))
267 (setq sizes (delq 0 sizes)))) 276 (setq sizes (delq 0 sizes))))
268 277
269 (setq families (sort families 'string-lessp) 278 (setq families (sort families 'string-lessp)
270 weights (sort weights 'string-lessp) 279 weights (sort weights 'string-lessp)
271 sizes (sort sizes '<)) 280 sizes (sort sizes '<))
272 281
273 (let ((rest cache)) 282 (dolist (entry cache)
274 (while rest 283 (aset entry 1 (sort (aref entry 1) 'string-lessp))
275 (aset (car rest) 1 (sort (aref (car rest) 1) 'string-lessp)) 284 (aset entry 2 (sort (aref entry 2) '<)))
276 (aset (car rest) 2 (sort (aref (car rest) 2) '<))
277 (setq rest (cdr rest))))
278 285
279 (message "Getting list of fonts from server... done.") 286 (message "Getting list of fonts from server... done.")
280 287
281 (setq dev-cache (assq device device-fonts-cache)) 288 (setq dev-cache (assq device device-fonts-cache))
282 (or dev-cache 289 (or dev-cache
283 (setq dev-cache (car (push (list device) device-fonts-cache)))) 290 (setq dev-cache (car (push (list device) device-fonts-cache))))
284 (setcdr dev-cache 291 (setcdr
285 (vector 292 dev-cache
286 cache 293 (vector
287 (mapcar #'(lambda (x) 294 cache
288 (vector x 295 (mapcar (lambda (x)
289 (list 'font-menu-set-font x nil nil) 296 (vector x
290 ':style 'radio ':active nil ':selected nil)) 297 (list 'font-menu-set-font x nil nil)
291 families) 298 ':style 'radio ':active nil ':selected nil))
292 (mapcar #'(lambda (x) 299 families)
293 (vector (if (/= 0 (% x 10)) 300 (mapcar (lambda (x)
294 ;; works with no LISP_FLOAT_TYPE 301 (vector (if (/= 0 (% x 10))
295 (concat (int-to-string (/ x 10)) "." 302 ;; works with no LISP_FLOAT_TYPE
296 (int-to-string (% x 10))) 303 (concat (int-to-string (/ x 10)) "."
297 (int-to-string (/ x 10))) 304 (int-to-string (% x 10)))
298 (list 'font-menu-set-font nil nil x) 305 (int-to-string (/ x 10)))
299 ':style 'radio ':active nil ':selected nil)) 306 (list 'font-menu-set-font nil nil x)
300 sizes) 307 ':style 'radio ':active nil ':selected nil))
301 (mapcar #'(lambda (x) 308 sizes)
302 (vector x 309 (mapcar (lambda (x)
303 (list 'font-menu-set-font nil x nil) 310 (vector x
304 ':style 'radio ':active nil ':selected nil)) 311 (list 'font-menu-set-font nil x nil)
305 weights))) 312 ':style 'radio ':active nil ':selected nil))
313 weights)))
306 (cdr dev-cache)))) 314 (cdr dev-cache))))
307 315
308 (defsubst font-menu-truename (face) 316 ;; Extract font information from a face. We examine both the
309 (hack-font-truename 317 ;; user-specified font name and the canonical (`true') font name.
310 (if (featurep 'mule) 318 ;; These can appear to have totally different properties.
311 (face-font-instance face nil 'ascii) 319 ;; For examples, see the prolog above.
312 (face-font-instance face)))) 320
313 321 ;; We use the user-specified one if possible, else use the truename.
314 ;;; Extract a font family from a face. 322 ;; If the user didn't specify one (with "-dt-*-*", for example)
315 ;;; Use the user-specified one if possible. 323 ;; get the truename and use the possibly suboptimal data from that.
316 ;;; If the user didn't specify one (with "*", for example) 324 (defun* font-menu-font-data (face dcache)
317 ;;; get the truename and use the guaranteed family from that. 325 (let* ((case-fold-search t)
318 (defun font-menu-family (face) 326 (domain (if font-menu-this-frame-only-p
319 (let ((dcache (cdr (assq (selected-device) device-fonts-cache))) 327 (selected-frame)
320 (name (font-instance-name (face-font-instance face))) 328 (selected-device)))
321 (family nil)) 329 (name (font-instance-name (face-font-instance face domain)))
330 (truename (font-instance-truename
331 (face-font-instance face domain
332 (if (featurep 'mule) 'ascii))))
333 family size weight entry slant)
322 (when (string-match x-font-regexp-foundry-and-family name) 334 (when (string-match x-font-regexp-foundry-and-family name)
323 (setq family (capitalize (match-string 1 name)))) 335 (setq family (capitalize (match-string 1 name)))
324 (when (not (and family (vassoc family (aref dcache 0)))) 336 (setq entry (vassoc family (aref dcache 0))))
325 (setq name (font-menu-truename face)) 337 (when (and (null entry)
326 (string-match x-font-regexp-foundry-and-family name) 338 (string-match x-font-regexp-foundry-and-family truename))
327 (setq family (capitalize (match-string 1 name)))) 339 (setq family (capitalize (match-string 1 truename)))
328 family)) 340 (setq entry (vassoc family (aref dcache 0))))
341 (when (null entry)
342 (return-from font-menu-font-data (make-vector 5 nil)))
343
344 (when (string-match x-font-regexp name)
345 (setq weight (capitalize (match-string 1 name)))
346 (setq size (string-to-int (match-string 6 name))))
347
348 (when (string-match x-font-regexp truename)
349 (when (not (member weight (aref entry 1)))
350 (setq weight (capitalize (match-string 1 truename))))
351 (when (not (member size (aref entry 2)))
352 (setq size (string-to-int (match-string 6 truename))))
353 (setq slant (capitalize (match-string 2 truename))))
354
355 (vector entry family size weight slant)))
329 356
330 ;;;###autoload 357 ;;;###autoload
331 (defun font-menu-family-constructor (ignored) 358 (defun font-menu-family-constructor (ignored)
332 ;; by Stig@hackvan.com 359 (catch 'menu
333 (if (not (eq 'x (device-type (selected-device)))) 360 (unless (eq 'x (device-type (selected-device)))
334 '(["Cannot parse current font" ding nil]) 361 (throw 'menu '(["Cannot parse current font" ding nil])))
335 (let* ((dcache (cdr (assq (selected-device) device-fonts-cache))) 362 (let* ((dcache (device-fonts-cache))
336 (name (font-menu-truename 'default)) 363 (font-data (font-menu-font-data 'default dcache))
337 (case-fold-search t) 364 (entry (aref font-data 0))
338 family weight size ; parsed from current font 365 (family (aref font-data 1))
339 entry ; font cache entry 366 (size (aref font-data 2))
367 (weight (aref font-data 3))
340 f) 368 f)
341 (or dcache 369 (unless family
342 (setq dcache (reset-device-font-menus (selected-device)))) 370 (throw 'menu '(["Cannot parse current font" ding nil])))
343 (if (not (string-match x-font-regexp name)) 371 ;; Items on the Font menu are enabled iff that font exists in
344 ;; couldn't parse current font 372 ;; the same size and weight as the current font (scalable fonts
345 '(["Cannot parse current font" ding nil]) 373 ;; exist in every size). Only the current font is marked as
346 (setq weight (capitalize (match-string 1 name))) 374 ;; selected.
347 (setq size (string-to-number (match-string 6 name))) 375 (mapcar
348 (setq family (font-menu-family 'default)) 376 (lambda (item)
349 (setq entry (vassoc family (aref dcache 0))) 377 (setq f (aref item 0)
350 (mapcar #'(lambda (item) 378 entry (vassoc f (aref dcache 0)))
351 ;; 379 (if (and (member weight (aref entry 1))
352 ;; Items on the Font menu are enabled iff that font 380 (or (member size (aref entry 2))
353 ;; exists in the same size and weight as the current 381 (and (not font-menu-ignore-scaled-fonts)
354 ;; font (scalable fonts exist in every size). Only the 382 (member 0 (aref entry 2)))))
355 ;; current font is marked as selected. 383 (enable-menu-item item)
356 ;; 384 (disable-menu-item item))
357 (setq f (aref item 0) 385 (if (string-equal family f)
358 entry (vassoc f (aref dcache 0))) 386 (select-toggle-menu-item item)
359 (if (and (member weight (aref entry 1)) 387 (deselect-toggle-menu-item item))
360 (or (member size (aref entry 2)) 388 item)
361 (and (not font-menu-ignore-scaled-fonts) 389 (aref dcache 1)))))
362 (member 0 (aref entry 2)))))
363 (enable-menu-item item)
364 (disable-menu-item item))
365 (if (equal family f)
366 (select-toggle-menu-item item)
367 (deselect-toggle-menu-item item))
368 item)
369 (aref dcache 1)))
370 )))
371 390
372 ;;;###autoload 391 ;;;###autoload
373 (defun font-menu-size-constructor (ignored) 392 (defun font-menu-size-constructor (ignored)
374 ;; by Stig@hackvan.com 393 (catch 'menu
375 (if (not (eq 'x (device-type (selected-device)))) 394 (unless (eq 'x (device-type (selected-device)))
376 '(["Cannot parse current font" ding nil]) 395 (throw 'menu '(["Cannot parse current font" ding nil])))
377 (let ((dcache (cdr (assq (selected-device) device-fonts-cache))) 396 (let* ((dcache (device-fonts-cache))
378 (name (font-menu-truename 'default)) 397 (font-data (font-menu-font-data 'default dcache))
379 (case-fold-search t) 398 (entry (aref font-data 0))
380 family size ; parsed from current font 399 (family (aref font-data 1))
381 entry ; font cache entry 400 (size (aref font-data 2))
382 s) 401 ;;(weight (aref font-data 3))
383 (or dcache 402 s)
384 (setq dcache (reset-device-font-menus (selected-device)))) 403 (unless family
385 (if (not (string-match x-font-regexp name)) 404 (throw 'menu '(["Cannot parse current font" ding nil])))
386 ;; couldn't parse current font 405 ;; Items on the Size menu are enabled iff current font has
387 '(["Cannot parse current font" ding nil]) 406 ;; that size. Only the size of the current font is selected.
388 (setq size (string-to-number (match-string 6 name))) 407 ;; (If the current font comes in size 0, it is scalable, and
389 (setq family (font-menu-family 'default)) 408 ;; thus has every size.)
390 (setq entry (vassoc family (aref dcache 0))) 409 (mapcar
391 (mapcar 410 (lambda (item)
392 (lambda (item) 411 (setq s (nth 3 (aref item 1)))
393 ;; 412 (if (or (member s (aref entry 2))
394 ;; Items on the Size menu are enabled iff current font has 413 (and (not font-menu-ignore-scaled-fonts)
395 ;; that size. Only the size of the current font is 414 (member 0 (aref entry 2))))
396 ;; selected. (If the current font comes in size 0, it is 415 (enable-menu-item item)
397 ;; scalable, and thus has every size.) 416 (disable-menu-item item))
398 ;; 417 (if (eq size s)
399 (setq s (nth 3 (aref item 1))) 418 (select-toggle-menu-item item)
400 (if (or (member s (aref entry 2)) 419 (deselect-toggle-menu-item item))
401 (and (not font-menu-ignore-scaled-fonts) 420 item)
402 (member 0 (aref entry 2)))) 421 (aref dcache 2)))))
403 (enable-menu-item item)
404 (disable-menu-item item))
405 (if (eq size s)
406 (select-toggle-menu-item item)
407 (deselect-toggle-menu-item item))
408 item)
409 (aref dcache 2)))
410 )))
411 422
412 ;;;###autoload 423 ;;;###autoload
413 (defun font-menu-weight-constructor (ignored) 424 (defun font-menu-weight-constructor (ignored)
414 ;; by Stig@hackvan.com 425 (catch 'menu
415 (if (not (eq 'x (device-type (selected-device)))) 426 (unless (eq 'x (device-type (selected-device)))
416 '(["Cannot parse current font" ding nil]) 427 (throw 'menu '(["Cannot parse current font" ding nil])))
417 (let ((dcache (cdr (assq (selected-device) device-fonts-cache))) 428 (let* ((dcache (device-fonts-cache))
418 (name (font-menu-truename 'default)) 429 (font-data (font-menu-font-data 'default dcache))
419 (case-fold-search t) 430 (entry (aref font-data 0))
420 family weight ; parsed from current font 431 (family (aref font-data 1))
421 entry ; font cache entry 432 ;;(size (aref font-data 2))
422 w) 433 (weight (aref font-data 3))
423 (or dcache 434 w)
424 (setq dcache (reset-device-font-menus (selected-device)))) 435 (unless family
425 (if (not (string-match x-font-regexp name)) 436 (throw 'menu '(["Cannot parse current font" ding nil])))
426 ;; couldn't parse current font 437 ;; Items on the Weight menu are enabled iff current font
427 '(["Cannot parse current font" ding nil]) 438 ;; has that weight. Only the weight of the current font
428 (setq weight (capitalize (match-string 1 name))) 439 ;; is selected.
429 (setq family (font-menu-family 'default)) 440 (mapcar
430 (setq entry (vassoc family (aref dcache 0))) 441 (lambda (item)
431 (mapcar #'(lambda (item) 442 (setq w (aref item 0))
432 ;; Items on the Weight menu are enabled iff current font 443 (if (member w (aref entry 1))
433 ;; has that weight. Only the weight of the current font 444 (enable-menu-item item)
434 ;; is selected. 445 (disable-menu-item item))
435 (setq w (aref item 0)) 446 (if (string-equal weight w)
436 (if (member w (aref entry 1)) 447 (select-toggle-menu-item item)
437 (enable-menu-item item) 448 (deselect-toggle-menu-item item))
438 (disable-menu-item item)) 449 item)
439 (if (equal weight w) 450 (aref dcache 3)))))
440 (select-toggle-menu-item item)
441 (deselect-toggle-menu-item item))
442 item)
443 (aref dcache 3)))
444 )))
445 451
446 452
447 ;;; Changing font sizes 453 ;;; Changing font sizes
448 454
449 (defun font-menu-set-font (family weight size) 455 (defun font-menu-set-font (family weight size)
450 ;; This is what gets run when an item is selected from any of the three 456 ;; This is what gets run when an item is selected from any of the three
451 ;; fonts menus. It needs to be rather clever. 457 ;; fonts menus. It needs to be rather clever.
452 ;; (size is measured in 10ths of points.) 458 ;; (size is measured in 10ths of points.)
453 (let ((faces (delq 'default (face-list))) 459 (let* ((dcache (device-fonts-cache))
454 (default-name (font-menu-truename 'default)) 460 (font-data (font-menu-font-data 'default dcache))
455 (case-fold-search t) 461 (from-family (aref font-data 1))
456 new-default-face-font 462 (from-size (aref font-data 2))
457 from-family from-weight from-size) 463 (from-weight (aref font-data 3))
458 ;; 464 (from-slant (aref font-data 4))
459 ;; First, parse out the default face's font. 465 new-default-face-font)
460 ;; 466 (unless from-family
461 (setq from-family (font-menu-family 'default)) 467 (signal 'error '("couldn't parse font name for default face")))
462 (or (string-match x-font-regexp default-name)
463 (signal 'error (list "couldn't parse font name" default-name)))
464 (setq from-weight (capitalize (match-string 1 default-name)))
465 (setq from-size (match-string 6 default-name))
466 (setq new-default-face-font 468 (setq new-default-face-font
467 (font-menu-load-font (or family from-family) 469 (font-menu-load-font (or family from-family)
468 (or weight from-weight) 470 (or weight from-weight)
469 (or size from-size) 471 (or size from-size)
470 default-name)) 472 from-slant
471 (while faces 473 font-menu-preferred-resolution))
472 (cond ((face-font-instance (car faces)) 474 (dolist (face (delq 'default (face-list)))
473 (message "Changing font of `%s'..." (car faces)) 475 (when (face-font-instance face)
474 (condition-case c 476 (message "Changing font of `%s'..." face)
475 (font-menu-change-face (car faces) 477 (condition-case c
476 from-family from-weight from-size 478 (font-menu-change-face face
477 family weight size) 479 from-family from-weight from-size
478 (error 480 family weight size)
479 (display-error c nil) 481 (error
480 (sit-for 1))))) 482 (display-error c nil)
481 (setq faces (cdr faces))) 483 (sit-for 1)))))
482 ;; Set the default face's font after hacking the other faces, so that 484 ;; Set the default face's font after hacking the other faces, so that
483 ;; the frame size doesn't change until we are all done. 485 ;; the frame size doesn't change until we are all done.
484 486
485 ;;; WMP - we need to honor font-menu-this-frame-only-p here! 487 ;;; WMP - we need to honor font-menu-this-frame-only-p here!
486 (set-face-font 'default new-default-face-font 488 (set-face-font 'default new-default-face-font
490 492
491 (defun font-menu-change-face (face 493 (defun font-menu-change-face (face
492 from-family from-weight from-size 494 from-family from-weight from-size
493 to-family to-weight to-size) 495 to-family to-weight to-size)
494 (or (symbolp face) (signal 'wrong-type-argument (list 'symbolp face))) 496 (or (symbolp face) (signal 'wrong-type-argument (list 'symbolp face)))
495 (let* ((name (font-menu-truename face)) 497 (let* ((dcache (device-fonts-cache))
496 (case-fold-search t) 498 (font-data (font-menu-font-data face dcache))
497 face-family 499 (face-family (aref font-data 1))
498 face-weight 500 (face-size (aref font-data 2))
499 face-size) 501 (face-weight (aref font-data 3))
500 ;; First, parse out the face's font. 502 (face-slant (aref font-data 4)))
501 (or (string-match x-font-regexp-foundry-and-family name) 503
502 (signal 'error (list "couldn't parse font name" name))) 504 (or face-family
503 (setq face-family (capitalize (match-string 1 name))) 505 (signal 'error (list "couldn't parse font name for face" face)))
504 (or (string-match x-font-regexp name)
505 (signal 'error (list "couldn't parse font name" name)))
506 (setq face-weight (match-string 1 name))
507 (setq face-size (match-string 6 name))
508 506
509 ;; If this face matches the old default face in the attribute we 507 ;; If this face matches the old default face in the attribute we
510 ;; are changing, then change it to the new attribute along that 508 ;; are changing, then change it to the new attribute along that
511 ;; dimension. Also, the face must have its own global attribute. 509 ;; dimension. Also, the face must have its own global attribute.
512 ;; If its value is inherited, we don't touch it. If any of this 510 ;; If its value is inherited, we don't touch it. If any of this
513 ;; is not true, we leave it alone. 511 ;; is not true, we leave it alone.
514 (if (and (face-font face 'global) 512 (when (and (face-font face 'global)
515 (cond 513 (cond
516 (to-family (equal face-family from-family)) 514 (to-family (string-equal face-family from-family))
517 (to-weight (equal face-weight from-weight)) 515 (to-weight (string-equal face-weight from-weight))
518 (to-size (equal face-size from-size)))) 516 (to-size (= face-size from-size))))
519 (set-face-font face 517 (set-face-font face
520 (font-menu-load-font (or to-family face-family) 518 (font-menu-load-font (or to-family face-family)
521 (or to-weight face-weight) 519 (or to-weight face-weight)
522 (or to-size face-size) 520 (or to-size face-size)
523 name) 521 face-slant
524 (and font-menu-this-frame-only-p 522 font-menu-preferred-resolution)
525 (selected-frame))) 523 (and font-menu-this-frame-only-p
526 nil))) 524 (selected-frame))))))
527 525
528 526 (defun font-menu-load-font (family weight size slant resolution)
529 (defun font-menu-load-font (family weight size from-font) 527 "Try to load a font with the requested properties.
530 (and (numberp size) (setq size (int-to-string size))) 528 The weight, slant and resolution are only hints."
531 (let ((case-fold-search t) 529 (when (integerp size) (setq size (int-to-string size)))
532 slant other-slant 530 (let (font)
533 registry encoding resx resy) 531 (catch 'got-font
534 (or (string-match x-font-regexp-registry-and-encoding from-font) 532 (dolist (weight (list weight "*"))
535 (signal 'error (list "couldn't parse font name" from-font))) 533 (dolist (slant
536 (setq registry (match-string 1 from-font) 534 (cond ((string-equal slant "O") '("O" "I" "*"))
537 encoding (match-string 2 from-font)) 535 ((string-equal slant "I") '("I" "O" "*"))
538 536 ((string-equal slant "*") '("*"))
539 (or (string-match x-font-regexp from-font) 537 (t (list slant "*"))))
540 (signal 'error (list "couldn't parse font name" from-font))) 538 (dolist (resolution
541 (setq slant (capitalize (match-string 2 from-font)) 539 (if (string-equal resolution "*-*")
542 resx (match-string 7 from-font) 540 (list resolution)
543 resy (match-string 8 from-font)) 541 (list resolution "*-*")))
544 (setq other-slant (cond ((equal slant "O") "I") ; oh, bite me. 542 (when (setq font
545 ((equal slant "I") "O") 543 (make-font-instance
546 (t nil))) 544 (concat "-*-" family "-" weight "-" slant "-*-*-*-"
547 ;; 545 size "-" resolution "-*-*-"
548 ;; Remember these values for the first font we switch away from 546 font-menu-registry-encoding)
549 ;; (the original default font). 547 nil t))
550 ;; 548 (throw 'got-font font))))))))
551 (or font-menu-preferred-resolution
552 (setq font-menu-preferred-resolution (cons resx resy)))
553 (or font-menu-preferred-registry
554 (setq font-menu-preferred-registry (cons registry encoding)))
555 ;;
556 ;; Now we know all the interesting properties of the font we want.
557 ;; Let's see what we can actually *get*.
558 ;;
559 (or ;; First try the default resolution, registry, and encoding.
560 (make-font-instance
561 (concat "-*-" family "-" weight "-" slant "-*-*-*-" size
562 "-" (car font-menu-preferred-resolution)
563 "-" (cdr font-menu-preferred-resolution)
564 "-*-*-"
565 (car font-menu-preferred-registry) "-"
566 (cdr font-menu-preferred-registry))
567 nil t)
568 ;; Then try that in the other slant.
569 (and other-slant
570 (make-font-instance
571 (concat "-*-" family "-" weight "-" other-slant
572 "-*-*-*-" size
573 "-" (car font-menu-preferred-resolution)
574 "-" (cdr font-menu-preferred-resolution)
575 "-*-*-"
576 (car font-menu-preferred-registry) "-"
577 (cdr font-menu-preferred-registry))
578 nil t))
579 ;; Then try the default resolution and registry, any encoding.
580 (make-font-instance
581 (concat "-*-" family "-" weight "-" slant "-*-*-*-" size
582 "-" (car font-menu-preferred-resolution)
583 "-" (cdr font-menu-preferred-resolution)
584 "-*-*-"
585 (car font-menu-preferred-registry) "-*")
586 nil t)
587 ;; Then try that in the other slant.
588 (and other-slant
589 (make-font-instance
590 (concat "-*-" family "-" weight "-" other-slant
591 "-*-*-*-" size
592 "-" (car font-menu-preferred-resolution)
593 "-" (cdr font-menu-preferred-resolution)
594 "-*-*-"
595 (car font-menu-preferred-registry) "-*")
596 nil t))
597 ;; Then try the default registry and encoding, any resolution.
598 (make-font-instance
599 (concat "-*-" family "-" weight "-" slant "-*-*-*-" size
600 "-*-*-*-*-"
601 (car font-menu-preferred-registry) "-"
602 (cdr font-menu-preferred-registry))
603 nil t)
604 ;; Then try that in the other slant.
605 (and other-slant
606 (make-font-instance
607 (concat "-*-" family "-" weight "-" other-slant
608 "-*-*-*-" size
609 "-*-*-*-*-"
610 (car font-menu-preferred-registry) "-"
611 (cdr font-menu-preferred-registry))
612 nil t))
613 ;; Then try the default registry, any encoding or resolution.
614 (make-font-instance
615 (concat "-*-" family "-" weight "-" slant "-*-*-*-" size
616 "-*-*-*-*-"
617 (car font-menu-preferred-registry) "-*")
618 nil t)
619 ;; Then try that in the other slant.
620 (and other-slant
621 (make-font-instance
622 (concat "-*-" family "-" weight "-" slant "-*-*-*-"
623 size "-*-*-*-*-"
624 (car font-menu-preferred-registry) "-*")
625 nil t))
626 ;; Then try anything in the same slant, and error if it fails...
627 (and other-slant
628 (make-font-instance
629 (concat "-*-" family "-" weight "-" slant "-*-*-*-"
630 size "-*-*-*-*-*-*")))
631 (make-font-instance
632 (concat "-*-" family "-" weight "-" (or other-slant slant)
633 "-*-*-*-" size "-*-*-*-*-*-*"))
634 )))
635 549
636 (defun flush-device-fonts-cache (device) 550 (defun flush-device-fonts-cache (device)
637 ;; by Stig@hackvan.com 551 ;; by Stig@hackvan.com
638 (let ((elt (assq device device-fonts-cache))) 552 (let ((elt (assq device device-fonts-cache)))
639 (and elt 553 (and elt