home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / window.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-31  |  112.4 KB  |  4,931 lines

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