lumen_runtime/
window_state.rs1use serde::{Deserialize, Serialize};
18use std::path::PathBuf;
19
20#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
24pub struct WindowState {
25 pub position: Option<[i32; 2]>,
28 pub size: Option<[u32; 2]>,
30 pub maximized: bool,
32}
33
34pub fn state_path(app_id: &str) -> Option<PathBuf> {
39 let base = state_dir()?;
40 Some(base.join("lumen").join(app_id).join("window-state.toml"))
41}
42
43fn state_dir() -> Option<PathBuf> {
44 #[cfg(target_os = "linux")]
45 {
46 if let Ok(d) = std::env::var("XDG_STATE_HOME")
47 && !d.is_empty()
48 {
49 return Some(PathBuf::from(d));
50 }
51 std::env::var("HOME").ok().map(|h| {
52 let mut p = PathBuf::from(h);
53 p.push(".local");
54 p.push("state");
55 p
56 })
57 }
58 #[cfg(target_os = "macos")]
59 {
60 std::env::var("HOME").ok().map(|h| {
61 let mut p = PathBuf::from(h);
62 p.push("Library");
63 p.push("Application Support");
64 p
65 })
66 }
67 #[cfg(target_os = "windows")]
68 {
69 std::env::var("LOCALAPPDATA").ok().map(PathBuf::from)
70 }
71 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
72 {
73 None
74 }
75}
76
77pub fn load(app_id: &str) -> WindowState {
81 let Some(path) = state_path(app_id) else {
82 return WindowState::default();
83 };
84 match std::fs::read_to_string(&path) {
85 Ok(src) => toml::from_str(&src).unwrap_or_default(),
86 Err(_) => WindowState::default(),
87 }
88}
89
90pub fn save(app_id: &str, state: &WindowState) {
93 let Some(path) = state_path(app_id) else {
94 return;
95 };
96 if let Some(parent) = path.parent()
97 && let Err(e) = std::fs::create_dir_all(parent)
98 {
99 eprintln!("lumenc: window-state mkdir failed: {e}");
100 return;
101 }
102 let body = match toml::to_string_pretty(state) {
103 Ok(s) => s,
104 Err(e) => {
105 eprintln!("lumenc: window-state serialize failed: {e}");
106 return;
107 }
108 };
109 if let Err(e) = std::fs::write(&path, body) {
110 eprintln!("lumenc: window-state write failed: {e}");
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn save_then_load_round_trips() {
120 let app_id = "lumenc-window-state-test";
121 let state = WindowState {
122 position: Some([100, 200]),
123 size: Some([1024, 768]),
124 maximized: false,
125 };
126 save(app_id, &state);
127 let loaded = load(app_id);
128 assert_eq!(loaded.position, Some([100, 200]));
129 assert_eq!(loaded.size, Some([1024, 768]));
130 assert!(!loaded.maximized);
131 }
132}