Commit: patch 9.2.0112: popup: windows flicker when updating text

2 views
Skip to first unread message

Christian Brabandt

unread,
Mar 5, 2026, 3:46:54 PM (yesterday) Mar 5
to vim...@googlegroups.com
patch 9.2.0112: popup: windows flicker when updating text

Commit: https://github.com/vim/vim/commit/4d0c57e15fd74fb9464178a06cb27acaa14081f7
Author: Yasuhiro Matsumoto <matt...@gmail.com>
Date: Thu Mar 5 20:33:40 2026 +0000

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 <matt...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/popupwin.c b/src/popupwin.c
index 7cd39b071..a9325e837 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -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);
}

diff --git a/src/screen.c b/src/screen.c
index 81becb984..01f9118d5 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -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)
diff --git a/src/version.c b/src/version.c
index 8f3e6f25c..6beefa483 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 112,
/**/
111,
/**/
Reply all
Reply to author
Forward
0 new messages