From e1be2f4c73b8a8d55e07a9499a72d7b943ac3fe7 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Wed, 26 Feb 2025 11:05:59 -0800 Subject: [PATCH] Fix persistence of the last closed window (#18623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Does what it says on the tin. Closes #18525 ## Validation Steps Performed * Enable persistence * Close the last window * Persisted ✅ --- .../WindowsTerminal/WindowEmperor.cpp | 49 ++++++++++++++----- src/cascadia/WindowsTerminal/WindowEmperor.h | 1 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index f5a646e991f..6a25256af6f 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -354,7 +354,10 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow) } // If we created no windows, e.g. because the args are "/?" we can just exit now. - _postQuitMessageIfNeeded(); + if (_windows.empty()) + { + _postQuitMessageIfNeeded(); + } } // ALWAYS change the _real_ CWD of the Terminal to system32, @@ -735,9 +738,30 @@ void WindowEmperor::_createMessageWindow(const wchar_t* className) StringCchCopy(_notificationIcon.szTip, ARRAYSIZE(_notificationIcon.szTip), appNameLoc.c_str()); } +// Counterpart to _postQuitMessageIfNeeded: +// If it returns true, don't close that last window, if any. +// This ensures we persist the last window. +bool WindowEmperor::_shouldSkipClosingWindows() const +{ + const auto globalSettings = _app.Logic().Settings().GlobalSettings(); + const size_t windowLimit = globalSettings.ShouldUsePersistedLayout() ? 1 : 0; + return _windows.size() <= windowLimit; +} + +// Posts a WM_QUIT as soon as we have no reason to exist anymore. +// That basically means no windows [^1] and no message boxes. +// +// [^1] Unless: +// * We've been asked to persist the last remaining window +// in which case we exit with 1 remaining window. +// * We're allowed to be headless +// in which case we never exit. void WindowEmperor::_postQuitMessageIfNeeded() const { - if (_messageBoxCount <= 0 && _windows.empty() && !_app.Logic().Settings().GlobalSettings().AllowHeadless()) + const auto globalSettings = _app.Logic().Settings().GlobalSettings(); + const size_t windowLimit = globalSettings.ShouldUsePersistedLayout() ? 1 : 0; + + if (_messageBoxCount <= 0 && _windows.size() <= windowLimit && !globalSettings.AllowHeadless()) { PostQuitMessage(0); } @@ -771,17 +795,20 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c { case WM_CLOSE_TERMINAL_WINDOW: { - const auto host = reinterpret_cast(lParam); - auto it = _windows.begin(); - const auto end = _windows.end(); - - for (; it != end; ++it) + if (!_shouldSkipClosingWindows()) { - if (host == it->get()) + const auto host = reinterpret_cast(lParam); + auto it = _windows.begin(); + const auto end = _windows.end(); + + for (; it != end; ++it) { - host->Close(); - _windows.erase(it); - break; + if (host == it->get()) + { + host->Close(); + _windows.erase(it); + break; + } } } diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.h b/src/cascadia/WindowsTerminal/WindowEmperor.h index ca30159ac2d..7012a7d66ee 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.h +++ b/src/cascadia/WindowsTerminal/WindowEmperor.h @@ -55,6 +55,7 @@ class WindowEmperor safe_void_coroutine _dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args); LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept; void _createMessageWindow(const wchar_t* className); + bool _shouldSkipClosingWindows() const; void _postQuitMessageIfNeeded() const; safe_void_coroutine _showMessageBox(winrt::hstring message, bool error); void _notificationAreaMenuRequested(WPARAM wParam);