One of the things I like about X11 is that it's not the
library API which is specified, but the wire protocol. This
allows building of abstractions in an idiomatic way for
every given language, with none of the penalties involved in
layering atop an existing foreign library – which
penalties can be both from impedance mismatches between the
implementation languages, and from maintenance headaches
should the details of the library change. Instead, the X11
wire protocol is extensible (through server extensions) in a
backward-compatible way, so code written for old versions of
the protocol continues to work, if perhaps less beautifully.
So, the Common Lisp community has inherited some work done
by Texas Instruments in 1987 to write an interface, named CLX to the
X11 protocol. Generally, the interface is quite idiomatic
and naturally Lispy; anecdotally,
it's nicer to use than Xlib (a C binding) – I haven't
heard enough about the new C bindings (XCB) to judge.
The downside of this language neutrality is the possibility
of not having enough eyes to find bugs and hands to fix
them: given that very few people use CLX, and fewer still
know much about the X11 protocol, problems can languish
unfixed for a long time. One such was exposed by the McCLIM
backend using freetype and the RENDER X11 extension for font
rendering: an attempt to display strings of more than 254
characters in length would generate nasty-looking X errors
(BadGlyphSet errors for strings of 255 characters,
followed by LengthError for longer strings).
From inspecting the X server source code, it would appear
that this is because the encoding of glyph sequences on the
wire for the RenderCompositeGlyph32 request (and
its 8-bit and 16-bit siblings) seems... how can I put
this... odd. The protocol
documentation is unclear (to me) on this issue, but it
seems that there is an 8-bit length field for a sequence of
glyphs from the current glyphset, and that 255 is an escape
code in that length field to indicate a change of glyphset.
I don't know why it was done this way, given that there are
then three spare bytes which are unused by this protocol
– maybe no-one anticipated that displaying strings of
255 or more characters might be desired? In any case, this,
coupled with a naïve interface to the protocol request,
explains the
errors we were seeing, as attempting to render a string of
255 characters triggered the escape code, meaning that x-
and y-offset values were in fact interpreted as a glyphset
– unsurprisingly, an invalid one. Strings longer than
255 characters would have only the low 8 bits encoded in the
length, and so would generate length mismatch errors.
Hooray, everything makes sense.
I've constructed a putative
fix for this in CLX, and sent it to the mailing list.
It's not quite as efficient as it could be, and there will
no doubt be extra hair as and when a :translate
keyword argument is added to that function, analogous to the
functionality for draw-glyphs, but it seems to work
on the limited testing I've given it. I'd appreciate
comments and corrections from people who actually know X11
and/or CLX, though.