@@ -84,6 +84,48 @@ static char *m_onlyone = N_("Already only one window");
8484// autocommands mess up the window structure.
8585static 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
28032847may_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