Expand description
Out-of-band X11 cursor delivery, the X11 counterpart of the Wayland compositor’s cursor
callback: one process-wide monitor thread (the X pointer is global, however many captures
run) parks in wait_for_event on its own connection for XFixes DisplayCursorNotify and
hands each new cursor to the registered CursorSink — the same payload the Wayland
backend sends, so a consumer needs one handler for both.
Keeping the cursor out of the framebuffer means pointer motion over static content never
dirties the damage hash or re-encodes video; capture_cursor compositing stays available
as the opt-in alternative.
The thread blocks — no polling. Stop and replay requests wake it by sending a
ClientMessage to a private InputOnly window from a short-lived connection, which also
keeps every request on the monitor’s own connection single-threaded. The SeqCst pairs on
stop/wake_win close the startup race where a stop lands before the wake window
exists: whichever side loses the ordering still observes the other’s store.
Structs§
Statics§
- CALLBACK 🔒
- The cursor sink from
set_cursor_callback, shared by every X11 capture. - REPLAY 🔒
- Deliver the current cursor on the next wake (a callback registered mid-run).
- SIZE_
CAP 🔒 - Longest delivered cursor edge; larger images are downscaled (
<= 0= uncapped). 128 is what a browser shows as a cursor, so an application’s own sprite travels whole. - SLOT 🔒
Functions§
- acquire
- An X11 capture started: the first one in spawns the monitor.
- cursor_
to_ 🔒png - XFixes ARGB image -> callback payload: cropped to the visible bounding box (hotspot
re-based to it), downscaled so the longest edge fits
cap, un-premultiplied, and PNG-encoded. Scaling runs in premultiplied space — per-channel filtering is only linear there, and fully transparent texels cannot bleed dark fringes into edges — and straight alpha is produced last, since that is what PNG carries. A fully transparent image is an intentional pointer hide. - deliver 🔒
- Hand a payload to the sink (skips quietly with no sink, no payload, or a consumer that is gone).
- fetch_
payload 🔒 - Fetch and convert the current cursor.
Noneon a fetch failure (XFixes returns an error while the cursor is not displayed, e.g. a blanked screen) or an encode failure — mirroring the Wayland gate where only real payloads or an explicit hide go downstream. - monitor_
thread 🔒 - release
- An X11 capture stopped: the last one out stops and joins the monitor. A caller holding the GIL runs it detached — the thread may be blocked delivering a cursor to a sink that needs it — and the join is bounded: a thread that misses the wake (X server wedged mid-shutdown) is abandoned with a warning rather than hanging the caller; it exits on its own next event. A stop issued from inside the cursor sink runs on the monitor thread itself, where a join can only time out: it signals and detaches instead, and the loop observes the stop flag once the sink returns.
- set_
callback - Register/replace the callback and re-deliver the current cursor to it.
Nonewithdraws it, releasing what the callback holds: the slot is process-wide and outlives the capture that set it, so a consumer that is going away has no other way to let go. - set_
size_ cap - setup 🔒
- shutdown
- Consumer teardown: drop the sink and signal the thread without joining —
SHUTDOWNalready gates it off the consumer, and a normal capture stop reaps it viarelease. - wake 🔒
- Wake the parked monitor: a ClientMessage to its private window (SendEvent with an empty
mask delivers to the window’s creator) from a short-lived connection. The send is
round-tripped (
check) so a failure has a name, and the whole wake is retried once. A zero window means setup hasn’t finished; the thread re-checks its flags before first parking, so the wake can be skipped.
Type Aliases§
- Payload 🔒
- The last payload handed to the sink, retained so a replay (late callback registration) re-sends it without touching the server — mirroring the Wayland backend, and immune to XFixes’ transient “cursor not displayed” fetch errors.