patch 9.2.0112: popup: windows flicker when updating text

Commit: 
https://github.com/vim/vim/commit/4d0c57e15fd74fb9464178a06cb27acaa14081f7
Author: Yasuhiro Matsumoto <[email protected]>
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 <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

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,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1vyFZ9-008Wkk-R1%40256bit.org.

Raspunde prin e-mail lui