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