Skip to content

Commit

Permalink
Add support for raw-window-handle
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tronical committed Mar 22, 2024
1 parent e4d12ca commit cede955
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions api/rs/slint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions internal/backends/selector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
5 changes: 4 additions & 1 deletion internal/backends/winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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" }
Expand All @@ -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"]
14 changes: 14 additions & 0 deletions internal/backends/winit/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
10 changes: 10 additions & 0 deletions internal/backends/winit/winitwindowadapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::WindowHandle<'_>, rwh_06::HandleError> {
rwh_06::HasWindowHandle::window_handle(&self.winit_window)
}

#[cfg(feature = "rwh_06")]
fn display_handle_06(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
rwh_06::HasDisplayHandle::display_handle(&self.winit_window)
}
}

impl WindowAdapterInternal for WinitWindowAdapter {
Expand Down
8 changes: 6 additions & 2 deletions internal/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -44,6 +44,8 @@ box-shadow-cache = []

shared-fontdb = ["i-slint-common/shared-fontdb"]

rwh_06 = ["dep:rwh_06"]

default = ["std", "unicode"]

[dependencies]
Expand Down Expand Up @@ -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"] }

Expand All @@ -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"] }
tokio = { version = "1.35", features = ["rt-multi-thread"] }
30 changes: 30 additions & 0 deletions internal/core/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::WindowHandle<'a>, rwh_06::HandleError> {
let adapter = self.0.window_adapter();
let wh = adapter.window_handle_06()?;
// Safety: The Rc<dyn WindowAdapter> 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<dyn WindowAdapter> of the caller.
#[allow(unsafe_code)]
Ok(unsafe {
core::mem::transmute::<rwh_06::WindowHandle<'_>, rwh_06::WindowHandle<'a>>(wh)
})
}
}

#[cfg(feature = "rwh_06")]
impl rwh_06::HasDisplayHandle for Window {
fn display_handle<'a>(&'a self) -> Result<rwh_06::DisplayHandle<'a>, rwh_06::HandleError> {
let adapter = self.0.window_adapter();
let wh = adapter.display_handle_06()?;
// Safety: The Rc<dyn WindowAdapter> 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<dyn WindowAdapter> of the caller.
#[allow(unsafe_code)]
Ok(unsafe {
core::mem::transmute::<rwh_06::DisplayHandle<'_>, rwh_06::DisplayHandle<'a>>(wh)
})
}
}

pub use crate::SharedString;

/// This trait is used to obtain references to global singletons exported in `.slint`
Expand Down
12 changes: 12 additions & 0 deletions internal/core/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::WindowHandle<'_>, 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::DisplayHandle<'_>, rwh_06::HandleError> {
Err(rwh_06::HandleError::NotSupported)
}
}

/// Implementation details behind [`WindowAdapter`], but since this
Expand Down
4 changes: 4 additions & 0 deletions internal/interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down

0 comments on commit cede955

Please sign in to comment.