diff options
Diffstat (limited to 'src/nvim/drawscreen.c')
-rw-r--r-- | src/nvim/drawscreen.c | 145 |
1 files changed, 68 insertions, 77 deletions
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index d2c2d7238b..7ad4193058 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -97,7 +97,7 @@ typedef enum { static bool redraw_popupmenu = false; static bool msg_grid_invalid = false; -static bool resizing = false; +static bool resizing_autocmd = false; static char *provider_err = NULL; @@ -115,7 +115,7 @@ void conceal_check_cursor_line(void) } } -/// Resize the screen to Rows and Columns. +/// Resize default_grid to Rows and Columns. /// /// Allocate default_grid.chars[] and other grid arrays. /// @@ -125,19 +125,18 @@ void conceal_check_cursor_line(void) /// default_grid.Columns to access items in default_grid.chars[]. Use Rows /// and Columns for positioning text etc. where the final size of the screen is /// needed. -void screenalloc(void) +bool default_grid_alloc(void) { + static bool resizing = false; + // It's possible that we produce an out-of-memory message below, which // will cause this function to be called again. To break the loop, just // return here. if (resizing) { - return; + return false; } resizing = true; - int retry_count = 0; - -retry: // Allocation of the screen buffers is done only when the size changes and // when Rows and Columns have been set and we have started doing full // screen stuff. @@ -148,24 +147,9 @@ retry: || Columns == 0 || (!full_screen && default_grid.chars == NULL)) { resizing = false; - return; - } - - // Note that the window sizes are updated before reallocating the arrays, - // thus we must not redraw here! - RedrawingDisabled++; - - // win_new_screensize will recompute floats position, but tell the - // compositor to not redraw them yet - ui_comp_set_screen_valid(false); - if (msg_grid.chars) { - msg_grid_invalid = true; + return false; } - win_new_screensize(); // fit the windows in the new sized screen - - comp_col(); // recompute columns for shown command and ruler - // We're changing the size of the screen. // - Allocate new arrays for default_grid // - Move lines from the old arrays into the new arrays, clear extra @@ -193,26 +177,13 @@ retry: default_grid.col_offset = 0; default_grid.handle = DEFAULT_GRID_HANDLE; - must_redraw = UPD_CLEAR; // need to clear the screen later - - RedrawingDisabled--; - - // Do not apply autocommands more than 3 times to avoid an endless loop - // in case applying autocommands always changes Rows or Columns. - if (starting == 0 && ++retry_count <= 3) { - apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); - // In rare cases, autocommands may have altered Rows or Columns, - // jump back to check if we need to allocate the screen again. - goto retry; - } - resizing = false; + return true; } void screenclear(void) { check_for_delay(false); - screenalloc(); // allocate screen buffers if size changed int i; @@ -281,13 +252,6 @@ void screen_resize(int width, int height) return; } - // curwin->w_buffer can be NULL when we are closing a window and the - // buffer has already been closed and removing a scrollbar causes a resize - // event. Don't resize then, it will happen after entering another buffer. - if (curwin->w_buffer == NULL) { - return; - } - resizing_screen = true; Rows = height; @@ -301,16 +265,54 @@ void screen_resize(int width, int height) width = Columns; p_lines = Rows; p_columns = Columns; - ui_call_grid_resize(1, width, height); - /// The window layout used to be adjusted here, but it now happens in - /// screenalloc() (also invoked from screenclear()). That is because the - /// recursize "resizing_screen" check above may skip this, but not screenalloc(). + // was invoked recursively from a VimResized autocmd, handled as a loop below + if (resizing_autocmd) { + return; + } + + int retry_count = 0; + resizing_autocmd = true; + + bool retry_resize = true; + while (retry_resize) { + retry_resize = default_grid_alloc(); - if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) { - screenclear(); + // Do not apply autocommands more than 3 times to avoid an endless loop + // in case applying autocommands always changes Rows or Columns. + if (++retry_count > 3) { + break; + } + + if (retry_resize) { + // In rare cases, autocommands may have altered Rows or Columns, + // retry to check if we need to allocate the screen again. + apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf); + } + } + + resizing_autocmd = false; + + ui_call_grid_resize(1, width, height); + + // win_new_screensize will recompute floats position, but tell the + // compositor to not redraw them yet + ui_comp_set_screen_valid(false); + if (msg_grid.chars) { + msg_grid_invalid = true; } + // Note that the window sizes are updated before reallocating the arrays, + // thus we must not redraw here! + RedrawingDisabled++; + + win_new_screensize(); // fit the windows in the new sized screen + + comp_col(); // recompute columns for shown command and ruler + + RedrawingDisabled--; + redraw_all_later(UPD_CLEAR); + if (starting != NO_SCREEN) { maketitle(); @@ -320,14 +322,11 @@ void screen_resize(int width, int height) // We only redraw when it's needed: // - While at the more prompt or executing an external command, don't // redraw, but position the cursor. - // - While editing the command line, only redraw that. + // - While editing the command line, only redraw that. TODO: lies // - in Ex mode, don't redraw anything. // - Otherwise, redraw right now, and position the cursor. - // Always need to call update_screen() or screenalloc(), to make - // sure Rows/Columns and the size of the screen is correct! if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM || exmode_active) { - screenalloc(); if (msg_grid.chars) { msg_grid_validate(); } @@ -378,7 +377,7 @@ int update_screen(void) // Don't do anything if the screen structures are (not yet) valid. // A VimResized autocmd can invoke redrawing in the middle of a resize, // which would bypass the checks in screen_resize for popupmenu etc. - if (!default_grid.chars || resizing) { + if (resizing_autocmd || !default_grid.chars) { return FAIL; } @@ -387,34 +386,25 @@ int update_screen(void) diff_redraw(true); } - int type = 0; - - if (must_redraw) { - if (type < must_redraw) { // use maximal type - type = must_redraw; - } - - // must_redraw is reset here, so that when we run into some weird - // reason to redraw while busy redrawing (e.g., asynchronous - // scrolling), or update_topline() in win_update() will cause a - // scroll, or a decoration provider requires a redraw, the screen - // will be redrawn later or in win_update(). - must_redraw = 0; - } - // Postpone the redrawing when it's not needed and when being called // recursively. if (!redrawing() || updating_screen) { - must_redraw = type; - if (type > UPD_INVERTED_ALL) { - curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now - } return FAIL; } + + int type = must_redraw; + + // must_redraw is reset here, so that when we run into some weird + // reason to redraw while busy redrawing (e.g., asynchronous + // scrolling), or update_topline() in win_update() will cause a + // scroll, or a decoration provider requires a redraw, the screen + // will be redrawn later or in win_update(). + must_redraw = 0; + updating_screen = 1; - display_tick++; // let syntax code know we're in a next round of - // display updating + display_tick++; // let syntax code know we're in a next round of + // display updating // Tricky: vim code can reset msg_scrolled behind our back, so need // separate bookkeeping for now. @@ -525,7 +515,8 @@ int update_screen(void) } if (type == UPD_CLEAR) { // first clear screen - screenclear(); // will reset clear_cmdline + screenclear(); // will reset clear_cmdline + // and set UPD_NOT_VALID for each window cmdline_screen_cleared(); // clear external cmdline state type = UPD_NOT_VALID; // must_redraw may be set indirectly, avoid another redraw later |