comparison src/window.c @ 34548:db67c09ccd53 v9.1.0175

patch 9.1.0175: wrong window positions with 'winfix{width,height}' Commit: https://github.com/vim/vim/commit/5866bc3a0f54115d5982fdc09bdbe4c45069265a Author: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Wed Mar 13 20:17:24 2024 +0100 patch 9.1.0175: wrong window positions with 'winfix{width,height}' Problem: winframe functions incorrectly recompute window positions if the altframe wasn't adjacent to the closed frame, which is possible if adjacent windows had 'winfix{width,height}' set. Solution: recompute for windows within the parent of the altframe and closed frame. Skip this (as before) if the altframe was top/left, but only if adjacent to the closed frame, as positions won't change in that case. Also correct the return value documentation for win_screenpos. (Sean Dewar) The issue revealed itself after removing the win_comp_pos call below winframe_restore in win_splitmove. Similarly, wrong positions could result from windows closed in other tabpages, as win_free_mem uses winframe_remove (at least until it is entered later, where enter_tabpage calls win_comp_pos). NOTE: As win_comp_pos handles only curtab, it's possible via other means for positions in non-current tabpages to be wrong (e.g: after changing 'laststatus', 'showtabline', etc.). Given enter_tabpage recomputes it, maybe it's intentional as an optimization? Should probably be documented in win_screenpos then, but I won't address that here. closes: #14191 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 Wed, 13 Mar 2024 20:30:03 +0100
parents c865c2f93a04
children f9b510d3ed32
comparison
equal deleted inserted replaced
34547:5ddbf662a64a 34548:db67c09ccd53
3491 // the space, and it is not flattened 3491 // the space, and it is not flattened
3492 { 3492 {
3493 frame_T *frp, *frp2, *frp3; 3493 frame_T *frp, *frp2, *frp3;
3494 frame_T *frp_close = win->w_frame; 3494 frame_T *frp_close = win->w_frame;
3495 win_T *wp; 3495 win_T *wp;
3496 int row, col;
3496 3497
3497 /* 3498 /*
3498 * If there is only one window there is nothing to remove. 3499 * If there is only one window there is nothing to remove.
3499 */ 3500 */
3500 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) 3501 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
3501 return NULL; 3502 return NULL;
3503
3504 // Save the position of the containing frame (which will also contain the
3505 // altframe) before we remove anything, to recompute window positions later.
3506 wp = frame2win(frp_close->fr_parent);
3507 row = wp->w_winrow;
3508 col = wp->w_wincol;
3502 3509
3503 /* 3510 /*
3504 * Remove the window from its frame. 3511 * Remove the window from its frame.
3505 */ 3512 */
3506 frp2 = win_altframe(win, tp); 3513 frp2 = win_altframe(win, tp);
3582 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width, 3589 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
3583 frp2 == frp_close->fr_next, FALSE); 3590 frp2 == frp_close->fr_next, FALSE);
3584 *dirp = 'h'; 3591 *dirp = 'h';
3585 } 3592 }
3586 3593
3587 // If rows/columns go to a window below/right its positions need to be 3594 // If the altframe wasn't adjacent and left/above, resizing it will have
3588 // updated. Can only be done after the sizes have been updated. 3595 // changed window positions within the parent frame. Recompute them.
3589 if (frp2 == frp_close->fr_next) 3596 if (frp2 != frp_close->fr_prev)
3590 { 3597 frame_comp_pos(frp_close->fr_parent, &row, &col);
3591 int row = win->w_winrow;
3592 int col = win->w_wincol;
3593
3594 frame_comp_pos(frp2, &row, &col);
3595 }
3596 3598
3597 if (unflat_altfr == NULL) 3599 if (unflat_altfr == NULL)
3598 frame_flatten(frp2); 3600 frame_flatten(frp2);
3599 else 3601 else
3600 *unflat_altfr = frp2; 3602 *unflat_altfr = frp2;
3664 */ 3666 */
3665 static void 3667 static void
3666 winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) 3668 winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr)
3667 { 3669 {
3668 frame_T *frp = wp->w_frame; 3670 frame_T *frp = wp->w_frame;
3669 int row = wp->w_winrow;
3670 int col = wp->w_wincol;
3671 3671
3672 // Put "wp"'s frame back where it was. 3672 // Put "wp"'s frame back where it was.
3673 if (frp->fr_prev != NULL) 3673 if (frp->fr_prev != NULL)
3674 frame_append(frp->fr_prev, frp); 3674 frame_append(frp->fr_prev, frp);
3675 else 3675 else
3689 // adjusts window sizes to fit restored statuslines/separators, if needed. 3689 // adjusts window sizes to fit restored statuslines/separators, if needed.
3690 if (dir == 'v') 3690 if (dir == 'v')
3691 { 3691 {
3692 frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, 3692 frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height,
3693 unflat_altfr == frp->fr_next, FALSE); 3693 unflat_altfr == frp->fr_next, FALSE);
3694 row += frp->fr_height;
3695 } 3694 }
3696 else if (dir == 'h') 3695 else if (dir == 'h')
3697 { 3696 {
3698 frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width, 3697 frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width,
3699 unflat_altfr == frp->fr_next, FALSE); 3698 unflat_altfr == frp->fr_next, FALSE);
3700 col += frp->fr_width; 3699 }
3701 } 3700
3702 3701 // Recompute window positions within the parent frame to restore them.
3703 // If rows/columns went to a window below/right, its positions need to be 3702 // Positions were unchanged if the altframe was adjacent and left/above.
3704 // restored. Can only be done after the sizes have been updated. 3703 if (unflat_altfr != frp->fr_prev)
3705 if (unflat_altfr == frp->fr_next) 3704 {
3706 frame_comp_pos(unflat_altfr, &row, &col); 3705 win_T *topleft = frame2win(frp->fr_parent);
3706 int row = topleft->w_winrow;
3707 int col = topleft->w_wincol;
3708
3709 frame_comp_pos(frp->fr_parent, &row, &col);
3710 }
3707 } 3711 }
3708 3712
3709 /* 3713 /*
3710 * Return a pointer to the frame that will receive the empty screen space that 3714 * Return a pointer to the frame that will receive the empty screen space that
3711 * is left over after "win" is closed. 3715 * is left over after "win" is closed.