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 <[email protected]>
---
 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


Reply via email to