Commit 9fdf9584d2bd
tarball6 files changed+44-3
@@ -323,4 +323,5 @@ pub struct Window {
323323
pub scratchpad: Option<String>,324324
pub visible: bool,325325
pub focused: bool,326
+ pub urgent: bool,326327
}@@ -69,6 +69,7 @@ pub struct Window {
6969
pub parent: Option<WindowId>,7070
pub sticky: bool,7171
pub scratchpad: Option<usize>,72
+ pub urgent: bool,7273
evicted_from: Option<String>,7374
}7475
@@ -339,6 +340,7 @@ impl Layout {
339340
parent: None,340341
sticky: false,341342
scratchpad: None,343
+ urgent: false,342344
evicted_from: None,343345
});344346
if let Some(o) = output {@@ -448,6 +450,7 @@ impl Layout {
448450
}449451
self.history.retain(|&h| h != w);450452
self.history.push(w);453
+ self.windows[w].urgent = false;451454
}452455
453456
/// The most recently focused visible window on the active output. Focus@@ -618,14 +621,29 @@ impl Layout {
618621
self.mark_urgent(w);619622
}620623
624
+ /// Flags a window that wants attention unless it already has the focus,625
+ /// and its tag too when the window is out of sight.621626
pub fn mark_urgent(&mut self, w: WindowId) {622
- if !self.visible(w)623
- && let Some(tag) = self.windows.get(w).map(|win| win.tag)624
- {627
+ if !self.windows.contains_key(w) {628
+ return;629
+ }630
+ if self.focused() != Some(w) {631
+ self.windows[w].urgent = true;632
+ }633
+ if !self.visible(w) {634
+ let tag = self.windows[w].tag;625635
self.tags[tag].urgent = true;626636
}627637
}628638
639
+ /// Drops the flag of the window holding the focus, which can reach it640
+ /// without `focus`, when the window before it closes or its tag is viewed.641
+ pub fn clear_focused_urgent(&mut self) {642
+ if let Some(w) = self.focused() {643
+ self.windows[w].urgent = false;644
+ }645
+ }646
+629647
pub fn send_to_output(&mut self, w: WindowId, o: OutputId) {630648
let Some(win) = self.windows.get(w) else {631649
return;@@ -611,3 +611,21 @@ fn autotile_dwindles_by_the_anchors_shape() {
611611
assert!(r(b).y < r(c).y && r(b).x == r(c).x);612612
assert!(r(c).x < r(d).x && r(c).y == r(d).y);613613
}614
+615
+#[test]616
+fn urgency_skips_the_focused_window_and_ends_with_focus() {617
+ let mut l = Layout::default();618
+ let o = l.add_output("a", AREA);619
+ let tag = l.tag("1");620
+ l.view(o, tag);621
+ let a = l.add_window(Some(o), Some(tag), None);622
+ let b = l.add_window(Some(o), Some(tag), None);623
+ l.focus(a);624
+ l.mark_urgent(a);625
+ l.mark_urgent(b);626
+ assert!(!l.window(a).unwrap().urgent);627
+ assert!(l.window(b).unwrap().urgent);628
+ assert!(!l.tags().any(|(_, t)| t.urgent));629
+ l.focus(b);630
+ assert!(!l.window(b).unwrap().urgent);631
+}@@ -202,6 +202,7 @@ fn snapshot(state: &State) -> monolith_ipc::State {
202202
.map(|s| s.name.clone()),203203
visible: l.visible(id),204204
focused: focused == Some(id),205
+ urgent: w.urgent,205206
}206207
})207208
.collect();@@ -138,6 +138,8 @@ pub fn build(
138138
if framed && deco.border > 0 {139139
let color = if focused == Some(id) {140140
deco.focused.0141
+ } else if layout.window(id).is_some_and(|w| w.urgent) {142
+ deco.urgent.0141143
} else {142144
deco.unfocused.0143145
};@@ -404,6 +404,7 @@ impl State {
404404
}405405
406406
pub fn sync_focus(&mut self) {407
+ self.wm.layout.clear_focused_urgent();407408
let focused = self.wm.layout.focused();408409
for (id, s) in self.wm.iter() {409410
let window = &s.window;