diff --git a/wayland-backend/CHANGELOG.md b/wayland-backend/CHANGELOG.md index 2066b25df7f..433ada7baa6 100644 --- a/wayland-backend/CHANGELOG.md +++ b/wayland-backend/CHANGELOG.md @@ -2,9 +2,13 @@ ## Unreleased +#### Additions + +- `Backend::manage_object` for handling foreign proxies with the sys backend + ## 0.3.4 -- 2024-05-30 -### Additions +#### Additions - Add `rwh_06` feature for `raw-window-handle` 0.6 @@ -14,7 +18,7 @@ ## 0.3.3 -- 2024-01-29 -### Additions +#### Additions - client: Implement `Eq` for `Backend` #### Bugfixes diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 60c8898b8e5..8d427847849 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -690,19 +690,8 @@ impl InnerBackend { // initialize the proxy let child_id = if let Some((child_interface, _)) = child_spec { - let child_alive = Arc::new(AtomicBool::new(true)); - let child_id = ObjectId { - id: InnerObjectId { - ptr: ret, - alive: Some(child_alive.clone()), - id: unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, ret) }, - interface: child_interface, - }, - }; - let child_udata = match data { - Some(data) => { - Box::new(ProxyUserData { alive: child_alive, data, interface: child_interface }) - } + let data = match data { + Some(data) => data, None => { // we destroy this proxy before panicking to avoid a leak, as it cannot be destroyed by the // main destructor given it does not yet have a proper user-data @@ -714,18 +703,8 @@ impl InnerBackend { ); } }; - guard.known_proxies.insert(ret); - unsafe { - ffi_dispatch!( - wayland_client_handle(), - wl_proxy_add_dispatcher, - ret, - dispatcher_func, - &RUST_MANAGED as *const u8 as *const c_void, - Box::into_raw(child_udata) as *mut c_void - ); - } - child_id + + unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) } } else { Self::null_id() }; @@ -750,7 +729,9 @@ impl InnerBackend { alive.store(false, Ordering::Release); udata.data.destroyed(ObjectId { id: id.clone() }); } + guard.known_proxies.remove(&id.ptr); + unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.ptr); } @@ -799,6 +780,54 @@ impl InnerBackend { Ok(()) } + + /// Start managing a Wayland object. + pub unsafe fn manage_object( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Arc, + ) -> ObjectId { + let mut guard = self.lock_state(); + unsafe { self.manage_object_internal(interface, proxy, data, &mut guard) } + } + + /// Start managing a Wayland object. + /// + /// Opposed to [`Self::manage_object`], this does not acquire any guards. + unsafe fn manage_object_internal( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Arc, + guard: &mut MutexGuard, + ) -> ObjectId { + let alive = Arc::new(AtomicBool::new(true)); + let object_id = ObjectId { + id: InnerObjectId { + ptr: proxy, + alive: Some(alive.clone()), + id: unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_get_id, proxy) }, + interface, + }, + }; + + guard.known_proxies.insert(proxy); + + let udata = Box::new(ProxyUserData { alive, data, interface }); + unsafe { + ffi_dispatch!( + wayland_client_handle(), + wl_proxy_add_dispatcher, + proxy, + dispatcher_func, + &RUST_MANAGED as *const u8 as *const c_void, + Box::into_raw(udata) as *mut c_void + ); + } + + object_id + } } unsafe extern "C" fn dispatcher_func( diff --git a/wayland-backend/src/sys/mod.rs b/wayland-backend/src/sys/mod.rs index 7ebb87d72c8..3f5569ee081 100644 --- a/wayland-backend/src/sys/mod.rs +++ b/wayland-backend/src/sys/mod.rs @@ -1,8 +1,13 @@ //! Implementations of the Wayland backends using the system `libwayland` -use crate::protocol::ArgumentType; +use std::sync::Arc; + +use wayland_sys::client::wl_proxy; use wayland_sys::common::{wl_argument, wl_array}; +use crate::client::{ObjectData, ObjectId}; +use crate::protocol::{ArgumentType, Interface}; + #[cfg(any(test, feature = "client_system"))] mod client_impl; #[cfg(any(test, feature = "server_system"))] @@ -90,6 +95,25 @@ impl client::Backend { pub fn display_ptr(&self) -> *mut wayland_sys::client::wl_display { self.backend.display_ptr() } + + /// Take over handling for a proxy created by a third party. + /// + /// # Safety + /// + /// There must never be more than one party managing an object. This is only + /// safe to call when a third party gave you ownership of an unmanaged proxy. + /// + /// The caller is also responsible for making sure the passed interface matches + /// the proxy. + #[inline] + pub unsafe fn manage_object( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Arc, + ) -> ObjectId { + unsafe { self.backend.manage_object(interface, proxy, data) } + } } // SAFETY: