]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0319: popup: rendering issues with partially transparent popups v9.2.0319
authorYasuhiro Matsumoto <mattn.jp@gmail.com>
Tue, 7 Apr 2026 20:26:17 +0000 (20:26 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 7 Apr 2026 20:26:17 +0000 (20:26 +0000)
Problem:  popup: rendering issues with partially transparent popups.
Solution: Redraw the area under the old popup position on move or
          resize. Apply the background blend only to the covered half of
          a double-width character. (Yasuhiro Matsumoto)

closes: #19881

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/popupwin.c
src/version.c

index 3ab96cb3e58da48b6c9f0a16aaec8bb7ee41a322..4b69b61893a8fe33acbe82e49bcbe9b578ac8d20 100644 (file)
@@ -46,6 +46,8 @@ static void may_start_message_win_timer(win_T *wp);
 static int popup_on_cmdline = FALSE;
 
 static void popup_adjust_position(win_T *wp);
+static void redraw_under_popup_area(int winrow, int wincol, int height,
+       int width, int leftoff);
 
 /*
  * Get option value for "key", which is "line" or "col".
@@ -3107,6 +3109,14 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
 {
     int                id;
     win_T      *wp;
+#ifdef FEAT_PROP_POPUP
+    int                old_popup_active;
+#endif
+    int                old_winrow;
+    int                old_wincol;
+    int                old_popup_height;
+    int                old_popup_width;
+    int                old_popup_leftoff;
 
     if (in_vim9script()
            && (check_for_number_arg(argvars, 0) == FAIL
@@ -3118,6 +3128,16 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
     if (wp == NULL)
        return;
 
+#ifdef FEAT_PROP_POPUP
+    old_popup_active = (wp->w_popup_flags & POPF_OPACITY)
+                                                   && wp->w_popup_blend > 0;
+#endif
+    old_winrow = wp->w_winrow;
+    old_wincol = wp->w_wincol;
+    old_popup_height = popup_height(wp);
+    old_popup_width = popup_width(wp);
+    old_popup_leftoff = wp->w_popup_leftoff;
+
     if (check_for_string_or_list_arg(argvars, 1) == FAIL)
        return;
 
@@ -3132,6 +3152,17 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
     if (must_redraw < UPD_VALID)
        must_redraw = UPD_VALID;
     popup_adjust_position(wp);
+
+#ifdef FEAT_PROP_POPUP
+    if (old_popup_active
+           && (old_winrow != wp->w_winrow
+               || old_wincol != wp->w_wincol
+               || old_popup_height != popup_height(wp)
+               || old_popup_width != popup_width(wp)
+               || old_popup_leftoff != wp->w_popup_leftoff))
+       redraw_under_popup_area(old_winrow, old_wincol,
+               old_popup_height, old_popup_width, old_popup_leftoff);
+#endif
 }
 
 /*
@@ -3316,6 +3347,49 @@ close_all_popups(int force)
            return;
 }
 
+/*
+ * Force windows under a popup area to redraw.
+ */
+    static void
+redraw_under_popup_area(int winrow, int wincol, int height, int width, int leftoff)
+{
+    int            r;
+
+    for (r = winrow; r < winrow + height && r < screen_Rows; ++r)
+    {
+       int         c;
+       win_T       *prev_twp = NULL;
+
+       if (r >= cmdline_row)
+       {
+           clear_cmdline = TRUE;
+           continue;
+       }
+
+       for (c = wincol; c < wincol + width - leftoff && c < screen_Columns; ++c)
+       {
+           int     line_cp = r;
+           int     col_cp = c;
+           win_T   *twp;
+
+           twp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
+           if (twp != NULL && twp != prev_twp)
+           {
+               prev_twp = twp;
+               if (line_cp < twp->w_height)
+               {
+                   linenr_T lnum;
+
+                   (void)mouse_comp_pos(twp, &line_cp, &col_cp, &lnum, NULL);
+                   redrawWinline(twp, lnum);
+               }
+               else if (line_cp == twp->w_height)
+                   twp->w_redr_status = TRUE;
+           }
+       }
+    }
+}
+
 /*
  * popup_move({id}, {options})
  */
@@ -3329,6 +3403,9 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED)
     int                old_wincol;
     int                old_height;
     int                old_width;
+    int                old_popup_height;
+    int                old_popup_width;
+    int                old_popup_leftoff;
 
     if (in_vim9script()
            && (check_for_number_arg(argvars, 0) == FAIL
@@ -3349,6 +3426,9 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED)
     old_wincol = wp->w_wincol;
     old_height = wp->w_height;
     old_width = wp->w_width;
+    old_popup_height = popup_height(wp);
+    old_popup_width = popup_width(wp);
+    old_popup_leftoff = wp->w_popup_leftoff;
 
     apply_move_options(wp, dict);
 
@@ -3367,39 +3447,8 @@ f_popup_move(typval_T *argvars, typval_T *rettv UNUSED)
        redraw_win_later(wp, UPD_NOT_VALID);
 
        if ((wp->w_popup_flags & POPF_OPACITY) && wp->w_popup_blend > 0)
-       {
-           int     total_h = old_height + popup_top_extra(wp)
-                       + wp->w_popup_border[2] + wp->w_popup_padding[2];
-           int     row;
-
-           for (row = old_winrow;
-                      row < old_winrow + total_h && row < screen_Rows; ++row)
-           {
-               if (row >= cmdline_row)
-                   clear_cmdline = TRUE;
-               else
-               {
-                   int         line_cp = row;
-                   int         col_cp = old_wincol;
-                   win_T       *twp;
-
-                   twp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
-                   if (twp != NULL)
-                   {
-                       if (line_cp >= twp->w_height)
-                           twp->w_redr_status = TRUE;
-                       else
-                       {
-                           linenr_T    lnum;
-
-                           (void)mouse_comp_pos(twp, &line_cp, &col_cp,
-                                                              &lnum, NULL);
-                           redrawWinline(twp, lnum);
-                       }
-                   }
-               }
-           }
-       }
+           redraw_under_popup_area(old_winrow, old_wincol,
+                   old_popup_height, old_popup_width, old_popup_leftoff);
     }
 }
 
