Compare commits

...

3 Commits

Author SHA1 Message Date
Dustin L. Howett
3870d61a6f Merge remote-tracking branch 'origin/release-1.20' into selfhost-1.20 2024-04-16 10:41:57 -05:00
Dustin L. Howett
83bbd2cc1f Pre-merge #17049 (Backport Session Persistence) 2024-04-16 10:33:49 -05:00
Leonard Hecker
d2862a8386 Backport session persistence improvements 2024-04-12 00:57:32 +02:00
43 changed files with 205 additions and 663 deletions

View File

@@ -19,6 +19,7 @@ AFew
AFill
AFX
AHelper
ahicon
ahz
AImpl
AInplace
@@ -227,6 +228,7 @@ commandline
commctrl
commdlg
COMMITID
commoncontrols
componentization
conapi
conareainfo
@@ -283,6 +285,7 @@ convarea
conwinuserrefs
coordnew
COPYCOLOR
COPYFROMRESOURCE
CORESYSTEM
cotaskmem
countof
@@ -578,6 +581,7 @@ EVENTID
eventing
evflags
evt
EXACTSIZEONLY
execd
executionengine
exemain
@@ -603,6 +607,7 @@ FEEF
fesb
FFAF
FFDE
FFFDb
FFrom
fgbg
FGCOLOR
@@ -772,6 +777,7 @@ hhx
HIBYTE
hicon
HIDEWINDOW
HIGHQUALITYSCALE
hinst
HISTORYBUFS
HISTORYNODUP
@@ -821,6 +827,7 @@ hwnd
HWNDPARENT
iccex
ICONERROR
ICONINFO
ICONINFORMATION
IConsole
ICONSTOP
@@ -842,7 +849,11 @@ IGNOREEND
IGNORELANGUAGE
IHosted
iid
IImage
IIo
ILC
ILCo
ILD
ime
IMPEXP
inbox
@@ -1116,8 +1127,8 @@ msix
msrc
MSVCRTD
MTSM
munges
Munged
munges
murmurhash
muxes
myapplet
@@ -1340,11 +1351,14 @@ pgomgr
PGONu
pguid
phhook
phico
phicon
phwnd
pidl
PIDLIST
pids
pii
piml
pinvoke
pipename
pipestr
@@ -1676,6 +1690,8 @@ slpit
SManifest
SMARTQUOTE
SMTO
snapcx
snapcy
SOLIDBOX
Solutiondir
somefile
@@ -1876,8 +1892,8 @@ UINTs
ul
ulcch
uld
uldb
uldash
uldb
ulwave
Unadvise
unattend

View File

@@ -1,5 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "GetWindowLayoutArgs.h"
#include "GetWindowLayoutArgs.g.cpp"

View File

@@ -1,31 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Class Name:
- GetWindowLayoutArgs.h
Abstract:
- This is a helper class for getting the window layout from a peasant.
Depending on if we are running on the monarch or on a peasant we might need
to switch what thread we are executing on. This gives us the option of
either returning the json result synchronously, or as a promise.
--*/
#pragma once
#include "GetWindowLayoutArgs.g.h"
namespace winrt::Microsoft::Terminal::Remoting::implementation
{
struct GetWindowLayoutArgs : public GetWindowLayoutArgsT<GetWindowLayoutArgs>
{
WINRT_PROPERTY(winrt::hstring, WindowLayoutJson, L"");
WINRT_PROPERTY(winrt::Windows::Foundation::IAsyncOperation<winrt::hstring>, WindowLayoutJsonAsync, nullptr)
};
}
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
{
BASIC_FACTORY(GetWindowLayoutArgs);
}

View File

@@ -37,12 +37,6 @@
<ClInclude Include="WindowActivatedArgs.h">
<DependentUpon>Peasant.idl</DependentUpon>
</ClInclude>
<ClInclude Include="GetWindowLayoutArgs.h">
<DependentUpon>Peasant.idl</DependentUpon>
</ClInclude>
<ClInclude Include="QuitAllRequestedArgs.h">
<DependentUpon>Monarch.idl</DependentUpon>
</ClInclude>
<ClInclude Include="pch.h" />
<ClInclude Include="MonarchFactory.h" />
<ClInclude Include="Peasant.h">
@@ -78,12 +72,6 @@
<ClCompile Include="WindowActivatedArgs.cpp">
<DependentUpon>Peasant.idl</DependentUpon>
</ClCompile>
<ClCompile Include="GetWindowLayoutArgs.cpp">
<DependentUpon>Peasant.idl</DependentUpon>
</ClCompile>
<ClCompile Include="QuitAllRequestedArgs.cpp">
<DependentUpon>Monarch.idl</DependentUpon>
</ClCompile>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>

View File

@@ -6,7 +6,6 @@
#include "Monarch.h"
#include "CommandlineArgs.h"
#include "FindTargetWindowArgs.h"
#include "QuitAllRequestedArgs.h"
#include "ProposeCommandlineResult.h"
#include "Monarch.g.cpp"
@@ -135,21 +134,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// - <none> used
// Return Value:
// - <none>
winrt::fire_and_forget Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
void Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/)
{
// Let the process hosting the monarch run any needed logic before
// closing all windows.
auto args = winrt::make_self<implementation::QuitAllRequestedArgs>();
_QuitAllRequestedHandlers(*this, *args);
if (const auto action = args->BeforeQuitAllAction())
if (_quitting.exchange(true, std::memory_order_relaxed))
{
co_await action;
return;
}
_quitting.store(true);
// Tell all peasants to exit.
const auto callback = [&](const auto& id, const auto& p) {
// We want to tell our peasant to quit last, so that we don't try
// to perform a bunch of elections on quit.
@@ -197,7 +188,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
// If we are quitting we don't care about maintaining our list of
// peasants anymore, and don't need to notify the host that something
// changed.
if (_quitting.load(std::memory_order_acquire))
if (_quitting.load(std::memory_order_relaxed))
{
return;
}
@@ -1036,30 +1027,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
_forEachPeasant(func, onError);
}
// Method Description:
// - Ask all peasants to return their window layout as json
// Arguments:
// - <none>
// Return Value:
// - The collection of window layouts from each peasant.
Windows::Foundation::Collections::IVector<winrt::hstring> Monarch::GetAllWindowLayouts()
{
std::vector<winrt::hstring> vec;
auto callback = [&](const auto& /*id*/, const auto& p) {
vec.emplace_back(p.GetWindowLayout());
};
auto onError = [](auto&& id) {
TraceLoggingWrite(g_hRemotingProvider,
"Monarch_GetAllWindowLayouts_Failed",
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not get a window layout from"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
};
_forEachPeasant(callback, onError);
return winrt::single_threaded_vector(std::move(vec));
}
void Monarch::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex,

View File

@@ -96,7 +96,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void SummonAllWindows();
bool DoesQuakeWindowExist();
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, const Windows::Foundation::IReference<Windows::Foundation::Rect>& windowBounds);
void RequestSendContent(const Remoting::RequestReceiveContentArgs& args);
@@ -106,8 +105,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
private:
@@ -146,8 +143,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
winrt::fire_and_forget _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args);
void _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args);
// Method Description:
// - Helper for doing something on each and every peasant.

View File

