74 lines
2.4 KiB
Rust
74 lines
2.4 KiB
Rust
//! Persistenter Zustand unter `%APPDATA%\VitosUpdater` (Phase 1: Fensterposition und -größe).
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Gespeicherte Fenstergeometrie in physischen Pixeln.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct WindowState {
|
|
pub x: i32,
|
|
pub y: i32,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub maximized: bool,
|
|
}
|
|
|
|
fn file(dir: &Path) -> PathBuf {
|
|
dir.join("window.json")
|
|
}
|
|
|
|
/// Lädt die gespeicherte Fenstergeometrie. Fehlt die Datei oder ist sie defekt, ist das Ergebnis `None`.
|
|
pub fn load_window_state(dir: &Path) -> Option<WindowState> {
|
|
let text = std::fs::read_to_string(file(dir)).ok()?;
|
|
serde_json::from_str(&text).ok()
|
|
}
|
|
|
|
/// Speichert die Fenstergeometrie atomar (Schreiben in temporäre Datei, dann Umbenennen).
|
|
pub fn save_window_state(dir: &Path, state: &WindowState) -> std::io::Result<()> {
|
|
std::fs::create_dir_all(dir)?;
|
|
let tmp = dir.join("window.json.tmp");
|
|
std::fs::write(&tmp, serde_json::to_string_pretty(state)?)?;
|
|
std::fs::rename(tmp, file(dir))
|
|
}
|
|
|
|
/// Prüft, ob ein Fensterrechteck ein Monitorrechteck `(x, y, breite, höhe)` ausreichend überlappt.
|
|
pub fn is_visible_on(state: &WindowState, monitors: &[(i32, i32, u32, u32)]) -> bool {
|
|
const MIN_VISIBLE: i64 = 120;
|
|
monitors.iter().any(|&(mx, my, mw, mh)| {
|
|
let left = i64::from(state.x.max(mx));
|
|
let top = i64::from(state.y.max(my));
|
|
let right = (i64::from(state.x) + i64::from(state.width)).min(i64::from(mx) + i64::from(mw));
|
|
let bottom = (i64::from(state.y) + i64::from(state.height)).min(i64::from(my) + i64::from(mh));
|
|
right - left >= MIN_VISIBLE && bottom - top >= MIN_VISIBLE
|
|
})
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn state(x: i32, y: i32) -> WindowState {
|
|
WindowState { x, y, width: 1280, height: 800, maximized: false }
|
|
}
|
|
|
|
#[test]
|
|
fn visible_on_primary_monitor() {
|
|
assert!(is_visible_on(&state(100, 100), &[(0, 0, 1920, 1080)]));
|
|
}
|
|
|
|
#[test]
|
|
fn offscreen_after_monitor_removed() {
|
|
assert!(!is_visible_on(&state(2500, 100), &[(0, 0, 1920, 1080)]));
|
|
}
|
|
|
|
#[test]
|
|
fn roundtrip() {
|
|
let dir = std::env::temp_dir().join("vitosupdater-test-window");
|
|
let s = state(10, 20);
|
|
save_window_state(&dir, &s).unwrap();
|
|
assert_eq!(load_window_state(&dir), Some(s));
|
|
let _ = std::fs::remove_dir_all(dir);
|
|
}
|
|
}
|