Repository: microsoft/terminal (language: cpp)

Issue:
Window layout persisted in `state.json` even if window persistence not enabled
### Windows Terminal version

1.20.11215.0

### Windows build number

10.0.22631.3447

### Other Software

_No response_

### Steps to reproduce

1. Ensure window persistence is turned off
2. Set windows terminal as your default terminal application
3. Go to run and type `cmd /k echo hello world`
4. Close the terminal
5. Inspect `%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\LocalState\state.json`

### Expected Behavior

There is no history of the command that I ran in `state.json`.

### Actual Behavior

`state.json` has leaked my super secret command line invocation!

```json
{
  "persistedWindowLayouts" : 
  [
    {
      "initialPosition" : "234,234",
      "initialSize" : 
      {
        "height" : 436.0,
        "width" : 873.0
      },
      "launchMode" : "default",
      "tabLayout" : 
      [
        {
          "action" : "newTab",
          "commandline" : "\"C:\\WINDOWS\\system32\\cmd.exe\" /k echo hello world",
          "profile" : "Command Prompt",
          "startingDirectory" : "C:\\Users\\Ian",
          "suppressApplicationTitle" : false,
          "tabTitle" : "C:\\WINDOWS\\system32\\cmd.exe"
        }
      ]
    }
  ],
  "settingsHash" : "190f05f1cd1315b4-01d98faa8aecd332"
}
```

This is not reproducible on version 1.19.11213.0.


Discussion / hints:
Oh dear... But #17206 was created a little earlier than this issue, so lets close it in favor of the older one. 🙂 /dup #17206
Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!
<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
I figured they were related, but not quite the same, so opened a separate ticket - given that this pre-dates 1.21.

Fix patch:
diff --git a/src/cascadia/TerminalApp/TerminalWindow.cpp b/src/cascadia/TerminalApp/TerminalWindow.cpp
index 749fd2e842c..c04a34affc9 100644
--- a/src/cascadia/TerminalApp/TerminalWindow.cpp
+++ b/src/cascadia/TerminalApp/TerminalWindow.cpp
@@ -263,7 +263,7 @@ namespace winrt::TerminalApp::implementation
         AppLogic::Current()->NotifyRootInitialized();
     }
 
-    void TerminalWindow::Quit()
+    void TerminalWindow::PersistState()
     {
         if (_root)
         {
diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h
index b10c29a8d72..40e94a39201 100644
--- a/src/cascadia/TerminalApp/TerminalWindow.h
+++ b/src/cascadia/TerminalApp/TerminalWindow.h
@@ -73,7 +73,7 @@ namespace winrt::TerminalApp::implementation
 
         void Create();
 
-        void Quit();
+        void PersistState();
 
         winrt::fire_and_forget UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);
 
diff --git a/src/cascadia/TerminalApp/TerminalWindow.idl b/src/cascadia/TerminalApp/TerminalWindow.idl
index 75c47fce8bf..2cf4b317298 100644
--- a/src/cascadia/TerminalApp/TerminalWindow.idl
+++ b/src/cascadia/TerminalApp/TerminalWindow.idl
@@ -61,7 +61,7 @@ namespace TerminalApp
         Boolean ShouldImmediatelyHandoffToElevated();
         void HandoffToElevated();
 
-        void Quit();
+        void PersistState();
 
         Windows.UI.Xaml.UIElement GetRoot();
 
diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp
index 94585f4391c..63d8de231d3 100644
--- a/src/cascadia/WindowsTerminal/AppHost.cpp
+++ b/src/cascadia/WindowsTerminal/AppHost.cpp
@@ -1184,13 +1184,16 @@ winrt::fire_and_forget AppHost::_QuitRequested(const winrt::Windows::Foundation:
     co_await wil::resume_foreground(_windowLogic.GetRoot().Dispatcher());
 
     const auto strongThis = weakThis.lock();
-    // GH #16235: If we don't have a window logic, we're already refrigerating, and won't have our _window either.
-    if (!strongThis || _windowLogic == nullptr)
+    if (!strongThis)
     {
         co_return;
     }
 
-    _windowLogic.Quit();
+    if (_appLogic && _windowLogic && _appLogic.ShouldUsePersistedLayout())
+    {
+        _windowLogic.PersistState();
+    }
+
     PostQuitMessage(0);
 }
 
diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
index a8f0961e420..1e78e721fd4 100644
--- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp
+++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp
@@ -348,6 +348,14 @@ void WindowEmperor::_becomeMonarch()
 
     _revokers.WindowCreated = _manager.WindowCreated(winrt::auto_revoke, { this, &WindowEmperor::_numberOfWindowsChanged });
     _revokers.WindowClosed = _manager.WindowClosed(winrt::auto_revoke, { this, &WindowEmperor::_numberOfWindowsChanged });
+
+    // If a previous session of Windows Terminal stored buffer_*.txt files, then we need to clean all those up on exit
+    // that aren't needed anymore, even if the user disabled the ShouldUsePersistedLayout() setting in the meantime.
+    {
+        const auto state = ApplicationState::SharedInstance();
+        const auto layouts = state.PersistedWindowLayouts();
+        _requiresPersistenceCleanupOnExit = layouts && layouts.Size() > 0;
+    }
 }
 
 // sender and args are always nullptr
@@ -486,7 +494,7 @@ void WindowEmperor::_finalizeSessionPersistence() const
     // Ensure to write the state.json before we TerminateProcess()
     state.Flush();
 
-    if (!_app.Logic().ShouldUsePersistedLayout())
+    if (!_requiresPersistenceCleanupOnExit)
     {
         return;
     }
diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.h b/src/cascadia/WindowsTerminal/WindowEmperor.h
index a35032e6d5e..d4186cbbb06 100644
--- a/src/cascadia/WindowsTerminal/WindowEmperor.h
+++ b/src/cascadia/WindowsTerminal/WindowEmperor.h
@@ -51,6 +51,7 @@ class WindowEmperor : public std::enable_shared_from_this<WindowEmperor>
 
     std::unique_ptr<NotificationIcon> _notificationIcon;
 
+    bool _requiresPersistenceCleanupOnExit = false;
     bool _quitting{ false };
 
     void _windowStartedHandlerPostXAML(const std::shared_ptr<WindowThread>& sender);


Test patch: