Python xlib change cursor

1.2k views Asked by At

How can I set the cursor for the root window (or any other window) in a python application using Xlib?

I have an instance of display and window (the root window). Using the C bindings; I could use XDefineCursor with a cursor I have created with XCreatePixmapCursor. How do I do the same with the python bindings?

I want to be able to use a default cursor, or a custom cursor.

1

There are 1 answers

1
Aleksi Torhamo On

There are two things you want to keep in mind when you need to find the python-xlib equivalent of any libX11 function:

  1. Unlike libX11, python-xlib is object-oriented; In this case, XCreatePixmapCursor() translates to pixmap.create_cursor().
  2. Most python-xlib methods map directly to X11 messages, ie. most helper functions aren't implemented; If you can't find a matching python-xlib method, you'll often want to look at the libX11 source code to figure out if the function is just a helper that calls some other function under the hood. In this case, if you look at the source code of XDefineCursor(), you'll see it's actually calling XChangeWindowAttributes(), meaning you'll want to use win.change_attributes() in python-xlib.

If you want to use XCreateFontCursor() to use a cursor from the cursor font, the second guideline again applies: It's calling XCreateGlyphCursor() under the hood, which corresponds to font.create_glyph_cursor().

Putting all of that together, here's what you'll get:

# Create font cursor
font = display.open_font('cursor')
cursor = font.create_glyph_cursor(font, Xlib.Xcursorfont.crosshair, Xlib.Xcursorfont.crosshair+1, (65535, 65535, 65535), (0, 0, 0))


# Use PIL to load a cursor image and ensure that it's 1-bit as required
im = Image.open('cursor.png').convert('1')
w, h = im.size

# Create pixmap cursor
mask = win.create_pixmap(w, h, 1)
gc = mask.create_gc(foreground=0, background=1)
mask.put_pil_image(gc, 0, 0, im)
cursor = mask.create_cursor(mask, (0, 0, 0), (65535, 65535, 65535), 0, 0)


# Change cursors for given windows
win.change_attributes(cursor=cursor)

If you're wondering about the significance of the +1 in the call to font.create_glyph_cursor(), that's explained in the source code of XCreateFontCursor().