From cede955886fdc1c763489408e7b80e8abd19251a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 22 Mar 2024 09:14:26 +0100 Subject: [PATCH] Add support for raw-window-handle Add a `rwh_06` feature to the Rust API crates, which adds support for version 0.6 of rwh to slint::Window, by delegation to the backend. HasDisplayHandle could also be provided on the backend, but that can be done separately if needed. This is only implemented for the winit backend right now. Fixes #877 --- Cargo.toml | 2 ++ api/rs/slint/Cargo.toml | 4 +++ internal/backends/selector/Cargo.toml | 2 ++ internal/backends/winit/Cargo.toml | 5 +++- internal/backends/winit/lib.rs | 14 +++++++++ internal/backends/winit/winitwindowadapter.rs | 10 +++++++ internal/core/Cargo.toml | 8 +++-- internal/core/api.rs | 30 +++++++++++++++++++ internal/core/window.rs | 12 ++++++++ internal/interpreter/Cargo.toml | 4 +++ 10 files changed, 88 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3b1da5e706b..2a0a524e414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -140,6 +140,8 @@ strum = { version = "0.26.1", default-features = false, features = ["derive"] } toml_edit = { version = "0.22.7" } cfg_aliases = { version = "0.2.0" } +rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["alloc"] } + [profile.release] lto = true panic = "abort" diff --git a/api/rs/slint/Cargo.toml b/api/rs/slint/Cargo.toml index 18507ce9bf7..0bbcf961e02 100644 --- a/api/rs/slint/Cargo.toml +++ b/api/rs/slint/Cargo.toml @@ -78,6 +78,10 @@ unsafe-single-threaded = ["i-slint-core/unsafe-single-threaded"] ## APIs to support screen readers and other assistive technologies. accessibility = ["i-slint-backend-selector/accessibility"] +### Enable integration with raw-window-handle version 0.6. This provides a HasWindowHandle and +### HasDisplayHandle implementation for slint::Window. +rwh_06 = ["i-slint-core/rwh_06", "i-slint-backend-selector/rwh_06"] + #! ### Backends #! Slint needs a backend that will act as liaison between Slint and the OS. diff --git a/internal/backends/selector/Cargo.toml b/internal/backends/selector/Cargo.toml index c0ed65bca98..07ddaca5abe 100644 --- a/internal/backends/selector/Cargo.toml +++ b/internal/backends/selector/Cargo.toml @@ -32,6 +32,8 @@ renderer-software = ["i-slint-backend-winit?/renderer-software", "i-slint-core/s rtti = ["i-slint-core/rtti", "i-slint-backend-qt?/rtti"] accessibility = ["i-slint-backend-winit?/accessibility"] +rwh_06 = ["i-slint-backend-winit?/rwh_06"] + # note that default enable the i-slint-backend-qt, but not its enable feature default = ["i-slint-backend-qt", "backend-winit"] diff --git a/internal/backends/winit/Cargo.toml b/internal/backends/winit/Cargo.toml index 0507198f35c..78ac6ed5a98 100644 --- a/internal/backends/winit/Cargo.toml +++ b/internal/backends/winit/Cargo.toml @@ -27,6 +27,7 @@ renderer-skia-opengl = ["renderer-skia", "i-slint-renderer-skia/opengl"] renderer-skia-vulkan = ["renderer-skia", "i-slint-renderer-skia/vulkan"] renderer-software = ["dep:softbuffer", "dep:imgref", "dep:rgb", "i-slint-core/software-renderer-systemfonts", "dep:bytemuck", "winit/rwh_05"] accessibility = ["dep:accesskit", "dep:accesskit_winit"] +rwh_06 = ["dep:rwh_06", "winit/rwh_06"] default = [] [dependencies] @@ -58,6 +59,8 @@ imgref = { version = "1.6.1", optional = true } rgb = { version = "0.8.27", optional = true } bytemuck = { workspace = true, optional = true, features = ["derive"] } +rwh_06 = { workspace = true, optional = true } + [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features=["HtmlInputElement", "HtmlCanvasElement", "Window", "Document", "Event", "KeyboardEvent", "InputEvent", "CompositionEvent", "DomStringMap", "ClipboardEvent", "DataTransfer"] } wasm-bindgen = { version = "0.2" } @@ -77,7 +80,7 @@ cocoa = { version = "0.25.0" } cfg_aliases = { workspace = true } [dev-dependencies] -slint = { path = "../../../api/rs/slint", default-features = false, features = ["std", "compat-1-2", "backend-winit", "renderer-software"] } +slint = { path = "../../../api/rs/slint", default-features = false, features = ["std", "compat-1-2", "backend-winit", "renderer-software", "rwh_06"] } [package.metadata.docs.rs] features = ["wayland", "renderer-software"] diff --git a/internal/backends/winit/lib.rs b/internal/backends/winit/lib.rs index cacfa5c5c69..6a43ddbe4e8 100644 --- a/internal/backends/winit/lib.rs +++ b/internal/backends/winit/lib.rs @@ -416,3 +416,17 @@ fn test_window_accessor() { let slint_window = app.window(); assert!(slint_window.has_winit_window()); } + +// Sorry, can't test with rust test harness and multiple threads. +#[cfg(not(any(target_arch = "wasm32", target_os = "macos", target_os = "ios")))] +#[test] +fn test_rwh() { + slint::platform::set_platform(Box::new(crate::Backend::new().unwrap())).unwrap(); + + use testui::*; + let app = App::new().unwrap(); + let slint_window = app.window(); + use rwh_06::{HasDisplayHandle, HasWindowHandle}; + assert!(slint_window.window_handle().is_ok()); + assert!(slint_window.display_handle().is_ok()); +} diff --git a/internal/backends/winit/winitwindowadapter.rs b/internal/backends/winit/winitwindowadapter.rs index 819b337e562..3b720d48f6e 100644 --- a/internal/backends/winit/winitwindowadapter.rs +++ b/internal/backends/winit/winitwindowadapter.rs @@ -617,6 +617,16 @@ impl WindowAdapter for WinitWindowAdapter { fn internal(&self, _: corelib::InternalToken) -> Option<&dyn WindowAdapterInternal> { Some(self) } + + #[cfg(feature = "rwh_06")] + fn window_handle_06(&self) -> Result, rwh_06::HandleError> { + rwh_06::HasWindowHandle::window_handle(&self.winit_window) + } + + #[cfg(feature = "rwh_06")] + fn display_handle_06(&self) -> Result, rwh_06::HandleError> { + rwh_06::HasDisplayHandle::display_handle(&self.winit_window) + } } impl WindowAdapterInternal for WinitWindowAdapter { diff --git a/internal/core/Cargo.toml b/internal/core/Cargo.toml index 9b97560f3c9..22bafe051f5 100644 --- a/internal/core/Cargo.toml +++ b/internal/core/Cargo.toml @@ -24,7 +24,7 @@ libm = ["num-traits/libm", "euclid/libm"] # Allow the viewer to query at runtime information about item types rtti = [] # Use the standard library -std = ["euclid/std", "once_cell/std", "scoped-tls-hkt", "lyon_path", "lyon_algorithms", "lyon_geom", "lyon_extra", "dep:web-time", "image-decoders", "svg"] +std = ["euclid/std", "once_cell/std", "scoped-tls-hkt", "lyon_path", "lyon_algorithms", "lyon_geom", "lyon_extra", "dep:web-time", "image-decoders", "svg", "rwh_06?/std"] # Unsafe feature meaning that there is only one core running and all thread_local are static. # You can only enable this feature if you are sure that any API of this crate is only called # from a single core, and not in a interrupt or signal handler. @@ -44,6 +44,8 @@ box-shadow-cache = [] shared-fontdb = ["i-slint-common/shared-fontdb"] +rwh_06 = ["dep:rwh_06"] + default = ["std", "unicode"] [dependencies] @@ -86,6 +88,8 @@ resvg = { workspace = true, optional = true } fontdb = { workspace = true, optional = true } serde = { version = "1.0.163", features = ["derive"], optional = true } +rwh_06 = { workspace = true, optional = true } + [target.'cfg(target_family = "unix")'.dependencies] gettext-rs = { version = "0.7", optional = true, features = ["gettext-system"] } @@ -107,4 +111,4 @@ ttf-parser = "0.20.0" fontdb = { workspace = true, default-features = true } serde_json = "1.0.96" tiny-skia = "0.11.0" -tokio = { version = "1.35", features = ["rt-multi-thread"] } \ No newline at end of file +tokio = { version = "1.35", features = ["rt-multi-thread"] } diff --git a/internal/core/api.rs b/internal/core/api.rs index 4aef11de405..e7fed20956e 100644 --- a/internal/core/api.rs +++ b/internal/core/api.rs @@ -573,6 +573,36 @@ impl Window { } } +#[cfg(feature = "rwh_06")] +impl rwh_06::HasWindowHandle for Window { + fn window_handle<'a>(&'a self) -> Result, rwh_06::HandleError> { + let adapter = self.0.window_adapter(); + let wh = adapter.window_handle_06()?; + // Safety: The Rc owns this slint::Window (&self). Therefore the caller of + // this function must also have a strong reference to the window adapter. The adapter above + // was created from a self weak and is the same as the Rc of the caller. + #[allow(unsafe_code)] + Ok(unsafe { + core::mem::transmute::, rwh_06::WindowHandle<'a>>(wh) + }) + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for Window { + fn display_handle<'a>(&'a self) -> Result, rwh_06::HandleError> { + let adapter = self.0.window_adapter(); + let wh = adapter.display_handle_06()?; + // Safety: The Rc owns this slint::Window (&self). Therefore the caller of + // this function must also have a strong reference to the window adapter. The adapter above + // was created from a self weak and is the same as the Rc of the caller. + #[allow(unsafe_code)] + Ok(unsafe { + core::mem::transmute::, rwh_06::DisplayHandle<'a>>(wh) + }) + } +} + pub use crate::SharedString; /// This trait is used to obtain references to global singletons exported in `.slint` diff --git a/internal/core/window.rs b/internal/core/window.rs index 7488cb1a980..ea7506effc6 100644 --- a/internal/core/window.rs +++ b/internal/core/window.rs @@ -137,6 +137,18 @@ pub trait WindowAdapter { fn internal(&self, _: crate::InternalToken) -> Option<&dyn WindowAdapterInternal> { None } + + /// Re-implement this to support exposing raw window handles (version 0.6). + #[cfg(feature = "rwh_06")] + fn window_handle_06(&self) -> Result, rwh_06::HandleError> { + Err(rwh_06::HandleError::NotSupported) + } + + /// Re-implement this to support exposing raw display handles (version 0.6). + #[cfg(feature = "rwh_06")] + fn display_handle_06(&self) -> Result, rwh_06::HandleError> { + Err(rwh_06::HandleError::NotSupported) + } } /// Implementation details behind [`WindowAdapter`], but since this diff --git a/internal/interpreter/Cargo.toml b/internal/interpreter/Cargo.toml index 9ecdf227ee9..6e187625af7 100644 --- a/internal/interpreter/Cargo.toml +++ b/internal/interpreter/Cargo.toml @@ -107,6 +107,10 @@ renderer-winit-software = ["renderer-software"] ## APIs to support screen readers and other assistive technologies. accessibility = ["i-slint-backend-selector/accessibility"] +### Enable integration with raw-window-handle version 0.6. This provides a HasWindowHandle and +### HasDisplayHandle implementation for slint::Window. +rwh_06 = ["i-slint-core/rwh_06", "i-slint-backend-selector/rwh_06"] + ## Features used internally by Slint tooling that are not stable and come without ## any stability guarantees whatsoever. internal = []