wl_client/proxy.rs
1//! Wayland proxy objects and helpers.
2//!
3//! Proxies represent objects in the wayland protocol. Libwayland uses `wl_proxy` pointers
4//! to represent proxies and `wl-client` provides safe types to handle them.
5//!
6//! # Proxy types
7//!
8//! There are four different types of proxies across two dimensions:
9//!
10//! - In libwayland:
11//! - A *wrapper* `wl_proxy` is a proxy that was created by calling the
12//! `wl_proxy_create_wrapper` function.
13//! - A *plain* `wl_proxy` is any other proxy.
14//! - In `wl-client`:
15//! - An *owned* proxy is a proxy that will destroy the underlying `wl_proxy` when it is
16//! dropped.
17//! - A *borrowed* proxy is a proxy that only references a `wl_proxy` and will never be
18//! used to destroy it.
19//!
20//! Therefore, each proxy is
21//!
22//! - an owned wrapper proxy,
23//! - an owned plain proxy,
24//! - a borrowed wrapper proxy, or
25//! - a borrowed plain proxy.
26//!
27//! # Owned proxies
28//!
29//! Owned proxies are proxies created by `wl-client`. They have a [`Queue`], also created by
30//! `wl-client`, which can be accessed by calling [`queue`].
31//!
32//! When an owned proxy is used to create a new wayland object, the function returns a new
33//! owned proxy that is assigned to the same queue as its parent.
34//!
35//! An owned proxy can be used to destroy the proxy by sending a destructor request or by
36//! using the [`destroy`] function. Owned proxies are implicitly destroyed with the
37//! [`destroy`] function in the following situations:
38//!
39//! - When the last reference to the owned proxy is dropped.
40//! - When the [`QueueOwner`] owning the proxy's queue is dropped. This is explained in
41//! detail in the documentation of [`Queue`].
42//!
43//! # Borrowed proxies
44//!
45//! Borrowed proxies might or might not have been created by `wl-client`. Each owned proxy
46//! derefs to a borrowed proxy but a borrowed proxy can also be created from raw
47//! `wl_proxy` pointers.
48//!
49//! Since the ownership of these proxies is unknown, they cannot be used to to destroy the
50//! proxy.
51//!
52//! If a request is sent on a borrowed proxy that creates a new wayland object, the caller
53//! must also pass in a [`Queue`]. The returned owned proxy will be assigned to this
54//! queue.
55//!
56//! # Creating wrapper proxies
57//!
58//! When working with wayland objects created by foreign code, the foreign code usually
59//! shares raw `wl_proxy` pointers. Given a [`Queue`], it is possible to create a new
60//! owned wrapper proxy by calling [`Queue::wrap_wl_proxy`].
61//!
62//! # Setting proxy event handlers
63//!
64//! Event handlers can be attached to owned plain proxies by using one of the following
65//! functions:
66//!
67//! - [`set_event_handler`] - for `Send + 'static` event handlers
68//! - [`set_event_handler_local`] - for `'static` event handlers
69//! - [`set_event_handler_no_op`]
70//! - [`Scope::set_event_handler`] - for `Send + 'scope` event handlers
71//! - [`Scope::set_event_handler_local`] - for `'scope` event handlers
72//!
73//! The `_local` variant allows setting event handlers that do not implement `Send`. The
74//! `_no_op` variant can be used to destroy compositor-created resources if
75//! the application is not otherwise interested in events.
76//!
77//! Event handlers cannot be set on owned wrapper proxies.
78//!
79//! For each proxy, the event handler can only be set once and once set it cannot be
80//! unset.
81
82#[expect(unused_imports)]
83use crate::Scope;
84pub use crate::proxy::low_level::borrowed::BorrowedProxyLock;
85#[expect(unused_imports)]
86use crate::{connection::Connection, queue::QueueOwner};
87use {
88 crate::{
89 Queue,
90 ffi::{self, wl_interface},
91 proxy::low_level::{
92 CreateEventHandler, EventHandler, UntypedBorrowedProxy, UntypedBorrowedProxyWrapper,
93 UntypedOwnedProxy, UntypedOwnedProxyWrapper,
94 },
95 },
96 std::{mem, ptr::NonNull},
97};
98
99pub mod low_level;
100#[cfg(test)]
101mod tests;
102
103/// An owned proxy.
104///
105/// This type is usually implemented by bindings that are automatically generated with the
106/// `wl-client-builder` crate.
107///
108/// # Safety
109///
110/// - `WL_INTERFACE` must refer to a valid interface specification.
111/// - It must be safe to transmute this type from an [`UntypedOwnedProxy`] that has an
112/// interface that is compatible with `WL_INTERFACE`.
113/// - The interface of the contained proxy must be compatible with `WL_INTERFACE`.
114/// - The [`EventHandler::mutable_type`] of the [`OwnedProxy::NoOpEventHandler`] must be
115/// `None` or the type ID of `()`.
116pub unsafe trait OwnedProxy: UntypedOwnedProxyWrapper {
117 /// The name of the interface.
118 const INTERFACE: &'static str;
119 /// The libwayland interface specification.
120 const WL_INTERFACE: &'static wl_interface;
121 /// An event handler that ignores all events without leaking memory.
122 const NO_OP_EVENT_HANDLER: Self::NoOpEventHandler;
123 /// The maximum protocol version supported by this type.
124 const MAX_VERSION: u32;
125
126 /// The borrowed version of this proxy.
127 type Borrowed: BorrowedProxy<Owned = Self>;
128 /// A type used to implement some technical operations on the proxy.
129 ///
130 /// This type exists to avoid polluting the function namespace of the proxy.
131 type Api;
132 /// An event handler that ignores all events without leaking memory.
133 type NoOpEventHandler: EventHandler + Send + 'static;
134}
135
136/// A borrowed proxy.
137///
138/// This type is usually implemented by bindings that are automatically generated with the
139/// `wl-client-builder` crate.
140///
141/// # Safety
142///
143/// - It must be safe to transmute this type from a [`UntypedBorrowedProxy`] that has an
144/// interface that is compatible with `Owned::WL_INTERFACE`.
145/// - The interface of the contained proxy must be compatible with `Owned::WL_INTERFACE`.
146pub unsafe trait BorrowedProxy: UntypedBorrowedProxyWrapper {
147 /// The owned version of this proxy.
148 type Owned: OwnedProxy<Borrowed = Self>;
149}
150
151#[inline]
152pub(crate) fn get_owned<T>(proxy: &T) -> &UntypedOwnedProxy
153where
154 T: UntypedOwnedProxyWrapper,
155{
156 // SAFETY: The trait requires that T is a transparent wrapper around UntypedOwnedProxy
157 unsafe { mem::transmute::<&T, &UntypedOwnedProxy>(proxy) }
158}
159
160#[inline]
161pub(crate) fn get_ref<T>(proxy: &T) -> &UntypedBorrowedProxy
162where
163 T: UntypedBorrowedProxyWrapper,
164{
165 // SAFETY: The trait requires that T is a transparent wrapper around UntypedBorrowedProxy
166 unsafe { mem::transmute::<&T, &UntypedBorrowedProxy>(proxy) }
167}
168
169/// Destroys a proxy without sending a wayland message.
170///
171/// This function only destroys the proxy in libwayland without sending a message to the
172/// compositor. You might use this function in the following situations:
173///
174/// - The type does not provide a destructor request.
175/// - In an event handler that destroys the object, e.g. `wl_callback.done`.
176/// - You want to deliberately leak the wayland object without leaking memory.
177///
178/// This function does nothing if the proxy is already destroyed.
179///
180/// # Panic
181///
182/// This function might panic if the proxy is attached to a local queue and the current
183/// thread is not the thread in which the queue was created.
184///
185/// # Example
186///
187/// ```
188/// # use std::ptr;
189/// # use wl_client::{proxy, Libwayland};
190/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
191/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
192/// #
193/// let lib = Libwayland::open().unwrap();
194/// let con = lib.connect_to_default_display().unwrap();
195/// let queue = con.create_queue(c"");
196/// let display: WlDisplay = queue.display();
197///
198/// let sync = display.sync();
199/// let sync2 = sync.clone();
200/// proxy::set_event_handler(&sync, WlCallback::on_done(move |_, _| {
201/// proxy::destroy(&sync2);
202/// }));
203///
204/// queue.dispatch_roundtrip_blocking().unwrap();
205/// assert!(proxy::wl_proxy(&*sync).is_none());
206/// ```
207#[inline]
208pub fn destroy(proxy: &impl UntypedOwnedProxyWrapper) {
209 get_owned(proxy).destroy();
210}
211
212/// Sets the event handler of the proxy.
213///
214/// This function can only be called once for each proxy. This function cannot be called
215/// on wrappers.
216///
217/// The event handler must implement [`Send`]. Use [`set_event_handler_local`] if your
218/// event handler does not implement `Send`.
219///
220/// # Panic
221///
222/// This function panics if
223///
224/// - the proxy has already been destroyed,
225/// - the proxy is a wrapper,
226/// - the proxy is attached to a local queue and the current thread is not the thread in
227/// which the queue was created,
228/// - the proxy already has an event handler, or
229/// - the event handler accepts a `&mut T`, `T != ()`, and the queue that the proxy
230/// is attached to was not created with this data type.
231///
232/// This function also panics if the interface of the created handler is not the same as
233/// the interface of the proxy. However, this cannot happen if you're using the bindings
234/// generated by `wl-client-builder`.
235///
236/// # Example
237///
238/// ```
239/// # use std::sync::Arc;
240/// # use std::sync::atomic::AtomicBool;
241/// # use std::sync::atomic::Ordering::Relaxed;
242/// # use wl_client::{proxy, Libwayland};
243/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
244/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
245/// #
246/// let lib = Libwayland::open().unwrap();
247/// let con = lib.connect_to_default_display().unwrap();
248/// let queue = con.create_queue(c"");
249/// let display: WlDisplay = queue.display();
250/// let sync = display.sync();
251/// let done = Arc::new(AtomicBool::new(false));
252///
253/// // Attach the event handler.
254/// let done2 = done.clone();
255/// proxy::set_event_handler(&sync, WlCallback::on_done(move |_, _| {
256/// done2.store(true, Relaxed);
257/// }));
258///
259/// // Wait for the compositor to send the `done` message.
260/// queue.dispatch_roundtrip_blocking().unwrap();
261///
262/// // The event handler sets the value to `true`.
263/// assert!(done.load(Relaxed));
264/// ```
265#[inline]
266pub fn set_event_handler<P, H>(proxy: &P, handler: H)
267where
268 P: OwnedProxy,
269 P::Api: CreateEventHandler<H>,
270 <P::Api as CreateEventHandler<H>>::EventHandler: Send + 'static,
271{
272 get_owned(proxy).set_event_handler(P::Api::create_event_handler(handler));
273}
274
275/// Sets the `!Send` event handler of the proxy.
276///
277/// This function is the same as [`set_event_handler`] except that the event handler does
278/// not have to implement [`Send`] and the queue of the proxy must be a
279/// [local queue](Connection::create_local_queue).
280///
281/// # Panic
282///
283/// This function panics whenever [`set_event_handler`] panics and also if the queue of
284/// the proxy is not a local queue.
285///
286/// # Example
287///
288/// ```
289/// # use std::cell::Cell;
290/// # use std::rc::Rc;
291/// # use std::sync::atomic::Ordering::Relaxed;
292/// # use wl_client::{proxy, Libwayland};
293/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
294/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
295/// #
296/// let lib = Libwayland::open().unwrap();
297/// let con = lib.connect_to_default_display().unwrap();
298/// let queue = con.create_local_queue(c"");
299/// let display: WlDisplay = queue.display();
300/// let sync = display.sync();
301/// let done = Rc::new(Cell::new(false));
302///
303/// // Attach the event handler.
304/// let done2 = done.clone();
305/// proxy::set_event_handler_local(&sync, WlCallback::on_done(move |_, _| {
306/// done2.set(true);
307/// }));
308///
309/// // Wait for the compositor to send the `done` message.
310/// queue.dispatch_roundtrip_blocking().unwrap();
311///
312/// // The event handler sets the value to `true`.
313/// assert!(done.get());
314/// ```
315#[inline]
316pub fn set_event_handler_local<P, H>(proxy: &P, handler: H)
317where
318 P: OwnedProxy,
319 P::Api: CreateEventHandler<H>,
320 <P::Api as CreateEventHandler<H>>::EventHandler: 'static,
321{
322 get_owned(proxy).set_event_handler_local(P::Api::create_event_handler(handler));
323}
324
325/// Sets the event handler of the proxy to ignore all events.
326///
327/// This can be used in the following situation:
328///
329/// - The application is not interested in events from this proxy.
330/// - But the interface has events that contain file descriptors or create new proxies.
331///
332/// Not setting any event handler would cause the file descriptors and new proxies to be
333/// leaked. Using this function will ensure that all resources are released.
334///
335/// # Example
336///
337/// ```
338/// # use wl_client::{proxy, Libwayland};
339/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
340/// #
341/// let lib = Libwayland::open().unwrap();
342/// let con = lib.connect_to_default_display().unwrap();
343/// let queue = con.create_queue(c"queue name");
344/// let display: WlDisplay = queue.display();
345///
346/// let sync = display.sync();
347/// proxy::set_event_handler_no_op(&sync);
348/// ```
349#[inline]
350pub fn set_event_handler_no_op<P>(proxy: &P)
351where
352 P: OwnedProxy,
353{
354 get_owned(proxy).set_event_handler(P::NO_OP_EVENT_HANDLER);
355}
356
357/// Locks the proxy for concurrent destruction.
358///
359/// If the proxy is not already destroyed, holding this lock will prevent other threads
360/// from destroying it.
361///
362/// Trying to destroy the proxy from this thread while holding this lock will deadlock.
363///
364/// This lock only locks out concurrent destruction. Multiple threads can acquire this
365/// lock at the same time.
366///
367/// # Example
368///
369/// ```
370/// # use std::{ptr, thread};
371/// # use std::sync::{Arc, Barrier};
372/// # use std::time::Duration;
373/// # use wl_client::{proxy, Libwayland};
374/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
375/// #
376/// let lib = Libwayland::open().unwrap();
377/// let con = lib.connect_to_default_display().unwrap();
378/// let queue = con.create_queue(c"");
379/// let display: WlDisplay = queue.display();
380///
381/// // Create a wl_callback that we will destroy in another thread.
382/// let sync1 = display.sync();
383/// let sync2 = sync1.clone();
384///
385/// // Lock the proxy to prevent the other thread from destroying it.
386/// let lock = proxy::lock(&*sync1);
387///
388/// // Create a barrier to synchronize with the other thread.
389/// let barrier1 = Arc::new(Barrier::new(2));
390/// let barrier2 = barrier1.clone();
391///
392/// thread::spawn(move || {
393/// // This will block until the main thread has released the lock.
394/// proxy::destroy(&sync2);
395/// barrier2.wait();
396/// });
397///
398/// // Sleep for a second to demonstrate that the proxy::destroy does in fact not proceed.
399/// thread::sleep(Duration::from_secs(1));
400///
401/// // The other spawned thread has not yet destroyed the proxy.
402/// assert!(lock.wl_proxy().is_some());
403/// // Drop the lock to let the other thread proceed.
404/// drop(lock);
405///
406/// // Wait for the other thread to run to completion.
407/// barrier1.wait();
408///
409/// // The proxy is now destroyed.
410/// assert!(proxy::wl_proxy(&*sync1).is_none());
411/// ```
412pub fn lock(proxy: &impl UntypedBorrowedProxyWrapper) -> BorrowedProxyLock<'_> {
413 get_ref(proxy).lock()
414}
415
416/// Returns the `wl_proxy` pointer of a proxy.
417///
418/// This function returns a null pointer if the proxy has already been destroyed.
419///
420/// If this function returns a non-null pointer, the proxy might still get invalidated at
421/// any time when another thread destroys the proxy. Consider using [`lock`] instead.
422///
423/// # Example
424///
425/// ```
426/// # use std::ptr;
427/// # use wl_client::{proxy, Libwayland};
428/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
429/// let lib = Libwayland::open().unwrap();
430/// let con = lib.connect_to_default_display().unwrap();
431/// let queue = con.create_queue(c"");
432/// let display: WlDisplay = queue.display();
433/// assert!(proxy::wl_proxy(&*display).is_some());
434/// ```
435#[inline]
436pub fn wl_proxy(proxy: &impl UntypedBorrowedProxyWrapper) -> Option<NonNull<ffi::wl_proxy>> {
437 get_ref(proxy).wl_proxy()
438}
439
440/// Returns the wayland object ID of a proxy.
441///
442/// If the proxy has already been destroyed, this function returns either the original
443/// ID or 0.
444///
445/// # Example
446///
447/// ```
448/// # use wl_client::{proxy, Libwayland};
449/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
450/// let lib = Libwayland::open().unwrap();
451/// let con = lib.connect_to_default_display().unwrap();
452/// let queue = con.create_queue(c"");
453///
454/// let display: WlDisplay = queue.display();
455/// assert_eq!(proxy::id(&*display), 1);
456/// ```
457#[inline]
458pub fn id(proxy: &impl UntypedBorrowedProxyWrapper) -> u32 {
459 get_ref(proxy).id()
460}
461
462/// Returns the version of this proxy object.
463///
464/// The version of the display object is always 0.
465///
466/// # Panic
467///
468/// Panics if the proxy is already destroyed.
469///
470/// # Example
471///
472/// ```
473/// # use wl_client::{proxy, Libwayland};
474/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
475/// let lib = Libwayland::open().unwrap();
476/// let con = lib.connect_to_default_display().unwrap();
477/// let queue = con.create_queue(c"");
478///
479/// let display: WlDisplay = queue.display();
480/// assert_eq!(proxy::version(&*display), 0);
481/// ```
482#[inline]
483pub fn version(proxy: &impl UntypedBorrowedProxyWrapper) -> u32 {
484 get_ref(proxy).version()
485}
486
487/// Returns the queue of a proxy.
488///
489/// # Example
490///
491/// ```
492/// # use wl_client::{proxy, Libwayland};
493/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
494/// let lib = Libwayland::open().unwrap();
495/// let con = lib.connect_to_default_display().unwrap();
496///
497/// let queue = con.create_queue(c"");
498/// let display: WlDisplay = queue.display();
499/// assert_eq!(proxy::queue(&display), &*queue);
500/// ```
501#[inline]
502pub fn queue(proxy: &impl UntypedOwnedProxyWrapper) -> &Queue {
503 get_owned(proxy).queue()
504}
505
506/// Returns whether this proxy is destroyed.
507///
508/// The proxy being destroyed and the wayland object being destroyed are two separate
509/// properties. A proxy can be destroyed even if the wayland object is not yet destroyed
510/// and vice versa.
511///
512/// In a multi-threaded application, a proxy might get destroyed immediately after this
513/// function returns `false`. You can use [`lock`] to keep a proxy alive for a while.
514///
515/// # Example
516///
517/// ```
518/// # use wl_client::{proxy, Libwayland};
519/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
520/// #
521/// let lib = Libwayland::open().unwrap();
522/// let con = lib.connect_to_default_display().unwrap();
523/// let queue = con.create_queue(c"");
524/// let display: WlDisplay = queue.display();
525///
526/// let sync = display.sync();
527/// assert!(proxy::is_not_destroyed(&*sync));
528///
529/// proxy::destroy(&sync);
530/// assert!(proxy::is_destroyed(&*sync));
531/// ```
532#[inline]
533pub fn is_destroyed(proxy: &impl UntypedBorrowedProxyWrapper) -> bool {
534 wl_proxy(proxy).is_none()
535}
536
537/// Returns whether this proxy is not destroyed.
538///
539/// This is the same as `!is_destroyed(proxy)`.
540#[inline]
541pub fn is_not_destroyed(proxy: &impl UntypedBorrowedProxyWrapper) -> bool {
542 !is_destroyed(proxy)
543}