Repository: microsoft/terminal (language: cpp)

Issue:
[1.21 canary] Session restore is restoring to the wrong screen coordinates and window size
Seems like we're off by a DPI scaling factor somewhere?

![image](https://github.com/microsoft/terminal/assets/18356694/81facd8e-f89f-4956-bd17-a3ee145f771c)


`settings`

```json
    "firstWindowPreference": "persistedWindowLayout",
    "initialCols": 80,
    "initialPosition": "-128,383",
    "initialRows": 24,
    "launchMode": "default",
```


`state`:

```json
	"persistedWindowLayouts" : 
	[
		{
			"initialSize" : 
			{
				"height" : 896.0,
				"width" : 1407.0
			},
			"launchMode" : "default",
			"tabLayout" : 
```


oops no `initialPosition`


Discussion / hints:
https://github.com/microsoft/terminal/pull/16598#discussion_r1511519304

Looks like `AppHost::_GetWindowLaunchPosition` is never called 

Fix patch:
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index ff4b6743e69..1749acce26f 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -8,6 +8,7 @@
 #include "RenameWindowRequestedArgs.g.cpp"
 #include "RequestMoveContentArgs.g.cpp"
 #include "RequestReceiveContentArgs.g.cpp"
+#include "LaunchPositionRequest.g.cpp"
 
 #include <filesystem>
 
@@ -1952,6 +1953,12 @@ namespace winrt::TerminalApp::implementation
 
         layout.InitialSize(windowSize);
 
+        // We don't actually know our own position. So we have to ask the window
+        // layer for that.
+        const auto launchPosRequest{ winrt::make<LaunchPositionRequest>() };
+        RequestLaunchPosition.raise(*this, launchPosRequest);
+        layout.InitialPosition(launchPosRequest.Position());
+
         ApplicationState::SharedInstance().AppendPersistedWindowLayout(layout);
     }
 
diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h
index 711d9f7b7ec..0dba78abd4b 100644
--- a/src/cascadia/TerminalApp/TerminalPage.h
+++ b/src/cascadia/TerminalApp/TerminalPage.h
@@ -10,6 +10,7 @@
 #include "RenameWindowRequestedArgs.g.h"
 #include "RequestMoveContentArgs.g.h"
 #include "RequestReceiveContentArgs.g.h"
+#include "LaunchPositionRequest.g.h"
 #include "Toast.h"
 
 #define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
@@ -79,6 +80,13 @@ namespace winrt::TerminalApp::implementation
             _TabIndex{ tabIndex } {};
     };
 
+    struct LaunchPositionRequest : LaunchPositionRequestT<LaunchPositionRequest>
+    {
+        LaunchPositionRequest() = default;
+
+        til::property<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> Position;
+    };
+
     struct TerminalPage : TerminalPageT<TerminalPage>
     {
     public:
@@ -186,6 +194,8 @@ namespace winrt::TerminalApp::implementation
         til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs> RequestMoveContent;
         til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs> RequestReceiveContent;
 
+        til::typed_event<IInspectable, winrt::TerminalApp::LaunchPositionRequest> RequestLaunchPosition;
+
         WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, PropertyChanged.raise, nullptr);
         WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, FrameBrush, PropertyChanged.raise, nullptr);
 
diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl
index 8ec4fa1dc9c..667350056b8 100644
--- a/src/cascadia/TerminalApp/TerminalPage.idl
+++ b/src/cascadia/TerminalApp/TerminalPage.idl
@@ -51,6 +51,11 @@ namespace TerminalApp
         Boolean IsQuakeWindow();
     };
 
+    runtimeclass LaunchPositionRequest
+    {
+        Microsoft.Terminal.Settings.Model.LaunchPosition Position;
+    }
+
     [default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged, Microsoft.Terminal.UI.IDirectKeyListener
     {
         TerminalPage(WindowProperties properties, ContentManager manager);
@@ -98,5 +103,7 @@ namespace TerminalApp
 
         event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
         event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
+
+        event Windows.Foundation.TypedEventHandler<Object, LaunchPositionRequest> RequestLaunchPosition;
     }
 }
diff --git a/src/cascadia/TerminalApp/TerminalWindow.h b/src/cascadia/TerminalApp/TerminalWindow.h
index d48d8d4f242..b10c29a8d72 100644
--- a/src/cascadia/TerminalApp/TerminalWindow.h
+++ b/src/cascadia/TerminalApp/TerminalWindow.h
@@ -231,6 +231,8 @@ namespace winrt::TerminalApp::implementation
         FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
         FORWARDED_TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs, _root, RequestReceiveContent);
 
