Skip to content

Instantly share code, notes, and snippets.

@rockorager
Last active November 6, 2025 17:24
Show Gist options
  • Save rockorager/e695fb2924d36b2bcf1fff4a3704bd83 to your computer and use it in GitHub Desktop.
Save rockorager/e695fb2924d36b2bcf1fff4a3704bd83 to your computer and use it in GitHub Desktop.

Private Mode for In-Band Window Resize Notifications

Terminal emulators typically receive window resize events by installing a signal handler for the SIGWINCH signal. Handling of these signals can create challenges due to their inherently racy properties. Resize events must be synchronized with other application state in a safe manner.

Standard control sequences exist to query the current terminal size from the terminal and receive an in-band control sequence with the window size. However, this system requires polling - which is not ideal. Usually, SIGWINCH handling is preferred.

This specification defines a single new Private Mode which enables automatic reporting of in-band text area resize events -

  • 2048 - Enable/disable reports for text area size in both characters and pixels

Note

When using ReadConsoleInput on Windows, resize notifications are already delivered in band.

Detection and Enabling

Detection is performed with a standard DECRQM query:

CSI ? 2048 $ p

To which the terminal will respond with a DECRPM response:

CSI ? 2048 ; Ps $ y

A Ps value of 0 or 4 means the mode is not supported. Reference

The reports can be enabled using DECSET or DECRST control sequences:

CSI ? 2048 h to enable the mode. CSI ? 2048 l to disable the mode.

Reports

The format of the response / notification is:

CSI 48 ; height_chars ; width_chars ; height_pix ; width_pix t

If a terminal is not capable of reporting pixel sizes, it must report them as 0. A terminal MUST report pixel sizes if it is capable of reporting them.

Any field MAY contain sub-parameters, separated by colons (':', ASCII 0x3A). If a client does not understand these, it MUST ignore subparameters. Currently, no subparameters are defined.

Note

The reported size MUST be the text area size. Text area does not include any padding the terminal applies to the window

Implementation Notes

When first enabled, the terminal MUST send a report of the current size.

If the mode is already enabled, the terminal MUST immediately report the current size if an attempt is made to enable the feature.

This specification does not dictate any sort of throttling or limiting the frequency with which reports can be sent.

The terminal MUST NOT send notifications until the internal resize is complete. That is, the terminal must be prepared for the TTY and application to behave at the new size prior to sending the sequence.

Important

The reported area MUST be the text area size. Font size changes can also affect the text area size

Example

An application queries the terminal for support:

A: \x1b[?2048$p

The terminal responds with:

T: \x1b[?2048;2y

The mode is supported but not currently enabled. The application enables the mode.

A: \x1b[?2048h

The terminal turns the mode on, and gives an immediate report of the window size.

T: \x1b[48;24;80;240;1600t

After some time, the user changes the window size. The terminal sends a new size report.

T: \x1b[48;48;80;480;1600t

@jquast
Copy link

jquast commented Nov 3, 2025

By my analysis the following 33 terminals tested, 4 support in-band resize notification, https://ucs-detect.readthedocs.io/results.html#dec-private-modes-support

  • ghostty
  • iTerm2
  • kitty
  • foot

And I have implemented it in my python TUI library, blessed, documented here https://blessed.readthedocs.io/en/latest/measuring.html#resizing

Because I feel strongly that this is needed, because SIGWINCH, and, its carrying protocol features/options (telnet, ssh) sometimes cannot reliably transmit about window size changes, I wrote previously in this demonstration program https://github.com/jquast/blessed/blob/master/bin/resize.py

A strange problem: programs that perform screen addressing incorrectly
determine the screen margins. Calls to reset(1) do not resolve the
issue.

This may often happen because the transport is incapable of communicating
the terminal size, such as over a serial line.

@ismail-yilmaz
Copy link

ismail-yilmaz commented Nov 6, 2025

Hi,

Bobcat will also start supporting this mode starting from v0.9.8 (the release is imminent).

The mode is recently implemented in the underlying terminal library (Upp::TerminalCtrl).

And it is already enabled in AUR package.

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