Skip to content

fix(tui): ioctl TIOCGWINSZ poll + self-SIGWINCH for reflow under proot/Termux - #41832

Open
Albertban wants to merge 10 commits into
anomalyco:devfrom
Albertban:pr/tui-resize-ioctl
Open

fix(tui): ioctl TIOCGWINSZ poll + self-SIGWINCH for reflow under proot/Termux#41832
Albertban wants to merge 10 commits into
anomalyco:devfrom
Albertban:pr/tui-resize-ioctl

Conversation

@Albertban

Copy link
Copy Markdown

Problem

Termux + proot (user-space syscall emulation) never forwards SIGWINCH to the
Bun process, and Bun's process.stdout.rows/columns stay frozen at the startup
value. The default TUI (rendered via packages/tui createCliRenderer) therefore
stays at the startup terminal size forever: raising the soft keyboard covers the
lower half, and rotating the device never reflows.

Fix

  • New packages/tui/src/termux-resize-fix.ts: every 300ms it reads the real
    terminal size via ioctl(TIOCGWINSZ) (Bun FFI against libc), and on change it
    both calls renderer.resize(cols, rows) and delivers SIGWINCH to itself
    (the handler path that reliably makes OpenTUI re-read the real size and
    repaint). Gracefully no-ops when bun:ffi/dlopen is unavailable.
  • packages/tui/src/app.tsx: starts the poll right after the renderer is
    created, stops it on destroy.

Test

  • Termux + proot Ubuntu (aarch64), glibc standalone build: keyboard show/hide and
    device rotation now reflow to the correct size within ~300ms.
  • On normal terminals (SIGWINCH delivered normally) this is a no-op fallback;
    regular resize path is untouched.

….stdout

In Termux + proot (and other stdio-proxy environments) SIGWINCH is never
delivered to the Bun process, so process.stdout rows/columns stay frozen
at the startup value and the renderer never reflows to keyboard/rotation
changes. Poll TIOCGWINSZ directly through ioctl (bun:ffi) and push real
size changes into the renderer via resize(), falling back to no polling
when the ioctl shim cannot be loaded.
v2 (ioctl polling) did not reflow under Termux+proot: the process.stdout.isTTY
gate likely disabled polling when the TUI swaps process.stdout, and
renderer.resize() appears to be a no-op in this build. v3 drops the gate and
on an ioctl-detected size change takes both paths:
  1) renderer.resize(cols, rows)  (may be a no-op in some builds)
  2) process.kill(self, SIGWINCH)  (reliably wakes OpenTUI's SIGWINCH handler,
     which re-reads the real terminal size and repaints - the path verified
     to actually reflow under Termux+proot)
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs:compliance This means the issue will auto-close after 2 hours. needs:issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant