comparison src/window.c @ 34379:37b4c89ba420 v9.1.0116

patch 9.1.0116: win_split_ins may not check available room Commit: https://github.com/vim/vim/commit/0fd44a5ad81ade342cb54d8984965bdedd2272c8 Author: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue Feb 20 20:28:15 2024 +0100 patch 9.1.0116: win_split_ins may not check available room Problem: win_split_ins has no check for E36 when moving an existing window Solution: check for room and fix the issues in f_win_splitmove() (Sean Dewar) win_split_ins has no check for E36 when moving an existing window, allowing for layouts with many overlapping zero-sized windows to be created (which may also cause drawing issues with tablines and such). f_win_splitmove also has some bugs. So check for room and fix the issues in f_win_splitmove. Handle failure in the two relevant win_split_ins callers by restoring the original layout, and factor the common logic into win_splitmove. Don't check for room when opening an autocommand window, as it's a temporary window that's rarely interacted with or drawn anyhow, and is rather important for some autocommands. Issues fixed in f_win_splitmove: - Error if splitting is disallowed. - Fix heap-use-after-frees if autocommands fired from switching to "targetwin" close "wp" or "oldwin". - Fix splitting the wrong window if autocommands fired from switching to "targetwin" switch to a different window. - Ensure -1 is returned for all errors. Also handle allocation failure a bit earlier in make_snapshot (callers, except win_splitmove, don't really care if a snapshot can't be made, so just ignore the return value). Note: Test_smoothscroll_in_zero_width_window failed after these changes with E36, as it was using the previous behaviour to create a zero-width window. I've fixed the test such that it fails with UBSAN as expected when v9.0.1367 is reverted (and simplified it too). related: #14042 Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Tue, 20 Feb 2024 22:30:04 +0100
parents d7cfd8fb1d75
children 4e0da2b33607
comparison
equal deleted inserted replaced
34378:4d02bc6ddd97 34379:37b4c89ba420
15 static void frame_comp_pos(frame_T *topfrp, int *row, int *col); 15 static void frame_comp_pos(frame_T *topfrp, int *row, int *col);
16 static void frame_setheight(frame_T *curfrp, int height); 16 static void frame_setheight(frame_T *curfrp, int height);
17 static void frame_setwidth(frame_T *curfrp, int width); 17 static void frame_setwidth(frame_T *curfrp, int width);
18 static void win_exchange(long); 18 static void win_exchange(long);
19 static void win_rotate(int, int); 19 static void win_rotate(int, int);
20 static void win_totop(int size, int flags);
21 static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height); 20 static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
22 static void trigger_winnewpre(void); 21 static void trigger_winnewpre(void);
23 static void trigger_winclosed(win_T *win); 22 static void trigger_winclosed(win_T *win);
24 static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp); 23 static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
25 static frame_T *win_altframe(win_T *win, tabpage_T *tp); 24 static frame_T *win_altframe(win_T *win, tabpage_T *tp);
29 static void win_fix_scroll(int resize); 28 static void win_fix_scroll(int resize);
30 static void win_fix_cursor(int normal); 29 static void win_fix_cursor(int normal);
31 static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh); 30 static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
32 static int frame_fixed_height(frame_T *frp); 31 static int frame_fixed_height(frame_T *frp);
33 static int frame_fixed_width(frame_T *frp); 32 static int frame_fixed_width(frame_T *frp);
34 static void frame_add_statusline(frame_T *frp); 33 static void frame_add_statusline(frame_T *frp, int adjust_winheight);
35 static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw); 34 static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw);
36 static void frame_add_vsep(frame_T *frp); 35 static void frame_add_vsep(frame_T *frp);
37 static int frame_minwidth(frame_T *topfrp, win_T *next_curwin); 36 static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
38 static void frame_fix_width(win_T *wp); 37 static void frame_fix_width(win_T *wp);
39 static int win_alloc_firstwin(win_T *oldwin); 38 static int win_alloc_firstwin(win_T *oldwin);
53 static void win_goto_ver(int up, long count); 52 static void win_goto_ver(int up, long count);
54 static void win_goto_hor(int left, long count); 53 static void win_goto_hor(int left, long count);
55 static void frame_add_height(frame_T *frp, int n); 54 static void frame_add_height(frame_T *frp, int n);
56 static void last_status_rec(frame_T *fr, int statusline); 55 static void last_status_rec(frame_T *fr, int statusline);
57 56
58 static void make_snapshot_rec(frame_T *fr, frame_T **frp); 57 static int make_snapshot_rec(frame_T *fr, frame_T **frp, int snap_wins);
59 static void clear_snapshot(tabpage_T *tp, int idx); 58 static void clear_snapshot(tabpage_T *tp, int idx);
60 static void clear_snapshot_rec(frame_T *fr); 59 static void clear_snapshot_rec(frame_T *fr);
61 static int check_snapshot_rec(frame_T *sn, frame_T *fr); 60 static int check_snapshot_rec(frame_T *sn, frame_T *fr);
62 static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr); 61 static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr);
63 static win_T *get_snapshot_curwin(int idx); 62 static win_T *get_snapshot_curwin(int idx);
63 static frame_T *make_full_snapshot(void);
64 static void restore_full_snapshot(frame_T *sn);
65 static void restore_full_snapshot_rec(frame_T *sn);
64 66
65 static int frame_check_height(frame_T *topfrp, int height); 67 static int frame_check_height(frame_T *topfrp, int height);
66 static int frame_check_width(frame_T *topfrp, int width); 68 static int frame_check_width(frame_T *topfrp, int width);
67 69
68 static win_T *win_alloc(win_T *after, int hidden); 70 static win_T *win_alloc(win_T *after, int hidden);
492 case 'K': 494 case 'K':
493 case 'J': 495 case 'J':
494 case 'H': 496 case 'H':
495 case 'L': 497 case 'L':
496 CHECK_CMDWIN; 498 CHECK_CMDWIN;
497 win_totop((int)Prenum, 499 if (ONE_WINDOW)
498 ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) 500 beep_flush();
499 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT)); 501 else
502 {
503 int dir = ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
504 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT);
505
506 (void)win_splitmove(curwin, (int)Prenum, dir);
507 }
500 break; 508 break;
501 509
502 // make all windows the same width and/or height 510 // make all windows the same width and/or height
503 case '=': 511 case '=':
504 { 512 {
856 else 864 else
857 STRCPY(bufp, cmd); 865 STRCPY(bufp, cmd);
858 } 866 }
859 867
860 /* 868 /*
861 * If "split_disallowed" is set give an error and return FAIL. 869 * If "split_disallowed" is set for "wp", give an error and return FAIL.
862 * Otherwise return OK. 870 * Otherwise return OK.
863 */ 871 */
864 static int 872 int
865 check_split_disallowed(void) 873 check_split_disallowed(win_T *wp)
866 { 874 {
867 if (split_disallowed > 0) 875 if (split_disallowed > 0)
868 { 876 {
869 emsg(_(e_cant_split_window_while_closing_another)); 877 emsg(_(e_cant_split_window_while_closing_another));
870 return FAIL; 878 return FAIL;
871 } 879 }
872 if (curwin->w_buffer->b_locked_split) 880 if (wp->w_buffer->b_locked_split)
873 { 881 {
874 emsg(_(e_cannot_split_window_when_closing_buffer)); 882 emsg(_(e_cannot_split_window_when_closing_buffer));
875 return FAIL; 883 return FAIL;
876 } 884 }
877 return OK; 885 return OK;
896 win_split(int size, int flags) 904 win_split(int size, int flags)
897 { 905 {
898 if (ERROR_IF_ANY_POPUP_WINDOW) 906 if (ERROR_IF_ANY_POPUP_WINDOW)
899 return FAIL; 907 return FAIL;
900 908
901 if (check_split_disallowed() == FAIL) 909 if (check_split_disallowed(curwin) == FAIL)
902 return FAIL; 910 return FAIL;
903 911
904 // When the ":tab" modifier was used open a new tab page instead. 912 // When the ":tab" modifier was used open a new tab page instead.
905 if (may_open_tabpage() == OK) 913 if (may_open_tabpage() == OK)
906 return OK; 914 return OK;
966 oldwin = curwin; 974 oldwin = curwin;
967 975
968 // add a status line when p_ls == 1 and splitting the first window 976 // add a status line when p_ls == 1 and splitting the first window
969 if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0) 977 if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0)
970 { 978 {
971 if (VISIBLE_HEIGHT(oldwin) <= p_wmh && new_wp == NULL) 979 if (!(flags & WSP_FORCE_ROOM) && VISIBLE_HEIGHT(oldwin) <= p_wmh)
972 { 980 {
973 emsg(_(e_not_enough_room)); 981 emsg(_(e_not_enough_room));
974 goto theend; 982 goto theend;
975 } 983 }
976 need_status = STATUS_HEIGHT; 984 need_status = STATUS_HEIGHT;
1024 { 1032 {
1025 minwidth = frame_minwidth(oldwin->w_frame, NOWIN); 1033 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
1026 available = oldwin->w_frame->fr_width; 1034 available = oldwin->w_frame->fr_width;
1027 needed += minwidth; 1035 needed += minwidth;
1028 } 1036 }
1029 if (available < needed && new_wp == NULL) 1037 if (!(flags & WSP_FORCE_ROOM) && available < needed)
1030 { 1038 {
1031 emsg(_(e_not_enough_room)); 1039 emsg(_(e_not_enough_room));
1032 goto theend; 1040 goto theend;
1033 } 1041 }
1034 if (new_size == 0) 1042 if (new_size == 0)
1107 { 1115 {
1108 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status; 1116 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
1109 available = oldwin->w_frame->fr_height; 1117 available = oldwin->w_frame->fr_height;
1110 needed += minheight; 1118 needed += minheight;
1111 } 1119 }
1112 if (available < needed && new_wp == NULL) 1120 if (!(flags & WSP_FORCE_ROOM) && available < needed)
1113 { 1121 {
1114 emsg(_(e_not_enough_room)); 1122 emsg(_(e_not_enough_room));
1115 goto theend; 1123 goto theend;
1116 } 1124 }
1117 oldwin_height = oldwin->w_height; 1125 oldwin_height = oldwin->w_height;
1358 + WINBAR_HEIGHT(wp) ; 1366 + WINBAR_HEIGHT(wp) ;
1359 1367
1360 if (!((flags & WSP_BOT) && p_ls == 0)) 1368 if (!((flags & WSP_BOT) && p_ls == 0))
1361 new_fr_height -= STATUS_HEIGHT; 1369 new_fr_height -= STATUS_HEIGHT;
1362 if (flags & WSP_BOT) 1370 if (flags & WSP_BOT)
1363 frame_add_statusline(curfrp); 1371 frame_add_statusline(curfrp, FALSE);
1364 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE); 1372 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
1365 } 1373 }
1366 else 1374 else
1367 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT)); 1375 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1368 if (before) // new window above current one 1376 if (before) // new window above current one
1898 1906
1899 redraw_all_later(UPD_NOT_VALID); 1907 redraw_all_later(UPD_NOT_VALID);
1900 } 1908 }
1901 1909
1902 /* 1910 /*
1903 * Move the current window to the very top/bottom/left/right of the screen. 1911 * Move "wp" into a new split in a given direction, possibly relative to the
1904 */ 1912 * current window.
1905 static void 1913 * "wp" must be valid in the current tabpage.
1906 win_totop(int size, int flags) 1914 * Returns FAIL for failure, OK otherwise.
1915 */
1916 int
1917 win_splitmove(win_T *wp, int size, int flags)
1907 { 1918 {
1908 int dir; 1919 int dir;
1909 int height = curwin->w_height; 1920 int height = wp->w_height;
1921 frame_T *frp;
1910 1922
1911 if (ONE_WINDOW) 1923 if (ONE_WINDOW)
1912 { 1924 return OK; // nothing to do
1913 beep_flush(); 1925 if (check_split_disallowed(wp) == FAIL)
1914 return; 1926 return FAIL;
1915 } 1927
1916 if (check_split_disallowed() == FAIL) 1928 // Undoing changes to frames if splitting fails is complicated.
1917 return; 1929 // Save a full snapshot to restore instead.
1930 frp = make_full_snapshot();
1931 if (frp == NULL)
1932 {
1933 emsg(_(e_out_of_memory));
1934 return FAIL;
1935 }
1918 1936
1919 // Remove the window and frame from the tree of frames. 1937 // Remove the window and frame from the tree of frames.
1920 (void)winframe_remove(curwin, &dir, NULL); 1938 (void)winframe_remove(wp, &dir, NULL);
1921 win_remove(curwin, NULL); 1939 win_remove(wp, NULL);
1922 last_status(FALSE); // may need to remove last status line 1940 last_status(FALSE); // may need to remove last status line
1923 (void)win_comp_pos(); // recompute window positions 1941 (void)win_comp_pos(); // recompute window positions
1924 1942
1925 // Split a window on the desired side and put the window there. 1943 // Split a window on the desired side and put "wp" there.
1926 (void)win_split_ins(size, flags, curwin, dir); 1944 if (win_split_ins(size, flags, wp, dir) == FAIL)
1927 if (!(flags & WSP_VERT)) 1945 {
1928 { 1946 // Restore the previous layout from the snapshot.
1929 win_setheight(height); 1947 vim_free(wp->w_frame);
1948 restore_full_snapshot(frp);
1949
1950 // Vertical separators to the left may have been lost. Restore them.
1951 frp = wp->w_frame;
1952 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL)
1953 frame_add_vsep(frp->fr_prev);
1954
1955 // Statuslines above may have been lost. Restore them.
1956 if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL)
1957 frame_add_statusline(frp->fr_prev, TRUE);
1958
1959 win_append(wp->w_prev, wp);
1960 return FAIL;
1961 }
1962 clear_snapshot_rec(frp);
1963
1964 // If splitting horizontally, try to preserve height.
1965 if (size == 0 && !(flags & WSP_VERT))
1966 {
1967 win_setheight_win(height, wp);
1930 if (p_ea) 1968 if (p_ea)
1931 win_equal(curwin, TRUE, 'v'); 1969 {
1970 // Equalize windows. Note that win_split_ins autocommands may have
1971 // made a window other than "wp" current.
1972 win_equal(curwin, curwin == wp, 'v');
1973 }
1932 } 1974 }
1933 1975
1934 #if defined(FEAT_GUI) 1976 #if defined(FEAT_GUI)
1935 // When 'guioptions' includes 'L' or 'R' may have to remove or add 1977 // When 'guioptions' includes 'L' or 'R' may have to remove or add
1936 // scrollbars. Have to update them anyway. 1978 // scrollbars. Have to update them anyway.
1937 gui_may_update_scrollbars(); 1979 gui_may_update_scrollbars();
1938 #endif 1980 #endif
1981 return OK;
1939 } 1982 }
1940 1983
1941 /* 1984 /*
1942 * Move window "win1" to below/right of "win2" and make "win1" the current 1985 * Move window "win1" to below/right of "win2" and make "win1" the current
1943 * window. Only works within the same frame! 1986 * window. Only works within the same frame!
3847 return TRUE; 3890 return TRUE;
3848 } 3891 }
3849 3892
3850 /* 3893 /*
3851 * Add a status line to windows at the bottom of "frp". 3894 * Add a status line to windows at the bottom of "frp".
3852 * Note: Does not check if there is room! 3895 * If "adjust_winheight" is set, reduce the height of windows without a
3896 * statusline to accommodate one; otherwise, there is no check for room!
3853 */ 3897 */
3854 static void 3898 static void
3855 frame_add_statusline(frame_T *frp) 3899 frame_add_statusline(frame_T *frp, int adjust_winheight)
3856 { 3900 {
3857 win_T *wp; 3901 win_T *wp;
3858 3902
3859 if (frp->fr_layout == FR_LEAF) 3903 if (frp->fr_layout == FR_LEAF)
3860 { 3904 {
3861 wp = frp->fr_win; 3905 wp = frp->fr_win;
3906 if (adjust_winheight && wp->w_status_height == 0
3907 && wp->w_height >= STATUS_HEIGHT) // don't make it negative
3908 wp->w_height -= STATUS_HEIGHT - wp->w_status_height;
3862 wp->w_status_height = STATUS_HEIGHT; 3909 wp->w_status_height = STATUS_HEIGHT;
3863 } 3910 }
3864 else if (frp->fr_layout == FR_ROW) 3911 else if (frp->fr_layout == FR_ROW)
3865 { 3912 {
3866 // Handle all the frames in the row. 3913 // Handle all the frames in the row.
3867 FOR_ALL_FRAMES(frp, frp->fr_child) 3914 FOR_ALL_FRAMES(frp, frp->fr_child)
3868 frame_add_statusline(frp); 3915 frame_add_statusline(frp, adjust_winheight);
3869 } 3916 }
3870 else // frp->fr_layout == FR_COL 3917 else // frp->fr_layout == FR_COL
3871 { 3918 {
3872 // Only need to handle the last frame in the column. 3919 // Only need to handle the last frame in the column.
3873 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) 3920 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
3874 ; 3921 ;
3875 frame_add_statusline(frp); 3922 frame_add_statusline(frp, adjust_winheight);
3876 } 3923 }
3877 } 3924 }
3878 3925
3879 /* 3926 /*
3880 * Set width of a frame. Handles recursively going through contained frames. 3927 * Set width of a frame. Handles recursively going through contained frames.
7496 */ 7543 */
7497 7544
7498 /* 7545 /*
7499 * Create a snapshot of the current frame sizes. 7546 * Create a snapshot of the current frame sizes.
7500 * "idx" is SNAP_HELP_IDX or SNAP_AUCMD_IDX. 7547 * "idx" is SNAP_HELP_IDX or SNAP_AUCMD_IDX.
7501 */ 7548 * Return FAIL if out of memory, OK otherwise.
7502 void 7549 */
7550 int
7503 make_snapshot(int idx) 7551 make_snapshot(int idx)
7504 { 7552 {
7505 clear_snapshot(curtab, idx); 7553 clear_snapshot(curtab, idx);
7506 make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]); 7554 if (make_snapshot_rec(topframe, &curtab->tp_snapshot[idx], FALSE) == FAIL)
7507 } 7555 {
7508 7556 clear_snapshot(curtab, idx);
7509 static void 7557 return FAIL;
7510 make_snapshot_rec(frame_T *fr, frame_T **frp) 7558 }
7559 return OK;
7560 }
7561
7562 static int
7563 make_snapshot_rec(frame_T *fr, frame_T **frp, int snap_wins)
7511 { 7564 {
7512 *frp = ALLOC_CLEAR_ONE(frame_T); 7565 *frp = ALLOC_CLEAR_ONE(frame_T);
7513 if (*frp == NULL) 7566 if (*frp == NULL)
7514 return; 7567 return FAIL;
7515 (*frp)->fr_layout = fr->fr_layout; 7568 (*frp)->fr_layout = fr->fr_layout;
7516 (*frp)->fr_width = fr->fr_width; 7569 (*frp)->fr_width = fr->fr_width;
7517 (*frp)->fr_height = fr->fr_height; 7570 (*frp)->fr_height = fr->fr_height;
7518 if (fr->fr_next != NULL) 7571 if (fr->fr_next != NULL)
7519 make_snapshot_rec(fr->fr_next, &((*frp)->fr_next)); 7572 {
7573 if (make_snapshot_rec(fr->fr_next, &((*frp)->fr_next), snap_wins)
7574 == FAIL)
7575 return FAIL;
7576 }
7520 if (fr->fr_child != NULL) 7577 if (fr->fr_child != NULL)
7521 make_snapshot_rec(fr->fr_child, &((*frp)->fr_child)); 7578 {
7522 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin) 7579 if (make_snapshot_rec(fr->fr_child, &((*frp)->fr_child), snap_wins)
7523 (*frp)->fr_win = curwin; 7580 == FAIL)
7581 return FAIL;
7582 }
7583 if (fr->fr_layout == FR_LEAF && (snap_wins || fr->fr_win == curwin))
7584 (*frp)->fr_win = fr->fr_win;
7585 return OK;
7524 } 7586 }
7525 7587
7526 /* 7588 /*
7527 * Remove any existing snapshot. 7589 * Remove any existing snapshot.
7528 */ 7590 */
7653 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child); 7715 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
7654 if (wp2 != NULL) 7716 if (wp2 != NULL)
7655 wp = wp2; 7717 wp = wp2;
7656 } 7718 }
7657 return wp; 7719 return wp;
7720 }
7721
7722 /*
7723 * Return a snapshot of all frames in the current tabpage and which windows are
7724 * in them, or NULL if out of memory.
7725 * Use clear_snapshot_rec to free the snapshot.
7726 */
7727 static frame_T *
7728 make_full_snapshot(void)
7729 {
7730 frame_T *frp;
7731
7732 if (make_snapshot_rec(topframe, &frp, TRUE) == FAIL)
7733 {
7734 clear_snapshot_rec(frp);
7735 return NULL;
7736 }
7737 return frp;
7738 }
7739
7740 /*
7741 * Restore all frames in the full snapshot "sn" for the current tabpage.
7742 * Caller must ensure that the screen size didn't change, no windows with frames
7743 * in the snapshot were freed, and windows with frames not in the snapshot are
7744 * removed from their frames!
7745 * Doesn't restore changed window vertical separators or statuslines.
7746 * Frees the old frames. Don't call clear_snapshot_rec on "sn" afterwards!
7747 */
7748 static void
7749 restore_full_snapshot(frame_T *sn)
7750 {
7751 if (sn == NULL)
7752 return;
7753
7754 clear_snapshot_rec(topframe);
7755 restore_full_snapshot_rec(sn);
7756 curtab->tp_topframe = topframe = sn;
7757 last_status(FALSE);
7758
7759 // If the amount of space available changed, first try setting the sizes of
7760 // windows with 'winfix{width,height}'. If that doesn't result in the right
7761 // size, forget about that option.
7762 if (topframe->fr_width != Columns)
7763 {
7764 frame_new_width(topframe, Columns, FALSE, TRUE);
7765 if (!frame_check_width(topframe, Columns))
7766 frame_new_width(topframe, Columns, FALSE, FALSE);
7767 }
7768 if (topframe->fr_height != ROWS_AVAIL)
7769 {
7770 frame_new_height(topframe, ROWS_AVAIL, FALSE, TRUE);
7771 if (!frame_check_height(topframe, ROWS_AVAIL))
7772 frame_new_height(topframe, ROWS_AVAIL, FALSE, FALSE);
7773 }
7774
7775 win_comp_pos();
7776 }
7777
7778 static void
7779 restore_full_snapshot_rec(frame_T *sn)
7780 {
7781 if (sn == NULL)
7782 return;
7783
7784 if (sn->fr_child != NULL)
7785 sn->fr_child->fr_parent = sn;
7786 if (sn->fr_next != NULL)
7787 {
7788 sn->fr_next->fr_parent = sn->fr_parent;
7789 sn->fr_next->fr_prev = sn;
7790 }
7791 if (sn->fr_win != NULL)
7792 {
7793 sn->fr_win->w_frame = sn;
7794 // Resize window to fit the frame.
7795 frame_new_height(sn, sn->fr_height, FALSE, FALSE);
7796 frame_new_width(sn, sn->fr_width, FALSE, FALSE);
7797 }
7798 restore_full_snapshot_rec(sn->fr_child);
7799 restore_full_snapshot_rec(sn->fr_next);
7658 } 7800 }
7659 7801
7660 #if defined(FEAT_GUI) || defined(PROTO) 7802 #if defined(FEAT_GUI) || defined(PROTO)
7661 /* 7803 /*
7662 * Return TRUE if there is any vertically split window. 7804 * Return TRUE if there is any vertically split window.