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
use std::{
borrow::Borrow,
sync::atomic::Ordering,
thread::{sleep, spawn, JoinHandle},
time::{Duration, Instant},
};
use crossbeam_channel::unbounded;
use display::Tui;
use super::{action::ViewAction, sender::Sender, View};
const MINIMUM_TICK_RATE: Duration = Duration::from_millis(20);
#[inline]
pub fn spawn_view_thread<T: Tui + Send + 'static>(mut view: View<T>) -> (Sender, JoinHandle<()>) {
let (sender, receiver) = unbounded();
let view_sender = Sender::new(sender.clone());
let refresh_thread_view_sender = view_sender.clone();
let view_render_slice = view_sender.clone_render_slice();
let crashed = view_sender.clone_poisoned();
let thread = spawn(move || {
let mut last_render_time = Instant::now() + MINIMUM_TICK_RATE;
let mut should_render = true;
for msg in receiver {
let mut err = false;
match msg {
ViewAction::Render => should_render = true,
ViewAction::Start => {
if view.start().is_err() {
err = true;
}
},
ViewAction::Stop => {
if view.end().is_err() {
err = true;
}
},
ViewAction::Refresh => {},
ViewAction::End => break,
}
if should_render && Instant::now() >= last_render_time {
last_render_time += MINIMUM_TICK_RATE;
should_render = false;
let render_slice = view_render_slice.lock();
if view.render(render_slice.borrow()).is_err() {
err = true;
}
}
if err {
crashed.store(true, Ordering::Release);
}
}
});
let _refresh_thread = spawn(move || {
let sleep_time = MINIMUM_TICK_RATE / 2;
let mut time = Instant::now();
while sender.send(ViewAction::Refresh).is_ok() {
loop {
sleep(time.saturating_duration_since(Instant::now()));
time += sleep_time;
if !refresh_thread_view_sender.is_paused() {
break;
}
}
}
});
(view_sender, thread)
}