From 96c5a501e101565927ae827c4d8461436a19511c 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. 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..b128ae84d2c 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 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..5a72225885e 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 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 = []