Some notes on using XFT fonts in TK 8.5
Due to Ubuntu 12.04 switching to TK 8.5 by default, I recently
discovered that I had never migrated to using XFT fonts in exmh when I moved the
rest of my environment to them (and sort of to UTF-8). Deciding to fix
that led me into a number of adventures, partly because exmh itself
generated XLFD font names in a number of important places. So here is
what I have learned about XFT font support in TK 8.5.
To start with, TK 8.5 has the XFT font name problem. It accepts a very limited subset of
normal XFT font naming, as seen in the
family [size [style ...]]
(You cannot supply styles without giving a size; this is not clearly
stated in the manpage.)
One thing you cannot do with the styles is specify that you only
want a monospace or a proportional font. The best you can do is use
font metrics ... -fixed' to see if you actually have a monospaced
or proportional font (see
font(n) for the details). This implies
that unlike with XLFD font names, there is no way to ask for a generic
monospaced or proportional font; the closest you can come is ask for one
of the generic font names (either the customary XFT generic names or TK
8.5's guaranteed to be there generic names).
Although it is not documented as such, if you are specifying this as
all one string (such as in a
-font argument), the family must be a
single word without spaces. This is rather unfortunate, because in the
XFT world it is common for font families to have multi-word names (eg
'DejaVu Sans', 'Times New Roman', and so on). You may have to create
some single word FontConfig aliases in order to use the fonts you want
in a TK program.
(This limitation goes away if you use the various
font commands to set
up fonts; if you specify the family directly with a
it can be a multi-word family name. But that may require a significant
rewrite in a program that was written to use
-font with font names
assembled on the fly, as is the case with exmh.)
By implication and corollary, TK 8.5 doesn't support the
'family1,family2,...' XFT search notation for family names. If you
want to search among multiple alternatives, you need to code it
yourself. This is made more difficult by the next issue.
Setting an XFT font as something's font always succeeds (assuming
that the font string is syntactically valid). Regardless of whether or
not the font you asked for actually exists, using it as a font will
never give errors. If your font does not actually exist, TK gives you,
well, something. This is especially dangerous because the styles you
can specify do not include monospace versus proportional; instead, I
believe that you always get the default proportional font if what you
asked for doesn't exist.
(This behavior is documented if you read
font(n) carefully. I seem to
get the FontConfig default sans-serif font, ie what 'sans-serif' maps
So how do you check that a font actually exists? Well, there isn't a
sure way that I know of; the best one I have so far is:
- first, accept a list of standard font family names that we believe
should always exist. My current one is:
monospace serif sans-serif times courier helvetica
(accepted in any case); this covers the standard FontConfig font
names and the standard TK font names.
font actual "...." -family to get the actual family name for
both the family we've been asked for (with the size and styles also
specified) and a font family that definitely doesn't exist; the latter
gives us the family name of the default font. If what we got isn't
what we asked for and is the default font family, the font we asked
for probably doesn't exist.
(The corner case is where we asked for something that is an alias for
the default font; in this case we should say that it exists. I don't
know how to detect this. That's why it's important to accept standard
You will probably be unsurprised to know that the guaranteed TK 8.5
font families of 'times', 'helvetica', and 'courier' do not necessarily
map to the default FontConfig fonts for 'serif, 'sans-serif', or
'monospace'. On Fedora 16 and Ubuntu, TK likes the Nimbus fonts for
these while DejaVu fonts are the normal default ones. As far as I know
you cannot change what font families TK will use for its guaranteed font
(If any of my readers use exmh and are interested in XFT
font support for it, I've posted my hack modifications to the
exmh-workers mailing list (you can find it on gmane.org). Since I'm only vaguely a
TCL/TK programmer, the code is far from ideal.)
Sidebar: What '
font create' fonts aren't
Because I had to confirm this myself just now, I'm going to write
it down: TK 8.5 allows you to create named fonts with '
name ...'. Such fonts are fully specified fonts and cannot be
used as building blocks to derive other fonts; they do not create
aliases for other general font families or the like. In other words you
font create example -family "Liberation Sans"
font actual "example 30 bold italic"
(Well, you can do this but it doesn't get you what you want.)
This is the core distinction between a font family and a realized TK
font. A realized TK font has a size, a set of styles, and so on, and it
has these whether or not you specified them (if you don't specify them
they take on default values). Here we created
example as a realized
font and if you inspect its attributes you can see that TK filled in
default values for the size and so on. As a realized font it is not a
font family and cannot be used as one (well, TK doesn't even notice that
we're trying to use it that way; font names and family names could be
described as being in completely different namespaces).
It would be really convenient if
font create could be used to create
and redefine font family aliases; then you could do things like redefine
what font family TK would use for 'times' (which would be handy if you
were dealing with a large body of existing code that used these font
family names) or create single-word aliases for font families with
spaces in their names. But it doesn't work that way at all.