Skip to main content

wayland_backend/sys/
mod.rs

1//! Implementations of the Wayland backends using the system `libwayland`
2
3use std::ptr::NonNull;
4use std::sync::Arc;
5
6use wayland_sys::client::wl_proxy;
7use wayland_sys::common::{wl_argument, wl_array};
8
9use crate::protocol::{ArgumentType, Interface};
10
11#[cfg(any(test, feature = "client_system", feature = "server_system"))]
12use std::ffi::c_void;
13
14#[cfg(any(test, feature = "client_system"))]
15mod client_impl;
16#[cfg(any(test, feature = "server_system"))]
17mod server_impl;
18
19/// Magic static for wayland objects managed by wayland-client or wayland-server
20///
21/// This static serves no purpose other than existing at a stable address.
22static RUST_MANAGED: u8 = 42;
23
24unsafe fn free_arrays(signature: &[ArgumentType], arglist: &[wl_argument]) {
25    for (typ, arg) in signature.iter().zip(arglist.iter()) {
26        if let ArgumentType::Array = typ {
27            // Safety: the arglist provided arglist must be valid for associated signature
28            // and contains pointers to boxed arrays as appropriate
29            let _ = unsafe { Box::from_raw(arg.a as *mut wl_array) };
30        }
31    }
32}
33
34/// Client-side implementation of a Wayland protocol backend using `libwayland`
35///
36/// Entrypoints are:
37/// - [`Backend::connect()`][client::Backend::connect()] method if you're creating the Wayland connection
38/// - [`Backend::from_foreign_display()`][client::Backend::from_foreign_display()] if you're interacting with an
39///   already existing Wayland connection through FFI.
40#[cfg(any(test, feature = "client_system"))]
41#[path = "../client_api.rs"]
42pub mod client;
43#[cfg(any(test, feature = "client_system"))]
44use client::{ObjectData, ObjectId};
45
46// API complements for FFI
47
48#[cfg(any(test, feature = "client_system"))]
49impl client::ObjectId {
50    /// Creates an object id from a libwayland-client pointer.
51    ///
52    /// # Errors
53    ///
54    /// This function returns an [`InvalidId`][client::InvalidId] error if the interface of the proxy does
55    /// not match the provided interface.
56    ///
57    /// # Safety
58    ///
59    /// The provided pointer must be a valid pointer to a `wl_resource` and remain valid for as
60    /// long as the retrieved `ObjectId` is used.
61    pub unsafe fn from_ptr(
62        interface: &'static crate::protocol::Interface,
63        ptr: NonNull<c_void>,
64    ) -> Result<Self, client::InvalidId> {
65        Ok(Self {
66            id: unsafe { client_impl::InnerObjectId::from_ptr(interface, ptr.cast::<wl_proxy>()) }?,
67        })
68    }
69
70    /// Get the underlying libwayland pointer for this object
71    ///
72    /// # Errors
73    ///
74    /// This function returns an [`InvalidId`][client::InvalidId] error if proxy has already
75    /// been destroyed.
76    pub fn as_ptr(&self) -> Result<NonNull<c_void>, client::InvalidId> {
77        Ok(self.id.as_ptr()?.cast())
78    }
79
80    /// Get the underlying display pointer for this object.
81    ///
82    /// This pointer is associated with the original display this object
83    /// belongs to.
84    #[cfg(feature = "libwayland_client_1_23")]
85    pub fn display_ptr(&self) -> Result<NonNull<c_void>, crate::types::client::InvalidId> {
86        Ok(self.id.display_ptr()?.cast())
87    }
88}
89
90#[cfg(any(test, feature = "client_system"))]
91impl client::Backend {
92    /// Creates a Backend from a foreign `*mut wl_display`.
93    ///
94    /// This is useful if you are writing a library that is expected to plug itself into an existing
95    /// Wayland connection.
96    ///
97    /// This will initialize the [`Backend`][Self] in "guest" mode, meaning it will not close the
98    /// connection on drop. After the [`Backend`][Self] is dropped, if the server sends an event
99    /// to an object that was created from it, that event will be silently discarded. This may lead to
100    /// protocol errors if the server expects an answer to that event, as such you should make sure to
101    /// cleanup your Wayland state before dropping the [`Backend`][Self].
102    ///
103    /// # Safety
104    ///
105    /// You need to ensure the `*mut wl_display` remains live as long as the  [`Backend`][Self]
106    /// (or its clones) exist.
107    pub unsafe fn from_foreign_display(display: NonNull<c_void>) -> Self {
108        Self {
109            backend: unsafe {
110                client_impl::InnerBackend::from_foreign_display(
111                    display.cast::<wayland_sys::client::wl_display>(),
112                )
113            },
114        }
115    }
116
117    /// Returns the underlying `wl_display` pointer to this backend.
118    ///
119    /// This pointer is needed to interface with EGL, Vulkan and other C libraries.
120    ///
121    /// This pointer is only valid for the lifetime of the backend.
122    pub fn display_ptr(&self) -> *mut c_void {
123        self.backend.display_ptr().cast()
124    }
125
126    /// Take over handling for a proxy created by a third party.
127    ///
128    /// # Safety
129    ///
130    /// There must never be more than one party managing an object. This is only
131    /// safe to call when a third party gave you ownership of an unmanaged proxy.
132    ///
133    /// The caller is also responsible for making sure the passed interface matches
134    /// the proxy.
135    #[inline]
136    pub unsafe fn manage_object(
137        &self,
138        interface: &'static Interface,
139        proxy: *mut c_void,
140        data: Arc<dyn ObjectData>,
141    ) -> ObjectId {
142        unsafe { self.backend.manage_object(interface, proxy.cast::<wl_proxy>(), data) }
143    }
144}
145
146#[cfg(any(test, feature = "client_system"))]
147impl client::ReadEventsGuard {
148    /// The same as [`read`], but doesn't dispatch events.
149    ///
150    /// To dispatch them, use [`dispatch_inner_queue`].
151    ///
152    /// [`read`]: client::ReadEventsGuard::read
153    /// [`dispatch_inner_queue`]: client::Backend::dispatch_inner_queue
154    pub fn read_without_dispatch(mut self) -> Result<(), client::WaylandError> {
155        self.guard.read_non_dispatch()
156    }
157}
158
159#[cfg(all(feature = "rwh_06", feature = "client_system"))]
160impl rwh_06::HasDisplayHandle for client::Backend {
161    fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
162        use std::ptr::NonNull;
163
164        // SAFETY:
165        // - The display_ptr will be valid, either because we have created the pointer or the caller which created the
166        //   backend has ensured the pointer is valid when `Backend::from_foreign_display` was called.
167        let ptr = unsafe { NonNull::new_unchecked(self.display_ptr().cast()) };
168        let handle = rwh_06::WaylandDisplayHandle::new(ptr);
169        let raw = rwh_06::RawDisplayHandle::Wayland(handle);
170
171        // SAFETY:
172        // - The display_ptr will be valid, either because we have created the pointer or the caller which created the
173        //   backend has ensured the pointer is valid when `Backend::from_foreign_display` was called.
174        // - The lifetime assigned to the DisplayHandle borrows the Backend, ensuring the display pointer
175        //   is valid..
176        // - The display_ptr will not change for the lifetime of the backend.
177        Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
178    }
179}
180
181/// Server-side implementation of a Wayland protocol backend using `libwayland`
182///
183/// The main entrypoint is the [`Backend::new()`][server::Backend::new()] method.
184#[cfg(any(test, feature = "server_system"))]
185#[path = "../server_api.rs"]
186pub mod server;
187
188#[cfg(any(test, feature = "server_system"))]
189impl server::ObjectId {
190    /// Creates an object from a C pointer.
191    ///
192    /// # Errors
193    ///
194    /// This function returns an [`InvalidId`][server::InvalidId] error if the interface of the
195    /// resource does not match the provided interface.
196    ///
197    /// # Safety
198    ///
199    /// The provided pointer must be a valid pointer to a `wl_resource` and remain valid for as
200    /// long as the retrieved `ObjectId` is used.
201    pub unsafe fn from_ptr(
202        interface: &'static crate::protocol::Interface,
203        ptr: NonNull<c_void>,
204    ) -> Result<Self, server::InvalidId> {
205        Ok(Self {
206            id: unsafe {
207                server_impl::InnerObjectId::from_ptr(
208                    Some(interface),
209                    ptr.cast::<wayland_sys::server::wl_resource>(),
210                )
211            }?,
212        })
213    }
214
215    /// Returns the pointer that represents this object.
216    ///
217    /// The pointer may be used to interoperate with libwayland.
218    ///
219    /// # Errors
220    ///
221    /// This function returns an [`InvalidId`][server::InvalidId] error if resource has already
222    /// been destroyed.
223    pub fn as_ptr(&self) -> Result<NonNull<c_void>, server::InvalidId> {
224        Ok(self.id.as_ptr()?.cast())
225    }
226}
227
228#[cfg(any(test, feature = "server_system"))]
229impl server::Handle {
230    /// Access the underlying `*mut wl_display` pointer
231    pub fn display_ptr(&self) -> *mut c_void {
232        self.handle.display_ptr().cast()
233    }
234}