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
//! Cursor blink cadence tied to painted frames.
//!
//! Derived from Herdr (Apache-2.0).
use std::time::Duration;
use gpui_kit::{Context, Task};
/// Half period of the cursor blink.
const PHASE: Duration = Duration::from_millis(530);
/// Retained blink state for one terminal.
///
/// The next tick is scheduled from `sync`, which runs during paint, so a
/// terminal that is not painting (hidden, occluded, in an inactive window)
/// stops the cadence on its own instead of holding a free-running timer.
pub(crate) struct Blink {
pub(crate) visible: bool,
task: Option<Task<()>>,
}
impl Blink {
pub(crate) fn new() -> Self {
Self {
visible: true,
task: None,
}
}
pub(crate) fn stop(&mut self) {
self.task = None;
self.visible = true;
}
/// Called once per painted frame. Starts, continues or stops the cadence
/// to match whether the cursor should blink.
pub(crate) fn sync<T: 'static>(
&mut self,
blinking: bool,
cx: &mut Context<T>,
on_tick: fn(&mut T, &mut Context<T>),
) {
if !blinking {
self.stop();
return;
}
if self.task.is_some() {
return;
}
self.task = Some(cx.spawn(async move |view, cx| {
cx.background_executor().timer(PHASE).await;
let _ = view.update(cx, on_tick);
}));
}
/// Advance the phase. The next tick is scheduled by the following paint.
pub(crate) fn tick(&mut self) {
self.task = None;
self.visible = !self.visible;
}
}