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}