Understanding X mouse cursors (and their several layers of history)

March 18, 2020

Like most if not all windowing systems, X has the concept of the mouse cursor and allows it to take on various shapes depending on what's going on and what the mouse is over. The mouse cursor is drawn by the server, which means that X programs need to have some way of telling the server what cursor shape they want at the moment (traditionally by associating a cursor shape with every window or sub-window area and then letting X work out which one to display based on where the mouse pointer was).

The X protocol (and server) come with a pre-defined set of cursors. If your program is happy with one of these, you use it by telling the X server that you want cursor number N with XCreateFontCursor(). As mentioned in the manpage (and hinted at by the function name), the server loads these cursors from a specific X font, which is exposed to clients under the special font name 'cursor'. Like the special 'fixed' font name, this isn't even a XLFD font name and so there's no way to specify what pixel size you want your cursors to be in; you get whatever (font) size the font is or the server decides on (if the X font the server is using is one where it can do that, and I'm not sure that the X server even supports resizable fonts for the special cursor font).

(The 'cursor' font is listed in 'xlsfonts' output and can be looked at with 'xfd -fn cursor'. There are often several alternate cursor fonts, which you can also look at; these would be used through XCreateGlyphCursor().)

The actual font that is the (default) cursor font can be set through a server command line argument (per XServer(1)). If not set, I believe it's whatever font called 'cursor' the X server finds while rummaging around its font directories. On my Fedora 31 machine, this font file is /usr/share/X11/fonts/misc/cursor.pcf.gz (ie, a bitmap font in PCF format, which I believe means that it has only a single size). This 'cursor' font has to be specially formatted to provide not just the actual image for each cursor but also the mask for what parts of the cursor are transparent (see here and here, and also here). This cursor font file is normally only present on machines with the X server, and because it's used (only) by the server, it only needs to be on the server's machine. In other words, this is a server side X font.

Of course, it didn't take long for people to be unhappy with the default X server cursors in the default size. In particular, people wanted themes, with their own choice of different looking cursors. Fortunately X had always provided an escape hatch for programs that wanted custom cursors; not only could they use an different font to get cursors from (although it had better be set up right), they could also define their own cursor bitmaps and masks with XCreatePixmapCursor() (and apparently there are additional options these days). So enterprising people built cursor theming on top of this, eventually with a more or less standard library for this, XCursor (see also the Arch wiki). Somewhat to my surprise, XCursor is used today even by things like xterm.

(I'm not sure how toolkits like GTK and desktops like KDE do all of this, but I think they're at least compatible with XCursor so you can use the same cursor themes and theme configuration files with both.)

Because cursor themes work by having the X client create bitmaps and then send them to the X server, they're reliant on having the cursor theme data that defines the cursors on every machine you run X programs from. This has the same drawbacks as modern X fonts do; how a given cursor theme is rendered (and if it is at all) depends on the individual client and the individual machine. If you run all of your X programs from one machine, either everything works or it doesn't. If you run your X programs from multiple machines and use a HiDPI display, you can discover that your Ubuntu machines are missing some cursor theme data files.

(Even if everyone has the same cursor theme data (and uses the same theme), they all need to agree about what size the cursors should be given various settings, your apparent display DPI, and so on.)

PS: It appears that even with XCursor, basic X programs make no attempt to scale up the size of (some) mouse cursors to match the size of other elements. For instance, I can run 'xterm -fs 24' to get pretty gigantic text, but the I-beam mouse cursor is the same size as always and so now pretty small compared to the letters themselves. Depending on your view, this may or may not be a feature; you can argue that the size of the mouse pointer you want is set by how visible various sizes are, not how well they match other elements of the window you're in. It could be pretty weird to move your mouse cursor from a big text xterm to a normal xterm and back and have the mouse cursor jump around in size.


Comments on this page:

By hobbs at 2020-05-14 03:22:21:

So I decided to check out what was in the cursor font with that "xfd" command and... Gumby? Yeah, that's Gumby.

Written on 18 March 2020.
« A problem I'm having with my HiDPI display, remote X, and (X) cursors
Sorting out Go's 'for ... = range ..' and when it copies things »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Mar 18 00:14:40 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.