?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
| Terminal | Version | Support | Notes |
|---|---|---|---|
| VT220 | manual, 2nd ed., 1984 | No | not in the manual |
| VT510 | manual, 1st ed., 1993 | No | not in the manual; not in Table 5-6 |
| xterm | patch 412, xterm-411a | No | not recognized; DECRQM reports 0, and CSI ? 998 n is not answered |
| libghostty-vt | 0f171f6 | Yes | VISIBILITY-1 to VISIBILITY-3: implements the mode and the query; always potentially visible, as its C API cannot change that |
| kitty | 0.49.2, its documentation | Yes | sends 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