Skip to main content

backdrop_blur_core/
liveness.rs

1//! Backdrop freshness as a *typed adapter obligation*, not a footnote. Whether a blurred
2//! backdrop stays correct as content behind it changes does **not** generalize across toolkits
3//! (egui is reactive-by-default: it does not repaint when behind-surface content changes, and
4//! has no region invalidation — "fresh as long as the host repaints" can be *zero* frames). So
5//! the adapter must state its intent with a domain type rather than assume the host repaints
6//! (DESIGN §4.6).
7
8use std::time::Duration;
9
10/// How often the frosted surface's backdrop must be re-grabbed and re-blurred. The adapter —
11/// not core — drives the host's `request_repaint` from this; core only names the obligation.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RepaintPolicy {
14    /// The backdrop is over still content (dialog, tooltip): grab once, never refresh. The
15    /// default — cheapest, and correct whenever the content behind the surface is static.
16    ///
17    /// `Static` means the adapter does not *drive* repaints for this surface — **not** that the
18    /// surface stops compositing. If the host repaints for any other reason (input, animation
19    /// elsewhere, another surface's `Live`), the frost still re-grabs and re-composites that frame.
20    /// It is "don't request frames," not "don't paint."
21    Static,
22    /// The backdrop is over animating content: refresh every frame. Names an idle-power cost
23    /// and is **required** for glass over moving content (otherwise the blur goes stale).
24    Live,
25    /// Refresh periodically — for content that changes on a known cadence.
26    Bounded(Duration),
27}
28
29impl Default for RepaintPolicy {
30    /// `Static` — the safe, cheap default for the common dialog/tooltip-over-still-content case.
31    fn default() -> Self {
32        Self::Static
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    #[test]
41    fn default_repaint_policy_is_static() {
42        assert_eq!(RepaintPolicy::default(), RepaintPolicy::Static);
43    }
44
45    #[test]
46    fn bounded_policy_carries_its_interval() {
47        let policy = RepaintPolicy::Bounded(Duration::from_millis(250));
48        assert_eq!(policy, RepaintPolicy::Bounded(Duration::from_millis(250)));
49        assert_ne!(policy, RepaintPolicy::Bounded(Duration::from_millis(500)));
50    }
51}