Bug reported by Marc Lehmann on the Debian BTS. He's using Xft 18.104.22.168 but I don't see any commit that could have fixed this since then. He says:
XftDrawRect works differently when the alpha channel is < 32768 depending on wether the server supports the Render extension or not.
First of all, it is documented to "fill a solid rectangle". This is the actual behaviour when the server supports Render: the pixel value (including alpha channel) is taken as it is and the destination rectangle will be filled with the value:
XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict,
&color->color, x, y, width, height);
(pictopsrc is documented to just copy all four channels (rgba) from source to destination).
However, when the Render extension is not supported by the server, the behaviour is different: when the alpha value is >= 32768, then the rectangle will be filled with the pixel value as-is (which is the correct behaviour), otherwise _NOTHING_ will be done:
if (color->color.alpha >= 0x8000)
XSetForeground (draw->dpy, draw->core.gc, color->pixel);
XFillRectangle (draw->dpy, draw->drawable, draw->core.gc,
x, y, width, height);
This makes xftdrawrect unsuitable for the purpose it was actually created for: filling the background to some defined value. Regardless of what the purpose behind XftDrawRect, this is completely different behaviour depending on wether the server supports Render or not.
(for example, when xftdrawrect'ing a 100% transparent red over a newly allocated and uncleared pixmap will result in that pixmap being filled with 100% transparent red when the server supports Render, and with retaining the garbage it contained when the server doesn't support Render).
The fix is to always call xfillrectangle even for partly transparent
colours, resulting in the same behaviour regardless of the availability of
Fixed in git, thanks!