wl_client/
lib.rs

1//! This crate provides safe wrappers around libwayland. It supports both blocking and
2//! async operations with any async runtime. Both `'static` and `'scoped`, `Send` and
3//! `!Send` event handlers are supported.
4//!
5//! The most important types provided by this crate are
6//!
7//! - [`Libwayland`]: A reference to a dynamically loaded `libwayland-client.so`.
8//! - [`Connection`]: A connection to a wayland compositor.
9//! - [`Queue`]: An event queue.
10//!
11//! This crate does not itself provide type-safe wrappers for wayland protocol objects
12//! (`wl_display`, `wl_keyboard`, etc). Instead, applications should use the
13//! [`wl-client-builder`] crate to generate these wrappers ahead of time or in `build.rs`.
14//!
15//! [`wl-client-builder`]: https://docs.rs/wl-client-builder
16//!
17//! # Example: Hello wayland
18//!
19//! The code of this example can be found in the `hello-wayland` example binary.
20//!
21//! ```
22//! # use wl_client::{proxy, Libwayland};
23//! # use wl_client::test_protocols::core::wl_callback::WlCallback;
24//! # use wl_client::test_protocols::core::wl_display::WlDisplay;
25//! #
26//! // Load the `libwayland-client.so` dynamic library.
27//! let lib = Libwayland::open().unwrap();
28//! // Connect to the default display determined by the `WAYLAND_DISPLAY` env var.
29//! let con = lib.connect_to_default_display().unwrap();
30//! // Create a new event queue with the name `hello-wayland`. This name will show up
31//! // when debugging applications with `WAYLAND_DEBUG=1`.
32//! let queue = con.create_queue(c"hello-wayland");
33//! // Get a reference to the `wl_display` singleton. This type was generated with the
34//! // `wl-client-builder` crate.
35//! let display: WlDisplay = queue.display();
36//! // Create a `wl_callback` object. The compositor will immediately respond with a
37//! // `wl_callback.done` event.
38//! let sync = display.sync();
39//! // Set the event handler of the proxy.
40//! proxy::set_event_handler(
41//!     &sync,
42//!     // When only handling a single event type, the following functional form can be
43//!     // used. In general, and when handling more than one event type, the event handler
44//!     // trait must be implemented. In this case, `WlCallbackEventHandler`.
45//!     WlCallback::on_done(|_, _| println!("Hello wayland!")),
46//! );
47//! // Perform a roundtrip to ensure that the `done` event has been dispatched.
48//! queue.dispatch_roundtrip_blocking().unwrap();
49//! ```
50//!
51//! # Example: Getting a registry snapshot
52//!
53//! The code of this example can be found in the `get-registry` example binary.
54//!
55//! ```
56//! # use parking_lot::Mutex;
57//! # use wl_client::Queue;
58//! # use wl_client::test_protocols::core::wl_display::WlDisplay;
59//! # use wl_client::test_protocols::core::wl_registry::WlRegistry;
60//! #
61//! struct Global {
62//!     pub name: u32,
63//!     pub interface: String,
64//!     pub version: u32,
65//! }
66//!
67//! fn get_registry_snapshot(queue: &Queue) -> (WlRegistry, Vec<Global>) {
68//!     // Create a new registry that will receive the globals and can later be used to
69//!     // bind them.
70//!     let registry = queue.display::<WlDisplay>().get_registry();
71//!     let globals = Mutex::new(vec![]);
72//!     // Since we don't care about registry events after this function returns, we can
73//!     // use a dispatch scope. The event handlers in this scope will not be called after
74//!     // the function returns.
75//!     queue.dispatch_scope_blocking(|scope| {
76//!         scope.set_event_handler(
77//!             &registry,
78//!             // Since we only want to create a snapshot, we don't care about
79//!             // global_remove events. This allows us to use the functional event handler
80//!             // form.
81//!             WlRegistry::on_global(|_, name, interface, version| {
82//!                 globals.lock().push(Global {
83//!                     name,
84//!                     interface: interface.to_string(),
85//!                     version,
86//!                 });
87//!             }),
88//!         );
89//!         queue.dispatch_roundtrip_blocking().unwrap();
90//!     });
91//!     // The event handler will no longer be called after this function returns but
92//!     // the registry can still be used to bind globals.
93//!     (registry, globals.into_inner())
94//! }
95//! ```
96//!
97//! # Example: Handling keyboard events
98//!
99//! The code of this example can be found in the `keyboard-events` example binary.
100//!
101//! ```
102//! # use std::cell::RefCell;
103//! # use std::rc::Rc;
104//! # use wl_client::proxy;
105//! # use wl_client::test_protocols::core::wl_keyboard::{WlKeyboard, WlKeyboardEventHandler, WlKeyboardKeyState, WlKeyboardRef};
106//! # use wl_client::test_protocols::core::wl_seat::{WlSeat, WlSeatCapability, WlSeatEventHandler, WlSeatRef};
107//! #
108//! /// The state used to handle seat and keyboard events. In a real application this
109//! /// would likely also contain a way to map keycodes to keysyms and to forward events
110//! /// to the rest of the application.
111//! struct Seat {
112//!     wl_seat: WlSeat,
113//!     wl_keyboard: RefCell<Option<WlKeyboard>>,
114//! }
115//!
116//! #[derive(Clone)]
117//! struct SeatEventHandler(Rc<Seat>);
118//!
119//! impl WlSeatEventHandler for SeatEventHandler {
120//!     fn capabilities(&self, _slf: &WlSeatRef, capabilities: WlSeatCapability) {
121//!         let kb = &mut *self.0.wl_keyboard.borrow_mut();
122//!         // When the seat loses/gains the keyboard capability, we need to
123//!         // destroy/create a wl_keyboard.
124//!         if capabilities.contains(WlSeatCapability::KEYBOARD) {
125//!             if kb.is_none() {
126//!                 let wl_keyboard = self.0.wl_seat.get_keyboard();
127//!                 // Since we're using `Rc` here, event handlers must be set with the
128//!                 // `_local` function which allows `!Send` event handlers.
129//!                 proxy::set_event_handler_local(&wl_keyboard, self.clone());
130//!                 *kb = Some(wl_keyboard);
131//!             }
132//!         } else {
133//!             if let Some(kb) = kb.take() {
134//!                 // The wl_keyboard.release request is only available since version 3.
135//!                 // If it's not available, at least destroy the client-side object.
136//!                 if proxy::version(&*kb) >= WlKeyboard::REQ__RELEASE__SINCE {
137//!                     kb.release();
138//!                 } else {
139//!                     proxy::destroy(&kb);
140//!                 }
141//!             }
142//!         }
143//!     }
144//! }
145//!
146//! // If more than one event type needs to be handled by an event handler, the convenient
147//! // functional API cannot be used. Instead the application needs to implement the
148//! // `*EventHandler` trait manually.
149//! impl WlKeyboardEventHandler for SeatEventHandler {
150//!     fn key(&self,
151//!         _slf: &WlKeyboardRef,
152//!         _serial: u32,
153//!         _time: u32,
154//!         key: u32,
155//!         state: WlKeyboardKeyState,
156//!     ) {
157//!         println!("key {key:} {state:?}");
158//!     }
159//!
160//!     fn modifiers(
161//!         &self,
162//!         _slf: &WlKeyboardRef,
163//!         _serial: u32,
164//!         mods_depressed: u32,
165//!         mods_latched: u32,
166//!         mods_locked: u32,
167//!         group: u32,
168//!     ) {
169//!         println!("modifiers {mods_depressed:x}, {mods_latched:x}, {mods_locked:x}, {group}");
170//!     }
171//! }
172//! ```
173//!
174//! # Example: Async roundtrip
175//!
176//! The code of this example can be found in the `async-dispatch` example binary.
177//!
178//! ```
179//! # use std::cell::Cell;
180//! # use wl_client::Libwayland;
181//! # use wl_client::test_protocols::core::wl_display::WlDisplay;
182//! # use wl_client::test_protocols::core::wl_registry::WlRegistry;
183//! #
184//! # async fn async_roundtrip() {
185//! let lib = Libwayland::open().unwrap();
186//! let con = lib.connect_to_default_display().unwrap();
187//! let queue = con.create_local_queue(c"async-roundtrip");
188//! let registry = queue.display::<WlDisplay>().get_registry();
189//! let num_globals = Cell::new(0);
190//! queue
191//!     .dispatch_scope_async(async |scope| {
192//!         scope.set_event_handler_local(
193//!             &registry,
194//!             WlRegistry::on_global(|_, _, _, _| {
195//!                 num_globals.set(num_globals.get() + 1);
196//!             }),
197//!         );
198//!         // This function can be used to perform an async roundtrip. It is
199//!         // compatible with any async runtime. This example also demonstrates
200//!         // that this works in combination with scoped event handlers.
201//!         queue.dispatch_roundtrip_async().await.unwrap();
202//!     })
203//!     .await;
204//! println!("number of globals: {}", num_globals.get());
205//! # }
206//! ```
207//!
208//! # Example: Async waiting for events
209//!
210//! The code of this example can be found in the `async-wait` example binary.
211//!
212//! ```
213//! # use wl_client::{proxy, Libwayland};
214//! # use wl_client::test_protocols::core::wl_callback::WlCallback;
215//! # use wl_client::test_protocols::core::wl_display::WlDisplay;
216//! #
217//! # async fn wait_for_events() {
218//! let lib = Libwayland::open().unwrap();
219//! let con = lib.connect_to_default_display().unwrap();
220//! let queue = con.create_local_queue(c"async-wait");
221//!
222//! let sync = queue.display::<WlDisplay>().sync();
223//! proxy::set_event_handler(&sync, WlCallback::on_done(|_, _| println!("done!")));
224//!
225//! loop {
226//!     // This future completes once there are events to dispatch in the queue.
227//!     queue.wait_for_events().await.unwrap();
228//!     queue.dispatch_pending().unwrap();
229//! }
230//! # }
231//! ```
232//!
233//! # Example: Poll-based event loop integration
234//!
235//! The code of this example can be found in the `poll-integration` example binary.
236//!
237//! ```
238//! # use std::os::fd::AsRawFd;
239//! # use mio::{Interest, Token};
240//! # use mio::unix::SourceFd;
241//! # use wl_client::{proxy, Libwayland};
242//! # use wl_client::test_protocols::core::wl_callback::WlCallback;
243//! # use wl_client::test_protocols::core::wl_display::WlDisplay;
244//! #
245//! # fn event_loop() {
246//! let lib = Libwayland::open().unwrap();
247//! let con = lib.connect_to_default_display().unwrap();
248//! let queue = con.create_local_queue(c"poll-integration");
249//!
250//! // The watcher exposes a file descriptor that will become readable when the queue
251//! // has new events.
252//! let watcher = queue.create_watcher().unwrap();
253//! let token = Token(0);
254//!
255//! let sync = queue.display::<WlDisplay>().sync();
256//! proxy::set_event_handler(&sync, WlCallback::on_done(|_, _| println!("done!")));
257//!
258//! let mut events = mio::Events::with_capacity(2);
259//! let mut poll = mio::Poll::new().unwrap();
260//! poll.registry()
261//!     .register(
262//!         &mut SourceFd(&watcher.as_raw_fd()),
263//!         token,
264//!         Interest::READABLE,
265//!     )
266//!     .unwrap();
267//!
268//! loop {
269//!     // Flush requests before polling.
270//!     con.flush().unwrap();
271//!     poll.poll(&mut events, None).unwrap();
272//!     for event in events.iter() {
273//!         if event.token() == token {
274//!             queue.dispatch_pending().unwrap();
275//!             // Reset the watcher to clear the readability status.
276//!             watcher.reset().unwrap();
277//!         }
278//!     }
279//!     events.clear();
280//! }
281//! # }
282//! ```
283
284#![allow(clippy::len_zero)]
285
286pub use {
287    connection::{Connection, wait_for_events::QueueWatcher},
288    fixed::Fixed,
289    libwayland::Libwayland,
290    proxy::low_level::owned::scope::Scope,
291    queue::{BorrowedQueue, DispatchLock, Queue, QueueOwner},
292};
293
294#[doc(hidden)]
295pub mod builder;
296mod connection;
297pub mod ffi;
298mod fixed;
299#[cfg_attr(any(test, feature = "_doctests"), path = "libwayland_test.rs")]
300mod libwayland;
301mod protocols;
302pub mod proxy;
303mod queue;
304#[cfg(any(test, feature = "_doctests"))]
305pub mod test_protocol_helpers;
306#[cfg(any(test, feature = "_doctests"))]
307pub mod test_protocols;
308#[cfg(test)]
309mod tests;
310mod utils;