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:
+33
-2
@@ -56,6 +56,9 @@ pub struct Edge {
|
||||
pops: HashMap<(Part, String), Instant>,
|
||||
switched: HashMap<String, (i64, Instant)>,
|
||||
|
||||
// workspaces hyprland made a moment ago (by switching to a new one), by id
|
||||
created: HashMap<i64, Instant>,
|
||||
|
||||
// the monitor whose top edge the pointer rests on, and whether it's over a part of the bar
|
||||
at_edge: Option<String>,
|
||||
over_bar: bool,
|
||||
@@ -84,6 +87,16 @@ impl Service for Edge {
|
||||
|
||||
let event = line.split(">>").next().unwrap_or("");
|
||||
|
||||
// createworkspacev2>>ID,NAME
|
||||
if event == "createworkspacev2"
|
||||
&& let Some(id) = line.split(">>").nth(1).and_then(|data| data.split(',').next()).and_then(|id| id.parse::<i64>().ok())
|
||||
{
|
||||
let mut edge = Edge::write();
|
||||
|
||||
edge.created.retain(|_, at| at.elapsed().as_secs_f32() < peeks::switch_s());
|
||||
edge.created.insert(id, Instant::now());
|
||||
}
|
||||
|
||||
if matches!(
|
||||
event.trim_end_matches("v2"),
|
||||
"fullscreen" | "workspace" | "focusedmon" | "openwindow" | "closewindow" | "movewindow" | "moveworkspace" | "activespecial" | "monitoradded" | "monitorremoved"
|
||||
@@ -130,6 +143,11 @@ impl Edge {
|
||||
(t < 1.0).then_some((*from, t))
|
||||
}
|
||||
|
||||
// how far a workspace hyprland just made has grown into the row, 0 to 1 over the switch; 1 for the rest
|
||||
pub fn grown(&self, id: i64) -> f32 {
|
||||
self.created.get(&id).map_or(1.0, |at| (at.elapsed().as_secs_f32() / peeks::switch_s().max(0.01)).min(1.0))
|
||||
}
|
||||
|
||||
fn fullscreen_on(&self, monitor: &str) -> bool {
|
||||
self.fullscreen.contains(monitor)
|
||||
}
|
||||
@@ -292,10 +310,15 @@ fn watch_media() {
|
||||
};
|
||||
|
||||
if let Some((known, before)) = &last {
|
||||
let new_player = players.iter().any(|name| !known.contains(name));
|
||||
let new_player = players.iter().find(|name| !known.contains(name));
|
||||
let new_song = !before.is_empty() && song != *before;
|
||||
|
||||
if new_player || new_song {
|
||||
// the one that changed: a new player, or the one whose song this is
|
||||
let changed = new_player.cloned().or_else(|| new_song.then(|| song.split('\u{1f}').next().unwrap_or("").to_string()));
|
||||
|
||||
if let Some(player) = changed
|
||||
&& !in_front(&player)
|
||||
{
|
||||
announce_media();
|
||||
}
|
||||
}
|
||||
@@ -304,6 +327,14 @@ fn watch_media() {
|
||||
}
|
||||
}
|
||||
|
||||
// whether the focused window is this player's app: then its song change is in plain sight
|
||||
fn in_front(player: &str) -> bool {
|
||||
let window = parse::json(&hyprctl("j/activewindow"));
|
||||
let class = window.first().and_then(|window| window.get("class")).and_then(parse::Value::text).unwrap_or("");
|
||||
|
||||
parse::same_app(class, player)
|
||||
}
|
||||
|
||||
fn announce_media() {
|
||||
let mut edge = Edge::write();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user