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`.
114pub unsafe trait OwnedProxy: UntypedOwnedProxyWrapper {
115    /// The name of the interface.
116    const INTERFACE: &'static str;
117    /// The libwayland interface specification.
118    const WL_INTERFACE: &'static wl_interface;
119    /// An event handler that ignores all events without leaking memory.
120    const NO_OP_EVENT_HANDLER: Self::NoOpEventHandler;
121    /// The maximum protocol version supported by this type.
122    const MAX_VERSION: u32;
123
124    /// The borrowed version of this proxy.
125    type Borrowed: BorrowedProxy<Owned = Self>;
126    /// A type used to implement some technical operations on the proxy.
127    ///
128    /// This type exists to avoid polluting the function namespace of the proxy.
129    type Api;
130    /// An event handler that ignores all events without leaking memory.
131    type NoOpEventHandler: EventHandler + Send + 'static;
132}
133
134/// A borrowed proxy.
135///
136/// This type is usually implemented by bindings that are automatically generated with the
137/// `wl-client-builder` crate.
138///
139/// # Safety
140///
141/// - It must be safe to transmute this type from a [`UntypedBorrowedProxy`] that has an
142///   interface that is compatible with `Owned::WL_INTERFACE`.
143/// - The interface of the contained proxy must be compatible with `Owned::WL_INTERFACE`.
144pub unsafe trait BorrowedProxy: UntypedBorrowedProxyWrapper {
145    /// The owned version of this proxy.
146    type Owned: OwnedProxy<Borrowed = Self>;
147}
148
149#[inline]
150pub(crate) fn get_owned<T>(proxy: &T) -> &UntypedOwnedProxy
151where
152    T: UntypedOwnedProxyWrapper,
153{
154    // SAFETY: The trait requires that T is a transparent wrapper around UntypedOwnedProxy
155    unsafe { mem::transmute::<&T, &UntypedOwnedProxy>(proxy) }
156}
157
158#[inline]
159pub(crate) fn get_ref<T>(proxy: &T) -> &UntypedBorrowedProxy
160where
161    T: UntypedBorrowedProxyWrapper,
162{
163    // SAFETY: The trait requires that T is a transparent wrapper around UntypedBorrowedProxy
164    unsafe { mem::transmute::<&T, &UntypedBorrowedProxy>(proxy) }
165}
166
167/// Destroys a proxy without sending a wayland message.
168///
169/// This function only destroys the proxy in libwayland without sending a message to the
170/// compositor. You might use this function in the following situations:
171///
172/// - The type does not provide a destructor request.
173/// - In an event handler that destroys the object, e.g. `wl_callback.done`.
174/// - You want to deliberately leak the wayland object without leaking memory.
175///
176/// This function does nothing if the proxy is already destroyed.
177///
178/// # Panic
179///
180/// This function might panic if the proxy is attached to a local queue and the current
181/// thread is not the thread in which the queue was created.
182///
183/// # Example
184///
185/// ```
186/// # use std::ptr;
187/// # use wl_client::{proxy, Libwayland};
188/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
189/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
190/// #
191/// let lib = Libwayland::open().unwrap();
192/// let con = lib.connect_to_default_display().unwrap();
193/// let queue = con.create_queue(c"");
194/// let display: WlDisplay = queue.display();
195///
196/// let sync = display.sync();
197/// let sync2 = sync.clone();
198/// proxy::set_event_handler(&sync, WlCallback::on_done(move |_, _| {
199///     proxy::destroy(&sync2);
200/// }));
201///
202/// queue.dispatch_roundtrip_blocking().unwrap();
203/// assert!(proxy::wl_proxy(&*sync).is_none());
204/// ```
205#[inline]
206pub fn destroy(proxy: &impl UntypedOwnedProxyWrapper) {
207    get_owned(proxy).destroy();
208}
209
210/// Sets the event handler of the proxy.
211///
212/// This function can only be called once for each proxy. This function cannot be called
213/// on wrappers.
214///
215/// The event handler must implement [`Send`]. Use [`set_event_handler_local`] if your
216/// event handler does not implement `Send`.
217///
218/// # Panic
219///
220/// This function panics if
221///
222/// - the proxy has already been destroyed,
223/// - the proxy is a wrapper,
224/// - the proxy is attached to a local queue and the current thread is not the thread in
225///   which the queue was created, or
226/// - the proxy already has an event handler.
227///
228/// This function also panics if the interface of the created handler is not the same as
229/// the interface of the proxy. However, this cannot happen if you're using the bindings
230/// generated by `wl-client-builder`.
231///
232/// # Example
233///
234/// ```
235/// # use std::sync::Arc;
236/// # use std::sync::atomic::AtomicBool;
237/// # use std::sync::atomic::Ordering::Relaxed;
238/// # use wl_client::{proxy, Libwayland};
239/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
240/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
241/// #
242/// let lib = Libwayland::open().unwrap();
243/// let con = lib.connect_to_default_display().unwrap();
244/// let queue = con.create_queue(c"");
245/// let display: WlDisplay = queue.display();
246/// let sync = display.sync();
247/// let done = Arc::new(AtomicBool::new(false));
248///
249/// // Attach the event handler.
250/// let done2 = done.clone();
251/// proxy::set_event_handler(&sync, WlCallback::on_done(move |_, _| {
252///     done2.store(true, Relaxed);
253/// }));
254///
255/// // Wait for the compositor to send the `done` message.
256/// queue.dispatch_roundtrip_blocking().unwrap();
257///
258/// // The event handler sets the value to `true`.
259/// assert!(done.load(Relaxed));
260/// ```
261#[inline]
262pub fn set_event_handler<P, H>(proxy: &P, handler: H)
263where
264    P: OwnedProxy,
265    P::Api: CreateEventHandler<H>,
266    <P::Api as CreateEventHandler<H>>::EventHandler: Send + 'static,
267{
268    get_owned(proxy).set_event_handler(P::Api::create_event_handler(handler));
269}
270
271/// Sets the `!Send` event handler of the proxy.
272///
273/// This function is the same as [`set_event_handler`] except that the event handler does
274/// not have to implement [`Send`] and the queue of the proxy must be a
275/// [local queue](Connection::create_local_queue).
276///
277/// # Panic
278///
279/// This function panics whenever [`set_event_handler`] panics and also if the queue of
280/// the proxy is not a local queue.
281///
282/// # Example
283///
284/// ```
285/// # use std::cell::Cell;
286/// # use std::rc::Rc;
287/// # use std::sync::atomic::Ordering::Relaxed;
288/// # use wl_client::{proxy, Libwayland};
289/// # use wl_client::test_protocols::core::wl_callback::{WlCallback, WlCallbackEventHandler, WlCallbackRef};
290/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
291/// #
292/// let lib = Libwayland::open().unwrap();
293/// let con = lib.connect_to_default_display().unwrap();
294/// let queue = con.create_local_queue(c"");
295/// let display: WlDisplay = queue.display();
296/// let sync = display.sync();
297/// let done = Rc::new(Cell::new(false));
298///
299/// // Attach the event handler.
300/// let done2 = done.clone();
301/// proxy::set_event_handler_local(&sync, WlCallback::on_done(move |_, _| {
302///     done2.set(true);
303/// }));
304///
305/// // Wait for the compositor to send the `done` message.
306/// queue.dispatch_roundtrip_blocking().unwrap();
307///
308/// // The event handler sets the value to `true`.
309/// assert!(done.get());
310/// ```
311#[inline]
312pub fn set_event_handler_local<P, H>(proxy: &P, handler: H)
313where
314    P: OwnedProxy,
315    P::Api: CreateEventHandler<H>,
316    <P::Api as CreateEventHandler<H>>::EventHandler: 'static,
317{
318    get_owned(proxy).set_event_handler_local(P::Api::create_event_handler(handler));
319}
320
321/// Sets the event handler of the proxy to ignore all events.
322///
323/// This can be used in the following situation:
324///
325/// - The application is not interested in events from this proxy.
326/// - But the interface has events that contain file descriptors or create new proxies.
327///
328/// Not setting any event handler would cause the file descriptors and new proxies to be
329/// leaked. Using this function will ensure that all resources are released.
330///
331/// # Example
332///
333/// ```
334/// # use wl_client::{proxy, Libwayland};
335/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
336/// #
337/// let lib = Libwayland::open().unwrap();
338/// let con = lib.connect_to_default_display().unwrap();
339/// let queue = con.create_queue(c"queue name");
340/// let display: WlDisplay = queue.display();
341///
342/// let sync = display.sync();
343/// proxy::set_event_handler_no_op(&sync);
344/// ```
345#[inline]
346pub fn set_event_handler_no_op<P>(proxy: &P)
347where
348    P: OwnedProxy,
349{
350    get_owned(proxy).set_event_handler(P::NO_OP_EVENT_HANDLER);
351}
352
353/// Locks the proxy for concurrent destruction.
354///
355/// If the proxy is not already destroyed, holding this lock will prevent other threads
356/// from destroying it.
357///
358/// Trying to destroy the proxy from this thread while holding this lock will deadlock.
359///
360/// This lock only locks out concurrent destruction. Multiple threads can acquire this
361/// lock at the same time.
362///
363/// # Example
364///
365/// ```
366/// # use std::{ptr, thread};
367/// # use std::sync::{Arc, Barrier};
368/// # use std::time::Duration;
369/// # use wl_client::{proxy, Libwayland};
370/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
371/// #
372/// let lib = Libwayland::open().unwrap();
373/// let con = lib.connect_to_default_display().unwrap();
374/// let queue = con.create_queue(c"");
375/// let display: WlDisplay = queue.display();
376///
377/// // Create a wl_callback that we will destroy in another thread.
378/// let sync1 = display.sync();
379/// let sync2 = sync1.clone();
380///
381/// // Lock the proxy to prevent the other thread from destroying it.
382/// let lock = proxy::lock(&*sync1);
383///
384/// // Create a barrier to synchronize with the other thread.
385/// let barrier1 = Arc::new(Barrier::new(2));
386/// let barrier2 = barrier1.clone();
387///
388/// thread::spawn(move || {
389///     // This will block until the main thread has released the lock.
390///     proxy::destroy(&sync2);
391///     barrier2.wait();
392/// });
393///
394/// // Sleep for a second to demonstrate that the proxy::destroy does in fact not proceed.
395/// thread::sleep(Duration::from_secs(1));
396///
397/// // The other spawned thread has not yet destroyed the proxy.
398/// assert!(lock.wl_proxy().is_some());
399/// // Drop the lock to let the other thread proceed.
400/// drop(lock);
401///
402/// // Wait for the other thread to run to completion.
403/// barrier1.wait();
404///
405/// // The proxy is now destroyed.
406/// assert!(proxy::wl_proxy(&*sync1).is_none());
407/// ```
408pub fn lock(proxy: &impl UntypedBorrowedProxyWrapper) -> BorrowedProxyLock<'_> {
409    get_ref(proxy).lock()
410}
411
412/// Returns the `wl_proxy` pointer of a proxy.
413///
414/// This function returns a null pointer if the proxy has already been destroyed.
415///
416/// If this function returns a non-null pointer, the proxy might still get invalidated at
417/// any time when another thread destroys the proxy. Consider using [`lock`] instead.
418///
419/// # Example
420///
421/// ```
422/// # use std::ptr;
423/// # use wl_client::{proxy, Libwayland};
424/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
425/// let lib = Libwayland::open().unwrap();
426/// let con = lib.connect_to_default_display().unwrap();
427/// let queue = con.create_queue(c"");
428/// let display: WlDisplay = queue.display();
429/// assert!(proxy::wl_proxy(&*display).is_some());
430/// ```
431#[inline]
432pub fn wl_proxy(proxy: &impl UntypedBorrowedProxyWrapper) -> Option<NonNull<ffi::wl_proxy>> {
433    get_ref(proxy).wl_proxy()
434}
435
436/// Returns the wayland object ID of a proxy.
437///
438/// If the proxy has already been destroyed, this function returns either the original
439/// ID or 0.
440///
441/// # Example
442///
443/// ```
444/// # use wl_client::{proxy, Libwayland};
445/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
446/// let lib = Libwayland::open().unwrap();
447/// let con = lib.connect_to_default_display().unwrap();
448/// let queue = con.create_queue(c"");
449///
450/// let display: WlDisplay = queue.display();
451/// assert_eq!(proxy::id(&*display), 1);
452/// ```
453#[inline]
454pub fn id(proxy: &impl UntypedBorrowedProxyWrapper) -> u32 {
455    get_ref(proxy).id()
456}
457
458/// Returns the version of this proxy object.
459///
460/// The version of the display object is always 0.
461///
462/// # Panic
463///
464/// Panics if the proxy is already destroyed.
465///
466/// # Example
467///
468/// ```
469/// # use wl_client::{proxy, Libwayland};
470/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
471/// let lib = Libwayland::open().unwrap();
472/// let con = lib.connect_to_default_display().unwrap();
473/// let queue = con.create_queue(c"");
474///
475/// let display: WlDisplay = queue.display();
476/// assert_eq!(proxy::version(&*display), 0);
477/// ```
478#[inline]
479pub fn version(proxy: &impl UntypedBorrowedProxyWrapper) -> u32 {
480    get_ref(proxy).version()
481}
482
483/// Returns the queue of a proxy.
484///
485/// # Example
486///
487/// ```
488/// # use wl_client::{proxy, Libwayland};
489/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
490/// let lib = Libwayland::open().unwrap();
491/// let con = lib.connect_to_default_display().unwrap();
492///
493/// let queue = con.create_queue(c"");
494/// let display: WlDisplay = queue.display();
495/// assert_eq!(proxy::queue(&display), &*queue);
496/// ```
497#[inline]
498pub fn queue(proxy: &impl UntypedOwnedProxyWrapper) -> &Queue {
499    get_owned(proxy).queue()
500}
501
502/// Returns whether this proxy is destroyed.
503///
504/// The proxy being destroyed and the wayland object being destroyed are two separate
505/// properties. A proxy can be destroyed even if the wayland object is not yet destroyed
506/// and vice versa.
507///
508/// In a multi-threaded application, a proxy might get destroyed immediately after this
509/// function returns `false`. You can use [`lock`] to keep a proxy alive for a while.
510///
511/// # Example
512///
513/// ```
514/// # use wl_client::{proxy, Libwayland};
515/// # use wl_client::test_protocols::core::wl_display::WlDisplay;
516/// #
517/// let lib = Libwayland::open().unwrap();
518/// let con = lib.connect_to_default_display().unwrap();
519/// let queue = con.create_queue(c"");
520/// let display: WlDisplay = queue.display();
521///
522/// let sync = display.sync();
523/// assert!(proxy::is_not_destroyed(&*sync));
524///
525/// proxy::destroy(&sync);
526/// assert!(proxy::is_destroyed(&*sync));
527/// ```
528#[inline]
529pub fn is_destroyed(proxy: &impl UntypedBorrowedProxyWrapper) -> bool {
530    wl_proxy(proxy).is_none()
531}
532
533/// Returns whether this proxy is not destroyed.
534///
535/// This is the same as `!is_destroyed(proxy)`.
536#[inline]
537pub fn is_not_destroyed(proxy: &impl UntypedBorrowedProxyWrapper) -> bool {
538    !is_destroyed(proxy)
539}