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

From: Ship Mints <[email-masked]>
Date: Mon, 31 Mar 2025 07:57:49 -0400

On Mon, Mar 31, 2025 at 3:59 AM martin rudalics <[email-masked]> wrote:

>  > I'm not using the display actions in my configuration and I don't invoke
>  > the tab-bar functions that use it.
>  >
>  > I have two tabs on a newly opened frame.  Both tabs have only one
> window.
>  > If I'm on tab 2, and I eval (kill-buffer), the frame disappears.
>  >
>  >  From inside window-deletable-p: tab-bar-mode=t #tabs=2 quit-restore
>  > parameter=nil window-dedicated-p=nil frame-root-window=t
>
> Can you give us a sequence of function calls that implement the behavior
> you sketch here.  From the text above I don't even understand whether
> this is about tab-bars or tab-lines.  Among others we need to know
> whether the window showing the buffer to be killed is dedicated to it
> and what the value of 'kill-buffer-quit-windows' is.  If the latter is
> non-nil, Emacs will try to call 'quit-restore-window' for any window
> showing that buffer and that function expects a 'quit-restore' parameter
> for that window.
>

I haven't experimented with kill-buffer-quit-windows yet so it's nil for me.

I've spelunked through my use-case state and it's, as usual, hard to tease
out.  Below with -Q reproduces the effect.

(setq kill-buffer-quit-windows nil)
(tab-bar-mode)
(select-frame-set-input-focus (make-frame))
(switch-to-buffer "FOO")
(tab-bar-new-tab)
(switch-to-buffer "BAR")
;; these emulate the effect I see
(set-window-prev-buffers nil nil)
(setq switch-to-prev-buffer-skip #'always)
(kill-buffer) ; frame is deleted when I expect the first tab to remain
intact

If the patch removes the test for window-dedicated-p, it leaves the first
tab in place.  I almost never use dedicated windows outside of a few
packages that do but those haven't been in play vis-a-vis this issue.  I
don't pretend to fully understand what situation w-d-p is intended to deal
with but if we can accommodate both, that'd be fine.

     ((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) ; <==== THIS WORKS BETTER
                    (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)

-Stephane