comparison src/window.c @ 34383:a84fe48ae523 v9.1.0118

patch 9.1.0118: Use different restoration strategy in win_splitmove Commit: https://github.com/vim/vim/commit/704966c2545897dfcf426dd9ef946aeb6fa80c38 Author: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue Feb 20 22:00:33 2024 +0100 patch 9.1.0118: Use different restoration strategy in win_splitmove Problem: saving and restoring all frames to split-move is overkill now that WinNewPre is not fired when split-moving. Solution: defer the flattening of frames until win_split_ins begins reorganising them, and attempt to restore the layout by undoing our changes. (Sean Dewar) This also means we no longer must allocate. 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:07 +0100
parents 4e0da2b33607
children 8b0e390b61fe
comparison
equal deleted inserted replaced
34382:17d926feeb82 34383:a84fe48ae523
28 static void win_fix_scroll(int resize); 28 static void win_fix_scroll(int resize);
29 static void win_fix_cursor(int normal); 29 static void win_fix_cursor(int normal);
30 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);
31 static int frame_fixed_height(frame_T *frp); 31 static int frame_fixed_height(frame_T *frp);
32 static int frame_fixed_width(frame_T *frp); 32 static int frame_fixed_width(frame_T *frp);
33 static void frame_add_statusline(frame_T *frp, int adjust_winheight); 33 static void frame_add_statusline(frame_T *frp);
34 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);
35 static void frame_add_vsep(frame_T *frp); 35 static void frame_add_vsep(frame_T *frp);
36 static int frame_minwidth(frame_T *topfrp, win_T *next_curwin); 36 static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
37 static void frame_fix_width(win_T *wp); 37 static void frame_fix_width(win_T *wp);
38 static int win_alloc_firstwin(win_T *oldwin); 38 static int win_alloc_firstwin(win_T *oldwin);
51 static void frame_remove(frame_T *frp); 51 static void frame_remove(frame_T *frp);
52 static void win_goto_ver(int up, long count); 52 static void win_goto_ver(int up, long count);
53 static void win_goto_hor(int left, long count); 53 static void win_goto_hor(int left, long count);
54 static void frame_add_height(frame_T *frp, int n); 54 static void frame_add_height(frame_T *frp, int n);
55 static void last_status_rec(frame_T *fr, int statusline); 55 static void last_status_rec(frame_T *fr, int statusline);
56 56 static void frame_flatten(frame_T *frp);
57 static int make_snapshot_rec(frame_T *fr, frame_T **frp, int snap_wins); 57 static void winframe_restore(win_T *wp, int dir, frame_T *to_flatten);
58
59 static int make_snapshot_rec(frame_T *fr, frame_T **frp);
58 static void clear_snapshot(tabpage_T *tp, int idx); 60 static void clear_snapshot(tabpage_T *tp, int idx);
59 static void clear_snapshot_rec(frame_T *fr); 61 static void clear_snapshot_rec(frame_T *fr);
60 static int check_snapshot_rec(frame_T *sn, frame_T *fr); 62 static int check_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 *restore_snapshot_rec(frame_T *sn, frame_T *fr);
62 static win_T *get_snapshot_curwin(int idx); 64 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);
66 65
67 static int frame_check_height(frame_T *topfrp, int height); 66 static int frame_check_height(frame_T *topfrp, int height);
68 static int frame_check_width(frame_T *topfrp, int width); 67 static int frame_check_width(frame_T *topfrp, int width);
69 68
70 static win_T *win_alloc(win_T *after, int hidden); 69 static win_T *win_alloc(win_T *after, int hidden);
926 if (flags & WSP_HELP) 925 if (flags & WSP_HELP)
927 make_snapshot(SNAP_HELP_IDX); 926 make_snapshot(SNAP_HELP_IDX);
928 else 927 else
929 clear_snapshot(curtab, SNAP_HELP_IDX); 928 clear_snapshot(curtab, SNAP_HELP_IDX);
930 929
931 return win_split_ins(size, flags, NULL, 0); 930 return win_split_ins(size, flags, NULL, 0, NULL);
932 } 931 }
933 932
934 /* 933 /*
935 * When "new_wp" is NULL: split the current window in two. 934 * When "new_wp" is NULL: split the current window in two.
936 * When "new_wp" is not NULL: insert this window at the far 935 * When "new_wp" is not NULL: insert this window at the far
937 * top/left/right/bottom. 936 * top/left/right/bottom.
937 * When "to_flatten" is not NULL: flatten this frame before reorganising frames;
938 * remains unflattened on failure.
939 *
938 * On failure, if "new_wp" was not NULL, no changes will have been made to the 940 * On failure, if "new_wp" was not NULL, no changes will have been made to the
939 * window layout or sizes. 941 * window layout or sizes.
940 * Return FAIL for failure, OK otherwise. 942 * Return FAIL for failure, OK otherwise.
941 */ 943 */
942 int 944 int
943 win_split_ins( 945 win_split_ins(
944 int size, 946 int size,
945 int flags, 947 int flags,
946 win_T *new_wp, 948 win_T *new_wp,
947 int dir) 949 int dir,
950 frame_T *to_flatten)
948 { 951 {
949 win_T *wp = new_wp; 952 win_T *wp = new_wp;
950 win_T *oldwin; 953 win_T *oldwin;
951 int new_size = size; 954 int new_size = size;
952 int i; 955 int i;
1217 1220
1218 // make the contents of the new window the same as the current one 1221 // make the contents of the new window the same as the current one
1219 win_init(wp, curwin, flags); 1222 win_init(wp, curwin, flags);
1220 } 1223 }
1221 1224
1225 // Going to reorganize frames now, make sure they're flat.
1226 if (to_flatten != NULL)
1227 frame_flatten(to_flatten);
1228
1222 /* 1229 /*
1223 * Reorganise the tree of frames to insert the new window. 1230 * Reorganise the tree of frames to insert the new window.
1224 */ 1231 */
1225 if (flags & (WSP_TOP | WSP_BOT)) 1232 if (flags & (WSP_TOP | WSP_BOT))
1226 { 1233 {
1369 + WINBAR_HEIGHT(wp) ; 1376 + WINBAR_HEIGHT(wp) ;
1370 1377
1371 if (!((flags & WSP_BOT) && p_ls == 0)) 1378 if (!((flags & WSP_BOT) && p_ls == 0))
1372 new_fr_height -= STATUS_HEIGHT; 1379 new_fr_height -= STATUS_HEIGHT;
1373 if (flags & WSP_BOT) 1380 if (flags & WSP_BOT)
1374 frame_add_statusline(curfrp, FALSE); 1381 frame_add_statusline(curfrp);
1375 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE); 1382 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
1376 } 1383 }
1377 else 1384 else
1378 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT)); 1385 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1379 if (before) // new window above current one 1386 if (before) // new window above current one
1919 int 1926 int
1920 win_splitmove(win_T *wp, int size, int flags) 1927 win_splitmove(win_T *wp, int size, int flags)
1921 { 1928 {
1922 int dir; 1929 int dir;
1923 int height = wp->w_height; 1930 int height = wp->w_height;
1924 frame_T *frp; 1931 frame_T *unflat_altfr;
1925 1932
1926 if (ONE_WINDOW) 1933 if (ONE_WINDOW)
1927 return OK; // nothing to do 1934 return OK; // nothing to do
1928 if (check_split_disallowed(wp) == FAIL) 1935 if (check_split_disallowed(wp) == FAIL)
1929 return FAIL; 1936 return FAIL;
1930 1937
1931 // Undoing changes to frames if splitting fails is complicated. 1938 // Remove the window and frame from the tree of frames. Don't flatten any
1932 // Save a full snapshot to restore instead. 1939 // frames yet so we can restore things if win_split_ins fails.
1933 frp = make_full_snapshot(); 1940 winframe_remove(wp, &dir, NULL, &unflat_altfr);
1934 if (frp == NULL)
1935 {
1936 emsg(_(e_out_of_memory));
1937 return FAIL;
1938 }
1939
1940 // Remove the window and frame from the tree of frames.
1941 (void)winframe_remove(wp, &dir, NULL);
1942 win_remove(wp, NULL); 1941 win_remove(wp, NULL);
1943 last_status(FALSE); // may need to remove last status line 1942 last_status(FALSE); // may need to remove last status line
1944 (void)win_comp_pos(); // recompute window positions 1943 (void)win_comp_pos(); // recompute window positions
1945 1944
1946 // Split a window on the desired side and put "wp" there. 1945 // Split a window on the desired side and put "wp" there.
1947 if (win_split_ins(size, flags, wp, dir) == FAIL) 1946 if (win_split_ins(size, flags, wp, dir, unflat_altfr) == FAIL)
1948 { 1947 {
1949 // Restore the previous layout from the snapshot. 1948 // win_split_ins doesn't change sizes or layout if it fails to insert an
1950 vim_free(wp->w_frame); 1949 // existing window, so just undo winframe_remove.
1951 restore_full_snapshot(frp); 1950 winframe_restore(wp, dir, unflat_altfr);
1952
1953 // Vertical separators to the left may have been lost. Restore them.
1954 frp = wp->w_frame;
1955 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL)
1956 frame_add_vsep(frp->fr_prev);
1957
1958 // Statuslines above may have been lost. Restore them.
1959 if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL)
1960 frame_add_statusline(frp->fr_prev, TRUE);
1961
1962 win_append(wp->w_prev, wp); 1951 win_append(wp->w_prev, wp);
1952 (void)win_comp_pos(); // recompute window positions
1963 return FAIL; 1953 return FAIL;
1964 } 1954 }
1965 clear_snapshot_rec(frp);
1966 1955
1967 // If splitting horizontally, try to preserve height. 1956 // If splitting horizontally, try to preserve height.
1968 if (size == 0 && !(flags & WSP_VERT)) 1957 if (size == 0 && !(flags & WSP_VERT))
1969 { 1958 {
1970 win_setheight_win(height, wp); 1959 win_setheight_win(height, wp);
3410 win_T *wp; 3399 win_T *wp;
3411 tabpage_T *win_tp = tp == NULL ? curtab : tp; 3400 tabpage_T *win_tp = tp == NULL ? curtab : tp;
3412 3401
3413 // Remove the window and its frame from the tree of frames. 3402 // Remove the window and its frame from the tree of frames.
3414 frp = win->w_frame; 3403 frp = win->w_frame;
3415 wp = winframe_remove(win, dirp, tp); 3404 wp = winframe_remove(win, dirp, tp, NULL);
3416 vim_free(frp); 3405 vim_free(frp);
3417 win_free(win, tp); 3406 win_free(win, tp);
3418 3407
3419 // When deleting the current window in the tab, select a new current 3408 // When deleting the current window in the tab, select a new current
3420 // window. 3409 // window.
3460 */ 3449 */
3461 win_T * 3450 win_T *
3462 winframe_remove( 3451 winframe_remove(
3463 win_T *win, 3452 win_T *win,
3464 int *dirp UNUSED, // set to 'v' or 'h' for direction if 'ea' 3453 int *dirp UNUSED, // set to 'v' or 'h' for direction if 'ea'
3465 tabpage_T *tp) // tab page "win" is in, NULL for current 3454 tabpage_T *tp, // tab page "win" is in, NULL for current
3455 frame_T **unflat_altfr) // if not NULL, set to pointer of frame that got
3456 // the space, and it is not flattened
3466 { 3457 {
3467 frame_T *frp, *frp2, *frp3; 3458 frame_T *frp, *frp2, *frp3;
3468 frame_T *frp_close = win->w_frame; 3459 frame_T *frp_close = win->w_frame;
3469 win_T *wp; 3460 win_T *wp;
3470 3461
3515 frp3 = frp3->fr_next; 3506 frp3 = frp3->fr_next;
3516 } 3507 }
3517 } 3508 }
3518 } 3509 }
3519 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height, 3510 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
3520 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE); 3511 frp2 == frp_close->fr_next, FALSE);
3521 *dirp = 'v'; 3512 *dirp = 'v';
3522 } 3513 }
3523 else 3514 else
3524 { 3515 {
3525 // When 'winfixwidth' is set, try to find another frame in the column 3516 // When 'winfixwidth' is set, try to find another frame in the column
3552 frp3 = frp3->fr_next; 3543 frp3 = frp3->fr_next;
3553 } 3544 }
3554 } 3545 }
3555 } 3546 }
3556 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width, 3547 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
3557 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE); 3548 frp2 == frp_close->fr_next, FALSE);
3558 *dirp = 'h'; 3549 *dirp = 'h';
3559 } 3550 }
3560 3551
3561 // If rows/columns go to a window below/right its positions need to be 3552 // If rows/columns go to a window below/right its positions need to be
3562 // updated. Can only be done after the sizes have been updated. 3553 // updated. Can only be done after the sizes have been updated.
3566 int col = win->w_wincol; 3557 int col = win->w_wincol;
3567 3558
3568 frame_comp_pos(frp2, &row, &col); 3559 frame_comp_pos(frp2, &row, &col);
3569 } 3560 }
3570 3561
3571 if (frp2->fr_next == NULL && frp2->fr_prev == NULL) 3562 if (unflat_altfr == NULL)
3572 { 3563 frame_flatten(frp2);
3573 // There is no other frame in this list, move its info to the parent 3564 else
3574 // and remove it. 3565 *unflat_altfr = frp2;
3575 frp2->fr_parent->fr_layout = frp2->fr_layout; 3566
3576 frp2->fr_parent->fr_child = frp2->fr_child; 3567 return wp;
3577 FOR_ALL_FRAMES(frp, frp2->fr_child) 3568 }
3578 frp->fr_parent = frp2->fr_parent; 3569
3579 frp2->fr_parent->fr_win = frp2->fr_win; 3570 /*
3580 if (frp2->fr_win != NULL) 3571 * Flatten "frp" into its parent frame if it's the only child, also merging its
3581 frp2->fr_win->w_frame = frp2->fr_parent; 3572 * list with the grandparent if they share the same layout.
3582 frp = frp2->fr_parent; 3573 * Frees "frp" if flattened; also "frp->fr_parent" if it has the same layout.
3574 * "frp" must be valid in the current tabpage.
3575 */
3576 static void
3577 frame_flatten(frame_T *frp)
3578 {
3579 frame_T *frp2, *frp3;
3580
3581 if (frp->fr_next != NULL || frp->fr_prev != NULL)
3582 return;
3583
3584 // There is no other frame in this list, move its info to the parent
3585 // and remove it.
3586 frp->fr_parent->fr_layout = frp->fr_layout;
3587 frp->fr_parent->fr_child = frp->fr_child;
3588 FOR_ALL_FRAMES(frp2, frp->fr_child)
3589 frp2->fr_parent = frp->fr_parent;
3590 frp->fr_parent->fr_win = frp->fr_win;
3591 if (frp->fr_win != NULL)
3592 frp->fr_win->w_frame = frp->fr_parent;
3593 frp2 = frp->fr_parent;
3594 if (topframe->fr_child == frp)
3595 topframe->fr_child = frp2;
3596 vim_free(frp);
3597
3598 frp = frp2->fr_parent;
3599 if (frp != NULL && frp->fr_layout == frp2->fr_layout)
3600 {
3601 // The frame above the parent has the same layout, have to merge
3602 // the frames into this list.
3603 if (frp->fr_child == frp2)
3604 frp->fr_child = frp2->fr_child;
3605 frp2->fr_child->fr_prev = frp2->fr_prev;
3606 if (frp2->fr_prev != NULL)
3607 frp2->fr_prev->fr_next = frp2->fr_child;
3608 for (frp3 = frp2->fr_child; ; frp3 = frp3->fr_next)
3609 {
3610 frp3->fr_parent = frp;
3611 if (frp3->fr_next == NULL)
3612 {
3613 frp3->fr_next = frp2->fr_next;
3614 if (frp2->fr_next != NULL)
3615 frp2->fr_next->fr_prev = frp3;
3616 break;
3617 }
3618 }
3583 if (topframe->fr_child == frp2) 3619 if (topframe->fr_child == frp2)
3584 topframe->fr_child = frp; 3620 topframe->fr_child = frp;
3585 vim_free(frp2); 3621 vim_free(frp2);
3586 3622 }
3587 frp2 = frp->fr_parent; 3623 }
3588 if (frp2 != NULL && frp2->fr_layout == frp->fr_layout) 3624
3589 { 3625 /*
3590 // The frame above the parent has the same layout, have to merge 3626 * Undo changes from a prior call to winframe_remove, also restoring lost
3591 // the frames into this list. 3627 * vertical separators and statuslines.
3592 if (frp2->fr_child == frp) 3628 * Caller must ensure no other changes were made to the layout or window sizes!
3593 frp2->fr_child = frp->fr_child; 3629 */
3594 frp->fr_child->fr_prev = frp->fr_prev; 3630 static void
3595 if (frp->fr_prev != NULL) 3631 winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr)
3596 frp->fr_prev->fr_next = frp->fr_child; 3632 {
3597 for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next) 3633 frame_T *frp = wp->w_frame;
3598 { 3634
3599 frp3->fr_parent = frp2; 3635 // Put "wp"'s frame back where it was.
3600 if (frp3->fr_next == NULL) 3636 if (frp->fr_prev != NULL)
3601 { 3637 frame_append(frp->fr_prev, frp);
3602 frp3->fr_next = frp->fr_next; 3638 else
3603 if (frp->fr_next != NULL) 3639 frame_insert(frp->fr_next, frp);
3604 frp->fr_next->fr_prev = frp3; 3640
3605 break; 3641 // Vertical separators to the left may have been lost. Restore them.
3606 } 3642 if (wp->w_vsep_width == 0
3607 } 3643 && frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL)
3608 if (topframe->fr_child == frp) 3644 frame_add_vsep(frp->fr_prev);
3609 topframe->fr_child = frp2; 3645
3610 vim_free(frp); 3646 // Statuslines above may have been lost. Restore them.
3611 } 3647 if (wp->w_status_height == 0
3612 } 3648 && frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL)
3613 3649 frame_add_statusline(frp->fr_prev);
3614 return wp; 3650
3651 // Restore the lost room that was redistributed to the altframe.
3652 if (dir == 'v')
3653 {
3654 frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height,
3655 unflat_altfr == frp->fr_next, FALSE);
3656 }
3657 else if (dir == 'h')
3658 {
3659 frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width,
3660 unflat_altfr == frp->fr_next, FALSE);
3661 }
3615 } 3662 }
3616 3663
3617 /* 3664 /*
3618 * Return a pointer to the frame that will receive the empty screen space that 3665 * Return a pointer to the frame that will receive the empty screen space that
3619 * is left over after "win" is closed. 3666 * is left over after "win" is closed.
3893 return TRUE; 3940 return TRUE;
3894 } 3941 }
3895 3942
3896 /* 3943 /*
3897 * Add a status line to windows at the bottom of "frp". 3944 * Add a status line to windows at the bottom of "frp".
3898 * If "adjust_winheight" is set, reduce the height of windows without a 3945 * Note: Does not check if there is room!
3899 * statusline to accommodate one; otherwise, there is no check for room!
3900 */ 3946 */
3901 static void 3947 static void
3902 frame_add_statusline(frame_T *frp, int adjust_winheight) 3948 frame_add_statusline(frame_T *frp)
3903 { 3949 {
3904 win_T *wp; 3950 win_T *wp;
3905 3951
3906 if (frp->fr_layout == FR_LEAF) 3952 if (frp->fr_layout == FR_LEAF)
3907 { 3953 {
3908 wp = frp->fr_win; 3954 wp = frp->fr_win;
3909 if (adjust_winheight && wp->w_status_height == 0
3910 && wp->w_height >= STATUS_HEIGHT) // don't make it negative
3911 wp->w_height -= STATUS_HEIGHT - wp->w_status_height;
3912 wp->w_status_height = STATUS_HEIGHT; 3955 wp->w_status_height = STATUS_HEIGHT;
3913 } 3956 }
3914 else if (frp->fr_layout == FR_ROW) 3957 else if (frp->fr_layout == FR_ROW)
3915 { 3958 {
3916 // Handle all the frames in the row. 3959 // Handle all the frames in the row.
3917 FOR_ALL_FRAMES(frp, frp->fr_child) 3960 FOR_ALL_FRAMES(frp, frp->fr_child)
3918 frame_add_statusline(frp, adjust_winheight); 3961 frame_add_statusline(frp);
3919 } 3962 }
3920 else // frp->fr_layout == FR_COL 3963 else // frp->fr_layout == FR_COL
3921 { 3964 {
3922 // Only need to handle the last frame in the column. 3965 // Only need to handle the last frame in the column.
3923 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) 3966 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
3924 ; 3967 ;
3925 frame_add_statusline(frp, adjust_winheight); 3968 frame_add_statusline(frp);
3926 } 3969 }
3927 } 3970 }
3928 3971
3929 /* 3972 /*
3930 * Set width of a frame. Handles recursively going through contained frames. 3973 * Set width of a frame. Handles recursively going through contained frames.
7552 */ 7595 */
7553 int 7596 int
7554 make_snapshot(int idx) 7597 make_snapshot(int idx)
7555 { 7598 {
7556 clear_snapshot(curtab, idx); 7599 clear_snapshot(curtab, idx);
7557 if (make_snapshot_rec(topframe, &curtab->tp_snapshot[idx], FALSE) == FAIL) 7600 if (make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]) == FAIL)
7558 { 7601 {
7559 clear_snapshot(curtab, idx); 7602 clear_snapshot(curtab, idx);
7560 return FAIL; 7603 return FAIL;
7561 } 7604 }
7562 return OK; 7605 return OK;
7563 } 7606 }
7564 7607
7565 static int 7608 static int
7566 make_snapshot_rec(frame_T *fr, frame_T **frp, int snap_wins) 7609 make_snapshot_rec(frame_T *fr, frame_T **frp)
7567 { 7610 {
7568 *frp = ALLOC_CLEAR_ONE(frame_T); 7611 *frp = ALLOC_CLEAR_ONE(frame_T);
7569 if (*frp == NULL) 7612 if (*frp == NULL)
7570 return FAIL; 7613 return FAIL;
7571 (*frp)->fr_layout = fr->fr_layout; 7614 (*frp)->fr_layout = fr->fr_layout;
7572 (*frp)->fr_width = fr->fr_width; 7615 (*frp)->fr_width = fr->fr_width;
7573 (*frp)->fr_height = fr->fr_height; 7616 (*frp)->fr_height = fr->fr_height;
7574 if (fr->fr_next != NULL) 7617 if (fr->fr_next != NULL)
7575 { 7618 {
7576 if (make_snapshot_rec(fr->fr_next, &((*frp)->fr_next), snap_wins) 7619 if (make_snapshot_rec(fr->fr_next, &((*frp)->fr_next)) == FAIL)
7577 == FAIL)
7578 return FAIL; 7620 return FAIL;
7579 } 7621 }
7580 if (fr->fr_child != NULL) 7622 if (fr->fr_child != NULL)
7581 { 7623 {
7582 if (make_snapshot_rec(fr->fr_child, &((*frp)->fr_child), snap_wins) 7624 if (make_snapshot_rec(fr->fr_child, &((*frp)->fr_child)) == FAIL)
7583 == FAIL)
7584 return FAIL; 7625 return FAIL;
7585 } 7626 }
7586 if (fr->fr_layout == FR_LEAF && (snap_wins || fr->fr_win == curwin)) 7627 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
7587 (*frp)->fr_win = fr->fr_win; 7628 (*frp)->fr_win = curwin;
7588 return OK; 7629 return OK;
7589 } 7630 }
7590 7631
7591 /* 7632 /*
7592 * Remove any existing snapshot. 7633 * Remove any existing snapshot.
7718 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child); 7759 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
7719 if (wp2 != NULL) 7760 if (wp2 != NULL)
7720 wp = wp2; 7761 wp = wp2;
7721 } 7762 }
7722 return wp; 7763 return wp;
7723 }
7724
7725 /*
7726 * Return a snapshot of all frames in the current tabpage and which windows are
7727 * in them, or NULL if out of memory.
7728 * Use clear_snapshot_rec to free the snapshot.
7729 */
7730 static frame_T *
7731 make_full_snapshot(void)
7732 {
7733 frame_T *frp;
7734
7735 if (make_snapshot_rec(topframe, &frp, TRUE) == FAIL)
7736 {
7737 clear_snapshot_rec(frp);
7738 return NULL;
7739 }
7740 return frp;
7741 }
7742
7743 /*
7744 * Restore all frames in the full snapshot "sn" for the current tabpage.
7745 * Caller must ensure that the screen size didn't change, no windows with frames
7746 * in the snapshot were freed, and windows with frames not in the snapshot are
7747 * removed from their frames!
7748 * Doesn't restore changed window vertical separators or statuslines.
7749 * Frees the old frames. Don't call clear_snapshot_rec on "sn" afterwards!
7750 */
7751 static void
7752 restore_full_snapshot(frame_T *sn)
7753 {
7754 if (sn == NULL)
7755 return;
7756
7757 clear_snapshot_rec(topframe);
7758 restore_full_snapshot_rec(sn);
7759 curtab->tp_topframe = topframe = sn;
7760 last_status(FALSE);
7761
7762 // If the amount of space available changed, first try setting the sizes of
7763 // windows with 'winfix{width,height}'. If that doesn't result in the right
7764 // size, forget about that option.
7765 if (topframe->fr_width != Columns)
7766 {
7767 frame_new_width(topframe, Columns, FALSE, TRUE);
7768 if (!frame_check_width(topframe, Columns))
7769 frame_new_width(topframe, Columns, FALSE, FALSE);
7770 }
7771 if (topframe->fr_height != ROWS_AVAIL)
7772 {
7773 frame_new_height(topframe, ROWS_AVAIL, FALSE, TRUE);
7774 if (!frame_check_height(topframe, ROWS_AVAIL))
7775 frame_new_height(topframe, ROWS_AVAIL, FALSE, FALSE);
7776 }
7777
7778 win_comp_pos();
7779 }
7780
7781 static void
7782 restore_full_snapshot_rec(frame_T *sn)
7783 {
7784 if (sn == NULL)
7785 return;
7786
7787 if (sn->fr_child != NULL)
7788 sn->fr_child->fr_parent = sn;
7789 if (sn->fr_next != NULL)
7790 {
7791 sn->fr_next->fr_parent = sn->fr_parent;
7792 sn->fr_next->fr_prev = sn;
7793 }
7794 if (sn->fr_win != NULL)
7795 {
7796 sn->fr_win->w_frame = sn;
7797 // Resize window to fit the frame.
7798 frame_new_height(sn, sn->fr_height, FALSE, FALSE);
7799 frame_new_width(sn, sn->fr_width, FALSE, FALSE);
7800 }
7801 restore_full_snapshot_rec(sn->fr_child);
7802 restore_full_snapshot_rec(sn->fr_next);
7803 } 7764 }
7804 7765
7805 #if defined(FEAT_GUI) || defined(PROTO) 7766 #if defined(FEAT_GUI) || defined(PROTO)
7806 /* 7767 /*
7807 * Return TRUE if there is any vertically split window. 7768 * Return TRUE if there is any vertically split window.