From 7fbfbcfdf6cbee369c9905eb14013e2d293714b3 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 29 May 2024 23:11:25 +0200 Subject: [PATCH 1/7] Add method for importing external proxies See #730. --- wayland-backend/src/client_api.rs | 20 +++++ wayland-backend/src/rs/client_impl/mod.rs | 11 +++ wayland-backend/src/sys/client_impl/mod.rs | 90 +++++++++++++--------- 3 files changed, 84 insertions(+), 37 deletions(-) diff --git a/wayland-backend/src/client_api.rs b/wayland-backend/src/client_api.rs index 392d6716433..d6ffd5fe261 100644 --- a/wayland-backend/src/client_api.rs +++ b/wayland-backend/src/client_api.rs @@ -11,6 +11,8 @@ use std::{ #[cfg(doc)] use std::io::ErrorKind::WouldBlock; +use wayland_sys::client::wl_proxy; + use crate::protocol::{Interface, Message, ObjectInfo}; use super::client_impl; @@ -286,6 +288,24 @@ impl Backend { pub fn dispatch_inner_queue(&self) -> Result { self.backend.dispatch_inner_queue() } + + /// Take over handling for a proxy created by a third party. + /// + /// Returns `None` on the Rust backend. + /// + /// # Safety + /// + /// There must never be more than one party managing an object. This is only + /// safe to call when a third party is transferring ownership of the proxy. + #[inline] + pub unsafe fn manage_object( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Option>, + ) -> Option { + unsafe { self.backend.manage_object(interface, proxy, data) } + } } /// Guard for synchronizing event reading across multiple threads diff --git a/wayland-backend/src/rs/client_impl/mod.rs b/wayland-backend/src/rs/client_impl/mod.rs index 2c833d0d9a0..42de23c37de 100644 --- a/wayland-backend/src/rs/client_impl/mod.rs +++ b/wayland-backend/src/rs/client_impl/mod.rs @@ -19,6 +19,7 @@ use crate::{ }, }; use smallvec::SmallVec; +use wayland_sys::client::wl_proxy; use super::{ client::*, @@ -510,6 +511,16 @@ impl InnerBackend { pub fn dispatch_inner_queue(&self) -> Result { Ok(0) } + + // Importing external objects is only possible with the system backend. + pub unsafe fn manage_object( + &self, + _interface: &'static Interface, + _proxy: *mut wl_proxy, + _data: Option>, + ) -> Option { + None + } } impl ProtocolState { diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 60c8898b8e5..1fd7e302976 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -521,7 +521,7 @@ impl InnerBackend { data: Option>, child_spec: Option<(&'static Interface, u32)>, ) -> Result { - let mut guard = self.lock_state(); + let guard = self.lock_state(); // check that the argument list is valid let message_desc = match id.interface.requests.get(opcode as usize) { Some(msg) => msg, @@ -690,42 +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 }) - } - 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 - unsafe { - ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, ret); - } - panic!( - "Sending a request creating an object without providing an object data." - ); - } - }; - 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 + drop(guard); + unsafe { self.manage_object(&child_interface, ret, data).unwrap() } } else { Self::null_id() }; @@ -750,7 +716,10 @@ impl InnerBackend { alive.store(false, Ordering::Release); udata.data.destroyed(ObjectId { id: id.clone() }); } + + let mut guard = self.lock_state(); guard.known_proxies.remove(&id.ptr); + unsafe { ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, id.ptr); } @@ -799,6 +768,53 @@ impl InnerBackend { Ok(()) } + + /// Start managing a Wayland object. + pub unsafe fn manage_object( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Option>, + ) -> Option { + let mut guard = self.lock_state(); + + 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, + }, + }; + + let udata = match data { + Some(data) => Box::new(ProxyUserData { alive, data, interface }), + 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 + unsafe { + ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy); + } + panic!("Sending a request creating an object without providing an object data."); + } + }; + + guard.known_proxies.insert(proxy); + + 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 + ); + } + + Some(object_id) + } } unsafe extern "C" fn dispatcher_func( From 06703518717675293228e7f9b0d60360723dd8ce Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Thu, 30 May 2024 02:49:46 +0200 Subject: [PATCH 2/7] Remove function from shared API --- wayland-backend/src/client_api.rs | 20 ------------------- wayland-backend/src/rs/client_impl/mod.rs | 11 ----------- wayland-backend/src/sys/client_impl/mod.rs | 6 +++--- wayland-backend/src/sys/mod.rs | 23 +++++++++++++++++++++- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/wayland-backend/src/client_api.rs b/wayland-backend/src/client_api.rs index d6ffd5fe261..392d6716433 100644 --- a/wayland-backend/src/client_api.rs +++ b/wayland-backend/src/client_api.rs @@ -11,8 +11,6 @@ use std::{ #[cfg(doc)] use std::io::ErrorKind::WouldBlock; -use wayland_sys::client::wl_proxy; - use crate::protocol::{Interface, Message, ObjectInfo}; use super::client_impl; @@ -288,24 +286,6 @@ impl Backend { pub fn dispatch_inner_queue(&self) -> Result { self.backend.dispatch_inner_queue() } - - /// Take over handling for a proxy created by a third party. - /// - /// Returns `None` on the Rust backend. - /// - /// # Safety - /// - /// There must never be more than one party managing an object. This is only - /// safe to call when a third party is transferring ownership of the proxy. - #[inline] - pub unsafe fn manage_object( - &self, - interface: &'static Interface, - proxy: *mut wl_proxy, - data: Option>, - ) -> Option { - unsafe { self.backend.manage_object(interface, proxy, data) } - } } /// Guard for synchronizing event reading across multiple threads diff --git a/wayland-backend/src/rs/client_impl/mod.rs b/wayland-backend/src/rs/client_impl/mod.rs index 42de23c37de..2c833d0d9a0 100644 --- a/wayland-backend/src/rs/client_impl/mod.rs +++ b/wayland-backend/src/rs/client_impl/mod.rs @@ -19,7 +19,6 @@ use crate::{ }, }; use smallvec::SmallVec; -use wayland_sys::client::wl_proxy; use super::{ client::*, @@ -511,16 +510,6 @@ impl InnerBackend { pub fn dispatch_inner_queue(&self) -> Result { Ok(0) } - - // Importing external objects is only possible with the system backend. - pub unsafe fn manage_object( - &self, - _interface: &'static Interface, - _proxy: *mut wl_proxy, - _data: Option>, - ) -> Option { - None - } } impl ProtocolState { diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 1fd7e302976..31040b7b9ab 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -691,7 +691,7 @@ impl InnerBackend { // initialize the proxy let child_id = if let Some((child_interface, _)) = child_spec { drop(guard); - unsafe { self.manage_object(&child_interface, ret, data).unwrap() } + unsafe { self.manage_object(&child_interface, ret, data) } } else { Self::null_id() }; @@ -775,7 +775,7 @@ impl InnerBackend { interface: &'static Interface, proxy: *mut wl_proxy, data: Option>, - ) -> Option { + ) -> ObjectId { let mut guard = self.lock_state(); let alive = Arc::new(AtomicBool::new(true)); @@ -813,7 +813,7 @@ impl InnerBackend { ); } - Some(object_id) + object_id } } diff --git a/wayland-backend/src/sys/mod.rs b/wayland-backend/src/sys/mod.rs index 7ebb87d72c8..2c66db6c674 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,22 @@ 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 is transferring ownership of the proxy. + #[inline] + pub unsafe fn manage_object( + &self, + interface: &'static Interface, + proxy: *mut wl_proxy, + data: Option>, + ) -> ObjectId { + unsafe { self.backend.manage_object(interface, proxy, data) } + } } // SAFETY: From ce997b06db9925a7b2a0d79480b6226db52743ee Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Thu, 30 May 2024 02:50:37 +0200 Subject: [PATCH 3/7] Fix clippy warning --- wayland-backend/src/sys/client_impl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 31040b7b9ab..2e7cb451793 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -691,7 +691,7 @@ impl InnerBackend { // initialize the proxy let child_id = if let Some((child_interface, _)) = child_spec { drop(guard); - unsafe { self.manage_object(&child_interface, ret, data) } + unsafe { self.manage_object(child_interface, ret, data) } } else { Self::null_id() }; From e17ba0bebc56824c8f1fa9cd790b55ea6934e2df Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 3 Jun 2024 13:38:15 +0200 Subject: [PATCH 4/7] Restore guard semantics --- wayland-backend/src/sys/client_impl/mod.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 2e7cb451793..6ff8d9f7b64 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -521,7 +521,7 @@ impl InnerBackend { data: Option>, child_spec: Option<(&'static Interface, u32)>, ) -> Result { - let guard = self.lock_state(); + let mut guard = self.lock_state(); // check that the argument list is valid let message_desc = match id.interface.requests.get(opcode as usize) { Some(msg) => msg, @@ -690,8 +690,7 @@ impl InnerBackend { // initialize the proxy let child_id = if let Some((child_interface, _)) = child_spec { - drop(guard); - unsafe { self.manage_object(child_interface, ret, data) } + unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) } } else { Self::null_id() }; @@ -717,7 +716,6 @@ impl InnerBackend { udata.data.destroyed(ObjectId { id: id.clone() }); } - let mut guard = self.lock_state(); guard.known_proxies.remove(&id.ptr); unsafe { @@ -777,7 +775,19 @@ impl InnerBackend { data: Option>, ) -> 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: Option>, + guard: &mut MutexGuard, + ) -> ObjectId { let alive = Arc::new(AtomicBool::new(true)); let object_id = ObjectId { id: InnerObjectId { From f8b3b3513405efe41cdd159b950ccdd2d39ed536 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 3 Jun 2024 13:43:20 +0200 Subject: [PATCH 5/7] Update documentation --- wayland-backend/CHANGELOG.md | 8 ++++++-- wayland-backend/src/sys/mod.rs | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) 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/mod.rs b/wayland-backend/src/sys/mod.rs index 2c66db6c674..da14281f4d1 100644 --- a/wayland-backend/src/sys/mod.rs +++ b/wayland-backend/src/sys/mod.rs @@ -101,7 +101,11 @@ impl client::Backend { /// # Safety /// /// There must never be more than one party managing an object. This is only - /// safe to call when a third party is transferring ownership of the proxy. + /// safe to call when a third party gave you ownership of an uninitialized + /// proxy. + /// + /// The caller is also responsible for making sure the passed interface matches + /// the proxy. #[inline] pub unsafe fn manage_object( &self, From af0fcef31a934b031e0704a2ae14f16f09be93d9 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 3 Jun 2024 14:51:42 +0200 Subject: [PATCH 6/7] Extract missing data handler --- wayland-backend/src/sys/client_impl/mod.rs | 31 ++++++++++++---------- wayland-backend/src/sys/mod.rs | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/wayland-backend/src/sys/client_impl/mod.rs b/wayland-backend/src/sys/client_impl/mod.rs index 6ff8d9f7b64..8d427847849 100644 --- a/wayland-backend/src/sys/client_impl/mod.rs +++ b/wayland-backend/src/sys/client_impl/mod.rs @@ -690,6 +690,20 @@ impl InnerBackend { // initialize the proxy let child_id = if let Some((child_interface, _)) = child_spec { + 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 + unsafe { + ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, ret); + } + panic!( + "Sending a request creating an object without providing an object data." + ); + } + }; + unsafe { self.manage_object_internal(child_interface, ret, data, &mut guard) } } else { Self::null_id() @@ -772,7 +786,7 @@ impl InnerBackend { &self, interface: &'static Interface, proxy: *mut wl_proxy, - data: Option>, + data: Arc, ) -> ObjectId { let mut guard = self.lock_state(); unsafe { self.manage_object_internal(interface, proxy, data, &mut guard) } @@ -785,7 +799,7 @@ impl InnerBackend { &self, interface: &'static Interface, proxy: *mut wl_proxy, - data: Option>, + data: Arc, guard: &mut MutexGuard, ) -> ObjectId { let alive = Arc::new(AtomicBool::new(true)); @@ -798,20 +812,9 @@ impl InnerBackend { }, }; - let udata = match data { - Some(data) => Box::new(ProxyUserData { alive, data, interface }), - 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 - unsafe { - ffi_dispatch!(wayland_client_handle(), wl_proxy_destroy, proxy); - } - panic!("Sending a request creating an object without providing an object data."); - } - }; - guard.known_proxies.insert(proxy); + let udata = Box::new(ProxyUserData { alive, data, interface }); unsafe { ffi_dispatch!( wayland_client_handle(), diff --git a/wayland-backend/src/sys/mod.rs b/wayland-backend/src/sys/mod.rs index da14281f4d1..05f538d6744 100644 --- a/wayland-backend/src/sys/mod.rs +++ b/wayland-backend/src/sys/mod.rs @@ -111,7 +111,7 @@ impl client::Backend { &self, interface: &'static Interface, proxy: *mut wl_proxy, - data: Option>, + data: Arc, ) -> ObjectId { unsafe { self.backend.manage_object(interface, proxy, data) } } From 46e208db449a91949d5ea5bcadab97df21982343 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 3 Jun 2024 14:52:56 +0200 Subject: [PATCH 7/7] Reword documentation --- wayland-backend/src/sys/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wayland-backend/src/sys/mod.rs b/wayland-backend/src/sys/mod.rs index 05f538d6744..3f5569ee081 100644 --- a/wayland-backend/src/sys/mod.rs +++ b/wayland-backend/src/sys/mod.rs @@ -101,8 +101,7 @@ impl client::Backend { /// # 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 uninitialized - /// proxy. + /// 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.