return FALSE;
}
+#ifdef FEAT_PROP_POPUP
+// Cells where ScreenLines[] was updated but terminal output was suppressed
+// because the cell was under an opacity popup. For these cells the terminal
+// no longer matches ScreenLines[], so the "cell unchanged, skip output"
+// optimization must not be applied until they are output again.
+static char_u *suppressed_cells = NULL;
+static int suppressed_rows = 0;
+static int suppressed_cols = 0;
+
+ static void
+mark_suppressed_cell(int row, int col)
+{
+ if (suppressed_cells == NULL
+ || suppressed_rows != screen_Rows
+ || suppressed_cols != screen_Columns)
+ {
+ vim_free(suppressed_cells);
+ suppressed_cells = alloc_clear(
+ (size_t)screen_Rows * screen_Columns);
+ if (suppressed_cells == NULL)
+ {
+ suppressed_rows = 0;
+ suppressed_cols = 0;
+ return;
+ }
+ suppressed_rows = screen_Rows;
+ suppressed_cols = screen_Columns;
+ }
+ suppressed_cells[row * suppressed_cols + col] = TRUE;
+}
+
+ static void
+unmark_suppressed_cell(int row, int col)
+{
+ if (suppressed_cells != NULL
+ && row >= 0 && row < suppressed_rows
+ && col >= 0 && col < suppressed_cols)
+ suppressed_cells[row * suppressed_cols + col] = FALSE;
+}
+
+ static int
+is_suppressed_cell(int row, int col)
+{
+ return suppressed_cells != NULL
+ && row >= 0 && row < suppressed_rows
+ && col >= 0 && col < suppressed_cols
+ && suppressed_cells[row * suppressed_cols + col];
+}
+#endif
+
#ifdef FEAT_PROP_POPUP
/*
* Cached attributes of the current opacity popup, computed once per
redraw_next = force || char_needs_redraw(off_from + char_cells,
off_to + char_cells, endcol - col - char_cells);
+#ifdef FEAT_PROP_POPUP
+ // A cell whose output was suppressed under an opacity popup does not
+ // match the terminal even when ScreenLines[] is unchanged.
+ if (!redraw_this && is_suppressed_cell(row, col + coloff))
+ redraw_this = TRUE;
+#endif
+
#ifdef FEAT_GUI
# ifdef FEAT_GUI_MSWIN
changed_this = changed_next;
// blank out the rest of the line
while (col < clear_width && ScreenLines[off_to] == ' '
&& ScreenAttrs[off_to] == 0
- && (!enc_utf8 || ScreenLinesUC[off_to] == 0))
+ && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
+#ifdef FEAT_PROP_POPUP
+ && !is_suppressed_cell(row, col + coloff)
+#endif
+ )
{
ScreenCols[off_to] =
(flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
|| (ScreenLinesUC[off] != 0
&& screen_comp_differs(off, u8cc))))
|| ScreenAttrs[off] != cell_attr
- || exmode_active;
+ || exmode_active
+#ifdef FEAT_PROP_POPUP
+ // Output was suppressed under an opacity popup: the terminal
+ // does not match ScreenLines[] even when unchanged.
+ || is_suppressed_cell(row, col)
+#endif
+ ;
if ((need_redraw || force_redraw_this) && !skip_for_popup(row, col))
{
ScreenLinesUC[off2] = 0;
screen_char(off2, row, col + 1);
}
+ mark_suppressed_cell(row, col);
+ if (enc_utf8 && ScreenLinesUC[off] != 0
+ && utf_char2cells(ScreenLinesUC[off]) == 2
+ && col + 1 < screen_Columns
+ && popup_is_under_opacity(row, col + 1))
+ mark_suppressed_cell(row, col + 1);
screen_cur_col = 9999;
return;
}
&& col + 1 < screen_Columns
&& popup_is_under_opacity(row, col + 1))
{
+ mark_suppressed_cell(row, col);
+ mark_suppressed_cell(row, col + 1);
screen_cur_col = 9999;
return;
}
windgoto(row, col);
+#ifdef FEAT_PROP_POPUP
+ // The cell is output below, the terminal matches ScreenLines again.
+ unmark_suppressed_cell(row, col);
+ if (enc_utf8 && ScreenLinesUC[off] != 0
+ && utf_char2cells(ScreenLinesUC[off]) == 2)
+ unmark_suppressed_cell(row, col + 1);
+#endif
+
if (screen_attr != attr)
screen_start_highlight(attr);
// If under a higher-zindex opacity popup, suppress output.
if (popup_is_under_opacity(row, col))
{
+ mark_suppressed_cell(row, col);
+ mark_suppressed_cell(row, col + 1);
screen_cur_col = 9999;
return;
}
// second byte directly.
screen_char(off, row, col);
out_char(ScreenLines[off + 1]);
+#ifdef FEAT_PROP_POPUP
+ unmark_suppressed_cell(row, col + 1);
+#endif
++screen_cur_col;
}
// skip blanks (used often, keep it fast!)
if (enc_utf8)
while (off < end_off && ScreenLines[off] == ' '
- && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
+ && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0
+#ifdef FEAT_PROP_POPUP
+ && !is_suppressed_cell(row,
+ (int)(off - LineOffset[row]))
+#endif
+ )
++off;
else
while (off < end_off && ScreenLines[off] == ' '
- && ScreenAttrs[off] == 0)
+ && ScreenAttrs[off] == 0
+#ifdef FEAT_PROP_POPUP
+ && !is_suppressed_cell(row,
+ (int)(off - LineOffset[row]))
+#endif
+ )
++off;
if (off < end_off) // something to be cleared
{
while (col--) // clear chars in ScreenLines
{
space_to_screenline(off, 0);
+#ifdef FEAT_PROP_POPUP
+ // T_CE cleared the terminal cell, it matches again.
+ unmark_suppressed_cell(row, (int)(off - LineOffset[row]));
+#endif
++off;
}
}
|| must_redraw == UPD_CLEAR // screen clear pending
#if defined(FEAT_GUI) || defined(UNIX)
|| force_next
+#endif
+#ifdef FEAT_PROP_POPUP
+ // Output was suppressed under an opacity popup: the
+ // terminal does not match ScreenLines[] even when
+ // unchanged.
+ || is_suppressed_cell(row, col)
#endif
)
// Skip if under a(nother) popup.
VIM_CLEAR(popup_mask);
VIM_CLEAR(popup_mask_next);
VIM_CLEAR(popup_transparent);
+ VIM_CLEAR(suppressed_cells);
+ suppressed_rows = 0;
+ suppressed_cols = 0;
#endif
}
did_clear = TRUE;
clear_cmdline = FALSE;
mode_displayed = FALSE;
+#ifdef FEAT_PROP_POPUP
+ // The display was cleared, the terminal matches ScreenLines again.
+ if (suppressed_cells != NULL)
+ vim_memset(suppressed_cells, 0,
+ (size_t)suppressed_rows * suppressed_cols);
+#endif
}
else
{
call StopVimInTerminal(buf)
endfunc
+func Test_popup_opacity_settext_no_leftover()
+ CheckScreendump
+
+ " Growing a no-highlight opacity popup with popup_settext() used to leave
+ " cells of the old, smaller popup on the screen: the background redraw
+ " under an opacity popup suppresses terminal output, so a later draw must
+ " not skip cells that look unchanged in ScreenLines.
+ let lines =<< trim END
+ call setline(1, ['some text here', '', '', '', '', '', 'more text'])
+ let g:winid = popup_create(['abc', 'ABC', '123', '456'],
+ \ #{line: 2, col: 2, border: [], highlight: 'None', opacity: 50})
+ END
+ call writefile(lines, 'XtestPopupOpacitySettext', 'D')
+ let buf = RunVimInTerminal('-S XtestPopupOpacitySettext', #{rows: 12})
+ call VerifyScreenDump(buf, 'Test_popupwin_opacity_settext_1', {})
+
+ " Replace with larger content: no cells of the small popup may remain.
+ call term_sendkeys(buf, ":call popup_settext(g:winid,"
+ \ .. " ['ABCDEFGHIJKLMNOPQRSTUVWXYZ', '', '', '', '', '.'])\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_opacity_settext_2', {})
+
+ " After closing the popup the screen must be fully restored.
+ call term_sendkeys(buf, ":call popup_clear()\<CR>")
+ call VerifyScreenDump(buf, 'Test_popupwin_opacity_settext_3', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_popup_opacity_terminal_no_freeze()
CheckFeature terminal
CheckUnix