1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// scheduler.rs was retired originally from https://github.com/alacritty/alacritty/blob/e35e5ad14fce8456afdd89f2b392b9924bb27471/alacritty/src/scheduler.rs
// which is licensed under Apache 2.0 license.
use crate::event::EventPayload;
use std::collections::VecDeque;
use std::time::{Duration, Instant};
use rio_window::event_loop::EventLoopProxy;
/// ID uniquely identifying a timer.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TimerId {
topic: Topic,
id: usize,
}
impl TimerId {
pub fn new(topic: Topic, id: usize) -> Self {
Self { topic, id }
}
}
/// Available timer topics.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Topic {
Render,
RenderRoute,
UpdateConfig,
CursorBlinking,
UpdateTitles,
SelectionScrolling,
}
/// Event scheduled to be emitted at a specific time.
#[derive(Debug)]
pub struct Timer {
pub deadline: Instant,
pub event: EventPayload,
pub id: TimerId,
interval: Option<Duration>,
}
/// Scheduler tracking all pending timers.
pub struct Scheduler {
timers: VecDeque<Timer>,
event_proxy: EventLoopProxy<EventPayload>,
}
impl Scheduler {
pub fn new(event_proxy: EventLoopProxy<EventPayload>) -> 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<Instant> {
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.front().map(|timer| timer.deadline)
}
/// Schedule a new event.
pub fn schedule(
&mut self,
event: EventPayload,
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(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<Timer> {
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 tab.
///
/// This must be called when a tab is removed to ensure that timers on intervals do not
/// stick around forever and cause a memory leak.
pub fn unschedule_window(&mut self, id: usize) {
self.timers.retain(|timer| timer.id.id != id);
}
}