Skip to content

Set pane styles without selecting the pane (fixes focus stealing) - #6

Merged
accessd merged 3 commits into
accessd:mainfrom
ignaciomella:fix-pane-style-focus-steal
Jul 25, 2026
Merged

accessd merged 3 commits into
accessd:mainfrom
ignaciomella:fix-pane-style-focus-steal

Conversation

@ignaciomella

@ignaciomella ignaciomella commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Problem

apply_pane_style / reset_pane_style (and the inline resets in pane-focus-in.sh / reset_all.sh) tint pane backgrounds with select-pane -t <pane> -P "bg=…". select-pane with -P still makes the target pane the active pane (verified on tmux 3.6a), so any agent state change that styles a non-active pane also moves focus.

The capture/restore added in 01b363c mitigates this but can't eliminate it:

  • it races with the user — switching panes between the capture and the restore snaps focus back to the stale captured pane;
  • when the script runs without a client context (e.g. from agent hooks), tmux display-message -p '#{pane_id}' can resolve a different pane than the one the attached client is on, so the restore itself moves the user's focus.

In practice, when working in a window that shares panes with running agents (a common grid layout), focus gets randomly yanked to another pane whenever an agent changes state.

Fix

Write the style through the pane-scoped window-style option instead:

tmux set-option -p -t "$pane_id" window-style "bg=…"

This sets the same style (select-pane -P is implemented on top of the same pane option) but has no focus side effect, so the capture/restore dance can be dropped entirely. Pane-scoped options need tmux ≥ 3.1, so this PR updates the README minimum from 3.0 to 3.1.

Verification

  • Added tests/test-pane-style-preserves-focus.sh to verify styling and reset preserve the active pane and window_zoomed_flag while applying the expected background to an inactive pane.
  • bash -n agent-indicator.tmux scripts/*.sh install.sh setup.sh tests/*.sh tests/lib/*.sh
  • shellcheck -x -S warning agent-indicator.tmux scripts/*.sh install.sh setup.sh tests/*.sh tests/lib/*.sh
  • python3 -m py_compile scripts/agent-limits.py
  • ./tests/run-all.sh

🤖 Generated with Claude Code

select-pane -P also makes the target pane the active pane, so styling a
non-active pane on agent state changes moved the user's focus. The
capture/restore introduced in 01b363c mitigates but doesn't eliminate it:
it races with user navigation, and when the script runs without a client
context (agent hooks) the captured "active" pane can be wrong, making the
restore itself steal focus.

Use the pane-scoped window-style option (set-option -p), which writes the
same style with no focus side effect, and drop the capture/restore dance.
Requires tmux >= 3.0 (already the documented minimum).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hammondr

Copy link
Copy Markdown

Independently reached the same fix on tmux 3.7b before finding this PR, and can confirm both the diagnosis and the resolution.

One consequence worth adding to the record: on 3.7b, select-pane -t <pane> -P "bg=..." against a non-active pane not only moves the active pane, it also clears the window zoomed flag. So in a zoomed layout, any background agent reaching needs-input or done unzooms the user's current view in addition to stealing focus. set-option -p -t <pane> window-style "bg=..." sets the same background with neither side effect.

Reproduction (tmux 3.7b), starting from a zoomed 2-pane window:

zoom pane %42 (active)               -> window_zoomed_flag=1  active=%42
select-pane -t %43 -P "bg=colour52"  -> window_zoomed_flag=0  active=%43
set-option -p -t %43 window-style "bg=colour52" (from zoom) -> window_zoomed_flag=1  active=%42

Verified end to end: a background pane transitioning to done while another pane is zoomed keeps both the zoom and the active pane, tints the background pane, and clears the tint on focus. +1 to merging this.

@accessd

accessd commented Jul 25, 2026

Copy link
Copy Markdown
Owner

So in a zoomed layout, any background agent reaching needs-input or done unzooms the user's current view in addition to stealing focus.

I've been struggled with this too! Nice to have the fix!

@accessd
accessd merged commit be4c353 into accessd:main Jul 25, 2026
2 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.

3 participants