Wandering Thoughts archives

2012-05-23

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 font(n) manpage:

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 -family argument 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 to.)

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.

  • use 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 aliases immediately.)

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 families.

(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 'font create 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 cannot do:

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.

programming/TK85XFTFontNotes written at 01:49:31; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.