mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-13 12:23:38 +01:00
fix(border): do not look for a border while holding the ghosts
The border manager holds the locks of the borders while it handles a notification and asks whether a window is ghosted as it does, which takes the lock of the ghosts. An animation of a ghost for a window that had no border when it was made, a new window, took the lock of the ghosts first and then looked for the border, which takes the locks of the borders. Each waited for the other, for good: the border manager answered no more notifications, which piled up until they were dropped, and every animation that was landed after that waited for its full two seconds with its ghost on screen. Look for the border with nothing held, and remember it afterwards.
This commit is contained in:
1 parent
9922a34bd7
commit
aa353a7158
1 file changed
+68
-12
@@ -246,20 +246,26 @@ fn queue_animated_rect(
|
|||||||
/// there, instead of every one it was sent in turn and further and further
|
/// there, instead of every one it was sent in turn and further and further
|
||||||
/// behind.
|
/// behind.
|
||||||
pub fn animate_to(source_hwnd: isize, rect: crate::core::Rect) {
|
pub fn animate_to(source_hwnd: isize, rect: crate::core::Rect) {
|
||||||
let border = {
|
let Some(known) = GHOSTED.lock().get(&source_hwnd).copied() else {
|
||||||
let mut ghosted = GHOSTED.lock();
|
return;
|
||||||
let Some(border) = ghosted.get_mut(&source_hwnd) else {
|
};
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// a window that had no border when its ghost was made can get one
|
let border = match known {
|
||||||
if border.is_none() {
|
Some(border) => border,
|
||||||
*border = window_border(source_hwnd).map(|border| border.border_hwnd);
|
None => {
|
||||||
}
|
// A window that had no border when its ghost was made can get one. It is looked for
|
||||||
|
// with nothing held: the border manager has the borders locked while it handles a
|
||||||
|
// notification, and asks if a window is ghosted as it does, which it is not to wait
|
||||||
|
// for to be answered by a thread that is waiting for it.
|
||||||
|
let Some(border) = window_border(source_hwnd).map(|border| border.border_hwnd) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
match *border {
|
if let Some(slot) = GHOSTED.lock().get_mut(&source_hwnd) {
|
||||||
Some(border) => border,
|
*slot = Some(border);
|
||||||
None => return,
|
}
|
||||||
|
|
||||||
|
border
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1157,6 +1163,56 @@ mod tests {
|
|||||||
assert!(!is_ghosted(hwnd));
|
assert!(!is_ghosted(hwnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The border manager holds the locks of the borders while it handles a notification, and
|
||||||
|
/// asks whether a window is ghosted as it does, while an animation of a ghost, which is told
|
||||||
|
/// the border of a window that has none as it is ghosted when it gets one, asks for it
|
||||||
|
#[test]
|
||||||
|
fn a_ghost_that_is_animated_does_not_keep_the_border_manager_from_asking_about_it() {
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
// a window handle nothing else in the tests uses, that has no border to follow
|
||||||
|
let hwnd = 0x7e57_0100;
|
||||||
|
set_ghosted(hwnd, true);
|
||||||
|
|
||||||
|
let (holding_tx, holding_rx) = channel();
|
||||||
|
let (done_tx, done_rx) = channel();
|
||||||
|
|
||||||
|
// the border manager: it has the borders locked
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let _borders = BORDER_STATE.lock();
|
||||||
|
let _windows_borders = WINDOWS_BORDERS.lock();
|
||||||
|
holding_tx.send(()).ok();
|
||||||
|
|
||||||
|
// until the animation is waiting for them
|
||||||
|
std::thread::sleep(Duration::from_millis(300));
|
||||||
|
done_tx.send(is_ghosted(hwnd)).ok();
|
||||||
|
});
|
||||||
|
|
||||||
|
// the animation of the ghost, a frame of it
|
||||||
|
holding_rx.recv().ok();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
animate_to(
|
||||||
|
hwnd,
|
||||||
|
crate::core::Rect {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
right: 10,
|
||||||
|
bottom: 10,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let asked = done_rx.recv_timeout(Duration::from_secs(5));
|
||||||
|
set_ghosted(hwnd, false);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
asked,
|
||||||
|
Ok(true),
|
||||||
|
"the border manager never got to ask, as the animation held what it asks for"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_border_is_only_told_of_a_rect_when_it_has_none_waiting() {
|
fn a_border_is_only_told_of_a_rect_when_it_has_none_waiting() {
|
||||||
let mut pending = HashMap::new();
|
let mut pending = HashMap::new();
|
||||||
|
|||||||
Reference in new issue
Block a user