xref: /vim-8.2.3635/src/window.c (revision 87fd0924)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read a list of people who contributed.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar 
10071d4279SBram Moolenaar #include "vim.h"
11071d4279SBram Moolenaar 
12baaa7e9eSBram Moolenaar static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, long Prenum);
13baaa7e9eSBram Moolenaar static void win_init(win_T *newp, win_T *oldp, int flags);
14baaa7e9eSBram Moolenaar static void win_init_some(win_T *newp, win_T *oldp);
15baaa7e9eSBram Moolenaar static void frame_comp_pos(frame_T *topfrp, int *row, int *col);
16baaa7e9eSBram Moolenaar static void frame_setheight(frame_T *curfrp, int height);
17baaa7e9eSBram Moolenaar static void frame_setwidth(frame_T *curfrp, int width);
18baaa7e9eSBram Moolenaar static void win_exchange(long);
19baaa7e9eSBram Moolenaar static void win_rotate(int, int);
20baaa7e9eSBram Moolenaar static void win_totop(int size, int flags);
21baaa7e9eSBram Moolenaar static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
2223beefedSnaohiro ono static void trigger_winclosed(win_T *win);
23baaa7e9eSBram Moolenaar static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
24baaa7e9eSBram Moolenaar static frame_T *win_altframe(win_T *win, tabpage_T *tp);
25baaa7e9eSBram Moolenaar static tabpage_T *alt_tabpage(void);
26baaa7e9eSBram Moolenaar static win_T *frame2win(frame_T *frp);
27baaa7e9eSBram Moolenaar static int frame_has_win(frame_T *frp, win_T *wp);
28baaa7e9eSBram Moolenaar static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
29baaa7e9eSBram Moolenaar static int frame_fixed_height(frame_T *frp);
30baaa7e9eSBram Moolenaar static int frame_fixed_width(frame_T *frp);
31baaa7e9eSBram Moolenaar static void frame_add_statusline(frame_T *frp);
32baaa7e9eSBram Moolenaar static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw);
33baaa7e9eSBram Moolenaar static void frame_add_vsep(frame_T *frp);
34baaa7e9eSBram Moolenaar static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
35baaa7e9eSBram Moolenaar static void frame_fix_width(win_T *wp);
36baaa7e9eSBram Moolenaar static int win_alloc_firstwin(win_T *oldwin);
37baaa7e9eSBram Moolenaar static void new_frame(win_T *wp);
38baaa7e9eSBram Moolenaar static tabpage_T *alloc_tabpage(void);
39baaa7e9eSBram Moolenaar static int leave_tabpage(buf_T *new_curbuf, int trigger_leave_autocmds);
40baaa7e9eSBram Moolenaar static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds);
41baaa7e9eSBram Moolenaar static void frame_fix_height(win_T *wp);
42baaa7e9eSBram Moolenaar static int frame_minheight(frame_T *topfrp, win_T *next_curwin);
435843f5f3SBram Moolenaar static int may_open_tabpage(void);
4457942237SBram Moolenaar static int win_enter_ext(win_T *wp, int flags);
45baaa7e9eSBram Moolenaar static void win_free(win_T *wp, tabpage_T *tp);
465843f5f3SBram Moolenaar static int win_unlisted(win_T *wp);
475843f5f3SBram Moolenaar static void win_append(win_T *after, win_T *wp);
48baaa7e9eSBram Moolenaar static void frame_append(frame_T *after, frame_T *frp);
49baaa7e9eSBram Moolenaar static void frame_insert(frame_T *before, frame_T *frp);
50baaa7e9eSBram Moolenaar static void frame_remove(frame_T *frp);
51baaa7e9eSBram Moolenaar static void win_goto_ver(int up, long count);
52baaa7e9eSBram Moolenaar static void win_goto_hor(int left, long count);
53baaa7e9eSBram Moolenaar static void frame_add_height(frame_T *frp, int n);
54baaa7e9eSBram Moolenaar static void last_status_rec(frame_T *fr, int statusline);
55071d4279SBram Moolenaar 
56baaa7e9eSBram Moolenaar static void make_snapshot_rec(frame_T *fr, frame_T **frp);
57baaa7e9eSBram Moolenaar static void clear_snapshot(tabpage_T *tp, int idx);
58baaa7e9eSBram Moolenaar static void clear_snapshot_rec(frame_T *fr);
59baaa7e9eSBram Moolenaar static int check_snapshot_rec(frame_T *sn, frame_T *fr);
60baaa7e9eSBram Moolenaar static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr);
61071d4279SBram Moolenaar 
62baaa7e9eSBram Moolenaar static int frame_check_height(frame_T *topfrp, int height);
63baaa7e9eSBram Moolenaar static int frame_check_width(frame_T *topfrp, int width);
64b893ac20SBram Moolenaar 
65baaa7e9eSBram Moolenaar static win_T *win_alloc(win_T *after, int hidden);
66071d4279SBram Moolenaar 
67e38eab22SBram Moolenaar #define NOWIN		(win_T *)-1	// non-existing window
68071d4279SBram Moolenaar 
6932466aa2SBram Moolenaar #define ROWS_AVAIL (Rows - p_ch - tabline_height())
704c3f536fSBram Moolenaar 
71d61f2f77SBram Moolenaar // flags for win_enter_ext()
72d61f2f77SBram Moolenaar #define WEE_UNDO_SYNC			0x01
73d61f2f77SBram Moolenaar #define WEE_CURWIN_INVALID		0x02
74d61f2f77SBram Moolenaar #define WEE_TRIGGER_NEW_AUTOCMDS	0x04
75d61f2f77SBram Moolenaar #define WEE_TRIGGER_ENTER_AUTOCMDS	0x08
76d61f2f77SBram Moolenaar #define WEE_TRIGGER_LEAVE_AUTOCMDS	0x10
7757942237SBram Moolenaar #define WEE_ALLOW_PARSE_MESSAGES	0x20
78d61f2f77SBram Moolenaar 
794c3f536fSBram Moolenaar static char *m_onlyone = N_("Already only one window");
804c3f536fSBram Moolenaar 
811417c766SBram Moolenaar // When non-zero splitting a window is forbidden.  Used to avoid that nasty
821417c766SBram Moolenaar // autocommands mess up the window structure.
831417c766SBram Moolenaar static int split_disallowed = 0;
841417c766SBram Moolenaar 
851417c766SBram Moolenaar // #define WIN_DEBUG
861417c766SBram Moolenaar #ifdef WIN_DEBUG
871417c766SBram Moolenaar /*
881417c766SBram Moolenaar  * Call this method to log the current window layout.
891417c766SBram Moolenaar  */
901417c766SBram Moolenaar     static void
log_frame_layout(frame_T * frame)911417c766SBram Moolenaar log_frame_layout(frame_T *frame)
921417c766SBram Moolenaar {
931417c766SBram Moolenaar     ch_log(NULL, "layout %s, wi: %d, he: %d, wwi: %d, whe: %d, id: %d",
941417c766SBram Moolenaar 	    frame->fr_layout == FR_LEAF ? "LEAF"
951417c766SBram Moolenaar 				  : frame->fr_layout == FR_ROW ? "ROW" : "COL",
961417c766SBram Moolenaar 	    frame->fr_width,
971417c766SBram Moolenaar 	    frame->fr_height,
981417c766SBram Moolenaar 	    frame->fr_win == NULL ? -1 : frame->fr_win->w_width,
991417c766SBram Moolenaar 	    frame->fr_win == NULL ? -1 : frame->fr_win->w_height,
1001417c766SBram Moolenaar 	    frame->fr_win == NULL ? -1 : frame->fr_win->w_id);
1011417c766SBram Moolenaar     if (frame->fr_child != NULL)
1021417c766SBram Moolenaar     {
1031417c766SBram Moolenaar 	ch_log(NULL, "children");
1041417c766SBram Moolenaar 	log_frame_layout(frame->fr_child);
1051417c766SBram Moolenaar 	if (frame->fr_next != NULL)
1061417c766SBram Moolenaar 	    ch_log(NULL, "END of children");
1071417c766SBram Moolenaar     }
1081417c766SBram Moolenaar     if (frame->fr_next != NULL)
1091417c766SBram Moolenaar 	log_frame_layout(frame->fr_next);
1101417c766SBram Moolenaar }
1111417c766SBram Moolenaar #endif
1121417c766SBram Moolenaar 
113071d4279SBram Moolenaar /*
11472e83c1aSBram Moolenaar  * All CTRL-W window commands are handled here, called from normal_cmd().
115071d4279SBram Moolenaar  */
116071d4279SBram Moolenaar     void
do_window(int nchar,long Prenum,int xchar)117b638a7beSBram Moolenaar do_window(
118b638a7beSBram Moolenaar     int		nchar,
119b638a7beSBram Moolenaar     long	Prenum,
120e38eab22SBram Moolenaar     int		xchar)	    // extra char from ":wincmd gx" or NUL
121071d4279SBram Moolenaar {
122071d4279SBram Moolenaar     long	Prenum1;
123071d4279SBram Moolenaar     win_T	*wp;
124071d4279SBram Moolenaar #if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
125071d4279SBram Moolenaar     char_u	*ptr;
126d1f56e68SBram Moolenaar     linenr_T    lnum = -1;
127071d4279SBram Moolenaar #endif
128071d4279SBram Moolenaar #ifdef FEAT_FIND_ID
129071d4279SBram Moolenaar     int		type = FIND_DEFINE;
130071d4279SBram Moolenaar     int		len;
131071d4279SBram Moolenaar #endif
132071d4279SBram Moolenaar     char_u	cbuf[40];
133071d4279SBram Moolenaar 
1343c01c4a0SBram Moolenaar     if (ERROR_IF_ANY_POPUP_WINDOW)
135815b76bfSBram Moolenaar 	return;
136071d4279SBram Moolenaar 
137071d4279SBram Moolenaar #ifdef FEAT_CMDWIN
1386f470023SBram Moolenaar # define CHECK_CMDWIN \
1396f470023SBram Moolenaar     do { \
1406f470023SBram Moolenaar 	if (cmdwin_type != 0) \
1416f470023SBram Moolenaar 	{ \
142108010aaSBram Moolenaar 	    emsg(_(e_invalid_in_cmdline_window)); \
1436f470023SBram Moolenaar 	    return; \
1446f470023SBram Moolenaar 	} \
1456f470023SBram Moolenaar     } while (0)
146071d4279SBram Moolenaar #else
1476f470023SBram Moolenaar # define CHECK_CMDWIN do { /**/ } while (0)
148071d4279SBram Moolenaar #endif
149071d4279SBram Moolenaar 
150815b76bfSBram Moolenaar     Prenum1 = Prenum == 0 ? 1 : Prenum;
151815b76bfSBram Moolenaar 
152071d4279SBram Moolenaar     switch (nchar)
153071d4279SBram Moolenaar     {
154e38eab22SBram Moolenaar // split current window in two parts, horizontally
155071d4279SBram Moolenaar     case 'S':
156071d4279SBram Moolenaar     case Ctrl_S:
157071d4279SBram Moolenaar     case 's':
1586f470023SBram Moolenaar 		CHECK_CMDWIN;
159e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
160b1b715d1SBram Moolenaar #ifdef FEAT_QUICKFIX
161e38eab22SBram Moolenaar 		// When splitting the quickfix window open a new buffer in it,
162e38eab22SBram Moolenaar 		// don't replicate the quickfix buffer.
163b1b715d1SBram Moolenaar 		if (bt_quickfix(curbuf))
164b1b715d1SBram Moolenaar 		    goto newwindow;
165b1b715d1SBram Moolenaar #endif
166071d4279SBram Moolenaar #ifdef FEAT_GUI
167071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
168071d4279SBram Moolenaar #endif
169cde88547SBram Moolenaar 		(void)win_split((int)Prenum, 0);
170071d4279SBram Moolenaar 		break;
171071d4279SBram Moolenaar 
172e38eab22SBram Moolenaar // split current window in two parts, vertically
173071d4279SBram Moolenaar     case Ctrl_V:
174071d4279SBram Moolenaar     case 'v':
1756f470023SBram Moolenaar 		CHECK_CMDWIN;
176e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
177990d95c0SBram Moolenaar #ifdef FEAT_QUICKFIX
178e38eab22SBram Moolenaar 		// When splitting the quickfix window open a new buffer in it,
179e38eab22SBram Moolenaar 		// don't replicate the quickfix buffer.
180990d95c0SBram Moolenaar 		if (bt_quickfix(curbuf))
181990d95c0SBram Moolenaar 		    goto newwindow;
182990d95c0SBram Moolenaar #endif
183071d4279SBram Moolenaar #ifdef FEAT_GUI
184071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
185071d4279SBram Moolenaar #endif
186cde88547SBram Moolenaar 		(void)win_split((int)Prenum, WSP_VERT);
187071d4279SBram Moolenaar 		break;
188071d4279SBram Moolenaar 
189e38eab22SBram Moolenaar // split current window and edit alternate file
190071d4279SBram Moolenaar     case Ctrl_HAT:
191071d4279SBram Moolenaar     case '^':
1926f470023SBram Moolenaar 		CHECK_CMDWIN;
193e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
1941bbb6194SBram Moolenaar 
1951bbb6194SBram Moolenaar 		if (buflist_findnr(Prenum == 0
1961bbb6194SBram Moolenaar 					? curwin->w_alt_fnum : Prenum) == NULL)
1971bbb6194SBram Moolenaar 		{
1981bbb6194SBram Moolenaar 		    if (Prenum == 0)
199108010aaSBram Moolenaar 			emsg(_(e_no_alternate_file));
2001bbb6194SBram Moolenaar 		    else
201f9e3e09fSBram Moolenaar 			semsg(_("E92: Buffer %ld not found"), Prenum);
2021bbb6194SBram Moolenaar 		    break;
2031bbb6194SBram Moolenaar 		}
2041bbb6194SBram Moolenaar 
2051bbb6194SBram Moolenaar 		if (!curbuf_locked() && win_split(0, 0) == OK)
2061bbb6194SBram Moolenaar 		    (void)buflist_getfile(
2071bbb6194SBram Moolenaar 			    Prenum == 0 ? curwin->w_alt_fnum : Prenum,
2081bbb6194SBram Moolenaar 			    (linenr_T)0, GETF_ALT, FALSE);
209071d4279SBram Moolenaar 		break;
210071d4279SBram Moolenaar 
211e38eab22SBram Moolenaar // open new window
212071d4279SBram Moolenaar     case Ctrl_N:
213071d4279SBram Moolenaar     case 'n':
2146f470023SBram Moolenaar 		CHECK_CMDWIN;
215e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
216b1b715d1SBram Moolenaar #ifdef FEAT_QUICKFIX
217b1b715d1SBram Moolenaar newwindow:
218b1b715d1SBram Moolenaar #endif
219071d4279SBram Moolenaar 		if (Prenum)
220e38eab22SBram Moolenaar 		    // window height
221990d95c0SBram Moolenaar 		    vim_snprintf((char *)cbuf, sizeof(cbuf) - 5, "%ld", Prenum);
222071d4279SBram Moolenaar 		else
223071d4279SBram Moolenaar 		    cbuf[0] = NUL;
22444a2f923SBram Moolenaar #if defined(FEAT_QUICKFIX)
225990d95c0SBram Moolenaar 		if (nchar == 'v' || nchar == Ctrl_V)
226990d95c0SBram Moolenaar 		    STRCAT(cbuf, "v");
227990d95c0SBram Moolenaar #endif
228071d4279SBram Moolenaar 		STRCAT(cbuf, "new");
229071d4279SBram Moolenaar 		do_cmdline_cmd(cbuf);
230071d4279SBram Moolenaar 		break;
231071d4279SBram Moolenaar 
232e38eab22SBram Moolenaar // quit current window
233071d4279SBram Moolenaar     case Ctrl_Q:
234071d4279SBram Moolenaar     case 'q':
235e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
2362f1e51a4SBram Moolenaar 		cmd_with_count("quit", cbuf, sizeof(cbuf), Prenum);
237b96a7f32SBram Moolenaar 		do_cmdline_cmd(cbuf);
238071d4279SBram Moolenaar 		break;
239071d4279SBram Moolenaar 
240e38eab22SBram Moolenaar // close current window
241071d4279SBram Moolenaar     case Ctrl_C:
242071d4279SBram Moolenaar     case 'c':
243e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
2442f1e51a4SBram Moolenaar 		cmd_with_count("close", cbuf, sizeof(cbuf), Prenum);
245b96a7f32SBram Moolenaar 		do_cmdline_cmd(cbuf);
246071d4279SBram Moolenaar 		break;
247071d4279SBram Moolenaar 
2484033c55eSBram Moolenaar #if defined(FEAT_QUICKFIX)
249e38eab22SBram Moolenaar // close preview window
250071d4279SBram Moolenaar     case Ctrl_Z:
251071d4279SBram Moolenaar     case 'z':
2526f470023SBram Moolenaar 		CHECK_CMDWIN;
253e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
254071d4279SBram Moolenaar 		do_cmdline_cmd((char_u *)"pclose");
255071d4279SBram Moolenaar 		break;
256071d4279SBram Moolenaar 
257e38eab22SBram Moolenaar // cursor to preview window
258071d4279SBram Moolenaar     case 'P':
25929323590SBram Moolenaar 		FOR_ALL_WINDOWS(wp)
260071d4279SBram Moolenaar 		    if (wp->w_p_pvw)
261071d4279SBram Moolenaar 			break;
262071d4279SBram Moolenaar 		if (wp == NULL)
263f9e3e09fSBram Moolenaar 		    emsg(_("E441: There is no preview window"));
264071d4279SBram Moolenaar 		else
265071d4279SBram Moolenaar 		    win_goto(wp);
266071d4279SBram Moolenaar 		break;
267071d4279SBram Moolenaar #endif
268071d4279SBram Moolenaar 
269e38eab22SBram Moolenaar // close all but current window
270071d4279SBram Moolenaar     case Ctrl_O:
271071d4279SBram Moolenaar     case 'o':
2726f470023SBram Moolenaar 		CHECK_CMDWIN;
273e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
2742f1e51a4SBram Moolenaar 		cmd_with_count("only", cbuf, sizeof(cbuf), Prenum);
275b96a7f32SBram Moolenaar 		do_cmdline_cmd(cbuf);
276071d4279SBram Moolenaar 		break;
277071d4279SBram Moolenaar 
278e38eab22SBram Moolenaar // cursor to next window with wrap around
279071d4279SBram Moolenaar     case Ctrl_W:
280071d4279SBram Moolenaar     case 'w':
281e38eab22SBram Moolenaar // cursor to previous window with wrap around
282071d4279SBram Moolenaar     case 'W':
2836f470023SBram Moolenaar 		CHECK_CMDWIN;
284e38eab22SBram Moolenaar 		if (ONE_WINDOW && Prenum != 1)	// just one window
285071d4279SBram Moolenaar 		    beep_flush();
286071d4279SBram Moolenaar 		else
287071d4279SBram Moolenaar 		{
288e38eab22SBram Moolenaar 		    if (Prenum)			// go to specified window
289071d4279SBram Moolenaar 		    {
290071d4279SBram Moolenaar 			for (wp = firstwin; --Prenum > 0; )
291071d4279SBram Moolenaar 			{
292071d4279SBram Moolenaar 			    if (wp->w_next == NULL)
293071d4279SBram Moolenaar 				break;
294071d4279SBram Moolenaar 			    else
295071d4279SBram Moolenaar 				wp = wp->w_next;
296071d4279SBram Moolenaar 			}
297071d4279SBram Moolenaar 		    }
298071d4279SBram Moolenaar 		    else
299071d4279SBram Moolenaar 		    {
300e38eab22SBram Moolenaar 			if (nchar == 'W')	    // go to previous window
301071d4279SBram Moolenaar 			{
302071d4279SBram Moolenaar 			    wp = curwin->w_prev;
303071d4279SBram Moolenaar 			    if (wp == NULL)
304e38eab22SBram Moolenaar 				wp = lastwin;	    // wrap around
305071d4279SBram Moolenaar 			}
306e38eab22SBram Moolenaar 			else			    // go to next window
307071d4279SBram Moolenaar 			{
308071d4279SBram Moolenaar 			    wp = curwin->w_next;
309071d4279SBram Moolenaar 			    if (wp == NULL)
310e38eab22SBram Moolenaar 				wp = firstwin;	    // wrap around
311071d4279SBram Moolenaar 			}
312071d4279SBram Moolenaar 		    }
313071d4279SBram Moolenaar 		    win_goto(wp);
314071d4279SBram Moolenaar 		}
315071d4279SBram Moolenaar 		break;
316071d4279SBram Moolenaar 
317e38eab22SBram Moolenaar // cursor to window below
318071d4279SBram Moolenaar     case 'j':
319071d4279SBram Moolenaar     case K_DOWN:
320071d4279SBram Moolenaar     case Ctrl_J:
3216f470023SBram Moolenaar 		CHECK_CMDWIN;
322071d4279SBram Moolenaar 		win_goto_ver(FALSE, Prenum1);
323071d4279SBram Moolenaar 		break;
324071d4279SBram Moolenaar 
325e38eab22SBram Moolenaar // cursor to window above
326071d4279SBram Moolenaar     case 'k':
327071d4279SBram Moolenaar     case K_UP:
328071d4279SBram Moolenaar     case Ctrl_K:
3296f470023SBram Moolenaar 		CHECK_CMDWIN;
330071d4279SBram Moolenaar 		win_goto_ver(TRUE, Prenum1);
331071d4279SBram Moolenaar 		break;
332071d4279SBram Moolenaar 
333e38eab22SBram Moolenaar // cursor to left window
334071d4279SBram Moolenaar     case 'h':
335071d4279SBram Moolenaar     case K_LEFT:
336071d4279SBram Moolenaar     case Ctrl_H:
337071d4279SBram Moolenaar     case K_BS:
3386f470023SBram Moolenaar 		CHECK_CMDWIN;
339071d4279SBram Moolenaar 		win_goto_hor(TRUE, Prenum1);
340071d4279SBram Moolenaar 		break;
341071d4279SBram Moolenaar 
342e38eab22SBram Moolenaar // cursor to right window
343071d4279SBram Moolenaar     case 'l':
344071d4279SBram Moolenaar     case K_RIGHT:
345071d4279SBram Moolenaar     case Ctrl_L:
3466f470023SBram Moolenaar 		CHECK_CMDWIN;
347071d4279SBram Moolenaar 		win_goto_hor(FALSE, Prenum1);
348071d4279SBram Moolenaar 		break;
349071d4279SBram Moolenaar 
350e38eab22SBram Moolenaar // move window to new tab page
3514c3f536fSBram Moolenaar     case 'T':
3524fdb8bd0SBram Moolenaar 		CHECK_CMDWIN;
353746ebd3bSBram Moolenaar 		if (one_window())
35432526b3cSBram Moolenaar 		    msg(_(m_onlyone));
3554c3f536fSBram Moolenaar 		else
3564c3f536fSBram Moolenaar 		{
3574c3f536fSBram Moolenaar 		    tabpage_T	*oldtab = curtab;
3584c3f536fSBram Moolenaar 		    tabpage_T	*newtab;
3594c3f536fSBram Moolenaar 
360e38eab22SBram Moolenaar 		    // First create a new tab with the window, then go back to
361e38eab22SBram Moolenaar 		    // the old tab and close the window there.
36289d4032cSBram Moolenaar 		    wp = curwin;
3634c3f536fSBram Moolenaar 		    if (win_new_tabpage((int)Prenum) == OK
3644c3f536fSBram Moolenaar 						     && valid_tabpage(oldtab))
3654c3f536fSBram Moolenaar 		    {
3664c3f536fSBram Moolenaar 			newtab = curtab;
36749e649fcSBram Moolenaar 			goto_tabpage_tp(oldtab, TRUE, TRUE);
3684c3f536fSBram Moolenaar 			if (curwin == wp)
3694c3f536fSBram Moolenaar 			    win_close(curwin, FALSE);
3704c3f536fSBram Moolenaar 			if (valid_tabpage(newtab))
37149e649fcSBram Moolenaar 			    goto_tabpage_tp(newtab, TRUE, TRUE);
3724c3f536fSBram Moolenaar 		    }
3734c3f536fSBram Moolenaar 		}
3744c3f536fSBram Moolenaar 		break;
3754c3f536fSBram Moolenaar 
376e38eab22SBram Moolenaar // cursor to top-left window
377071d4279SBram Moolenaar     case 't':
378071d4279SBram Moolenaar     case Ctrl_T:
379071d4279SBram Moolenaar 		win_goto(firstwin);
380071d4279SBram Moolenaar 		break;
381071d4279SBram Moolenaar 
382e38eab22SBram Moolenaar // cursor to bottom-right window
383071d4279SBram Moolenaar     case 'b':
384071d4279SBram Moolenaar     case Ctrl_B:
385071d4279SBram Moolenaar 		win_goto(lastwin);
386071d4279SBram Moolenaar 		break;
387071d4279SBram Moolenaar 
388e38eab22SBram Moolenaar // cursor to last accessed (previous) window
389071d4279SBram Moolenaar     case 'p':
390071d4279SBram Moolenaar     case Ctrl_P:
3913dda7db4SBram Moolenaar 		if (!win_valid(prevwin))
392071d4279SBram Moolenaar 		    beep_flush();
393071d4279SBram Moolenaar 		else
394071d4279SBram Moolenaar 		    win_goto(prevwin);
395071d4279SBram Moolenaar 		break;
396071d4279SBram Moolenaar 
397e38eab22SBram Moolenaar // exchange current and next window
398071d4279SBram Moolenaar     case 'x':
399071d4279SBram Moolenaar     case Ctrl_X:
4006f470023SBram Moolenaar 		CHECK_CMDWIN;
401071d4279SBram Moolenaar 		win_exchange(Prenum);
402071d4279SBram Moolenaar 		break;
403071d4279SBram Moolenaar 
404e38eab22SBram Moolenaar // rotate windows downwards
405071d4279SBram Moolenaar     case Ctrl_R:
406071d4279SBram Moolenaar     case 'r':
4076f470023SBram Moolenaar 		CHECK_CMDWIN;
408e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
409e38eab22SBram Moolenaar 		win_rotate(FALSE, (int)Prenum1);    // downwards
410071d4279SBram Moolenaar 		break;
411071d4279SBram Moolenaar 
412e38eab22SBram Moolenaar // rotate windows upwards
413071d4279SBram Moolenaar     case 'R':
4146f470023SBram Moolenaar 		CHECK_CMDWIN;
415e38eab22SBram Moolenaar 		reset_VIsual_and_resel();	// stop Visual mode
416e38eab22SBram Moolenaar 		win_rotate(TRUE, (int)Prenum1);	    // upwards
417071d4279SBram Moolenaar 		break;
418071d4279SBram Moolenaar 
419e38eab22SBram Moolenaar // move window to the very top/bottom/left/right
420071d4279SBram Moolenaar     case 'K':
421071d4279SBram Moolenaar     case 'J':
422071d4279SBram Moolenaar     case 'H':
423071d4279SBram Moolenaar     case 'L':
4246f470023SBram Moolenaar 		CHECK_CMDWIN;
425071d4279SBram Moolenaar 		win_totop((int)Prenum,
426071d4279SBram Moolenaar 			((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
427071d4279SBram Moolenaar 			| ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
428071d4279SBram Moolenaar 		break;
429071d4279SBram Moolenaar 
430e38eab22SBram Moolenaar // make all windows the same height
431071d4279SBram Moolenaar     case '=':
432071d4279SBram Moolenaar #ifdef FEAT_GUI
433071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
434071d4279SBram Moolenaar #endif
435071d4279SBram Moolenaar 		win_equal(NULL, FALSE, 'b');
436071d4279SBram Moolenaar 		break;
437071d4279SBram Moolenaar 
438e38eab22SBram Moolenaar // increase current window height
439071d4279SBram Moolenaar     case '+':
440071d4279SBram Moolenaar #ifdef FEAT_GUI
441071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
442071d4279SBram Moolenaar #endif
443071d4279SBram Moolenaar 		win_setheight(curwin->w_height + (int)Prenum1);
444071d4279SBram Moolenaar 		break;
445071d4279SBram Moolenaar 
446e38eab22SBram Moolenaar // decrease current window height
447071d4279SBram Moolenaar     case '-':
448071d4279SBram Moolenaar #ifdef FEAT_GUI
449071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
450071d4279SBram Moolenaar #endif
451071d4279SBram Moolenaar 		win_setheight(curwin->w_height - (int)Prenum1);
452071d4279SBram Moolenaar 		break;
453071d4279SBram Moolenaar 
454e38eab22SBram Moolenaar // set current window height
455071d4279SBram Moolenaar     case Ctrl__:
456071d4279SBram Moolenaar     case '_':
457071d4279SBram Moolenaar #ifdef FEAT_GUI
458071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
459071d4279SBram Moolenaar #endif
460071d4279SBram Moolenaar 		win_setheight(Prenum ? (int)Prenum : 9999);
461071d4279SBram Moolenaar 		break;
462071d4279SBram Moolenaar 
463e38eab22SBram Moolenaar // increase current window width
464071d4279SBram Moolenaar     case '>':
465071d4279SBram Moolenaar #ifdef FEAT_GUI
466071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
467071d4279SBram Moolenaar #endif
468071d4279SBram Moolenaar 		win_setwidth(curwin->w_width + (int)Prenum1);
469071d4279SBram Moolenaar 		break;
470071d4279SBram Moolenaar 
471e38eab22SBram Moolenaar // decrease current window width
472071d4279SBram Moolenaar     case '<':
473071d4279SBram Moolenaar #ifdef FEAT_GUI
474071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
475071d4279SBram Moolenaar #endif
476071d4279SBram Moolenaar 		win_setwidth(curwin->w_width - (int)Prenum1);
477071d4279SBram Moolenaar 		break;
478071d4279SBram Moolenaar 
479e38eab22SBram Moolenaar // set current window width
480071d4279SBram Moolenaar     case '|':
481071d4279SBram Moolenaar #ifdef FEAT_GUI
482071d4279SBram Moolenaar 		need_mouse_correct = TRUE;
483071d4279SBram Moolenaar #endif
484071d4279SBram Moolenaar 		win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
485071d4279SBram Moolenaar 		break;
486071d4279SBram Moolenaar 
487e38eab22SBram Moolenaar // jump to tag and split window if tag exists (in preview window)
488071d4279SBram Moolenaar #if defined(FEAT_QUICKFIX)
489071d4279SBram Moolenaar     case '}':
4906f470023SBram Moolenaar 		CHECK_CMDWIN;
491071d4279SBram Moolenaar 		if (Prenum)
492071d4279SBram Moolenaar 		    g_do_tagpreview = Prenum;
493071d4279SBram Moolenaar 		else
494071d4279SBram Moolenaar 		    g_do_tagpreview = p_pvh;
495071d4279SBram Moolenaar #endif
496e38eab22SBram Moolenaar 		// FALLTHROUGH
497071d4279SBram Moolenaar     case ']':
498071d4279SBram Moolenaar     case Ctrl_RSB:
4996f470023SBram Moolenaar 		CHECK_CMDWIN;
500e38eab22SBram Moolenaar 		// keep Visual mode, can select words to use as a tag
501071d4279SBram Moolenaar 		if (Prenum)
502071d4279SBram Moolenaar 		    postponed_split = Prenum;
503071d4279SBram Moolenaar 		else
504071d4279SBram Moolenaar 		    postponed_split = -1;
505da014b94SBram Moolenaar #ifdef FEAT_QUICKFIX
50656095e1cSBram Moolenaar 		if (nchar != '}')
507d355c50aSBram Moolenaar 		    g_do_tagpreview = 0;
508da014b94SBram Moolenaar #endif
509071d4279SBram Moolenaar 
510e38eab22SBram Moolenaar 		// Execute the command right here, required when "wincmd ]"
511e38eab22SBram Moolenaar 		// was used in a function.
512071d4279SBram Moolenaar 		do_nv_ident(Ctrl_RSB, NUL);
513071d4279SBram Moolenaar 		break;
514071d4279SBram Moolenaar 
515071d4279SBram Moolenaar #ifdef FEAT_SEARCHPATH
516e38eab22SBram Moolenaar // edit file name under cursor in a new window
517071d4279SBram Moolenaar     case 'f':
518d1f56e68SBram Moolenaar     case 'F':
519071d4279SBram Moolenaar     case Ctrl_F:
5208dff818eSBram Moolenaar wingotofile:
5216f470023SBram Moolenaar 		CHECK_CMDWIN;
522d857f0e0SBram Moolenaar 
523d1f56e68SBram Moolenaar 		ptr = grab_file_name(Prenum1, &lnum);
524071d4279SBram Moolenaar 		if (ptr != NULL)
525071d4279SBram Moolenaar 		{
5265d2ca040SBram Moolenaar 		    tabpage_T	*oldtab = curtab;
5275d2ca040SBram Moolenaar 		    win_T	*oldwin = curwin;
528071d4279SBram Moolenaar # ifdef FEAT_GUI
529071d4279SBram Moolenaar 		    need_mouse_correct = TRUE;
530071d4279SBram Moolenaar # endif
531071d4279SBram Moolenaar 		    setpcmark();
532071d4279SBram Moolenaar 		    if (win_split(0, 0) == OK)
533071d4279SBram Moolenaar 		    {
5343368ea21SBram Moolenaar 			RESET_BINDING(curwin);
5355d2ca040SBram Moolenaar 			if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
5365d2ca040SBram Moolenaar 						   ECMD_HIDE, NULL) == FAIL)
5375d2ca040SBram Moolenaar 			{
538e38eab22SBram Moolenaar 			    // Failed to open the file, close the window
539e38eab22SBram Moolenaar 			    // opened for it.
5405d2ca040SBram Moolenaar 			    win_close(curwin, FALSE);
5415d2ca040SBram Moolenaar 			    goto_tabpage_win(oldtab, oldwin);
5425d2ca040SBram Moolenaar 			}
5435d2ca040SBram Moolenaar 			else if (nchar == 'F' && lnum >= 0)
544d1f56e68SBram Moolenaar 			{
545d1f56e68SBram Moolenaar 			    curwin->w_cursor.lnum = lnum;
546d1f56e68SBram Moolenaar 			    check_cursor_lnum();
547d1f56e68SBram Moolenaar 			    beginline(BL_SOL | BL_FIX);
548d1f56e68SBram Moolenaar 			}
549071d4279SBram Moolenaar 		    }
550071d4279SBram Moolenaar 		    vim_free(ptr);
551071d4279SBram Moolenaar 		}
552071d4279SBram Moolenaar 		break;
553071d4279SBram Moolenaar #endif
554071d4279SBram Moolenaar 
555071d4279SBram Moolenaar #ifdef FEAT_FIND_ID
556e38eab22SBram Moolenaar // Go to the first occurrence of the identifier under cursor along path in a
557e38eab22SBram Moolenaar // new window -- webb
558e38eab22SBram Moolenaar     case 'i':			    // Go to any match
559071d4279SBram Moolenaar     case Ctrl_I:
560071d4279SBram Moolenaar 		type = FIND_ANY;
561e38eab22SBram Moolenaar 		// FALLTHROUGH
562e38eab22SBram Moolenaar     case 'd':			    // Go to definition, using 'define'
563071d4279SBram Moolenaar     case Ctrl_D:
5646f470023SBram Moolenaar 		CHECK_CMDWIN;
565071d4279SBram Moolenaar 		if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
566071d4279SBram Moolenaar 		    break;
567071d4279SBram Moolenaar 		find_pattern_in_path(ptr, 0, len, TRUE,
568071d4279SBram Moolenaar 			Prenum == 0 ? TRUE : FALSE, type,
569071d4279SBram Moolenaar 			Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
570071d4279SBram Moolenaar 		curwin->w_set_curswant = TRUE;
571071d4279SBram Moolenaar 		break;
572071d4279SBram Moolenaar #endif
573071d4279SBram Moolenaar 
574e38eab22SBram Moolenaar // Quickfix window only: view the result under the cursor in a new split.
5750a08c63dSBram Moolenaar #if defined(FEAT_QUICKFIX)
57605159a0cSBram Moolenaar     case K_KENTER:
57705159a0cSBram Moolenaar     case CAR:
57805159a0cSBram Moolenaar 		if (bt_quickfix(curbuf))
5790a08c63dSBram Moolenaar 		    qf_view_result(TRUE);
58005159a0cSBram Moolenaar 		break;
5810a08c63dSBram Moolenaar #endif
58205159a0cSBram Moolenaar 
583e38eab22SBram Moolenaar // CTRL-W g  extended commands
584071d4279SBram Moolenaar     case 'g':
585071d4279SBram Moolenaar     case Ctrl_G:
5866f470023SBram Moolenaar 		CHECK_CMDWIN;
587071d4279SBram Moolenaar #ifdef USE_ON_FLY_SCROLL
588e38eab22SBram Moolenaar 		dont_scroll = TRUE;		// disallow scrolling here
589071d4279SBram Moolenaar #endif
590071d4279SBram Moolenaar 		++no_mapping;
591e38eab22SBram Moolenaar 		++allow_keys;   // no mapping for xchar, but allow key codes
592071d4279SBram Moolenaar 		if (xchar == NUL)
59361abfd11SBram Moolenaar 		    xchar = plain_vgetc();
594071d4279SBram Moolenaar 		LANGMAP_ADJUST(xchar, TRUE);
595071d4279SBram Moolenaar 		--no_mapping;
596071d4279SBram Moolenaar 		--allow_keys;
597071d4279SBram Moolenaar #ifdef FEAT_CMDL_INFO
598071d4279SBram Moolenaar 		(void)add_to_showcmd(xchar);
599071d4279SBram Moolenaar #endif
600071d4279SBram Moolenaar 		switch (xchar)
601071d4279SBram Moolenaar 		{
602071d4279SBram Moolenaar #if defined(FEAT_QUICKFIX)
603071d4279SBram Moolenaar 		    case '}':
604071d4279SBram Moolenaar 			xchar = Ctrl_RSB;
605071d4279SBram Moolenaar 			if (Prenum)
606071d4279SBram Moolenaar 			    g_do_tagpreview = Prenum;
607071d4279SBram Moolenaar 			else
608071d4279SBram Moolenaar 			    g_do_tagpreview = p_pvh;
609071d4279SBram Moolenaar #endif
610e38eab22SBram Moolenaar 			// FALLTHROUGH
611071d4279SBram Moolenaar 		    case ']':
612071d4279SBram Moolenaar 		    case Ctrl_RSB:
613e38eab22SBram Moolenaar 			// keep Visual mode, can select words to use as a tag
614071d4279SBram Moolenaar 			if (Prenum)
615071d4279SBram Moolenaar 			    postponed_split = Prenum;
616071d4279SBram Moolenaar 			else
617071d4279SBram Moolenaar 			    postponed_split = -1;
618071d4279SBram Moolenaar 
619e38eab22SBram Moolenaar 			// Execute the command right here, required when
620e38eab22SBram Moolenaar 			// "wincmd g}" was used in a function.
621071d4279SBram Moolenaar 			do_nv_ident('g', xchar);
622071d4279SBram Moolenaar 			break;
623071d4279SBram Moolenaar 
6248dff818eSBram Moolenaar #ifdef FEAT_SEARCHPATH
625e38eab22SBram Moolenaar 		    case 'f':	    // CTRL-W gf: "gf" in a new tab page
626e38eab22SBram Moolenaar 		    case 'F':	    // CTRL-W gF: "gF" in a new tab page
627e1004401SBram Moolenaar 			cmdmod.cmod_tab = tabpage_index(curtab) + 1;
62857657d85SBram Moolenaar 			nchar = xchar;
6298dff818eSBram Moolenaar 			goto wingotofile;
6308dff818eSBram Moolenaar #endif
63172e83c1aSBram Moolenaar 		    case 't':	    // CTRL-W gt: go to next tab page
63272e83c1aSBram Moolenaar 			goto_tabpage((int)Prenum);
63372e83c1aSBram Moolenaar 			break;
63472e83c1aSBram Moolenaar 
635882d02eeSBram Moolenaar 		    case 'T':	    // CTRL-W gT: go to previous tab page
636882d02eeSBram Moolenaar 			goto_tabpage(-(int)Prenum1);
637882d02eeSBram Moolenaar 			break;
638882d02eeSBram Moolenaar 
63962a23250SBram Moolenaar 		    case TAB:	    // CTRL-W g<Tab>: go to last used tab page
64062a23250SBram Moolenaar 			if (goto_tabpage_lastused() == FAIL)
64162a23250SBram Moolenaar 			    beep_flush();
64262a23250SBram Moolenaar 			break;
64362a23250SBram Moolenaar 
644071d4279SBram Moolenaar 		    default:
645071d4279SBram Moolenaar 			beep_flush();
646071d4279SBram Moolenaar 			break;
647071d4279SBram Moolenaar 		}
648071d4279SBram Moolenaar 		break;
649071d4279SBram Moolenaar 
650071d4279SBram Moolenaar     default:	beep_flush();
651071d4279SBram Moolenaar 		break;
652071d4279SBram Moolenaar     }
653071d4279SBram Moolenaar }
654071d4279SBram Moolenaar 
65584c8e5abSBram Moolenaar /*
656b731689eSBram Moolenaar  * Figure out the address type for ":wincmd".
65784c8e5abSBram Moolenaar  */
65884c8e5abSBram Moolenaar     void
get_wincmd_addr_type(char_u * arg,exarg_T * eap)659b638a7beSBram Moolenaar get_wincmd_addr_type(char_u *arg, exarg_T *eap)
66084c8e5abSBram Moolenaar {
66184c8e5abSBram Moolenaar     switch (*arg)
66284c8e5abSBram Moolenaar     {
66384c8e5abSBram Moolenaar     case 'S':
66484c8e5abSBram Moolenaar     case Ctrl_S:
66584c8e5abSBram Moolenaar     case 's':
66684c8e5abSBram Moolenaar     case Ctrl_N:
66784c8e5abSBram Moolenaar     case 'n':
66884c8e5abSBram Moolenaar     case 'j':
66984c8e5abSBram Moolenaar     case Ctrl_J:
67084c8e5abSBram Moolenaar     case 'k':
67184c8e5abSBram Moolenaar     case Ctrl_K:
67284c8e5abSBram Moolenaar     case 'T':
67384c8e5abSBram Moolenaar     case Ctrl_R:
67484c8e5abSBram Moolenaar     case 'r':
67584c8e5abSBram Moolenaar     case 'R':
67684c8e5abSBram Moolenaar     case 'K':
67784c8e5abSBram Moolenaar     case 'J':
67884c8e5abSBram Moolenaar     case '+':
67984c8e5abSBram Moolenaar     case '-':
68084c8e5abSBram Moolenaar     case Ctrl__:
68184c8e5abSBram Moolenaar     case '_':
68284c8e5abSBram Moolenaar     case '|':
68384c8e5abSBram Moolenaar     case ']':
68484c8e5abSBram Moolenaar     case Ctrl_RSB:
68584c8e5abSBram Moolenaar     case 'g':
68684c8e5abSBram Moolenaar     case Ctrl_G:
68784c8e5abSBram Moolenaar     case Ctrl_V:
68884c8e5abSBram Moolenaar     case 'v':
68984c8e5abSBram Moolenaar     case 'h':
69084c8e5abSBram Moolenaar     case Ctrl_H:
69184c8e5abSBram Moolenaar     case 'l':
69284c8e5abSBram Moolenaar     case Ctrl_L:
69384c8e5abSBram Moolenaar     case 'H':
69484c8e5abSBram Moolenaar     case 'L':
69584c8e5abSBram Moolenaar     case '>':
69684c8e5abSBram Moolenaar     case '<':
69784c8e5abSBram Moolenaar #if defined(FEAT_QUICKFIX)
69884c8e5abSBram Moolenaar     case '}':
69984c8e5abSBram Moolenaar #endif
70084c8e5abSBram Moolenaar #ifdef FEAT_SEARCHPATH
70184c8e5abSBram Moolenaar     case 'f':
70284c8e5abSBram Moolenaar     case 'F':
70384c8e5abSBram Moolenaar     case Ctrl_F:
70484c8e5abSBram Moolenaar #endif
70584c8e5abSBram Moolenaar #ifdef FEAT_FIND_ID
70684c8e5abSBram Moolenaar     case 'i':
70784c8e5abSBram Moolenaar     case Ctrl_I:
70884c8e5abSBram Moolenaar     case 'd':
70984c8e5abSBram Moolenaar     case Ctrl_D:
71084c8e5abSBram Moolenaar #endif
711b731689eSBram Moolenaar 		// window size or any count
712b731689eSBram Moolenaar 		eap->addr_type = ADDR_OTHER;
71384c8e5abSBram Moolenaar 		break;
71484c8e5abSBram Moolenaar 
71584c8e5abSBram Moolenaar     case Ctrl_HAT:
71684c8e5abSBram Moolenaar     case '^':
717b731689eSBram Moolenaar 		// buffer number
71884c8e5abSBram Moolenaar 		eap->addr_type = ADDR_BUFFERS;
71984c8e5abSBram Moolenaar 		break;
72084c8e5abSBram Moolenaar 
72184c8e5abSBram Moolenaar     case Ctrl_Q:
72284c8e5abSBram Moolenaar     case 'q':
72384c8e5abSBram Moolenaar     case Ctrl_C:
72484c8e5abSBram Moolenaar     case 'c':
72584c8e5abSBram Moolenaar     case Ctrl_O:
72684c8e5abSBram Moolenaar     case 'o':
72784c8e5abSBram Moolenaar     case Ctrl_W:
72884c8e5abSBram Moolenaar     case 'w':
72984c8e5abSBram Moolenaar     case 'W':
73084c8e5abSBram Moolenaar     case 'x':
73184c8e5abSBram Moolenaar     case Ctrl_X:
732b731689eSBram Moolenaar 		// window number
73384c8e5abSBram Moolenaar 		eap->addr_type = ADDR_WINDOWS;
73484c8e5abSBram Moolenaar 		break;
73584c8e5abSBram Moolenaar 
73684c8e5abSBram Moolenaar #if defined(FEAT_QUICKFIX)
73784c8e5abSBram Moolenaar     case Ctrl_Z:
73884c8e5abSBram Moolenaar     case 'z':
73984c8e5abSBram Moolenaar     case 'P':
74084c8e5abSBram Moolenaar #endif
74184c8e5abSBram Moolenaar     case 't':
74284c8e5abSBram Moolenaar     case Ctrl_T:
74384c8e5abSBram Moolenaar     case 'b':
74484c8e5abSBram Moolenaar     case Ctrl_B:
74584c8e5abSBram Moolenaar     case 'p':
74684c8e5abSBram Moolenaar     case Ctrl_P:
74784c8e5abSBram Moolenaar     case '=':
74884c8e5abSBram Moolenaar     case CAR:
749b731689eSBram Moolenaar 		// no count
750b731689eSBram Moolenaar 		eap->addr_type = ADDR_NONE;
75184c8e5abSBram Moolenaar 		break;
75284c8e5abSBram Moolenaar     }
75384c8e5abSBram Moolenaar }
75484c8e5abSBram Moolenaar 
7552f1e51a4SBram Moolenaar     static void
cmd_with_count(char * cmd,char_u * bufp,size_t bufsize,long Prenum)756b638a7beSBram Moolenaar cmd_with_count(
757b638a7beSBram Moolenaar     char	*cmd,
758b638a7beSBram Moolenaar     char_u	*bufp,
759b638a7beSBram Moolenaar     size_t	bufsize,
760b638a7beSBram Moolenaar     long	Prenum)
7612f1e51a4SBram Moolenaar {
7622f1e51a4SBram Moolenaar     if (Prenum > 0)
7631ff89deeSBram Moolenaar 	vim_snprintf((char *)bufp, bufsize, "%s %ld", cmd, Prenum);
7641ff89deeSBram Moolenaar     else
7651ff89deeSBram Moolenaar 	STRCPY(bufp, cmd);
7662f1e51a4SBram Moolenaar }
7672f1e51a4SBram Moolenaar 
768071d4279SBram Moolenaar /*
7691417c766SBram Moolenaar  * If "split_disallowed" is set given an error and return FAIL.
7701417c766SBram Moolenaar  * Otherwise return OK.
7711417c766SBram Moolenaar  */
7721417c766SBram Moolenaar     static int
check_split_disallowed()7731417c766SBram Moolenaar check_split_disallowed()
7741417c766SBram Moolenaar {
7751417c766SBram Moolenaar     if (split_disallowed > 0)
7761417c766SBram Moolenaar     {
7771417c766SBram Moolenaar 	emsg(_("E242: Can't split a window while closing another"));
7781417c766SBram Moolenaar 	return FAIL;
7791417c766SBram Moolenaar     }
780983d83ffSBram Moolenaar     if (curwin->w_buffer->b_locked_split)
781983d83ffSBram Moolenaar     {
782983d83ffSBram Moolenaar 	emsg(_(e_cannot_split_window_when_closing_buffer));
783983d83ffSBram Moolenaar 	return FAIL;
784983d83ffSBram Moolenaar     }
7851417c766SBram Moolenaar     return OK;
7861417c766SBram Moolenaar }
7871417c766SBram Moolenaar 
7881417c766SBram Moolenaar /*
789071d4279SBram Moolenaar  * split the current window, implements CTRL-W s and :split
790071d4279SBram Moolenaar  *
791071d4279SBram Moolenaar  * "size" is the height or width for the new window, 0 to use half of current
792071d4279SBram Moolenaar  * height or width.
793071d4279SBram Moolenaar  *
794071d4279SBram Moolenaar  * "flags":
795071d4279SBram Moolenaar  * WSP_ROOM: require enough room for new window
796071d4279SBram Moolenaar  * WSP_VERT: vertical split.
797071d4279SBram Moolenaar  * WSP_TOP:  open window at the top-left of the shell (help window).
798071d4279SBram Moolenaar  * WSP_BOT:  open window at the bottom-right of the shell (quickfix window).
799071d4279SBram Moolenaar  * WSP_HELP: creating the help window, keep layout snapshot
800071d4279SBram Moolenaar  *
801071d4279SBram Moolenaar  * return FAIL for failure, OK otherwise
802071d4279SBram Moolenaar  */
803071d4279SBram Moolenaar     int
win_split(int size,int flags)804b638a7beSBram Moolenaar win_split(int size, int flags)
805071d4279SBram Moolenaar {
8063c01c4a0SBram Moolenaar     if (ERROR_IF_ANY_POPUP_WINDOW)
807815b76bfSBram Moolenaar 	return FAIL;
808815b76bfSBram Moolenaar 
809983d83ffSBram Moolenaar     if (check_split_disallowed() == FAIL)
810983d83ffSBram Moolenaar 	return FAIL;
811983d83ffSBram Moolenaar 
812e38eab22SBram Moolenaar     // When the ":tab" modifier was used open a new tab page instead.
81380a94a58SBram Moolenaar     if (may_open_tabpage() == OK)
81480a94a58SBram Moolenaar 	return OK;
81580a94a58SBram Moolenaar 
816e38eab22SBram Moolenaar     // Add flags from ":vertical", ":topleft" and ":botright".
817e1004401SBram Moolenaar     flags |= cmdmod.cmod_split;
818071d4279SBram Moolenaar     if ((flags & WSP_TOP) && (flags & WSP_BOT))
819071d4279SBram Moolenaar     {
820f9e3e09fSBram Moolenaar 	emsg(_("E442: Can't split topleft and botright at the same time"));
821071d4279SBram Moolenaar 	return FAIL;
822071d4279SBram Moolenaar     }
823071d4279SBram Moolenaar 
824e38eab22SBram Moolenaar     // When creating the help window make a snapshot of the window layout.
825e38eab22SBram Moolenaar     // Otherwise clear the snapshot, it's now invalid.
826071d4279SBram Moolenaar     if (flags & WSP_HELP)
827746ebd3bSBram Moolenaar 	make_snapshot(SNAP_HELP_IDX);
828071d4279SBram Moolenaar     else
829746ebd3bSBram Moolenaar 	clear_snapshot(curtab, SNAP_HELP_IDX);
830071d4279SBram Moolenaar 
831071d4279SBram Moolenaar     return win_split_ins(size, flags, NULL, 0);
832071d4279SBram Moolenaar }
833071d4279SBram Moolenaar 
834071d4279SBram Moolenaar /*
83570b2a56dSBram Moolenaar  * When "new_wp" is NULL: split the current window in two.
83670b2a56dSBram Moolenaar  * When "new_wp" is not NULL: insert this window at the far
837071d4279SBram Moolenaar  * top/left/right/bottom.
838071d4279SBram Moolenaar  * return FAIL for failure, OK otherwise
839071d4279SBram Moolenaar  */
840746ebd3bSBram Moolenaar     int
win_split_ins(int size,int flags,win_T * new_wp,int dir)841b638a7beSBram Moolenaar win_split_ins(
842b638a7beSBram Moolenaar     int		size,
843b638a7beSBram Moolenaar     int		flags,
844b638a7beSBram Moolenaar     win_T	*new_wp,
845b638a7beSBram Moolenaar     int		dir)
846071d4279SBram Moolenaar {
84770b2a56dSBram Moolenaar     win_T	*wp = new_wp;
848071d4279SBram Moolenaar     win_T	*oldwin;
849071d4279SBram Moolenaar     int		new_size = size;
850071d4279SBram Moolenaar     int		i;
851071d4279SBram Moolenaar     int		need_status = 0;
852071d4279SBram Moolenaar     int		do_equal = FALSE;
853071d4279SBram Moolenaar     int		needed;
854071d4279SBram Moolenaar     int		available;
855071d4279SBram Moolenaar     int		oldwin_height = 0;
856071d4279SBram Moolenaar     int		layout;
85754368f27SBram Moolenaar     frame_T	*frp, *curfrp, *frp2, *prevfrp;
858071d4279SBram Moolenaar     int		before;
859b4d21355SBram Moolenaar     int		minheight;
8601f538355SBram Moolenaar     int		wmh1;
86198da6ecaSBram Moolenaar     int		did_set_fraction = FALSE;
862071d4279SBram Moolenaar 
863071d4279SBram Moolenaar     if (flags & WSP_TOP)
864071d4279SBram Moolenaar 	oldwin = firstwin;
865071d4279SBram Moolenaar     else if (flags & WSP_BOT)
866071d4279SBram Moolenaar 	oldwin = lastwin;
867071d4279SBram Moolenaar     else
868071d4279SBram Moolenaar 	oldwin = curwin;
869071d4279SBram Moolenaar 
870e38eab22SBram Moolenaar     // add a status line when p_ls == 1 and splitting the first window
871459ca563SBram Moolenaar     if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0)
872071d4279SBram Moolenaar     {
873415a6939SBram Moolenaar 	if (VISIBLE_HEIGHT(oldwin) <= p_wmh && new_wp == NULL)
874071d4279SBram Moolenaar 	{
875e29a27f6SBram Moolenaar 	    emsg(_(e_not_enough_room));
876071d4279SBram Moolenaar 	    return FAIL;
877071d4279SBram Moolenaar 	}
878071d4279SBram Moolenaar 	need_status = STATUS_HEIGHT;
879071d4279SBram Moolenaar     }
880071d4279SBram Moolenaar 
881ee79cbc7SBram Moolenaar #ifdef FEAT_GUI
882e38eab22SBram Moolenaar     // May be needed for the scrollbars that are going to change.
883ee79cbc7SBram Moolenaar     if (gui.in_use)
884ee79cbc7SBram Moolenaar 	out_flush();
885ee79cbc7SBram Moolenaar #endif
886ee79cbc7SBram Moolenaar 
887071d4279SBram Moolenaar     if (flags & WSP_VERT)
888071d4279SBram Moolenaar     {
889a0485493SBram Moolenaar 	int	wmw1;
890a0485493SBram Moolenaar 	int	minwidth;
891a0485493SBram Moolenaar 
892071d4279SBram Moolenaar 	layout = FR_ROW;
893071d4279SBram Moolenaar 
894071d4279SBram Moolenaar 	/*
895071d4279SBram Moolenaar 	 * Check if we are able to split the current window and compute its
896071d4279SBram Moolenaar 	 * width.
897071d4279SBram Moolenaar 	 */
898e38eab22SBram Moolenaar 	// Current window requires at least 1 space.
8991f538355SBram Moolenaar 	wmw1 = (p_wmw == 0 ? 1 : p_wmw);
9001f538355SBram Moolenaar 	needed = wmw1 + 1;
901071d4279SBram Moolenaar 	if (flags & WSP_ROOM)
9021f538355SBram Moolenaar 	    needed += p_wiw - wmw1;
90354368f27SBram Moolenaar 	if (flags & (WSP_BOT | WSP_TOP))
904071d4279SBram Moolenaar 	{
9051f538355SBram Moolenaar 	    minwidth = frame_minwidth(topframe, NOWIN);
906071d4279SBram Moolenaar 	    available = topframe->fr_width;
907b4d21355SBram Moolenaar 	    needed += minwidth;
908071d4279SBram Moolenaar 	}
90954368f27SBram Moolenaar 	else if (p_ea)
91054368f27SBram Moolenaar 	{
91154368f27SBram Moolenaar 	    minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
91254368f27SBram Moolenaar 	    prevfrp = oldwin->w_frame;
91354368f27SBram Moolenaar 	    for (frp = oldwin->w_frame->fr_parent; frp != NULL;
91454368f27SBram Moolenaar 							frp = frp->fr_parent)
91554368f27SBram Moolenaar 	    {
91654368f27SBram Moolenaar 		if (frp->fr_layout == FR_ROW)
9173d1491edSBram Moolenaar 		    FOR_ALL_FRAMES(frp2, frp->fr_child)
91854368f27SBram Moolenaar 			if (frp2 != prevfrp)
91954368f27SBram Moolenaar 			    minwidth += frame_minwidth(frp2, NOWIN);
92054368f27SBram Moolenaar 		prevfrp = frp;
92154368f27SBram Moolenaar 	    }
92254368f27SBram Moolenaar 	    available = topframe->fr_width;
92354368f27SBram Moolenaar 	    needed += minwidth;
92454368f27SBram Moolenaar 	}
925071d4279SBram Moolenaar 	else
926b4d21355SBram Moolenaar 	{
9271f538355SBram Moolenaar 	    minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
9281f538355SBram Moolenaar 	    available = oldwin->w_frame->fr_width;
9291f538355SBram Moolenaar 	    needed += minwidth;
930b4d21355SBram Moolenaar 	}
93170b2a56dSBram Moolenaar 	if (available < needed && new_wp == NULL)
932071d4279SBram Moolenaar 	{
933e29a27f6SBram Moolenaar 	    emsg(_(e_not_enough_room));
934071d4279SBram Moolenaar 	    return FAIL;
935071d4279SBram Moolenaar 	}
936071d4279SBram Moolenaar 	if (new_size == 0)
937071d4279SBram Moolenaar 	    new_size = oldwin->w_width / 2;
938b4d21355SBram Moolenaar 	if (new_size > available - minwidth - 1)
939b4d21355SBram Moolenaar 	    new_size = available - minwidth - 1;
9401f538355SBram Moolenaar 	if (new_size < wmw1)
9411f538355SBram Moolenaar 	    new_size = wmw1;
942071d4279SBram Moolenaar 
943e38eab22SBram Moolenaar 	// if it doesn't fit in the current window, need win_equal()
944071d4279SBram Moolenaar 	if (oldwin->w_width - new_size - 1 < p_wmw)
945071d4279SBram Moolenaar 	    do_equal = TRUE;
946be4d506bSBram Moolenaar 
947e38eab22SBram Moolenaar 	// We don't like to take lines for the new window from a
948e38eab22SBram Moolenaar 	// 'winfixwidth' window.  Take them from a window to the left or right
949e38eab22SBram Moolenaar 	// instead, if possible. Add one for the separator.
950be4d506bSBram Moolenaar 	if (oldwin->w_p_wfw)
95138e34836SBram Moolenaar 	    win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
95267f7131eSBram Moolenaar 
953e38eab22SBram Moolenaar 	// Only make all windows the same width if one of them (except oldwin)
954e38eab22SBram Moolenaar 	// is wider than one of the split windows.
95567f7131eSBram Moolenaar 	if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
95667f7131eSBram Moolenaar 					 && oldwin->w_frame->fr_parent != NULL)
95767f7131eSBram Moolenaar 	{
95867f7131eSBram Moolenaar 	    frp = oldwin->w_frame->fr_parent->fr_child;
95967f7131eSBram Moolenaar 	    while (frp != NULL)
96067f7131eSBram Moolenaar 	    {
96167f7131eSBram Moolenaar 		if (frp->fr_win != oldwin && frp->fr_win != NULL
96267f7131eSBram Moolenaar 			&& (frp->fr_win->w_width > new_size
96367f7131eSBram Moolenaar 			    || frp->fr_win->w_width > oldwin->w_width
964df46f6f0SBram Moolenaar 							      - new_size - 1))
96567f7131eSBram Moolenaar 		{
96667f7131eSBram Moolenaar 		    do_equal = TRUE;
96767f7131eSBram Moolenaar 		    break;
96867f7131eSBram Moolenaar 		}
96967f7131eSBram Moolenaar 		frp = frp->fr_next;
97067f7131eSBram Moolenaar 	    }
97167f7131eSBram Moolenaar 	}
972071d4279SBram Moolenaar     }
973071d4279SBram Moolenaar     else
974071d4279SBram Moolenaar     {
975071d4279SBram Moolenaar 	layout = FR_COL;
976071d4279SBram Moolenaar 
977071d4279SBram Moolenaar 	/*
978071d4279SBram Moolenaar 	 * Check if we are able to split the current window and compute its
979071d4279SBram Moolenaar 	 * height.
980071d4279SBram Moolenaar 	 */
981e38eab22SBram Moolenaar 	// Current window requires at least 1 space.
982415a6939SBram Moolenaar 	wmh1 = (p_wmh == 0 ? 1 : p_wmh) + WINBAR_HEIGHT(curwin);
9831f538355SBram Moolenaar 	needed = wmh1 + STATUS_HEIGHT;
984071d4279SBram Moolenaar 	if (flags & WSP_ROOM)
9851f538355SBram Moolenaar 	    needed += p_wh - wmh1;
98654368f27SBram Moolenaar 	if (flags & (WSP_BOT | WSP_TOP))
987071d4279SBram Moolenaar 	{
9881f538355SBram Moolenaar 	    minheight = frame_minheight(topframe, NOWIN) + need_status;
989071d4279SBram Moolenaar 	    available = topframe->fr_height;
990b4d21355SBram Moolenaar 	    needed += minheight;
991071d4279SBram Moolenaar 	}
99254368f27SBram Moolenaar 	else if (p_ea)
99354368f27SBram Moolenaar 	{
99454368f27SBram Moolenaar 	    minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
99554368f27SBram Moolenaar 	    prevfrp = oldwin->w_frame;
99654368f27SBram Moolenaar 	    for (frp = oldwin->w_frame->fr_parent; frp != NULL;
99754368f27SBram Moolenaar 							frp = frp->fr_parent)
99854368f27SBram Moolenaar 	    {
99954368f27SBram Moolenaar 		if (frp->fr_layout == FR_COL)
10003d1491edSBram Moolenaar 		    FOR_ALL_FRAMES(frp2, frp->fr_child)
100154368f27SBram Moolenaar 			if (frp2 != prevfrp)
100254368f27SBram Moolenaar 			    minheight += frame_minheight(frp2, NOWIN);
100354368f27SBram Moolenaar 		prevfrp = frp;
100454368f27SBram Moolenaar 	    }
100554368f27SBram Moolenaar 	    available = topframe->fr_height;
100654368f27SBram Moolenaar 	    needed += minheight;
100754368f27SBram Moolenaar 	}
1008071d4279SBram Moolenaar 	else
1009071d4279SBram Moolenaar 	{
10101f538355SBram Moolenaar 	    minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
10111f538355SBram Moolenaar 	    available = oldwin->w_frame->fr_height;
10121f538355SBram Moolenaar 	    needed += minheight;
1013071d4279SBram Moolenaar 	}
101470b2a56dSBram Moolenaar 	if (available < needed && new_wp == NULL)
1015071d4279SBram Moolenaar 	{
1016e29a27f6SBram Moolenaar 	    emsg(_(e_not_enough_room));
1017071d4279SBram Moolenaar 	    return FAIL;
1018071d4279SBram Moolenaar 	}
1019071d4279SBram Moolenaar 	oldwin_height = oldwin->w_height;
1020071d4279SBram Moolenaar 	if (need_status)
1021071d4279SBram Moolenaar 	{
1022071d4279SBram Moolenaar 	    oldwin->w_status_height = STATUS_HEIGHT;
1023071d4279SBram Moolenaar 	    oldwin_height -= STATUS_HEIGHT;
1024071d4279SBram Moolenaar 	}
1025071d4279SBram Moolenaar 	if (new_size == 0)
1026071d4279SBram Moolenaar 	    new_size = oldwin_height / 2;
1027b4d21355SBram Moolenaar 	if (new_size > available - minheight - STATUS_HEIGHT)
1028b4d21355SBram Moolenaar 	    new_size = available - minheight - STATUS_HEIGHT;
10291f538355SBram Moolenaar 	if (new_size < wmh1)
10301f538355SBram Moolenaar 	    new_size = wmh1;
1031071d4279SBram Moolenaar 
1032e38eab22SBram Moolenaar 	// if it doesn't fit in the current window, need win_equal()
1033071d4279SBram Moolenaar 	if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
1034071d4279SBram Moolenaar 	    do_equal = TRUE;
1035071d4279SBram Moolenaar 
1036e38eab22SBram Moolenaar 	// We don't like to take lines for the new window from a
1037e38eab22SBram Moolenaar 	// 'winfixheight' window.  Take them from a window above or below
1038e38eab22SBram Moolenaar 	// instead, if possible.
1039071d4279SBram Moolenaar 	if (oldwin->w_p_wfh)
1040071d4279SBram Moolenaar 	{
1041e38eab22SBram Moolenaar 	    // Set w_fraction now so that the cursor keeps the same relative
1042e38eab22SBram Moolenaar 	    // vertical position using the old height.
104398da6ecaSBram Moolenaar 	    set_fraction(oldwin);
104498da6ecaSBram Moolenaar 	    did_set_fraction = TRUE;
104598da6ecaSBram Moolenaar 
1046071d4279SBram Moolenaar 	    win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
1047071d4279SBram Moolenaar 								      oldwin);
1048071d4279SBram Moolenaar 	    oldwin_height = oldwin->w_height;
1049071d4279SBram Moolenaar 	    if (need_status)
1050071d4279SBram Moolenaar 		oldwin_height -= STATUS_HEIGHT;
1051071d4279SBram Moolenaar 	}
105267f7131eSBram Moolenaar 
1053e38eab22SBram Moolenaar 	// Only make all windows the same height if one of them (except oldwin)
1054e38eab22SBram Moolenaar 	// is higher than one of the split windows.
105544a2f923SBram Moolenaar 	if (!do_equal && p_ea && size == 0 && *p_ead != 'h'
105667f7131eSBram Moolenaar 	   && oldwin->w_frame->fr_parent != NULL)
105767f7131eSBram Moolenaar 	{
105867f7131eSBram Moolenaar 	    frp = oldwin->w_frame->fr_parent->fr_child;
105967f7131eSBram Moolenaar 	    while (frp != NULL)
106067f7131eSBram Moolenaar 	    {
106167f7131eSBram Moolenaar 		if (frp->fr_win != oldwin && frp->fr_win != NULL
106267f7131eSBram Moolenaar 			&& (frp->fr_win->w_height > new_size
106367f7131eSBram Moolenaar 			    || frp->fr_win->w_height > oldwin_height - new_size
106467f7131eSBram Moolenaar 							      - STATUS_HEIGHT))
106567f7131eSBram Moolenaar 		{
106667f7131eSBram Moolenaar 		    do_equal = TRUE;
106767f7131eSBram Moolenaar 		    break;
106867f7131eSBram Moolenaar 		}
106967f7131eSBram Moolenaar 		frp = frp->fr_next;
107067f7131eSBram Moolenaar 	    }
107167f7131eSBram Moolenaar 	}
1072071d4279SBram Moolenaar     }
1073071d4279SBram Moolenaar 
1074071d4279SBram Moolenaar     /*
1075071d4279SBram Moolenaar      * allocate new window structure and link it in the window list
1076071d4279SBram Moolenaar      */
1077071d4279SBram Moolenaar     if ((flags & WSP_TOP) == 0
1078071d4279SBram Moolenaar 	    && ((flags & WSP_BOT)
1079071d4279SBram Moolenaar 		|| (flags & WSP_BELOW)
1080071d4279SBram Moolenaar 		|| (!(flags & WSP_ABOVE)
108144a2f923SBram Moolenaar 		    && ( (flags & WSP_VERT) ? p_spr : p_sb))))
1082071d4279SBram Moolenaar     {
1083e38eab22SBram Moolenaar 	// new window below/right of current one
108470b2a56dSBram Moolenaar 	if (new_wp == NULL)
1085746ebd3bSBram Moolenaar 	    wp = win_alloc(oldwin, FALSE);
1086071d4279SBram Moolenaar 	else
1087071d4279SBram Moolenaar 	    win_append(oldwin, wp);
1088071d4279SBram Moolenaar     }
1089071d4279SBram Moolenaar     else
1090071d4279SBram Moolenaar     {
109170b2a56dSBram Moolenaar 	if (new_wp == NULL)
1092746ebd3bSBram Moolenaar 	    wp = win_alloc(oldwin->w_prev, FALSE);
1093071d4279SBram Moolenaar 	else
1094071d4279SBram Moolenaar 	    win_append(oldwin->w_prev, wp);
1095071d4279SBram Moolenaar     }
1096071d4279SBram Moolenaar 
109770b2a56dSBram Moolenaar     if (new_wp == NULL)
1098071d4279SBram Moolenaar     {
1099071d4279SBram Moolenaar 	if (wp == NULL)
1100071d4279SBram Moolenaar 	    return FAIL;
1101071d4279SBram Moolenaar 
1102746ebd3bSBram Moolenaar 	new_frame(wp);
1103746ebd3bSBram Moolenaar 	if (wp->w_frame == NULL)
1104746ebd3bSBram Moolenaar 	{
1105746ebd3bSBram Moolenaar 	    win_free(wp, NULL);
1106746ebd3bSBram Moolenaar 	    return FAIL;
1107746ebd3bSBram Moolenaar 	}
1108746ebd3bSBram Moolenaar 
1109e38eab22SBram Moolenaar 	// make the contents of the new window the same as the current one
1110884ae644SBram Moolenaar 	win_init(wp, curwin, flags);
1111071d4279SBram Moolenaar     }
1112071d4279SBram Moolenaar 
1113071d4279SBram Moolenaar     /*
1114071d4279SBram Moolenaar      * Reorganise the tree of frames to insert the new window.
1115071d4279SBram Moolenaar      */
1116071d4279SBram Moolenaar     if (flags & (WSP_TOP | WSP_BOT))
1117071d4279SBram Moolenaar     {
1118071d4279SBram Moolenaar 	if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
1119071d4279SBram Moolenaar 	    || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
1120071d4279SBram Moolenaar 	{
1121071d4279SBram Moolenaar 	    curfrp = topframe->fr_child;
1122071d4279SBram Moolenaar 	    if (flags & WSP_BOT)
1123071d4279SBram Moolenaar 		while (curfrp->fr_next != NULL)
1124071d4279SBram Moolenaar 		    curfrp = curfrp->fr_next;
1125071d4279SBram Moolenaar 	}
1126071d4279SBram Moolenaar 	else
1127071d4279SBram Moolenaar 	    curfrp = topframe;
1128071d4279SBram Moolenaar 	before = (flags & WSP_TOP);
1129071d4279SBram Moolenaar     }
1130071d4279SBram Moolenaar     else
1131071d4279SBram Moolenaar     {
1132071d4279SBram Moolenaar 	curfrp = oldwin->w_frame;
1133071d4279SBram Moolenaar 	if (flags & WSP_BELOW)
1134071d4279SBram Moolenaar 	    before = FALSE;
1135071d4279SBram Moolenaar 	else if (flags & WSP_ABOVE)
1136071d4279SBram Moolenaar 	    before = TRUE;
113744a2f923SBram Moolenaar 	else if (flags & WSP_VERT)
1138071d4279SBram Moolenaar 	    before = !p_spr;
1139071d4279SBram Moolenaar 	else
1140071d4279SBram Moolenaar 	    before = !p_sb;
1141071d4279SBram Moolenaar     }
1142071d4279SBram Moolenaar     if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
1143071d4279SBram Moolenaar     {
1144e38eab22SBram Moolenaar 	// Need to create a new frame in the tree to make a branch.
1145c799fe20SBram Moolenaar 	frp = ALLOC_CLEAR_ONE(frame_T);
1146071d4279SBram Moolenaar 	*frp = *curfrp;
1147071d4279SBram Moolenaar 	curfrp->fr_layout = layout;
1148071d4279SBram Moolenaar 	frp->fr_parent = curfrp;
1149071d4279SBram Moolenaar 	frp->fr_next = NULL;
1150071d4279SBram Moolenaar 	frp->fr_prev = NULL;
1151071d4279SBram Moolenaar 	curfrp->fr_child = frp;
1152071d4279SBram Moolenaar 	curfrp->fr_win = NULL;
1153071d4279SBram Moolenaar 	curfrp = frp;
1154071d4279SBram Moolenaar 	if (frp->fr_win != NULL)
1155071d4279SBram Moolenaar 	    oldwin->w_frame = frp;
1156071d4279SBram Moolenaar 	else
11573d1491edSBram Moolenaar 	    FOR_ALL_FRAMES(frp, frp->fr_child)
1158071d4279SBram Moolenaar 		frp->fr_parent = curfrp;
1159071d4279SBram Moolenaar     }
1160071d4279SBram Moolenaar 
116170b2a56dSBram Moolenaar     if (new_wp == NULL)
1162746ebd3bSBram Moolenaar 	frp = wp->w_frame;
1163071d4279SBram Moolenaar     else
116470b2a56dSBram Moolenaar 	frp = new_wp->w_frame;
1165071d4279SBram Moolenaar     frp->fr_parent = curfrp->fr_parent;
1166071d4279SBram Moolenaar 
1167e38eab22SBram Moolenaar     // Insert the new frame at the right place in the frame list.
1168071d4279SBram Moolenaar     if (before)
1169071d4279SBram Moolenaar 	frame_insert(curfrp, frp);
1170071d4279SBram Moolenaar     else
1171071d4279SBram Moolenaar 	frame_append(curfrp, frp);
1172071d4279SBram Moolenaar 
1173e38eab22SBram Moolenaar     // Set w_fraction now so that the cursor keeps the same relative
1174e38eab22SBram Moolenaar     // vertical position.
117598da6ecaSBram Moolenaar     if (!did_set_fraction)
11760215e8e1SBram Moolenaar 	set_fraction(oldwin);
11770215e8e1SBram Moolenaar     wp->w_fraction = oldwin->w_fraction;
11780215e8e1SBram Moolenaar 
1179071d4279SBram Moolenaar     if (flags & WSP_VERT)
1180071d4279SBram Moolenaar     {
1181071d4279SBram Moolenaar 	wp->w_p_scr = curwin->w_p_scr;
11820215e8e1SBram Moolenaar 
1183071d4279SBram Moolenaar 	if (need_status)
1184071d4279SBram Moolenaar 	{
11859b73a78eSBram Moolenaar 	    win_new_height(oldwin, oldwin->w_height - 1);
1186071d4279SBram Moolenaar 	    oldwin->w_status_height = need_status;
1187071d4279SBram Moolenaar 	}
1188071d4279SBram Moolenaar 	if (flags & (WSP_TOP | WSP_BOT))
1189071d4279SBram Moolenaar 	{
1190e38eab22SBram Moolenaar 	    // set height and row of new window to full height
119132466aa2SBram Moolenaar 	    wp->w_winrow = tabline_height();
1192d326ad6eSBram Moolenaar 	    win_new_height(wp, curfrp->fr_height - (p_ls > 0)
11933167c3e7SBram Moolenaar 							  - WINBAR_HEIGHT(wp));
1194071d4279SBram Moolenaar 	    wp->w_status_height = (p_ls > 0);
1195071d4279SBram Moolenaar 	}
1196071d4279SBram Moolenaar 	else
1197071d4279SBram Moolenaar 	{
1198e38eab22SBram Moolenaar 	    // height and row of new window is same as current window
1199071d4279SBram Moolenaar 	    wp->w_winrow = oldwin->w_winrow;
1200415a6939SBram Moolenaar 	    win_new_height(wp, VISIBLE_HEIGHT(oldwin));
1201071d4279SBram Moolenaar 	    wp->w_status_height = oldwin->w_status_height;
1202071d4279SBram Moolenaar 	}
1203071d4279SBram Moolenaar 	frp->fr_height = curfrp->fr_height;
1204071d4279SBram Moolenaar 
1205e38eab22SBram Moolenaar 	// "new_size" of the current window goes to the new window, use
1206e38eab22SBram Moolenaar 	// one column for the vertical separator
12079b73a78eSBram Moolenaar 	win_new_width(wp, new_size);
1208071d4279SBram Moolenaar 	if (before)
1209071d4279SBram Moolenaar 	    wp->w_vsep_width = 1;
1210071d4279SBram Moolenaar 	else
1211071d4279SBram Moolenaar 	{
1212071d4279SBram Moolenaar 	    wp->w_vsep_width = oldwin->w_vsep_width;
1213071d4279SBram Moolenaar 	    oldwin->w_vsep_width = 1;
1214071d4279SBram Moolenaar 	}
1215071d4279SBram Moolenaar 	if (flags & (WSP_TOP | WSP_BOT))
1216071d4279SBram Moolenaar 	{
1217071d4279SBram Moolenaar 	    if (flags & WSP_BOT)
1218071d4279SBram Moolenaar 		frame_add_vsep(curfrp);
1219e38eab22SBram Moolenaar 	    // Set width of neighbor frame
1220071d4279SBram Moolenaar 	    frame_new_width(curfrp, curfrp->fr_width
1221be4d506bSBram Moolenaar 		     - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
1222be4d506bSBram Moolenaar 								       FALSE);
1223071d4279SBram Moolenaar 	}
1224071d4279SBram Moolenaar 	else
1225be4d506bSBram Moolenaar 	    win_new_width(oldwin, oldwin->w_width - (new_size + 1));
1226e38eab22SBram Moolenaar 	if (before)	// new window left of current one
1227071d4279SBram Moolenaar 	{
1228071d4279SBram Moolenaar 	    wp->w_wincol = oldwin->w_wincol;
1229071d4279SBram Moolenaar 	    oldwin->w_wincol += new_size + 1;
1230071d4279SBram Moolenaar 	}
1231e38eab22SBram Moolenaar 	else		// new window right of current one
1232071d4279SBram Moolenaar 	    wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
1233071d4279SBram Moolenaar 	frame_fix_width(oldwin);
1234071d4279SBram Moolenaar 	frame_fix_width(wp);
1235071d4279SBram Moolenaar     }
1236071d4279SBram Moolenaar     else
1237071d4279SBram Moolenaar     {
1238e38eab22SBram Moolenaar 	// width and column of new window is same as current window
1239071d4279SBram Moolenaar 	if (flags & (WSP_TOP | WSP_BOT))
1240071d4279SBram Moolenaar 	{
1241071d4279SBram Moolenaar 	    wp->w_wincol = 0;
12429b73a78eSBram Moolenaar 	    win_new_width(wp, Columns);
1243071d4279SBram Moolenaar 	    wp->w_vsep_width = 0;
1244071d4279SBram Moolenaar 	}
1245071d4279SBram Moolenaar 	else
1246071d4279SBram Moolenaar 	{
1247071d4279SBram Moolenaar 	    wp->w_wincol = oldwin->w_wincol;
12489b73a78eSBram Moolenaar 	    win_new_width(wp, oldwin->w_width);
1249071d4279SBram Moolenaar 	    wp->w_vsep_width = oldwin->w_vsep_width;
1250071d4279SBram Moolenaar 	}
1251071d4279SBram Moolenaar 	frp->fr_width = curfrp->fr_width;
1252071d4279SBram Moolenaar 
1253e38eab22SBram Moolenaar 	// "new_size" of the current window goes to the new window, use
1254e38eab22SBram Moolenaar 	// one row for the status line
1255071d4279SBram Moolenaar 	win_new_height(wp, new_size);
1256071d4279SBram Moolenaar 	if (flags & (WSP_TOP | WSP_BOT))
1257991dea3aSBram Moolenaar 	{
1258d326ad6eSBram Moolenaar 	    int new_fr_height = curfrp->fr_height - new_size
12593167c3e7SBram Moolenaar 							  + WINBAR_HEIGHT(wp) ;
1260991dea3aSBram Moolenaar 
1261991dea3aSBram Moolenaar 	    if (!((flags & WSP_BOT) && p_ls == 0))
1262991dea3aSBram Moolenaar 		new_fr_height -= STATUS_HEIGHT;
1263991dea3aSBram Moolenaar 	    frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
1264991dea3aSBram Moolenaar 	}
1265071d4279SBram Moolenaar 	else
1266071d4279SBram Moolenaar 	    win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1267e38eab22SBram Moolenaar 	if (before)	// new window above current one
1268071d4279SBram Moolenaar 	{
1269071d4279SBram Moolenaar 	    wp->w_winrow = oldwin->w_winrow;
1270071d4279SBram Moolenaar 	    wp->w_status_height = STATUS_HEIGHT;
1271071d4279SBram Moolenaar 	    oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
1272071d4279SBram Moolenaar 	}
1273e38eab22SBram Moolenaar 	else		// new window below current one
1274071d4279SBram Moolenaar 	{
1275415a6939SBram Moolenaar 	    wp->w_winrow = oldwin->w_winrow + VISIBLE_HEIGHT(oldwin)
1276415a6939SBram Moolenaar 							       + STATUS_HEIGHT;
1277071d4279SBram Moolenaar 	    wp->w_status_height = oldwin->w_status_height;
1278991dea3aSBram Moolenaar 	    if (!(flags & WSP_BOT))
1279991dea3aSBram Moolenaar 		oldwin->w_status_height = STATUS_HEIGHT;
1280071d4279SBram Moolenaar 	}
1281071d4279SBram Moolenaar 	if (flags & WSP_BOT)
1282071d4279SBram Moolenaar 	    frame_add_statusline(curfrp);
1283071d4279SBram Moolenaar 	frame_fix_height(wp);
1284071d4279SBram Moolenaar 	frame_fix_height(oldwin);
1285071d4279SBram Moolenaar     }
1286071d4279SBram Moolenaar 
1287071d4279SBram Moolenaar     if (flags & (WSP_TOP | WSP_BOT))
1288071d4279SBram Moolenaar 	(void)win_comp_pos();
1289071d4279SBram Moolenaar 
1290668008beSBram Moolenaar      // Both windows need redrawing.  Update all status lines, in case they
1291668008beSBram Moolenaar      // show something related to the window count or position.
1292071d4279SBram Moolenaar     redraw_win_later(wp, NOT_VALID);
1293071d4279SBram Moolenaar     redraw_win_later(oldwin, NOT_VALID);
1294668008beSBram Moolenaar     status_redraw_all();
1295071d4279SBram Moolenaar 
1296071d4279SBram Moolenaar     if (need_status)
1297071d4279SBram Moolenaar     {
1298071d4279SBram Moolenaar 	msg_row = Rows - 1;
1299071d4279SBram Moolenaar 	msg_col = sc_col;
1300e38eab22SBram Moolenaar 	msg_clr_eos_force();	// Old command/ruler may still be there
1301071d4279SBram Moolenaar 	comp_col();
1302071d4279SBram Moolenaar 	msg_row = Rows - 1;
1303e38eab22SBram Moolenaar 	msg_col = 0;	// put position back at start of line
1304071d4279SBram Moolenaar     }
1305071d4279SBram Moolenaar 
1306071d4279SBram Moolenaar     /*
13079b73a78eSBram Moolenaar      * equalize the window sizes.
1308071d4279SBram Moolenaar      */
1309071d4279SBram Moolenaar     if (do_equal || dir != 0)
1310071d4279SBram Moolenaar 	win_equal(wp, TRUE,
1311071d4279SBram Moolenaar 		(flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
131244a2f923SBram Moolenaar 		: dir == 'h' ? 'b' : 'v');
1313071d4279SBram Moolenaar 
1314e38eab22SBram Moolenaar     // Don't change the window height/width to 'winheight' / 'winwidth' if a
1315e38eab22SBram Moolenaar     // size was given.
1316071d4279SBram Moolenaar     if (flags & WSP_VERT)
1317071d4279SBram Moolenaar     {
1318071d4279SBram Moolenaar 	i = p_wiw;
1319071d4279SBram Moolenaar 	if (size != 0)
1320071d4279SBram Moolenaar 	    p_wiw = size;
1321071d4279SBram Moolenaar 
1322071d4279SBram Moolenaar # ifdef FEAT_GUI
1323e38eab22SBram Moolenaar 	// When 'guioptions' includes 'L' or 'R' may have to add scrollbars.
1324071d4279SBram Moolenaar 	if (gui.in_use)
1325071d4279SBram Moolenaar 	    gui_init_which_components(NULL);
1326071d4279SBram Moolenaar # endif
1327071d4279SBram Moolenaar     }
1328071d4279SBram Moolenaar     else
1329071d4279SBram Moolenaar     {
1330071d4279SBram Moolenaar 	i = p_wh;
1331071d4279SBram Moolenaar 	if (size != 0)
1332071d4279SBram Moolenaar 	    p_wh = size;
1333071d4279SBram Moolenaar     }
13349b73a78eSBram Moolenaar 
133523fb7a99SBram Moolenaar #ifdef FEAT_JUMPLIST
1336e38eab22SBram Moolenaar     // Keep same changelist position in new window.
133723fb7a99SBram Moolenaar     wp->w_changelistidx = oldwin->w_changelistidx;
133823fb7a99SBram Moolenaar #endif
133923fb7a99SBram Moolenaar 
13409b73a78eSBram Moolenaar     /*
13419b73a78eSBram Moolenaar      * make the new window the current window
13429b73a78eSBram Moolenaar      */
134357942237SBram Moolenaar     (void)win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS
134457942237SBram Moolenaar 		    | WEE_TRIGGER_ENTER_AUTOCMDS | WEE_TRIGGER_LEAVE_AUTOCMDS);
1345071d4279SBram Moolenaar     if (flags & WSP_VERT)
1346071d4279SBram Moolenaar 	p_wiw = i;
1347071d4279SBram Moolenaar     else
1348071d4279SBram Moolenaar 	p_wh = i;
1349071d4279SBram Moolenaar 
1350071d4279SBram Moolenaar     return OK;
1351071d4279SBram Moolenaar }
1352071d4279SBram Moolenaar 
1353746ebd3bSBram Moolenaar 
13542a0449d1SBram Moolenaar /*
13552a0449d1SBram Moolenaar  * Initialize window "newp" from window "oldp".
13562a0449d1SBram Moolenaar  * Used when splitting a window and when creating a new tab page.
13572a0449d1SBram Moolenaar  * The windows will both edit the same buffer.
1358884ae644SBram Moolenaar  * WSP_NEWLOC may be specified in flags to prevent the location list from
1359884ae644SBram Moolenaar  * being copied.
13602a0449d1SBram Moolenaar  */
13612a0449d1SBram Moolenaar     static void
win_init(win_T * newp,win_T * oldp,int flags UNUSED)1362b638a7beSBram Moolenaar win_init(win_T *newp, win_T *oldp, int flags UNUSED)
13632a0449d1SBram Moolenaar {
13642a0449d1SBram Moolenaar     int		i;
13652a0449d1SBram Moolenaar 
13662a0449d1SBram Moolenaar     newp->w_buffer = oldp->w_buffer;
1367860cae1cSBram Moolenaar #ifdef FEAT_SYN_HL
1368fd29f462SBram Moolenaar     newp->w_s = &(oldp->w_buffer->b_s);
1369860cae1cSBram Moolenaar #endif
13702a0449d1SBram Moolenaar     oldp->w_buffer->b_nwindows++;
13712a0449d1SBram Moolenaar     newp->w_cursor = oldp->w_cursor;
13722a0449d1SBram Moolenaar     newp->w_valid = 0;
13732a0449d1SBram Moolenaar     newp->w_curswant = oldp->w_curswant;
13742a0449d1SBram Moolenaar     newp->w_set_curswant = oldp->w_set_curswant;
13752a0449d1SBram Moolenaar     newp->w_topline = oldp->w_topline;
13762a0449d1SBram Moolenaar #ifdef FEAT_DIFF
13772a0449d1SBram Moolenaar     newp->w_topfill = oldp->w_topfill;
13782a0449d1SBram Moolenaar #endif
13792a0449d1SBram Moolenaar     newp->w_leftcol = oldp->w_leftcol;
13802a0449d1SBram Moolenaar     newp->w_pcmark = oldp->w_pcmark;
13812a0449d1SBram Moolenaar     newp->w_prev_pcmark = oldp->w_prev_pcmark;
13822a0449d1SBram Moolenaar     newp->w_alt_fnum = oldp->w_alt_fnum;
13834c3f536fSBram Moolenaar     newp->w_wrow = oldp->w_wrow;
13842a0449d1SBram Moolenaar     newp->w_fraction = oldp->w_fraction;
13852a0449d1SBram Moolenaar     newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
13862a0449d1SBram Moolenaar #ifdef FEAT_JUMPLIST
13872a0449d1SBram Moolenaar     copy_jumplist(oldp, newp);
13882a0449d1SBram Moolenaar #endif
13892a0449d1SBram Moolenaar #ifdef FEAT_QUICKFIX
1390884ae644SBram Moolenaar     if (flags & WSP_NEWLOC)
1391884ae644SBram Moolenaar     {
1392e38eab22SBram Moolenaar 	// Don't copy the location list.
1393884ae644SBram Moolenaar 	newp->w_llist = NULL;
1394884ae644SBram Moolenaar 	newp->w_llist_ref = NULL;
1395884ae644SBram Moolenaar     }
1396884ae644SBram Moolenaar     else
139709037503SBram Moolenaar 	copy_loclist_stack(oldp, newp);
13982a0449d1SBram Moolenaar #endif
1399bd2dc347SBram Moolenaar     newp->w_localdir = (oldp->w_localdir == NULL)
1400bd2dc347SBram Moolenaar 				    ? NULL : vim_strsave(oldp->w_localdir);
1401a9a47d15SBram Moolenaar     newp->w_prevdir = (oldp->w_prevdir == NULL)
1402a9a47d15SBram Moolenaar 				    ? NULL : vim_strsave(oldp->w_prevdir);
14032a0449d1SBram Moolenaar 
1404e38eab22SBram Moolenaar     // copy tagstack and folds
14052a0449d1SBram Moolenaar     for (i = 0; i < oldp->w_tagstacklen; i++)
14062a0449d1SBram Moolenaar     {
140745e18cbdSBram Moolenaar 	taggy_T	*tag = &newp->w_tagstack[i];
140845e18cbdSBram Moolenaar 	*tag = oldp->w_tagstack[i];
140945e18cbdSBram Moolenaar 	if (tag->tagname != NULL)
141045e18cbdSBram Moolenaar 	    tag->tagname = vim_strsave(tag->tagname);
141145e18cbdSBram Moolenaar 	if (tag->user_data != NULL)
141245e18cbdSBram Moolenaar 	    tag->user_data = vim_strsave(tag->user_data);
14132a0449d1SBram Moolenaar     }
14142a0449d1SBram Moolenaar     newp->w_tagstackidx = oldp->w_tagstackidx;
14152a0449d1SBram Moolenaar     newp->w_tagstacklen = oldp->w_tagstacklen;
14162a0449d1SBram Moolenaar #ifdef FEAT_FOLDING
14172a0449d1SBram Moolenaar     copyFoldingState(oldp, newp);
14182a0449d1SBram Moolenaar #endif
1419746ebd3bSBram Moolenaar 
1420746ebd3bSBram Moolenaar     win_init_some(newp, oldp);
14211a38442dSBram Moolenaar 
14221a38442dSBram Moolenaar #ifdef FEAT_SYN_HL
14231a38442dSBram Moolenaar     check_colorcolumn(newp);
14241a38442dSBram Moolenaar #endif
1425*87fd0924SBram Moolenaar #ifdef FEAT_TERMINAL
1426*87fd0924SBram Moolenaar     term_update_wincolor(newp);
1427*87fd0924SBram Moolenaar #endif
1428746ebd3bSBram Moolenaar }
1429746ebd3bSBram Moolenaar 
1430746ebd3bSBram Moolenaar /*
1431746ebd3bSBram Moolenaar  * Initialize window "newp" from window "old".
1432746ebd3bSBram Moolenaar  * Only the essential things are copied.
1433746ebd3bSBram Moolenaar  */
1434746ebd3bSBram Moolenaar     static void
win_init_some(win_T * newp,win_T * oldp)1435b638a7beSBram Moolenaar win_init_some(win_T *newp, win_T *oldp)
1436746ebd3bSBram Moolenaar {
1437e38eab22SBram Moolenaar     // Use the same argument list.
1438746ebd3bSBram Moolenaar     newp->w_alist = oldp->w_alist;
1439746ebd3bSBram Moolenaar     ++newp->w_alist->al_refcount;
1440746ebd3bSBram Moolenaar     newp->w_arg_idx = oldp->w_arg_idx;
1441746ebd3bSBram Moolenaar 
1442e38eab22SBram Moolenaar     // copy options from existing window
1443746ebd3bSBram Moolenaar     win_copy_options(oldp, newp);
14442a0449d1SBram Moolenaar }
14452a0449d1SBram Moolenaar 
1446b0ebbda0SBram Moolenaar /*
1447b0ebbda0SBram Moolenaar  * Return TRUE if "win" is a global popup or a popup in the current tab page.
1448b0ebbda0SBram Moolenaar  */
1449b53fb31aSBram Moolenaar     int
win_valid_popup(win_T * win UNUSED)1450682725c1SBram Moolenaar win_valid_popup(win_T *win UNUSED)
14514d784b21SBram Moolenaar {
145205ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
14534d784b21SBram Moolenaar     win_T	*wp;
14544d784b21SBram Moolenaar 
1455aeea7215SBram Moolenaar     FOR_ALL_POPUPWINS(wp)
14564d784b21SBram Moolenaar 	if (wp == win)
14574d784b21SBram Moolenaar 	    return TRUE;
1458aeea7215SBram Moolenaar     FOR_ALL_POPUPWINS_IN_TAB(curtab, wp)
14594d784b21SBram Moolenaar 	if (wp == win)
14604d784b21SBram Moolenaar 	    return TRUE;
14614d784b21SBram Moolenaar #endif
14624d784b21SBram Moolenaar     return FALSE;
14634d784b21SBram Moolenaar }
1464071d4279SBram Moolenaar 
1465071d4279SBram Moolenaar /*
1466e59215c7SBram Moolenaar  * Check if "win" is a pointer to an existing window in the current tab page.
1467071d4279SBram Moolenaar  */
1468071d4279SBram Moolenaar     int
win_valid(win_T * win)1469b638a7beSBram Moolenaar win_valid(win_T *win)
1470071d4279SBram Moolenaar {
1471071d4279SBram Moolenaar     win_T	*wp;
1472071d4279SBram Moolenaar 
1473071d4279SBram Moolenaar     if (win == NULL)
1474071d4279SBram Moolenaar 	return FALSE;
147529323590SBram Moolenaar     FOR_ALL_WINDOWS(wp)
1476071d4279SBram Moolenaar 	if (wp == win)
1477071d4279SBram Moolenaar 	    return TRUE;
14784d784b21SBram Moolenaar     return win_valid_popup(win);
1479071d4279SBram Moolenaar }
1480071d4279SBram Moolenaar 
1481071d4279SBram Moolenaar /*
1482cbcd9cbdSBram Moolenaar  * Find window "id" in the current tab page.
14838adc8d9bSBram Moolenaar  * Also find popup windows.
1484cbcd9cbdSBram Moolenaar  * Return NULL if not found.
1485cbcd9cbdSBram Moolenaar  */
1486cbcd9cbdSBram Moolenaar     win_T *
win_find_by_id(int id)1487cbcd9cbdSBram Moolenaar win_find_by_id(int id)
1488cbcd9cbdSBram Moolenaar {
1489cbcd9cbdSBram Moolenaar     win_T   *wp;
1490cbcd9cbdSBram Moolenaar 
1491cbcd9cbdSBram Moolenaar     FOR_ALL_WINDOWS(wp)
1492cbcd9cbdSBram Moolenaar 	if (wp->w_id == id)
1493cbcd9cbdSBram Moolenaar 	    return wp;
14948adc8d9bSBram Moolenaar #ifdef FEAT_PROP_POPUP
14958adc8d9bSBram Moolenaar     FOR_ALL_POPUPWINS(wp)
14968adc8d9bSBram Moolenaar 	if (wp->w_id == id)
14978adc8d9bSBram Moolenaar 	    return wp;
14988adc8d9bSBram Moolenaar     FOR_ALL_POPUPWINS_IN_TAB(curtab, wp)
14998adc8d9bSBram Moolenaar 	if (wp->w_id == id)
15008adc8d9bSBram Moolenaar 	    return wp;
15018adc8d9bSBram Moolenaar #endif
1502cbcd9cbdSBram Moolenaar     return NULL;
1503cbcd9cbdSBram Moolenaar }
1504cbcd9cbdSBram Moolenaar 
1505cbcd9cbdSBram Moolenaar /*
1506e59215c7SBram Moolenaar  * Check if "win" is a pointer to an existing window in any tab page.
1507e59215c7SBram Moolenaar  */
1508e59215c7SBram Moolenaar     int
win_valid_any_tab(win_T * win)1509e59215c7SBram Moolenaar win_valid_any_tab(win_T *win)
1510e59215c7SBram Moolenaar {
1511e59215c7SBram Moolenaar     win_T	*wp;
1512e59215c7SBram Moolenaar     tabpage_T	*tp;
1513e59215c7SBram Moolenaar 
1514e59215c7SBram Moolenaar     if (win == NULL)
1515e59215c7SBram Moolenaar 	return FALSE;
1516e59215c7SBram Moolenaar     FOR_ALL_TABPAGES(tp)
1517e59215c7SBram Moolenaar     {
1518e59215c7SBram Moolenaar 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
1519e59215c7SBram Moolenaar 	{
1520e59215c7SBram Moolenaar 	    if (wp == win)
1521e59215c7SBram Moolenaar 		return TRUE;
1522e59215c7SBram Moolenaar 	}
152305ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
1524aeea7215SBram Moolenaar 	FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
1525b0ebbda0SBram Moolenaar 	    if (wp == win)
1526b0ebbda0SBram Moolenaar 		return TRUE;
1527b0ebbda0SBram Moolenaar #endif
1528e59215c7SBram Moolenaar     }
15294d784b21SBram Moolenaar     return win_valid_popup(win);
1530e59215c7SBram Moolenaar }
1531e59215c7SBram Moolenaar 
1532e59215c7SBram Moolenaar /*
1533071d4279SBram Moolenaar  * Return the number of windows.
1534071d4279SBram Moolenaar  */
1535071d4279SBram Moolenaar     int
win_count(void)1536b638a7beSBram Moolenaar win_count(void)
1537071d4279SBram Moolenaar {
1538071d4279SBram Moolenaar     win_T	*wp;
1539071d4279SBram Moolenaar     int		count = 0;
1540071d4279SBram Moolenaar 
154129323590SBram Moolenaar     FOR_ALL_WINDOWS(wp)
1542071d4279SBram Moolenaar 	++count;
1543071d4279SBram Moolenaar     return count;
1544071d4279SBram Moolenaar }
1545071d4279SBram Moolenaar 
1546071d4279SBram Moolenaar /*
1547071d4279SBram Moolenaar  * Make "count" windows on the screen.
1548071d4279SBram Moolenaar  * Return actual number of windows on the screen.
1549071d4279SBram Moolenaar  * Must be called when there is just one window, filling the whole screen
1550071d4279SBram Moolenaar  * (excluding the command line).
1551071d4279SBram Moolenaar  */
1552071d4279SBram Moolenaar     int
make_windows(int count,int vertical UNUSED)1553b638a7beSBram Moolenaar make_windows(
1554b638a7beSBram Moolenaar     int		count,
1555e38eab22SBram Moolenaar     int		vertical UNUSED)  // split windows vertically if TRUE
1556071d4279SBram Moolenaar {
1557071d4279SBram Moolenaar     int		maxcount;
1558071d4279SBram Moolenaar     int		todo;
1559071d4279SBram Moolenaar 
1560071d4279SBram Moolenaar     if (vertical)
1561071d4279SBram Moolenaar     {
1562e38eab22SBram Moolenaar 	// Each windows needs at least 'winminwidth' lines and a separator
1563e38eab22SBram Moolenaar 	// column.
1564071d4279SBram Moolenaar 	maxcount = (curwin->w_width + curwin->w_vsep_width
1565071d4279SBram Moolenaar 					     - (p_wiw - p_wmw)) / (p_wmw + 1);
1566071d4279SBram Moolenaar     }
1567071d4279SBram Moolenaar     else
1568071d4279SBram Moolenaar     {
1569e38eab22SBram Moolenaar 	// Each window needs at least 'winminheight' lines and a status line.
1570415a6939SBram Moolenaar 	maxcount = (VISIBLE_HEIGHT(curwin) + curwin->w_status_height
1571071d4279SBram Moolenaar 				  - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
1572071d4279SBram Moolenaar     }
1573071d4279SBram Moolenaar 
1574071d4279SBram Moolenaar     if (maxcount < 2)
1575071d4279SBram Moolenaar 	maxcount = 2;
1576071d4279SBram Moolenaar     if (count > maxcount)
1577071d4279SBram Moolenaar 	count = maxcount;
1578071d4279SBram Moolenaar 
1579071d4279SBram Moolenaar     /*
1580071d4279SBram Moolenaar      * add status line now, otherwise first window will be too big
1581071d4279SBram Moolenaar      */
1582071d4279SBram Moolenaar     if (count > 1)
1583071d4279SBram Moolenaar 	last_status(TRUE);
1584071d4279SBram Moolenaar 
1585071d4279SBram Moolenaar     /*
1586071d4279SBram Moolenaar      * Don't execute autocommands while creating the windows.  Must do that
1587071d4279SBram Moolenaar      * when putting the buffers in the windows.
1588071d4279SBram Moolenaar      */
158978ab331eSBram Moolenaar     block_autocmds();
1590071d4279SBram Moolenaar 
1591e38eab22SBram Moolenaar     // todo is number of windows left to create
1592071d4279SBram Moolenaar     for (todo = count - 1; todo > 0; --todo)
1593071d4279SBram Moolenaar 	if (vertical)
1594071d4279SBram Moolenaar 	{
1595071d4279SBram Moolenaar 	    if (win_split(curwin->w_width - (curwin->w_width - todo)
1596071d4279SBram Moolenaar 			/ (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
1597071d4279SBram Moolenaar 		break;
1598071d4279SBram Moolenaar 	}
1599071d4279SBram Moolenaar 	else
1600071d4279SBram Moolenaar 	{
1601071d4279SBram Moolenaar 	    if (win_split(curwin->w_height - (curwin->w_height - todo
1602071d4279SBram Moolenaar 			    * STATUS_HEIGHT) / (todo + 1)
1603071d4279SBram Moolenaar 			- STATUS_HEIGHT, WSP_ABOVE) == FAIL)
1604071d4279SBram Moolenaar 		break;
1605071d4279SBram Moolenaar 	}
1606071d4279SBram Moolenaar 
160778ab331eSBram Moolenaar     unblock_autocmds();
1608071d4279SBram Moolenaar 
1609e38eab22SBram Moolenaar     // return actual number of windows
1610071d4279SBram Moolenaar     return (count - todo);
1611071d4279SBram Moolenaar }
1612071d4279SBram Moolenaar 
1613071d4279SBram Moolenaar /*
1614071d4279SBram Moolenaar  * Exchange current and next window
1615071d4279SBram Moolenaar  */
1616071d4279SBram Moolenaar     static void
win_exchange(long Prenum)1617b638a7beSBram Moolenaar win_exchange(long Prenum)
1618071d4279SBram Moolenaar {
1619071d4279SBram Moolenaar     frame_T	*frp;
1620071d4279SBram Moolenaar     frame_T	*frp2;
1621071d4279SBram Moolenaar     win_T	*wp;
1622071d4279SBram Moolenaar     win_T	*wp2;
1623071d4279SBram Moolenaar     int		temp;
1624071d4279SBram Moolenaar 
16253c01c4a0SBram Moolenaar     if (ERROR_IF_ANY_POPUP_WINDOW)
1626815b76bfSBram Moolenaar 	return;
1627815b76bfSBram Moolenaar     if (ONE_WINDOW)	    // just one window
1628071d4279SBram Moolenaar     {
1629071d4279SBram Moolenaar 	beep_flush();
1630071d4279SBram Moolenaar 	return;
1631071d4279SBram Moolenaar     }
1632071d4279SBram Moolenaar 
1633071d4279SBram Moolenaar #ifdef FEAT_GUI
1634071d4279SBram Moolenaar     need_mouse_correct = TRUE;
1635071d4279SBram Moolenaar #endif
1636071d4279SBram Moolenaar 
1637071d4279SBram Moolenaar     /*
1638071d4279SBram Moolenaar      * find window to exchange with
1639071d4279SBram Moolenaar      */
1640071d4279SBram Moolenaar     if (Prenum)
1641071d4279SBram Moolenaar     {
1642071d4279SBram Moolenaar 	frp = curwin->w_frame->fr_parent->fr_child;
1643071d4279SBram Moolenaar 	while (frp != NULL && --Prenum > 0)
1644071d4279SBram Moolenaar 	    frp = frp->fr_next;
1645071d4279SBram Moolenaar     }
1646e38eab22SBram Moolenaar     else if (curwin->w_frame->fr_next != NULL)	// Swap with next
1647071d4279SBram Moolenaar 	frp = curwin->w_frame->fr_next;
1648e38eab22SBram Moolenaar     else    // Swap last window in row/col with previous
1649071d4279SBram Moolenaar 	frp = curwin->w_frame->fr_prev;
1650071d4279SBram Moolenaar 
1651e38eab22SBram Moolenaar     // We can only exchange a window with another window, not with a frame
1652e38eab22SBram Moolenaar     // containing windows.
1653071d4279SBram Moolenaar     if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
1654071d4279SBram Moolenaar 	return;
1655071d4279SBram Moolenaar     wp = frp->fr_win;
1656071d4279SBram Moolenaar 
1657071d4279SBram Moolenaar /*
1658071d4279SBram Moolenaar  * 1. remove curwin from the list. Remember after which window it was in wp2
1659071d4279SBram Moolenaar  * 2. insert curwin before wp in the list
1660071d4279SBram Moolenaar  * if wp != wp2
1661071d4279SBram Moolenaar  *    3. remove wp from the list
1662071d4279SBram Moolenaar  *    4. insert wp after wp2
1663071d4279SBram Moolenaar  * 5. exchange the status line height and vsep width.
1664071d4279SBram Moolenaar  */
1665071d4279SBram Moolenaar     wp2 = curwin->w_prev;
1666071d4279SBram Moolenaar     frp2 = curwin->w_frame->fr_prev;
1667071d4279SBram Moolenaar     if (wp->w_prev != curwin)
1668071d4279SBram Moolenaar     {
1669f740b29aSBram Moolenaar 	win_remove(curwin, NULL);
1670071d4279SBram Moolenaar 	frame_remove(curwin->w_frame);
1671071d4279SBram Moolenaar 	win_append(wp->w_prev, curwin);
1672071d4279SBram Moolenaar 	frame_insert(frp, curwin->w_frame);
1673071d4279SBram Moolenaar     }
1674071d4279SBram Moolenaar     if (wp != wp2)
1675071d4279SBram Moolenaar     {
1676f740b29aSBram Moolenaar 	win_remove(wp, NULL);
1677071d4279SBram Moolenaar 	frame_remove(wp->w_frame);
1678071d4279SBram Moolenaar 	win_append(wp2, wp);
1679071d4279SBram Moolenaar 	if (frp2 == NULL)
1680071d4279SBram Moolenaar 	    frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
1681071d4279SBram Moolenaar 	else
1682071d4279SBram Moolenaar 	    frame_append(frp2, wp->w_frame);
1683071d4279SBram Moolenaar     }
1684071d4279SBram Moolenaar     temp = curwin->w_status_height;
1685071d4279SBram Moolenaar     curwin->w_status_height = wp->w_status_height;
1686071d4279SBram Moolenaar     wp->w_status_height = temp;
1687071d4279SBram Moolenaar     temp = curwin->w_vsep_width;
1688071d4279SBram Moolenaar     curwin->w_vsep_width = wp->w_vsep_width;
1689071d4279SBram Moolenaar     wp->w_vsep_width = temp;
1690071d4279SBram Moolenaar 
1691071d4279SBram Moolenaar     frame_fix_height(curwin);
1692071d4279SBram Moolenaar     frame_fix_height(wp);
1693071d4279SBram Moolenaar     frame_fix_width(curwin);
1694071d4279SBram Moolenaar     frame_fix_width(wp);
1695071d4279SBram Moolenaar 
1696e38eab22SBram Moolenaar     (void)win_comp_pos();		// recompute window positions
1697071d4279SBram Moolenaar 
1698071d4279SBram Moolenaar     win_enter(wp, TRUE);
1699bf3250a8SBram Moolenaar     redraw_all_later(NOT_VALID);
1700071d4279SBram Moolenaar }
1701071d4279SBram Moolenaar 
1702071d4279SBram Moolenaar /*
1703071d4279SBram Moolenaar  * rotate windows: if upwards TRUE the second window becomes the first one
1704071d4279SBram Moolenaar  *		   if upwards FALSE the first window becomes the second one
1705071d4279SBram Moolenaar  */
1706071d4279SBram Moolenaar     static void
win_rotate(int upwards,int count)1707b638a7beSBram Moolenaar win_rotate(int upwards, int count)
1708071d4279SBram Moolenaar {
1709071d4279SBram Moolenaar     win_T	*wp1;
1710071d4279SBram Moolenaar     win_T	*wp2;
1711071d4279SBram Moolenaar     frame_T	*frp;
1712071d4279SBram Moolenaar     int		n;
1713071d4279SBram Moolenaar 
1714e38eab22SBram Moolenaar     if (ONE_WINDOW)		// nothing to do
1715071d4279SBram Moolenaar     {
1716071d4279SBram Moolenaar 	beep_flush();
1717071d4279SBram Moolenaar 	return;
1718071d4279SBram Moolenaar     }
1719071d4279SBram Moolenaar 
1720071d4279SBram Moolenaar #ifdef FEAT_GUI
1721071d4279SBram Moolenaar     need_mouse_correct = TRUE;
1722071d4279SBram Moolenaar #endif
1723071d4279SBram Moolenaar 
1724e38eab22SBram Moolenaar     // Check if all frames in this row/col have one window.
17253d1491edSBram Moolenaar     FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child)
1726071d4279SBram Moolenaar 	if (frp->fr_win == NULL)
1727071d4279SBram Moolenaar 	{
1728f9e3e09fSBram Moolenaar 	    emsg(_("E443: Cannot rotate when another window is split"));
1729071d4279SBram Moolenaar 	    return;
1730071d4279SBram Moolenaar 	}
1731071d4279SBram Moolenaar 
1732071d4279SBram Moolenaar     while (count--)
1733071d4279SBram Moolenaar     {
1734e38eab22SBram Moolenaar 	if (upwards)		// first window becomes last window
1735071d4279SBram Moolenaar 	{
1736e38eab22SBram Moolenaar 	    // remove first window/frame from the list
1737071d4279SBram Moolenaar 	    frp = curwin->w_frame->fr_parent->fr_child;
1738071d4279SBram Moolenaar 	    wp1 = frp->fr_win;
1739f740b29aSBram Moolenaar 	    win_remove(wp1, NULL);
1740071d4279SBram Moolenaar 	    frame_remove(frp);
1741071d4279SBram Moolenaar 
1742e38eab22SBram Moolenaar 	    // find last frame and append removed window/frame after it
1743071d4279SBram Moolenaar 	    for ( ; frp->fr_next != NULL; frp = frp->fr_next)
1744071d4279SBram Moolenaar 		;
1745071d4279SBram Moolenaar 	    win_append(frp->fr_win, wp1);
1746071d4279SBram Moolenaar 	    frame_append(frp, wp1->w_frame);
1747071d4279SBram Moolenaar 
1748e38eab22SBram Moolenaar 	    wp2 = frp->fr_win;		// previously last window
1749071d4279SBram Moolenaar 	}
1750e38eab22SBram Moolenaar 	else			// last window becomes first window
1751071d4279SBram Moolenaar 	{
1752e38eab22SBram Moolenaar 	    // find last window/frame in the list and remove it
1753071d4279SBram Moolenaar 	    for (frp = curwin->w_frame; frp->fr_next != NULL;
1754071d4279SBram Moolenaar 							   frp = frp->fr_next)
1755071d4279SBram Moolenaar 		;
1756071d4279SBram Moolenaar 	    wp1 = frp->fr_win;
1757e38eab22SBram Moolenaar 	    wp2 = wp1->w_prev;		    // will become last window
1758f740b29aSBram Moolenaar 	    win_remove(wp1, NULL);
1759071d4279SBram Moolenaar 	    frame_remove(frp);
1760071d4279SBram Moolenaar 
1761e38eab22SBram Moolenaar 	    // append the removed window/frame before the first in the list
1762071d4279SBram Moolenaar 	    win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
1763071d4279SBram Moolenaar 	    frame_insert(frp->fr_parent->fr_child, frp);
1764071d4279SBram Moolenaar 	}
1765071d4279SBram Moolenaar 
1766e38eab22SBram Moolenaar 	// exchange status height and vsep width of old and new last window
1767071d4279SBram Moolenaar 	n = wp2->w_status_height;
1768071d4279SBram Moolenaar 	wp2->w_status_height = wp1->w_status_height;
1769071d4279SBram Moolenaar 	wp1->w_status_height = n;
1770071d4279SBram Moolenaar 	frame_fix_height(wp1);
1771071d4279SBram Moolenaar 	frame_fix_height(wp2);
1772071d4279SBram Moolenaar 	n = wp2->w_vsep_width;
1773071d4279SBram Moolenaar 	wp2->w_vsep_width = wp1->w_vsep_width;
1774071d4279SBram Moolenaar 	wp1->w_vsep_width = n;
1775071d4279SBram Moolenaar 	frame_fix_width(wp1);
1776071d4279SBram Moolenaar 	frame_fix_width(wp2);
1777071d4279SBram Moolenaar 
1778e38eab22SBram Moolenaar 	// recompute w_winrow and w_wincol for all windows
1779071d4279SBram Moolenaar 	(void)win_comp_pos();
1780071d4279SBram Moolenaar     }
1781071d4279SBram Moolenaar 
1782bf3250a8SBram Moolenaar     redraw_all_later(NOT_VALID);
1783071d4279SBram Moolenaar }
1784071d4279SBram Moolenaar 
1785071d4279SBram Moolenaar /*
1786071d4279SBram Moolenaar  * Move the current window to the very top/bottom/left/right of the screen.
1787071d4279SBram Moolenaar  */
1788071d4279SBram Moolenaar     static void
win_totop(int size,int flags)1789b638a7beSBram Moolenaar win_totop(int size, int flags)
1790071d4279SBram Moolenaar {
1791071d4279SBram Moolenaar     int		dir;
1792071d4279SBram Moolenaar     int		height = curwin->w_height;
1793071d4279SBram Moolenaar 
1794459ca563SBram Moolenaar     if (ONE_WINDOW)
1795071d4279SBram Moolenaar     {
1796071d4279SBram Moolenaar 	beep_flush();
1797071d4279SBram Moolenaar 	return;
1798071d4279SBram Moolenaar     }
17991417c766SBram Moolenaar     if (check_split_disallowed() == FAIL)
18001417c766SBram Moolenaar 	return;
1801071d4279SBram Moolenaar 
1802e38eab22SBram Moolenaar     // Remove the window and frame from the tree of frames.
1803f740b29aSBram Moolenaar     (void)winframe_remove(curwin, &dir, NULL);
1804f740b29aSBram Moolenaar     win_remove(curwin, NULL);
1805e38eab22SBram Moolenaar     last_status(FALSE);	    // may need to remove last status line
1806e38eab22SBram Moolenaar     (void)win_comp_pos();   // recompute window positions
1807071d4279SBram Moolenaar 
1808e38eab22SBram Moolenaar     // Split a window on the desired side and put the window there.
1809071d4279SBram Moolenaar     (void)win_split_ins(size, flags, curwin, dir);
1810071d4279SBram Moolenaar     if (!(flags & WSP_VERT))
1811071d4279SBram Moolenaar     {
1812071d4279SBram Moolenaar 	win_setheight(height);
1813071d4279SBram Moolenaar 	if (p_ea)
1814071d4279SBram Moolenaar 	    win_equal(curwin, TRUE, 'v');
1815071d4279SBram Moolenaar     }
1816071d4279SBram Moolenaar 
181744a2f923SBram Moolenaar #if defined(FEAT_GUI)
1818e38eab22SBram Moolenaar     // When 'guioptions' includes 'L' or 'R' may have to remove or add
1819e38eab22SBram Moolenaar     // scrollbars.  Have to update them anyway.
1820746ebd3bSBram Moolenaar     gui_may_update_scrollbars();
1821071d4279SBram Moolenaar #endif
1822071d4279SBram Moolenaar }
1823071d4279SBram Moolenaar 
1824071d4279SBram Moolenaar /*
1825071d4279SBram Moolenaar  * Move window "win1" to below/right of "win2" and make "win1" the current
1826071d4279SBram Moolenaar  * window.  Only works within the same frame!
1827071d4279SBram Moolenaar  */
1828071d4279SBram Moolenaar     void
win_move_after(win_T * win1,win_T * win2)1829b638a7beSBram Moolenaar win_move_after(win_T *win1, win_T *win2)
1830071d4279SBram Moolenaar {
1831071d4279SBram Moolenaar     int		height;
1832071d4279SBram Moolenaar 
1833e38eab22SBram Moolenaar     // check if the arguments are reasonable
1834071d4279SBram Moolenaar     if (win1 == win2)
1835071d4279SBram Moolenaar 	return;
1836071d4279SBram Moolenaar 
1837e38eab22SBram Moolenaar     // check if there is something to do
1838071d4279SBram Moolenaar     if (win2->w_next != win1)
1839071d4279SBram Moolenaar     {
18401417c766SBram Moolenaar 	if (win1->w_frame->fr_parent != win2->w_frame->fr_parent)
18411417c766SBram Moolenaar 	{
18421417c766SBram Moolenaar 	    iemsg("INTERNAL: trying to move a window into another frame");
18431417c766SBram Moolenaar 	    return;
18441417c766SBram Moolenaar 	}
18451417c766SBram Moolenaar 
18465d3c9f8cSBram Moolenaar 	// may need to move the status line/vertical separator of the last
18475d3c9f8cSBram Moolenaar 	// window
1848071d4279SBram Moolenaar 	if (win1 == lastwin)
1849071d4279SBram Moolenaar 	{
1850071d4279SBram Moolenaar 	    height = win1->w_prev->w_status_height;
1851071d4279SBram Moolenaar 	    win1->w_prev->w_status_height = win1->w_status_height;
1852071d4279SBram Moolenaar 	    win1->w_status_height = height;
18530396ab01SBram Moolenaar 	    if (win1->w_prev->w_vsep_width == 1)
18540396ab01SBram Moolenaar 	    {
1855e38eab22SBram Moolenaar 		// Remove the vertical separator from the last-but-one window,
1856e38eab22SBram Moolenaar 		// add it to the last window.  Adjust the frame widths.
1857071d4279SBram Moolenaar 		win1->w_prev->w_vsep_width = 0;
18580396ab01SBram Moolenaar 		win1->w_prev->w_frame->fr_width -= 1;
1859071d4279SBram Moolenaar 		win1->w_vsep_width = 1;
18600396ab01SBram Moolenaar 		win1->w_frame->fr_width += 1;
18610396ab01SBram Moolenaar 	    }
1862071d4279SBram Moolenaar 	}
1863071d4279SBram Moolenaar 	else if (win2 == lastwin)
1864071d4279SBram Moolenaar 	{
1865071d4279SBram Moolenaar 	    height = win1->w_status_height;
1866071d4279SBram Moolenaar 	    win1->w_status_height = win2->w_status_height;
1867071d4279SBram Moolenaar 	    win2->w_status_height = height;
18680396ab01SBram Moolenaar 	    if (win1->w_vsep_width == 1)
18690396ab01SBram Moolenaar 	    {
1870e38eab22SBram Moolenaar 		// Remove the vertical separator from win1, add it to the last
1871e38eab22SBram Moolenaar 		// window, win2.  Adjust the frame widths.
1872071d4279SBram Moolenaar 		win2->w_vsep_width = 1;
18730396ab01SBram Moolenaar 		win2->w_frame->fr_width += 1;
1874071d4279SBram Moolenaar 		win1->w_vsep_width = 0;
18750396ab01SBram Moolenaar 		win1->w_frame->fr_width -= 1;
18760396ab01SBram Moolenaar 	    }
1877071d4279SBram Moolenaar 	}
1878f740b29aSBram Moolenaar 	win_remove(win1, NULL);
1879071d4279SBram Moolenaar 	frame_remove(win1->w_frame);
1880071d4279SBram Moolenaar 	win_append(win2, win1);
1881071d4279SBram Moolenaar 	frame_append(win2->w_frame, win1->w_frame);
1882071d4279SBram Moolenaar 
1883e38eab22SBram Moolenaar 	(void)win_comp_pos();	// recompute w_winrow for all windows
1884071d4279SBram Moolenaar 	redraw_later(NOT_VALID);
1885071d4279SBram Moolenaar     }
1886071d4279SBram Moolenaar     win_enter(win1, FALSE);
1887071d4279SBram Moolenaar }
1888071d4279SBram Moolenaar 
1889071d4279SBram Moolenaar /*
1890071d4279SBram Moolenaar  * Make all windows the same height.
1891071d4279SBram Moolenaar  * 'next_curwin' will soon be the current window, make sure it has enough
1892071d4279SBram Moolenaar  * rows.
1893071d4279SBram Moolenaar  */
1894071d4279SBram Moolenaar     void
win_equal(win_T * next_curwin,int current,int dir)1895b638a7beSBram Moolenaar win_equal(
1896e38eab22SBram Moolenaar     win_T	*next_curwin,	// pointer to current window to be or NULL
1897e38eab22SBram Moolenaar     int		current,	// do only frame with current window
1898e38eab22SBram Moolenaar     int		dir)		// 'v' for vertically, 'h' for horizontally,
1899e38eab22SBram Moolenaar 				// 'b' for both, 0 for using p_ead
1900071d4279SBram Moolenaar {
1901071d4279SBram Moolenaar     if (dir == 0)
1902071d4279SBram Moolenaar 	dir = *p_ead;
1903071d4279SBram Moolenaar     win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
190432466aa2SBram Moolenaar 		      topframe, dir, 0, tabline_height(),
19051d2ba7faSBram Moolenaar 					   (int)Columns, topframe->fr_height);
1906071d4279SBram Moolenaar }
1907071d4279SBram Moolenaar 
1908071d4279SBram Moolenaar /*
1909071d4279SBram Moolenaar  * Set a frame to a new position and height, spreading the available room
1910071d4279SBram Moolenaar  * equally over contained frames.
1911071d4279SBram Moolenaar  * The window "next_curwin" (if not NULL) should at least get the size from
1912071d4279SBram Moolenaar  * 'winheight' and 'winwidth' if possible.
1913071d4279SBram Moolenaar  */
1914071d4279SBram Moolenaar     static void
win_equal_rec(win_T * next_curwin,int current,frame_T * topfr,int dir,int col,int row,int width,int height)1915b638a7beSBram Moolenaar win_equal_rec(
1916e38eab22SBram Moolenaar     win_T	*next_curwin,	// pointer to current window to be or NULL
1917e38eab22SBram Moolenaar     int		current,	// do only frame with current window
1918e38eab22SBram Moolenaar     frame_T	*topfr,		// frame to set size off
1919e38eab22SBram Moolenaar     int		dir,		// 'v', 'h' or 'b', see win_equal()
1920e38eab22SBram Moolenaar     int		col,		// horizontal position for frame
1921e38eab22SBram Moolenaar     int		row,		// vertical position for frame
1922e38eab22SBram Moolenaar     int		width,		// new width of frame
1923e38eab22SBram Moolenaar     int		height)		// new height of frame
1924071d4279SBram Moolenaar {
1925071d4279SBram Moolenaar     int		n, m;
1926071d4279SBram Moolenaar     int		extra_sep = 0;
1927071d4279SBram Moolenaar     int		wincount, totwincount = 0;
1928071d4279SBram Moolenaar     frame_T	*fr;
1929071d4279SBram Moolenaar     int		next_curwin_size = 0;
1930071d4279SBram Moolenaar     int		room = 0;
1931071d4279SBram Moolenaar     int		new_size;
1932071d4279SBram Moolenaar     int		has_next_curwin = 0;
1933071d4279SBram Moolenaar     int		hnc;
1934071d4279SBram Moolenaar 
1935071d4279SBram Moolenaar     if (topfr->fr_layout == FR_LEAF)
1936071d4279SBram Moolenaar     {
1937e38eab22SBram Moolenaar 	// Set the width/height of this frame.
1938e38eab22SBram Moolenaar 	// Redraw when size or position changes
1939071d4279SBram Moolenaar 	if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
1940071d4279SBram Moolenaar 		|| topfr->fr_width != width || topfr->fr_win->w_wincol != col
1941071d4279SBram Moolenaar 	   )
1942071d4279SBram Moolenaar 	{
1943071d4279SBram Moolenaar 	    topfr->fr_win->w_winrow = row;
1944071d4279SBram Moolenaar 	    frame_new_height(topfr, height, FALSE, FALSE);
1945071d4279SBram Moolenaar 	    topfr->fr_win->w_wincol = col;
1946be4d506bSBram Moolenaar 	    frame_new_width(topfr, width, FALSE, FALSE);
1947bf3250a8SBram Moolenaar 	    redraw_all_later(NOT_VALID);
1948071d4279SBram Moolenaar 	}
1949071d4279SBram Moolenaar     }
1950071d4279SBram Moolenaar     else if (topfr->fr_layout == FR_ROW)
1951071d4279SBram Moolenaar     {
1952071d4279SBram Moolenaar 	topfr->fr_width = width;
1953071d4279SBram Moolenaar 	topfr->fr_height = height;
1954071d4279SBram Moolenaar 
1955e38eab22SBram Moolenaar 	if (dir != 'v')			// equalize frame widths
1956071d4279SBram Moolenaar 	{
1957e38eab22SBram Moolenaar 	    // Compute the maximum number of windows horizontally in this
1958e38eab22SBram Moolenaar 	    // frame.
1959071d4279SBram Moolenaar 	    n = frame_minwidth(topfr, NOWIN);
1960e38eab22SBram Moolenaar 	    // add one for the rightmost window, it doesn't have a separator
1961071d4279SBram Moolenaar 	    if (col + width == Columns)
1962071d4279SBram Moolenaar 		extra_sep = 1;
1963071d4279SBram Moolenaar 	    else
1964071d4279SBram Moolenaar 		extra_sep = 0;
1965071d4279SBram Moolenaar 	    totwincount = (n + extra_sep) / (p_wmw + 1);
1966be4d506bSBram Moolenaar 	    has_next_curwin = frame_has_win(topfr, next_curwin);
1967071d4279SBram Moolenaar 
1968be4d506bSBram Moolenaar 	    /*
1969be4d506bSBram Moolenaar 	     * Compute width for "next_curwin" window and room available for
1970be4d506bSBram Moolenaar 	     * other windows.
1971be4d506bSBram Moolenaar 	     * "m" is the minimal width when counting p_wiw for "next_curwin".
1972be4d506bSBram Moolenaar 	     */
1973071d4279SBram Moolenaar 	    m = frame_minwidth(topfr, next_curwin);
1974071d4279SBram Moolenaar 	    room = width - m;
1975071d4279SBram Moolenaar 	    if (room < 0)
1976071d4279SBram Moolenaar 	    {
1977071d4279SBram Moolenaar 		next_curwin_size = p_wiw + room;
1978071d4279SBram Moolenaar 		room = 0;
1979071d4279SBram Moolenaar 	    }
1980071d4279SBram Moolenaar 	    else
1981071d4279SBram Moolenaar 	    {
1982be4d506bSBram Moolenaar 		next_curwin_size = -1;
19833d1491edSBram Moolenaar 		FOR_ALL_FRAMES(fr, topfr->fr_child)
1984be4d506bSBram Moolenaar 		{
1985e38eab22SBram Moolenaar 		    // If 'winfixwidth' set keep the window width if
1986e38eab22SBram Moolenaar 		    // possible.
1987e38eab22SBram Moolenaar 		    // Watch out for this window being the next_curwin.
1988be4d506bSBram Moolenaar 		    if (frame_fixed_width(fr))
1989be4d506bSBram Moolenaar 		    {
1990be4d506bSBram Moolenaar 			n = frame_minwidth(fr, NOWIN);
1991be4d506bSBram Moolenaar 			new_size = fr->fr_width;
1992be4d506bSBram Moolenaar 			if (frame_has_win(fr, next_curwin))
1993be4d506bSBram Moolenaar 			{
1994be4d506bSBram Moolenaar 			    room += p_wiw - p_wmw;
1995be4d506bSBram Moolenaar 			    next_curwin_size = 0;
1996be4d506bSBram Moolenaar 			    if (new_size < p_wiw)
1997be4d506bSBram Moolenaar 				new_size = p_wiw;
1998be4d506bSBram Moolenaar 			}
1999be4d506bSBram Moolenaar 			else
2000e38eab22SBram Moolenaar 			    // These windows don't use up room.
2001be4d506bSBram Moolenaar 			    totwincount -= (n + (fr->fr_next == NULL
2002be4d506bSBram Moolenaar 					      ? extra_sep : 0)) / (p_wmw + 1);
2003be4d506bSBram Moolenaar 			room -= new_size - n;
2004be4d506bSBram Moolenaar 			if (room < 0)
2005be4d506bSBram Moolenaar 			{
2006be4d506bSBram Moolenaar 			    new_size += room;
2007be4d506bSBram Moolenaar 			    room = 0;
2008be4d506bSBram Moolenaar 			}
2009be4d506bSBram Moolenaar 			fr->fr_newwidth = new_size;
2010be4d506bSBram Moolenaar 		    }
2011be4d506bSBram Moolenaar 		}
2012be4d506bSBram Moolenaar 		if (next_curwin_size == -1)
2013be4d506bSBram Moolenaar 		{
2014be4d506bSBram Moolenaar 		    if (!has_next_curwin)
2015be4d506bSBram Moolenaar 			next_curwin_size = 0;
2016be4d506bSBram Moolenaar 		    else if (totwincount > 1
2017be4d506bSBram Moolenaar 			    && (room + (totwincount - 2))
2018be4d506bSBram Moolenaar 						  / (totwincount - 1) > p_wiw)
2019be4d506bSBram Moolenaar 		    {
2020e38eab22SBram Moolenaar 			// Can make all windows wider than 'winwidth', spread
2021e38eab22SBram Moolenaar 			// the room equally.
2022b21e5843SBram Moolenaar 			next_curwin_size = (room + p_wiw
2023b21e5843SBram Moolenaar 					    + (totwincount - 1) * p_wmw
2024071d4279SBram Moolenaar 					    + (totwincount - 1)) / totwincount;
2025071d4279SBram Moolenaar 			room -= next_curwin_size - p_wiw;
2026be4d506bSBram Moolenaar 		    }
2027071d4279SBram Moolenaar 		    else
2028071d4279SBram Moolenaar 			next_curwin_size = p_wiw;
2029071d4279SBram Moolenaar 		}
2030be4d506bSBram Moolenaar 	    }
2031be4d506bSBram Moolenaar 
2032be4d506bSBram Moolenaar 	    if (has_next_curwin)
2033e38eab22SBram Moolenaar 		--totwincount;		// don't count curwin
2034071d4279SBram Moolenaar 	}
2035071d4279SBram Moolenaar 
20363d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fr, topfr->fr_child)
2037071d4279SBram Moolenaar 	{
2038071d4279SBram Moolenaar 	    wincount = 1;
2039071d4279SBram Moolenaar 	    if (fr->fr_next == NULL)
2040e38eab22SBram Moolenaar 		// last frame gets all that remains (avoid roundoff error)
2041071d4279SBram Moolenaar 		new_size = width;
2042071d4279SBram Moolenaar 	    else if (dir == 'v')
2043071d4279SBram Moolenaar 		new_size = fr->fr_width;
2044be4d506bSBram Moolenaar 	    else if (frame_fixed_width(fr))
2045be4d506bSBram Moolenaar 	    {
2046be4d506bSBram Moolenaar 		new_size = fr->fr_newwidth;
2047e38eab22SBram Moolenaar 		wincount = 0;	    // doesn't count as a sizeable window
2048be4d506bSBram Moolenaar 	    }
2049071d4279SBram Moolenaar 	    else
2050071d4279SBram Moolenaar 	    {
2051e38eab22SBram Moolenaar 		// Compute the maximum number of windows horiz. in "fr".
2052071d4279SBram Moolenaar 		n = frame_minwidth(fr, NOWIN);
2053071d4279SBram Moolenaar 		wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
2054071d4279SBram Moolenaar 								/ (p_wmw + 1);
2055071d4279SBram Moolenaar 		m = frame_minwidth(fr, next_curwin);
2056be4d506bSBram Moolenaar 		if (has_next_curwin)
2057be4d506bSBram Moolenaar 		    hnc = frame_has_win(fr, next_curwin);
2058be4d506bSBram Moolenaar 		else
2059be4d506bSBram Moolenaar 		    hnc = FALSE;
2060e38eab22SBram Moolenaar 		if (hnc)	    // don't count next_curwin
2061071d4279SBram Moolenaar 		    --wincount;
2062be4d506bSBram Moolenaar 		if (totwincount == 0)
2063be4d506bSBram Moolenaar 		    new_size = room;
2064be4d506bSBram Moolenaar 		else
2065071d4279SBram Moolenaar 		    new_size = (wincount * room + ((unsigned)totwincount >> 1))
2066071d4279SBram Moolenaar 								/ totwincount;
2067e38eab22SBram Moolenaar 		if (hnc)	    // add next_curwin size
2068071d4279SBram Moolenaar 		{
2069071d4279SBram Moolenaar 		    next_curwin_size -= p_wiw - (m - n);
2070071d4279SBram Moolenaar 		    new_size += next_curwin_size;
2071be4d506bSBram Moolenaar 		    room -= new_size - next_curwin_size;
2072071d4279SBram Moolenaar 		}
2073be4d506bSBram Moolenaar 		else
2074be4d506bSBram Moolenaar 		    room -= new_size;
2075be4d506bSBram Moolenaar 		new_size += n;
2076071d4279SBram Moolenaar 	    }
2077071d4279SBram Moolenaar 
2078e38eab22SBram Moolenaar 	    // Skip frame that is full width when splitting or closing a
2079e38eab22SBram Moolenaar 	    // window, unless equalizing all frames.
2080071d4279SBram Moolenaar 	    if (!current || dir != 'v' || topfr->fr_parent != NULL
2081071d4279SBram Moolenaar 		    || (new_size != fr->fr_width)
2082071d4279SBram Moolenaar 		    || frame_has_win(fr, next_curwin))
2083071d4279SBram Moolenaar 		win_equal_rec(next_curwin, current, fr, dir, col, row,
2084be4d506bSBram Moolenaar 							    new_size, height);
2085be4d506bSBram Moolenaar 	    col += new_size;
2086be4d506bSBram Moolenaar 	    width -= new_size;
2087071d4279SBram Moolenaar 	    totwincount -= wincount;
2088071d4279SBram Moolenaar 	}
2089071d4279SBram Moolenaar     }
2090e38eab22SBram Moolenaar     else // topfr->fr_layout == FR_COL
2091071d4279SBram Moolenaar     {
2092071d4279SBram Moolenaar 	topfr->fr_width = width;
2093071d4279SBram Moolenaar 	topfr->fr_height = height;
2094071d4279SBram Moolenaar 
2095e38eab22SBram Moolenaar 	if (dir != 'h')			// equalize frame heights
2096071d4279SBram Moolenaar 	{
2097e38eab22SBram Moolenaar 	    // Compute maximum number of windows vertically in this frame.
2098071d4279SBram Moolenaar 	    n = frame_minheight(topfr, NOWIN);
2099e38eab22SBram Moolenaar 	    // add one for the bottom window if it doesn't have a statusline
2100071d4279SBram Moolenaar 	    if (row + height == cmdline_row && p_ls == 0)
2101071d4279SBram Moolenaar 		extra_sep = 1;
2102071d4279SBram Moolenaar 	    else
2103071d4279SBram Moolenaar 		extra_sep = 0;
2104071d4279SBram Moolenaar 	    totwincount = (n + extra_sep) / (p_wmh + 1);
2105071d4279SBram Moolenaar 	    has_next_curwin = frame_has_win(topfr, next_curwin);
2106071d4279SBram Moolenaar 
2107071d4279SBram Moolenaar 	    /*
2108071d4279SBram Moolenaar 	     * Compute height for "next_curwin" window and room available for
2109071d4279SBram Moolenaar 	     * other windows.
2110071d4279SBram Moolenaar 	     * "m" is the minimal height when counting p_wh for "next_curwin".
2111071d4279SBram Moolenaar 	     */
2112071d4279SBram Moolenaar 	    m = frame_minheight(topfr, next_curwin);
2113071d4279SBram Moolenaar 	    room = height - m;
2114071d4279SBram Moolenaar 	    if (room < 0)
2115071d4279SBram Moolenaar 	    {
2116e38eab22SBram Moolenaar 		// The room is less then 'winheight', use all space for the
2117e38eab22SBram Moolenaar 		// current window.
2118071d4279SBram Moolenaar 		next_curwin_size = p_wh + room;
2119071d4279SBram Moolenaar 		room = 0;
2120071d4279SBram Moolenaar 	    }
2121071d4279SBram Moolenaar 	    else
2122071d4279SBram Moolenaar 	    {
2123071d4279SBram Moolenaar 		next_curwin_size = -1;
21243d1491edSBram Moolenaar 		FOR_ALL_FRAMES(fr, topfr->fr_child)
2125071d4279SBram Moolenaar 		{
2126e38eab22SBram Moolenaar 		    // If 'winfixheight' set keep the window height if
2127e38eab22SBram Moolenaar 		    // possible.
2128e38eab22SBram Moolenaar 		    // Watch out for this window being the next_curwin.
2129071d4279SBram Moolenaar 		    if (frame_fixed_height(fr))
2130071d4279SBram Moolenaar 		    {
2131071d4279SBram Moolenaar 			n = frame_minheight(fr, NOWIN);
2132071d4279SBram Moolenaar 			new_size = fr->fr_height;
2133071d4279SBram Moolenaar 			if (frame_has_win(fr, next_curwin))
2134071d4279SBram Moolenaar 			{
2135071d4279SBram Moolenaar 			    room += p_wh - p_wmh;
2136071d4279SBram Moolenaar 			    next_curwin_size = 0;
2137071d4279SBram Moolenaar 			    if (new_size < p_wh)
2138071d4279SBram Moolenaar 				new_size = p_wh;
2139071d4279SBram Moolenaar 			}
2140071d4279SBram Moolenaar 			else
2141e38eab22SBram Moolenaar 			    // These windows don't use up room.
2142071d4279SBram Moolenaar 			    totwincount -= (n + (fr->fr_next == NULL
2143071d4279SBram Moolenaar 					      ? extra_sep : 0)) / (p_wmh + 1);
2144071d4279SBram Moolenaar 			room -= new_size - n;
2145071d4279SBram Moolenaar 			if (room < 0)
2146071d4279SBram Moolenaar 			{
2147071d4279SBram Moolenaar 			    new_size += room;
2148071d4279SBram Moolenaar 			    room = 0;
2149071d4279SBram Moolenaar 			}
2150071d4279SBram Moolenaar 			fr->fr_newheight = new_size;
2151071d4279SBram Moolenaar 		    }
2152071d4279SBram Moolenaar 		}
2153071d4279SBram Moolenaar 		if (next_curwin_size == -1)
2154071d4279SBram Moolenaar 		{
2155071d4279SBram Moolenaar 		    if (!has_next_curwin)
2156071d4279SBram Moolenaar 			next_curwin_size = 0;
2157071d4279SBram Moolenaar 		    else if (totwincount > 1
2158071d4279SBram Moolenaar 			    && (room + (totwincount - 2))
2159071d4279SBram Moolenaar 						   / (totwincount - 1) > p_wh)
2160071d4279SBram Moolenaar 		    {
2161e38eab22SBram Moolenaar 			// can make all windows higher than 'winheight',
2162e38eab22SBram Moolenaar 			// spread the room equally.
2163b21e5843SBram Moolenaar 			next_curwin_size = (room + p_wh
2164b21e5843SBram Moolenaar 					   + (totwincount - 1) * p_wmh
2165071d4279SBram Moolenaar 					   + (totwincount - 1)) / totwincount;
2166071d4279SBram Moolenaar 			room -= next_curwin_size - p_wh;
2167071d4279SBram Moolenaar 		    }
2168071d4279SBram Moolenaar 		    else
2169071d4279SBram Moolenaar 			next_curwin_size = p_wh;
2170071d4279SBram Moolenaar 		}
2171071d4279SBram Moolenaar 	    }
2172071d4279SBram Moolenaar 
2173071d4279SBram Moolenaar 	    if (has_next_curwin)
2174e38eab22SBram Moolenaar 		--totwincount;		// don't count curwin
2175071d4279SBram Moolenaar 	}
2176071d4279SBram Moolenaar 
21773d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fr, topfr->fr_child)
2178071d4279SBram Moolenaar 	{
2179071d4279SBram Moolenaar 	    wincount = 1;
2180071d4279SBram Moolenaar 	    if (fr->fr_next == NULL)
2181e38eab22SBram Moolenaar 		// last frame gets all that remains (avoid roundoff error)
2182071d4279SBram Moolenaar 		new_size = height;
2183071d4279SBram Moolenaar 	    else if (dir == 'h')
2184071d4279SBram Moolenaar 		new_size = fr->fr_height;
2185071d4279SBram Moolenaar 	    else if (frame_fixed_height(fr))
2186071d4279SBram Moolenaar 	    {
2187071d4279SBram Moolenaar 		new_size = fr->fr_newheight;
2188e38eab22SBram Moolenaar 		wincount = 0;	    // doesn't count as a sizeable window
2189071d4279SBram Moolenaar 	    }
2190071d4279SBram Moolenaar 	    else
2191071d4279SBram Moolenaar 	    {
2192e38eab22SBram Moolenaar 		// Compute the maximum number of windows vert. in "fr".
2193071d4279SBram Moolenaar 		n = frame_minheight(fr, NOWIN);
2194071d4279SBram Moolenaar 		wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
2195071d4279SBram Moolenaar 								/ (p_wmh + 1);
2196071d4279SBram Moolenaar 		m = frame_minheight(fr, next_curwin);
2197071d4279SBram Moolenaar 		if (has_next_curwin)
2198071d4279SBram Moolenaar 		    hnc = frame_has_win(fr, next_curwin);
2199071d4279SBram Moolenaar 		else
2200071d4279SBram Moolenaar 		    hnc = FALSE;
2201e38eab22SBram Moolenaar 		if (hnc)	    // don't count next_curwin
2202071d4279SBram Moolenaar 		    --wincount;
2203071d4279SBram Moolenaar 		if (totwincount == 0)
2204071d4279SBram Moolenaar 		    new_size = room;
2205071d4279SBram Moolenaar 		else
2206071d4279SBram Moolenaar 		    new_size = (wincount * room + ((unsigned)totwincount >> 1))
2207071d4279SBram Moolenaar 								/ totwincount;
2208e38eab22SBram Moolenaar 		if (hnc)	    // add next_curwin size
2209071d4279SBram Moolenaar 		{
2210071d4279SBram Moolenaar 		    next_curwin_size -= p_wh - (m - n);
2211071d4279SBram Moolenaar 		    new_size += next_curwin_size;
2212071d4279SBram Moolenaar 		    room -= new_size - next_curwin_size;
2213071d4279SBram Moolenaar 		}
2214071d4279SBram Moolenaar 		else
2215071d4279SBram Moolenaar 		    room -= new_size;
2216071d4279SBram Moolenaar 		new_size += n;
2217071d4279SBram Moolenaar 	    }
2218e38eab22SBram Moolenaar 	    // Skip frame that is full width when splitting or closing a
2219e38eab22SBram Moolenaar 	    // window, unless equalizing all frames.
2220071d4279SBram Moolenaar 	    if (!current || dir != 'h' || topfr->fr_parent != NULL
2221071d4279SBram Moolenaar 		    || (new_size != fr->fr_height)
2222071d4279SBram Moolenaar 		    || frame_has_win(fr, next_curwin))
2223071d4279SBram Moolenaar 		win_equal_rec(next_curwin, current, fr, dir, col, row,
2224071d4279SBram Moolenaar 							     width, new_size);
2225071d4279SBram Moolenaar 	    row += new_size;
2226071d4279SBram Moolenaar 	    height -= new_size;
2227071d4279SBram Moolenaar 	    totwincount -= wincount;
2228071d4279SBram Moolenaar 	}
2229071d4279SBram Moolenaar     }
2230071d4279SBram Moolenaar }
2231071d4279SBram Moolenaar 
22326d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
22336d41c78eSBram Moolenaar     static void
leaving_window(win_T * win)22346d41c78eSBram Moolenaar leaving_window(win_T *win)
22356d41c78eSBram Moolenaar {
2236f98b845dSBram Moolenaar     // Only matters for a prompt window.
2237f98b845dSBram Moolenaar     if (!bt_prompt(win->w_buffer))
2238f98b845dSBram Moolenaar 	return;
2239f98b845dSBram Moolenaar 
22406d41c78eSBram Moolenaar     // When leaving a prompt window stop Insert mode and perhaps restart
22416d41c78eSBram Moolenaar     // it when entering that window again.
22426d41c78eSBram Moolenaar     win->w_buffer->b_prompt_insert = restart_edit;
2243942b4541SBram Moolenaar     if (restart_edit != 0 && mode_displayed)
2244e38eab22SBram Moolenaar 	clear_cmdline = TRUE;		// unshow mode later
22456d41c78eSBram Moolenaar     restart_edit = NUL;
22466d41c78eSBram Moolenaar 
22476d41c78eSBram Moolenaar     // When leaving the window (or closing the window) was done from a
2248f98b845dSBram Moolenaar     // callback we need to break out of the Insert mode loop and restart Insert
2249f98b845dSBram Moolenaar     // mode when entering the window again.
22506d41c78eSBram Moolenaar     if (State & INSERT)
2251891e1fd8SBram Moolenaar     {
22526d41c78eSBram Moolenaar 	stop_insert_mode = TRUE;
2253f98b845dSBram Moolenaar 	if (win->w_buffer->b_prompt_insert == NUL)
2254891e1fd8SBram Moolenaar 	    win->w_buffer->b_prompt_insert = 'A';
2255891e1fd8SBram Moolenaar     }
22566d41c78eSBram Moolenaar }
22576d41c78eSBram Moolenaar 
2258bdf931c2SBram Moolenaar     void
entering_window(win_T * win)22596d41c78eSBram Moolenaar entering_window(win_T *win)
22606d41c78eSBram Moolenaar {
2261f98b845dSBram Moolenaar     // Only matters for a prompt window.
2262f98b845dSBram Moolenaar     if (!bt_prompt(win->w_buffer))
2263f98b845dSBram Moolenaar 	return;
2264f98b845dSBram Moolenaar 
2265891e1fd8SBram Moolenaar     // When switching to a prompt buffer that was in Insert mode, don't stop
2266891e1fd8SBram Moolenaar     // Insert mode, it may have been set in leaving_window().
2267f98b845dSBram Moolenaar     if (win->w_buffer->b_prompt_insert != NUL)
2268891e1fd8SBram Moolenaar 	stop_insert_mode = FALSE;
2269891e1fd8SBram Moolenaar 
2270f98b845dSBram Moolenaar     // When entering the prompt window restart Insert mode if we were in Insert
2271f98b845dSBram Moolenaar     // mode when we left it.
22726d41c78eSBram Moolenaar     restart_edit = win->w_buffer->b_prompt_insert;
22736d41c78eSBram Moolenaar }
22746d41c78eSBram Moolenaar #endif
22756d41c78eSBram Moolenaar 
2276071d4279SBram Moolenaar /*
22778c752bd6SBram Moolenaar  * Close all windows for buffer "buf".
2278071d4279SBram Moolenaar  */
2279071d4279SBram Moolenaar     void
close_windows(buf_T * buf,int keep_curwin)2280b638a7beSBram Moolenaar close_windows(
2281b638a7beSBram Moolenaar     buf_T	*buf,
2282e38eab22SBram Moolenaar     int		keep_curwin)	    // don't close "curwin"
2283071d4279SBram Moolenaar {
2284f740b29aSBram Moolenaar     win_T	*wp;
2285f740b29aSBram Moolenaar     tabpage_T   *tp, *nexttp;
228632466aa2SBram Moolenaar     int		h = tabline_height();
228712c11d55SBram Moolenaar     int		count = tabpage_index(NULL);
2288071d4279SBram Moolenaar 
2289071d4279SBram Moolenaar     ++RedrawingDisabled;
2290f740b29aSBram Moolenaar 
2291459ca563SBram Moolenaar     for (wp = firstwin; wp != NULL && !ONE_WINDOW; )
2292071d4279SBram Moolenaar     {
2293362ce480SBram Moolenaar 	if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
2294f2bd8ef2SBram Moolenaar 		&& !(wp->w_closing || wp->w_buffer->b_locked > 0))
2295071d4279SBram Moolenaar 	{
22968c752bd6SBram Moolenaar 	    if (win_close(wp, FALSE) == FAIL)
2297e38eab22SBram Moolenaar 		// If closing the window fails give up, to avoid looping
2298e38eab22SBram Moolenaar 		// forever.
22998c752bd6SBram Moolenaar 		break;
2300f740b29aSBram Moolenaar 
2301e38eab22SBram Moolenaar 	    // Start all over, autocommands may change the window layout.
2302f740b29aSBram Moolenaar 	    wp = firstwin;
2303071d4279SBram Moolenaar 	}
2304071d4279SBram Moolenaar 	else
2305f740b29aSBram Moolenaar 	    wp = wp->w_next;
2306071d4279SBram Moolenaar     }
2307f740b29aSBram Moolenaar 
2308e38eab22SBram Moolenaar     // Also check windows in other tab pages.
2309f740b29aSBram Moolenaar     for (tp = first_tabpage; tp != NULL; tp = nexttp)
2310f740b29aSBram Moolenaar     {
2311f740b29aSBram Moolenaar 	nexttp = tp->tp_next;
231249d7bf13SBram Moolenaar 	if (tp != curtab)
2313aeea7215SBram Moolenaar 	    FOR_ALL_WINDOWS_IN_TAB(tp, wp)
2314362ce480SBram Moolenaar 		if (wp->w_buffer == buf
2315f2bd8ef2SBram Moolenaar 		    && !(wp->w_closing || wp->w_buffer->b_locked > 0))
2316f740b29aSBram Moolenaar 		{
2317f740b29aSBram Moolenaar 		    win_close_othertab(wp, FALSE, tp);
2318f740b29aSBram Moolenaar 
2319e38eab22SBram Moolenaar 		    // Start all over, the tab page may be closed and
2320e38eab22SBram Moolenaar 		    // autocommands may change the window layout.
2321f740b29aSBram Moolenaar 		    nexttp = first_tabpage;
2322f740b29aSBram Moolenaar 		    break;
2323f740b29aSBram Moolenaar 		}
2324f740b29aSBram Moolenaar     }
2325f740b29aSBram Moolenaar 
2326071d4279SBram Moolenaar     --RedrawingDisabled;
2327f740b29aSBram Moolenaar 
232812c11d55SBram Moolenaar     if (count != tabpage_index(NULL))
232912c11d55SBram Moolenaar 	apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
233012c11d55SBram Moolenaar 
23314c7e9db0SBram Moolenaar     redraw_tabline = TRUE;
233232466aa2SBram Moolenaar     if (h != tabline_height())
2333f740b29aSBram Moolenaar 	shell_new_rows();
2334071d4279SBram Moolenaar }
2335071d4279SBram Moolenaar 
2336071d4279SBram Moolenaar /*
2337746ebd3bSBram Moolenaar  * Return TRUE if the current window is the only window that exists (ignoring
2338746ebd3bSBram Moolenaar  * "aucmd_win").
233949d7bf13SBram Moolenaar  * Returns FALSE if there is a window, possibly in another tab page.
23401d2ba7faSBram Moolenaar  */
234149d7bf13SBram Moolenaar     static int
last_window(void)2342b638a7beSBram Moolenaar last_window(void)
23431d2ba7faSBram Moolenaar {
2344746ebd3bSBram Moolenaar     return (one_window() && first_tabpage->tp_next == NULL);
2345746ebd3bSBram Moolenaar }
2346746ebd3bSBram Moolenaar 
2347746ebd3bSBram Moolenaar /*
2348746ebd3bSBram Moolenaar  * Return TRUE if there is only one window other than "aucmd_win" in the
2349746ebd3bSBram Moolenaar  * current tab page.
2350746ebd3bSBram Moolenaar  */
235142ec6565SBram Moolenaar     int
one_window(void)2352b638a7beSBram Moolenaar one_window(void)
2353746ebd3bSBram Moolenaar {
2354746ebd3bSBram Moolenaar     win_T	*wp;
2355746ebd3bSBram Moolenaar     int		seen_one = FALSE;
2356746ebd3bSBram Moolenaar 
2357746ebd3bSBram Moolenaar     FOR_ALL_WINDOWS(wp)
2358746ebd3bSBram Moolenaar     {
2359746ebd3bSBram Moolenaar 	if (wp != aucmd_win)
2360746ebd3bSBram Moolenaar 	{
2361746ebd3bSBram Moolenaar 	    if (seen_one)
2362746ebd3bSBram Moolenaar 		return FALSE;
2363746ebd3bSBram Moolenaar 	    seen_one = TRUE;
2364746ebd3bSBram Moolenaar 	}
2365746ebd3bSBram Moolenaar     }
2366746ebd3bSBram Moolenaar     return TRUE;
23671d2ba7faSBram Moolenaar }
23681d2ba7faSBram Moolenaar 
23691d2ba7faSBram Moolenaar /*
2370bef1c36aSBram Moolenaar  * Close the possibly last window in a tab page.
2371bef1c36aSBram Moolenaar  * Returns TRUE when the window was closed already.
2372bef1c36aSBram Moolenaar  */
2373bef1c36aSBram Moolenaar     static int
close_last_window_tabpage(win_T * win,int free_buf,tabpage_T * prev_curtab)2374b638a7beSBram Moolenaar close_last_window_tabpage(
2375b638a7beSBram Moolenaar     win_T	*win,
2376b638a7beSBram Moolenaar     int		free_buf,
2377b638a7beSBram Moolenaar     tabpage_T   *prev_curtab)
2378bef1c36aSBram Moolenaar {
2379a1f4cb93SBram Moolenaar     if (ONE_WINDOW)
2380bef1c36aSBram Moolenaar     {
238149e649fcSBram Moolenaar 	buf_T	*old_curbuf = curbuf;
238249e649fcSBram Moolenaar 
2383bef1c36aSBram Moolenaar 	/*
2384bef1c36aSBram Moolenaar 	 * Closing the last window in a tab page.  First go to another tab
2385bef1c36aSBram Moolenaar 	 * page and then close the window and the tab page.  This avoids that
2386bef1c36aSBram Moolenaar 	 * curwin and curtab are invalid while we are freeing memory, they may
2387bef1c36aSBram Moolenaar 	 * be used in GUI events.
2388a8596c47SBram Moolenaar 	 * Don't trigger autocommands yet, they may use wrong values, so do
2389a8596c47SBram Moolenaar 	 * that below.
2390bef1c36aSBram Moolenaar 	 */
239149e649fcSBram Moolenaar 	goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
2392bef1c36aSBram Moolenaar 	redraw_tabline = TRUE;
2393bef1c36aSBram Moolenaar 
2394e38eab22SBram Moolenaar 	// Safety check: Autocommands may have closed the window when jumping
2395e38eab22SBram Moolenaar 	// to the other tab page.
2396bef1c36aSBram Moolenaar 	if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win)
2397bef1c36aSBram Moolenaar 	{
2398bef1c36aSBram Moolenaar 	    int	    h = tabline_height();
2399bef1c36aSBram Moolenaar 
2400bef1c36aSBram Moolenaar 	    win_close_othertab(win, free_buf, prev_curtab);
2401bef1c36aSBram Moolenaar 	    if (h != tabline_height())
2402bef1c36aSBram Moolenaar 		shell_new_rows();
2403bef1c36aSBram Moolenaar 	}
24046d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
24056d41c78eSBram Moolenaar 	entering_window(curwin);
24066d41c78eSBram Moolenaar #endif
2407e38eab22SBram Moolenaar 	// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
2408e38eab22SBram Moolenaar 	// that now.
240912c11d55SBram Moolenaar 	apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
2410a8596c47SBram Moolenaar 	apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
241149e649fcSBram Moolenaar 	apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
241249e649fcSBram Moolenaar 	if (old_curbuf != curbuf)
241349e649fcSBram Moolenaar 	    apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
2414bef1c36aSBram Moolenaar 	return TRUE;
2415bef1c36aSBram Moolenaar     }
2416bef1c36aSBram Moolenaar     return FALSE;
2417bef1c36aSBram Moolenaar }
2418bef1c36aSBram Moolenaar 
2419bef1c36aSBram Moolenaar /*
24207c7f01e2SBram Moolenaar  * Close the buffer of "win" and unload it if "action" is DOBUF_UNLOAD.
24217c7f01e2SBram Moolenaar  * "action" can also be zero (do nothing) or DOBUF_WIPE.
24224d784b21SBram Moolenaar  * "abort_if_last" is passed to close_buffer(): abort closing if all other
24234d784b21SBram Moolenaar  * windows are closed.
24244d784b21SBram Moolenaar  */
24254d784b21SBram Moolenaar     static void
win_close_buffer(win_T * win,int action,int abort_if_last)24267c7f01e2SBram Moolenaar win_close_buffer(win_T *win, int action, int abort_if_last)
24274d784b21SBram Moolenaar {
24284d784b21SBram Moolenaar #ifdef FEAT_SYN_HL
24294d784b21SBram Moolenaar     // Free independent synblock before the buffer is freed.
24304d784b21SBram Moolenaar     if (win->w_buffer != NULL)
24314d784b21SBram Moolenaar 	reset_synblock(win);
24324d784b21SBram Moolenaar #endif
24334d784b21SBram Moolenaar 
24344d784b21SBram Moolenaar #ifdef FEAT_QUICKFIX
24354d784b21SBram Moolenaar     // When the quickfix/location list window is closed, unlist the buffer.
24364d784b21SBram Moolenaar     if (win->w_buffer != NULL && bt_quickfix(win->w_buffer))
24374d784b21SBram Moolenaar 	win->w_buffer->b_p_bl = FALSE;
24384d784b21SBram Moolenaar #endif
24394d784b21SBram Moolenaar 
24404d784b21SBram Moolenaar     // Close the link to the buffer.
24414d784b21SBram Moolenaar     if (win->w_buffer != NULL)
24424d784b21SBram Moolenaar     {
24434d784b21SBram Moolenaar 	bufref_T    bufref;
24444d784b21SBram Moolenaar 
24454d784b21SBram Moolenaar 	set_bufref(&bufref, curbuf);
24464d784b21SBram Moolenaar 	win->w_closing = TRUE;
2447a6e8f888SBram Moolenaar 	close_buffer(win, win->w_buffer, action, abort_if_last, FALSE);
24484d784b21SBram Moolenaar 	if (win_valid_any_tab(win))
24494d784b21SBram Moolenaar 	    win->w_closing = FALSE;
24504d784b21SBram Moolenaar 	// Make sure curbuf is valid. It can become invalid if 'bufhidden' is
24514d784b21SBram Moolenaar 	// "wipe".
24524d784b21SBram Moolenaar 	if (!bufref_valid(&bufref))
24534d784b21SBram Moolenaar 	    curbuf = firstbuf;
24544d784b21SBram Moolenaar     }
24554d784b21SBram Moolenaar }
24564d784b21SBram Moolenaar 
24574d784b21SBram Moolenaar /*
2458910f66f9SBram Moolenaar  * Close window "win".  Only works for the current tab page.
2459071d4279SBram Moolenaar  * If "free_buf" is TRUE related buffer may be unloaded.
2460071d4279SBram Moolenaar  *
246142ec6565SBram Moolenaar  * Called by :quit, :close, :xit, :wq and findtag().
2462c93df6b0SBram Moolenaar  * Returns FAIL when the window was not closed.
2463071d4279SBram Moolenaar  */
2464c93df6b0SBram Moolenaar     int
win_close(win_T * win,int free_buf)2465b638a7beSBram Moolenaar win_close(win_T *win, int free_buf)
2466071d4279SBram Moolenaar {
2467071d4279SBram Moolenaar     win_T	*wp;
2468071d4279SBram Moolenaar     int		other_buffer = FALSE;
2469071d4279SBram Moolenaar     int		close_curwin = FALSE;
2470071d4279SBram Moolenaar     int		dir;
2471071d4279SBram Moolenaar     int		help_window = FALSE;
2472c1b52863SBram Moolenaar     tabpage_T   *prev_curtab = curtab;
247341cc038fSBram Moolenaar     frame_T	*win_frame = win->w_frame->fr_parent;
2474c8234779SBram Moolenaar #ifdef FEAT_DIFF
2475c8234779SBram Moolenaar     int		had_diffmode = win->w_p_diff;
2476c8234779SBram Moolenaar #endif
2477f18e8a96SBram Moolenaar #ifdef MESSAGE_QUEUE
247857942237SBram Moolenaar     int		did_decrement = FALSE;
2479f18e8a96SBram Moolenaar #endif
2480071d4279SBram Moolenaar 
2481d98c0b63SBram Moolenaar #if defined(FEAT_TERMINAL) && defined(FEAT_PROP_POPUP)
2482d98c0b63SBram Moolenaar     // Can close a popup window with a terminal if the job has finished.
2483d98c0b63SBram Moolenaar     if (may_close_term_popup() == OK)
2484d98c0b63SBram Moolenaar 	return OK;
2485d98c0b63SBram Moolenaar #endif
24863c01c4a0SBram Moolenaar     if (ERROR_IF_ANY_POPUP_WINDOW)
2487815b76bfSBram Moolenaar 	return FAIL;
2488815b76bfSBram Moolenaar 
24891d2ba7faSBram Moolenaar     if (last_window())
2490071d4279SBram Moolenaar     {
2491f9e3e09fSBram Moolenaar 	emsg(_("E444: Cannot close last window"));
2492c93df6b0SBram Moolenaar 	return FAIL;
2493071d4279SBram Moolenaar     }
2494071d4279SBram Moolenaar 
2495e0ab94e7SBram Moolenaar     if (win->w_closing || (win->w_buffer != NULL
2496e0ab94e7SBram Moolenaar 					       && win->w_buffer->b_locked > 0))
2497e38eab22SBram Moolenaar 	return FAIL; // window is already being closed
24984d784b21SBram Moolenaar     if (win_unlisted(win))
2499746ebd3bSBram Moolenaar     {
2500cf844170SBram Moolenaar 	emsg(_(e_autocmd_close));
2501c93df6b0SBram Moolenaar 	return FAIL;
2502746ebd3bSBram Moolenaar     }
2503746ebd3bSBram Moolenaar     if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
2504746ebd3bSBram Moolenaar     {
2505f9e3e09fSBram Moolenaar 	emsg(_("E814: Cannot close window, only autocmd window would remain"));
2506c93df6b0SBram Moolenaar 	return FAIL;
2507746ebd3bSBram Moolenaar     }
2508746ebd3bSBram Moolenaar 
2509e38eab22SBram Moolenaar     // When closing the last window in a tab page first go to another tab page
2510e38eab22SBram Moolenaar     // and then close the window and the tab page to avoid that curwin and
2511e38eab22SBram Moolenaar     // curtab are invalid while we are freeing memory.
2512bef1c36aSBram Moolenaar     if (close_last_window_tabpage(win, free_buf, prev_curtab))
2513c93df6b0SBram Moolenaar       return FAIL;
2514c9b4b05bSBram Moolenaar 
2515e38eab22SBram Moolenaar     // When closing the help window, try restoring a snapshot after closing
2516e38eab22SBram Moolenaar     // the window.  Otherwise clear the snapshot, it's now invalid.
2517d28cc3f5SBram Moolenaar     if (bt_help(win->w_buffer))
2518071d4279SBram Moolenaar 	help_window = TRUE;
2519071d4279SBram Moolenaar     else
2520746ebd3bSBram Moolenaar 	clear_snapshot(curtab, SNAP_HELP_IDX);
2521071d4279SBram Moolenaar 
2522071d4279SBram Moolenaar     if (win == curwin)
2523071d4279SBram Moolenaar     {
25246d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
25256d41c78eSBram Moolenaar 	leaving_window(curwin);
25266d41c78eSBram Moolenaar #endif
2527071d4279SBram Moolenaar 	/*
2528071d4279SBram Moolenaar 	 * Guess which window is going to be the new current window.
2529071d4279SBram Moolenaar 	 * This may change because of the autocommands (sigh).
2530071d4279SBram Moolenaar 	 */
2531f740b29aSBram Moolenaar 	wp = frame2win(win_altframe(win, NULL));
2532071d4279SBram Moolenaar 
2533071d4279SBram Moolenaar 	/*
2534362ce480SBram Moolenaar 	 * Be careful: If autocommands delete the window or cause this window
2535362ce480SBram Moolenaar 	 * to be the last one left, return now.
2536071d4279SBram Moolenaar 	 */
2537071d4279SBram Moolenaar 	if (wp->w_buffer != curbuf)
2538071d4279SBram Moolenaar 	{
2539071d4279SBram Moolenaar 	    other_buffer = TRUE;
2540362ce480SBram Moolenaar 	    win->w_closing = TRUE;
2541071d4279SBram Moolenaar 	    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
2542362ce480SBram Moolenaar 	    if (!win_valid(win))
2543c93df6b0SBram Moolenaar 		return FAIL;
2544362ce480SBram Moolenaar 	    win->w_closing = FALSE;
2545362ce480SBram Moolenaar 	    if (last_window())
2546c93df6b0SBram Moolenaar 		return FAIL;
2547071d4279SBram Moolenaar 	}
2548362ce480SBram Moolenaar 	win->w_closing = TRUE;
2549071d4279SBram Moolenaar 	apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
2550362ce480SBram Moolenaar 	if (!win_valid(win))
2551c93df6b0SBram Moolenaar 	    return FAIL;
2552362ce480SBram Moolenaar 	win->w_closing = FALSE;
2553362ce480SBram Moolenaar 	if (last_window())
2554c93df6b0SBram Moolenaar 	    return FAIL;
2555071d4279SBram Moolenaar #ifdef FEAT_EVAL
2556e38eab22SBram Moolenaar 	// autocmds may abort script processing
2557071d4279SBram Moolenaar 	if (aborting())
2558c93df6b0SBram Moolenaar 	    return FAIL;
2559071d4279SBram Moolenaar #endif
2560071d4279SBram Moolenaar     }
2561071d4279SBram Moolenaar 
2562053b9fa9SBram Moolenaar #ifdef FEAT_GUI
2563647e24baSBram Moolenaar     // Avoid trouble with scrollbars that are going to be deleted in
2564647e24baSBram Moolenaar     // win_free().
2565053b9fa9SBram Moolenaar     if (gui.in_use)
2566053b9fa9SBram Moolenaar 	out_flush();
2567053b9fa9SBram Moolenaar #endif
2568053b9fa9SBram Moolenaar 
256905ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
257012034e22SBram Moolenaar     if (popup_win_closed(win) && !win_valid(win))
257112034e22SBram Moolenaar 	return FAIL;
257212034e22SBram Moolenaar #endif
257323beefedSnaohiro ono 
257423beefedSnaohiro ono     // Trigger WinClosed just before starting to free window-related resources.
257523beefedSnaohiro ono     trigger_winclosed(win);
257623beefedSnaohiro ono     // autocmd may have freed the window already.
257723beefedSnaohiro ono     if (!win_valid_any_tab(win))
257823beefedSnaohiro ono 	return OK;
257923beefedSnaohiro ono 
25807c7f01e2SBram Moolenaar     win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE);
2581c1b52863SBram Moolenaar 
2582802418d5SBram Moolenaar     if (only_one_window() && win_valid(win) && win->w_buffer == NULL
2583802418d5SBram Moolenaar 	    && (last_window() || curtab != prev_curtab
2584802418d5SBram Moolenaar 		|| close_last_window_tabpage(win, free_buf, prev_curtab)))
25852b90ed29SBram Moolenaar     {
2586e38eab22SBram Moolenaar 	// Autocommands have closed all windows, quit now.  Restore
2587e38eab22SBram Moolenaar 	// curwin->w_buffer, otherwise writing viminfo may fail.
25882b90ed29SBram Moolenaar 	if (curwin->w_buffer == NULL)
25892b90ed29SBram Moolenaar 	    curwin->w_buffer = curbuf;
2590802418d5SBram Moolenaar 	getout(0);
25912b90ed29SBram Moolenaar     }
2592802418d5SBram Moolenaar 
2593e38eab22SBram Moolenaar     // Autocommands may have moved to another tab page.
259411fbc286SBram Moolenaar     if (curtab != prev_curtab && win_valid_any_tab(win)
259511fbc286SBram Moolenaar 						      && win->w_buffer == NULL)
259611fbc286SBram Moolenaar     {
2597e38eab22SBram Moolenaar 	// Need to close the window anyway, since the buffer is NULL.
259811fbc286SBram Moolenaar 	win_close_othertab(win, FALSE, prev_curtab);
259911fbc286SBram Moolenaar 	return FAIL;
260011fbc286SBram Moolenaar     }
260111fbc286SBram Moolenaar 
2602e38eab22SBram Moolenaar     // Autocommands may have closed the window already or closed the only
2603e38eab22SBram Moolenaar     // other window.
260411fbc286SBram Moolenaar     if (!win_valid(win) || last_window()
2605bef1c36aSBram Moolenaar 	    || close_last_window_tabpage(win, free_buf, prev_curtab))
2606c93df6b0SBram Moolenaar 	return FAIL;
2607071d4279SBram Moolenaar 
26081417c766SBram Moolenaar     // Now we are really going to close the window.  Disallow any autocommand
26091417c766SBram Moolenaar     // to split a window to avoid trouble.
26104778b4d0SBram Moolenaar     // Also bail out of parse_queued_messages() to avoid it tries to update the
26114778b4d0SBram Moolenaar     // screen.
26121417c766SBram Moolenaar     ++split_disallowed;
26134778b4d0SBram Moolenaar #ifdef MESSAGE_QUEUE
26144778b4d0SBram Moolenaar     ++dont_parse_messages;
26154778b4d0SBram Moolenaar #endif
26161417c766SBram Moolenaar 
2617e38eab22SBram Moolenaar     // Free the memory used for the window and get the window that received
2618e38eab22SBram Moolenaar     // the screen space.
2619c1b52863SBram Moolenaar     wp = win_free_mem(win, &dir, NULL);
2620c1b52863SBram Moolenaar 
2621e38eab22SBram Moolenaar     // Make sure curwin isn't invalid.  It can cause severe trouble when
2622e38eab22SBram Moolenaar     // printing an error message.  For win_equal() curbuf needs to be valid
2623e38eab22SBram Moolenaar     // too.
2624c1b52863SBram Moolenaar     if (win == curwin)
2625071d4279SBram Moolenaar     {
2626071d4279SBram Moolenaar 	curwin = wp;
2627071d4279SBram Moolenaar #ifdef FEAT_QUICKFIX
2628071d4279SBram Moolenaar 	if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
2629071d4279SBram Moolenaar 	{
2630071d4279SBram Moolenaar 	    /*
263148cc5fe8SBram Moolenaar 	     * If the cursor goes to the preview or the quickfix window, try
2632071d4279SBram Moolenaar 	     * finding another window to go to.
2633071d4279SBram Moolenaar 	     */
2634071d4279SBram Moolenaar 	    for (;;)
2635071d4279SBram Moolenaar 	    {
2636071d4279SBram Moolenaar 		if (wp->w_next == NULL)
2637071d4279SBram Moolenaar 		    wp = firstwin;
2638071d4279SBram Moolenaar 		else
2639071d4279SBram Moolenaar 		    wp = wp->w_next;
2640071d4279SBram Moolenaar 		if (wp == curwin)
2641071d4279SBram Moolenaar 		    break;
2642071d4279SBram Moolenaar 		if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
2643071d4279SBram Moolenaar 		{
2644071d4279SBram Moolenaar 		    curwin = wp;
2645071d4279SBram Moolenaar 		    break;
2646071d4279SBram Moolenaar 		}
2647071d4279SBram Moolenaar 	    }
2648071d4279SBram Moolenaar 	}
2649071d4279SBram Moolenaar #endif
2650071d4279SBram Moolenaar 	curbuf = curwin->w_buffer;
2651071d4279SBram Moolenaar 	close_curwin = TRUE;
2652f79225edSBram Moolenaar 
2653e38eab22SBram Moolenaar 	// The cursor position may be invalid if the buffer changed after last
2654e38eab22SBram Moolenaar 	// using the window.
2655f79225edSBram Moolenaar 	check_cursor();
2656071d4279SBram Moolenaar     }
265744a2f923SBram Moolenaar     if (p_ea && (*p_ead == 'b' || *p_ead == dir))
2658e38eab22SBram Moolenaar 	// If the frame of the closed window contains the new current window,
2659e38eab22SBram Moolenaar 	// only resize that frame.  Otherwise resize all windows.
266041cc038fSBram Moolenaar 	win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
2661071d4279SBram Moolenaar     else
2662071d4279SBram Moolenaar 	win_comp_pos();
2663071d4279SBram Moolenaar     if (close_curwin)
2664071d4279SBram Moolenaar     {
266557942237SBram Moolenaar 	// Pass WEE_ALLOW_PARSE_MESSAGES to decrement dont_parse_messages
266657942237SBram Moolenaar 	// before autocommands.
2667f18e8a96SBram Moolenaar #ifdef MESSAGE_QUEUE
2668f18e8a96SBram Moolenaar 	did_decrement =
2669f18e8a96SBram Moolenaar #else
2670f18e8a96SBram Moolenaar 	(void)
2671f18e8a96SBram Moolenaar #endif
2672f18e8a96SBram Moolenaar 	    win_enter_ext(wp,
267357942237SBram Moolenaar 		WEE_CURWIN_INVALID | WEE_TRIGGER_ENTER_AUTOCMDS
267457942237SBram Moolenaar 		      | WEE_TRIGGER_LEAVE_AUTOCMDS | WEE_ALLOW_PARSE_MESSAGES);
2675071d4279SBram Moolenaar 	if (other_buffer)
2676e38eab22SBram Moolenaar 	    // careful: after this wp and win may be invalid!
2677071d4279SBram Moolenaar 	    apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
2678071d4279SBram Moolenaar     }
2679071d4279SBram Moolenaar 
26801417c766SBram Moolenaar     --split_disallowed;
26814778b4d0SBram Moolenaar #ifdef MESSAGE_QUEUE
268257942237SBram Moolenaar     if (!did_decrement)
26834778b4d0SBram Moolenaar 	--dont_parse_messages;
26844778b4d0SBram Moolenaar #endif
26851417c766SBram Moolenaar 
2686071d4279SBram Moolenaar     /*
26871d2ba7faSBram Moolenaar      * If last window has a status line now and we don't want one,
26881d2ba7faSBram Moolenaar      * remove the status line.
2689071d4279SBram Moolenaar      */
2690071d4279SBram Moolenaar     last_status(FALSE);
2691071d4279SBram Moolenaar 
2692e38eab22SBram Moolenaar     // After closing the help window, try restoring the window layout from
2693e38eab22SBram Moolenaar     // before it was opened.
2694071d4279SBram Moolenaar     if (help_window)
2695746ebd3bSBram Moolenaar 	restore_snapshot(SNAP_HELP_IDX, close_curwin);
2696071d4279SBram Moolenaar 
2697c8234779SBram Moolenaar #ifdef FEAT_DIFF
2698c8234779SBram Moolenaar     // If the window had 'diff' set and now there is only one window left in
2699c8234779SBram Moolenaar     // the tab page with 'diff' set, and "closeoff" is in 'diffopt', then
2700c8234779SBram Moolenaar     // execute ":diffoff!".
2701c8234779SBram Moolenaar     if (diffopt_closeoff() && had_diffmode && curtab == prev_curtab)
2702c8234779SBram Moolenaar     {
2703c8234779SBram Moolenaar 	int	diffcount = 0;
2704c8234779SBram Moolenaar 	win_T	*dwin;
2705c8234779SBram Moolenaar 
2706c8234779SBram Moolenaar 	FOR_ALL_WINDOWS(dwin)
2707c8234779SBram Moolenaar 	    if (dwin->w_p_diff)
2708c8234779SBram Moolenaar 		++diffcount;
2709c8234779SBram Moolenaar 	if (diffcount == 1)
2710c8234779SBram Moolenaar 	    do_cmdline_cmd((char_u *)"diffoff!");
2711c8234779SBram Moolenaar     }
2712c8234779SBram Moolenaar #endif
2713c8234779SBram Moolenaar 
271444a2f923SBram Moolenaar #if defined(FEAT_GUI)
2715e38eab22SBram Moolenaar     // When 'guioptions' includes 'L' or 'R' may have to remove scrollbars.
2716071d4279SBram Moolenaar     if (gui.in_use && !win_hasvertsplit())
2717071d4279SBram Moolenaar 	gui_init_which_components(NULL);
2718071d4279SBram Moolenaar #endif
2719071d4279SBram Moolenaar 
2720071d4279SBram Moolenaar     redraw_all_later(NOT_VALID);
2721c93df6b0SBram Moolenaar     return OK;
2722071d4279SBram Moolenaar }
2723071d4279SBram Moolenaar 
272423beefedSnaohiro ono     static void
trigger_winclosed(win_T * win)272523beefedSnaohiro ono trigger_winclosed(win_T *win)
272623beefedSnaohiro ono {
272723beefedSnaohiro ono     static int	recursive = FALSE;
272823beefedSnaohiro ono     char_u	winid[NUMBUFLEN];
272923beefedSnaohiro ono 
273023beefedSnaohiro ono     if (recursive)
273123beefedSnaohiro ono 	return;
273223beefedSnaohiro ono     recursive = TRUE;
273323beefedSnaohiro ono     vim_snprintf((char *)winid, sizeof(winid), "%i", win->w_id);
273423beefedSnaohiro ono     apply_autocmds(EVENT_WINCLOSED, winid, winid, FALSE, win->w_buffer);
273523beefedSnaohiro ono     recursive = FALSE;
273623beefedSnaohiro ono }
273723beefedSnaohiro ono 
2738071d4279SBram Moolenaar /*
2739f740b29aSBram Moolenaar  * Close window "win" in tab page "tp", which is not the current tab page.
2740bef1c36aSBram Moolenaar  * This may be the last window in that tab page and result in closing the tab,
2741f740b29aSBram Moolenaar  * thus "tp" may become invalid!
2742c9b4b05bSBram Moolenaar  * Caller must check if buffer is hidden and whether the tabline needs to be
2743c9b4b05bSBram Moolenaar  * updated.
2744f740b29aSBram Moolenaar  */
2745f740b29aSBram Moolenaar     void
win_close_othertab(win_T * win,int free_buf,tabpage_T * tp)2746b638a7beSBram Moolenaar win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
2747f740b29aSBram Moolenaar {
2748f740b29aSBram Moolenaar     win_T	*wp;
2749f740b29aSBram Moolenaar     int		dir;
2750f740b29aSBram Moolenaar     tabpage_T   *ptp = NULL;
27514d770fb5SBram Moolenaar     int		free_tp = FALSE;
2752f740b29aSBram Moolenaar 
2753e38eab22SBram Moolenaar     // Get here with win->w_buffer == NULL when win_close() detects the tab
2754e38eab22SBram Moolenaar     // page changed.
2755e0ab94e7SBram Moolenaar     if (win->w_closing || (win->w_buffer != NULL
2756e0ab94e7SBram Moolenaar 					       && win->w_buffer->b_locked > 0))
2757e38eab22SBram Moolenaar 	return; // window is already being closed
2758362ce480SBram Moolenaar 
275923beefedSnaohiro ono     // Trigger WinClosed just before starting to free window-related resources.
276023beefedSnaohiro ono     trigger_winclosed(win);
276123beefedSnaohiro ono     // autocmd may have freed the window already.
276223beefedSnaohiro ono     if (!win_valid_any_tab(win))
276323beefedSnaohiro ono 	return;
276423beefedSnaohiro ono 
276511fbc286SBram Moolenaar     if (win->w_buffer != NULL)
2766e38eab22SBram Moolenaar 	// Close the link to the buffer.
2767a6e8f888SBram Moolenaar 	close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0,
2768a6e8f888SBram Moolenaar 								 FALSE, FALSE);
2769f740b29aSBram Moolenaar 
2770e38eab22SBram Moolenaar     // Careful: Autocommands may have closed the tab page or made it the
2771e38eab22SBram Moolenaar     // current tab page.
2772f740b29aSBram Moolenaar     for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
2773f740b29aSBram Moolenaar 	;
277449d7bf13SBram Moolenaar     if (ptp == NULL || tp == curtab)
2775f740b29aSBram Moolenaar 	return;
2776f740b29aSBram Moolenaar 
2777e38eab22SBram Moolenaar     // Autocommands may have closed the window already.
2778f740b29aSBram Moolenaar     for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
2779f740b29aSBram Moolenaar 	;
2780f740b29aSBram Moolenaar     if (wp == NULL)
2781f740b29aSBram Moolenaar 	return;
2782f740b29aSBram Moolenaar 
2783e38eab22SBram Moolenaar     // When closing the last window in a tab page remove the tab page.
2784cde88547SBram Moolenaar     if (tp->tp_firstwin == tp->tp_lastwin)
2785f740b29aSBram Moolenaar     {
2786f740b29aSBram Moolenaar 	if (tp == first_tabpage)
2787f740b29aSBram Moolenaar 	    first_tabpage = tp->tp_next;
2788f740b29aSBram Moolenaar 	else
2789f740b29aSBram Moolenaar 	{
2790f740b29aSBram Moolenaar 	    for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
2791f740b29aSBram Moolenaar 							   ptp = ptp->tp_next)
2792f740b29aSBram Moolenaar 		;
2793f740b29aSBram Moolenaar 	    if (ptp == NULL)
2794f740b29aSBram Moolenaar 	    {
279595f09603SBram Moolenaar 		internal_error("win_close_othertab()");
2796f740b29aSBram Moolenaar 		return;
2797f740b29aSBram Moolenaar 	    }
2798f740b29aSBram Moolenaar 	    ptp->tp_next = tp->tp_next;
2799f740b29aSBram Moolenaar 	}
28004d770fb5SBram Moolenaar 	free_tp = TRUE;
2801f740b29aSBram Moolenaar     }
28024d770fb5SBram Moolenaar 
2803e38eab22SBram Moolenaar     // Free the memory used for the window.
28044d770fb5SBram Moolenaar     win_free_mem(win, &dir, tp);
28054d770fb5SBram Moolenaar 
28064d770fb5SBram Moolenaar     if (free_tp)
28074d770fb5SBram Moolenaar 	free_tabpage(tp);
2808f740b29aSBram Moolenaar }
2809f740b29aSBram Moolenaar 
2810f740b29aSBram Moolenaar /*
28110a5fe214SBram Moolenaar  * Free the memory used for a window.
28120a5fe214SBram Moolenaar  * Returns a pointer to the window that got the freed up space.
28130a5fe214SBram Moolenaar  */
28140a5fe214SBram Moolenaar     static win_T *
win_free_mem(win_T * win,int * dirp,tabpage_T * tp)2815b638a7beSBram Moolenaar win_free_mem(
2816b638a7beSBram Moolenaar     win_T	*win,
2817e38eab22SBram Moolenaar     int		*dirp,		// set to 'v' or 'h' for direction if 'ea'
2818e38eab22SBram Moolenaar     tabpage_T	*tp)		// tab page "win" is in, NULL for current
28190a5fe214SBram Moolenaar {
28200a5fe214SBram Moolenaar     frame_T	*frp;
28210a5fe214SBram Moolenaar     win_T	*wp;
2822f3c51bbfSBram Moolenaar     tabpage_T	*win_tp = tp == NULL ? curtab : tp;
28230a5fe214SBram Moolenaar 
2824e38eab22SBram Moolenaar     // Remove the window and its frame from the tree of frames.
28250a5fe214SBram Moolenaar     frp = win->w_frame;
2826f740b29aSBram Moolenaar     wp = winframe_remove(win, dirp, tp);
28270a5fe214SBram Moolenaar     vim_free(frp);
2828f740b29aSBram Moolenaar     win_free(win, tp);
28290a5fe214SBram Moolenaar 
2830f3c51bbfSBram Moolenaar     // When deleting the current window in the tab, select a new current
2831f3c51bbfSBram Moolenaar     // window.
2832f3c51bbfSBram Moolenaar     if (win == win_tp->tp_curwin)
2833f3c51bbfSBram Moolenaar 	win_tp->tp_curwin = wp;
2834910f66f9SBram Moolenaar 
28350a5fe214SBram Moolenaar     return wp;
28360a5fe214SBram Moolenaar }
28370a5fe214SBram Moolenaar 
28380a5fe214SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
28390a5fe214SBram Moolenaar     void
win_free_all(void)2840b638a7beSBram Moolenaar win_free_all(void)
28410a5fe214SBram Moolenaar {
28420a5fe214SBram Moolenaar     int		dummy;
28430a5fe214SBram Moolenaar 
2844f740b29aSBram Moolenaar     while (first_tabpage->tp_next != NULL)
2845f740b29aSBram Moolenaar 	tabpage_close(TRUE);
2846f740b29aSBram Moolenaar 
2847746ebd3bSBram Moolenaar     if (aucmd_win != NULL)
2848746ebd3bSBram Moolenaar     {
2849746ebd3bSBram Moolenaar 	(void)win_free_mem(aucmd_win, &dummy, NULL);
2850746ebd3bSBram Moolenaar 	aucmd_win = NULL;
2851746ebd3bSBram Moolenaar     }
2852f061e0beSBram Moolenaar 
2853f061e0beSBram Moolenaar     while (firstwin != NULL)
2854f061e0beSBram Moolenaar 	(void)win_free_mem(firstwin, &dummy, NULL);
28554e036c9eSBram Moolenaar 
2856e38eab22SBram Moolenaar     // No window should be used after this. Set curwin to NULL to crash
2857e38eab22SBram Moolenaar     // instead of using freed memory.
28584e036c9eSBram Moolenaar     curwin = NULL;
28590a5fe214SBram Moolenaar }
28600a5fe214SBram Moolenaar #endif
28610a5fe214SBram Moolenaar 
28620a5fe214SBram Moolenaar /*
2863071d4279SBram Moolenaar  * Remove a window and its frame from the tree of frames.
2864071d4279SBram Moolenaar  * Returns a pointer to the window that got the freed up space.
2865071d4279SBram Moolenaar  */
2866746ebd3bSBram Moolenaar     win_T *
winframe_remove(win_T * win,int * dirp UNUSED,tabpage_T * tp)2867b638a7beSBram Moolenaar winframe_remove(
2868b638a7beSBram Moolenaar     win_T	*win,
2869e38eab22SBram Moolenaar     int		*dirp UNUSED,	// set to 'v' or 'h' for direction if 'ea'
2870e38eab22SBram Moolenaar     tabpage_T	*tp)		// tab page "win" is in, NULL for current
2871071d4279SBram Moolenaar {
2872071d4279SBram Moolenaar     frame_T	*frp, *frp2, *frp3;
2873071d4279SBram Moolenaar     frame_T	*frp_close = win->w_frame;
2874071d4279SBram Moolenaar     win_T	*wp;
2875071d4279SBram Moolenaar 
2876071d4279SBram Moolenaar     /*
2877f740b29aSBram Moolenaar      * If there is only one window there is nothing to remove.
2878f740b29aSBram Moolenaar      */
2879a1f4cb93SBram Moolenaar     if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
2880f740b29aSBram Moolenaar 	return NULL;
2881f740b29aSBram Moolenaar 
2882f740b29aSBram Moolenaar     /*
2883071d4279SBram Moolenaar      * Remove the window from its frame.
2884071d4279SBram Moolenaar      */
2885f740b29aSBram Moolenaar     frp2 = win_altframe(win, tp);
2886071d4279SBram Moolenaar     wp = frame2win(frp2);
2887071d4279SBram Moolenaar 
2888e38eab22SBram Moolenaar     // Remove this frame from the list of frames.
2889071d4279SBram Moolenaar     frame_remove(frp_close);
2890071d4279SBram Moolenaar 
2891071d4279SBram Moolenaar     if (frp_close->fr_parent->fr_layout == FR_COL)
2892071d4279SBram Moolenaar     {
2893e38eab22SBram Moolenaar 	// When 'winfixheight' is set, try to find another frame in the column
2894e38eab22SBram Moolenaar 	// (as close to the closed frame as possible) to distribute the height
2895e38eab22SBram Moolenaar 	// to.
289648cc5fe8SBram Moolenaar 	if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
289748cc5fe8SBram Moolenaar 	{
289848cc5fe8SBram Moolenaar 	    frp = frp_close->fr_prev;
289948cc5fe8SBram Moolenaar 	    frp3 = frp_close->fr_next;
290048cc5fe8SBram Moolenaar 	    while (frp != NULL || frp3 != NULL)
290148cc5fe8SBram Moolenaar 	    {
290248cc5fe8SBram Moolenaar 		if (frp != NULL)
290348cc5fe8SBram Moolenaar 		{
29049e1e358dSBram Moolenaar 		    if (!frame_fixed_height(frp))
290548cc5fe8SBram Moolenaar 		    {
290648cc5fe8SBram Moolenaar 			frp2 = frp;
29079e1e358dSBram Moolenaar 			wp = frame2win(frp2);
290848cc5fe8SBram Moolenaar 			break;
290948cc5fe8SBram Moolenaar 		    }
291048cc5fe8SBram Moolenaar 		    frp = frp->fr_prev;
291148cc5fe8SBram Moolenaar 		}
291248cc5fe8SBram Moolenaar 		if (frp3 != NULL)
291348cc5fe8SBram Moolenaar 		{
291448cc5fe8SBram Moolenaar 		    if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
291548cc5fe8SBram Moolenaar 		    {
291648cc5fe8SBram Moolenaar 			frp2 = frp3;
291748cc5fe8SBram Moolenaar 			wp = frp3->fr_win;
291848cc5fe8SBram Moolenaar 			break;
291948cc5fe8SBram Moolenaar 		    }
292048cc5fe8SBram Moolenaar 		    frp3 = frp3->fr_next;
292148cc5fe8SBram Moolenaar 		}
292248cc5fe8SBram Moolenaar 	    }
292348cc5fe8SBram Moolenaar 	}
2924071d4279SBram Moolenaar 	frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
2925071d4279SBram Moolenaar 			    frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
2926071d4279SBram Moolenaar 	*dirp = 'v';
2927071d4279SBram Moolenaar     }
2928071d4279SBram Moolenaar     else
2929071d4279SBram Moolenaar     {
2930e38eab22SBram Moolenaar 	// When 'winfixwidth' is set, try to find another frame in the column
2931e38eab22SBram Moolenaar 	// (as close to the closed frame as possible) to distribute the width
2932e38eab22SBram Moolenaar 	// to.
293348cc5fe8SBram Moolenaar 	if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
293448cc5fe8SBram Moolenaar 	{
293548cc5fe8SBram Moolenaar 	    frp = frp_close->fr_prev;
293648cc5fe8SBram Moolenaar 	    frp3 = frp_close->fr_next;
293748cc5fe8SBram Moolenaar 	    while (frp != NULL || frp3 != NULL)
293848cc5fe8SBram Moolenaar 	    {
293948cc5fe8SBram Moolenaar 		if (frp != NULL)
294048cc5fe8SBram Moolenaar 		{
29419e1e358dSBram Moolenaar 		    if (!frame_fixed_width(frp))
294248cc5fe8SBram Moolenaar 		    {
294348cc5fe8SBram Moolenaar 			frp2 = frp;
29449e1e358dSBram Moolenaar 			wp = frame2win(frp2);
294548cc5fe8SBram Moolenaar 			break;
294648cc5fe8SBram Moolenaar 		    }
294748cc5fe8SBram Moolenaar 		    frp = frp->fr_prev;
294848cc5fe8SBram Moolenaar 		}
294948cc5fe8SBram Moolenaar 		if (frp3 != NULL)
295048cc5fe8SBram Moolenaar 		{
295148cc5fe8SBram Moolenaar 		    if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
295248cc5fe8SBram Moolenaar 		    {
295348cc5fe8SBram Moolenaar 			frp2 = frp3;
295448cc5fe8SBram Moolenaar 			wp = frp3->fr_win;
295548cc5fe8SBram Moolenaar 			break;
295648cc5fe8SBram Moolenaar 		    }
295748cc5fe8SBram Moolenaar 		    frp3 = frp3->fr_next;
295848cc5fe8SBram Moolenaar 		}
295948cc5fe8SBram Moolenaar 	    }
296048cc5fe8SBram Moolenaar 	}
2961071d4279SBram Moolenaar 	frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
2962be4d506bSBram Moolenaar 			    frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
2963071d4279SBram Moolenaar 	*dirp = 'h';
2964071d4279SBram Moolenaar     }
2965071d4279SBram Moolenaar 
2966e38eab22SBram Moolenaar     // If rows/columns go to a window below/right its positions need to be
2967e38eab22SBram Moolenaar     // updated.  Can only be done after the sizes have been updated.
2968071d4279SBram Moolenaar     if (frp2 == frp_close->fr_next)
2969071d4279SBram Moolenaar     {
2970071d4279SBram Moolenaar 	int row = win->w_winrow;
297153f8174eSBram Moolenaar 	int col = win->w_wincol;
2972071d4279SBram Moolenaar 
2973071d4279SBram Moolenaar 	frame_comp_pos(frp2, &row, &col);
2974071d4279SBram Moolenaar     }
2975071d4279SBram Moolenaar 
2976071d4279SBram Moolenaar     if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
2977071d4279SBram Moolenaar     {
2978e38eab22SBram Moolenaar 	// There is no other frame in this list, move its info to the parent
2979e38eab22SBram Moolenaar 	// and remove it.
2980071d4279SBram Moolenaar 	frp2->fr_parent->fr_layout = frp2->fr_layout;
2981071d4279SBram Moolenaar 	frp2->fr_parent->fr_child = frp2->fr_child;
29823d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, frp2->fr_child)
2983071d4279SBram Moolenaar 	    frp->fr_parent = frp2->fr_parent;
2984071d4279SBram Moolenaar 	frp2->fr_parent->fr_win = frp2->fr_win;
2985071d4279SBram Moolenaar 	if (frp2->fr_win != NULL)
2986071d4279SBram Moolenaar 	    frp2->fr_win->w_frame = frp2->fr_parent;
2987071d4279SBram Moolenaar 	frp = frp2->fr_parent;
29886f361c99SBram Moolenaar 	if (topframe->fr_child == frp2)
29896f361c99SBram Moolenaar 	    topframe->fr_child = frp;
2990071d4279SBram Moolenaar 	vim_free(frp2);
2991071d4279SBram Moolenaar 
2992071d4279SBram Moolenaar 	frp2 = frp->fr_parent;
2993071d4279SBram Moolenaar 	if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
2994071d4279SBram Moolenaar 	{
2995e38eab22SBram Moolenaar 	    // The frame above the parent has the same layout, have to merge
2996e38eab22SBram Moolenaar 	    // the frames into this list.
2997071d4279SBram Moolenaar 	    if (frp2->fr_child == frp)
2998071d4279SBram Moolenaar 		frp2->fr_child = frp->fr_child;
2999071d4279SBram Moolenaar 	    frp->fr_child->fr_prev = frp->fr_prev;
3000071d4279SBram Moolenaar 	    if (frp->fr_prev != NULL)
3001071d4279SBram Moolenaar 		frp->fr_prev->fr_next = frp->fr_child;
3002071d4279SBram Moolenaar 	    for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
3003071d4279SBram Moolenaar 	    {
3004071d4279SBram Moolenaar 		frp3->fr_parent = frp2;
3005071d4279SBram Moolenaar 		if (frp3->fr_next == NULL)
3006071d4279SBram Moolenaar 		{
3007071d4279SBram Moolenaar 		    frp3->fr_next = frp->fr_next;
3008071d4279SBram Moolenaar 		    if (frp->fr_next != NULL)
3009071d4279SBram Moolenaar 			frp->fr_next->fr_prev = frp3;
3010071d4279SBram Moolenaar 		    break;
3011071d4279SBram Moolenaar 		}
3012071d4279SBram Moolenaar 	    }
30136f361c99SBram Moolenaar 	    if (topframe->fr_child == frp)
30146f361c99SBram Moolenaar 		topframe->fr_child = frp2;
3015071d4279SBram Moolenaar 	    vim_free(frp);
3016071d4279SBram Moolenaar 	}
3017071d4279SBram Moolenaar     }
3018071d4279SBram Moolenaar 
3019071d4279SBram Moolenaar     return wp;
3020071d4279SBram Moolenaar }
3021071d4279SBram Moolenaar 
3022071d4279SBram Moolenaar /*
3023c136af29SBram Moolenaar  * Return a pointer to the frame that will receive the empty screen space that
3024c136af29SBram Moolenaar  * is left over after "win" is closed.
3025c136af29SBram Moolenaar  *
3026c136af29SBram Moolenaar  * If 'splitbelow' or 'splitright' is set, the space goes above or to the left
3027c136af29SBram Moolenaar  * by default.  Otherwise, the free space goes below or to the right.  The
3028c136af29SBram Moolenaar  * result is that opening a window and then immediately closing it will
3029c136af29SBram Moolenaar  * preserve the initial window layout.  The 'wfh' and 'wfw' settings are
3030c136af29SBram Moolenaar  * respected when possible.
3031071d4279SBram Moolenaar  */
3032071d4279SBram Moolenaar     static frame_T *
win_altframe(win_T * win,tabpage_T * tp)3033b638a7beSBram Moolenaar win_altframe(
3034b638a7beSBram Moolenaar     win_T	*win,
3035e38eab22SBram Moolenaar     tabpage_T	*tp)		// tab page "win" is in, NULL for current
3036071d4279SBram Moolenaar {
3037071d4279SBram Moolenaar     frame_T	*frp;
3038c136af29SBram Moolenaar     frame_T	*other_fr, *target_fr;
3039071d4279SBram Moolenaar 
3040a1f4cb93SBram Moolenaar     if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
30411d2ba7faSBram Moolenaar 	return alt_tabpage()->tp_curwin->w_frame;
30421d2ba7faSBram Moolenaar 
3043071d4279SBram Moolenaar     frp = win->w_frame;
3044c136af29SBram Moolenaar 
3045c136af29SBram Moolenaar     if (frp->fr_prev == NULL)
3046071d4279SBram Moolenaar 	return frp->fr_next;
3047c136af29SBram Moolenaar     if (frp->fr_next == NULL)
3048071d4279SBram Moolenaar 	return frp->fr_prev;
3049c136af29SBram Moolenaar 
3050edd327ccSBram Moolenaar     // By default the next window will get the space that was abandoned by this
3051edd327ccSBram Moolenaar     // window
3052c136af29SBram Moolenaar     target_fr = frp->fr_next;
3053c136af29SBram Moolenaar     other_fr  = frp->fr_prev;
3054edd327ccSBram Moolenaar 
3055edd327ccSBram Moolenaar     // If this is part of a column of windows and 'splitbelow' is true then the
3056edd327ccSBram Moolenaar     // previous window will get the space.
3057edd327ccSBram Moolenaar     if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_COL && p_sb)
3058edd327ccSBram Moolenaar     {
3059edd327ccSBram Moolenaar 	target_fr = frp->fr_prev;
3060edd327ccSBram Moolenaar 	other_fr  = frp->fr_next;
3061edd327ccSBram Moolenaar     }
3062edd327ccSBram Moolenaar 
3063edd327ccSBram Moolenaar     // If this is part of a row of windows, and 'splitright' is true then the
3064edd327ccSBram Moolenaar     // previous window will get the space.
3065edd327ccSBram Moolenaar     if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW && p_spr)
3066c136af29SBram Moolenaar     {
3067c136af29SBram Moolenaar 	target_fr = frp->fr_prev;
3068c136af29SBram Moolenaar 	other_fr  = frp->fr_next;
3069c136af29SBram Moolenaar     }
3070c136af29SBram Moolenaar 
3071e38eab22SBram Moolenaar     // If 'wfh' or 'wfw' is set for the target and not for the alternate
3072e38eab22SBram Moolenaar     // window, reverse the selection.
3073c136af29SBram Moolenaar     if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
3074c136af29SBram Moolenaar     {
3075c136af29SBram Moolenaar 	if (frame_fixed_width(target_fr) && !frame_fixed_width(other_fr))
3076c136af29SBram Moolenaar 	    target_fr = other_fr;
3077c136af29SBram Moolenaar     }
3078c136af29SBram Moolenaar     else
3079c136af29SBram Moolenaar     {
3080c136af29SBram Moolenaar 	if (frame_fixed_height(target_fr) && !frame_fixed_height(other_fr))
3081c136af29SBram Moolenaar 	    target_fr = other_fr;
3082c136af29SBram Moolenaar     }
3083c136af29SBram Moolenaar 
3084c136af29SBram Moolenaar     return target_fr;
3085071d4279SBram Moolenaar }
3086071d4279SBram Moolenaar 
3087071d4279SBram Moolenaar /*
30881d2ba7faSBram Moolenaar  * Return the tabpage that will be used if the current one is closed.
30891d2ba7faSBram Moolenaar  */
30901d2ba7faSBram Moolenaar     static tabpage_T *
alt_tabpage(void)3091b638a7beSBram Moolenaar alt_tabpage(void)
30921d2ba7faSBram Moolenaar {
309349d7bf13SBram Moolenaar     tabpage_T	*tp;
30941d2ba7faSBram Moolenaar 
3095e38eab22SBram Moolenaar     // Use the next tab page if possible.
309680a94a58SBram Moolenaar     if (curtab->tp_next != NULL)
309749d7bf13SBram Moolenaar 	return curtab->tp_next;
30981d2ba7faSBram Moolenaar 
3099e38eab22SBram Moolenaar     // Find the last but one tab page.
310080a94a58SBram Moolenaar     for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
310180a94a58SBram Moolenaar 	;
31021d2ba7faSBram Moolenaar     return tp;
31031d2ba7faSBram Moolenaar }
31041d2ba7faSBram Moolenaar 
31051d2ba7faSBram Moolenaar /*
3106071d4279SBram Moolenaar  * Find the left-upper window in frame "frp".
3107071d4279SBram Moolenaar  */
3108071d4279SBram Moolenaar     static win_T *
frame2win(frame_T * frp)3109b638a7beSBram Moolenaar frame2win(frame_T *frp)
3110071d4279SBram Moolenaar {
3111071d4279SBram Moolenaar     while (frp->fr_win == NULL)
3112071d4279SBram Moolenaar 	frp = frp->fr_child;
3113071d4279SBram Moolenaar     return frp->fr_win;
3114071d4279SBram Moolenaar }
3115071d4279SBram Moolenaar 
3116071d4279SBram Moolenaar /*
3117071d4279SBram Moolenaar  * Return TRUE if frame "frp" contains window "wp".
3118071d4279SBram Moolenaar  */
3119071d4279SBram Moolenaar     static int
frame_has_win(frame_T * frp,win_T * wp)3120b638a7beSBram Moolenaar frame_has_win(frame_T *frp, win_T *wp)
3121071d4279SBram Moolenaar {
3122071d4279SBram Moolenaar     frame_T	*p;
3123071d4279SBram Moolenaar 
3124071d4279SBram Moolenaar     if (frp->fr_layout == FR_LEAF)
3125071d4279SBram Moolenaar 	return frp->fr_win == wp;
3126071d4279SBram Moolenaar 
31273d1491edSBram Moolenaar     FOR_ALL_FRAMES(p, frp->fr_child)
3128071d4279SBram Moolenaar 	if (frame_has_win(p, wp))
3129071d4279SBram Moolenaar 	    return TRUE;
3130071d4279SBram Moolenaar     return FALSE;
3131071d4279SBram Moolenaar }
3132071d4279SBram Moolenaar 
3133071d4279SBram Moolenaar /*
3134071d4279SBram Moolenaar  * Set a new height for a frame.  Recursively sets the height for contained
3135071d4279SBram Moolenaar  * frames and windows.  Caller must take care of positions.
3136071d4279SBram Moolenaar  */
3137071d4279SBram Moolenaar     static void
frame_new_height(frame_T * topfrp,int height,int topfirst,int wfh)3138b638a7beSBram Moolenaar frame_new_height(
3139b638a7beSBram Moolenaar     frame_T	*topfrp,
3140b638a7beSBram Moolenaar     int		height,
3141e38eab22SBram Moolenaar     int		topfirst,	// resize topmost contained frame first
3142e38eab22SBram Moolenaar     int		wfh)		// obey 'winfixheight' when there is a choice;
3143e38eab22SBram Moolenaar 				// may cause the height not to be set
3144071d4279SBram Moolenaar {
3145071d4279SBram Moolenaar     frame_T	*frp;
3146071d4279SBram Moolenaar     int		extra_lines;
3147071d4279SBram Moolenaar     int		h;
3148071d4279SBram Moolenaar 
3149071d4279SBram Moolenaar     if (topfrp->fr_win != NULL)
3150071d4279SBram Moolenaar     {
3151e38eab22SBram Moolenaar 	// Simple case: just one window.
3152071d4279SBram Moolenaar 	win_new_height(topfrp->fr_win,
3153d326ad6eSBram Moolenaar 				    height - topfrp->fr_win->w_status_height
31543167c3e7SBram Moolenaar 					      - WINBAR_HEIGHT(topfrp->fr_win));
3155071d4279SBram Moolenaar     }
3156071d4279SBram Moolenaar     else if (topfrp->fr_layout == FR_ROW)
3157071d4279SBram Moolenaar     {
3158071d4279SBram Moolenaar 	do
3159071d4279SBram Moolenaar 	{
3160e38eab22SBram Moolenaar 	    // All frames in this row get the same new height.
31613d1491edSBram Moolenaar 	    FOR_ALL_FRAMES(frp, topfrp->fr_child)
3162071d4279SBram Moolenaar 	    {
3163071d4279SBram Moolenaar 		frame_new_height(frp, height, topfirst, wfh);
3164071d4279SBram Moolenaar 		if (frp->fr_height > height)
3165071d4279SBram Moolenaar 		{
3166e38eab22SBram Moolenaar 		    // Could not fit the windows, make the whole row higher.
3167071d4279SBram Moolenaar 		    height = frp->fr_height;
3168071d4279SBram Moolenaar 		    break;
3169071d4279SBram Moolenaar 		}
3170071d4279SBram Moolenaar 	    }
3171071d4279SBram Moolenaar 	}
3172071d4279SBram Moolenaar 	while (frp != NULL);
3173071d4279SBram Moolenaar     }
3174e38eab22SBram Moolenaar     else    // fr_layout == FR_COL
3175071d4279SBram Moolenaar     {
3176e38eab22SBram Moolenaar 	// Complicated case: Resize a column of frames.  Resize the bottom
3177e38eab22SBram Moolenaar 	// frame first, frames above that when needed.
3178071d4279SBram Moolenaar 
3179071d4279SBram Moolenaar 	frp = topfrp->fr_child;
3180071d4279SBram Moolenaar 	if (wfh)
3181e38eab22SBram Moolenaar 	    // Advance past frames with one window with 'wfh' set.
3182071d4279SBram Moolenaar 	    while (frame_fixed_height(frp))
3183071d4279SBram Moolenaar 	    {
3184071d4279SBram Moolenaar 		frp = frp->fr_next;
3185071d4279SBram Moolenaar 		if (frp == NULL)
3186e38eab22SBram Moolenaar 		    return;	    // no frame without 'wfh', give up
3187071d4279SBram Moolenaar 	    }
3188071d4279SBram Moolenaar 	if (!topfirst)
3189071d4279SBram Moolenaar 	{
3190e38eab22SBram Moolenaar 	    // Find the bottom frame of this column
3191071d4279SBram Moolenaar 	    while (frp->fr_next != NULL)
3192071d4279SBram Moolenaar 		frp = frp->fr_next;
3193071d4279SBram Moolenaar 	    if (wfh)
3194e38eab22SBram Moolenaar 		// Advance back for frames with one window with 'wfh' set.
3195071d4279SBram Moolenaar 		while (frame_fixed_height(frp))
3196071d4279SBram Moolenaar 		    frp = frp->fr_prev;
3197071d4279SBram Moolenaar 	}
3198071d4279SBram Moolenaar 
3199071d4279SBram Moolenaar 	extra_lines = height - topfrp->fr_height;
3200071d4279SBram Moolenaar 	if (extra_lines < 0)
3201071d4279SBram Moolenaar 	{
3202e38eab22SBram Moolenaar 	    // reduce height of contained frames, bottom or top frame first
3203071d4279SBram Moolenaar 	    while (frp != NULL)
3204071d4279SBram Moolenaar 	    {
3205071d4279SBram Moolenaar 		h = frame_minheight(frp, NULL);
3206071d4279SBram Moolenaar 		if (frp->fr_height + extra_lines < h)
3207071d4279SBram Moolenaar 		{
3208071d4279SBram Moolenaar 		    extra_lines += frp->fr_height - h;
3209071d4279SBram Moolenaar 		    frame_new_height(frp, h, topfirst, wfh);
3210071d4279SBram Moolenaar 		}
3211071d4279SBram Moolenaar 		else
3212071d4279SBram Moolenaar 		{
3213071d4279SBram Moolenaar 		    frame_new_height(frp, frp->fr_height + extra_lines,
3214071d4279SBram Moolenaar 							       topfirst, wfh);
3215071d4279SBram Moolenaar 		    break;
3216071d4279SBram Moolenaar 		}
3217071d4279SBram Moolenaar 		if (topfirst)
3218071d4279SBram Moolenaar 		{
3219071d4279SBram Moolenaar 		    do
3220071d4279SBram Moolenaar 			frp = frp->fr_next;
3221071d4279SBram Moolenaar 		    while (wfh && frp != NULL && frame_fixed_height(frp));
3222071d4279SBram Moolenaar 		}
3223071d4279SBram Moolenaar 		else
3224071d4279SBram Moolenaar 		{
3225071d4279SBram Moolenaar 		    do
3226071d4279SBram Moolenaar 			frp = frp->fr_prev;
3227071d4279SBram Moolenaar 		    while (wfh && frp != NULL && frame_fixed_height(frp));
3228071d4279SBram Moolenaar 		}
3229e38eab22SBram Moolenaar 		// Increase "height" if we could not reduce enough frames.
3230071d4279SBram Moolenaar 		if (frp == NULL)
3231071d4279SBram Moolenaar 		    height -= extra_lines;
3232071d4279SBram Moolenaar 	    }
3233071d4279SBram Moolenaar 	}
3234071d4279SBram Moolenaar 	else if (extra_lines > 0)
3235071d4279SBram Moolenaar 	{
3236e38eab22SBram Moolenaar 	    // increase height of bottom or top frame
3237071d4279SBram Moolenaar 	    frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
3238071d4279SBram Moolenaar 	}
3239071d4279SBram Moolenaar     }
3240071d4279SBram Moolenaar     topfrp->fr_height = height;
3241071d4279SBram Moolenaar }
3242071d4279SBram Moolenaar 
3243071d4279SBram Moolenaar /*
3244071d4279SBram Moolenaar  * Return TRUE if height of frame "frp" should not be changed because of
3245071d4279SBram Moolenaar  * the 'winfixheight' option.
3246071d4279SBram Moolenaar  */
3247071d4279SBram Moolenaar     static int
frame_fixed_height(frame_T * frp)3248b638a7beSBram Moolenaar frame_fixed_height(frame_T *frp)
3249071d4279SBram Moolenaar {
3250e38eab22SBram Moolenaar     // frame with one window: fixed height if 'winfixheight' set.
3251071d4279SBram Moolenaar     if (frp->fr_win != NULL)
3252071d4279SBram Moolenaar 	return frp->fr_win->w_p_wfh;
3253071d4279SBram Moolenaar 
3254071d4279SBram Moolenaar     if (frp->fr_layout == FR_ROW)
3255071d4279SBram Moolenaar     {
3256e38eab22SBram Moolenaar 	// The frame is fixed height if one of the frames in the row is fixed
3257e38eab22SBram Moolenaar 	// height.
32583d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, frp->fr_child)
3259071d4279SBram Moolenaar 	    if (frame_fixed_height(frp))
3260071d4279SBram Moolenaar 		return TRUE;
3261071d4279SBram Moolenaar 	return FALSE;
3262071d4279SBram Moolenaar     }
3263071d4279SBram Moolenaar 
3264e38eab22SBram Moolenaar     // frp->fr_layout == FR_COL: The frame is fixed height if all of the
3265e38eab22SBram Moolenaar     // frames in the row are fixed height.
32663d1491edSBram Moolenaar     FOR_ALL_FRAMES(frp, frp->fr_child)
3267071d4279SBram Moolenaar 	if (!frame_fixed_height(frp))
3268071d4279SBram Moolenaar 	    return FALSE;
3269071d4279SBram Moolenaar     return TRUE;
3270071d4279SBram Moolenaar }
3271071d4279SBram Moolenaar 
3272071d4279SBram Moolenaar /*
3273be4d506bSBram Moolenaar  * Return TRUE if width of frame "frp" should not be changed because of
3274be4d506bSBram Moolenaar  * the 'winfixwidth' option.
3275be4d506bSBram Moolenaar  */
3276be4d506bSBram Moolenaar     static int
frame_fixed_width(frame_T * frp)3277b638a7beSBram Moolenaar frame_fixed_width(frame_T *frp)
3278be4d506bSBram Moolenaar {
3279e38eab22SBram Moolenaar     // frame with one window: fixed width if 'winfixwidth' set.
3280be4d506bSBram Moolenaar     if (frp->fr_win != NULL)
3281be4d506bSBram Moolenaar 	return frp->fr_win->w_p_wfw;
3282be4d506bSBram Moolenaar 
3283be4d506bSBram Moolenaar     if (frp->fr_layout == FR_COL)
3284be4d506bSBram Moolenaar     {
3285e38eab22SBram Moolenaar 	// The frame is fixed width if one of the frames in the row is fixed
3286e38eab22SBram Moolenaar 	// width.
32873d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, frp->fr_child)
3288be4d506bSBram Moolenaar 	    if (frame_fixed_width(frp))
3289be4d506bSBram Moolenaar 		return TRUE;
3290be4d506bSBram Moolenaar 	return FALSE;
3291be4d506bSBram Moolenaar     }
3292be4d506bSBram Moolenaar 
3293e38eab22SBram Moolenaar     // frp->fr_layout == FR_ROW: The frame is fixed width if all of the
3294e38eab22SBram Moolenaar     // frames in the row are fixed width.
32953d1491edSBram Moolenaar     FOR_ALL_FRAMES(frp, frp->fr_child)
3296be4d506bSBram Moolenaar 	if (!frame_fixed_width(frp))
3297be4d506bSBram Moolenaar 	    return FALSE;
3298be4d506bSBram Moolenaar     return TRUE;
3299be4d506bSBram Moolenaar }
3300be4d506bSBram Moolenaar 
3301be4d506bSBram Moolenaar /*
3302071d4279SBram Moolenaar  * Add a status line to windows at the bottom of "frp".
3303071d4279SBram Moolenaar  * Note: Does not check if there is room!
3304071d4279SBram Moolenaar  */
3305071d4279SBram Moolenaar     static void
frame_add_statusline(frame_T * frp)3306b638a7beSBram Moolenaar frame_add_statusline(frame_T *frp)
3307071d4279SBram Moolenaar {
3308071d4279SBram Moolenaar     win_T	*wp;
3309071d4279SBram Moolenaar 
3310071d4279SBram Moolenaar     if (frp->fr_layout == FR_LEAF)
3311071d4279SBram Moolenaar     {
3312071d4279SBram Moolenaar 	wp = frp->fr_win;
3313071d4279SBram Moolenaar 	if (wp->w_status_height == 0)
3314071d4279SBram Moolenaar 	{
3315e38eab22SBram Moolenaar 	    if (wp->w_height > 0)	// don't make it negative
3316071d4279SBram Moolenaar 		--wp->w_height;
3317071d4279SBram Moolenaar 	    wp->w_status_height = STATUS_HEIGHT;
3318071d4279SBram Moolenaar 	}
3319071d4279SBram Moolenaar     }
3320071d4279SBram Moolenaar     else if (frp->fr_layout == FR_ROW)
3321071d4279SBram Moolenaar     {
3322e38eab22SBram Moolenaar 	// Handle all the frames in the row.
33233d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, frp->fr_child)
3324071d4279SBram Moolenaar 	    frame_add_statusline(frp);
3325071d4279SBram Moolenaar     }
3326e38eab22SBram Moolenaar     else // frp->fr_layout == FR_COL
3327071d4279SBram Moolenaar     {
3328e38eab22SBram Moolenaar 	// Only need to handle the last frame in the column.
3329071d4279SBram Moolenaar 	for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
3330071d4279SBram Moolenaar 	    ;
3331071d4279SBram Moolenaar 	frame_add_statusline(frp);
3332071d4279SBram Moolenaar     }
3333071d4279SBram Moolenaar }
3334071d4279SBram Moolenaar 
3335071d4279SBram Moolenaar /*
3336071d4279SBram Moolenaar  * Set width of a frame.  Handles recursively going through contained frames.
3337071d4279SBram Moolenaar  * May remove separator line for windows at the right side (for win_close()).
3338071d4279SBram Moolenaar  */
3339071d4279SBram Moolenaar     static void
frame_new_width(frame_T * topfrp,int width,int leftfirst,int wfw)3340b638a7beSBram Moolenaar frame_new_width(
3341b638a7beSBram Moolenaar     frame_T	*topfrp,
3342b638a7beSBram Moolenaar     int		width,
3343e38eab22SBram Moolenaar     int		leftfirst,	// resize leftmost contained frame first
3344e38eab22SBram Moolenaar     int		wfw)		// obey 'winfixwidth' when there is a choice;
3345e38eab22SBram Moolenaar 				// may cause the width not to be set
3346071d4279SBram Moolenaar {
3347071d4279SBram Moolenaar     frame_T	*frp;
3348071d4279SBram Moolenaar     int		extra_cols;
3349071d4279SBram Moolenaar     int		w;
3350071d4279SBram Moolenaar     win_T	*wp;
3351071d4279SBram Moolenaar 
3352071d4279SBram Moolenaar     if (topfrp->fr_layout == FR_LEAF)
3353071d4279SBram Moolenaar     {
3354e38eab22SBram Moolenaar 	// Simple case: just one window.
3355071d4279SBram Moolenaar 	wp = topfrp->fr_win;
3356e38eab22SBram Moolenaar 	// Find out if there are any windows right of this one.
3357071d4279SBram Moolenaar 	for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
3358071d4279SBram Moolenaar 	    if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
3359071d4279SBram Moolenaar 		break;
3360071d4279SBram Moolenaar 	if (frp->fr_parent == NULL)
3361071d4279SBram Moolenaar 	    wp->w_vsep_width = 0;
3362071d4279SBram Moolenaar 	win_new_width(wp, width - wp->w_vsep_width);
3363071d4279SBram Moolenaar     }
3364071d4279SBram Moolenaar     else if (topfrp->fr_layout == FR_COL)
3365071d4279SBram Moolenaar     {
3366be4d506bSBram Moolenaar 	do
3367be4d506bSBram Moolenaar 	{
3368e38eab22SBram Moolenaar 	    // All frames in this column get the same new width.
33693d1491edSBram Moolenaar 	    FOR_ALL_FRAMES(frp, topfrp->fr_child)
3370be4d506bSBram Moolenaar 	    {
3371be4d506bSBram Moolenaar 		frame_new_width(frp, width, leftfirst, wfw);
3372be4d506bSBram Moolenaar 		if (frp->fr_width > width)
3373be4d506bSBram Moolenaar 		{
3374e38eab22SBram Moolenaar 		    // Could not fit the windows, make whole column wider.
3375be4d506bSBram Moolenaar 		    width = frp->fr_width;
3376be4d506bSBram Moolenaar 		    break;
3377be4d506bSBram Moolenaar 		}
3378be4d506bSBram Moolenaar 	    }
3379be4d506bSBram Moolenaar 	} while (frp != NULL);
3380071d4279SBram Moolenaar     }
3381e38eab22SBram Moolenaar     else    // fr_layout == FR_ROW
3382071d4279SBram Moolenaar     {
3383e38eab22SBram Moolenaar 	// Complicated case: Resize a row of frames.  Resize the rightmost
3384e38eab22SBram Moolenaar 	// frame first, frames left of it when needed.
3385071d4279SBram Moolenaar 
3386071d4279SBram Moolenaar 	frp = topfrp->fr_child;
3387be4d506bSBram Moolenaar 	if (wfw)
3388e38eab22SBram Moolenaar 	    // Advance past frames with one window with 'wfw' set.
3389be4d506bSBram Moolenaar 	    while (frame_fixed_width(frp))
3390be4d506bSBram Moolenaar 	    {
3391be4d506bSBram Moolenaar 		frp = frp->fr_next;
3392be4d506bSBram Moolenaar 		if (frp == NULL)
3393e38eab22SBram Moolenaar 		    return;	    // no frame without 'wfw', give up
3394be4d506bSBram Moolenaar 	    }
3395071d4279SBram Moolenaar 	if (!leftfirst)
3396be4d506bSBram Moolenaar 	{
3397e38eab22SBram Moolenaar 	    // Find the rightmost frame of this row
3398071d4279SBram Moolenaar 	    while (frp->fr_next != NULL)
3399071d4279SBram Moolenaar 		frp = frp->fr_next;
3400be4d506bSBram Moolenaar 	    if (wfw)
3401e38eab22SBram Moolenaar 		// Advance back for frames with one window with 'wfw' set.
3402be4d506bSBram Moolenaar 		while (frame_fixed_width(frp))
3403be4d506bSBram Moolenaar 		    frp = frp->fr_prev;
3404be4d506bSBram Moolenaar 	}
3405071d4279SBram Moolenaar 
3406071d4279SBram Moolenaar 	extra_cols = width - topfrp->fr_width;
3407071d4279SBram Moolenaar 	if (extra_cols < 0)
3408071d4279SBram Moolenaar 	{
3409e38eab22SBram Moolenaar 	    // reduce frame width, rightmost frame first
3410071d4279SBram Moolenaar 	    while (frp != NULL)
3411071d4279SBram Moolenaar 	    {
3412071d4279SBram Moolenaar 		w = frame_minwidth(frp, NULL);
3413071d4279SBram Moolenaar 		if (frp->fr_width + extra_cols < w)
3414071d4279SBram Moolenaar 		{
3415071d4279SBram Moolenaar 		    extra_cols += frp->fr_width - w;
3416be4d506bSBram Moolenaar 		    frame_new_width(frp, w, leftfirst, wfw);
3417071d4279SBram Moolenaar 		}
3418071d4279SBram Moolenaar 		else
3419071d4279SBram Moolenaar 		{
3420be4d506bSBram Moolenaar 		    frame_new_width(frp, frp->fr_width + extra_cols,
3421be4d506bSBram Moolenaar 							      leftfirst, wfw);
3422071d4279SBram Moolenaar 		    break;
3423071d4279SBram Moolenaar 		}
3424071d4279SBram Moolenaar 		if (leftfirst)
3425be4d506bSBram Moolenaar 		{
3426be4d506bSBram Moolenaar 		    do
3427071d4279SBram Moolenaar 			frp = frp->fr_next;
3428be4d506bSBram Moolenaar 		    while (wfw && frp != NULL && frame_fixed_width(frp));
3429be4d506bSBram Moolenaar 		}
3430071d4279SBram Moolenaar 		else
3431be4d506bSBram Moolenaar 		{
3432be4d506bSBram Moolenaar 		    do
3433071d4279SBram Moolenaar 			frp = frp->fr_prev;
3434be4d506bSBram Moolenaar 		    while (wfw && frp != NULL && frame_fixed_width(frp));
3435be4d506bSBram Moolenaar 		}
3436e38eab22SBram Moolenaar 		// Increase "width" if we could not reduce enough frames.
3437be4d506bSBram Moolenaar 		if (frp == NULL)
3438be4d506bSBram Moolenaar 		    width -= extra_cols;
3439071d4279SBram Moolenaar 	    }
3440071d4279SBram Moolenaar 	}
3441071d4279SBram Moolenaar 	else if (extra_cols > 0)
3442071d4279SBram Moolenaar 	{
3443e38eab22SBram Moolenaar 	    // increase width of rightmost frame
3444be4d506bSBram Moolenaar 	    frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
3445071d4279SBram Moolenaar 	}
3446071d4279SBram Moolenaar     }
3447071d4279SBram Moolenaar     topfrp->fr_width = width;
3448071d4279SBram Moolenaar }
3449071d4279SBram Moolenaar 
3450071d4279SBram Moolenaar /*
3451071d4279SBram Moolenaar  * Add the vertical separator to windows at the right side of "frp".
3452071d4279SBram Moolenaar  * Note: Does not check if there is room!
3453071d4279SBram Moolenaar  */
3454071d4279SBram Moolenaar     static void
frame_add_vsep(frame_T * frp)3455b638a7beSBram Moolenaar frame_add_vsep(frame_T *frp)
3456071d4279SBram Moolenaar {
3457071d4279SBram Moolenaar     win_T	*wp;
3458071d4279SBram Moolenaar 
3459071d4279SBram Moolenaar     if (frp->fr_layout == FR_LEAF)
3460071d4279SBram Moolenaar     {
3461071d4279SBram Moolenaar 	wp = frp->fr_win;
3462071d4279SBram Moolenaar 	if (wp->w_vsep_width == 0)
3463071d4279SBram Moolenaar 	{
3464e38eab22SBram Moolenaar 	    if (wp->w_width > 0)	// don't make it negative
3465071d4279SBram Moolenaar 		--wp->w_width;
3466071d4279SBram Moolenaar 	    wp->w_vsep_width = 1;
3467071d4279SBram Moolenaar 	}
3468071d4279SBram Moolenaar     }
3469071d4279SBram Moolenaar     else if (frp->fr_layout == FR_COL)
3470071d4279SBram Moolenaar     {
3471e38eab22SBram Moolenaar 	// Handle all the frames in the column.
34723d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, frp->fr_child)
3473071d4279SBram Moolenaar 	    frame_add_vsep(frp);
3474071d4279SBram Moolenaar     }
3475e38eab22SBram Moolenaar     else // frp->fr_layout == FR_ROW
3476071d4279SBram Moolenaar     {
3477e38eab22SBram Moolenaar 	// Only need to handle the last frame in the row.
3478071d4279SBram Moolenaar 	frp = frp->fr_child;
3479071d4279SBram Moolenaar 	while (frp->fr_next != NULL)
3480071d4279SBram Moolenaar 	    frp = frp->fr_next;
3481071d4279SBram Moolenaar 	frame_add_vsep(frp);
3482071d4279SBram Moolenaar     }
3483071d4279SBram Moolenaar }
3484071d4279SBram Moolenaar 
3485071d4279SBram Moolenaar /*
3486071d4279SBram Moolenaar  * Set frame width from the window it contains.
3487071d4279SBram Moolenaar  */
3488071d4279SBram Moolenaar     static void
frame_fix_width(win_T * wp)3489b638a7beSBram Moolenaar frame_fix_width(win_T *wp)
3490071d4279SBram Moolenaar {
3491071d4279SBram Moolenaar     wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
3492071d4279SBram Moolenaar }
3493071d4279SBram Moolenaar 
3494071d4279SBram Moolenaar /*
3495071d4279SBram Moolenaar  * Set frame height from the window it contains.
3496071d4279SBram Moolenaar  */
3497071d4279SBram Moolenaar     static void
frame_fix_height(win_T * wp)3498b638a7beSBram Moolenaar frame_fix_height(win_T *wp)
3499071d4279SBram Moolenaar {
3500415a6939SBram Moolenaar     wp->w_frame->fr_height = VISIBLE_HEIGHT(wp) + wp->w_status_height;
3501071d4279SBram Moolenaar }
3502071d4279SBram Moolenaar 
3503071d4279SBram Moolenaar /*
3504071d4279SBram Moolenaar  * Compute the minimal height for frame "topfrp".
3505071d4279SBram Moolenaar  * Uses the 'winminheight' option.
3506071d4279SBram Moolenaar  * When "next_curwin" isn't NULL, use p_wh for this window.
3507071d4279SBram Moolenaar  * When "next_curwin" is NOWIN, don't use at least one line for the current
3508071d4279SBram Moolenaar  * window.
3509071d4279SBram Moolenaar  */
3510071d4279SBram Moolenaar     static int
frame_minheight(frame_T * topfrp,win_T * next_curwin)3511b638a7beSBram Moolenaar frame_minheight(frame_T *topfrp, win_T *next_curwin)
3512071d4279SBram Moolenaar {
3513071d4279SBram Moolenaar     frame_T	*frp;
3514071d4279SBram Moolenaar     int		m;
3515071d4279SBram Moolenaar     int		n;
3516071d4279SBram Moolenaar 
3517071d4279SBram Moolenaar     if (topfrp->fr_win != NULL)
3518071d4279SBram Moolenaar     {
3519071d4279SBram Moolenaar 	if (topfrp->fr_win == next_curwin)
3520071d4279SBram Moolenaar 	    m = p_wh + topfrp->fr_win->w_status_height;
3521071d4279SBram Moolenaar 	else
3522071d4279SBram Moolenaar 	{
3523e38eab22SBram Moolenaar 	    // window: minimal height of the window plus status line
3524071d4279SBram Moolenaar 	    m = p_wmh + topfrp->fr_win->w_status_height;
3525415a6939SBram Moolenaar 	    if (topfrp->fr_win == curwin && next_curwin == NULL)
3526415a6939SBram Moolenaar 	    {
3527e38eab22SBram Moolenaar 		// Current window is minimal one line high and WinBar is
3528e38eab22SBram Moolenaar 		// visible.
3529415a6939SBram Moolenaar 		if (p_wmh == 0)
3530071d4279SBram Moolenaar 		    ++m;
3531415a6939SBram Moolenaar 		m += WINBAR_HEIGHT(curwin);
3532415a6939SBram Moolenaar 	    }
3533071d4279SBram Moolenaar 	}
3534071d4279SBram Moolenaar     }
3535071d4279SBram Moolenaar     else if (topfrp->fr_layout == FR_ROW)
3536071d4279SBram Moolenaar     {
3537e38eab22SBram Moolenaar 	// get the minimal height from each frame in this row
3538071d4279SBram Moolenaar 	m = 0;
35393d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
3540071d4279SBram Moolenaar 	{
3541071d4279SBram Moolenaar 	    n = frame_minheight(frp, next_curwin);
3542071d4279SBram Moolenaar 	    if (n > m)
3543071d4279SBram Moolenaar 		m = n;
3544071d4279SBram Moolenaar 	}
3545071d4279SBram Moolenaar     }
3546071d4279SBram Moolenaar     else
3547071d4279SBram Moolenaar     {
3548e38eab22SBram Moolenaar 	// Add up the minimal heights for all frames in this column.
3549071d4279SBram Moolenaar 	m = 0;
35503d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
3551071d4279SBram Moolenaar 	    m += frame_minheight(frp, next_curwin);
3552071d4279SBram Moolenaar     }
3553071d4279SBram Moolenaar 
3554071d4279SBram Moolenaar     return m;
3555071d4279SBram Moolenaar }
3556071d4279SBram Moolenaar 
3557071d4279SBram Moolenaar /*
3558071d4279SBram Moolenaar  * Compute the minimal width for frame "topfrp".
3559071d4279SBram Moolenaar  * When "next_curwin" isn't NULL, use p_wiw for this window.
3560071d4279SBram Moolenaar  * When "next_curwin" is NOWIN, don't use at least one column for the current
3561071d4279SBram Moolenaar  * window.
3562071d4279SBram Moolenaar  */
3563071d4279SBram Moolenaar     static int
frame_minwidth(frame_T * topfrp,win_T * next_curwin)3564b638a7beSBram Moolenaar frame_minwidth(
3565b638a7beSBram Moolenaar     frame_T	*topfrp,
3566e38eab22SBram Moolenaar     win_T	*next_curwin)	// use p_wh and p_wiw for next_curwin
3567071d4279SBram Moolenaar {
3568071d4279SBram Moolenaar     frame_T	*frp;
3569071d4279SBram Moolenaar     int		m, n;
3570071d4279SBram Moolenaar 
3571071d4279SBram Moolenaar     if (topfrp->fr_win != NULL)
3572071d4279SBram Moolenaar     {
3573071d4279SBram Moolenaar 	if (topfrp->fr_win == next_curwin)
3574071d4279SBram Moolenaar 	    m = p_wiw + topfrp->fr_win->w_vsep_width;
3575071d4279SBram Moolenaar 	else
3576071d4279SBram Moolenaar 	{
3577e38eab22SBram Moolenaar 	    // window: minimal width of the window plus separator column
3578071d4279SBram Moolenaar 	    m = p_wmw + topfrp->fr_win->w_vsep_width;
3579e38eab22SBram Moolenaar 	    // Current window is minimal one column wide
3580071d4279SBram Moolenaar 	    if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
3581071d4279SBram Moolenaar 		++m;
3582071d4279SBram Moolenaar 	}
3583071d4279SBram Moolenaar     }
3584071d4279SBram Moolenaar     else if (topfrp->fr_layout == FR_COL)
3585071d4279SBram Moolenaar     {
3586e38eab22SBram Moolenaar 	// get the minimal width from each frame in this column
3587071d4279SBram Moolenaar 	m = 0;
35883d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
3589071d4279SBram Moolenaar 	{
3590071d4279SBram Moolenaar 	    n = frame_minwidth(frp, next_curwin);
3591071d4279SBram Moolenaar 	    if (n > m)
3592071d4279SBram Moolenaar 		m = n;
3593071d4279SBram Moolenaar 	}
3594071d4279SBram Moolenaar     }
3595071d4279SBram Moolenaar     else
3596071d4279SBram Moolenaar     {
3597e38eab22SBram Moolenaar 	// Add up the minimal widths for all frames in this row.
3598071d4279SBram Moolenaar 	m = 0;
35993d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
3600071d4279SBram Moolenaar 	    m += frame_minwidth(frp, next_curwin);
3601071d4279SBram Moolenaar     }
3602071d4279SBram Moolenaar 
3603071d4279SBram Moolenaar     return m;
3604071d4279SBram Moolenaar }
3605071d4279SBram Moolenaar 
3606071d4279SBram Moolenaar 
3607071d4279SBram Moolenaar /*
3608071d4279SBram Moolenaar  * Try to close all windows except current one.
3609071d4279SBram Moolenaar  * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
3610071d4279SBram Moolenaar  * used and the buffer was modified.
3611071d4279SBram Moolenaar  *
3612071d4279SBram Moolenaar  * Used by ":bdel" and ":only".
3613071d4279SBram Moolenaar  */
3614071d4279SBram Moolenaar     void
close_others(int message,int forceit)3615b638a7beSBram Moolenaar close_others(
3616b638a7beSBram Moolenaar     int		message,
3617e38eab22SBram Moolenaar     int		forceit)	    // always hide all other windows
3618071d4279SBram Moolenaar {
3619071d4279SBram Moolenaar     win_T	*wp;
3620071d4279SBram Moolenaar     win_T	*nextwp;
3621071d4279SBram Moolenaar     int		r;
3622071d4279SBram Moolenaar 
3623746ebd3bSBram Moolenaar     if (one_window())
3624071d4279SBram Moolenaar     {
3625f2bd8ef2SBram Moolenaar 	if (message && !autocmd_busy)
362632526b3cSBram Moolenaar 	    msg(_(m_onlyone));
3627071d4279SBram Moolenaar 	return;
3628071d4279SBram Moolenaar     }
3629071d4279SBram Moolenaar 
3630e38eab22SBram Moolenaar     // Be very careful here: autocommands may change the window layout.
3631071d4279SBram Moolenaar     for (wp = firstwin; win_valid(wp); wp = nextwp)
3632071d4279SBram Moolenaar     {
3633071d4279SBram Moolenaar 	nextwp = wp->w_next;
3634e38eab22SBram Moolenaar 	if (wp != curwin)		// don't close current window
3635071d4279SBram Moolenaar 	{
3636071d4279SBram Moolenaar 
3637e38eab22SBram Moolenaar 	    // Check if it's allowed to abandon this window
3638071d4279SBram Moolenaar 	    r = can_abandon(wp->w_buffer, forceit);
3639e38eab22SBram Moolenaar 	    if (!win_valid(wp))		// autocommands messed wp up
3640071d4279SBram Moolenaar 	    {
3641071d4279SBram Moolenaar 		nextwp = firstwin;
3642071d4279SBram Moolenaar 		continue;
3643071d4279SBram Moolenaar 	    }
3644071d4279SBram Moolenaar 	    if (!r)
3645071d4279SBram Moolenaar 	    {
3646071d4279SBram Moolenaar #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3647e1004401SBram Moolenaar 		if (message && (p_confirm
3648e1004401SBram Moolenaar 			     || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
3649071d4279SBram Moolenaar 		{
3650071d4279SBram Moolenaar 		    dialog_changed(wp->w_buffer, FALSE);
3651e38eab22SBram Moolenaar 		    if (!win_valid(wp))		// autocommands messed wp up
3652071d4279SBram Moolenaar 		    {
3653071d4279SBram Moolenaar 			nextwp = firstwin;
3654071d4279SBram Moolenaar 			continue;
3655071d4279SBram Moolenaar 		    }
3656071d4279SBram Moolenaar 		}
3657071d4279SBram Moolenaar 		if (bufIsChanged(wp->w_buffer))
3658071d4279SBram Moolenaar #endif
3659071d4279SBram Moolenaar 		    continue;
3660071d4279SBram Moolenaar 	    }
3661eb44a68bSBram Moolenaar 	    win_close(wp, !buf_hide(wp->w_buffer)
3662eb44a68bSBram Moolenaar 					       && !bufIsChanged(wp->w_buffer));
3663071d4279SBram Moolenaar 	}
3664071d4279SBram Moolenaar     }
3665071d4279SBram Moolenaar 
3666459ca563SBram Moolenaar     if (message && !ONE_WINDOW)
3667f9e3e09fSBram Moolenaar 	emsg(_("E445: Other window contains changes"));
3668071d4279SBram Moolenaar }
3669071d4279SBram Moolenaar 
36705843f5f3SBram Moolenaar     static void
win_init_empty(win_T * wp)3671b638a7beSBram Moolenaar win_init_empty(win_T *wp)
3672f061e0beSBram Moolenaar {
3673f061e0beSBram Moolenaar     redraw_win_later(wp, NOT_VALID);
3674f061e0beSBram Moolenaar     wp->w_lines_valid = 0;
3675f061e0beSBram Moolenaar     wp->w_cursor.lnum = 1;
3676f061e0beSBram Moolenaar     wp->w_curswant = wp->w_cursor.col = 0;
3677f061e0beSBram Moolenaar     wp->w_cursor.coladd = 0;
3678e38eab22SBram Moolenaar     wp->w_pcmark.lnum = 1;	// pcmark not cleared but set to line 1
3679f061e0beSBram Moolenaar     wp->w_pcmark.col = 0;
3680f061e0beSBram Moolenaar     wp->w_prev_pcmark.lnum = 0;
3681f061e0beSBram Moolenaar     wp->w_prev_pcmark.col = 0;
3682f061e0beSBram Moolenaar     wp->w_topline = 1;
3683071d4279SBram Moolenaar #ifdef FEAT_DIFF
3684f061e0beSBram Moolenaar     wp->w_topfill = 0;
3685071d4279SBram Moolenaar #endif
3686f061e0beSBram Moolenaar     wp->w_botline = 2;
36874d784b21SBram Moolenaar #if defined(FEAT_SYN_HL) || defined(FEAT_SPELL)
3688a971b82bSBram Moolenaar     wp->w_s = &wp->w_buffer->b_s;
3689a971b82bSBram Moolenaar #endif
3690*87fd0924SBram Moolenaar #ifdef FEAT_TERMINAL
3691*87fd0924SBram Moolenaar     term_reset_wincolor(wp);
3692*87fd0924SBram Moolenaar #endif
3693071d4279SBram Moolenaar }
3694071d4279SBram Moolenaar 
3695071d4279SBram Moolenaar /*
36965843f5f3SBram Moolenaar  * Init the current window "curwin".
36975843f5f3SBram Moolenaar  * Called when a new file is being edited.
36985843f5f3SBram Moolenaar  */
36995843f5f3SBram Moolenaar     void
curwin_init(void)37005843f5f3SBram Moolenaar curwin_init(void)
37015843f5f3SBram Moolenaar {
37025843f5f3SBram Moolenaar     win_init_empty(curwin);
37035843f5f3SBram Moolenaar }
37045843f5f3SBram Moolenaar 
37055843f5f3SBram Moolenaar /*
3706071d4279SBram Moolenaar  * Allocate the first window and put an empty buffer in it.
3707071d4279SBram Moolenaar  * Called from main().
37081d2ba7faSBram Moolenaar  * Return FAIL when something goes wrong (out of memory).
3709071d4279SBram Moolenaar  */
37101d2ba7faSBram Moolenaar     int
win_alloc_first(void)3711b638a7beSBram Moolenaar win_alloc_first(void)
3712071d4279SBram Moolenaar {
37132a0449d1SBram Moolenaar     if (win_alloc_firstwin(NULL) == FAIL)
37141d2ba7faSBram Moolenaar 	return FAIL;
37151d2ba7faSBram Moolenaar 
371649d7bf13SBram Moolenaar     first_tabpage = alloc_tabpage();
37171d2ba7faSBram Moolenaar     if (first_tabpage == NULL)
37181d2ba7faSBram Moolenaar 	return FAIL;
37191d2ba7faSBram Moolenaar     first_tabpage->tp_topframe = topframe;
372049d7bf13SBram Moolenaar     curtab = first_tabpage;
3721a44b3eeaSBram Moolenaar     curtab->tp_firstwin = firstwin;
3722a44b3eeaSBram Moolenaar     curtab->tp_lastwin = lastwin;
3723a44b3eeaSBram Moolenaar     curtab->tp_curwin = curwin;
3724746ebd3bSBram Moolenaar 
37251d2ba7faSBram Moolenaar     return OK;
37261d2ba7faSBram Moolenaar }
37271d2ba7faSBram Moolenaar 
3728746ebd3bSBram Moolenaar /*
37294d784b21SBram Moolenaar  * Allocate and init a window that is not a regular window.
37304d784b21SBram Moolenaar  * This can only be done after the first window is fully initialized, thus it
37314d784b21SBram Moolenaar  * can't be in win_alloc_first().
37324d784b21SBram Moolenaar  */
37334d784b21SBram Moolenaar     win_T *
win_alloc_popup_win(void)37344d784b21SBram Moolenaar win_alloc_popup_win(void)
37354d784b21SBram Moolenaar {
37364d784b21SBram Moolenaar     win_T *wp;
37374d784b21SBram Moolenaar 
37384d784b21SBram Moolenaar     wp = win_alloc(NULL, TRUE);
37394d784b21SBram Moolenaar     if (wp != NULL)
37404d784b21SBram Moolenaar     {
37414d784b21SBram Moolenaar 	// We need to initialize options with something, using the current
37424d784b21SBram Moolenaar 	// window makes most sense.
37434d784b21SBram Moolenaar 	win_init_some(wp, curwin);
37444d784b21SBram Moolenaar 
37454d784b21SBram Moolenaar 	RESET_BINDING(wp);
37464d784b21SBram Moolenaar 	new_frame(wp);
37474d784b21SBram Moolenaar     }
37484d784b21SBram Moolenaar     return wp;
37494d784b21SBram Moolenaar }
37504d784b21SBram Moolenaar 
37514d784b21SBram Moolenaar /*
37524d784b21SBram Moolenaar  * Initialize window "wp" to display buffer "buf".
3753746ebd3bSBram Moolenaar  */
3754746ebd3bSBram Moolenaar     void
win_init_popup_win(win_T * wp,buf_T * buf)37554d784b21SBram Moolenaar win_init_popup_win(win_T *wp, buf_T *buf)
3756746ebd3bSBram Moolenaar {
37574d784b21SBram Moolenaar     wp->w_buffer = buf;
37584d784b21SBram Moolenaar     ++buf->b_nwindows;
37594d784b21SBram Moolenaar     win_init_empty(wp); // set cursor and topline to safe values
37604d784b21SBram Moolenaar 
37614d784b21SBram Moolenaar     // Make sure w_localdir and globaldir are NULL to avoid a chdir() in
37624d784b21SBram Moolenaar     // win_enter_ext().
37634d784b21SBram Moolenaar     VIM_CLEAR(wp->w_localdir);
3764746ebd3bSBram Moolenaar }
3765746ebd3bSBram Moolenaar 
37661d2ba7faSBram Moolenaar /*
37672a0449d1SBram Moolenaar  * Allocate the first window or the first window in a new tab page.
37682a0449d1SBram Moolenaar  * When "oldwin" is NULL create an empty buffer for it.
37694033c55eSBram Moolenaar  * When "oldwin" is not NULL copy info from it to the new window.
37701d2ba7faSBram Moolenaar  * Return FAIL when something goes wrong (out of memory).
37711d2ba7faSBram Moolenaar  */
37721d2ba7faSBram Moolenaar     static int
win_alloc_firstwin(win_T * oldwin)3773b638a7beSBram Moolenaar win_alloc_firstwin(win_T *oldwin)
37741d2ba7faSBram Moolenaar {
3775746ebd3bSBram Moolenaar     curwin = win_alloc(NULL, FALSE);
37762a0449d1SBram Moolenaar     if (oldwin == NULL)
37772a0449d1SBram Moolenaar     {
3778e38eab22SBram Moolenaar 	// Very first window, need to create an empty buffer for it and
3779e38eab22SBram Moolenaar 	// initialize from scratch.
3780071d4279SBram Moolenaar 	curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
3781071d4279SBram Moolenaar 	if (curwin == NULL || curbuf == NULL)
37821d2ba7faSBram Moolenaar 	    return FAIL;
3783071d4279SBram Moolenaar 	curwin->w_buffer = curbuf;
3784860cae1cSBram Moolenaar #ifdef FEAT_SYN_HL
3785860cae1cSBram Moolenaar 	curwin->w_s = &(curbuf->b_s);
3786860cae1cSBram Moolenaar #endif
3787e38eab22SBram Moolenaar 	curbuf->b_nwindows = 1;	// there is one window
3788071d4279SBram Moolenaar 	curwin->w_alist = &global_alist;
3789e38eab22SBram Moolenaar 	curwin_init();		// init current window
37902a0449d1SBram Moolenaar     }
37912a0449d1SBram Moolenaar     else
37922a0449d1SBram Moolenaar     {
3793e38eab22SBram Moolenaar 	// First window in new tab page, initialize it from "oldwin".
3794884ae644SBram Moolenaar 	win_init(curwin, oldwin, 0);
37952a0449d1SBram Moolenaar 
3796e38eab22SBram Moolenaar 	// We don't want cursor- and scroll-binding in the first window.
37973368ea21SBram Moolenaar 	RESET_BINDING(curwin);
37982a0449d1SBram Moolenaar     }
3799071d4279SBram Moolenaar 
3800746ebd3bSBram Moolenaar     new_frame(curwin);
3801746ebd3bSBram Moolenaar     if (curwin->w_frame == NULL)
38021d2ba7faSBram Moolenaar 	return FAIL;
3803746ebd3bSBram Moolenaar     topframe = curwin->w_frame;
3804071d4279SBram Moolenaar     topframe->fr_width = Columns;
3805071d4279SBram Moolenaar     topframe->fr_height = Rows - p_ch;
38061d2ba7faSBram Moolenaar 
38071d2ba7faSBram Moolenaar     return OK;
38081d2ba7faSBram Moolenaar }
38091d2ba7faSBram Moolenaar 
38101d2ba7faSBram Moolenaar /*
3811746ebd3bSBram Moolenaar  * Create a frame for window "wp".
3812746ebd3bSBram Moolenaar  */
3813746ebd3bSBram Moolenaar     static void
new_frame(win_T * wp)3814746ebd3bSBram Moolenaar new_frame(win_T *wp)
3815746ebd3bSBram Moolenaar {
3816c799fe20SBram Moolenaar     frame_T *frp = ALLOC_CLEAR_ONE(frame_T);
3817746ebd3bSBram Moolenaar 
3818746ebd3bSBram Moolenaar     wp->w_frame = frp;
3819746ebd3bSBram Moolenaar     if (frp != NULL)
3820746ebd3bSBram Moolenaar     {
3821746ebd3bSBram Moolenaar 	frp->fr_layout = FR_LEAF;
3822746ebd3bSBram Moolenaar 	frp->fr_win = wp;
3823746ebd3bSBram Moolenaar     }
3824746ebd3bSBram Moolenaar }
3825746ebd3bSBram Moolenaar 
3826746ebd3bSBram Moolenaar /*
38271d2ba7faSBram Moolenaar  * Initialize the window and frame size to the maximum.
38281d2ba7faSBram Moolenaar  */
38291d2ba7faSBram Moolenaar     void
win_init_size(void)3830b638a7beSBram Moolenaar win_init_size(void)
38311d2ba7faSBram Moolenaar {
38321d2ba7faSBram Moolenaar     firstwin->w_height = ROWS_AVAIL;
38331d2ba7faSBram Moolenaar     topframe->fr_height = ROWS_AVAIL;
38341d2ba7faSBram Moolenaar     firstwin->w_width = Columns;
38351d2ba7faSBram Moolenaar     topframe->fr_width = Columns;
3836071d4279SBram Moolenaar }
3837071d4279SBram Moolenaar 
383849d7bf13SBram Moolenaar /*
383949d7bf13SBram Moolenaar  * Allocate a new tabpage_T and init the values.
384049d7bf13SBram Moolenaar  * Returns NULL when out of memory.
384149d7bf13SBram Moolenaar  */
384249d7bf13SBram Moolenaar     static tabpage_T *
alloc_tabpage(void)3843b638a7beSBram Moolenaar alloc_tabpage(void)
384449d7bf13SBram Moolenaar {
384549d7bf13SBram Moolenaar     tabpage_T	*tp;
3846371d5403SBram Moolenaar # ifdef FEAT_GUI
3847371d5403SBram Moolenaar     int		i;
3848429fa853SBram Moolenaar # endif
3849371d5403SBram Moolenaar 
3850429fa853SBram Moolenaar 
3851c799fe20SBram Moolenaar     tp = ALLOC_CLEAR_ONE(tabpage_T);
3852429fa853SBram Moolenaar     if (tp == NULL)
3853429fa853SBram Moolenaar 	return NULL;
3854429fa853SBram Moolenaar 
3855429fa853SBram Moolenaar # ifdef FEAT_EVAL
3856e38eab22SBram Moolenaar     // init t: variables
3857429fa853SBram Moolenaar     tp->tp_vars = dict_alloc();
3858429fa853SBram Moolenaar     if (tp->tp_vars == NULL)
3859429fa853SBram Moolenaar     {
3860429fa853SBram Moolenaar 	vim_free(tp);
3861429fa853SBram Moolenaar 	return NULL;
3862429fa853SBram Moolenaar     }
3863429fa853SBram Moolenaar     init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
3864429fa853SBram Moolenaar # endif
3865429fa853SBram Moolenaar 
3866429fa853SBram Moolenaar # ifdef FEAT_GUI
3867371d5403SBram Moolenaar     for (i = 0; i < 3; i++)
3868371d5403SBram Moolenaar 	tp->tp_prev_which_scrollbars[i] = -1;
3869371d5403SBram Moolenaar # endif
387049d7bf13SBram Moolenaar # ifdef FEAT_DIFF
387149d7bf13SBram Moolenaar     tp->tp_diff_invalid = TRUE;
387249d7bf13SBram Moolenaar # endif
3873c6fe9195SBram Moolenaar     tp->tp_ch_used = p_ch;
3874429fa853SBram Moolenaar 
387549d7bf13SBram Moolenaar     return tp;
387649d7bf13SBram Moolenaar }
387749d7bf13SBram Moolenaar 
3878d8fc5c0bSBram Moolenaar     void
free_tabpage(tabpage_T * tp)3879b638a7beSBram Moolenaar free_tabpage(tabpage_T *tp)
388049d7bf13SBram Moolenaar {
3881746ebd3bSBram Moolenaar     int idx;
3882746ebd3bSBram Moolenaar 
388349d7bf13SBram Moolenaar # ifdef FEAT_DIFF
388449d7bf13SBram Moolenaar     diff_clear(tp);
388549d7bf13SBram Moolenaar # endif
388605ad5ff0SBram Moolenaar # ifdef FEAT_PROP_POPUP
38879c27b1c6SBram Moolenaar     while (tp->tp_first_popupwin != NULL)
388803a9f848SBram Moolenaar 	popup_close_tabpage(tp, tp->tp_first_popupwin->w_id, TRUE);
38894d784b21SBram Moolenaar #endif
3890746ebd3bSBram Moolenaar     for (idx = 0; idx < SNAP_COUNT; ++idx)
3891746ebd3bSBram Moolenaar 	clear_snapshot(tp, idx);
3892910f66f9SBram Moolenaar #ifdef FEAT_EVAL
3893e38eab22SBram Moolenaar     vars_clear(&tp->tp_vars->dv_hashtab);	// free all t: variables
3894429fa853SBram Moolenaar     hash_init(&tp->tp_vars->dv_hashtab);
3895429fa853SBram Moolenaar     unref_var_dict(tp->tp_vars);
3896910f66f9SBram Moolenaar #endif
38975e538ecdSBram Moolenaar 
389862a23250SBram Moolenaar     if (tp == lastused_tabpage)
389962a23250SBram Moolenaar 	lastused_tabpage = NULL;
390062a23250SBram Moolenaar 
390100aa069dSBram Moolenaar     vim_free(tp->tp_localdir);
3902002bc799SBram Moolenaar     vim_free(tp->tp_prevdir);
390300aa069dSBram Moolenaar 
39045e538ecdSBram Moolenaar #ifdef FEAT_PYTHON
39055e538ecdSBram Moolenaar     python_tabpage_free(tp);
39065e538ecdSBram Moolenaar #endif
39075e538ecdSBram Moolenaar 
39085e538ecdSBram Moolenaar #ifdef FEAT_PYTHON3
39095e538ecdSBram Moolenaar     python3_tabpage_free(tp);
39105e538ecdSBram Moolenaar #endif
39115e538ecdSBram Moolenaar 
391249d7bf13SBram Moolenaar     vim_free(tp);
391349d7bf13SBram Moolenaar }
391449d7bf13SBram Moolenaar 
39151d2ba7faSBram Moolenaar /*
39162a0449d1SBram Moolenaar  * Create a new Tab page with one window.
39172a0449d1SBram Moolenaar  * It will edit the current buffer, like after ":split".
391880a94a58SBram Moolenaar  * When "after" is 0 put it just after the current Tab page.
391980a94a58SBram Moolenaar  * Otherwise put it just before tab page "after".
39201d2ba7faSBram Moolenaar  * Return FAIL or OK.
39211d2ba7faSBram Moolenaar  */
39221d2ba7faSBram Moolenaar     int
win_new_tabpage(int after)3923b638a7beSBram Moolenaar win_new_tabpage(int after)
39241d2ba7faSBram Moolenaar {
392549d7bf13SBram Moolenaar     tabpage_T	*tp = curtab;
392694f4ffa7SBram Moolenaar     tabpage_T	*prev_tp = curtab;
39271d2ba7faSBram Moolenaar     tabpage_T	*newtp;
392880a94a58SBram Moolenaar     int		n;
39291d2ba7faSBram Moolenaar 
393049d7bf13SBram Moolenaar     newtp = alloc_tabpage();
39311d2ba7faSBram Moolenaar     if (newtp == NULL)
39321d2ba7faSBram Moolenaar 	return FAIL;
39331d2ba7faSBram Moolenaar 
3934e38eab22SBram Moolenaar     // Remember the current windows in this Tab page.
393549e649fcSBram Moolenaar     if (leave_tabpage(curbuf, TRUE) == FAIL)
39367e8fd636SBram Moolenaar     {
39377e8fd636SBram Moolenaar 	vim_free(newtp);
39387e8fd636SBram Moolenaar 	return FAIL;
39397e8fd636SBram Moolenaar     }
394049d7bf13SBram Moolenaar     curtab = newtp;
39411d2ba7faSBram Moolenaar 
394200aa069dSBram Moolenaar     newtp->tp_localdir = (tp->tp_localdir == NULL)
394300aa069dSBram Moolenaar 				    ? NULL : vim_strsave(tp->tp_localdir);
3944e38eab22SBram Moolenaar     // Create a new empty window.
39452a0449d1SBram Moolenaar     if (win_alloc_firstwin(tp->tp_curwin) == OK)
39461d2ba7faSBram Moolenaar     {
3947e38eab22SBram Moolenaar 	// Make the new Tab page the new topframe.
394880a94a58SBram Moolenaar 	if (after == 1)
394980a94a58SBram Moolenaar 	{
3950e38eab22SBram Moolenaar 	    // New tab page becomes the first one.
395180a94a58SBram Moolenaar 	    newtp->tp_next = first_tabpage;
395280a94a58SBram Moolenaar 	    first_tabpage = newtp;
395380a94a58SBram Moolenaar 	}
395480a94a58SBram Moolenaar 	else
395580a94a58SBram Moolenaar 	{
395680a94a58SBram Moolenaar 	    if (after > 0)
395780a94a58SBram Moolenaar 	    {
3958e38eab22SBram Moolenaar 		// Put new tab page before tab page "after".
395980a94a58SBram Moolenaar 		n = 2;
396080a94a58SBram Moolenaar 		for (tp = first_tabpage; tp->tp_next != NULL
396180a94a58SBram Moolenaar 					       && n < after; tp = tp->tp_next)
396280a94a58SBram Moolenaar 		    ++n;
396380a94a58SBram Moolenaar 	    }
39641d2ba7faSBram Moolenaar 	    newtp->tp_next = tp->tp_next;
39651d2ba7faSBram Moolenaar 	    tp->tp_next = newtp;
396680a94a58SBram Moolenaar 	}
3967a44b3eeaSBram Moolenaar 	newtp->tp_firstwin = newtp->tp_lastwin = newtp->tp_curwin = curwin;
3968a44b3eeaSBram Moolenaar 
39691d2ba7faSBram Moolenaar 	win_init_size();
397032466aa2SBram Moolenaar 	firstwin->w_winrow = tabline_height();
3971910f66f9SBram Moolenaar 	win_comp_scroll(curwin);
39721d2ba7faSBram Moolenaar 
39731d2ba7faSBram Moolenaar 	newtp->tp_topframe = topframe;
3974f740b29aSBram Moolenaar 	last_status(FALSE);
3975607a95edSBram Moolenaar 
397694f4ffa7SBram Moolenaar 	lastused_tabpage = prev_tp;
397762a23250SBram Moolenaar 
3978607a95edSBram Moolenaar #if defined(FEAT_GUI)
3979e38eab22SBram Moolenaar 	// When 'guioptions' includes 'L' or 'R' may have to remove or add
3980e38eab22SBram Moolenaar 	// scrollbars.  Have to update them anyway.
3981746ebd3bSBram Moolenaar 	gui_may_update_scrollbars();
3982607a95edSBram Moolenaar #endif
39836d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
39846d41c78eSBram Moolenaar 	entering_window(curwin);
39856d41c78eSBram Moolenaar #endif
3986607a95edSBram Moolenaar 
3987bf3250a8SBram Moolenaar 	redraw_all_later(NOT_VALID);
3988c917da4bSBram Moolenaar 	apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
39892a0449d1SBram Moolenaar 	apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
3990c917da4bSBram Moolenaar 	apply_autocmds(EVENT_TABNEW, NULL, NULL, FALSE, curbuf);
399149e649fcSBram Moolenaar 	apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
39921d2ba7faSBram Moolenaar 	return OK;
39931d2ba7faSBram Moolenaar     }
39941d2ba7faSBram Moolenaar 
3995e38eab22SBram Moolenaar     // Failed, get back the previous Tab page
399649e649fcSBram Moolenaar     enter_tabpage(curtab, curbuf, TRUE, TRUE);
39971d2ba7faSBram Moolenaar     return FAIL;
39981d2ba7faSBram Moolenaar }
39991d2ba7faSBram Moolenaar 
40001d2ba7faSBram Moolenaar /*
400180a94a58SBram Moolenaar  * Open a new tab page if ":tab cmd" was used.  It will edit the same buffer,
400280a94a58SBram Moolenaar  * like with ":split".
400380a94a58SBram Moolenaar  * Returns OK if a new tab page was created, FAIL otherwise.
400480a94a58SBram Moolenaar  */
40055843f5f3SBram Moolenaar     static int
may_open_tabpage(void)4006b638a7beSBram Moolenaar may_open_tabpage(void)
400780a94a58SBram Moolenaar {
4008e1004401SBram Moolenaar     int		n = (cmdmod.cmod_tab == 0)
4009e1004401SBram Moolenaar 				       ? postponed_split_tab : cmdmod.cmod_tab;
401080a94a58SBram Moolenaar 
4011d326ce83SBram Moolenaar     if (n != 0)
401280a94a58SBram Moolenaar     {
4013e1004401SBram Moolenaar 	cmdmod.cmod_tab = 0;	    // reset it to avoid doing it twice
4014d326ce83SBram Moolenaar 	postponed_split_tab = 0;
401580a94a58SBram Moolenaar 	return win_new_tabpage(n);
401680a94a58SBram Moolenaar     }
401780a94a58SBram Moolenaar     return FAIL;
401880a94a58SBram Moolenaar }
401980a94a58SBram Moolenaar 
402080a94a58SBram Moolenaar /*
402149d7bf13SBram Moolenaar  * Create up to "maxcount" tabpages with empty windows.
402249d7bf13SBram Moolenaar  * Returns the number of resulting tab pages.
40231d2ba7faSBram Moolenaar  */
402449d7bf13SBram Moolenaar     int
make_tabpages(int maxcount)4025b638a7beSBram Moolenaar make_tabpages(int maxcount)
40261d2ba7faSBram Moolenaar {
402749d7bf13SBram Moolenaar     int		count = maxcount;
402849d7bf13SBram Moolenaar     int		todo;
40291d2ba7faSBram Moolenaar 
4030e38eab22SBram Moolenaar     // Limit to 'tabpagemax' tabs.
4031e1438bb8SBram Moolenaar     if (count > p_tpm)
4032e1438bb8SBram Moolenaar 	count = p_tpm;
403349d7bf13SBram Moolenaar 
403449d7bf13SBram Moolenaar     /*
403549d7bf13SBram Moolenaar      * Don't execute autocommands while creating the tab pages.  Must do that
403649d7bf13SBram Moolenaar      * when putting the buffers in the windows.
403749d7bf13SBram Moolenaar      */
403878ab331eSBram Moolenaar     block_autocmds();
403949d7bf13SBram Moolenaar 
404049d7bf13SBram Moolenaar     for (todo = count - 1; todo > 0; --todo)
404180a94a58SBram Moolenaar 	if (win_new_tabpage(0) == FAIL)
40421d2ba7faSBram Moolenaar 	    break;
404349d7bf13SBram Moolenaar 
404478ab331eSBram Moolenaar     unblock_autocmds();
404549d7bf13SBram Moolenaar 
4046e38eab22SBram Moolenaar     // return actual number of tab pages
404749d7bf13SBram Moolenaar     return (count - todo);
40481d2ba7faSBram Moolenaar }
40491d2ba7faSBram Moolenaar 
40501d2ba7faSBram Moolenaar /*
4051f740b29aSBram Moolenaar  * Return TRUE when "tpc" points to a valid tab page.
4052f740b29aSBram Moolenaar  */
4053f740b29aSBram Moolenaar     int
valid_tabpage(tabpage_T * tpc)4054b638a7beSBram Moolenaar valid_tabpage(tabpage_T *tpc)
4055f740b29aSBram Moolenaar {
4056f740b29aSBram Moolenaar     tabpage_T	*tp;
4057f740b29aSBram Moolenaar 
405829323590SBram Moolenaar     FOR_ALL_TABPAGES(tp)
4059f740b29aSBram Moolenaar 	if (tp == tpc)
4060f740b29aSBram Moolenaar 	    return TRUE;
4061f740b29aSBram Moolenaar     return FALSE;
4062f740b29aSBram Moolenaar }
4063f740b29aSBram Moolenaar 
4064f740b29aSBram Moolenaar /*
40658c752bd6SBram Moolenaar  * Return TRUE when "tpc" points to a valid tab page and at least one window is
40668c752bd6SBram Moolenaar  * valid.
40678c752bd6SBram Moolenaar  */
40688c752bd6SBram Moolenaar     int
valid_tabpage_win(tabpage_T * tpc)40698c752bd6SBram Moolenaar valid_tabpage_win(tabpage_T *tpc)
40708c752bd6SBram Moolenaar {
40718c752bd6SBram Moolenaar     tabpage_T	*tp;
40728c752bd6SBram Moolenaar     win_T	*wp;
40738c752bd6SBram Moolenaar 
40748c752bd6SBram Moolenaar     FOR_ALL_TABPAGES(tp)
40758c752bd6SBram Moolenaar     {
40768c752bd6SBram Moolenaar 	if (tp == tpc)
40778c752bd6SBram Moolenaar 	{
40788c752bd6SBram Moolenaar 	    FOR_ALL_WINDOWS_IN_TAB(tp, wp)
40798c752bd6SBram Moolenaar 	    {
40808c752bd6SBram Moolenaar 		if (win_valid_any_tab(wp))
40818c752bd6SBram Moolenaar 		    return TRUE;
40828c752bd6SBram Moolenaar 	    }
40838c752bd6SBram Moolenaar 	    return FALSE;
40848c752bd6SBram Moolenaar 	}
40858c752bd6SBram Moolenaar     }
4086e38eab22SBram Moolenaar     // shouldn't happen
40878c752bd6SBram Moolenaar     return FALSE;
40888c752bd6SBram Moolenaar }
40898c752bd6SBram Moolenaar 
40908c752bd6SBram Moolenaar /*
40918c752bd6SBram Moolenaar  * Close tabpage "tab", assuming it has no windows in it.
40928c752bd6SBram Moolenaar  * There must be another tabpage or this will crash.
40938c752bd6SBram Moolenaar  */
40948c752bd6SBram Moolenaar     void
close_tabpage(tabpage_T * tab)40958c752bd6SBram Moolenaar close_tabpage(tabpage_T *tab)
40968c752bd6SBram Moolenaar {
40978c752bd6SBram Moolenaar     tabpage_T	*ptp;
40988c752bd6SBram Moolenaar 
40998c752bd6SBram Moolenaar     if (tab == first_tabpage)
41008c752bd6SBram Moolenaar     {
41018c752bd6SBram Moolenaar 	first_tabpage = tab->tp_next;
41028c752bd6SBram Moolenaar 	ptp = first_tabpage;
41038c752bd6SBram Moolenaar     }
41048c752bd6SBram Moolenaar     else
41058c752bd6SBram Moolenaar     {
41068c752bd6SBram Moolenaar 	for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
41078c752bd6SBram Moolenaar 							    ptp = ptp->tp_next)
41088c752bd6SBram Moolenaar 	    ;
4109a37ffaa5SBram Moolenaar 	assert(ptp != NULL);
41108c752bd6SBram Moolenaar 	ptp->tp_next = tab->tp_next;
41118c752bd6SBram Moolenaar     }
41128c752bd6SBram Moolenaar 
41138c752bd6SBram Moolenaar     goto_tabpage_tp(ptp, FALSE, FALSE);
41148c752bd6SBram Moolenaar     free_tabpage(tab);
41158c752bd6SBram Moolenaar }
41168c752bd6SBram Moolenaar 
41178c752bd6SBram Moolenaar /*
4118f740b29aSBram Moolenaar  * Find tab page "n" (first one is 1).  Returns NULL when not found.
4119f740b29aSBram Moolenaar  */
4120f740b29aSBram Moolenaar     tabpage_T *
find_tabpage(int n)4121b638a7beSBram Moolenaar find_tabpage(int n)
4122f740b29aSBram Moolenaar {
4123f740b29aSBram Moolenaar     tabpage_T	*tp;
4124f740b29aSBram Moolenaar     int		i = 1;
4125f740b29aSBram Moolenaar 
412600aa069dSBram Moolenaar     if (n == 0)
412700aa069dSBram Moolenaar 	return curtab;
412800aa069dSBram Moolenaar 
4129f740b29aSBram Moolenaar     for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
4130f740b29aSBram Moolenaar 	++i;
4131f740b29aSBram Moolenaar     return tp;
4132f740b29aSBram Moolenaar }
4133f740b29aSBram Moolenaar 
4134f740b29aSBram Moolenaar /*
413532466aa2SBram Moolenaar  * Get index of tab page "tp".  First one has index 1.
4136ba6c0524SBram Moolenaar  * When not found returns number of tab pages plus one.
413732466aa2SBram Moolenaar  */
413832466aa2SBram Moolenaar     int
tabpage_index(tabpage_T * ftp)4139b638a7beSBram Moolenaar tabpage_index(tabpage_T *ftp)
414032466aa2SBram Moolenaar {
414132466aa2SBram Moolenaar     int		i = 1;
414232466aa2SBram Moolenaar     tabpage_T	*tp;
414332466aa2SBram Moolenaar 
414432466aa2SBram Moolenaar     for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
414532466aa2SBram Moolenaar 	++i;
414632466aa2SBram Moolenaar     return i;
414732466aa2SBram Moolenaar }
414832466aa2SBram Moolenaar 
414932466aa2SBram Moolenaar /*
41507e8fd636SBram Moolenaar  * Prepare for leaving the current tab page.
415184a05accSBram Moolenaar  * When autocommands change "curtab" we don't leave the tab page and return
41527e8fd636SBram Moolenaar  * FAIL.
41537e8fd636SBram Moolenaar  * Careful: When OK is returned need to get a new tab page very very soon!
41541d2ba7faSBram Moolenaar  */
41557e8fd636SBram Moolenaar     static int
leave_tabpage(buf_T * new_curbuf UNUSED,int trigger_leave_autocmds UNUSED)4156b638a7beSBram Moolenaar leave_tabpage(
4157e38eab22SBram Moolenaar     buf_T	*new_curbuf UNUSED,    // what is going to be the new curbuf,
4158e38eab22SBram Moolenaar 				       // NULL if unknown
4159b638a7beSBram Moolenaar     int		trigger_leave_autocmds UNUSED)
41601d2ba7faSBram Moolenaar {
41617e8fd636SBram Moolenaar     tabpage_T	*tp = curtab;
41627e8fd636SBram Moolenaar 
41636d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
41646d41c78eSBram Moolenaar     leaving_window(curwin);
41656d41c78eSBram Moolenaar #endif
4166e38eab22SBram Moolenaar     reset_VIsual_and_resel();	// stop Visual mode
416749e649fcSBram Moolenaar     if (trigger_leave_autocmds)
416849e649fcSBram Moolenaar     {
41697e8fd636SBram Moolenaar 	if (new_curbuf != curbuf)
41707e8fd636SBram Moolenaar 	{
41717e8fd636SBram Moolenaar 	    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
41727e8fd636SBram Moolenaar 	    if (curtab != tp)
41737e8fd636SBram Moolenaar 		return FAIL;
41747e8fd636SBram Moolenaar 	}
41757e8fd636SBram Moolenaar 	apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
41767e8fd636SBram Moolenaar 	if (curtab != tp)
41777e8fd636SBram Moolenaar 	    return FAIL;
41782a0449d1SBram Moolenaar 	apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
41797e8fd636SBram Moolenaar 	if (curtab != tp)
41807e8fd636SBram Moolenaar 	    return FAIL;
418149e649fcSBram Moolenaar     }
418298ea5defSBram Moolenaar #if defined(FEAT_GUI)
4183e38eab22SBram Moolenaar     // Remove the scrollbars.  They may be added back later.
418498ea5defSBram Moolenaar     if (gui.in_use)
418598ea5defSBram Moolenaar 	gui_remove_scrollbars();
418698ea5defSBram Moolenaar #endif
41871d2ba7faSBram Moolenaar     tp->tp_curwin = curwin;
4188f740b29aSBram Moolenaar     tp->tp_prevwin = prevwin;
41891d2ba7faSBram Moolenaar     tp->tp_firstwin = firstwin;
41901d2ba7faSBram Moolenaar     tp->tp_lastwin = lastwin;
419198ea5defSBram Moolenaar     tp->tp_old_Rows = Rows;
419298ea5defSBram Moolenaar     tp->tp_old_Columns = Columns;
41931d2ba7faSBram Moolenaar     firstwin = NULL;
41941d2ba7faSBram Moolenaar     lastwin = NULL;
41957e8fd636SBram Moolenaar     return OK;
41961d2ba7faSBram Moolenaar }
41971d2ba7faSBram Moolenaar 
41981d2ba7faSBram Moolenaar /*
41991d2ba7faSBram Moolenaar  * Start using tab page "tp".
42002a0449d1SBram Moolenaar  * Only to be used after leave_tabpage() or freeing the current tab page.
420149e649fcSBram Moolenaar  * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
420249e649fcSBram Moolenaar  * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
42031d2ba7faSBram Moolenaar  */
42041d2ba7faSBram Moolenaar     static void
enter_tabpage(tabpage_T * tp,buf_T * old_curbuf UNUSED,int trigger_enter_autocmds,int trigger_leave_autocmds)4205b638a7beSBram Moolenaar enter_tabpage(
4206b638a7beSBram Moolenaar     tabpage_T	*tp,
4207b638a7beSBram Moolenaar     buf_T	*old_curbuf UNUSED,
4208f1d2501eSBram Moolenaar     int		trigger_enter_autocmds,
4209f1d2501eSBram Moolenaar     int		trigger_leave_autocmds)
42101d2ba7faSBram Moolenaar {
4211479950f6SBram Moolenaar     int		row;
421298ea5defSBram Moolenaar     int		old_off = tp->tp_firstwin->w_winrow;
4213773560bcSBram Moolenaar     win_T	*next_prevwin = tp->tp_prevwin;
421462a23250SBram Moolenaar     tabpage_T	*last_tab = curtab;
421598ea5defSBram Moolenaar 
421649d7bf13SBram Moolenaar     curtab = tp;
42171d2ba7faSBram Moolenaar     firstwin = tp->tp_firstwin;
42181d2ba7faSBram Moolenaar     lastwin = tp->tp_lastwin;
42191d2ba7faSBram Moolenaar     topframe = tp->tp_topframe;
4220773560bcSBram Moolenaar 
4221e38eab22SBram Moolenaar     // We would like doing the TabEnter event first, but we don't have a
4222e38eab22SBram Moolenaar     // valid current window yet, which may break some commands.
4223e38eab22SBram Moolenaar     // This triggers autocommands, thus may make "tp" invalid.
422457942237SBram Moolenaar     (void)win_enter_ext(tp->tp_curwin, WEE_CURWIN_INVALID
4225d61f2f77SBram Moolenaar 		  | (trigger_enter_autocmds ? WEE_TRIGGER_ENTER_AUTOCMDS : 0)
4226d61f2f77SBram Moolenaar 		  | (trigger_leave_autocmds ? WEE_TRIGGER_LEAVE_AUTOCMDS : 0));
4227773560bcSBram Moolenaar     prevwin = next_prevwin;
4228773560bcSBram Moolenaar 
4229e38eab22SBram Moolenaar     last_status(FALSE);		// status line may appear or disappear
4230479950f6SBram Moolenaar     row = win_comp_pos();	// recompute w_winrow for all windows
423149d7bf13SBram Moolenaar #ifdef FEAT_DIFF
423249d7bf13SBram Moolenaar     diff_need_scrollbind = TRUE;
423349d7bf13SBram Moolenaar #endif
42341d2ba7faSBram Moolenaar 
4235e38eab22SBram Moolenaar     // The tabpage line may have appeared or disappeared, may need to resize
4236e38eab22SBram Moolenaar     // the frames for that.  When the Vim window was resized need to update
4237e38eab22SBram Moolenaar     // frame sizes too.  Use the stored value of p_ch, so that it can be
4238e38eab22SBram Moolenaar     // different for each tab page.
42390fef0aebSBram Moolenaar     if (p_ch != curtab->tp_ch_used)
42400fef0aebSBram Moolenaar 	clear_cmdline = TRUE;
4241c6fe9195SBram Moolenaar     p_ch = curtab->tp_ch_used;
4242479950f6SBram Moolenaar 
4243479950f6SBram Moolenaar     // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is
4244479950f6SBram Moolenaar     // changed but p_ch and tp_ch_used are not changed. Thus we also need to
4245479950f6SBram Moolenaar     // check cmdline_row.
4246479950f6SBram Moolenaar     if ((row < cmdline_row) && (cmdline_row <= Rows - p_ch))
4247479950f6SBram Moolenaar 	clear_cmdline = TRUE;
4248479950f6SBram Moolenaar 
424932466aa2SBram Moolenaar     if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
425032466aa2SBram Moolenaar #ifdef FEAT_GUI_TABLINE
425132466aa2SBram Moolenaar 			    && !gui_use_tabline()
425232466aa2SBram Moolenaar #endif
425332466aa2SBram Moolenaar 		))
425498ea5defSBram Moolenaar 	shell_new_rows();
42557e8fd636SBram Moolenaar     if (curtab->tp_old_Columns != Columns && starting == 0)
4256e38eab22SBram Moolenaar 	shell_new_columns();	// update window widths
425798ea5defSBram Moolenaar 
425862a23250SBram Moolenaar     lastused_tabpage = last_tab;
425962a23250SBram Moolenaar 
426098ea5defSBram Moolenaar #if defined(FEAT_GUI)
4261e38eab22SBram Moolenaar     // When 'guioptions' includes 'L' or 'R' may have to remove or add
4262e38eab22SBram Moolenaar     // scrollbars.  Have to update them anyway.
4263746ebd3bSBram Moolenaar     gui_may_update_scrollbars();
42641d2ba7faSBram Moolenaar #endif
42651d2ba7faSBram Moolenaar 
4266e38eab22SBram Moolenaar     // Apply autocommands after updating the display, when 'rows' and
4267e38eab22SBram Moolenaar     // 'columns' have been set correctly.
426849e649fcSBram Moolenaar     if (trigger_enter_autocmds)
4269a8596c47SBram Moolenaar     {
42705ad15df9SBram Moolenaar 	apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
42715ad15df9SBram Moolenaar 	if (old_curbuf != curbuf)
42725ad15df9SBram Moolenaar 	    apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
4273a8596c47SBram Moolenaar     }
42745ad15df9SBram Moolenaar 
4275bf3250a8SBram Moolenaar     redraw_all_later(NOT_VALID);
42761d2ba7faSBram Moolenaar }
42771d2ba7faSBram Moolenaar 
42781d2ba7faSBram Moolenaar /*
42791d2ba7faSBram Moolenaar  * Go to tab page "n".  For ":tab N" and "Ngt".
428032466aa2SBram Moolenaar  * When "n" is 9999 go to the last tab page.
42811d2ba7faSBram Moolenaar  */
42821d2ba7faSBram Moolenaar     void
goto_tabpage(int n)4283b638a7beSBram Moolenaar goto_tabpage(int n)
42841d2ba7faSBram Moolenaar {
42851f3601e9SBram Moolenaar     tabpage_T	*tp = NULL;  // shut up compiler
428680a94a58SBram Moolenaar     tabpage_T	*ttp;
42871d2ba7faSBram Moolenaar     int		i;
42881d2ba7faSBram Moolenaar 
4289d68071d8SBram Moolenaar     if (text_locked())
4290d68071d8SBram Moolenaar     {
4291e38eab22SBram Moolenaar 	// Not allowed when editing the command line.
42925a49789aSBram Moolenaar 	text_locked_msg();
4293d68071d8SBram Moolenaar 	return;
4294d68071d8SBram Moolenaar     }
4295d68071d8SBram Moolenaar 
4296e38eab22SBram Moolenaar     // If there is only one it can't work.
42972a0449d1SBram Moolenaar     if (first_tabpage->tp_next == NULL)
42982a0449d1SBram Moolenaar     {
42992a0449d1SBram Moolenaar 	if (n > 1)
43002a0449d1SBram Moolenaar 	    beep_flush();
43012a0449d1SBram Moolenaar 	return;
43022a0449d1SBram Moolenaar     }
43032a0449d1SBram Moolenaar 
43041d2ba7faSBram Moolenaar     if (n == 0)
43051d2ba7faSBram Moolenaar     {
4306e38eab22SBram Moolenaar 	// No count, go to next tab page, wrap around end.
43077e8fd636SBram Moolenaar 	if (curtab->tp_next == NULL)
43081d2ba7faSBram Moolenaar 	    tp = first_tabpage;
43091d2ba7faSBram Moolenaar 	else
43107e8fd636SBram Moolenaar 	    tp = curtab->tp_next;
43111d2ba7faSBram Moolenaar     }
431280a94a58SBram Moolenaar     else if (n < 0)
431380a94a58SBram Moolenaar     {
4314e38eab22SBram Moolenaar 	// "gT": go to previous tab page, wrap around end.  "N gT" repeats
4315e38eab22SBram Moolenaar 	// this N times.
431680a94a58SBram Moolenaar 	ttp = curtab;
431780a94a58SBram Moolenaar 	for (i = n; i < 0; ++i)
431880a94a58SBram Moolenaar 	{
431980a94a58SBram Moolenaar 	    for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
432080a94a58SBram Moolenaar 		    tp = tp->tp_next)
432180a94a58SBram Moolenaar 		;
432280a94a58SBram Moolenaar 	    ttp = tp;
432380a94a58SBram Moolenaar 	}
432480a94a58SBram Moolenaar     }
432532466aa2SBram Moolenaar     else if (n == 9999)
432632466aa2SBram Moolenaar     {
4327e38eab22SBram Moolenaar 	// Go to last tab page.
432832466aa2SBram Moolenaar 	for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
432932466aa2SBram Moolenaar 	    ;
433032466aa2SBram Moolenaar     }
43311d2ba7faSBram Moolenaar     else
43321d2ba7faSBram Moolenaar     {
4333e38eab22SBram Moolenaar 	// Go to tab page "n".
433432466aa2SBram Moolenaar 	tp = find_tabpage(n);
43351d2ba7faSBram Moolenaar 	if (tp == NULL)
43361d2ba7faSBram Moolenaar 	{
43371d2ba7faSBram Moolenaar 	    beep_flush();
43381d2ba7faSBram Moolenaar 	    return;
43391d2ba7faSBram Moolenaar 	}
43401d2ba7faSBram Moolenaar     }
43411d2ba7faSBram Moolenaar 
434249e649fcSBram Moolenaar     goto_tabpage_tp(tp, TRUE, TRUE);
434332466aa2SBram Moolenaar 
434432466aa2SBram Moolenaar #ifdef FEAT_GUI_TABLINE
434532466aa2SBram Moolenaar     if (gui_use_tabline())
4346a226a6ddSBram Moolenaar 	gui_mch_set_curtab(tabpage_index(curtab));
434732466aa2SBram Moolenaar #endif
434832466aa2SBram Moolenaar }
434932466aa2SBram Moolenaar 
435032466aa2SBram Moolenaar /*
435132466aa2SBram Moolenaar  * Go to tabpage "tp".
435249e649fcSBram Moolenaar  * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
435349e649fcSBram Moolenaar  * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
435432466aa2SBram Moolenaar  * Note: doesn't update the GUI tab.
435532466aa2SBram Moolenaar  */
435632466aa2SBram Moolenaar     void
goto_tabpage_tp(tabpage_T * tp,int trigger_enter_autocmds,int trigger_leave_autocmds)4357b638a7beSBram Moolenaar goto_tabpage_tp(
4358b638a7beSBram Moolenaar     tabpage_T	*tp,
4359b638a7beSBram Moolenaar     int		trigger_enter_autocmds,
4360b638a7beSBram Moolenaar     int		trigger_leave_autocmds)
436132466aa2SBram Moolenaar {
4362e38eab22SBram Moolenaar     // Don't repeat a message in another tab page.
4363c6af8125SBram Moolenaar     set_keep_msg(NULL, 0);
4364c6af8125SBram Moolenaar 
436549e649fcSBram Moolenaar     if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
436649e649fcSBram Moolenaar 					trigger_leave_autocmds) == OK)
43677e8fd636SBram Moolenaar     {
43687e8fd636SBram Moolenaar 	if (valid_tabpage(tp))
436949e649fcSBram Moolenaar 	    enter_tabpage(tp, curbuf, trigger_enter_autocmds,
437049e649fcSBram Moolenaar 		    trigger_leave_autocmds);
43717e8fd636SBram Moolenaar 	else
437249e649fcSBram Moolenaar 	    enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
437349e649fcSBram Moolenaar 		    trigger_leave_autocmds);
43747e8fd636SBram Moolenaar     }
43751d2ba7faSBram Moolenaar }
4376071d4279SBram Moolenaar 
4377071d4279SBram Moolenaar /*
437862a23250SBram Moolenaar  * Go to the last accessed tab page, if there is one.
437962a23250SBram Moolenaar  * Return OK or FAIL
438062a23250SBram Moolenaar  */
438162a23250SBram Moolenaar     int
goto_tabpage_lastused(void)438262a23250SBram Moolenaar goto_tabpage_lastused(void)
438362a23250SBram Moolenaar {
438462a23250SBram Moolenaar     if (valid_tabpage(lastused_tabpage))
438562a23250SBram Moolenaar     {
438662a23250SBram Moolenaar 	goto_tabpage_tp(lastused_tabpage, TRUE, TRUE);
438762a23250SBram Moolenaar 	return OK;
438862a23250SBram Moolenaar     }
438962a23250SBram Moolenaar     return FAIL;
439062a23250SBram Moolenaar }
439162a23250SBram Moolenaar 
439262a23250SBram Moolenaar /*
4393779b74b2SBram Moolenaar  * Enter window "wp" in tab page "tp".
4394779b74b2SBram Moolenaar  * Also updates the GUI tab.
4395779b74b2SBram Moolenaar  */
4396779b74b2SBram Moolenaar     void
goto_tabpage_win(tabpage_T * tp,win_T * wp)4397b638a7beSBram Moolenaar goto_tabpage_win(tabpage_T *tp, win_T *wp)
4398779b74b2SBram Moolenaar {
439949e649fcSBram Moolenaar     goto_tabpage_tp(tp, TRUE, TRUE);
4400779b74b2SBram Moolenaar     if (curtab == tp && win_valid(wp))
4401779b74b2SBram Moolenaar     {
4402779b74b2SBram Moolenaar 	win_enter(wp, TRUE);
4403779b74b2SBram Moolenaar # ifdef FEAT_GUI_TABLINE
4404779b74b2SBram Moolenaar 	if (gui_use_tabline())
4405779b74b2SBram Moolenaar 	    gui_mch_set_curtab(tabpage_index(curtab));
4406779b74b2SBram Moolenaar # endif
4407779b74b2SBram Moolenaar     }
4408779b74b2SBram Moolenaar }
4409779b74b2SBram Moolenaar 
4410779b74b2SBram Moolenaar /*
441140ce3a4eSBram Moolenaar  * Move the current tab page to after tab page "nr".
441280a94a58SBram Moolenaar  */
441380a94a58SBram Moolenaar     void
tabpage_move(int nr)4414b638a7beSBram Moolenaar tabpage_move(int nr)
441580a94a58SBram Moolenaar {
441640ce3a4eSBram Moolenaar     int		n = 1;
441740ce3a4eSBram Moolenaar     tabpage_T	*tp, *tp_dst;
441880a94a58SBram Moolenaar 
441980a94a58SBram Moolenaar     if (first_tabpage->tp_next == NULL)
442080a94a58SBram Moolenaar 	return;
442180a94a58SBram Moolenaar 
442240ce3a4eSBram Moolenaar     for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next)
442340ce3a4eSBram Moolenaar 	++n;
442440ce3a4eSBram Moolenaar 
442540ce3a4eSBram Moolenaar     if (tp == curtab || (nr > 0 && tp->tp_next != NULL
442640ce3a4eSBram Moolenaar 						    && tp->tp_next == curtab))
442740ce3a4eSBram Moolenaar 	return;
442840ce3a4eSBram Moolenaar 
442940ce3a4eSBram Moolenaar     tp_dst = tp;
443040ce3a4eSBram Moolenaar 
4431e38eab22SBram Moolenaar     // Remove the current tab page from the list of tab pages.
443280a94a58SBram Moolenaar     if (curtab == first_tabpage)
443380a94a58SBram Moolenaar 	first_tabpage = curtab->tp_next;
443480a94a58SBram Moolenaar     else
443580a94a58SBram Moolenaar     {
443629323590SBram Moolenaar 	FOR_ALL_TABPAGES(tp)
443780a94a58SBram Moolenaar 	    if (tp->tp_next == curtab)
443880a94a58SBram Moolenaar 		break;
4439e38eab22SBram Moolenaar 	if (tp == NULL)	// "cannot happen"
444080a94a58SBram Moolenaar 	    return;
444180a94a58SBram Moolenaar 	tp->tp_next = curtab->tp_next;
444280a94a58SBram Moolenaar     }
444380a94a58SBram Moolenaar 
4444e38eab22SBram Moolenaar     // Re-insert it at the specified position.
444540ce3a4eSBram Moolenaar     if (nr <= 0)
444680a94a58SBram Moolenaar     {
444780a94a58SBram Moolenaar 	curtab->tp_next = first_tabpage;
444880a94a58SBram Moolenaar 	first_tabpage = curtab;
444980a94a58SBram Moolenaar     }
445080a94a58SBram Moolenaar     else
445180a94a58SBram Moolenaar     {
445240ce3a4eSBram Moolenaar 	curtab->tp_next = tp_dst->tp_next;
445340ce3a4eSBram Moolenaar 	tp_dst->tp_next = curtab;
445480a94a58SBram Moolenaar     }
445580a94a58SBram Moolenaar 
4456e38eab22SBram Moolenaar     // Need to redraw the tabline.  Tab page contents doesn't change.
445780a94a58SBram Moolenaar     redraw_tabline = TRUE;
445880a94a58SBram Moolenaar }
445980a94a58SBram Moolenaar 
446080a94a58SBram Moolenaar 
446180a94a58SBram Moolenaar /*
4462071d4279SBram Moolenaar  * Go to another window.
4463071d4279SBram Moolenaar  * When jumping to another buffer, stop Visual mode.  Do this before
4464071d4279SBram Moolenaar  * changing windows so we can yank the selection into the '*' register.
4465071d4279SBram Moolenaar  * When jumping to another window on the same buffer, adjust its cursor
4466071d4279SBram Moolenaar  * position to keep the same Visual area.
4467071d4279SBram Moolenaar  */
4468071d4279SBram Moolenaar     void
win_goto(win_T * wp)4469b638a7beSBram Moolenaar win_goto(win_T *wp)
4470071d4279SBram Moolenaar {
447123c347c6SBram Moolenaar #ifdef FEAT_CONCEAL
447223c347c6SBram Moolenaar     win_T	*owp = curwin;
447323c347c6SBram Moolenaar #endif
447423c347c6SBram Moolenaar 
44758bf716cdSBram Moolenaar #ifdef FEAT_PROP_POPUP
44763c01c4a0SBram Moolenaar     if (ERROR_IF_ANY_POPUP_WINDOW)
4477815b76bfSBram Moolenaar 	return;
44788bf716cdSBram Moolenaar     if (popup_is_popup(wp))
44798bf716cdSBram Moolenaar     {
44808bf716cdSBram Moolenaar 	emsg(_("E366: Not allowed to enter a popup window"));
44818bf716cdSBram Moolenaar 	return;
44828bf716cdSBram Moolenaar     }
44838bf716cdSBram Moolenaar #endif
44846adb9ea0SBram Moolenaar     if (text_and_win_locked())
4485071d4279SBram Moolenaar     {
4486071d4279SBram Moolenaar 	beep_flush();
44872d3f489eSBram Moolenaar 	text_locked_msg();
4488071d4279SBram Moolenaar 	return;
4489071d4279SBram Moolenaar     }
4490910f66f9SBram Moolenaar     if (curbuf_locked())
4491910f66f9SBram Moolenaar 	return;
449205a7bb36SBram Moolenaar 
4493071d4279SBram Moolenaar     if (wp->w_buffer != curbuf)
4494071d4279SBram Moolenaar 	reset_VIsual_and_resel();
4495071d4279SBram Moolenaar     else if (VIsual_active)
4496071d4279SBram Moolenaar 	wp->w_cursor = curwin->w_cursor;
4497071d4279SBram Moolenaar 
4498071d4279SBram Moolenaar #ifdef FEAT_GUI
4499071d4279SBram Moolenaar     need_mouse_correct = TRUE;
4500071d4279SBram Moolenaar #endif
4501071d4279SBram Moolenaar     win_enter(wp, TRUE);
450223c347c6SBram Moolenaar 
450323c347c6SBram Moolenaar #ifdef FEAT_CONCEAL
4504535d5b65SBram Moolenaar     // Conceal cursor line in previous window, unconceal in current window.
4505530e7dfaSBram Moolenaar     if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
4506535d5b65SBram Moolenaar 	redrawWinline(owp, owp->w_cursor.lnum);
4507530e7dfaSBram Moolenaar     if (curwin->w_p_cole > 0 && !msg_scrolled)
4508530e7dfaSBram Moolenaar 	need_cursor_line_redraw = TRUE;
450923c347c6SBram Moolenaar #endif
4510071d4279SBram Moolenaar }
4511071d4279SBram Moolenaar 
45128ee52affSYegappan Lakshmanan #if defined(FEAT_PERL) || defined(PROTO)
4513071d4279SBram Moolenaar /*
4514071d4279SBram Moolenaar  * Find window number "winnr" (counting top to bottom).
4515071d4279SBram Moolenaar  */
4516071d4279SBram Moolenaar     win_T *
win_find_nr(int winnr)4517b638a7beSBram Moolenaar win_find_nr(int winnr)
4518071d4279SBram Moolenaar {
4519071d4279SBram Moolenaar     win_T	*wp;
4520071d4279SBram Moolenaar 
452129323590SBram Moolenaar     FOR_ALL_WINDOWS(wp)
4522071d4279SBram Moolenaar 	if (--winnr == 0)
4523071d4279SBram Moolenaar 	    break;
4524071d4279SBram Moolenaar     return wp;
4525071d4279SBram Moolenaar }
4526071d4279SBram Moolenaar #endif
4527071d4279SBram Moolenaar 
45284033c55eSBram Moolenaar #if ((defined(FEAT_PYTHON) || defined(FEAT_PYTHON3))) || defined(PROTO)
4529105bc355SBram Moolenaar /*
4530105bc355SBram Moolenaar  * Find the tabpage for window "win".
4531105bc355SBram Moolenaar  */
4532105bc355SBram Moolenaar     tabpage_T *
win_find_tabpage(win_T * win)4533b638a7beSBram Moolenaar win_find_tabpage(win_T *win)
4534105bc355SBram Moolenaar {
4535105bc355SBram Moolenaar     win_T	*wp;
4536105bc355SBram Moolenaar     tabpage_T	*tp;
4537105bc355SBram Moolenaar 
453829323590SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
4539105bc355SBram Moolenaar 	    if (wp == win)
4540105bc355SBram Moolenaar 		return tp;
4541105bc355SBram Moolenaar     return NULL;
4542105bc355SBram Moolenaar }
4543105bc355SBram Moolenaar #endif
4544105bc355SBram Moolenaar 
4545071d4279SBram Moolenaar /*
454646ad288bSBram Moolenaar  * Get the above or below neighbor window of the specified window.
454746ad288bSBram Moolenaar  *   up - TRUE for the above neighbor
454846ad288bSBram Moolenaar  *   count - nth neighbor window
454946ad288bSBram Moolenaar  * Returns the specified window if the neighbor is not found.
4550071d4279SBram Moolenaar  */
455146ad288bSBram Moolenaar     win_T *
win_vert_neighbor(tabpage_T * tp,win_T * wp,int up,long count)455246ad288bSBram Moolenaar win_vert_neighbor(tabpage_T *tp, win_T *wp, int up, long count)
4553071d4279SBram Moolenaar {
4554071d4279SBram Moolenaar     frame_T	*fr;
4555071d4279SBram Moolenaar     frame_T	*nfr;
4556071d4279SBram Moolenaar     frame_T	*foundfr;
4557071d4279SBram Moolenaar 
4558631ebc48SBram Moolenaar #ifdef FEAT_PROP_POPUP
4559631ebc48SBram Moolenaar     if (popup_is_popup(wp))
4560631ebc48SBram Moolenaar 	// popups don't have neighbors.
4561631ebc48SBram Moolenaar 	return NULL;
4562631ebc48SBram Moolenaar #endif
456346ad288bSBram Moolenaar     foundfr = wp->w_frame;
4564071d4279SBram Moolenaar     while (count--)
4565071d4279SBram Moolenaar     {
4566071d4279SBram Moolenaar 	/*
4567071d4279SBram Moolenaar 	 * First go upwards in the tree of frames until we find a upwards or
4568071d4279SBram Moolenaar 	 * downwards neighbor.
4569071d4279SBram Moolenaar 	 */
4570071d4279SBram Moolenaar 	fr = foundfr;
4571071d4279SBram Moolenaar 	for (;;)
4572071d4279SBram Moolenaar 	{
457346ad288bSBram Moolenaar 	    if (fr == tp->tp_topframe)
4574071d4279SBram Moolenaar 		goto end;
4575071d4279SBram Moolenaar 	    if (up)
4576071d4279SBram Moolenaar 		nfr = fr->fr_prev;
4577071d4279SBram Moolenaar 	    else
4578071d4279SBram Moolenaar 		nfr = fr->fr_next;
4579071d4279SBram Moolenaar 	    if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
4580071d4279SBram Moolenaar 		break;
4581071d4279SBram Moolenaar 	    fr = fr->fr_parent;
4582071d4279SBram Moolenaar 	}
4583071d4279SBram Moolenaar 
4584071d4279SBram Moolenaar 	/*
4585071d4279SBram Moolenaar 	 * Now go downwards to find the bottom or top frame in it.
4586071d4279SBram Moolenaar 	 */
4587071d4279SBram Moolenaar 	for (;;)
4588071d4279SBram Moolenaar 	{
4589071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_LEAF)
4590071d4279SBram Moolenaar 	    {
4591071d4279SBram Moolenaar 		foundfr = nfr;
4592071d4279SBram Moolenaar 		break;
4593071d4279SBram Moolenaar 	    }
4594071d4279SBram Moolenaar 	    fr = nfr->fr_child;
4595071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_ROW)
4596071d4279SBram Moolenaar 	    {
4597e38eab22SBram Moolenaar 		// Find the frame at the cursor row.
4598071d4279SBram Moolenaar 		while (fr->fr_next != NULL
4599071d4279SBram Moolenaar 			&& frame2win(fr)->w_wincol + fr->fr_width
460046ad288bSBram Moolenaar 					 <= wp->w_wincol + wp->w_wcol)
4601071d4279SBram Moolenaar 		    fr = fr->fr_next;
4602071d4279SBram Moolenaar 	    }
4603071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_COL && up)
4604071d4279SBram Moolenaar 		while (fr->fr_next != NULL)
4605071d4279SBram Moolenaar 		    fr = fr->fr_next;
4606071d4279SBram Moolenaar 	    nfr = fr;
4607071d4279SBram Moolenaar 	}
4608071d4279SBram Moolenaar     }
4609071d4279SBram Moolenaar end:
461046ad288bSBram Moolenaar     return foundfr != NULL ? foundfr->fr_win : NULL;
4611071d4279SBram Moolenaar }
4612071d4279SBram Moolenaar 
4613071d4279SBram Moolenaar /*
461446ad288bSBram Moolenaar  * Move to window above or below "count" times.
4615071d4279SBram Moolenaar  */
4616071d4279SBram Moolenaar     static void
win_goto_ver(int up,long count)461746ad288bSBram Moolenaar win_goto_ver(
461846ad288bSBram Moolenaar     int		up,		// TRUE to go to win above
4619b638a7beSBram Moolenaar     long	count)
4620071d4279SBram Moolenaar {
462146ad288bSBram Moolenaar     win_T	*win;
462246ad288bSBram Moolenaar 
4623219c7d06SBram Moolenaar #ifdef FEAT_PROP_POPUP
4624219c7d06SBram Moolenaar     if (ERROR_IF_TERM_POPUP_WINDOW)
4625219c7d06SBram Moolenaar 	return;
4626219c7d06SBram Moolenaar #endif
462746ad288bSBram Moolenaar     win = win_vert_neighbor(curtab, curwin, up, count);
462846ad288bSBram Moolenaar     if (win != NULL)
462946ad288bSBram Moolenaar 	win_goto(win);
463046ad288bSBram Moolenaar }
463146ad288bSBram Moolenaar 
463246ad288bSBram Moolenaar /*
463346ad288bSBram Moolenaar  * Get the left or right neighbor window of the specified window.
463446ad288bSBram Moolenaar  *   left - TRUE for the left neighbor
463546ad288bSBram Moolenaar  *   count - nth neighbor window
463646ad288bSBram Moolenaar  * Returns the specified window if the neighbor is not found.
463746ad288bSBram Moolenaar  */
463846ad288bSBram Moolenaar     win_T *
win_horz_neighbor(tabpage_T * tp,win_T * wp,int left,long count)463946ad288bSBram Moolenaar win_horz_neighbor(tabpage_T *tp, win_T *wp, int left, long count)
464046ad288bSBram Moolenaar {
4641071d4279SBram Moolenaar     frame_T	*fr;
4642071d4279SBram Moolenaar     frame_T	*nfr;
4643071d4279SBram Moolenaar     frame_T	*foundfr;
4644071d4279SBram Moolenaar 
4645631ebc48SBram Moolenaar #ifdef FEAT_PROP_POPUP
4646631ebc48SBram Moolenaar     if (popup_is_popup(wp))
4647631ebc48SBram Moolenaar 	// popups don't have neighbors.
4648631ebc48SBram Moolenaar 	return NULL;
4649631ebc48SBram Moolenaar #endif
465046ad288bSBram Moolenaar     foundfr = wp->w_frame;
4651071d4279SBram Moolenaar     while (count--)
4652071d4279SBram Moolenaar     {
4653071d4279SBram Moolenaar 	/*
4654071d4279SBram Moolenaar 	 * First go upwards in the tree of frames until we find a left or
4655071d4279SBram Moolenaar 	 * right neighbor.
4656071d4279SBram Moolenaar 	 */
4657071d4279SBram Moolenaar 	fr = foundfr;
4658071d4279SBram Moolenaar 	for (;;)
4659071d4279SBram Moolenaar 	{
466046ad288bSBram Moolenaar 	    if (fr == tp->tp_topframe)
4661071d4279SBram Moolenaar 		goto end;
4662071d4279SBram Moolenaar 	    if (left)
4663071d4279SBram Moolenaar 		nfr = fr->fr_prev;
4664071d4279SBram Moolenaar 	    else
4665071d4279SBram Moolenaar 		nfr = fr->fr_next;
4666071d4279SBram Moolenaar 	    if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
4667071d4279SBram Moolenaar 		break;
4668071d4279SBram Moolenaar 	    fr = fr->fr_parent;
4669071d4279SBram Moolenaar 	}
4670071d4279SBram Moolenaar 
4671071d4279SBram Moolenaar 	/*
4672071d4279SBram Moolenaar 	 * Now go downwards to find the leftmost or rightmost frame in it.
4673071d4279SBram Moolenaar 	 */
4674071d4279SBram Moolenaar 	for (;;)
4675071d4279SBram Moolenaar 	{
4676071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_LEAF)
4677071d4279SBram Moolenaar 	    {
4678071d4279SBram Moolenaar 		foundfr = nfr;
4679071d4279SBram Moolenaar 		break;
4680071d4279SBram Moolenaar 	    }
4681071d4279SBram Moolenaar 	    fr = nfr->fr_child;
4682071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_COL)
4683071d4279SBram Moolenaar 	    {
4684e38eab22SBram Moolenaar 		// Find the frame at the cursor row.
4685071d4279SBram Moolenaar 		while (fr->fr_next != NULL
4686071d4279SBram Moolenaar 			&& frame2win(fr)->w_winrow + fr->fr_height
468746ad288bSBram Moolenaar 					 <= wp->w_winrow + wp->w_wrow)
4688071d4279SBram Moolenaar 		    fr = fr->fr_next;
4689071d4279SBram Moolenaar 	    }
4690071d4279SBram Moolenaar 	    if (nfr->fr_layout == FR_ROW && left)
4691071d4279SBram Moolenaar 		while (fr->fr_next != NULL)
4692071d4279SBram Moolenaar 		    fr = fr->fr_next;
4693071d4279SBram Moolenaar 	    nfr = fr;
4694071d4279SBram Moolenaar 	}
4695071d4279SBram Moolenaar     }
4696071d4279SBram Moolenaar end:
469746ad288bSBram Moolenaar     return foundfr != NULL ? foundfr->fr_win : NULL;
469846ad288bSBram Moolenaar }
469946ad288bSBram Moolenaar 
470046ad288bSBram Moolenaar /*
470146ad288bSBram Moolenaar  * Move to left or right window.
470246ad288bSBram Moolenaar  */
470346ad288bSBram Moolenaar     static void
win_goto_hor(int left,long count)470446ad288bSBram Moolenaar win_goto_hor(
470546ad288bSBram Moolenaar     int		left,		// TRUE to go to left win
470646ad288bSBram Moolenaar     long	count)
470746ad288bSBram Moolenaar {
470846ad288bSBram Moolenaar     win_T	*win;
470946ad288bSBram Moolenaar 
4710219c7d06SBram Moolenaar #ifdef FEAT_PROP_POPUP
4711219c7d06SBram Moolenaar     if (ERROR_IF_TERM_POPUP_WINDOW)
4712219c7d06SBram Moolenaar 	return;
4713219c7d06SBram Moolenaar #endif
471446ad288bSBram Moolenaar     win = win_horz_neighbor(curtab, curwin, left, count);
471546ad288bSBram Moolenaar     if (win != NULL)
471646ad288bSBram Moolenaar 	win_goto(win);
4717071d4279SBram Moolenaar }
4718071d4279SBram Moolenaar 
4719071d4279SBram Moolenaar /*
4720071d4279SBram Moolenaar  * Make window "wp" the current window.
4721071d4279SBram Moolenaar  */
4722071d4279SBram Moolenaar     void
win_enter(win_T * wp,int undo_sync)4723b638a7beSBram Moolenaar win_enter(win_T *wp, int undo_sync)
4724071d4279SBram Moolenaar {
472557942237SBram Moolenaar     (void)win_enter_ext(wp, (undo_sync ? WEE_UNDO_SYNC : 0)
4726d61f2f77SBram Moolenaar 		    | WEE_TRIGGER_ENTER_AUTOCMDS | WEE_TRIGGER_LEAVE_AUTOCMDS);
4727071d4279SBram Moolenaar }
4728071d4279SBram Moolenaar 
4729071d4279SBram Moolenaar /*
4730d61f2f77SBram Moolenaar  * Make window "wp" the current window.
4731d61f2f77SBram Moolenaar  * Can be called with "flags" containing WEE_CURWIN_INVALID, which means that
4732d61f2f77SBram Moolenaar  * curwin has just been closed and isn't valid.
473357942237SBram Moolenaar  * Returns TRUE when dont_parse_messages was decremented.
4734071d4279SBram Moolenaar  */
473557942237SBram Moolenaar     static int
win_enter_ext(win_T * wp,int flags)4736d61f2f77SBram Moolenaar win_enter_ext(win_T *wp, int flags)
4737071d4279SBram Moolenaar {
4738071d4279SBram Moolenaar     int		other_buffer = FALSE;
4739d61f2f77SBram Moolenaar     int		curwin_invalid = (flags & WEE_CURWIN_INVALID);
474057942237SBram Moolenaar     int		did_decrement = FALSE;
4741071d4279SBram Moolenaar 
4742e38eab22SBram Moolenaar     if (wp == curwin && !curwin_invalid)	// nothing to do
474357942237SBram Moolenaar 	return FALSE;
4744071d4279SBram Moolenaar 
47456d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
47466d41c78eSBram Moolenaar     if (!curwin_invalid)
47476d41c78eSBram Moolenaar 	leaving_window(curwin);
47486d41c78eSBram Moolenaar #endif
47496d41c78eSBram Moolenaar 
4750d61f2f77SBram Moolenaar     if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS))
4751071d4279SBram Moolenaar     {
4752071d4279SBram Moolenaar 	/*
4753071d4279SBram Moolenaar 	 * Be careful: If autocommands delete the window, return now.
4754071d4279SBram Moolenaar 	 */
4755071d4279SBram Moolenaar 	if (wp->w_buffer != curbuf)
4756071d4279SBram Moolenaar 	{
4757071d4279SBram Moolenaar 	    apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
4758071d4279SBram Moolenaar 	    other_buffer = TRUE;
4759071d4279SBram Moolenaar 	    if (!win_valid(wp))
476057942237SBram Moolenaar 		return FALSE;
4761071d4279SBram Moolenaar 	}
4762071d4279SBram Moolenaar 	apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
4763071d4279SBram Moolenaar 	if (!win_valid(wp))
476457942237SBram Moolenaar 	    return FALSE;
4765071d4279SBram Moolenaar #ifdef FEAT_EVAL
4766e38eab22SBram Moolenaar 	// autocmds may abort script processing
4767071d4279SBram Moolenaar 	if (aborting())
476857942237SBram Moolenaar 	    return FALSE;
4769071d4279SBram Moolenaar #endif
4770071d4279SBram Moolenaar     }
4771071d4279SBram Moolenaar 
4772e38eab22SBram Moolenaar     // sync undo before leaving the current buffer
4773d61f2f77SBram Moolenaar     if ((flags & WEE_UNDO_SYNC) && curbuf != wp->w_buffer)
4774779b74b2SBram Moolenaar 	u_sync(FALSE);
4775ec1561caSBram Moolenaar 
4776e38eab22SBram Moolenaar     // Might need to scroll the old window before switching, e.g., when the
4777e38eab22SBram Moolenaar     // cursor was moved.
4778ec1561caSBram Moolenaar     update_topline();
4779ec1561caSBram Moolenaar 
4780e38eab22SBram Moolenaar     // may have to copy the buffer options when 'cpo' contains 'S'
4781071d4279SBram Moolenaar     if (wp->w_buffer != curbuf)
4782071d4279SBram Moolenaar 	buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
4783071d4279SBram Moolenaar     if (!curwin_invalid)
4784071d4279SBram Moolenaar     {
4785e38eab22SBram Moolenaar 	prevwin = curwin;	// remember for CTRL-W p
4786071d4279SBram Moolenaar 	curwin->w_redr_status = TRUE;
4787071d4279SBram Moolenaar     }
4788071d4279SBram Moolenaar     curwin = wp;
4789071d4279SBram Moolenaar     curbuf = wp->w_buffer;
4790071d4279SBram Moolenaar     check_cursor();
4791071d4279SBram Moolenaar     if (!virtual_active())
4792071d4279SBram Moolenaar 	curwin->w_cursor.coladd = 0;
4793e38eab22SBram Moolenaar     changed_line_abv_curs();	// assume cursor position needs updating
4794071d4279SBram Moolenaar 
479557942237SBram Moolenaar     // Now it is OK to parse messages again, which may be needed in
479657942237SBram Moolenaar     // autocommands.
479757942237SBram Moolenaar #ifdef MESSAGE_QUEUE
479857942237SBram Moolenaar     if (flags & WEE_ALLOW_PARSE_MESSAGES)
479957942237SBram Moolenaar     {
480057942237SBram Moolenaar 	--dont_parse_messages;
480157942237SBram Moolenaar 	did_decrement = TRUE;
480257942237SBram Moolenaar     }
480357942237SBram Moolenaar #endif
480457942237SBram Moolenaar 
48057f13b24aSBram Moolenaar     fix_current_dir();
4806071d4279SBram Moolenaar 
48076d41c78eSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
48086d41c78eSBram Moolenaar     entering_window(curwin);
48096d41c78eSBram Moolenaar #endif
4810ec66c41dSBram Moolenaar     // Careful: autocommands may close the window and make "wp" invalid
4811d61f2f77SBram Moolenaar     if (flags & WEE_TRIGGER_NEW_AUTOCMDS)
4812c917da4bSBram Moolenaar 	apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
4813d61f2f77SBram Moolenaar     if (flags & WEE_TRIGGER_ENTER_AUTOCMDS)
481449e649fcSBram Moolenaar     {
4815071d4279SBram Moolenaar 	apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
4816071d4279SBram Moolenaar 	if (other_buffer)
4817071d4279SBram Moolenaar 	    apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
481849e649fcSBram Moolenaar     }
4819071d4279SBram Moolenaar 
4820071d4279SBram Moolenaar #ifdef FEAT_TITLE
4821071d4279SBram Moolenaar     maketitle();
4822071d4279SBram Moolenaar #endif
4823071d4279SBram Moolenaar     curwin->w_redr_status = TRUE;
4824fbbd102bSBram Moolenaar #ifdef FEAT_TERMINAL
4825ec66c41dSBram Moolenaar     if (bt_terminal(curwin->w_buffer))
4826a27e1dcdSBram Moolenaar 	// terminal is likely in another mode
4827a27e1dcdSBram Moolenaar 	redraw_mode = TRUE;
4828fbbd102bSBram Moolenaar #endif
482949d7bf13SBram Moolenaar     redraw_tabline = TRUE;
4830071d4279SBram Moolenaar     if (restart_edit)
4831e38eab22SBram Moolenaar 	redraw_later(VALID);	// causes status line redraw
4832071d4279SBram Moolenaar 
4833e38eab22SBram Moolenaar     // set window height to desired minimal value
483429b7d7a9SBram Moolenaar     if (curwin->w_height < p_wh && !curwin->w_p_wfh
483505ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
483629b7d7a9SBram Moolenaar 	    && !popup_is_popup(curwin)
483729b7d7a9SBram Moolenaar #endif
483829b7d7a9SBram Moolenaar 	    )
4839071d4279SBram Moolenaar 	win_setheight((int)p_wh);
4840071d4279SBram Moolenaar     else if (curwin->w_height == 0)
4841071d4279SBram Moolenaar 	win_setheight(1);
4842071d4279SBram Moolenaar 
4843e38eab22SBram Moolenaar     // set window width to desired minimal value
4844be4d506bSBram Moolenaar     if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
4845071d4279SBram Moolenaar 	win_setwidth((int)p_wiw);
4846071d4279SBram Moolenaar 
4847b20b9e14SBram Moolenaar     setmouse();			// in case jumped to/from help buffer
4848071d4279SBram Moolenaar 
4849e38eab22SBram Moolenaar     // Change directories when the 'acd' option is set.
48506f470023SBram Moolenaar     DO_AUTOCHDIR;
485157942237SBram Moolenaar 
485257942237SBram Moolenaar     return did_decrement;
4853071d4279SBram Moolenaar }
4854071d4279SBram Moolenaar 
48557f13b24aSBram Moolenaar /*
48567f13b24aSBram Moolenaar  * Used after making another window the current one: change directory if
48577f13b24aSBram Moolenaar  * needed.
48587f13b24aSBram Moolenaar  */
48597f13b24aSBram Moolenaar     void
fix_current_dir(void)48607f13b24aSBram Moolenaar fix_current_dir(void)
48617f13b24aSBram Moolenaar {
48627f13b24aSBram Moolenaar     if (curwin->w_localdir != NULL || curtab->tp_localdir != NULL)
48637f13b24aSBram Moolenaar     {
48647f13b24aSBram Moolenaar 	char_u	*dirname;
48657f13b24aSBram Moolenaar 
48667f13b24aSBram Moolenaar 	// Window or tab has a local directory: Save current directory as
48677f13b24aSBram Moolenaar 	// global directory (unless that was done already) and change to the
48687f13b24aSBram Moolenaar 	// local directory.
48697f13b24aSBram Moolenaar 	if (globaldir == NULL)
48707f13b24aSBram Moolenaar 	{
48717f13b24aSBram Moolenaar 	    char_u	cwd[MAXPATHL];
48727f13b24aSBram Moolenaar 
48737f13b24aSBram Moolenaar 	    if (mch_dirname(cwd, MAXPATHL) == OK)
48747f13b24aSBram Moolenaar 		globaldir = vim_strsave(cwd);
48757f13b24aSBram Moolenaar 	}
48767f13b24aSBram Moolenaar 	if (curwin->w_localdir != NULL)
48777f13b24aSBram Moolenaar 	    dirname = curwin->w_localdir;
48787f13b24aSBram Moolenaar 	else
48797f13b24aSBram Moolenaar 	    dirname = curtab->tp_localdir;
48807f13b24aSBram Moolenaar 
48817f13b24aSBram Moolenaar 	if (mch_chdir((char *)dirname) == 0)
48820526815cSBram Moolenaar 	{
48830526815cSBram Moolenaar 	    last_chdir_reason = NULL;
48847f13b24aSBram Moolenaar 	    shorten_fnames(TRUE);
48857f13b24aSBram Moolenaar 	}
48860526815cSBram Moolenaar     }
48877f13b24aSBram Moolenaar     else if (globaldir != NULL)
48887f13b24aSBram Moolenaar     {
48897f13b24aSBram Moolenaar 	// Window doesn't have a local directory and we are not in the global
48907f13b24aSBram Moolenaar 	// directory: Change to the global directory.
48917f13b24aSBram Moolenaar 	vim_ignored = mch_chdir((char *)globaldir);
48927f13b24aSBram Moolenaar 	VIM_CLEAR(globaldir);
48930526815cSBram Moolenaar 	last_chdir_reason = NULL;
48947f13b24aSBram Moolenaar 	shorten_fnames(TRUE);
48957f13b24aSBram Moolenaar     }
48967f13b24aSBram Moolenaar }
4897071d4279SBram Moolenaar 
4898071d4279SBram Moolenaar /*
4899779b74b2SBram Moolenaar  * Jump to the first open window that contains buffer "buf", if one exists.
4900779b74b2SBram Moolenaar  * Returns a pointer to the window found, otherwise NULL.
4901071d4279SBram Moolenaar  */
4902071d4279SBram Moolenaar     win_T *
buf_jump_open_win(buf_T * buf)4903b638a7beSBram Moolenaar buf_jump_open_win(buf_T *buf)
4904071d4279SBram Moolenaar {
4905482a2b5cSBram Moolenaar     win_T	*wp = NULL;
4906071d4279SBram Moolenaar 
4907482a2b5cSBram Moolenaar     if (curwin->w_buffer == buf)
4908482a2b5cSBram Moolenaar 	wp = curwin;
4909482a2b5cSBram Moolenaar     else
491029323590SBram Moolenaar 	FOR_ALL_WINDOWS(wp)
4911071d4279SBram Moolenaar 	    if (wp->w_buffer == buf)
4912071d4279SBram Moolenaar 		break;
4913071d4279SBram Moolenaar     if (wp != NULL)
4914071d4279SBram Moolenaar 	win_enter(wp, FALSE);
4915482a2b5cSBram Moolenaar     return wp;
4916071d4279SBram Moolenaar }
4917779b74b2SBram Moolenaar 
4918779b74b2SBram Moolenaar /*
4919779b74b2SBram Moolenaar  * Jump to the first open window in any tab page that contains buffer "buf",
4920779b74b2SBram Moolenaar  * if one exists.
4921779b74b2SBram Moolenaar  * Returns a pointer to the window found, otherwise NULL.
4922779b74b2SBram Moolenaar  */
4923779b74b2SBram Moolenaar     win_T *
buf_jump_open_tab(buf_T * buf)4924b638a7beSBram Moolenaar buf_jump_open_tab(buf_T *buf)
4925779b74b2SBram Moolenaar {
4926482a2b5cSBram Moolenaar     win_T	*wp = buf_jump_open_win(buf);
4927779b74b2SBram Moolenaar     tabpage_T	*tp;
4928779b74b2SBram Moolenaar 
4929779b74b2SBram Moolenaar     if (wp != NULL)
4930779b74b2SBram Moolenaar 	return wp;
4931779b74b2SBram Moolenaar 
493229323590SBram Moolenaar     FOR_ALL_TABPAGES(tp)
4933779b74b2SBram Moolenaar 	if (tp != curtab)
4934779b74b2SBram Moolenaar 	{
4935aeea7215SBram Moolenaar 	    FOR_ALL_WINDOWS_IN_TAB(tp, wp)
4936779b74b2SBram Moolenaar 		if (wp->w_buffer == buf)
4937779b74b2SBram Moolenaar 		    break;
4938779b74b2SBram Moolenaar 	    if (wp != NULL)
4939779b74b2SBram Moolenaar 	    {
4940779b74b2SBram Moolenaar 		goto_tabpage_win(tp, wp);
4941779b74b2SBram Moolenaar 		if (curwin != wp)
4942e38eab22SBram Moolenaar 		    wp = NULL;	// something went wrong
4943779b74b2SBram Moolenaar 		break;
4944779b74b2SBram Moolenaar 	    }
4945779b74b2SBram Moolenaar 	}
4946482a2b5cSBram Moolenaar     return wp;
4947779b74b2SBram Moolenaar }
4948071d4279SBram Moolenaar 
4949888ccac8SBram Moolenaar static int last_win_id = LOWEST_WIN_ID - 1;
495086edef66SBram Moolenaar 
4951071d4279SBram Moolenaar /*
4952746ebd3bSBram Moolenaar  * Allocate a window structure and link it in the window list when "hidden" is
4953746ebd3bSBram Moolenaar  * FALSE.
4954071d4279SBram Moolenaar  */
4955071d4279SBram Moolenaar     static win_T *
win_alloc(win_T * after UNUSED,int hidden UNUSED)4956b638a7beSBram Moolenaar win_alloc(win_T *after UNUSED, int hidden UNUSED)
4957071d4279SBram Moolenaar {
495870b2a56dSBram Moolenaar     win_T	*new_wp;
4959071d4279SBram Moolenaar 
4960071d4279SBram Moolenaar     /*
4961071d4279SBram Moolenaar      * allocate window structure and linesizes arrays
4962071d4279SBram Moolenaar      */
4963c799fe20SBram Moolenaar     new_wp = ALLOC_CLEAR_ONE(win_T);
4964429fa853SBram Moolenaar     if (new_wp == NULL)
4965429fa853SBram Moolenaar 	return NULL;
4966429fa853SBram Moolenaar 
4967429fa853SBram Moolenaar     if (win_alloc_lines(new_wp) == FAIL)
4968071d4279SBram Moolenaar     {
496970b2a56dSBram Moolenaar 	vim_free(new_wp);
4970429fa853SBram Moolenaar 	return NULL;
4971071d4279SBram Moolenaar     }
4972071d4279SBram Moolenaar 
497386edef66SBram Moolenaar     new_wp->w_id = ++last_win_id;
497486edef66SBram Moolenaar 
4975429fa853SBram Moolenaar #ifdef FEAT_EVAL
4976e38eab22SBram Moolenaar     // init w: variables
4977429fa853SBram Moolenaar     new_wp->w_vars = dict_alloc();
4978429fa853SBram Moolenaar     if (new_wp->w_vars == NULL)
4979071d4279SBram Moolenaar     {
4980429fa853SBram Moolenaar 	win_free_lsize(new_wp);
4981429fa853SBram Moolenaar 	vim_free(new_wp);
4982429fa853SBram Moolenaar 	return NULL;
4983429fa853SBram Moolenaar     }
4984429fa853SBram Moolenaar     init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
4985429fa853SBram Moolenaar #endif
4986429fa853SBram Moolenaar 
4987e38eab22SBram Moolenaar     // Don't execute autocommands while the window is not properly
4988e38eab22SBram Moolenaar     // initialized yet.  gui_create_scrollbar() may trigger a FocusGained
4989e38eab22SBram Moolenaar     // event.
499078ab331eSBram Moolenaar     block_autocmds();
4991f2bd8ef2SBram Moolenaar 
4992071d4279SBram Moolenaar     /*
4993071d4279SBram Moolenaar      * link the window in the window list
4994071d4279SBram Moolenaar      */
4995746ebd3bSBram Moolenaar     if (!hidden)
499670b2a56dSBram Moolenaar 	win_append(after, new_wp);
499770b2a56dSBram Moolenaar     new_wp->w_wincol = 0;
499870b2a56dSBram Moolenaar     new_wp->w_width = Columns;
4999071d4279SBram Moolenaar 
5000e38eab22SBram Moolenaar     // position the display and the cursor at the top of the file.
500170b2a56dSBram Moolenaar     new_wp->w_topline = 1;
5002071d4279SBram Moolenaar #ifdef FEAT_DIFF
500370b2a56dSBram Moolenaar     new_wp->w_topfill = 0;
5004071d4279SBram Moolenaar #endif
500570b2a56dSBram Moolenaar     new_wp->w_botline = 2;
500670b2a56dSBram Moolenaar     new_wp->w_cursor.lnum = 1;
500770b2a56dSBram Moolenaar     new_wp->w_scbind_pos = 1;
5008071d4279SBram Moolenaar 
5009375e3390SBram Moolenaar     // use global option value for global-local options
5010375e3390SBram Moolenaar     new_wp->w_p_so = -1;
5011375e3390SBram Moolenaar     new_wp->w_p_siso = -1;
5012375e3390SBram Moolenaar 
5013e38eab22SBram Moolenaar     // We won't calculate w_fraction until resizing the window
501470b2a56dSBram Moolenaar     new_wp->w_fraction = 0;
501570b2a56dSBram Moolenaar     new_wp->w_prev_fraction_row = -1;
5016071d4279SBram Moolenaar 
5017071d4279SBram Moolenaar #ifdef FEAT_GUI
5018071d4279SBram Moolenaar     if (gui.in_use)
5019071d4279SBram Moolenaar     {
502070b2a56dSBram Moolenaar 	gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
502170b2a56dSBram Moolenaar 		SBAR_LEFT, new_wp);
502270b2a56dSBram Moolenaar 	gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
502370b2a56dSBram Moolenaar 		SBAR_RIGHT, new_wp);
5024071d4279SBram Moolenaar     }
5025071d4279SBram Moolenaar #endif
5026071d4279SBram Moolenaar #ifdef FEAT_FOLDING
502770b2a56dSBram Moolenaar     foldInitWin(new_wp);
5028071d4279SBram Moolenaar #endif
502978ab331eSBram Moolenaar     unblock_autocmds();
50306ee10162SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
503170b2a56dSBram Moolenaar     new_wp->w_match_head = NULL;
503270b2a56dSBram Moolenaar     new_wp->w_next_match_id = 4;
50336ee10162SBram Moolenaar #endif
503470b2a56dSBram Moolenaar     return new_wp;
5035071d4279SBram Moolenaar }
5036071d4279SBram Moolenaar 
5037071d4279SBram Moolenaar /*
5038ff18df03SBram Moolenaar  * Remove window 'wp' from the window list and free the structure.
5039071d4279SBram Moolenaar  */
5040071d4279SBram Moolenaar     static void
win_free(win_T * wp,tabpage_T * tp)5041b638a7beSBram Moolenaar win_free(
5042b638a7beSBram Moolenaar     win_T	*wp,
5043e38eab22SBram Moolenaar     tabpage_T	*tp)		// tab page "win" is in, NULL for current
5044071d4279SBram Moolenaar {
5045071d4279SBram Moolenaar     int		i;
5046ff18df03SBram Moolenaar     buf_T	*buf;
5047ff18df03SBram Moolenaar     wininfo_T	*wip;
5048071d4279SBram Moolenaar 
5049f061e0beSBram Moolenaar #ifdef FEAT_FOLDING
5050f061e0beSBram Moolenaar     clearFolding(wp);
5051f061e0beSBram Moolenaar #endif
5052f061e0beSBram Moolenaar 
5053e38eab22SBram Moolenaar     // reduce the reference count to the argument list.
5054f061e0beSBram Moolenaar     alist_unlink(wp->w_alist);
5055f061e0beSBram Moolenaar 
5056e38eab22SBram Moolenaar     // Don't execute autocommands while the window is halfway being deleted.
5057e38eab22SBram Moolenaar     // gui_mch_destroy_scrollbar() may trigger a FocusGained event.
505878ab331eSBram Moolenaar     block_autocmds();
5059ee79cbc7SBram Moolenaar 
50600ba04296SBram Moolenaar #ifdef FEAT_LUA
50610ba04296SBram Moolenaar     lua_window_free(wp);
50620ba04296SBram Moolenaar #endif
50630ba04296SBram Moolenaar 
5064325b7a2fSBram Moolenaar #ifdef FEAT_MZSCHEME
5065325b7a2fSBram Moolenaar     mzscheme_window_free(wp);
5066325b7a2fSBram Moolenaar #endif
5067325b7a2fSBram Moolenaar 
5068071d4279SBram Moolenaar #ifdef FEAT_PERL
5069071d4279SBram Moolenaar     perl_win_free(wp);
5070071d4279SBram Moolenaar #endif
5071071d4279SBram Moolenaar 
5072071d4279SBram Moolenaar #ifdef FEAT_PYTHON
5073071d4279SBram Moolenaar     python_window_free(wp);
5074071d4279SBram Moolenaar #endif
5075071d4279SBram Moolenaar 
5076bd5e15fdSBram Moolenaar #ifdef FEAT_PYTHON3
5077bd5e15fdSBram Moolenaar     python3_window_free(wp);
5078bd5e15fdSBram Moolenaar #endif
5079bd5e15fdSBram Moolenaar 
5080071d4279SBram Moolenaar #ifdef FEAT_TCL
5081071d4279SBram Moolenaar     tcl_window_free(wp);
5082071d4279SBram Moolenaar #endif
5083071d4279SBram Moolenaar 
5084071d4279SBram Moolenaar #ifdef FEAT_RUBY
5085071d4279SBram Moolenaar     ruby_window_free(wp);
5086071d4279SBram Moolenaar #endif
5087071d4279SBram Moolenaar 
5088071d4279SBram Moolenaar     clear_winopt(&wp->w_onebuf_opt);
5089071d4279SBram Moolenaar     clear_winopt(&wp->w_allbuf_opt);
5090071d4279SBram Moolenaar 
50917a33ebfcSzeertzjq     vim_free(wp->w_lcs_chars.multispace);
50927a33ebfcSzeertzjq 
5093071d4279SBram Moolenaar #ifdef FEAT_EVAL
5094e38eab22SBram Moolenaar     vars_clear(&wp->w_vars->dv_hashtab);	// free all w: variables
5095429fa853SBram Moolenaar     hash_init(&wp->w_vars->dv_hashtab);
5096429fa853SBram Moolenaar     unref_var_dict(wp->w_vars);
5097071d4279SBram Moolenaar #endif
5098071d4279SBram Moolenaar 
50993dda7db4SBram Moolenaar     {
51003dda7db4SBram Moolenaar 	tabpage_T	*ttp;
51013dda7db4SBram Moolenaar 
5102071d4279SBram Moolenaar 	if (prevwin == wp)
5103071d4279SBram Moolenaar 	    prevwin = NULL;
510429323590SBram Moolenaar 	FOR_ALL_TABPAGES(ttp)
51053dda7db4SBram Moolenaar 	    if (ttp->tp_prevwin == wp)
51063dda7db4SBram Moolenaar 		ttp->tp_prevwin = NULL;
51073dda7db4SBram Moolenaar     }
5108071d4279SBram Moolenaar     win_free_lsize(wp);
5109071d4279SBram Moolenaar 
5110071d4279SBram Moolenaar     for (i = 0; i < wp->w_tagstacklen; ++i)
511155008aadSBram Moolenaar     {
5112071d4279SBram Moolenaar 	vim_free(wp->w_tagstack[i].tagname);
511355008aadSBram Moolenaar 	vim_free(wp->w_tagstack[i].user_data);
511455008aadSBram Moolenaar     }
5115071d4279SBram Moolenaar     vim_free(wp->w_localdir);
5116002bc799SBram Moolenaar     vim_free(wp->w_prevdir);
51176ee10162SBram Moolenaar 
5118e38eab22SBram Moolenaar     // Remove the window from the b_wininfo lists, it may happen that the
5119e38eab22SBram Moolenaar     // freed memory is re-used for another window.
512029323590SBram Moolenaar     FOR_ALL_BUFFERS(buf)
5121aeea7215SBram Moolenaar 	FOR_ALL_BUF_WININFO(buf, wip)
5122ff18df03SBram Moolenaar 	    if (wip->wi_win == wp)
51234882d983SBram Moolenaar 	    {
51244882d983SBram Moolenaar 		wininfo_T	*wip2;
51254882d983SBram Moolenaar 
51264882d983SBram Moolenaar 		// If there already is an entry with "wi_win" set to NULL it
51274882d983SBram Moolenaar 		// must be removed, it would never be used.
5128b5098060SBram Moolenaar 		// Skip "wip" itself, otherwise Coverity complains.
51294882d983SBram Moolenaar 		for (wip2 = buf->b_wininfo; wip2 != NULL; wip2 = wip2->wi_next)
5130b5098060SBram Moolenaar 		    if (wip2 != wip && wip2->wi_win == NULL)
51314882d983SBram Moolenaar 		    {
51324882d983SBram Moolenaar 			if (wip2->wi_next != NULL)
51334882d983SBram Moolenaar 			    wip2->wi_next->wi_prev = wip2->wi_prev;
51344882d983SBram Moolenaar 			if (wip2->wi_prev == NULL)
51354882d983SBram Moolenaar 			    buf->b_wininfo = wip2->wi_next;
51364882d983SBram Moolenaar 			else
51374882d983SBram Moolenaar 			    wip2->wi_prev->wi_next = wip2->wi_next;
51384882d983SBram Moolenaar 			free_wininfo(wip2);
51394882d983SBram Moolenaar 			break;
51404882d983SBram Moolenaar 		    }
51414882d983SBram Moolenaar 
5142ff18df03SBram Moolenaar 		wip->wi_win = NULL;
51434882d983SBram Moolenaar 	    }
5144ff18df03SBram Moolenaar 
5145071d4279SBram Moolenaar #ifdef FEAT_SEARCH_EXTRA
51466ee10162SBram Moolenaar     clear_matches(wp);
5147071d4279SBram Moolenaar #endif
51486ee10162SBram Moolenaar 
5149071d4279SBram Moolenaar #ifdef FEAT_JUMPLIST
5150071d4279SBram Moolenaar     free_jumplist(wp);
5151071d4279SBram Moolenaar #endif
5152071d4279SBram Moolenaar 
515328c258fdSBram Moolenaar #ifdef FEAT_QUICKFIX
515428c258fdSBram Moolenaar     qf_free_all(wp);
515528c258fdSBram Moolenaar #endif
515628c258fdSBram Moolenaar 
5157071d4279SBram Moolenaar #ifdef FEAT_GUI
5158071d4279SBram Moolenaar     if (gui.in_use)
5159071d4279SBram Moolenaar     {
5160071d4279SBram Moolenaar 	gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
5161071d4279SBram Moolenaar 	gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
5162071d4279SBram Moolenaar     }
5163e38eab22SBram Moolenaar #endif // FEAT_GUI
5164071d4279SBram Moolenaar 
51651b9645deSBram Moolenaar #ifdef FEAT_MENU
51661b9645deSBram Moolenaar     remove_winbar(wp);
51671b9645deSBram Moolenaar #endif
516805ad5ff0SBram Moolenaar #ifdef FEAT_PROP_POPUP
51699eaac896SBram Moolenaar     free_callback(&wp->w_close_cb);
5170bf0eff0bSBram Moolenaar     free_callback(&wp->w_filter_cb);
5171790498b5SBram Moolenaar     for (i = 0; i < 4; ++i)
5172790498b5SBram Moolenaar 	VIM_CLEAR(wp->w_border_highlight[i]);
51734cd583c6SBram Moolenaar     vim_free(wp->w_scrollbar_highlight);
51744cd583c6SBram Moolenaar     vim_free(wp->w_thumb_highlight);
5175eb2310d4SBram Moolenaar     vim_free(wp->w_popup_title);
5176c662ec99SBram Moolenaar     list_unref(wp->w_popup_mask);
51770aca293fSBram Moolenaar     vim_free(wp->w_popup_mask_cells);
5178bf0eff0bSBram Moolenaar #endif
51791b9645deSBram Moolenaar 
5180860cae1cSBram Moolenaar #ifdef FEAT_SYN_HL
51811a38442dSBram Moolenaar     vim_free(wp->w_p_cc_cols);
5182860cae1cSBram Moolenaar #endif
5183860cae1cSBram Moolenaar 
51844d784b21SBram Moolenaar     if (win_valid_any_tab(wp))
5185f740b29aSBram Moolenaar 	win_remove(wp, tp);
51863be85856SBram Moolenaar     if (autocmd_busy)
51873be85856SBram Moolenaar     {
51883be85856SBram Moolenaar 	wp->w_next = au_pending_free_win;
51893be85856SBram Moolenaar 	au_pending_free_win = wp;
51903be85856SBram Moolenaar     }
51913be85856SBram Moolenaar     else
5192071d4279SBram Moolenaar 	vim_free(wp);
5193ee79cbc7SBram Moolenaar 
519478ab331eSBram Moolenaar     unblock_autocmds();
5195071d4279SBram Moolenaar }
5196071d4279SBram Moolenaar 
5197071d4279SBram Moolenaar /*
51984d784b21SBram Moolenaar  * Return TRUE if "wp" is not in the list of windows: the autocmd window or a
51994d784b21SBram Moolenaar  * popup window.
52004d784b21SBram Moolenaar  */
52015843f5f3SBram Moolenaar     static int
win_unlisted(win_T * wp)52024d784b21SBram Moolenaar win_unlisted(win_T *wp)
52034d784b21SBram Moolenaar {
52045b8cfedfSBram Moolenaar     return wp == aucmd_win || WIN_IS_POPUP(wp);
52054d784b21SBram Moolenaar }
52064d784b21SBram Moolenaar 
520705ad5ff0SBram Moolenaar #if defined(FEAT_PROP_POPUP) || defined(PROTO)
52084d784b21SBram Moolenaar /*
52094d784b21SBram Moolenaar  * Free a popup window.  This does not take the window out of the window list
52104d784b21SBram Moolenaar  * and assumes there is only one toplevel frame, no split.
52114d784b21SBram Moolenaar  */
52124d784b21SBram Moolenaar     void
win_free_popup(win_T * win)52134d784b21SBram Moolenaar win_free_popup(win_T *win)
52144d784b21SBram Moolenaar {
52155b8cfedfSBram Moolenaar     if (bt_popup(win->w_buffer))
521600b0d6d8SBram Moolenaar 	win_close_buffer(win, DOBUF_WIPE_REUSE, FALSE);
52175b8cfedfSBram Moolenaar     else
5218a6e8f888SBram Moolenaar 	close_buffer(win, win->w_buffer, 0, FALSE, FALSE);
521935d5af6cSBram Moolenaar # if defined(FEAT_TIMERS)
522051fe3b14SBram Moolenaar     if (win->w_popup_timer != NULL)
522151fe3b14SBram Moolenaar 	stop_timer(win->w_popup_timer);
522235d5af6cSBram Moolenaar # endif
52234d784b21SBram Moolenaar     vim_free(win->w_frame);
52244d784b21SBram Moolenaar     win_free(win, NULL);
52254d784b21SBram Moolenaar }
522635d5af6cSBram Moolenaar #endif
52274d784b21SBram Moolenaar 
52284d784b21SBram Moolenaar /*
5229071d4279SBram Moolenaar  * Append window "wp" in the window list after window "after".
5230071d4279SBram Moolenaar  */
52315843f5f3SBram Moolenaar     static void
win_append(win_T * after,win_T * wp)5232b638a7beSBram Moolenaar win_append(win_T *after, win_T *wp)
5233071d4279SBram Moolenaar {
5234071d4279SBram Moolenaar     win_T	*before;
5235071d4279SBram Moolenaar 
5236e38eab22SBram Moolenaar     if (after == NULL)	    // after NULL is in front of the first
5237071d4279SBram Moolenaar 	before = firstwin;
5238071d4279SBram Moolenaar     else
5239071d4279SBram Moolenaar 	before = after->w_next;
5240071d4279SBram Moolenaar 
5241071d4279SBram Moolenaar     wp->w_next = before;
5242071d4279SBram Moolenaar     wp->w_prev = after;
5243071d4279SBram Moolenaar     if (after == NULL)
5244071d4279SBram Moolenaar 	firstwin = wp;
5245071d4279SBram Moolenaar     else
5246071d4279SBram Moolenaar 	after->w_next = wp;
5247071d4279SBram Moolenaar     if (before == NULL)
5248071d4279SBram Moolenaar 	lastwin = wp;
5249071d4279SBram Moolenaar     else
5250071d4279SBram Moolenaar 	before->w_prev = wp;
5251071d4279SBram Moolenaar }
5252071d4279SBram Moolenaar 
5253071d4279SBram Moolenaar /*
5254071d4279SBram Moolenaar  * Remove a window from the window list.
5255071d4279SBram Moolenaar  */
5256746ebd3bSBram Moolenaar     void
win_remove(win_T * wp,tabpage_T * tp)5257b638a7beSBram Moolenaar win_remove(
5258b638a7beSBram Moolenaar     win_T	*wp,
5259e38eab22SBram Moolenaar     tabpage_T	*tp)		// tab page "win" is in, NULL for current
5260071d4279SBram Moolenaar {
5261071d4279SBram Moolenaar     if (wp->w_prev != NULL)
5262071d4279SBram Moolenaar 	wp->w_prev->w_next = wp->w_next;
5263f740b29aSBram Moolenaar     else if (tp == NULL)
5264816968deSBram Moolenaar 	firstwin = curtab->tp_firstwin = wp->w_next;
5265f740b29aSBram Moolenaar     else
5266f740b29aSBram Moolenaar 	tp->tp_firstwin = wp->w_next;
5267816968deSBram Moolenaar 
5268071d4279SBram Moolenaar     if (wp->w_next != NULL)
5269071d4279SBram Moolenaar 	wp->w_next->w_prev = wp->w_prev;
5270f740b29aSBram Moolenaar     else if (tp == NULL)
5271816968deSBram Moolenaar 	lastwin = curtab->tp_lastwin = wp->w_prev;
5272f740b29aSBram Moolenaar     else
5273f740b29aSBram Moolenaar 	tp->tp_lastwin = wp->w_prev;
5274071d4279SBram Moolenaar }
5275071d4279SBram Moolenaar 
5276071d4279SBram Moolenaar /*
5277071d4279SBram Moolenaar  * Append frame "frp" in a frame list after frame "after".
5278071d4279SBram Moolenaar  */
5279071d4279SBram Moolenaar     static void
frame_append(frame_T * after,frame_T * frp)5280b638a7beSBram Moolenaar frame_append(frame_T *after, frame_T *frp)
5281071d4279SBram Moolenaar {
5282071d4279SBram Moolenaar     frp->fr_next = after->fr_next;
5283071d4279SBram Moolenaar     after->fr_next = frp;
5284071d4279SBram Moolenaar     if (frp->fr_next != NULL)
5285071d4279SBram Moolenaar 	frp->fr_next->fr_prev = frp;
5286071d4279SBram Moolenaar     frp->fr_prev = after;
5287071d4279SBram Moolenaar }
5288071d4279SBram Moolenaar 
5289071d4279SBram Moolenaar /*
5290071d4279SBram Moolenaar  * Insert frame "frp" in a frame list before frame "before".
5291071d4279SBram Moolenaar  */
5292071d4279SBram Moolenaar     static void
frame_insert(frame_T * before,frame_T * frp)5293b638a7beSBram Moolenaar frame_insert(frame_T *before, frame_T *frp)
5294071d4279SBram Moolenaar {
5295071d4279SBram Moolenaar     frp->fr_next = before;
5296071d4279SBram Moolenaar     frp->fr_prev = before->fr_prev;
5297071d4279SBram Moolenaar     before->fr_prev = frp;
5298071d4279SBram Moolenaar     if (frp->fr_prev != NULL)
5299071d4279SBram Moolenaar 	frp->fr_prev->fr_next = frp;
5300071d4279SBram Moolenaar     else
5301071d4279SBram Moolenaar 	frp->fr_parent->fr_child = frp;
5302071d4279SBram Moolenaar }
5303071d4279SBram Moolenaar 
5304071d4279SBram Moolenaar /*
5305071d4279SBram Moolenaar  * Remove a frame from a frame list.
5306071d4279SBram Moolenaar  */
5307071d4279SBram Moolenaar     static void
frame_remove(frame_T * frp)5308b638a7beSBram Moolenaar frame_remove(frame_T *frp)
5309071d4279SBram Moolenaar {
5310071d4279SBram Moolenaar     if (frp->fr_prev != NULL)
5311071d4279SBram Moolenaar 	frp->fr_prev->fr_next = frp->fr_next;
5312071d4279SBram Moolenaar     else
5313071d4279SBram Moolenaar 	frp->fr_parent->fr_child = frp->fr_next;
5314071d4279SBram Moolenaar     if (frp->fr_next != NULL)
5315071d4279SBram Moolenaar 	frp->fr_next->fr_prev = frp->fr_prev;
5316071d4279SBram Moolenaar }
5317071d4279SBram Moolenaar 
5318071d4279SBram Moolenaar /*
5319071d4279SBram Moolenaar  * Allocate w_lines[] for window "wp".
5320071d4279SBram Moolenaar  * Return FAIL for failure, OK for success.
5321071d4279SBram Moolenaar  */
5322071d4279SBram Moolenaar     int
win_alloc_lines(win_T * wp)5323b638a7beSBram Moolenaar win_alloc_lines(win_T *wp)
5324071d4279SBram Moolenaar {
5325071d4279SBram Moolenaar     wp->w_lines_valid = 0;
5326c799fe20SBram Moolenaar     wp->w_lines = ALLOC_CLEAR_MULT(wline_T, Rows );
5327071d4279SBram Moolenaar     if (wp->w_lines == NULL)
5328071d4279SBram Moolenaar 	return FAIL;
5329071d4279SBram Moolenaar     return OK;
5330071d4279SBram Moolenaar }
5331071d4279SBram Moolenaar 
5332071d4279SBram Moolenaar /*
5333071d4279SBram Moolenaar  * free lsize arrays for a window
5334071d4279SBram Moolenaar  */
5335071d4279SBram Moolenaar     void
win_free_lsize(win_T * wp)5336b638a7beSBram Moolenaar win_free_lsize(win_T *wp)
5337071d4279SBram Moolenaar {
5338e38eab22SBram Moolenaar     // TODO: why would wp be NULL here?
533906e4a6dfSBram Moolenaar     if (wp != NULL)
5340d23a8236SBram Moolenaar 	VIM_CLEAR(wp->w_lines);
534106e4a6dfSBram Moolenaar }
5342071d4279SBram Moolenaar 
5343071d4279SBram Moolenaar /*
5344071d4279SBram Moolenaar  * Called from win_new_shellsize() after Rows changed.
5345f740b29aSBram Moolenaar  * This only does the current tab page, others must be done when made active.
5346071d4279SBram Moolenaar  */
5347071d4279SBram Moolenaar     void
shell_new_rows(void)5348b638a7beSBram Moolenaar shell_new_rows(void)
5349071d4279SBram Moolenaar {
53501d2ba7faSBram Moolenaar     int		h = (int)ROWS_AVAIL;
5351071d4279SBram Moolenaar 
5352e38eab22SBram Moolenaar     if (firstwin == NULL)	// not initialized yet
5353071d4279SBram Moolenaar 	return;
5354071d4279SBram Moolenaar     if (h < frame_minheight(topframe, NULL))
5355071d4279SBram Moolenaar 	h = frame_minheight(topframe, NULL);
5356be4d506bSBram Moolenaar 
5357e38eab22SBram Moolenaar     // First try setting the heights of windows with 'winfixheight'.  If
5358e38eab22SBram Moolenaar     // that doesn't result in the right height, forget about that option.
5359071d4279SBram Moolenaar     frame_new_height(topframe, h, FALSE, TRUE);
5360b893ac20SBram Moolenaar     if (!frame_check_height(topframe, h))
5361071d4279SBram Moolenaar 	frame_new_height(topframe, h, FALSE, FALSE);
5362071d4279SBram Moolenaar 
5363e38eab22SBram Moolenaar     (void)win_comp_pos();		// recompute w_winrow and w_wincol
5364071d4279SBram Moolenaar     compute_cmdrow();
5365c6fe9195SBram Moolenaar     curtab->tp_ch_used = p_ch;
536605159a0cSBram Moolenaar 
5367071d4279SBram Moolenaar #if 0
5368e38eab22SBram Moolenaar     // Disabled: don't want making the screen smaller make a window larger.
5369071d4279SBram Moolenaar     if (p_ea)
5370071d4279SBram Moolenaar 	win_equal(curwin, FALSE, 'v');
5371071d4279SBram Moolenaar #endif
5372071d4279SBram Moolenaar }
5373071d4279SBram Moolenaar 
5374071d4279SBram Moolenaar /*
5375071d4279SBram Moolenaar  * Called from win_new_shellsize() after Columns changed.
5376071d4279SBram Moolenaar  */
5377071d4279SBram Moolenaar     void
shell_new_columns(void)5378b638a7beSBram Moolenaar shell_new_columns(void)
5379071d4279SBram Moolenaar {
5380e38eab22SBram Moolenaar     if (firstwin == NULL)	// not initialized yet
5381071d4279SBram Moolenaar 	return;
5382be4d506bSBram Moolenaar 
5383e38eab22SBram Moolenaar     // First try setting the widths of windows with 'winfixwidth'.  If that
5384e38eab22SBram Moolenaar     // doesn't result in the right width, forget about that option.
5385be4d506bSBram Moolenaar     frame_new_width(topframe, (int)Columns, FALSE, TRUE);
5386b893ac20SBram Moolenaar     if (!frame_check_width(topframe, Columns))
5387be4d506bSBram Moolenaar 	frame_new_width(topframe, (int)Columns, FALSE, FALSE);
5388be4d506bSBram Moolenaar 
5389e38eab22SBram Moolenaar     (void)win_comp_pos();		// recompute w_winrow and w_wincol
5390071d4279SBram Moolenaar #if 0
5391e38eab22SBram Moolenaar     // Disabled: don't want making the screen smaller make a window larger.
5392071d4279SBram Moolenaar     if (p_ea)
5393071d4279SBram Moolenaar 	win_equal(curwin, FALSE, 'h');
5394071d4279SBram Moolenaar #endif
5395071d4279SBram Moolenaar }
5396071d4279SBram Moolenaar 
5397071d4279SBram Moolenaar #if defined(FEAT_CMDWIN) || defined(PROTO)
5398071d4279SBram Moolenaar /*
5399071d4279SBram Moolenaar  * Save the size of all windows in "gap".
5400071d4279SBram Moolenaar  */
5401071d4279SBram Moolenaar     void
win_size_save(garray_T * gap)5402b638a7beSBram Moolenaar win_size_save(garray_T *gap)
5403071d4279SBram Moolenaar 
5404071d4279SBram Moolenaar {
5405071d4279SBram Moolenaar     win_T	*wp;
5406071d4279SBram Moolenaar 
5407071d4279SBram Moolenaar     ga_init2(gap, (int)sizeof(int), 1);
54081c329c04SBram Moolenaar     if (ga_grow(gap, win_count() * 2 + 1) == OK)
54091c329c04SBram Moolenaar     {
54101c329c04SBram Moolenaar 	// first entry is value of 'lines'
54111c329c04SBram Moolenaar 	((int *)gap->ga_data)[gap->ga_len++] = Rows;
54121c329c04SBram Moolenaar 
541329323590SBram Moolenaar 	FOR_ALL_WINDOWS(wp)
5414071d4279SBram Moolenaar 	{
5415071d4279SBram Moolenaar 	    ((int *)gap->ga_data)[gap->ga_len++] =
5416071d4279SBram Moolenaar 					       wp->w_width + wp->w_vsep_width;
5417071d4279SBram Moolenaar 	    ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
5418071d4279SBram Moolenaar 	}
5419071d4279SBram Moolenaar     }
54201c329c04SBram Moolenaar }
5421071d4279SBram Moolenaar 
5422071d4279SBram Moolenaar /*
54231c329c04SBram Moolenaar  * Restore window sizes, but only if the number of windows is still the same
54241c329c04SBram Moolenaar  * and 'lines' didn't change.
5425071d4279SBram Moolenaar  * Does not free the growarray.
5426071d4279SBram Moolenaar  */
5427071d4279SBram Moolenaar     void
win_size_restore(garray_T * gap)5428b638a7beSBram Moolenaar win_size_restore(garray_T *gap)
5429071d4279SBram Moolenaar {
5430071d4279SBram Moolenaar     win_T	*wp;
5431b643e777SBram Moolenaar     int		i, j;
5432071d4279SBram Moolenaar 
54331c329c04SBram Moolenaar     if (win_count() * 2 + 1 == gap->ga_len
54341c329c04SBram Moolenaar 	    && ((int *)gap->ga_data)[0] == Rows)
5435071d4279SBram Moolenaar     {
5436e38eab22SBram Moolenaar 	// The order matters, because frames contain other frames, but it's
5437e38eab22SBram Moolenaar 	// difficult to get right. The easy way out is to do it twice.
5438b643e777SBram Moolenaar 	for (j = 0; j < 2; ++j)
5439b643e777SBram Moolenaar 	{
54401c329c04SBram Moolenaar 	    i = 1;
544129323590SBram Moolenaar 	    FOR_ALL_WINDOWS(wp)
5442071d4279SBram Moolenaar 	    {
5443071d4279SBram Moolenaar 		frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
5444071d4279SBram Moolenaar 		win_setheight_win(((int *)gap->ga_data)[i++], wp);
5445071d4279SBram Moolenaar 	    }
5446b643e777SBram Moolenaar 	}
5447e38eab22SBram Moolenaar 	// recompute the window positions
5448071d4279SBram Moolenaar 	(void)win_comp_pos();
5449071d4279SBram Moolenaar     }
5450071d4279SBram Moolenaar }
5451e38eab22SBram Moolenaar #endif // FEAT_CMDWIN
5452071d4279SBram Moolenaar 
5453071d4279SBram Moolenaar /*
5454071d4279SBram Moolenaar  * Update the position for all windows, using the width and height of the
5455071d4279SBram Moolenaar  * frames.
5456071d4279SBram Moolenaar  * Returns the row just after the last window.
5457071d4279SBram Moolenaar  */
545898ea5defSBram Moolenaar     int
win_comp_pos(void)5459b638a7beSBram Moolenaar win_comp_pos(void)
5460071d4279SBram Moolenaar {
546132466aa2SBram Moolenaar     int		row = tabline_height();
5462071d4279SBram Moolenaar     int		col = 0;
5463071d4279SBram Moolenaar 
5464071d4279SBram Moolenaar     frame_comp_pos(topframe, &row, &col);
5465071d4279SBram Moolenaar     return row;
5466071d4279SBram Moolenaar }
5467071d4279SBram Moolenaar 
5468071d4279SBram Moolenaar /*
5469071d4279SBram Moolenaar  * Update the position of the windows in frame "topfrp", using the width and
5470071d4279SBram Moolenaar  * height of the frames.
5471071d4279SBram Moolenaar  * "*row" and "*col" are the top-left position of the frame.  They are updated
5472071d4279SBram Moolenaar  * to the bottom-right position plus one.
5473071d4279SBram Moolenaar  */
5474071d4279SBram Moolenaar     static void
frame_comp_pos(frame_T * topfrp,int * row,int * col)5475b638a7beSBram Moolenaar frame_comp_pos(frame_T *topfrp, int *row, int *col)
5476071d4279SBram Moolenaar {
5477071d4279SBram Moolenaar     win_T	*wp;
5478071d4279SBram Moolenaar     frame_T	*frp;
5479071d4279SBram Moolenaar     int		startcol;
5480071d4279SBram Moolenaar     int		startrow;
5481415a6939SBram Moolenaar     int		h;
5482071d4279SBram Moolenaar 
5483071d4279SBram Moolenaar     wp = topfrp->fr_win;
5484071d4279SBram Moolenaar     if (wp != NULL)
5485071d4279SBram Moolenaar     {
548644a2f923SBram Moolenaar 	if (wp->w_winrow != *row || wp->w_wincol != *col)
5487071d4279SBram Moolenaar 	{
5488e38eab22SBram Moolenaar 	    // position changed, redraw
5489071d4279SBram Moolenaar 	    wp->w_winrow = *row;
5490071d4279SBram Moolenaar 	    wp->w_wincol = *col;
5491071d4279SBram Moolenaar 	    redraw_win_later(wp, NOT_VALID);
5492071d4279SBram Moolenaar 	    wp->w_redr_status = TRUE;
5493071d4279SBram Moolenaar 	}
5494e38eab22SBram Moolenaar 	// WinBar will not show if the window height is zero
5495415a6939SBram Moolenaar 	h = VISIBLE_HEIGHT(wp) + wp->w_status_height;
5496415a6939SBram Moolenaar 	*row += h > topfrp->fr_height ? topfrp->fr_height : h;
5497071d4279SBram Moolenaar 	*col += wp->w_width + wp->w_vsep_width;
5498071d4279SBram Moolenaar     }
5499071d4279SBram Moolenaar     else
5500071d4279SBram Moolenaar     {
5501071d4279SBram Moolenaar 	startrow = *row;
5502071d4279SBram Moolenaar 	startcol = *col;
55033d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
5504071d4279SBram Moolenaar 	{
5505071d4279SBram Moolenaar 	    if (topfrp->fr_layout == FR_ROW)
5506e38eab22SBram Moolenaar 		*row = startrow;	// all frames are at the same row
5507071d4279SBram Moolenaar 	    else
5508e38eab22SBram Moolenaar 		*col = startcol;	// all frames are at the same col
5509071d4279SBram Moolenaar 	    frame_comp_pos(frp, row, col);
5510071d4279SBram Moolenaar 	}
5511071d4279SBram Moolenaar     }
5512071d4279SBram Moolenaar }
5513071d4279SBram Moolenaar 
5514071d4279SBram Moolenaar /*
5515071d4279SBram Moolenaar  * Set current window height and take care of repositioning other windows to
5516071d4279SBram Moolenaar  * fit around it.
5517071d4279SBram Moolenaar  */
5518071d4279SBram Moolenaar     void
win_setheight(int height)5519b638a7beSBram Moolenaar win_setheight(int height)
5520071d4279SBram Moolenaar {
5521071d4279SBram Moolenaar     win_setheight_win(height, curwin);
5522071d4279SBram Moolenaar }
5523071d4279SBram Moolenaar 
5524071d4279SBram Moolenaar /*
5525071d4279SBram Moolenaar  * Set the window height of window "win" and take care of repositioning other
5526071d4279SBram Moolenaar  * windows to fit around it.
5527071d4279SBram Moolenaar  */
5528071d4279SBram Moolenaar     void
win_setheight_win(int height,win_T * win)5529b638a7beSBram Moolenaar win_setheight_win(int height, win_T *win)
5530071d4279SBram Moolenaar {
5531071d4279SBram Moolenaar     int		row;
5532071d4279SBram Moolenaar 
5533071d4279SBram Moolenaar     if (win == curwin)
5534071d4279SBram Moolenaar     {
5535e38eab22SBram Moolenaar 	// Always keep current window at least one line high, even when
5536e38eab22SBram Moolenaar 	// 'winminheight' is zero.
5537071d4279SBram Moolenaar 	if (height < p_wmh)
5538071d4279SBram Moolenaar 	    height = p_wmh;
5539071d4279SBram Moolenaar 	if (height == 0)
5540071d4279SBram Moolenaar 	    height = 1;
5541415a6939SBram Moolenaar 	height += WINBAR_HEIGHT(curwin);
5542071d4279SBram Moolenaar     }
5543071d4279SBram Moolenaar 
5544071d4279SBram Moolenaar     frame_setheight(win->w_frame, height + win->w_status_height);
5545071d4279SBram Moolenaar 
5546e38eab22SBram Moolenaar     // recompute the window positions
5547071d4279SBram Moolenaar     row = win_comp_pos();
5548071d4279SBram Moolenaar 
5549071d4279SBram Moolenaar     /*
5550071d4279SBram Moolenaar      * If there is extra space created between the last window and the command
5551071d4279SBram Moolenaar      * line, clear it.
5552071d4279SBram Moolenaar      */
5553071d4279SBram Moolenaar     if (full_screen && msg_scrolled == 0 && row < cmdline_row)
5554071d4279SBram Moolenaar 	screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5555071d4279SBram Moolenaar     cmdline_row = row;
5556071d4279SBram Moolenaar     msg_row = row;
5557071d4279SBram Moolenaar     msg_col = 0;
5558071d4279SBram Moolenaar 
5559071d4279SBram Moolenaar     redraw_all_later(NOT_VALID);
5560071d4279SBram Moolenaar }
5561071d4279SBram Moolenaar 
5562071d4279SBram Moolenaar /*
5563071d4279SBram Moolenaar  * Set the height of a frame to "height" and take care that all frames and
5564071d4279SBram Moolenaar  * windows inside it are resized.  Also resize frames on the left and right if
5565071d4279SBram Moolenaar  * the are in the same FR_ROW frame.
5566071d4279SBram Moolenaar  *
5567071d4279SBram Moolenaar  * Strategy:
5568071d4279SBram Moolenaar  * If the frame is part of a FR_COL frame, try fitting the frame in that
5569071d4279SBram Moolenaar  * frame.  If that doesn't work (the FR_COL frame is too small), recursively
5570071d4279SBram Moolenaar  * go to containing frames to resize them and make room.
5571071d4279SBram Moolenaar  * If the frame is part of a FR_ROW frame, all frames must be resized as well.
5572071d4279SBram Moolenaar  * Check for the minimal height of the FR_ROW frame.
5573071d4279SBram Moolenaar  * At the top level we can also use change the command line height.
5574071d4279SBram Moolenaar  */
5575071d4279SBram Moolenaar     static void
frame_setheight(frame_T * curfrp,int height)5576b638a7beSBram Moolenaar frame_setheight(frame_T *curfrp, int height)
5577071d4279SBram Moolenaar {
5578e38eab22SBram Moolenaar     int		room;		// total number of lines available
5579e38eab22SBram Moolenaar     int		take;		// number of lines taken from other windows
5580e38eab22SBram Moolenaar     int		room_cmdline;	// lines available from cmdline
5581071d4279SBram Moolenaar     int		run;
5582071d4279SBram Moolenaar     frame_T	*frp;
5583071d4279SBram Moolenaar     int		h;
5584071d4279SBram Moolenaar     int		room_reserved;
5585071d4279SBram Moolenaar 
5586e38eab22SBram Moolenaar     // If the height already is the desired value, nothing to do.
5587071d4279SBram Moolenaar     if (curfrp->fr_height == height)
5588071d4279SBram Moolenaar 	return;
5589071d4279SBram Moolenaar 
5590071d4279SBram Moolenaar     if (curfrp->fr_parent == NULL)
5591071d4279SBram Moolenaar     {
5592e38eab22SBram Moolenaar 	// topframe: can only change the command line
55931d2ba7faSBram Moolenaar 	if (height > ROWS_AVAIL)
55941d2ba7faSBram Moolenaar 	    height = ROWS_AVAIL;
5595071d4279SBram Moolenaar 	if (height > 0)
5596071d4279SBram Moolenaar 	    frame_new_height(curfrp, height, FALSE, FALSE);
5597071d4279SBram Moolenaar     }
5598071d4279SBram Moolenaar     else if (curfrp->fr_parent->fr_layout == FR_ROW)
5599071d4279SBram Moolenaar     {
5600e38eab22SBram Moolenaar 	// Row of frames: Also need to resize frames left and right of this
5601e38eab22SBram Moolenaar 	// one.  First check for the minimal height of these.
5602071d4279SBram Moolenaar 	h = frame_minheight(curfrp->fr_parent, NULL);
5603071d4279SBram Moolenaar 	if (height < h)
5604071d4279SBram Moolenaar 	    height = h;
5605071d4279SBram Moolenaar 	frame_setheight(curfrp->fr_parent, height);
5606071d4279SBram Moolenaar     }
5607071d4279SBram Moolenaar     else
5608071d4279SBram Moolenaar     {
5609071d4279SBram Moolenaar 	/*
5610071d4279SBram Moolenaar 	 * Column of frames: try to change only frames in this column.
5611071d4279SBram Moolenaar 	 */
5612071d4279SBram Moolenaar 	/*
5613071d4279SBram Moolenaar 	 * Do this twice:
5614071d4279SBram Moolenaar 	 * 1: compute room available, if it's not enough try resizing the
5615071d4279SBram Moolenaar 	 *    containing frame.
5616071d4279SBram Moolenaar 	 * 2: compute the room available and adjust the height to it.
5617071d4279SBram Moolenaar 	 * Try not to reduce the height of a window with 'winfixheight' set.
5618071d4279SBram Moolenaar 	 */
5619071d4279SBram Moolenaar 	for (run = 1; run <= 2; ++run)
5620071d4279SBram Moolenaar 	{
5621071d4279SBram Moolenaar 	    room = 0;
5622071d4279SBram Moolenaar 	    room_reserved = 0;
56233d1491edSBram Moolenaar 	    FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
5624071d4279SBram Moolenaar 	    {
5625071d4279SBram Moolenaar 		if (frp != curfrp
5626071d4279SBram Moolenaar 			&& frp->fr_win != NULL
5627071d4279SBram Moolenaar 			&& frp->fr_win->w_p_wfh)
5628071d4279SBram Moolenaar 		    room_reserved += frp->fr_height;
5629071d4279SBram Moolenaar 		room += frp->fr_height;
5630071d4279SBram Moolenaar 		if (frp != curfrp)
5631071d4279SBram Moolenaar 		    room -= frame_minheight(frp, NULL);
5632071d4279SBram Moolenaar 	    }
5633071d4279SBram Moolenaar 	    if (curfrp->fr_width != Columns)
5634071d4279SBram Moolenaar 		room_cmdline = 0;
5635071d4279SBram Moolenaar 	    else
5636071d4279SBram Moolenaar 	    {
5637071d4279SBram Moolenaar 		room_cmdline = Rows - p_ch - (lastwin->w_winrow
5638415a6939SBram Moolenaar 						+ VISIBLE_HEIGHT(lastwin)
5639415a6939SBram Moolenaar 						+ lastwin->w_status_height);
5640071d4279SBram Moolenaar 		if (room_cmdline < 0)
5641071d4279SBram Moolenaar 		    room_cmdline = 0;
5642071d4279SBram Moolenaar 	    }
5643071d4279SBram Moolenaar 
5644071d4279SBram Moolenaar 	    if (height <= room + room_cmdline)
5645071d4279SBram Moolenaar 		break;
5646071d4279SBram Moolenaar 	    if (run == 2 || curfrp->fr_width == Columns)
5647071d4279SBram Moolenaar 	    {
5648071d4279SBram Moolenaar 		if (height > room + room_cmdline)
5649071d4279SBram Moolenaar 		    height = room + room_cmdline;
5650071d4279SBram Moolenaar 		break;
5651071d4279SBram Moolenaar 	    }
5652071d4279SBram Moolenaar 	    frame_setheight(curfrp->fr_parent, height
5653071d4279SBram Moolenaar 		+ frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
5654071d4279SBram Moolenaar 	}
5655071d4279SBram Moolenaar 
5656071d4279SBram Moolenaar 	/*
5657071d4279SBram Moolenaar 	 * Compute the number of lines we will take from others frames (can be
5658071d4279SBram Moolenaar 	 * negative!).
5659071d4279SBram Moolenaar 	 */
5660071d4279SBram Moolenaar 	take = height - curfrp->fr_height;
5661071d4279SBram Moolenaar 
5662e38eab22SBram Moolenaar 	// If there is not enough room, also reduce the height of a window
5663e38eab22SBram Moolenaar 	// with 'winfixheight' set.
5664071d4279SBram Moolenaar 	if (height > room + room_cmdline - room_reserved)
5665071d4279SBram Moolenaar 	    room_reserved = room + room_cmdline - height;
5666e38eab22SBram Moolenaar 	// If there is only a 'winfixheight' window and making the
5667e38eab22SBram Moolenaar 	// window smaller, need to make the other window taller.
5668071d4279SBram Moolenaar 	if (take < 0 && room - curfrp->fr_height < room_reserved)
5669071d4279SBram Moolenaar 	    room_reserved = 0;
5670071d4279SBram Moolenaar 
5671071d4279SBram Moolenaar 	if (take > 0 && room_cmdline > 0)
5672071d4279SBram Moolenaar 	{
5673e38eab22SBram Moolenaar 	    // use lines from cmdline first
5674071d4279SBram Moolenaar 	    if (take < room_cmdline)
5675071d4279SBram Moolenaar 		room_cmdline = take;
5676071d4279SBram Moolenaar 	    take -= room_cmdline;
5677071d4279SBram Moolenaar 	    topframe->fr_height += room_cmdline;
5678071d4279SBram Moolenaar 	}
5679071d4279SBram Moolenaar 
5680071d4279SBram Moolenaar 	/*
5681071d4279SBram Moolenaar 	 * set the current frame to the new height
5682071d4279SBram Moolenaar 	 */
5683071d4279SBram Moolenaar 	frame_new_height(curfrp, height, FALSE, FALSE);
5684071d4279SBram Moolenaar 
5685071d4279SBram Moolenaar 	/*
5686071d4279SBram Moolenaar 	 * First take lines from the frames after the current frame.  If
5687071d4279SBram Moolenaar 	 * that is not enough, takes lines from frames above the current
5688071d4279SBram Moolenaar 	 * frame.
5689071d4279SBram Moolenaar 	 */
5690071d4279SBram Moolenaar 	for (run = 0; run < 2; ++run)
5691071d4279SBram Moolenaar 	{
5692071d4279SBram Moolenaar 	    if (run == 0)
5693e38eab22SBram Moolenaar 		frp = curfrp->fr_next;	// 1st run: start with next window
5694071d4279SBram Moolenaar 	    else
5695e38eab22SBram Moolenaar 		frp = curfrp->fr_prev;	// 2nd run: start with prev window
5696071d4279SBram Moolenaar 	    while (frp != NULL && take != 0)
5697071d4279SBram Moolenaar 	    {
5698071d4279SBram Moolenaar 		h = frame_minheight(frp, NULL);
5699071d4279SBram Moolenaar 		if (room_reserved > 0
5700071d4279SBram Moolenaar 			&& frp->fr_win != NULL
5701071d4279SBram Moolenaar 			&& frp->fr_win->w_p_wfh)
5702071d4279SBram Moolenaar 		{
5703071d4279SBram Moolenaar 		    if (room_reserved >= frp->fr_height)
5704071d4279SBram Moolenaar 			room_reserved -= frp->fr_height;
5705071d4279SBram Moolenaar 		    else
5706071d4279SBram Moolenaar 		    {
5707071d4279SBram Moolenaar 			if (frp->fr_height - room_reserved > take)
5708071d4279SBram Moolenaar 			    room_reserved = frp->fr_height - take;
5709071d4279SBram Moolenaar 			take -= frp->fr_height - room_reserved;
5710071d4279SBram Moolenaar 			frame_new_height(frp, room_reserved, FALSE, FALSE);
5711071d4279SBram Moolenaar 			room_reserved = 0;
5712071d4279SBram Moolenaar 		    }
5713071d4279SBram Moolenaar 		}
5714071d4279SBram Moolenaar 		else
5715071d4279SBram Moolenaar 		{
5716071d4279SBram Moolenaar 		    if (frp->fr_height - take < h)
5717071d4279SBram Moolenaar 		    {
5718071d4279SBram Moolenaar 			take -= frp->fr_height - h;
5719071d4279SBram Moolenaar 			frame_new_height(frp, h, FALSE, FALSE);
5720071d4279SBram Moolenaar 		    }
5721071d4279SBram Moolenaar 		    else
5722071d4279SBram Moolenaar 		    {
5723071d4279SBram Moolenaar 			frame_new_height(frp, frp->fr_height - take,
5724071d4279SBram Moolenaar 								FALSE, FALSE);
5725071d4279SBram Moolenaar 			take = 0;
5726071d4279SBram Moolenaar 		    }
5727071d4279SBram Moolenaar 		}
5728071d4279SBram Moolenaar 		if (run == 0)
5729071d4279SBram Moolenaar 		    frp = frp->fr_next;
5730071d4279SBram Moolenaar 		else
5731071d4279SBram Moolenaar 		    frp = frp->fr_prev;
5732071d4279SBram Moolenaar 	    }
5733071d4279SBram Moolenaar 	}
5734071d4279SBram Moolenaar     }
5735071d4279SBram Moolenaar }
5736071d4279SBram Moolenaar 
5737071d4279SBram Moolenaar /*
5738071d4279SBram Moolenaar  * Set current window width and take care of repositioning other windows to
5739071d4279SBram Moolenaar  * fit around it.
5740071d4279SBram Moolenaar  */
5741071d4279SBram Moolenaar     void
win_setwidth(int width)5742b638a7beSBram Moolenaar win_setwidth(int width)
5743071d4279SBram Moolenaar {
5744071d4279SBram Moolenaar     win_setwidth_win(width, curwin);
5745071d4279SBram Moolenaar }
5746071d4279SBram Moolenaar 
5747071d4279SBram Moolenaar     void
win_setwidth_win(int width,win_T * wp)5748b638a7beSBram Moolenaar win_setwidth_win(int width, win_T *wp)
5749071d4279SBram Moolenaar {
5750e38eab22SBram Moolenaar     // Always keep current window at least one column wide, even when
5751e38eab22SBram Moolenaar     // 'winminwidth' is zero.
5752071d4279SBram Moolenaar     if (wp == curwin)
5753071d4279SBram Moolenaar     {
5754071d4279SBram Moolenaar 	if (width < p_wmw)
5755071d4279SBram Moolenaar 	    width = p_wmw;
5756071d4279SBram Moolenaar 	if (width == 0)
5757071d4279SBram Moolenaar 	    width = 1;
5758071d4279SBram Moolenaar     }
575989015a67SBram Moolenaar     else if (width < 0)
576089015a67SBram Moolenaar 	width = 0;
5761071d4279SBram Moolenaar 
5762071d4279SBram Moolenaar     frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
5763071d4279SBram Moolenaar 
5764e38eab22SBram Moolenaar     // recompute the window positions
5765071d4279SBram Moolenaar     (void)win_comp_pos();
5766071d4279SBram Moolenaar 
5767071d4279SBram Moolenaar     redraw_all_later(NOT_VALID);
5768071d4279SBram Moolenaar }
5769071d4279SBram Moolenaar 
5770071d4279SBram Moolenaar /*
5771071d4279SBram Moolenaar  * Set the width of a frame to "width" and take care that all frames and
5772071d4279SBram Moolenaar  * windows inside it are resized.  Also resize frames above and below if the
5773071d4279SBram Moolenaar  * are in the same FR_ROW frame.
5774071d4279SBram Moolenaar  *
5775071d4279SBram Moolenaar  * Strategy is similar to frame_setheight().
5776071d4279SBram Moolenaar  */
5777071d4279SBram Moolenaar     static void
frame_setwidth(frame_T * curfrp,int width)5778b638a7beSBram Moolenaar frame_setwidth(frame_T *curfrp, int width)
5779071d4279SBram Moolenaar {
5780e38eab22SBram Moolenaar     int		room;		// total number of lines available
5781e38eab22SBram Moolenaar     int		take;		// number of lines taken from other windows
5782071d4279SBram Moolenaar     int		run;
5783071d4279SBram Moolenaar     frame_T	*frp;
5784071d4279SBram Moolenaar     int		w;
5785be4d506bSBram Moolenaar     int		room_reserved;
5786071d4279SBram Moolenaar 
5787e38eab22SBram Moolenaar     // If the width already is the desired value, nothing to do.
5788071d4279SBram Moolenaar     if (curfrp->fr_width == width)
5789071d4279SBram Moolenaar 	return;
5790071d4279SBram Moolenaar 
5791071d4279SBram Moolenaar     if (curfrp->fr_parent == NULL)
5792e38eab22SBram Moolenaar 	// topframe: can't change width
5793071d4279SBram Moolenaar 	return;
5794071d4279SBram Moolenaar 
5795071d4279SBram Moolenaar     if (curfrp->fr_parent->fr_layout == FR_COL)
5796071d4279SBram Moolenaar     {
5797e38eab22SBram Moolenaar 	// Column of frames: Also need to resize frames above and below of
5798e38eab22SBram Moolenaar 	// this one.  First check for the minimal width of these.
5799071d4279SBram Moolenaar 	w = frame_minwidth(curfrp->fr_parent, NULL);
5800071d4279SBram Moolenaar 	if (width < w)
5801071d4279SBram Moolenaar 	    width = w;
5802071d4279SBram Moolenaar 	frame_setwidth(curfrp->fr_parent, width);
5803071d4279SBram Moolenaar     }
5804071d4279SBram Moolenaar     else
5805071d4279SBram Moolenaar     {
5806071d4279SBram Moolenaar 	/*
5807071d4279SBram Moolenaar 	 * Row of frames: try to change only frames in this row.
5808071d4279SBram Moolenaar 	 *
5809071d4279SBram Moolenaar 	 * Do this twice:
5810071d4279SBram Moolenaar 	 * 1: compute room available, if it's not enough try resizing the
5811071d4279SBram Moolenaar 	 *    containing frame.
5812071d4279SBram Moolenaar 	 * 2: compute the room available and adjust the width to it.
5813071d4279SBram Moolenaar 	 */
5814071d4279SBram Moolenaar 	for (run = 1; run <= 2; ++run)
5815071d4279SBram Moolenaar 	{
5816071d4279SBram Moolenaar 	    room = 0;
5817be4d506bSBram Moolenaar 	    room_reserved = 0;
58183d1491edSBram Moolenaar 	    FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
5819071d4279SBram Moolenaar 	    {
5820be4d506bSBram Moolenaar 		if (frp != curfrp
5821be4d506bSBram Moolenaar 			&& frp->fr_win != NULL
5822be4d506bSBram Moolenaar 			&& frp->fr_win->w_p_wfw)
5823be4d506bSBram Moolenaar 		    room_reserved += frp->fr_width;
5824071d4279SBram Moolenaar 		room += frp->fr_width;
5825071d4279SBram Moolenaar 		if (frp != curfrp)
5826071d4279SBram Moolenaar 		    room -= frame_minwidth(frp, NULL);
5827071d4279SBram Moolenaar 	    }
5828071d4279SBram Moolenaar 
5829071d4279SBram Moolenaar 	    if (width <= room)
5830071d4279SBram Moolenaar 		break;
58311d2ba7faSBram Moolenaar 	    if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
5832071d4279SBram Moolenaar 	    {
5833071d4279SBram Moolenaar 		if (width > room)
5834071d4279SBram Moolenaar 		    width = room;
5835071d4279SBram Moolenaar 		break;
5836071d4279SBram Moolenaar 	    }
5837071d4279SBram Moolenaar 	    frame_setwidth(curfrp->fr_parent, width
5838071d4279SBram Moolenaar 		 + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
5839071d4279SBram Moolenaar 	}
5840071d4279SBram Moolenaar 
5841071d4279SBram Moolenaar 	/*
5842071d4279SBram Moolenaar 	 * Compute the number of lines we will take from others frames (can be
5843071d4279SBram Moolenaar 	 * negative!).
5844071d4279SBram Moolenaar 	 */
5845071d4279SBram Moolenaar 	take = width - curfrp->fr_width;
5846071d4279SBram Moolenaar 
5847e38eab22SBram Moolenaar 	// If there is not enough room, also reduce the width of a window
5848e38eab22SBram Moolenaar 	// with 'winfixwidth' set.
5849be4d506bSBram Moolenaar 	if (width > room - room_reserved)
5850be4d506bSBram Moolenaar 	    room_reserved = room - width;
5851e38eab22SBram Moolenaar 	// If there is only a 'winfixwidth' window and making the
5852e38eab22SBram Moolenaar 	// window smaller, need to make the other window narrower.
5853be4d506bSBram Moolenaar 	if (take < 0 && room - curfrp->fr_width < room_reserved)
5854be4d506bSBram Moolenaar 	    room_reserved = 0;
5855be4d506bSBram Moolenaar 
5856071d4279SBram Moolenaar 	/*
5857071d4279SBram Moolenaar 	 * set the current frame to the new width
5858071d4279SBram Moolenaar 	 */
5859be4d506bSBram Moolenaar 	frame_new_width(curfrp, width, FALSE, FALSE);
5860071d4279SBram Moolenaar 
5861071d4279SBram Moolenaar 	/*
5862071d4279SBram Moolenaar 	 * First take lines from the frames right of the current frame.  If
5863071d4279SBram Moolenaar 	 * that is not enough, takes lines from frames left of the current
5864071d4279SBram Moolenaar 	 * frame.
5865071d4279SBram Moolenaar 	 */
5866071d4279SBram Moolenaar 	for (run = 0; run < 2; ++run)
5867071d4279SBram Moolenaar 	{
5868071d4279SBram Moolenaar 	    if (run == 0)
5869e38eab22SBram Moolenaar 		frp = curfrp->fr_next;	// 1st run: start with next window
5870071d4279SBram Moolenaar 	    else
5871e38eab22SBram Moolenaar 		frp = curfrp->fr_prev;	// 2nd run: start with prev window
5872071d4279SBram Moolenaar 	    while (frp != NULL && take != 0)
5873071d4279SBram Moolenaar 	    {
5874071d4279SBram Moolenaar 		w = frame_minwidth(frp, NULL);
5875be4d506bSBram Moolenaar 		if (room_reserved > 0
5876be4d506bSBram Moolenaar 			&& frp->fr_win != NULL
5877be4d506bSBram Moolenaar 			&& frp->fr_win->w_p_wfw)
5878071d4279SBram Moolenaar 		{
5879be4d506bSBram Moolenaar 		    if (room_reserved >= frp->fr_width)
5880be4d506bSBram Moolenaar 			room_reserved -= frp->fr_width;
5881be4d506bSBram Moolenaar 		    else
5882be4d506bSBram Moolenaar 		    {
5883be4d506bSBram Moolenaar 			if (frp->fr_width - room_reserved > take)
5884be4d506bSBram Moolenaar 			    room_reserved = frp->fr_width - take;
5885be4d506bSBram Moolenaar 			take -= frp->fr_width - room_reserved;
5886be4d506bSBram Moolenaar 			frame_new_width(frp, room_reserved, FALSE, FALSE);
5887be4d506bSBram Moolenaar 			room_reserved = 0;
5888be4d506bSBram Moolenaar 		    }
5889071d4279SBram Moolenaar 		}
5890071d4279SBram Moolenaar 		else
5891071d4279SBram Moolenaar 		{
5892be4d506bSBram Moolenaar 		    if (frp->fr_width - take < w)
5893be4d506bSBram Moolenaar 		    {
5894be4d506bSBram Moolenaar 			take -= frp->fr_width - w;
5895be4d506bSBram Moolenaar 			frame_new_width(frp, w, FALSE, FALSE);
5896be4d506bSBram Moolenaar 		    }
5897be4d506bSBram Moolenaar 		    else
5898be4d506bSBram Moolenaar 		    {
5899be4d506bSBram Moolenaar 			frame_new_width(frp, frp->fr_width - take,
5900be4d506bSBram Moolenaar 								FALSE, FALSE);
5901071d4279SBram Moolenaar 			take = 0;
5902071d4279SBram Moolenaar 		    }
5903be4d506bSBram Moolenaar 		}
5904071d4279SBram Moolenaar 		if (run == 0)
5905071d4279SBram Moolenaar 		    frp = frp->fr_next;
5906071d4279SBram Moolenaar 		else
5907071d4279SBram Moolenaar 		    frp = frp->fr_prev;
5908071d4279SBram Moolenaar 	    }
5909071d4279SBram Moolenaar 	}
5910071d4279SBram Moolenaar     }
5911071d4279SBram Moolenaar }
5912071d4279SBram Moolenaar 
5913071d4279SBram Moolenaar /*
59141c3c1049SBram Moolenaar  * Check 'winminheight' for a valid value and reduce it if needed.
5915071d4279SBram Moolenaar  */
5916071d4279SBram Moolenaar     void
win_setminheight(void)5917b638a7beSBram Moolenaar win_setminheight(void)
5918071d4279SBram Moolenaar {
5919071d4279SBram Moolenaar     int		room;
59201c3c1049SBram Moolenaar     int		needed;
5921071d4279SBram Moolenaar     int		first = TRUE;
5922071d4279SBram Moolenaar 
59231c3c1049SBram Moolenaar     // loop until there is a 'winminheight' that is possible
5924071d4279SBram Moolenaar     while (p_wmh > 0)
5925071d4279SBram Moolenaar     {
59269e813b3dSBram Moolenaar 	room = Rows - p_ch;
59279e813b3dSBram Moolenaar 	needed = min_rows() - 1;  // 1 was added for the cmdline
59281c3c1049SBram Moolenaar 	if (room >= needed)
5929071d4279SBram Moolenaar 	    break;
5930071d4279SBram Moolenaar 	--p_wmh;
5931071d4279SBram Moolenaar 	if (first)
5932071d4279SBram Moolenaar 	{
5933e29a27f6SBram Moolenaar 	    emsg(_(e_not_enough_room));
5934071d4279SBram Moolenaar 	    first = FALSE;
5935071d4279SBram Moolenaar 	}
5936071d4279SBram Moolenaar     }
5937071d4279SBram Moolenaar }
5938071d4279SBram Moolenaar 
59391c3c1049SBram Moolenaar /*
59401c3c1049SBram Moolenaar  * Check 'winminwidth' for a valid value and reduce it if needed.
59411c3c1049SBram Moolenaar  */
59421c3c1049SBram Moolenaar     void
win_setminwidth(void)59431c3c1049SBram Moolenaar win_setminwidth(void)
59441c3c1049SBram Moolenaar {
59451c3c1049SBram Moolenaar     int		room;
59461c3c1049SBram Moolenaar     int		needed;
59471c3c1049SBram Moolenaar     int		first = TRUE;
59481c3c1049SBram Moolenaar 
59491c3c1049SBram Moolenaar     // loop until there is a 'winminheight' that is possible
59501c3c1049SBram Moolenaar     while (p_wmw > 0)
59511c3c1049SBram Moolenaar     {
59521c3c1049SBram Moolenaar 	room = Columns;
59531c3c1049SBram Moolenaar 	needed = frame_minwidth(topframe, NULL);
59541c3c1049SBram Moolenaar 	if (room >= needed)
59551c3c1049SBram Moolenaar 	    break;
59561c3c1049SBram Moolenaar 	--p_wmw;
59571c3c1049SBram Moolenaar 	if (first)
59581c3c1049SBram Moolenaar 	{
5959e29a27f6SBram Moolenaar 	    emsg(_(e_not_enough_room));
59601c3c1049SBram Moolenaar 	    first = FALSE;
59611c3c1049SBram Moolenaar 	}
59621c3c1049SBram Moolenaar     }
59631c3c1049SBram Moolenaar }
59641c3c1049SBram Moolenaar 
5965071d4279SBram Moolenaar /*
5966071d4279SBram Moolenaar  * Status line of dragwin is dragged "offset" lines down (negative is up).
5967071d4279SBram Moolenaar  */
5968071d4279SBram Moolenaar     void
win_drag_status_line(win_T * dragwin,int offset)5969b638a7beSBram Moolenaar win_drag_status_line(win_T *dragwin, int offset)
5970071d4279SBram Moolenaar {
5971071d4279SBram Moolenaar     frame_T	*curfr;
5972071d4279SBram Moolenaar     frame_T	*fr;
5973071d4279SBram Moolenaar     int		room;
5974071d4279SBram Moolenaar     int		row;
5975e38eab22SBram Moolenaar     int		up;	// if TRUE, drag status line up, otherwise down
5976071d4279SBram Moolenaar     int		n;
5977071d4279SBram Moolenaar 
5978071d4279SBram Moolenaar     fr = dragwin->w_frame;
5979071d4279SBram Moolenaar     curfr = fr;
5980e38eab22SBram Moolenaar     if (fr != topframe)		// more than one window
5981071d4279SBram Moolenaar     {
5982071d4279SBram Moolenaar 	fr = fr->fr_parent;
5983e38eab22SBram Moolenaar 	// When the parent frame is not a column of frames, its parent should
5984e38eab22SBram Moolenaar 	// be.
5985071d4279SBram Moolenaar 	if (fr->fr_layout != FR_COL)
5986071d4279SBram Moolenaar 	{
5987071d4279SBram Moolenaar 	    curfr = fr;
5988e38eab22SBram Moolenaar 	    if (fr != topframe)	// only a row of windows, may drag statusline
5989071d4279SBram Moolenaar 		fr = fr->fr_parent;
5990071d4279SBram Moolenaar 	}
5991071d4279SBram Moolenaar     }
5992071d4279SBram Moolenaar 
5993e38eab22SBram Moolenaar     // If this is the last frame in a column, may want to resize the parent
5994e38eab22SBram Moolenaar     // frame instead (go two up to skip a row of frames).
5995071d4279SBram Moolenaar     while (curfr != topframe && curfr->fr_next == NULL)
5996071d4279SBram Moolenaar     {
5997071d4279SBram Moolenaar 	if (fr != topframe)
5998071d4279SBram Moolenaar 	    fr = fr->fr_parent;
5999071d4279SBram Moolenaar 	curfr = fr;
6000071d4279SBram Moolenaar 	if (fr != topframe)
6001071d4279SBram Moolenaar 	    fr = fr->fr_parent;
6002071d4279SBram Moolenaar     }
6003071d4279SBram Moolenaar 
6004e38eab22SBram Moolenaar     if (offset < 0) // drag up
6005071d4279SBram Moolenaar     {
6006071d4279SBram Moolenaar 	up = TRUE;
6007071d4279SBram Moolenaar 	offset = -offset;
6008e38eab22SBram Moolenaar 	// sum up the room of the current frame and above it
6009071d4279SBram Moolenaar 	if (fr == curfr)
6010071d4279SBram Moolenaar 	{
6011e38eab22SBram Moolenaar 	    // only one window
6012071d4279SBram Moolenaar 	    room = fr->fr_height - frame_minheight(fr, NULL);
6013071d4279SBram Moolenaar 	}
6014071d4279SBram Moolenaar 	else
6015071d4279SBram Moolenaar 	{
6016071d4279SBram Moolenaar 	    room = 0;
6017071d4279SBram Moolenaar 	    for (fr = fr->fr_child; ; fr = fr->fr_next)
6018071d4279SBram Moolenaar 	    {
6019071d4279SBram Moolenaar 		room += fr->fr_height - frame_minheight(fr, NULL);
6020071d4279SBram Moolenaar 		if (fr == curfr)
6021071d4279SBram Moolenaar 		    break;
6022071d4279SBram Moolenaar 	    }
6023071d4279SBram Moolenaar 	}
6024e38eab22SBram Moolenaar 	fr = curfr->fr_next;		// put fr at frame that grows
6025071d4279SBram Moolenaar     }
6026e38eab22SBram Moolenaar     else    // drag down
6027071d4279SBram Moolenaar     {
6028071d4279SBram Moolenaar 	up = FALSE;
6029071d4279SBram Moolenaar 	/*
6030071d4279SBram Moolenaar 	 * Only dragging the last status line can reduce p_ch.
6031071d4279SBram Moolenaar 	 */
6032071d4279SBram Moolenaar 	room = Rows - cmdline_row;
6033071d4279SBram Moolenaar 	if (curfr->fr_next == NULL)
6034071d4279SBram Moolenaar 	    room -= 1;
6035071d4279SBram Moolenaar 	else
6036071d4279SBram Moolenaar 	    room -= p_ch;
6037071d4279SBram Moolenaar 	if (room < 0)
6038071d4279SBram Moolenaar 	    room = 0;
6039e38eab22SBram Moolenaar 	// sum up the room of frames below of the current one
60403d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fr, curfr->fr_next)
6041071d4279SBram Moolenaar 	    room += fr->fr_height - frame_minheight(fr, NULL);
6042e38eab22SBram Moolenaar 	fr = curfr;			// put fr at window that grows
6043071d4279SBram Moolenaar     }
6044071d4279SBram Moolenaar 
6045e38eab22SBram Moolenaar     if (room < offset)		// Not enough room
6046e38eab22SBram Moolenaar 	offset = room;		// Move as far as we can
6047071d4279SBram Moolenaar     if (offset <= 0)
6048071d4279SBram Moolenaar 	return;
6049071d4279SBram Moolenaar 
6050071d4279SBram Moolenaar     /*
6051071d4279SBram Moolenaar      * Grow frame fr by "offset" lines.
6052071d4279SBram Moolenaar      * Doesn't happen when dragging the last status line up.
6053071d4279SBram Moolenaar      */
6054071d4279SBram Moolenaar     if (fr != NULL)
6055071d4279SBram Moolenaar 	frame_new_height(fr, fr->fr_height + offset, up, FALSE);
6056071d4279SBram Moolenaar 
6057071d4279SBram Moolenaar     if (up)
6058e38eab22SBram Moolenaar 	fr = curfr;		// current frame gets smaller
6059071d4279SBram Moolenaar     else
6060e38eab22SBram Moolenaar 	fr = curfr->fr_next;	// next frame gets smaller
6061071d4279SBram Moolenaar 
6062071d4279SBram Moolenaar     /*
6063071d4279SBram Moolenaar      * Now make the other frames smaller.
6064071d4279SBram Moolenaar      */
6065071d4279SBram Moolenaar     while (fr != NULL && offset > 0)
6066071d4279SBram Moolenaar     {
6067071d4279SBram Moolenaar 	n = frame_minheight(fr, NULL);
6068071d4279SBram Moolenaar 	if (fr->fr_height - offset <= n)
6069071d4279SBram Moolenaar 	{
6070071d4279SBram Moolenaar 	    offset -= fr->fr_height - n;
6071071d4279SBram Moolenaar 	    frame_new_height(fr, n, !up, FALSE);
6072071d4279SBram Moolenaar 	}
6073071d4279SBram Moolenaar 	else
6074071d4279SBram Moolenaar 	{
6075071d4279SBram Moolenaar 	    frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
6076071d4279SBram Moolenaar 	    break;
6077071d4279SBram Moolenaar 	}
6078071d4279SBram Moolenaar 	if (up)
6079071d4279SBram Moolenaar 	    fr = fr->fr_prev;
6080071d4279SBram Moolenaar 	else
6081071d4279SBram Moolenaar 	    fr = fr->fr_next;
6082071d4279SBram Moolenaar     }
6083071d4279SBram Moolenaar     row = win_comp_pos();
6084071d4279SBram Moolenaar     screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
6085071d4279SBram Moolenaar     cmdline_row = row;
6086071d4279SBram Moolenaar     p_ch = Rows - cmdline_row;
6087071d4279SBram Moolenaar     if (p_ch < 1)
6088071d4279SBram Moolenaar 	p_ch = 1;
6089c6fe9195SBram Moolenaar     curtab->tp_ch_used = p_ch;
6090f71a3db4SBram Moolenaar     redraw_all_later(SOME_VALID);
6091071d4279SBram Moolenaar     showmode();
6092071d4279SBram Moolenaar }
6093071d4279SBram Moolenaar 
6094071d4279SBram Moolenaar /*
6095071d4279SBram Moolenaar  * Separator line of dragwin is dragged "offset" lines right (negative is left).
6096071d4279SBram Moolenaar  */
6097071d4279SBram Moolenaar     void
win_drag_vsep_line(win_T * dragwin,int offset)6098b638a7beSBram Moolenaar win_drag_vsep_line(win_T *dragwin, int offset)
6099071d4279SBram Moolenaar {
6100071d4279SBram Moolenaar     frame_T	*curfr;
6101071d4279SBram Moolenaar     frame_T	*fr;
6102071d4279SBram Moolenaar     int		room;
6103e38eab22SBram Moolenaar     int		left;	// if TRUE, drag separator line left, otherwise right
6104071d4279SBram Moolenaar     int		n;
6105071d4279SBram Moolenaar 
6106071d4279SBram Moolenaar     fr = dragwin->w_frame;
6107e38eab22SBram Moolenaar     if (fr == topframe)		// only one window (cannot happen?)
6108071d4279SBram Moolenaar 	return;
6109071d4279SBram Moolenaar     curfr = fr;
6110071d4279SBram Moolenaar     fr = fr->fr_parent;
6111e38eab22SBram Moolenaar     // When the parent frame is not a row of frames, its parent should be.
6112071d4279SBram Moolenaar     if (fr->fr_layout != FR_ROW)
6113071d4279SBram Moolenaar     {
6114e38eab22SBram Moolenaar 	if (fr == topframe)	// only a column of windows (cannot happen?)
6115071d4279SBram Moolenaar 	    return;
6116071d4279SBram Moolenaar 	curfr = fr;
6117071d4279SBram Moolenaar 	fr = fr->fr_parent;
6118071d4279SBram Moolenaar     }
6119071d4279SBram Moolenaar 
6120e38eab22SBram Moolenaar     // If this is the last frame in a row, may want to resize a parent
6121e38eab22SBram Moolenaar     // frame instead.
6122071d4279SBram Moolenaar     while (curfr->fr_next == NULL)
6123071d4279SBram Moolenaar     {
6124071d4279SBram Moolenaar 	if (fr == topframe)
6125071d4279SBram Moolenaar 	    break;
6126071d4279SBram Moolenaar 	curfr = fr;
6127071d4279SBram Moolenaar 	fr = fr->fr_parent;
6128071d4279SBram Moolenaar 	if (fr != topframe)
6129071d4279SBram Moolenaar 	{
6130071d4279SBram Moolenaar 	    curfr = fr;
6131071d4279SBram Moolenaar 	    fr = fr->fr_parent;
6132071d4279SBram Moolenaar 	}
6133071d4279SBram Moolenaar     }
6134071d4279SBram Moolenaar 
6135e38eab22SBram Moolenaar     if (offset < 0) // drag left
6136071d4279SBram Moolenaar     {
6137071d4279SBram Moolenaar 	left = TRUE;
6138071d4279SBram Moolenaar 	offset = -offset;
6139e38eab22SBram Moolenaar 	// sum up the room of the current frame and left of it
6140071d4279SBram Moolenaar 	room = 0;
6141071d4279SBram Moolenaar 	for (fr = fr->fr_child; ; fr = fr->fr_next)
6142071d4279SBram Moolenaar 	{
6143071d4279SBram Moolenaar 	    room += fr->fr_width - frame_minwidth(fr, NULL);
6144071d4279SBram Moolenaar 	    if (fr == curfr)
6145071d4279SBram Moolenaar 		break;
6146071d4279SBram Moolenaar 	}
6147e38eab22SBram Moolenaar 	fr = curfr->fr_next;		// put fr at frame that grows
6148071d4279SBram Moolenaar     }
6149e38eab22SBram Moolenaar     else    // drag right
6150071d4279SBram Moolenaar     {
6151071d4279SBram Moolenaar 	left = FALSE;
6152e38eab22SBram Moolenaar 	// sum up the room of frames right of the current one
6153071d4279SBram Moolenaar 	room = 0;
61543d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fr, curfr->fr_next)
6155071d4279SBram Moolenaar 	    room += fr->fr_width - frame_minwidth(fr, NULL);
6156e38eab22SBram Moolenaar 	fr = curfr;			// put fr at window that grows
6157071d4279SBram Moolenaar     }
6158071d4279SBram Moolenaar 
6159e38eab22SBram Moolenaar     if (room < offset)		// Not enough room
6160e38eab22SBram Moolenaar 	offset = room;		// Move as far as we can
6161e38eab22SBram Moolenaar     if (offset <= 0)		// No room at all, quit.
6162071d4279SBram Moolenaar 	return;
6163294a7e55SBram Moolenaar     if (fr == NULL)
6164e38eab22SBram Moolenaar 	return;			// Safety check, should not happen.
6165071d4279SBram Moolenaar 
6166e38eab22SBram Moolenaar     // grow frame fr by offset lines
6167be4d506bSBram Moolenaar     frame_new_width(fr, fr->fr_width + offset, left, FALSE);
6168071d4279SBram Moolenaar 
6169e38eab22SBram Moolenaar     // shrink other frames: current and at the left or at the right
6170071d4279SBram Moolenaar     if (left)
6171e38eab22SBram Moolenaar 	fr = curfr;		// current frame gets smaller
6172071d4279SBram Moolenaar     else
6173e38eab22SBram Moolenaar 	fr = curfr->fr_next;	// next frame gets smaller
6174071d4279SBram Moolenaar 
6175071d4279SBram Moolenaar     while (fr != NULL && offset > 0)
6176071d4279SBram Moolenaar     {
6177071d4279SBram Moolenaar 	n = frame_minwidth(fr, NULL);
6178071d4279SBram Moolenaar 	if (fr->fr_width - offset <= n)
6179071d4279SBram Moolenaar 	{
6180071d4279SBram Moolenaar 	    offset -= fr->fr_width - n;
6181be4d506bSBram Moolenaar 	    frame_new_width(fr, n, !left, FALSE);
6182071d4279SBram Moolenaar 	}
6183071d4279SBram Moolenaar 	else
6184071d4279SBram Moolenaar 	{
6185be4d506bSBram Moolenaar 	    frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
6186071d4279SBram Moolenaar 	    break;
6187071d4279SBram Moolenaar 	}
6188071d4279SBram Moolenaar 	if (left)
6189071d4279SBram Moolenaar 	    fr = fr->fr_prev;
6190071d4279SBram Moolenaar 	else
6191071d4279SBram Moolenaar 	    fr = fr->fr_next;
6192071d4279SBram Moolenaar     }
6193071d4279SBram Moolenaar     (void)win_comp_pos();
6194071d4279SBram Moolenaar     redraw_all_later(NOT_VALID);
6195071d4279SBram Moolenaar }
6196071d4279SBram Moolenaar 
61970215e8e1SBram Moolenaar #define FRACTION_MULT	16384L
61980215e8e1SBram Moolenaar 
61990215e8e1SBram Moolenaar /*
62000215e8e1SBram Moolenaar  * Set wp->w_fraction for the current w_wrow and w_height.
62013679c179SBram Moolenaar  * Has no effect when the window is less than two lines.
62020215e8e1SBram Moolenaar  */
62039dc2ce39SBram Moolenaar     void
set_fraction(win_T * wp)6204b638a7beSBram Moolenaar set_fraction(win_T *wp)
62050215e8e1SBram Moolenaar {
62063679c179SBram Moolenaar     if (wp->w_height > 1)
62078fcb60f9SBram Moolenaar 	// When cursor is in the first line the percentage is computed as if
62088fcb60f9SBram Moolenaar 	// it's halfway that line.  Thus with two lines it is 25%, with three
62098fcb60f9SBram Moolenaar 	// lines 17%, etc.  Similarly for the last line: 75%, 83%, etc.
62100215e8e1SBram Moolenaar 	wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
62118fcb60f9SBram Moolenaar 				     + FRACTION_MULT / 2) / (long)wp->w_height;
62120215e8e1SBram Moolenaar }
62130215e8e1SBram Moolenaar 
6214071d4279SBram Moolenaar /*
6215071d4279SBram Moolenaar  * Set the height of a window.
62161b9645deSBram Moolenaar  * "height" excludes any window toolbar.
6217071d4279SBram Moolenaar  * This takes care of the things inside the window, not what happens to the
6218071d4279SBram Moolenaar  * window position, the frame or to other windows.
6219071d4279SBram Moolenaar  */
62206763c140SBram Moolenaar     void
win_new_height(win_T * wp,int height)6221b638a7beSBram Moolenaar win_new_height(win_T *wp, int height)
6222071d4279SBram Moolenaar {
622356b3bf89SBram Moolenaar     int		prev_height = wp->w_height;
6224071d4279SBram Moolenaar 
6225e38eab22SBram Moolenaar     // Don't want a negative height.  Happens when splitting a tiny window.
6226e38eab22SBram Moolenaar     // Will equalize heights soon to fix it.
6227071d4279SBram Moolenaar     if (height < 0)
6228071d4279SBram Moolenaar 	height = 0;
62294c3f536fSBram Moolenaar     if (wp->w_height == height)
6230e38eab22SBram Moolenaar 	return;	    // nothing to do
6231071d4279SBram Moolenaar 
623256b3bf89SBram Moolenaar     if (wp->w_height > 0)
623356b3bf89SBram Moolenaar     {
623456b3bf89SBram Moolenaar 	if (wp == curwin)
6235e38eab22SBram Moolenaar 	    // w_wrow needs to be valid. When setting 'laststatus' this may
6236e38eab22SBram Moolenaar 	    // call win_new_height() recursively.
62370ae36a5cSBram Moolenaar 	    validate_cursor();
62380ae36a5cSBram Moolenaar 	if (wp->w_height != prev_height)
6239e38eab22SBram Moolenaar 	    return;  // Recursive call already changed the size, bail out here
6240e38eab22SBram Moolenaar 		     //	to avoid the following to mess things up.
624156b3bf89SBram Moolenaar 	if (wp->w_wrow != wp->w_prev_fraction_row)
62420215e8e1SBram Moolenaar 	    set_fraction(wp);
624356b3bf89SBram Moolenaar     }
6244071d4279SBram Moolenaar 
6245071d4279SBram Moolenaar     wp->w_height = height;
6246071d4279SBram Moolenaar     wp->w_skipcol = 0;
6247071d4279SBram Moolenaar 
6248e38eab22SBram Moolenaar     // There is no point in adjusting the scroll position when exiting.  Some
6249e38eab22SBram Moolenaar     // values might be invalid.
6250955f198fSBram Moolenaar     if (!exiting)
625146328f9aSBram Moolenaar 	scroll_to_fraction(wp, prev_height);
625246328f9aSBram Moolenaar }
625346328f9aSBram Moolenaar 
625446328f9aSBram Moolenaar     void
scroll_to_fraction(win_T * wp,int prev_height)625546328f9aSBram Moolenaar scroll_to_fraction(win_T *wp, int prev_height)
625646328f9aSBram Moolenaar {
625746328f9aSBram Moolenaar     linenr_T	lnum;
625846328f9aSBram Moolenaar     int		sline, line_size;
625946328f9aSBram Moolenaar     int		height = wp->w_height;
626046328f9aSBram Moolenaar 
6261a9b2535fSBram Moolenaar     // Don't change w_topline in any of these cases:
6262a9b2535fSBram Moolenaar     // - window height is 0
6263a9b2535fSBram Moolenaar     // - 'scrollbind' is set and this isn't the current window
6264bd2d68c2SBram Moolenaar     // - window height is sufficient to display the whole buffer and first line
6265bd2d68c2SBram Moolenaar     //   is visible.
6266a9b2535fSBram Moolenaar     if (height > 0
6267a9b2535fSBram Moolenaar         && (!wp->w_p_scb || wp == curwin)
6268bd2d68c2SBram Moolenaar         && (height < wp->w_buffer->b_ml.ml_line_count || wp->w_topline > 1))
6269071d4279SBram Moolenaar     {
62703411469dSBram Moolenaar 	/*
62713411469dSBram Moolenaar 	 * Find a value for w_topline that shows the cursor at the same
62723411469dSBram Moolenaar 	 * relative position in the window as before (more or less).
62733411469dSBram Moolenaar 	 */
6274071d4279SBram Moolenaar 	lnum = wp->w_cursor.lnum;
6275e38eab22SBram Moolenaar 	if (lnum < 1)		// can happen when starting up
6276071d4279SBram Moolenaar 	    lnum = 1;
62778fcb60f9SBram Moolenaar 	wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L)
62788fcb60f9SBram Moolenaar 							       / FRACTION_MULT;
6279071d4279SBram Moolenaar 	line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
6280071d4279SBram Moolenaar 	sline = wp->w_wrow - line_size;
628126470639SBram Moolenaar 
628226470639SBram Moolenaar 	if (sline >= 0)
628326470639SBram Moolenaar 	{
6284e38eab22SBram Moolenaar 	    // Make sure the whole cursor line is visible, if possible.
628526470639SBram Moolenaar 	    int rows = plines_win(wp, lnum, FALSE);
628626470639SBram Moolenaar 
628726470639SBram Moolenaar 	    if (sline > wp->w_height - rows)
628826470639SBram Moolenaar 	    {
628926470639SBram Moolenaar 		sline = wp->w_height - rows;
629026470639SBram Moolenaar 		wp->w_wrow -= rows - line_size;
629126470639SBram Moolenaar 	    }
629226470639SBram Moolenaar 	}
629326470639SBram Moolenaar 
6294071d4279SBram Moolenaar 	if (sline < 0)
6295071d4279SBram Moolenaar 	{
6296071d4279SBram Moolenaar 	    /*
6297071d4279SBram Moolenaar 	     * Cursor line would go off top of screen if w_wrow was this high.
629826470639SBram Moolenaar 	     * Make cursor line the first line in the window.  If not enough
629926470639SBram Moolenaar 	     * room use w_skipcol;
6300071d4279SBram Moolenaar 	     */
6301071d4279SBram Moolenaar 	    wp->w_wrow = line_size;
630226470639SBram Moolenaar 	    if (wp->w_wrow >= wp->w_height
63030263146bSBram Moolenaar 				       && (wp->w_width - win_col_off(wp)) > 0)
630426470639SBram Moolenaar 	    {
63050263146bSBram Moolenaar 		wp->w_skipcol += wp->w_width - win_col_off(wp);
630626470639SBram Moolenaar 		--wp->w_wrow;
630726470639SBram Moolenaar 		while (wp->w_wrow >= wp->w_height)
630826470639SBram Moolenaar 		{
63090263146bSBram Moolenaar 		    wp->w_skipcol += wp->w_width - win_col_off(wp)
631026470639SBram Moolenaar 							   + win_col_off2(wp);
631126470639SBram Moolenaar 		    --wp->w_wrow;
631226470639SBram Moolenaar 		}
631326470639SBram Moolenaar 	    }
6314071d4279SBram Moolenaar 	}
6315dd0402a7SBram Moolenaar 	else if (sline > 0)
6316071d4279SBram Moolenaar 	{
631726470639SBram Moolenaar 	    while (sline > 0 && lnum > 1)
6318071d4279SBram Moolenaar 	    {
6319071d4279SBram Moolenaar #ifdef FEAT_FOLDING
6320071d4279SBram Moolenaar 		hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
6321071d4279SBram Moolenaar 		if (lnum == 1)
6322071d4279SBram Moolenaar 		{
6323e38eab22SBram Moolenaar 		    // first line in buffer is folded
6324071d4279SBram Moolenaar 		    line_size = 1;
6325071d4279SBram Moolenaar 		    --sline;
6326071d4279SBram Moolenaar 		    break;
6327071d4279SBram Moolenaar 		}
6328071d4279SBram Moolenaar #endif
6329071d4279SBram Moolenaar 		--lnum;
6330071d4279SBram Moolenaar #ifdef FEAT_DIFF
6331071d4279SBram Moolenaar 		if (lnum == wp->w_topline)
6332071d4279SBram Moolenaar 		    line_size = plines_win_nofill(wp, lnum, TRUE)
6333071d4279SBram Moolenaar 							      + wp->w_topfill;
6334071d4279SBram Moolenaar 		else
6335071d4279SBram Moolenaar #endif
6336071d4279SBram Moolenaar 		    line_size = plines_win(wp, lnum, TRUE);
6337071d4279SBram Moolenaar 		sline -= line_size;
6338071d4279SBram Moolenaar 	    }
63393411469dSBram Moolenaar 
6340071d4279SBram Moolenaar 	    if (sline < 0)
6341071d4279SBram Moolenaar 	    {
6342071d4279SBram Moolenaar 		/*
6343071d4279SBram Moolenaar 		 * Line we want at top would go off top of screen.  Use next
6344071d4279SBram Moolenaar 		 * line instead.
6345071d4279SBram Moolenaar 		 */
6346071d4279SBram Moolenaar #ifdef FEAT_FOLDING
6347071d4279SBram Moolenaar 		hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
6348071d4279SBram Moolenaar #endif
6349071d4279SBram Moolenaar 		lnum++;
6350071d4279SBram Moolenaar 		wp->w_wrow -= line_size + sline;
6351071d4279SBram Moolenaar 	    }
6352dd0402a7SBram Moolenaar 	    else if (sline > 0)
6353071d4279SBram Moolenaar 	    {
63548fcb60f9SBram Moolenaar 		// First line of file reached, use that as topline.
6355071d4279SBram Moolenaar 		lnum = 1;
6356071d4279SBram Moolenaar 		wp->w_wrow -= sline;
6357071d4279SBram Moolenaar 	    }
6358071d4279SBram Moolenaar 	}
63598fcb60f9SBram Moolenaar 	set_topline(wp, lnum);
6360dd0402a7SBram Moolenaar     }
6361071d4279SBram Moolenaar 
6362071d4279SBram Moolenaar     if (wp == curwin)
6363071d4279SBram Moolenaar     {
6364375e3390SBram Moolenaar 	if (get_scrolloff_value())
6365071d4279SBram Moolenaar 	    update_topline();
6366e38eab22SBram Moolenaar 	curs_columns(FALSE);	// validate w_wrow
6367071d4279SBram Moolenaar     }
636856b3bf89SBram Moolenaar     if (prev_height > 0)
6369071d4279SBram Moolenaar 	wp->w_prev_fraction_row = wp->w_wrow;
6370071d4279SBram Moolenaar 
6371071d4279SBram Moolenaar     win_comp_scroll(wp);
6372f71a3db4SBram Moolenaar     redraw_win_later(wp, SOME_VALID);
6373071d4279SBram Moolenaar     wp->w_redr_status = TRUE;
6374071d4279SBram Moolenaar     invalidate_botline_win(wp);
6375071d4279SBram Moolenaar }
6376071d4279SBram Moolenaar 
6377071d4279SBram Moolenaar /*
6378071d4279SBram Moolenaar  * Set the width of a window.
6379071d4279SBram Moolenaar  */
63806763c140SBram Moolenaar     void
win_new_width(win_T * wp,int width)6381b638a7beSBram Moolenaar win_new_width(win_T *wp, int width)
6382071d4279SBram Moolenaar {
6383071d4279SBram Moolenaar     wp->w_width = width;
6384071d4279SBram Moolenaar     wp->w_lines_valid = 0;
6385071d4279SBram Moolenaar     changed_line_abv_curs_win(wp);
6386071d4279SBram Moolenaar     invalidate_botline_win(wp);
6387071d4279SBram Moolenaar     if (wp == curwin)
6388071d4279SBram Moolenaar     {
6389071d4279SBram Moolenaar 	update_topline();
6390e38eab22SBram Moolenaar 	curs_columns(TRUE);	// validate w_wrow
6391071d4279SBram Moolenaar     }
6392071d4279SBram Moolenaar     redraw_win_later(wp, NOT_VALID);
6393071d4279SBram Moolenaar     wp->w_redr_status = TRUE;
6394071d4279SBram Moolenaar }
6395071d4279SBram Moolenaar 
6396071d4279SBram Moolenaar     void
win_comp_scroll(win_T * wp)6397b638a7beSBram Moolenaar win_comp_scroll(win_T *wp)
6398071d4279SBram Moolenaar {
639974667060SBram Moolenaar #if defined(FEAT_EVAL)
640074667060SBram Moolenaar     int old_w_p_scr = wp->w_p_scr;
640174667060SBram Moolenaar #endif
640274667060SBram Moolenaar 
6403071d4279SBram Moolenaar     wp->w_p_scr = ((unsigned)wp->w_height >> 1);
6404071d4279SBram Moolenaar     if (wp->w_p_scr == 0)
6405071d4279SBram Moolenaar 	wp->w_p_scr = 1;
640674667060SBram Moolenaar #if defined(FEAT_EVAL)
640774667060SBram Moolenaar     if (wp->w_p_scr != old_w_p_scr)
640874667060SBram Moolenaar     {
640974667060SBram Moolenaar 	// Used by "verbose set scroll".
641074667060SBram Moolenaar 	wp->w_p_script_ctx[WV_SCROLL].sc_sid = SID_WINLAYOUT;
641174667060SBram Moolenaar 	wp->w_p_script_ctx[WV_SCROLL].sc_lnum = 0;
641274667060SBram Moolenaar     }
641374667060SBram Moolenaar #endif
6414071d4279SBram Moolenaar }
6415071d4279SBram Moolenaar 
6416071d4279SBram Moolenaar /*
6417071d4279SBram Moolenaar  * command_height: called whenever p_ch has been changed
6418071d4279SBram Moolenaar  */
6419071d4279SBram Moolenaar     void
command_height(void)6420b638a7beSBram Moolenaar command_height(void)
6421071d4279SBram Moolenaar {
6422071d4279SBram Moolenaar     int		h;
6423071d4279SBram Moolenaar     frame_T	*frp;
6424c6fe9195SBram Moolenaar     int		old_p_ch = curtab->tp_ch_used;
6425071d4279SBram Moolenaar 
6426e38eab22SBram Moolenaar     // Use the value of p_ch that we remembered.  This is needed for when the
6427e38eab22SBram Moolenaar     // GUI starts up, we can't be sure in what order things happen.  And when
6428e38eab22SBram Moolenaar     // p_ch was changed in another tab page.
6429c6fe9195SBram Moolenaar     curtab->tp_ch_used = p_ch;
643005159a0cSBram Moolenaar 
6431e38eab22SBram Moolenaar     // Find bottom frame with width of screen.
6432071d4279SBram Moolenaar     frp = lastwin->w_frame;
6433071d4279SBram Moolenaar     while (frp->fr_width != Columns && frp->fr_parent != NULL)
6434071d4279SBram Moolenaar 	frp = frp->fr_parent;
6435071d4279SBram Moolenaar 
6436e38eab22SBram Moolenaar     // Avoid changing the height of a window with 'winfixheight' set.
6437071d4279SBram Moolenaar     while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
6438071d4279SBram Moolenaar 						      && frp->fr_win->w_p_wfh)
6439071d4279SBram Moolenaar 	frp = frp->fr_prev;
6440071d4279SBram Moolenaar 
6441071d4279SBram Moolenaar     if (starting != NO_SCREEN)
6442071d4279SBram Moolenaar     {
6443071d4279SBram Moolenaar 	cmdline_row = Rows - p_ch;
6444071d4279SBram Moolenaar 
6445e38eab22SBram Moolenaar 	if (p_ch > old_p_ch)		    // p_ch got bigger
6446071d4279SBram Moolenaar 	{
6447071d4279SBram Moolenaar 	    while (p_ch > old_p_ch)
6448071d4279SBram Moolenaar 	    {
6449071d4279SBram Moolenaar 		if (frp == NULL)
6450071d4279SBram Moolenaar 		{
6451e29a27f6SBram Moolenaar 		    emsg(_(e_not_enough_room));
6452071d4279SBram Moolenaar 		    p_ch = old_p_ch;
6453719939c8SBram Moolenaar 		    curtab->tp_ch_used = p_ch;
6454071d4279SBram Moolenaar 		    cmdline_row = Rows - p_ch;
6455071d4279SBram Moolenaar 		    break;
6456071d4279SBram Moolenaar 		}
6457071d4279SBram Moolenaar 		h = frp->fr_height - frame_minheight(frp, NULL);
6458071d4279SBram Moolenaar 		if (h > p_ch - old_p_ch)
6459071d4279SBram Moolenaar 		    h = p_ch - old_p_ch;
6460071d4279SBram Moolenaar 		old_p_ch += h;
6461071d4279SBram Moolenaar 		frame_add_height(frp, -h);
6462071d4279SBram Moolenaar 		frp = frp->fr_prev;
6463071d4279SBram Moolenaar 	    }
6464071d4279SBram Moolenaar 
6465e38eab22SBram Moolenaar 	    // Recompute window positions.
6466071d4279SBram Moolenaar 	    (void)win_comp_pos();
6467071d4279SBram Moolenaar 
6468e38eab22SBram Moolenaar 	    // clear the lines added to cmdline
6469071d4279SBram Moolenaar 	    if (full_screen)
6470071d4279SBram Moolenaar 		screen_fill((int)(cmdline_row), (int)Rows, 0,
6471071d4279SBram Moolenaar 						   (int)Columns, ' ', ' ', 0);
6472071d4279SBram Moolenaar 	    msg_row = cmdline_row;
6473071d4279SBram Moolenaar 	    redraw_cmdline = TRUE;
6474071d4279SBram Moolenaar 	    return;
6475071d4279SBram Moolenaar 	}
6476071d4279SBram Moolenaar 
6477071d4279SBram Moolenaar 	if (msg_row < cmdline_row)
6478071d4279SBram Moolenaar 	    msg_row = cmdline_row;
6479071d4279SBram Moolenaar 	redraw_cmdline = TRUE;
6480071d4279SBram Moolenaar     }
6481071d4279SBram Moolenaar     frame_add_height(frp, (int)(old_p_ch - p_ch));
6482071d4279SBram Moolenaar 
6483e38eab22SBram Moolenaar     // Recompute window positions.
6484071d4279SBram Moolenaar     if (frp != lastwin->w_frame)
6485071d4279SBram Moolenaar 	(void)win_comp_pos();
6486071d4279SBram Moolenaar }
6487071d4279SBram Moolenaar 
6488071d4279SBram Moolenaar /*
6489071d4279SBram Moolenaar  * Resize frame "frp" to be "n" lines higher (negative for less high).
6490071d4279SBram Moolenaar  * Also resize the frames it is contained in.
6491071d4279SBram Moolenaar  */
6492071d4279SBram Moolenaar     static void
frame_add_height(frame_T * frp,int n)6493b638a7beSBram Moolenaar frame_add_height(frame_T *frp, int n)
6494071d4279SBram Moolenaar {
6495071d4279SBram Moolenaar     frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
6496071d4279SBram Moolenaar     for (;;)
6497071d4279SBram Moolenaar     {
6498071d4279SBram Moolenaar 	frp = frp->fr_parent;
6499071d4279SBram Moolenaar 	if (frp == NULL)
6500071d4279SBram Moolenaar 	    break;
6501071d4279SBram Moolenaar 	frp->fr_height += n;
6502071d4279SBram Moolenaar     }
6503071d4279SBram Moolenaar }
6504071d4279SBram Moolenaar 
6505071d4279SBram Moolenaar /*
6506071d4279SBram Moolenaar  * Add or remove a status line for the bottom window(s), according to the
6507071d4279SBram Moolenaar  * value of 'laststatus'.
6508071d4279SBram Moolenaar  */
6509071d4279SBram Moolenaar     void
last_status(int morewin)6510b638a7beSBram Moolenaar last_status(
6511e38eab22SBram Moolenaar     int		morewin)	// pretend there are two or more windows
6512071d4279SBram Moolenaar {
6513e38eab22SBram Moolenaar     // Don't make a difference between horizontal or vertical split.
6514071d4279SBram Moolenaar     last_status_rec(topframe, (p_ls == 2
6515459ca563SBram Moolenaar 			  || (p_ls == 1 && (morewin || !ONE_WINDOW))));
6516071d4279SBram Moolenaar }
6517071d4279SBram Moolenaar 
6518071d4279SBram Moolenaar     static void
last_status_rec(frame_T * fr,int statusline)6519b638a7beSBram Moolenaar last_status_rec(frame_T *fr, int statusline)
6520071d4279SBram Moolenaar {
6521071d4279SBram Moolenaar     frame_T	*fp;
6522071d4279SBram Moolenaar     win_T	*wp;
6523071d4279SBram Moolenaar 
6524071d4279SBram Moolenaar     if (fr->fr_layout == FR_LEAF)
6525071d4279SBram Moolenaar     {
6526071d4279SBram Moolenaar 	wp = fr->fr_win;
6527071d4279SBram Moolenaar 	if (wp->w_status_height != 0 && !statusline)
6528071d4279SBram Moolenaar 	{
6529e38eab22SBram Moolenaar 	    // remove status line
6530071d4279SBram Moolenaar 	    win_new_height(wp, wp->w_height + 1);
6531071d4279SBram Moolenaar 	    wp->w_status_height = 0;
6532071d4279SBram Moolenaar 	    comp_col();
6533071d4279SBram Moolenaar 	}
6534071d4279SBram Moolenaar 	else if (wp->w_status_height == 0 && statusline)
6535071d4279SBram Moolenaar 	{
6536e38eab22SBram Moolenaar 	    // Find a frame to take a line from.
6537071d4279SBram Moolenaar 	    fp = fr;
6538071d4279SBram Moolenaar 	    while (fp->fr_height <= frame_minheight(fp, NULL))
6539071d4279SBram Moolenaar 	    {
6540071d4279SBram Moolenaar 		if (fp == topframe)
6541071d4279SBram Moolenaar 		{
6542e29a27f6SBram Moolenaar 		    emsg(_(e_not_enough_room));
6543071d4279SBram Moolenaar 		    return;
6544071d4279SBram Moolenaar 		}
6545e38eab22SBram Moolenaar 		// In a column of frames: go to frame above.  If already at
6546e38eab22SBram Moolenaar 		// the top or in a row of frames: go to parent.
6547071d4279SBram Moolenaar 		if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
6548071d4279SBram Moolenaar 		    fp = fp->fr_prev;
6549071d4279SBram Moolenaar 		else
6550071d4279SBram Moolenaar 		    fp = fp->fr_parent;
6551071d4279SBram Moolenaar 	    }
6552071d4279SBram Moolenaar 	    wp->w_status_height = 1;
6553071d4279SBram Moolenaar 	    if (fp != fr)
6554071d4279SBram Moolenaar 	    {
6555071d4279SBram Moolenaar 		frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
6556071d4279SBram Moolenaar 		frame_fix_height(wp);
6557071d4279SBram Moolenaar 		(void)win_comp_pos();
6558071d4279SBram Moolenaar 	    }
6559071d4279SBram Moolenaar 	    else
6560071d4279SBram Moolenaar 		win_new_height(wp, wp->w_height - 1);
6561071d4279SBram Moolenaar 	    comp_col();
6562f71a3db4SBram Moolenaar 	    redraw_all_later(SOME_VALID);
6563071d4279SBram Moolenaar 	}
6564071d4279SBram Moolenaar     }
6565071d4279SBram Moolenaar     else if (fr->fr_layout == FR_ROW)
6566071d4279SBram Moolenaar     {
6567e38eab22SBram Moolenaar 	// vertically split windows, set status line for each one
65683d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fp, fr->fr_child)
6569071d4279SBram Moolenaar 	    last_status_rec(fp, statusline);
6570071d4279SBram Moolenaar     }
6571071d4279SBram Moolenaar     else
6572071d4279SBram Moolenaar     {
6573e38eab22SBram Moolenaar 	// horizontally split window, set status line for last one
6574071d4279SBram Moolenaar 	for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
6575071d4279SBram Moolenaar 	    ;
6576071d4279SBram Moolenaar 	last_status_rec(fp, statusline);
6577071d4279SBram Moolenaar     }
6578071d4279SBram Moolenaar }
6579071d4279SBram Moolenaar 
65801d2ba7faSBram Moolenaar /*
658198ea5defSBram Moolenaar  * Return the number of lines used by the tab page line.
65821d2ba7faSBram Moolenaar  */
65831d2ba7faSBram Moolenaar     int
tabline_height(void)6584b638a7beSBram Moolenaar tabline_height(void)
65851d2ba7faSBram Moolenaar {
658632466aa2SBram Moolenaar #ifdef FEAT_GUI_TABLINE
6587e38eab22SBram Moolenaar     // When the GUI has the tabline then this always returns zero.
658832466aa2SBram Moolenaar     if (gui_use_tabline())
658932466aa2SBram Moolenaar 	return 0;
659032466aa2SBram Moolenaar #endif
65912a0449d1SBram Moolenaar     switch (p_stal)
659298ea5defSBram Moolenaar     {
659398ea5defSBram Moolenaar 	case 0: return 0;
659498ea5defSBram Moolenaar 	case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
659598ea5defSBram Moolenaar     }
65961d2ba7faSBram Moolenaar     return 1;
65971d2ba7faSBram Moolenaar }
65981d2ba7faSBram Moolenaar 
6599071d4279SBram Moolenaar /*
6600071d4279SBram Moolenaar  * Return the minimal number of rows that is needed on the screen to display
6601071d4279SBram Moolenaar  * the current number of windows.
6602071d4279SBram Moolenaar  */
6603071d4279SBram Moolenaar     int
min_rows(void)6604b638a7beSBram Moolenaar min_rows(void)
6605071d4279SBram Moolenaar {
6606071d4279SBram Moolenaar     int		total;
6607f740b29aSBram Moolenaar     tabpage_T	*tp;
6608f740b29aSBram Moolenaar     int		n;
6609071d4279SBram Moolenaar 
6610e38eab22SBram Moolenaar     if (firstwin == NULL)	// not initialized yet
6611071d4279SBram Moolenaar 	return MIN_LINES;
6612071d4279SBram Moolenaar 
6613f740b29aSBram Moolenaar     total = 0;
661429323590SBram Moolenaar     FOR_ALL_TABPAGES(tp)
6615f740b29aSBram Moolenaar     {
6616f740b29aSBram Moolenaar 	n = frame_minheight(tp->tp_topframe, NULL);
6617f740b29aSBram Moolenaar 	if (total < n)
6618f740b29aSBram Moolenaar 	    total = n;
6619f740b29aSBram Moolenaar     }
662032466aa2SBram Moolenaar     total += tabline_height();
6621e38eab22SBram Moolenaar     total += 1;		// count the room for the command line
6622071d4279SBram Moolenaar     return total;
6623071d4279SBram Moolenaar }
6624071d4279SBram Moolenaar 
6625071d4279SBram Moolenaar /*
66261c329c04SBram Moolenaar  * Return TRUE if there is only one window and only one tab page, not
662749d7bf13SBram Moolenaar  * counting a help or preview window, unless it is the current window.
66284d784b21SBram Moolenaar  * Does not count unlisted windows.
6629071d4279SBram Moolenaar  */
6630071d4279SBram Moolenaar     int
only_one_window(void)6631b638a7beSBram Moolenaar only_one_window(void)
6632071d4279SBram Moolenaar {
6633071d4279SBram Moolenaar     int		count = 0;
6634071d4279SBram Moolenaar     win_T	*wp;
6635071d4279SBram Moolenaar 
6636d98c0b63SBram Moolenaar #if defined(FEAT_PROP_POPUP)
6637d98c0b63SBram Moolenaar     // If the current window is a popup then there always is another window.
6638d98c0b63SBram Moolenaar     if (popup_is_popup(curwin))
6639d98c0b63SBram Moolenaar 	return FALSE;
6640d98c0b63SBram Moolenaar #endif
6641d98c0b63SBram Moolenaar 
6642e38eab22SBram Moolenaar     // If there is another tab page there always is another window.
66431d2ba7faSBram Moolenaar     if (first_tabpage->tp_next != NULL)
66441d2ba7faSBram Moolenaar 	return FALSE;
66451d2ba7faSBram Moolenaar 
664629323590SBram Moolenaar     FOR_ALL_WINDOWS(wp)
6647802418d5SBram Moolenaar 	if (wp->w_buffer != NULL
6648d28cc3f5SBram Moolenaar 		&& (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
6649071d4279SBram Moolenaar # ifdef FEAT_QUICKFIX
6650071d4279SBram Moolenaar 		    || wp->w_p_pvw
6651071d4279SBram Moolenaar # endif
6652f2bd8ef2SBram Moolenaar 	     ) || wp == curwin) && wp != aucmd_win)
6653071d4279SBram Moolenaar 	    ++count;
6654071d4279SBram Moolenaar     return (count <= 1);
6655071d4279SBram Moolenaar }
6656071d4279SBram Moolenaar 
6657071d4279SBram Moolenaar /*
6658071d4279SBram Moolenaar  * Correct the cursor line number in other windows.  Used after changing the
6659071d4279SBram Moolenaar  * current buffer, and before applying autocommands.
6660071d4279SBram Moolenaar  * When "do_curwin" is TRUE, also check current window.
6661071d4279SBram Moolenaar  */
6662071d4279SBram Moolenaar     void
check_lnums(int do_curwin)6663b638a7beSBram Moolenaar check_lnums(int do_curwin)
6664071d4279SBram Moolenaar {
6665071d4279SBram Moolenaar     win_T	*wp;
6666f740b29aSBram Moolenaar     tabpage_T	*tp;
6667f740b29aSBram Moolenaar 
6668f740b29aSBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
6669071d4279SBram Moolenaar 	if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
6670071d4279SBram Moolenaar 	{
6671a68e5959SBram Moolenaar 	    // save the original cursor position and topline
6672a68e5959SBram Moolenaar 	    wp->w_save_cursor.w_cursor_save = wp->w_cursor;
6673a68e5959SBram Moolenaar 	    wp->w_save_cursor.w_topline_save = wp->w_topline;
6674a68e5959SBram Moolenaar 
6675071d4279SBram Moolenaar 	    if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6676071d4279SBram Moolenaar 		wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6677071d4279SBram Moolenaar 	    if (wp->w_topline > curbuf->b_ml.ml_line_count)
6678071d4279SBram Moolenaar 		wp->w_topline = curbuf->b_ml.ml_line_count;
6679a68e5959SBram Moolenaar 
6680a68e5959SBram Moolenaar 	    // save the corrected cursor position and topline
6681a68e5959SBram Moolenaar 	    wp->w_save_cursor.w_cursor_corr = wp->w_cursor;
6682a68e5959SBram Moolenaar 	    wp->w_save_cursor.w_topline_corr = wp->w_topline;
6683a68e5959SBram Moolenaar 	}
6684a68e5959SBram Moolenaar }
6685a68e5959SBram Moolenaar 
6686a68e5959SBram Moolenaar /*
6687a68e5959SBram Moolenaar  * Reset cursor and topline to its stored values from check_lnums().
6688a68e5959SBram Moolenaar  * check_lnums() must have been called first!
6689a68e5959SBram Moolenaar  */
6690a68e5959SBram Moolenaar     void
reset_lnums()6691a68e5959SBram Moolenaar reset_lnums()
6692a68e5959SBram Moolenaar {
6693a68e5959SBram Moolenaar     win_T	*wp;
6694a68e5959SBram Moolenaar     tabpage_T	*tp;
6695a68e5959SBram Moolenaar 
6696a68e5959SBram Moolenaar     FOR_ALL_TAB_WINDOWS(tp, wp)
6697a68e5959SBram Moolenaar 	if (wp->w_buffer == curbuf)
6698a68e5959SBram Moolenaar 	{
6699a68e5959SBram Moolenaar 	    // Restore the value if the autocommand didn't change it.
6700a68e5959SBram Moolenaar 	    if (EQUAL_POS(wp->w_save_cursor.w_cursor_corr, wp->w_cursor))
6701a68e5959SBram Moolenaar 		wp->w_cursor = wp->w_save_cursor.w_cursor_save;
6702a68e5959SBram Moolenaar 	    if (wp->w_save_cursor.w_topline_corr == wp->w_topline)
6703a68e5959SBram Moolenaar 		wp->w_topline = wp->w_save_cursor.w_topline_save;
6704071d4279SBram Moolenaar 	}
6705071d4279SBram Moolenaar }
6706071d4279SBram Moolenaar 
6707071d4279SBram Moolenaar /*
6708071d4279SBram Moolenaar  * A snapshot of the window sizes, to restore them after closing the help
6709071d4279SBram Moolenaar  * window.
6710071d4279SBram Moolenaar  * Only these fields are used:
6711071d4279SBram Moolenaar  * fr_layout
6712071d4279SBram Moolenaar  * fr_width
6713071d4279SBram Moolenaar  * fr_height
6714071d4279SBram Moolenaar  * fr_next
6715071d4279SBram Moolenaar  * fr_child
6716071d4279SBram Moolenaar  * fr_win (only valid for the old curwin, NULL otherwise)
6717071d4279SBram Moolenaar  */
6718071d4279SBram Moolenaar 
6719071d4279SBram Moolenaar /*
6720071d4279SBram Moolenaar  * Create a snapshot of the current frame sizes.
6721071d4279SBram Moolenaar  */
6722746ebd3bSBram Moolenaar     void
make_snapshot(int idx)6723b638a7beSBram Moolenaar make_snapshot(int idx)
6724071d4279SBram Moolenaar {
6725746ebd3bSBram Moolenaar     clear_snapshot(curtab, idx);
6726746ebd3bSBram Moolenaar     make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
6727071d4279SBram Moolenaar }
6728071d4279SBram Moolenaar 
6729071d4279SBram Moolenaar     static void
make_snapshot_rec(frame_T * fr,frame_T ** frp)6730b638a7beSBram Moolenaar make_snapshot_rec(frame_T *fr, frame_T **frp)
6731071d4279SBram Moolenaar {
6732c799fe20SBram Moolenaar     *frp = ALLOC_CLEAR_ONE(frame_T);
6733071d4279SBram Moolenaar     if (*frp == NULL)
6734071d4279SBram Moolenaar 	return;
6735071d4279SBram Moolenaar     (*frp)->fr_layout = fr->fr_layout;
6736071d4279SBram Moolenaar     (*frp)->fr_width = fr->fr_width;
6737071d4279SBram Moolenaar     (*frp)->fr_height = fr->fr_height;
6738071d4279SBram Moolenaar     if (fr->fr_next != NULL)
6739071d4279SBram Moolenaar 	make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
6740071d4279SBram Moolenaar     if (fr->fr_child != NULL)
6741071d4279SBram Moolenaar 	make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
6742071d4279SBram Moolenaar     if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
6743071d4279SBram Moolenaar 	(*frp)->fr_win = curwin;
6744071d4279SBram Moolenaar }
6745071d4279SBram Moolenaar 
6746071d4279SBram Moolenaar /*
6747071d4279SBram Moolenaar  * Remove any existing snapshot.
6748071d4279SBram Moolenaar  */
6749071d4279SBram Moolenaar     static void
clear_snapshot(tabpage_T * tp,int idx)6750b638a7beSBram Moolenaar clear_snapshot(tabpage_T *tp, int idx)
6751071d4279SBram Moolenaar {
6752746ebd3bSBram Moolenaar     clear_snapshot_rec(tp->tp_snapshot[idx]);
6753746ebd3bSBram Moolenaar     tp->tp_snapshot[idx] = NULL;
6754071d4279SBram Moolenaar }
6755071d4279SBram Moolenaar 
6756071d4279SBram Moolenaar     static void
clear_snapshot_rec(frame_T * fr)6757b638a7beSBram Moolenaar clear_snapshot_rec(frame_T *fr)
6758071d4279SBram Moolenaar {
6759071d4279SBram Moolenaar     if (fr != NULL)
6760071d4279SBram Moolenaar     {
6761071d4279SBram Moolenaar 	clear_snapshot_rec(fr->fr_next);
6762071d4279SBram Moolenaar 	clear_snapshot_rec(fr->fr_child);
6763071d4279SBram Moolenaar 	vim_free(fr);
6764071d4279SBram Moolenaar     }
6765071d4279SBram Moolenaar }
6766071d4279SBram Moolenaar 
6767071d4279SBram Moolenaar /*
6768071d4279SBram Moolenaar  * Restore a previously created snapshot, if there is any.
6769071d4279SBram Moolenaar  * This is only done if the screen size didn't change and the window layout is
6770071d4279SBram Moolenaar  * still the same.
6771071d4279SBram Moolenaar  */
6772746ebd3bSBram Moolenaar     void
restore_snapshot(int idx,int close_curwin)6773b638a7beSBram Moolenaar restore_snapshot(
6774b638a7beSBram Moolenaar     int		idx,
6775e38eab22SBram Moolenaar     int		close_curwin)	    // closing current window
6776071d4279SBram Moolenaar {
6777071d4279SBram Moolenaar     win_T	*wp;
6778071d4279SBram Moolenaar 
6779746ebd3bSBram Moolenaar     if (curtab->tp_snapshot[idx] != NULL
6780746ebd3bSBram Moolenaar 	    && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
6781746ebd3bSBram Moolenaar 	    && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
6782746ebd3bSBram Moolenaar 	    && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
6783071d4279SBram Moolenaar     {
6784746ebd3bSBram Moolenaar 	wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
6785071d4279SBram Moolenaar 	win_comp_pos();
6786071d4279SBram Moolenaar 	if (wp != NULL && close_curwin)
6787071d4279SBram Moolenaar 	    win_goto(wp);
6788bf3250a8SBram Moolenaar 	redraw_all_later(NOT_VALID);
6789071d4279SBram Moolenaar     }
6790746ebd3bSBram Moolenaar     clear_snapshot(curtab, idx);
6791071d4279SBram Moolenaar }
6792071d4279SBram Moolenaar 
6793071d4279SBram Moolenaar /*
6794071d4279SBram Moolenaar  * Check if frames "sn" and "fr" have the same layout, same following frames
6795343b8c04SBram Moolenaar  * and same children.  And the window pointer is valid.
6796071d4279SBram Moolenaar  */
6797071d4279SBram Moolenaar     static int
check_snapshot_rec(frame_T * sn,frame_T * fr)6798b638a7beSBram Moolenaar check_snapshot_rec(frame_T *sn, frame_T *fr)
6799071d4279SBram Moolenaar {
6800071d4279SBram Moolenaar     if (sn->fr_layout != fr->fr_layout
6801071d4279SBram Moolenaar 	    || (sn->fr_next == NULL) != (fr->fr_next == NULL)
6802071d4279SBram Moolenaar 	    || (sn->fr_child == NULL) != (fr->fr_child == NULL)
6803071d4279SBram Moolenaar 	    || (sn->fr_next != NULL
6804071d4279SBram Moolenaar 		&& check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
6805071d4279SBram Moolenaar 	    || (sn->fr_child != NULL
6806343b8c04SBram Moolenaar 		&& check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
68072c90d511SBram Moolenaar 	    || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
6808071d4279SBram Moolenaar 	return FAIL;
6809071d4279SBram Moolenaar     return OK;
6810071d4279SBram Moolenaar }
6811071d4279SBram Moolenaar 
6812071d4279SBram Moolenaar /*
6813071d4279SBram Moolenaar  * Copy the size of snapshot frame "sn" to frame "fr".  Do the same for all
6814071d4279SBram Moolenaar  * following frames and children.
6815071d4279SBram Moolenaar  * Returns a pointer to the old current window, or NULL.
6816071d4279SBram Moolenaar  */
6817071d4279SBram Moolenaar     static win_T *
restore_snapshot_rec(frame_T * sn,frame_T * fr)6818b638a7beSBram Moolenaar restore_snapshot_rec(frame_T *sn, frame_T *fr)
6819071d4279SBram Moolenaar {
6820071d4279SBram Moolenaar     win_T	*wp = NULL;
6821071d4279SBram Moolenaar     win_T	*wp2;
6822071d4279SBram Moolenaar 
6823071d4279SBram Moolenaar     fr->fr_height = sn->fr_height;
6824071d4279SBram Moolenaar     fr->fr_width = sn->fr_width;
6825071d4279SBram Moolenaar     if (fr->fr_layout == FR_LEAF)
6826071d4279SBram Moolenaar     {
6827071d4279SBram Moolenaar 	frame_new_height(fr, fr->fr_height, FALSE, FALSE);
6828be4d506bSBram Moolenaar 	frame_new_width(fr, fr->fr_width, FALSE, FALSE);
6829071d4279SBram Moolenaar 	wp = sn->fr_win;
6830071d4279SBram Moolenaar     }
6831071d4279SBram Moolenaar     if (sn->fr_next != NULL)
6832071d4279SBram Moolenaar     {
6833071d4279SBram Moolenaar 	wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
6834071d4279SBram Moolenaar 	if (wp2 != NULL)
6835071d4279SBram Moolenaar 	    wp = wp2;
6836071d4279SBram Moolenaar     }
6837071d4279SBram Moolenaar     if (sn->fr_child != NULL)
6838071d4279SBram Moolenaar     {
6839071d4279SBram Moolenaar 	wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
6840071d4279SBram Moolenaar 	if (wp2 != NULL)
6841071d4279SBram Moolenaar 	    wp = wp2;
6842071d4279SBram Moolenaar     }
6843071d4279SBram Moolenaar     return wp;
6844071d4279SBram Moolenaar }
6845071d4279SBram Moolenaar 
68464033c55eSBram Moolenaar #if defined(FEAT_GUI) || defined(PROTO)
6847071d4279SBram Moolenaar /*
6848071d4279SBram Moolenaar  * Return TRUE if there is any vertically split window.
6849071d4279SBram Moolenaar  */
6850071d4279SBram Moolenaar     int
win_hasvertsplit(void)6851b638a7beSBram Moolenaar win_hasvertsplit(void)
6852071d4279SBram Moolenaar {
6853071d4279SBram Moolenaar     frame_T	*fr;
6854071d4279SBram Moolenaar 
6855071d4279SBram Moolenaar     if (topframe->fr_layout == FR_ROW)
6856071d4279SBram Moolenaar 	return TRUE;
6857071d4279SBram Moolenaar 
6858071d4279SBram Moolenaar     if (topframe->fr_layout == FR_COL)
68593d1491edSBram Moolenaar 	FOR_ALL_FRAMES(fr, topframe->fr_child)
6860071d4279SBram Moolenaar 	    if (fr->fr_layout == FR_ROW)
6861071d4279SBram Moolenaar 		return TRUE;
6862071d4279SBram Moolenaar 
6863071d4279SBram Moolenaar     return FALSE;
6864071d4279SBram Moolenaar }
6865071d4279SBram Moolenaar #endif
68666ee10162SBram Moolenaar 
68676d21645fSBram Moolenaar #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
68686d21645fSBram Moolenaar     int
get_win_number(win_T * wp,win_T * first_win)68695e538ecdSBram Moolenaar get_win_number(win_T *wp, win_T *first_win)
68706d21645fSBram Moolenaar {
68716d21645fSBram Moolenaar     int		i = 1;
68726d21645fSBram Moolenaar     win_T	*w;
68736d21645fSBram Moolenaar 
68745e538ecdSBram Moolenaar     for (w = first_win; w != NULL && w != wp; w = W_NEXT(w))
68756d21645fSBram Moolenaar 	++i;
68766d21645fSBram Moolenaar 
68776d21645fSBram Moolenaar     if (w == NULL)
68786d21645fSBram Moolenaar 	return 0;
68796d21645fSBram Moolenaar     else
68806d21645fSBram Moolenaar 	return i;
68816d21645fSBram Moolenaar }
68825e538ecdSBram Moolenaar 
68835e538ecdSBram Moolenaar     int
get_tab_number(tabpage_T * tp UNUSED)68848c0e322fSBram Moolenaar get_tab_number(tabpage_T *tp UNUSED)
68855e538ecdSBram Moolenaar {
68865e538ecdSBram Moolenaar     int		i = 1;
68875e538ecdSBram Moolenaar     tabpage_T	*t;
68885e538ecdSBram Moolenaar 
68895e538ecdSBram Moolenaar     for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next)
68905e538ecdSBram Moolenaar 	++i;
68915e538ecdSBram Moolenaar 
68925e538ecdSBram Moolenaar     if (t == NULL)
68935e538ecdSBram Moolenaar 	return 0;
68945e538ecdSBram Moolenaar     else
68955e538ecdSBram Moolenaar 	return i;
68965e538ecdSBram Moolenaar }
68976d21645fSBram Moolenaar #endif
6898b893ac20SBram Moolenaar 
6899b893ac20SBram Moolenaar /*
6900b893ac20SBram Moolenaar  * Return TRUE if "topfrp" and its children are at the right height.
6901b893ac20SBram Moolenaar  */
6902b893ac20SBram Moolenaar     static int
frame_check_height(frame_T * topfrp,int height)6903b638a7beSBram Moolenaar frame_check_height(frame_T *topfrp, int height)
6904b893ac20SBram Moolenaar {
6905b893ac20SBram Moolenaar     frame_T *frp;
6906b893ac20SBram Moolenaar 
6907b893ac20SBram Moolenaar     if (topfrp->fr_height != height)
6908b893ac20SBram Moolenaar 	return FALSE;
6909b893ac20SBram Moolenaar 
6910b893ac20SBram Moolenaar     if (topfrp->fr_layout == FR_ROW)
69113d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
6912b893ac20SBram Moolenaar 	    if (frp->fr_height != height)
6913b893ac20SBram Moolenaar 		return FALSE;
6914b893ac20SBram Moolenaar 
6915b893ac20SBram Moolenaar     return TRUE;
6916b893ac20SBram Moolenaar }
6917b893ac20SBram Moolenaar 
6918b893ac20SBram Moolenaar /*
6919b893ac20SBram Moolenaar  * Return TRUE if "topfrp" and its children are at the right width.
6920b893ac20SBram Moolenaar  */
6921b893ac20SBram Moolenaar     static int
frame_check_width(frame_T * topfrp,int width)6922b638a7beSBram Moolenaar frame_check_width(frame_T *topfrp, int width)
6923b893ac20SBram Moolenaar {
6924b893ac20SBram Moolenaar     frame_T *frp;
6925b893ac20SBram Moolenaar 
6926b893ac20SBram Moolenaar     if (topfrp->fr_width != width)
6927b893ac20SBram Moolenaar 	return FALSE;
6928b893ac20SBram Moolenaar 
6929b893ac20SBram Moolenaar     if (topfrp->fr_layout == FR_COL)
69303d1491edSBram Moolenaar 	FOR_ALL_FRAMES(frp, topfrp->fr_child)
6931b893ac20SBram Moolenaar 	    if (frp->fr_width != width)
6932b893ac20SBram Moolenaar 		return FALSE;
6933b893ac20SBram Moolenaar 
6934b893ac20SBram Moolenaar     return TRUE;
6935b893ac20SBram Moolenaar }
6936b893ac20SBram Moolenaar 
6937e677df8dSBram Moolenaar #if defined(FEAT_SYN_HL) || defined(PROTO)
6938e677df8dSBram Moolenaar /*
6939e677df8dSBram Moolenaar  * Simple int comparison function for use with qsort()
6940e677df8dSBram Moolenaar  */
6941e677df8dSBram Moolenaar     static int
int_cmp(const void * a,const void * b)6942e677df8dSBram Moolenaar int_cmp(const void *a, const void *b)
6943e677df8dSBram Moolenaar {
6944e677df8dSBram Moolenaar     return *(const int *)a - *(const int *)b;
6945e677df8dSBram Moolenaar }
6946e677df8dSBram Moolenaar 
6947e677df8dSBram Moolenaar /*
6948e677df8dSBram Moolenaar  * Handle setting 'colorcolumn' or 'textwidth' in window "wp".
6949e677df8dSBram Moolenaar  * Returns error message, NULL if it's OK.
6950e677df8dSBram Moolenaar  */
6951e677df8dSBram Moolenaar     char *
check_colorcolumn(win_T * wp)6952e677df8dSBram Moolenaar check_colorcolumn(win_T *wp)
6953e677df8dSBram Moolenaar {
6954e677df8dSBram Moolenaar     char_u	*s;
6955e677df8dSBram Moolenaar     int		col;
6956e677df8dSBram Moolenaar     int		count = 0;
6957e677df8dSBram Moolenaar     int		color_cols[256];
6958e677df8dSBram Moolenaar     int		i;
6959e677df8dSBram Moolenaar     int		j = 0;
6960e677df8dSBram Moolenaar 
6961e677df8dSBram Moolenaar     if (wp->w_buffer == NULL)
6962e677df8dSBram Moolenaar 	return NULL;  // buffer was closed
6963e677df8dSBram Moolenaar 
6964e677df8dSBram Moolenaar     for (s = wp->w_p_cc; *s != NUL && count < 255;)
6965e677df8dSBram Moolenaar     {
6966e677df8dSBram Moolenaar 	if (*s == '-' || *s == '+')
6967e677df8dSBram Moolenaar 	{
6968e677df8dSBram Moolenaar 	    // -N and +N: add to 'textwidth'
6969e677df8dSBram Moolenaar 	    col = (*s == '-') ? -1 : 1;
6970e677df8dSBram Moolenaar 	    ++s;
6971e677df8dSBram Moolenaar 	    if (!VIM_ISDIGIT(*s))
6972e677df8dSBram Moolenaar 		return e_invarg;
6973e677df8dSBram Moolenaar 	    col = col * getdigits(&s);
6974e677df8dSBram Moolenaar 	    if (wp->w_buffer->b_p_tw == 0)
6975e677df8dSBram Moolenaar 		goto skip;  // 'textwidth' not set, skip this item
6976e677df8dSBram Moolenaar 	    col += wp->w_buffer->b_p_tw;
6977e677df8dSBram Moolenaar 	    if (col < 0)
6978e677df8dSBram Moolenaar 		goto skip;
6979e677df8dSBram Moolenaar 	}
6980e677df8dSBram Moolenaar 	else if (VIM_ISDIGIT(*s))
6981e677df8dSBram Moolenaar 	    col = getdigits(&s);
6982e677df8dSBram Moolenaar 	else
6983e677df8dSBram Moolenaar 	    return e_invarg;
6984e677df8dSBram Moolenaar 	color_cols[count++] = col - 1;  // 1-based to 0-based
6985e677df8dSBram Moolenaar skip:
6986e677df8dSBram Moolenaar 	if (*s == NUL)
6987e677df8dSBram Moolenaar 	    break;
6988e677df8dSBram Moolenaar 	if (*s != ',')
6989e677df8dSBram Moolenaar 	    return e_invarg;
6990e677df8dSBram Moolenaar 	if (*++s == NUL)
6991e677df8dSBram Moolenaar 	    return e_invarg;  // illegal trailing comma as in "set cc=80,"
6992e677df8dSBram Moolenaar     }
6993e677df8dSBram Moolenaar 
6994e677df8dSBram Moolenaar     vim_free(wp->w_p_cc_cols);
6995e677df8dSBram Moolenaar     if (count == 0)
6996e677df8dSBram Moolenaar 	wp->w_p_cc_cols = NULL;
6997e677df8dSBram Moolenaar     else
6998e677df8dSBram Moolenaar     {
6999e677df8dSBram Moolenaar 	wp->w_p_cc_cols = ALLOC_MULT(int, count + 1);
7000e677df8dSBram Moolenaar 	if (wp->w_p_cc_cols != NULL)
7001e677df8dSBram Moolenaar 	{
7002e677df8dSBram Moolenaar 	    // sort the columns for faster usage on screen redraw inside
7003e677df8dSBram Moolenaar 	    // win_line()
7004e677df8dSBram Moolenaar 	    qsort(color_cols, count, sizeof(int), int_cmp);
7005e677df8dSBram Moolenaar 
7006e677df8dSBram Moolenaar 	    for (i = 0; i < count; ++i)
7007e677df8dSBram Moolenaar 		// skip duplicates
7008e677df8dSBram Moolenaar 		if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i])
7009e677df8dSBram Moolenaar 		    wp->w_p_cc_cols[j++] = color_cols[i];
7010e677df8dSBram Moolenaar 	    wp->w_p_cc_cols[j] = -1;  // end marker
7011e677df8dSBram Moolenaar 	}
7012e677df8dSBram Moolenaar     }
7013e677df8dSBram Moolenaar 
7014e677df8dSBram Moolenaar     return NULL;  // no error
7015e677df8dSBram Moolenaar }
7016e677df8dSBram Moolenaar #endif
7017