From: Yasuhiro Matsumoto Date: Thu, 5 Mar 2026 20:33:40 +0000 (+0000) Subject: patch 9.2.0112: popup: windows flicker when updating text X-Git-Tag: v9.2.0112^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4d0c57e15fd74fb9464178a06cb27acaa14081f7;p=thirdparty%2Fvim.git 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 Signed-off-by: Christian Brabandt --- diff --git a/src/popupwin.c b/src/popupwin.c index 7cd39b071c..a9325e8377 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 81becb9846..01f9118d5d 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 8f3e6f25c7..6beefa4837 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, /**/