wayland-client

Low-level, type-safe Rust bindings for the client side of the Wayland display protocol, with typed event dispatch.

Library
Cargo
v0.31.15
1,419stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
86/100Excellent
Development Activity96
Maintenance72
Community76
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
84/100Excellent
Architecture85
Code Quality88
Innovation78
Learning Curve85

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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search