@@ -3415,7 +3464,13 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     linenr_T   old_firstline;
 #ifdef FEAT_PROP_POPUP
     int                old_blend;
+    int                old_popup_active;
 #endif
+    int                old_winrow;
+    int                old_wincol;
+    int                old_popup_height;
+    int                old_popup_width;
+    int                old_popup_leftoff;
     int                old_zindex;
     int                old_popup_flags;
     char_u     *old_scrollbar_highlight;
@@ -3441,7 +3496,14 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     old_firstline = wp->w_firstline;
 #ifdef FEAT_PROP_POPUP
     old_blend = wp->w_popup_blend;
+    old_popup_active = (wp->w_popup_flags & POPF_OPACITY)
+                                                   && wp->w_popup_blend > 0;
 #endif
+    old_winrow = wp->w_winrow;
+    old_wincol = wp->w_wincol;
+    old_popup_height = popup_height(wp);
+    old_popup_width = popup_width(wp);
+    old_popup_leftoff = wp->w_popup_leftoff;
     old_zindex = wp->w_zindex;
     old_popup_flags = wp->w_popup_flags;
     old_scrollbar_highlight = wp->w_scrollbar_highlight;
@@ -3514,6 +3576,17 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
     // popup_adjust_position() only sets popup_mask_refresh when the
     // position or size actually changed.
     popup_adjust_position(wp);
+
+#ifdef FEAT_PROP_POPUP
+    if (old_popup_active
+           && (old_winrow != wp->w_winrow
+               || old_wincol != wp->w_wincol
+               || old_popup_height != popup_height(wp)
+               || old_popup_width != popup_width(wp)
+               || old_popup_leftoff != wp->w_popup_leftoff))
+       redraw_under_popup_area(old_winrow, old_wincol,
+               old_popup_height, old_popup_width, old_popup_leftoff);
+#endif
 }
 
 /*
@@ -4755,10 +4828,15 @@ draw_opacity_padding_cell(
                            && utf_char2cells(ScreenLinesUC[base_off]) == 2)
                    {
                        // The left half still has the wide char on screen.
-                       // Clear it to a space.
+                       // Clear it to an unblended space: only the right half is
+                       // covered by the popup background.
                        ScreenLines[base_off] = ' ';
                        ScreenLinesUC[base_off] = 0;
                        ScreenAttrs[base_off] = saved_screenattrs[base_save_off];
+                       popup_set_base_screen_cell(row, base_col,
+                               ScreenLines[base_off],
+                               ScreenAttrs[base_off],
+                               ScreenLinesUC[base_off]);
                        screen_char(base_off, row, base_col);
 
                        // Draw padding in the right half.
@@ -4778,43 +4856,6 @@ draw_opacity_padding_cell(
                        return;
                    }
 
-                   // screen_line() already cleared the base cell (popup
-                   // content was a space).  Restore the full wide char from
-                   // saved background so it shows through with opacity.
-                   if (base_save_off >= 0
-                           && saved_screenlinesuc != NULL
-                           && saved_screenlinesuc[base_save_off] != 0
-                           && utf_char2cells(
-                               saved_screenlinesuc[base_save_off]) == 2)
-                   {
-                       ScreenLines[base_off] =
-                                       saved_screenlines[base_save_off];
-                       ScreenLinesUC[base_off] =
-                                       saved_screenlinesuc[base_save_off];
-                       ScreenLines[off] = saved_screenlines[save_off];
-                       ScreenLinesUC[off] = saved_screenlinesuc[save_off];
-                       ScreenAttrs[base_off] =
-                                       saved_screenattrs[base_save_off];
-                       ScreenAttrs[off] = saved_screenattrs[save_off];
-
-                       int popup_attr_val =
-                                       get_win_attr(screen_opacity_popup);
-                       int blend = screen_opacity_popup->w_popup_blend;
-                       ScreenAttrs[base_off] = hl_blend_attr(
-                               ScreenAttrs[base_off],
-                               popup_attr_val, blend, TRUE);
-                       ScreenAttrs[off] = ScreenAttrs[base_off];
-                       popup_set_base_screen_cell(row, base_col,
-                               ScreenLines[base_off],
-                               ScreenAttrs[base_off],
-                               ScreenLinesUC[base_off]);
-                       popup_set_base_screen_cell(row, col,
-                               ScreenLines[off], ScreenAttrs[off],
-                               ScreenLinesUC[off]);
-                       screen_char(base_off, row, base_col);
-                       return;
-                   }
-
                    // Draw padding in the right half.
                    ScreenLines[off] = ' ';
                    ScreenAttrs[off] = saved_screenattrs[save_off];
index 37aed30c3225019e346b77363e52258abcf99fdc..8e20e639c05ded9fa7e1ab1b4234c05bbf3f5f54 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    319,
 /**/
     318,
 /**/