Mercurial > vim
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. |