Skip to content

focus_trap: End the Tab search at the first repeated stop - #3642

Merged
huacnlee merged 4 commits into
longbridge:mainfrom
boboshan:focus-trap-repeated-stop
Oct 24, 2026
Merged

huacnlee merged 4 commits into
longbridge:mainfrom
boboshan:focus-trap-repeated-stop

Conversation

@boboshan

@boboshan boboshan commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

In an active focus trap, advance_focus (Tab and Shift-Tab) walks the window's tab order until focus is inside the trap, and stops early only when focus comes back to the first stop it reached. If GPUI's tab order cycles without passing that stop, it never comes back. We hit this with Shift-Tab from a modal in an application whose tab order held a stop that focus_prev returned as its own previous stop: the walk stayed on that stop, and the window hung on the key press. We have not isolated what makes GPUI's order do that; a handle tracked twice in one frame does not do it on its own.

The search now records the stops it visits and, at the first repeat, focuses the trap's container, the fallback it already uses for a trap with no reachable stops. A full cycle behaves as before.

No public API changes.

How to Test

  • focus_trap_search_ends_at_a_short_cycle_on_its_container drives advance_focus with a scripted advance (first, second, second) that panics when it runs out, so the previous loop fails in about 0.06s instead of hanging.
  • The existing focus-trap tests still pass, including wrapping past 256 background stops, a trap without stops, and an inactive trap.
  • On this branch, macOS, Rust 1.99.1: cargo clippy -p gpui-base --locked -- --deny warnings, cargo test -p gpui-base --features test-support --lib root, cargo fmt --check and typos.

Checklist

  • I have read the CONTRIBUTING document and followed the guidelines.
  • Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate.
  • Passed cargo run for story tests related to the changes.
  • Tested macOS, Windows and Linux platforms performance (if the change is platform-specific)

🤖 Generated with Claude Code

advance_focus stopped only when focus came back to the first stop it
reached. A tab order that cycles without passing that stop, such as a stop
whose previous stop is itself, made Tab or Shift-Tab out of a trap loop
forever. The search now ends at any repeated stop and focuses the trap's
container, as it already did for a trap without reachable stops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@boboshan
boboshan marked this pull request as ready for review October 22, 2026 12:48
@huacnlee
huacnlee enabled auto-merge (squash) October 24, 2026 03:56
@huacnlee
huacnlee merged commit ae8d232 into longbridge:main Oct 24, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants