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
//! Where overlays sit in the frame being drawn, for native views over the
//! window (a webview) that nothing gpui paints can cover.
//!
//! A cover is a rectangle recorded during prepaint, stamped with its place in
//! the frame's prepaint order. gpui prepaints an element that paints over
//! another after that other one: a later sibling, a `deferred` layer, the
//! tooltip, the drag preview. So a native view takes a [`mark`] in its own
//! prepaint and asks [`covered`] in its paint, when every cover of the frame
//! is recorded.
//!
//! [`crate::surface`]'s cards and the dialog and sheet scrims record
//! themselves. Anything else an app floats puts a [`cover`] in it.
//!
//! A cover in a view gpui reuses from the last frame (`AnyView::cached`) is not
//! recorded.
use std::{
collections::HashMap,
sync::atomic::{AtomicU64, Ordering},
};
use gpui::{App, Bounds, Global, IntoElement, Pixels, Styled, Window, WindowId, canvas};
/// A place in a frame's prepaint order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Mark(u64);
/// An element filling its parent, recorded as a cover. Its parent's box is
/// what it records, so it goes in the overlay's outermost box.
pub fn cover() -> impl IntoElement {
canvas(record, |_, _, _, _| {}).absolute().size_full()
}
/// Records `bounds` as covered. Call it from prepaint.
pub fn record(bounds: Bounds<Pixels>, window: &mut Window, cx: &mut App) {
let bounds = bounds.intersect(&window.content_mask().bounds);
let mark = next();
let id = window.window_handle().window_id();
let covers = cx.default_global::<Covers>();
if let Some(frame) = covers.0.get_mut(&id) {
frame.push((mark, bounds));
return;
}
covers.0.insert(id, vec![(mark, bounds)]);
// Runs before the next frame is drawn.
window.on_next_frame(move |_, cx| {
cx.default_global::<Covers>().0.remove(&id);
});
}
/// The current place in the prepaint order. Call it from prepaint.
pub fn mark() -> Mark {
next()
}
/// Whether a cover recorded after `mark` in this frame overlaps `bounds`. Call
/// it from paint.
pub fn covered(mark: Mark, bounds: Bounds<Pixels>, window: &Window, cx: &App) -> bool {
cx.try_global::<Covers>()
.and_then(|covers| covers.0.get(&window.window_handle().window_id()))
.is_some_and(|frame| {
frame
.iter()
.any(|(at, cover)| *at > mark && cover.intersects(&bounds))
})
}
fn next() -> Mark {
static NEXT: AtomicU64 = AtomicU64::new(1);
Mark(NEXT.fetch_add(1, Ordering::Relaxed))
}
/// This frame's covers, per window.
#[derive(Default)]
struct Covers(HashMap<WindowId, Vec<(Mark, Bounds<Pixels>)>>);
impl Global for Covers {}