Fix handling of scroll position when swapping screens.

If the user is scrolled back in the scrollback when a screen-swap
takes place, and if we're not configured to reset the scrollback
completely on the grounds that the swap is display activity, then we
should do the same thing we do for other kinds of display activity:
strive to keep the scroll position pointing at the same text. In this
case, that means adjusting term->disptop by the number of virtual
lines added to the scrollback to allow the main screen to be viewed
while the alt screen is active.

This improves the quality of behaviour in that corner case, but more
importantly, it should also fix a case of the dreaded line==NULL
assertion failure, which someone just reported against 0.73 when
exiting tmux (hence, switching away from the alt screen) while
scrolled back in a purely virtual scrollback buffer: the virtual
scrollback lines vanished, but disptop was still set to a negative
value, which made it out of range.

(cherry picked from commit 22453b46da)
This commit is contained in:
Simon Tatham 2019-12-30 23:23:42 +00:00
Родитель b77bcae021
Коммит 874ce8239c
1 изменённых файлов: 35 добавлений и 0 удалений

Просмотреть файл

@ -2046,6 +2046,21 @@ static void swap_screen(Terminal *term, int which,
reset = false; /* do no weird resetting if which==0 */
if (which != term->alt_which) {
if (term->erase_to_scrollback && term->alt_screen &&
term->alt_which && term->disptop < 0) {
/*
* We're swapping away from the alternate screen, so some
* lines are about to vanish from the virtual scrollback.
* Adjust disptop by that much, so that (if we're not
* resetting the scrollback anyway on a display event) the
* current scroll position still ends up pointing at the
* same text.
*/
term->disptop += term->alt_sblines;
if (term->disptop > 0)
term->disptop = 0;
}
term->alt_which = which;
ttr = term->alt_screen;
@ -2120,6 +2135,26 @@ static void swap_screen(Terminal *term, int which,
if (!reset)
term->save_sco_acs = term->alt_save_sco_acs;
term->alt_save_sco_acs = t;
if (term->erase_to_scrollback && term->alt_screen &&
term->alt_which && term->disptop < 0) {
/*
* Inverse of the adjustment at the top of this function.
* This time, we're swapping _to_ the alternate screen, so
* some lines are about to _appear_ in the virtual
* scrollback, and we adjust disptop in the other
* direction.
*
* Both these adjustments depend on the value stored in
* term->alt_sblines while the alt screen is selected,
* which is why we had to do one _before_ switching away
* from it and the other _after_ switching to it.
*/
term->disptop -= term->alt_sblines;
int limit = -sblines(term);
if (term->disptop < limit)
term->disptop = limit;
}
}
if (reset && term->screen) {