fix: prioritize activation region hits over CSD overflow in scrolling hit testing#3453
fix: prioritize activation region hits over CSD overflow in scrolling hit testing#3453odtgit wants to merge 1 commit intoniri-wm:mainfrom
Conversation
|
Have you tried using negative struts instead..? |
|
Yes, that's how the investigation started. It was never working reliably
regardless of the strut size, even when hovering over the window (clicking
would work though). With the fix it's working for me regardless of the
strut size, as long as there is one, the focus will shift properly.
Tested - alacritty, firefox, chromium, discord, spotify -> all work, unless
maximized, ie. as intended.
…On Sun, Feb 15, 2026 at 8:10 PM Semper_ ***@***.***> wrote:
*Sempyos* left a comment (niri-wm/niri#3453)
<#3453 (comment)>
Have you tried using negative struts instead..?
—
Reply to this email directly, view it on GitHub
<#3453 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADZCURM767RLBSQCLV4Y55D4MDAB7AVCNFSM6AAAAACVGQZC7SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTSMBVGAZDIMJVGQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
The problem is that there can be a legit part of a surface that sticks out. Most popups should be fine as they grab pointer input, but what about nongrabbing popups? (I'm not sure if there's a good test client, but I think if you unconditionally return from the xdg toplevel Perhaps restricting focus-follows-mouse specifically (and not normal pointer input) from triggering outside the activation region is better? |
01a7500 to
0427226
Compare
0427226 to
305c28a
Compare
what this fixes
focus-follows-mouse edge panning doesn't work reliably with CSD windows. with struts enabled and two 0.5-proportion columns side by side, moving the mouse to the screen edge should focus the adjacent peeking column - but CSD windows like firefox and alacritty block it most of the time, while SSD windows work fine.
root cause
CSD windows have buffers and input regions that extend beyond their
geometry()bounds (shadows, resize handles etc). inScrollingSpace::window_under(), tiles are checked in render order and the first tile whosehit()returnsSomewins. sincehit()checksis_in_input_region()first - which delegates to the wayland client's input region without clipping to tile bounds - the CSD shadow bleeds into the strut zone, the active column steals the hit, focus-follows-mouse sees the same window already focused, and nothing happens.SSD windows don't have this issue because their
geometry().locis(0,0)and their buffer doesn't extend beyond the geometry.worth noting that
clip-to-geometryonly affects rendering, not input - so it can't help here either.the fix
instead of unconditionally clipping all pointer input to the activation region (which would break legitimate CSD surfaces extending beyond tile bounds, like GTK 3 subsurface popups or non-grabbing popups), this uses a two-pass approach in
ScrollingSpace::window_under():hit()including CSD overflow regions. this preserves normal pointer input on legitimate surfaces extending beyond tile bounds.the first pass almost always matches (pointer is within some tile's bounds), so the second pass only runs when the pointer is in a CSD overflow zone outside all tile bounds - negligible performance impact.
adds
Tile::hit_within_activation_region()which checks activation region first, then input region within it. the originalTile::hit()is unchanged.also updated
resize_edges_under()inworkspace.rsto usehit_within_activation_region()for consistency - it had a comment explicitly noting it should matchwindow_under()behavior, and resize edge calculations are relative to tile geometry so CSD overflow hits would produce meaningless edges anyway.what about other hit testing paths
hit_tile(). CSD overlap between floating windows is a z-order concern, not a strut/peeking issue. left as-is.hit_tile()on the single dragged tile. no overlap with itself, no change needed.Activateand disables resize. unaffected.tested with
same tight layout - 4px gaps, 2px struts, 2px focus ring border,
clip-to-geometry true,prefer-no-csdon:tried to test for regressions with the second pass (GTK 3 subsurface popups, non-grabbing popups) but couldn't find a good client that reliably produces CSD surfaces extending beyond tile bounds in a way that would exercise the fallback path. if anyone has a test case for that I'm happy to verify.
would definitely benefit from further testing, but since this enables a purely mouse-driven horizontal scrolling use-case that was broken before, I think it's worth checking out.