patch 9.1.1202: Missing TabClosedPre autocommand

Problem:  Missing TabClosedPre autocommand
          (zoumi)
Solution: Add the TabClosedPre autcommand (Jim Zhou).

fixes: #16518
closes: #16855

Signed-off-by: Jim Zhou <jimzhouzzy@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/window.c b/src/window.c
index cc76f79..cce7f4c 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2978,6 +2978,33 @@
     recursive = FALSE;
 }
 
+    static void
+trigger_tabclosedpre(tabpage_T *tp)
+{
+    static int	recursive = FALSE;
+    tabpage_T	*ptp = curtab;
+
+    // Quickly return when no TabClosedPre autocommands to be executed or
+    // already executing
+    if (!has_tabclosedpre() || recursive)
+	return;
+
+    if (valid_tabpage(tp))
+	goto_tabpage_tp(tp, FALSE, FALSE);
+    recursive = TRUE;
+    window_layout_lock();
+    apply_autocmds(EVENT_TABCLOSEDPRE, NULL, NULL, FALSE, NULL);
+    window_layout_unlock();
+    recursive = FALSE;
+    // tabpage may have been modified or deleted by autocmds
+    if (valid_tabpage(ptp))
+	// try to recover the tappage first
+	goto_tabpage_tp(ptp, FALSE, FALSE);
+    else
+	// fall back to the first tappage
+	goto_tabpage_tp(first_tabpage, FALSE, FALSE);
+}
+
 /*
  * Make a snapshot of all the window scroll positions and sizes of the current
  * tab page.
@@ -3353,6 +3380,14 @@
 	    return;
     }
 
+    if (tp->tp_firstwin == tp->tp_lastwin)
+    {
+	trigger_tabclosedpre(tp);
+	// 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,