diff --git a/api/cpp/platform.rs b/api/cpp/platform.rs index 79d858ad8..00258d91f 100644 --- a/api/cpp/platform.rs +++ b/api/cpp/platform.rs @@ -511,18 +511,34 @@ mod software_renderer { pub mod skia { use super::*; use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; + use std::rc::Rc; - struct CppRawHandle(RawWindowHandle, RawDisplayHandle); + struct RawHandlePair((RawWindowHandle, RawDisplayHandle)); - // the raw handle type are #[non_exhaustive], so they can't be initialize with the convenient syntax. Work that around. - macro_rules! init_raw { - ($ty:ty { $($var:ident),* }) => { - { - let mut h = <$ty>::empty(); - $(h.$var = $var;)* - h - } - }; + impl raw_window_handle::HasDisplayHandle for RawHandlePair { + fn display_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + // Safety: It is assumed that the C++ side keeps the window/display handles alive. + Ok(unsafe { raw_window_handle::DisplayHandle::borrow_raw(self.0 .1) }) + } + } + + impl raw_window_handle::HasWindowHandle for RawHandlePair { + fn window_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + // Safety: It is assumed that the C++ side keeps the window/display handles alive. + Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(self.0 .0) }) + } + } + + struct CppRawHandle(Rc); + + impl From<(RawWindowHandle, RawDisplayHandle)> for CppRawHandle { + fn from(pair: (RawWindowHandle, RawDisplayHandle)) -> Self { + Self(Rc::new(RawHandlePair(pair))) + } } type CppRawHandleOpaque = *const c_void; @@ -530,15 +546,14 @@ pub mod skia { #[no_mangle] pub unsafe extern "C" fn slint_new_raw_window_handle_win32( hwnd: *mut c_void, - hinstance: *mut c_void, + _hinstance: *mut c_void, ) -> CppRawHandleOpaque { - let handle = CppRawHandle( - RawWindowHandle::Win32(init_raw!(raw_window_handle::Win32WindowHandle { - hwnd, - hinstance - })), - RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::empty()), - ); + let handle = CppRawHandle::from(( + RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle::new( + (hwnd as isize).try_into().expect("C++: NativeWindowHandle created with null hwnd"), + )), + RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::new()), + )); Box::into_raw(Box::new(handle)) as CppRawHandleOpaque } @@ -550,10 +565,21 @@ pub mod skia { screen: core::ffi::c_int, ) -> CppRawHandleOpaque { use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle}; - let handle = CppRawHandle( - RawWindowHandle::Xcb(init_raw!(XcbWindowHandle { window, visual_id })), - RawDisplayHandle::Xcb(init_raw!(XcbDisplayHandle { connection, screen })), - ); + let handle = CppRawHandle::from(( + RawWindowHandle::Xcb({ + let mut hnd = XcbWindowHandle::new( + window + .try_into() + .expect("C++: NativeWindowHandle created with null xcb window handle"), + ); + hnd.visual_id = visual_id.try_into().ok(); + hnd + }), + RawDisplayHandle::Xcb(XcbDisplayHandle::new( + Some(core::ptr::NonNull::new_unchecked(connection)), + screen, + )), + )); Box::into_raw(Box::new(handle)) as CppRawHandleOpaque } @@ -565,10 +591,17 @@ pub mod skia { screen: core::ffi::c_int, ) -> CppRawHandleOpaque { use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle}; - let handle = CppRawHandle( - RawWindowHandle::Xlib(init_raw!(XlibWindowHandle { window, visual_id })), - RawDisplayHandle::Xlib(init_raw!(XlibDisplayHandle { display, screen })), - ); + let handle = CppRawHandle::from(( + RawWindowHandle::Xlib({ + let mut hnd = XlibWindowHandle::new(window); + hnd.visual_id = visual_id; + hnd + }), + RawDisplayHandle::Xlib(XlibDisplayHandle::new( + Some(core::ptr::NonNull::new_unchecked(display)), + screen, + )), + )); Box::into_raw(Box::new(handle)) as CppRawHandleOpaque } @@ -578,23 +611,29 @@ pub mod skia { display: *mut c_void, ) -> CppRawHandleOpaque { use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; - let handle = CppRawHandle( - RawWindowHandle::Wayland(init_raw!(WaylandWindowHandle { surface })), - RawDisplayHandle::Wayland(init_raw!(WaylandDisplayHandle { display })), - ); + let handle = CppRawHandle::from(( + RawWindowHandle::Wayland(WaylandWindowHandle::new(core::ptr::NonNull::new_unchecked( + surface, + ))), + RawDisplayHandle::Wayland(WaylandDisplayHandle::new( + core::ptr::NonNull::new_unchecked(display), + )), + )); Box::into_raw(Box::new(handle)) as CppRawHandleOpaque } #[no_mangle] pub unsafe extern "C" fn slint_new_raw_window_handle_appkit( ns_view: *mut c_void, - ns_window: *mut c_void, + _ns_window: *mut c_void, ) -> CppRawHandleOpaque { use raw_window_handle::{AppKitDisplayHandle, AppKitWindowHandle}; - let handle = CppRawHandle( - RawWindowHandle::AppKit(init_raw!(AppKitWindowHandle { ns_view, ns_window })), - RawDisplayHandle::AppKit(AppKitDisplayHandle::empty()), - ); + let handle = CppRawHandle::from(( + RawWindowHandle::AppKit(AppKitWindowHandle::new(core::ptr::NonNull::new_unchecked( + ns_view, + ))), + RawDisplayHandle::AppKit(AppKitDisplayHandle::new()), + )); Box::into_raw(Box::new(handle)) as CppRawHandleOpaque } @@ -613,21 +652,10 @@ pub mod skia { ) -> SkiaRendererOpaque { let handle = &*(handle_opaque as *const CppRawHandle); - // Safety: This is safe because the handle remains valid; the next rwh release provides `new()` without unsafe. - let active_handle = unsafe { raw_window_handle::ActiveHandle::new_unchecked() }; - - // Safety: the C++ code should ensure that the handle is valid - let (window_handle, display_handle) = unsafe { - ( - raw_window_handle::WindowHandle::borrow_raw(handle.0, active_handle), - raw_window_handle::DisplayHandle::borrow_raw(handle.1), - ) - }; - let boxed_renderer: Box = Box::new( SkiaRenderer::new( - window_handle, - display_handle, + handle.0.clone(), + handle.0.clone(), PhysicalSize { width: size.width, height: size.height }, ) .unwrap(), diff --git a/internal/backends/winit/event_loop.rs b/internal/backends/winit/event_loop.rs index 40fa10d48..b0ca2a2e0 100644 --- a/internal/backends/winit/event_loop.rs +++ b/internal/backends/winit/event_loop.rs @@ -485,7 +485,7 @@ impl EventLoopState { Event::Resumed => ALL_WINDOWS.with(|ws| { for (_, window_weak) in ws.borrow().iter() { if let Some(w) = window_weak.upgrade() { - if let Err(e) = w.renderer.resumed(&w.winit_window()) { + if let Err(e) = w.renderer.resumed(w.winit_window()) { self.loop_error = Some(e); } } diff --git a/internal/backends/winit/lib.rs b/internal/backends/winit/lib.rs index ab58a4700..02d1a2595 100644 --- a/internal/backends/winit/lib.rs +++ b/internal/backends/winit/lib.rs @@ -32,6 +32,8 @@ pub enum SlintUserEvent { } mod renderer { + use std::rc::Rc; + use i_slint_core::platform::PlatformError; pub trait WinitCompatibleRenderer { @@ -43,7 +45,7 @@ mod renderer { fn occluded(&self, _: bool) {} // Got winit::Event::Resumed - fn resumed(&self, _winit_window: &winit::window::Window) -> Result<(), PlatformError> { + fn resumed(&self, _winit_window: Rc) -> Result<(), PlatformError> { Ok(()) } } diff --git a/internal/backends/winit/renderer/skia.rs b/internal/backends/winit/renderer/skia.rs index 9b6d37b92..df0913d04 100644 --- a/internal/backends/winit/renderer/skia.rs +++ b/internal/backends/winit/renderer/skia.rs @@ -5,7 +5,6 @@ use std::rc::Rc; use crate::winitwindowadapter::physical_size_to_slint; use i_slint_core::platform::PlatformError; -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; pub struct WinitSkiaRenderer { renderer: i_slint_renderer_skia::SkiaRenderer, @@ -13,11 +12,11 @@ pub struct WinitSkiaRenderer { impl WinitSkiaRenderer { pub fn new( - window_builder: winit::window::WindowBuilder, + window_attributes: winit::window::WindowAttributes, ) -> Result<(Box, Rc), PlatformError> { let winit_window = Rc::new(crate::event_loop::with_window_target(|event_loop| { - window_builder.build(event_loop.event_loop_target()).map_err(|winit_os_error| { + event_loop.create_window(window_attributes).map_err(|winit_os_error| { format!("Error creating native window for Skia rendering: {}", winit_os_error) .into() }) @@ -37,11 +36,11 @@ impl WinitSkiaRenderer { #[cfg(not(target_os = "android"))] pub fn new_software( - window_builder: winit::window::WindowBuilder, + window_attributes: winit::window::WindowAttributes, ) -> Result<(Box, Rc), PlatformError> { let winit_window = Rc::new(crate::event_loop::with_window_target(|event_loop| { - window_builder.build(event_loop.event_loop_target()).map_err(|winit_os_error| { + event_loop.create_window(window_attributes).map_err(|winit_os_error| { format!("Error creating native window for Skia rendering: {}", winit_os_error) .into() }) @@ -60,11 +59,11 @@ impl WinitSkiaRenderer { } pub fn new_opengl( - window_builder: winit::window::WindowBuilder, + window_attributes: winit::window::WindowAttributes, ) -> Result<(Box, Rc), PlatformError> { let winit_window = Rc::new(crate::event_loop::with_window_target(|event_loop| { - window_builder.build(event_loop.event_loop_target()).map_err(|winit_os_error| { + event_loop.create_window(window_attributes).map_err(|winit_os_error| { format!("Error creating native window for Skia rendering: {}", winit_os_error) .into() }) @@ -92,29 +91,12 @@ impl super::WinitCompatibleRenderer for WinitSkiaRenderer { &self.renderer } - fn resumed(&self, winit_window: &winit::window::Window) -> Result<(), PlatformError> { + fn resumed(&self, winit_window: Rc) -> Result<(), PlatformError> { let size = winit_window.inner_size(); - // Safety: This is safe because the handle remains valid; the next rwh release provides `new()` without unsafe. - let active_handle = unsafe { raw_window_handle::ActiveHandle::new_unchecked() }; - - // Safety: API wise we can't guarantee that the window/display handles remain valid, so we - // use unsafe here. However the winit window adapter keeps the winit window alive as long as - // the renderer. - // TODO: remove once winit implements HasWindowHandle/HasDisplayHandle - let (window_handle, display_handle) = unsafe { - ( - raw_window_handle::WindowHandle::borrow_raw( - winit_window.raw_window_handle(), - active_handle, - ), - raw_window_handle::DisplayHandle::borrow_raw(winit_window.raw_display_handle()), - ) - }; - self.renderer.set_window_handle( - window_handle, - display_handle, + winit_window.clone(), + winit_window.clone(), physical_size_to_slint(&size), winit_window.scale_factor() as f32, ) diff --git a/internal/backends/winit/winitwindowadapter.rs b/internal/backends/winit/winitwindowadapter.rs index e32fbd095..eee30439c 100644 --- a/internal/backends/winit/winitwindowadapter.rs +++ b/internal/backends/winit/winitwindowadapter.rs @@ -174,7 +174,7 @@ impl WinitWindowAdapter { }); let winit_window = self_rc.winit_window(); - if let Err(e) = self_rc.renderer.resumed(&winit_window) { + if let Err(e) = self_rc.renderer.resumed(winit_window.clone()) { i_slint_core::debug_log!("Error initialing renderer in winit backend with window: {e}"); } let id = winit_window.id(); diff --git a/internal/renderers/skia/d3d_surface.rs b/internal/renderers/skia/d3d_surface.rs index 990000646..b8b35b5e1 100644 --- a/internal/renderers/skia/d3d_surface.rs +++ b/internal/renderers/skia/d3d_surface.rs @@ -4,6 +4,7 @@ use i_slint_core::api::PhysicalSize as PhysicalWindowSize; use i_slint_core::platform::PlatformError; use std::cell::RefCell; +use std::rc::Rc; use windows::core::Interface; use windows::Win32::Graphics::Direct3D::D3D_FEATURE_LEVEL_11_0; use windows::Win32::Graphics::Dxgi::Common::DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN; @@ -245,8 +246,8 @@ pub struct D3DSurface { impl super::Surface for D3DSurface { fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - _display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + _display_handle: Rc, size: PhysicalWindowSize, ) -> Result { let factory_flags = 0; @@ -357,6 +358,10 @@ impl super::Surface for D3DSurface { let gr_context = unsafe { skia_safe::gpu::DirectContext::new_d3d(&backend_context, None) } .ok_or_else(|| format!("unable to create Skia D3D DirectContext"))?; + let window_handle = window_handle + .window_handle() + .map_err(|e| format!("error obtaining window handle for skia d3d renderer: {e}"))?; + let swap_chain = RefCell::new(SwapChain::new( queue, &device, diff --git a/internal/renderers/skia/lib.rs b/internal/renderers/skia/lib.rs index 584cf8002..1ae0f434d 100644 --- a/internal/renderers/skia/lib.rs +++ b/internal/renderers/skia/lib.rs @@ -63,8 +63,8 @@ cfg_if::cfg_if! { } fn create_default_surface( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, ) -> Result, PlatformError> { match DefaultSurface::new(window_handle.clone(), display_handle.clone(), size) { @@ -94,8 +94,8 @@ pub struct SkiaRenderer { rendering_first_time: Cell, surface: RefCell>>, surface_factory: fn( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, ) -> Result, PlatformError>, pre_present_callback: RefCell>>, @@ -157,8 +157,8 @@ impl SkiaRenderer { /// Creates a new renderer is associated with the provided window adapter. pub fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, ) -> Result { Ok(Self::new_with_surface(create_default_surface(window_handle, display_handle, size)?)) @@ -192,8 +192,8 @@ impl SkiaRenderer { /// Reset the surface to the window given the window handle pub fn set_window_handle( &self, - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, scale_factor: f32, ) -> Result<(), PlatformError> { @@ -547,8 +547,8 @@ impl Drop for SkiaRenderer { pub trait Surface { /// Creates a new surface with the given window, display, and size. fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, ) -> Result where diff --git a/internal/renderers/skia/metal_surface.rs b/internal/renderers/skia/metal_surface.rs index 86522cc80..568571384 100644 --- a/internal/renderers/skia/metal_surface.rs +++ b/internal/renderers/skia/metal_surface.rs @@ -8,10 +8,10 @@ use i_slint_core::api::PhysicalSize as PhysicalWindowSize; use metal::MTLPixelFormat; use objc::{rc::autoreleasepool, runtime::YES}; -use raw_window_handle::HasRawWindowHandle; use skia_safe::gpu::mtl; use std::cell::RefCell; +use std::rc::Rc; /// This surface renders into the given window using Metal. The provided display argument /// is ignored, as it has no meaning on macOS. @@ -23,8 +23,8 @@ pub struct MetalSurface { impl super::Surface for MetalSurface { fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - _display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + _display_handle: Rc, size: PhysicalWindowSize, ) -> Result { let device = metal::Device::system_default() @@ -39,10 +39,14 @@ impl super::Surface for MetalSurface { layer.set_drawable_size(CGSize::new(size.width as f64, size.height as f64)); unsafe { - let view = match window_handle.raw_window_handle() { + let view = match window_handle + .window_handle() + .map_err(|e| format!("Error obtaining window handle for skia metal renderer: {e}"))? + .as_raw() + { raw_window_handle::RawWindowHandle::AppKit( raw_window_handle::AppKitWindowHandle { ns_view, .. }, - ) => ns_view, + ) => ns_view.as_ptr(), _ => { return Err("Skia Renderer: Metal surface is only supported with AppKit".into()) } diff --git a/internal/renderers/skia/opengl_surface.rs b/internal/renderers/skia/opengl_surface.rs index a049ca60c..5e8eee530 100644 --- a/internal/renderers/skia/opengl_surface.rs +++ b/internal/renderers/skia/opengl_surface.rs @@ -1,7 +1,9 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 -use std::{cell::RefCell, num::NonZeroU32}; +use std::cell::RefCell; +use std::num::NonZeroU32; +use std::rc::Rc; use glutin::{ config::GetGlConfig, @@ -24,8 +26,8 @@ pub struct OpenGLSurface { impl super::Surface for OpenGLSurface { fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, size: PhysicalWindowSize, ) -> Result { let width: std::num::NonZeroU32 = size.width.try_into().map_err(|_| { @@ -35,6 +37,13 @@ impl super::Surface for OpenGLSurface { format!("Attempting to create window surface with an invalid height: {}", size.height) })?; + let window_handle = window_handle + .window_handle() + .map_err(|e| format!("error obtaining window handle for skia opengl renderer: {e}"))?; + let display_handle = display_handle + .display_handle() + .map_err(|e| format!("error obtaining display handle for skia opengl renderer: {e}"))?; + let (current_glutin_context, glutin_surface) = Self::init_glutin(window_handle, display_handle, width, height)?; @@ -220,17 +229,14 @@ impl OpenGLSurface { } let gl_display = unsafe { - glutin::display::Display::new( - _display_handle.as_raw(), - display_api_preference, - ) - .map_err(|glutin_error| { - format!( - "Error creating glutin display for native display {:#?}: {}", - _display_handle.as_raw(), - glutin_error - ) - })? + glutin::display::Display::new(_display_handle.as_raw(), display_api_preference) + .map_err(|glutin_error| { + format!( + "Error creating glutin display for native display {:#?}: {}", + _display_handle.as_raw(), + glutin_error + ) + })? }; let config_template_builder = glutin::config::ConfigTemplateBuilder::new(); @@ -315,10 +321,10 @@ impl OpenGLSurface { if let raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle { ns_view, .. - }) = _window_handle.raw_window_handle() + }) = _window_handle.as_raw() { use cocoa::appkit::NSView; - let view_id: cocoa::base::id = ns_view as *const _ as *mut _; + let view_id: cocoa::base::id = ns_view.as_ptr() as *const _ as *mut _; unsafe { NSView::setLayerContentsPlacement(view_id, cocoa::appkit::NSViewLayerContentsPlacement::NSViewLayerContentsPlacementTopLeft) } diff --git a/internal/renderers/skia/software_surface.rs b/internal/renderers/skia/software_surface.rs index 462aaa68c..9cbd21e47 100644 --- a/internal/renderers/skia/software_surface.rs +++ b/internal/renderers/skia/software_surface.rs @@ -3,7 +3,9 @@ use i_slint_core::api::PhysicalSize as PhysicalWindowSize; -use std::{cell::RefCell, num::NonZeroU32}; +use std::cell::RefCell; +use std::num::NonZeroU32; +use std::rc::Rc; pub trait RenderBuffer { fn with_buffer( @@ -20,8 +22,13 @@ pub trait RenderBuffer { } struct SoftbufferRenderBuffer { - _context: softbuffer::Context, - surface: RefCell, + _context: softbuffer::Context>, + surface: RefCell< + softbuffer::Surface< + Rc, + Rc, + >, + >, } impl RenderBuffer for SoftbufferRenderBuffer { @@ -74,18 +81,17 @@ pub struct SoftwareSurface { impl super::Surface for SoftwareSurface { fn new( - window_handle: raw_window_handle::WindowHandle<'_>, - display_handle: raw_window_handle::DisplayHandle<'_>, + window_handle: Rc, + display_handle: Rc, _size: PhysicalWindowSize, ) -> Result { - let _context = unsafe { - softbuffer::Context::new(&display_handle) - .map_err(|e| format!("Error creating softbuffer context: {e}"))? - }; + let _context = softbuffer::Context::new(display_handle) + .map_err(|e| format!("Error creating softbuffer context: {e}"))?; - let surface = unsafe { softbuffer::Surface::new(&_context, &window_handle) }.map_err( - |softbuffer_error| format!("Error creating softbuffer surface: {}", softbuffer_error), - )?; + let surface = + softbuffer::Surface::new(&_context, window_handle).map_err(|softbuffer_error| { + format!("Error creating softbuffer surface: {}", softbuffer_error) + })?; let surface_access = Box::new(SoftbufferRenderBuffer { _context, surface: RefCell::new(surface) });