use windows::Win32::Foundation::HWND;
use crate::borders::{Border, BorderState, BorderStyle, style_for_state};
use crate::common::Rect;
use crate::registry::types::{FloatingState, TilingState, WindowState};
use super::types::FlowWM;
pub(super) fn float_border_rect(visible_rect: Rect, thickness: u32, overlap: u32) -> Rect {
let outset = thickness as i32 - overlap as i32;
visible_rect.inset(-outset)
}
impl FlowWM {
pub(super) fn border_style_for(&self, hwnd: isize) -> Option<BorderStyle> {
let window = self.registry.get_window(HWND(hwnd as *mut _))?;
let is_focused = self.registry.focused() == Some(crate::common::WindowId(hwnd));
let state = match window.state {
WindowState::Tiling(TilingState::Active { .. }) => {
if is_focused {
BorderState::Focused
} else {
BorderState::Unfocused
}
}
WindowState::Floating(FloatingState::Active { .. }) => {
if is_focused {
BorderState::Focused
} else {
BorderState::Floating
}
}
WindowState::Tiling(TilingState::Minimized | TilingState::Hidden)
| WindowState::Floating(FloatingState::Minimized | FloatingState::Hidden)
| WindowState::Ignored(_) => return None,
};
let mut style = style_for_state(&self.config.borders, state);
style.corner_preference = window
.border
.as_ref()
.map(|b| b.corner_preference())
.unwrap_or_else(|| {
crate::registry::win32::get_window_corner_preference(HWND(hwnd as *mut _))
.unwrap_or_default()
});
Some(style)
}
pub(super) fn refresh_border_for(&mut self, hwnd: isize) {
let desired = self.border_style_for(hwnd);
let (thickness, overlap) = (self.config.borders.thickness, self.config.borders.overlap);
let Some(window) = self.registry.get_window_mut(HWND(hwnd as *mut _)) else {
return;
};
match desired {
None => {
window.border = None;
}
Some(style) => {
if let Some(border) = window.border.as_ref() {
let geo = match &window.state {
WindowState::Floating(FloatingState::Active { rect }) => {
Some(float_border_rect(*rect, thickness, overlap))
}
_ => None,
};
border.seat_above_target();
if let Some(rect) = geo {
border.set_geometry(rect);
}
border.set_style(style);
} else {
let current_rect = match &window.state {
WindowState::Tiling(TilingState::Active { .. }) => window.tiled_rect,
WindowState::Floating(FloatingState::Active { rect }) => {
Some(float_border_rect(*rect, thickness, overlap))
}
_ => None,
};
match Border::create(style, hwnd) {
Ok(b) => {
if let Some(rect) = current_rect {
b.set_geometry(rect);
}
window.border = Some(b);
}
Err(e) => {
log::error!("failed to create border overlay for hwnd {hwnd}: {e}");
}
}
}
}
}
}
pub(super) fn refresh_all_border_styles(&mut self) {
let snapshot: Vec<isize> = self.registry.windows().map(|w| w.hwnd.0 as isize).collect();
for raw in snapshot {
self.refresh_border_for(raw);
}
}
}