i_slint_renderer_software/
minimal_software_window.rs1use super::{RepaintBufferType, SoftwareRenderer};
5use alloc::rc::{Rc, Weak};
6use core::cell::Cell;
7use i_slint_core::api::Window;
8use i_slint_core::platform::Renderer;
9use i_slint_core::window::WindowAdapter;
10
11pub struct MinimalSoftwareWindow {
14 window: Window,
15 renderer: SoftwareRenderer,
16 needs_redraw: Cell<bool>,
17 size: Cell<i_slint_core::api::PhysicalSize>,
18}
19
20impl MinimalSoftwareWindow {
21 pub fn new(repaint_buffer_type: RepaintBufferType) -> Rc<Self> {
25 Rc::new_cyclic(|w: &Weak<Self>| Self {
26 window: Window::new(w.clone()),
27 renderer: SoftwareRenderer::new_with_repaint_buffer_type(repaint_buffer_type),
28 needs_redraw: Default::default(),
29 size: Default::default(),
30 })
31 }
32 pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
40 if self.needs_redraw.replace(false)
41 || self.renderer.rendering_metrics_collector.as_ref().is_some_and(|m| m.refresh_mode() == i_slint_core::graphics::rendering_metrics_collector::RefreshMode::FullSpeed)
42 {
43 render_callback(&self.renderer);
44 true
45 } else {
46 false
47 }
48 }
49
50 #[cfg(feature = "experimental")]
51 pub async fn draw_async_if_needed(
59 &self,
60 render_callback: impl AsyncFnOnce(&SoftwareRenderer),
61 ) -> bool {
62 if self.needs_redraw.replace(false) || self.renderer.rendering_metrics_collector.is_some() {
63 render_callback(&self.renderer).await;
64 true
65 } else {
66 false
67 }
68 }
69
70 #[doc(hidden)]
71 pub fn set_size(&self, size: impl Into<i_slint_core::api::WindowSize>) {
75 self.window.set_size(size);
76 }
77}
78
79impl WindowAdapter for MinimalSoftwareWindow {
80 fn window(&self) -> &Window {
81 &self.window
82 }
83
84 fn renderer(&self) -> &dyn Renderer {
85 &self.renderer
86 }
87
88 fn size(&self) -> i_slint_core::api::PhysicalSize {
89 self.size.get()
90 }
91 fn set_size(&self, size: i_slint_core::api::WindowSize) {
92 let sf = self.window.scale_factor();
93 self.size.set(size.to_physical(sf));
94 let logical_size = size.to_logical(sf);
95 self.window
96 .dispatch_event(i_slint_core::platform::WindowEvent::Resized { size: logical_size });
97 }
98
99 fn request_redraw(&self) {
100 self.needs_redraw.set(true);
101 }
102}
103
104impl core::ops::Deref for MinimalSoftwareWindow {
105 type Target = Window;
106 fn deref(&self) -> &Self::Target {
107 &self.window
108 }
109}
110
111#[test]
112fn test_empty_window() {
113 let msw = MinimalSoftwareWindow::new(RepaintBufferType::NewBuffer);
120 msw.window().request_redraw();
121 let mut region = None;
122 let render_called = msw.draw_if_needed(|renderer| {
123 let mut buffer = i_slint_core::graphics::SharedPixelBuffer::<
124 i_slint_core::graphics::Rgb8Pixel,
125 >::new(100, 100);
126 let stride = buffer.width() as usize;
127 region = Some(renderer.render(buffer.make_mut_slice(), stride));
128 });
129 assert!(render_called);
130 let region = region.unwrap();
131 assert_eq!(region.bounding_box_size(), i_slint_core::api::PhysicalSize::default());
132 assert_eq!(region.bounding_box_origin(), i_slint_core::api::PhysicalPosition::default());
133}