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

From: martin rudalics <[email-masked]>
Date: Thu, 3 Apr 2025 11:12:33 +0200

>> IIUC the context is
 >>
 >>        (quit-window)
 >>        (should (eq (length (window-list)) 1))
 >>        (should (eq (length (frame-list)) 2))
 >>        ;; FIXME: uncomment (should (equal (buffer-name) "*Messages*"))
 >>
 >> What is 'quit-window' supposed to do - delete the frame?
 >
 > 'q' is supposed to delete one of two windows and move focus
 > to the remaining window:
 >
 > 1. C-x 5 5 C-h i
 > 2. C-h e
 > 3. q
 >
 > should make the selected window with the buffer *Messages*.
 > And it does when trying the same interactively.
 >
 >> In either case we would have to know which window gets selected when
 >> the 'quit-window' call returns and which buffer it shows.
 >
 > Interactively it selects the *Messages* window, but not in tests.
 > This is because for tests window-system is nil, so it behaves
 > weirdly in noninteractive tests.

The non-interactive behavior is, in some sense, the correct one.  Here
in 'quit-restore-window'

       ;; If the previously selected window is still alive, select it.
       (window--quit-restore-select-window quit-restore-2))

quit-restore-2 is the window on *scratch* and it gets selected
interactively _and_ non-interactively.  The latter tested with

(progn
   (other-frame-prefix)
   (info)
   (view-echo-area-messages)
   (let (window-system)
     (quit-window))
   (buffer-name))

If, in interactive use, instead of "q" you run

(defun foo ()
   (interactive)
   (quit-window)
   (message "%s" (selected-window)))

you will see that 'quit-window' selects *scratch*.  But in interactive
behavior, the *Messages* frame still has input focus and so its window
gets re-selected later.

You get the "correct" interactive behavior with

(defun window--quit-restore-select-window (window)
   "Select WINDOW after having quit another one.
Do not select an inactive minibuffer window."
   (when (and (window-live-p window)
              (or (not (window-minibuffer-p window))
                  (minibuffer-window-active-p window)))
     (let ((frame (window-frame window)))
       (set-frame-selected-window frame window)
       (unless (eq frame (selected-frame))
	(select-frame-set-input-focus frame)))))

but I'm not even sure whether we want it.  And it still won't match the
non-interactive behavior if you can't set frame focus there.

martin