1use std::{
18 collections::HashMap,
19 sync::atomic::{AtomicU64, Ordering},
20};
21
22use gpui::{App, Bounds, Global, IntoElement, Pixels, Styled, Window, WindowId, canvas};
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
26pub struct Mark(u64);
27
28pub fn cover() -> impl IntoElement {
31 canvas(record, |_, _, _, _| {}).absolute().size_full()
32}
33
34pub fn record(bounds: Bounds<Pixels>, window: &mut Window, cx: &mut App) {
36 let bounds = bounds.intersect(&window.content_mask().bounds);
37 let mark = next();
38 let id = window.window_handle().window_id();
39 let covers = cx.default_global::<Covers>();
40 if let Some(frame) = covers.0.get_mut(&id) {
41 frame.push((mark, bounds));
42 return;
43 }
44 covers.0.insert(id, vec![(mark, bounds)]);
45 window.on_next_frame(move |_, cx| {
47 cx.default_global::<Covers>().0.remove(&id);
48 });
49}
50
51pub fn mark() -> Mark {
53 next()
54}
55
56pub fn covered(mark: Mark, bounds: Bounds<Pixels>, window: &Window, cx: &App) -> bool {
59 cx.try_global::<Covers>()
60 .and_then(|covers| covers.0.get(&window.window_handle().window_id()))
61 .is_some_and(|frame| {
62 frame
63 .iter()
64 .any(|(at, cover)| *at > mark && cover.intersects(&bounds))
65 })
66}
67
68fn next() -> Mark {
69 static NEXT: AtomicU64 = AtomicU64::new(1);
70 Mark(NEXT.fetch_add(1, Ordering::Relaxed))
71}
72
73#[derive(Default)]
75struct Covers(HashMap<WindowId, Vec<(Mark, Bounds<Pixels>)>>);
76
77impl Global for Covers {}