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}