patch 9.2.0483: popup: terminal embedded in an opacity popup freezes Vim on input

Problem:  When a terminal buffer is shown inside a popup with 'opacity'
          set to a value other than 100, typing into it freezes Vim.
          Only the first keystroke is drawn; afterwards no input is
          processed and the screen stops updating.
Solution: When marking background lines for redraw to keep opacity
          blend cells fresh, do not raise must_redraw.  This marking
          happens from inside update_screen() (via
          may_update_popup_mask()), so raising must_redraw makes
          terminal_loop()'s "while (must_redraw != 0) update_screen()"
          loop never terminate.  Add redraw_win_range_now() that
          updates only the per-window state and use it from
          redraw_win_under_opacity_popup() (Hirohito Higashi)

fixes:  #20214
closes: #20220

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi
2026-05-15 15:02:48 +00:00
committed by Christian Brabandt
parent 37d61dae72
commit f281493c49
5 changed files with 54 additions and 1 deletions
+22
View File
@@ -3497,6 +3497,28 @@ redraw_win_range_later(
}
}
/*
* Like redraw_win_range_later() but do not raise the global must_redraw.
* Use this from inside an update_screen() pass (where the redraw will be
* picked up this cycle), to avoid triggering an extra full redraw cycle.
*/
void
redraw_win_range_now(
win_T *wp,
linenr_T first,
linenr_T last)
{
if (last >= wp->w_topline && first < wp->w_botline)
{
if (wp->w_redraw_top == 0 || wp->w_redraw_top > first)
wp->w_redraw_top = first;
if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < last)
wp->w_redraw_bot = last;
if (wp->w_redr_type < UPD_VALID)
wp->w_redr_type = UPD_VALID;
}
}
#ifdef FEAT_EVAL
static bool redraw_cb_in_progress = false;
+3 -1
View File
@@ -5311,7 +5311,9 @@ redraw_win_under_opacity_popup(win_T *wp)
linenr_T lnum;
(void)mouse_comp_pos(twp, &line_cp, &col_cp, &lnum, NULL);
redrawWinline(twp, lnum);
// Called from inside update_screen(); raising must_redraw
// would loop the outer redraw indefinitely.
redraw_win_range_now(twp, lnum, lnum);
}
else if (line_cp == twp->w_height)
// Status bar line: mark for redraw to prevent
+1
View File
@@ -25,6 +25,7 @@ void redraw_statuslines(void);
void win_redraw_last_status(frame_T *frp);
void redrawWinline(win_T *wp, linenr_T lnum);
void redraw_win_range_later(win_T *wp, linenr_T first, linenr_T last);
void redraw_win_range_now(win_T *wp, linenr_T first, linenr_T last);
void f_redraw_listener_add(typval_T *argvars, typval_T *rettv);
void f_redraw_listener_remove(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
+26
View File
@@ -5180,6 +5180,32 @@ func Test_popup_opacity_zero()
call StopVimInTerminal(buf)
endfunc
func Test_popup_opacity_terminal_no_freeze()
CheckFeature terminal
CheckUnix
let g:test_is_flaky = 1
let origwin = win_getid()
let termbuf = term_start(&shell, #{hidden: 1})
let winid = popup_create(termbuf, #{minwidth: 40, minheight: 10,
\ border: [1, 1, 1, 1], opacity: 10})
call WaitForAssert({-> assert_equal("run", job_status(term_getjob(termbuf)))})
call WaitForAssert({-> assert_equal(' ', screenstring(screenrow(), screencol() - 1))})
" Before the fix typing froze Vim: redraw under an opacity popup raised
" must_redraw every cycle, trapping terminal_loop in its redraw loop.
call feedkeys('x', 'xt')
call term_wait(termbuf)
redraw
call WaitForAssert({-> assert_equal('x', screenstring(screenrow(), screencol() - 1))})
call feedkeys("\<BS>", 'xt')
call feedkeys("exit\<CR>", 'xt')
call WaitForAssert({-> assert_equal("dead", job_status(term_getjob(termbuf)))})
call feedkeys(":quit\<CR>", 'xt')
call assert_equal(origwin, win_getid())
endfunc
func Test_popup_getwininfo_tabnr()
tab split
let winid1 = popup_create('sup', #{tabpage: 1})
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
483,
/**/
482,
/**/