patch 9.2.0230: popup: opacity not working accross vert splits
Commit:
https://github.com/vim/vim/commit/196cf9f644b39b9c2b742b271d5d78e9bb31745c
Author: Yasuhiro Matsumoto <
matt...@gmail.com>
Date: Sun Mar 22 20:38:22 2026 +0000
patch 9.2.0230: popup: opacity not working accross vert splits
Problem: popup: opacity not working across vert splits
Solution: Iterate over the full popup width to find all underlying
windows (Yasuhiro Matsumoto)
redraw_win_under_opacity_popup() only checked the popup's left column
to find underlying windows. When a popup spans a vertical split, the
right-side window was never forced to redraw, causing blended
ScreenAttrs values to accumulate across redraw cycles.
Iterate across the full popup width to find and redraw all underlying
windows.
closes: #19737
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 fe06777f7..ed6f6fc1b 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -4298,6 +4298,7 @@ popup_mark_opacity_zindex(win_T *wp)
redraw_win_under_opacity_popup(win_T *wp)
{
int height;
+ int width;
int r;
if (!(wp->w_popup_flags & POPF_OPACITY) || wp->w_popup_blend <= 0
@@ -4305,27 +4306,38 @@ redraw_win_under_opacity_popup(win_T *wp)
return;
height = popup_height(wp);
+ width = popup_width(wp);
for (r = wp->w_winrow;
r < wp->w_winrow + height && r < screen_Rows; ++r)
{
- int line_cp = r;
- int col_cp = wp->w_wincol;
- win_T *twp;
+ int col;
+ win_T *prev_twp = NULL;
- twp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
- if (twp != NULL)
+ // Check across the full width of the popup to find all underlying
+ // windows (e.g., when the popup spans a vertical split).
+ for (col = wp->w_wincol;
+ col < wp->w_wincol + width && col < screen_Columns; ++col)
{
- if (line_cp < twp->w_height)
+ int line_cp = r;
+ int col_cp = col;
+ win_T *twp;
+
+ twp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
+ if (twp != NULL && twp != prev_twp)
{
- linenr_T lnum;
+ 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);
+ (void)mouse_comp_pos(twp, &line_cp, &col_cp, &lnum, NULL);
+ redrawWinline(twp, lnum);
+ }
+ else if (line_cp == twp->w_height)
+ // Status bar line: mark for redraw to prevent
+ // opacity blend accumulation.
+ twp->w_redr_status = TRUE;
}
- else if (line_cp == twp->w_height)
- // Status bar line: mark for redraw to prevent
- // opacity blend accumulation.
- twp->w_redr_status = TRUE;
}
}
}
diff --git a/src/testdir/dumps/Test_popupwin_opacity_vsplit_1.dump b/src/testdir/dumps/Test_popupwin_opacity_vsplit_1.dump
new file mode 100644
index 000000000..f67209056
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_opacity_vsplit_1.dump
@@ -0,0 +1,12 @@
+>r+0&#ffffff0|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @1|o|p|a|c|i|t|y| |o|v|e|r+1&&|l+0&&|v|s|p|l|i|t|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @8|1|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+| +0&&@77
diff --git a/src/testdir/dumps/Test_popupwin_opacity_vsplit_2.dump b/src/testdir/dumps/Test_popupwin_opacity_vsplit_2.dump
new file mode 100644
index 000000000..cf2f42681
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_opacity_vsplit_2.dump
@@ -0,0 +1,12 @@
+|r+0&#ffffff0|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @1|o|p|a|c|i|t|y| |o|v|e|r+1&&|l+0&&|v|s|p|l|i|t|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+>r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|r|i|g|h|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @12||+1&&|l+0&&|e|f|t| |w|i|n|d|o|w| |t|e|x|t| |h|e|r|e| |x@3| @10
+|[+3&&|N|o| |N|a|m|e|]| |[|+|]| @8|6|,|1| @11|A|l@1| |[+1&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
+| +0&&@77
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 41cd6f0d0..ab6a74d07 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -4985,4 +4985,44 @@ func Test_popup_conceal_wrap()
call StopVimInTerminal(buf)
endfunc
+func Test_popup_opacity_vsplit()
+ CheckScreendump
+
+ " Opacity popup spanning a vertical split should redraw both windows
+ " underneath, not just the left one (blend accumulation bug).
+ let lines =<< trim END
+ call setline(1, repeat(['left window text here xxxx'], 10))
+ vnew
+ call setline(1, repeat(['right window text here xxxx'], 10))
+ wincmd h
+ hi PopupColor guibg=darkblue guifg=white
+ let g:pop_id = popup_create(['opacity over vsplit'], #{
+ \ line: 3, col: 30,
+ \ minwidth: 25,
+ \ highlight: 'PopupColor',
+ \ opacity: 50,
+ \ zindex: 50,
+ \})
+ END
+ call writefile(lines, 'XtestPopupOpacityVsplit', 'D')
+ let buf = RunVimInTerminal('-S XtestPopupOpacityVsplit', #{rows: 12, cols: 80})
+ call VerifyScreenDump(buf, 'Test_popupwin_opacity_vsplit_1', {})
+
+ " Move cursor multiple times to trigger redraws; without the fix the
+ " right-side window blend accumulates on each redraw cycle.
+ call term_sendkeys(buf, "j")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "j")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "j")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "j")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "j")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_popupwin_opacity_vsplit_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2
diff --git a/src/version.c b/src/version.c
index fd702323c..cfd6d0657 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 */
+/**/
+ 230,
/**/
229,
/**/