mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-12 17:21:03 +00:00
Implement buffer restore (#16598)
This changeset allows Windows Terminal to dump its buffer contents as UTF-16LE VT text onto disk and restore it later. This functionality is enabled whenever `persistedWindowLayout` is being used. Closes #961 Closes #16741 ## Validation Steps Performed * Open multiple windows with multiple tabs and restart the app Everything's restored ✅ * Reopen a tab with output from `RenderingTests.exe` Everything's restored ✅ * Closing tabs and windows with Ctrl+W deletes their buffer dumps ✅ * Closing tabs doesn't create buffer dumps ✅
This commit is contained in:
2
.github/actions/spelling/expect/expect.txt
vendored
2
.github/actions/spelling/expect/expect.txt
vendored
@@ -597,6 +597,7 @@ FECF
|
||||
FEEF
|
||||
fesb
|
||||
FFAF
|
||||
ffd
|
||||
FFDE
|
||||
FFFDb
|
||||
fgbg
|
||||
@@ -757,6 +758,7 @@ hdr
|
||||
HDROP
|
||||
hdrstop
|
||||
HEIGHTSCROLL
|
||||
hfind
|
||||
hfont
|
||||
hfontresource
|
||||
hglobal
|
||||
|
||||
@@ -62,6 +62,11 @@ bool TextColor::CanBeBrightened() const noexcept
|
||||
return IsIndex16() || IsDefault();
|
||||
}
|
||||
|
||||
ColorType TextColor::GetType() const noexcept
|
||||
{
|
||||
return _meta;
|
||||
}
|
||||
|
||||
bool TextColor::IsLegacy() const noexcept
|
||||
{
|
||||
return (IsIndex16() || IsIndex256()) && _index < 16;
|
||||
@@ -280,15 +285,3 @@ BYTE TextColor::GetLegacyIndex(const BYTE defaultIndex) const noexcept
|
||||
return til::at(CompressedRgbToIndex16, compressedRgb);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Return a COLORREF containing our stored value. Will return garbage if this
|
||||
//attribute is not a RGB attribute.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - a COLORREF containing our stored value
|
||||
COLORREF TextColor::GetRGB() const noexcept
|
||||
{
|
||||
return RGB(_red, _green, _blue);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
}
|
||||
|
||||
bool CanBeBrightened() const noexcept;
|
||||
ColorType GetType() const noexcept;
|
||||
bool IsLegacy() const noexcept;
|
||||
bool IsIndex16() const noexcept;
|
||||
bool IsIndex256() const noexcept;
|
||||
@@ -133,12 +134,11 @@ public:
|
||||
COLORREF GetColor(const std::array<COLORREF, TABLE_SIZE>& colorTable, const size_t defaultIndex, bool brighten = false) const noexcept;
|
||||
BYTE GetLegacyIndex(const BYTE defaultIndex) const noexcept;
|
||||
|
||||
constexpr BYTE GetIndex() const noexcept
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
COLORREF GetRGB() const noexcept;
|
||||
constexpr BYTE GetIndex() const noexcept { return _index; }
|
||||
constexpr BYTE GetR() const noexcept { return _red; }
|
||||
constexpr BYTE GetG() const noexcept { return _green; }
|
||||
constexpr BYTE GetB() const noexcept { return _blue; }
|
||||
constexpr COLORREF GetRGB() const noexcept { return RGB(_red, _green, _blue); }
|
||||
|
||||
static constexpr BYTE TransposeLegacyIndex(const size_t index)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "UTextAdapter.h"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
#include "../renderer/base/renderer.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
#include "../types/inc/utils.hpp"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
@@ -2508,6 +2507,237 @@ void TextBuffer::_AppendRTFText(std::string& contentBuilder, const std::wstring_
|
||||
}
|
||||
}
|
||||
|
||||
void TextBuffer::Serialize(const wchar_t* destination) const
|
||||
{
|
||||
const wil::unique_handle file{ CreateFileW(destination, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
|
||||
THROW_LAST_ERROR_IF(!file);
|
||||
|
||||
static constexpr size_t writeThreshold = 32 * 1024;
|
||||
std::wstring buffer;
|
||||
buffer.reserve(writeThreshold + writeThreshold / 2);
|
||||
buffer.push_back(L'\uFEFF');
|
||||
|
||||
const til::CoordType lastRowWithText = GetLastNonSpaceCharacter(nullptr).y;
|
||||
CharacterAttributes previousAttr = CharacterAttributes::Unused1;
|
||||
TextColor previousFg;
|
||||
TextColor previousBg;
|
||||
TextColor previousUl;
|
||||
uint16_t previousHyperlinkId = 0;
|
||||
|
||||
// This iterates through each row. The exit condition is at the end
|
||||
// of the for() loop so that we can properly handle file flushing.
|
||||
for (til::CoordType currentRow = 0;; currentRow++)
|
||||
{
|
||||
const auto& row = GetRowByOffset(currentRow);
|
||||
|
||||
if (const auto lr = row.GetLineRendition(); lr != LineRendition::SingleWidth)
|
||||
{
|
||||
static constexpr std::wstring_view mappings[] = {
|
||||
L"\x1b#6", // LineRendition::DoubleWidth
|
||||
L"\x1b#3", // LineRendition::DoubleHeightTop
|
||||
L"\x1b#4", // LineRendition::DoubleHeightBottom
|
||||
};
|
||||
const auto idx = std::clamp(static_cast<int>(lr) - 1, 0, 2);
|
||||
buffer.append(til::at(mappings, idx));
|
||||
}
|
||||
|
||||
const auto& runs = row.Attributes().runs();
|
||||
auto it = runs.begin();
|
||||
const auto end = runs.end();
|
||||
const auto last = end - 1;
|
||||
til::CoordType oldX = 0;
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
const auto attr = it->value.GetCharacterAttributes();
|
||||
const auto hyperlinkId = it->value.GetHyperlinkId();
|
||||
const auto fg = it->value.GetForeground();
|
||||
const auto bg = it->value.GetBackground();
|
||||
const auto ul = it->value.GetUnderlineColor();
|
||||
|
||||
if (previousAttr != attr)
|
||||
{
|
||||
const auto attrDelta = attr ^ previousAttr;
|
||||
|
||||
{
|
||||
struct Mapping
|
||||
{
|
||||
CharacterAttributes attr;
|
||||
uint8_t change[2]; // [0] = off, [1] = on
|
||||
};
|
||||
static constexpr Mapping mappings[] = {
|
||||
{ CharacterAttributes::Intense, { 22, 1 } },
|
||||
{ CharacterAttributes::Italics, { 23, 3 } },
|
||||
{ CharacterAttributes::Blinking, { 25, 5 } },
|
||||
{ CharacterAttributes::Invisible, { 28, 8 } },
|
||||
{ CharacterAttributes::CrossedOut, { 29, 9 } },
|
||||
{ CharacterAttributes::Faint, { 22, 2 } },
|
||||
{ CharacterAttributes::TopGridline, { 55, 53 } },
|
||||
{ CharacterAttributes::ReverseVideo, { 27, 7 } },
|
||||
{ CharacterAttributes::BottomGridline, { 24, 4 } },
|
||||
};
|
||||
for (const auto& mapping : mappings)
|
||||
{
|
||||
if (WI_IsAnyFlagSet(attrDelta, mapping.attr))
|
||||
{
|
||||
const auto n = til::at(mapping.change, WI_IsAnyFlagSet(attr, mapping.attr));
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[{}m"), n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsAnyFlagSet(attrDelta, CharacterAttributes::UnderlineStyle))
|
||||
{
|
||||
static constexpr std::wstring_view mappings[] = {
|
||||
L"\x1b[24m", // UnderlineStyle::NoUnderline
|
||||
L"\x1b[4m", // UnderlineStyle::SinglyUnderlined
|
||||
L"\x1b[21m", // UnderlineStyle::DoublyUnderlined
|
||||
L"\x1b[4:3m", // UnderlineStyle::CurlyUnderlined
|
||||
L"\x1b[4:4m", // UnderlineStyle::DottedUnderlined
|
||||
L"\x1b[4:5m", // UnderlineStyle::DashedUnderlined
|
||||
};
|
||||
|
||||
auto idx = WI_EnumValue(it->value.GetUnderlineStyle());
|
||||
if (idx >= std::size(mappings))
|
||||
{
|
||||
idx = 1; // UnderlineStyle::SinglyUnderlined
|
||||
}
|
||||
|
||||
buffer.append(til::at(mappings, idx));
|
||||
}
|
||||
|
||||
previousAttr = attr;
|
||||
}
|
||||
|
||||
if (previousFg != fg)
|
||||
{
|
||||
switch (fg.GetType())
|
||||
{
|
||||
case ColorType::IsDefault:
|
||||
buffer.append(L"\x1b[39m");
|
||||
break;
|
||||
case ColorType::IsIndex16:
|
||||
{
|
||||
uint8_t index = WI_IsFlagSet(fg.GetIndex(), 8) ? 90 : 30;
|
||||
index += fg.GetIndex() & 7;
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[{}m"), index);
|
||||
break;
|
||||
}
|
||||
case ColorType::IsIndex256:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[38;5;{}m"), fg.GetIndex());
|
||||
break;
|
||||
case ColorType::IsRgb:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[38;2;{};{};{}m"), fg.GetR(), fg.GetG(), fg.GetB());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
previousFg = fg;
|
||||
}
|
||||
|
||||
if (previousBg != bg)
|
||||
{
|
||||
switch (bg.GetType())
|
||||
{
|
||||
case ColorType::IsDefault:
|
||||
buffer.append(L"\x1b[49m");
|
||||
break;
|
||||
case ColorType::IsIndex16:
|
||||
{
|
||||
uint8_t index = WI_IsFlagSet(bg.GetIndex(), 8) ? 100 : 40;
|
||||
index += bg.GetIndex() & 7;
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[{}m"), index);
|
||||
break;
|
||||
}
|
||||
case ColorType::IsIndex256:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[48;5;{}m"), bg.GetIndex());
|
||||
break;
|
||||
case ColorType::IsRgb:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[48;2;{};{};{}m"), bg.GetR(), bg.GetG(), bg.GetB());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
previousBg = bg;
|
||||
}
|
||||
|
||||
if (previousUl != ul)
|
||||
{
|
||||
switch (fg.GetType())
|
||||
{
|
||||
case ColorType::IsDefault:
|
||||
buffer.append(L"\x1b[59m");
|
||||
break;
|
||||
case ColorType::IsIndex256:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[58:5:{}m"), ul.GetIndex());
|
||||
break;
|
||||
case ColorType::IsRgb:
|
||||
fmt::format_to(std::back_inserter(buffer), FMT_COMPILE(L"\x1b[58:2::{}:{}:{}m"), ul.GetR(), ul.GetG(), ul.GetB());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
previousUl = ul;
|
||||
}
|
||||
|
||||
if (previousHyperlinkId != hyperlinkId)
|
||||
{
|
||||
if (hyperlinkId)
|
||||
{
|
||||
const auto uri = GetHyperlinkUriFromId(hyperlinkId);
|
||||
if (!uri.empty())
|
||||
{
|
||||
buffer.append(L"\x1b]8;;");
|
||||
buffer.append(uri);
|
||||
buffer.append(L"\x1b\\");
|
||||
previousHyperlinkId = hyperlinkId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(L"\x1b]8;;\x1b\\");
|
||||
previousHyperlinkId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto newX = oldX + it->length;
|
||||
// Trim whitespace with default attributes from the end of each line.
|
||||
if (it == last && it->value == TextAttribute{})
|
||||
{
|
||||
// This can result in oldX > newX, but that's okay because GetText()
|
||||
// is robust against that and returns an empty string.
|
||||
newX = row.MeasureRight();
|
||||
}
|
||||
|
||||
buffer.append(row.GetText(oldX, newX));
|
||||
oldX = newX;
|
||||
}
|
||||
|
||||
const auto moreRowsRemaining = currentRow < lastRowWithText;
|
||||
|
||||
if (!row.WasWrapForced() || !moreRowsRemaining)
|
||||
{
|
||||
buffer.append(L"\r\n");
|
||||
}
|
||||
|
||||
if (buffer.size() >= writeThreshold || !moreRowsRemaining)
|
||||
{
|
||||
const auto fileSize = gsl::narrow<DWORD>(buffer.size() * sizeof(wchar_t));
|
||||
DWORD bytesWritten = 0;
|
||||
THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), buffer.data(), fileSize, &bytesWritten, nullptr));
|
||||
if (bytesWritten != fileSize)
|
||||
{
|
||||
THROW_WIN32_MSG(ERROR_WRITE_FAULT, "failed to write");
|
||||
}
|
||||
}
|
||||
|
||||
if (!moreRowsRemaining)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Reflow the contents from the old buffer into the new buffer. The new buffer
|
||||
// can have different dimensions than the old buffer. If it does, then this
|
||||
|
||||
@@ -319,6 +319,8 @@ public:
|
||||
const bool isIntenseBold,
|
||||
std::function<std::tuple<COLORREF, COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors) const noexcept;
|
||||
|
||||
void Serialize(const wchar_t* destination) const;
|
||||
|
||||
struct PositionInformation
|
||||
{
|
||||
til::CoordType mutableViewportTop{ 0 };
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "GetWindowLayoutArgs.h"
|
||||
#include "GetWindowLayoutArgs.g.cpp"
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>();
|
||||
QuitAllRequested.raise(*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,
|
||||
|
||||
@@ -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,7 +105,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> WindowCreated;
|
||||
til::typed_event<> WindowClosed;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
|
||||
|
||||
@@ -146,8 +144,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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>();
|
||||
GetWindowLayoutRequested.raise(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)
|
||||
{
|
||||
SendContentRequested.raise(*this, args);
|
||||
|
||||
@@ -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);
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs> WindowActivated;
|
||||
@@ -79,7 +78,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> QuitAllRequested;
|
||||
til::typed_event<> QuitRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest> AttachRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs> SendContentRequested;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "QuitAllRequestedArgs.h"
|
||||
#include "QuitAllRequestedArgs.g.cpp"
|
||||
@@ -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);
|
||||
}
|
||||
@@ -92,7 +92,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
_monarch.WindowCreated({ get_weak(), &WindowManager::_bubbleWindowCreated });
|
||||
_monarch.WindowClosed({ get_weak(), &WindowManager::_bubbleWindowClosed });
|
||||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_bubbleQuitAllRequested });
|
||||
|
||||
_monarch.RequestNewWindow({ get_weak(), &WindowManager::_raiseRequestNewWindow });
|
||||
}
|
||||
@@ -356,8 +355,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
_monarch.AddPeasant(*p);
|
||||
|
||||
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_bubbleGetWindowLayoutRequested });
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_CreateOurPeasant",
|
||||
TraceLoggingUInt64(p->GetID(), "peasantID", "The ID of our new peasant"),
|
||||
@@ -367,10 +364,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return *p;
|
||||
}
|
||||
|
||||
void WindowManager::_bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e)
|
||||
{
|
||||
GetWindowLayoutRequested.raise(s, e);
|
||||
}
|
||||
void WindowManager::_bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e)
|
||||
{
|
||||
WindowCreated.raise(s, e);
|
||||
@@ -379,10 +372,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
WindowClosed.raise(s, e);
|
||||
}
|
||||
void WindowManager::_bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e)
|
||||
{
|
||||
QuitAllRequested.raise(s, e);
|
||||
}
|
||||
|
||||
void WindowManager::SignalClose(const Remoting::Peasant& peasant)
|
||||
{
|
||||
@@ -429,18 +418,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();
|
||||
@@ -451,19 +428,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,
|
||||
|
||||
@@ -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,8 +49,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
til::typed_event<> WindowCreated;
|
||||
til::typed_event<> WindowClosed;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
|
||||
|
||||
private:
|
||||
@@ -71,8 +67,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
void _bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _bubbleWindowClosed(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e);
|
||||
void _bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -549,6 +549,9 @@ void AppCommandlineArgs::_addNewTerminalArgs(AppCommandlineArgs::NewTerminalSubc
|
||||
subcommand.profileNameOption = subcommand.subcommand->add_option("-p,--profile",
|
||||
_profileName,
|
||||
RS_A(L"CmdProfileArgDesc"));
|
||||
subcommand.sessionIdOption = subcommand.subcommand->add_option("--sessionId",
|
||||
_sessionId,
|
||||
RS_A(L"CmdSessionIdArgDesc"));
|
||||
subcommand.startingDirectoryOption = subcommand.subcommand->add_option("-d,--startingDirectory",
|
||||
_startingDirectory,
|
||||
RS_A(L"CmdStartingDirArgDesc"));
|
||||
@@ -628,6 +631,13 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT
|
||||
args.Profile(winrt::to_hstring(_profileName));
|
||||
}
|
||||
|
||||
if (*subcommand.sessionIdOption)
|
||||
{
|
||||
const auto str = winrt::to_hstring(_sessionId);
|
||||
const auto id = ::Microsoft::Console::Utils::GuidFromString(str.c_str());
|
||||
args.SessionId(id);
|
||||
}
|
||||
|
||||
if (*subcommand.startingDirectoryOption)
|
||||
{
|
||||
args.StartingDirectory(winrt::to_hstring(_startingDirectory));
|
||||
@@ -714,6 +724,7 @@ bool AppCommandlineArgs::_noCommandsProvided()
|
||||
void AppCommandlineArgs::_resetStateToDefault()
|
||||
{
|
||||
_profileName.clear();
|
||||
_sessionId.clear();
|
||||
_startingDirectory.clear();
|
||||
_startingTitle.clear();
|
||||
_startingTabColor.clear();
|
||||
|
||||
@@ -62,6 +62,7 @@ private:
|
||||
CLI::App* subcommand;
|
||||
CLI::Option* commandlineOption;
|
||||
CLI::Option* profileNameOption;
|
||||
CLI::Option* sessionIdOption;
|
||||
CLI::Option* startingDirectoryOption;
|
||||
CLI::Option* titleOption;
|
||||
CLI::Option* tabColorOption;
|
||||
@@ -96,6 +97,7 @@ private:
|
||||
// Are you adding a new sub-command? Make sure to update _noCommandsProvided!
|
||||
|
||||
std::string _profileName;
|
||||
std::string _sessionId;
|
||||
std::string _startingDirectory;
|
||||
std::string _startingTitle;
|
||||
std::string _startingTabColor;
|
||||
|
||||
@@ -702,22 +702,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace TerminalApp
|
||||
Boolean HasSettingsStartupActions();
|
||||
|
||||
Boolean ShouldUsePersistedLayout();
|
||||
void SaveWindowLayoutJsons(Windows.Foundation.Collections.IVector<String> layouts);
|
||||
|
||||
void ReloadSettings();
|
||||
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
enum BuildStartupKind
|
||||
{
|
||||
None,
|
||||
Content,
|
||||
MovePane,
|
||||
Persist,
|
||||
};
|
||||
|
||||
runtimeclass BellEventArgs
|
||||
{
|
||||
@@ -20,7 +27,7 @@ namespace TerminalApp
|
||||
UInt64 TaskbarProgress { get; };
|
||||
Boolean ReadOnly { get; };
|
||||
|
||||
Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent);
|
||||
Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(BuildStartupKind kind);
|
||||
|
||||
void Focus(Windows.UI.Xaml.FocusState reason);
|
||||
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
#include "pch.h"
|
||||
#include "Pane.h"
|
||||
|
||||
#include "AppLogic.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <Mmsystem.h>
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Graphics::Display;
|
||||
using namespace winrt::Windows::UI;
|
||||
@@ -20,7 +14,6 @@ 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;
|
||||
|
||||
static const int PaneBorderSize = 2;
|
||||
static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
|
||||
@@ -105,21 +98,13 @@ Pane::Pane(std::shared_ptr<Pane> first,
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Extract the terminal settings from the current (leaf) pane's control
|
||||
// to be used to create an equivalent control
|
||||
// Arguments:
|
||||
// - asContent: when true, we're trying to serialize this pane for moving across
|
||||
// windows. In that case, we'll need to fill in the content guid for our new
|
||||
// terminal args.
|
||||
// Return Value:
|
||||
// - Arguments appropriate for a SplitPane or NewTab action
|
||||
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
|
||||
// Extract the terminal settings from the current (leaf) pane's control
|
||||
// to be used to create an equivalent control
|
||||
NewTerminalArgs Pane::GetTerminalArgsForPane(BuildStartupKind kind) const
|
||||
{
|
||||
// Leaves are the only things that have controls
|
||||
assert(_IsLeaf());
|
||||
|
||||
return _content.GetNewTerminalArgs(asContent);
|
||||
return _content.GetNewTerminalArgs(kind);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -142,16 +127,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)
|
||||
{
|
||||
@@ -165,18 +147,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()) },
|
||||
@@ -223,10 +205,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);
|
||||
|
||||
@@ -104,8 +104,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::BuildStartupKind kind);
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(winrt::TerminalApp::BuildStartupKind kind) const;
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
|
||||
@@ -187,9 +187,6 @@
|
||||
<data name="Quit" xml:space="preserve">
|
||||
<value>Quit</value>
|
||||
</data>
|
||||
<data name="CloseWindowWarningTitle" xml:space="preserve">
|
||||
<value>Do you want to close all tabs?</value>
|
||||
</data>
|
||||
<data name="MultiplePanes" xml:space="preserve">
|
||||
<value>Multiple panes</value>
|
||||
</data>
|
||||
@@ -340,6 +337,9 @@
|
||||
<data name="CmdProfileArgDesc" xml:space="preserve">
|
||||
<value>Open with the given profile. Accepts either the name or GUID of a profile</value>
|
||||
</data>
|
||||
<data name="CmdSessionIdArgDesc" xml:space="preserve">
|
||||
<value>Sets the WT_SESSION variable; must be a GUID</value>
|
||||
</data>
|
||||
<data name="CmdSplitPaneDesc" xml:space="preserve">
|
||||
<value>Create a new split pane</value>
|
||||
</data>
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace winrt::TerminalApp::implementation
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
NewTerminalArgs ScratchpadContent::GetNewTerminalArgs(const bool /* asContent */) const
|
||||
NewTerminalArgs ScratchpadContent::GetNewTerminalArgs(const BuildStartupKind /* kind */) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
void Close();
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
winrt::hstring Title() { return L"Scratchpad"; }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -22,7 +22,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,
|
||||
|
||||
@@ -429,7 +429,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);
|
||||
@@ -486,7 +486,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.
|
||||
LastTabClosed.raise(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
|
||||
CloseWindowRequested.raise(*this, nullptr);
|
||||
}
|
||||
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
|
||||
{
|
||||
@@ -767,11 +767,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));
|
||||
@@ -1139,12 +1139,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
LastTabClosed.raise(*this, winrt::make<LastTabClosedEventArgs>(false));
|
||||
CloseWindowRequested.raise(*this, nullptr);
|
||||
co_return;
|
||||
}
|
||||
else
|
||||
@@ -1277,6 +1276,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto id = settings.SessionId(); id != winrt::guid{})
|
||||
{
|
||||
valueSet.Insert(L"sessionId", Windows::Foundation::PropertyValue::CreateGuid(id));
|
||||
}
|
||||
|
||||
connection.Initialize(valueSet);
|
||||
|
||||
TraceLoggingWrite(
|
||||
@@ -1891,19 +1895,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;
|
||||
@@ -1911,7 +1907,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()));
|
||||
}
|
||||
|
||||
@@ -1938,7 +1934,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;
|
||||
@@ -1955,20 +1951,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)
|
||||
{
|
||||
@@ -1987,15 +1978,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();
|
||||
CloseWindowRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -2057,7 +2040,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();
|
||||
@@ -2199,7 +2182,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);
|
||||
@@ -3041,7 +3024,17 @@ namespace winrt::TerminalApp::implementation
|
||||
// TermControl will copy the settings out of the settings passed to it.
|
||||
|
||||
const auto content = _manager.CreateCore(settings.DefaultSettings(), settings.UnfocusedSettings(), connection);
|
||||
return _SetupControl(TermControl{ content });
|
||||
const TermControl control{ content };
|
||||
|
||||
if (const auto id = settings.DefaultSettings().SessionId(); id != winrt::guid{})
|
||||
{
|
||||
const auto settingsDir = CascadiaSettings::SettingsDirectory();
|
||||
const auto idStr = Utils::GuidToPlainString(id);
|
||||
const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr);
|
||||
control.RestoreFromPath(path);
|
||||
}
|
||||
|
||||
return _SetupControl(control);
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_AttachControlToContent(const uint64_t& contentId)
|
||||
@@ -5124,7 +5117,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);
|
||||
|
||||
@@ -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 ---------------------------------
|
||||
til::typed_event<IInspectable, winrt::hstring> TitleChanged;
|
||||
til::typed_event<IInspectable, winrt::TerminalApp::LastTabClosedEventArgs> LastTabClosed;
|
||||
til::typed_event<IInspectable, IInspectable> CloseWindowRequested;
|
||||
til::typed_event<IInspectable, winrt::Windows::UI::Xaml::UIElement> SetTitleBarContent;
|
||||
til::typed_event<IInspectable, IInspectable> FocusModeChanged;
|
||||
til::typed_event<IInspectable, IInspectable> FullscreenChanged;
|
||||
@@ -185,7 +175,7 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<IInspectable, IInspectable> SetTaskbarProgress;
|
||||
til::typed_event<IInspectable, IInspectable> Initialized;
|
||||
til::typed_event<IInspectable, IInspectable> IdentifyWindowsRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
til::typed_event<IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
til::typed_event<IInspectable, IInspectable> SummonWindowRequested;
|
||||
|
||||
til::typed_event<IInspectable, IInspectable> CloseRequested;
|
||||
@@ -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{};
|
||||
@@ -348,7 +337,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);
|
||||
|
||||
@@ -14,11 +14,6 @@ namespace TerminalApp
|
||||
void Detach(Microsoft.Terminal.Control.TermControl control);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass LastTabClosedEventArgs
|
||||
{
|
||||
Boolean ClearPersistedState { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass RenameWindowRequestedArgs
|
||||
{
|
||||
String ProposedName { get; };
|
||||
@@ -86,7 +81,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;
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "TerminalPaneContent.h"
|
||||
#include "TerminalPaneContent.g.cpp"
|
||||
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
#include "BellEventArgs.g.cpp"
|
||||
#include "TerminalPaneContent.g.cpp"
|
||||
|
||||
#include <Mmsystem.h>
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
@@ -77,7 +80,7 @@ namespace winrt::TerminalApp::implementation
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const bool asContent) const
|
||||
NewTerminalArgs TerminalPaneContent::GetNewTerminalArgs(const BuildStartupKind kind) const
|
||||
{
|
||||
NewTerminalArgs args{};
|
||||
const auto& controlSettings = _control.Settings();
|
||||
@@ -119,12 +122,32 @@ namespace winrt::TerminalApp::implementation
|
||||
// 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;
|
||||
case BuildStartupKind::Persist:
|
||||
{
|
||||
const auto connection = _control.Connection();
|
||||
const auto id = connection ? connection.SessionId() : winrt::guid{};
|
||||
|
||||
if (id != winrt::guid{})
|
||||
{
|
||||
const auto settingsDir = CascadiaSettings::SettingsDirectory();
|
||||
const auto idStr = ::Microsoft::Console::Utils::GuidToPlainString(id);
|
||||
const auto path = fmt::format(FMT_COMPILE(L"{}\\buffer_{}.txt"), settingsDir, idStr);
|
||||
_control.PersistToPath(path);
|
||||
args.SessionId(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return args;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
void Close();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(BuildStartupKind kind) const;
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
|
||||
@@ -432,18 +432,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));
|
||||
|
||||
@@ -79,7 +79,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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
@@ -218,7 +213,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);
|
||||
|
||||
@@ -74,7 +74,6 @@ namespace TerminalApp
|
||||
|
||||
void IdentifyWindow();
|
||||
void SetPersistedLayoutIdx(UInt32 idx);
|
||||
void ClearPersistedWindowState();
|
||||
|
||||
void RenameFailed();
|
||||
void RequestExitFullscreen();
|
||||
@@ -89,7 +88,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; };
|
||||
@@ -97,8 +96,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();
|
||||
@@ -118,7 +115,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;
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -9,8 +9,10 @@
|
||||
#include <dsound.h>
|
||||
|
||||
#include <DefaultSettings.h>
|
||||
#include <utils.hpp>
|
||||
#include <LibraryResources.h>
|
||||
#include <unicode.hpp>
|
||||
#include <utils.hpp>
|
||||
#include <WinUser.h>
|
||||
|
||||
#include "EventArgs.h"
|
||||
#include "../../renderer/atlas/AtlasEngine.h"
|
||||
@@ -399,10 +401,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_initializedTerminal.store(true, std::memory_order_relaxed);
|
||||
} // scope for TerminalLock
|
||||
|
||||
// Start the connection outside of lock, because it could
|
||||
// start writing output immediately.
|
||||
_connection.Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1711,6 +1709,50 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::PersistToPath(const wchar_t* path) const
|
||||
{
|
||||
const auto lock = _terminal->LockForReading();
|
||||
_terminal->SerializeMainBuffer(path);
|
||||
}
|
||||
|
||||
void ControlCore::RestoreFromPath(const wchar_t* path) const
|
||||
{
|
||||
const wil::unique_handle file{ CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
|
||||
if (!file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t buffer[32 * 1024];
|
||||
DWORD read = 0;
|
||||
|
||||
// Ensure the text file starts with a UTF-16 BOM.
|
||||
if (!ReadFile(file.get(), &buffer[0], 2, &read, nullptr) || read < 2 || buffer[0] != L'\uFEFF')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!ReadFile(file.get(), &buffer[0], sizeof(buffer), &read, nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_terminal->Write({ &buffer[0], read / 2 });
|
||||
|
||||
if (read < sizeof(buffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This pushes the restored contents up into the scrollback.
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_terminal->Write(L"\x1b[2J");
|
||||
}
|
||||
|
||||
void ControlCore::_rendererWarning(const HRESULT hr, wil::zwstring_view parameter)
|
||||
{
|
||||
RendererWarning.raise(*this, winrt::make<RendererWarningArgs>(hr, winrt::hstring{ parameter }));
|
||||
|
||||
@@ -150,6 +150,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode);
|
||||
|
||||
void Close();
|
||||
void PersistToPath(const wchar_t* path) const;
|
||||
void RestoreFromPath(const wchar_t* path) const;
|
||||
|
||||
#pragma region ICoreState
|
||||
const size_t TaskbarState() const noexcept;
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace Microsoft.Terminal.Control
|
||||
String ProfileName;
|
||||
String ProfileSource;
|
||||
|
||||
Boolean EnableUnfocusedAcrylic;
|
||||
Boolean EnableUnfocusedAcrylic { get; };
|
||||
Guid SessionId { get; };
|
||||
ScrollbarState ScrollState { get; };
|
||||
|
||||
String FontFace { get; };
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "TermControl.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include "TermControlAutomationPeer.h"
|
||||
#include "../../renderer/atlas/AtlasEngine.h"
|
||||
@@ -1068,7 +1069,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_interactivity.Initialize();
|
||||
|
||||
if (!_restorePath.empty())
|
||||
{
|
||||
winrt::get_self<ControlCore>(_core)->RestoreFromPath(_restorePath.c_str());
|
||||
_restorePath = {};
|
||||
}
|
||||
|
||||
_core.Connection().Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2259,6 +2269,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.ExpandSelectionToWord();
|
||||
}
|
||||
|
||||
void TermControl::RestoreFromPath(winrt::hstring path)
|
||||
{
|
||||
_restorePath = std::move(path);
|
||||
}
|
||||
|
||||
void TermControl::PersistToPath(const winrt::hstring& path) const
|
||||
{
|
||||
winrt::get_self<ControlCore>(_core)->PersistToPath(path.c_str());
|
||||
}
|
||||
|
||||
void TermControl::Close()
|
||||
{
|
||||
if (!_IsClosing())
|
||||
@@ -2293,6 +2313,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::Detach()
|
||||
{
|
||||
_revokers = {};
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ToggleMarkMode();
|
||||
bool SwitchSelectionEndpoint();
|
||||
bool ExpandSelectionToWord();
|
||||
void RestoreFromPath(winrt::hstring path);
|
||||
void PersistToPath(const winrt::hstring& path) const;
|
||||
void Close();
|
||||
Windows::Foundation::Size CharacterDimensions() const;
|
||||
Windows::Foundation::Size MinimumSize();
|
||||
@@ -249,6 +251,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
SafeDispatcherTimer _blinkTimer;
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
winrt::hstring _restorePath;
|
||||
bool _showMarksInScrollbar{ false };
|
||||
|
||||
bool _isBackgroundLight{ false };
|
||||
|
||||
@@ -93,6 +93,8 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean SwitchSelectionEndpoint();
|
||||
Boolean ExpandSelectionToWord();
|
||||
void ClearBuffer(ClearBufferType clearType);
|
||||
void RestoreFromPath(String path);
|
||||
void PersistToPath(String path);
|
||||
void Close();
|
||||
Windows.Foundation.Size CharacterDimensions { get; };
|
||||
Windows.Foundation.Size MinimumSize { get; };
|
||||
|
||||
@@ -1549,6 +1549,11 @@ std::wstring_view Terminal::CurrentCommand() const
|
||||
return _activeBuffer().CurrentCommand();
|
||||
}
|
||||
|
||||
void Terminal::SerializeMainBuffer(const wchar_t* destination) const
|
||||
{
|
||||
_mainBuffer->Serialize(destination);
|
||||
}
|
||||
|
||||
void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode)
|
||||
{
|
||||
const auto colorSelection = [this](const til::point coordStart, const til::point coordEnd, const TextAttribute& attr) {
|
||||
|
||||
@@ -126,6 +126,7 @@ public:
|
||||
til::property<bool> AlwaysNotifyOnBufferRotation;
|
||||
|
||||
std::wstring_view CurrentCommand() const;
|
||||
void SerializeMainBuffer(const wchar_t* destination) const;
|
||||
|
||||
#pragma region ITerminalApi
|
||||
// These methods are defined in TerminalApi.cpp
|
||||
|
||||
@@ -129,6 +129,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
ss << fmt::format(L"--profile \"{}\" ", Profile());
|
||||
}
|
||||
|
||||
if (const auto id = SessionId(); id != winrt::guid{})
|
||||
{
|
||||
const auto str = ::Microsoft::Console::Utils::GuidToString(id);
|
||||
ss << fmt::format(L"--sessionId \"{}\" ", str);
|
||||
}
|
||||
|
||||
// The caller is always expected to provide the evaluated profile in the
|
||||
// NewTerminalArgs, not the index
|
||||
//
|
||||
|
||||
@@ -309,6 +309,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
ACTION_ARG(Windows::Foundation::IReference<Windows::UI::Color>, TabColor, nullptr);
|
||||
ACTION_ARG(Windows::Foundation::IReference<int32_t>, ProfileIndex, nullptr);
|
||||
ACTION_ARG(winrt::hstring, Profile, L"");
|
||||
ACTION_ARG(winrt::guid, SessionId, winrt::guid{});
|
||||
ACTION_ARG(bool, AppendCommandLine, false);
|
||||
ACTION_ARG(Windows::Foundation::IReference<bool>, SuppressApplicationTitle, nullptr);
|
||||
ACTION_ARG(winrt::hstring, ColorScheme);
|
||||
@@ -322,6 +323,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static constexpr std::string_view TabColorKey{ "tabColor" };
|
||||
static constexpr std::string_view ProfileIndexKey{ "index" };
|
||||
static constexpr std::string_view ProfileKey{ "profile" };
|
||||
static constexpr std::string_view SessionIdKey{ "sessionId" };
|
||||
static constexpr std::string_view AppendCommandLineKey{ "appendCommandLine" };
|
||||
static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" };
|
||||
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
|
||||
@@ -362,6 +364,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::GetValueForKey(json, TabTitleKey, args->_TabTitle);
|
||||
JsonUtils::GetValueForKey(json, ProfileIndexKey, args->_ProfileIndex);
|
||||
JsonUtils::GetValueForKey(json, ProfileKey, args->_Profile);
|
||||
JsonUtils::GetValueForKey(json, SessionIdKey, args->_SessionId);
|
||||
JsonUtils::GetValueForKey(json, TabColorKey, args->_TabColor);
|
||||
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
@@ -383,6 +386,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::SetValueForKey(json, TabTitleKey, args->_TabTitle);
|
||||
JsonUtils::SetValueForKey(json, ProfileIndexKey, args->_ProfileIndex);
|
||||
JsonUtils::SetValueForKey(json, ProfileKey, args->_Profile);
|
||||
JsonUtils::SetValueForKey(json, SessionIdKey, args->_SessionId);
|
||||
JsonUtils::SetValueForKey(json, TabColorKey, args->_TabColor);
|
||||
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
@@ -400,6 +404,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
copy->_TabColor = _TabColor;
|
||||
copy->_ProfileIndex = _ProfileIndex;
|
||||
copy->_Profile = _Profile;
|
||||
copy->_SessionId = _SessionId;
|
||||
copy->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
||||
copy->_ColorScheme = _ColorScheme;
|
||||
copy->_Elevate = _Elevate;
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
String TabTitle;
|
||||
Windows.Foundation.IReference<Windows.UI.Color> TabColor;
|
||||
String Profile; // Either a GUID or a profile's name if the GUID isn't a match
|
||||
Guid SessionId;
|
||||
Boolean AppendCommandLine;
|
||||
|
||||
// We use IReference<> to treat some args as nullable where null means
|
||||
|
||||
@@ -240,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;
|
||||
}
|
||||
|
||||
@@ -294,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 \
|
||||
|
||||
@@ -69,6 +69,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
void FromJson(const Json::Value& root, FileSource parseSource) const noexcept;
|
||||
Json::Value ToJson(FileSource parseSource) const noexcept;
|
||||
|
||||
void AppendPersistedWindowLayout(Model::WindowLayout layout);
|
||||
|
||||
// State getters/setters
|
||||
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
|
||||
type name() const noexcept; \
|
||||
|
||||
@@ -32,6 +32,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
void Flush();
|
||||
void Reset();
|
||||
|
||||
void AppendPersistedWindowLayout(WindowLayout layout);
|
||||
|
||||
String SettingsHash;
|
||||
Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts;
|
||||
Windows.Foundation.Collections.IVector<String> RecentCommands;
|
||||
|
||||
@@ -106,6 +106,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static Model::CascadiaSettings LoadDefaults();
|
||||
static Model::CascadiaSettings LoadAll();
|
||||
|
||||
static winrt::hstring SettingsDirectory();
|
||||
static winrt::hstring SettingsPath();
|
||||
static winrt::hstring DefaultSettingsPath();
|
||||
static winrt::hstring ApplicationDisplayName();
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
static CascadiaSettings LoadDefaults();
|
||||
static CascadiaSettings LoadAll();
|
||||
|
||||
static String SettingsDirectory { get; };
|
||||
static String SettingsPath { get; };
|
||||
static String DefaultSettingsPath { get; };
|
||||
static Boolean IsPortableMode { get; };
|
||||
|
||||
@@ -1244,6 +1244,13 @@ winrt::hstring CascadiaSettings::_calculateHash(std::string_view settings, const
|
||||
return winrt::hstring{ hash };
|
||||
}
|
||||
|
||||
// This returns something akin to %LOCALAPPDATA%\Packages\WindowsTerminalDev_8wekyb3d8bbwe\LocalState
|
||||
// just like SettingsPath(), but without the trailing \settings.json.
|
||||
winrt::hstring CascadiaSettings::SettingsDirectory()
|
||||
{
|
||||
return winrt::hstring{ GetBaseSettingsPath().native() };
|
||||
}
|
||||
|
||||
// function Description:
|
||||
// - Returns the full path to the settings file, either within the application
|
||||
// package, or in its unpackaged location. This path is under the "Local
|
||||
|
||||
@@ -126,6 +126,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
if (newTerminalArgs)
|
||||
{
|
||||
if (const auto id = newTerminalArgs.SessionId(); id != winrt::guid{})
|
||||
{
|
||||
defaultSettings.SessionId(id);
|
||||
}
|
||||
|
||||
// Override commandline, starting directory if they exist in newTerminalArgs
|
||||
if (!newTerminalArgs.Commandline().empty())
|
||||
{
|
||||
|
||||
@@ -118,6 +118,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileSource);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, guid, SessionId);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, EnableUnfocusedAcrylic, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
// The getters for these are already defined in IControlSettings. So
|
||||
// we're just adding the setters here, because TerminalApp likes to be
|
||||
// able to change these at runtime (e.g. when duplicating a pane).
|
||||
Guid SessionId { set; };
|
||||
String Commandline { set; };
|
||||
String StartingDirectory { set; };
|
||||
|
||||
|
||||
@@ -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
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> QuitAllRequested;
|
||||
til::typed_event<> QuitRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest> AttachRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs> SendContentRequested;
|
||||
};
|
||||
@@ -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
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> WindowCreated;
|
||||
til::typed_event<> WindowClosed;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, Remoting::QuitAllRequestedArgs> QuitAllRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, Remoting::WindowRequestedArgs> RequestNewWindow;
|
||||
};
|
||||
|
||||
|
||||
@@ -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*/,
|
||||
|
||||
@@ -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{};
|
||||
|
||||
|
||||
@@ -348,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::chrono::seconds(10), [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
|
||||
@@ -584,6 +485,80 @@ void WindowEmperor::_finalizeSessionPersistence() const
|
||||
|
||||
// Ensure to write the state.json before we TerminateProcess()
|
||||
state.Flush();
|
||||
|
||||
if (!_app.Logic().ShouldUsePersistedLayout())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the "buffer_{guid}.txt" files that we expect to be there
|
||||
std::unordered_set<winrt::guid> sessionIds;
|
||||
if (const auto layouts = state.PersistedWindowLayouts())
|
||||
{
|
||||
for (const auto& windowLayout : layouts)
|
||||
{
|
||||
for (const auto& actionAndArgs : windowLayout.TabLayout())
|
||||
{
|
||||
const auto args = actionAndArgs.Args();
|
||||
NewTerminalArgs terminalArgs{ nullptr };
|
||||
|
||||
if (const auto tabArgs = args.try_as<NewTabArgs>())
|
||||
{
|
||||
terminalArgs = tabArgs.TerminalArgs();
|
||||
}
|
||||
else if (const auto paneArgs = args.try_as<SplitPaneArgs>())
|
||||
{
|
||||
terminalArgs = paneArgs.TerminalArgs();
|
||||
}
|
||||
|
||||
if (terminalArgs)
|
||||
{
|
||||
sessionIds.emplace(terminalArgs.SessionId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the "buffer_{guid}.txt" files that shouldn't be there
|
||||
// e.g. "buffer_FD40D746-163E-444C-B9B2-6A3EA2B26722.txt"
|
||||
{
|
||||
const std::filesystem::path settingsDirectory{ std::wstring_view{ CascadiaSettings::SettingsDirectory() } };
|
||||
const auto filter = settingsDirectory / L"buffer_*";
|
||||
WIN32_FIND_DATAW ffd;
|
||||
|
||||
// This could also use std::filesystem::directory_iterator.
|
||||
// I was just slightly bothered by how it doesn't have a O(1) .filename()
|
||||
// function, even though the underlying Win32 APIs provide it for free.
|
||||
// Both work fine.
|
||||
const wil::unique_hfind handle{ FindFirstFileExW(filter.c_str(), FindExInfoBasic, &ffd, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH) };
|
||||
if (!handle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
const auto nameLen = wcsnlen_s(&ffd.cFileName[0], ARRAYSIZE(ffd.cFileName));
|
||||
const std::wstring_view name{ &ffd.cFileName[0], nameLen };
|
||||
|
||||
if (nameLen != 47)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
wchar_t guidStr[39];
|
||||
guidStr[0] = L'{';
|
||||
memcpy(&guidStr[1], name.data() + 7, 36 * sizeof(wchar_t));
|
||||
guidStr[37] = L'}';
|
||||
guidStr[38] = L'\0';
|
||||
|
||||
const auto id = Utils::GuidFromString(&guidStr[0]);
|
||||
if (!sessionIds.contains(id))
|
||||
{
|
||||
std::filesystem::remove(settingsDirectory / name);
|
||||
}
|
||||
} while (FindNextFileW(handle.get(), &ffd));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
@@ -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);
|
||||
@@ -90,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{};
|
||||
};
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#define CONTROL_SETTINGS(X) \
|
||||
X(winrt::hstring, ProfileName) \
|
||||
X(winrt::hstring, ProfileSource) \
|
||||
X(winrt::guid, SessionId) \
|
||||
X(bool, EnableUnfocusedAcrylic, false) \
|
||||
X(winrt::hstring, Padding, DEFAULT_PADDING) \
|
||||
X(winrt::hstring, FontFace, L"Consolas") \
|
||||
|
||||
@@ -577,18 +577,26 @@ namespace til
|
||||
|
||||
void resize(size_type new_size)
|
||||
{
|
||||
_generic_resize(new_size, [](auto&& beg, auto&& end) {
|
||||
_generic_resize(new_size, [](iterator&& beg, iterator&& end) {
|
||||
std::uninitialized_value_construct(beg, end);
|
||||
});
|
||||
}
|
||||
|
||||
void resize(size_type new_size, const_reference value)
|
||||
{
|
||||
_generic_resize(new_size, [&](auto&& beg, auto&& end) {
|
||||
_generic_resize(new_size, [&](iterator&& beg, iterator&& end) {
|
||||
std::uninitialized_fill(beg, end, value);
|
||||
});
|
||||
}
|
||||
|
||||
void resize_and_overwrite(size_type new_size, auto op)
|
||||
requires std::is_trivial_v<T>
|
||||
{
|
||||
_size = 0;
|
||||
reserve(new_size);
|
||||
_size = std::move(op)(_data, new_size);
|
||||
}
|
||||
|
||||
void shrink_to_fit()
|
||||
{
|
||||
if (_capacity == N || _size == _capacity)
|
||||
@@ -863,7 +871,7 @@ namespace til
|
||||
|
||||
// An optimization for the most common vector type which is trivially constructible, destructible and copyable.
|
||||
// This allows us to drop exception handlers (= no need to push onto the stack) and replace two moves with just one.
|
||||
if constexpr (noexcept(func(begin())) && std::is_trivially_destructible_v<T> && std::is_trivially_copyable_v<T>)
|
||||
if constexpr (noexcept(func(begin())) && std::is_trivial_v<T>)
|
||||
{
|
||||
_size = new_size;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user