Skip to main content

Crate os_cursors

Crate os_cursors 

Source
Expand description

Per-app custom mouse cursors, no toolkit fork required.

UI toolkits (gpui included) ask the OS for named cursors — +[NSCursor arrowCursor] on macOS, LoadCursorW(IDC_ARROW) on Windows, a freedesktop name like "default" on Linux. This crate changes what those answers look like for the current process only, from below the toolkit:

  • macOS — the NSCursor class methods are swizzled (supported objc runtime API) to return cursors built from your images. Call install on the main thread.
  • Windows — a thread-scoped WH_CALLWNDPROCRET hook watches WM_SETCURSOR; when the toolkit sets a standard IDC_* cursor, it is swapped for yours. Windows collapses several logical cursors onto one handle (all horizontal resizes are IDC_SIZEWE, hands are IDC_HAND), so only the cursors in that granularity install — the rest return false. Call install on the UI thread.
  • Linux — the platform already does per-process theming: libXcursor/libwayland-cursor read XCURSOR_THEME / XCURSOR_PATH / XCURSOR_SIZE. use_xcursor_theme sets them; per-image install is a no-op. Must run before the display connection (i.e. first thing in main). Caveat: a Wayland client using the cursor-shape-v1 protocol delegates drawing to the compositor and cannot be themed — gpui’s current backend does not, but check yours.

The pack currency is the XCursor theme directory — the standard Linux cursor-theme format, so every existing theme is drop-in content. xcursor parses and writes the binary files, pure Rust, no deps.

Modules§

xcursor
The XCursor binary format — parse and write, pure Rust.

Structs§

Image
One cursor image (a single size — one XCursor frame).

Enums§

Cursor
The named cursors an app can replace — the intersection AppKit vends and gpui requests. ResizeColumn/ResizeRow don’t appear: every platform aliases them onto ResizeLeftRight/ResizeUpDown.

Functions§

best_image
From a parsed set of frames, the best single frame for a target pixel size: the smallest nominal size ≥ target_px, else the largest available. (First frame wins among animation siblings of one size.)
install
Replace cursor with the best-fitting frame from images.
reset
Remove every installed cursor; the native ones return.
use_xcursor_theme
Linux: point this process at an XCursor theme — themes_dir/name/cursors/ must exist. Sets XCURSOR_PATH (prepended), XCURSOR_THEME, and XCURSOR_SIZE, which libXcursor and libwayland-cursor read when the UI first connects — so this must run before any windowing/display setup and before other threads exist (environment mutation is process-global). No-op false on macOS/Windows — use install.