use i_slint_core::partial_renderer::DirtyRegion;
#[cfg(not(docsrs))]
use slint::{PhysicalSize, Window, platform::WindowAdapter};
#[cfg(not(docsrs))]
#[cfg(feature = "i-slint-renderer-skia")]
use smithay_client_toolkit::shm::slot::{Slot, SlotPool};
use std::{
cell::Cell,
cell::RefCell,
fmt::Debug,
rc::{Rc, Weak},
sync::{Arc, Mutex},
};
use tracing::{info, warn};
#[cfg(feature = "i-slint-renderer-skia")]
use i_slint_renderer_skia::{
skia_safe::{self, ColorType},
software_surface::RenderBuffer,
};
#[cfg(feature = "i-slint-renderer-skia")]
#[cfg(not(docsrs))]
pub struct SkiaSoftwareBufferReal {
pub primary_slot: RefCell<Slot>,
pub pool: Rc<RefCell<SlotPool>>,
pub last_dirty_region: RefCell<Option<DirtyRegion>>,
}
impl RenderBuffer for SkiaSoftwareBufferReal {
fn with_buffer(
&self,
_: &Window,
size: PhysicalSize,
render_callback: &mut dyn for<'a> FnMut(
std::num::NonZero<u32>,
std::num::NonZero<u32>,
ColorType,
u8,
&'a mut [u8],
) -> Result<
Option<DirtyRegion>,
slint::PlatformError,
>,
) -> std::result::Result<(), slint::PlatformError> {
let Some((width, height)): Option<(std::num::NonZeroU32, std::num::NonZeroU32)> =
size.width.try_into().ok().zip(size.height.try_into().ok())
else {
return Ok(());
};
let pool = &mut self.pool.borrow_mut();
*self.last_dirty_region.borrow_mut() = render_callback(
width,
height,
skia_safe::ColorType::BGRA8888,
1,
self.primary_slot.borrow_mut().canvas(pool).unwrap(),
)
.unwrap();
Ok(())
}
}
#[cfg(feature = "i-slint-renderer-skia")]
use i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext, software_surface::SoftwareSurface};
#[cfg(feature = "i-slint-renderer-skia")]
pub struct SpellSkiaWinAdapterReal {
pub(crate) window: Window,
pub(crate) size: Cell<PhysicalSize>,
pub(crate) renderer: SkiaRenderer,
#[allow(dead_code)]
pub(crate) buffer_slint: Rc<SkiaSoftwareBufferReal>,
pub(crate) needs_redraw: Cell<bool>,
pub(crate) scale_factor: Cell<f32>,
#[allow(clippy::type_complexity)]
pub(crate) slint_event_proxy: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>,
}
impl Debug for SpellSkiaWinAdapterReal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SpellSkiaWinAdapter")
.field("size", &self.size)
.field("redraw", &self.needs_redraw)
.finish()
}
}
impl WindowAdapter for SpellSkiaWinAdapterReal {
fn window(&self) -> &slint::Window {
&self.window
}
fn size(&self) -> PhysicalSize {
self.size.get()
}
fn renderer(&self) -> &dyn slint::platform::Renderer {
&self.renderer
}
fn set_size(&self, size: slint::WindowSize) {
info!("Set_size is called");
self.size.set(size.to_physical(self.scale_factor.get()));
self.window
.dispatch_event(slint::platform::WindowEvent::Resized {
size: size.to_logical(self.scale_factor.get()),
})
}
fn request_redraw(&self) {
self.needs_redraw.set(true);
}
}
impl SpellSkiaWinAdapterReal {
#[allow(clippy::type_complexity)]
pub fn new(
pool: Rc<RefCell<SlotPool>>,
primary_slot: RefCell<Slot>,
width: u32,
height: u32,
slint_proxy: Arc<Mutex<Vec<Box<dyn FnOnce() + Send>>>>,
) -> Rc<Self> {
let buffer = Rc::new(SkiaSoftwareBufferReal {
primary_slot,
pool,
last_dirty_region: Default::default(),
});
let renderer = SkiaRenderer::new_with_surface(
&SkiaSharedContext::default(),
Box::new(SoftwareSurface::from(buffer.clone())),
);
Rc::new_cyclic(|w: &Weak<Self>| Self {
window: slint::Window::new(w.clone()),
size: Cell::new(PhysicalSize { width, height }),
renderer,
buffer_slint: buffer,
needs_redraw: Cell::new(true),
scale_factor: Cell::new(1.),
slint_event_proxy: slint_proxy,
})
}
pub fn draw(&self) -> bool {
if self.needs_redraw.replace(false) {
self.renderer.render().unwrap_or_else(|err| {
warn!("Panicking because of error: {}", err);
panic!("Seems like you have initialised slint before SpellWin");
});
true
} else {
false
}
}
pub(crate) fn draw_if_needed(&self) -> bool {
self.draw()
}
pub(crate) fn try_dispatch_event(
&self,
event: slint::platform::WindowEvent,
) -> Result<(), slint::PlatformError> {
self.window.try_dispatch_event(event)
}
}