diff --git a/lisp/window.el b/lisp/window.el index 5822947f2fe..119de1eb38f 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4143,6 +4143,18 @@ 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) + (window-dedicated-p window)) + ;; Don't close the tab if more windows were created explicitly + (< (seq-count (lambda (w) (window-parameter w 'quit-restore)) + (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 @@ -4979,6 +4991,9 @@ 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) + 'tab) ((eq deletable 'frame) (let ((frame (window-frame window))) (cond @@ -5340,13 +5355,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 diff --git a/test/lisp/tab-bar-tests.el b/test/lisp/tab-bar-tests.el index aa8384b24e8..8e8e75ce720 100644 --- a/test/lisp/tab-bar-tests.el +++ b/test/lisp/tab-bar-tests.el @@ -42,10 +42,116 @@ tab-bar-tests-close-other-tabs (should (eq (length tab-bar-closed-tabs) 0))) (ert-deftest tab-bar-tests-close-other-tabs-default () - (tab-bar-tests-close-other-tabs nil)) + (tab-bar-tests-close-other-tabs nil) + ;; Clean up tabs afterwards + (tab-bar-tabs-set nil)) (ert-deftest tab-bar-tests-close-other-tabs-with-arg () - (dotimes (i 5) (tab-bar-tests-close-other-tabs i))) + (dotimes (i 5) (tab-bar-tests-close-other-tabs i)) + ;; Clean up tabs afterwards + (tab-bar-tabs-set nil)) + +(ert-deftest tab-bar-tests-quit-restore-window () + (let* ((frame-params (when noninteractive + '((window-system . nil) + (tty-type . "linux")))) + (pop-up-frame-alist frame-params) + (frame-auto-hide-function 'delete-frame)) + + ;; 1.1. 'quit-restore-window' should delete the frame + ;; from initial window (bug#59862) + (progn + (should (eq (length (frame-list)) 1)) + (other-frame-prefix) + (info) + (should (eq (length (frame-list)) 2)) + (should (equal (buffer-name) "*info*")) + (view-echo-area-messages) + (other-window 1) + (should (eq (length (window-list)) 2)) + (should (equal (buffer-name) "*Messages*")) + (quit-window) + (should (eq (length (window-list)) 1)) + (should (equal (buffer-name) "*info*")) + (quit-window) + (should (eq (length (frame-list)) 1))) + + ;; 1.2. 'quit-restore-window' should not delete the frame + ;; from non-initial window (bug#59862) + (progn + (should (eq (length (frame-list)) 1)) + (other-frame-prefix) + (info) + (should (eq (length (frame-list)) 2)) + (should (equal (buffer-name) "*info*")) + (view-echo-area-messages) + (should (eq (length (window-list)) 2)) + (should (equal (buffer-name) "*info*")) + (quit-window) + (should (eq (length (window-list)) 1)) + (should (eq (length (frame-list)) 2)) + (should (equal (buffer-name) "*Messages*")) + (quit-window) + (should (eq (length (frame-list)) 2)) + ;; Clean up the frame afterwards + (delete-frame)) + + ;; 2.1. 'quit-restore-window' should close the tab + ;; from initial window (bug#59862) + (progn + (should (eq (length (tab-bar-tabs)) 1)) + (other-tab-prefix) + (info) + (should (eq (length (tab-bar-tabs)) 2)) + (should (equal (buffer-name) "*info*")) + (view-echo-area-messages) + (other-window 1) + (should (eq (length (window-list)) 2)) + (should (equal (buffer-name) "*Messages*")) + (quit-window) + (should (eq (length (window-list)) 1)) + (should (equal (buffer-name) "*info*")) + (quit-window) + (should (eq (length (tab-bar-tabs)) 1))) + + ;; 2.2. 'quit-restore-window' should not close the tab + ;; from non-initial window (bug#59862) + (progn + (should (eq (length (tab-bar-tabs)) 1)) + (other-tab-prefix) + (info) + (should (eq (length (tab-bar-tabs)) 2)) + (should (equal (buffer-name) "*info*")) + (view-echo-area-messages) + (should (eq (length (window-list)) 2)) + (should (equal (buffer-name) "*info*")) + (quit-window) + (should (eq (length (window-list)) 1)) + (should (eq (length (tab-bar-tabs)) 2)) + (should (equal (buffer-name) "*Messages*")) + (quit-window) + (should (eq (length (tab-bar-tabs)) 2)) + ;; Clean up the tab afterwards + (tab-close)) + + ;; 3. Don't delete the frame with dedicated window + ;; from the second tab (bug#71386) + (with-selected-frame (make-frame frame-params) + (switch-to-buffer (generate-new-buffer "test1")) + (tab-new) + (switch-to-buffer (generate-new-buffer "test2")) + (set-window-dedicated-p (selected-window) t) + (kill-buffer) + (should (eq (length (frame-list)) 2)) + (should (eq (length (tab-bar-tabs)) 1)) + ;; But now should delete the frame with dedicated window + ;; from the last tab + (set-window-dedicated-p (selected-window) t) + (kill-buffer) + (should (eq (length (frame-list)) 1))) + + ;; Clean up tabs afterwards + (tab-bar-tabs-set nil))) (provide 'tab-bar-tests) ;;; tab-bar-tests.el ends here