+        FORWARDED_TYPED_EVENT(RequestLaunchPosition, Windows::Foundation::IInspectable, winrt::TerminalApp::LaunchPositionRequest, _root, RequestLaunchPosition);
+
 #ifdef UNIT_TESTING
         friend class TerminalAppLocalTests::CommandlineTest;
 #endif
diff --git a/src/cascadia/TerminalApp/TerminalWindow.idl b/src/cascadia/TerminalApp/TerminalWindow.idl
index 1700686e1db..75c47fce8bf 100644
--- a/src/cascadia/TerminalApp/TerminalWindow.idl
+++ b/src/cascadia/TerminalApp/TerminalWindow.idl
@@ -137,6 +137,7 @@ namespace TerminalApp
 
         event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
         event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
+        event Windows.Foundation.TypedEventHandler<Object, LaunchPositionRequest> RequestLaunchPosition;
 
         void AttachContent(String content, UInt32 tabIndex);
         void SendContentToOther(RequestReceiveContentArgs args);
diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp
index 0fe39c1cc56..5470db596f5 100644
--- a/src/cascadia/WindowsTerminal/AppHost.cpp
+++ b/src/cascadia/WindowsTerminal/AppHost.cpp
@@ -341,6 +341,7 @@ void AppHost::Initialize()
     _revokers.RaiseVisualBell = _windowLogic.RaiseVisualBell(winrt::auto_revoke, { this, &AppHost::_RaiseVisualBell });
     _revokers.SystemMenuChangeRequested = _windowLogic.SystemMenuChangeRequested(winrt::auto_revoke, { this, &AppHost::_SystemMenuChangeRequested });
     _revokers.ChangeMaximizeRequested = _windowLogic.ChangeMaximizeRequested(winrt::auto_revoke, { this, &AppHost::_ChangeMaximizeRequested });
+    _revokers.RequestLaunchPosition = _windowLogic.RequestLaunchPosition(winrt::auto_revoke, { this, &AppHost::_HandleRequestLaunchPosition });
 
     _windowCallbacks.MaximizeChanged = _window->MaximizeChanged([this](bool newMaximize) {
         if (_windowLogic)
@@ -510,6 +511,14 @@ void AppHost::AppTitleChanged(const winrt::Windows::Foundation::IInspectable& /*
     _windowManager.UpdateActiveTabTitle(newTitle, _peasant);
 }
 
+// The terminal page is responsible for persisting it's own state, but it does
+// need to ask us where exactly on the screen the window is.
+void AppHost::_HandleRequestLaunchPosition(const winrt::Windows::Foundation::IInspectable& /*sender*/,
+                                           winrt::TerminalApp::LaunchPositionRequest args)
+{
+    args.Position(_GetWindowLaunchPosition());
+}
+
 LaunchPosition AppHost::_GetWindowLaunchPosition()
 {
     LaunchPosition pos{};
diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h
index a22fc85a948..cc90c21c1c1 100644
--- a/src/cascadia/WindowsTerminal/AppHost.h
+++ b/src/cascadia/WindowsTerminal/AppHost.h
@@ -160,6 +160,9 @@ class AppHost : public std::enable_shared_from_this<AppHost>
     void _stopFrameTimer();
     void _updateFrameColor(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&);
 
+    void _HandleRequestLaunchPosition(const winrt::Windows::Foundation::IInspectable& sender,
+                                      winrt::TerminalApp::LaunchPositionRequest args);
+
     // Helper struct. By putting these all into one struct, we can revoke them
     // all at once, by assigning _revokers to a fresh Revokers instance. That'll
     // cause us to dtor the old one, which will immediately call revoke on all
@@ -195,6 +198,7 @@ class AppHost : public std::enable_shared_from_this<AppHost>
         winrt::TerminalApp::TerminalWindow::ShowWindowChanged_revoker ShowWindowChanged;
         winrt::TerminalApp::TerminalWindow::RequestMoveContent_revoker RequestMoveContent;
         winrt::TerminalApp::TerminalWindow::RequestReceiveContent_revoker RequestReceiveContent;
+        winrt::TerminalApp::TerminalWindow::RequestLaunchPosition_revoker RequestLaunchPosition;
         winrt::TerminalApp::TerminalWindow::PropertyChanged_revoker PropertyChanged;
         winrt::TerminalApp::TerminalWindow::SettingsChanged_revoker SettingsChanged;
 


Test patch: