i_slint_backend_winit/
frame_throttle.rs1use std::rc::{Rc, Weak};
5
6use i_slint_core::timers::{Timer, TimerMode};
7
8use crate::winitwindowadapter::WinitWindowAdapter;
9
10pub fn create_frame_throttle(
11 window_adapter: Weak<WinitWindowAdapter>,
12 _is_wayland: bool,
13) -> Box<dyn FrameThrottle> {
14 if _is_wayland {
15 WinitBasedFrameThrottle::new(window_adapter)
16 } else {
17 TimerBasedFrameThrottle::new(window_adapter)
18 }
19}
20
21pub trait FrameThrottle {
22 fn request_throttled_redraw(&self);
23}
24
25struct TimerBasedFrameThrottle {
26 window_adapter: Weak<WinitWindowAdapter>,
27 timer: Rc<Timer>,
28}
29
30impl TimerBasedFrameThrottle {
31 fn new(window_adapter: Weak<WinitWindowAdapter>) -> Box<dyn FrameThrottle> {
32 Box::new(Self { window_adapter, timer: Rc::new(Timer::default()) })
33 }
34}
35
36impl FrameThrottle for TimerBasedFrameThrottle {
37 fn request_throttled_redraw(&self) {
38 if self.timer.running() {
39 return;
40 }
41 let refresh_interval_millihertz = self
42 .window_adapter
43 .upgrade()
44 .and_then(|adapter| adapter.winit_window())
45 .and_then(|winit_window| winit_window.current_monitor())
46 .and_then(|monitor| monitor.refresh_rate_millihertz())
47 .unwrap_or(60000) as u64;
48 let window_adapter = self.window_adapter.clone();
49 let timer = Rc::downgrade(&self.timer);
50 let interval =
51 std::time::Duration::from_millis((1000 * 1000) / refresh_interval_millihertz);
52 self.timer.start(TimerMode::Repeated, interval, move || {
53 redraw_now(&window_adapter);
54
55 let Some(timer) = timer.upgrade() else { return };
56 let Some(window_adapter) = window_adapter.upgrade() else { return };
57
58 let keep_running = window_adapter.pending_redraw();
59
60 if timer.running() {
61 if !keep_running {
62 timer.stop();
63 }
64 } else {
65 if keep_running {
66 timer.restart();
67 }
68 }
69 });
70 }
71}
72
73fn redraw_now(window_adapter: &Weak<WinitWindowAdapter>) {
74 let Some(winit_window) = window_adapter.upgrade().and_then(|adapter| adapter.winit_window())
75 else {
76 return;
77 };
78 winit_window.request_redraw();
79}
80
81struct WinitBasedFrameThrottle {
82 window_adapter: Weak<WinitWindowAdapter>,
83}
84
85impl WinitBasedFrameThrottle {
86 fn new(window_adapter: Weak<WinitWindowAdapter>) -> Box<dyn FrameThrottle> {
87 Box::new(Self { window_adapter })
88 }
89}
90
91impl FrameThrottle for WinitBasedFrameThrottle {
92 fn request_throttled_redraw(&self) {
93 redraw_now(&self.window_adapter)
94 }
95}