@@ -785,13 +785,19 @@ apply_general_options(win_T *wp, dict_T *dict)
785785 if (di != NULL )
786786 {
787787 nr = dict_get_number (dict , "opacity" );
788- if (nr > 0 && nr <= 100 )
788+ if (nr > 0 && nr < 100 )
789789 {
790- // opacity: 0-100, where 0= transparent, 100=opaque
790+ // opacity: 1-99, partially transparent
791791 // Convert to blend (0=opaque, 100=transparent)
792792 wp -> w_popup_flags |= POPF_OPACITY ;
793793 wp -> w_popup_blend = 100 - nr ;
794794 }
795+ else if (nr == 100 )
796+ {
797+ // Fully opaque, same as no opacity set.
798+ wp -> w_popup_flags &= ~POPF_OPACITY ;
799+ wp -> w_popup_blend = 0 ;
800+ }
795801 else
796802 {
797803 wp -> w_popup_flags &= ~POPF_OPACITY ;
@@ -1098,7 +1104,8 @@ apply_options(win_T *wp, dict_T *dict, int create)
10981104 wp -> w_valid &= ~VALID_BOTLINE ;
10991105 }
11001106
1101- popup_mask_refresh = TRUE;
1107+ if (create )
1108+ popup_mask_refresh = TRUE;
11021109 popup_highlight_curline (wp );
11031110
11041111 return OK ;
@@ -3106,7 +3113,15 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
31063113 return ;
31073114
31083115 popup_set_buffer_text (wp -> w_buffer , argvars [1 ]);
3109- redraw_win_later (wp , UPD_NOT_VALID );
3116+
3117+ // Redraw the popup window without triggering a full screen redraw.
3118+ // Using redraw_win_later() with UPD_NOT_VALID would set the global
3119+ // must_redraw, causing may_update_popup_mask() to refresh the mask and
3120+ // redraw windows behind the popup, resulting in flickering.
3121+ wp -> w_redr_type = UPD_NOT_VALID ;
3122+ wp -> w_lines_valid = 0 ;
3123+ if (must_redraw < UPD_VALID )
3124+ must_redraw = UPD_VALID ;
31103125 popup_adjust_position (wp );
31113126}
31123127
@@ -3391,6 +3406,7 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
33913406 char_u * old_thumb_highlight ;
33923407 char_u * old_border_highlight [4 ];
33933408 int need_redraw = FALSE;
3409+ int need_reposition = FALSE;
33943410 int i ;
33953411
33963412 if (in_vim9script ()
@@ -3419,13 +3435,25 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
34193435
34203436 (void )apply_options (wp , dict , FALSE);
34213437
3438+ // Keep "firstline" sticky across popup_setoptions(): when it is set, any
3439+ // property update should reapply it and restore the displayed top line.
3440+ if (wp -> w_firstline > 0
3441+ && wp -> w_firstline <= wp -> w_buffer -> b_ml .ml_line_count )
3442+ wp -> w_topline = wp -> w_firstline ;
3443+
34223444 // Check if visual options changed and redraw if needed
34233445 if (old_firstline != wp -> w_firstline )
34243446 need_redraw = TRUE;
34253447 if (old_zindex != wp -> w_zindex )
3448+ {
34263449 need_redraw = TRUE;
3450+ need_reposition = TRUE;
3451+ }
34273452 if (old_popup_flags != wp -> w_popup_flags )
3453+ {
34283454 need_redraw = TRUE;
3455+ need_reposition = TRUE;
3456+ }
34293457 if (old_scrollbar_highlight != wp -> w_scrollbar_highlight )
34303458 need_redraw = TRUE;
34313459 if (old_thumb_highlight != wp -> w_thumb_highlight )
@@ -3437,17 +3465,38 @@ f_popup_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
34373465 break ;
34383466 }
34393467
3440- if (need_redraw )
3468+ if (need_reposition )
3469+ {
34413470 redraw_win_later (wp , UPD_NOT_VALID );
3471+ popup_mask_refresh = TRUE;
3472+ }
3473+ else if (need_redraw )
3474+ {
3475+ // Only content changed (e.g. firstline, highlight): redraw the
3476+ // popup window without updating the popup mask or triggering a
3477+ // full screen redraw. This avoids flickering of windows behind
3478+ // the popup.
3479+ wp -> w_redr_type = UPD_NOT_VALID ;
3480+ wp -> w_lines_valid = 0 ;
3481+ if (must_redraw < UPD_VALID )
3482+ must_redraw = UPD_VALID ;
3483+ }
3484+
34423485#ifdef FEAT_PROP_POPUP
34433486 // Force redraw if opacity value changed
34443487 if (old_blend != wp -> w_popup_blend )
34453488 {
34463489 redraw_win_later (wp , UPD_NOT_VALID );
34473490 // Also redraw windows below the popup
34483491 redraw_all_later (UPD_NOT_VALID );
3492+ popup_mask_refresh = TRUE;
34493493 }
34503494#endif
3495+
3496+ // Always recalculate popup position/size: other options like border,
3497+ // close, padding may have changed without affecting w_popup_flags.
3498+ // popup_adjust_position() only sets popup_mask_refresh when the
3499+ // position or size actually changed.
34513500 popup_adjust_position (wp );
34523501}
34533502
0 commit comments