From: Yasuhiro Matsumoto Date: Tue, 7 Apr 2026 20:26:17 +0000 (+0000) Subject: patch 9.2.0319: popup: rendering issues with partially transparent popups X-Git-Tag: v9.2.0319^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c79edc0df9832715eb2537a8d5e9b91ff191a131;p=thirdparty%2Fvim.git patch 9.2.0319: popup: rendering issues with partially transparent popups 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 Signed-off-by: Christian Brabandt --- diff --git a/src/popupwin.c b/src/popupwin.c index 3ab96cb3e5..4b69b61893 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -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]; diff --git a/src/version.c b/src/version.c index 37aed30c32..8e20e639c0 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 */ +/**/ + 319, /**/ 318, /**/