patch 9.2.0112: popup: windows flicker when updating text

Problem:  popup: windows flicker when updating text
Solution: Only refresh the popup mask if the position or size changed,
          manually set the window redraw type instead of using
          redraw_win_later() to avoid triggering a full screen redraw.
          Handle opacity 100 correctly. Keep "firstline" sticky when
          setting options (Yasuhiro Matsumoto).

related: #19510
closes:  #19559

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yasuhiro Matsumoto
2026-03-05 20:33:40 +00:00
committed by Christian Brabandt
parent 0fe3ca6031
commit 4d0c57e15f
3 changed files with 57 additions and 6 deletions
+54 -5
View File
@@ -785,13 +785,19 @@ apply_general_options(win_T *wp, dict_T *dict)
if (di != NULL)
{
nr = dict_get_number(dict, "opacity");
if (nr > 0 && nr <= 100)
if (nr > 0 && nr < 100)
{
// opacity: 0-100, where 0=transparent, 100=opaque
// opacity: 1-99, partially transparent
// Convert to blend (0=opaque, 100=transparent)
wp->w_popup_flags |= POPF_OPACITY;
wp->w_popup_blend = 100 - nr;
}
else if (nr == 100)
{
// Fully opaque, same as no opacity set.
wp->w_popup_flags &= ~POPF_OPACITY;
wp->w_popup_blend = 0;
}
else
{
wp->w_popup_flags &= ~POPF_OPACITY;
@@ -1098,7 +1104,8 @@ apply_options(win_T *wp, dict_T *dict, int create)
wp->w_valid &= ~VALID_BOTLINE;
}
popup_mask_refresh = TRUE;
if (create)
popup_mask_refresh = TRUE;
popup_highlight_curline(wp);
return OK;
@@ -3106,7 +3113,15 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
return;
popup_set_buffer_text(wp->w_buffer, argvars[1]);
redraw_win_later(wp, UPD_NOT_VALID);
// Redraw the popup window without triggering a full screen redraw.
// Using redraw_win_later() with UPD_NOT_VALID would set the global
// must_redraw, causing may_update_popup_mask() to refresh the mask and
// redraw windows behind the popup, resulting in flickering.
wp->w_redr_type = UPD_NOT_VALID;
wp->w_lines_valid = 0;
if (must_redraw < UPD_VALID)
must_redraw = UPD_VALID;
popup_adjust_position(wp);
}
@@ -3391,6 +3406,7 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
char_u *old_thumb_highlight;
char_u *old_border_highlight[4];
int need_redraw = FALSE;
int need_reposition = FALSE;
int i;
if (in_vim9script()
@@ -3419,13 +3435,25 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
(void)apply_options(wp, dict, FALSE);
// Keep "firstline" sticky across popup_setoptions(): when it is set, any
// property update should reapply it and restore the displayed top line.
if (wp->w_firstline > 0
&& wp->w_firstline <= wp->w_buffer->b_ml.ml_line_count)
wp->w_topline = wp->w_firstline;
// Check if visual options changed and redraw if needed
if (old_firstline != wp->w_firstline)
need_redraw = TRUE;
if (old_zindex != wp->w_zindex)
{
need_redraw = TRUE;
need_reposition = TRUE;
}
if (old_popup_flags != wp->w_popup_flags)
{
need_redraw = TRUE;
need_reposition = TRUE;
}
if (old_scrollbar_highlight != wp->w_scrollbar_highlight)
need_redraw = TRUE;
if (old_thumb_highlight != wp->w_thumb_highlight)
@@ -3437,8 +3465,23 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
break;
}
if (need_redraw)
if (need_reposition)
{
redraw_win_later(wp, UPD_NOT_VALID);
popup_mask_refresh = TRUE;
}
else if (need_redraw)
{
// Only content changed (e.g. firstline, highlight): redraw the
// popup window without updating the popup mask or triggering a
// full screen redraw. This avoids flickering of windows behind
// the popup.
wp->w_redr_type = UPD_NOT_VALID;
wp->w_lines_valid = 0;
if (must_redraw < UPD_VALID)
must_redraw = UPD_VALID;
}
#ifdef FEAT_PROP_POPUP
// Force redraw if opacity value changed
if (old_blend != wp->w_popup_blend)
@@ -3446,8 +3489,14 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
redraw_win_later(wp, UPD_NOT_VALID);
// Also redraw windows below the popup
redraw_all_later(UPD_NOT_VALID);
popup_mask_refresh = TRUE;
}
#endif
// Always recalculate popup position/size: other options like border,
// close, padding may have changed without affecting w_popup_flags.
// popup_adjust_position() only sets popup_mask_refresh when the
// position or size actually changed.
popup_adjust_position(wp);
}
+1 -1
View File
@@ -627,7 +627,7 @@ screen_line(
ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
}
if (enc_dbcs == DBCS_JPNU) // Copilot's suggestion for DBCS_JPNU
if (enc_dbcs == DBCS_JPNU)
ScreenLines2[off_to] = ScreenLines2[off_from];
if (enc_dbcs != 0 && char_cells == 2)
+2
View File
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
112,
/**/
111,
/**/