//! Scheduler for emitting events at a specific time in the future. use std::collections::VecDeque; use std::time::{Duration, Instant}; use glutin::event_loop::EventLoopProxy; use glutin::window::WindowId; use crate::event::Event; /// ID uniquely identifying a timer. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TimerId { topic: Topic, window_id: WindowId, } impl TimerId { pub fn new(topic: Topic, window_id: WindowId) -> Self { Self { topic, window_id } } } /// Available timer topics. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Topic { SelectionScrolling, DelayedSearch, BlinkCursor, BlinkTimeout, } /// Event scheduled to be emitted at a specific time. pub struct Timer { pub deadline: Instant, pub event: Event, pub id: TimerId, interval: Option, } /// Scheduler tracking all pending timers. pub struct Scheduler { timers: VecDeque, event_proxy: EventLoopProxy, } impl Scheduler { pub fn new(event_proxy: EventLoopProxy) -> Self { Self { timers: VecDeque::new(), event_proxy } } /// Process all pending timers. /// /// If there are still timers pending after all ready events have been processed, the closest /// pending deadline will be returned. pub fn update(&mut self) -> Option { let now = Instant::now(); while !self.timers.is_empty() && self.timers[0].deadline <= now { if let Some(timer) = self.timers.pop_front() { // Automatically repeat the event. if let Some(interval) = timer.interval { self.schedule(timer.event.clone(), interval, true, timer.id); } let _ = self.event_proxy.send_event(timer.event); } } self.timers.get(0).map(|timer| timer.deadline) } /// Schedule a new event. pub fn schedule(&mut self, event: Event, interval: Duration, repeat: bool, timer_id: TimerId) { let deadline = Instant::now() + interval; // Get insert position in the schedule. let index = self .timers .iter() .position(|timer| timer.deadline > deadline) .unwrap_or_else(|| self.timers.len()); // Set the automatic event repeat rate. let interval = if repeat { Some(interval) } else { None }; self.timers.insert(index, Timer { interval, deadline, event, id: timer_id }); } /// Cancel a scheduled event. pub fn unschedule(&mut self, id: TimerId) -> Option { let index = self.timers.iter().position(|timer| timer.id == id)?; self.timers.remove(index) } /// Check if a timer is already scheduled. pub fn scheduled(&mut self, id: TimerId) -> bool { self.timers.iter().any(|timer| timer.id == id) } /// Remove all timers scheduled for a window. /// /// This must be called when a window is removed to ensure that timers on intervals do not /// stick around forever and cause a memory leak. pub fn unschedule_window(&mut self, window_id: WindowId) { self.timers.retain(|timer| timer.id.window_id != window_id); } }