use std::time::{Duration, Instant};
use windows::Win32::Foundation::HWND;
use crate::common::WindowId;
use crate::registry::hooks::{
float_hwnds_snapshot, float_tracking_active, is_float_hwnd, set_float_tracking_active,
};
use crate::registry::types::{FloatingState, WindowState};
use crate::registry::win32 as registry_win32;
use super::borders::float_border_rect;
use super::types::FlowWM;
impl FlowWM {
pub(super) fn on_float_location_changed(&mut self, hwnd: isize) {
if !float_tracking_active() {
return;
}
if !is_float_hwnd(hwnd) {
return;
}
self.store_float_rect(hwnd);
}
fn store_float_rect(&mut self, hwnd: isize) {
let hwnd_handle = HWND(hwnd as *mut _);
let window_rect = match registry_win32::get_window_rect(hwnd_handle) {
Ok(r) => r,
Err(e) => {
log::debug!("float location: GetWindowRect failed for {hwnd}: {e}");
return;
}
};
let Some(window) = self.registry.get_window(hwnd_handle) else {
return;
};
if !matches!(
window.state,
WindowState::Floating(FloatingState::Active { .. })
) {
return;
}
let invisible_bounds = window.invisible_bounds;
let visible_rect = invisible_bounds.window_to_visible(window_rect);
let wid = WindowId(hwnd);
let border_rect = float_border_rect(
visible_rect,
self.config.borders.thickness,
self.config.borders.overlap,
);
if !self.active_workspace().floating.contains(wid) {
return;
}
self.active_workspace_mut().floating.add(wid, visible_rect);
if let Some(win) = self.registry.get_window_mut(hwnd_handle) {
win.state = WindowState::Floating(FloatingState::Active { rect: visible_rect });
if let Some(border) = win.border.as_ref() {
border.set_geometry(border_rect);
}
}
log::trace!(
"float location: hwnd={hwnd} stored visible rect ({},{},{},{})",
visible_rect.x,
visible_rect.y,
visible_rect.width,
visible_rect.height
);
}
pub(super) fn arm_float_tracking_suppression(&mut self) {
set_float_tracking_active(false);
const RESUME_EPSILON_MS: u64 = 16;
let duration_ms = u64::from(self.config.animation.duration_ms);
self.float_resume_deadline =
Some(Instant::now() + Duration::from_millis(duration_ms + RESUME_EPSILON_MS));
log::debug!(
"float tracking suppressed: resume in {} ms ({} ms duration + {} ms epsilon)",
duration_ms + RESUME_EPSILON_MS,
duration_ms,
RESUME_EPSILON_MS,
);
}
pub(super) fn maybe_resume_float_tracking(&mut self) {
let Some(deadline) = self.float_resume_deadline else {
return;
};
if Instant::now() < deadline {
return;
}
let hwnds = float_hwnds_snapshot();
log::debug!(
"float tracking resume: polling {} float window(s) before re-enabling",
hwnds.len(),
);
for hwnd in hwnds {
self.store_float_rect(hwnd);
}
set_float_tracking_active(true);
self.float_resume_deadline = None;
log::debug!("float tracking resumed");
}
}