patch 8.2.3591: no event is triggered when closing a window

Problem:    No event is triggered when closing a window.
Solution:   Add the WinClosed event. (Naohiro Ono, closes #9110)
diff --git a/src/autocmd.c b/src/autocmd.c
index 1704cd4..14cd4af 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -186,6 +186,7 @@
     {"VimLeave",	EVENT_VIMLEAVE},
     {"VimLeavePre",	EVENT_VIMLEAVEPRE},
     {"WinNew",		EVENT_WINNEW},
+    {"WinClosed",	EVENT_WINCLOSED},
     {"WinEnter",	EVENT_WINENTER},
     {"WinLeave",	EVENT_WINLEAVE},
     {"VimResized",	EVENT_VIMRESIZED},
@@ -2042,7 +2043,8 @@
 		|| event == EVENT_OPTIONSET
 		|| event == EVENT_QUICKFIXCMDPOST
 		|| event == EVENT_DIRCHANGED
-		|| event == EVENT_MODECHANGED)
+		|| event == EVENT_MODECHANGED
+		|| event == EVENT_WINCLOSED)
 	{
 	    fname = vim_strsave(fname);
 	    autocmd_fname_full = TRUE; // don't expand it later
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index 8161183..9eb718f 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
Binary files differ
diff --git a/src/version.c b/src/version.c
index e294d8e..ca022bf 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3591,
+/**/
     3590,
 /**/
     3589,
diff --git a/src/vim.h b/src/vim.h
index 22451c7..f86d68d 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1379,6 +1379,7 @@
     EVENT_WINENTER,		// after entering a window
     EVENT_WINLEAVE,		// before leaving a window
     EVENT_WINNEW,		// when entering a new window
+    EVENT_WINCLOSED,		// after closing a window
     EVENT_VIMSUSPEND,		// before Vim is suspended
     EVENT_VIMRESUME,		// after Vim is resumed
 
diff --git a/src/window.c b/src/window.c
index 5de6ed7..226d6c1 100644
--- a/src/window.c
+++ b/src/window.c
@@ -19,6 +19,7 @@
 static void win_rotate(int, int);
 static void win_totop(int size, int flags);
 static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
+static void trigger_winclosed(win_T *win);
 static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
 static frame_T *win_altframe(win_T *win, tabpage_T *tp);
 static tabpage_T *alt_tabpage(void);
@@ -2566,6 +2567,13 @@
     if (popup_win_closed(win) && !win_valid(win))
 	return FAIL;
 #endif
+
+    // Trigger WinClosed just before starting to free window-related resources.
+    trigger_winclosed(win);
+    // autocmd may have freed the window already.
+    if (!win_valid_any_tab(win))
+	return OK;
+
     win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, TRUE);
 
     if (only_one_window() && win_valid(win) && win->w_buffer == NULL
@@ -2710,6 +2718,20 @@
     return OK;
 }
 
+    static void
+trigger_winclosed(win_T *win)
+{
+    static int	recursive = FALSE;
+    char_u	winid[NUMBUFLEN];
+
+    if (recursive)
+	return;
+    recursive = TRUE;
+    vim_snprintf((char *)winid, sizeof(winid), "%i", win->w_id);
+    apply_autocmds(EVENT_WINCLOSED, winid, winid, FALSE, win->w_buffer);
+    recursive = FALSE;
+}
+
 /*
  * Close window "win" in tab page "tp", which is not the current tab page.
  * This may be the last window in that tab page and result in closing the tab,
@@ -2731,6 +2753,12 @@
 					       && win->w_buffer->b_locked > 0))
 	return; // window is already being closed
 
+    // Trigger WinClosed just before starting to free window-related resources.
+    trigger_winclosed(win);
+    // autocmd may have freed the window already.
+    if (!win_valid_any_tab(win))
+	return;
+
     if (win->w_buffer != NULL)
 	// Close the link to the buffer.
 	close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0,