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.
This commit is contained in:
Daniel Eklöf 2022-05-11 17:58:18 +02:00
parent 3431619d07
commit fc67bff9c0
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 18 additions and 4 deletions

View file

@ -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

View file

@ -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);