[PATCH 18/20] fbconsole: implement alternate screen buffer (ESC[?1049h/l)

Ahmad Fatoum a.fatoum at barebox.org
Sun May 3 01:33:20 PDT 2026


The alternate screen buffer is distinct from the scrollback-enabled
primary buffer and meant for full screen applications.

The ?1049 mode in particular is a superset of it that includes saving
the cursor and clearing the buffer when entering.

Implement it via taking a snapshot of the framebuffer's pixels.

Link: https://terminalguide.namepad.de/mode/p1049/
Signed-off-by: Ahmad Fatoum <a.fatoum at barebox.org>
---
 drivers/video/fbconsole.c | 46 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c
index bed55de7571e..3a2a680fc719 100644
--- a/drivers/video/fbconsole.c
+++ b/drivers/video/fbconsole.c
@@ -81,6 +81,10 @@ struct fbc_priv {
 	struct fbc_screen_state cur;
 	struct fbc_screen_state saved; /* DEC cursor save (\e7) */
 
+	struct fbc_screen_state altscreen_saved;
+	void *altscreen_buf;	/* pixel snapshot while in alternate screen */
+	size_t altscreen_size;
+
 	unsigned int rotation;
 	enum state_t state;
 
@@ -651,6 +655,21 @@ static bool fbc_parse_csi(struct fbc_priv *priv)
 			/* show cursor now */
 			toggle_cursor_visibility(priv);
 			return true;
+		case 1049: /* alternate screen: save pixel buffer and state */
+			if (!priv->altscreen_buf) {
+				void *src = gui_screen_render_buffer(priv->sc);
+				size_t sz = priv->fb->line_length * priv->fb->yres;
+
+				priv->altscreen_buf = memdup(src, sz);
+				if (priv->altscreen_buf) {
+					priv->altscreen_size  = sz;
+					priv->altscreen_saved = priv->cur;
+				}
+				priv->cur = (struct fbc_screen_state){};
+				fbc_reset_colors(priv);
+				cls(priv);
+			}
+			return true;
 		}
 		break;
 	case 'l':
@@ -664,6 +683,27 @@ static bool fbc_parse_csi(struct fbc_priv *priv)
 			/* hide cursor now */
 			priv->cur.flags |= HIDE_CURSOR;
 			return true;
+		case 1049: /* alternate screen: restore pixel buffer and state */
+			if (priv->altscreen_buf) {
+				void *dst = gui_screen_render_buffer(priv->sc);
+				size_t sz = priv->fb->line_length * priv->fb->yres;
+
+				if (sz == priv->altscreen_size) {
+					memcpy(dst, priv->altscreen_buf, sz);
+					gu_screen_blit(priv->sc);
+				} else {
+					cls(priv);
+				}
+				free(priv->altscreen_buf);
+				priv->altscreen_buf  = NULL;
+				priv->altscreen_size = 0;
+				priv->cur = priv->altscreen_saved;
+			} else {
+				priv->cur = (struct fbc_screen_state){};
+				fbc_reset_colors(priv);
+				cls(priv);
+			}
+			return true;
 		}
 		break;
 	case 'J':
@@ -914,6 +954,12 @@ static int fbc_close(struct console_device *cdev)
 	struct fbc_priv *priv = container_of(cdev,
 					struct fbc_priv, cdev);
 
+	if (priv->altscreen_buf) {
+		free(priv->altscreen_buf);
+		priv->altscreen_buf  = NULL;
+		priv->altscreen_size = 0;
+	}
+
 	if (priv->active) {
 		fb_close(priv->sc);
 		priv->active = false;
-- 
2.47.3




More information about the barebox mailing list