@@ -46,11 +46,6 @@ namespace Microsoft.Terminal.Remoting
Windows.Foundation.IReference<UInt64> WindowID;
}
[default_interface] runtimeclass QuitAllRequestedArgs {
QuitAllRequestedArgs();
Windows.Foundation.IAsyncAction BeforeQuitAllAction;
}
struct PeasantInfo
{
UInt64 Id;
@@ -72,7 +67,6 @@ namespace Microsoft.Terminal.Remoting
void SummonAllWindows();
Boolean DoesQuakeWindowExist();
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
void RequestMoveContent(String window, String content, UInt32 tabIndex, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
void RequestSendContent(RequestReceiveContentArgs args);
@@ -82,7 +76,6 @@ namespace Microsoft.Terminal.Remoting
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
event Windows.Foundation.TypedEventHandler<Object, WindowRequestedArgs> RequestNewWindow;
};

View File

@@ -5,7 +5,6 @@
#include "Peasant.h"
#include "CommandlineArgs.h"
#include "SummonWindowBehavior.h"
#include "GetWindowLayoutArgs.h"
#include "Peasant.g.cpp"
#include "../../types/inc/utils.hpp"
#include "AttachRequest.g.cpp"
@@ -309,26 +308,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
// Method Description:
// - Request and return the window layout from the current TerminalPage
// Arguments:
// - <none>
// Return Value:
// - the window layout as a json string
hstring Peasant::GetWindowLayout()
{
auto args = winrt::make_self<implementation::GetWindowLayoutArgs>();
_GetWindowLayoutRequestedHandlers(nullptr, *args);
if (const auto op = args->WindowLayoutJsonAsync())
{
// This will fail if called on the UI thread, so the monarch should
// never set WindowLayoutJsonAsync.
auto str = op.get();
return str;
}
return args->WindowLayoutJson();
}
void Peasant::SendContent(const Remoting::RequestReceiveContentArgs& args)
{
_SendContentRequestedHandlers(*this, args);

View File

@@ -65,7 +65,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
winrt::hstring GetWindowLayout();
void SendContent(const winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs& args);
WINRT_PROPERTY(winrt::hstring, WindowName);
@@ -82,7 +81,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);

View File

@@ -32,12 +32,6 @@ namespace Microsoft.Terminal.Remoting
Windows.Foundation.DateTime ActivatedTime { get; };
};
[default_interface] runtimeclass GetWindowLayoutArgs {
GetWindowLayoutArgs();
String WindowLayoutJson;
Windows.Foundation.IAsyncOperation<String> WindowLayoutJsonAsync;
}
enum MonitorBehavior
{
InPlace,
@@ -88,7 +82,6 @@ namespace Microsoft.Terminal.Remoting
void RequestHideNotificationIcon();
void RequestQuitAll();
void Quit();
String GetWindowLayout();
void AttachContentToWindow(AttachRequest request);
void SendContent(RequestReceiveContentArgs args);
@@ -102,7 +95,6 @@ namespace Microsoft.Terminal.Remoting
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;

View File

@@ -1,5 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "QuitAllRequestedArgs.h"
#include "QuitAllRequestedArgs.g.cpp"

View File

@@ -1,29 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Class Name:
- QuitAllRequestedArgs.h
Abstract:
- This is a helper class for allowing the monarch to run code before telling all
peasants to quit. This way the monarch can raise an event and get back a future
to wait for before continuing.
--*/
#pragma once
#include "QuitAllRequestedArgs.g.h"
namespace winrt::Microsoft::Terminal::Remoting::implementation
{
struct QuitAllRequestedArgs : public QuitAllRequestedArgsT<QuitAllRequestedArgs>
{
WINRT_PROPERTY(winrt::Windows::Foundation::IAsyncAction, BeforeQuitAllAction, nullptr)
};
}
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
{
BASIC_FACTORY(QuitAllRequestedArgs);
}

View File

@@ -92,8 +92,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
_monarch.WindowCreated({ get_weak(), &WindowManager::_WindowCreatedHandlers });
_monarch.WindowClosed({ get_weak(), &WindowManager::_WindowClosedHandlers });
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
_monarch.RequestNewWindow({ get_weak(), &WindowManager::_raiseRequestNewWindow });
}
@@ -356,8 +354,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
_monarch.AddPeasant(*p);
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
TraceLoggingWrite(g_hRemotingProvider,
"WindowManager_CreateOurPeasant",
TraceLoggingUInt64(p->GetID(), "peasantID", "The ID of our new peasant"),
@@ -412,18 +408,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return 0;
}
// Method Description:
// - Ask the monarch to quit all windows.
// Arguments:
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget WindowManager::RequestQuitAll(Remoting::Peasant peasant)
{
co_await winrt::resume_background();
peasant.RequestQuitAll();
}
bool WindowManager::DoesQuakeWindowExist()
{
return _monarch.DoesQuakeWindowExist();
@@ -434,19 +418,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::get_self<implementation::Peasant>(peasant)->ActiveTabTitle(title);
}
Windows::Foundation::Collections::IVector<winrt::hstring> WindowManager::GetAllWindowLayouts()
{
if (_monarch)
{
try
{
return _monarch.GetAllWindowLayouts();
}
CATCH_LOG()
}
return nullptr;
}
winrt::fire_and_forget WindowManager::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex,

View File

@@ -38,10 +38,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
uint64_t GetNumberOfPeasants();
static winrt::fire_and_forget RequestQuitAll(Remoting::Peasant peasant);
void UpdateActiveTabTitle(const winrt::hstring& title, const Remoting::Peasant& peasant);
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
bool DoesQuakeWindowExist();
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
@@ -51,9 +49,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
private:

View File

@@ -14,12 +14,10 @@ namespace Microsoft.Terminal.Remoting
void SignalClose(Peasant p);
void UpdateActiveTabTitle(String title, Peasant p);
static void RequestQuitAll(Peasant p);
void SummonWindow(SummonWindowSelectionArgs args);
void SummonAllWindows();
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos();
UInt64 GetNumberOfPeasants();
@@ -33,8 +31,6 @@ namespace Microsoft.Terminal.Remoting
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowClosed;
event Windows.Foundation.TypedEventHandler<Object, QuitAllRequestedArgs> QuitAllRequested;
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
event Windows.Foundation.TypedEventHandler<Object, WindowRequestedArgs> RequestNewWindow;

View File

