use crate::tab::Tab;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use tokio::runtime::Runtime;
impl Tab {
pub fn start_refresh_task(
&mut self,
runtime: Arc<Runtime>,
window: Arc<winit::window::Window>,
active_fps: u32,
inactive_fps: u32,
) {
let terminal_clone = Arc::clone(&self.terminal);
let is_active = Arc::clone(&self.is_active);
let active_interval_ms = (1000 / active_fps.max(1)) as u64;
let inactive_interval_ms = (1000 / inactive_fps.max(1)) as u64;
let handle = runtime.spawn(async move {
let mut last_gen = 0u64;
let mut was_running: Option<bool> = None;
let mut idle_streak = 0u32;
const MAX_INACTIVE_IDLE_INTERVAL_MS: u64 = 250;
loop {
let is_active_now = is_active.load(Ordering::Relaxed);
let interval_ms = if is_active_now {
active_interval_ms
} else if idle_streak > 0 {
(inactive_interval_ms << idle_streak.min(4)).min(MAX_INACTIVE_IDLE_INTERVAL_MS)
} else {
inactive_interval_ms
};
tokio::time::sleep(tokio::time::Duration::from_millis(interval_ms)).await;
let should_redraw = if let Ok(term) = terminal_clone.try_read() {
let current_gen = term.update_generation();
let gen_changed = current_gen > last_gen;
if gen_changed {
last_gen = current_gen;
}
let running = term.poll_liveness();
let died = refresh_redraw_on_death(&mut was_running, running);
gen_changed || died
} else {
false
};
if should_redraw {
idle_streak = 0;
window.request_redraw();
} else if is_active_now {
idle_streak = 0;
} else {
idle_streak = idle_streak.saturating_add(1);
}
}
});
self.refresh_task = Some(handle);
}
pub fn stop_refresh_task(&mut self) {
if let Some(handle) = self.refresh_task.take() {
handle.abort();
}
}
}
fn refresh_redraw_on_death(was_running: &mut Option<bool>, running: bool) -> bool {
let died = *was_running == Some(true) && !running;
*was_running = Some(running);
died
}
#[cfg(test)]
mod tests {
use super::refresh_redraw_on_death;
#[test]
fn death_edge_fires_once_and_not_on_first_poll() {
let mut state = None;
assert!(!refresh_redraw_on_death(&mut state, false));
assert_eq!(state, Some(false));
assert!(!refresh_redraw_on_death(&mut state, false));
assert!(!refresh_redraw_on_death(&mut state, false));
assert!(!refresh_redraw_on_death(&mut state, true));
assert!(refresh_redraw_on_death(&mut state, false));
}
}