^[control-codes live in libghostty-vt

Private modes

?2033 Visibility Reports

Have the terminal tell the program whether its output can be seen, so that it can stop drawing while hidden.

CSI ? 2033 h/l
Specification
Private Mode for Terminal Visibility Reports

With CSI ? 2033 h set, the terminal tells the program whether its view can be seen, so that a program can pause animations and other expensive drawing while nobody is looking. The report is a private Device Status Report, CSI ? 999 ; Ps n, where Ps is 1, potentially visible, or 2, not visible. Setting the mode sends a report at once, even when it was already set, and the terminal sends another each time the state changes; CSI ? 2033 l stops them and sends nothing. A program that wants the state just once asks with CSI ? 998 n, which is answered with the same report and leaves the mode as it was. The pattern is that of dark and light mode detection, ?2031, whose query and report are CSI ? 996 n and CSI ? 997 ; Ps n.

Focus does not answer the question. A focus report says which view gets the keyboard, but an unfocused terminal can still be on screen, and a focused one can be covered, in a background tab, or on a workspace not being shown.

It is neither xterm’s nor DEC’s. Its definition is Private Mode for Terminal Visibility Reports, by Tim Culverhouse, dated July 25, 2026, read on October 23, 2026. A program finds out whether a terminal has it by asking with DECRQM: 1 or 2 means it does, and 0, 4 or no answer means it does not.

The specification makes potentially visible the safe answer. A terminal reports 2 only when it knows that the view cannot be seen, and 1 whenever it does not know, or when any of the views showing the session might be seen; a program takes any value it does not know as 1. The view meant is the session’s own, not only its window: a tab that is not selected, a pane not displayed, a window minimized, hidden, fully covered or on another workspace, and a surface whose compositor has stopped presenting it. On macOS a window whose NSWindow.occlusionState lacks NSWindowOcclusionStateVisible is fully covered, and on Wayland an xdg_toplevel in the suspended state can be taken as not visible; the specification gives these as examples rather than requirements.

Not visible is a hint, not an instruction. The program may stop animating, put off redrawing, or skip other work that only matters on screen, but it should go on reading input and keeping the state it will need, and draw its latest state as soon as a 1 arrives. It may not assume that the terminal will stay hidden for any length of time.

A default xterm has no mode 2033. It answers DECRQM for it with 0, as it does for any mode it does not know (do_dec_rqm), and does not answer CSI ? 998 n, which falls through to the empty default of its DSR dispatch (CASE_DSR). The cases follow xterm.

libghostty-vt implements it, added in Ghostty pull request #13494 by the specification’s author, so the cases that expect xterm’s silence are known differences. Mode 2033 is report_visibility in modes.zig, off to begin with, and ?998 is in the DSR table in device_status.zig; setting the mode or asking sends the report from sendVisibilityReport in stream_terminal.zig. The state it reports is the terminal’s flags.visible, which starts out true, so libghostty-vt answers 1 until its host says otherwise, and which RIS leaves alone, since it belongs to the view rather than to the terminal. Ghostty sets it from the occlusion state its app reports, and on GTK 4.12 and later that includes the window’s suspended state, so a window on another workspace is reported as not visible. libghostty-vt’s C API offers no way to set it, so a program embedding the library always gets 1, as the cases here do.

Support

TerminalVersionSupportNotes
VT220manual, 2nd ed., 1984Nonot in the manual
VT510manual, 1st ed., 1993Nonot in the manual; not in Table 5-6
xtermpatch 412, xterm-411aNonot recognized; DECRQM reports 0, and CSI ? 998 n is not answered
libghostty-vt0f171f6YesVISIBILITY-1 to VISIBILITY-3: implements the mode and the query; always potentially visible, as its C API cannot change that
kitty0.49.2, its documentationYessends a report when the mode is set and on each change (screen.c, set_mode_from_const); since 0.48.2

Validation

VISIBILITY-1: A default xterm does not recognize it

\e[?2033$p
\e[?2033h
\e[?2033$p
|____|
reply \e[?2033;0$y\e[?2033;0$y

VISIBILITY-2: Setting it sends nothing in a default xterm

\e[?2033h
|____|
reply none

VISIBILITY-3: A default xterm does not answer the query

\e[?998n
|____|
reply none

VISIBILITY-4: The screen does not change

A
\e[?2033h
\e[?998n
\e[?2033l
B
|AB__|
cursor 1,3
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.