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:
+39
-31
@@ -76,24 +76,41 @@ impl Blend for Colors {
|
||||
|
||||
pub struct Theme {
|
||||
colors: Animation<Colors>,
|
||||
// where the colours are going; a reread that lands on them again starts no fade
|
||||
target: Colors,
|
||||
}
|
||||
|
||||
impl Service for Theme {
|
||||
fn new() -> Self {
|
||||
Self { colors: Animation::new(fallback()) }
|
||||
Self { colors: Animation::new(fallback()), target: fallback() }
|
||||
}
|
||||
|
||||
/*
|
||||
* waits on the kernel instead of polling: amane::watch_file watches the folder, so
|
||||
* matugen writing a new file and renaming it over the old one is seen too.
|
||||
* config.toml on its own thread, the theme here; either change re-reads both
|
||||
* config.toml on its own thread, the theme here. a changed config.toml redraws
|
||||
* everything; the colours fade only if it changed them (its fallback colours)
|
||||
*/
|
||||
fn listen() {
|
||||
reload();
|
||||
reload(true);
|
||||
|
||||
thread::spawn(|| follow("config.toml"));
|
||||
thread::spawn(|| {
|
||||
for _ in amane::watch_file(&config_file("config.toml").to_string_lossy()) {
|
||||
// one save can arrive as several writes: let it finish, then read once
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
|
||||
follow("theme");
|
||||
if config::reread() {
|
||||
touch();
|
||||
reload(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for _ in amane::watch_file(&config_file("theme").to_string_lossy()) {
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
|
||||
reload(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,41 +119,26 @@ pub fn touch() {
|
||||
let _ = Theme::write();
|
||||
}
|
||||
|
||||
// what was read last, (theme, config.toml); none until the first read
|
||||
static LAST: Mutex<Option<(String, String)>> = Mutex::new(None);
|
||||
// the theme file as read last; none until the first read
|
||||
static LAST: Mutex<Option<String>> = Mutex::new(None);
|
||||
|
||||
fn follow(name: &str) {
|
||||
for _ in amane::watch_file(&config_file(name).to_string_lossy()) {
|
||||
// one save can arrive as several writes: let it finish, then read once
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
|
||||
reload();
|
||||
}
|
||||
}
|
||||
|
||||
// a deleted theme file sends no event: the defaults come back at the next start
|
||||
fn reload() {
|
||||
let read = (read("theme"), read("config.toml"));
|
||||
/*
|
||||
* the theme file, read anew; `again` also when it's unchanged, for new fallback colours.
|
||||
* a deleted theme file sends no event: the defaults come back at the next start
|
||||
*/
|
||||
fn reload(again: bool) {
|
||||
let theme = fs::read_to_string(config_file("theme")).unwrap_or_default();
|
||||
|
||||
let mut last = LAST.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
|
||||
// a write that changes nothing redraws nothing
|
||||
if last.as_ref() == Some(&read) {
|
||||
if last.as_ref() == Some(&theme) && !again {
|
||||
return;
|
||||
}
|
||||
|
||||
if last.as_ref().is_none_or(|(_, config)| *config != read.1) {
|
||||
config::apply_text(&read.1);
|
||||
}
|
||||
|
||||
// the colours at startup show at once, later changes cross-fade
|
||||
apply(&read.0, last.is_none());
|
||||
apply(&theme, last.is_none());
|
||||
|
||||
*last = Some(read);
|
||||
}
|
||||
|
||||
fn read(name: &str) -> String {
|
||||
fs::read_to_string(config_file(name)).unwrap_or_default()
|
||||
*last = Some(theme);
|
||||
}
|
||||
|
||||
// $XDG_CONFIG_HOME, or ~/.config
|
||||
@@ -178,10 +180,16 @@ fn apply(theme: &str, startup: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if !startup && Theme::read().target == colors {
|
||||
return;
|
||||
}
|
||||
|
||||
let fade = if startup { 0 } else { config::appearance::colors::transition_ms() };
|
||||
|
||||
let mut theme = Theme::write();
|
||||
|
||||
theme.target = colors;
|
||||
|
||||
// a change in the middle of a fade starts from the colours on screen now
|
||||
let now = theme.colors.value();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user