^[control-codes live in libghostty-vt

Private modes

?1049 Alternate Screen

Switch to a second screen for full-screen programs, and back to the one the shell was using.

CSI ? 1049 h
xterm
Functions using CSI

A terminal keeps two screens. The normal one is where the shell runs and has the scrollback; the alternate one has no scrollback, and a full-screen program such as an editor or a pager switches to it on starting and back on leaving, so that the shell’s screen reappears as it was. None of this is DEC’s: it is xterm’s, and these modes are xterm’s numbers in DEC’s private space.

ModeSetReset
47switch to the alternate screenswitch to the normal screen
1047switch to the alternate screenclear the alternate screen, then switch to the normal screen
1048save the cursor, as DECSCrestore the cursor, as DECRC
1049save the cursor, switch to the alternate screen, and clear itswitch to the normal screen, and restore the cursor
1046allow the switchforbid it, and switch to the normal screen

1049 is the one programs use: it is what the smcup and rmcup capabilities of most terminfo entries for xterm-like terminals send.

The cases follow xterm (dpmodes and L7906-L7922, ToAlternate, FromAlternate):

  • The switch itself moves nothing. The cursor stays where it was, and so do the character attributes, unless 1048 or 1049 saves and restores them.
  • What is on the alternate screen stays there between visits, unless 1047 clears it on the way out or 1049 on the way in.
  • Each screen has its own saved cursor, for DECSC and DECRC as much as for these modes. 1049 saves into the slot of the screen it was on when it was set, and restores from the normal screen’s (CursorSave, CursorRestore).
  • RIS goes back to the normal screen.

DECRQM is answered with xterm’s own state rather than each mode’s (do_dec_rqm, L5713-L5718). 47, 1047 and 1049 all report whether the alternate screen is showing, whichever of them switched to it. 1048 reports whether the current screen has a saved cursor at all. 1046 reports the flag behind it, which is set when switching is forbidden, so it answers the opposite of the mode’s own sense: reset after CSI ? 1046 h. The cases expect all of this, bugs included.

libghostty-vt does the switching as xterm does, and has the same per-screen saved cursor. Its DECRQM answers each mode from its own flag, and it does not know mode 1046 at all, so the cases about those are known differences.

Validation

ALT-1: The alternate screen starts blank

AB
\e[?47h
|____|
|____|
cursor 1,3

ALT-2: And the normal screen comes back as it was

AB
\e[?47h
X
\e[?47l
|AB__|
|____|
cursor 1,4

ALT-3: The cursor stays where it was

AB
\e[2;2H
\e[?47h
|____|
|____|
cursor 2,2

ALT-4: 47 keeps the alternate screen between visits

AB
\e[?47h
X
\e[?47l
\e[?47h   # back again
|__X_|
|____|
cursor 1,4

ALT-5: 1047 clears it on the way out

AB
\e[?1047h
X
\e[?1047l
\e[?1047h
|____|
|____|
cursor 1,4

ALT-6: But not on the way in

AB
\e[?47h
X
\e[?47l
\e[?1047h
|__X_|
|____|
cursor 1,4

ALT-7: 1049 clears it on the way in

AB
\e[?47h
X
\e[?47l
\e[?1049h
|____|
|____|
cursor 1,4

ALT-8: And restores the cursor on the way out

AB
\e[?1049h
\e[2;4H
X
\e[?1049l
|AB__|
|____|
cursor 1,3

ALT-9: 1049 saves the character attributes too

\e[1m     # bold
\e[?1049h
\e[0m
\e[?1049l
B
|B___|
|____|
attr 1,1 bold

ALT-10: Resetting 1049 on the normal screen still restores

\e[2;3H
\e7
\e[1;1H
\e[?1049l
|____|
|____|
cursor 2,3

ALT-11: Each screen has its own saved cursor

\e[2;2H
\e7       # saved for the normal screen
\e[?47h
\e[2;4H
\e7       # saved for the alternate screen
\e[?47l
\e[1;1H
\e8
|____|
|____|
cursor 2,2

ALT-12: Nothing saved on the alternate screen

\e[2;2H
\e7
\e[?47h
\e[1;4H
\e8       # the alternate screen has nothing saved: home
|____|
|____|
cursor 1,1

ALT-13: 1049 set on the alternate screen

AB
\e[?47h
X
\e[?1049h # saves into the alternate screen's slot
\e[?1049l # restores from the normal screen's: nothing there
|AB__|
|____|
cursor 1,1

ALT-14: 1048 is DECSC and DECRC

\e[2;3H
\e[?1048h
\e[1;1H
\e[?1048l
|____|
|____|
cursor 2,3

ALT-15: DECRQM reports the screen, not the mode

\e[?1049h
\e[?47$p
\e[?1047$p
\e[?1049$p
|____|
|____|
reply \e[?47;1$y\e[?1047;1$y\e[?1049;1$y

ALT-16: 1048 reports a saved cursor

\e7
\e[?1048$p
|____|
|____|
reply \e[?1048;1$y

ALT-17: 1046 answers backwards

\e[?1046h # allow switching, as it already is
\e[?1046$p
|____|
|____|
reply \e[?1046;2$y

ALT-18: Switching forbidden

AB
\e[?1046l
\e[?47h   # ignored
X
|ABX_|
|____|

ALT-19: RIS goes back to the normal screen

AB
\e[?47h
\ec
\e[?47$p
|____|
|____|
cursor 1,1
reply \e[?47;2$y
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.