To: vim_dev@googlegroups.com Subject: Patch 9.0.0907 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0907 Problem: Restoring window after WinScrolled may fail. Solution: Lock the window layout when triggering WinScrolled. Files: src/window.c, src/proto/window.pro, src/errors.h, src/ex_docmd.c *** ../vim-9.0.0906/src/window.c 2022-11-01 18:34:02.783964409 +0000 --- src/window.c 2022-11-19 11:25:22.357826785 +0000 *************** *** 84,89 **** --- 84,131 ---- // autocommands mess up the window structure. static int split_disallowed = 0; + // When non-zero closing a window is forbidden. Used to avoid that nasty + // autocommands mess up the window structure. + static int close_disallowed = 0; + + /* + * Disallow changing the window layout (split window, close window, move + * window). Resizing is still allowed. + * Used for autocommands that temporarily use another window and need to + * make sure the previously selected window is still there. + * Must be matched with exactly one call to window_layout_unlock()! + */ + static void + window_layout_lock(void) + { + ++split_disallowed; + ++close_disallowed; + } + + static void + window_layout_unlock(void) + { + --split_disallowed; + --close_disallowed; + } + + /* + * When the window layout cannot be changed give an error and return TRUE. + */ + int + window_layout_locked(void) + { + if (split_disallowed > 0 || close_disallowed > 0) + { + if (close_disallowed == 0) + emsg(_(e_cannot_split_window_when_closing_buffer)); + else + emsg(_(e_not_allowed_to_change_window_layout_in_this_autocmd)); + return TRUE; + } + return FALSE; + } + // #define WIN_DEBUG #ifdef WIN_DEBUG /* *************** *** 2531,2536 **** --- 2573,2580 ---- emsg(_(e_cannot_close_last_window)); return FAIL; } + if (window_layout_locked()) + return FAIL; if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_locked > 0)) *************** *** 2802,2825 **** void may_trigger_winscrolled(void) { - win_T *wp = curwin; static int recursive = FALSE; - char_u winid[NUMBUFLEN]; if (recursive || !has_winscrolled()) return; if (wp->w_last_topline != wp->w_topline || wp->w_last_leftcol != wp->w_leftcol || wp->w_last_skipcol != wp->w_skipcol || wp->w_last_width != wp->w_width || wp->w_last_height != wp->w_height) { ! vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id); recursive = TRUE; apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer); recursive = FALSE; // an autocmd may close the window, "wp" may be invalid now if (win_valid_any_tab(wp)) --- 2846,2873 ---- void may_trigger_winscrolled(void) { static int recursive = FALSE; if (recursive || !has_winscrolled()) return; + win_T *wp = curwin; if (wp->w_last_topline != wp->w_topline || wp->w_last_leftcol != wp->w_leftcol || wp->w_last_skipcol != wp->w_skipcol || wp->w_last_width != wp->w_width || wp->w_last_height != wp->w_height) { ! // "curwin" may be different from the actual current window, make sure ! // it can be restored. ! window_layout_lock(); recursive = TRUE; + char_u winid[NUMBUFLEN]; + vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id); apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE, wp->w_buffer); recursive = FALSE; + window_layout_unlock(); // an autocmd may close the window, "wp" may be invalid now if (win_valid_any_tab(wp)) *************** *** 4014,4019 **** --- 4062,4069 ---- emsg(_(e_invalid_in_cmdline_window)); return FAIL; } + if (window_layout_locked()) + return FAIL; newtp = alloc_tabpage(); if (newtp == NULL) *** ../vim-9.0.0906/src/proto/window.pro 2022-07-23 09:06:23.620970749 +0100 --- src/proto/window.pro 2022-11-19 11:25:26.341827109 +0000 *************** *** 1,4 **** --- 1,5 ---- /* window.c */ + int window_layout_locked(void); win_T *prevwin_curwin(void); void do_window(int nchar, long Prenum, int xchar); void get_wincmd_addr_type(char_u *arg, exarg_T *eap); *** ../vim-9.0.0906/src/errors.h 2022-11-13 23:30:02.423807434 +0000 --- src/errors.h 2022-11-19 11:12:36.641489018 +0000 *************** *** 3341,3343 **** --- 3341,3345 ---- #endif EXTERN char e_cannot_change_user_commands_while_listing[] INIT(= N_("E1311: Cannot change user commands while listing")); + EXTERN char e_not_allowed_to_change_window_layout_in_this_autocmd[] + INIT(= N_("E1312: Not allowed to change the window layout in this autocmd")); *** ../vim-9.0.0906/src/ex_docmd.c 2022-11-11 22:57:41.774304953 +0000 --- src/ex_docmd.c 2022-11-19 11:29:24.325833848 +0000 *************** *** 6055,6060 **** --- 6055,6062 ---- emsg(_(e_cannot_close_autocmd_or_popup_window)); return; } + if (window_layout_locked()) + return; need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); if (need_hide && !buf_hide(buf) && !forceit) *************** *** 6227,6233 **** cmdwin_result = K_IGNORE; else if (first_tabpage->tp_next == NULL) emsg(_(e_cannot_close_last_tab_page)); ! else { tab_number = get_tabpage_arg(eap); if (eap->errmsg == NULL) --- 6229,6235 ---- cmdwin_result = K_IGNORE; else if (first_tabpage->tp_next == NULL) emsg(_(e_cannot_close_last_tab_page)); ! else if (!window_layout_locked()) { tab_number = get_tabpage_arg(eap); if (eap->errmsg == NULL) *************** *** 6263,6269 **** cmdwin_result = K_IGNORE; else if (first_tabpage->tp_next == NULL) msg(_("Already only one tab page")); ! else { tab_number = get_tabpage_arg(eap); if (eap->errmsg == NULL) --- 6265,6271 ---- cmdwin_result = K_IGNORE; else if (first_tabpage->tp_next == NULL) msg(_("Already only one tab page")); ! else if (!window_layout_locked()) { tab_number = get_tabpage_arg(eap); if (eap->errmsg == NULL) *************** *** 6296,6301 **** --- 6298,6306 ---- void tabpage_close(int forceit) { + if (window_layout_locked()) + return; + // First close all the windows but the current one. If that worked then // close the last window in this tab, that will close it. if (!ONE_WINDOW) *************** *** 6341,6354 **** static void ex_only(exarg_T *eap) { ! win_T *wp; ! int wnr; # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif if (eap->addr_count > 0) { ! wnr = eap->line2; for (wp = firstwin; --wnr > 0; ) { if (wp->w_next == NULL) --- 6346,6360 ---- static void ex_only(exarg_T *eap) { ! if (window_layout_locked()) ! return; # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif if (eap->addr_count > 0) { ! win_T *wp; ! int wnr = eap->line2; for (wp = firstwin; --wnr > 0; ) { if (wp->w_next == NULL) *************** *** 6367,6372 **** --- 6373,6380 ---- // ":hide" or ":hide | cmd": hide current window if (!eap->skip) { + if (window_layout_locked()) + return; #ifdef FEAT_GUI need_mouse_correct = TRUE; #endif *** ../vim-9.0.0906/src/version.c 2022-11-19 10:47:45.758339628 +0000 --- src/version.c 2022-11-19 11:03:29.545672203 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 907, /**/ -- From "know your smileys": % Bike accident. A bit far-fetched, I suppose; although... o _ _ _ _o /\_ _ \\o (_)\__/o (_) _< \_ _>(_) (_)/<_ \_| \ _|/' \/ (_)>(_) (_) (_) (_) (_)' _\o_ /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///