@@ -124,8 +124,7 @@ namespace winrt::TerminalApp::implementation
return appLogic->GetSettings();
}
AppLogic::AppLogic() :
_reloadState{ std::chrono::milliseconds(100), []() { ApplicationState::SharedInstance().Reload(); } }
AppLogic::AppLogic()
{
// For your own sanity, it's better to do setup outside the ctor.
// If you do any setup in the ctor that ends up throwing an exception,
@@ -327,10 +326,6 @@ namespace winrt::TerminalApp::implementation
{
_reloadSettings->Run();
}
else if (ApplicationState::SharedInstance().IsStatePath(modifiedBasename))
{
_reloadState();
}
});
}
@@ -702,22 +697,6 @@ namespace winrt::TerminalApp::implementation
return _settings.GlobalSettings().ShouldUsePersistedLayout();
}
void AppLogic::SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector<hstring>& layouts)
{
std::vector<WindowLayout> converted;
converted.reserve(layouts.Size());
for (const auto& json : layouts)
{
if (json != L"")
{
converted.emplace_back(WindowLayout::FromJson(json));
}
}
ApplicationState::SharedInstance().PersistedWindowLayouts(winrt::single_threaded_vector(std::move(converted)));
}
TerminalApp::ParseCommandlineResult AppLogic::GetParseCommandlineMessage(array_view<const winrt::hstring> args)
{
::TerminalApp::AppCommandlineArgs _appArgs;

View File

@@ -53,9 +53,7 @@ namespace winrt::TerminalApp::implementation
void NotifyRootInitialized();
bool HasSettingsStartupActions() const noexcept;
bool ShouldUsePersistedLayout() const;
void SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector<hstring>& layouts);
[[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept;
@@ -91,7 +89,6 @@ namespace winrt::TerminalApp::implementation
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
til::throttled_func_trailing<> _reloadState;
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};

View File

@@ -37,7 +37,6 @@ namespace TerminalApp
Boolean HasSettingsStartupActions();
Boolean ShouldUsePersistedLayout();
void SaveWindowLayoutJsons(Windows.Foundation.Collections.IVector<String> layouts);
void ReloadSettings();

View File

@@ -19,7 +19,7 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
using namespace winrt::TerminalApp;
using namespace TerminalApp;
using namespace winrt::TerminalApp::implementation;
static const int PaneBorderSize = 2;
static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
@@ -124,7 +124,7 @@ void Pane::_removeControlEvents()
// terminal args.
// Return Value:
// - Arguments appropriate for a SplitPane or NewTab action
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
NewTerminalArgs Pane::GetTerminalArgsForPane(BuildStartupKind kind) const
{
// Leaves are the only things that have controls
assert(_IsLeaf());
@@ -169,12 +169,17 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
// object. That would work for schemes set by the Terminal, but not ones set
// by VT, but that seems good enough.
// Only fill in the ContentId if absolutely needed. If you fill in a number
// here (even 0), we'll serialize that number, AND treat that action as an
// "attach existing" rather than a "create"
if (asContent)
switch (kind)
{
case BuildStartupKind::Content:
case BuildStartupKind::MovePane:
// Only fill in the ContentId if absolutely needed. If you fill in a number
// here (even 0), we'll serialize that number, AND treat that action as an
// "attach existing" rather than a "create"
args.ContentId(_control.ContentId());
break;
default:
break;
}
return args;
@@ -200,16 +205,13 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
// - The state from building the startup actions, includes a vector of commands,
// the original root pane, the id of the focused pane, and the number of panes
// created.
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId,
uint32_t nextId,
const bool asContent,
const bool asMovePane)
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId, BuildStartupKind kind)
{
// Normally, if we're a leaf, return an empt set of actions, because the
// parent pane will build the SplitPane action for us. If we're building
// actions for a movePane action though, we'll still need to include
// ourselves.
if (!asMovePane && _IsLeaf())
if (kind != BuildStartupKind::MovePane && _IsLeaf())
{
if (_lastActive)
{
@@ -223,18 +225,18 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId,
auto buildSplitPane = [&](auto newPane) {
ActionAndArgs actionAndArgs;
actionAndArgs.Action(ShortcutAction::SplitPane);
const auto terminalArgs{ newPane->GetTerminalArgsForPane(asContent) };
const auto terminalArgs{ newPane->GetTerminalArgsForPane(kind) };
// When creating a pane the split size is the size of the new pane
// and not position.
const auto splitDirection = _splitState == SplitState::Horizontal ? SplitDirection::Down : SplitDirection::Right;
const auto splitSize = (asContent && _IsLeaf() ? .5 : 1. - _desiredSplitPosition);
const auto splitSize = (kind != BuildStartupKind::None && _IsLeaf() ? .5 : 1. - _desiredSplitPosition);
SplitPaneArgs args{ SplitType::Manual, splitDirection, splitSize, terminalArgs };
actionAndArgs.Args(args);
return actionAndArgs;
};
if (asContent && _IsLeaf())
if (kind != BuildStartupKind::None && _IsLeaf())
{
return {
.args = { buildSplitPane(shared_from_this()) },
@@ -281,10 +283,10 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId,
// We now need to execute the commands for each side of the tree
// We've done one split, so the first-most child will have currentId, and the
// one after it will be incremented.
auto firstState = _firstChild->BuildStartupActions(currentId, nextId + 1);
auto firstState = _firstChild->BuildStartupActions(currentId, nextId + 1, kind);
// the next id for the second branch depends on how many splits were in the
// first child.
auto secondState = _secondChild->BuildStartupActions(nextId, nextId + firstState.panesCreated + 1);
auto secondState = _secondChild->BuildStartupActions(nextId, nextId + firstState.panesCreated + 1, kind);
std::vector<ActionAndArgs> actions{};
actions.reserve(firstState.args.size() + secondState.args.size() + 3);

View File

@@ -31,6 +31,7 @@ namespace TerminalAppLocalTests
namespace winrt::TerminalApp::implementation
{
struct TerminalTab;
enum class BuildStartupKind;
}
enum class Borders : int
@@ -99,8 +100,8 @@ public:
std::optional<uint32_t> focusedPaneId;
uint32_t panesCreated;
};
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, winrt::TerminalApp::implementation::BuildStartupKind kind);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(winrt::TerminalApp::implementation::BuildStartupKind kind) const;
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);

View File

@@ -57,7 +57,7 @@ namespace winrt::TerminalApp::implementation
// re-evaluate including that arg in this action then.
// Return Value:
// - The list of actions.
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(BuildStartupKind) const
{
ASSERT_UI_THREAD();

View File

@@ -30,7 +30,7 @@ namespace winrt::TerminalApp::implementation
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const override;
private:
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;

View File

@@ -12,6 +12,14 @@ namespace TerminalAppLocalTests
namespace winrt::TerminalApp::implementation
{
enum class BuildStartupKind
{
None,
Content,
MovePane,
Persist,
};
struct TabBase : TabBaseT<TabBase>
{
public:
@@ -22,7 +30,7 @@ namespace winrt::TerminalApp::implementation
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const = 0;
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const = 0;
virtual std::optional<winrt::Windows::UI::Color> GetTabColor();
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,

View File

@@ -428,7 +428,7 @@ namespace winrt::TerminalApp::implementation
}
auto t = winrt::get_self<implementation::TabBase>(tab);
auto actions = t->BuildStartupActions();
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
_RemoveTab(tab);
@@ -485,7 +485,7 @@ namespace winrt::TerminalApp::implementation
// if the user manually closed all tabs.
// Do this only if we are the last window; the monarch will notice
// we are missing and remove us that way otherwise.
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
_CloseWindowRequestedHandlers(*this, nullptr);
}
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
{
@@ -766,11 +766,11 @@ namespace winrt::TerminalApp::implementation
// This doesn't handle refocusing anything in particular, the
// result will be that the last pane created is focused. In the
// case of a single pane that is the desired behavior anyways.
auto state = pane->BuildStartupActions(0, 1);
auto state = pane->BuildStartupActions(0, 1, BuildStartupKind::None);
{
ActionAndArgs splitPaneAction{};
splitPaneAction.Action(ShortcutAction::SplitPane);
SplitPaneArgs splitPaneArgs{ SplitDirection::Automatic, state.firstPane->GetTerminalArgsForPane() };
SplitPaneArgs splitPaneArgs{ SplitDirection::Automatic, state.firstPane->GetTerminalArgsForPane(BuildStartupKind::None) };
splitPaneAction.Args(splitPaneArgs);
state.args.emplace(state.args.begin(), std::move(splitPaneAction));
@@ -1138,12 +1138,4 @@ namespace winrt::TerminalApp::implementation
{
return _tabs.Size() > 1;
}
void TerminalPage::_RemoveAllTabs()
{
// Since _RemoveTabs is asynchronous, create a snapshot of the tabs we want to remove
std::vector<winrt::TerminalApp::TabBase> tabsToRemove;
std::copy(begin(_tabs), end(_tabs), std::back_inserter(tabsToRemove));
_RemoveTabs(tabsToRemove);
}
}

View File

@@ -5,7 +5,6 @@
#include "pch.h"
#include "TerminalPage.h"
#include "TerminalPage.g.cpp"
#include "LastTabClosedEventArgs.g.cpp"
#include "RenameWindowRequestedArgs.g.cpp"
#include "RequestMoveContentArgs.g.cpp"
#include "RequestReceiveContentArgs.g.cpp"
@@ -654,9 +653,9 @@ namespace winrt::TerminalApp::implementation
// GH#12267: Make sure that we don't instantly close ourselves when
// we're readying to accept a defterm connection. In that case, we don't
// have a tab yet, but will once we're initialized.
if (_tabs.Size() == 0 && !(_shouldStartInboundListener || _isEmbeddingInboundListener))
if (_tabs.Size() == 0 && !_shouldStartInboundListener && !_isEmbeddingInboundListener)
{
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(false));
_CloseWindowRequestedHandlers(*this, nullptr);
co_return;
}
else
@@ -1900,19 +1899,11 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Saves the window position and tab layout to the application state
// - This does not create the InitialPosition field, that needs to be
// added externally.
// Arguments:
// - <none>
// Return Value:
// - the window layout
WindowLayout TerminalPage::GetWindowLayout()
void TerminalPage::PersistState()
{
if (_startupState != StartupState::Initialized)
{
return nullptr;
return;
}
std::vector<ActionAndArgs> actions;
@@ -1920,7 +1911,7 @@ namespace winrt::TerminalApp::implementation
for (auto tab : _tabs)
{
auto t = winrt::get_self<implementation::TabBase>(tab);
auto tabActions = t->BuildStartupActions();
auto tabActions = t->BuildStartupActions(BuildStartupKind::Persist);
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
}
@@ -1947,7 +1938,7 @@ namespace winrt::TerminalApp::implementation
actions.emplace_back(std::move(action));
}
WindowLayout layout{};
WindowLayout layout;
layout.TabLayout(winrt::single_threaded_vector<ActionAndArgs>(std::move(actions)));
auto mode = LaunchMode::DefaultMode;
@@ -1964,20 +1955,15 @@ namespace winrt::TerminalApp::implementation
layout.InitialSize(windowSize);
return layout;
ApplicationState::SharedInstance().AppendPersistedWindowLayout(layout);
}
// Method Description:
// - Close the terminal app. If there is more
// than one tab opened, show a warning dialog.
// Arguments:
// - bypassDialog: if true a dialog won't be shown even if the user would
// normally get confirmation. This is used in the case where the user
// has already been prompted by the Quit action.
fire_and_forget TerminalPage::CloseWindow(bool bypassDialog)
fire_and_forget TerminalPage::CloseWindow()
{
if (!bypassDialog &&
_HasMultipleTabs() &&
if (_HasMultipleTabs() &&
_settings.GlobalSettings().ConfirmCloseAllTabs() &&
!_displayingCloseDialog)
{
@@ -1996,15 +1982,7 @@ namespace winrt::TerminalApp::implementation
}
}
if (_settings.GlobalSettings().ShouldUsePersistedLayout())
{
// Don't delete the ApplicationState when all of the tabs are removed.
// If there is still a monarch living they will get the event that
// a window closed and trigger a new save without this window.
_maintainStateOnTabClose = true;
}
_RemoveAllTabs();
_CloseWindowRequestedHandlers(*this, nullptr);
}
// Method Description:
@@ -2066,7 +2044,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto pane{ terminalTab->GetActivePane() })
{
auto startupActions = pane->BuildStartupActions(0, 1, true, true);
auto startupActions = pane->BuildStartupActions(0, 1, BuildStartupKind::MovePane);
_DetachPaneFromWindow(pane);
_MoveContent(std::move(startupActions.args), windowId, tabIdx);
focusedTab->DetachPane();
@@ -2208,7 +2186,7 @@ namespace winrt::TerminalApp::implementation
if (tab)
{
auto startupActions = tab->BuildStartupActions(true);
auto startupActions = tab->BuildStartupActions(BuildStartupKind::Content);
_DetachTabFromWindow(tab);
_MoveContent(std::move(startupActions), windowId, 0);
_RemoveTab(*tab);
@@ -5135,7 +5113,7 @@ namespace winrt::TerminalApp::implementation
const uint32_t tabIndex,
std::optional<til::point> dragPoint)
{
auto startupActions = _stashed.draggedTab->BuildStartupActions(true);
auto startupActions = _stashed.draggedTab->BuildStartupActions(BuildStartupKind::Content);
_DetachTabFromWindow(_stashed.draggedTab);
_MoveContent(std::move(startupActions), windowId, tabIndex, dragPoint);

View File

@@ -7,7 +7,6 @@
#include "TerminalTab.h"
#include "AppKeyBindings.h"
#include "AppCommandlineArgs.h"
#include "LastTabClosedEventArgs.g.h"
#include "RenameWindowRequestedArgs.g.h"
#include "RequestMoveContentArgs.g.h"
#include "RequestReceiveContentArgs.g.h"
@@ -44,15 +43,6 @@ namespace winrt::TerminalApp::implementation
ScrollDown = 1
};
struct LastTabClosedEventArgs : LastTabClosedEventArgsT<LastTabClosedEventArgs>
{
WINRT_PROPERTY(bool, ClearPersistedState);
public:
LastTabClosedEventArgs(const bool& shouldClear) :
_ClearPersistedState{ shouldClear } {};
};
struct RenameWindowRequestedArgs : RenameWindowRequestedArgsT<RenameWindowRequestedArgs>
{
WINRT_PROPERTY(winrt::hstring, ProposedName);
@@ -105,7 +95,6 @@ namespace winrt::TerminalApp::implementation
bool ShouldImmediatelyHandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
hstring Title();
@@ -121,7 +110,8 @@ namespace winrt::TerminalApp::implementation
SuggestionsControl LoadSuggestionsUI();
winrt::fire_and_forget RequestQuit();
winrt::fire_and_forget CloseWindow(bool bypassDialog);
winrt::fire_and_forget CloseWindow();
void PersistState();
void ToggleFocusMode();
void ToggleFullscreen();
@@ -175,7 +165,7 @@ namespace winrt::TerminalApp::implementation
// -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(TitleChanged, IInspectable, winrt::hstring);
TYPED_EVENT(LastTabClosed, IInspectable, winrt::TerminalApp::LastTabClosedEventArgs);
TYPED_EVENT(CloseWindowRequested, IInspectable, IInspectable);
TYPED_EVENT(SetTitleBarContent, IInspectable, winrt::Windows::UI::Xaml::UIElement);
TYPED_EVENT(FocusModeChanged, IInspectable, IInspectable);
TYPED_EVENT(FullscreenChanged, IInspectable, IInspectable);
@@ -232,7 +222,6 @@ namespace winrt::TerminalApp::implementation
std::optional<uint32_t> _loadFromPersistedLayoutIdx{};
bool _maintainStateOnTabClose{ false };
bool _rearranging{ false };
std::optional<int> _rearrangeFrom{};
std::optional<int> _rearrangeTo{};
@@ -349,7 +338,6 @@ namespace winrt::TerminalApp::implementation
void _DismissTabContextMenus();
void _FocusCurrentTab(const bool focusAlways);
bool _HasMultipleTabs() const;
void _RemoveAllTabs();
void _SelectNextTab(const bool bMoveRight, const Windows::Foundation::IReference<Microsoft::Terminal::Settings::Model::TabSwitcherMode>& customTabSwitcherMode);
bool _SelectTab(uint32_t tabIndex);

View File

@@ -15,11 +15,6 @@ namespace TerminalApp
void Detach(Microsoft.Terminal.Control.TermControl control);
}
[default_interface] runtimeclass LastTabClosedEventArgs
{
Boolean ClearPersistedState { get; };
};
[default_interface] runtimeclass RenameWindowRequestedArgs
{
String ProposedName { get; };
@@ -87,7 +82,7 @@ namespace TerminalApp
void SendContentToOther(RequestReceiveContentArgs args);
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;

View File

@@ -427,18 +427,18 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - A vector of commands
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(const bool asContent) const
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(BuildStartupKind kind) const
{
ASSERT_UI_THREAD();
// Give initial ids (0 for the child created with this tab,
// 1 for the child after the first split.
auto state = _rootPane->BuildStartupActions(0, 1, asContent);
auto state = _rootPane->BuildStartupActions(0, 1, kind);
{
ActionAndArgs newTabAction{};
newTabAction.Action(ShortcutAction::NewTab);
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) };
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(kind) };
newTabAction.Args(newTabArgs);
state.args.emplace(state.args.begin(), std::move(newTabAction));

View File

@@ -78,7 +78,7 @@ namespace winrt::TerminalApp::implementation
void EnterZoom();
void ExitZoom();
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(BuildStartupKind kind) const override;
int GetLeafPaneCount() const noexcept;

View File

@@ -267,7 +267,7 @@ namespace winrt::TerminalApp::implementation
{
if (_root)
{
_root->CloseWindow(true);
_root->PersistState();
}
}
@@ -916,32 +916,11 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
void TerminalWindow::CloseWindow(LaunchPosition pos, const bool isLastWindow)
void TerminalWindow::CloseWindow()
{
if (_root)
{
// If persisted layout is enabled and we are the last window closing
// we should save our state.
if (_settings.GlobalSettings().ShouldUsePersistedLayout() && isLastWindow)
{
if (const auto layout = _root->GetWindowLayout())
{
layout.InitialPosition(pos);
const auto state = ApplicationState::SharedInstance();
state.PersistedWindowLayouts(winrt::single_threaded_vector<WindowLayout>({ layout }));
}
}
_root->CloseWindow(false);
}
}
void TerminalWindow::ClearPersistedWindowState()
{
if (_settings.GlobalSettings().ShouldUsePersistedLayout())
{
auto state = ApplicationState::SharedInstance();
state.PersistedWindowLayouts(nullptr);
_root->CloseWindow();
}
}
@@ -1134,19 +1113,6 @@ namespace winrt::TerminalApp::implementation
return winrt::to_hstring(_appArgs.GetExitMessage());
}
hstring TerminalWindow::GetWindowLayoutJson(LaunchPosition position)
{
if (_root != nullptr)
{
if (const auto layout = _root->GetWindowLayout())
{
layout.InitialPosition(position);
return WindowLayout::ToJson(layout);
}
}
return L"";
}
void TerminalWindow::SetPersistedLayoutIdx(const uint32_t idx)
{
_loadFromPersistedLayoutIdx = idx;

View File

@@ -95,8 +95,6 @@ namespace winrt::TerminalApp::implementation
bool AlwaysOnTop() const;
bool AutoHideWindow();
hstring GetWindowLayoutJson(Microsoft::Terminal::Settings::Model::LaunchPosition position);
void IdentifyWindow();
void RenameFailed();
@@ -104,9 +102,6 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::WindowLayout LoadPersistedLayout();
void SetPersistedLayoutIdx(const uint32_t idx);
void SetNumberOfOpenWindows(const uint64_t num);
bool ShouldUsePersistedLayout() const;
void ClearPersistedWindowState();
void RequestExitFullscreen();
@@ -125,7 +120,7 @@ namespace winrt::TerminalApp::implementation
void TitlebarClicked();
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position, const bool isLastWindow);
void CloseWindow();
void WindowVisibilityChanged(const bool showOrHide);
winrt::TerminalApp::TaskbarState TaskbarState();
@@ -215,7 +210,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(SetTitleBarContent, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::UIElement, _root, SetTitleBarContent);
FORWARDED_TYPED_EVENT(TitleChanged, winrt::Windows::Foundation::IInspectable, winrt::hstring, _root, TitleChanged);
FORWARDED_TYPED_EVENT(LastTabClosed, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs, _root, LastTabClosed);
FORWARDED_TYPED_EVENT(CloseWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, CloseWindowRequested);
FORWARDED_TYPED_EVENT(FocusModeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FocusModeChanged);
FORWARDED_TYPED_EVENT(FullscreenChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FullscreenChanged);
FORWARDED_TYPED_EVENT(ChangeMaximizeRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, ChangeMaximizeRequested);

View File

@@ -75,7 +75,6 @@ namespace TerminalApp
void IdentifyWindow();
void SetPersistedLayoutIdx(UInt32 idx);
void ClearPersistedWindowState();
void RenameFailed();
void RequestExitFullscreen();
@@ -90,7 +89,7 @@ namespace TerminalApp
Boolean GetInitialAlwaysOnTop();
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
void TitlebarClicked();
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position, Boolean isLastWindow);
void CloseWindow();
void WindowVisibilityChanged(Boolean showOrHide);
TaskbarState TaskbarState{ get; };
@@ -98,8 +97,6 @@ namespace TerminalApp
Windows.UI.Xaml.Media.Brush FrameBrush { get; };
void WindowActivated(Boolean activated);
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
Boolean GetMinimizeToNotificationArea();
Boolean GetAlwaysShowNotificationIcon();
Boolean GetShowTitleInTitlebar();
@@ -119,7 +116,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;

