mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0477: popup: leftover content after popup_free under layout change
Problem: popup_mask still marks the freed popup's cells as covered
until may_update_popup_mask() runs inside the next
update_screen. Any screen_fill / screen_puts called in
between (for example msg_clr_eos triggered by a status message
from :copen) hits skip_for_popup() and silently drops writes
to those cells, so the popup's chars survive on screen until
those cells happen to be redrawn for another reason.
Solution: Add popup_clear_mask_for() and call it from popup_hide() and
popup_free() when the popup was visible, so the upcoming
writes take effect immediately (Yasuhiro Matsumoto)
Note: The test is limited to MS-Windows because the original report
(#20178) was reproduced there and the redraw timing required to
surface the bug differs on other platforms.
fixes: #20178
closes: #20188
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
38237411e4
commit
3a9e1bb7e2
@@ -3522,10 +3522,38 @@ f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
popup_close_and_callback(wp, &argvars[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear popup_mask entries for the cells covered by "wp" so that
|
||||
* screen_fill / screen_puts calls made before the next update_screen()
|
||||
* (e.g. msg_clr_eos triggered by a status message) are not silently
|
||||
* dropped by skip_for_popup(). Without this the popup's chars survive
|
||||
* on screen until may_update_popup_mask() runs and the affected cells
|
||||
* happen to be redrawn.
|
||||
*/
|
||||
static void
|
||||
popup_clear_mask_for(win_T *wp)
|
||||
{
|
||||
int r, c;
|
||||
int row_start, col_start, row_end, col_end;
|
||||
|
||||
if (popup_mask == NULL || !popup_visible)
|
||||
return;
|
||||
|
||||
row_start = MAX(wp->w_winrow, 0);
|
||||
col_start = MAX(wp->w_wincol, 0);
|
||||
row_end = MIN(wp->w_winrow + popup_height(wp), (int)screen_Rows);
|
||||
col_end = MIN(wp->w_wincol + popup_width(wp), (int)screen_Columns);
|
||||
|
||||
for (r = row_start; r < row_end; ++r)
|
||||
for (c = col_start; c < col_end; ++c)
|
||||
popup_mask[r * screen_Columns + c] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
popup_hide(win_T *wp)
|
||||
{
|
||||
popup_area_T old_area;
|
||||
int was_visible = (wp->w_popup_flags & POPF_HIDDEN) == 0;
|
||||
|
||||
#ifdef FEAT_TERMINAL
|
||||
if (error_if_term_popup_window())
|
||||
@@ -3541,6 +3569,9 @@ popup_hide(win_T *wp)
|
||||
if (wp->w_winrow + popup_height(wp) >= cmdline_row)
|
||||
clear_cmdline = TRUE;
|
||||
|
||||
if (was_visible)
|
||||
popup_clear_mask_for(wp);
|
||||
|
||||
if (old_area.active)
|
||||
popup_redraw_exposed_area(&old_area);
|
||||
else
|
||||
@@ -3725,6 +3756,7 @@ f_popup_setbuf(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
popup_free(win_T *wp)
|
||||
{
|
||||
popup_area_T old_area;
|
||||
int was_visible = (wp->w_popup_flags & POPF_HIDDEN) == 0;
|
||||
|
||||
popup_save_area(wp, &old_area);
|
||||
|
||||
@@ -3733,6 +3765,9 @@ popup_free(win_T *wp)
|
||||
if (wp->w_winrow + popup_height(wp) >= cmdline_row)
|
||||
clear_cmdline = TRUE;
|
||||
|
||||
if (was_visible)
|
||||
popup_clear_mask_for(wp);
|
||||
|
||||
popup_redraw_exposed_area(&old_area);
|
||||
|
||||
win_free_popup(wp);
|
||||
|
||||
@@ -5408,4 +5408,52 @@ func Test_popupwin_close_status_redraw()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_popupwin_close_copen_redraw()
|
||||
CheckMSWindows
|
||||
CheckFeature quickfix
|
||||
|
||||
func! s:OpenPopup()
|
||||
call popup_create(repeat(['ZZZZZZZZZ'], 10), #{
|
||||
\ pos: 'botright',
|
||||
\ col: &columns,
|
||||
\ line: &lines,
|
||||
\ filter: function('s:PopupFilter'),
|
||||
\ })
|
||||
endfunc
|
||||
func! s:PopupFilter(winid, key)
|
||||
if a:key ==# 'q'
|
||||
call popup_close(a:winid)
|
||||
copen
|
||||
endif
|
||||
return 1
|
||||
endfunc
|
||||
|
||||
enew!
|
||||
call setline(1, range(1, 30))
|
||||
call setqflist(map(range(1, 20),
|
||||
\ {_, v -> {'bufnr': bufnr('%'), 'lnum': v, 'col': 1, 'text': 'item ' .. v}}))
|
||||
|
||||
call s:OpenPopup()
|
||||
redraw
|
||||
call feedkeys('q', 'xt')
|
||||
redraw
|
||||
cclose
|
||||
redraw
|
||||
|
||||
call s:OpenPopup()
|
||||
redraw
|
||||
call feedkeys('q', 'xt')
|
||||
redraw
|
||||
|
||||
for row in range(&lines - 9, &lines)
|
||||
let line = join(map(range(1, &columns), 'screenstring(row, v:val)'), '')
|
||||
call assert_notmatch('Z', line)
|
||||
endfor
|
||||
|
||||
cclose
|
||||
bwipe!
|
||||
delfunc s:OpenPopup
|
||||
delfunc s:PopupFilter
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
477,
|
||||
/**/
|
||||
476,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user