# HG changeset patch # User Bram Moolenaar # Date 1668946504 -3600 # Node ID 981f7bc781bbf8be7899f5474d3f28d07a6864ea # Parent 8444cb4177993248695e795b45b84053b6de8c6e patch 9.0.0915: WinScrolled may trigger immediately when defined Commit: https://github.com/vim/vim/commit/29967732761d1ffb5592db5f5aa7036f5b52abf1 Author: Bram Moolenaar Date: Sun Nov 20 12:11:45 2022 +0000 patch 9.0.0915: WinScrolled may trigger immediately when defined Problem: WinScrolled may trigger immediately when defined. Solution: Initialize the fields in all windows. (closes https://github.com/vim/vim/issues/11582) diff --git a/src/autocmd.c b/src/autocmd.c --- a/src/autocmd.c +++ b/src/autocmd.c @@ -1264,14 +1264,20 @@ do_autocmd_event( get_mode(last_mode); #endif // Initialize the fields checked by the WinScrolled trigger to - // stop it from firing right after the first autocmd is defined. + // prevent it from firing right after the first autocmd is + // defined. if (event == EVENT_WINSCROLLED && !has_winscrolled()) { - curwin->w_last_topline = curwin->w_topline; - curwin->w_last_leftcol = curwin->w_leftcol; - curwin->w_last_skipcol = curwin->w_skipcol; - curwin->w_last_width = curwin->w_width; - curwin->w_last_height = curwin->w_height; + tabpage_T *save_curtab = curtab; + tabpage_T *tp; + FOR_ALL_TABPAGES(tp) + { + unuse_tabpage(curtab); + use_tabpage(tp); + snapshot_windows_scroll_size(); + } + unuse_tabpage(curtab); + use_tabpage(save_curtab); } if (is_buflocal) diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -18,12 +18,15 @@ void curwin_init(void); void close_windows(buf_T *buf, int keep_curwin); int one_window(void); int win_close(win_T *win, int free_buf); +void snapshot_windows_scroll_size(void); void may_make_initial_scroll_size_snapshot(void); void may_trigger_winscrolled(void); void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp); void win_free_all(void); win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp); void close_others(int message, int forceit); +void unuse_tabpage(tabpage_T *tp); +void use_tabpage(tabpage_T *tp); int win_alloc_first(void); win_T *win_alloc_popup_win(void); void win_init_popup_win(win_T *wp, buf_T *buf); diff --git a/src/testdir/dumps/Test_winscrolled_not_when_defined_1.dump b/src/testdir/dumps/Test_winscrolled_not_when_defined_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_winscrolled_not_when_defined_1.dump @@ -0,0 +1,10 @@ +>a+0&#ffffff0@2| @56 +|b@2| @56 +|~+0#4040ff13&| @58 +|~| @58 +|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @28|1|,|1| @11|A|l@1 +|a+0&&@2| @56 +|b@2| @56 +|~+0#4040ff13&| @58 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @28|1|,|1| @11|A|l@1 +|:+0&&|a|u| |W|i|n|S|c|r|o|l@1|e|d| |*| |c|a|l@1| |t|i|m|e|r|_|s|t|a|r|t|(|1|0@1|,| |'|S|h|o|w|T|r|i|g@1|e|r|e|d|'|)| @3 diff --git a/src/testdir/dumps/Test_winscrolled_not_when_defined_2.dump b/src/testdir/dumps/Test_winscrolled_not_when_defined_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_winscrolled_not_when_defined_2.dump @@ -0,0 +1,10 @@ +>b+0&#ffffff0@2| @56 +|~+0#4040ff13&| @58 +|~| @58 +|~| @58 +|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @28|2|,|1| @11|B|o|t +|a+0&&@2| @56 +|b@2| @56 +|~+0#4040ff13&| @58 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @28|1|,|1| @11|A|l@1 +|t+0&&|r|i|g@1|e|r|e|d| @50 diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -439,6 +439,32 @@ func Test_WinScrolled_once_only() call StopVimInTerminal(buf) endfunc +" Check that WinScrolled is not triggered immediately when defined and there +" are split windows. +func Test_WinScrolled_not_when_defined() + CheckRunVimInTerminal + + let lines =<< trim END + call setline(1, ['aaa', 'bbb']) + echo 'nothing happened' + func ShowTriggered(id) + echo 'triggered' + endfunc + END + call writefile(lines, 'Xtest_winscrolled_not', 'D') + let buf = RunVimInTerminal('-S Xtest_winscrolled_not', #{rows: 10, cols: 60, statusoff: 2}) + call term_sendkeys(buf, ":split\") + call TermWait(buf) + " use a timer to show the message after redrawing + call term_sendkeys(buf, ":au WinScrolled * call timer_start(100, 'ShowTriggered')\") + call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_1', {}) + + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_2', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_WinScrolled_long_wrapped() CheckRunVimInTerminal diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 915, +/**/ 914, /**/ 913, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -2846,7 +2846,7 @@ trigger_winclosed(win_T *win) * Make a snapshot of all the window scroll positions and sizes of the current * tab page. */ - static void + void snapshot_windows_scroll_size(void) { win_T *wp; @@ -3864,6 +3864,33 @@ close_others( } /* + * Store the relevant window pointers for tab page "tp". To be used before + * use_tabpage(). + */ + void +unuse_tabpage(tabpage_T *tp) +{ + tp->tp_topframe = topframe; + tp->tp_firstwin = firstwin; + tp->tp_lastwin = lastwin; + tp->tp_curwin = curwin; +} + +/* + * Set the relevant pointers to use tab page "tp". May want to call + * unuse_tabpage() first. + */ + void +use_tabpage(tabpage_T *tp) +{ + curtab = tp; + topframe = curtab->tp_topframe; + firstwin = curtab->tp_firstwin; + lastwin = curtab->tp_lastwin; + curwin = curtab->tp_curwin; +} + +/* * Allocate the first window and put an empty buffer in it. * Called from main(). * Return FAIL when something goes wrong (out of memory). @@ -3877,11 +3904,8 @@ win_alloc_first(void) first_tabpage = alloc_tabpage(); if (first_tabpage == NULL) return FAIL; - first_tabpage->tp_topframe = topframe; curtab = first_tabpage; - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab->tp_curwin = curwin; + unuse_tabpage(first_tabpage); return OK; } @@ -4389,10 +4413,7 @@ enter_tabpage( win_T *next_prevwin = tp->tp_prevwin; tabpage_T *last_tab = curtab; - curtab = tp; - firstwin = tp->tp_firstwin; - lastwin = tp->tp_lastwin; - topframe = tp->tp_topframe; + use_tabpage(tp); // We would like doing the TabEnter event first, but we don't have a // valid current window yet, which may break some commands.