View File

@@ -117,7 +117,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
private:
Model::Profile _profile;
winrt::guid _originalProfileGuid;
winrt::guid _originalProfileGuid{};
winrt::hstring _lastBgImagePath;
winrt::hstring _lastStartingDirectoryPath;
Editor::AppearanceViewModel _defaultAppearanceViewModel;

View File

@@ -102,34 +102,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// The destructor ensures that the last write is flushed to disk before returning.
ApplicationState::~ApplicationState()
{
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_Start",
TraceLoggingDescription("Event at the start of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
Flush();
}
void ApplicationState::Flush()
{
// This will ensure that we not just cancel the last outstanding timer,
// but instead force it to run as soon as possible and wait for it to complete.
_throttler.flush();
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_End",
TraceLoggingDescription("Event at the end of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
// Re-read the state.json from disk.
void ApplicationState::Reload() const noexcept
{
_read();
}
bool ApplicationState::IsStatePath(const winrt::hstring& filename)
{
static const auto sharedPath{ _sharedPath.filename() };
static const auto elevatedPath{ _elevatedPath.filename() };
return filename == sharedPath || filename == elevatedPath;
}
// Method Description:
@@ -260,8 +240,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Returns the application-global ApplicationState object.
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance()
{
auto root{ GetBaseSettingsPath() };
static auto state = winrt::make_self<ApplicationState>(root);
static auto state = winrt::make_self<ApplicationState>(GetBaseSettingsPath());
return *state;
}
@@ -299,7 +278,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Json::Value ApplicationState::_toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept
{
{
auto state = _state.lock_shared();
const auto state = _state.lock_shared();
// GH#11222: We only write properties that are of the same type (Local
// or Shared) which we requested. If we didn't want to serialize this
@@ -314,6 +293,20 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return root;
}
void ApplicationState::AppendPersistedWindowLayout(Model::WindowLayout layout)
{
{
const auto state = _state.lock();
if (!state->PersistedWindowLayouts || !*state->PersistedWindowLayouts)
{
state->PersistedWindowLayouts = winrt::single_threaded_vector<Model::WindowLayout>();
}
state->PersistedWindowLayouts->Append(std::move(layout));
}
_throttler();
}
// Generate all getter/setters
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
type ApplicationState::name() const noexcept \
@@ -326,7 +319,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void ApplicationState::name(const type& value) noexcept \
{ \
{ \
auto state = _state.lock(); \
const auto state = _state.lock(); \
state->name.emplace(value); \
} \
\

View File

@@ -63,14 +63,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
~ApplicationState();
// Methods
void Reload() const noexcept;
void Flush();
void Reset() noexcept;
void FromJson(const Json::Value& root, FileSource parseSource) const noexcept;
Json::Value ToJson(FileSource parseSource) const noexcept;
// General getters/setters
bool IsStatePath(const winrt::hstring& filename);
void AppendPersistedWindowLayout(Model::WindowLayout layout);
// State getters/setters
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \

View File

@@ -29,10 +29,10 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass ApplicationState {
static ApplicationState SharedInstance();
void Reload();
void Flush();
void Reset();
Boolean IsStatePath(String filename);
void AppendPersistedWindowLayout(WindowLayout layout);
String SettingsHash;
Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts;

View File

@@ -410,7 +410,7 @@ bool SettingsLoader::FixupUserSettings()
{
struct CommandlinePatch
{
winrt::guid guid;
winrt::guid guid{};
std::wstring_view before;
std::wstring_view after;
};

View File

@@ -83,7 +83,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static constexpr bool debugFeaturesDefault{ true };
#endif
winrt::guid _defaultProfile;
winrt::guid _defaultProfile{};
bool _legacyReloadEnvironmentVariables{ true };
winrt::com_ptr<implementation::ActionMap> _actionMap{ winrt::make_self<implementation::ActionMap>() };

View File

@@ -82,7 +82,6 @@ namespace RemotingUnitTests
void Summon(const Remoting::SummonWindowBehavior& /*args*/) DIE;
void RequestShowNotificationIcon() DIE;
void RequestHideNotificationIcon() DIE;
winrt::hstring GetWindowLayout() DIE;
void RequestQuitAll() DIE;
void Quit() DIE;
void AttachContentToWindow(Remoting::AttachRequest) DIE;
@@ -97,7 +96,6 @@ namespace RemotingUnitTests
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, Remoting::GetWindowLayoutArgs);
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);
};
@@ -117,7 +115,6 @@ namespace RemotingUnitTests
void SummonAllWindows() DIE;
bool DoesQuakeWindowExist() DIE;
winrt::Windows::Foundation::Collections::IVectorView<Remoting::PeasantInfo> GetPeasantInfos() DIE;
winrt::Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts() DIE;
void RequestMoveContent(winrt::hstring, winrt::hstring, uint32_t, winrt::Windows::Foundation::IReference<winrt::Windows::Foundation::Rect>) DIE;
void RequestSendContent(Remoting::RequestReceiveContentArgs) DIE;
@@ -126,7 +123,6 @@ namespace RemotingUnitTests
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, Remoting::QuitAllRequestedArgs);
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, Remoting::WindowRequestedArgs);
};

View File

@@ -215,49 +215,51 @@ void AppHost::_HandleSessionRestore(const bool startedForContent)
// we'll leave it here.
const auto numPeasants = _windowManager.GetNumberOfPeasants();
// Don't attempt to session restore if we're just making a window for tear-out
if (!startedForContent && numPeasants == 1)
if (startedForContent || numPeasants != 1 || !_appLogic.ShouldUsePersistedLayout())
{
const auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
if (_appLogic.ShouldUsePersistedLayout() &&
layouts &&
layouts.Size() > 0)
return;
}
const auto state = ApplicationState::SharedInstance();
const auto layouts = state.PersistedWindowLayouts();
if (layouts && layouts.Size() > 0)
{
uint32_t startIdx = 0;
// We want to create a window for every saved layout.
// If we are the only window, and no commandline arguments were provided
// then we should just use the current window to load the first layout.
// Otherwise create this window normally with its commandline, and create
// a new window using the first saved layout information.
// The 2nd+ layout will always get a new window.
if (!_windowLogic.HasCommandlineArguments() &&
!_appLogic.HasSettingsStartupActions())
{
uint32_t startIdx = 0;
// We want to create a window for every saved layout.
// If we are the only window, and no commandline arguments were provided
// then we should just use the current window to load the first layout.
// Otherwise create this window normally with its commandline, and create
// a new window using the first saved layout information.
// The 2nd+ layout will always get a new window.
if (!_windowLogic.HasCommandlineArguments() &&
!_appLogic.HasSettingsStartupActions())
{
_windowLogic.SetPersistedLayoutIdx(startIdx);
startIdx += 1;
}
_windowLogic.SetPersistedLayoutIdx(startIdx);
startIdx += 1;
}
// Create new windows for each of the other saved layouts.
for (const auto size = layouts.Size(); startIdx < size; startIdx += 1)
{
auto newWindowArgs = fmt::format(L"{0} -w new -s {1}", args.Commandline()[0], startIdx);
// Create new windows for each of the other saved layouts.
for (const auto size = layouts.Size(); startIdx < size; startIdx += 1)
{
auto newWindowArgs = fmt::format(L"{0} -w new -s {1}", args.Commandline()[0], startIdx);
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
wil::unique_process_information pi;
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
wil::unique_process_information pi;
LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr,
newWindowArgs.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
false, // bInheritHandles
DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT, // doCreationFlags
nullptr, // lpEnvironment
nullptr, // lpStartingDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
));
}
LOG_IF_WIN32_BOOL_FALSE(CreateProcessW(nullptr,
newWindowArgs.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
false, // bInheritHandles
DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT, // doCreationFlags
nullptr, // lpEnvironment
nullptr, // lpStartingDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
));
}
}
}
@@ -317,7 +319,7 @@ void AppHost::Initialize()
// Register the 'X' button of the window for a warning experience of multiple
// tabs opened, this is consistent with Alt+F4 closing
_windowCallbacks.WindowCloseButtonClicked = _window->WindowCloseButtonClicked([this]() {
_CloseRequested(nullptr, nullptr);
_windowLogic.CloseWindow();
});
// If the user requests a close in another way handle the same as if the 'X'
// was clicked.
@@ -350,7 +352,7 @@ void AppHost::Initialize()
_windowCallbacks.AutomaticShutdownRequested = _window->AutomaticShutdownRequested([this]() {
// Raised when the OS is beginning an update of the app. We will quit,
// to save our state, before the OS manually kills us.
Remoting::WindowManager::RequestQuitAll(_peasant);
_quit();
});
// Load bearing: make sure the PropertyChanged handler is added before we
@@ -362,7 +364,7 @@ void AppHost::Initialize()
_windowLogic.Create();
_revokers.TitleChanged = _windowLogic.TitleChanged(winrt::auto_revoke, { this, &AppHost::AppTitleChanged });
_revokers.LastTabClosed = _windowLogic.LastTabClosed(winrt::auto_revoke, { this, &AppHost::LastTabClosed });
_revokers.CloseWindowRequested = _windowLogic.CloseWindowRequested(winrt::auto_revoke, { this, &AppHost::_CloseRequested });
_revokers.SetTaskbarProgress = _windowLogic.SetTaskbarProgress(winrt::auto_revoke, { this, &AppHost::SetTaskbarProgress });
_revokers.IdentifyWindowsRequested = _windowLogic.IdentifyWindowsRequested(winrt::auto_revoke, { this, &AppHost::_IdentifyWindowsRequested });
_revokers.RenameWindowRequested = _windowLogic.RenameWindowRequested(winrt::auto_revoke, { this, &AppHost::_RenameWindowRequested });
@@ -382,22 +384,6 @@ void AppHost::Initialize()
_revokers.RequestReceiveContent = _windowLogic.RequestReceiveContent(winrt::auto_revoke, { this, &AppHost::_handleReceiveContent });
_revokers.SendContentRequested = _peasant.SendContentRequested(winrt::auto_revoke, { this, &AppHost::_handleSendContent });
// Add our GetWindowLayoutRequested handler AFTER the xaml island is
// started. Our _GetWindowLayoutAsync handler requires us to be able to work
// on our UI thread, which requires that we have a Dispatcher ready for us
// to move to. If we set up this callback in the ctor, then it is possible
// for there to be a time slice where
// * the monarch creates the peasant for us,
// * we get constructed (registering the callback)
// * then the monarch attempts to query all _peasants_ for their layout,
// coming back to ask us even before XAML has been created.
_GetWindowLayoutRequestedToken = _peasant.GetWindowLayoutRequested([this](auto&&,
const Remoting::GetWindowLayoutArgs& args) {
// The peasants are running on separate threads, so they'll need to
// swap what context they are in to the ui thread to get the actual layout.
args.WindowLayoutJsonAsync(_GetWindowLayoutAsync());
});
// BODGY
// On certain builds of Windows, when Terminal is set as the default
// it will accumulate an unbounded amount of queued animations while
@@ -452,6 +438,16 @@ void AppHost::Close()
}
}
winrt::fire_and_forget AppHost::_quit()
{
const auto peasant = _peasant;
co_await winrt::resume_background();
ApplicationState::SharedInstance().PersistedWindowLayouts(nullptr);
peasant.RequestQuitAll();
}
void AppHost::_revokeWindowCallbacks()
{
// You'll recall, IslandWindow isn't a WinRT type so it can't have auto-revokers.
@@ -514,42 +510,6 @@ void AppHost::AppTitleChanged(const winrt::Windows::Foundation::IInspectable& /*
_windowManager.UpdateActiveTabTitle(newTitle, _peasant);
}
// Method Description:
// - Called when no tab is remaining to close the window.
// Arguments:
// - sender: unused
// - LastTabClosedEventArgs: unused
// Return Value:
// - <none>
void AppHost::LastTabClosed(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::TerminalApp::LastTabClosedEventArgs& args)
{
// We don't want to try to save layouts if we are about to close.
_peasant.GetWindowLayoutRequested(_GetWindowLayoutRequestedToken);
// If the user closes the last tab, in the last window, _by closing the tab_
// (not by closing the whole window), we need to manually persist an empty
// window state here. That will cause the terminal to re-open with the usual
// settings (not the persisted state)
if (args.ClearPersistedState() &&
_windowManager.GetNumberOfPeasants() == 1)
{
_windowLogic.ClearPersistedWindowState();
}
// Remove ourself from the list of peasants so that we aren't included in
// any future requests. This will also mean we block until any existing
// event handler finishes.
_windowManager.SignalClose(_peasant);
if (Utils::IsWindows11())
{
PostQuitMessage(0);
}
else
{
PostMessageW(_window->GetInteropHandle(), WM_REFRIGERATE, 0, 0);
}
}
LaunchPosition AppHost::_GetWindowLaunchPosition()
{
LaunchPosition pos{};
@@ -952,42 +912,6 @@ winrt::fire_and_forget AppHost::_peasantNotifyActivateWindow()
});
}
// Method Description:
// - Asynchronously get the window layout from the current page. This is
// done async because we need to switch between the ui thread and the calling
// thread.
// - NB: The peasant calling this must not be running on the UI thread, otherwise
// they will crash since they just call .get on the async operation.
// Arguments:
// - <none>
// Return Value:
// - The window layout as a json string.
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> AppHost::_GetWindowLayoutAsync()
{
winrt::hstring layoutJson = L"";
auto weakThis{ weak_from_this() };
// Use the main thread since we are accessing controls.
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)
{
co_return layoutJson;
}
try
{
const auto pos = _GetWindowLaunchPosition();
layoutJson = _windowLogic.GetWindowLayoutJson(pos);
}
CATCH_LOG()
co_return layoutJson;
}
void AppHost::_HandleSummon(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const Remoting::SummonWindowBehavior& args)
{
@@ -1264,13 +1188,14 @@ winrt::fire_and_forget AppHost::_QuitRequested(const winrt::Windows::Foundation:
}
_windowLogic.Quit();
PostQuitMessage(0);
}
// Raised from TerminalWindow. We handle by bubbling the request to the window manager.
void AppHost::_RequestQuitAll(const winrt::Windows::Foundation::IInspectable&,
const winrt::Windows::Foundation::IInspectable&)
{
Remoting::WindowManager::RequestQuitAll(_peasant);
_quit();
}
void AppHost::_ShowWindowChanged(const winrt::Windows::Foundation::IInspectable&,
@@ -1370,9 +1295,25 @@ void AppHost::_WindowMoved()
void AppHost::_CloseRequested(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
const auto pos = _GetWindowLaunchPosition();
const bool isLastWindow = _windowManager.GetNumberOfPeasants() == 1;
_windowLogic.CloseWindow(pos, isLastWindow);
if (_windowManager.GetNumberOfPeasants() <= 1)
{
_quit();
return;
}
// Remove ourself from the list of peasants so that we aren't included in
// any future requests. This will also mean we block until any existing
// event handler finishes.
_windowManager.SignalClose(_peasant);
if (Utils::IsWindows11())
{
PostQuitMessage(0);
}
else
{
PostMessageW(_window->GetInteropHandle(), WM_REFRIGERATE, 0, 0);
}
}
void AppHost::_PropertyChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,

View File

@@ -20,7 +20,6 @@ public:
std::unique_ptr<IslandWindow> window = nullptr) noexcept;
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);
void LastTabClosed(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::LastTabClosedEventArgs& args);
void Initialize();
void Close();
@@ -64,8 +63,7 @@ private:
uint32_t _launchShowWindowCommand{ SW_NORMAL };
void _preInit();
winrt::fire_and_forget _quit();
void _revokeWindowCallbacks();
void _HandleCommandlineArgs(const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
@@ -100,8 +98,6 @@ private:
void _DispatchCommandline(winrt::Windows::Foundation::IInspectable sender,
winrt::Microsoft::Terminal::Remoting::CommandlineArgs args);
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> _GetWindowLayoutAsync();
void _HandleSummon(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior& args);
@@ -112,10 +108,6 @@ private:
winrt::fire_and_forget _RenameWindowRequested(const winrt::Windows::Foundation::IInspectable sender,
const winrt::TerminalApp::RenameWindowRequestedArgs args);
GUID _CurrentDesktopGuid();
bool _LazyLoadDesktopManager();
void _HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::TerminalApp::SettingsLoadEventArgs& args);
@@ -168,8 +160,6 @@ private:
void _stopFrameTimer();
void _updateFrameColor(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&);
winrt::event_token _GetWindowLayoutRequestedToken;
// 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
@@ -194,7 +184,7 @@ private:
winrt::TerminalApp::TerminalWindow::SystemMenuChangeRequested_revoker SystemMenuChangeRequested;
winrt::TerminalApp::TerminalWindow::ChangeMaximizeRequested_revoker ChangeMaximizeRequested;
winrt::TerminalApp::TerminalWindow::TitleChanged_revoker TitleChanged;
winrt::TerminalApp::TerminalWindow::LastTabClosed_revoker LastTabClosed;
winrt::TerminalApp::TerminalWindow::CloseWindowRequested_revoker CloseWindowRequested;
winrt::TerminalApp::TerminalWindow::SetTaskbarProgress_revoker SetTaskbarProgress;
winrt::TerminalApp::TerminalWindow::IdentifyWindowsRequested_revoker IdentifyWindowsRequested;
winrt::TerminalApp::TerminalWindow::RenameWindowRequested_revoker RenameWindowRequested;
@@ -208,7 +198,6 @@ private:
winrt::TerminalApp::TerminalWindow::PropertyChanged_revoker PropertyChanged;
winrt::TerminalApp::TerminalWindow::SettingsChanged_revoker SettingsChanged;
winrt::Microsoft::Terminal::Remoting::WindowManager::QuitAllRequested_revoker QuitAllRequested;
winrt::Microsoft::Terminal::Remoting::Peasant::SendContentRequested_revoker SendContentRequested;
} _revokers{};

View File

@@ -127,6 +127,9 @@ void WindowEmperor::WaitForWindows()
TranslateMessage(&message);
DispatchMessage(&message);
}
_finalizeSessionPersistence();
TerminateProcess(GetCurrentProcess(), 0);
}
void WindowEmperor::_createNewWindowThread(const Remoting::WindowRequestedArgs& args)
@@ -345,116 +348,17 @@ void WindowEmperor::_becomeMonarch()
_revokers.WindowCreated = _manager.WindowCreated(winrt::auto_revoke, { this, &WindowEmperor::_numberOfWindowsChanged });
_revokers.WindowClosed = _manager.WindowClosed(winrt::auto_revoke, { this, &WindowEmperor::_numberOfWindowsChanged });
// If the monarch receives a QuitAll event it will signal this event to be
// ran before each peasant is closed.
_revokers.QuitAllRequested = _manager.QuitAllRequested(winrt::auto_revoke, { this, &WindowEmperor::_quitAllRequested });
// The monarch should be monitoring if it should save the window layout.
// We want at least some delay to prevent the first save from overwriting
_getWindowLayoutThrottler.emplace(std::move(std::chrono::seconds(10)), std::move([this]() { _saveWindowLayoutsRepeat(); }));
_getWindowLayoutThrottler.value()();
}
// sender and args are always nullptr
void WindowEmperor::_numberOfWindowsChanged(const winrt::Windows::Foundation::IInspectable&,
const winrt::Windows::Foundation::IInspectable&)
{
if (_getWindowLayoutThrottler)
{
_getWindowLayoutThrottler.value()();
}
// If we closed out the quake window, and don't otherwise need the tray
// icon, let's get rid of it.
_checkWindowsForNotificationIcon();
}
// Raised from our windowManager (on behalf of the monarch). We respond by
// giving the monarch an async function that the manager should wait on before
// completing the quit.
void WindowEmperor::_quitAllRequested(const winrt::Windows::Foundation::IInspectable&,
const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& args)
{
_quitting = true;
// Make sure that the current timer is destroyed so that it doesn't attempt
// to run while we are in the middle of quitting.
if (_getWindowLayoutThrottler.has_value())
{
_getWindowLayoutThrottler.reset();
}
// Tell the monarch to wait for the window layouts to save before
// everyone quits.
args.BeforeQuitAllAction(_saveWindowLayouts());
}
#pragma region LayoutPersistence
winrt::Windows::Foundation::IAsyncAction WindowEmperor::_saveWindowLayouts()
{
// Make sure we run on a background thread to not block anything.
co_await winrt::resume_background();
if (_app.Logic().ShouldUsePersistedLayout())
{
try
{
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Collect",
TraceLoggingDescription("Logged when collecting window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
const auto layoutJsons = _manager.GetAllWindowLayouts();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Save",
TraceLoggingDescription("Logged when writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_app.Logic().SaveWindowLayoutJsons(layoutJsons);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Failed",
TraceLoggingDescription("An error occurred when collecting or writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
}
co_return;
}
winrt::fire_and_forget WindowEmperor::_saveWindowLayoutsRepeat()
{
// Make sure we run on a background thread to not block anything.
co_await winrt::resume_background();
co_await _saveWindowLayouts();
// Don't need to save too frequently.
co_await winrt::resume_after(30s);
// As long as we are supposed to keep saving, request another save.
// This will be delayed by the throttler so that at most one save happens
// per 10 seconds, if a save is requested by another source simultaneously.
if (_getWindowLayoutThrottler.has_value())
{
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_requestGetLayout",
TraceLoggingDescription("Logged when triggering a throttled write of the window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_getWindowLayoutThrottler.value()();
}
}
#pragma endregion
#pragma region WindowProc
@@ -575,6 +479,14 @@ winrt::fire_and_forget WindowEmperor::_close()
PostQuitMessage(0);
}
void WindowEmperor::_finalizeSessionPersistence() const
{
const auto state = ApplicationState::SharedInstance();
// Ensure to write the state.json before we TerminateProcess()
state.Flush();
}
#pragma endregion
#pragma region GlobalHotkeys

View File

@@ -44,8 +44,6 @@ private:
til::shared_mutex<std::vector<std::shared_ptr<WindowThread>>> _oldThreads;
std::optional<til::throttled_func_trailing<>> _getWindowLayoutThrottler;
winrt::event_token _WindowCreatedToken;
winrt::event_token _WindowClosedToken;
@@ -61,15 +59,10 @@ private:
void _becomeMonarch();
void _numberOfWindowsChanged(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::Foundation::IInspectable&);
void _quitAllRequested(const winrt::Windows::Foundation::IInspectable&,
const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs&);
winrt::fire_and_forget _windowIsQuakeWindowChanged(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::Foundation::IInspectable args);
winrt::fire_and_forget _windowRequestUpdateSettings();
winrt::Windows::Foundation::IAsyncAction _saveWindowLayouts();
winrt::fire_and_forget _saveWindowLayoutsRepeat();
void _createMessageWindow();
void _hotkeyPressed(const long hotkeyIndex);
@@ -78,6 +71,7 @@ private:
winrt::fire_and_forget _setupGlobalHotkeys();
winrt::fire_and_forget _close();
void _finalizeSessionPersistence() const;
void _createNotificationIcon();
void _destroyNotificationIcon();
@@ -89,6 +83,5 @@ private:
{
winrt::Microsoft::Terminal::Remoting::WindowManager::WindowCreated_revoker WindowCreated;
winrt::Microsoft::Terminal::Remoting::WindowManager::WindowClosed_revoker WindowClosed;
winrt::Microsoft::Terminal::Remoting::WindowManager::QuitAllRequested_revoker QuitAllRequested;
} _revokers{};
};