Subject: Re: bug#71386: 29.1; Frame is auto-deleted even when it has multiple tabs

From: Juri Linkov <[email-masked]>
Date: Sun, 30 Mar 2025 09:35:09 +0300

> I've been bitten by this same issue where kill-buffer /
> replace-buffer-in-windows doesn't take available tab-bar tabs into
> consideration as viable replacement windows to restore when quitting the
> last window on a frame.  I looked at 29+, 30, 31 window.el/.c and
> tab-bar.el and I can't find if this was resolved or if there was a recipe
> to avoid this.
>
> I've resorted to wrapping kill-buffer using a custom function, not advice,
> to inhibit deleting the frame.
>
> Do any of you recall if this bug was addressed and how?  If not, may I
> assist in some way?

Sorry, I'm still testing the fix attached below.
Does it work for you?

diff --git a/lisp/window.el b/lisp/window.el
index befbc679b23..715b8e745c9 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4187,6 +4187,21 @@ window-deletable-p
 
   (let ((frame (window-frame window)))
     (cond
+     ((and tab-bar-mode
+           ;; Fall back to frame handling in case of less than 2 tabs
+           (> (length (funcall tab-bar-tabs-function frame)) 1)
+           ;; Close the tab with the initial window (bug#59862)
+           (or (eq (nth 1 (window-parameter window 'quit-restore)) 'tab)
+               ;; or with the dedicated window (bug#71386)
+               (and (window-dedicated-p window)
+                    (frame-root-window-p window)))
+           ;; Don't close the tab if more windows were created explicitly
+           (< (seq-count (lambda (w)
+                           (memq (car (window-parameter w 'quit-restore))
+                                 '(window tab frame same)))
+                         (window-list-1 nil 'nomini))
+              2))
+      'tab)
      ((frame-root-window-p window)
       ;; WINDOW's frame can be deleted only if there are other frames
       ;; on the same terminal, and it does not contain the active
@@ -5022,6 +5037,10 @@ window--delete
   (unless (and dedicated-only (not (window-dedicated-p window)))
     (let ((deletable (window-deletable-p window)))
       (cond
+       ((eq deletable 'tab)
+        (tab-bar-close-tab)
+        (message "Tab closed after deleting the last window")
+        'tab)
        ((eq deletable 'frame)
 	(let ((frame (window-frame window)))
 	  (cond
@@ -5388,13 +5407,7 @@ quit-restore-window
       ;; If the previously selected window is still alive, select it.
       (window--quit-restore-select-window quit-restore-2))
      ((and (not prev-buffer)
-	   (eq (nth 1 quit-restore) 'tab)
-	   (eq (nth 3 quit-restore) buffer))
-      (tab-bar-close-tab)
-      ;; If the previously selected window is still alive, select it.
-      (window--quit-restore-select-window quit-restore-2))
-     ((and (not prev-buffer)
-	   (or (eq (nth 1 quit-restore) 'frame)
+	   (or (memq (nth 1 quit-restore) '(frame tab))
 	       (and (eq (nth 1 quit-restore) 'window)
 		    ;; If the window has been created on an existing
 		    ;; frame and ended up as the sole window on that