New workspaces grow in; config saves don't redraw everything or race; media peek skips the player in front
- A workspace Hyprland makes for a switch (createworkspacev2) grows into the row over the slide instead of appearing at full size; the window keeps the full room meanwhile. - Every config.toml save restarted the colour Animation, and Animation::new runs its clock even from a colour to itself, so every window redrew for 0.4 s per save. The colours now only fade when they change. - The file watch could read config.toml halfway through the shell's own save and reset settings to their defaults. Saves and rereads share one lock, the file is written to a new file and renamed over, and the shell's own saves are skipped by the watch. - A song change or new player only pops the island when the focused window isn't that player's app (parse::same_app, tested).
This commit is contained in:
+52
-5
@@ -505,6 +505,17 @@ static VALUES: LazyLock<RwLock<HashMap<String, Value>>> = LazyLock::new(Default:
|
||||
// what was wrong in the file when it was last read, for the config window
|
||||
static ERRORS: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
|
||||
/*
|
||||
* config.toml as the shell last wrote or read it. every save and every reread holds
|
||||
* this lock, so the file watch can't read a save halfway or undo a change it raced
|
||||
* with (it once reset settings to their defaults that way), and skips the shell's own saves
|
||||
*/
|
||||
static WRITTEN: Mutex<String> = Mutex::new(String::new());
|
||||
|
||||
fn written() -> std::sync::MutexGuard<'static, String> {
|
||||
WRITTEN.lock().unwrap_or_else(PoisonError::into_inner)
|
||||
}
|
||||
|
||||
// ponytail: a lock and a hash lookup per call, a few hundred a frame; a snapshot struct if a profile ever shows it
|
||||
fn get<T: Setting>(path: &str, default: impl FnOnce() -> T) -> T {
|
||||
VALUES.read().unwrap_or_else(PoisonError::into_inner).get(path).and_then(T::read).unwrap_or_else(default)
|
||||
@@ -520,17 +531,37 @@ pub fn option(path: &str) -> Option<&'static Opt> {
|
||||
|
||||
// at startup: config.toml, or the first time, one made from the old shell.conf
|
||||
pub fn load() {
|
||||
let mut written = written();
|
||||
|
||||
let text = fs::read_to_string(file()).unwrap_or_else(|_| {
|
||||
migrate();
|
||||
|
||||
let text = render();
|
||||
|
||||
let _ = fs::write(file(), &text);
|
||||
let _ = write_file(&text);
|
||||
|
||||
text
|
||||
});
|
||||
|
||||
apply_text(&text);
|
||||
|
||||
*written = text;
|
||||
}
|
||||
|
||||
// config.toml changed on disk: a hand edit applies, the shell's own saves are skipped. whether it applied
|
||||
pub fn reread() -> bool {
|
||||
let mut written = written();
|
||||
let text = fs::read_to_string(file()).unwrap_or_default();
|
||||
|
||||
if text == *written {
|
||||
return false;
|
||||
}
|
||||
|
||||
apply_text(&text);
|
||||
|
||||
*written = text;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// shell.conf's four settings, moved to their places in config.toml
|
||||
@@ -667,26 +698,42 @@ pub fn override_of(path: &str) -> Option<Value> {
|
||||
pub fn set(path: &str, value: Value) -> Result<(), String> {
|
||||
check(path, &value)?;
|
||||
|
||||
let mut written = written();
|
||||
|
||||
VALUES.write().unwrap_or_else(PoisonError::into_inner).insert(path.to_string(), value);
|
||||
|
||||
save()
|
||||
save(&mut written)
|
||||
}
|
||||
|
||||
// back to the default (a Hyprland option: back to Hyprland's own config)
|
||||
pub fn reset(path: &str) -> Result<(), String> {
|
||||
let mut written = written();
|
||||
|
||||
VALUES.write().unwrap_or_else(PoisonError::into_inner).remove(path);
|
||||
|
||||
save()
|
||||
save(&mut written)
|
||||
}
|
||||
|
||||
fn save() -> Result<(), String> {
|
||||
fs::write(file(), render()).map_err(|error| format!("couldn't write {}: {error}", file().display()))?;
|
||||
fn save(written: &mut String) -> Result<(), String> {
|
||||
let text = render();
|
||||
|
||||
write_file(&text).map_err(|error| format!("couldn't write {}: {error}", file().display()))?;
|
||||
|
||||
*written = text;
|
||||
|
||||
theme::touch();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// whole or not at all: a new file renamed over the old, so no reader sees half of it
|
||||
fn write_file(text: &str) -> std::io::Result<()> {
|
||||
let fresh = file().with_extension("toml.new");
|
||||
|
||||
fs::write(&fresh, text)?;
|
||||
fs::rename(&fresh, file())
|
||||
}
|
||||
|
||||
// config.toml as the shell writes it: every setting with its help, then the Hyprland options set here
|
||||
pub fn render() -> String {
|
||||
let mut out = String::from(
|
||||
|
||||
Reference in New Issue
Block a user