wayland-client
Low-level, type-safe Rust bindings for the client side of the Wayland display protocol, with typed event dispatch.
Repository Health
Technical Analysis
wayland-client is the core crate for writing Wayland client applications in Rust. It provides the Connection and EventQueue types that manage the socket-level conversation with a Wayland compositor, plus strongly-typed Proxy objects for the core protocol interfaces, generated at build time from the official XML specification via the sibling wayland-scanner crate.
Events are delivered through a Dispatch<Interface, State> trait rather than untyped callbacks, so your application’s state struct receives compile-time-checked event handling for every Wayland object it manages. It is intentionally low-level: most application authors build on top of it via a toolkit such as Smithay’s Client Toolkit, while wayland-client itself is aimed at toolkit authors, compositor tooling, and anyone who needs direct control over the protocol.
What You Get
- A Connection type that opens and owns the Wayland Unix-socket connection, including environment-based auto-discovery via connect_to_env()
- An EventQueue/QueueHandle pair for routing and dispatching incoming protocol events to your own state type, with support for multiple independent queues
- Generated, strongly-typed Proxy structs and request/event enums for every core-protocol interface (wl_display, wl_registry, wl_surface, wl_compositor, etc.)
- A pluggable backend: a pure-Rust protocol implementation by default, or an FFI backend against the system libwayland via the system feature
- Roundtrip synchronization helpers (roundtrip(), blocking_dispatch()) for deterministic startup sequencing against the compositor
Common Use Cases
- Building a Wayland-native windowing toolkit or GUI framework’s low-level backend
- Writing compositor-adjacent utilities such as status bars, launchers, or screen-capture tools that talk directly to Sway, Hyprland, or other compositors
- Wiring GPU surface creation (via wayland-egl) into an OpenGL or Vulkan renderer on Linux desktops
- Prototyping or consuming draft Wayland protocol extensions ahead of their inclusion in wayland-protocols
Under The Hood
Architecture wayland-client is one crate in the Smithay-maintained wayland-rs Cargo workspace, layered on top of wayland-backend (the actual wire-protocol engine, offered as either a pure-Rust or libwayland-FFI implementation) and wayland-scanner (which generates typed Proxy structs and event/request enums from the wayland.xml protocol specification bundled in the crate). The runtime core is Connection (src/conn.rs), which wraps a wayland_backend::client::Backend and owns the socket lifecycle including WAYLAND_SOCKET/WAYLAND_DISPLAY/XDG_RUNTIME_DIR environment resolution, and EventQueue (src/event_queue.rs), which buffers incoming messages and drives Dispatch::event() calls against a caller-supplied State on dispatch_pending()/roundtrip(). globals.rs adds a GlobalList convenience layer over the raw wl_registry object. Because event delivery is synchronous and single-threaded against State, application logic needs no locking during processing. Any change to the core Proxy/Dispatch abstraction would ripple into every downstream crate in the workspace (wayland-protocols, wayland-cursor, wayland-egl) as well as external toolkits like Smithay’s Client Toolkit that build on it.
Tech Stack Pure Rust, edition 2024, minimum rust-version 1.86, built as part of a 13-member Cargo workspace. Direct dependencies are path-linked siblings wayland-backend (0.3.15) and wayland-scanner (0.31.10, invoked from build.rs), plus bitflags 2 for protocol flag types and rustix 1.0.2 (event feature) for low-level Unix fd/epoll handling in place of raw libc calls, with an optional log 0.4 integration. Dev-dependencies (wayland-protocols, futures-channel, futures-util, tokio with rt-multi-thread/net, tempfile) support the crate’s examples, including an async/tokio integration example. Feature flags (system, dlopen, libwayland_1_23) select between the built-in Rust backend and various libwayland FFI linking strategies. The deployment target is any Linux or BSD desktop running a Wayland compositor.
Code Quality Integration testing lives in a dedicated wayland-tests workspace member with over 20 end-to-end test files (client_dispatch.rs, client_proxies.rs, protocol_errors.rs, destroyed_object.rs, threads.rs, xdg_shell_ping.rs, and more) that exercise real client/server round trips rather than unit-testing wayland-client in isolation; no #[test] functions live directly under wayland-client/src. Error handling is explicit and typed (ConnectError, DispatchError, InvalidId, WaylandError enums) rather than panicking or swallowing failures. CI (.github/workflows/ci.yml) runs cargo fmt —check, cargo clippy —all —all-features —all-targets — -D warnings as a deny-level gate, and cargo-deny for dependency/license auditing, backed by a Cirrus CI configuration for extra platform coverage — a notably rigorous bar for a systems-level crate. Naming follows idiomatic Rust conventions and the crate carries extensive rustdoc, including a runnable doc-tested example embedded directly in lib.rs.
API Design The public surface centers on four well-named entry points — Connection, EventQueue, QueueHandle, and the Dispatch trait — introduced through a complete getting-started example in the crate’s top-level documentation, and boilerplate is minimized by auto-generating typed request/event methods per protocol interface instead of requiring hand-written message (de)serialization. Dispatch<Interface, UserData> is explicitly designed for delegation: third-party crates can implement it generically over a consumer’s own State type, which is how toolkits like Smithay’s Client Toolkit offer drop-in event handling without forcing every user to implement each interface by hand. The tradeoff is a real learning curve — understanding how queues, dispatch, and generated proxies fit together takes some upfront investment — but the crate-level example and consistent naming keep that cost manageable, and downstream toolkits exist specifically to abstract it further for application authors.