use super::placement::Area;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Foreground {
Nobody,
Ours,
Shell,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Blur {
pub button_down: bool,
pub foreground: Foreground,
pub guarded: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Verdict {
Hide,
Keep(&'static str),
}
pub(crate) fn verdict(blur: Blur) -> Verdict {
match blur.foreground {
Foreground::Ours => Verdict::Keep("focus stayed in this process"),
Foreground::Shell if !blur.button_down => Verdict::Keep("taskbar activated itself"),
_ if blur.guarded && !blur.button_down => Verdict::Keep("guarded: our own show/focus"),
_ => Verdict::Hide,
}
}
pub(crate) const TOGGLE_WINDOW_MS: u128 = 600;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct PressHide {
pub x: i32,
pub y: i32,
}
pub(crate) fn is_toggle_close(hide: Option<PressHide>, elapsed_ms: u128, icon: Area) -> bool {
hide.is_some_and(|press| {
elapsed_ms <= TOGGLE_WINDOW_MS
&& press.x >= icon.x
&& press.x < icon.x + icon.width
&& press.y >= icon.y
&& press.y < icon.y + icon.height
})
}
#[cfg(test)]
mod tests {
use super::*;
const ICON: Area = Area {
x: 3154,
y: 1392,
width: 32,
height: 48,
};
fn blur(foreground: Foreground, button_down: bool, guarded: bool) -> Blur {
Blur {
button_down,
foreground,
guarded,
}
}
#[test]
fn a_click_on_another_window_closes_the_popover() {
assert_eq!(verdict(blur(Foreground::Other, true, false)), Verdict::Hide);
assert_eq!(
verdict(blur(Foreground::Other, false, false)),
Verdict::Hide
);
}
#[test]
fn a_click_right_after_opening_closes_it_despite_the_guard() {
assert_eq!(verdict(blur(Foreground::Other, true, true)), Verdict::Hide);
assert_eq!(verdict(blur(Foreground::Shell, true, true)), Verdict::Hide);
assert_eq!(verdict(blur(Foreground::Nobody, true, true)), Verdict::Hide);
}
#[test]
fn the_guard_still_swallows_the_bounce_of_our_own_show() {
assert!(matches!(
verdict(blur(Foreground::Other, false, true)),
Verdict::Keep(_)
));
assert!(matches!(
verdict(blur(Foreground::Nobody, false, true)),
Verdict::Keep(_)
));
}
#[test]
fn focus_moving_inside_this_process_never_closes() {
assert!(matches!(
verdict(blur(Foreground::Ours, true, false)),
Verdict::Keep(_)
));
}
#[test]
fn the_taskbar_activating_itself_keeps_it_but_a_click_on_it_does_not() {
assert!(matches!(
verdict(blur(Foreground::Shell, false, false)),
Verdict::Keep(_)
));
assert_eq!(verdict(blur(Foreground::Shell, true, false)), Verdict::Hide);
}
#[test]
fn the_icon_mouse_up_after_a_press_on_it_is_a_toggle_close() {
let press = Some(PressHide { x: 3170, y: 1416 });
assert!(is_toggle_close(press, 120, ICON));
}
#[test]
fn a_late_or_elsewhere_press_does_not_swallow_the_next_click() {
let press = Some(PressHide { x: 3170, y: 1416 });
assert!(!is_toggle_close(press, TOGGLE_WINDOW_MS + 1, ICON));
let elsewhere = Some(PressHide { x: 1200, y: 700 });
assert!(!is_toggle_close(elsewhere, 120, ICON));
assert!(!is_toggle_close(None, 0, ICON));
}
}