changeset 22838:80bd5de5dcab v8.2.1966

patch 8.2.1966: popup becomes current window after closing a terminal window Commit: https://github.com/vim/vim/commit/cbcd9cbd77acc8cc97c0d44683d96c01d3dd0fa7 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Nov 7 16:58:59 2020 +0100 patch 8.2.1966: popup becomes current window after closing a terminal window Problem: Popup becomes current window after closing a terminal window. Solution: When restoring the window after executing autocommands, check that the window ID is still the same. (Naruhiko Nishino, closes #7272)
author Bram Moolenaar <Bram@vim.org>
date Sat, 07 Nov 2020 17:00:05 +0100
parents a1e5d99414e8
children 5a6b1d00c97e
files src/autocmd.c src/proto/window.pro src/structs.h src/testdir/test_popupwin.vim src/version.c src/window.c
diffstat 6 files changed, 62 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -1433,9 +1433,9 @@ aucmd_prepbuf(
 	// window.  Expect a few side effects...
 	win = curwin;
 
-    aco->save_curwin = curwin;
+    aco->save_curwin_id = curwin->w_id;
     aco->save_curbuf = curbuf;
-    aco->save_prevwin = prevwin;
+    aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
     if (win != NULL)
     {
 	// There is a window for "buf" in the current tab page, make it the
@@ -1481,7 +1481,7 @@ aucmd_prepbuf(
 	curwin = aucmd_win;
     }
     curbuf = buf;
-    aco->new_curwin = curwin;
+    aco->new_curwin_id = curwin->w_id;
     set_bufref(&aco->new_curbuf, curbuf);
 }
 
@@ -1493,7 +1493,8 @@ aucmd_prepbuf(
 aucmd_restbuf(
     aco_save_T	*aco)		// structure holding saved values
 {
-    int dummy;
+    int	    dummy;
+    win_T   *save_curwin;
 
     if (aco->use_aucmd_win)
     {
@@ -1533,8 +1534,9 @@ win_found:
 	(void)win_comp_pos();   // recompute window positions
 	unblock_autocmds();
 
-	if (win_valid(aco->save_curwin))
-	    curwin = aco->save_curwin;
+	save_curwin = win_find_by_id(aco->save_curwin_id);
+	if (save_curwin != NULL)
+	    curwin = save_curwin;
 	else
 	    // Hmm, original window disappeared.  Just use the first one.
 	    curwin = firstwin;
@@ -1543,9 +1545,7 @@ win_found:
 	// May need to restore insert mode for a prompt buffer.
 	entering_window(curwin);
 #endif
-
-	if (win_valid(aco->save_prevwin))
-	    prevwin = aco->save_prevwin;
+	prevwin = win_find_by_id(aco->save_prevwin_id);
 #ifdef FEAT_EVAL
 	vars_clear(&aucmd_win->w_vars->dv_hashtab);  // free all w: variables
 	hash_init(&aucmd_win->w_vars->dv_hashtab);   // re-use the hashtab
@@ -1571,13 +1571,15 @@ win_found:
     }
     else
     {
-	// restore curwin
-	if (win_valid(aco->save_curwin))
+	// Restore curwin.  Use the window ID, a window may have been closed
+	// and the memory re-used for another one.
+	save_curwin = win_find_by_id(aco->save_curwin_id);
+	if (save_curwin != NULL)
 	{
 	    // Restore the buffer which was previously edited by curwin, if
 	    // it was changed, we are still the same window and the buffer is
 	    // valid.
-	    if (curwin == aco->new_curwin
+	    if (curwin->w_id == aco->new_curwin_id
 		    && curbuf != aco->new_curbuf.br_buf
 		    && bufref_valid(&aco->new_curbuf)
 		    && aco->new_curbuf.br_buf->b_ml.ml_mfp != NULL)
@@ -1592,10 +1594,9 @@ win_found:
 		++curbuf->b_nwindows;
 	    }
 
-	    curwin = aco->save_curwin;
+	    curwin = save_curwin;
 	    curbuf = curwin->w_buffer;
-	    if (win_valid(aco->save_prevwin))
-		prevwin = aco->save_prevwin;
+	    prevwin = win_find_by_id(aco->save_prevwin_id);
 	    // In case the autocommand moves the cursor to a position that
 	    // does not exist in curbuf.
 	    check_cursor();
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -5,6 +5,7 @@ int win_split(int size, int flags);
 int win_split_ins(int size, int flags, win_T *new_wp, int dir);
 int win_valid_popup(win_T *win);
 int win_valid(win_T *win);
+win_T *win_find_by_id(int id);
 int win_valid_any_tab(win_T *win);
 int win_count(void);
 int make_windows(int count, int vertical);
--- a/src/structs.h
+++ b/src/structs.h
@@ -3889,13 +3889,13 @@ typedef int vimmenu_T;
  */
 typedef struct
 {
-    buf_T	*save_curbuf;	// saved curbuf
-    int		use_aucmd_win;	// using aucmd_win
-    win_T	*save_curwin;	// saved curwin
-    win_T	*new_curwin;	// new curwin
-    win_T	*save_prevwin;	// saved prevwin
-    bufref_T	new_curbuf;	// new curbuf
-    char_u	*globaldir;	// saved value of globaldir
+    buf_T	*save_curbuf;	    // saved curbuf
+    int		use_aucmd_win;	    // using aucmd_win
+    int		save_curwin_id;	    // ID of saved curwin
+    int		new_curwin_id;	    // ID of new curwin
+    int		save_prevwin_id;    // ID of saved prevwin
+    bufref_T	new_curbuf;	    // new curbuf
+    char_u	*globaldir;	    // saved value of globaldir
 } aco_save_T;
 
 /*
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -3737,5 +3737,26 @@ func Test_popupwin_splitmove()
   bwipe
 endfunc
 
+func Test_popupwin_exiting_terminal()
+  CheckFeature terminal
+
+  " Tests that when creating a popup right after closing a terminal window does
+  " not make the popup the current window.
+  let winid = win_getid()
+  try
+    augroup Test_popupwin_exiting_terminal
+      autocmd!
+      autocmd WinEnter * :call popup_create('test', {})
+    augroup END
+    let bnr = term_start(&shell, #{term_finish: 'close'})
+    call term_sendkeys(bnr, "exit\r\n")
+    call WaitForAssert({-> assert_equal(winid, win_getid())})
+  finally
+    call popup_clear(1)
+    augroup Test_popupwin_exiting_terminal
+      autocmd!
+    augroup END
+  endtry
+endfunc
 
 " vim: shiftwidth=2 sts=2
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1966,
+/**/
     1965,
 /**/
     1964,
--- a/src/window.c
+++ b/src/window.c
@@ -1461,6 +1461,21 @@ win_valid(win_T *win)
 }
 
 /*
+ * Find window "id" in the current tab page.
+ * Return NULL if not found.
+ */
+    win_T *
+win_find_by_id(int id)
+{
+    win_T   *wp;
+
+    FOR_ALL_WINDOWS(wp)
+	if (wp->w_id == id)
+	    return wp;
+    return NULL;
+}
+
+/*
  * Check if "win" is a pointer to an existing window in any tab page.
  */
     int