window-rule: add block-pointer-constraints to suppress pointer-lock activation#4045
Open
joshsymonds wants to merge 5 commits into
Open
window-rule: add block-pointer-constraints to suppress pointer-lock activation#4045joshsymonds wants to merge 5 commits into
joshsymonds wants to merge 5 commits into
Conversation
New per-window-rule bool, default unset. Mirrors the block-out-from pattern: knuffel #[child, unwrap(argument)] accepting `block-pointer-constraints true` in KDL. No runtime behavior yet; that lands in a follow-up commit once ResolvedWindowRules + the activation gate at maybe_activate_pointer_constraint are in place. Parser test extends the existing window-rule fixture in lib.rs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds block_pointer_constraints to ResolvedWindowRules with last-Some- wins resolution in compute(), and short-circuits Niri::maybe_activate_pointer_constraint when the constrained surface's root toplevel belongs to a window matched by a rule with this flag set. The walk-to-root before the layout lookup mirrors the existing pattern in PointerConstraintsHandler::cursor_position_hint — pointer constraints can be requested on subsurfaces too, but window rules resolve on the toplevel. Both Locked and Confined variants are suppressed unconditionally: the rule is opt-in per window, so apps that legitimately need either variant (games, drawing tablets, 3D modelers) are unaffected unless they match a user-authored rule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the wiki section users will hit when they look for "why is my cursor sticking on an overlay." Example KDL is intentionally generic (app-id="some-app") rather than naming a specific vendor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four small fixups surfaced by the four-reviewer audit: - src/niri.rs: replace inline `get_parent`-walk with the existing `Niri::find_root_shell_surface` helper. The helper consults the cached root_surface map and walks popups to their parent toplevel via find_popup_root_surface — the raw walk lacked both. Drops the newly-added `get_parent` import, restoring the pre-patch import surface in niri.rs. - src/window/mod.rs: trim the 7-line doc comment on ResolvedWindowRules::block_pointer_constraints to a one-line summary matching adjacent fields. Long-form prose lives in the wiki. - docs/wiki/Configuration:-Window-Rules.md: change `Since: next` to `Since: next release` to match upstream's release-bump workflow (commit 8fd9fb7's find/replace targets the longer form). Replace the generic app-id="some-app" example with a concrete Zoom annotate_toolbar example that matches the originally-stated use case. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviewer feedback: the gate ran unconditionally before with_pointer_constraint, paying for find_root_shell_surface + find_window_and_output on every pointer motion even when no constraint exists for the focused surface (which is the common case — ~100% of motions over non-constraint surfaces). Relocate the check inside the with_pointer_constraint callback, after the constraint-present early-return. Restores the pre-patch fast path: the rule lookup only runs when a constraint actually exists to be activated. Semantics are preserved — the block still short-circuits before constraint.activate(); the only observable difference is where the short-circuit lives relative to the protocol bind/activate boundary. The constraint stays bound but inactive either way. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Member
|
Thanks, however in this case it sounds like the app is buggy and should fix its behavior. |
Author
|
Maybe, but I think my chances of getting Zoom to do this are pretty low! No worries if you don't want to accept this though. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
block-pointer-constraintswindow-rule (Option<bool>) thatsuppresses activation of
zwp_pointer_constraints_v1constraints formatching windows. Both
LockedandConfinedvariants are suppressedunconditionally — the rule is opt-in per window, so apps that
legitimately need pointer-constraints (games, drawing tablets, 3D
modelers) are unaffected unless explicitly matched.
Motivation
Some clients request a pointer-lock as part of a tooltip / annotation /
overlay UI surface that users don't actually want to engage when the
cursor merely crosses it — the constraint locks the cursor in place
until pointer focus moves away (which from a user's perspective looks
like "the cursor is stuck"). A per-window opt-out preserves the
protocol for its intended uses while letting users disable it for
specific surfaces.
Concrete motivating case: Zoom's
annotate_toolbaroverlay (a smallfloating toolbar that appears during screen-sharing-with-annotation)
requests a pointer-lock on hover. Users only want to interact with the
toolbar deliberately, but on niri the lock activates whenever the
cursor crosses the overlay's region.
Implementation
niri-config/src/window_rule.rs): newblock_pointer_constraints: Option<bool>field onWindowRuleadjacent to
block_out_from, with the standard#[knuffel(child, unwrap(argument))]annotation.src/window/mod.rs): same field onResolvedWindowRules, last-Some-wins resolution incompute().src/niri.rs):Niri::maybe_activate_pointer_constraint()short-circuits when the constrained surface's root toplevel matches a
rule with this flag set. The check is placed inside the
with_pointer_constraintcallback after the constraint-presentearly-return, so the no-constraint fast path that runs on every
pointer motion is unchanged. Root-surface resolution uses the existing
Niri::find_root_shell_surfacehelper (popups + subsurfaces arehandled correctly).
niri-config/src/lib.rsextends the existingwindow-rule fixture to cover the new property round-tripping.
#### block-pointer-constraintssection indocs/wiki/Configuration:-Window-Rules.mdbetweenblock-out-fromand
opacity, with the motivating Zoom example.Design notes
binds and the client's request still arrives at smithay; niri just
never calls
constraint.activate(). Well-behaved clients gaterelative-motion mode and similar features on the constraint being
active, so they degrade gracefully to normal absolute-motion input.
Confinedconstraint with asufficiently large region produces the same user-visible "cursor
stuck" pattern as
Locked; suppressing both keeps the rule'ssemantics predictable. A future enhancement could split this into an
enum if a real use case demands variant-specific control.
break games, drawing tablets, and Blender-style middle-drag
interactions; per-window keeps the rule narrowly scoped.
Test plan
cargo build --workspacecleancargo test -p niri-configpasses (parser test exercises the new field, wiki-parses test confirms the KDL example parses)cargo clippy --workspace --all-targets -- -D warningscleancargo fmt --check --allcleanannotate_toolbar) — verification in progress on next session