srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/core/src/manager/hittest.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-08-08 23:56:00 +0200
committersrdusr <[email protected]>2024-08-08 23:56:00 +0200
commit52b0b8927fa56f42ad6b39fb45bbed5a2d392dce (patch)
treed72e8a090c28e828c7e3980a9b0e69b31ebfc262 /crates/core/src/manager/hittest.rs
parentb0a6b67cbfb080ee44b6a6fa005dd63ab0f93cd8 (diff)
downloadsrdwm-52b0b8927fa56f42ad6b39fb45bbed5a2d392dce.tar.gz
srdwm-52b0b8927fa56f42ad6b39fb45bbed5a2d392dce.zip
Fix clicks landing on a window hidden on another workspace
WindowManager::hit_test/window_at filtered only by `!w.minimized`, never by workspace - but a window on a workspace that isn't current is not minimized, it's just not shown. Rendering (visible_windows/ visible_windows_front_to_back) already restricted to the current workspace; hit-testing didn't, so a click landing on where an invisible window's stale on-screen geometry happened to sit routed to that window instead of whatever was actually visible underneath. Reported live. Fixed by adding the same workspace check rendering already uses, plus a regression test with two identically-positioned windows on different workspaces.
Diffstat (limited to 'crates/core/src/manager/hittest.rs')
-rw-r--r--crates/core/src/manager/hittest.rs21
1 files changed, 16 insertions, 5 deletions
diff --git a/crates/core/src/manager/hittest.rs b/crates/core/src/manager/hittest.rs
index 918acb5..2d52b57 100644
--- a/crates/core/src/manager/hittest.rs
+++ b/crates/core/src/manager/hittest.rs
@@ -10,9 +10,18 @@ impl WindowManager {
/// Topmost window whose frame contains `(x, y)`, along with what part of
/// its titlebar/border was hit (button, drag area, resize edge).
+ ///
+ /// Restricted to the current workspace, same as `visible_windows`/
+ /// `visible_windows_front_to_back` - a window on another workspace is
+ /// never minimized (that's a separate flag from "not currently shown"),
+ /// so without this a click landing on its old on-screen geometry hit
+ /// *that* window instead of whatever the user could actually see.
+ /// Reported live: clicking a window while a differently-workspaced one
+ /// happened to occupy the same screen coordinates sent the click to the
+ /// invisible one.
pub fn hit_test(&self, x: i32, y: i32) -> Option<(WindowId, TitlebarHit)> {
for w in self.order.iter().rev().filter_map(|id| self.windows.get(id)) {
- if w.minimized {
+ if w.minimized || w.workspace != self.current_workspace {
continue;
}
if let Some(hit) = ResizeEdge::hit_test(w.geometry, x, y, w.decorated, w.border_width, self.resize_margin) {
@@ -22,15 +31,17 @@ impl WindowManager {
None
}
- /// Topmost non-minimised window containing a point, ignoring
- /// decorations. Used for modifier+drag, where the grab applies anywhere
- /// in the window rather than only on the titlebar (`hit_test`).
+ /// Topmost non-minimised window on the current workspace containing a
+ /// point, ignoring decorations. Used for modifier+drag, where the grab
+ /// applies anywhere in the window rather than only on the titlebar
+ /// (`hit_test`). See `hit_test`'s doc comment for why the workspace
+ /// check is load-bearing, not redundant with `minimized`.
pub fn window_at(&self, x: i32, y: i32) -> Option<WindowId> {
self.order
.iter()
.rev()
.filter_map(|id| self.windows.get(id))
- .find(|w| !w.minimized && w.geometry.contains_point(x, y))
+ .find(|w| !w.minimized && w.workspace == self.current_workspace && w.geometry.contains_point(x, y))
.map(|w| w.id)
}