use teksilo_core::ObserverHandle;
use teksilo_core::{Signal, WindowConfig, WindowState};
use teksilo_settings::{PerWindowState, WindowStateService};
const DEFAULT_MIN_SIZE: (u32, u32) = (320, 240);
const FALLBACK_WORK_AREA: (u32, u32) = (1920, 1080);
fn monitor_work_area(target: &winit::event_loop::ActiveEventLoop) -> (u32, u32) {
if let Some(monitor) = target.primary_monitor() {
let scale = monitor.scale_factor();
let logical: winit::dpi::LogicalSize<u32> = monitor.size().to_logical(scale);
return (logical.width.max(1), logical.height.max(1));
}
if let Some(monitor) = target.available_monitors().next() {
let scale = monitor.scale_factor();
let logical: winit::dpi::LogicalSize<u32> = monitor.size().to_logical(scale);
return (logical.width.max(1), logical.height.max(1));
}
FALLBACK_WORK_AREA
}
pub(crate) fn apply_restored_geometry(
config: &mut WindowConfig,
service: &WindowStateService,
target: &winit::event_loop::ActiveEventLoop,
) {
let Some(label) = config.string_id.clone() else {
return;
};
let Some(saved) = service.state_for(&label) else {
return;
};
let min_size = config.min_size.unwrap_or(DEFAULT_MIN_SIZE);
let work_area = monitor_work_area(target);
let sanitized = saved.sanitize(min_size, work_area);
config.size = (sanitized.width, sanitized.height);
config.position = Some((sanitized.x, sanitized.y));
config.initial_placement = sanitized.placement;
}
pub(crate) fn install_persist_observers(
state: &WindowState,
service: WindowStateService,
label: String,
) -> Vec<ObserverHandle> {
let mut handles = Vec::with_capacity(3);
record_snapshot(&service, state, &label);
let placement = state.placement().clone();
let size = state.size().clone();
let position = state.position().clone();
handles.push(observe(
state.size(),
service.clone(),
placement.clone(),
size.clone(),
position.clone(),
label.clone(),
));
handles.push(observe(
state.position(),
service.clone(),
placement.clone(),
size.clone(),
position.clone(),
label.clone(),
));
handles.push(observe(
state.placement(),
service,
placement,
size,
position,
label,
));
handles
}
fn observe<T: Clone + 'static>(
signal: &Signal<T>,
service: WindowStateService,
placement: Signal<teksilo_core::WindowPlacement>,
size: Signal<(u32, u32)>,
position: Signal<(i32, i32)>,
label: String,
) -> ObserverHandle {
signal.observe(move |_| {
let (w, h) = size.get();
let (x, y) = position.get();
let placement = placement.get();
let _ = service.record(PerWindowState {
label: label.clone(),
x,
y,
width: w,
height: h,
placement,
});
})
}
fn record_snapshot(service: &WindowStateService, state: &WindowState, label: &str) {
let (w, h) = state.size().get();
let (x, y) = state.position().get();
let placement = state.placement().get();
let _ = service.record(PerWindowState {
label: label.to_string(),
x,
y,
width: w,
height: h,
placement,
});
}