Bitmap Fonts for my Terminal
Categories: [ IT ]
Since I started with Linux, back in 1997, my xterm have been using always the same font: a bitmap, fixed font which produces 6x13 pixels glyphs. I'm convinced that a bitmap font is the best possible choice for not-so-high resolution LCD monitors (I have a 17" 1280x1024 monitor which results in a 96 dpi resolution) where any vector font would inevitably produce aliased or fuzzy glyphs. My bitmap font is crisp and has no rainbow edges (who in his right mind could imagine that subpixel antialiasig is a good idea?).
With the xterm, I could simply specify the font as 6x13 and it would use it. That was simple, because it was meant for it.
Today I switched from pure X11 xterm to GTK-based evilvte and while evilvte is apparently a great tool, it didn't want to use my beloved 6x13 bitmap font. It would use 6x12 or 7x13, but not the one in the middle. The font is however available on the system through fontconfig, since I could find it withfc-match
:
$ fc-match Fixed-10:style=semicondensed 6x13-ISO8859-1.pcf.gz: "Fixed" "SemiCondensed"But evilvte, while showing "SemiCondensed" as an option in its font dialog, just seemed to ignore it. The fontconfig documentation mentions that one can trigger debug output by setting an environment variable
FC_DEBUG=1
. With it,
I could see how Pango (GTK's font managemnt system) was interacting with
fontconfig:
fc-match Fixed-10:semicondensed Match Pattern has 19 elts (size 32) family: "Fixed"(s) … style: "semicondensed"(s) slant: 0(i)(s) weight: 100(i)(s) width: 100(i)(s) … Pattern has 18 elts (size 18) family: "Fixed"(w) style: "SemiCondensed"(w) slant: 0(i)(w) weight: 100(i)(w) width: 87(i)(w) … file: "/usr/share/fonts/X11/misc/6x13-ISO8859-1.pcf.gz"(w)
That's the right font file.
While Pango:python mygtk.py "Fixed SemiCondensed 10" Match Pattern has 20 elts (size 32) family: "Fixed"(s) … slant: 0(i)(s) weight: 80(i)(s) width: 87(i)(s) … Pattern has 18 elts (size 18) family: "Fixed"(w) style: "Regular"(w) slant: 0(i)(w) weight: 80(i)(w) width: 100(i)(w) … file: "/usr/share/fonts/X11/misc/7x13-ISO8859-1.pcf.gz"(w)
And that's not the right font file…
Notice the important difference: fc-match asks for a weight of 100 (and style
SemiCondensed) while Pango asks for weight 80 and width 87 (which is
apparently equivalent to semi-condensed). Since my font had a weight of 100,
it was never selected. However, when requesting a bold version (fc-match
Fixed-10:semicondensed:bold
or python mygtk.py "Fixed SemiCondensed Bold
10"
) the same font is found (6x13B-ISO8859-1.pcf.gz, which is the bold
counterpart of my font). That took me several hours to find out.
Since the root of the problem seemd to be the weight, I needed to find out how to make Pango tell fontconfig to use a different weight, since there is apparently nothing between “Regular” (Pango 400, fontconfig 80) and “Bold” (Pango 700, fontconfig 200). And then, completely by accident, I found out there is actually a middle value: “Medium” (Pango 500, fontconfig 100), which is exactly what I neeed. But the outdated PyGTK documentation and the well-hidden man page (and very little help from Google and DuckDuckGo in finding a decent documentation for Pango, I must say) didn't make this any easy.
So finally, the magic font description I put in evilvte's config is “Fixed Medium SemiCondensed 10”. With it, Pango selects the font I want:$ python mygtk.py "Fixed Medium SemiCondensed 10" Match Pattern has 20 elts (size 32) family: "Fixed"(s) … slant: 0(i)(s) weight: 100(i)(s) width: 87(i)(s) … Pattern has 18 elts (size 18) family: "Fixed"(w) style: "SemiCondensed"(w) slant: 0(i)(w) weight: 100(i)(w) width: 87(i)(w) … file: "/usr/share/fonts/X11/misc/6x13-ISO8859-1.pcf.gz"(w)
Appendix
Themygtk.py
script is a simple GTK tool I wrote for the purpose of using a
specific Pango font description and producing the fontconfig debug output.
This is the script:
import gtk import pango import gobject import sys window = gtk.Window(gtk.WINDOW_TOPLEVEL) tv = gtk.Label("Hello World") tv.modify_font(pango.FontDescription(sys.argv[1])) window.add(tv) tv.show() window.show() gobject.timeout_add(100, gtk.main_quit) gtk.main()