// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial use core::ffi::c_void; use i_slint_core::api::{PhysicalSize, Window}; use i_slint_core::graphics::{IntSize, Rgb8Pixel}; use i_slint_core::platform::{Platform, PlatformError}; use i_slint_core::renderer::Renderer; use i_slint_core::software_renderer::{RepaintBufferType, SoftwareRenderer}; use i_slint_core::window::ffi::WindowAdapterRcOpaque; use i_slint_core::window::{WindowAdapter, WindowAdapterSealed}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use std::rc::Rc; type WindowAdapterUserData = *mut c_void; // FIXME wrapper over &dyn Renderer #[repr(C)] pub struct RendererPtr { _a: *const c_void, _b: *const c_void, } pub struct CppWindowAdapter { window: Window, user_data: WindowAdapterUserData, drop: unsafe extern "C" fn(WindowAdapterUserData), /// Safety: the returned pointer must live for the lifetime of self get_renderer_ref: unsafe extern "C" fn(WindowAdapterUserData) -> RendererPtr, show: unsafe extern "C" fn(WindowAdapterUserData), hide: unsafe extern "C" fn(WindowAdapterUserData), request_redraw: unsafe extern "C" fn(WindowAdapterUserData), } impl Drop for CppWindowAdapter { fn drop(&mut self) { unsafe { (self.drop)(self.user_data) }; } } impl WindowAdapter for CppWindowAdapter { fn window(&self) -> &Window { &self.window } } impl WindowAdapterSealed for CppWindowAdapter { fn renderer(&self) -> &dyn Renderer { unsafe { core::mem::transmute((self.get_renderer_ref)(self.user_data)) } } fn show(&self) -> Result<(), PlatformError> { unsafe { (self.show)(self.user_data) }; Ok(()) } fn hide(&self) { unsafe { (self.hide)(self.user_data) } } fn request_redraw(&self) { unsafe { (self.request_redraw)(self.user_data) } } } #[no_mangle] pub unsafe extern "C" fn slint_window_adapter_new( user_data: WindowAdapterUserData, drop: unsafe extern "C" fn(WindowAdapterUserData), get_renderer_ref: unsafe extern "C" fn(WindowAdapterUserData) -> RendererPtr, show: unsafe extern "C" fn(WindowAdapterUserData), hide: unsafe extern "C" fn(WindowAdapterUserData), request_redraw: unsafe extern "C" fn(WindowAdapterUserData), target: *mut WindowAdapterRcOpaque, ) { let window = Rc::::new_cyclic(|w| CppWindowAdapter { window: Window::new(w.clone()), user_data, drop, get_renderer_ref, show, request_redraw, hide, }); core::ptr::write(target as *mut Rc, window); } type PlatformUserData = *mut c_void; struct CppPlatform { user_data: PlatformUserData, drop: unsafe extern "C" fn(PlatformUserData), window_factory: unsafe extern "C" fn(PlatformUserData, *mut WindowAdapterRcOpaque), } impl Drop for CppPlatform { fn drop(&mut self) { unsafe { (self.drop)(self.user_data) }; } } impl Platform for CppPlatform { fn create_window_adapter(&self) -> Result, PlatformError> { let mut uninit = core::mem::MaybeUninit::>::uninit(); unsafe { (self.window_factory)( self.user_data, uninit.as_mut_ptr() as *mut WindowAdapterRcOpaque, ); Ok(uninit.assume_init()) } } } #[no_mangle] pub unsafe extern "C" fn slint_platform_register( user_data: PlatformUserData, drop: unsafe extern "C" fn(PlatformUserData), window_factory: unsafe extern "C" fn(PlatformUserData, *mut WindowAdapterRcOpaque), ) { let p = CppPlatform { user_data, drop, window_factory }; i_slint_core::platform::set_platform(Box::new(p)).unwrap(); } #[no_mangle] pub unsafe extern "C" fn slint_windowrc_has_active_animations( handle: *const WindowAdapterRcOpaque, ) -> bool { let window_adapter = &*(handle as *const Rc); window_adapter.window().has_active_animations() } #[no_mangle] pub extern "C" fn slint_platform_update_timers_and_animations() { i_slint_core::platform::update_timers_and_animations() } type SoftwareRendererOpaque = *const c_void; #[no_mangle] pub unsafe extern "C" fn slint_software_renderer_new( buffer_age: u32, window: &WindowAdapterRcOpaque, ) -> SoftwareRendererOpaque { let window = core::mem::transmute::<&WindowAdapterRcOpaque, &Rc>(window); let weak = Rc::downgrade(window); let repaint_buffer_type = match buffer_age { 0 => RepaintBufferType::NewBuffer, 1 => RepaintBufferType::ReusedBuffer, 2 => RepaintBufferType::SwappedBuffers, _ => unreachable!(), }; Box::into_raw(Box::new(SoftwareRenderer::new(repaint_buffer_type, weak))) as SoftwareRendererOpaque } #[no_mangle] pub unsafe extern "C" fn slint_software_renderer_drop(r: SoftwareRendererOpaque) { drop(Box::from_raw(r as *mut SoftwareRenderer)); } #[no_mangle] pub unsafe extern "C" fn slint_software_renderer_render_rgb8( r: SoftwareRendererOpaque, buffer: *mut Rgb8Pixel, buffer_len: usize, pixel_stride: usize, ) { let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len); (*(r as *const SoftwareRenderer)).render(buffer, pixel_stride) } #[no_mangle] pub unsafe extern "C" fn slint_software_renderer_handle(r: SoftwareRendererOpaque) -> RendererPtr { let r = (r as *const SoftwareRenderer) as *const dyn Renderer; core::mem::transmute(r) } type SkiaRendererOpaque = *const c_void; type SkiaRenderer = i_slint_renderer_skia::SkiaRenderer; struct CppRawHandle(RawWindowHandle, RawDisplayHandle); // Safety: the C++ code should ensure that the handle is valid unsafe impl raw_window_handle::HasRawWindowHandle for CppRawHandle { fn raw_window_handle(&self) -> RawWindowHandle { self.0 } } // Safety: the C++ code should ensure that the handle is valid unsafe impl raw_window_handle::HasRawDisplayHandle for CppRawHandle { fn raw_display_handle(&self) -> RawDisplayHandle { self.1 } } // 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 } }; } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_new( window: &WindowAdapterRcOpaque, ) -> SkiaRendererOpaque { let window = core::mem::transmute::<&WindowAdapterRcOpaque, &Rc>(window); let weak = Rc::downgrade(window); Box::into_raw(Box::new(SkiaRenderer::new(weak))) as SkiaRendererOpaque } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_drop(r: SkiaRendererOpaque) { drop(Box::from_raw(r as *mut SkiaRenderer)) } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_show_win32( r: SkiaRendererOpaque, hwnd: *mut c_void, hinstance: *mut c_void, size: IntSize, ) { let r = &*(r as *const SkiaRenderer); let handle = CppRawHandle( RawWindowHandle::Win32(init_raw!(raw_window_handle::Win32WindowHandle { hwnd, hinstance })), RawDisplayHandle::Windows(raw_window_handle::WindowsDisplayHandle::empty()), ); r.show(handle, PhysicalSize { width: size.width, height: size.height }) } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_show_x11( r: SkiaRendererOpaque, window: u32, visual_id: u32, connection: *mut c_void, screen: core::ffi::c_int, size: IntSize, ) { use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle}; let r = &*(r as *const SkiaRenderer); let handle = CppRawHandle( RawWindowHandle::Xcb(init_raw!(XcbWindowHandle { window, visual_id })), RawDisplayHandle::Xcb(init_raw!(XcbDisplayHandle { connection, screen })), ); r.show(handle, PhysicalSize { width: size.width, height: size.height }) } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_show_wayland( r: SkiaRendererOpaque, surface: *mut c_void, display: *mut c_void, size: IntSize, ) { use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; let r = &*(r as *const SkiaRenderer); let handle = CppRawHandle( RawWindowHandle::Wayland(init_raw!(WaylandWindowHandle { surface })), RawDisplayHandle::Wayland(init_raw!(WaylandDisplayHandle { display })), ); r.show(handle, PhysicalSize { width: size.width, height: size.height }) } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_show_appkit( r: SkiaRendererOpaque, ns_view: *mut c_void, ns_window: *mut c_void, size: IntSize, ) { use raw_window_handle::{AppKitDisplayHandle, AppKitWindowHandle}; let r = &*(r as *const SkiaRenderer); let handle = CppRawHandle( RawWindowHandle::AppKit(init_raw!(AppKitWindowHandle { ns_view, ns_window })), RawDisplayHandle::AppKit(AppKitDisplayHandle::empty()), ); r.show(handle, PhysicalSize { width: size.width, height: size.height }) } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_hide(r: SkiaRendererOpaque) { let r = &*(r as *const SkiaRenderer); r.hide() } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_resize(r: SkiaRendererOpaque, size: IntSize) { let r = &*(r as *const SkiaRenderer); r.resize_event(PhysicalSize { width: size.width, height: size.height }); } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_render(r: SkiaRendererOpaque, size: IntSize) { let r = &*(r as *const SkiaRenderer); r.render(PhysicalSize { width: size.width, height: size.height }); } #[no_mangle] pub unsafe extern "C" fn slint_skia_renderer_handle(r: SkiaRendererOpaque) -> RendererPtr { let r = (r as *const SkiaRenderer) as *const dyn Renderer; core::mem::transmute(r) }