Resize & focus¶
Resize¶
tui.resize(cols, rows) changes the simulated terminal size. Under
the hood:
ioctl(fd, TIOCSWINSZ, …)on the PTY master — the kernel deliversSIGWINCHto the child's process group.- The internal
pyte.Screenis resized to match so subsequent reads use the new geometry. TuiConfig.cols/rowsare updated for any downstream logic (snapshot dimensions, etc).
await tui.resize(cols=120, rows=40)
await tui.wait_for_stable(quiet_ms=150)
assert tui.alive, "app should not crash on resize"
Why wait_for_stable after resize¶
Apps typically re-render on resize. Without a settle, an assertion
right after resize might catch the screen mid-redraw.
Rapid resize burst¶
Real users drag window corners — that produces a flood of SIGWINCH. Test that your app survives it:
for cols in (130, 120, 110, 100, 110, 120, 130, 140):
await tui.resize(cols, 44)
await tui.wait_for_stable(quiet_ms=300)
assert tui.alive
Tiny terminal¶
Most TUIs have a minimum viable size. They should degrade, not panic:
await tui.resize(40, 10) # below most minimums
await tui.wait_for_stable(quiet_ms=300)
assert tui.alive
Original size¶
await tui.start("myapp", cols=80, rows=24)
await tui.resize(120, 40)
# … do stuff …
await tui.resize(80, 24) # restore
Focus events¶
DEC mode 1004 makes the terminal send \x1b[I on focus-in and
\x1b[O on focus-out. Apps use this to pause animations, dim cursors,
or reload state on tab return.
await tui.focus(in_=False) # user clicked away
await tui.wait_for_text("paused")
await tui.focus(in_=True) # user came back
await tui.wait_for_text("running")
No-op if the app didn't ask for them¶
async def test_focus(tui):
await tui.start("myapp")
await tui.wait_for_text("Ready")
# If mode 1004 isn't on, focus() does nothing — no error.
await tui.focus(in_=False)
For strict tests:
await tui.wait_for_predicate(
lambda _: tui._emu.is_focus_events(),
timeout=2,
description="focus reporting enabled",
)
await tui.focus(in_=False)
DEC mode reference¶
The framework tracks these private modes. Query via
tui._emu.private_modes (a frozenset[int]) or the helper
predicates:
| Code | What | Helper |
|---|---|---|
| 1000 | X10 mouse tracking | is_mouse_tracking() |
| 1002 | Button-event mouse | is_mouse_tracking() |
| 1003 | Any-event mouse (incl. hover) | is_mouse_tracking() |
| 1004 | Focus events | is_focus_events() |
| 1006 | SGR mouse encoding | (combined w/ 1000/1002/1003) |
| 1049 | Alt screen buffer | – |
| 2004 | Bracketed paste | is_bracketed_paste() |
is_mouse_tracking() returns true if any of 1000/1002/1003 is on —
those are the "is the app listening for mouse" modes. 1006 is the
encoding choice; it can be on without any tracking active.
Next: Cell-grid snapshots →