blob: 03cc56c7ecf88fc99f050c3de907e83b2b5e8eac [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read a list of people who contributed.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10#include "vim.h"
11
12#ifdef HAVE_FCNTL_H
13# include <fcntl.h> /* for chdir() */
14#endif
15
16static int path_is_url __ARGS((char_u *p));
17#if defined(FEAT_WINDOWS) || defined(PROTO)
18static int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +000019static void frame_comp_pos __ARGS((frame_T *topfrp, int *row, int *col));
20static void frame_setheight __ARGS((frame_T *curfrp, int height));
21#ifdef FEAT_VERTSPLIT
22static void frame_setwidth __ARGS((frame_T *curfrp, int width));
23#endif
24static void win_exchange __ARGS((long));
25static void win_rotate __ARGS((int, int));
26static void win_totop __ARGS((int size, int flags));
27static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height));
Bram Moolenaar49d7bf12006-02-17 21:45:41 +000028static int last_window __ARGS((void));
Bram Moolenaarf740b292006-02-16 22:11:02 +000029static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
30static win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp));
31static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000032static tabpage_T *alt_tabpage __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +000033static win_T *frame2win __ARGS((frame_T *frp));
34static int frame_has_win __ARGS((frame_T *frp, win_T *wp));
35static void frame_new_height __ARGS((frame_T *topfrp, int height, int topfirst, int wfh));
36static int frame_fixed_height __ARGS((frame_T *frp));
37#ifdef FEAT_VERTSPLIT
38static void frame_add_statusline __ARGS((frame_T *frp));
39static void frame_new_width __ARGS((frame_T *topfrp, int width, int leftfirst));
40static void frame_add_vsep __ARGS((frame_T *frp));
41static int frame_minwidth __ARGS((frame_T *topfrp, win_T *next_curwin));
42static void frame_fix_width __ARGS((win_T *wp));
43#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000044#endif
45static int win_alloc_firstwin __ARGS((void));
46#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +000047static tabpage_T *alloc_tabpage __ARGS((void));
48static void free_tabpage __ARGS((tabpage_T *tp));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000049static void leave_tabpage __ARGS((tabpage_T *tp));
50static void enter_tabpage __ARGS((tabpage_T *tp, buf_T *old_curbuf));
Bram Moolenaar071d4272004-06-13 20:20:40 +000051static void frame_fix_height __ARGS((win_T *wp));
52static int frame_minheight __ARGS((frame_T *topfrp, win_T *next_curwin));
53static void win_enter_ext __ARGS((win_T *wp, int undo_sync, int no_curwin));
Bram Moolenaarf740b292006-02-16 22:11:02 +000054static void win_free __ARGS((win_T *wp, tabpage_T *tp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000055static void win_append __ARGS((win_T *, win_T *));
Bram Moolenaarf740b292006-02-16 22:11:02 +000056static void win_remove __ARGS((win_T *, tabpage_T *tp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static void frame_append __ARGS((frame_T *after, frame_T *frp));
58static void frame_insert __ARGS((frame_T *before, frame_T *frp));
59static void frame_remove __ARGS((frame_T *frp));
60#ifdef FEAT_VERTSPLIT
61static void win_new_width __ARGS((win_T *wp, int width));
Bram Moolenaar071d4272004-06-13 20:20:40 +000062static void win_goto_ver __ARGS((int up, long count));
63static void win_goto_hor __ARGS((int left, long count));
64#endif
65static void frame_add_height __ARGS((frame_T *frp, int n));
66static void last_status_rec __ARGS((frame_T *fr, int statusline));
67
68static void make_snapshot __ARGS((void));
69static void make_snapshot_rec __ARGS((frame_T *fr, frame_T **frp));
70static void clear_snapshot __ARGS((void));
71static void clear_snapshot_rec __ARGS((frame_T *fr));
72static void restore_snapshot __ARGS((int close_curwin));
73static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
74static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
75
76#endif /* FEAT_WINDOWS */
77static win_T *win_alloc __ARGS((win_T *after));
78static void win_new_height __ARGS((win_T *, int));
79
80#define URL_SLASH 1 /* path_is_url() has found "://" */
81#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
82
83#define NOWIN (win_T *)-1 /* non-exisiting window */
84
Bram Moolenaar05159a02005-02-26 23:04:13 +000085#ifdef FEAT_WINDOWS
86static long p_ch_used = 1L; /* value of 'cmdheight' when frame
87 size was set */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000088# define ROWS_AVAIL (Rows - p_ch - tabpageline_height())
89#else
90# define ROWS_AVAIL (Rows - p_ch)
Bram Moolenaar05159a02005-02-26 23:04:13 +000091#endif
92
Bram Moolenaar071d4272004-06-13 20:20:40 +000093#if defined(FEAT_WINDOWS) || defined(PROTO)
94/*
95 * all CTRL-W window commands are handled here, called from normal_cmd().
96 */
97 void
98do_window(nchar, Prenum, xchar)
99 int nchar;
100 long Prenum;
101 int xchar; /* extra char from ":wincmd gx" or NUL */
102{
103 long Prenum1;
104 win_T *wp;
105#if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
106 char_u *ptr;
107#endif
108#ifdef FEAT_FIND_ID
109 int type = FIND_DEFINE;
110 int len;
111#endif
112 char_u cbuf[40];
113
114 if (Prenum == 0)
115 Prenum1 = 1;
116 else
117 Prenum1 = Prenum;
118
119#ifdef FEAT_CMDWIN
120# define CHECK_CMDWIN if (cmdwin_type != 0) { EMSG(_(e_cmdwin)); break; }
121#else
122# define CHECK_CMDWIN
123#endif
124
125 switch (nchar)
126 {
127/* split current window in two parts, horizontally */
128 case 'S':
129 case Ctrl_S:
130 case 's':
131 CHECK_CMDWIN
132#ifdef FEAT_VISUAL
133 reset_VIsual_and_resel(); /* stop Visual mode */
134#endif
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000135#ifdef FEAT_QUICKFIX
136 /* When splitting the quickfix window open a new buffer in it,
137 * don't replicate the quickfix buffer. */
138 if (bt_quickfix(curbuf))
139 goto newwindow;
140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141#ifdef FEAT_GUI
142 need_mouse_correct = TRUE;
143#endif
144 win_split((int)Prenum, 0);
145 break;
146
147#ifdef FEAT_VERTSPLIT
148/* split current window in two parts, vertically */
149 case Ctrl_V:
150 case 'v':
151 CHECK_CMDWIN
152#ifdef FEAT_VISUAL
153 reset_VIsual_and_resel(); /* stop Visual mode */
154#endif
155#ifdef FEAT_GUI
156 need_mouse_correct = TRUE;
157#endif
158 win_split((int)Prenum, WSP_VERT);
159 break;
160#endif
161
162/* split current window and edit alternate file */
163 case Ctrl_HAT:
164 case '^':
165 CHECK_CMDWIN
166#ifdef FEAT_VISUAL
167 reset_VIsual_and_resel(); /* stop Visual mode */
168#endif
169 STRCPY(cbuf, "split #");
170 if (Prenum)
171 sprintf((char *)cbuf + 7, "%ld", Prenum);
172 do_cmdline_cmd(cbuf);
173 break;
174
175/* open new window */
176 case Ctrl_N:
177 case 'n':
178 CHECK_CMDWIN
179#ifdef FEAT_VISUAL
180 reset_VIsual_and_resel(); /* stop Visual mode */
181#endif
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000182#ifdef FEAT_QUICKFIX
183newwindow:
184#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185 if (Prenum)
186 sprintf((char *)cbuf, "%ld", Prenum); /* window height */
187 else
188 cbuf[0] = NUL;
189 STRCAT(cbuf, "new");
190 do_cmdline_cmd(cbuf);
191 break;
192
193/* quit current window */
194 case Ctrl_Q:
195 case 'q':
196#ifdef FEAT_VISUAL
197 reset_VIsual_and_resel(); /* stop Visual mode */
198#endif
199 do_cmdline_cmd((char_u *)"quit");
200 break;
201
202/* close current window */
203 case Ctrl_C:
204 case 'c':
205#ifdef FEAT_VISUAL
206 reset_VIsual_and_resel(); /* stop Visual mode */
207#endif
208 do_cmdline_cmd((char_u *)"close");
209 break;
210
211#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
212/* close preview window */
213 case Ctrl_Z:
214 case 'z':
215 CHECK_CMDWIN
216#ifdef FEAT_VISUAL
217 reset_VIsual_and_resel(); /* stop Visual mode */
218#endif
219 do_cmdline_cmd((char_u *)"pclose");
220 break;
221
222/* cursor to preview window */
223 case 'P':
224 for (wp = firstwin; wp != NULL; wp = wp->w_next)
225 if (wp->w_p_pvw)
226 break;
227 if (wp == NULL)
228 EMSG(_("E441: There is no preview window"));
229 else
230 win_goto(wp);
231 break;
232#endif
233
234/* close all but current window */
235 case Ctrl_O:
236 case 'o':
237 CHECK_CMDWIN
238#ifdef FEAT_VISUAL
239 reset_VIsual_and_resel(); /* stop Visual mode */
240#endif
241 do_cmdline_cmd((char_u *)"only");
242 break;
243
244/* cursor to next window with wrap around */
245 case Ctrl_W:
246 case 'w':
247/* cursor to previous window with wrap around */
248 case 'W':
249 CHECK_CMDWIN
250 if (lastwin == firstwin && Prenum != 1) /* just one window */
251 beep_flush();
252 else
253 {
254 if (Prenum) /* go to specified window */
255 {
256 for (wp = firstwin; --Prenum > 0; )
257 {
258 if (wp->w_next == NULL)
259 break;
260 else
261 wp = wp->w_next;
262 }
263 }
264 else
265 {
266 if (nchar == 'W') /* go to previous window */
267 {
268 wp = curwin->w_prev;
269 if (wp == NULL)
270 wp = lastwin; /* wrap around */
271 }
272 else /* go to next window */
273 {
274 wp = curwin->w_next;
275 if (wp == NULL)
276 wp = firstwin; /* wrap around */
277 }
278 }
279 win_goto(wp);
280 }
281 break;
282
283/* cursor to window below */
284 case 'j':
285 case K_DOWN:
286 case Ctrl_J:
287 CHECK_CMDWIN
288#ifdef FEAT_VERTSPLIT
289 win_goto_ver(FALSE, Prenum1);
290#else
291 for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
292 wp = wp->w_next)
293 ;
294 win_goto(wp);
295#endif
296 break;
297
298/* cursor to window above */
299 case 'k':
300 case K_UP:
301 case Ctrl_K:
302 CHECK_CMDWIN
303#ifdef FEAT_VERTSPLIT
304 win_goto_ver(TRUE, Prenum1);
305#else
306 for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
307 wp = wp->w_prev)
308 ;
309 win_goto(wp);
310#endif
311 break;
312
313#ifdef FEAT_VERTSPLIT
314/* cursor to left window */
315 case 'h':
316 case K_LEFT:
317 case Ctrl_H:
318 case K_BS:
319 CHECK_CMDWIN
320 win_goto_hor(TRUE, Prenum1);
321 break;
322
323/* cursor to right window */
324 case 'l':
325 case K_RIGHT:
326 case Ctrl_L:
327 CHECK_CMDWIN
328 win_goto_hor(FALSE, Prenum1);
329 break;
330#endif
331
332/* cursor to top-left window */
333 case 't':
334 case Ctrl_T:
335 win_goto(firstwin);
336 break;
337
338/* cursor to bottom-right window */
339 case 'b':
340 case Ctrl_B:
341 win_goto(lastwin);
342 break;
343
344/* cursor to last accessed (previous) window */
345 case 'p':
346 case Ctrl_P:
347 if (prevwin == NULL)
348 beep_flush();
349 else
350 win_goto(prevwin);
351 break;
352
353/* exchange current and next window */
354 case 'x':
355 case Ctrl_X:
356 CHECK_CMDWIN
357 win_exchange(Prenum);
358 break;
359
360/* rotate windows downwards */
361 case Ctrl_R:
362 case 'r':
363 CHECK_CMDWIN
364#ifdef FEAT_VISUAL
365 reset_VIsual_and_resel(); /* stop Visual mode */
366#endif
367 win_rotate(FALSE, (int)Prenum1); /* downwards */
368 break;
369
370/* rotate windows upwards */
371 case 'R':
372 CHECK_CMDWIN
373#ifdef FEAT_VISUAL
374 reset_VIsual_and_resel(); /* stop Visual mode */
375#endif
376 win_rotate(TRUE, (int)Prenum1); /* upwards */
377 break;
378
379/* move window to the very top/bottom/left/right */
380 case 'K':
381 case 'J':
382#ifdef FEAT_VERTSPLIT
383 case 'H':
384 case 'L':
385#endif
386 CHECK_CMDWIN
387 win_totop((int)Prenum,
388 ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
389 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
390 break;
391
392/* make all windows the same height */
393 case '=':
394#ifdef FEAT_GUI
395 need_mouse_correct = TRUE;
396#endif
397 win_equal(NULL, FALSE, 'b');
398 break;
399
400/* increase current window height */
401 case '+':
402#ifdef FEAT_GUI
403 need_mouse_correct = TRUE;
404#endif
405 win_setheight(curwin->w_height + (int)Prenum1);
406 break;
407
408/* decrease current window height */
409 case '-':
410#ifdef FEAT_GUI
411 need_mouse_correct = TRUE;
412#endif
413 win_setheight(curwin->w_height - (int)Prenum1);
414 break;
415
416/* set current window height */
417 case Ctrl__:
418 case '_':
419#ifdef FEAT_GUI
420 need_mouse_correct = TRUE;
421#endif
422 win_setheight(Prenum ? (int)Prenum : 9999);
423 break;
424
425#ifdef FEAT_VERTSPLIT
426/* increase current window width */
427 case '>':
428#ifdef FEAT_GUI
429 need_mouse_correct = TRUE;
430#endif
431 win_setwidth(curwin->w_width + (int)Prenum1);
432 break;
433
434/* decrease current window width */
435 case '<':
436#ifdef FEAT_GUI
437 need_mouse_correct = TRUE;
438#endif
439 win_setwidth(curwin->w_width - (int)Prenum1);
440 break;
441
442/* set current window width */
443 case '|':
444#ifdef FEAT_GUI
445 need_mouse_correct = TRUE;
446#endif
447 win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
448 break;
449#endif
450
451/* jump to tag and split window if tag exists (in preview window) */
452#if defined(FEAT_QUICKFIX)
453 case '}':
454 CHECK_CMDWIN
455 if (Prenum)
456 g_do_tagpreview = Prenum;
457 else
458 g_do_tagpreview = p_pvh;
459 /*FALLTHROUGH*/
460#endif
461 case ']':
462 case Ctrl_RSB:
463 CHECK_CMDWIN
464#ifdef FEAT_VISUAL
465 reset_VIsual_and_resel(); /* stop Visual mode */
466#endif
467 if (Prenum)
468 postponed_split = Prenum;
469 else
470 postponed_split = -1;
471
472 /* Execute the command right here, required when
473 * "wincmd ]" was used in a function. */
474 do_nv_ident(Ctrl_RSB, NUL);
475 break;
476
477#ifdef FEAT_SEARCHPATH
478/* edit file name under cursor in a new window */
479 case 'f':
480 case Ctrl_F:
481 CHECK_CMDWIN
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000482
483 ptr = grab_file_name(Prenum1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484 if (ptr != NULL)
485 {
486#ifdef FEAT_GUI
487 need_mouse_correct = TRUE;
488#endif
489 setpcmark();
490 if (win_split(0, 0) == OK)
491 {
492# ifdef FEAT_SCROLLBIND
493 curwin->w_p_scb = FALSE;
494# endif
495 (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
496 ECMD_HIDE);
497 }
498 vim_free(ptr);
499 }
500 break;
501#endif
502
503#ifdef FEAT_FIND_ID
504/* Go to the first occurence of the identifier under cursor along path in a
505 * new window -- webb
506 */
507 case 'i': /* Go to any match */
508 case Ctrl_I:
509 type = FIND_ANY;
510 /* FALLTHROUGH */
511 case 'd': /* Go to definition, using 'define' */
512 case Ctrl_D:
513 CHECK_CMDWIN
514 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
515 break;
516 find_pattern_in_path(ptr, 0, len, TRUE,
517 Prenum == 0 ? TRUE : FALSE, type,
518 Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
519 curwin->w_set_curswant = TRUE;
520 break;
521#endif
522
Bram Moolenaar05159a02005-02-26 23:04:13 +0000523 case K_KENTER:
524 case CAR:
525#if defined(FEAT_QUICKFIX)
526 /*
527 * In a quickfix window a <CR> jumps to the error under the
528 * cursor in a new window.
529 */
530 if (bt_quickfix(curbuf))
531 {
Bram Moolenaar28c258f2006-01-25 22:02:51 +0000532 sprintf((char *)cbuf, "split +%ld%s",
533 (long)curwin->w_cursor.lnum,
534 (curwin->w_llist_ref == NULL) ? "cc" : "ll");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 do_cmdline_cmd(cbuf);
536 }
537#endif
538 break;
539
540
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541/* CTRL-W g extended commands */
542 case 'g':
543 case Ctrl_G:
544 CHECK_CMDWIN
545#ifdef USE_ON_FLY_SCROLL
546 dont_scroll = TRUE; /* disallow scrolling here */
547#endif
548 ++no_mapping;
549 ++allow_keys; /* no mapping for xchar, but allow key codes */
550 if (xchar == NUL)
551 xchar = safe_vgetc();
552#ifdef FEAT_LANGMAP
553 LANGMAP_ADJUST(xchar, TRUE);
554#endif
555 --no_mapping;
556 --allow_keys;
557#ifdef FEAT_CMDL_INFO
558 (void)add_to_showcmd(xchar);
559#endif
560 switch (xchar)
561 {
562#if defined(FEAT_QUICKFIX)
563 case '}':
564 xchar = Ctrl_RSB;
565 if (Prenum)
566 g_do_tagpreview = Prenum;
567 else
568 g_do_tagpreview = p_pvh;
569 /*FALLTHROUGH*/
570#endif
571 case ']':
572 case Ctrl_RSB:
573#ifdef FEAT_VISUAL
574 reset_VIsual_and_resel(); /* stop Visual mode */
575#endif
576 if (Prenum)
577 postponed_split = Prenum;
578 else
579 postponed_split = -1;
580
581 /* Execute the command right here, required when
582 * "wincmd g}" was used in a function. */
583 do_nv_ident('g', xchar);
584 break;
585
586 default:
587 beep_flush();
588 break;
589 }
590 break;
591
592 default: beep_flush();
593 break;
594 }
595}
596
597/*
598 * split the current window, implements CTRL-W s and :split
599 *
600 * "size" is the height or width for the new window, 0 to use half of current
601 * height or width.
602 *
603 * "flags":
604 * WSP_ROOM: require enough room for new window
605 * WSP_VERT: vertical split.
606 * WSP_TOP: open window at the top-left of the shell (help window).
607 * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
608 * WSP_HELP: creating the help window, keep layout snapshot
609 *
610 * return FAIL for failure, OK otherwise
611 */
612 int
613win_split(size, flags)
614 int size;
615 int flags;
616{
617 /* Add flags from ":vertical", ":topleft" and ":botright". */
618 flags |= cmdmod.split;
619 if ((flags & WSP_TOP) && (flags & WSP_BOT))
620 {
621 EMSG(_("E442: Can't split topleft and botright at the same time"));
622 return FAIL;
623 }
624
625 /* When creating the help window make a snapshot of the window layout.
626 * Otherwise clear the snapshot, it's now invalid. */
627 if (flags & WSP_HELP)
628 make_snapshot();
629 else
630 clear_snapshot();
631
632 return win_split_ins(size, flags, NULL, 0);
633}
634
635/*
636 * When "newwin" is NULL: split a window in two.
637 * When "newwin" is not NULL: insert this window at the far
638 * top/left/right/bottom.
639 * return FAIL for failure, OK otherwise
640 */
641 static int
642win_split_ins(size, flags, newwin, dir)
643 int size;
644 int flags;
645 win_T *newwin;
646 int dir;
647{
648 win_T *wp = newwin;
649 win_T *oldwin;
650 int new_size = size;
651 int i;
652 int need_status = 0;
653 int do_equal = FALSE;
654 int needed;
655 int available;
656 int oldwin_height = 0;
657 int layout;
658 frame_T *frp, *curfrp;
659 int before;
660
661 if (flags & WSP_TOP)
662 oldwin = firstwin;
663 else if (flags & WSP_BOT)
664 oldwin = lastwin;
665 else
666 oldwin = curwin;
667
668 /* add a status line when p_ls == 1 and splitting the first window */
669 if (lastwin == firstwin && p_ls == 1 && oldwin->w_status_height == 0)
670 {
671 if (oldwin->w_height <= p_wmh && newwin == NULL)
672 {
673 EMSG(_(e_noroom));
674 return FAIL;
675 }
676 need_status = STATUS_HEIGHT;
677 }
678
679#ifdef FEAT_VERTSPLIT
680 if (flags & WSP_VERT)
681 {
682 layout = FR_ROW;
683 do_equal = (p_ea && new_size == 0 && *p_ead != 'v');
684
685 /*
686 * Check if we are able to split the current window and compute its
687 * width.
688 */
689 needed = p_wmw + 1;
690 if (flags & WSP_ROOM)
691 needed += p_wiw - p_wmw;
692 if (p_ea || (flags & (WSP_BOT | WSP_TOP)))
693 {
694 available = topframe->fr_width;
695 needed += frame_minwidth(topframe, NULL);
696 }
697 else
698 available = oldwin->w_width;
699 if (available < needed && newwin == NULL)
700 {
701 EMSG(_(e_noroom));
702 return FAIL;
703 }
704 if (new_size == 0)
705 new_size = oldwin->w_width / 2;
706 if (new_size > oldwin->w_width - p_wmw - 1)
707 new_size = oldwin->w_width - p_wmw - 1;
708 if (new_size < p_wmw)
709 new_size = p_wmw;
710
711 /* if it doesn't fit in the current window, need win_equal() */
712 if (oldwin->w_width - new_size - 1 < p_wmw)
713 do_equal = TRUE;
714 }
715 else
716#endif
717 {
718 layout = FR_COL;
719 do_equal = (p_ea && new_size == 0
720#ifdef FEAT_VERTSPLIT
721 && *p_ead != 'h'
722#endif
723 );
724
725 /*
726 * Check if we are able to split the current window and compute its
727 * height.
728 */
729 needed = p_wmh + STATUS_HEIGHT + need_status;
730 if (flags & WSP_ROOM)
731 needed += p_wh - p_wmh;
732 if (p_ea || (flags & (WSP_BOT | WSP_TOP)))
733 {
734 available = topframe->fr_height;
735 needed += frame_minheight(topframe, NULL);
736 }
737 else
738 {
739 available = oldwin->w_height;
740 needed += p_wmh;
741 }
742 if (available < needed && newwin == NULL)
743 {
744 EMSG(_(e_noroom));
745 return FAIL;
746 }
747 oldwin_height = oldwin->w_height;
748 if (need_status)
749 {
750 oldwin->w_status_height = STATUS_HEIGHT;
751 oldwin_height -= STATUS_HEIGHT;
752 }
753 if (new_size == 0)
754 new_size = oldwin_height / 2;
755
756 if (new_size > oldwin_height - p_wmh - STATUS_HEIGHT)
757 new_size = oldwin_height - p_wmh - STATUS_HEIGHT;
758 if (new_size < p_wmh)
759 new_size = p_wmh;
760
761 /* if it doesn't fit in the current window, need win_equal() */
762 if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
763 do_equal = TRUE;
764
765 /* We don't like to take lines for the new window from a
766 * 'winfixheight' window. Take them from a window above or below
767 * instead, if possible. */
768 if (oldwin->w_p_wfh)
769 {
770 win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
771 oldwin);
772 oldwin_height = oldwin->w_height;
773 if (need_status)
774 oldwin_height -= STATUS_HEIGHT;
775 }
776 }
777
778 /*
779 * allocate new window structure and link it in the window list
780 */
781 if ((flags & WSP_TOP) == 0
782 && ((flags & WSP_BOT)
783 || (flags & WSP_BELOW)
784 || (!(flags & WSP_ABOVE)
785 && (
786#ifdef FEAT_VERTSPLIT
787 (flags & WSP_VERT) ? p_spr :
788#endif
789 p_sb))))
790 {
791 /* new window below/right of current one */
792 if (newwin == NULL)
793 wp = win_alloc(oldwin);
794 else
795 win_append(oldwin, wp);
796 }
797 else
798 {
799 if (newwin == NULL)
800 wp = win_alloc(oldwin->w_prev);
801 else
802 win_append(oldwin->w_prev, wp);
803 }
804
805 if (newwin == NULL)
806 {
807 if (wp == NULL)
808 return FAIL;
809
810 /*
811 * make the contents of the new window the same as the current one
812 */
813 wp->w_buffer = curbuf;
814 curbuf->b_nwindows++;
815 wp->w_cursor = curwin->w_cursor;
816 wp->w_valid = 0;
817 wp->w_curswant = curwin->w_curswant;
818 wp->w_set_curswant = curwin->w_set_curswant;
819 wp->w_topline = curwin->w_topline;
820#ifdef FEAT_DIFF
821 wp->w_topfill = curwin->w_topfill;
822#endif
823 wp->w_leftcol = curwin->w_leftcol;
824 wp->w_pcmark = curwin->w_pcmark;
825 wp->w_prev_pcmark = curwin->w_prev_pcmark;
826 wp->w_alt_fnum = curwin->w_alt_fnum;
827 wp->w_fraction = curwin->w_fraction;
828 wp->w_prev_fraction_row = curwin->w_prev_fraction_row;
829#ifdef FEAT_JUMPLIST
830 copy_jumplist(curwin, wp);
831#endif
Bram Moolenaar28c258f2006-01-25 22:02:51 +0000832#ifdef FEAT_QUICKFIX
833 copy_loclist(curwin, wp);
834#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 if (curwin->w_localdir != NULL)
836 wp->w_localdir = vim_strsave(curwin->w_localdir);
837
838 /* Use the same argument list. */
839 wp->w_alist = curwin->w_alist;
840 ++wp->w_alist->al_refcount;
841 wp->w_arg_idx = curwin->w_arg_idx;
842
843 /*
844 * copy tagstack and options from existing window
845 */
846 for (i = 0; i < curwin->w_tagstacklen; i++)
847 {
848 wp->w_tagstack[i] = curwin->w_tagstack[i];
849 if (wp->w_tagstack[i].tagname != NULL)
850 wp->w_tagstack[i].tagname =
851 vim_strsave(wp->w_tagstack[i].tagname);
852 }
853 wp->w_tagstackidx = curwin->w_tagstackidx;
854 wp->w_tagstacklen = curwin->w_tagstacklen;
855 win_copy_options(curwin, wp);
856#ifdef FEAT_FOLDING
857 copyFoldingState(curwin, wp);
858#endif
859 }
860
861 /*
862 * Reorganise the tree of frames to insert the new window.
863 */
864 if (flags & (WSP_TOP | WSP_BOT))
865 {
866#ifdef FEAT_VERTSPLIT
867 if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
868 || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
869#else
870 if (topframe->fr_layout == FR_COL)
871#endif
872 {
873 curfrp = topframe->fr_child;
874 if (flags & WSP_BOT)
875 while (curfrp->fr_next != NULL)
876 curfrp = curfrp->fr_next;
877 }
878 else
879 curfrp = topframe;
880 before = (flags & WSP_TOP);
881 }
882 else
883 {
884 curfrp = oldwin->w_frame;
885 if (flags & WSP_BELOW)
886 before = FALSE;
887 else if (flags & WSP_ABOVE)
888 before = TRUE;
889 else
890#ifdef FEAT_VERTSPLIT
891 if (flags & WSP_VERT)
892 before = !p_spr;
893 else
894#endif
895 before = !p_sb;
896 }
897 if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
898 {
899 /* Need to create a new frame in the tree to make a branch. */
900 frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
901 *frp = *curfrp;
902 curfrp->fr_layout = layout;
903 frp->fr_parent = curfrp;
904 frp->fr_next = NULL;
905 frp->fr_prev = NULL;
906 curfrp->fr_child = frp;
907 curfrp->fr_win = NULL;
908 curfrp = frp;
909 if (frp->fr_win != NULL)
910 oldwin->w_frame = frp;
911 else
912 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
913 frp->fr_parent = curfrp;
914 }
915
916 if (newwin == NULL)
917 {
918 /* Create a frame for the new window. */
919 frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
920 frp->fr_layout = FR_LEAF;
921 frp->fr_win = wp;
922 wp->w_frame = frp;
923 }
924 else
925 frp = newwin->w_frame;
926 frp->fr_parent = curfrp->fr_parent;
927
928 /* Insert the new frame at the right place in the frame list. */
929 if (before)
930 frame_insert(curfrp, frp);
931 else
932 frame_append(curfrp, frp);
933
934#ifdef FEAT_VERTSPLIT
935 if (flags & WSP_VERT)
936 {
937 wp->w_p_scr = curwin->w_p_scr;
938 if (need_status)
939 {
940 --oldwin->w_height;
941 oldwin->w_status_height = need_status;
942 }
943 if (flags & (WSP_TOP | WSP_BOT))
944 {
945 /* set height and row of new window to full height */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +0000946 wp->w_winrow = tabpageline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947 wp->w_height = curfrp->fr_height - (p_ls > 0);
948 wp->w_status_height = (p_ls > 0);
949 }
950 else
951 {
952 /* height and row of new window is same as current window */
953 wp->w_winrow = oldwin->w_winrow;
954 wp->w_height = oldwin->w_height;
955 wp->w_status_height = oldwin->w_status_height;
956 }
957 frp->fr_height = curfrp->fr_height;
958
959 /* "new_size" of the current window goes to the new window, use
960 * one column for the vertical separator */
961 wp->w_width = new_size;
962 if (before)
963 wp->w_vsep_width = 1;
964 else
965 {
966 wp->w_vsep_width = oldwin->w_vsep_width;
967 oldwin->w_vsep_width = 1;
968 }
969 if (flags & (WSP_TOP | WSP_BOT))
970 {
971 if (flags & WSP_BOT)
972 frame_add_vsep(curfrp);
973 /* Set width of neighbor frame */
974 frame_new_width(curfrp, curfrp->fr_width
975 - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP);
976 }
977 else
978 oldwin->w_width -= new_size + 1;
979 if (before) /* new window left of current one */
980 {
981 wp->w_wincol = oldwin->w_wincol;
982 oldwin->w_wincol += new_size + 1;
983 }
984 else /* new window right of current one */
985 wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
986 frame_fix_width(oldwin);
987 frame_fix_width(wp);
988 }
989 else
990#endif
991 {
992 /* width and column of new window is same as current window */
993#ifdef FEAT_VERTSPLIT
994 if (flags & (WSP_TOP | WSP_BOT))
995 {
996 wp->w_wincol = 0;
997 wp->w_width = Columns;
998 wp->w_vsep_width = 0;
999 }
1000 else
1001 {
1002 wp->w_wincol = oldwin->w_wincol;
1003 wp->w_width = oldwin->w_width;
1004 wp->w_vsep_width = oldwin->w_vsep_width;
1005 }
1006 frp->fr_width = curfrp->fr_width;
1007#endif
1008
1009 /* "new_size" of the current window goes to the new window, use
1010 * one row for the status line */
1011 win_new_height(wp, new_size);
1012 if (flags & (WSP_TOP | WSP_BOT))
1013 frame_new_height(curfrp, curfrp->fr_height
1014 - (new_size + STATUS_HEIGHT), flags & WSP_TOP, FALSE);
1015 else
1016 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1017 if (before) /* new window above current one */
1018 {
1019 wp->w_winrow = oldwin->w_winrow;
1020 wp->w_status_height = STATUS_HEIGHT;
1021 oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
1022 }
1023 else /* new window below current one */
1024 {
1025 wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
1026 wp->w_status_height = oldwin->w_status_height;
1027 oldwin->w_status_height = STATUS_HEIGHT;
1028 }
1029#ifdef FEAT_VERTSPLIT
1030 if (flags & WSP_BOT)
1031 frame_add_statusline(curfrp);
1032#endif
1033 frame_fix_height(wp);
1034 frame_fix_height(oldwin);
1035 }
1036
1037 if (flags & (WSP_TOP | WSP_BOT))
1038 (void)win_comp_pos();
1039
1040 /*
1041 * Both windows need redrawing
1042 */
1043 redraw_win_later(wp, NOT_VALID);
1044 wp->w_redr_status = TRUE;
1045 redraw_win_later(oldwin, NOT_VALID);
1046 oldwin->w_redr_status = TRUE;
1047
1048 if (need_status)
1049 {
1050 msg_row = Rows - 1;
1051 msg_col = sc_col;
1052 msg_clr_eos_force(); /* Old command/ruler may still be there */
1053 comp_col();
1054 msg_row = Rows - 1;
1055 msg_col = 0; /* put position back at start of line */
1056 }
1057
1058 /*
1059 * make the new window the current window and redraw
1060 */
1061 if (do_equal || dir != 0)
1062 win_equal(wp, TRUE,
1063#ifdef FEAT_VERTSPLIT
1064 (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
1065 : dir == 'h' ? 'b' :
1066#endif
1067 'v');
1068
1069 /* Don't change the window height/width to 'winheight' / 'winwidth' if a
1070 * size was given. */
1071#ifdef FEAT_VERTSPLIT
1072 if (flags & WSP_VERT)
1073 {
1074 i = p_wiw;
1075 if (size != 0)
1076 p_wiw = size;
1077
1078# ifdef FEAT_GUI
1079 /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
1080 if (gui.in_use)
1081 gui_init_which_components(NULL);
1082# endif
1083 }
1084 else
1085#endif
1086 {
1087 i = p_wh;
1088 if (size != 0)
1089 p_wh = size;
1090 }
1091 win_enter(wp, FALSE);
1092#ifdef FEAT_VERTSPLIT
1093 if (flags & WSP_VERT)
1094 p_wiw = i;
1095 else
1096#endif
1097 p_wh = i;
1098
1099 return OK;
1100}
1101
1102#endif /* FEAT_WINDOWS */
1103
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104#if defined(FEAT_WINDOWS) || defined(PROTO)
1105/*
1106 * Check if "win" is a pointer to an existing window.
1107 */
1108 int
1109win_valid(win)
1110 win_T *win;
1111{
1112 win_T *wp;
1113
1114 if (win == NULL)
1115 return FALSE;
1116 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1117 if (wp == win)
1118 return TRUE;
1119 return FALSE;
1120}
1121
1122/*
1123 * Return the number of windows.
1124 */
1125 int
1126win_count()
1127{
1128 win_T *wp;
1129 int count = 0;
1130
1131 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1132 ++count;
1133 return count;
1134}
1135
1136/*
1137 * Make "count" windows on the screen.
1138 * Return actual number of windows on the screen.
1139 * Must be called when there is just one window, filling the whole screen
1140 * (excluding the command line).
1141 */
1142/*ARGSUSED*/
1143 int
1144make_windows(count, vertical)
1145 int count;
1146 int vertical; /* split windows vertically if TRUE */
1147{
1148 int maxcount;
1149 int todo;
1150
1151#ifdef FEAT_VERTSPLIT
1152 if (vertical)
1153 {
1154 /* Each windows needs at least 'winminwidth' lines and a separator
1155 * column. */
1156 maxcount = (curwin->w_width + curwin->w_vsep_width
1157 - (p_wiw - p_wmw)) / (p_wmw + 1);
1158 }
1159 else
1160#endif
1161 {
1162 /* Each window needs at least 'winminheight' lines and a status line. */
1163 maxcount = (curwin->w_height + curwin->w_status_height
1164 - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
1165 }
1166
1167 if (maxcount < 2)
1168 maxcount = 2;
1169 if (count > maxcount)
1170 count = maxcount;
1171
1172 /*
1173 * add status line now, otherwise first window will be too big
1174 */
1175 if (count > 1)
1176 last_status(TRUE);
1177
1178#ifdef FEAT_AUTOCMD
1179 /*
1180 * Don't execute autocommands while creating the windows. Must do that
1181 * when putting the buffers in the windows.
1182 */
1183 ++autocmd_block;
1184#endif
1185
1186 /* todo is number of windows left to create */
1187 for (todo = count - 1; todo > 0; --todo)
1188#ifdef FEAT_VERTSPLIT
1189 if (vertical)
1190 {
1191 if (win_split(curwin->w_width - (curwin->w_width - todo)
1192 / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
1193 break;
1194 }
1195 else
1196#endif
1197 {
1198 if (win_split(curwin->w_height - (curwin->w_height - todo
1199 * STATUS_HEIGHT) / (todo + 1)
1200 - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
1201 break;
1202 }
1203
1204#ifdef FEAT_AUTOCMD
1205 --autocmd_block;
1206#endif
1207
1208 /* return actual number of windows */
1209 return (count - todo);
1210}
1211
1212/*
1213 * Exchange current and next window
1214 */
1215 static void
1216win_exchange(Prenum)
1217 long Prenum;
1218{
1219 frame_T *frp;
1220 frame_T *frp2;
1221 win_T *wp;
1222 win_T *wp2;
1223 int temp;
1224
1225 if (lastwin == firstwin) /* just one window */
1226 {
1227 beep_flush();
1228 return;
1229 }
1230
1231#ifdef FEAT_GUI
1232 need_mouse_correct = TRUE;
1233#endif
1234
1235 /*
1236 * find window to exchange with
1237 */
1238 if (Prenum)
1239 {
1240 frp = curwin->w_frame->fr_parent->fr_child;
1241 while (frp != NULL && --Prenum > 0)
1242 frp = frp->fr_next;
1243 }
1244 else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
1245 frp = curwin->w_frame->fr_next;
1246 else /* Swap last window in row/col with previous */
1247 frp = curwin->w_frame->fr_prev;
1248
1249 /* We can only exchange a window with another window, not with a frame
1250 * containing windows. */
1251 if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
1252 return;
1253 wp = frp->fr_win;
1254
1255/*
1256 * 1. remove curwin from the list. Remember after which window it was in wp2
1257 * 2. insert curwin before wp in the list
1258 * if wp != wp2
1259 * 3. remove wp from the list
1260 * 4. insert wp after wp2
1261 * 5. exchange the status line height and vsep width.
1262 */
1263 wp2 = curwin->w_prev;
1264 frp2 = curwin->w_frame->fr_prev;
1265 if (wp->w_prev != curwin)
1266 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001267 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 frame_remove(curwin->w_frame);
1269 win_append(wp->w_prev, curwin);
1270 frame_insert(frp, curwin->w_frame);
1271 }
1272 if (wp != wp2)
1273 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001274 win_remove(wp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275 frame_remove(wp->w_frame);
1276 win_append(wp2, wp);
1277 if (frp2 == NULL)
1278 frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
1279 else
1280 frame_append(frp2, wp->w_frame);
1281 }
1282 temp = curwin->w_status_height;
1283 curwin->w_status_height = wp->w_status_height;
1284 wp->w_status_height = temp;
1285#ifdef FEAT_VERTSPLIT
1286 temp = curwin->w_vsep_width;
1287 curwin->w_vsep_width = wp->w_vsep_width;
1288 wp->w_vsep_width = temp;
1289
1290 /* If the windows are not in the same frame, exchange the sizes to avoid
1291 * messing up the window layout. Otherwise fix the frame sizes. */
1292 if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
1293 {
1294 temp = curwin->w_height;
1295 curwin->w_height = wp->w_height;
1296 wp->w_height = temp;
1297 temp = curwin->w_width;
1298 curwin->w_width = wp->w_width;
1299 wp->w_width = temp;
1300 }
1301 else
1302 {
1303 frame_fix_height(curwin);
1304 frame_fix_height(wp);
1305 frame_fix_width(curwin);
1306 frame_fix_width(wp);
1307 }
1308#endif
1309
1310 (void)win_comp_pos(); /* recompute window positions */
1311
1312 win_enter(wp, TRUE);
1313 redraw_later(CLEAR);
1314}
1315
1316/*
1317 * rotate windows: if upwards TRUE the second window becomes the first one
1318 * if upwards FALSE the first window becomes the second one
1319 */
1320 static void
1321win_rotate(upwards, count)
1322 int upwards;
1323 int count;
1324{
1325 win_T *wp1;
1326 win_T *wp2;
1327 frame_T *frp;
1328 int n;
1329
1330 if (firstwin == lastwin) /* nothing to do */
1331 {
1332 beep_flush();
1333 return;
1334 }
1335
1336#ifdef FEAT_GUI
1337 need_mouse_correct = TRUE;
1338#endif
1339
1340#ifdef FEAT_VERTSPLIT
1341 /* Check if all frames in this row/col have one window. */
1342 for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
1343 frp = frp->fr_next)
1344 if (frp->fr_win == NULL)
1345 {
1346 EMSG(_("E443: Cannot rotate when another window is split"));
1347 return;
1348 }
1349#endif
1350
1351 while (count--)
1352 {
1353 if (upwards) /* first window becomes last window */
1354 {
1355 /* remove first window/frame from the list */
1356 frp = curwin->w_frame->fr_parent->fr_child;
1357 wp1 = frp->fr_win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001358 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 frame_remove(frp);
1360
1361 /* find last frame and append removed window/frame after it */
1362 for ( ; frp->fr_next != NULL; frp = frp->fr_next)
1363 ;
1364 win_append(frp->fr_win, wp1);
1365 frame_append(frp, wp1->w_frame);
1366
1367 wp2 = frp->fr_win; /* previously last window */
1368 }
1369 else /* last window becomes first window */
1370 {
1371 /* find last window/frame in the list and remove it */
1372 for (frp = curwin->w_frame; frp->fr_next != NULL;
1373 frp = frp->fr_next)
1374 ;
1375 wp1 = frp->fr_win;
1376 wp2 = wp1->w_prev; /* will become last window */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001377 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378 frame_remove(frp);
1379
1380 /* append the removed window/frame before the first in the list */
1381 win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
1382 frame_insert(frp->fr_parent->fr_child, frp);
1383 }
1384
1385 /* exchange status height and vsep width of old and new last window */
1386 n = wp2->w_status_height;
1387 wp2->w_status_height = wp1->w_status_height;
1388 wp1->w_status_height = n;
1389 frame_fix_height(wp1);
1390 frame_fix_height(wp2);
1391#ifdef FEAT_VERTSPLIT
1392 n = wp2->w_vsep_width;
1393 wp2->w_vsep_width = wp1->w_vsep_width;
1394 wp1->w_vsep_width = n;
1395 frame_fix_width(wp1);
1396 frame_fix_width(wp2);
1397#endif
1398
1399 /* recompute w_winrow and w_wincol for all windows */
1400 (void)win_comp_pos();
1401 }
1402
1403 redraw_later(CLEAR);
1404}
1405
1406/*
1407 * Move the current window to the very top/bottom/left/right of the screen.
1408 */
1409 static void
1410win_totop(size, flags)
1411 int size;
1412 int flags;
1413{
1414 int dir;
1415 int height = curwin->w_height;
1416
1417 if (lastwin == firstwin)
1418 {
1419 beep_flush();
1420 return;
1421 }
1422
1423 /* Remove the window and frame from the tree of frames. */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001424 (void)winframe_remove(curwin, &dir, NULL);
1425 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001426 last_status(FALSE); /* may need to remove last status line */
1427 (void)win_comp_pos(); /* recompute window positions */
1428
1429 /* Split a window on the desired side and put the window there. */
1430 (void)win_split_ins(size, flags, curwin, dir);
1431 if (!(flags & WSP_VERT))
1432 {
1433 win_setheight(height);
1434 if (p_ea)
1435 win_equal(curwin, TRUE, 'v');
1436 }
1437
1438#if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
1439 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
1440 * scrollbars. Have to update them anyway. */
1441 if (gui.in_use)
1442 {
1443 out_flush();
1444 gui_init_which_components(NULL);
1445 gui_update_scrollbars(TRUE);
1446 }
1447 need_mouse_correct = TRUE;
1448#endif
1449
1450}
1451
1452/*
1453 * Move window "win1" to below/right of "win2" and make "win1" the current
1454 * window. Only works within the same frame!
1455 */
1456 void
1457win_move_after(win1, win2)
1458 win_T *win1, *win2;
1459{
1460 int height;
1461
1462 /* check if the arguments are reasonable */
1463 if (win1 == win2)
1464 return;
1465
1466 /* check if there is something to do */
1467 if (win2->w_next != win1)
1468 {
1469 /* may need move the status line/vertical separator of the last window
1470 * */
1471 if (win1 == lastwin)
1472 {
1473 height = win1->w_prev->w_status_height;
1474 win1->w_prev->w_status_height = win1->w_status_height;
1475 win1->w_status_height = height;
1476#ifdef FEAT_VERTSPLIT
1477 win1->w_prev->w_vsep_width = 0;
1478 win1->w_vsep_width = 1;
1479#endif
1480 }
1481 else if (win2 == lastwin)
1482 {
1483 height = win1->w_status_height;
1484 win1->w_status_height = win2->w_status_height;
1485 win2->w_status_height = height;
1486#ifdef FEAT_VERTSPLIT
1487 win2->w_vsep_width = 1;
1488 win1->w_vsep_width = 0;
1489#endif
1490 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00001491 win_remove(win1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001492 frame_remove(win1->w_frame);
1493 win_append(win2, win1);
1494 frame_append(win2->w_frame, win1->w_frame);
1495
1496 (void)win_comp_pos(); /* recompute w_winrow for all windows */
1497 redraw_later(NOT_VALID);
1498 }
1499 win_enter(win1, FALSE);
1500}
1501
1502/*
1503 * Make all windows the same height.
1504 * 'next_curwin' will soon be the current window, make sure it has enough
1505 * rows.
1506 */
1507 void
1508win_equal(next_curwin, current, dir)
1509 win_T *next_curwin; /* pointer to current window to be or NULL */
1510 int current; /* do only frame with current window */
1511 int dir; /* 'v' for vertically, 'h' for horizontally,
1512 'b' for both, 0 for using p_ead */
1513{
1514 if (dir == 0)
1515#ifdef FEAT_VERTSPLIT
1516 dir = *p_ead;
1517#else
1518 dir = 'b';
1519#endif
1520 win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001521 topframe, dir, 0, tabpageline_height(),
1522 (int)Columns, topframe->fr_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001523}
1524
1525/*
1526 * Set a frame to a new position and height, spreading the available room
1527 * equally over contained frames.
1528 * The window "next_curwin" (if not NULL) should at least get the size from
1529 * 'winheight' and 'winwidth' if possible.
1530 */
1531 static void
1532win_equal_rec(next_curwin, current, topfr, dir, col, row, width, height)
1533 win_T *next_curwin; /* pointer to current window to be or NULL */
1534 int current; /* do only frame with current window */
1535 frame_T *topfr; /* frame to set size off */
1536 int dir; /* 'v', 'h' or 'b', see win_equal() */
1537 int col; /* horizontal position for frame */
1538 int row; /* vertical position for frame */
1539 int width; /* new width of frame */
1540 int height; /* new height of frame */
1541{
1542 int n, m;
1543 int extra_sep = 0;
1544 int wincount, totwincount = 0;
1545 frame_T *fr;
1546 int next_curwin_size = 0;
1547 int room = 0;
1548 int new_size;
1549 int has_next_curwin = 0;
1550 int hnc;
1551
1552 if (topfr->fr_layout == FR_LEAF)
1553 {
1554 /* Set the width/height of this frame.
1555 * Redraw when size or position changes */
1556 if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
1557#ifdef FEAT_VERTSPLIT
1558 || topfr->fr_width != width || topfr->fr_win->w_wincol != col
1559#endif
1560 )
1561 {
1562 topfr->fr_win->w_winrow = row;
1563 frame_new_height(topfr, height, FALSE, FALSE);
1564#ifdef FEAT_VERTSPLIT
1565 topfr->fr_win->w_wincol = col;
1566 frame_new_width(topfr, width, FALSE);
1567#endif
1568 redraw_all_later(CLEAR);
1569 }
1570 }
1571#ifdef FEAT_VERTSPLIT
1572 else if (topfr->fr_layout == FR_ROW)
1573 {
1574 topfr->fr_width = width;
1575 topfr->fr_height = height;
1576
1577 if (dir != 'v') /* equalize frame widths */
1578 {
1579 /* Compute the maximum number of windows horizontally in this
1580 * frame. */
1581 n = frame_minwidth(topfr, NOWIN);
1582 /* add one for the rightmost window, it doesn't have a separator */
1583 if (col + width == Columns)
1584 extra_sep = 1;
1585 else
1586 extra_sep = 0;
1587 totwincount = (n + extra_sep) / (p_wmw + 1);
1588
1589 /* Compute room available for windows other than "next_curwin" */
1590 m = frame_minwidth(topfr, next_curwin);
1591 room = width - m;
1592 if (room < 0)
1593 {
1594 next_curwin_size = p_wiw + room;
1595 room = 0;
1596 }
1597 else if (n == m) /* doesn't contain curwin */
1598 next_curwin_size = 0;
1599 else
1600 {
1601 next_curwin_size = (room + p_wiw + (totwincount - 1) * p_wmw
1602 + (totwincount - 1)) / totwincount;
1603 if (next_curwin_size > p_wiw)
1604 room -= next_curwin_size - p_wiw;
1605 else
1606 next_curwin_size = p_wiw;
1607 }
1608 if (n != m)
1609 --totwincount; /* don't count curwin */
1610 }
1611
1612 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1613 {
1614 n = m = 0;
1615 wincount = 1;
1616 if (fr->fr_next == NULL)
1617 /* last frame gets all that remains (avoid roundoff error) */
1618 new_size = width;
1619 else if (dir == 'v')
1620 new_size = fr->fr_width;
1621 else
1622 {
1623 /* Compute the maximum number of windows horiz. in "fr". */
1624 n = frame_minwidth(fr, NOWIN);
1625 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
1626 / (p_wmw + 1);
1627 m = frame_minwidth(fr, next_curwin);
1628 if (n != m) /* don't count next_curwin */
1629 --wincount;
1630 new_size = (wincount * room + ((unsigned)totwincount >> 1))
1631 / totwincount;
1632 if (n != m) /* add next_curwin size */
1633 {
1634 next_curwin_size -= p_wiw - (m - n);
1635 new_size += next_curwin_size;
1636 }
1637 }
1638
1639 /* Skip frame that is full height when splitting or closing a
1640 * window, unless equalizing all frames. */
1641 if (!current || dir != 'v' || topfr->fr_parent != NULL
1642 || (new_size != fr->fr_width)
1643 || frame_has_win(fr, next_curwin))
1644 win_equal_rec(next_curwin, current, fr, dir, col, row,
1645 new_size + n, height);
1646 col += new_size + n;
1647 width -= new_size + n;
1648 if (n != m) /* contains curwin */
1649 room -= new_size - next_curwin_size;
1650 else
1651 room -= new_size;
1652 totwincount -= wincount;
1653 }
1654 }
1655#endif
1656 else /* topfr->fr_layout == FR_COL */
1657 {
1658#ifdef FEAT_VERTSPLIT
1659 topfr->fr_width = width;
1660#endif
1661 topfr->fr_height = height;
1662
1663 if (dir != 'h') /* equalize frame heights */
1664 {
1665 /* Compute maximum number of windows vertically in this frame. */
1666 n = frame_minheight(topfr, NOWIN);
1667 /* add one for the bottom window if it doesn't have a statusline */
1668 if (row + height == cmdline_row && p_ls == 0)
1669 extra_sep = 1;
1670 else
1671 extra_sep = 0;
1672 totwincount = (n + extra_sep) / (p_wmh + 1);
1673 has_next_curwin = frame_has_win(topfr, next_curwin);
1674
1675 /*
1676 * Compute height for "next_curwin" window and room available for
1677 * other windows.
1678 * "m" is the minimal height when counting p_wh for "next_curwin".
1679 */
1680 m = frame_minheight(topfr, next_curwin);
1681 room = height - m;
1682 if (room < 0)
1683 {
1684 /* The room is less then 'winheight', use all space for the
1685 * current window. */
1686 next_curwin_size = p_wh + room;
1687 room = 0;
1688 }
1689 else
1690 {
1691 next_curwin_size = -1;
1692 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1693 {
1694 /* If 'winfixheight' set keep the window height if
1695 * possible.
1696 * Watch out for this window being the next_curwin. */
1697 if (frame_fixed_height(fr))
1698 {
1699 n = frame_minheight(fr, NOWIN);
1700 new_size = fr->fr_height;
1701 if (frame_has_win(fr, next_curwin))
1702 {
1703 room += p_wh - p_wmh;
1704 next_curwin_size = 0;
1705 if (new_size < p_wh)
1706 new_size = p_wh;
1707 }
1708 else
1709 /* These windows don't use up room. */
1710 totwincount -= (n + (fr->fr_next == NULL
1711 ? extra_sep : 0)) / (p_wmh + 1);
1712 room -= new_size - n;
1713 if (room < 0)
1714 {
1715 new_size += room;
1716 room = 0;
1717 }
1718 fr->fr_newheight = new_size;
1719 }
1720 }
1721 if (next_curwin_size == -1)
1722 {
1723 if (!has_next_curwin)
1724 next_curwin_size = 0;
1725 else if (totwincount > 1
1726 && (room + (totwincount - 2))
1727 / (totwincount - 1) > p_wh)
1728 {
1729 next_curwin_size = (room + p_wh + totwincount * p_wmh
1730 + (totwincount - 1)) / totwincount;
1731 room -= next_curwin_size - p_wh;
1732 }
1733 else
1734 next_curwin_size = p_wh;
1735 }
1736 }
1737
1738 if (has_next_curwin)
1739 --totwincount; /* don't count curwin */
1740 }
1741
1742 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1743 {
1744 n = m = 0;
1745 wincount = 1;
1746 if (fr->fr_next == NULL)
1747 /* last frame gets all that remains (avoid roundoff error) */
1748 new_size = height;
1749 else if (dir == 'h')
1750 new_size = fr->fr_height;
1751 else if (frame_fixed_height(fr))
1752 {
1753 new_size = fr->fr_newheight;
1754 wincount = 0; /* doesn't count as a sizeable window */
1755 }
1756 else
1757 {
1758 /* Compute the maximum number of windows vert. in "fr". */
1759 n = frame_minheight(fr, NOWIN);
1760 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
1761 / (p_wmh + 1);
1762 m = frame_minheight(fr, next_curwin);
1763 if (has_next_curwin)
1764 hnc = frame_has_win(fr, next_curwin);
1765 else
1766 hnc = FALSE;
1767 if (hnc) /* don't count next_curwin */
1768 --wincount;
1769 if (totwincount == 0)
1770 new_size = room;
1771 else
1772 new_size = (wincount * room + ((unsigned)totwincount >> 1))
1773 / totwincount;
1774 if (hnc) /* add next_curwin size */
1775 {
1776 next_curwin_size -= p_wh - (m - n);
1777 new_size += next_curwin_size;
1778 room -= new_size - next_curwin_size;
1779 }
1780 else
1781 room -= new_size;
1782 new_size += n;
1783 }
1784 /* Skip frame that is full width when splitting or closing a
1785 * window, unless equalizing all frames. */
1786 if (!current || dir != 'h' || topfr->fr_parent != NULL
1787 || (new_size != fr->fr_height)
1788 || frame_has_win(fr, next_curwin))
1789 win_equal_rec(next_curwin, current, fr, dir, col, row,
1790 width, new_size);
1791 row += new_size;
1792 height -= new_size;
1793 totwincount -= wincount;
1794 }
1795 }
1796}
1797
1798/*
1799 * close all windows for buffer 'buf'
1800 */
1801 void
Bram Moolenaarf740b292006-02-16 22:11:02 +00001802close_windows(buf, keep_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 buf_T *buf;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001804 int keep_curwin; /* don't close "curwin" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805{
Bram Moolenaarf740b292006-02-16 22:11:02 +00001806 win_T *wp;
1807 tabpage_T *tp, *nexttp;
1808 int h = tabpageline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809
1810 ++RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001811
1812 for (wp = firstwin; wp != NULL && lastwin != firstwin; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001814 if (wp->w_buffer == buf && (!keep_curwin || wp != curwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001816 win_close(wp, FALSE);
1817
1818 /* Start all over, autocommands may change the window layout. */
1819 wp = firstwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 }
1821 else
Bram Moolenaarf740b292006-02-16 22:11:02 +00001822 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00001824
1825 /* Also check windows in other tab pages. */
1826 for (tp = first_tabpage; tp != NULL; tp = nexttp)
1827 {
1828 nexttp = tp->tp_next;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001829 if (tp != curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00001830 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1831 if (wp->w_buffer == buf)
1832 {
1833 win_close_othertab(wp, FALSE, tp);
1834
1835 /* Start all over, the tab page may be closed and
1836 * autocommands may change the window layout. */
1837 nexttp = first_tabpage;
1838 break;
1839 }
1840 }
1841
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 --RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001843
1844 if (h != tabpageline_height())
1845 shell_new_rows();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846}
1847
1848/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001849 * Return TRUE if the current window is the only window that exists.
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001850 * Returns FALSE if there is a window, possibly in another tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001851 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001852 static int
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001853last_window()
1854{
1855 return (lastwin == firstwin && first_tabpage->tp_next == NULL);
1856}
1857
1858/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00001859 * Close window "win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 * If "free_buf" is TRUE related buffer may be unloaded.
1861 *
1862 * called by :quit, :close, :xit, :wq and findtag()
1863 */
1864 void
1865win_close(win, free_buf)
1866 win_T *win;
1867 int free_buf;
1868{
1869 win_T *wp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001870 buf_T *old_curbuf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871#ifdef FEAT_AUTOCMD
1872 int other_buffer = FALSE;
1873#endif
1874 int close_curwin = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001875 int dir;
1876 int help_window = FALSE;
1877
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001878 if (last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 {
1880 EMSG(_("E444: Cannot close last window"));
1881 return;
1882 }
1883
1884 /* When closing the help window, try restoring a snapshot after closing
1885 * the window. Otherwise clear the snapshot, it's now invalid. */
1886 if (win->w_buffer->b_help)
1887 help_window = TRUE;
1888 else
1889 clear_snapshot();
1890
1891#ifdef FEAT_AUTOCMD
1892 if (win == curwin)
1893 {
1894 /*
1895 * Guess which window is going to be the new current window.
1896 * This may change because of the autocommands (sigh).
1897 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001898 wp = frame2win(win_altframe(win, NULL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899
1900 /*
1901 * Be careful: If autocommands delete the window, return now.
1902 */
1903 if (wp->w_buffer != curbuf)
1904 {
1905 other_buffer = TRUE;
1906 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001907 if (!win_valid(win) || last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 return;
1909 }
1910 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001911 if (!win_valid(win) || last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 return;
1913# ifdef FEAT_EVAL
1914 /* autocmds may abort script processing */
1915 if (aborting())
1916 return;
1917# endif
1918 }
1919#endif
1920
1921 /*
1922 * Close the link to the buffer.
1923 */
1924 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
1925 /* Autocommands may have closed the window already, or closed the only
1926 * other window. */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001927 if (!win_valid(win) || last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 return;
1929
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00001930 /* Free the memory used for the window. */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001931 wp = win_free_mem(win, &dir, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001933 /* When closing the last window in a tab page go to another tab page. */
1934 if (wp == NULL)
1935 {
1936 tabpage_T *ptp = NULL;
1937 tabpage_T *tp;
1938 tabpage_T *atp = alt_tabpage();
1939
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001940 for (tp = first_tabpage; tp != curtab; tp = tp->tp_next)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001941 ptp = tp;
1942 if (tp == NULL)
1943 {
1944 EMSG2(_(e_intern2), "win_close()");
1945 return;
1946 }
1947 if (ptp == NULL)
1948 first_tabpage = tp->tp_next;
1949 else
1950 ptp->tp_next = tp->tp_next;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00001951 free_tabpage(tp);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001952
1953 /* We don't do the window resizing stuff, let enter_tabpage() take
1954 * care of entering a window in another tab page. */
1955 enter_tabpage(atp, old_curbuf);
1956 return;
1957 }
1958
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 /* Make sure curwin isn't invalid. It can cause severe trouble when
1960 * printing an error message. For win_equal() curbuf needs to be valid
1961 * too. */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001962 else if (win == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 {
1964 curwin = wp;
1965#ifdef FEAT_QUICKFIX
1966 if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
1967 {
1968 /*
1969 * The cursor goes to the preview or the quickfix window, try
1970 * finding another window to go to.
1971 */
1972 for (;;)
1973 {
1974 if (wp->w_next == NULL)
1975 wp = firstwin;
1976 else
1977 wp = wp->w_next;
1978 if (wp == curwin)
1979 break;
1980 if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
1981 {
1982 curwin = wp;
1983 break;
1984 }
1985 }
1986 }
1987#endif
1988 curbuf = curwin->w_buffer;
1989 close_curwin = TRUE;
1990 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001991 if (p_ea
1992#ifdef FEAT_VERTSPLIT
1993 && (*p_ead == 'b' || *p_ead == dir)
1994#endif
1995 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001996 win_equal(curwin, TRUE,
1997#ifdef FEAT_VERTSPLIT
1998 dir
1999#else
2000 0
2001#endif
2002 );
2003 else
2004 win_comp_pos();
2005 if (close_curwin)
2006 {
2007 win_enter_ext(wp, FALSE, TRUE);
2008#ifdef FEAT_AUTOCMD
2009 if (other_buffer)
2010 /* careful: after this wp and win may be invalid! */
2011 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
2012#endif
2013 }
2014
2015 /*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002016 * If last window has a status line now and we don't want one,
2017 * remove the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 */
2019 last_status(FALSE);
2020
2021 /* After closing the help window, try restoring the window layout from
2022 * before it was opened. */
2023 if (help_window)
2024 restore_snapshot(close_curwin);
2025
2026#if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
2027 /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
2028 if (gui.in_use && !win_hasvertsplit())
2029 gui_init_which_components(NULL);
2030#endif
2031
2032 redraw_all_later(NOT_VALID);
2033}
2034
2035/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002036 * Close window "win" in tab page "tp", which is not the current tab page.
2037 * This may be the last window ih that tab page and result in closing the tab,
2038 * thus "tp" may become invalid!
2039 * Called must check if buffer is hidden.
2040 */
2041 void
2042win_close_othertab(win, free_buf, tp)
2043 win_T *win;
2044 int free_buf;
2045 tabpage_T *tp;
2046{
2047 win_T *wp;
2048 int dir;
2049 tabpage_T *ptp = NULL;
2050
2051 /* Close the link to the buffer. */
2052 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0);
2053
2054 /* Careful: Autocommands may have closed the tab page or made it the
2055 * current tab page. */
2056 for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
2057 ;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002058 if (ptp == NULL || tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002059 return;
2060
2061 /* Autocommands may have closed the window already. */
2062 for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
2063 ;
2064 if (wp == NULL)
2065 return;
2066
2067 /* Free the memory used for the window. */
2068 wp = win_free_mem(win, &dir, tp);
2069
2070 /* When closing the last window in a tab page remove the tab page. */
2071 if (wp == NULL)
2072 {
2073 if (tp == first_tabpage)
2074 first_tabpage = tp->tp_next;
2075 else
2076 {
2077 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
2078 ptp = ptp->tp_next)
2079 ;
2080 if (ptp == NULL)
2081 {
2082 EMSG2(_(e_intern2), "win_close_othertab()");
2083 return;
2084 }
2085 ptp->tp_next = tp->tp_next;
2086 }
2087 vim_free(tp);
2088 }
2089}
2090
2091/*
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002092 * Free the memory used for a window.
2093 * Returns a pointer to the window that got the freed up space.
2094 */
2095 static win_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002096win_free_mem(win, dirp, tp)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002097 win_T *win;
2098 int *dirp; /* set to 'v' or 'h' for direction if 'ea' */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002099 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002100{
2101 frame_T *frp;
2102 win_T *wp;
2103
Bram Moolenaarea408852005-06-25 22:49:46 +00002104#ifdef FEAT_FOLDING
2105 clearFolding(win);
2106#endif
2107
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002108 /* reduce the reference count to the argument list. */
2109 alist_unlink(win->w_alist);
2110
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002111 /* Remove the window and its frame from the tree of frames. */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002112 frp = win->w_frame;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002113 wp = winframe_remove(win, dirp, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002114 vim_free(frp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002115 win_free(win, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002116
2117 return wp;
2118}
2119
2120#if defined(EXITFREE) || defined(PROTO)
2121 void
2122win_free_all()
2123{
2124 int dummy;
2125
Bram Moolenaarf740b292006-02-16 22:11:02 +00002126# ifdef FEAT_WINDOWS
2127 while (first_tabpage->tp_next != NULL)
2128 tabpage_close(TRUE);
2129# endif
2130
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002131 while (firstwin != NULL)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002132 (void)win_free_mem(firstwin, &dummy, NULL);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002133}
2134#endif
2135
2136/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 * Remove a window and its frame from the tree of frames.
2138 * Returns a pointer to the window that got the freed up space.
2139 */
2140/*ARGSUSED*/
2141 static win_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002142winframe_remove(win, dirp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 win_T *win;
2144 int *dirp; /* set to 'v' or 'h' for direction if 'ea' */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002145 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146{
2147 frame_T *frp, *frp2, *frp3;
2148 frame_T *frp_close = win->w_frame;
2149 win_T *wp;
2150 int old_height = 0;
2151
2152 /*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002153 * If there is only one window there is nothing to remove.
2154 */
2155 if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
2156 return NULL;
2157
2158 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002159 * Remove the window from its frame.
2160 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002161 frp2 = win_altframe(win, tp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 wp = frame2win(frp2);
2163
2164 /* Remove this frame from the list of frames. */
2165 frame_remove(frp_close);
2166
2167#ifdef FEAT_VERTSPLIT
2168 if (frp_close->fr_parent->fr_layout == FR_COL)
2169 {
2170#endif
2171 /* When 'winfixheight' is set, remember its old size and restore
2172 * it later (it's a simplistic solution...). Don't do this if the
2173 * window will occupy the full height of the screen. */
2174 if (frp2->fr_win != NULL
2175 && (frp2->fr_next != NULL || frp2->fr_prev != NULL)
2176 && frp2->fr_win->w_p_wfh)
2177 old_height = frp2->fr_win->w_height;
2178 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
2179 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
2180 if (old_height != 0)
2181 win_setheight_win(old_height, frp2->fr_win);
2182#ifdef FEAT_VERTSPLIT
2183 *dirp = 'v';
2184 }
2185 else
2186 {
2187 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
2188 frp2 == frp_close->fr_next ? TRUE : FALSE);
2189 *dirp = 'h';
2190 }
2191#endif
2192
2193 /* If rows/columns go to a window below/right its positions need to be
2194 * updated. Can only be done after the sizes have been updated. */
2195 if (frp2 == frp_close->fr_next)
2196 {
2197 int row = win->w_winrow;
2198 int col = W_WINCOL(win);
2199
2200 frame_comp_pos(frp2, &row, &col);
2201 }
2202
2203 if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
2204 {
2205 /* There is no other frame in this list, move its info to the parent
2206 * and remove it. */
2207 frp2->fr_parent->fr_layout = frp2->fr_layout;
2208 frp2->fr_parent->fr_child = frp2->fr_child;
2209 for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
2210 frp->fr_parent = frp2->fr_parent;
2211 frp2->fr_parent->fr_win = frp2->fr_win;
2212 if (frp2->fr_win != NULL)
2213 frp2->fr_win->w_frame = frp2->fr_parent;
2214 frp = frp2->fr_parent;
2215 vim_free(frp2);
2216
2217 frp2 = frp->fr_parent;
2218 if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
2219 {
2220 /* The frame above the parent has the same layout, have to merge
2221 * the frames into this list. */
2222 if (frp2->fr_child == frp)
2223 frp2->fr_child = frp->fr_child;
2224 frp->fr_child->fr_prev = frp->fr_prev;
2225 if (frp->fr_prev != NULL)
2226 frp->fr_prev->fr_next = frp->fr_child;
2227 for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
2228 {
2229 frp3->fr_parent = frp2;
2230 if (frp3->fr_next == NULL)
2231 {
2232 frp3->fr_next = frp->fr_next;
2233 if (frp->fr_next != NULL)
2234 frp->fr_next->fr_prev = frp3;
2235 break;
2236 }
2237 }
2238 vim_free(frp);
2239 }
2240 }
2241
2242 return wp;
2243}
2244
2245/*
2246 * Find out which frame is going to get the freed up space when "win" is
2247 * closed.
2248 * if 'splitbelow'/'splitleft' the space goes to the window above/left.
2249 * if 'nosplitbelow'/'nosplitleft' the space goes to the window below/right.
2250 * This makes opening a window and closing it immediately keep the same window
2251 * layout.
2252 */
2253 static frame_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002254win_altframe(win, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002256 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257{
2258 frame_T *frp;
2259 int b;
2260
Bram Moolenaarf740b292006-02-16 22:11:02 +00002261 if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002262 /* Last window in this tab page, will go to next tab page. */
2263 return alt_tabpage()->tp_curwin->w_frame;
2264
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 frp = win->w_frame;
2266#ifdef FEAT_VERTSPLIT
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002267 if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 b = p_spr;
2269 else
2270#endif
2271 b = p_sb;
2272 if ((!b && frp->fr_next != NULL) || frp->fr_prev == NULL)
2273 return frp->fr_next;
2274 return frp->fr_prev;
2275}
2276
2277/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002278 * Return the tabpage that will be used if the current one is closed.
2279 */
2280 static tabpage_T *
2281alt_tabpage()
2282{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002283 tabpage_T *tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002284
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002285 /* Use the next tab page if it exists. */
2286 if (curtab->tp_next != NULL)
2287 return curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002288
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002289 /* Find the previous tab page. */
2290 for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
2291 if (tp->tp_next == curtab)
2292 return tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002293 return first_tabpage;
2294}
2295
2296/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 * Find the left-upper window in frame "frp".
2298 */
2299 static win_T *
2300frame2win(frp)
2301 frame_T *frp;
2302{
2303 while (frp->fr_win == NULL)
2304 frp = frp->fr_child;
2305 return frp->fr_win;
2306}
2307
2308/*
2309 * Return TRUE if frame "frp" contains window "wp".
2310 */
2311 static int
2312frame_has_win(frp, wp)
2313 frame_T *frp;
2314 win_T *wp;
2315{
2316 frame_T *p;
2317
2318 if (frp->fr_layout == FR_LEAF)
2319 return frp->fr_win == wp;
2320
2321 for (p = frp->fr_child; p != NULL; p = p->fr_next)
2322 if (frame_has_win(p, wp))
2323 return TRUE;
2324 return FALSE;
2325}
2326
2327/*
2328 * Set a new height for a frame. Recursively sets the height for contained
2329 * frames and windows. Caller must take care of positions.
2330 */
2331 static void
2332frame_new_height(topfrp, height, topfirst, wfh)
2333 frame_T *topfrp;
2334 int height;
2335 int topfirst; /* resize topmost contained frame first */
2336 int wfh; /* obey 'winfixheight' when there is a choice;
2337 may cause the height not to be set */
2338{
2339 frame_T *frp;
2340 int extra_lines;
2341 int h;
2342
2343 if (topfrp->fr_win != NULL)
2344 {
2345 /* Simple case: just one window. */
2346 win_new_height(topfrp->fr_win,
2347 height - topfrp->fr_win->w_status_height);
2348 }
2349#ifdef FEAT_VERTSPLIT
2350 else if (topfrp->fr_layout == FR_ROW)
2351 {
2352 do
2353 {
2354 /* All frames in this row get the same new height. */
2355 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2356 {
2357 frame_new_height(frp, height, topfirst, wfh);
2358 if (frp->fr_height > height)
2359 {
2360 /* Could not fit the windows, make the whole row higher. */
2361 height = frp->fr_height;
2362 break;
2363 }
2364 }
2365 }
2366 while (frp != NULL);
2367 }
2368#endif
2369 else
2370 {
2371 /* Complicated case: Resize a column of frames. Resize the bottom
2372 * frame first, frames above that when needed. */
2373
2374 frp = topfrp->fr_child;
2375 if (wfh)
2376 /* Advance past frames with one window with 'wfh' set. */
2377 while (frame_fixed_height(frp))
2378 {
2379 frp = frp->fr_next;
2380 if (frp == NULL)
2381 return; /* no frame without 'wfh', give up */
2382 }
2383 if (!topfirst)
2384 {
2385 /* Find the bottom frame of this column */
2386 while (frp->fr_next != NULL)
2387 frp = frp->fr_next;
2388 if (wfh)
2389 /* Advance back for frames with one window with 'wfh' set. */
2390 while (frame_fixed_height(frp))
2391 frp = frp->fr_prev;
2392 }
2393
2394 extra_lines = height - topfrp->fr_height;
2395 if (extra_lines < 0)
2396 {
2397 /* reduce height of contained frames, bottom or top frame first */
2398 while (frp != NULL)
2399 {
2400 h = frame_minheight(frp, NULL);
2401 if (frp->fr_height + extra_lines < h)
2402 {
2403 extra_lines += frp->fr_height - h;
2404 frame_new_height(frp, h, topfirst, wfh);
2405 }
2406 else
2407 {
2408 frame_new_height(frp, frp->fr_height + extra_lines,
2409 topfirst, wfh);
2410 break;
2411 }
2412 if (topfirst)
2413 {
2414 do
2415 frp = frp->fr_next;
2416 while (wfh && frp != NULL && frame_fixed_height(frp));
2417 }
2418 else
2419 {
2420 do
2421 frp = frp->fr_prev;
2422 while (wfh && frp != NULL && frame_fixed_height(frp));
2423 }
2424 /* Increase "height" if we could not reduce enough frames. */
2425 if (frp == NULL)
2426 height -= extra_lines;
2427 }
2428 }
2429 else if (extra_lines > 0)
2430 {
2431 /* increase height of bottom or top frame */
2432 frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
2433 }
2434 }
2435 topfrp->fr_height = height;
2436}
2437
2438/*
2439 * Return TRUE if height of frame "frp" should not be changed because of
2440 * the 'winfixheight' option.
2441 */
2442 static int
2443frame_fixed_height(frp)
2444 frame_T *frp;
2445{
2446 /* frame with one window: fixed height if 'winfixheight' set. */
2447 if (frp->fr_win != NULL)
2448 return frp->fr_win->w_p_wfh;
2449
2450 if (frp->fr_layout == FR_ROW)
2451 {
2452 /* The frame is fixed height if one of the frames in the row is fixed
2453 * height. */
2454 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2455 if (frame_fixed_height(frp))
2456 return TRUE;
2457 return FALSE;
2458 }
2459
2460 /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
2461 * frames in the row are fixed height. */
2462 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2463 if (!frame_fixed_height(frp))
2464 return FALSE;
2465 return TRUE;
2466}
2467
2468#ifdef FEAT_VERTSPLIT
2469/*
2470 * Add a status line to windows at the bottom of "frp".
2471 * Note: Does not check if there is room!
2472 */
2473 static void
2474frame_add_statusline(frp)
2475 frame_T *frp;
2476{
2477 win_T *wp;
2478
2479 if (frp->fr_layout == FR_LEAF)
2480 {
2481 wp = frp->fr_win;
2482 if (wp->w_status_height == 0)
2483 {
2484 if (wp->w_height > 0) /* don't make it negative */
2485 --wp->w_height;
2486 wp->w_status_height = STATUS_HEIGHT;
2487 }
2488 }
2489 else if (frp->fr_layout == FR_ROW)
2490 {
2491 /* Handle all the frames in the row. */
2492 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2493 frame_add_statusline(frp);
2494 }
2495 else /* frp->fr_layout == FR_COL */
2496 {
2497 /* Only need to handle the last frame in the column. */
2498 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
2499 ;
2500 frame_add_statusline(frp);
2501 }
2502}
2503
2504/*
2505 * Set width of a frame. Handles recursively going through contained frames.
2506 * May remove separator line for windows at the right side (for win_close()).
2507 */
2508 static void
2509frame_new_width(topfrp, width, leftfirst)
2510 frame_T *topfrp;
2511 int width;
2512 int leftfirst; /* resize leftmost contained frame first */
2513{
2514 frame_T *frp;
2515 int extra_cols;
2516 int w;
2517 win_T *wp;
2518
2519 if (topfrp->fr_layout == FR_LEAF)
2520 {
2521 /* Simple case: just one window. */
2522 wp = topfrp->fr_win;
2523 /* Find out if there are any windows right of this one. */
2524 for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
2525 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
2526 break;
2527 if (frp->fr_parent == NULL)
2528 wp->w_vsep_width = 0;
2529 win_new_width(wp, width - wp->w_vsep_width);
2530 }
2531 else if (topfrp->fr_layout == FR_COL)
2532 {
2533 /* All frames in this column get the same new width. */
2534 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2535 frame_new_width(frp, width, leftfirst);
2536 }
2537 else /* fr_layout == FR_ROW */
2538 {
2539 /* Complicated case: Resize a row of frames. Resize the rightmost
2540 * frame first, frames left of it when needed. */
2541
2542 /* Find the rightmost frame of this row */
2543 frp = topfrp->fr_child;
2544 if (!leftfirst)
2545 while (frp->fr_next != NULL)
2546 frp = frp->fr_next;
2547
2548 extra_cols = width - topfrp->fr_width;
2549 if (extra_cols < 0)
2550 {
2551 /* reduce frame width, rightmost frame first */
2552 while (frp != NULL)
2553 {
2554 w = frame_minwidth(frp, NULL);
2555 if (frp->fr_width + extra_cols < w)
2556 {
2557 extra_cols += frp->fr_width - w;
2558 frame_new_width(frp, w, leftfirst);
2559 }
2560 else
2561 {
2562 frame_new_width(frp, frp->fr_width + extra_cols, leftfirst);
2563 break;
2564 }
2565 if (leftfirst)
2566 frp = frp->fr_next;
2567 else
2568 frp = frp->fr_prev;
2569 }
2570 }
2571 else if (extra_cols > 0)
2572 {
2573 /* increase width of rightmost frame */
2574 frame_new_width(frp, frp->fr_width + extra_cols, leftfirst);
2575 }
2576 }
2577 topfrp->fr_width = width;
2578}
2579
2580/*
2581 * Add the vertical separator to windows at the right side of "frp".
2582 * Note: Does not check if there is room!
2583 */
2584 static void
2585frame_add_vsep(frp)
2586 frame_T *frp;
2587{
2588 win_T *wp;
2589
2590 if (frp->fr_layout == FR_LEAF)
2591 {
2592 wp = frp->fr_win;
2593 if (wp->w_vsep_width == 0)
2594 {
2595 if (wp->w_width > 0) /* don't make it negative */
2596 --wp->w_width;
2597 wp->w_vsep_width = 1;
2598 }
2599 }
2600 else if (frp->fr_layout == FR_COL)
2601 {
2602 /* Handle all the frames in the column. */
2603 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2604 frame_add_vsep(frp);
2605 }
2606 else /* frp->fr_layout == FR_ROW */
2607 {
2608 /* Only need to handle the last frame in the row. */
2609 frp = frp->fr_child;
2610 while (frp->fr_next != NULL)
2611 frp = frp->fr_next;
2612 frame_add_vsep(frp);
2613 }
2614}
2615
2616/*
2617 * Set frame width from the window it contains.
2618 */
2619 static void
2620frame_fix_width(wp)
2621 win_T *wp;
2622{
2623 wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
2624}
2625#endif
2626
2627/*
2628 * Set frame height from the window it contains.
2629 */
2630 static void
2631frame_fix_height(wp)
2632 win_T *wp;
2633{
2634 wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
2635}
2636
2637/*
2638 * Compute the minimal height for frame "topfrp".
2639 * Uses the 'winminheight' option.
2640 * When "next_curwin" isn't NULL, use p_wh for this window.
2641 * When "next_curwin" is NOWIN, don't use at least one line for the current
2642 * window.
2643 */
2644 static int
2645frame_minheight(topfrp, next_curwin)
2646 frame_T *topfrp;
2647 win_T *next_curwin;
2648{
2649 frame_T *frp;
2650 int m;
2651#ifdef FEAT_VERTSPLIT
2652 int n;
2653#endif
2654
2655 if (topfrp->fr_win != NULL)
2656 {
2657 if (topfrp->fr_win == next_curwin)
2658 m = p_wh + topfrp->fr_win->w_status_height;
2659 else
2660 {
2661 /* window: minimal height of the window plus status line */
2662 m = p_wmh + topfrp->fr_win->w_status_height;
2663 /* Current window is minimal one line high */
2664 if (p_wmh == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
2665 ++m;
2666 }
2667 }
2668#ifdef FEAT_VERTSPLIT
2669 else if (topfrp->fr_layout == FR_ROW)
2670 {
2671 /* get the minimal height from each frame in this row */
2672 m = 0;
2673 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2674 {
2675 n = frame_minheight(frp, next_curwin);
2676 if (n > m)
2677 m = n;
2678 }
2679 }
2680#endif
2681 else
2682 {
2683 /* Add up the minimal heights for all frames in this column. */
2684 m = 0;
2685 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2686 m += frame_minheight(frp, next_curwin);
2687 }
2688
2689 return m;
2690}
2691
2692#ifdef FEAT_VERTSPLIT
2693/*
2694 * Compute the minimal width for frame "topfrp".
2695 * When "next_curwin" isn't NULL, use p_wiw for this window.
2696 * When "next_curwin" is NOWIN, don't use at least one column for the current
2697 * window.
2698 */
2699 static int
2700frame_minwidth(topfrp, next_curwin)
2701 frame_T *topfrp;
2702 win_T *next_curwin; /* use p_wh and p_wiw for next_curwin */
2703{
2704 frame_T *frp;
2705 int m, n;
2706
2707 if (topfrp->fr_win != NULL)
2708 {
2709 if (topfrp->fr_win == next_curwin)
2710 m = p_wiw + topfrp->fr_win->w_vsep_width;
2711 else
2712 {
2713 /* window: minimal width of the window plus separator column */
2714 m = p_wmw + topfrp->fr_win->w_vsep_width;
2715 /* Current window is minimal one column wide */
2716 if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
2717 ++m;
2718 }
2719 }
2720 else if (topfrp->fr_layout == FR_COL)
2721 {
2722 /* get the minimal width from each frame in this column */
2723 m = 0;
2724 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2725 {
2726 n = frame_minwidth(frp, next_curwin);
2727 if (n > m)
2728 m = n;
2729 }
2730 }
2731 else
2732 {
2733 /* Add up the minimal widths for all frames in this row. */
2734 m = 0;
2735 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2736 m += frame_minwidth(frp, next_curwin);
2737 }
2738
2739 return m;
2740}
2741#endif
2742
2743
2744/*
2745 * Try to close all windows except current one.
2746 * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
2747 * used and the buffer was modified.
2748 *
2749 * Used by ":bdel" and ":only".
2750 */
2751 void
2752close_others(message, forceit)
2753 int message;
2754 int forceit; /* always hide all other windows */
2755{
2756 win_T *wp;
2757 win_T *nextwp;
2758 int r;
2759
2760 if (lastwin == firstwin)
2761 {
2762 if (message
2763#ifdef FEAT_AUTOCMD
2764 && !autocmd_busy
2765#endif
2766 )
2767 MSG(_("Already only one window"));
2768 return;
2769 }
2770
2771 /* Be very careful here: autocommands may change the window layout. */
2772 for (wp = firstwin; win_valid(wp); wp = nextwp)
2773 {
2774 nextwp = wp->w_next;
2775 if (wp != curwin) /* don't close current window */
2776 {
2777
2778 /* Check if it's allowed to abandon this window */
2779 r = can_abandon(wp->w_buffer, forceit);
2780#ifdef FEAT_AUTOCMD
2781 if (!win_valid(wp)) /* autocommands messed wp up */
2782 {
2783 nextwp = firstwin;
2784 continue;
2785 }
2786#endif
2787 if (!r)
2788 {
2789#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2790 if (message && (p_confirm || cmdmod.confirm) && p_write)
2791 {
2792 dialog_changed(wp->w_buffer, FALSE);
2793# ifdef FEAT_AUTOCMD
2794 if (!win_valid(wp)) /* autocommands messed wp up */
2795 {
2796 nextwp = firstwin;
2797 continue;
2798 }
2799# endif
2800 }
2801 if (bufIsChanged(wp->w_buffer))
2802#endif
2803 continue;
2804 }
2805 win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
2806 }
2807 }
2808
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002809 if (message && lastwin != firstwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 EMSG(_("E445: Other window contains changes"));
2811}
2812
2813#endif /* FEAT_WINDOWS */
2814
2815/*
2816 * init the cursor in the window
2817 *
2818 * called when a new file is being edited
2819 */
2820 void
2821win_init(wp)
2822 win_T *wp;
2823{
2824 redraw_win_later(wp, NOT_VALID);
2825 wp->w_lines_valid = 0;
2826 wp->w_cursor.lnum = 1;
2827 wp->w_curswant = wp->w_cursor.col = 0;
2828#ifdef FEAT_VIRTUALEDIT
2829 wp->w_cursor.coladd = 0;
2830#endif
2831 wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
2832 wp->w_pcmark.col = 0;
2833 wp->w_prev_pcmark.lnum = 0;
2834 wp->w_prev_pcmark.col = 0;
2835 wp->w_topline = 1;
2836#ifdef FEAT_DIFF
2837 wp->w_topfill = 0;
2838#endif
2839 wp->w_botline = 2;
2840#ifdef FEAT_FKMAP
2841 if (curwin->w_p_rl)
2842 wp->w_farsi = W_CONV + W_R_L;
2843 else
2844 wp->w_farsi = W_CONV;
2845#endif
2846}
2847
2848/*
2849 * Allocate the first window and put an empty buffer in it.
2850 * Called from main().
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002851 * Return FAIL when something goes wrong (out of memory).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002853 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854win_alloc_first()
2855{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002856 if (win_alloc_firstwin() == FAIL)
2857 return FAIL;
2858
2859#ifdef FEAT_WINDOWS
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002860 first_tabpage = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002861 if (first_tabpage == NULL)
2862 return FAIL;
2863 first_tabpage->tp_topframe = topframe;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002864 curtab = first_tabpage;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002865#endif
2866 return OK;
2867}
2868
2869/*
2870 * Allocate one window and put an empty buffer in it.
2871 * Called to create the first window in a new tab page.
2872 * Return FAIL when something goes wrong (out of memory).
2873 */
2874 static int
2875win_alloc_firstwin()
2876{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877 curwin = win_alloc(NULL);
2878 curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
2879 if (curwin == NULL || curbuf == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002880 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 curwin->w_buffer = curbuf;
2882 curbuf->b_nwindows = 1; /* there is one window */
2883#ifdef FEAT_WINDOWS
2884 curwin->w_alist = &global_alist;
2885#endif
2886 win_init(curwin); /* init current window */
2887
2888 topframe = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
2889 if (topframe == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002890 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 topframe->fr_layout = FR_LEAF;
2892#ifdef FEAT_VERTSPLIT
2893 topframe->fr_width = Columns;
2894#endif
2895 topframe->fr_height = Rows - p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00002896#ifdef FEAT_WINDOWS
2897 p_ch_used = p_ch;
2898#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002899 topframe->fr_win = curwin;
2900 curwin->w_frame = topframe;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002901
2902 return OK;
2903}
2904
2905/*
2906 * Initialize the window and frame size to the maximum.
2907 */
2908 void
2909win_init_size()
2910{
2911 firstwin->w_height = ROWS_AVAIL;
2912 topframe->fr_height = ROWS_AVAIL;
2913#ifdef FEAT_VERTSPLIT
2914 firstwin->w_width = Columns;
2915 topframe->fr_width = Columns;
2916#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917}
2918
2919#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002920
2921/*
2922 * Allocate a new tabpage_T and init the values.
2923 * Returns NULL when out of memory.
2924 */
2925 static tabpage_T *
2926alloc_tabpage()
2927{
2928 tabpage_T *tp;
2929
2930 tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
2931 if (tp != NULL)
2932 {
2933# ifdef FEAT_DIFF
2934 tp->tp_diff_invalid = TRUE;
2935# endif
2936 }
2937 return tp;
2938}
2939
2940 static void
2941free_tabpage(tp)
2942 tabpage_T *tp;
2943{
2944# ifdef FEAT_DIFF
2945 diff_clear(tp);
2946# endif
2947 vim_free(tp);
2948}
2949
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002950/*
2951 * Create a new Tab page with one empty window.
2952 * Put it just after the current Tab page.
2953 * Return FAIL or OK.
2954 */
2955 int
2956win_new_tabpage()
2957{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002958 tabpage_T *tp = curtab;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002959 tabpage_T *newtp;
2960
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002961 newtp = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002962 if (newtp == NULL)
2963 return FAIL;
2964
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002965 /* Remember the current windows in this Tab page. */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002966 leave_tabpage(curtab);
2967 curtab = newtp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002968
2969 /* Create a new empty window. */
2970 if (win_alloc_firstwin() == OK)
2971 {
2972 /* copy options from previous to new curwin */
2973 win_copy_options(tp->tp_curwin, curwin);
2974
2975 /* Make the new Tab page the new topframe. */
2976 newtp->tp_next = tp->tp_next;
2977 tp->tp_next = newtp;
2978 win_init_size();
2979 firstwin->w_winrow = tabpageline_height();
2980
2981 newtp->tp_topframe = topframe;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002982 last_status(FALSE);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002983 redraw_all_later(CLEAR);
2984 return OK;
2985 }
2986
2987 /* Failed, get back the previous Tab page */
2988 topframe = tp->tp_topframe;
2989 curwin = tp->tp_curwin;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002990 prevwin = tp->tp_prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002991 firstwin = tp->tp_firstwin;
2992 lastwin = tp->tp_lastwin;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002993 curtab = tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002994 return FAIL;
2995}
2996
2997/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002998 * Create up to "maxcount" tabpages with empty windows.
2999 * Returns the number of resulting tab pages.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003000 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003001 int
3002make_tabpages(maxcount)
3003 int maxcount;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003004{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003005 int count = maxcount;
3006 int todo;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003007
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003008 /* Limit to 10 tabs. */
3009 if (count > 10)
3010 count = 10;
3011
3012#ifdef FEAT_AUTOCMD
3013 /*
3014 * Don't execute autocommands while creating the tab pages. Must do that
3015 * when putting the buffers in the windows.
3016 */
3017 ++autocmd_block;
3018#endif
3019
3020 for (todo = count - 1; todo > 0; --todo)
3021 if (win_new_tabpage() == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003022 break;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003023
3024#ifdef FEAT_AUTOCMD
3025 --autocmd_block;
3026#endif
3027
3028 /* return actual number of tab pages */
3029 return (count - todo);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003030}
3031
3032/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003033 * Return TRUE when "tpc" points to a valid tab page.
3034 */
3035 int
3036valid_tabpage(tpc)
3037 tabpage_T *tpc;
3038{
3039 tabpage_T *tp;
3040
3041 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
3042 if (tp == tpc)
3043 return TRUE;
3044 return FALSE;
3045}
3046
3047/*
3048 * Find tab page "n" (first one is 1). Returns NULL when not found.
3049 */
3050 tabpage_T *
3051find_tabpage(n)
3052 int n;
3053{
3054 tabpage_T *tp;
3055 int i = 1;
3056
3057 for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
3058 ++i;
3059 return tp;
3060}
3061
3062/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003063 * Prepare for leaving the current tab page "tp".
3064 */
3065 static void
3066leave_tabpage(tp)
3067 tabpage_T *tp;
3068{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003069#if defined(FEAT_GUI)
3070 /* Remove the scrollbars. They may be added back later. */
3071 if (gui.in_use)
3072 gui_remove_scrollbars();
3073#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003074 tp->tp_curwin = curwin;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003075 tp->tp_prevwin = prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003076 tp->tp_firstwin = firstwin;
3077 tp->tp_lastwin = lastwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003078 tp->tp_old_Rows = Rows;
3079 tp->tp_old_Columns = Columns;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003080 firstwin = NULL;
3081 lastwin = NULL;
3082}
3083
3084/*
3085 * Start using tab page "tp".
3086 */
3087/*ARGSUSED*/
3088 static void
3089enter_tabpage(tp, old_curbuf)
3090 tabpage_T *tp;
3091 buf_T *old_curbuf;
3092{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003093 int old_off = tp->tp_firstwin->w_winrow;
3094
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003095 curtab = tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003096 firstwin = tp->tp_firstwin;
3097 lastwin = tp->tp_lastwin;
3098 topframe = tp->tp_topframe;
3099 win_enter_ext(tp->tp_curwin, FALSE, TRUE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00003100 prevwin = tp->tp_prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003101
3102#ifdef FEAT_AUTOCMD
3103 if (old_curbuf != curbuf)
3104 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
3105#endif
3106
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003107 last_status(FALSE); /* status line may appear or disappear */
3108 (void)win_comp_pos(); /* recompute w_winrow for all windows */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003109 must_redraw = CLEAR; /* need to redraw everything */
3110#ifdef FEAT_DIFF
3111 diff_need_scrollbind = TRUE;
3112#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003113
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003114 /* The tabpage line may have appeared or disappeared, may need to resize
3115 * the frames for that. When the Vim window was resized need to update
3116 * frame sizes too. */
3117 if (tp->tp_old_Rows != Rows || old_off != firstwin->w_winrow)
3118 shell_new_rows();
3119#ifdef FEAT_VERTSPLIT
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003120 if (tp->tp_old_Columns != Columns && starting == 0)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003121 shell_new_columns(); /* update window widths */
3122#endif
3123
3124#if defined(FEAT_GUI)
3125 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3126 * scrollbars. Have to update them anyway. */
3127 if (gui.in_use)
3128 {
3129 out_flush();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003130 gui_init_which_components(NULL);
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003131 gui_update_scrollbars(TRUE);
3132 }
3133 need_mouse_correct = TRUE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003134#endif
3135
3136 redraw_all_later(CLEAR);
3137}
3138
3139/*
3140 * Go to tab page "n". For ":tab N" and "Ngt".
3141 */
3142 void
3143goto_tabpage(n)
3144 int n;
3145{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003146 tabpage_T *otp = curtab;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003147 tabpage_T *tp;
3148 int i;
3149
3150 if (otp == NULL)
3151 return;
3152
3153 if (n == 0)
3154 {
3155 /* No count, go to next tab page, wrap around end. */
3156 if (otp->tp_next == NULL)
3157 tp = first_tabpage;
3158 else
3159 tp = otp->tp_next;
3160 }
3161 else
3162 {
3163 /* Go to tab page "n". */
3164 i = 0;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003165 for (tp = first_tabpage; ++i != n && tp != NULL; tp = tp->tp_next)
3166 ;
3167 if (tp == NULL)
3168 {
3169 beep_flush();
3170 return;
3171 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003172 }
3173
3174 leave_tabpage(otp);
3175 enter_tabpage(tp, curbuf);
3176}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003177
3178/*
3179 * Go to another window.
3180 * When jumping to another buffer, stop Visual mode. Do this before
3181 * changing windows so we can yank the selection into the '*' register.
3182 * When jumping to another window on the same buffer, adjust its cursor
3183 * position to keep the same Visual area.
3184 */
3185 void
3186win_goto(wp)
3187 win_T *wp;
3188{
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003189 if (text_locked())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003190 {
3191 beep_flush();
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00003192 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193 return;
3194 }
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00003195
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196#ifdef FEAT_VISUAL
3197 if (wp->w_buffer != curbuf)
3198 reset_VIsual_and_resel();
3199 else if (VIsual_active)
3200 wp->w_cursor = curwin->w_cursor;
3201#endif
3202
3203#ifdef FEAT_GUI
3204 need_mouse_correct = TRUE;
3205#endif
3206 win_enter(wp, TRUE);
3207}
3208
3209#if defined(FEAT_PERL) || defined(PROTO)
3210/*
3211 * Find window number "winnr" (counting top to bottom).
3212 */
3213 win_T *
3214win_find_nr(winnr)
3215 int winnr;
3216{
3217 win_T *wp;
3218
3219# ifdef FEAT_WINDOWS
3220 for (wp = firstwin; wp != NULL; wp = wp->w_next)
3221 if (--winnr == 0)
3222 break;
3223 return wp;
3224# else
3225 return curwin;
3226# endif
3227}
3228#endif
3229
3230#ifdef FEAT_VERTSPLIT
3231/*
3232 * Move to window above or below "count" times.
3233 */
3234 static void
3235win_goto_ver(up, count)
3236 int up; /* TRUE to go to win above */
3237 long count;
3238{
3239 frame_T *fr;
3240 frame_T *nfr;
3241 frame_T *foundfr;
3242
3243 foundfr = curwin->w_frame;
3244 while (count--)
3245 {
3246 /*
3247 * First go upwards in the tree of frames until we find a upwards or
3248 * downwards neighbor.
3249 */
3250 fr = foundfr;
3251 for (;;)
3252 {
3253 if (fr == topframe)
3254 goto end;
3255 if (up)
3256 nfr = fr->fr_prev;
3257 else
3258 nfr = fr->fr_next;
3259 if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
3260 break;
3261 fr = fr->fr_parent;
3262 }
3263
3264 /*
3265 * Now go downwards to find the bottom or top frame in it.
3266 */
3267 for (;;)
3268 {
3269 if (nfr->fr_layout == FR_LEAF)
3270 {
3271 foundfr = nfr;
3272 break;
3273 }
3274 fr = nfr->fr_child;
3275 if (nfr->fr_layout == FR_ROW)
3276 {
3277 /* Find the frame at the cursor row. */
3278 while (fr->fr_next != NULL
3279 && frame2win(fr)->w_wincol + fr->fr_width
3280 <= curwin->w_wincol + curwin->w_wcol)
3281 fr = fr->fr_next;
3282 }
3283 if (nfr->fr_layout == FR_COL && up)
3284 while (fr->fr_next != NULL)
3285 fr = fr->fr_next;
3286 nfr = fr;
3287 }
3288 }
3289end:
3290 if (foundfr != NULL)
3291 win_goto(foundfr->fr_win);
3292}
3293
3294/*
3295 * Move to left or right window.
3296 */
3297 static void
3298win_goto_hor(left, count)
3299 int left; /* TRUE to go to left win */
3300 long count;
3301{
3302 frame_T *fr;
3303 frame_T *nfr;
3304 frame_T *foundfr;
3305
3306 foundfr = curwin->w_frame;
3307 while (count--)
3308 {
3309 /*
3310 * First go upwards in the tree of frames until we find a left or
3311 * right neighbor.
3312 */
3313 fr = foundfr;
3314 for (;;)
3315 {
3316 if (fr == topframe)
3317 goto end;
3318 if (left)
3319 nfr = fr->fr_prev;
3320 else
3321 nfr = fr->fr_next;
3322 if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
3323 break;
3324 fr = fr->fr_parent;
3325 }
3326
3327 /*
3328 * Now go downwards to find the leftmost or rightmost frame in it.
3329 */
3330 for (;;)
3331 {
3332 if (nfr->fr_layout == FR_LEAF)
3333 {
3334 foundfr = nfr;
3335 break;
3336 }
3337 fr = nfr->fr_child;
3338 if (nfr->fr_layout == FR_COL)
3339 {
3340 /* Find the frame at the cursor row. */
3341 while (fr->fr_next != NULL
3342 && frame2win(fr)->w_winrow + fr->fr_height
3343 <= curwin->w_winrow + curwin->w_wrow)
3344 fr = fr->fr_next;
3345 }
3346 if (nfr->fr_layout == FR_ROW && left)
3347 while (fr->fr_next != NULL)
3348 fr = fr->fr_next;
3349 nfr = fr;
3350 }
3351 }
3352end:
3353 if (foundfr != NULL)
3354 win_goto(foundfr->fr_win);
3355}
3356#endif
3357
3358/*
3359 * Make window "wp" the current window.
3360 */
3361 void
3362win_enter(wp, undo_sync)
3363 win_T *wp;
3364 int undo_sync;
3365{
3366 win_enter_ext(wp, undo_sync, FALSE);
3367}
3368
3369/*
3370 * Make window wp the current window.
3371 * Can be called with "curwin_invalid" TRUE, which means that curwin has just
3372 * been closed and isn't valid.
3373 */
3374 static void
3375win_enter_ext(wp, undo_sync, curwin_invalid)
3376 win_T *wp;
3377 int undo_sync;
3378 int curwin_invalid;
3379{
3380#ifdef FEAT_AUTOCMD
3381 int other_buffer = FALSE;
3382#endif
3383
3384 if (wp == curwin && !curwin_invalid) /* nothing to do */
3385 return;
3386
3387#ifdef FEAT_AUTOCMD
3388 if (!curwin_invalid)
3389 {
3390 /*
3391 * Be careful: If autocommands delete the window, return now.
3392 */
3393 if (wp->w_buffer != curbuf)
3394 {
3395 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
3396 other_buffer = TRUE;
3397 if (!win_valid(wp))
3398 return;
3399 }
3400 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
3401 if (!win_valid(wp))
3402 return;
3403# ifdef FEAT_EVAL
3404 /* autocmds may abort script processing */
3405 if (aborting())
3406 return;
3407# endif
3408 }
3409#endif
3410
3411 /* sync undo before leaving the current buffer */
3412 if (undo_sync && curbuf != wp->w_buffer)
3413 u_sync();
3414 /* may have to copy the buffer options when 'cpo' contains 'S' */
3415 if (wp->w_buffer != curbuf)
3416 buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
3417 if (!curwin_invalid)
3418 {
3419 prevwin = curwin; /* remember for CTRL-W p */
3420 curwin->w_redr_status = TRUE;
3421 }
3422 curwin = wp;
3423 curbuf = wp->w_buffer;
3424 check_cursor();
3425#ifdef FEAT_VIRTUALEDIT
3426 if (!virtual_active())
3427 curwin->w_cursor.coladd = 0;
3428#endif
3429 changed_line_abv_curs(); /* assume cursor position needs updating */
3430
3431 if (curwin->w_localdir != NULL)
3432 {
3433 /* Window has a local directory: Save current directory as global
3434 * directory (unless that was done already) and change to the local
3435 * directory. */
3436 if (globaldir == NULL)
3437 {
3438 char_u cwd[MAXPATHL];
3439
3440 if (mch_dirname(cwd, MAXPATHL) == OK)
3441 globaldir = vim_strsave(cwd);
3442 }
3443 mch_chdir((char *)curwin->w_localdir);
3444 shorten_fnames(TRUE);
3445 }
3446 else if (globaldir != NULL)
3447 {
3448 /* Window doesn't have a local directory and we are not in the global
3449 * directory: Change to the global directory. */
3450 mch_chdir((char *)globaldir);
3451 vim_free(globaldir);
3452 globaldir = NULL;
3453 shorten_fnames(TRUE);
3454 }
3455
3456#ifdef FEAT_AUTOCMD
3457 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
3458 if (other_buffer)
3459 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
3460#endif
3461
3462#ifdef FEAT_TITLE
3463 maketitle();
3464#endif
3465 curwin->w_redr_status = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003466 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 if (restart_edit)
3468 redraw_later(VALID); /* causes status line redraw */
3469
3470 /* set window height to desired minimal value */
3471 if (curwin->w_height < p_wh && !curwin->w_p_wfh)
3472 win_setheight((int)p_wh);
3473 else if (curwin->w_height == 0)
3474 win_setheight(1);
3475
3476#ifdef FEAT_VERTSPLIT
3477 /* set window width to desired minimal value */
3478 if (curwin->w_width < p_wiw)
3479 win_setwidth((int)p_wiw);
3480#endif
3481
3482#ifdef FEAT_MOUSE
3483 setmouse(); /* in case jumped to/from help buffer */
3484#endif
3485
3486#if defined(FEAT_NETBEANS_INTG) || defined(FEAT_SUN_WORKSHOP)
3487 /* Change directories when the acd option is set on and after
3488 * switching windows. */
3489 if (p_acd && curbuf->b_ffname != NULL
3490 && vim_chdirfile(curbuf->b_ffname) == OK)
3491 shorten_fnames(TRUE);
3492#endif
3493}
3494
3495#endif /* FEAT_WINDOWS */
3496
3497#if defined(FEAT_WINDOWS) || defined(FEAT_SIGNS) || defined(PROTO)
3498/*
3499 * Jump to the first open window that contains buffer buf if one exists
3500 * TODO: Alternatively jump to last open window? Dependent from 'splitbelow'?
3501 * Returns pointer to window if it exists, otherwise NULL.
3502 */
3503 win_T *
3504buf_jump_open_win(buf)
3505 buf_T *buf;
3506{
3507# ifdef FEAT_WINDOWS
3508 win_T *wp;
3509
3510 for (wp = firstwin; wp; wp = wp->w_next)
3511 if (wp->w_buffer == buf)
3512 break;
3513 if (wp != NULL)
3514 win_enter(wp, FALSE);
3515 return wp;
3516# else
3517 if (curwin->w_buffer == buf)
3518 return curwin;
3519 return NULL;
3520# endif
3521}
3522#endif
3523
3524/*
3525 * allocate a window structure and link it in the window list
3526 */
3527/*ARGSUSED*/
3528 static win_T *
3529win_alloc(after)
3530 win_T *after;
3531{
3532 win_T *newwin;
3533
3534 /*
3535 * allocate window structure and linesizes arrays
3536 */
3537 newwin = (win_T *)alloc_clear((unsigned)sizeof(win_T));
3538 if (newwin != NULL && win_alloc_lines(newwin) == FAIL)
3539 {
3540 vim_free(newwin);
3541 newwin = NULL;
3542 }
3543
3544 if (newwin != NULL)
3545 {
3546 /*
3547 * link the window in the window list
3548 */
3549#ifdef FEAT_WINDOWS
3550 win_append(after, newwin);
3551#endif
3552#ifdef FEAT_VERTSPLIT
3553 newwin->w_wincol = 0;
3554 newwin->w_width = Columns;
3555#endif
3556
3557 /* position the display and the cursor at the top of the file. */
3558 newwin->w_topline = 1;
3559#ifdef FEAT_DIFF
3560 newwin->w_topfill = 0;
3561#endif
3562 newwin->w_botline = 2;
3563 newwin->w_cursor.lnum = 1;
3564#ifdef FEAT_SCROLLBIND
3565 newwin->w_scbind_pos = 1;
3566#endif
3567
3568 /* We won't calculate w_fraction until resizing the window */
3569 newwin->w_fraction = 0;
3570 newwin->w_prev_fraction_row = -1;
3571
3572#ifdef FEAT_GUI
3573 if (gui.in_use)
3574 {
3575 out_flush();
3576 gui_create_scrollbar(&newwin->w_scrollbars[SBAR_LEFT],
3577 SBAR_LEFT, newwin);
3578 gui_create_scrollbar(&newwin->w_scrollbars[SBAR_RIGHT],
3579 SBAR_RIGHT, newwin);
3580 }
3581#endif
3582#ifdef FEAT_EVAL
Bram Moolenaar1fad5d42005-01-25 21:44:33 +00003583 /* init w: variables */
3584 init_var_dict(&newwin->w_vars, &newwin->w_winvar);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585#endif
3586#ifdef FEAT_FOLDING
3587 foldInitWin(newwin);
3588#endif
3589 }
3590 return newwin;
3591}
3592
3593#if defined(FEAT_WINDOWS) || defined(PROTO)
3594
3595/*
3596 * remove window 'wp' from the window list and free the structure
3597 */
3598 static void
Bram Moolenaarf740b292006-02-16 22:11:02 +00003599win_free(wp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003601 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602{
3603 int i;
3604
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003605#ifdef FEAT_MZSCHEME
3606 mzscheme_window_free(wp);
3607#endif
3608
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609#ifdef FEAT_PERL
3610 perl_win_free(wp);
3611#endif
3612
3613#ifdef FEAT_PYTHON
3614 python_window_free(wp);
3615#endif
3616
3617#ifdef FEAT_TCL
3618 tcl_window_free(wp);
3619#endif
3620
3621#ifdef FEAT_RUBY
3622 ruby_window_free(wp);
3623#endif
3624
3625 clear_winopt(&wp->w_onebuf_opt);
3626 clear_winopt(&wp->w_allbuf_opt);
3627
3628#ifdef FEAT_EVAL
Bram Moolenaar1fad5d42005-01-25 21:44:33 +00003629 vars_clear(&wp->w_vars.dv_hashtab); /* free all w: variables */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630#endif
3631
3632 if (prevwin == wp)
3633 prevwin = NULL;
3634 win_free_lsize(wp);
3635
3636 for (i = 0; i < wp->w_tagstacklen; ++i)
3637 vim_free(wp->w_tagstack[i].tagname);
3638
3639 vim_free(wp->w_localdir);
3640#ifdef FEAT_SEARCH_EXTRA
3641 vim_free(wp->w_match.regprog);
3642#endif
3643#ifdef FEAT_JUMPLIST
3644 free_jumplist(wp);
3645#endif
3646
Bram Moolenaar28c258f2006-01-25 22:02:51 +00003647#ifdef FEAT_QUICKFIX
3648 qf_free_all(wp);
3649#endif
3650
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651#ifdef FEAT_GUI
3652 if (gui.in_use)
3653 {
3654 out_flush();
3655 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
3656 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
3657 }
3658#endif /* FEAT_GUI */
3659
Bram Moolenaarf740b292006-02-16 22:11:02 +00003660 win_remove(wp, tp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 vim_free(wp);
3662}
3663
3664/*
3665 * Append window "wp" in the window list after window "after".
3666 */
3667 static void
3668win_append(after, wp)
3669 win_T *after, *wp;
3670{
3671 win_T *before;
3672
3673 if (after == NULL) /* after NULL is in front of the first */
3674 before = firstwin;
3675 else
3676 before = after->w_next;
3677
3678 wp->w_next = before;
3679 wp->w_prev = after;
3680 if (after == NULL)
3681 firstwin = wp;
3682 else
3683 after->w_next = wp;
3684 if (before == NULL)
3685 lastwin = wp;
3686 else
3687 before->w_prev = wp;
3688}
3689
3690/*
3691 * Remove a window from the window list.
3692 */
3693 static void
Bram Moolenaarf740b292006-02-16 22:11:02 +00003694win_remove(wp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003695 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003696 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697{
3698 if (wp->w_prev != NULL)
3699 wp->w_prev->w_next = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003700 else if (tp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 firstwin = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003702 else
3703 tp->tp_firstwin = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704 if (wp->w_next != NULL)
3705 wp->w_next->w_prev = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003706 else if (tp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 lastwin = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003708 else
3709 tp->tp_lastwin = wp->w_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710}
3711
3712/*
3713 * Append frame "frp" in a frame list after frame "after".
3714 */
3715 static void
3716frame_append(after, frp)
3717 frame_T *after, *frp;
3718{
3719 frp->fr_next = after->fr_next;
3720 after->fr_next = frp;
3721 if (frp->fr_next != NULL)
3722 frp->fr_next->fr_prev = frp;
3723 frp->fr_prev = after;
3724}
3725
3726/*
3727 * Insert frame "frp" in a frame list before frame "before".
3728 */
3729 static void
3730frame_insert(before, frp)
3731 frame_T *before, *frp;
3732{
3733 frp->fr_next = before;
3734 frp->fr_prev = before->fr_prev;
3735 before->fr_prev = frp;
3736 if (frp->fr_prev != NULL)
3737 frp->fr_prev->fr_next = frp;
3738 else
3739 frp->fr_parent->fr_child = frp;
3740}
3741
3742/*
3743 * Remove a frame from a frame list.
3744 */
3745 static void
3746frame_remove(frp)
3747 frame_T *frp;
3748{
3749 if (frp->fr_prev != NULL)
3750 frp->fr_prev->fr_next = frp->fr_next;
3751 else
3752 frp->fr_parent->fr_child = frp->fr_next;
3753 if (frp->fr_next != NULL)
3754 frp->fr_next->fr_prev = frp->fr_prev;
3755}
3756
3757#endif /* FEAT_WINDOWS */
3758
3759/*
3760 * Allocate w_lines[] for window "wp".
3761 * Return FAIL for failure, OK for success.
3762 */
3763 int
3764win_alloc_lines(wp)
3765 win_T *wp;
3766{
3767 wp->w_lines_valid = 0;
3768 wp->w_lines = (wline_T *)alloc((unsigned)(Rows * sizeof(wline_T)));
3769 if (wp->w_lines == NULL)
3770 return FAIL;
3771 return OK;
3772}
3773
3774/*
3775 * free lsize arrays for a window
3776 */
3777 void
3778win_free_lsize(wp)
3779 win_T *wp;
3780{
3781 vim_free(wp->w_lines);
3782 wp->w_lines = NULL;
3783}
3784
3785/*
3786 * Called from win_new_shellsize() after Rows changed.
Bram Moolenaarf740b292006-02-16 22:11:02 +00003787 * This only does the current tab page, others must be done when made active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 */
3789 void
3790shell_new_rows()
3791{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003792 int h = (int)ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793
3794 if (firstwin == NULL) /* not initialized yet */
3795 return;
3796#ifdef FEAT_WINDOWS
3797 if (h < frame_minheight(topframe, NULL))
3798 h = frame_minheight(topframe, NULL);
3799 /* First try setting the heights of windows without 'winfixheight'. If
3800 * that doesn't result in the right height, forget about that option. */
3801 frame_new_height(topframe, h, FALSE, TRUE);
3802 if (topframe->fr_height != h)
3803 frame_new_height(topframe, h, FALSE, FALSE);
3804
3805 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
3806#else
3807 if (h < 1)
3808 h = 1;
3809 win_new_height(firstwin, h);
3810#endif
3811 compute_cmdrow();
Bram Moolenaar05159a02005-02-26 23:04:13 +00003812#ifdef FEAT_WINDOWS
3813 p_ch_used = p_ch;
3814#endif
3815
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816#if 0
3817 /* Disabled: don't want making the screen smaller make a window larger. */
3818 if (p_ea)
3819 win_equal(curwin, FALSE, 'v');
3820#endif
3821}
3822
3823#if defined(FEAT_VERTSPLIT) || defined(PROTO)
3824/*
3825 * Called from win_new_shellsize() after Columns changed.
3826 */
3827 void
3828shell_new_columns()
3829{
3830 if (firstwin == NULL) /* not initialized yet */
3831 return;
3832 frame_new_width(topframe, (int)Columns, FALSE);
3833 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
3834#if 0
3835 /* Disabled: don't want making the screen smaller make a window larger. */
3836 if (p_ea)
3837 win_equal(curwin, FALSE, 'h');
3838#endif
3839}
3840#endif
3841
3842#if defined(FEAT_CMDWIN) || defined(PROTO)
3843/*
3844 * Save the size of all windows in "gap".
3845 */
3846 void
3847win_size_save(gap)
3848 garray_T *gap;
3849
3850{
3851 win_T *wp;
3852
3853 ga_init2(gap, (int)sizeof(int), 1);
3854 if (ga_grow(gap, win_count() * 2) == OK)
3855 for (wp = firstwin; wp != NULL; wp = wp->w_next)
3856 {
3857 ((int *)gap->ga_data)[gap->ga_len++] =
3858 wp->w_width + wp->w_vsep_width;
3859 ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
3860 }
3861}
3862
3863/*
3864 * Restore window sizes, but only if the number of windows is still the same.
3865 * Does not free the growarray.
3866 */
3867 void
3868win_size_restore(gap)
3869 garray_T *gap;
3870{
3871 win_T *wp;
3872 int i;
3873
3874 if (win_count() * 2 == gap->ga_len)
3875 {
3876 i = 0;
3877 for (wp = firstwin; wp != NULL; wp = wp->w_next)
3878 {
3879 frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
3880 win_setheight_win(((int *)gap->ga_data)[i++], wp);
3881 }
3882 /* recompute the window positions */
3883 (void)win_comp_pos();
3884 }
3885}
3886#endif /* FEAT_CMDWIN */
3887
3888#if defined(FEAT_WINDOWS) || defined(PROTO)
3889/*
3890 * Update the position for all windows, using the width and height of the
3891 * frames.
3892 * Returns the row just after the last window.
3893 */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003894 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895win_comp_pos()
3896{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003897 int row = tabpageline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 int col = 0;
3899
3900 frame_comp_pos(topframe, &row, &col);
3901 return row;
3902}
3903
3904/*
3905 * Update the position of the windows in frame "topfrp", using the width and
3906 * height of the frames.
3907 * "*row" and "*col" are the top-left position of the frame. They are updated
3908 * to the bottom-right position plus one.
3909 */
3910 static void
3911frame_comp_pos(topfrp, row, col)
3912 frame_T *topfrp;
3913 int *row;
3914 int *col;
3915{
3916 win_T *wp;
3917 frame_T *frp;
3918#ifdef FEAT_VERTSPLIT
3919 int startcol;
3920 int startrow;
3921#endif
3922
3923 wp = topfrp->fr_win;
3924 if (wp != NULL)
3925 {
3926 if (wp->w_winrow != *row
3927#ifdef FEAT_VERTSPLIT
3928 || wp->w_wincol != *col
3929#endif
3930 )
3931 {
3932 /* position changed, redraw */
3933 wp->w_winrow = *row;
3934#ifdef FEAT_VERTSPLIT
3935 wp->w_wincol = *col;
3936#endif
3937 redraw_win_later(wp, NOT_VALID);
3938 wp->w_redr_status = TRUE;
3939 }
3940 *row += wp->w_height + wp->w_status_height;
3941#ifdef FEAT_VERTSPLIT
3942 *col += wp->w_width + wp->w_vsep_width;
3943#endif
3944 }
3945 else
3946 {
3947#ifdef FEAT_VERTSPLIT
3948 startrow = *row;
3949 startcol = *col;
3950#endif
3951 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3952 {
3953#ifdef FEAT_VERTSPLIT
3954 if (topfrp->fr_layout == FR_ROW)
3955 *row = startrow; /* all frames are at the same row */
3956 else
3957 *col = startcol; /* all frames are at the same col */
3958#endif
3959 frame_comp_pos(frp, row, col);
3960 }
3961 }
3962}
3963
3964#endif /* FEAT_WINDOWS */
3965
3966/*
3967 * Set current window height and take care of repositioning other windows to
3968 * fit around it.
3969 */
3970 void
3971win_setheight(height)
3972 int height;
3973{
3974 win_setheight_win(height, curwin);
3975}
3976
3977/*
3978 * Set the window height of window "win" and take care of repositioning other
3979 * windows to fit around it.
3980 */
3981 void
3982win_setheight_win(height, win)
3983 int height;
3984 win_T *win;
3985{
3986 int row;
3987
3988 if (win == curwin)
3989 {
3990 /* Always keep current window at least one line high, even when
3991 * 'winminheight' is zero. */
3992#ifdef FEAT_WINDOWS
3993 if (height < p_wmh)
3994 height = p_wmh;
3995#endif
3996 if (height == 0)
3997 height = 1;
3998 }
3999
4000#ifdef FEAT_WINDOWS
4001 frame_setheight(win->w_frame, height + win->w_status_height);
4002
4003 /* recompute the window positions */
4004 row = win_comp_pos();
4005#else
4006 if (height > topframe->fr_height)
4007 height = topframe->fr_height;
4008 win->w_height = height;
4009 row = height;
4010#endif
4011
4012 /*
4013 * If there is extra space created between the last window and the command
4014 * line, clear it.
4015 */
4016 if (full_screen && msg_scrolled == 0 && row < cmdline_row)
4017 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
4018 cmdline_row = row;
4019 msg_row = row;
4020 msg_col = 0;
4021
4022 redraw_all_later(NOT_VALID);
4023}
4024
4025#if defined(FEAT_WINDOWS) || defined(PROTO)
4026
4027/*
4028 * Set the height of a frame to "height" and take care that all frames and
4029 * windows inside it are resized. Also resize frames on the left and right if
4030 * the are in the same FR_ROW frame.
4031 *
4032 * Strategy:
4033 * If the frame is part of a FR_COL frame, try fitting the frame in that
4034 * frame. If that doesn't work (the FR_COL frame is too small), recursively
4035 * go to containing frames to resize them and make room.
4036 * If the frame is part of a FR_ROW frame, all frames must be resized as well.
4037 * Check for the minimal height of the FR_ROW frame.
4038 * At the top level we can also use change the command line height.
4039 */
4040 static void
4041frame_setheight(curfrp, height)
4042 frame_T *curfrp;
4043 int height;
4044{
4045 int room; /* total number of lines available */
4046 int take; /* number of lines taken from other windows */
4047 int room_cmdline; /* lines available from cmdline */
4048 int run;
4049 frame_T *frp;
4050 int h;
4051 int room_reserved;
4052
4053 /* If the height already is the desired value, nothing to do. */
4054 if (curfrp->fr_height == height)
4055 return;
4056
4057 if (curfrp->fr_parent == NULL)
4058 {
4059 /* topframe: can only change the command line */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004060 if (height > ROWS_AVAIL)
4061 height = ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062 if (height > 0)
4063 frame_new_height(curfrp, height, FALSE, FALSE);
4064 }
4065 else if (curfrp->fr_parent->fr_layout == FR_ROW)
4066 {
4067 /* Row of frames: Also need to resize frames left and right of this
4068 * one. First check for the minimal height of these. */
4069 h = frame_minheight(curfrp->fr_parent, NULL);
4070 if (height < h)
4071 height = h;
4072 frame_setheight(curfrp->fr_parent, height);
4073 }
4074 else
4075 {
4076 /*
4077 * Column of frames: try to change only frames in this column.
4078 */
4079#ifdef FEAT_VERTSPLIT
4080 /*
4081 * Do this twice:
4082 * 1: compute room available, if it's not enough try resizing the
4083 * containing frame.
4084 * 2: compute the room available and adjust the height to it.
4085 * Try not to reduce the height of a window with 'winfixheight' set.
4086 */
4087 for (run = 1; run <= 2; ++run)
4088#else
4089 for (;;)
4090#endif
4091 {
4092 room = 0;
4093 room_reserved = 0;
4094 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
4095 frp = frp->fr_next)
4096 {
4097 if (frp != curfrp
4098 && frp->fr_win != NULL
4099 && frp->fr_win->w_p_wfh)
4100 room_reserved += frp->fr_height;
4101 room += frp->fr_height;
4102 if (frp != curfrp)
4103 room -= frame_minheight(frp, NULL);
4104 }
4105#ifdef FEAT_VERTSPLIT
4106 if (curfrp->fr_width != Columns)
4107 room_cmdline = 0;
4108 else
4109#endif
4110 {
4111 room_cmdline = Rows - p_ch - (lastwin->w_winrow
4112 + lastwin->w_height + lastwin->w_status_height);
4113 if (room_cmdline < 0)
4114 room_cmdline = 0;
4115 }
4116
4117 if (height <= room + room_cmdline)
4118 break;
4119#ifdef FEAT_VERTSPLIT
4120 if (run == 2 || curfrp->fr_width == Columns)
4121#endif
4122 {
4123 if (height > room + room_cmdline)
4124 height = room + room_cmdline;
4125 break;
4126 }
4127#ifdef FEAT_VERTSPLIT
4128 frame_setheight(curfrp->fr_parent, height
4129 + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
4130#endif
4131 /*NOTREACHED*/
4132 }
4133
4134 /*
4135 * Compute the number of lines we will take from others frames (can be
4136 * negative!).
4137 */
4138 take = height - curfrp->fr_height;
4139
4140 /* If there is not enough room, also reduce the height of a window
4141 * with 'winfixheight' set. */
4142 if (height > room + room_cmdline - room_reserved)
4143 room_reserved = room + room_cmdline - height;
4144 /* If there is only a 'winfixheight' window and making the
4145 * window smaller, need to make the other window taller. */
4146 if (take < 0 && room - curfrp->fr_height < room_reserved)
4147 room_reserved = 0;
4148
4149 if (take > 0 && room_cmdline > 0)
4150 {
4151 /* use lines from cmdline first */
4152 if (take < room_cmdline)
4153 room_cmdline = take;
4154 take -= room_cmdline;
4155 topframe->fr_height += room_cmdline;
4156 }
4157
4158 /*
4159 * set the current frame to the new height
4160 */
4161 frame_new_height(curfrp, height, FALSE, FALSE);
4162
4163 /*
4164 * First take lines from the frames after the current frame. If
4165 * that is not enough, takes lines from frames above the current
4166 * frame.
4167 */
4168 for (run = 0; run < 2; ++run)
4169 {
4170 if (run == 0)
4171 frp = curfrp->fr_next; /* 1st run: start with next window */
4172 else
4173 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
4174 while (frp != NULL && take != 0)
4175 {
4176 h = frame_minheight(frp, NULL);
4177 if (room_reserved > 0
4178 && frp->fr_win != NULL
4179 && frp->fr_win->w_p_wfh)
4180 {
4181 if (room_reserved >= frp->fr_height)
4182 room_reserved -= frp->fr_height;
4183 else
4184 {
4185 if (frp->fr_height - room_reserved > take)
4186 room_reserved = frp->fr_height - take;
4187 take -= frp->fr_height - room_reserved;
4188 frame_new_height(frp, room_reserved, FALSE, FALSE);
4189 room_reserved = 0;
4190 }
4191 }
4192 else
4193 {
4194 if (frp->fr_height - take < h)
4195 {
4196 take -= frp->fr_height - h;
4197 frame_new_height(frp, h, FALSE, FALSE);
4198 }
4199 else
4200 {
4201 frame_new_height(frp, frp->fr_height - take,
4202 FALSE, FALSE);
4203 take = 0;
4204 }
4205 }
4206 if (run == 0)
4207 frp = frp->fr_next;
4208 else
4209 frp = frp->fr_prev;
4210 }
4211 }
4212 }
4213}
4214
4215#if defined(FEAT_VERTSPLIT) || defined(PROTO)
4216/*
4217 * Set current window width and take care of repositioning other windows to
4218 * fit around it.
4219 */
4220 void
4221win_setwidth(width)
4222 int width;
4223{
4224 win_setwidth_win(width, curwin);
4225}
4226
4227 void
4228win_setwidth_win(width, wp)
4229 int width;
4230 win_T *wp;
4231{
4232 /* Always keep current window at least one column wide, even when
4233 * 'winminwidth' is zero. */
4234 if (wp == curwin)
4235 {
4236 if (width < p_wmw)
4237 width = p_wmw;
4238 if (width == 0)
4239 width = 1;
4240 }
4241
4242 frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
4243
4244 /* recompute the window positions */
4245 (void)win_comp_pos();
4246
4247 redraw_all_later(NOT_VALID);
4248}
4249
4250/*
4251 * Set the width of a frame to "width" and take care that all frames and
4252 * windows inside it are resized. Also resize frames above and below if the
4253 * are in the same FR_ROW frame.
4254 *
4255 * Strategy is similar to frame_setheight().
4256 */
4257 static void
4258frame_setwidth(curfrp, width)
4259 frame_T *curfrp;
4260 int width;
4261{
4262 int room; /* total number of lines available */
4263 int take; /* number of lines taken from other windows */
4264 int run;
4265 frame_T *frp;
4266 int w;
4267
4268 /* If the width already is the desired value, nothing to do. */
4269 if (curfrp->fr_width == width)
4270 return;
4271
4272 if (curfrp->fr_parent == NULL)
4273 /* topframe: can't change width */
4274 return;
4275
4276 if (curfrp->fr_parent->fr_layout == FR_COL)
4277 {
4278 /* Column of frames: Also need to resize frames above and below of
4279 * this one. First check for the minimal width of these. */
4280 w = frame_minwidth(curfrp->fr_parent, NULL);
4281 if (width < w)
4282 width = w;
4283 frame_setwidth(curfrp->fr_parent, width);
4284 }
4285 else
4286 {
4287 /*
4288 * Row of frames: try to change only frames in this row.
4289 *
4290 * Do this twice:
4291 * 1: compute room available, if it's not enough try resizing the
4292 * containing frame.
4293 * 2: compute the room available and adjust the width to it.
4294 */
4295 for (run = 1; run <= 2; ++run)
4296 {
4297 room = 0;
4298 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
4299 frp = frp->fr_next)
4300 {
4301 room += frp->fr_width;
4302 if (frp != curfrp)
4303 room -= frame_minwidth(frp, NULL);
4304 }
4305
4306 if (width <= room)
4307 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004308 if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 {
4310 if (width > room)
4311 width = room;
4312 break;
4313 }
4314 frame_setwidth(curfrp->fr_parent, width
4315 + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
4316 }
4317
4318
4319 /*
4320 * Compute the number of lines we will take from others frames (can be
4321 * negative!).
4322 */
4323 take = width - curfrp->fr_width;
4324
4325 /*
4326 * set the current frame to the new width
4327 */
4328 frame_new_width(curfrp, width, FALSE);
4329
4330 /*
4331 * First take lines from the frames right of the current frame. If
4332 * that is not enough, takes lines from frames left of the current
4333 * frame.
4334 */
4335 for (run = 0; run < 2; ++run)
4336 {
4337 if (run == 0)
4338 frp = curfrp->fr_next; /* 1st run: start with next window */
4339 else
4340 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
4341 while (frp != NULL && take != 0)
4342 {
4343 w = frame_minwidth(frp, NULL);
4344 if (frp->fr_width - take < w)
4345 {
4346 take -= frp->fr_width - w;
4347 frame_new_width(frp, w, FALSE);
4348 }
4349 else
4350 {
4351 frame_new_width(frp, frp->fr_width - take, FALSE);
4352 take = 0;
4353 }
4354 if (run == 0)
4355 frp = frp->fr_next;
4356 else
4357 frp = frp->fr_prev;
4358 }
4359 }
4360 }
4361}
4362#endif /* FEAT_VERTSPLIT */
4363
4364/*
4365 * Check 'winminheight' for a valid value.
4366 */
4367 void
4368win_setminheight()
4369{
4370 int room;
4371 int first = TRUE;
4372 win_T *wp;
4373
4374 /* loop until there is a 'winminheight' that is possible */
4375 while (p_wmh > 0)
4376 {
4377 /* TODO: handle vertical splits */
4378 room = -p_wh;
4379 for (wp = firstwin; wp != NULL; wp = wp->w_next)
4380 room += wp->w_height - p_wmh;
4381 if (room >= 0)
4382 break;
4383 --p_wmh;
4384 if (first)
4385 {
4386 EMSG(_(e_noroom));
4387 first = FALSE;
4388 }
4389 }
4390}
4391
4392#ifdef FEAT_MOUSE
4393
4394/*
4395 * Status line of dragwin is dragged "offset" lines down (negative is up).
4396 */
4397 void
4398win_drag_status_line(dragwin, offset)
4399 win_T *dragwin;
4400 int offset;
4401{
4402 frame_T *curfr;
4403 frame_T *fr;
4404 int room;
4405 int row;
4406 int up; /* if TRUE, drag status line up, otherwise down */
4407 int n;
4408
4409 fr = dragwin->w_frame;
4410 curfr = fr;
4411 if (fr != topframe) /* more than one window */
4412 {
4413 fr = fr->fr_parent;
4414 /* When the parent frame is not a column of frames, its parent should
4415 * be. */
4416 if (fr->fr_layout != FR_COL)
4417 {
4418 curfr = fr;
4419 if (fr != topframe) /* only a row of windows, may drag statusline */
4420 fr = fr->fr_parent;
4421 }
4422 }
4423
4424 /* If this is the last frame in a column, may want to resize the parent
4425 * frame instead (go two up to skip a row of frames). */
4426 while (curfr != topframe && curfr->fr_next == NULL)
4427 {
4428 if (fr != topframe)
4429 fr = fr->fr_parent;
4430 curfr = fr;
4431 if (fr != topframe)
4432 fr = fr->fr_parent;
4433 }
4434
4435 if (offset < 0) /* drag up */
4436 {
4437 up = TRUE;
4438 offset = -offset;
4439 /* sum up the room of the current frame and above it */
4440 if (fr == curfr)
4441 {
4442 /* only one window */
4443 room = fr->fr_height - frame_minheight(fr, NULL);
4444 }
4445 else
4446 {
4447 room = 0;
4448 for (fr = fr->fr_child; ; fr = fr->fr_next)
4449 {
4450 room += fr->fr_height - frame_minheight(fr, NULL);
4451 if (fr == curfr)
4452 break;
4453 }
4454 }
4455 fr = curfr->fr_next; /* put fr at frame that grows */
4456 }
4457 else /* drag down */
4458 {
4459 up = FALSE;
4460 /*
4461 * Only dragging the last status line can reduce p_ch.
4462 */
4463 room = Rows - cmdline_row;
4464 if (curfr->fr_next == NULL)
4465 room -= 1;
4466 else
4467 room -= p_ch;
4468 if (room < 0)
4469 room = 0;
4470 /* sum up the room of frames below of the current one */
4471 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
4472 room += fr->fr_height - frame_minheight(fr, NULL);
4473 fr = curfr; /* put fr at window that grows */
4474 }
4475
4476 if (room < offset) /* Not enough room */
4477 offset = room; /* Move as far as we can */
4478 if (offset <= 0)
4479 return;
4480
4481 /*
4482 * Grow frame fr by "offset" lines.
4483 * Doesn't happen when dragging the last status line up.
4484 */
4485 if (fr != NULL)
4486 frame_new_height(fr, fr->fr_height + offset, up, FALSE);
4487
4488 if (up)
4489 fr = curfr; /* current frame gets smaller */
4490 else
4491 fr = curfr->fr_next; /* next frame gets smaller */
4492
4493 /*
4494 * Now make the other frames smaller.
4495 */
4496 while (fr != NULL && offset > 0)
4497 {
4498 n = frame_minheight(fr, NULL);
4499 if (fr->fr_height - offset <= n)
4500 {
4501 offset -= fr->fr_height - n;
4502 frame_new_height(fr, n, !up, FALSE);
4503 }
4504 else
4505 {
4506 frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
4507 break;
4508 }
4509 if (up)
4510 fr = fr->fr_prev;
4511 else
4512 fr = fr->fr_next;
4513 }
4514 row = win_comp_pos();
4515 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
4516 cmdline_row = row;
4517 p_ch = Rows - cmdline_row;
4518 if (p_ch < 1)
4519 p_ch = 1;
4520 redraw_all_later(NOT_VALID);
4521 showmode();
4522}
4523
4524#ifdef FEAT_VERTSPLIT
4525/*
4526 * Separator line of dragwin is dragged "offset" lines right (negative is left).
4527 */
4528 void
4529win_drag_vsep_line(dragwin, offset)
4530 win_T *dragwin;
4531 int offset;
4532{
4533 frame_T *curfr;
4534 frame_T *fr;
4535 int room;
4536 int left; /* if TRUE, drag separator line left, otherwise right */
4537 int n;
4538
4539 fr = dragwin->w_frame;
4540 if (fr == topframe) /* only one window (cannot happe?) */
4541 return;
4542 curfr = fr;
4543 fr = fr->fr_parent;
4544 /* When the parent frame is not a row of frames, its parent should be. */
4545 if (fr->fr_layout != FR_ROW)
4546 {
4547 if (fr == topframe) /* only a column of windows (cannot happen?) */
4548 return;
4549 curfr = fr;
4550 fr = fr->fr_parent;
4551 }
4552
4553 /* If this is the last frame in a row, may want to resize a parent
4554 * frame instead. */
4555 while (curfr->fr_next == NULL)
4556 {
4557 if (fr == topframe)
4558 break;
4559 curfr = fr;
4560 fr = fr->fr_parent;
4561 if (fr != topframe)
4562 {
4563 curfr = fr;
4564 fr = fr->fr_parent;
4565 }
4566 }
4567
4568 if (offset < 0) /* drag left */
4569 {
4570 left = TRUE;
4571 offset = -offset;
4572 /* sum up the room of the current frame and left of it */
4573 room = 0;
4574 for (fr = fr->fr_child; ; fr = fr->fr_next)
4575 {
4576 room += fr->fr_width - frame_minwidth(fr, NULL);
4577 if (fr == curfr)
4578 break;
4579 }
4580 fr = curfr->fr_next; /* put fr at frame that grows */
4581 }
4582 else /* drag right */
4583 {
4584 left = FALSE;
4585 /* sum up the room of frames right of the current one */
4586 room = 0;
4587 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
4588 room += fr->fr_width - frame_minwidth(fr, NULL);
4589 fr = curfr; /* put fr at window that grows */
4590 }
4591
4592 if (room < offset) /* Not enough room */
4593 offset = room; /* Move as far as we can */
4594 if (offset <= 0) /* No room at all, quit. */
4595 return;
4596
4597 /* grow frame fr by offset lines */
4598 frame_new_width(fr, fr->fr_width + offset, left);
4599
4600 /* shrink other frames: current and at the left or at the right */
4601 if (left)
4602 fr = curfr; /* current frame gets smaller */
4603 else
4604 fr = curfr->fr_next; /* next frame gets smaller */
4605
4606 while (fr != NULL && offset > 0)
4607 {
4608 n = frame_minwidth(fr, NULL);
4609 if (fr->fr_width - offset <= n)
4610 {
4611 offset -= fr->fr_width - n;
4612 frame_new_width(fr, n, !left);
4613 }
4614 else
4615 {
4616 frame_new_width(fr, fr->fr_width - offset, !left);
4617 break;
4618 }
4619 if (left)
4620 fr = fr->fr_prev;
4621 else
4622 fr = fr->fr_next;
4623 }
4624 (void)win_comp_pos();
4625 redraw_all_later(NOT_VALID);
4626}
4627#endif /* FEAT_VERTSPLIT */
4628#endif /* FEAT_MOUSE */
4629
4630#endif /* FEAT_WINDOWS */
4631
4632/*
4633 * Set the height of a window.
4634 * This takes care of the things inside the window, not what happens to the
4635 * window position, the frame or to other windows.
4636 */
4637 static void
4638win_new_height(wp, height)
4639 win_T *wp;
4640 int height;
4641{
4642 linenr_T lnum;
Bram Moolenaar34114692005-01-02 11:28:13 +00004643 linenr_T bot;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 int sline, line_size;
Bram Moolenaar34114692005-01-02 11:28:13 +00004645 int space;
4646 int did_below = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647#define FRACTION_MULT 16384L
4648
4649 /* Don't want a negative height. Happens when splitting a tiny window.
4650 * Will equalize heights soon to fix it. */
4651 if (height < 0)
4652 height = 0;
4653
4654 if (wp->w_wrow != wp->w_prev_fraction_row && wp->w_height > 0)
4655 wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
4656 + FRACTION_MULT / 2) / (long)wp->w_height;
4657
4658 wp->w_height = height;
4659 wp->w_skipcol = 0;
4660
4661 /* Don't change w_topline when height is zero. Don't set w_topline when
4662 * 'scrollbind' is set and this isn't the current window. */
4663 if (height > 0
4664#ifdef FEAT_SCROLLBIND
4665 && (!wp->w_p_scb || wp == curwin)
4666#endif
4667 )
4668 {
Bram Moolenaar34114692005-01-02 11:28:13 +00004669 /*
4670 * Find a value for w_topline that shows the cursor at the same
4671 * relative position in the window as before (more or less).
4672 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673 lnum = wp->w_cursor.lnum;
4674 if (lnum < 1) /* can happen when starting up */
4675 lnum = 1;
4676 wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
4677 line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
4678 sline = wp->w_wrow - line_size;
4679 if (sline < 0)
4680 {
4681 /*
4682 * Cursor line would go off top of screen if w_wrow was this high.
4683 */
4684 wp->w_wrow = line_size;
4685 }
4686 else
4687 {
Bram Moolenaar34114692005-01-02 11:28:13 +00004688 space = height;
4689 while (lnum > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 {
Bram Moolenaar34114692005-01-02 11:28:13 +00004691 space -= line_size;
4692 if (space > 0 && sline <= 0 && !did_below)
4693 {
4694 /* Try to use "~" lines below the text to avoid that text
4695 * is above the window while there are empty lines.
4696 * Subtract the rows below the cursor from "space" and
4697 * give the rest to "sline". */
4698 did_below = TRUE;
4699 bot = wp->w_cursor.lnum;
4700 while (space > 0)
4701 {
4702 if (wp->w_buffer->b_ml.ml_line_count - bot >= space)
4703 space = 0;
4704 else
4705 {
4706#ifdef FEAT_FOLDING
4707 hasFoldingWin(wp, bot, NULL, &bot, TRUE, NULL);
4708#endif
4709 if (bot >= wp->w_buffer->b_ml.ml_line_count)
4710 break;
4711 ++bot;
4712 space -= plines_win(wp, bot, TRUE);
4713 }
4714 }
4715 if (bot == wp->w_buffer->b_ml.ml_line_count && space > 0)
4716 sline += space;
4717 }
4718 if (sline <= 0)
4719 break;
4720
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721#ifdef FEAT_FOLDING
4722 hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
4723 if (lnum == 1)
4724 {
4725 /* first line in buffer is folded */
4726 line_size = 1;
4727 --sline;
4728 break;
4729 }
4730#endif
4731 --lnum;
4732#ifdef FEAT_DIFF
4733 if (lnum == wp->w_topline)
4734 line_size = plines_win_nofill(wp, lnum, TRUE)
4735 + wp->w_topfill;
4736 else
4737#endif
4738 line_size = plines_win(wp, lnum, TRUE);
4739 sline -= line_size;
4740 }
Bram Moolenaar34114692005-01-02 11:28:13 +00004741
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 if (sline < 0)
4743 {
4744 /*
4745 * Line we want at top would go off top of screen. Use next
4746 * line instead.
4747 */
4748#ifdef FEAT_FOLDING
4749 hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
4750#endif
4751 lnum++;
4752 wp->w_wrow -= line_size + sline;
4753 }
4754 else if (sline > 0)
4755 {
4756 /* First line of file reached, use that as topline. */
4757 lnum = 1;
4758 wp->w_wrow -= sline;
4759 }
4760 }
4761 set_topline(wp, lnum);
4762 }
4763
4764 if (wp == curwin)
4765 {
4766 if (p_so)
4767 update_topline();
4768 curs_columns(FALSE); /* validate w_wrow */
4769 }
4770 wp->w_prev_fraction_row = wp->w_wrow;
4771
4772 win_comp_scroll(wp);
4773 redraw_win_later(wp, NOT_VALID);
4774#ifdef FEAT_WINDOWS
4775 wp->w_redr_status = TRUE;
4776#endif
4777 invalidate_botline_win(wp);
4778}
4779
4780#ifdef FEAT_VERTSPLIT
4781/*
4782 * Set the width of a window.
4783 */
4784 static void
4785win_new_width(wp, width)
4786 win_T *wp;
4787 int width;
4788{
4789 wp->w_width = width;
4790 wp->w_lines_valid = 0;
4791 changed_line_abv_curs_win(wp);
4792 invalidate_botline_win(wp);
4793 if (wp == curwin)
4794 {
4795 update_topline();
4796 curs_columns(TRUE); /* validate w_wrow */
4797 }
4798 redraw_win_later(wp, NOT_VALID);
4799 wp->w_redr_status = TRUE;
4800}
4801#endif
4802
4803 void
4804win_comp_scroll(wp)
4805 win_T *wp;
4806{
4807 wp->w_p_scr = ((unsigned)wp->w_height >> 1);
4808 if (wp->w_p_scr == 0)
4809 wp->w_p_scr = 1;
4810}
4811
4812/*
4813 * command_height: called whenever p_ch has been changed
4814 */
4815 void
4816command_height(old_p_ch)
4817 long old_p_ch;
4818{
4819#ifdef FEAT_WINDOWS
4820 int h;
4821 frame_T *frp;
4822
Bram Moolenaar05159a02005-02-26 23:04:13 +00004823 /* When passed a negative value use the value of p_ch that we remembered.
4824 * This is needed for when the GUI starts up, we can't be sure in what
4825 * order things happen. */
4826 if (old_p_ch < 0)
4827 old_p_ch = p_ch_used;
4828 p_ch_used = p_ch;
4829
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830 /* Find bottom frame with width of screen. */
4831 frp = lastwin->w_frame;
4832# ifdef FEAT_VERTSPLIT
4833 while (frp->fr_width != Columns && frp->fr_parent != NULL)
4834 frp = frp->fr_parent;
4835# endif
4836
4837 /* Avoid changing the height of a window with 'winfixheight' set. */
4838 while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
4839 && frp->fr_win->w_p_wfh)
4840 frp = frp->fr_prev;
4841
4842 if (starting != NO_SCREEN)
4843 {
4844 cmdline_row = Rows - p_ch;
4845
4846 if (p_ch > old_p_ch) /* p_ch got bigger */
4847 {
4848 while (p_ch > old_p_ch)
4849 {
4850 if (frp == NULL)
4851 {
4852 EMSG(_(e_noroom));
4853 p_ch = old_p_ch;
4854 cmdline_row = Rows - p_ch;
4855 break;
4856 }
4857 h = frp->fr_height - frame_minheight(frp, NULL);
4858 if (h > p_ch - old_p_ch)
4859 h = p_ch - old_p_ch;
4860 old_p_ch += h;
4861 frame_add_height(frp, -h);
4862 frp = frp->fr_prev;
4863 }
4864
4865 /* Recompute window positions. */
4866 (void)win_comp_pos();
4867
4868 /* clear the lines added to cmdline */
4869 if (full_screen)
4870 screen_fill((int)(cmdline_row), (int)Rows, 0,
4871 (int)Columns, ' ', ' ', 0);
4872 msg_row = cmdline_row;
4873 redraw_cmdline = TRUE;
4874 return;
4875 }
4876
4877 if (msg_row < cmdline_row)
4878 msg_row = cmdline_row;
4879 redraw_cmdline = TRUE;
4880 }
4881 frame_add_height(frp, (int)(old_p_ch - p_ch));
4882
4883 /* Recompute window positions. */
4884 if (frp != lastwin->w_frame)
4885 (void)win_comp_pos();
4886#else
4887 win_setheight((int)(firstwin->w_height + old_p_ch - p_ch));
4888 cmdline_row = Rows - p_ch;
4889#endif
4890}
4891
4892#if defined(FEAT_WINDOWS) || defined(PROTO)
4893/*
4894 * Resize frame "frp" to be "n" lines higher (negative for less high).
4895 * Also resize the frames it is contained in.
4896 */
4897 static void
4898frame_add_height(frp, n)
4899 frame_T *frp;
4900 int n;
4901{
4902 frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
4903 for (;;)
4904 {
4905 frp = frp->fr_parent;
4906 if (frp == NULL)
4907 break;
4908 frp->fr_height += n;
4909 }
4910}
4911
4912/*
4913 * Add or remove a status line for the bottom window(s), according to the
4914 * value of 'laststatus'.
4915 */
4916 void
4917last_status(morewin)
4918 int morewin; /* pretend there are two or more windows */
4919{
4920 /* Don't make a difference between horizontal or vertical split. */
4921 last_status_rec(topframe, (p_ls == 2
4922 || (p_ls == 1 && (morewin || lastwin != firstwin))));
4923}
4924
4925 static void
4926last_status_rec(fr, statusline)
4927 frame_T *fr;
4928 int statusline;
4929{
4930 frame_T *fp;
4931 win_T *wp;
4932
4933 if (fr->fr_layout == FR_LEAF)
4934 {
4935 wp = fr->fr_win;
4936 if (wp->w_status_height != 0 && !statusline)
4937 {
4938 /* remove status line */
4939 win_new_height(wp, wp->w_height + 1);
4940 wp->w_status_height = 0;
4941 comp_col();
4942 }
4943 else if (wp->w_status_height == 0 && statusline)
4944 {
4945 /* Find a frame to take a line from. */
4946 fp = fr;
4947 while (fp->fr_height <= frame_minheight(fp, NULL))
4948 {
4949 if (fp == topframe)
4950 {
4951 EMSG(_(e_noroom));
4952 return;
4953 }
4954 /* In a column of frames: go to frame above. If already at
4955 * the top or in a row of frames: go to parent. */
4956 if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
4957 fp = fp->fr_prev;
4958 else
4959 fp = fp->fr_parent;
4960 }
4961 wp->w_status_height = 1;
4962 if (fp != fr)
4963 {
4964 frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
4965 frame_fix_height(wp);
4966 (void)win_comp_pos();
4967 }
4968 else
4969 win_new_height(wp, wp->w_height - 1);
4970 comp_col();
4971 redraw_all_later(NOT_VALID);
4972 }
4973 }
4974#ifdef FEAT_VERTSPLIT
4975 else if (fr->fr_layout == FR_ROW)
4976 {
4977 /* vertically split windows, set status line for each one */
4978 for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
4979 last_status_rec(fp, statusline);
4980 }
4981#endif
4982 else
4983 {
4984 /* horizontally split window, set status line for last one */
4985 for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
4986 ;
4987 last_status_rec(fp, statusline);
4988 }
4989}
4990
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004991/*
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00004992 * Return the number of lines used by the tab page line.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004993 */
4994 int
4995tabpageline_height()
4996{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00004997 switch (p_tal)
4998 {
4999 case 0: return 0;
5000 case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
5001 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005002 return 1;
5003}
5004
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005#endif /* FEAT_WINDOWS */
5006
5007#if defined(FEAT_SEARCHPATH) || defined(PROTO)
5008/*
Bram Moolenaard857f0e2005-06-21 22:37:39 +00005009 * Get the file name at the cursor.
5010 * If Visual mode is active, use the selected text if it's in one line.
5011 * Returns the name in allocated memory, NULL for failure.
5012 */
5013 char_u *
5014grab_file_name(count)
5015 long count;
5016{
5017# ifdef FEAT_VISUAL
5018 if (VIsual_active)
5019 {
5020 int len;
5021 char_u *ptr;
5022
5023 if (get_visual_text(NULL, &ptr, &len) == FAIL)
5024 return NULL;
5025 return find_file_name_in_path(ptr, len,
5026 FNAME_MESS|FNAME_EXP|FNAME_REL, count, curbuf->b_ffname);
5027 }
5028# endif
5029 return file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP|FNAME_REL, count);
5030}
5031
5032/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033 * Return the file name under or after the cursor.
5034 *
5035 * The 'path' option is searched if the file name is not absolute.
5036 * The string returned has been alloc'ed and should be freed by the caller.
5037 * NULL is returned if the file name or file is not found.
5038 *
5039 * options:
5040 * FNAME_MESS give error messages
5041 * FNAME_EXP expand to path
5042 * FNAME_HYP check for hypertext link
5043 * FNAME_INCL apply "includeexpr"
5044 */
5045 char_u *
5046file_name_at_cursor(options, count)
5047 int options;
5048 long count;
5049{
5050 return file_name_in_line(ml_get_curline(),
5051 curwin->w_cursor.col, options, count, curbuf->b_ffname);
5052}
5053
5054/*
5055 * Return the name of the file under or after ptr[col].
5056 * Otherwise like file_name_at_cursor().
5057 */
5058 char_u *
5059file_name_in_line(line, col, options, count, rel_fname)
5060 char_u *line;
5061 int col;
5062 int options;
5063 long count;
5064 char_u *rel_fname; /* file we are searching relative to */
5065{
5066 char_u *ptr;
5067 int len;
5068
5069 /*
5070 * search forward for what could be the start of a file name
5071 */
5072 ptr = line + col;
5073 while (*ptr != NUL && !vim_isfilec(*ptr))
Bram Moolenaar0dd492f2005-06-22 22:25:07 +00005074 mb_ptr_adv(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075 if (*ptr == NUL) /* nothing found */
5076 {
5077 if (options & FNAME_MESS)
5078 EMSG(_("E446: No file name under cursor"));
5079 return NULL;
5080 }
5081
5082 /*
5083 * Search backward for first char of the file name.
5084 * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
5085 */
5086 while (ptr > line)
5087 {
5088#ifdef FEAT_MBYTE
5089 if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
5090 ptr -= len + 1;
5091 else
5092#endif
5093 if (vim_isfilec(ptr[-1])
5094 || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
5095 --ptr;
5096 else
5097 break;
5098 }
5099
5100 /*
5101 * Search forward for the last char of the file name.
5102 * Also allow "://" when ':' is not in 'isfname'.
5103 */
5104 len = 0;
5105 while (vim_isfilec(ptr[len])
5106 || ((options & FNAME_HYP) && path_is_url(ptr + len)))
5107#ifdef FEAT_MBYTE
5108 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005109 len += (*mb_ptr2len)(ptr + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110 else
5111#endif
5112 ++len;
5113
5114 /*
5115 * If there is trailing punctuation, remove it.
5116 * But don't remove "..", could be a directory name.
5117 */
5118 if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
5119 && ptr[len - 2] != '.')
5120 --len;
5121
5122 return find_file_name_in_path(ptr, len, options, count, rel_fname);
5123}
5124
5125# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
5126static char_u *eval_includeexpr __ARGS((char_u *ptr, int len));
5127
5128 static char_u *
5129eval_includeexpr(ptr, len)
5130 char_u *ptr;
5131 int len;
5132{
5133 char_u *res;
5134
5135 set_vim_var_string(VV_FNAME, ptr, len);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00005136 res = eval_to_string_safe(curbuf->b_p_inex, NULL,
5137 was_set_insecurely((char_u *)"includeexpr"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138 set_vim_var_string(VV_FNAME, NULL, 0);
5139 return res;
5140}
5141#endif
5142
5143/*
5144 * Return the name of the file ptr[len] in 'path'.
5145 * Otherwise like file_name_at_cursor().
5146 */
5147 char_u *
5148find_file_name_in_path(ptr, len, options, count, rel_fname)
5149 char_u *ptr;
5150 int len;
5151 int options;
5152 long count;
5153 char_u *rel_fname; /* file we are searching relative to */
5154{
5155 char_u *file_name;
5156 int c;
5157# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
5158 char_u *tofree = NULL;
5159
5160 if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
5161 {
5162 tofree = eval_includeexpr(ptr, len);
5163 if (tofree != NULL)
5164 {
5165 ptr = tofree;
5166 len = (int)STRLEN(ptr);
5167 }
5168 }
5169# endif
5170
5171 if (options & FNAME_EXP)
5172 {
5173 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
5174 TRUE, rel_fname);
5175
5176# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
5177 /*
5178 * If the file could not be found in a normal way, try applying
5179 * 'includeexpr' (unless done already).
5180 */
5181 if (file_name == NULL
5182 && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
5183 {
5184 tofree = eval_includeexpr(ptr, len);
5185 if (tofree != NULL)
5186 {
5187 ptr = tofree;
5188 len = (int)STRLEN(ptr);
5189 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
5190 TRUE, rel_fname);
5191 }
5192 }
5193# endif
5194 if (file_name == NULL && (options & FNAME_MESS))
5195 {
5196 c = ptr[len];
5197 ptr[len] = NUL;
5198 EMSG2(_("E447: Can't find file \"%s\" in path"), ptr);
5199 ptr[len] = c;
5200 }
5201
5202 /* Repeat finding the file "count" times. This matters when it
5203 * appears several times in the path. */
5204 while (file_name != NULL && --count > 0)
5205 {
5206 vim_free(file_name);
5207 file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
5208 }
5209 }
5210 else
5211 file_name = vim_strnsave(ptr, len);
5212
5213# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
5214 vim_free(tofree);
5215# endif
5216
5217 return file_name;
5218}
5219#endif /* FEAT_SEARCHPATH */
5220
5221/*
5222 * Check if the "://" of a URL is at the pointer, return URL_SLASH.
5223 * Also check for ":\\", which MS Internet Explorer accepts, return
5224 * URL_BACKSLASH.
5225 */
5226 static int
5227path_is_url(p)
5228 char_u *p;
5229{
5230 if (STRNCMP(p, "://", (size_t)3) == 0)
5231 return URL_SLASH;
5232 else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
5233 return URL_BACKSLASH;
5234 return 0;
5235}
5236
5237/*
5238 * Check if "fname" starts with "name://". Return URL_SLASH if it does.
5239 * Return URL_BACKSLASH for "name:\\".
5240 * Return zero otherwise.
5241 */
5242 int
5243path_with_url(fname)
5244 char_u *fname;
5245{
5246 char_u *p;
5247
5248 for (p = fname; isalpha(*p); ++p)
5249 ;
5250 return path_is_url(p);
5251}
5252
5253/*
5254 * Return TRUE if "name" is a full (absolute) path name or URL.
5255 */
5256 int
5257vim_isAbsName(name)
5258 char_u *name;
5259{
5260 return (path_with_url(name) != 0 || mch_isFullName(name));
5261}
5262
5263/*
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005264 * Get absolute file name into buffer "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005265 *
5266 * return FAIL for failure, OK otherwise
5267 */
5268 int
5269vim_FullName(fname, buf, len, force)
5270 char_u *fname, *buf;
5271 int len;
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005272 int force; /* force expansion even when already absolute */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273{
5274 int retval = OK;
5275 int url;
5276
5277 *buf = NUL;
5278 if (fname == NULL)
5279 return FAIL;
5280
5281 url = path_with_url(fname);
5282 if (!url)
5283 retval = mch_FullName(fname, buf, len, force);
5284 if (url || retval == FAIL)
5285 {
5286 /* something failed; use the file name (truncate when too long) */
Bram Moolenaarb6356332005-07-18 21:40:44 +00005287 vim_strncpy(buf, fname, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 }
5289#if defined(MACOS_CLASSIC) || defined(OS2) || defined(MSDOS) || defined(MSWIN)
5290 slash_adjust(buf);
5291#endif
5292 return retval;
5293}
5294
5295/*
5296 * Return the minimal number of rows that is needed on the screen to display
5297 * the current number of windows.
5298 */
5299 int
5300min_rows()
5301{
5302 int total;
Bram Moolenaarf740b292006-02-16 22:11:02 +00005303#ifdef FEAT_WINDOWS
5304 tabpage_T *tp;
5305 int n;
5306#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307
5308 if (firstwin == NULL) /* not initialized yet */
5309 return MIN_LINES;
5310
Bram Moolenaar071d4272004-06-13 20:20:40 +00005311#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00005312 total = 0;
5313 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
5314 {
5315 n = frame_minheight(tp->tp_topframe, NULL);
5316 if (total < n)
5317 total = n;
5318 }
5319 total += tabpageline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320#else
Bram Moolenaarf740b292006-02-16 22:11:02 +00005321 total = 1; /* at least one window should have a line! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005322#endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00005323 total += 1; /* count the room for the command line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005324 return total;
5325}
5326
5327/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00005328 * Return TRUE if there is only one window (in the current tab page), not
5329 * counting a help or preview window, unless it is the current window.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330 */
5331 int
5332only_one_window()
5333{
5334#ifdef FEAT_WINDOWS
5335 int count = 0;
5336 win_T *wp;
5337
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005338 /* If there is another tab page there always is another window. */
5339 if (first_tabpage->tp_next != NULL)
5340 return FALSE;
5341
Bram Moolenaar071d4272004-06-13 20:20:40 +00005342 for (wp = firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar92922402005-01-31 18:57:18 +00005343 if (!((wp->w_buffer->b_help && !curbuf->b_help)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344# ifdef FEAT_QUICKFIX
5345 || wp->w_p_pvw
5346# endif
5347 ) || wp == curwin)
5348 ++count;
5349 return (count <= 1);
5350#else
5351 return TRUE;
5352#endif
5353}
5354
5355#if defined(FEAT_WINDOWS) || defined(FEAT_AUTOCMD) || defined(PROTO)
5356/*
5357 * Correct the cursor line number in other windows. Used after changing the
5358 * current buffer, and before applying autocommands.
5359 * When "do_curwin" is TRUE, also check current window.
5360 */
5361 void
5362check_lnums(do_curwin)
5363 int do_curwin;
5364{
5365 win_T *wp;
5366
5367#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00005368 tabpage_T *tp;
5369
5370 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
5372#else
5373 wp = curwin;
5374 if (do_curwin)
5375#endif
5376 {
5377 if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
5378 wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5379 if (wp->w_topline > curbuf->b_ml.ml_line_count)
5380 wp->w_topline = curbuf->b_ml.ml_line_count;
5381 }
5382}
5383#endif
5384
5385#if defined(FEAT_WINDOWS) || defined(PROTO)
5386
5387/*
5388 * A snapshot of the window sizes, to restore them after closing the help
5389 * window.
5390 * Only these fields are used:
5391 * fr_layout
5392 * fr_width
5393 * fr_height
5394 * fr_next
5395 * fr_child
5396 * fr_win (only valid for the old curwin, NULL otherwise)
5397 */
5398static frame_T *snapshot = NULL;
5399
5400/*
5401 * Create a snapshot of the current frame sizes.
5402 */
5403 static void
5404make_snapshot()
5405{
5406 clear_snapshot();
5407 make_snapshot_rec(topframe, &snapshot);
5408}
5409
5410 static void
5411make_snapshot_rec(fr, frp)
5412 frame_T *fr;
5413 frame_T **frp;
5414{
5415 *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
5416 if (*frp == NULL)
5417 return;
5418 (*frp)->fr_layout = fr->fr_layout;
5419# ifdef FEAT_VERTSPLIT
5420 (*frp)->fr_width = fr->fr_width;
5421# endif
5422 (*frp)->fr_height = fr->fr_height;
5423 if (fr->fr_next != NULL)
5424 make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
5425 if (fr->fr_child != NULL)
5426 make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
5427 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
5428 (*frp)->fr_win = curwin;
5429}
5430
5431/*
5432 * Remove any existing snapshot.
5433 */
5434 static void
5435clear_snapshot()
5436{
5437 clear_snapshot_rec(snapshot);
5438 snapshot = NULL;
5439}
5440
5441 static void
5442clear_snapshot_rec(fr)
5443 frame_T *fr;
5444{
5445 if (fr != NULL)
5446 {
5447 clear_snapshot_rec(fr->fr_next);
5448 clear_snapshot_rec(fr->fr_child);
5449 vim_free(fr);
5450 }
5451}
5452
5453/*
5454 * Restore a previously created snapshot, if there is any.
5455 * This is only done if the screen size didn't change and the window layout is
5456 * still the same.
5457 */
5458 static void
5459restore_snapshot(close_curwin)
5460 int close_curwin; /* closing current window */
5461{
5462 win_T *wp;
5463
5464 if (snapshot != NULL
5465# ifdef FEAT_VERTSPLIT
5466 && snapshot->fr_width == topframe->fr_width
5467# endif
5468 && snapshot->fr_height == topframe->fr_height
5469 && check_snapshot_rec(snapshot, topframe) == OK)
5470 {
5471 wp = restore_snapshot_rec(snapshot, topframe);
5472 win_comp_pos();
5473 if (wp != NULL && close_curwin)
5474 win_goto(wp);
5475 redraw_all_later(CLEAR);
5476 }
5477 clear_snapshot();
5478}
5479
5480/*
5481 * Check if frames "sn" and "fr" have the same layout, same following frames
5482 * and same children.
5483 */
5484 static int
5485check_snapshot_rec(sn, fr)
5486 frame_T *sn;
5487 frame_T *fr;
5488{
5489 if (sn->fr_layout != fr->fr_layout
5490 || (sn->fr_next == NULL) != (fr->fr_next == NULL)
5491 || (sn->fr_child == NULL) != (fr->fr_child == NULL)
5492 || (sn->fr_next != NULL
5493 && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
5494 || (sn->fr_child != NULL
5495 && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL))
5496 return FAIL;
5497 return OK;
5498}
5499
5500/*
5501 * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all
5502 * following frames and children.
5503 * Returns a pointer to the old current window, or NULL.
5504 */
5505 static win_T *
5506restore_snapshot_rec(sn, fr)
5507 frame_T *sn;
5508 frame_T *fr;
5509{
5510 win_T *wp = NULL;
5511 win_T *wp2;
5512
5513 fr->fr_height = sn->fr_height;
5514# ifdef FEAT_VERTSPLIT
5515 fr->fr_width = sn->fr_width;
5516# endif
5517 if (fr->fr_layout == FR_LEAF)
5518 {
5519 frame_new_height(fr, fr->fr_height, FALSE, FALSE);
5520# ifdef FEAT_VERTSPLIT
5521 frame_new_width(fr, fr->fr_width, FALSE);
5522# endif
5523 wp = sn->fr_win;
5524 }
5525 if (sn->fr_next != NULL)
5526 {
5527 wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
5528 if (wp2 != NULL)
5529 wp = wp2;
5530 }
5531 if (sn->fr_child != NULL)
5532 {
5533 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
5534 if (wp2 != NULL)
5535 wp = wp2;
5536 }
5537 return wp;
5538}
5539
5540#endif
5541
5542#if (defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)) || defined(PROTO)
5543/*
5544 * Return TRUE if there is any vertically split window.
5545 */
5546 int
5547win_hasvertsplit()
5548{
5549 frame_T *fr;
5550
5551 if (topframe->fr_layout == FR_ROW)
5552 return TRUE;
5553
5554 if (topframe->fr_layout == FR_COL)
5555 for (fr = topframe->fr_child; fr != NULL; fr = fr->fr_next)
5556 if (fr->fr_layout == FR_ROW)
5557 return TRUE;
5558
5559 return FALSE;
5560}
5561#endif