Skip to main content

wayland_backend/sys/
mod.rs

1//! Implementations of the Wayland backends using the system `libwayland`
2
3use smallvec::SmallVec;
4use std::ffi::CString;
5use std::num::NonZeroU32;
6use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
7use std::ptr::{self, NonNull};
8use std::sync::Arc;
9
10use wayland_sys::client::wl_proxy;
11use wayland_sys::common::{wl_argument, wl_array};
12
13use crate::protocol::{Argument, ArgumentType, Interface, OwnedArgument};
14
15#[cfg(any(test, feature = "client_system", feature = "server_system"))]
16use std::ffi::c_void;
17
18#[cfg(any(test, feature = "client_system"))]
19mod client_impl;
20#[cfg(any(test, feature = "server_system"))]
21mod server_impl;
22
23/// Magic static for wayland objects managed by wayland-client or wayland-server
24///
25/// This static serves no purpose other than existing at a stable address.
26static RUST_MANAGED: u8 = 42;
27
28/// Client-side implementation of a Wayland protocol backend using `libwayland`
29///
30/// Entrypoints are:
31/// - [`Backend::connect()`][client::Backend::connect()] method if you're creating the Wayland connection
32/// - [`Backend::from_foreign_display()`][client::Backend::from_foreign_display()] if you're interacting with an
33///   already existing Wayland connection through FFI.
34#[cfg(any(test, feature = "client_system"))]
35#[path = "../client_api.rs"]
36pub mod client;
37#[cfg(any(test, feature = "client_system"))]
38use client::{ObjectData, ObjectId};
39
40// API complements for FFI
41
42#[cfg(any(test, feature = "client_system"))]
43impl client::ObjectId {
44    /// Creates an object id from a libwayland-client pointer.
45    ///
46    /// # Errors
47    ///
48    /// This function returns an [`InvalidId`][client::InvalidId] error if the interface of the proxy does
49    /// not match the provided interface.
50    ///
51    /// # Safety
52    ///
53    /// The provided pointer must be a valid pointer to a `wl_resource` and remain valid for as
54    /// long as the retrieved `ObjectId` is used.
55    pub unsafe fn from_ptr(
56        interface: &'static crate::protocol::Interface,
57        ptr: NonNull<c_void>,
58    ) -> Result<Self, client::InvalidId> {
59        Ok(Self {
60            id: unsafe { client_impl::InnerObjectId::from_ptr(interface, ptr.cast::<wl_proxy>()) }?,
61        })
62    }
63
64    /// Get the underlying libwayland pointer for this object
65    ///
66    /// # Errors
67    ///
68    /// This function returns an [`InvalidId`][client::InvalidId] error if proxy has already
69    /// been destroyed.
70    pub fn as_ptr(&self) -> Result<NonNull<c_void>, client::InvalidId> {
71        Ok(self.id.as_ptr()?.cast())
72    }
73
74    /// Get the underlying display pointer for this object.
75    ///
76    /// This pointer is associated with the original display this object
77    /// belongs to.
78    #[cfg(feature = "libwayland_client_1_23")]
79    pub fn display_ptr(&self) -> Result<NonNull<c_void>, crate::types::client::InvalidId> {
80        Ok(self.id.display_ptr()?.cast())
81    }
82}
83
84#[cfg(any(test, feature = "client_system"))]
85impl client::Backend {
86    /// Creates a Backend from a foreign `*mut wl_display`.
87    ///
88    /// This is useful if you are writing a library that is expected to plug itself into an existing
89    /// Wayland connection.
90    ///
91    /// This will initialize the [`Backend`][Self] in "guest" mode, meaning it will not close the
92    /// connection on drop. After the [`Backend`][Self] is dropped, if the server sends an event
93    /// to an object that was created from it, that event will be silently discarded. This may lead to
94    /// protocol errors if the server expects an answer to that event, as such you should make sure to
95    /// cleanup your Wayland state before dropping the [`Backend`][Self].
96    ///
97    /// # Safety
98    ///
99    /// You need to ensure the `*mut wl_display` remains live as long as the  [`Backend`][Self]
100    /// (or its clones) exist.
101    pub unsafe fn from_foreign_display(display: NonNull<c_void>) -> Self {
102        Self {
103            backend: unsafe {
104                client_impl::InnerBackend::from_foreign_display(
105                    display.cast::<wayland_sys::client::wl_display>(),
106                )
107            },
108        }
109    }
110
111    /// Returns the underlying `wl_display` pointer to this backend.
112    ///
113    /// This pointer is needed to interface with EGL, Vulkan and other C libraries.
114    ///
115    /// This pointer is only valid for the lifetime of the backend.
116    pub fn display_ptr(&self) -> *mut c_void {
117        self.backend.display_ptr().cast()
118    }
119
120    /// Take over handling for a proxy created by a third party.
121    ///
122    /// # Safety
123    ///
124    /// There must never be more than one party managing an object. This is only
125    /// safe to call when a third party gave you ownership of an unmanaged proxy.
126    ///
127    /// The caller is also responsible for making sure the passed interface matches
128    /// the proxy.
129    #[inline]
130    pub unsafe fn manage_object(
131        &self,
132        interface: &'static Interface,
133        proxy: *mut c_void,
134        data: Arc<dyn ObjectData>,
135    ) -> ObjectId {
136        unsafe { self.backend.manage_object(interface, proxy.cast::<wl_proxy>(), data) }
137    }
138}
139
140#[cfg(any(test, feature = "client_system"))]
141impl client::ReadEventsGuard {
142    /// The same as [`read`], but doesn't dispatch events.
143    ///
144    /// To dispatch them, use [`dispatch_inner_queue`].
145    ///
146    /// [`read`]: client::ReadEventsGuard::read
147    /// [`dispatch_inner_queue`]: client::Backend::dispatch_inner_queue
148    pub fn read_without_dispatch(mut self) -> Result<(), client::WaylandError> {
149        self.guard.read_non_dispatch()
150    }
151}
152
153#[cfg(all(feature = "rwh_06", feature = "client_system"))]
154impl rwh_06::HasDisplayHandle for client::Backend {
155    fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
156        use std::ptr::NonNull;
157
158        // SAFETY:
159        // - The display_ptr will be valid, either because we have created the pointer or the caller which created the
160        //   backend has ensured the pointer is valid when `Backend::from_foreign_display` was called.
161        let ptr = unsafe { NonNull::new_unchecked(self.display_ptr().cast()) };
162        let handle = rwh_06::WaylandDisplayHandle::new(ptr);
163        let raw = rwh_06::RawDisplayHandle::Wayland(handle);
164
165        // SAFETY:
166        // - The display_ptr will be valid, either because we have created the pointer or the caller which created the
167        //   backend has ensured the pointer is valid when `Backend::from_foreign_display` was called.
168        // - The lifetime assigned to the DisplayHandle borrows the Backend, ensuring the display pointer
169        //   is valid..
170        // - The display_ptr will not change for the lifetime of the backend.
171        Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
172    }
173}
174
175/// Server-side implementation of a Wayland protocol backend using `libwayland`
176///
177/// The main entrypoint is the [`Backend::new()`][server::Backend::new()] method.
178#[cfg(any(test, feature = "server_system"))]
179#[path = "../server_api.rs"]
180pub mod server;
181
182#[cfg(any(test, feature = "server_system"))]
183impl server::ObjectId {
184    /// Creates an object from a C pointer.
185    ///
186    /// # Errors
187    ///
188    /// This function returns an [`InvalidId`][server::InvalidId] error if the interface of the
189    /// resource does not match the provided interface.
190    ///
191    /// # Safety
192    ///
193    /// The provided pointer must be a valid pointer to a `wl_resource` and remain valid for as
194    /// long as the retrieved `ObjectId` is used.
195    pub unsafe fn from_ptr(
196        interface: &'static crate::protocol::Interface,
197        ptr: NonNull<c_void>,
198    ) -> Result<Self, server::InvalidId> {
199        Ok(Self {
200            id: unsafe {
201                server_impl::InnerObjectId::from_ptr(
202                    Some(interface),
203                    ptr.cast::<wayland_sys::server::wl_resource>(),
204                )
205            }?,
206        })
207    }
208
209    /// Returns the pointer that represents this object.
210    ///
211    /// The pointer may be used to interoperate with libwayland.
212    ///
213    /// # Errors
214    ///
215    /// This function returns an [`InvalidId`][server::InvalidId] error if resource has already
216    /// been destroyed.
217    pub fn as_ptr(&self) -> Result<NonNull<c_void>, server::InvalidId> {
218        Ok(self.id.as_ptr()?.cast())
219    }
220}
221
222#[cfg(any(test, feature = "server_system"))]
223impl server::Handle {
224    /// Access the underlying `*mut wl_display` pointer
225    pub fn display_ptr(&self) -> *mut c_void {
226        self.handle.display_ptr().cast()
227    }
228}
229
230unsafe fn parse_arg<O>(
231    typ: &ArgumentType,
232    arg: &wl_argument,
233) -> OwnedArgument<Option<NonNull<O>>, Option<NonZeroU32>> {
234    match typ {
235        ArgumentType::Uint => OwnedArgument::Uint(unsafe { arg.u }),
236        ArgumentType::Int => OwnedArgument::Int(unsafe { arg.i }),
237        ArgumentType::Fixed => OwnedArgument::Fixed(unsafe { arg.f }),
238        ArgumentType::Fd => OwnedArgument::Fd(unsafe { OwnedFd::from_raw_fd(arg.h) }),
239        ArgumentType::Array => {
240            let array = unsafe { &*arg.a };
241            // Safety: the array provided by libwayland must be valid
242            let content = unsafe { std::slice::from_raw_parts(array.data as *mut u8, array.size) };
243            OwnedArgument::Array(Box::new(content.into()))
244        }
245        ArgumentType::Str(_) => {
246            let ptr = unsafe { arg.s };
247            // Safety: the c-string provided by libwayland must be valid
248            OwnedArgument::Str(if !ptr.is_null() {
249                // TODO: Should we error on invalid UTF-8?
250                let s = unsafe { std::ffi::CStr::from_ptr(ptr) }.to_string_lossy();
251                Some(Box::new(s.into_owned()))
252            } else {
253                None
254            })
255        }
256        ArgumentType::Object(_) => OwnedArgument::Object(NonNull::new(unsafe { arg.o as *mut O })),
257        ArgumentType::NewId => OwnedArgument::NewId(NonZeroU32::new(unsafe { arg.n })),
258    }
259}
260
261struct SerializedArgs {
262    signature: &'static [ArgumentType],
263    args: SmallVec<[wl_argument; 4]>,
264}
265
266impl SerializedArgs {
267    fn new(signature: &'static [ArgumentType]) -> Self {
268        Self { signature, args: SmallVec::<[wl_argument; 4]>::with_capacity(signature.len()) }
269    }
270
271    fn add<O>(&mut self, arg: Argument<Option<NonNull<O>>, Option<NonZeroU32>>) {
272        self.args.push(match arg {
273            Argument::Uint(u) => wl_argument { u },
274            Argument::Int(i) => wl_argument { i },
275            Argument::Fixed(f) => wl_argument { f },
276            Argument::Fd(h) => wl_argument { h: h.as_raw_fd() },
277            Argument::Array(ref a) => {
278                let a = Box::new(wl_array {
279                    size: a.len(),
280                    alloc: a.len(),
281                    data: a.as_ptr() as *mut _,
282                });
283                wl_argument { a: Box::into_raw(a) }
284            }
285            Argument::Str(Some(ref s)) => {
286                // Panic if string contains internal \0 byte
287                let s = CString::new((**s).to_owned()).unwrap();
288                wl_argument { s: s.into_raw() }
289            }
290            Argument::Str(None) => wl_argument { s: std::ptr::null() },
291            Argument::Object(o) => {
292                wl_argument { o: o.map_or_else(ptr::null, |o| o.as_ptr()) as *const _ }
293            }
294            Argument::NewId(n) => wl_argument { n: n.map_or(0, |n| n.get()) },
295        });
296    }
297}
298
299impl Drop for SerializedArgs {
300    fn drop(&mut self) {
301        for (typ, arg) in self.signature.iter().zip(self.args.iter()) {
302            // Safety: the arglist provided arglist must be valid for associated signature
303            // and contains pointers to boxed arrays/cstrings as appropriate
304            if let ArgumentType::Array = typ {
305                let _ = unsafe { Box::from_raw(arg.a as *mut wl_array) };
306            } else if let ArgumentType::Str(_) = typ {
307                let ptr = unsafe { arg.s };
308                if !ptr.is_null() {
309                    let _ = unsafe { CString::from_raw(ptr as *mut _) };
310                }
311            }
312        }
313    }
314}
315
316fn cast_non_null_ref<T>(ptr: &NonNull<T>) -> &Option<NonNull<T>> {
317    // SAFETY: `Option<NonNull<T>>` is guaranteed to have same repr as `NonNull<T>`
318    unsafe { &*(ptr as *const _ as *const _) }
319}