mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-02 12:58:23 +00:00
C++ wrapper for the Skia backend
This commit is contained in:
parent
b8b892a91d
commit
fe0e881418
3 changed files with 217 additions and 14 deletions
|
|
@ -34,15 +34,17 @@ renderer-winit-femtovg = ["i-slint-backend-selector/renderer-winit-femtovg"]
|
||||||
renderer-winit-skia = ["i-slint-backend-selector/renderer-winit-skia"]
|
renderer-winit-skia = ["i-slint-backend-selector/renderer-winit-skia"]
|
||||||
renderer-winit-skia-opengl = ["i-slint-backend-selector/renderer-winit-skia-opengl"]
|
renderer-winit-skia-opengl = ["i-slint-backend-selector/renderer-winit-skia-opengl"]
|
||||||
|
|
||||||
experimental = []
|
experimental = ["i-slint-renderer-skia", "raw-window-handle"]
|
||||||
|
|
||||||
default = ["backend-winit", "renderer-winit-femtovg", "backend-qt"]
|
default = ["backend-winit", "renderer-winit-femtovg", "backend-qt", "experimental"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
i-slint-backend-selector = { version = "=0.3.3", path="../../internal/backends/selector" }
|
i-slint-backend-selector = { version = "=0.3.3", path="../../internal/backends/selector" }
|
||||||
i-slint-backend-testing = { version = "=0.3.3", path="../../internal/backends/testing", optional = true }
|
i-slint-backend-testing = { version = "=0.3.3", path="../../internal/backends/testing", optional = true }
|
||||||
|
i-slint-renderer-skia = { version = "=0.3.3", path="../../internal/renderers/skia", optional = true, features = ["opengl", "x11", "wayland"] }
|
||||||
i-slint-core = { version = "=0.3.3", path="../../internal/core", features = ["ffi"] }
|
i-slint-core = { version = "=0.3.3", path="../../internal/core", features = ["ffi"] }
|
||||||
slint-interpreter = { version = "=0.3.3", path="../../internal/interpreter", default-features = false, features = ["ffi", "compat-0-3-0"], optional = true }
|
slint-interpreter = { version = "=0.3.3", path="../../internal/interpreter", default-features = false, features = ["ffi", "compat-0-3-0"], optional = true }
|
||||||
|
raw-window-handle = { version = "0.5", optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@
|
||||||
|
|
||||||
# include "slint.h"
|
# include "slint.h"
|
||||||
|
|
||||||
|
struct xcb_connection_t;
|
||||||
|
struct wl_surface;
|
||||||
|
struct wl_display;
|
||||||
|
|
||||||
namespace slint {
|
namespace slint {
|
||||||
|
|
||||||
/// This namespace contains experimental API.
|
/// This namespace contains experimental API.
|
||||||
|
|
@ -22,7 +26,7 @@ namespace platform {
|
||||||
|
|
||||||
/// The Renderer is one of the Type provided by Slint to do the rendering of a scene.
|
/// The Renderer is one of the Type provided by Slint to do the rendering of a scene.
|
||||||
///
|
///
|
||||||
/// See for example SoftwareRenderer
|
/// See SoftwareRenderer or SkiaRenderer
|
||||||
template<typename R>
|
template<typename R>
|
||||||
concept Renderer = requires(R r)
|
concept Renderer = requires(R r)
|
||||||
{
|
{
|
||||||
|
|
@ -109,6 +113,16 @@ public:
|
||||||
///
|
///
|
||||||
/// Note that this function can only be called if the window was initialized, which is only
|
/// Note that this function can only be called if the window was initialized, which is only
|
||||||
/// the case after it has been returned from a call to Platform::create_window_adaptor
|
/// the case after it has been returned from a call to Platform::create_window_adaptor
|
||||||
|
const Window &window() const
|
||||||
|
{
|
||||||
|
if (!was_initialized)
|
||||||
|
std::abort();
|
||||||
|
// This works because cbindgen_private::WindowAdapterRcOpaque and Window have the same
|
||||||
|
// layout
|
||||||
|
return *reinterpret_cast<const Window *>(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overload
|
||||||
Window &window()
|
Window &window()
|
||||||
{
|
{
|
||||||
if (!was_initialized)
|
if (!was_initialized)
|
||||||
|
|
@ -170,7 +184,7 @@ public:
|
||||||
[](void *p, cbindgen_private::WindowAdapterRcOpaque *out) {
|
[](void *p, cbindgen_private::WindowAdapterRcOpaque *out) {
|
||||||
auto w = reinterpret_cast<const Platform *>(p)->create_window_adaptor();
|
auto w = reinterpret_cast<const Platform *>(p)->create_window_adaptor();
|
||||||
*out = w->initialize();
|
*out = w->initialize();
|
||||||
w.release();
|
(void)w.release();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -229,6 +243,76 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Slint's Skia renderer.
|
||||||
|
///
|
||||||
|
/// To be used as a template parameter of the WindowAdapter.
|
||||||
|
///
|
||||||
|
/// The show() and hide() function must be called from the WindowAdapter's re-implementation
|
||||||
|
/// of the homonymous functions
|
||||||
|
///
|
||||||
|
/// Use render to perform the rendering.
|
||||||
|
|
||||||
|
class SkiaRenderer
|
||||||
|
{
|
||||||
|
mutable cbindgen_private::SkiaRendererOpaque inner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~SkiaRenderer()
|
||||||
|
{
|
||||||
|
if (inner) {
|
||||||
|
cbindgen_private::slint_skia_renderer_drop(inner);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SkiaRenderer(const SkiaRenderer &) = delete;
|
||||||
|
SkiaRenderer &operator=(const SkiaRenderer &) = delete;
|
||||||
|
SkiaRenderer() = default;
|
||||||
|
|
||||||
|
/// \private
|
||||||
|
void init(const cbindgen_private::WindowAdapterRcOpaque *win) const
|
||||||
|
{
|
||||||
|
if (inner) {
|
||||||
|
cbindgen_private::slint_skia_renderer_drop(inner);
|
||||||
|
}
|
||||||
|
inner = cbindgen_private::slint_skia_renderer_new(win);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \private
|
||||||
|
cbindgen_private::RendererPtr renderer_handle() const
|
||||||
|
{
|
||||||
|
return cbindgen_private::slint_skia_renderer_handle(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(PhysicalSize size) const
|
||||||
|
{
|
||||||
|
cbindgen_private::slint_skia_renderer_render(inner, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(PhysicalSize size) const
|
||||||
|
{
|
||||||
|
cbindgen_private::slint_skia_renderer_resize(inner, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hide() const { cbindgen_private::slint_skia_renderer_hide(inner); }
|
||||||
|
|
||||||
|
void show(uint32_t /*xcb_window_t*/ window, uint32_t /*xcb_visualid_t*/ visual_id,
|
||||||
|
xcb_connection_t *connection, int screen, PhysicalSize size) const
|
||||||
|
{
|
||||||
|
cbindgen_private::slint_skia_renderer_show_x11(inner, window, visual_id, connection, screen,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show(wl_surface *surface, wl_display *display, PhysicalSize size) const
|
||||||
|
{
|
||||||
|
cbindgen_private::slint_skia_renderer_show_wayland(inner, surface, display, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Windows handle
|
||||||
|
void show(void *HWND, void *hinstance, PhysicalSize size) const
|
||||||
|
{
|
||||||
|
cbindgen_private::slint_skia_renderer_show_win32(inner, HWND, hinstance, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Call this function at each iteration of the event loop to call the timer handler and advance
|
/// Call this function at each iteration of the event loop to call the timer handler and advance
|
||||||
/// the animations. This should be called before the rendering or processing input events
|
/// the animations. This should be called before the rendering or processing input events
|
||||||
inline void update_timers_and_animations()
|
inline void update_timers_and_animations()
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||||
|
|
||||||
use core::ffi::c_void;
|
use core::ffi::c_void;
|
||||||
use i_slint_core::api::Window;
|
use i_slint_core::api::{PhysicalSize, Window};
|
||||||
use i_slint_core::graphics::Rgb8Pixel;
|
use i_slint_core::graphics::{IntSize, Rgb8Pixel};
|
||||||
use i_slint_core::platform::Platform;
|
use i_slint_core::platform::Platform;
|
||||||
use i_slint_core::renderer::Renderer;
|
use i_slint_core::renderer::Renderer;
|
||||||
use i_slint_core::software_renderer::SoftwareRenderer;
|
use i_slint_core::software_renderer::SoftwareRenderer;
|
||||||
use i_slint_core::window::ffi::WindowAdapterRcOpaque;
|
use i_slint_core::window::ffi::WindowAdapterRcOpaque;
|
||||||
use i_slint_core::window::{WindowAdapter, WindowAdapterSealed};
|
use i_slint_core::window::{WindowAdapter, WindowAdapterSealed};
|
||||||
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
type WindowAdapterUserData = *mut c_void;
|
type WindowAdapterUserData = *mut c_void;
|
||||||
|
|
@ -120,6 +121,19 @@ pub unsafe extern "C" fn slint_platform_register(
|
||||||
i_slint_core::platform::set_platform(Box::new(p)).unwrap();
|
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<dyn WindowAdapter>);
|
||||||
|
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;
|
type SoftwareRendererOpaque = *const c_void;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
@ -178,15 +192,118 @@ pub unsafe extern "C" fn slint_software_renderer_handle(
|
||||||
core::mem::transmute(r)
|
core::mem::transmute(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
type SkiaRendererOpaque = *const c_void;
|
||||||
pub unsafe extern "C" fn slint_windowrc_has_active_animations(
|
type SkiaRenderer = i_slint_renderer_skia::SkiaRenderer<CppRawHandle>;
|
||||||
handle: *const WindowAdapterRcOpaque,
|
|
||||||
) -> bool {
|
struct CppRawHandle(RawWindowHandle, RawDisplayHandle);
|
||||||
let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
|
// Safety: the C++ code should ensure that the handle is valid
|
||||||
window_adapter.window().has_active_animations()
|
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]
|
#[no_mangle]
|
||||||
pub extern "C" fn slint_platform_update_timers_and_animations() {
|
pub unsafe extern "C" fn slint_skia_renderer_new(
|
||||||
i_slint_core::platform::update_timers_and_animations()
|
window: &WindowAdapterRcOpaque,
|
||||||
|
) -> SkiaRendererOpaque {
|
||||||
|
let window = core::mem::transmute::<&WindowAdapterRcOpaque, &Rc<dyn WindowAdapter>>(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_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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue