Skip to content

fix(renderer): handle SIGTSTP to prevent mouse garbling on external suspend#907

Open
agutmanstein-scale wants to merge 2 commits intoanomalyco:mainfrom
agutmanstein-scale:fix/sigtstp-mouse-garble
Open

fix(renderer): handle SIGTSTP to prevent mouse garbling on external suspend#907
agutmanstein-scale wants to merge 2 commits intoanomalyco:mainfrom
agutmanstein-scale:fix/sigtstp-mouse-garble

Conversation

@agutmanstein-scale
Copy link
Copy Markdown

Issue for this PR

Closes #906

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

When a process receives SIGTSTP from an external source (job control, terminal multiplexer, code-server), the process is suspended by the kernel without any terminal cleanup. Mouse tracking and raw mode remain active, causing mouse events to echo as garbled text in the shell.

This PR adds SIGTSTP/SIGCONT signal handlers to the renderer that call suspend()/resume() — the same cleanup that the manual suspend keybind uses.

Implementation:

  • sigtstpHandler: calls suspend() to disable mouse/raw mode, removes itself, re-raises SIGTSTP for default suspend behavior
  • sigcontHandler: re-registers the SIGTSTP handler, calls resume() to restore terminal state
  • addSigtstpListeners()/removeSigtstpListeners(): symmetric lifecycle management matching addExitListeners()/removeExitListeners()
  • Registered in constructor, removed in suspend(), cleanupBeforeDestroy(); re-added in resume()

How did you verify your code works?

  • Code review: the handlers delegate to the existing suspend()/resume() which are already well-tested
  • The SIGTSTP handler correctly removes itself before re-raising (avoids infinite loop)
  • Lifecycle is symmetric with exit listeners

Reproduction without fix

# Terminal 1: run any opentui app with mouse tracking
opencode

# Terminal 2: send SIGTSTP
kill -TSTP $(pgrep -f opencode)

# Terminal 1: move mouse → garbled escape sequences

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

…uspend

When a process receives SIGTSTP from an external source (e.g., job
control, terminal multiplexer, code-server), the process is suspended
by the kernel without any terminal cleanup. Mouse tracking, Kitty
keyboard protocol, and raw mode remain active, causing mouse events
to appear as garbled escape sequences in the shell.

Add SIGTSTP/SIGCONT signal handlers that call suspend()/resume() to
properly clean up terminal state before suspension and restore it
after resuming. The SIGTSTP handler removes itself before re-raising
the signal to allow the default suspend behavior.

The handlers are registered alongside exit listeners and removed
symmetrically in suspend(), resume(), and cleanupBeforeDestroy().

Fixes anomalyco#906

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
agutmanstein-scale added a commit to agutmanstein-scale/opencode that referenced this pull request Apr 1, 2026
When opencode receives SIGTSTP from an external source (code-server
terminal management, job control, kill -TSTP), the process is
suspended without terminal cleanup. Mouse tracking remains enabled,
causing mouse events to echo as garbled escape sequences in the shell.

Register SIGTSTP/SIGCONT handlers after renderer creation that call
renderer.suspend()/resume() — the same cleanup the manual suspend
keybind uses. The SIGTSTP handler removes itself before re-raising
to allow default suspend behavior.

Includes test-sigtstp-mouse.sh reproduction script.

Upstream fix: anomalyco/opentui#907
Closes anomalyco#20506

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
18vijayb pushed a commit to 18vijayb/opencode that referenced this pull request Apr 2, 2026
When opencode receives SIGTSTP from an external source (code-server
terminal management, job control, kill -TSTP), the process is
suspended without terminal cleanup. Mouse tracking remains enabled,
causing mouse events to echo as garbled escape sequences in the shell.

Register SIGTSTP/SIGCONT handlers after renderer creation that call
renderer.suspend()/resume() — the same cleanup the manual suspend
keybind uses. The SIGTSTP handler removes itself before re-raising
to allow default suspend behavior.

Includes test-sigtstp-mouse.sh reproduction script.

Upstream fix: anomalyco/opentui#907
Closes anomalyco#20506

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… input

When SIGCONT arrives without a prior SIGTSTP through our handler
(e.g., terminal refocus/reconnect in code-server), calling resume()
adds a duplicate stdin listener — every keystroke is delivered twice.

Guard resume() with _suspendedBySigtstp so it only runs if our
SIGTSTP handler actually called suspend().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
agutmanstein-scale added a commit to agutmanstein-scale/opencode that referenced this pull request Apr 2, 2026
When opencode receives SIGTSTP from an external source (code-server
terminal management, job control, kill -TSTP), the process is
suspended without terminal cleanup. Mouse tracking remains enabled,
causing mouse events to echo as garbled escape sequences in the shell.

Register SIGTSTP/SIGCONT handlers after renderer creation that call
renderer.suspend()/resume() — the same cleanup the manual suspend
keybind uses. The SIGTSTP handler removes itself before re-raising
to allow default suspend behavior.

Includes test-sigtstp-mouse.sh reproduction script.

Upstream fix: anomalyco/opentui#907
Closes anomalyco#20506

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

bug: missing SIGTSTP handler causes mouse garbling when process is externally suspended

1 participant