diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-06-08 16:01:13 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-06-08 16:01:13 +0200 |
commit | 33796b39b9f00b42ca57fa00dbbb52316d9d38ff (patch) | |
tree | 61be6b15346ab09eeaf971afbad6900ecb43efb0 /src/screen.c | |
parent | 7c348bb5ad106cfa35dd45560c5ac5d3c8496c96 (diff) | |
download | vim-git-33796b39b9f00b42ca57fa00dbbb52316d9d38ff.tar.gz |
patch 8.1.1493: redrawing with popups is slow and causes flickerv8.1.1493
Problem: Redrawing with popups is slow and causes flicker.
Solution: Avoid clearing and redrawing using a zindex mask.
Diffstat (limited to 'src/screen.c')
-rw-r--r-- | src/screen.c | 214 |
1 files changed, 166 insertions, 48 deletions
diff --git a/src/screen.c b/src/screen.c index 8092fd244..fb1085327 100644 --- a/src/screen.c +++ b/src/screen.c @@ -610,15 +610,10 @@ update_screen(int type_arg) curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */ return FAIL; } + #ifdef FEAT_TEXT_PROP - // TODO: avoid redrawing everything when there is a popup window. - if (popup_any_visible()) - { - if (type < NOT_VALID) - type = NOT_VALID; - FOR_ALL_WINDOWS(wp) - wp->w_redr_type = NOT_VALID; - } + // Update popup_mask if needed. + type = may_update_popup_mask(type); #endif updating_screen = TRUE; @@ -880,6 +875,10 @@ update_prepare(void) #ifdef FEAT_SEARCH_EXTRA start_search_hl(); #endif +#ifdef FEAT_TEXT_PROP + // Update popup_mask if needed. + may_update_popup_mask(0); +#endif } /* @@ -992,11 +991,6 @@ update_debug_sign(buf_T *buf, linenr_T lnum) win_redr_status(wp, FALSE); } -#ifdef FEAT_TEXT_PROP - // Display popup windows on top of the others. - update_popups(); -#endif - update_finish(); } #endif @@ -1021,6 +1015,82 @@ get_wcr_attr(win_T *wp) #ifdef FEAT_TEXT_PROP /* + * Update "popup_mask" if needed. + * Also recomputes the popup size and positions. + * Also updates "popup_visible". + * If more redrawing is needed than "type_arg" a higher value is returned. + */ + int +may_update_popup_mask(int type_arg) +{ + int type = type_arg; + win_T *wp; + + if (popup_mask_tab != curtab) + popup_mask_refresh = TRUE; + if (!popup_mask_refresh) + { + // Check if any buffer has changed. + for (wp = first_popupwin; wp != NULL; wp = wp->w_next) + if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_mask_refresh = TRUE; + for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next) + if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_mask_refresh = TRUE; + if (!popup_mask_refresh) + return type; + } + + popup_mask_refresh = FALSE; + popup_mask_tab = curtab; + + popup_visible = FALSE; + vim_memset(popup_mask, 0, screen_Rows * screen_Columns * sizeof(short)); + + // Find the window with the lowest zindex that hasn't been handled yet, + // so that the window with a higher zindex overwrites the value in + // popup_mask. + popup_reset_handled(); + while ((wp = find_next_popup(TRUE)) != NULL) + { + int top_off, bot_off; + int left_off, right_off; + short *p; + int line, col; + + popup_visible = TRUE; + + // Recompute the position if the text changed. + if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) + popup_adjust_position(wp); + + // the position and size are for the inside, add the padding and + // border + top_off = wp->w_popup_padding[0] + wp->w_popup_border[0]; + bot_off = wp->w_popup_padding[2] + wp->w_popup_border[2]; + left_off = wp->w_popup_padding[3] + wp->w_popup_border[3]; + right_off = wp->w_popup_padding[1] + wp->w_popup_border[1]; + + for (line = wp->w_winrow + top_off; + line < wp->w_winrow + wp->w_height + bot_off + && line < screen_Rows; ++line) + for (col = wp->w_wincol + left_off; + col < wp->w_wincol + wp->w_width + right_off + && col < screen_Columns; ++col) + { + p = popup_mask + line * screen_Columns + col; + if (*p != wp->w_zindex) + { + *p = wp->w_zindex; + type = NOT_VALID; + } + } + } + + return type; +} + +/* * Return a string of "len" spaces in IObuff. */ static char_u * @@ -1049,14 +1119,13 @@ update_popups(void) // Find the window with the lowest zindex that hasn't been updated yet, // so that the window with a higher zindex is drawn later, thus goes on // top. - // TODO: don't redraw every popup every time. - popup_visible = FALSE; popup_reset_handled(); while ((wp = find_next_popup(TRUE)) != NULL) { - // Recompute the position if the text changed. - if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) - popup_adjust_position(wp); + // This drawing uses the zindex of the popup window, so that it's on + // top of the text but doesn't draw when another popup with higher + // zindex is on top of the character. + screen_zindex = wp->w_zindex; // adjust w_winrow and w_wincol for border and padding, since // win_update() doesn't handle them. @@ -1067,7 +1136,6 @@ update_popups(void) // Draw the popup text. win_update(wp); - popup_visible = TRUE; wp->w_winrow -= top_off; wp->w_wincol -= left_off; @@ -1190,6 +1258,9 @@ update_popups(void) wp->w_wincol + total_width - 1, border_attr[2]); } } + + // Back to the normal zindex. + screen_zindex = 0; } } #endif @@ -6477,6 +6548,11 @@ screen_line( redraw_this = TRUE; } #endif +#ifdef FEAT_TEXT_PROP + // Skip if under a(nother) popup. + if (popup_mask[row * screen_Columns + col + coloff] > screen_zindex) + redraw_this = FALSE; +#endif if (redraw_this) { @@ -6721,6 +6797,7 @@ screen_line( if (clear_width > 0 #ifdef FEAT_TEXT_PROP && !(flags & SLF_POPUP) // no separator for popup window + && popup_mask[row * screen_Columns + col + coloff] <= screen_zindex #endif ) { @@ -6821,11 +6898,6 @@ redraw_statuslines(void) win_redr_status(wp, FALSE); if (redraw_tabline) draw_tabline(); - -#ifdef FEAT_TEXT_PROP - // Display popup windows on top of the status lines. - update_popups(); -#endif } #if defined(FEAT_WILDMENU) || defined(PROTO) @@ -8577,9 +8649,21 @@ screen_char(unsigned off, int row, int col) return; #ifdef FEAT_INS_EXPAND - if (pum_under_menu(row, col)) + // Skip if under the popup menu. + // Popup windows with zindex higher than POPUPMENU_ZINDEX go on top. + if (pum_under_menu(row, col) +# ifdef FEAT_TEXT_PROP + && screen_zindex <= POPUPMENU_ZINDEX +# endif + ) return; #endif +#ifdef FEAT_TEXT_PROP + // Skip if under a(nother) popup. + if (popup_mask[row * screen_Columns + col] > screen_zindex) + return; +#endif + /* Outputting a character in the last cell on the screen may scroll the * screen up. Only do it when the "xn" termcap property is set, otherwise * mark the character invalid (update it when scrolled up). */ @@ -8869,7 +8953,7 @@ screen_fill( c = c1; for (col = start_col; col < end_col; ++col) { - if (ScreenLines[off] != c + if ((ScreenLines[off] != c || (enc_utf8 && (int)ScreenLinesUC[off] != (c >= 0x80 ? c : 0)) || ScreenAttrs[off] != attr @@ -8877,6 +8961,11 @@ screen_fill( || force_next #endif ) +#ifdef FEAT_TEXT_PROP + // Skip if under a(nother) popup. + && popup_mask[row * screen_Columns + col] <= screen_zindex +#endif + ) { #if defined(FEAT_GUI) || defined(UNIX) /* The bold trick may make a single row of pixels appear in @@ -9013,6 +9102,9 @@ screenalloc(int doclear) unsigned *new_LineOffset; char_u *new_LineWraps; short *new_TabPageIdxs; +#ifdef FEAT_TEXT_PROP + short *new_popup_mask; +#endif tabpage_T *tp; static int entered = FALSE; /* avoid recursiveness */ static int done_outofmem_msg = FALSE; /* did outofmem message */ @@ -9094,6 +9186,9 @@ retry: new_LineOffset = LALLOC_MULT(unsigned, Rows); new_LineWraps = LALLOC_MULT(char_u, Rows); new_TabPageIdxs = LALLOC_MULT(short, Columns); +#ifdef FEAT_TEXT_PROP + new_popup_mask = LALLOC_MULT(short, Rows * Columns); +#endif FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -9136,6 +9231,9 @@ give_up: || new_LineOffset == NULL || new_LineWraps == NULL || new_TabPageIdxs == NULL +#ifdef FEAT_TEXT_PROP + || new_popup_mask == NULL +#endif || outofmem) { if (ScreenLines != NULL || !done_outofmem_msg) @@ -9156,6 +9254,9 @@ give_up: VIM_CLEAR(new_LineOffset); VIM_CLEAR(new_LineWraps); VIM_CLEAR(new_TabPageIdxs); +#ifdef FEAT_TEXT_PROP + VIM_CLEAR(new_popup_mask); +#endif } else { @@ -9242,6 +9343,11 @@ give_up: LineOffset = new_LineOffset; LineWraps = new_LineWraps; TabPageIdxs = new_TabPageIdxs; +#ifdef FEAT_TEXT_PROP + popup_mask = new_popup_mask; + vim_memset(popup_mask, 0, screen_Rows * screen_Columns * sizeof(short)); + popup_mask_refresh = TRUE; +#endif /* It's important that screen_Rows and screen_Columns reflect the actual * size of ScreenLines[]. Set them before calling anything. */ @@ -9296,15 +9402,18 @@ free_screenlines(void) { int i; - vim_free(ScreenLinesUC); + VIM_CLEAR(ScreenLinesUC); for (i = 0; i < Screen_mco; ++i) - vim_free(ScreenLinesC[i]); - vim_free(ScreenLines2); - vim_free(ScreenLines); - vim_free(ScreenAttrs); - vim_free(LineOffset); - vim_free(LineWraps); - vim_free(TabPageIdxs); + VIM_CLEAR(ScreenLinesC[i]); + VIM_CLEAR(ScreenLines2); + VIM_CLEAR(ScreenLines); + VIM_CLEAR(ScreenAttrs); + VIM_CLEAR(LineOffset); + VIM_CLEAR(LineWraps); + VIM_CLEAR(TabPageIdxs); +#ifdef FEAT_TEXT_PROP + VIM_CLEAR(popup_mask); +#endif } void @@ -9429,6 +9538,7 @@ linecopy(int to, int from, win_T *wp) /* * Return TRUE if clearing with term string "p" would work. * It can't work when the string is empty or it won't set the right background. + * Don't clear to end-of-line when there are popups, it may cause flicker. */ int can_clear(char_u *p) @@ -9443,7 +9553,11 @@ can_clear(char_u *p) #else || cterm_normal_bg_color == 0 #endif - || *T_UT != NUL)); + || *T_UT != NUL) +#ifdef FEAT_TEXT_PROP + && !(p == T_CE && popup_visible) +#endif + ); } /* @@ -9891,22 +10005,26 @@ win_do_lines( if (!redrawing() || line_count <= 0) return FAIL; - /* When inserting lines would result in loss of command output, just redraw - * the lines. */ + // When inserting lines would result in loss of command output, just redraw + // the lines. if (no_win_do_lines_ins && !del) return FAIL; - /* only a few lines left: redraw is faster */ + // only a few lines left: redraw is faster if (mayclear && Rows - line_count < 5 && wp->w_width == Columns) { if (!no_win_do_lines_ins) - screenclear(); /* will set wp->w_lines_valid to 0 */ + screenclear(); // will set wp->w_lines_valid to 0 return FAIL; } - /* - * Delete all remaining lines - */ +#ifdef FEAT_TEXT_PROP + // this doesn't work when tere are popups visible + if (popup_visible) + return FAIL; +#endif + + // Delete all remaining lines if (row + line_count >= wp->w_height) { screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height, @@ -10024,12 +10142,17 @@ screen_ins_lines( * - the line count is less than one * - the line count is more than 'ttyscroll' * - redrawing for a callback and there is a modeless selection + * - there is a popup window */ - if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll + if (!screen_valid(TRUE) + || line_count <= 0 || line_count > p_ttyscroll #ifdef FEAT_CLIPBOARD || (clip_star.state != SELECT_CLEARED && redrawing_for_callback > 0) #endif +#ifdef FEAT_TEXT_PROP + || popup_visible +#endif ) return FAIL; @@ -11136,11 +11259,6 @@ showruler(int always) /* Redraw the tab pages line if needed. */ if (redraw_tabline) draw_tabline(); - -#ifdef FEAT_TEXT_PROP - // Display popup windows on top of everything. - update_popups(); -#endif } #ifdef FEAT_CMDL_INFO |