* [PATCH] vt: add support for smput/rmput escape codes
@ 2025-08-24 14:20 Calixte Pernot
2025-08-25 5:47 ` Jiri Slaby
0 siblings, 1 reply; 4+ messages in thread
From: Calixte Pernot @ 2025-08-24 14:20 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby; +Cc: linux-kernel, linux-serial, Calixte Pernot
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>
---
drivers/tty/vt/vt.c | 59 ++++++++++++++++++++++++++++++++++
include/linux/console_struct.h | 3 ++
2 files changed, 62 insertions(+)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 62049ceb3..0e3632aa1 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -141,6 +141,7 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
static void vc_init(struct vc_data *vc, int do_clear);
static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void restore_cur(struct vc_data *vc);
static void save_cur(struct vc_data *vc);
static void reset_terminal(struct vc_data *vc, int do_clear);
static void con_flush_chars(struct tty_struct *tty);
@@ -1344,6 +1345,10 @@ struct vc_data *vc_deallocate(unsigned int currcons)
kfree(vc->vc_screenbuf);
vc_cons[currcons].d = NULL;
}
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ }
return vc;
}
@@ -1878,6 +1883,46 @@ static int get_bracketed_paste(struct tty_struct *tty)
return vc->vc_bracketed_paste;
}
+/* console_lock is held */
+static void enter_alt_screen(struct vc_data *vc)
+{
+ unsigned int size = vc->vc_rows * vc->vc_cols * 2;
+
+ if (vc->vc_saved_screen != NULL)
+ return; /* Already inside an alt-screen */
+ vc->vc_saved_screen = kzalloc(size, GFP_NOWAIT);
+ if (vc->vc_saved_screen == NULL)
+ return;
+ memcpy(vc->vc_saved_screen, (u16 *)vc->vc_origin, size);
+ vc->vc_saved_rows = vc->vc_rows;
+ vc->vc_saved_cols = vc->vc_cols;
+ save_cur(vc);
+ /* clear entire screen */
+ csi_J(vc, CSI_J_FULL);
+}
+
+/* console_lock is held */
+static void leave_alt_screen(struct vc_data *vc)
+{
+ unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
+ unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
+ unsigned short *src, *dest;
+
+ if (vc->vc_saved_screen == NULL)
+ return; /* Not inside an alt-screen */
+ for (int r = 0; r < rows; r++) {
+ src = vc->vc_saved_screen + r * vc->vc_saved_cols;
+ dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
+ memcpy(dest, src, 2 * cols);
+ }
+ restore_cur(vc);
+ /* Update the entire screen */
+ if (con_should_update(vc))
+ do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+}
+
enum {
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1888,6 +1933,7 @@ enum {
CSI_DEC_hl_MOUSE_X10 = 9,
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
CSI_DEC_hl_MOUSE_VT200 = 1000,
+ CSI_DEC_hl_ALT_SCREEN = 1049,
CSI_DEC_hl_BRACKETED_PASTE = 2004,
};
@@ -1944,6 +1990,12 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
case CSI_DEC_hl_BRACKETED_PASTE:
vc->vc_bracketed_paste = on_off;
break;
+ case CSI_DEC_hl_ALT_SCREEN:
+ if (on_off)
+ enter_alt_screen(vc);
+ else
+ leave_alt_screen(vc);
+ break;
}
}
@@ -2182,6 +2234,13 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_deccm = global_cursor_default;
vc->vc_decim = 0;
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ vc->vc_saved_rows = 0;
+ vc->vc_saved_cols = 0;
+ }
+
vt_reset_keyboard(vc->vc_num);
vc->vc_cursor_type = cur_default;
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 59b4fec5f..f9aabc3cf 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -159,6 +159,9 @@ struct vc_data {
struct uni_pagedict *uni_pagedict;
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
u32 **vc_uni_lines; /* unicode screen content */
+ unsigned short *vc_saved_screen;
+ unsigned int vc_saved_cols;
+ unsigned int vc_saved_rows;
/* additional information is in vt_kern.h */
};
--
2.50.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] vt: add support for smput/rmput escape codes
2025-08-24 14:20 [PATCH] vt: add support for smput/rmput escape codes Calixte Pernot
@ 2025-08-25 5:47 ` Jiri Slaby
2025-08-25 11:41 ` Calixte Pernot
2025-08-25 12:56 ` [PATCH v2] " Calixte Pernot
0 siblings, 2 replies; 4+ messages in thread
From: Jiri Slaby @ 2025-08-25 5:47 UTC (permalink / raw)
To: Calixte Pernot, Greg Kroah-Hartman; +Cc: linux-kernel, linux-serial
Hi,
On 24. 08. 25, 16:20, Calixte Pernot wrote:
> 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>
...
> --- a/drivers/tty/vt/vt.c
> +++ b/drivers/tty/vt/vt.c
...
> @@ -1878,6 +1883,46 @@ static int get_bracketed_paste(struct tty_struct *tty)
> return vc->vc_bracketed_paste;
> }
>
> +/* console_lock is held */
> +static void enter_alt_screen(struct vc_data *vc)
> +{
> + unsigned int size = vc->vc_rows * vc->vc_cols * 2;
> +
> + if (vc->vc_saved_screen != NULL)
> + return; /* Already inside an alt-screen */
All this is protected by console_lock, right?
> + vc->vc_saved_screen = kzalloc(size, GFP_NOWAIT);
Why GFP_NOWAIT?
> + if (vc->vc_saved_screen == NULL)
> + return;
> + memcpy(vc->vc_saved_screen, (u16 *)vc->vc_origin, size);
kmemdup();
> + vc->vc_saved_rows = vc->vc_rows;
> + vc->vc_saved_cols = vc->vc_cols;
> + save_cur(vc);
> + /* clear entire screen */
> + csi_J(vc, CSI_J_FULL);
> +}
> +
> +/* console_lock is held */
> +static void leave_alt_screen(struct vc_data *vc)
> +{
> + unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
> + unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
> + unsigned short *src, *dest;
u16
> +
> + if (vc->vc_saved_screen == NULL)
> + return; /* Not inside an alt-screen */
> + for (int r = 0; r < rows; r++) {
unsigned
> + src = vc->vc_saved_screen + r * vc->vc_saved_cols;
> + dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
> + memcpy(dest, src, 2 * cols);
> + }
> + restore_cur(vc);
> + /* Update the entire screen */
> + if (con_should_update(vc))
> + do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
> + kfree(vc->vc_saved_screen);
> + vc->vc_saved_screen = NULL;
> +}
...
> --- a/include/linux/console_struct.h
> +++ b/include/linux/console_struct.h
> @@ -159,6 +159,9 @@ struct vc_data {
> struct uni_pagedict *uni_pagedict;
> struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
> u32 **vc_uni_lines; /* unicode screen content */
> + unsigned short *vc_saved_screen;
u16 *
> + unsigned int vc_saved_cols;
> + unsigned int vc_saved_rows;
> /* additional information is in vt_kern.h */
> };
>
thanks,
--
js
suse labs
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] vt: add support for smput/rmput escape codes
2025-08-25 5:47 ` Jiri Slaby
@ 2025-08-25 11:41 ` Calixte Pernot
2025-08-25 12:56 ` [PATCH v2] " Calixte Pernot
1 sibling, 0 replies; 4+ messages in thread
From: Calixte Pernot @ 2025-08-25 11:41 UTC (permalink / raw)
To: Jiri Slaby, Greg Kroah-Hartman; +Cc: linux-kernel, linux-serial
Hi, thanks for your response.
On 8/25/25 07:47, Jiri Slaby wrote:
> Hi,
>
> On 24. 08. 25, 16:20, Calixte Pernot wrote:
>> 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>
> ...
>> --- a/drivers/tty/vt/vt.c
>> +++ b/drivers/tty/vt/vt.c
> ...
>> @@ -1878,6 +1883,46 @@ static int get_bracketed_paste(struct
>> tty_struct *tty)
>> return vc->vc_bracketed_paste;
>> }
>> +/* console_lock is held */
>> +static void enter_alt_screen(struct vc_data *vc)
>> +{
>> + unsigned int size = vc->vc_rows * vc->vc_cols * 2;
>> +
>> + if (vc->vc_saved_screen != NULL)
>> + return; /* Already inside an alt-screen */
>
> All this is protected by console_lock, right?
Yes. The 2 functions I added are called by csi_DEC_hl, itself protected
by console_lock.
console_lock() is called in do_con_write, and the call stack looks like
this:
do_con_write -> do_con_trol -> csi_DEC -> csi_DEC_hl ->
enter/leave_alt_screen
>> + vc->vc_saved_screen = kzalloc(size, GFP_NOWAIT);
>
> Why GFP_NOWAIT?
To be honest I used the same flags as vc->vc_screenbuf, but after
"reading the F-ing manual", this seems unappropriate here.
"GFP_KERNEL implies GFP_RECLAIM, which means that direct reclaim may be
triggered under memory pressure; the calling context must be allowed to
sleep"
I guess we are allowed to sleep here (please correct me if i'm wrong),
so GFP_KERNEL must be more appropriate.
>> + if (vc->vc_saved_screen == NULL)
>> + return;
>> + memcpy(vc->vc_saved_screen, (u16 *)vc->vc_origin, size);
>
> kmemdup();
>
>> ed_cols, vc->vc_cols);
>> + unsigned short *src, *dest;
>
> u16
>
>> +
>> + if (vc->vc_saved_screen == NULL)
>> + return; /* Not inside an alt-screen */
>> + for (int r = 0; r < rows; r++) {
>
> unsigned
>> --- a/include/linux/console_struct.h
>> +++ b/include/linux/console_struct.h
>> @@ -159,6 +159,9 @@ struct vc_data {
>> struct uni_pagedict *uni_pagedict;
>> struct uni_pagedict **uni_pagedict_loc; /* [!] Location of
>> uni_pagedict variable for this console */
>> u32 **vc_uni_lines; /* unicode screen content */
>> + unsigned short *vc_saved_screen;
>
> u16 *
>
>> + unsigned int vc_saved_cols;
>> + unsigned int vc_saved_rows;
>> /* additional information is in vt_kern.h */
>> };
>
> thanks,
Thanks for the review, I'll rewrite the patch with the suggested changes
and send it back.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2] vt: add support for smput/rmput escape codes
2025-08-25 5:47 ` Jiri Slaby
2025-08-25 11:41 ` Calixte Pernot
@ 2025-08-25 12:56 ` Calixte Pernot
1 sibling, 0 replies; 4+ messages in thread
From: Calixte Pernot @ 2025-08-25 12:56 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby; +Cc: linux-kernel, linux-serial, Calixte Pernot
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>
---
drivers/tty/vt/vt.c | 58 ++++++++++++++++++++++++++++++++++
include/linux/console_struct.h | 3 ++
2 files changed, 61 insertions(+)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 62049ceb3..bda2a6f76 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -141,6 +141,7 @@ static const struct consw *con_driver_map[MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
static void vc_init(struct vc_data *vc, int do_clear);
static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void restore_cur(struct vc_data *vc);
static void save_cur(struct vc_data *vc);
static void reset_terminal(struct vc_data *vc, int do_clear);
static void con_flush_chars(struct tty_struct *tty);
@@ -1344,6 +1345,10 @@ struct vc_data *vc_deallocate(unsigned int currcons)
kfree(vc->vc_screenbuf);
vc_cons[currcons].d = NULL;
}
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ }
return vc;
}
@@ -1878,6 +1883,45 @@ static int get_bracketed_paste(struct tty_struct *tty)
return vc->vc_bracketed_paste;
}
+/* console_lock is held */
+static void enter_alt_screen(struct vc_data *vc)
+{
+ unsigned int size = vc->vc_rows * vc->vc_cols * 2;
+
+ if (vc->vc_saved_screen != NULL)
+ return; /* Already inside an alt-screen */
+ vc->vc_saved_screen = kmemdup((u16 *)vc->vc_origin, size, GFP_KERNEL);
+ if (vc->vc_saved_screen == NULL)
+ return;
+ vc->vc_saved_rows = vc->vc_rows;
+ vc->vc_saved_cols = vc->vc_cols;
+ save_cur(vc);
+ /* clear entire screen */
+ csi_J(vc, CSI_J_FULL);
+}
+
+/* console_lock is held */
+static void leave_alt_screen(struct vc_data *vc)
+{
+ unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
+ unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
+ u16 *src, *dest;
+
+ if (vc->vc_saved_screen == NULL)
+ return; /* Not inside an alt-screen */
+ for (unsigned int r = 0; r < rows; r++) {
+ src = vc->vc_saved_screen + r * vc->vc_saved_cols;
+ dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
+ memcpy(dest, src, 2 * cols);
+ }
+ restore_cur(vc);
+ /* Update the entire screen */
+ if (con_should_update(vc))
+ do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+}
+
enum {
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1888,6 +1932,7 @@ enum {
CSI_DEC_hl_MOUSE_X10 = 9,
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
CSI_DEC_hl_MOUSE_VT200 = 1000,
+ CSI_DEC_hl_ALT_SCREEN = 1049,
CSI_DEC_hl_BRACKETED_PASTE = 2004,
};
@@ -1944,6 +1989,12 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
case CSI_DEC_hl_BRACKETED_PASTE:
vc->vc_bracketed_paste = on_off;
break;
+ case CSI_DEC_hl_ALT_SCREEN:
+ if (on_off)
+ enter_alt_screen(vc);
+ else
+ leave_alt_screen(vc);
+ break;
}
}
@@ -2182,6 +2233,13 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_deccm = global_cursor_default;
vc->vc_decim = 0;
+ if (vc->vc_saved_screen != NULL) {
+ kfree(vc->vc_saved_screen);
+ vc->vc_saved_screen = NULL;
+ vc->vc_saved_rows = 0;
+ vc->vc_saved_cols = 0;
+ }
+
vt_reset_keyboard(vc->vc_num);
vc->vc_cursor_type = cur_default;
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 59b4fec5f..13b35637b 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -159,6 +159,9 @@ struct vc_data {
struct uni_pagedict *uni_pagedict;
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
u32 **vc_uni_lines; /* unicode screen content */
+ u16 *vc_saved_screen;
+ unsigned int vc_saved_cols;
+ unsigned int vc_saved_rows;
/* additional information is in vt_kern.h */
};
--
2.50.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-08-25 12:57 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-24 14:20 [PATCH] vt: add support for smput/rmput escape codes Calixte Pernot
2025-08-25 5:47 ` Jiri Slaby
2025-08-25 11:41 ` Calixte Pernot
2025-08-25 12:56 ` [PATCH v2] " Calixte Pernot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).