Skip to content

Commit d63a855

Browse files
committed
patch 9.0.0907: restoring window after WinScrolled may fail
Problem: Restoring window after WinScrolled may fail. Solution: Lock the window layout when triggering WinScrolled.
1 parent ff95ce0 commit d63a855

5 files changed

Lines changed: 71 additions & 8 deletions

File tree

src/errors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,3 +3341,5 @@ EXTERN char e_cannot_change_menus_while_listing[]
33413341
#endif
33423342
EXTERN char e_cannot_change_user_commands_while_listing[]
33433343
INIT(= N_("E1311: Cannot change user commands while listing"));
3344+
EXTERN char e_not_allowed_to_change_window_layout_in_this_autocmd[]
3345+
INIT(= N_("E1312: Not allowed to change the window layout in this autocmd"));

src/ex_docmd.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6055,6 +6055,8 @@ ex_win_close(
60556055
emsg(_(e_cannot_close_autocmd_or_popup_window));
60566056
return;
60576057
}
6058+
if (window_layout_locked())
6059+
return;
60586060

60596061
need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
60606062
if (need_hide && !buf_hide(buf) && !forceit)
@@ -6227,7 +6229,7 @@ ex_tabclose(exarg_T *eap)
62276229
cmdwin_result = K_IGNORE;
62286230
else if (first_tabpage->tp_next == NULL)
62296231
emsg(_(e_cannot_close_last_tab_page));
6230-
else
6232+
else if (!window_layout_locked())
62316233
{
62326234
tab_number = get_tabpage_arg(eap);
62336235
if (eap->errmsg == NULL)
@@ -6263,7 +6265,7 @@ ex_tabonly(exarg_T *eap)
62636265
cmdwin_result = K_IGNORE;
62646266
else if (first_tabpage->tp_next == NULL)
62656267
msg(_("Already only one tab page"));
6266-
else
6268+
else if (!window_layout_locked())
62676269
{
62686270
tab_number = get_tabpage_arg(eap);
62696271
if (eap->errmsg == NULL)
@@ -6296,6 +6298,9 @@ ex_tabonly(exarg_T *eap)
62966298
void
62976299
tabpage_close(int forceit)
62986300
{
6301+
if (window_layout_locked())
6302+
return;
6303+
62996304
// First close all the windows but the current one. If that worked then
63006305
// close the last window in this tab, that will close it.
63016306
if (!ONE_WINDOW)
@@ -6341,14 +6346,15 @@ tabpage_close_other(tabpage_T *tp, int forceit)
63416346
static void
63426347
ex_only(exarg_T *eap)
63436348
{
6344-
win_T *wp;
6345-
int wnr;
6349+
if (window_layout_locked())
6350+
return;
63466351
# ifdef FEAT_GUI
63476352
need_mouse_correct = TRUE;
63486353
# endif
63496354
if (eap->addr_count > 0)
63506355
{
6351-
wnr = eap->line2;
6356+
win_T *wp;
6357+
int wnr = eap->line2;
63526358
for (wp = firstwin; --wnr > 0; )
63536359
{
63546360
if (wp->w_next == NULL)
@@ -6367,6 +6373,8 @@ ex_hide(exarg_T *eap UNUSED)
63676373
// ":hide" or ":hide | cmd": hide current window
63686374
if (!eap->skip)
63696375
{
6376+
if (window_layout_locked())
6377+
return;
63706378
#ifdef FEAT_GUI
63716379
need_mouse_correct = TRUE;
63726380
#endif

src/proto/window.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* window.c */
2+
int window_layout_locked(void);
23
win_T *prevwin_curwin(void);
34
void do_window(int nchar, long Prenum, int xchar);
45
void get_wincmd_addr_type(char_u *arg, exarg_T *eap);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
907,
698700
/**/
699701
906,
700702
/**/

src/window.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,48 @@ static char *m_onlyone = N_("Already only one window");
8484
// autocommands mess up the window structure.
8585
static int split_disallowed = 0;
8686

87+
// When non-zero closing a window is forbidden. Used to avoid that nasty
88+
// autocommands mess up the window structure.
89+
static int close_disallowed = 0;
90+
91+
/*
92+
* Disallow changing the window layout (split window, close window, move
93+
* window). Resizing is still allowed.
94+
* Used for autocommands that temporarily use another window and need to
95+
* make sure the previously selected window is still there.
96+
* Must be matched with exactly one call to window_layout_unlock()!
97+
*/
98+
static void
99+
window_layout_lock(void)
100+
{
101+
++split_disallowed;
102+
++close_disallowed;
103+
}
104+
105+
static void
106+
window_layout_unlock(void)
107+
{
108+
--split_disallowed;
109+
--close_disallowed;
110+
}
111+
112+
/*
113+
* When the window layout cannot be changed give an error and return TRUE.
114+
*/
115+
int
116+
window_layout_locked(void)
117+
{
118+
if (split_disallowed > 0 || close_disallowed > 0)
119+
{
120+
if (close_disallowed == 0)
121+
emsg(_(e_cannot_split_window_when_closing_buffer));
122+
else
123+
emsg(_(e_not_allowed_to_change_window_layout_in_this_autocmd));
124+
return TRUE;
125+
}
126+
return FALSE;
127+
}
128+
87129
// #define WIN_DEBUG
88130
#ifdef WIN_DEBUG
89131
/*
@@ -2531,6 +2573,8 @@ win_close(win_T *win, int free_buf)
25312573
emsg(_(e_cannot_close_last_window));
25322574
return FAIL;
25332575
}
2576+
if (window_layout_locked())
2577+
return FAIL;
25342578

25352579
if (win->w_closing || (win->w_buffer != NULL
25362580
&& win->w_buffer->b_locked > 0))
@@ -2802,24 +2846,28 @@ trigger_winclosed(win_T *win)
28022846
void
28032847
may_trigger_winscrolled(void)
28042848
{
2805-
win_T *wp = curwin;
28062849
static int recursive = FALSE;
2807-
char_u winid[NUMBUFLEN];
28082850

28092851
if (recursive || !has_winscrolled())
28102852
return;
28112853

2854+
win_T *wp = curwin;
28122855
if (wp->w_last_topline != wp->w_topline
28132856
|| wp->w_last_leftcol != wp->w_leftcol
28142857
|| wp->w_last_skipcol != wp->w_skipcol
28152858
|| wp->w_last_width != wp->w_width
28162859
|| wp->w_last_height != wp->w_height)
28172860
{
2818-
vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id);
2861+
// "curwin" may be different from the actual current window, make sure
2862+
// it can be restored.
2863+
window_layout_lock();
28192864

28202865
recursive = TRUE;
2866+
char_u winid[NUMBUFLEN];
2867+
vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id);
28212868
apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer);
28222869
recursive = FALSE;
2870+
window_layout_unlock();
28232871

28242872
// an autocmd may close the window, "wp" may be invalid now
28252873
if (win_valid_any_tab(wp))
@@ -4014,6 +4062,8 @@ win_new_tabpage(int after)
40144062
emsg(_(e_invalid_in_cmdline_window));
40154063
return FAIL;
40164064
}
4065+
if (window_layout_locked())
4066+
return FAIL;
40174067

40184068
newtp = alloc_tabpage();
40194069
if (newtp == NULL)

0 commit comments

Comments
 (0)