Skip to content

Commit 23743ba

Browse files
Calixte Pernotgregkh
authored andcommitted
vt: add support for smput/rmput escape codes
Support "\e[?1049h" and "\e[?1049l" escape codes. This patch allows programs to enter and leave alternate screens. This feature is widely available in graphical terminal emulators and mostly used by fullscreen terminal-based user interfaces such as text editors. Most editors such as vim and nano assume this escape code in not supported and will not try to print the escape sequence if TERM=linux. To try out this patch, run `TERM=xterm-256color vim` inside a VT. Signed-off-by: Calixte Pernot <calixte.pernot@grenoble-inp.org> Link: https://lore.kernel.org/r/20250825125607.2478-3-calixte.pernot@grenoble-inp.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cc4d900 commit 23743ba

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

drivers/tty/vt/vt.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES];
141141
static int con_open(struct tty_struct *, struct file *);
142142
static void vc_init(struct vc_data *vc, int do_clear);
143143
static void gotoxy(struct vc_data *vc, int new_x, int new_y);
144+
static void restore_cur(struct vc_data *vc);
144145
static void save_cur(struct vc_data *vc);
145146
static void reset_terminal(struct vc_data *vc, int do_clear);
146147
static void con_flush_chars(struct tty_struct *tty);
@@ -1341,6 +1342,10 @@ struct vc_data *vc_deallocate(unsigned int currcons)
13411342
kfree(vc->vc_screenbuf);
13421343
vc_cons[currcons].d = NULL;
13431344
}
1345+
if (vc->vc_saved_screen != NULL) {
1346+
kfree(vc->vc_saved_screen);
1347+
vc->vc_saved_screen = NULL;
1348+
}
13441349
return vc;
13451350
}
13461351

@@ -1875,6 +1880,45 @@ static int get_bracketed_paste(struct tty_struct *tty)
18751880
return vc->vc_bracketed_paste;
18761881
}
18771882

1883+
/* console_lock is held */
1884+
static void enter_alt_screen(struct vc_data *vc)
1885+
{
1886+
unsigned int size = vc->vc_rows * vc->vc_cols * 2;
1887+
1888+
if (vc->vc_saved_screen != NULL)
1889+
return; /* Already inside an alt-screen */
1890+
vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
1891+
if (vc->vc_saved_screen == NULL)
1892+
return;
1893+
vc->vc_saved_rows = vc->vc_rows;
1894+
vc->vc_saved_cols = vc->vc_cols;
1895+
save_cur(vc);
1896+
/* clear entire screen */
1897+
csi_J(vc, CSI_J_FULL);
1898+
}
1899+
1900+
/* console_lock is held */
1901+
static void leave_alt_screen(struct vc_data *vc)
1902+
{
1903+
unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
1904+
unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
1905+
u16 *src, *dest;
1906+
1907+
if (vc->vc_saved_screen == NULL)
1908+
return; /* Not inside an alt-screen */
1909+
for (unsigned int r = 0; r < rows; r++) {
1910+
src = vc->vc_saved_screen + r * vc->vc_saved_cols;
1911+
dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
1912+
memcpy(dest, src, 2 * cols);
1913+
}
1914+
restore_cur(vc);
1915+
/* Update the entire screen */
1916+
if (con_should_update(vc))
1917+
do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
1918+
kfree(vc->vc_saved_screen);
1919+
vc->vc_saved_screen = NULL;
1920+
}
1921+
18781922
enum {
18791923
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
18801924
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1885,6 +1929,7 @@ enum {
18851929
CSI_DEC_hl_MOUSE_X10 = 9,
18861930
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
18871931
CSI_DEC_hl_MOUSE_VT200 = 1000,
1932+
CSI_DEC_hl_ALT_SCREEN = 1049,
18881933
CSI_DEC_hl_BRACKETED_PASTE = 2004,
18891934
};
18901935

@@ -1941,6 +1986,12 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
19411986
case CSI_DEC_hl_BRACKETED_PASTE:
19421987
vc->vc_bracketed_paste = on_off;
19431988
break;
1989+
case CSI_DEC_hl_ALT_SCREEN:
1990+
if (on_off)
1991+
enter_alt_screen(vc);
1992+
else
1993+
leave_alt_screen(vc);
1994+
break;
19441995
}
19451996
}
19461997

@@ -2179,6 +2230,13 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
21792230
vc->vc_deccm = global_cursor_default;
21802231
vc->vc_decim = 0;
21812232

2233+
if (vc->vc_saved_screen != NULL) {
2234+
kfree(vc->vc_saved_screen);
2235+
vc->vc_saved_screen = NULL;
2236+
vc->vc_saved_rows = 0;
2237+
vc->vc_saved_cols = 0;
2238+
}
2239+
21822240
vt_reset_keyboard(vc->vc_num);
21832241

21842242
vc->vc_cursor_type = cur_default;

include/linux/console_struct.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ struct vc_data {
159159
struct uni_pagedict *uni_pagedict;
160160
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
161161
u32 **vc_uni_lines; /* unicode screen content */
162+
u16 *vc_saved_screen;
163+
unsigned int vc_saved_cols;
164+
unsigned int vc_saved_rows;
162165
/* additional information is in vt_kern.h */
163166
};
164167

0 commit comments

Comments
 (0)