From fc67bff9c0732f205b6850e4e6585355fc565482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 11 May 2022 17:58:18 +0200 Subject: [PATCH] terminal: move viewport when part of it is scrolled out If the viewport is at the top of the scrollback, and a program is scrolling (e.g. by emitting newlines), the viewport needs to be moved. Otherwise, the top of the viewport will show the *bottom* of the scrollback (i.e. the newly emitted lines), and the bottom of the viewport shows the top of the scrollback. How do we detect if the viewport needs to be moved? We convert its absolute row number to a scrollback relative row. This number is also the maximum number of rows we can scroll without the viewport being scrolled out. In other words, if the number of rows to scroll is larger than the viewports scrollback relative row number, the viewport needs to moved. How much do we need to move it? The difference between the number of rows to scroll, and the viewports scrollback relative row number. Example: if the viewport is at the very top of the scrollback, its scrollback relative row number is 0. In this case, it needs to be moved the same number of rows as is being scrolled. --- CHANGELOG.md | 5 +++++ terminal.c | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68e67049..cf54368d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,11 @@ ### Deprecated ### Removed ### Fixed + +* Graphical corruption when viewport is at the top of the scrollback, + and the output is scrolling. + + ### Security ### Contributors diff --git a/terminal.c b/terminal.c index 960d6d24..09c9caea 100644 --- a/terminal.c +++ b/terminal.c @@ -23,6 +23,7 @@ #include "log.h" #include "async.h" +#include "commands.h" #include "config.h" #include "debug.h" #include "extract.h" @@ -34,9 +35,9 @@ #include "reaper.h" #include "render.h" #include "selection.h" +#include "shm.h" #include "sixel.h" #include "slave.h" -#include "shm.h" #include "spawn.h" #include "url-mode.h" #include "util.h" @@ -2544,13 +2545,22 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows sixel_scroll_up(term, rows); + /* How many lines from the scrollback start is the current viewport? */ + int view_sb_start_distance = grid_row_abs_to_sb( + term->grid, term->rows, term->grid->view); + bool view_follows = term->grid->view == term->grid->offset; term->grid->offset += rows; term->grid->offset &= term->grid->num_rows - 1; - if (view_follows) { + if (likely(view_follows)) { selection_view_down(term, term->grid->offset); term->grid->view = term->grid->offset; + } else if (unlikely(rows > view_sb_start_distance)) { + /* Part of current view is being scrolled out */ + int new_view = grid_row_sb_to_abs(term->grid, term->rows, 0); + selection_view_down(term, new_view); + cmd_scrollback_down(term, rows - view_sb_start_distance); } /* Top non-scrolling region. */ @@ -2611,8 +2621,7 @@ term_scroll_reverse_partial(struct terminal *term, bool view_follows = term->grid->view == term->grid->offset; term->grid->offset -= rows; - while (term->grid->offset < 0) - term->grid->offset += term->grid->num_rows; + term->grid->offset += term->grid->num_rows; term->grid->offset &= term->grid->num_rows - 1; xassert(term->grid->offset >= 0);