mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 13:57:43 +00:00
Compare commits
189 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8428f666bf | ||
|
|
a35c23f667 | ||
|
|
8c5bfb5756 | ||
|
|
59d6ff29a8 | ||
|
|
7591b0f404 | ||
|
|
2c15f97ee8 | ||
|
|
48aa555428 | ||
|
|
b983c69c8e | ||
|
|
fda16631cc | ||
|
|
88033246f1 | ||
|
|
08f6a53be5 | ||
|
|
8e2c7a7bdd | ||
|
|
1e331a037c | ||
|
|
5c852c3c4c | ||
|
|
7e2eb0d8e5 | ||
|
|
17dbc7b5ce | ||
|
|
08acc90e5f | ||
|
|
4f8d64ec6f | ||
|
|
5164bffa78 | ||
|
|
ada3f427a0 | ||
|
|
5e23a72beb | ||
|
|
0199aba286 | ||
|
|
b589d092e9 | ||
|
|
74260ce6e1 | ||
|
|
01388c95b0 | ||
|
|
fa1140dc07 | ||
|
|
e1472095e2 | ||
|
|
b9dc8c3f5b | ||
|
|
055cdfedd0 | ||
|
|
257fe33269 | ||
|
|
34bc66f8bf | ||
|
|
6934bc8d05 | ||
|
|
cacb822cf6 | ||
|
|
b75fb24512 | ||
|
|
c79f27c3da | ||
|
|
273f2a84ef | ||
|
|
d2a5a4aab7 | ||
|
|
9a4739659b | ||
|
|
7649725150 | ||
|
|
b1a867db6c | ||
|
|
614ec58c31 | ||
|
|
70450afe7e | ||
|
|
9ec9da3da2 | ||
|
|
b5dbae9244 | ||
|
|
d67815bf0c | ||
|
|
6586c4a816 | ||
|
|
0cf13d81b1 | ||
|
|
2537342ffb | ||
|
|
c6cce0fd6b | ||
|
|
b41ae7115c | ||
|
|
c2a2caf029 | ||
|
|
951ece1f3e | ||
|
|
1f8766e972 | ||
|
|
091660e96d | ||
|
|
0e0d8572a3 | ||
|
|
9da1192993 | ||
|
|
f9caf191a9 | ||
|
|
13257dafa0 | ||
|
|
ecab57fba1 | ||
|
|
091f32c575 | ||
|
|
62a4ee058b | ||
|
|
2bc578bc6c | ||
|
|
667b6586d2 | ||
|
|
bc80943fd9 | ||
|
|
aa8b0c564d | ||
|
|
118bffa6cd | ||
|
|
f10dfac20f | ||
|
|
e5f98807e2 | ||
|
|
8cac90fc4d | ||
|
|
d06ad8b5dc | ||
|
|
4b22963f9d | ||
|
|
855a79dbe0 | ||
|
|
28735112d2 | ||
|
|
83da057a70 | ||
|
|
3988a1c4e5 | ||
|
|
2262f5574e | ||
|
|
77346000df | ||
|
|
7d903dea4a | ||
|
|
4eba01f919 | ||
|
|
f0802618e8 | ||
|
|
68fad338cc | ||
|
|
0f0316f322 | ||
|
|
3f9decaa82 | ||
|
|
d9d4d2e62d | ||
|
|
82224bc87a | ||
|
|
a9ac218c4d | ||
|
|
603a2ce53a | ||
|
|
2621519f20 | ||
|
|
1ec8c0de2e | ||
|
|
a4f19a9dff | ||
|
|
33685d9e9d | ||
|
|
65084c84ec | ||
|
|
0ce6309c11 | ||
|
|
c0658975b2 | ||
|
|
a76993365e | ||
|
|
dffb41601b | ||
|
|
e40575b18b | ||
|
|
cfa61088fe | ||
|
|
0ad5b596bd | ||
|
|
7660937139 | ||
|
|
45487294a0 | ||
|
|
f904e5d22d | ||
|
|
0395dc40a3 | ||
|
|
7e91bdb289 | ||
|
|
c69f0bc444 | ||
|
|
e214624e1f | ||
|
|
b0726c2057 | ||
|
|
055da357b1 | ||
|
|
950ce6c4fc | ||
|
|
0b79e81ae9 | ||
|
|
a7379ca8e9 | ||
|
|
4d5f6d27fb | ||
|
|
3fb8e8cac3 | ||
|
|
6e6d14e0dc | ||
|
|
a5a9930354 | ||
|
|
0f4c4d8eef | ||
|
|
8bb839113a | ||
|
|
dc1ae9a895 | ||
|
|
84e228f1fe | ||
|
|
3026922e59 | ||
|
|
64257d830a | ||
|
|
4db381e2cb | ||
|
|
40fdbc1536 | ||
|
|
07ff4183e4 | ||
|
|
d5396d1104 | ||
|
|
93e9dc505d | ||
|
|
761bd6a6ab | ||
|
|
23c4d4c0f8 | ||
|
|
4e7da2ec13 | ||
|
|
2332f0c0e4 | ||
|
|
337b7b5699 | ||
|
|
a7353ac347 | ||
|
|
f27db5997e | ||
|
|
2822c36507 | ||
|
|
f06e484324 | ||
|
|
9924e23dec | ||
|
|
47336c0982 | ||
|
|
2122eec186 | ||
|
|
81524ea71e | ||
|
|
e3fa46ff94 | ||
|
|
38b28e5bdb | ||
|
|
700aadcb15 | ||
|
|
7bad8c9642 | ||
|
|
eea6a7bcca | ||
|
|
1cef94e696 | ||
|
|
c9ed8dc042 | ||
|
|
e2882055ee | ||
|
|
ee63aff320 | ||
|
|
ad1f331154 | ||
|
|
c82051ffdd | ||
|
|
11f6561153 | ||
|
|
380f0295ca | ||
|
|
828695ee8a | ||
|
|
ba7b5aec79 | ||
|
|
c282797cac | ||
|
|
a20201fff2 | ||
|
|
40046c38dc | ||
|
|
427a4a51c5 | ||
|
|
17057d147d | ||
|
|
631f690e42 | ||
|
|
57d1dd4358 | ||
|
|
713ea71725 | ||
|
|
0f33913423 | ||
|
|
1f56807fa0 | ||
|
|
0a6c21fed0 | ||
|
|
ebe5fd8163 | ||
|
|
d143f312d3 | ||
|
|
3bd6957a6d | ||
|
|
6a2239d487 | ||
|
|
4dcc67b4d7 | ||
|
|
37a8fde29c | ||
|
|
1b4f1efb09 | ||
|
|
e623299ac6 | ||
|
|
274d62d8a8 | ||
|
|
f655296c1e | ||
|
|
7a3e2e098d | ||
|
|
2c4613a494 | ||
|
|
f5b030c28c | ||
|
|
d456210f37 | ||
|
|
af14c2b751 | ||
|
|
ef7e2edfa5 | ||
|
|
5116ca1e77 | ||
|
|
2195515937 | ||
|
|
99bc280207 | ||
|
|
439b21f879 | ||
|
|
936c01f948 | ||
|
|
e6220b7fe7 | ||
|
|
a5255ba8ed | ||
|
|
581acd40d9 |
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
@@ -160,6 +160,7 @@ rcx
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
RLO
|
||||
ROOTOWNER
|
||||
roundf
|
||||
RSHIFT
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -6,7 +6,7 @@
|
||||
"C_Cpp.loggingLevel": "None",
|
||||
"files.associations": {
|
||||
"xstring": "cpp",
|
||||
"*.idl": "cpp",
|
||||
"*.idl": "midl3",
|
||||
"array": "cpp",
|
||||
"future": "cpp",
|
||||
"istream": "cpp",
|
||||
@@ -106,4 +106,4 @@
|
||||
"**/packages/**": true,
|
||||
"**/Generated Files/**": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1822,7 +1822,7 @@
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the theme. This will be displayed in the settings UI.",
|
||||
"not": {
|
||||
"not": {
|
||||
"enum": [ "light", "dark", "system" ]
|
||||
}
|
||||
},
|
||||
@@ -2092,6 +2092,11 @@
|
||||
"description": "When set to true, the terminal will focus the pane on mouse hover.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"compatibility.isolatedMode": {
|
||||
"default": false,
|
||||
"description": "When set to true, Terminal windows will not be able to interact with each other (including global hotkeys, tab drag/drop, running commandlines in existing windows, etc.). This is a compatibility escape hatch for users who are running into certain windowing issues.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"copyFormatting": {
|
||||
"default": true,
|
||||
"description": "When set to `true`, the color and font formatting of selected text is also copied to your clipboard. When set to `false`, only plain text is copied to your clipboard. An array of specific formats can also be used. Supported array values include `html` and `rtf`. Plain text is always copied.",
|
||||
|
||||
@@ -164,8 +164,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
@@ -287,8 +288,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
@@ -412,8 +414,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(L"${profile.name}", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
@@ -527,8 +530,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
@@ -621,8 +625,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
@@ -744,8 +749,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
@@ -880,8 +886,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
@@ -982,8 +989,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size());
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(settings.ActionMap().NameMap(), settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
@@ -1205,8 +1213,9 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_ARE_EQUAL(L"${scheme.name}", realArgs.TerminalArgs().Profile());
|
||||
}
|
||||
|
||||
auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes());
|
||||
_logCommandNames(expandedCommands.GetView());
|
||||
settings.ExpandCommands();
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommandNames(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
|
||||
@@ -42,6 +42,17 @@ namespace TerminalAppLocalTests
|
||||
// an updated TAEF that will let us install framework packages when the test
|
||||
// package is deployed. Until then, these tests won't deploy in CI.
|
||||
|
||||
struct WindowProperties : winrt::implements<WindowProperties, winrt::TerminalApp::IWindowProperties>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(uint64_t, WindowId);
|
||||
WINRT_PROPERTY(winrt::hstring, WindowNameForDisplay);
|
||||
WINRT_PROPERTY(winrt::hstring, WindowIdForDisplay);
|
||||
|
||||
public:
|
||||
bool IsQuakeWindow() { return _WindowName == L"_quake"; };
|
||||
};
|
||||
|
||||
class TabTests
|
||||
{
|
||||
// For this set of tests, we need to activate some XAML content. For
|
||||
@@ -110,6 +121,7 @@ namespace TerminalAppLocalTests
|
||||
void _initializeTerminalPage(winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage>& page,
|
||||
CascadiaSettings initialSettings);
|
||||
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> _commonSetup();
|
||||
winrt::com_ptr<WindowProperties> _windowProperties;
|
||||
};
|
||||
|
||||
template<typename TFunction>
|
||||
@@ -239,11 +251,15 @@ namespace TerminalAppLocalTests
|
||||
// it's weird.
|
||||
winrt::TerminalApp::TerminalPage projectedPage{ nullptr };
|
||||
|
||||
_windowProperties = winrt::make_self<WindowProperties>();
|
||||
winrt::TerminalApp::IWindowProperties iProps{ *_windowProperties };
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Construct the TerminalPage"));
|
||||
auto result = RunOnUIThread([&projectedPage, &page, initialSettings]() {
|
||||
auto result = RunOnUIThread([&projectedPage, &page, initialSettings, iProps]() {
|
||||
projectedPage = winrt::TerminalApp::TerminalPage();
|
||||
page.copy_from(winrt::get_self<winrt::TerminalApp::implementation::TerminalPage>(projectedPage));
|
||||
page->_settings = initialSettings;
|
||||
page->WindowProperties(iProps);
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
|
||||
@@ -1242,10 +1258,13 @@ namespace TerminalAppLocalTests
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
auto page = _commonSetup();
|
||||
page->RenameWindowRequested([&page](auto&&, const winrt::TerminalApp::RenameWindowRequestedArgs args) {
|
||||
page->RenameWindowRequested([&page, this](auto&&, const winrt::TerminalApp::RenameWindowRequestedArgs args) {
|
||||
// In the real terminal, this would bounce up to the monarch and
|
||||
// come back down. Instead, immediately call back and set the name.
|
||||
page->WindowName(args.ProposedName());
|
||||
//
|
||||
// This replicates how TerminalWindow works
|
||||
_windowProperties->WindowName(args.ProposedName());
|
||||
page->WindowNameChanged();
|
||||
});
|
||||
|
||||
auto windowNameChanged = false;
|
||||
@@ -1260,7 +1279,7 @@ namespace TerminalAppLocalTests
|
||||
page->_RequestWindowRename(winrt::hstring{ L"Foo" });
|
||||
});
|
||||
TestOnUIThread([&]() {
|
||||
VERIFY_ARE_EQUAL(L"Foo", page->_WindowName);
|
||||
VERIFY_ARE_EQUAL(L"Foo", page->WindowName());
|
||||
VERIFY_IS_TRUE(windowNameChanged,
|
||||
L"The window name should have changed, and we should have raised a notification that WindowNameForDisplay changed");
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "ProposeCommandlineResult.h"
|
||||
|
||||
#include "Monarch.g.cpp"
|
||||
#include "WindowRequestedArgs.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace winrt;
|
||||
@@ -687,6 +688,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
case WindowingBehaviorUseName:
|
||||
windowID = _lookupPeasantIdForName(targetWindowName);
|
||||
break;
|
||||
case WindowingBehaviorUseNone:
|
||||
// This should be impossible. The if statement above should have
|
||||
// prevented WindowingBehaviorUseNone from falling in here.
|
||||
// Explode, because this is a programming error.
|
||||
THROW_HR(E_UNEXPECTED);
|
||||
default:
|
||||
windowID = ::base::saturated_cast<uint64_t>(targetWindow);
|
||||
break;
|
||||
@@ -724,6 +730,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
result->WindowName(targetWindowName);
|
||||
result->ShouldCreateWindow(true);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
// If this fails, it'll be logged in the following
|
||||
// TraceLoggingWrite statement, with succeeded=false
|
||||
}
|
||||
@@ -759,9 +767,20 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto result{ winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true) };
|
||||
result->Id(windowID);
|
||||
result->WindowName(targetWindowName);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
else if (targetWindow == WindowingBehaviorUseNone)
|
||||
{
|
||||
// In this case, the targetWindow was UseNone, which means that we
|
||||
// want to make a message box, but otherwise not make a Terminal
|
||||
// window.
|
||||
auto result = winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(false);
|
||||
return *result;
|
||||
}
|
||||
|
||||
// If we get here, we couldn't find an existing window. Make a new one.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
@@ -773,6 +792,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// In this case, no usable ID was provided. Return { true, nullopt }
|
||||
auto result = winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true);
|
||||
result->WindowName(targetWindowName);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
@@ -1034,4 +1056,95 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
return winrt::single_threaded_vector(std::move(vec));
|
||||
}
|
||||
|
||||
void Monarch::RequestMoveContent(winrt::hstring window,
|
||||
winrt::hstring content,
|
||||
uint32_t tabIndex,
|
||||
Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds)
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_Requested",
|
||||
TraceLoggingWideString(window.c_str(), "window", "The name of the window we tried to move to"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
uint64_t windowId = _lookupPeasantIdForName(window);
|
||||
if (windowId == 0)
|
||||
{
|
||||
// Try the name as an integer ID
|
||||
uint32_t temp;
|
||||
if (!Utils::StringToUint(window.c_str(), temp))
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_FailedToParseId",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
windowId = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto targetPeasant{ _getPeasant(windowId) })
|
||||
{
|
||||
auto request = winrt::make_self<implementation::AttachRequest>(content, tabIndex);
|
||||
targetPeasant.AttachContentToWindow(*request);
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_Completed",
|
||||
TraceLoggingInt64(windowId, "windowId", "The ID of the peasant which we sent the content to"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_MoveContent_NoWindow",
|
||||
TraceLoggingInt64(windowId, "windowId", "We could not find a peasant with this ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// In the case where window couldn't be found, then create a window
|
||||
// for that name / ID.
|
||||
//
|
||||
// Don't let the window literally be named "-1", because that's silly
|
||||
auto request = winrt::make_self<implementation::WindowRequestedArgs>(window == L"-1" ? L"" : window,
|
||||
content,
|
||||
windowBounds);
|
||||
_RequestNewWindowHandlers(*this, *request);
|
||||
}
|
||||
}
|
||||
|
||||
// Very similar to the above. Someone came and told us that they were the target of a drag/drop, and they know who started it.
|
||||
// We will go tell the person who started it that they should send that target the content which was dragged.
|
||||
void Monarch::RequestSendContent(Remoting::RequestReceiveContentArgs args)
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SendContent_Requested",
|
||||
TraceLoggingUInt64(args.SourceWindow(), "source", "The window which started the drag"),
|
||||
TraceLoggingUInt64(args.TargetWindow(), "target", "The window which was the target of the drop"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
if (auto senderPeasant{ _getPeasant(args.SourceWindow()) })
|
||||
{
|
||||
senderPeasant.SendContent(args);
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SendContent_Completed",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't find the peasant that started the drag. Well that
|
||||
// sure is weird, but that would indicate that the sender closed
|
||||
// after starting the drag. No matter. We can just do nothing.
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_SendContent_NoWindow",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Monarch.g.h"
|
||||
#include "Peasant.h"
|
||||
#include "WindowActivatedArgs.h"
|
||||
#include "WindowRequestedArgs.g.h"
|
||||
#include <atomic>
|
||||
|
||||
// We sure different GUIDs here depending on whether we're running a Release,
|
||||
@@ -38,6 +39,36 @@ namespace RemotingUnitTests
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct WindowRequestedArgs : public WindowRequestedArgsT<WindowRequestedArgs>
|
||||
{
|
||||
public:
|
||||
WindowRequestedArgs(const Remoting::ProposeCommandlineResult& result, const Remoting::CommandlineArgs& command) :
|
||||
_Id{ result.Id() },
|
||||
_WindowName{ result.WindowName() },
|
||||
_args{ command.Commandline() },
|
||||
_CurrentDirectory{ command.CurrentDirectory() } {};
|
||||
|
||||
WindowRequestedArgs(const winrt::hstring& window, const winrt::hstring& content, Windows::Foundation::IReference<Windows::Foundation::Rect> bounds) :
|
||||
_Id{ nullptr },
|
||||
_WindowName{ window },
|
||||
_args{},
|
||||
_CurrentDirectory{},
|
||||
_Content{ content },
|
||||
_InitialBounds{ bounds } {};
|
||||
|
||||
void Commandline(const winrt::array_view<const winrt::hstring>& value) { _args = { value.begin(), value.end() }; };
|
||||
winrt::com_array<winrt::hstring> Commandline() { return winrt::com_array<winrt::hstring>{ _args.begin(), _args.end() }; }
|
||||
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<uint64_t>, Id);
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(winrt::hstring, CurrentDirectory);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
|
||||
|
||||
private:
|
||||
winrt::com_array<winrt::hstring> _args;
|
||||
};
|
||||
|
||||
struct Monarch : public MonarchT<Monarch>
|
||||
{
|
||||
Monarch();
|
||||
@@ -60,6 +91,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
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, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
|
||||
void RequestSendContent(Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
@@ -67,6 +101,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
|
||||
|
||||
private:
|
||||
uint64_t _ourPID;
|
||||
|
||||
@@ -191,4 +227,5 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Monarch);
|
||||
BASIC_FACTORY(WindowRequestedArgs);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,19 @@ namespace Microsoft.Terminal.Remoting
|
||||
Boolean ShouldCreateWindow { get; }; // If you name this `CreateWindow`, the compiler will explode
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass WindowRequestedArgs {
|
||||
WindowRequestedArgs(ProposeCommandlineResult result, CommandlineArgs command);
|
||||
|
||||
Windows.Foundation.IReference<UInt64> Id { get; };
|
||||
String WindowName { get; };
|
||||
|
||||
String[] Commandline { get; };
|
||||
String CurrentDirectory { get; };
|
||||
|
||||
String Content { get; };
|
||||
Windows.Foundation.IReference<Windows.Foundation.Rect> InitialBounds { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass SummonWindowSelectionArgs {
|
||||
SummonWindowSelectionArgs();
|
||||
SummonWindowSelectionArgs(String windowName);
|
||||
@@ -31,8 +44,7 @@ namespace Microsoft.Terminal.Remoting
|
||||
Windows.Foundation.IReference<UInt64> WindowID;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass QuitAllRequestedArgs
|
||||
{
|
||||
[default_interface] runtimeclass QuitAllRequestedArgs {
|
||||
QuitAllRequestedArgs();
|
||||
Windows.Foundation.IAsyncAction BeforeQuitAllAction;
|
||||
}
|
||||
@@ -60,12 +72,17 @@ namespace Microsoft.Terminal.Remoting
|
||||
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);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
|
||||
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;
|
||||
};
|
||||
|
||||
runtimeclass Monarch : [default] IMonarch
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "GetWindowLayoutArgs.h"
|
||||
#include "Peasant.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "AttachRequest.g.cpp"
|
||||
#include "RequestReceiveContentArgs.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
@@ -275,6 +277,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::AttachContentToWindow(Remoting::AttachRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
_AttachRequestedHandlers(*this, request);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_AttachContentToWindow",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
void Peasant::Quit()
|
||||
{
|
||||
try
|
||||
@@ -310,4 +328,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
}
|
||||
return args->WindowLayoutJson();
|
||||
}
|
||||
|
||||
void Peasant::SendContent(winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs args)
|
||||
{
|
||||
_SendContentRequestedHandlers(*this, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "Peasant.g.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
#include "AttachRequest.g.h"
|
||||
#include "RequestReceiveContentArgs.g.h"
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
@@ -12,6 +14,31 @@ namespace RemotingUnitTests
|
||||
};
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct AttachRequest : public AttachRequestT<AttachRequest>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
|
||||
public:
|
||||
AttachRequest(winrt::hstring content,
|
||||
uint32_t tabIndex) :
|
||||
_Content{ content },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct RequestReceiveContentArgs : RequestReceiveContentArgsT<RequestReceiveContentArgs>
|
||||
{
|
||||
WINRT_PROPERTY(uint64_t, SourceWindow);
|
||||
WINRT_PROPERTY(uint64_t, TargetWindow);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
|
||||
public:
|
||||
RequestReceiveContentArgs(const uint64_t src, const uint64_t tgt, const uint32_t tabIndex) :
|
||||
_SourceWindow{ src },
|
||||
_TargetWindow{ tgt },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct Peasant : public PeasantT<Peasant>
|
||||
{
|
||||
Peasant();
|
||||
@@ -32,11 +59,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void RequestQuitAll();
|
||||
void Quit();
|
||||
|
||||
void AttachContentToWindow(Remoting::AttachRequest request);
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
|
||||
|
||||
winrt::hstring GetWindowLayout();
|
||||
void SendContent(winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
|
||||
@@ -47,12 +77,16 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
|
||||
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
|
||||
TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
uint64_t _ourPID;
|
||||
@@ -69,4 +103,5 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Peasant);
|
||||
BASIC_FACTORY(RequestReceiveContentArgs);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ namespace Microsoft.Terminal.Remoting
|
||||
ToMouse,
|
||||
};
|
||||
|
||||
|
||||
[default_interface] runtimeclass SummonWindowBehavior {
|
||||
SummonWindowBehavior();
|
||||
Boolean MoveToCurrentDesktop;
|
||||
@@ -52,6 +51,18 @@ namespace Microsoft.Terminal.Remoting
|
||||
MonitorBehavior ToMonitor;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass AttachRequest {
|
||||
String Content { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
}
|
||||
[default_interface] runtimeclass RequestReceiveContentArgs {
|
||||
RequestReceiveContentArgs(UInt64 src, UInt64 tgt, UInt32 tabIndex);
|
||||
|
||||
UInt64 SourceWindow { get; };
|
||||
UInt64 TargetWindow { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
};
|
||||
|
||||
interface IPeasant
|
||||
{
|
||||
CommandlineArgs InitialArgs { get; };
|
||||
@@ -70,23 +81,31 @@ namespace Microsoft.Terminal.Remoting
|
||||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
void Summon(SummonWindowBehavior behavior);
|
||||
|
||||
void RequestShowNotificationIcon();
|
||||
void RequestHideNotificationIcon();
|
||||
void RequestQuitAll();
|
||||
void Quit();
|
||||
String GetWindowLayout();
|
||||
|
||||
void AttachContentToWindow(AttachRequest request);
|
||||
void SendContent(RequestReceiveContentArgs args);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
|
||||
|
||||
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;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, AttachRequest> AttachRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> SendContentRequested;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "WindowManager.h"
|
||||
#include "MonarchFactory.h"
|
||||
#include "CommandlineArgs.h"
|
||||
|
||||
#include "../inc/WindowingBehavior.h"
|
||||
#include "MonarchFactory.h"
|
||||
|
||||
#include "CommandlineArgs.h"
|
||||
#include "FindTargetWindowArgs.h"
|
||||
#include "ProposeCommandlineResult.h"
|
||||
|
||||
@@ -21,32 +24,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
WindowManager::WindowManager()
|
||||
{
|
||||
_monarchWaitInterrupt.create();
|
||||
|
||||
// Register with COM as a server for the Monarch class
|
||||
_registerAsMonarch();
|
||||
// Instantiate an instance of the Monarch. This may or may not be in-proc!
|
||||
auto foundMonarch = false;
|
||||
while (!foundMonarch)
|
||||
{
|
||||
try
|
||||
{
|
||||
_createMonarchAndCallbacks();
|
||||
// _createMonarchAndCallbacks will initialize _isKing
|
||||
foundMonarch = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If we fail to find the monarch,
|
||||
// stay in this jail until we do.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInCtor",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager()
|
||||
{
|
||||
// IMPORTANT! Tear down the registration as soon as we exit. If we're not a
|
||||
@@ -55,32 +33,185 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// monarch!
|
||||
CoRevokeClassObject(_registrationHostClass);
|
||||
_registrationHostClass = 0;
|
||||
SignalClose();
|
||||
_monarchWaitInterrupt.SetEvent();
|
||||
|
||||
// A thread is joinable once it's been started. Basically this just
|
||||
// makes sure that the thread isn't just default-constructed.
|
||||
if (_electionThread.joinable())
|
||||
{
|
||||
_electionThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::SignalClose()
|
||||
void WindowManager::_createMonarch()
|
||||
{
|
||||
// Heads up! This only works because we're using
|
||||
// "metadata-based-marshalling" for our WinRT types. That means the OS is
|
||||
// using the .winmd file we generate to figure out the proxy/stub
|
||||
// definitions for our types automatically. This only works in the following
|
||||
// cases:
|
||||
//
|
||||
// * If we're running unpackaged: the .winmd must be a sibling of the .exe
|
||||
// * If we're running packaged: the .winmd must be in the package root
|
||||
_monarch = try_create_instance<Remoting::IMonarch>(Monarch_clsid,
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
// Check if we became the king, and if we are, wire up callbacks.
|
||||
void WindowManager::_createCallbacks()
|
||||
{
|
||||
assert(_monarch);
|
||||
// Here, we're the king!
|
||||
//
|
||||
// This is where you should do any additional setup that might need to be
|
||||
// done when we become the king. This will be called both for the first
|
||||
// window, and when the current monarch dies.
|
||||
|
||||
_monarch.WindowCreated({ get_weak(), &WindowManager::_WindowCreatedHandlers });
|
||||
_monarch.WindowClosed({ get_weak(), &WindowManager::_WindowClosedHandlers });
|
||||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
|
||||
|
||||
_monarch.RequestNewWindow({ get_weak(), &WindowManager::_raiseRequestNewWindow });
|
||||
}
|
||||
|
||||
void WindowManager::_registerAsMonarch()
|
||||
{
|
||||
winrt::check_hresult(CoRegisterClassObject(Monarch_clsid,
|
||||
winrt::make<::MonarchFactory>().get(),
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
REGCLS_MULTIPLEUSE,
|
||||
&_registrationHostClass));
|
||||
}
|
||||
|
||||
void WindowManager::_raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
|
||||
{
|
||||
_FindTargetWindowRequestedHandlers(sender, args);
|
||||
}
|
||||
void WindowManager::_raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args)
|
||||
{
|
||||
_RequestNewWindowHandlers(sender, args);
|
||||
}
|
||||
|
||||
Remoting::ProposeCommandlineResult WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args, const bool isolatedMode)
|
||||
{
|
||||
bool shouldCreateWindow = false;
|
||||
|
||||
if (!isolatedMode)
|
||||
{
|
||||
// _createMonarch always attempts to connect an existing monarch. In
|
||||
// isolated mode, we don't want to do that.
|
||||
_createMonarch();
|
||||
}
|
||||
|
||||
if (_monarch)
|
||||
{
|
||||
try
|
||||
// We connected to a monarch instance, not us though. This won't hit
|
||||
// in isolated mode.
|
||||
|
||||
shouldCreateWindow = false;
|
||||
// Send the commandline over to the monarch process
|
||||
if (_proposeToMonarch(args))
|
||||
{
|
||||
_monarch.SignalClose(_peasant.GetID());
|
||||
// If that succeeded, then we don't need to make a new window.
|
||||
// Our job is done. Either the monarch is going to run the
|
||||
// commandline in an existing window, or a new one, but either way,
|
||||
// this process doesn't need to make a new window.
|
||||
|
||||
return winrt::make<ProposeCommandlineResult>(shouldCreateWindow);
|
||||
}
|
||||
// Otherwise, we'll try to handle this ourselves.
|
||||
}
|
||||
|
||||
// Theoretically, this condition is always true here:
|
||||
//
|
||||
// if (_monarch == nullptr)
|
||||
//
|
||||
// If we do still have a _monarch at this point, then we must have
|
||||
// successfully proposed to it in _proposeToMonarch, so we can't get
|
||||
// here with a monarch.
|
||||
{
|
||||
// No preexisting instance.
|
||||
|
||||
// Raise an event, to ask how to handle this commandline. We can't ask
|
||||
// the app ourselves - we exist isolated from that knowledge (and
|
||||
// dependency hell). The WindowManager will raise this up to the app
|
||||
// host, which will then ask the AppLogic, who will then parse the
|
||||
// commandline and determine the provided ID of the window.
|
||||
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
|
||||
|
||||
// This is handled by some handler in-proc
|
||||
_FindTargetWindowRequestedHandlers(*this, *findWindowArgs);
|
||||
|
||||
// After the event was handled, ResultTargetWindow() will be filled with
|
||||
// the parsed result.
|
||||
const auto targetWindow = findWindowArgs->ResultTargetWindow();
|
||||
const auto targetWindowName = findWindowArgs->ResultTargetWindowName();
|
||||
|
||||
if (targetWindow == WindowingBehaviorUseNone)
|
||||
{
|
||||
// This commandline doesn't deserve a window. Don't make a monarch
|
||||
// either.
|
||||
shouldCreateWindow = false;
|
||||
|
||||
return winrt::make<ProposeCommandlineResult>(shouldCreateWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This commandline _does_ want a window, which means we do want
|
||||
// to create a window, and a monarch.
|
||||
//
|
||||
// Congrats! This is now THE PROCESS. It's the only one that's
|
||||
// getting any windows.
|
||||
|
||||
// In isolated mode, we don't want to register as the monarch,
|
||||
// we just want to make a local one. So we'll skip this step.
|
||||
// The condition below it will handle making the unregistered
|
||||
// local monarch.
|
||||
|
||||
if (!isolatedMode)
|
||||
{
|
||||
_registerAsMonarch();
|
||||
_createMonarch();
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_IntentionallyIsolated",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
if (!_monarch)
|
||||
{
|
||||
// Something catastrophically bad happened here OR we were
|
||||
// intentionally in isolated mode. We don't want to just
|
||||
// exit immediately. Instead, we'll just instantiate a local
|
||||
// Monarch instance, without registering it. We're firmly in
|
||||
// the realm of undefined behavior, but better to have some
|
||||
// window than not.
|
||||
_monarch = winrt::make<Monarch>();
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_FailedToCoCreate",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
_createCallbacks();
|
||||
|
||||
// So, we wanted a new peasant. Cool!
|
||||
//
|
||||
// We need to fill in args.ResultTargetWindow,
|
||||
// args.ResultTargetWindowName so that we can create the new
|
||||
// window with those values. Otherwise, the very first window
|
||||
// won't obey the given name / ID.
|
||||
//
|
||||
// So let's just ask the monarch (ourselves) to get those values.
|
||||
return _monarch.ProposeCommandline(args);
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::_proposeToMonarch(const Remoting::CommandlineArgs& args,
|
||||
std::optional<uint64_t>& givenID,
|
||||
winrt::hstring& givenName)
|
||||
// Method Description:
|
||||
// - Helper attempting to call to the monarch multiple times. If the monarch
|
||||
// fails to respond, or we encounter any sort of error, we'll try again
|
||||
// until we find one, or decisively determine there isn't one.
|
||||
bool WindowManager::_proposeToMonarch(const Remoting::CommandlineArgs& args)
|
||||
{
|
||||
// these two errors are Win32 errors, convert them to HRESULTS so we can actually compare below.
|
||||
static constexpr auto RPC_SERVER_UNAVAILABLE_HR = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
|
||||
@@ -114,10 +245,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// dies between now and the inspection of
|
||||
// `result.ShouldCreateWindow` below, we don't want to explode
|
||||
// (since _proposeToMonarch is not try/caught).
|
||||
auto outOfProcResult = _monarch.ProposeCommandline(args);
|
||||
result = winrt::make<implementation::ProposeCommandlineResult>(outOfProcResult);
|
||||
|
||||
proposedCommandline = true;
|
||||
_monarch.ProposeCommandline(args);
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -154,560 +284,74 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_monarch = winrt::make<winrt::Microsoft::Terminal::Remoting::implementation::Monarch>();
|
||||
_createCallbacks();
|
||||
// Set the monarch to null, so that we'll create a new one
|
||||
// (or just generally check if we need to even make a window
|
||||
// for this commandline.)
|
||||
_monarch = nullptr;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We failed to ask the monarch. It must have died. Try and
|
||||
// find the real monarch. Don't perform an election, that
|
||||
// assumes we have a peasant, which we don't yet.
|
||||
_createMonarchAndCallbacks();
|
||||
// _createMonarchAndCallbacks will initialize _isKing
|
||||
}
|
||||
if (_isKing)
|
||||
{
|
||||
// We became the king. We don't need to ProposeCommandline to ourself, we're just
|
||||
// going to do it.
|
||||
//
|
||||
// Return early, because there's nothing else for us to do here.
|
||||
// find another monarch.
|
||||
_createMonarch();
|
||||
if (!_monarch)
|
||||
{
|
||||
// We failed to create a monarch. That means there
|
||||
// aren't any other windows, and we can become the monarch.
|
||||
return false;
|
||||
}
|
||||
// Go back around the loop.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_becameKing",
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// In WindowManager::ProposeCommandline, had we been the
|
||||
// king originally, we would have started by setting
|
||||
// this to true. We became the monarch here, so set it
|
||||
// here as well.
|
||||
_shouldCreateWindow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Here, we created the new monarch, it wasn't us, so we're
|
||||
// gonna go through the while loop again and ask the new
|
||||
// king.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_proposeToMonarch_tryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
|
||||
// Here, the monarch (not us) has replied to the message. Get the
|
||||
// valuables out of the response:
|
||||
_shouldCreateWindow = result.ShouldCreateWindow();
|
||||
if (result.Id())
|
||||
{
|
||||
givenID = result.Id().Value();
|
||||
}
|
||||
givenName = result.WindowName();
|
||||
|
||||
// TraceLogging doesn't have a good solution for logging an
|
||||
// optional. So we have to repeat the calls here:
|
||||
if (givenID)
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingPointer(nullptr, "Id", "No ID provided"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
void WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args)
|
||||
{
|
||||
// If we're the king, we _definitely_ want to process the arguments, we were
|
||||
// launched with them!
|
||||
//
|
||||
// Otherwise, the King will tell us if we should make a new window
|
||||
_shouldCreateWindow = _isKing;
|
||||
std::optional<uint64_t> givenID;
|
||||
winrt::hstring givenName{};
|
||||
if (!_isKing)
|
||||
{
|
||||
_proposeToMonarch(args, givenID, givenName);
|
||||
}
|
||||
|
||||
// During _proposeToMonarch, it's possible that we found that the king was dead, and we're the new king. Cool! Do this now.
|
||||
if (_isKing)
|
||||
{
|
||||
// We're the monarch, we don't need to propose anything. We're just
|
||||
// going to do it.
|
||||
//
|
||||
// However, we _do_ need to ask what our name should be. It's
|
||||
// possible someone started the _first_ wt with something like `wt
|
||||
// -w king` as the commandline - we want to make sure we set our
|
||||
// name to "king".
|
||||
//
|
||||
// The FindTargetWindow event is the WindowManager's way of saying
|
||||
// "I do not know how to figure out how to turn this list of args
|
||||
// into a window ID/name. Whoever's listening to this event does, so
|
||||
// I'll ask them". It's a convoluted way of hooking the
|
||||
// WindowManager up to AppLogic without actually telling it anything
|
||||
// about TerminalApp (or even WindowsTerminal)
|
||||
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
|
||||
_raiseFindTargetWindowRequested(nullptr, *findWindowArgs);
|
||||
|
||||
const auto responseId = findWindowArgs->ResultTargetWindow();
|
||||
if (responseId > 0)
|
||||
{
|
||||
givenID = ::base::saturated_cast<uint64_t>(responseId);
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else if (responseId == WindowingBehaviorUseName)
|
||||
{
|
||||
givenName = findWindowArgs->ResultTargetWindowName();
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(0, "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(0, "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(L"", "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
|
||||
if (_shouldCreateWindow)
|
||||
{
|
||||
// If we should create a new window, then instantiate our Peasant
|
||||
// instance, and tell that peasant to handle that commandline.
|
||||
_createOurPeasant({ givenID }, givenName);
|
||||
|
||||
// Spawn a thread to wait on the monarch, and handle the election
|
||||
if (!_isKing)
|
||||
{
|
||||
_createPeasantThread();
|
||||
}
|
||||
|
||||
// This right here will just tell us to stash the args away for the
|
||||
// future. The AppHost hasn't yet set up the callbacks, and the rest
|
||||
// of the app hasn't started at all. We'll note them and come back
|
||||
// later.
|
||||
_peasant.ExecuteCommandline(args);
|
||||
}
|
||||
// Otherwise, we'll do _nothing_.
|
||||
// I don't think we can ever get here, but the compiler doesn't know
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowManager::ShouldCreateWindow()
|
||||
{
|
||||
return _shouldCreateWindow;
|
||||
}
|
||||
|
||||
void WindowManager::_registerAsMonarch()
|
||||
{
|
||||
winrt::check_hresult(CoRegisterClassObject(Monarch_clsid,
|
||||
winrt::make<::MonarchFactory>().get(),
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
REGCLS_MULTIPLEUSE,
|
||||
&_registrationHostClass));
|
||||
}
|
||||
|
||||
void WindowManager::_createMonarch()
|
||||
{
|
||||
// Heads up! This only works because we're using
|
||||
// "metadata-based-marshalling" for our WinRT types. That means the OS is
|
||||
// using the .winmd file we generate to figure out the proxy/stub
|
||||
// definitions for our types automatically. This only works in the following
|
||||
// cases:
|
||||
//
|
||||
// * If we're running unpackaged: the .winmd must be a sibling of the .exe
|
||||
// * If we're running packaged: the .winmd must be in the package root
|
||||
_monarch = create_instance<Remoting::IMonarch>(Monarch_clsid,
|
||||
CLSCTX_LOCAL_SERVER);
|
||||
}
|
||||
|
||||
// Tries to instantiate a monarch, tries again, and eventually either throws
|
||||
// (so that the caller will try again) or falls back to the isolated
|
||||
// monarch.
|
||||
void WindowManager::_redundantCreateMonarch()
|
||||
{
|
||||
_createMonarch();
|
||||
|
||||
if (_monarch == nullptr)
|
||||
{
|
||||
// See MSFT:38540483, GH#12774 for details.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_NullMonarchTryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// Here we're gonna just give it a quick second try.Probably not
|
||||
// definitive, but might help.
|
||||
_createMonarch();
|
||||
}
|
||||
|
||||
if (_monarch == nullptr)
|
||||
{
|
||||
// See MSFT:38540483, GH#12774 for details.
|
||||
if constexpr (Feature_IsolatedMonarchMode::IsEnabled())
|
||||
{
|
||||
// Fall back to having a in proc monarch. Were now isolated from
|
||||
// other windows. This is a pretty torn state, but at least we
|
||||
// didn't just explode.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_NullMonarchIsolateMode",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_monarch = winrt::make<winrt::Microsoft::Terminal::Remoting::implementation::Monarch>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The monarch is null. We're hoping that we can find another,
|
||||
// hopefully us. We're gonna go back around the loop again and
|
||||
// see what happens. If this is really an infinite loop (where
|
||||
// the OS won't even give us back US as the monarch), then I
|
||||
// suppose we'll find out soon enough.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_NullMonarchTryAgain",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
winrt::hresult_error(E_UNEXPECTED, L"Did not expect the Monarch to ever be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This can throw! Callers include:
|
||||
// - the constructor, who performs this in a loop until it successfully
|
||||
// find a a monarch
|
||||
// - the performElection method, which is called in the waitOnMonarch
|
||||
// thread. All the calls in that thread are wrapped in try/catch's
|
||||
// already.
|
||||
// - _createOurPeasant, who might do this in a loop to establish us with the
|
||||
// monarch.
|
||||
void WindowManager::_createMonarchAndCallbacks()
|
||||
{
|
||||
_redundantCreateMonarch();
|
||||
// We're pretty confident that we have a Monarch here.
|
||||
_createCallbacks();
|
||||
}
|
||||
|
||||
// Check if we became the king, and if we are, wire up callbacks.
|
||||
void WindowManager::_createCallbacks()
|
||||
{
|
||||
// Save the result of checking if we're the king. We want to avoid
|
||||
// unnecessary calls back and forth if we can.
|
||||
_isKing = _areWeTheKing();
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ConnectedToMonarch",
|
||||
TraceLoggingUInt64(_monarch.GetPID(), "monarchPID", "The PID of the new Monarch"),
|
||||
TraceLoggingBoolean(_isKing, "isKing", "true if we are the new monarch"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
if (_peasant)
|
||||
{
|
||||
if (const auto& lastActivated{ _peasant.GetLastActivatedArgs() })
|
||||
{
|
||||
// Inform the monarch of the time we were last activated
|
||||
_monarch.HandleActivatePeasant(lastActivated);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isKing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Here, we're the king!
|
||||
//
|
||||
// This is where you should do any additional setup that might need to be
|
||||
// done when we become the king. This will be called both for the first
|
||||
// window, and when the current monarch dies.
|
||||
|
||||
_monarch.WindowCreated({ get_weak(), &WindowManager::_WindowCreatedHandlers });
|
||||
_monarch.WindowClosed({ get_weak(), &WindowManager::_WindowClosedHandlers });
|
||||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
|
||||
|
||||
_BecameMonarchHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
bool WindowManager::_areWeTheKing()
|
||||
{
|
||||
const auto ourPID{ GetCurrentProcessId() };
|
||||
const auto kingPID{ _monarch.GetPID() };
|
||||
return (ourPID == kingPID);
|
||||
}
|
||||
|
||||
Remoting::IPeasant WindowManager::_createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName)
|
||||
Remoting::Peasant WindowManager::CreatePeasant(Remoting::WindowRequestedArgs args)
|
||||
{
|
||||
auto p = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
if (givenID)
|
||||
if (args.Id())
|
||||
{
|
||||
p->AssignID(givenID.value());
|
||||
p->AssignID(args.Id().Value());
|
||||
}
|
||||
|
||||
// If the name wasn't specified, this will be an empty string.
|
||||
p->WindowName(givenName);
|
||||
_peasant = *p;
|
||||
p->WindowName(args.WindowName());
|
||||
|
||||
// Try to add us to the monarch. If that fails, try to find a monarch
|
||||
// again, until we find one (we will eventually find us)
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
_monarch.AddPeasant(_peasant);
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Wrap this in its own try/catch, because this can throw.
|
||||
_createMonarchAndCallbacks();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
p->ExecuteCommandline(*winrt::make_self<CommandlineArgs>(args.Commandline(), args.CurrentDirectory()));
|
||||
|
||||
_peasant.GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
|
||||
_monarch.AddPeasant(*p);
|
||||
|
||||
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_CreateOurPeasant",
|
||||
TraceLoggingUInt64(_peasant.GetID(), "peasantID", "The ID of our new peasant"),
|
||||
TraceLoggingUInt64(p->GetID(), "peasantID", "The ID of our new peasant"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
// If the peasant asks us to quit we should not try to act in future elections.
|
||||
_peasant.QuitRequested([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto wm = weakThis.get())
|
||||
{
|
||||
wm->_monarchWaitInterrupt.SetEvent();
|
||||
}
|
||||
});
|
||||
|
||||
return _peasant;
|
||||
return *p;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to connect to the monarch process. This might be us!
|
||||
// - For the new monarch, add us to their list of peasants.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - true iff we're the new monarch process.
|
||||
// NOTE: This can throw!
|
||||
bool WindowManager::_performElection()
|
||||
void WindowManager::SignalClose(Remoting::Peasant peasant)
|
||||
{
|
||||
_createMonarchAndCallbacks();
|
||||
|
||||
// Tell the new monarch who we are. We might be that monarch!
|
||||
_monarch.AddPeasant(_peasant);
|
||||
|
||||
// This method is only called when a _new_ monarch is elected. So
|
||||
// don't do anything here that needs to be done for all monarch
|
||||
// windows. This should only be for work that's done when a window
|
||||
// _becomes_ a monarch, after the death of the previous monarch.
|
||||
return _isKing;
|
||||
}
|
||||
|
||||
void WindowManager::_createPeasantThread()
|
||||
{
|
||||
// If we catch an exception trying to get at the monarch ever, we can
|
||||
// set the _monarchWaitInterrupt, and use that to trigger a new
|
||||
// election. Though, we wouldn't be able to retry the function that
|
||||
// caused the exception in the first place...
|
||||
|
||||
_electionThread = std::thread([this] {
|
||||
_waitOnMonarchThread();
|
||||
});
|
||||
}
|
||||
|
||||
void WindowManager::_waitOnMonarchThread()
|
||||
{
|
||||
// This is the array of HANDLEs that we're going to wait on in
|
||||
// WaitForMultipleObjects below.
|
||||
// * waits[0] will be the handle to the monarch process. It gets
|
||||
// signalled when the process exits / dies.
|
||||
// * waits[1] is the handle to our _monarchWaitInterrupt event. Another
|
||||
// thread can use that to manually break this loop. We'll do that when
|
||||
// we're getting torn down.
|
||||
HANDLE waits[2];
|
||||
waits[1] = _monarchWaitInterrupt.get();
|
||||
const auto peasantID = _peasant.GetID(); // safe: _peasant is in-proc.
|
||||
|
||||
auto exitThreadRequested = false;
|
||||
while (!exitThreadRequested)
|
||||
if (_monarch)
|
||||
{
|
||||
// At any point in all this, the current monarch might die. If it
|
||||
// does, we'll go straight to a new election, in the "jail"
|
||||
// try/catch below. Worst case, eventually, we'll become the new
|
||||
// monarch.
|
||||
try
|
||||
{
|
||||
// This might fail to even ask the monarch for its PID.
|
||||
wil::unique_handle hMonarch{ OpenProcess(PROCESS_ALL_ACCESS,
|
||||
FALSE,
|
||||
static_cast<DWORD>(_monarch.GetPID())) };
|
||||
|
||||
// If we fail to open the monarch, then they don't exist
|
||||
// anymore! Go straight to an election.
|
||||
if (hMonarch.get() == nullptr)
|
||||
{
|
||||
const auto gle = GetLastError();
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_FailedToOpenMonarch",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
exitThreadRequested = _performElection();
|
||||
continue;
|
||||
}
|
||||
|
||||
waits[0] = hMonarch.get();
|
||||
auto waitResult = WaitForMultipleObjects(2, waits, FALSE, INFINITE);
|
||||
|
||||
switch (waitResult)
|
||||
{
|
||||
case WAIT_OBJECT_0 + 0: // waits[0] was signaled, the handle to the monarch process
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchDied",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// Connect to the new monarch, which might be us!
|
||||
// If we become the monarch, then we'll return true and exit this thread.
|
||||
exitThreadRequested = _performElection();
|
||||
break;
|
||||
|
||||
case WAIT_OBJECT_0 + 1: // waits[1] was signaled, our manual interrupt
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchWaitInterrupted",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
// This should be impossible.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchWaitTimeout",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// Returning any other value is invalid. Just die.
|
||||
const auto gle = GetLastError();
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_WaitFailed",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
ExitProcess(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Theoretically, if window[1] dies when we're trying to get
|
||||
// its PID we'll get here. If we just try to do the election
|
||||
// once here, it's possible we might elect window[2], but have
|
||||
// it die before we add ourselves as a peasant. That
|
||||
// _performElection call will throw, and we wouldn't catch it
|
||||
// here, and we'd die.
|
||||
|
||||
// Instead, we're going to have a resilient election process.
|
||||
// We're going to keep trying an election, until one _doesn't_
|
||||
// throw an exception. That might mean burning through all the
|
||||
// other dying monarchs until we find us as the monarch. But if
|
||||
// this process is alive, then there's _someone_ in the line of
|
||||
// succession.
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInWaitThread",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
auto foundNewMonarch = false;
|
||||
while (!foundNewMonarch)
|
||||
{
|
||||
try
|
||||
{
|
||||
exitThreadRequested = _performElection();
|
||||
// It doesn't matter if we're the monarch, or someone
|
||||
// else is, but if we complete the election, then we've
|
||||
// registered with a new one. We can escape this jail
|
||||
// and re-enter society.
|
||||
foundNewMonarch = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If we fail to acknowledge the results of the election,
|
||||
// stay in this jail until we do.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInNestedWaitThread",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
_monarch.SignalClose(peasant.GetID());
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
}
|
||||
|
||||
Remoting::Peasant WindowManager::CurrentWindow()
|
||||
{
|
||||
return _peasant;
|
||||
}
|
||||
|
||||
void WindowManager::_raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
|
||||
{
|
||||
_FindTargetWindowRequestedHandlers(sender, args);
|
||||
}
|
||||
|
||||
bool WindowManager::IsMonarch()
|
||||
{
|
||||
return _isKing;
|
||||
}
|
||||
|
||||
void WindowManager::SummonWindow(const Remoting::SummonWindowSelectionArgs& args)
|
||||
{
|
||||
// We should only ever get called when we are the monarch, because only
|
||||
@@ -747,10 +391,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestShowNotificationIcon()
|
||||
winrt::fire_and_forget WindowManager::RequestShowNotificationIcon(Remoting::Peasant peasant)
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestShowNotificationIcon();
|
||||
peasant.RequestShowNotificationIcon();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -759,11 +403,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestHideNotificationIcon()
|
||||
winrt::fire_and_forget WindowManager::RequestHideNotificationIcon(Remoting::Peasant peasant)
|
||||
{
|
||||
auto strongThis{ get_strong() };
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestHideNotificationIcon();
|
||||
peasant.RequestHideNotificationIcon();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -772,11 +416,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestQuitAll()
|
||||
winrt::fire_and_forget WindowManager::RequestQuitAll(Remoting::Peasant peasant)
|
||||
{
|
||||
auto strongThis{ get_strong() };
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestQuitAll();
|
||||
peasant.RequestQuitAll();
|
||||
}
|
||||
|
||||
bool WindowManager::DoesQuakeWindowExist()
|
||||
@@ -784,9 +428,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return _monarch.DoesQuakeWindowExist();
|
||||
}
|
||||
|
||||
void WindowManager::UpdateActiveTabTitle(winrt::hstring title)
|
||||
void WindowManager::UpdateActiveTabTitle(winrt::hstring title, Remoting::Peasant peasant)
|
||||
{
|
||||
winrt::get_self<implementation::Peasant>(_peasant)->ActiveTabTitle(title);
|
||||
winrt::get_self<implementation::Peasant>(peasant)->ActiveTabTitle(title);
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> WindowManager::GetAllWindowLayouts()
|
||||
@@ -801,4 +445,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::fire_and_forget WindowManager::RequestMoveContent(winrt::hstring window,
|
||||
winrt::hstring content,
|
||||
uint32_t tabIndex,
|
||||
Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds)
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_monarch.RequestMoveContent(window, content, tabIndex, windowBounds);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget WindowManager::RequestSendContent(Remoting::RequestReceiveContentArgs args)
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_monarch.RequestSendContent(args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- WindowManager.h
|
||||
|
||||
Abstract:
|
||||
- The Window Manager takes care of coordinating the monarch and peasant for this
|
||||
process.
|
||||
@@ -16,9 +14,7 @@ Abstract:
|
||||
- When the monarch needs to ask the TerminalApp about how to parse a
|
||||
commandline, it'll ask by raising an event that we'll bubble up to the
|
||||
AppHost.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WindowManager.g.h"
|
||||
@@ -29,30 +25,31 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct WindowManager : public WindowManagerT<WindowManager>
|
||||
{
|
||||
public:
|
||||
WindowManager();
|
||||
~WindowManager();
|
||||
winrt::Microsoft::Terminal::Remoting::ProposeCommandlineResult ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args, const bool isolatedMode);
|
||||
Remoting::Peasant CreatePeasant(Remoting::WindowRequestedArgs args);
|
||||
|
||||
void ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
bool ShouldCreateWindow();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant CurrentWindow();
|
||||
bool IsMonarch();
|
||||
void SignalClose(Remoting::Peasant peasant);
|
||||
void SummonWindow(const Remoting::SummonWindowSelectionArgs& args);
|
||||
void SignalClose();
|
||||
|
||||
void SummonAllWindows();
|
||||
uint64_t GetNumberOfPeasants();
|
||||
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
|
||||
|
||||
winrt::fire_and_forget RequestShowNotificationIcon();
|
||||
winrt::fire_and_forget RequestHideNotificationIcon();
|
||||
winrt::fire_and_forget RequestQuitAll();
|
||||
bool DoesQuakeWindowExist();
|
||||
void UpdateActiveTabTitle(winrt::hstring title);
|
||||
uint64_t GetNumberOfPeasants();
|
||||
winrt::fire_and_forget RequestShowNotificationIcon(Remoting::Peasant peasant);
|
||||
winrt::fire_and_forget RequestHideNotificationIcon(Remoting::Peasant peasant);
|
||||
winrt::fire_and_forget RequestQuitAll(Remoting::Peasant peasant);
|
||||
void UpdateActiveTabTitle(winrt::hstring title, 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);
|
||||
winrt::fire_and_forget RequestSendContent(Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(BecameMonarch, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
@@ -60,34 +57,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
|
||||
|
||||
private:
|
||||
bool _shouldCreateWindow{ false };
|
||||
bool _isKing{ false };
|
||||
DWORD _registrationHostClass{ 0 };
|
||||
winrt::Microsoft::Terminal::Remoting::IMonarch _monarch{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
|
||||
|
||||
wil::unique_event _monarchWaitInterrupt;
|
||||
std::thread _electionThread;
|
||||
|
||||
void _registerAsMonarch();
|
||||
void _createMonarch();
|
||||
void _redundantCreateMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
void _createCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName);
|
||||
void _registerAsMonarch();
|
||||
|
||||
bool _performElection();
|
||||
void _createPeasantThread();
|
||||
void _waitOnMonarchThread();
|
||||
bool _proposeToMonarch(const Remoting::CommandlineArgs& args);
|
||||
|
||||
void _createCallbacks();
|
||||
void _raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
|
||||
|
||||
void _proposeToMonarch(const Remoting::CommandlineArgs& args,
|
||||
std::optional<uint64_t>& givenID,
|
||||
winrt::hstring& givenName);
|
||||
void _raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,29 +7,39 @@ namespace Microsoft.Terminal.Remoting
|
||||
[default_interface] runtimeclass WindowManager
|
||||
{
|
||||
WindowManager();
|
||||
void ProposeCommandline(CommandlineArgs args);
|
||||
void SignalClose();
|
||||
Boolean ShouldCreateWindow { get; };
|
||||
IPeasant CurrentWindow();
|
||||
Boolean IsMonarch { get; };
|
||||
|
||||
ProposeCommandlineResult ProposeCommandline(CommandlineArgs args, Boolean isolatedMode);
|
||||
Peasant CreatePeasant(WindowRequestedArgs args);
|
||||
|
||||
void SignalClose(Peasant p);
|
||||
void RequestShowNotificationIcon(Peasant p);
|
||||
void RequestHideNotificationIcon(Peasant p);
|
||||
void UpdateActiveTabTitle(String title, Peasant p);
|
||||
void RequestQuitAll(Peasant p);
|
||||
|
||||
void SummonWindow(SummonWindowSelectionArgs args);
|
||||
void SummonAllWindows();
|
||||
void RequestShowNotificationIcon();
|
||||
void RequestHideNotificationIcon();
|
||||
|
||||
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
|
||||
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos();
|
||||
|
||||
UInt64 GetNumberOfPeasants();
|
||||
void RequestQuitAll();
|
||||
void UpdateActiveTabTitle(String title);
|
||||
|
||||
Boolean DoesQuakeWindowExist();
|
||||
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos();
|
||||
|
||||
void RequestMoveContent(String window, String content, UInt32 tabIndex, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
|
||||
void RequestSendContent(RequestReceiveContentArgs args);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> BecameMonarch;
|
||||
|
||||
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, Object> ShowNotificationIconRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowRequestedArgs> RequestNewWindow;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,27 +24,5 @@ namespace winrt::TerminalApp::implementation
|
||||
Name(command.Name());
|
||||
KeyChordText(command.KeyChordText());
|
||||
Icon(command.IconPath());
|
||||
|
||||
_commandChangedRevoker = command.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
|
||||
auto item{ weakThis.get() };
|
||||
auto senderCommand{ sender.try_as<Microsoft::Terminal::Settings::Model::Command>() };
|
||||
|
||||
if (item && senderCommand)
|
||||
{
|
||||
auto changedProperty = e.PropertyName();
|
||||
if (changedProperty == L"Name")
|
||||
{
|
||||
item->Name(senderCommand.Name());
|
||||
}
|
||||
else if (changedProperty == L"KeyChordText")
|
||||
{
|
||||
item->KeyChordText(senderCommand.KeyChordText());
|
||||
}
|
||||
else if (changedProperty == L"IconPath")
|
||||
{
|
||||
item->Icon(senderCommand.IconPath());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,22 +77,7 @@ namespace winrt::TerminalApp::implementation
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
void App::OnLaunched(const LaunchActivatedEventArgs& /*e*/)
|
||||
{
|
||||
// if this is a UWP... it means its our problem to hook up the content to the window here.
|
||||
if (_isUwp)
|
||||
{
|
||||
auto content = Window::Current().Content();
|
||||
if (content == nullptr)
|
||||
{
|
||||
auto logic = Logic();
|
||||
logic.RunAsUwp(); // Must set UWP status first, settings might change based on it.
|
||||
logic.ReloadSettings();
|
||||
logic.Create();
|
||||
|
||||
auto page = logic.GetRoot().as<TerminalPage>();
|
||||
|
||||
Window::Current().Content(page);
|
||||
Window::Current().Activate();
|
||||
}
|
||||
}
|
||||
// We used to support a pure UWP version of the Terminal. This method
|
||||
// was only ever used to do UWP-specific setup of our App.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
|
||||
{
|
||||
auto moved = _MovePane(realArgs.TabIndex());
|
||||
auto moved = _MovePane(realArgs);
|
||||
args.Handled(moved);
|
||||
}
|
||||
}
|
||||
@@ -789,17 +789,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = actionArgs.ActionArgs().try_as<MoveTabArgs>())
|
||||
{
|
||||
auto direction = realArgs.Direction();
|
||||
if (direction != MoveTabDirection::None)
|
||||
{
|
||||
if (auto focusedTabIndex = _GetFocusedTabIndex())
|
||||
{
|
||||
auto currentTabIndex = focusedTabIndex.value();
|
||||
auto delta = direction == MoveTabDirection::Forward ? 1 : -1;
|
||||
_TryMoveTab(currentTabIndex, currentTabIndex + delta);
|
||||
}
|
||||
}
|
||||
actionArgs.Handled(true);
|
||||
auto moved = _MoveTab(realArgs);
|
||||
actionArgs.Handled(moved);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,7 @@ void AppCommandlineArgs::_buildMovePaneParser()
|
||||
if (_movePaneTabIndex >= 0)
|
||||
{
|
||||
movePaneAction.Action(ShortcutAction::MovePane);
|
||||
MovePaneArgs args{ static_cast<unsigned int>(_movePaneTabIndex) };
|
||||
MovePaneArgs args{ static_cast<unsigned int>(_movePaneTabIndex), L"" };
|
||||
movePaneAction.Args(args);
|
||||
_startupActions.push_back(movePaneAction);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,12 @@
|
||||
|
||||
#include "AppLogic.g.h"
|
||||
#include "FindTargetWindowResult.g.h"
|
||||
#include "SystemMenuChangeArgs.g.h"
|
||||
|
||||
#include "Jumplist.h"
|
||||
#include "LanguageProfileNotifier.h"
|
||||
#include "TerminalPage.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "TerminalWindow.h"
|
||||
#include "ContentManager.h"
|
||||
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
#include <ThrottledFunc.h>
|
||||
@@ -36,18 +38,7 @@ namespace winrt::TerminalApp::implementation
|
||||
FindTargetWindowResult(id, L""){};
|
||||
};
|
||||
|
||||
struct SystemMenuChangeArgs : SystemMenuChangeArgsT<SystemMenuChangeArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Name, L"");
|
||||
WINRT_PROPERTY(SystemMenuChangeAction, Action, SystemMenuChangeAction::Add);
|
||||
WINRT_PROPERTY(SystemMenuItemHandler, Handler, nullptr);
|
||||
|
||||
public:
|
||||
SystemMenuChangeArgs(const winrt::hstring& name, SystemMenuChangeAction action, SystemMenuItemHandler handler = nullptr) :
|
||||
_Name{ name }, _Action{ action }, _Handler{ handler } {};
|
||||
};
|
||||
|
||||
struct AppLogic : AppLogicT<AppLogic, IInitializeWithWindow>
|
||||
struct AppLogic : AppLogicT<AppLogic>
|
||||
{
|
||||
public:
|
||||
static AppLogic* Current() noexcept;
|
||||
@@ -56,172 +47,70 @@ namespace winrt::TerminalApp::implementation
|
||||
AppLogic();
|
||||
~AppLogic() = default;
|
||||
|
||||
STDMETHODIMP Initialize(HWND hwnd);
|
||||
|
||||
void Create();
|
||||
bool IsUwp() const noexcept;
|
||||
void RunAsUwp();
|
||||
bool IsElevated() const noexcept;
|
||||
void ReloadSettings();
|
||||
|
||||
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;
|
||||
|
||||
void Quit();
|
||||
|
||||
bool HasCommandlineArguments() const noexcept;
|
||||
bool HasSettingsStartupActions() const noexcept;
|
||||
int32_t SetStartupCommandline(array_view<const winrt::hstring> actions);
|
||||
int32_t ExecuteCommandline(array_view<const winrt::hstring> actions, const winrt::hstring& cwd);
|
||||
TerminalApp::FindTargetWindowResult FindTargetWindow(array_view<const winrt::hstring> actions);
|
||||
winrt::hstring ParseCommandlineMessage();
|
||||
bool ShouldExitEarly();
|
||||
|
||||
bool FocusMode() const;
|
||||
bool Fullscreen() const;
|
||||
void Maximized(bool newMaximized);
|
||||
bool AlwaysOnTop() const;
|
||||
bool AutoHideWindow();
|
||||
|
||||
bool ShouldUsePersistedLayout();
|
||||
bool ShouldImmediatelyHandoffToElevated();
|
||||
void HandoffToElevated();
|
||||
hstring GetWindowLayoutJson(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
void SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector<hstring>& layouts);
|
||||
void IdentifyWindow();
|
||||
void RenameFailed();
|
||||
winrt::hstring WindowName();
|
||||
void WindowName(const winrt::hstring& name);
|
||||
uint64_t WindowId();
|
||||
void WindowId(const uint64_t& id);
|
||||
void SetPersistedLayoutIdx(const uint32_t idx);
|
||||
void SetNumberOfOpenWindows(const uint64_t num);
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
void RequestExitFullscreen();
|
||||
|
||||
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
|
||||
bool CenterOnLaunch();
|
||||
TerminalApp::InitialPosition GetInitialPosition(int64_t defaultInitialX, int64_t defaultInitialY);
|
||||
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme();
|
||||
Microsoft::Terminal::Settings::Model::LaunchMode GetLaunchMode();
|
||||
bool GetShowTabsInTitlebar();
|
||||
bool GetInitialAlwaysOnTop();
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
|
||||
Windows::UI::Xaml::UIElement GetRoot() noexcept;
|
||||
|
||||
void SetInboundListener();
|
||||
|
||||
hstring Title();
|
||||
void TitlebarClicked();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
winrt::TerminalApp::TaskbarState TaskbarState();
|
||||
winrt::Windows::UI::Xaml::Media::Brush TitlebarBrush();
|
||||
void WindowActivated(const bool activated);
|
||||
|
||||
bool GetMinimizeToNotificationArea();
|
||||
bool GetAlwaysShowNotificationIcon();
|
||||
bool GetShowTitleInTitlebar();
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
|
||||
void DismissDialog();
|
||||
|
||||
Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> GlobalHotkeys();
|
||||
|
||||
Microsoft::Terminal::Settings::Model::Theme Theme();
|
||||
bool IsolatedMode();
|
||||
bool AllowHeadless();
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
|
||||
// Usually we'd just do
|
||||
// WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
//
|
||||
// But what we're doing here is exposing the Page's PropertyChanged _as
|
||||
// our own event_. It's a FORWARDED_CALLBACK, essentially.
|
||||
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _root->PropertyChanged(handler); }
|
||||
void PropertyChanged(winrt::event_token const& token) { _root->PropertyChanged(token); }
|
||||
TerminalApp::TerminalWindow CreateNewWindow();
|
||||
|
||||
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme);
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
|
||||
winrt::TerminalApp::ContentManager ContentManager();
|
||||
|
||||
TerminalApp::ParseCommandlineResult GetParseCommandlineMessage(array_view<const winrt::hstring> args);
|
||||
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
|
||||
|
||||
private:
|
||||
bool _isUwp{ false };
|
||||
bool _isElevated{ false };
|
||||
|
||||
// If you add controls here, but forget to null them either here or in
|
||||
// the ctor, you're going to have a bad time. It'll mysteriously fail to
|
||||
// activate the AppLogic.
|
||||
// ALSO: If you add any UIElements as roots here, make sure they're
|
||||
// updated in _ApplyTheme. The root currently is _root.
|
||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
winrt::hstring _settingsLoadExceptionText;
|
||||
HRESULT _settingsLoadedResult = S_OK;
|
||||
bool _loadedInitialSettings = false;
|
||||
|
||||
uint64_t _numOpenWindows{ 0 };
|
||||
|
||||
std::shared_mutex _dialogLock;
|
||||
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog;
|
||||
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
bool _hasSettingsStartupActions{ false };
|
||||
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
|
||||
til::throttled_func_trailing<> _reloadState;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};
|
||||
|
||||
// These fields invoke _reloadSettings and must be destroyed before _reloadSettings.
|
||||
// (C++ destroys members in reverse-declaration-order.)
|
||||
winrt::com_ptr<LanguageProfileNotifier> _languageProfileNotifier;
|
||||
wil::unique_folder_change_reader_nothrow _reader;
|
||||
|
||||
TerminalApp::ContentManager _contentManager{ *winrt::make_self<implementation::ContentManager>() };
|
||||
|
||||
static TerminalApp::FindTargetWindowResult _doFindTargetWindow(winrt::array_view<const hstring> args,
|
||||
const Microsoft::Terminal::Settings::Model::WindowingMode& windowingBehavior);
|
||||
|
||||
void _ShowLoadErrorsDialog(const winrt::hstring& titleKey, const winrt::hstring& contentKey, HRESULT settingsLoadedResult);
|
||||
void _ShowLoadWarningsDialog();
|
||||
bool _IsKeyboardServiceEnabled();
|
||||
|
||||
void _ApplyLanguageSettingChange() noexcept;
|
||||
void _RefreshThemeRoutine();
|
||||
fire_and_forget _ApplyStartupTaskStateChange();
|
||||
|
||||
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
|
||||
void _ProcessLazySettingsChanges();
|
||||
void _RegisterSettingsChange();
|
||||
fire_and_forget _DispatchReloadSettings();
|
||||
void _OpenSettingsUI();
|
||||
|
||||
bool _hasCommandLineArguments{ false };
|
||||
bool _hasSettingsStartupActions{ false };
|
||||
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings;
|
||||
|
||||
// These are events that are handled by the TerminalPage, but are
|
||||
// exposed through the AppLogic. This macro is used to forward the event
|
||||
// directly to them.
|
||||
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(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);
|
||||
FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged);
|
||||
FORWARDED_TYPED_EVENT(RaiseVisualBell, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, RaiseVisualBell);
|
||||
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
|
||||
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
|
||||
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged);
|
||||
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
|
||||
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
|
||||
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
|
||||
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalAppLocalTests::CommandlineTest;
|
||||
|
||||
@@ -1,41 +1,25 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TerminalPage.idl";
|
||||
import "ShortcutActionDispatch.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "TerminalWindow.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
struct InitialPosition
|
||||
{
|
||||
Int64 X;
|
||||
Int64 Y;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass FindTargetWindowResult
|
||||
{
|
||||
Int32 WindowId { get; };
|
||||
String WindowName { get; };
|
||||
};
|
||||
|
||||
delegate void SystemMenuItemHandler();
|
||||
|
||||
enum SystemMenuChangeAction
|
||||
struct ParseCommandlineResult
|
||||
{
|
||||
Add = 0,
|
||||
Remove = 1
|
||||
String Message;
|
||||
Int32 ExitCode;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SystemMenuChangeArgs {
|
||||
String Name { get; };
|
||||
SystemMenuChangeAction Action { get; };
|
||||
SystemMenuItemHandler Handler { get; };
|
||||
};
|
||||
|
||||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass AppLogic
|
||||
{
|
||||
AppLogic();
|
||||
|
||||
@@ -50,94 +34,27 @@ namespace TerminalApp
|
||||
void RunAsUwp();
|
||||
Boolean IsElevated();
|
||||
|
||||
Boolean HasCommandlineArguments();
|
||||
ContentManager ContentManager { get; };
|
||||
|
||||
Boolean HasSettingsStartupActions();
|
||||
Int32 SetStartupCommandline(String[] commands);
|
||||
Int32 ExecuteCommandline(String[] commands, String cwd);
|
||||
String ParseCommandlineMessage { get; };
|
||||
Boolean ShouldExitEarly { get; };
|
||||
|
||||
void Quit();
|
||||
|
||||
void ReloadSettings();
|
||||
Windows.UI.Xaml.UIElement GetRoot();
|
||||
|
||||
void SetInboundListener();
|
||||
|
||||
String Title { get; };
|
||||
|
||||
Boolean FocusMode { get; };
|
||||
Boolean Fullscreen { get; };
|
||||
void Maximized(Boolean newMaximized);
|
||||
Boolean AlwaysOnTop { get; };
|
||||
Boolean AutoHideWindow { get; };
|
||||
|
||||
void IdentifyWindow();
|
||||
String WindowName;
|
||||
UInt64 WindowId;
|
||||
void SetPersistedLayoutIdx(UInt32 idx);
|
||||
void SetNumberOfOpenWindows(UInt64 num);
|
||||
void RenameFailed();
|
||||
void RequestExitFullscreen();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean CenterOnLaunch { get; };
|
||||
|
||||
InitialPosition GetInitialPosition(Int64 defaultInitialX, Int64 defaultInitialY);
|
||||
Windows.UI.Xaml.ElementTheme GetRequestedTheme();
|
||||
Microsoft.Terminal.Settings.Model.LaunchMode GetLaunchMode();
|
||||
Boolean GetShowTabsInTitlebar();
|
||||
Boolean GetInitialAlwaysOnTop();
|
||||
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
|
||||
void TitlebarClicked();
|
||||
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
void WindowVisibilityChanged(Boolean showOrHide);
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
|
||||
void WindowActivated(Boolean activated);
|
||||
|
||||
Boolean ShouldUsePersistedLayout();
|
||||
Boolean ShouldImmediatelyHandoffToElevated();
|
||||
void HandoffToElevated();
|
||||
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
void SaveWindowLayoutJsons(Windows.Foundation.Collections.IVector<String> layouts);
|
||||
|
||||
Boolean GetMinimizeToNotificationArea();
|
||||
Boolean GetAlwaysShowNotificationIcon();
|
||||
Boolean GetShowTitleInTitlebar();
|
||||
void ReloadSettings();
|
||||
|
||||
Microsoft.Terminal.Settings.Model.Theme Theme { get; };
|
||||
Boolean IsolatedMode { get; };
|
||||
Boolean AllowHeadless { get; };
|
||||
|
||||
FindTargetWindowResult FindTargetWindow(String[] args);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Microsoft.Terminal.Settings.Model.Command> GlobalHotkeys();
|
||||
TerminalWindow CreateNewWindow();
|
||||
|
||||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
void DismissDialog();
|
||||
ParseCommandlineResult GetParseCommandlineMessage(String[] args);
|
||||
|
||||
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, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ChangeMaximizeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RaiseVisualBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SettingsChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
|
||||
IMapView<Microsoft.Terminal.Control.KeyChord, Microsoft.Terminal.Settings.Model.Command> GlobalHotkeys();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, SettingsLoadEventArgs> SettingsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
75
src/cascadia/TerminalApp/ContentManager.cpp
Normal file
75
src/cascadia/TerminalApp/ContentManager.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ContentManager.h"
|
||||
#include "ContentManager.g.cpp"
|
||||
|
||||
#include <wil/token_helpers.h>
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Control;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ControlInteractivity ContentManager::CreateCore(Microsoft::Terminal::Control::IControlSettings settings,
|
||||
IControlAppearance unfocusedAppearance,
|
||||
TerminalConnection::ITerminalConnection connection)
|
||||
{
|
||||
auto content = ControlInteractivity{ settings, unfocusedAppearance, connection };
|
||||
content.Closed({ this, &ContentManager::_closedHandler });
|
||||
const auto& contentGuid{ content.Id() };
|
||||
_content.Insert(contentGuid, content);
|
||||
return content;
|
||||
}
|
||||
|
||||
ControlInteractivity ContentManager::LookupCore(winrt::guid id)
|
||||
{
|
||||
return _content.TryLookup(id);
|
||||
}
|
||||
|
||||
void ContentManager::Detach(const Microsoft::Terminal::Control::TermControl& control)
|
||||
{
|
||||
const auto contentGuid{ control.ContentGuid() };
|
||||
if (const auto& content{ LookupCore(contentGuid) })
|
||||
{
|
||||
control.Detach();
|
||||
content.Attached({ get_weak(), &ContentManager::_finalizeDetach });
|
||||
_recentlyDetachedContent.Insert(contentGuid, content);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentManager::_finalizeDetach(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e)
|
||||
{
|
||||
if (const auto& content{ sender.try_as<winrt::Microsoft::Terminal::Control::ControlInteractivity>() })
|
||||
{
|
||||
_recentlyDetachedContent.TryRemove(content.Id());
|
||||
}
|
||||
}
|
||||
|
||||
void ContentManager::_closedHandler(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e)
|
||||
{
|
||||
if (const auto& content{ sender.try_as<winrt::Microsoft::Terminal::Control::ControlInteractivity>() })
|
||||
{
|
||||
const auto& contentGuid{ content.Id() };
|
||||
_content.TryRemove(contentGuid);
|
||||
_recentlyDetachedContent.TryRemove(contentGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/cascadia/TerminalApp/ContentManager.h
Normal file
37
src/cascadia/TerminalApp/ContentManager.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ContentManager.g.h"
|
||||
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct ContentManager : ContentManagerT<ContentManager>
|
||||
{
|
||||
public:
|
||||
ContentManager() = default;
|
||||
Microsoft::Terminal::Control::ControlInteractivity CreateCore(Microsoft::Terminal::Control::IControlSettings settings,
|
||||
Microsoft::Terminal::Control::IControlAppearance unfocusedAppearance,
|
||||
Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
|
||||
Microsoft::Terminal::Control::ControlInteractivity LookupCore(winrt::guid id);
|
||||
|
||||
void Detach(const Microsoft::Terminal::Control::TermControl& control);
|
||||
|
||||
private:
|
||||
Windows::Foundation::Collections::IMap<winrt::guid, Microsoft::Terminal::Control::ControlInteractivity> _content{
|
||||
winrt::multi_threaded_map<winrt::guid, Microsoft::Terminal::Control::ControlInteractivity>()
|
||||
};
|
||||
|
||||
Windows::Foundation::Collections::IMap<winrt::guid, Microsoft::Terminal::Control::ControlInteractivity> _recentlyDetachedContent{
|
||||
winrt::multi_threaded_map<winrt::guid, Microsoft::Terminal::Control::ControlInteractivity>()
|
||||
};
|
||||
|
||||
void _finalizeDetach(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e);
|
||||
|
||||
void _closedHandler(winrt::Windows::Foundation::IInspectable sender,
|
||||
winrt::Windows::Foundation::IInspectable e);
|
||||
};
|
||||
}
|
||||
@@ -33,9 +33,6 @@ static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
|
||||
static const int AnimationDurationInMilliseconds = 200;
|
||||
static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(AnimationDurationInMilliseconds)));
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
|
||||
|
||||
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
|
||||
_control{ control },
|
||||
_lastActive{ lastFocused },
|
||||
@@ -83,7 +80,7 @@ Pane::Pane(std::shared_ptr<Pane> first,
|
||||
|
||||
// Use the unfocused border color as the pane background, so an actual color
|
||||
// appears behind panes as we animate them sliding in.
|
||||
_root.Background(s_unfocusedBorderBrush);
|
||||
_root.Background(_themeResources.unfocusedBorderBrush);
|
||||
|
||||
_root.Children().Append(_borderFirst);
|
||||
_root.Children().Append(_borderSecond);
|
||||
@@ -111,10 +108,12 @@ Pane::Pane(std::shared_ptr<Pane> first,
|
||||
// - Extract the terminal settings from the current (leaf) pane's control
|
||||
// to be used to create an equivalent control
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// - 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
|
||||
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
|
||||
{
|
||||
// Leaves are the only things that have controls
|
||||
assert(_IsLeaf());
|
||||
@@ -159,6 +158,12 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||
// object. That would work for schemes set by the Terminal, but not ones set
|
||||
// by VT, but that seems good enough.
|
||||
|
||||
// Only fill in the ContentGuid if absolutely needed.
|
||||
if (asContent)
|
||||
{
|
||||
args.ContentGuid(_control.ContentGuid());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -170,36 +175,62 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||
// Arguments:
|
||||
// - currentId: the id to use for the current/first pane
|
||||
// - nextId: the id to use for a new pane if we split
|
||||
// - asContent: We're serializing this set of actions as content actions for
|
||||
// moving to other windows, so we need to make sure to include ContentGuid's
|
||||
// in the final actions.
|
||||
// - asMovePane: only used with asContent. When this is true, we're building
|
||||
// these actions as a part of moving the pane to another window, but without
|
||||
// the context of the hosting tab. In that case, we'll want to build a
|
||||
// splitPane action even if we're just a single leaf, because there's no other
|
||||
// parent to try and build an action for us.
|
||||
// Return Value:
|
||||
// - 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)
|
||||
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId,
|
||||
uint32_t nextId,
|
||||
const bool asContent,
|
||||
const bool asMovePane)
|
||||
{
|
||||
// if we are a leaf then all there is to do is defer to the parent.
|
||||
if (_IsLeaf())
|
||||
// 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 (_lastActive)
|
||||
{
|
||||
return { {}, shared_from_this(), currentId, 0 };
|
||||
// empty args, this is the first pane, currentId is
|
||||
return { .args = {}, .firstPane = shared_from_this(), .focusedPaneId = currentId, .panesCreated = 0 };
|
||||
}
|
||||
|
||||
return { {}, shared_from_this(), std::nullopt, 0 };
|
||||
return { .args = {}, .firstPane = shared_from_this(), .focusedPaneId = std::nullopt, .panesCreated = 0 };
|
||||
}
|
||||
|
||||
auto buildSplitPane = [&](auto newPane) {
|
||||
ActionAndArgs actionAndArgs;
|
||||
actionAndArgs.Action(ShortcutAction::SplitPane);
|
||||
const auto terminalArgs{ newPane->GetTerminalArgsForPane() };
|
||||
const auto terminalArgs{ newPane->GetTerminalArgsForPane(asContent) };
|
||||
// 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;
|
||||
SplitPaneArgs args{ SplitType::Manual, splitDirection, 1. - _desiredSplitPosition, terminalArgs };
|
||||
const auto splitSize = (asContent && _IsLeaf() ? .5 : 1. - _desiredSplitPosition);
|
||||
SplitPaneArgs args{ SplitType::Manual, splitDirection, splitSize, terminalArgs };
|
||||
actionAndArgs.Args(args);
|
||||
|
||||
return actionAndArgs;
|
||||
};
|
||||
|
||||
if (asContent && _IsLeaf())
|
||||
{
|
||||
return {
|
||||
.args = { buildSplitPane(shared_from_this()) },
|
||||
.firstPane = shared_from_this(),
|
||||
.focusedPaneId = currentId,
|
||||
.panesCreated = 1
|
||||
};
|
||||
}
|
||||
|
||||
auto buildMoveFocus = [](auto direction) {
|
||||
MoveFocusArgs args{ direction };
|
||||
|
||||
@@ -226,7 +257,12 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
|
||||
focusedPaneId = nextId;
|
||||
}
|
||||
|
||||
return { { actionAndArgs }, _firstChild, focusedPaneId, 1 };
|
||||
return {
|
||||
.args = { actionAndArgs },
|
||||
.firstPane = _firstChild,
|
||||
.focusedPaneId = focusedPaneId,
|
||||
.panesCreated = 1
|
||||
};
|
||||
}
|
||||
|
||||
// We now need to execute the commands for each side of the tree
|
||||
@@ -263,7 +299,12 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
|
||||
// mutually exclusive.
|
||||
const auto focusedPaneId = firstState.focusedPaneId.has_value() ? firstState.focusedPaneId : secondState.focusedPaneId;
|
||||
|
||||
return { actions, firstState.firstPane, focusedPaneId, firstState.panesCreated + secondState.panesCreated + 1 };
|
||||
return {
|
||||
.args = { actions },
|
||||
.firstPane = firstState.firstPane,
|
||||
.focusedPaneId = focusedPaneId,
|
||||
.panesCreated = firstState.panesCreated + secondState.panesCreated + 1
|
||||
};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1396,8 +1437,8 @@ void Pane::UpdateVisuals()
|
||||
{
|
||||
_UpdateBorders();
|
||||
}
|
||||
_borderFirst.BorderBrush(_lastActive ? s_focusedBorderBrush : s_unfocusedBorderBrush);
|
||||
_borderSecond.BorderBrush(_lastActive ? s_focusedBorderBrush : s_unfocusedBorderBrush);
|
||||
_borderFirst.BorderBrush(_lastActive ? _themeResources.focusedBorderBrush : _themeResources.unfocusedBorderBrush);
|
||||
_borderSecond.BorderBrush(_lastActive ? _themeResources.focusedBorderBrush : _themeResources.unfocusedBorderBrush);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1849,7 +1890,7 @@ winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst)
|
||||
Controls::Grid dummyGrid;
|
||||
// GH#603 - we can safely add a BG here, as the control is gone right
|
||||
// away, to fill the space as the rest of the pane expands.
|
||||
dummyGrid.Background(s_unfocusedBorderBrush);
|
||||
dummyGrid.Background(_themeResources.unfocusedBorderBrush);
|
||||
// It should be the size of the closed pane.
|
||||
dummyGrid.Width(removedOriginalSize.Width);
|
||||
dummyGrid.Height(removedOriginalSize.Height);
|
||||
@@ -2127,7 +2168,7 @@ void Pane::_SetupEntranceAnimation()
|
||||
// * If we give the parent (us) root BG a color, then a transparent pane
|
||||
// will flash opaque during the animation, then back to transparent, which
|
||||
// looks bad.
|
||||
_secondChild->_root.Background(s_unfocusedBorderBrush);
|
||||
_secondChild->_root.Background(_themeResources.unfocusedBorderBrush);
|
||||
|
||||
const auto [firstSize, secondSize] = _CalcChildrenSizes(::base::saturated_cast<float>(totalSize));
|
||||
|
||||
@@ -3092,51 +3133,20 @@ float Pane::_ClampSplitPosition(const bool widthOrHeight, const float requestedV
|
||||
return std::clamp(requestedValue, minSplitPosition, maxSplitPosition);
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Attempts to load some XAML resources that the Pane will need. This includes:
|
||||
// * The Color we'll use for active Panes's borders - SystemAccentColor
|
||||
// * The Brush we'll use for inactive Panes - TabViewBackground (to match the
|
||||
// color of the titlebar)
|
||||
// Arguments:
|
||||
// - requestedTheme: this should be the currently active Theme for the app
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::SetupResources(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
|
||||
// Method Description:
|
||||
// - Update our stored brushes for the current theme. This will also recursively
|
||||
// update all our children.
|
||||
// - TerminalPage creates these brushes and ultimately owns them. Effectively,
|
||||
// we're just storing a smart pointer to the page's brushes.
|
||||
void Pane::UpdateResources(const PaneResources& resources)
|
||||
{
|
||||
const auto res = Application::Current().Resources();
|
||||
const auto accentColorKey = winrt::box_value(L"SystemAccentColor");
|
||||
if (res.HasKey(accentColorKey))
|
||||
{
|
||||
const auto colorFromResources = ThemeLookup(res, requestedTheme, accentColorKey);
|
||||
// If SystemAccentColor is _not_ a Color for some reason, use
|
||||
// Transparent as the color, so we don't do this process again on
|
||||
// the next pane (by leaving s_focusedBorderBrush nullptr)
|
||||
auto actualColor = winrt::unbox_value_or<Color>(colorFromResources, Colors::Black());
|
||||
s_focusedBorderBrush = SolidColorBrush(actualColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// DON'T use Transparent here - if it's "Transparent", then it won't
|
||||
// be able to hittest for clicks, and then clicking on the border
|
||||
// will eat focus.
|
||||
s_focusedBorderBrush = SolidColorBrush{ Colors::Black() };
|
||||
}
|
||||
_themeResources = resources;
|
||||
UpdateVisuals();
|
||||
|
||||
const auto unfocusedBorderBrushKey = winrt::box_value(L"UnfocusedBorderBrush");
|
||||
if (res.HasKey(unfocusedBorderBrushKey))
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
// MAKE SURE TO USE ThemeLookup, so that we get the correct resource for
|
||||
// the requestedTheme, not just the value from the resources (which
|
||||
// might not respect the settings' requested theme)
|
||||
auto obj = ThemeLookup(res, requestedTheme, unfocusedBorderBrushKey);
|
||||
s_unfocusedBorderBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// DON'T use Transparent here - if it's "Transparent", then it won't
|
||||
// be able to hittest for clicks, and then clicking on the border
|
||||
// will eat focus.
|
||||
s_unfocusedBorderBrush = SolidColorBrush{ Colors::Black() };
|
||||
_firstChild->UpdateResources(resources);
|
||||
_secondChild->UpdateResources(resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,12 @@ enum class SplitState : int
|
||||
Vertical = 2
|
||||
};
|
||||
|
||||
struct PaneResources
|
||||
{
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush focusedBorderBrush{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush unfocusedBorderBrush{ nullptr };
|
||||
};
|
||||
|
||||
class Pane : public std::enable_shared_from_this<Pane>
|
||||
{
|
||||
public:
|
||||
@@ -91,8 +97,8 @@ public:
|
||||
std::optional<uint32_t> focusedPaneId;
|
||||
uint32_t panesCreated;
|
||||
};
|
||||
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId);
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane() const;
|
||||
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;
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
@@ -136,7 +142,7 @@ public:
|
||||
|
||||
bool ContainsReadOnly() const;
|
||||
|
||||
static void SetupResources(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
void UpdateResources(const PaneResources& resources);
|
||||
|
||||
// Method Description:
|
||||
// - A helper method for ad-hoc recursion on a pane tree. Walks the pane
|
||||
@@ -217,8 +223,8 @@ private:
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
||||
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
|
||||
|
||||
PaneResources _themeResources;
|
||||
|
||||
#pragma region Properties that need to be transferred between child / parent panes upon splitting / closing
|
||||
std::shared_ptr<Pane> _firstChild{ nullptr };
|
||||
|
||||
30
src/cascadia/TerminalApp/SettingsLoadEventArgs.h
Normal file
30
src/cascadia/TerminalApp/SettingsLoadEventArgs.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SettingsLoadEventArgs.g.h"
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SettingsLoadEventArgs : SettingsLoadEventArgsT<SettingsLoadEventArgs>
|
||||
{
|
||||
WINRT_PROPERTY(bool, Reload, false);
|
||||
WINRT_PROPERTY(uint64_t, Result, S_OK);
|
||||
WINRT_PROPERTY(winrt::hstring, ExceptionText, L"");
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>, Warnings, nullptr);
|
||||
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::CascadiaSettings, NewSettings, nullptr);
|
||||
|
||||
public:
|
||||
SettingsLoadEventArgs(bool reload,
|
||||
uint64_t result,
|
||||
const winrt::hstring& exceptionText,
|
||||
const winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& warnings,
|
||||
const Microsoft::Terminal::Settings::Model::CascadiaSettings& newSettings) :
|
||||
_Reload{ reload },
|
||||
_Result{ result },
|
||||
_ExceptionText{ exceptionText },
|
||||
_Warnings{ warnings },
|
||||
_NewSettings{ newSettings } {};
|
||||
};
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The list of actions.
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions() const
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
|
||||
{
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::OpenSettings);
|
||||
|
||||
@@ -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 override;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
|
||||
|
||||
@@ -264,6 +264,19 @@ namespace winrt::TerminalApp::implementation
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
}
|
||||
});
|
||||
|
||||
// BODGY: When the tab is drag/dropped, the TabView gets a
|
||||
// TabDragStarting. However, the way it is implemented[^1], the
|
||||
// TabViewItem needs either an Item or a Content for the event to
|
||||
// include the correct TabViewItem. Otherwise, it will just return the
|
||||
// first TabViewItem in the TabView with the same Content as the dragged
|
||||
// tab (which, if the Content is null, will be the _first_ tab).
|
||||
//
|
||||
// So here, we'll stick an empty border in, just so that every tab has a
|
||||
// Content which is not equal to the others.
|
||||
//
|
||||
// [^1]: microsoft-ui-xaml/blob/92fbfcd55f05c92ac65569f5d284c5b36492091e/dev/TabView/TabView.cpp#L751-L758
|
||||
TabViewItem().Content(winrt::WUX::Controls::Border{});
|
||||
}
|
||||
|
||||
std::optional<winrt::Windows::UI::Color> TabBase::GetTabColor()
|
||||
|
||||
@@ -23,7 +23,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 = 0;
|
||||
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const = 0;
|
||||
|
||||
virtual std::optional<winrt::Windows::UI::Color> GetTabColor();
|
||||
void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
|
||||
|
||||
@@ -512,6 +512,11 @@ namespace winrt::TerminalApp::implementation
|
||||
_mruTabs.RemoveAt(mruIndex);
|
||||
}
|
||||
|
||||
if (_stashedDraggedTab && *_stashedDraggedTab == tab)
|
||||
{
|
||||
_stashedDraggedTab = nullptr;
|
||||
}
|
||||
|
||||
_tabs.RemoveAt(tabIndex);
|
||||
_tabView.TabItems().RemoveAt(tabIndex);
|
||||
_UpdateTabIndices();
|
||||
@@ -523,7 +528,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.
|
||||
if (!_maintainStateOnTabClose && ShouldUsePersistedLayout(_settings) && _numOpenWindows == 1)
|
||||
if (!_maintainStateOnTabClose && _settings.GlobalSettings().ShouldUsePersistedLayout() && _numOpenWindows == 1)
|
||||
{
|
||||
auto state = ApplicationState::SharedInstance();
|
||||
state.PersistedWindowLayouts(nullptr);
|
||||
@@ -709,7 +714,8 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::TerminalApp::TabBase TerminalPage::_GetTabByTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept
|
||||
{
|
||||
uint32_t tabIndexFromControl{};
|
||||
if (_tabView.TabItems().IndexOf(tabViewItem, tabIndexFromControl))
|
||||
const auto items{ _tabView.TabItems() };
|
||||
if (items.IndexOf(tabViewItem, tabIndexFromControl))
|
||||
{
|
||||
// If IndexOf returns true, we've actually got an index
|
||||
return _tabs.GetAt(tabIndexFromControl);
|
||||
|
||||
@@ -138,6 +138,15 @@
|
||||
<ClInclude Include="AppLogic.h">
|
||||
<DependentUpon>AppLogic.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ContentManager.h">
|
||||
<DependentUpon>TerminalPage.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TerminalWindow.h">
|
||||
<DependentUpon>TerminalWindow.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsLoadEventArgs.h">
|
||||
<DependentUpon>TerminalWindow.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Toast.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
@@ -231,6 +240,12 @@
|
||||
<ClCompile Include="AppLogic.cpp">
|
||||
<DependentUpon>AppLogic.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ContentManager.cpp">
|
||||
<DependentUpon>TerminalPage.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TerminalWindow.cpp">
|
||||
<DependentUpon>TerminalWindow.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
<ClCompile Include="Toast.cpp" />
|
||||
</ItemGroup>
|
||||
@@ -252,6 +267,7 @@
|
||||
<Midl Include="ShortcutActionDispatch.idl" />
|
||||
<Midl Include="AppKeyBindings.idl" />
|
||||
<Midl Include="AppLogic.idl" />
|
||||
<Midl Include="TerminalWindow.idl" />
|
||||
<Midl Include="MinMaxCloseControl.idl">
|
||||
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,8 @@
|
||||
#include "AppKeyBindings.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "RenameWindowRequestedArgs.g.h"
|
||||
#include "RequestMoveContentArgs.g.h"
|
||||
#include "RequestReceiveContentArgs.g.h"
|
||||
#include "Toast.h"
|
||||
|
||||
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
@@ -50,24 +52,48 @@ namespace winrt::TerminalApp::implementation
|
||||
_ProposedName{ name } {};
|
||||
};
|
||||
|
||||
struct RequestMoveContentArgs : RequestMoveContentArgsT<RequestMoveContentArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Window);
|
||||
WINRT_PROPERTY(winrt::hstring, Content);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Point>, WindowPosition);
|
||||
|
||||
public:
|
||||
RequestMoveContentArgs(const winrt::hstring window, const winrt::hstring content, uint32_t tabIndex) :
|
||||
_Window{ window },
|
||||
_Content{ content },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct RequestReceiveContentArgs : RequestReceiveContentArgsT<RequestReceiveContentArgs>
|
||||
{
|
||||
WINRT_PROPERTY(uint64_t, SourceWindow);
|
||||
WINRT_PROPERTY(uint64_t, TargetWindow);
|
||||
WINRT_PROPERTY(uint32_t, TabIndex);
|
||||
|
||||
public:
|
||||
RequestReceiveContentArgs(const uint64_t src, const uint64_t tgt, const uint32_t tabIndex) :
|
||||
_SourceWindow{ src },
|
||||
_TargetWindow{ tgt },
|
||||
_TabIndex{ tabIndex } {};
|
||||
};
|
||||
|
||||
struct TerminalPage : TerminalPageT<TerminalPage>
|
||||
{
|
||||
public:
|
||||
TerminalPage();
|
||||
TerminalPage(const TerminalApp::ContentManager& manager);
|
||||
|
||||
// This implements shobjidl's IInitializeWithWindow, but due to a XAML Compiler bug we cannot
|
||||
// put it in our inheritance graph. https://github.com/microsoft/microsoft-ui-xaml/issues/3331
|
||||
STDMETHODIMP Initialize(HWND hwnd);
|
||||
|
||||
void SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI);
|
||||
winrt::fire_and_forget SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI);
|
||||
|
||||
void Create();
|
||||
|
||||
bool ShouldUsePersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
bool ShouldImmediatelyHandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
std::optional<uint32_t> LoadPersistedLayoutIdx(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::WindowLayout LoadPersistedLayout(Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
|
||||
Microsoft::Terminal::Settings::Model::WindowLayout GetWindowLayout();
|
||||
|
||||
winrt::fire_and_forget NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e);
|
||||
@@ -117,20 +143,14 @@ namespace winrt::TerminalApp::implementation
|
||||
const bool initial,
|
||||
const winrt::hstring cwd = L"");
|
||||
|
||||
// Normally, WindowName and WindowId would be
|
||||
// WINRT_OBSERVABLE_PROPERTY's, but we want them to raise
|
||||
// WindowNameForDisplay and WindowIdForDisplay instead
|
||||
winrt::hstring WindowName() const noexcept;
|
||||
winrt::fire_and_forget WindowName(const winrt::hstring& value);
|
||||
uint64_t WindowId() const noexcept;
|
||||
void WindowId(const uint64_t& value);
|
||||
// For the sake of XAML binding:
|
||||
winrt::hstring WindowName() const noexcept { return _WindowProperties.WindowName(); };
|
||||
uint64_t WindowId() const noexcept { return _WindowProperties.WindowId(); };
|
||||
winrt::hstring WindowIdForDisplay() const noexcept { return _WindowProperties.WindowIdForDisplay(); };
|
||||
winrt::hstring WindowNameForDisplay() const noexcept { return _WindowProperties.WindowNameForDisplay(); };
|
||||
|
||||
void SetNumberOfOpenWindows(const uint64_t value);
|
||||
void SetPersistedLayoutIdx(const uint32_t value);
|
||||
|
||||
winrt::hstring WindowIdForDisplay() const noexcept;
|
||||
winrt::hstring WindowNameForDisplay() const noexcept;
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
bool IsElevated() const noexcept;
|
||||
|
||||
void OpenSettingsUI();
|
||||
@@ -138,6 +158,13 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
TerminalApp::IWindowProperties WindowProperties();
|
||||
void WindowProperties(const TerminalApp::IWindowProperties& props);
|
||||
winrt::fire_and_forget WindowNameChanged();
|
||||
|
||||
winrt::fire_and_forget AttachContent(winrt::hstring content, uint32_t tabIndex);
|
||||
winrt::fire_and_forget SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
@@ -153,13 +180,16 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(Initialized, IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable);
|
||||
TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
|
||||
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(ShowWindowChanged, IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs)
|
||||
|
||||
TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs);
|
||||
TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs);
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, TitlebarBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
@@ -192,8 +222,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _isFullscreen{ false };
|
||||
bool _isMaximized{ false };
|
||||
bool _isAlwaysOnTop{ false };
|
||||
winrt::hstring _WindowName{};
|
||||
uint64_t _WindowId{ 0 };
|
||||
|
||||
std::optional<uint32_t> _loadFromPersistedLayoutIdx{};
|
||||
uint64_t _numOpenWindows{ 0 };
|
||||
|
||||
@@ -230,7 +259,17 @@ namespace winrt::TerminalApp::implementation
|
||||
int _renamerLayoutCount{ 0 };
|
||||
bool _renamerPressedEnter{ false };
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
|
||||
TerminalApp::IWindowProperties _WindowProperties{ nullptr };
|
||||
|
||||
PaneResources _paneResources;
|
||||
|
||||
TerminalApp::ContentManager _manager{ nullptr };
|
||||
|
||||
winrt::com_ptr<winrt::TerminalApp::implementation::TabBase> _stashedDraggedTab{ nullptr };
|
||||
til::point _dragOffset{ 0, 0 };
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult>
|
||||
_ShowDialogHelper(const std::wstring_view& name);
|
||||
|
||||
void _ShowAboutDialog();
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowQuitDialog();
|
||||
@@ -273,10 +312,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _UpdateCommandsForPalette();
|
||||
void _SetBackgroundImage(const winrt::Microsoft::Terminal::Settings::Model::IAppearanceConfig& newAppearance);
|
||||
|
||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, Microsoft::Terminal::Settings::Model::Command> _ExpandCommands(Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::Command> commandsToExpand,
|
||||
Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::Profile> profiles,
|
||||
Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::ColorScheme> schemes);
|
||||
|
||||
void _DuplicateFocusedTab();
|
||||
void _DuplicateTab(const TerminalTab& tab);
|
||||
|
||||
@@ -301,7 +336,8 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _SelectTab(uint32_t tabIndex);
|
||||
bool _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
bool _MovePane(const uint32_t tabIdx);
|
||||
bool _MovePane(const Microsoft::Terminal::Settings::Model::MovePaneArgs args);
|
||||
bool _MoveTab(const Microsoft::Terminal::Settings::Model::MoveTabArgs args);
|
||||
|
||||
template<typename F>
|
||||
bool _ApplyToActiveControls(F f)
|
||||
@@ -392,6 +428,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
|
||||
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Control::TermControl& term);
|
||||
winrt::Microsoft::Terminal::Control::TermControl _InitControlFromContent(const winrt::guid& contentGuid);
|
||||
|
||||
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
|
||||
const winrt::TerminalApp::TabBase& sourceTab = nullptr,
|
||||
@@ -459,9 +497,22 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _updateThemeColors();
|
||||
void _updateTabCloseButton(const winrt::Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem);
|
||||
void _updatePaneResources(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
|
||||
|
||||
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
|
||||
void _onTabDragStarting(winrt::Microsoft::UI::Xaml::Controls::TabView sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDragStartingEventArgs e);
|
||||
void _onTabStripDragOver(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||
winrt::fire_and_forget _onTabStripDrop(winrt::Windows::Foundation::IInspectable sender, winrt::Windows::UI::Xaml::DragEventArgs e);
|
||||
winrt::fire_and_forget _onTabDroppedOutside(winrt::Windows::Foundation::IInspectable sender, winrt::Microsoft::UI::Xaml::Controls::TabViewTabDroppedOutsideEventArgs e);
|
||||
|
||||
void _DetachPaneFromWindow(std::shared_ptr<Pane> pane);
|
||||
void _DetachTabFromWindow(const winrt::com_ptr<TabBase>& terminalTab);
|
||||
void _MoveContent(std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions,
|
||||
const winrt::hstring& windowName,
|
||||
const uint32_t tabIndex,
|
||||
Windows::Foundation::IReference<Windows::Foundation::Point> dragPoint = nullptr);
|
||||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
|
||||
@@ -477,4 +528,5 @@ namespace winrt::TerminalApp::implementation
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(TerminalPage);
|
||||
BASIC_FACTORY(RequestReceiveContentArgs);
|
||||
}
|
||||
|
||||
@@ -5,21 +5,56 @@ import "IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
|
||||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
[default_interface] runtimeclass ContentManager
|
||||
{
|
||||
Microsoft.Terminal.Control.ControlInteractivity CreateCore(Microsoft.Terminal.Control.IControlSettings settings,
|
||||
Microsoft.Terminal.Control.IControlAppearance unfocusedAppearance,
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
Microsoft.Terminal.Control.ControlInteractivity LookupCore(Guid id);
|
||||
void Detach(Microsoft.Terminal.Control.TermControl control);
|
||||
}
|
||||
|
||||
delegate void LastTabClosedEventArgs();
|
||||
|
||||
[default_interface] runtimeclass RenameWindowRequestedArgs
|
||||
{
|
||||
String ProposedName { get; };
|
||||
};
|
||||
[default_interface] runtimeclass RequestMoveContentArgs
|
||||
{
|
||||
String Window { get; };
|
||||
String Content { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
Windows.Foundation.IReference<Windows.Foundation.Point> WindowPosition { get; };
|
||||
};
|
||||
[default_interface] runtimeclass RequestReceiveContentArgs {
|
||||
RequestReceiveContentArgs(UInt64 src, UInt64 tgt, UInt32 tabIndex);
|
||||
|
||||
UInt64 SourceWindow { get; };
|
||||
UInt64 TargetWindow { get; };
|
||||
UInt32 TabIndex { get; };
|
||||
};
|
||||
|
||||
interface IDialogPresenter
|
||||
{
|
||||
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
|
||||
};
|
||||
|
||||
interface IWindowProperties
|
||||
{
|
||||
String WindowName { get; };
|
||||
UInt64 WindowId { get; };
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
Boolean IsQuakeWindow();
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
{
|
||||
TerminalPage();
|
||||
TerminalPage(ContentManager manager);
|
||||
|
||||
// XAML bound properties
|
||||
String ApplicationDisplayName { get; };
|
||||
@@ -29,13 +64,9 @@ namespace TerminalApp
|
||||
Boolean Fullscreen { get; };
|
||||
Boolean AlwaysOnTop { get; };
|
||||
|
||||
IWindowProperties WindowProperties { get; };
|
||||
void IdentifyWindow();
|
||||
String WindowName;
|
||||
UInt64 WindowId;
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
void RenameFailed();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
// We cannot use the default XAML APIs because we want to make sure
|
||||
// that there's only one application-global dialog visible at a time,
|
||||
@@ -45,9 +76,16 @@ namespace TerminalApp
|
||||
String KeyboardServiceDisabledText { get; };
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
void AttachContent(String content, UInt32 tabIndex);
|
||||
|
||||
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
|
||||
void WindowActivated(Boolean activated);
|
||||
void SendContentToOther(RequestReceiveContentArgs args);
|
||||
|
||||
String WindowName { get; };
|
||||
UInt64 WindowId { get; };
|
||||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
|
||||
@@ -59,10 +97,13 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,16 +438,16 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - A vector of commands
|
||||
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions() const
|
||||
std::vector<ActionAndArgs> TerminalTab::BuildStartupActions(const bool asContent) const
|
||||
{
|
||||
// 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);
|
||||
auto state = _rootPane->BuildStartupActions(0, 1, asContent);
|
||||
|
||||
{
|
||||
ActionAndArgs newTabAction{};
|
||||
newTabAction.Action(ShortcutAction::NewTab);
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane() };
|
||||
NewTabArgs newTabArgs{ state.firstPane->GetTerminalArgsForPane(asContent) };
|
||||
newTabAction.Args(newTabArgs);
|
||||
|
||||
state.args.emplace(state.args.begin(), std::move(newTabAction));
|
||||
@@ -783,6 +783,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool TerminalTab::FocusPane(const uint32_t id)
|
||||
{
|
||||
if (_rootPane == nullptr)
|
||||
return false;
|
||||
_changingActivePane = true;
|
||||
const auto res = _rootPane->FocusPane(id);
|
||||
_changingActivePane = false;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void EnterZoom();
|
||||
void ExitZoom();
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
|
||||
|
||||
int GetLeafPaneCount() const noexcept;
|
||||
|
||||
|
||||
1363
src/cascadia/TerminalApp/TerminalWindow.cpp
Normal file
1363
src/cascadia/TerminalApp/TerminalWindow.cpp
Normal file
File diff suppressed because it is too large
Load Diff
223
src/cascadia/TerminalApp/TerminalWindow.h
Normal file
223
src/cascadia/TerminalApp/TerminalWindow.h
Normal file
@@ -0,0 +1,223 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TerminalWindow.g.h"
|
||||
#include "SystemMenuChangeArgs.g.h"
|
||||
|
||||
#include "SettingsLoadEventArgs.h"
|
||||
#include "TerminalPage.h"
|
||||
#include "SettingsLoadEventArgs.h"
|
||||
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
#include <ThrottledFunc.h>
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
class CommandlineTest;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SystemMenuChangeArgs : SystemMenuChangeArgsT<SystemMenuChangeArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Name, L"");
|
||||
WINRT_PROPERTY(SystemMenuChangeAction, Action, SystemMenuChangeAction::Add);
|
||||
WINRT_PROPERTY(SystemMenuItemHandler, Handler, nullptr);
|
||||
|
||||
public:
|
||||
SystemMenuChangeArgs(const winrt::hstring& name, SystemMenuChangeAction action, SystemMenuItemHandler handler = nullptr) :
|
||||
_Name{ name }, _Action{ action }, _Handler{ handler } {};
|
||||
};
|
||||
|
||||
struct TerminalWindow : TerminalWindowT<TerminalWindow, IInitializeWithWindow>
|
||||
{
|
||||
public:
|
||||
TerminalWindow(const TerminalApp::SettingsLoadEventArgs& settingsLoadedResult, const TerminalApp::ContentManager& manager);
|
||||
~TerminalWindow() = default;
|
||||
|
||||
STDMETHODIMP Initialize(HWND hwnd);
|
||||
|
||||
void Create();
|
||||
|
||||
bool IsUwp() const noexcept;
|
||||
bool IsElevated() const noexcept;
|
||||
|
||||
void Quit();
|
||||
|
||||
winrt::fire_and_forget UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);
|
||||
|
||||
bool HasCommandlineArguments() const noexcept;
|
||||
|
||||
int32_t SetStartupCommandline(array_view<const winrt::hstring> actions);
|
||||
void SetStartupContent(winrt::hstring content, Windows::Foundation::IReference<Windows::Foundation::Rect> contentBounds);
|
||||
int32_t ExecuteCommandline(array_view<const winrt::hstring> actions, const winrt::hstring& cwd);
|
||||
void SetSettingsStartupArgs(const std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
winrt::hstring ParseCommandlineMessage();
|
||||
bool ShouldExitEarly();
|
||||
|
||||
bool ShouldImmediatelyHandoffToElevated();
|
||||
void HandoffToElevated();
|
||||
|
||||
bool FocusMode() const;
|
||||
bool Fullscreen() const;
|
||||
void Maximized(bool newMaximized);
|
||||
bool AlwaysOnTop() const;
|
||||
bool AutoHideWindow();
|
||||
|
||||
hstring GetWindowLayoutJson(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
|
||||
void IdentifyWindow();
|
||||
void RenameFailed();
|
||||
|
||||
std::optional<uint32_t> LoadPersistedLayoutIdx() const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::WindowLayout LoadPersistedLayout() const;
|
||||
|
||||
void SetPersistedLayoutIdx(const uint32_t idx);
|
||||
void SetNumberOfOpenWindows(const uint64_t num);
|
||||
bool ShouldUsePersistedLayout() const;
|
||||
|
||||
void RequestExitFullscreen();
|
||||
|
||||
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
|
||||
bool CenterOnLaunch();
|
||||
TerminalApp::InitialPosition GetInitialPosition(int64_t defaultInitialX, int64_t defaultInitialY);
|
||||
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme();
|
||||
Microsoft::Terminal::Settings::Model::LaunchMode GetLaunchMode();
|
||||
bool GetShowTabsInTitlebar();
|
||||
bool GetInitialAlwaysOnTop();
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
|
||||
Windows::UI::Xaml::UIElement GetRoot() noexcept;
|
||||
|
||||
hstring Title();
|
||||
void TitlebarClicked();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position);
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
winrt::TerminalApp::TaskbarState TaskbarState();
|
||||
winrt::Windows::UI::Xaml::Media::Brush TitlebarBrush();
|
||||
void WindowActivated(const bool activated);
|
||||
|
||||
bool GetMinimizeToNotificationArea();
|
||||
bool GetAlwaysShowNotificationIcon();
|
||||
bool RequestsTrayIcon();
|
||||
|
||||
bool GetShowTitleInTitlebar();
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
|
||||
void DismissDialog();
|
||||
|
||||
Microsoft::Terminal::Settings::Model::Theme Theme();
|
||||
void UpdateSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::SettingsLoadEventArgs& arg);
|
||||
|
||||
// Normally, WindowName and WindowId would be
|
||||
// WINRT_OBSERVABLE_PROPERTY's, but we want them to raise
|
||||
// WindowNameForDisplay and WindowIdForDisplay instead
|
||||
winrt::hstring WindowName() const noexcept;
|
||||
void WindowName(const winrt::hstring& value);
|
||||
uint64_t WindowId() const noexcept;
|
||||
void WindowId(const uint64_t& value);
|
||||
winrt::hstring WindowIdForDisplay() const noexcept;
|
||||
winrt::hstring WindowNameForDisplay() const noexcept;
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
|
||||
void AttachContent(winrt::hstring content, uint32_t tabIndex);
|
||||
void SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
|
||||
// Usually we'd just do
|
||||
// WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
//
|
||||
// But what we're doing here is exposing the Page's PropertyChanged _as
|
||||
// our own event_. It's a FORWARDED_CALLBACK, essentially.
|
||||
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _root->PropertyChanged(handler); }
|
||||
void PropertyChanged(winrt::event_token const& token) { _root->PropertyChanged(token); }
|
||||
|
||||
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme);
|
||||
|
||||
private:
|
||||
// If you add controls here, but forget to null them either here or in
|
||||
// the ctor, you're going to have a bad time. It'll mysteriously fail to
|
||||
// activate the AppLogic.
|
||||
// ALSO: If you add any UIElements as roots here, make sure they're
|
||||
// updated in _ApplyTheme. The root currently is _root.
|
||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog{ nullptr };
|
||||
std::shared_mutex _dialogLock;
|
||||
|
||||
bool _hasCommandLineArguments{ false };
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
bool _gotSettingsStartupActions{ false };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _settingsStartupArgs{};
|
||||
Windows::Foundation::IReference<Windows::Foundation::Rect> _contentBounds{ nullptr };
|
||||
|
||||
winrt::hstring _WindowName{};
|
||||
uint64_t _WindowId{ 0 };
|
||||
|
||||
uint64_t _numOpenWindows{ 1 };
|
||||
std::optional<uint32_t> _loadFromPersistedLayoutIdx{};
|
||||
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
TerminalApp::SettingsLoadEventArgs _initialLoadResult{ nullptr };
|
||||
|
||||
TerminalApp::ContentManager _manager{ nullptr };
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _initialContentArgs;
|
||||
|
||||
void _ShowLoadErrorsDialog(const winrt::hstring& titleKey,
|
||||
const winrt::hstring& contentKey,
|
||||
HRESULT settingsLoadedResult,
|
||||
const winrt::hstring& exceptionText);
|
||||
void _ShowLoadWarningsDialog(const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings>& warnings);
|
||||
|
||||
bool _IsKeyboardServiceEnabled();
|
||||
|
||||
void _RefreshThemeRoutine();
|
||||
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void _OpenSettingsUI();
|
||||
// These are events that are handled by the TerminalPage, but are
|
||||
// exposed through the AppLogic. This macro is used to forward the event
|
||||
// directly to them.
|
||||
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(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);
|
||||
FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged);
|
||||
FORWARDED_TYPED_EVENT(RaiseVisualBell, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, RaiseVisualBell);
|
||||
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
|
||||
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
|
||||
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
|
||||
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
|
||||
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
|
||||
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);
|
||||
|
||||
TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable);
|
||||
|
||||
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
|
||||
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
|
||||
|
||||
FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
|
||||
FORWARDED_TYPED_EVENT(RequestReceiveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestReceiveContentArgs, _root, RequestReceiveContent);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalAppLocalTests::CommandlineTest;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(TerminalWindow);
|
||||
}
|
||||
145
src/cascadia/TerminalApp/TerminalWindow.idl
Normal file
145
src/cascadia/TerminalApp/TerminalWindow.idl
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TerminalPage.idl";
|
||||
import "ShortcutActionDispatch.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
struct InitialPosition
|
||||
{
|
||||
Int64 X;
|
||||
Int64 Y;
|
||||
};
|
||||
|
||||
delegate void SystemMenuItemHandler();
|
||||
|
||||
enum SystemMenuChangeAction
|
||||
{
|
||||
Add = 0,
|
||||
Remove = 1
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SystemMenuChangeArgs {
|
||||
String Name { get; };
|
||||
SystemMenuChangeAction Action { get; };
|
||||
SystemMenuItemHandler Handler { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SettingsLoadEventArgs
|
||||
{
|
||||
Boolean Reload { get; };
|
||||
UInt64 Result { get; };
|
||||
IVector<Microsoft.Terminal.Settings.Model.SettingsLoadWarnings> Warnings { get; };
|
||||
String ExceptionText { get; };
|
||||
|
||||
Microsoft.Terminal.Settings.Model.CascadiaSettings NewSettings { get; };
|
||||
|
||||
};
|
||||
|
||||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
[default_interface] runtimeclass TerminalWindow : IDirectKeyListener, IDialogPresenter, IWindowProperties, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
TerminalWindow(SettingsLoadEventArgs result, ContentManager manager);
|
||||
|
||||
// For your own sanity, it's better to do setup outside the ctor.
|
||||
// If you do any setup in the ctor that ends up throwing an exception,
|
||||
// then it might look like TermApp just failed to activate, which will
|
||||
// cause you to chase down the rabbit hole of "why is TermApp not
|
||||
// registered?" when it definitely is.
|
||||
void Create();
|
||||
|
||||
Boolean IsElevated();
|
||||
|
||||
Boolean HasCommandlineArguments();
|
||||
|
||||
Int32 SetStartupCommandline(String[] commands);
|
||||
void SetStartupContent(String json, Windows.Foundation.IReference<Windows.Foundation.Rect> bounds);
|
||||
Int32 ExecuteCommandline(String[] commands, String cwd);
|
||||
String ParseCommandlineMessage { get; };
|
||||
Boolean ShouldExitEarly { get; };
|
||||
|
||||
Boolean ShouldImmediatelyHandoffToElevated();
|
||||
void HandoffToElevated();
|
||||
|
||||
void Quit();
|
||||
|
||||
Windows.UI.Xaml.UIElement GetRoot();
|
||||
|
||||
String Title { get; };
|
||||
Boolean FocusMode { get; };
|
||||
Boolean Fullscreen { get; };
|
||||
void Maximized(Boolean newMaximized);
|
||||
Boolean AlwaysOnTop { get; };
|
||||
Boolean AutoHideWindow { get; };
|
||||
|
||||
void IdentifyWindow();
|
||||
void SetPersistedLayoutIdx(UInt32 idx);
|
||||
void SetNumberOfOpenWindows(UInt64 num);
|
||||
void RenameFailed();
|
||||
void RequestExitFullscreen();
|
||||
|
||||
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean CenterOnLaunch { get; };
|
||||
|
||||
InitialPosition GetInitialPosition(Int64 defaultInitialX, Int64 defaultInitialY);
|
||||
Windows.UI.Xaml.ElementTheme GetRequestedTheme();
|
||||
Microsoft.Terminal.Settings.Model.LaunchMode GetLaunchMode();
|
||||
Boolean GetShowTabsInTitlebar();
|
||||
Boolean GetInitialAlwaysOnTop();
|
||||
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
|
||||
void TitlebarClicked();
|
||||
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
void WindowVisibilityChanged(Boolean showOrHide);
|
||||
|
||||
TaskbarState TaskbarState{ get; };
|
||||
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
|
||||
void WindowActivated(Boolean activated);
|
||||
|
||||
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
|
||||
|
||||
Boolean GetMinimizeToNotificationArea();
|
||||
Boolean GetAlwaysShowNotificationIcon();
|
||||
Boolean RequestsTrayIcon();
|
||||
Boolean GetShowTitleInTitlebar();
|
||||
|
||||
// These already have accessors as a part of IWindowProperties, but we
|
||||
// also want to be able to set them.
|
||||
String WindowName { set; };
|
||||
UInt64 WindowId { set; };
|
||||
|
||||
// See IDialogPresenter and TerminalPage's DialogPresenter for more
|
||||
// information.
|
||||
void DismissDialog();
|
||||
|
||||
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, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ChangeMaximizeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RaiseVisualBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, SettingsLoadEventArgs> SettingsChanged;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RequestReceiveContentArgs> RequestReceiveContent;
|
||||
|
||||
void AttachContent(String content, UInt32 tabIndex);
|
||||
void SendContentToOther(RequestReceiveContentArgs args);
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
_setupDispatcherAndCallbacks();
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
|
||||
void ControlCore::_setupDispatcherAndCallbacks()
|
||||
{
|
||||
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
|
||||
// us the same dispatcher as TermControl::Dispatcher(). If we're out of
|
||||
// proc, this'll return null. We'll need to instead make a new
|
||||
@@ -211,8 +217,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
core->_ScrollPositionChangedHandlers(*core, update);
|
||||
}
|
||||
});
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
|
||||
ControlCore::~ControlCore()
|
||||
@@ -225,6 +229,30 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::Detach()
|
||||
{
|
||||
// Disable the renderer, so that it doesn't try to start any new frames
|
||||
// for our engines while we're not attached to anything.
|
||||
_renderer->WaitForPaintCompletionAndDisable(INFINITE);
|
||||
|
||||
_tsfTryRedrawCanvas.reset();
|
||||
_updatePatternLocations.reset();
|
||||
_updateScrollBar.reset();
|
||||
}
|
||||
|
||||
void ControlCore::Reparent(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
_settings->KeyBindings(keyBindings);
|
||||
_setupDispatcherAndCallbacks();
|
||||
const auto actualNewSize = _actualFont.GetSize();
|
||||
// Bubble this up, so our new control knows how big we want the font.
|
||||
_FontSizeChangedHandlers(actualNewSize.width, actualNewSize.height, true);
|
||||
|
||||
// Turn the rendering back on now that we're ready to go.
|
||||
_renderer->EnablePainting();
|
||||
_AttachedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
bool ControlCore::Initialize(const double actualWidth,
|
||||
const double actualHeight,
|
||||
const double compositionScale)
|
||||
@@ -574,7 +602,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// itself - it was initiated by the mouse wheel, or the scrollbar.
|
||||
_terminal->UserScrollViewport(viewTop);
|
||||
|
||||
(*_updatePatternLocations)();
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::AdjustOpacity(const double adjustment)
|
||||
@@ -971,18 +1002,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ControlCore::SizeChanged(const double width,
|
||||
const double height)
|
||||
{
|
||||
// _refreshSizeUnderLock redraws the entire terminal.
|
||||
// Don't call it if we don't have to.
|
||||
if (_panelWidth == width && _panelHeight == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_panelWidth = width;
|
||||
_panelHeight = height;
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_refreshSizeUnderLock();
|
||||
SizeOrScaleChanged(width, height, _compositionScale);
|
||||
}
|
||||
|
||||
void ControlCore::ScaleChanged(const double scale)
|
||||
@@ -991,19 +1011,31 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return;
|
||||
}
|
||||
SizeOrScaleChanged(_panelWidth, _panelHeight, scale);
|
||||
}
|
||||
|
||||
void ControlCore::SizeOrScaleChanged(const double width,
|
||||
const double height,
|
||||
const double scale)
|
||||
{
|
||||
// _refreshSizeUnderLock redraws the entire terminal.
|
||||
// Don't call it if we don't have to.
|
||||
if (_compositionScale == scale)
|
||||
if (_panelWidth == width && _panelHeight == height && _compositionScale == scale)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto oldScale = _compositionScale;
|
||||
|
||||
_panelWidth = width;
|
||||
_panelHeight = height;
|
||||
_compositionScale = scale;
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
// _updateFont relies on the new _compositionScale set above
|
||||
_updateFont();
|
||||
if (oldScale != scale)
|
||||
{
|
||||
// _updateFont relies on the new _compositionScale set above
|
||||
_updateFont();
|
||||
}
|
||||
_refreshSizeUnderLock();
|
||||
}
|
||||
|
||||
@@ -1364,7 +1396,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto update{ winrt::make<ScrollPositionChangedArgs>(viewTop,
|
||||
viewHeight,
|
||||
bufferSize) };
|
||||
if (!_inUnitTests)
|
||||
if (!_inUnitTests && _updateScrollBar)
|
||||
{
|
||||
_updateScrollBar->Run(update);
|
||||
}
|
||||
@@ -1374,14 +1406,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
// Additionally, start the throttled update of where our links are.
|
||||
(*_updatePatternLocations)();
|
||||
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_terminalCursorPositionChanged()
|
||||
{
|
||||
// When the buffer's cursor moves, start the throttled func to
|
||||
// eventually dispatch a CursorPositionChanged event.
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
if (_tsfTryRedrawCanvas)
|
||||
{
|
||||
_tsfTryRedrawCanvas->Run();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_terminalTaskbarProgressChanged()
|
||||
@@ -1409,7 +1448,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// The UI thread might try to acquire the console lock from time to time.
|
||||
// --> Unlock it, so the UI doesn't hang while we're busy.
|
||||
const auto suspension = _terminal->SuspendLock();
|
||||
|
||||
// This call will block for the duration, unless shutdown early.
|
||||
_midiAudio.PlayNote(reinterpret_cast<HWND>(_owningHwnd), noteNumber, velocity, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
|
||||
}
|
||||
@@ -1660,6 +1698,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// _renderer will always exist since it's introduced in the ctor
|
||||
_renderer->AddRenderEngine(pEngine);
|
||||
}
|
||||
void ControlCore::DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
{
|
||||
_renderer->RemoveRenderEngine(pEngine);
|
||||
}
|
||||
|
||||
bool ControlCore::IsInReadOnlyMode() const
|
||||
{
|
||||
@@ -1683,7 +1725,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_terminal->Write(hstr);
|
||||
|
||||
// Start the throttled update of where our hyperlinks are.
|
||||
(*_updatePatternLocations)();
|
||||
if (_updatePatternLocations)
|
||||
{
|
||||
(*_updatePatternLocations)();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -1692,6 +1737,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ControlCore::SwapChainHandle() const
|
||||
{
|
||||
// This is called by:
|
||||
// * TermControl::RenderEngineSwapChainChanged, who is only registered
|
||||
// after Core::Initialize() is called.
|
||||
// * TermControl::_InitializeTerminal, after the call to Initialize, for
|
||||
// _AttachDxgiSwapChainToXaml.
|
||||
// In both cases, we'll have a _renderEngine by then.
|
||||
return _renderEngine ? reinterpret_cast<uint64_t>(_renderEngine->GetSwapChainHandle()) : 0u;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Clear the contents of the buffer. The region cleared is given by
|
||||
// clearType:
|
||||
|
||||
@@ -63,6 +63,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const double compositionScale);
|
||||
void EnablePainting();
|
||||
|
||||
void Detach();
|
||||
|
||||
void UpdateSettings(const Control::IControlSettings& settings, const IControlAppearance& newAppearance);
|
||||
void ApplyAppearance(const bool& focused);
|
||||
Control::IControlSettings Settings() { return *_settings; };
|
||||
@@ -73,8 +75,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme);
|
||||
|
||||
uint64_t SwapChainHandle() const;
|
||||
void Reparent(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
void SizeChanged(const double width, const double height);
|
||||
void ScaleChanged(const double scale);
|
||||
void SizeOrScaleChanged(const double width, const double height, const double scale);
|
||||
|
||||
void AdjustFontSize(float fontSizeDelta);
|
||||
void ResetFontSize();
|
||||
@@ -190,6 +196,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool& selectionNeedsToBeCopied);
|
||||
|
||||
void AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
void DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
|
||||
bool IsInReadOnlyMode() const;
|
||||
void ToggleReadOnlyMode();
|
||||
@@ -233,6 +240,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
@@ -285,6 +294,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
void _setupDispatcherAndCallbacks();
|
||||
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
|
||||
@@ -76,6 +76,8 @@ namespace Microsoft.Terminal.Control
|
||||
IControlAppearance UnfocusedAppearance { get; };
|
||||
Boolean HasUnfocusedAppearance();
|
||||
|
||||
UInt64 SwapChainHandle { get; };
|
||||
|
||||
Windows.Foundation.Size FontSize { get; };
|
||||
String FontFaceName { get; };
|
||||
UInt16 FontWeight { get; };
|
||||
@@ -108,6 +110,7 @@ namespace Microsoft.Terminal.Control
|
||||
void AdjustFontSize(Single fontSizeDelta);
|
||||
void SizeChanged(Double width, Double height);
|
||||
void ScaleChanged(Double scale);
|
||||
void SizeOrScaleChanged(Double width, Double height, Double scale);
|
||||
|
||||
void ToggleShaderEffects();
|
||||
void ToggleReadOnlyMode();
|
||||
@@ -126,7 +129,6 @@ namespace Microsoft.Terminal.Control
|
||||
String HoveredUriText { get; };
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
|
||||
|
||||
void Close();
|
||||
void BlinkCursor();
|
||||
Boolean IsInReadOnlyMode { get; };
|
||||
Boolean CursorOn;
|
||||
@@ -162,5 +164,7 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,7 +44,48 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_lastMouseClickPos{},
|
||||
_selectionNeedsToBeCopied{ false }
|
||||
{
|
||||
_guid = ::Microsoft::Console::Utils::CreateGuid();
|
||||
|
||||
_core = winrt::make_self<ControlCore>(settings, unfocusedAppearance, connection);
|
||||
|
||||
_core->Attached([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto self{ weakThis.get() })
|
||||
{
|
||||
self->_AttachedHandlers(*self, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
winrt::guid ControlInteractivity::Id()
|
||||
{
|
||||
return _guid;
|
||||
}
|
||||
|
||||
void ControlInteractivity::Detach()
|
||||
{
|
||||
if (_uiaEngine)
|
||||
{
|
||||
// There's a potential race here where we've removed the TermControl
|
||||
// from the UI tree, but the UIA engine is in the middle of a paint,
|
||||
// and the UIA engine will try to dispatch to the
|
||||
// TermControlAutomationPeer, which (is now)/(will very soon be) gone.
|
||||
//
|
||||
// To alleviate, make sure to disable the UIA engine and remove it,
|
||||
// and ALSO disable the renderer. Core.Detach will take care of the
|
||||
// WaitForPaintCompletionAndDisable (which will stop the renderer
|
||||
// after all current engines are done painting).
|
||||
//
|
||||
// Simply disabling the UIA engine is not enough, because it's
|
||||
// possible that it had already started presenting here.
|
||||
LOG_IF_FAILED(_uiaEngine->Disable());
|
||||
_core->DetachUiaEngine(_uiaEngine.get());
|
||||
}
|
||||
_core->Detach();
|
||||
}
|
||||
|
||||
void ControlInteractivity::Reparent(const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
_core->Reparent(keyBindings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -73,6 +114,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return *_core;
|
||||
}
|
||||
|
||||
void ControlInteractivity::Close()
|
||||
{
|
||||
_ClosedHandlers(*this, nullptr);
|
||||
if (_core)
|
||||
{
|
||||
_core->Close();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the number of clicks that occurred (double and triple click support).
|
||||
// Every call to this function registers a click.
|
||||
@@ -649,7 +699,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
try
|
||||
{
|
||||
const auto autoPeer = winrt::make_self<implementation::InteractivityAutomationPeer>(this);
|
||||
|
||||
if (_uiaEngine)
|
||||
{
|
||||
_core->DetachUiaEngine(_uiaEngine.get());
|
||||
}
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
|
||||
_core->AttachUiaEngine(_uiaEngine.get());
|
||||
return *autoPeer;
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void Initialize();
|
||||
Control::ControlCore Core();
|
||||
|
||||
void Close();
|
||||
void Detach();
|
||||
|
||||
Control::InteractivityAutomationPeer OnCreateAutomationPeer();
|
||||
::Microsoft::Console::Render::IRenderData* GetRenderData() const;
|
||||
|
||||
@@ -85,10 +88,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void SetEndSelectionPoint(const Core::Point pixelPosition);
|
||||
bool ManglePathsForWsl();
|
||||
|
||||
winrt::guid Id();
|
||||
void Reparent(const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Closed, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
// NOTE: _uiaEngine must be ordered before _core.
|
||||
//
|
||||
@@ -129,6 +138,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _lastHoveredInterval{ std::nullopt };
|
||||
|
||||
winrt::guid _guid;
|
||||
|
||||
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
|
||||
void _updateSystemParameterSettings() noexcept;
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ namespace Microsoft.Terminal.Control
|
||||
void GotFocus();
|
||||
void LostFocus();
|
||||
|
||||
Guid Id { get; };
|
||||
void Reparent(Microsoft.Terminal.Control.IKeyBindings keyBindings);
|
||||
void Detach();
|
||||
|
||||
void Close();
|
||||
|
||||
InteractivityAutomationPeer OnCreateAutomationPeer();
|
||||
|
||||
Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference<CopyFormat> formats);
|
||||
@@ -65,6 +71,8 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Closed;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,6 +50,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TermControl::TermControl(IControlSettings settings,
|
||||
Control::IControlAppearance unfocusedAppearance,
|
||||
TerminalConnection::ITerminalConnection connection) :
|
||||
TermControl{ winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, connection) }
|
||||
{
|
||||
}
|
||||
|
||||
TermControl::TermControl(Control::ControlInteractivity content) :
|
||||
_interactivity{ content },
|
||||
_isInternalScrollBarUpdate{ false },
|
||||
_autoScrollVelocity{ 0 },
|
||||
_autoScrollingPointerPoint{ std::nullopt },
|
||||
@@ -61,32 +67,35 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, connection);
|
||||
_core = _interactivity.Core();
|
||||
|
||||
// These events might all be triggered by the connection, but that
|
||||
// should be drained and closed before we complete destruction. So these
|
||||
// are safe.
|
||||
_core.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
|
||||
_core.WarningBell({ this, &TermControl::_coreWarningBell });
|
||||
_core.CursorPositionChanged({ this, &TermControl::_CursorPositionChanged });
|
||||
|
||||
// This event is specifically triggered by the renderer thread, a BG thread. Use a weak ref here.
|
||||
_core.RendererEnteredErrorState({ get_weak(), &TermControl::_RendererEnteredErrorState });
|
||||
_revokers.RendererEnteredErrorState = _core.RendererEnteredErrorState(winrt::auto_revoke, { get_weak(), &TermControl::_RendererEnteredErrorState });
|
||||
|
||||
// These callbacks can only really be triggered by UI interactions. So
|
||||
// they don't need weak refs - they can't be triggered unless we're
|
||||
// alive.
|
||||
_core.BackgroundColorChanged({ this, &TermControl::_coreBackgroundColorChanged });
|
||||
_core.FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
|
||||
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
|
||||
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
|
||||
_core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
|
||||
_core.FoundMatch({ this, &TermControl::_coreFoundMatch });
|
||||
_core.UpdateSelectionMarkers({ this, &TermControl::_updateSelectionMarkers });
|
||||
_core.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
|
||||
_interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
|
||||
_interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
|
||||
_revokers.BackgroundColorChanged = _core.BackgroundColorChanged(winrt::auto_revoke, { get_weak(), &TermControl::_coreBackgroundColorChanged });
|
||||
_revokers.FontSizeChanged = _core.FontSizeChanged(winrt::auto_revoke, { get_weak(), &TermControl::_coreFontSizeChanged });
|
||||
_revokers.TransparencyChanged = _core.TransparencyChanged(winrt::auto_revoke, { get_weak(), &TermControl::_coreTransparencyChanged });
|
||||
_revokers.RaiseNotice = _core.RaiseNotice(winrt::auto_revoke, { get_weak(), &TermControl::_coreRaisedNotice });
|
||||
_revokers.HoveredHyperlinkChanged = _core.HoveredHyperlinkChanged(winrt::auto_revoke, { get_weak(), &TermControl::_hoveredHyperlinkChanged });
|
||||
_revokers.FoundMatch = _core.FoundMatch(winrt::auto_revoke, { get_weak(), &TermControl::_coreFoundMatch });
|
||||
_revokers.UpdateSelectionMarkers = _core.UpdateSelectionMarkers(winrt::auto_revoke, { get_weak(), &TermControl::_updateSelectionMarkers });
|
||||
_revokers.coreOpenHyperlink = _core.OpenHyperlink(winrt::auto_revoke, { get_weak(), &TermControl::_HyperlinkHandler });
|
||||
_revokers.interactivityOpenHyperlink = _interactivity.OpenHyperlink(winrt::auto_revoke, { get_weak(), &TermControl::_HyperlinkHandler });
|
||||
_revokers.interactivityScrollPositionChanged = _interactivity.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
|
||||
|
||||
// "Bubbled" events - ones we want to handle, by raising our own event.
|
||||
_revokers.CopyToClipboard = _core.CopyToClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCopyToClipboard });
|
||||
_revokers.TitleChanged = _core.TitleChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleTitleChanged });
|
||||
_revokers.TabColorChanged = _core.TabColorChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleTabColorChanged });
|
||||
_revokers.TaskbarProgressChanged = _core.TaskbarProgressChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSetTaskbarProgress });
|
||||
_revokers.ConnectionStateChanged = _core.ConnectionStateChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleConnectionStateChanged });
|
||||
_revokers.ShowWindowChanged = _core.ShowWindowChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleShowWindowChanged });
|
||||
_revokers.CloseTerminalRequested = _core.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCloseTerminalRequested });
|
||||
|
||||
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
||||
|
||||
// Initialize the terminal only once the swapchainpanel is loaded - that
|
||||
// way, we'll be able to query the real pixel size it got on layout
|
||||
@@ -95,8 +104,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// in any layout change chain. That gives us great flexibility in finding the right point
|
||||
// at which to initialize our renderer (and our terminal).
|
||||
// Any earlier than the last layout update and we may not know the terminal's starting size.
|
||||
|
||||
if (_InitializeTerminal())
|
||||
if (_InitializeTerminal(false))
|
||||
{
|
||||
// Only let this succeed once.
|
||||
_layoutUpdatedRevoker.revoke();
|
||||
@@ -130,13 +138,52 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// These events might all be triggered by the connection, but that
|
||||
// should be drained and closed before we complete destruction. So these
|
||||
// are safe.
|
||||
//
|
||||
// NOTE: _ScrollPositionChanged has to be registered after we set up the
|
||||
// _updateScrollBar func. Otherwise, we could get a callback from an
|
||||
// attached content before we set up the throttled func, and that'll A/V
|
||||
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
|
||||
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
|
||||
_revokers.CursorPositionChanged = _core.CursorPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_CursorPositionChanged });
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||
_autoScrollTimer.Tick({ get_weak(), &TermControl::_UpdateAutoScroll });
|
||||
|
||||
_ApplyUISettings();
|
||||
}
|
||||
|
||||
Control::TermControl TermControl::AttachContent(Control::ControlInteractivity content, const Microsoft::Terminal::Control::IKeyBindings& keyBindings)
|
||||
{
|
||||
const auto term{ winrt::make_self<TermControl>(content) };
|
||||
term->_AttachDxgiSwapChainToXaml(reinterpret_cast<HANDLE>(term->_core.SwapChainHandle()));
|
||||
content.Reparent(keyBindings);
|
||||
|
||||
// Initialize the terminal only once the swapchainpanel is loaded - that
|
||||
// way, we'll be able to query the real pixel size it got on layout
|
||||
auto r = term->SwapChainPanel().LayoutUpdated(winrt::auto_revoke, [term](auto /*s*/, auto /*e*/) {
|
||||
// Replace the normal initialize routine with one that will allow up
|
||||
// to complete initialization even though the Core was already
|
||||
// initialized.
|
||||
if (term->_InitializeTerminal(true))
|
||||
{
|
||||
// Only let this succeed once.
|
||||
term->_layoutUpdatedRevoker.revoke();
|
||||
}
|
||||
});
|
||||
term->_layoutUpdatedRevoker.swap(r);
|
||||
|
||||
return *term;
|
||||
}
|
||||
|
||||
winrt::guid TermControl::ContentGuid() const
|
||||
{
|
||||
return _interactivity.Id();
|
||||
}
|
||||
|
||||
void TermControl::_throttledUpdateScrollbar(const ScrollBarUpdate& update)
|
||||
{
|
||||
// Assumptions:
|
||||
@@ -808,7 +855,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
nativePanel->SetSwapChainHandle(swapChainHandle);
|
||||
}
|
||||
|
||||
bool TermControl::_InitializeTerminal()
|
||||
bool TermControl::_InitializeTerminal(const bool reattach)
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
@@ -832,18 +879,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// after Enable, then it'll be possible to paint the frame once
|
||||
// _before_ the warning handler is set up, and then warnings from
|
||||
// the first paint will be ignored!
|
||||
_core.RendererWarning({ get_weak(), &TermControl::_RendererWarning });
|
||||
_revokers.RendererWarning = _core.RendererWarning(winrt::auto_revoke, { get_weak(), &TermControl::_RendererWarning });
|
||||
|
||||
const auto coreInitialized = _core.Initialize(panelWidth,
|
||||
panelHeight,
|
||||
panelScaleX);
|
||||
if (!coreInitialized)
|
||||
// If we're re-attaching an existing content, then we want to proceed even though the Terminal was already initialized.
|
||||
if (!reattach)
|
||||
{
|
||||
return false;
|
||||
const auto coreInitialized = _core.Initialize(panelWidth,
|
||||
panelHeight,
|
||||
panelScaleX);
|
||||
if (!coreInitialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_interactivity.Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
_core.SizeOrScaleChanged(panelWidth, panelHeight, panelScaleX);
|
||||
}
|
||||
_interactivity.Initialize();
|
||||
|
||||
_core.SwapChainChanged({ get_weak(), &TermControl::RenderEngineSwapChainChanged });
|
||||
_revokers.SwapChainChanged = _core.SwapChainChanged(winrt::auto_revoke, { get_weak(), &TermControl::RenderEngineSwapChainChanged });
|
||||
_core.EnablePainting();
|
||||
|
||||
auto bufferHeight = _core.BufferHeight();
|
||||
@@ -1144,12 +1199,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: GH#5000
|
||||
// The Core owning the keybindings is weird. That's for sure. In the
|
||||
// future, we may want to pass the keybindings into the control
|
||||
// separately, so the control can have a pointer to an in-proc
|
||||
// Keybindings object, rather than routing through the ControlCore.
|
||||
// (see GH#5000)
|
||||
auto bindings = _core.Settings().KeyBindings();
|
||||
if (!bindings)
|
||||
{
|
||||
@@ -1998,13 +2047,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_RestorePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
_revokers = {};
|
||||
|
||||
// Disconnect the TSF input control so it doesn't receive EditContext events.
|
||||
TSFInputControl().Close();
|
||||
_autoScrollTimer.Stop();
|
||||
|
||||
_core.Close();
|
||||
if (!_detached)
|
||||
{
|
||||
_interactivity.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void TermControl::Detach()
|
||||
{
|
||||
_revokers = {};
|
||||
_interactivity.Detach();
|
||||
_detached = true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Scrolls the viewport of the terminal and updates the scroll bar accordingly
|
||||
@@ -2741,18 +2801,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
IControlSettings TermControl::Settings() const
|
||||
{
|
||||
// TODO: GH#5000
|
||||
// We still need this in a couple places:
|
||||
// - Pane.cpp uses this for parsing out the StartingTitle, Commandline,
|
||||
// etc for Pane::GetTerminalArgsForPane.
|
||||
// - TerminalTab::_CreateToolTipTitle uses the ProfileName for the
|
||||
// tooltip for the tab.
|
||||
//
|
||||
// These both happen on the UI thread right now. In the future, when we
|
||||
// have to hop across the process boundary to get at the core settings,
|
||||
// it may make sense to cache these values inside the TermControl
|
||||
// itself, so it can do the hop once when it's first setup, rather than
|
||||
// when it's needed by the UI thread.
|
||||
return _core.Settings();
|
||||
}
|
||||
|
||||
@@ -2939,9 +2987,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// Ensure the marker is oriented properly
|
||||
// (i.e. if start is at the beginning of the buffer, it should be flipped)
|
||||
auto transform{ marker.RenderTransform().as<Windows::UI::Xaml::Media::ScaleTransform>() };
|
||||
transform.ScaleX(std::abs(transform.ScaleX()) * (flipMarker ? -1.0 : 1.0));
|
||||
marker.RenderTransform(transform);
|
||||
//
|
||||
// Note - This RenderTransform might not be a
|
||||
// ScaleTransform, if we haven't had a _coreFontSizeChanged
|
||||
// handled yet, because that's the first place we set the
|
||||
// RenderTransform
|
||||
if (const auto& transform{ marker.RenderTransform().try_as<Windows::UI::Xaml::Media::ScaleTransform>() })
|
||||
{
|
||||
transform.ScaleX(std::abs(transform.ScaleX()) * (flipMarker ? -1.0 : 1.0));
|
||||
marker.RenderTransform(transform);
|
||||
}
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
auto terminalPos{ targetEnd ? markerData.EndPos : markerData.StartPos };
|
||||
|
||||
@@ -25,14 +25,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
struct TermControl : TermControlT<TermControl>
|
||||
{
|
||||
TermControl(IControlSettings settings,
|
||||
Control::IControlAppearance unfocusedAppearance,
|
||||
TerminalConnection::ITerminalConnection connection);
|
||||
TermControl(Control::ControlInteractivity content);
|
||||
|
||||
TermControl(IControlSettings settings, Control::IControlAppearance unfocusedAppearance, TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
static Control::TermControl AttachContent(Control::ControlInteractivity content, const Microsoft::Terminal::Control::IKeyBindings& keyBindings);
|
||||
|
||||
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings);
|
||||
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance);
|
||||
IControlSettings Settings() const;
|
||||
|
||||
winrt::guid ContentGuid() const;
|
||||
|
||||
hstring GetProfileName() const;
|
||||
|
||||
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
|
||||
@@ -136,21 +140,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void AdjustOpacity(const double opacity, const bool relative);
|
||||
|
||||
void Detach();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// clang-format off
|
||||
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
||||
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs, _core, CopyToClipboard);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs, _core, TitleChanged);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable, _core, TabColorChanged);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs, _core, ShowWindowChanged);
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable, _core, CloseTerminalRequested);
|
||||
// UNDER NO CIRCUMSTANCES SHOULD YOU ADD A (PROJECTED_)FORWARDED_TYPED_EVENT HERE
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
@@ -218,6 +225,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool _showMarksInScrollbar{ false };
|
||||
|
||||
bool _isBackgroundLight{ false };
|
||||
bool _detached{ false };
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
@@ -243,7 +251,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
static bool _isColorLight(til::color bg) noexcept;
|
||||
void _changeBackgroundOpacity();
|
||||
|
||||
bool _InitializeTerminal();
|
||||
bool _InitializeTerminal(const bool reattach);
|
||||
void _SetFontSize(int fontSize);
|
||||
void _TappedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
void _KeyDownHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
@@ -315,6 +323,36 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
til::point _toPosInDips(const Core::Point terminalCellPos);
|
||||
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
|
||||
|
||||
struct Revokers
|
||||
{
|
||||
Control::ControlCore::ScrollPositionChanged_revoker coreScrollPositionChanged;
|
||||
Control::ControlCore::WarningBell_revoker WarningBell;
|
||||
Control::ControlCore::CursorPositionChanged_revoker CursorPositionChanged;
|
||||
Control::ControlCore::RendererEnteredErrorState_revoker RendererEnteredErrorState;
|
||||
Control::ControlCore::BackgroundColorChanged_revoker BackgroundColorChanged;
|
||||
Control::ControlCore::FontSizeChanged_revoker FontSizeChanged;
|
||||
Control::ControlCore::TransparencyChanged_revoker TransparencyChanged;
|
||||
Control::ControlCore::RaiseNotice_revoker RaiseNotice;
|
||||
Control::ControlCore::HoveredHyperlinkChanged_revoker HoveredHyperlinkChanged;
|
||||
Control::ControlCore::FoundMatch_revoker FoundMatch;
|
||||
Control::ControlCore::UpdateSelectionMarkers_revoker UpdateSelectionMarkers;
|
||||
Control::ControlCore::OpenHyperlink_revoker coreOpenHyperlink;
|
||||
Control::ControlCore::CopyToClipboard_revoker CopyToClipboard;
|
||||
Control::ControlCore::TitleChanged_revoker TitleChanged;
|
||||
Control::ControlCore::TabColorChanged_revoker TabColorChanged;
|
||||
Control::ControlCore::TaskbarProgressChanged_revoker TaskbarProgressChanged;
|
||||
Control::ControlCore::ConnectionStateChanged_revoker ConnectionStateChanged;
|
||||
Control::ControlCore::ShowWindowChanged_revoker ShowWindowChanged;
|
||||
Control::ControlCore::CloseTerminalRequested_revoker CloseTerminalRequested;
|
||||
// These are set up in _InitializeTerminal
|
||||
Control::ControlCore::RendererWarning_revoker RendererWarning;
|
||||
Control::ControlCore::SwapChainChanged_revoker SwapChainChanged;
|
||||
|
||||
Control::ControlInteractivity::OpenHyperlink_revoker interactivityOpenHyperlink;
|
||||
Control::ControlInteractivity::ScrollPositionChanged_revoker interactivityScrollPositionChanged;
|
||||
Control::ControlInteractivity::PasteFromClipboard_revoker PasteFromClipboard;
|
||||
} _revokers{};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import "IMouseWheelListener.idl";
|
||||
import "IControlSettings.idl";
|
||||
import "ControlInteractivity.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "EventArgs.idl";
|
||||
import "ICoreState.idl";
|
||||
@@ -17,10 +18,14 @@ namespace Microsoft.Terminal.Control
|
||||
ICoreState,
|
||||
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
TermControl(ControlInteractivity content);
|
||||
|
||||
TermControl(IControlSettings settings,
|
||||
IControlAppearance unfocusedAppearance,
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
||||
static TermControl AttachContent(ControlInteractivity content, Microsoft.Terminal.Control.IKeyBindings keyBindings);
|
||||
|
||||
static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings,
|
||||
UInt32 dpi,
|
||||
Int32 commandlineCols,
|
||||
@@ -29,6 +34,8 @@ namespace Microsoft.Terminal.Control
|
||||
void UpdateControlSettings(IControlSettings settings);
|
||||
void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
|
||||
|
||||
Guid ContentGuid{ get; };
|
||||
|
||||
Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
||||
|
||||
event FontSizeChangedEventArgs FontSizeChanged;
|
||||
@@ -100,5 +107,7 @@ namespace Microsoft.Terminal.Control
|
||||
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
void Detach();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,4 +423,30 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
const auto found = GeneratedActionNames.find(_Action);
|
||||
return found != GeneratedActionNames.end() ? found->second : L"";
|
||||
}
|
||||
|
||||
winrt::hstring ActionAndArgs::Serialize(winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> args)
|
||||
{
|
||||
Json::Value json{ Json::objectValue };
|
||||
JsonUtils::SetValueForKey(json, "actions", args);
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
auto str = Json::writeString(wbuilder, json);
|
||||
return winrt::to_hstring(str);
|
||||
}
|
||||
winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> ActionAndArgs::Deserialize(winrt::hstring content)
|
||||
{
|
||||
auto data = winrt::to_string(content);
|
||||
|
||||
std::string errs;
|
||||
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
|
||||
Json::Value root;
|
||||
if (!reader->parse(data.data(), data.data() + data.size(), &root, &errs))
|
||||
{
|
||||
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> result{ nullptr };
|
||||
JsonUtils::GetValueForKey(root, "actions", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
std::vector<SettingsLoadWarnings>& warnings);
|
||||
static Json::Value ToJson(const Model::ActionAndArgs& val);
|
||||
|
||||
static winrt::hstring Serialize(winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> args);
|
||||
static winrt::Windows::Foundation::Collections::IVector<Model::ActionAndArgs> Deserialize(winrt::hstring content);
|
||||
|
||||
ActionAndArgs() = default;
|
||||
ActionAndArgs(ShortcutAction action);
|
||||
ActionAndArgs(ShortcutAction action, IActionArgs args) :
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ResizePaneArgs.g.cpp"
|
||||
#include "MoveFocusArgs.g.cpp"
|
||||
#include "MovePaneArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "SwapPaneArgs.g.cpp"
|
||||
#include "AdjustFontSizeArgs.g.cpp"
|
||||
#include "SendInputArgs.g.cpp"
|
||||
@@ -28,7 +29,6 @@
|
||||
#include "CloseOtherTabsArgs.g.cpp"
|
||||
#include "CloseTabsAfterArgs.g.cpp"
|
||||
#include "CloseTabArgs.g.cpp"
|
||||
#include "MoveTabArgs.g.cpp"
|
||||
#include "ScrollToMarkArgs.g.cpp"
|
||||
#include "AddMarkArgs.g.cpp"
|
||||
#include "FindMatchArgs.g.cpp"
|
||||
@@ -245,6 +245,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring MovePaneArgs::GenerateName() const
|
||||
{
|
||||
if (!Window().empty())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(L"{}, window:{}, tab index:{}", RS_(L"MovePaneCommandKey"), Window(), TabIndex())
|
||||
};
|
||||
}
|
||||
return winrt::hstring{
|
||||
fmt::format(L"{}, tab index:{}", RS_(L"MovePaneCommandKey"), TabIndex())
|
||||
};
|
||||
@@ -648,6 +654,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring MoveTabArgs::GenerateName() const
|
||||
{
|
||||
if (!Window().empty())
|
||||
{
|
||||
return winrt::hstring{
|
||||
fmt::format(std::wstring_view(RS_(L"MoveTabToWindowCommandKey")),
|
||||
Window())
|
||||
};
|
||||
}
|
||||
|
||||
winrt::hstring directionString;
|
||||
switch (Direction())
|
||||
{
|
||||
|
||||
@@ -96,8 +96,9 @@ private:
|
||||
X(Windows::Foundation::IReference<Control::CopyFormat>, CopyFormatting, "copyFormatting", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MOVE_PANE_ARGS(X) \
|
||||
X(uint32_t, TabIndex, "index", false, 0)
|
||||
#define MOVE_PANE_ARGS(X) \
|
||||
X(uint32_t, TabIndex, "index", false, 0) \
|
||||
X(winrt::hstring, Window, "window", false, L"")
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SWITCH_TO_TAB_ARGS(X) \
|
||||
@@ -172,8 +173,15 @@ private:
|
||||
X(Windows::Foundation::IReference<uint32_t>, Index, "index", false, nullptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MOVE_TAB_ARGS(X) \
|
||||
X(MoveTabDirection, Direction, "direction", args->Direction() == MoveTabDirection::None, MoveTabDirection::None)
|
||||
// Interestingly, the order MATTERS here. Window has to be BEFORE Direction,
|
||||
// because otherwise we won't have parsed the Window yet when we validate the
|
||||
// Direction.
|
||||
#define MOVE_TAB_ARGS(X) \
|
||||
X(winrt::hstring, Window, "window", false, L"") \
|
||||
X(MoveTabDirection, Direction, "direction", (args->Direction() == MoveTabDirection::None) && (args->Window().empty()), MoveTabDirection::None)
|
||||
|
||||
// Other ideas:
|
||||
// X(uint32_t, TabIndex, "index", false, 0) \ // target? source?
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SCROLL_UP_ARGS(X) \
|
||||
@@ -276,6 +284,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
ACTION_ARG(Windows::Foundation::IReference<bool>, SuppressApplicationTitle, nullptr);
|
||||
ACTION_ARG(winrt::hstring, ColorScheme);
|
||||
ACTION_ARG(Windows::Foundation::IReference<bool>, Elevate, nullptr);
|
||||
ACTION_ARG(winrt::guid, ContentGuid);
|
||||
|
||||
static constexpr std::string_view CommandlineKey{ "commandline" };
|
||||
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
|
||||
@@ -286,6 +295,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" };
|
||||
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
|
||||
static constexpr std::string_view ElevateKey{ "elevate" };
|
||||
static constexpr std::string_view ContentKey{ "__content" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
@@ -304,7 +314,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
otherAsUs->_Profile == _Profile &&
|
||||
otherAsUs->_SuppressApplicationTitle == _SuppressApplicationTitle &&
|
||||
otherAsUs->_ColorScheme == _ColorScheme &&
|
||||
otherAsUs->_Elevate == _Elevate;
|
||||
otherAsUs->_Elevate == _Elevate &&
|
||||
otherAsUs->_ContentGuid == _ContentGuid;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -321,6 +332,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
JsonUtils::GetValueForKey(json, ElevateKey, args->_Elevate);
|
||||
JsonUtils::GetValueForKey(json, ContentKey, args->_ContentGuid);
|
||||
return *args;
|
||||
}
|
||||
static Json::Value ToJson(const Model::NewTerminalArgs& val)
|
||||
@@ -340,6 +352,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, args->_SuppressApplicationTitle);
|
||||
JsonUtils::SetValueForKey(json, ColorSchemeKey, args->_ColorScheme);
|
||||
JsonUtils::SetValueForKey(json, ElevateKey, args->_Elevate);
|
||||
JsonUtils::SetValueForKey(json, ContentKey, args->_ContentGuid);
|
||||
return json;
|
||||
}
|
||||
Model::NewTerminalArgs Copy() const
|
||||
@@ -354,6 +367,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
copy->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
||||
copy->_ColorScheme = _ColorScheme;
|
||||
copy->_Elevate = _Elevate;
|
||||
copy->_ContentGuid = _ContentGuid;
|
||||
return *copy;
|
||||
}
|
||||
size_t Hash() const
|
||||
@@ -373,6 +387,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
h.write(SuppressApplicationTitle());
|
||||
h.write(ColorScheme());
|
||||
h.write(Elevate());
|
||||
h.write(ContentGuid());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -132,6 +132,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
// not modify whatever the profile's value is (either true or false)
|
||||
Windows.Foundation.IReference<Boolean> Elevate;
|
||||
|
||||
Guid ContentGuid{ get; set; };
|
||||
|
||||
Boolean Equals(NewTerminalArgs other);
|
||||
String GenerateName();
|
||||
String ToCommandline();
|
||||
@@ -158,8 +160,9 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass MovePaneArgs : IActionArgs
|
||||
{
|
||||
MovePaneArgs(UInt32 tabIndex);
|
||||
MovePaneArgs(UInt32 tabIndex, String Window);
|
||||
UInt32 TabIndex;
|
||||
String Window;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SwitchToTabArgs : IActionArgs
|
||||
@@ -276,8 +279,9 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass MoveTabArgs : IActionArgs
|
||||
{
|
||||
MoveTabArgs(MoveTabDirection direction);
|
||||
MoveTabArgs(String window, MoveTabDirection direction);
|
||||
MoveTabDirection Direction { get; };
|
||||
String Window { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ScrollUpArgs : IActionArgs
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::Control;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
@@ -118,7 +119,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves a map of actions that can be bound to a key
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::ActionAndArgs> ActionMap::AvailableActions()
|
||||
IMapView<hstring, Model::ActionAndArgs> ActionMap::AvailableActions()
|
||||
{
|
||||
if (!_AvailableActionsCache)
|
||||
{
|
||||
@@ -172,7 +173,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
// - Retrieves a map of command names to the commands themselves
|
||||
// - These commands should not be modified directly because they may result in
|
||||
// an invalid state for the `ActionMap`
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::Command> ActionMap::NameMap()
|
||||
IMapView<hstring, Model::Command> ActionMap::NameMap()
|
||||
{
|
||||
if (!_NameMapCache)
|
||||
{
|
||||
@@ -283,7 +284,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
return cumulativeActions;
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IMapView<Control::KeyChord, Model::Command> ActionMap::GlobalHotkeys()
|
||||
IMapView<Control::KeyChord, Model::Command> ActionMap::GlobalHotkeys()
|
||||
{
|
||||
if (!_GlobalHotkeysCache)
|
||||
{
|
||||
@@ -292,7 +293,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
return _GlobalHotkeysCache.GetView();
|
||||
}
|
||||
|
||||
Windows::Foundation::Collections::IMapView<Control::KeyChord, Model::Command> ActionMap::KeyBindings()
|
||||
IMapView<Control::KeyChord, Model::Command> ActionMap::KeyBindings()
|
||||
{
|
||||
if (!_KeyBindingMapCache)
|
||||
{
|
||||
@@ -854,4 +855,79 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
cmd->ActionAndArgs(action);
|
||||
AddAction(*cmd);
|
||||
}
|
||||
|
||||
void ActionMap::_recursiveUpdateCommandKeybindingLabels()
|
||||
{
|
||||
const auto& commands{ _ExpandedMapCache };
|
||||
|
||||
for (const auto& nameAndCmd : commands)
|
||||
{
|
||||
const auto& command = nameAndCmd.Value();
|
||||
if (command.HasNestedCommands())
|
||||
{
|
||||
_recursiveUpdateCommandKeybindingLabels();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's a keybinding that's bound to exactly this command,
|
||||
// then get the keychord and display it as a
|
||||
// part of the command in the UI.
|
||||
// We specifically need to do this for nested commands.
|
||||
const auto keyChord{ GetKeyBindingForAction(command.ActionAndArgs().Action(),
|
||||
command.ActionAndArgs().Args()) };
|
||||
command.RegisterKey(keyChord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a helper to aid in sorting commands by their `Name`s, alphabetically.
|
||||
static bool _compareSchemeNames(const ColorScheme& lhs, const ColorScheme& rhs)
|
||||
{
|
||||
std::wstring leftName{ lhs.Name() };
|
||||
std::wstring rightName{ rhs.Name() };
|
||||
return leftName.compare(rightName) < 0;
|
||||
}
|
||||
|
||||
void ActionMap::ExpandCommands(const IVectorView<Model::Profile>& profiles,
|
||||
const IMapView<winrt::hstring, Model::ColorScheme>& schemes)
|
||||
{
|
||||
// TODO in review - It's a little weird to stash the expanded commands
|
||||
// into a separate map. Is it possible to just replace the name map with
|
||||
// the post-expanded commands?
|
||||
//
|
||||
// WHILE also making sure that upon re-saving the commands, we don't
|
||||
// actually serialize the results of the expansion. I don't think it is.
|
||||
|
||||
auto warnings{ winrt::single_threaded_vector<SettingsLoadWarnings>() };
|
||||
|
||||
std::vector<Model::ColorScheme> sortedSchemes;
|
||||
sortedSchemes.reserve(schemes.Size());
|
||||
|
||||
for (const auto& nameAndScheme : schemes)
|
||||
{
|
||||
sortedSchemes.push_back(nameAndScheme.Value());
|
||||
}
|
||||
std::sort(sortedSchemes.begin(),
|
||||
sortedSchemes.end(),
|
||||
_compareSchemeNames);
|
||||
|
||||
auto copyOfCommands = winrt::single_threaded_map<winrt::hstring, Model::Command>();
|
||||
|
||||
const auto& commandsToExpand{ NameMap() };
|
||||
for (const auto& nameAndCommand : commandsToExpand)
|
||||
{
|
||||
copyOfCommands.Insert(nameAndCommand.Key(), nameAndCommand.Value());
|
||||
}
|
||||
|
||||
Command::ExpandCommands(copyOfCommands,
|
||||
profiles,
|
||||
winrt::param::vector_view<Model::ColorScheme>{ sortedSchemes },
|
||||
warnings);
|
||||
|
||||
_ExpandedMapCache = copyOfCommands;
|
||||
}
|
||||
IMapView<hstring, Model::Command> ActionMap::ExpandedCommands()
|
||||
{
|
||||
return _ExpandedMapCache.GetView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
void DeleteKeyBinding(const Control::KeyChord& keys);
|
||||
void RegisterKeyBinding(Control::KeyChord keys, Model::ActionAndArgs action);
|
||||
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::Command> ExpandedCommands();
|
||||
void ExpandCommands(const Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
|
||||
const Windows::Foundation::Collections::IMapView<winrt::hstring, Model::ColorScheme>& schemes);
|
||||
|
||||
private:
|
||||
std::optional<Model::Command> _GetActionByID(const InternalActionID actionID) const;
|
||||
std::optional<Model::Command> _GetActionByKeyChordInternal(const Control::KeyChord& keys) const;
|
||||
@@ -90,11 +94,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
void _TryUpdateName(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
|
||||
void _TryUpdateKeyChord(const Model::Command& cmd, const Model::Command& oldCmd, const Model::Command& consolidatedCmd);
|
||||
|
||||
void _recursiveUpdateCommandKeybindingLabels();
|
||||
|
||||
Windows::Foundation::Collections::IMap<hstring, Model::ActionAndArgs> _AvailableActionsCache{ nullptr };
|
||||
Windows::Foundation::Collections::IMap<hstring, Model::Command> _NameMapCache{ nullptr };
|
||||
Windows::Foundation::Collections::IMap<Control::KeyChord, Model::Command> _GlobalHotkeysCache{ nullptr };
|
||||
Windows::Foundation::Collections::IMap<Control::KeyChord, Model::Command> _KeyBindingMapCache{ nullptr };
|
||||
|
||||
Windows::Foundation::Collections::IMap<hstring, Model::Command> _ExpandedMapCache{ nullptr };
|
||||
|
||||
std::unordered_map<winrt::hstring, Model::Command> _NestedCommands;
|
||||
std::vector<Model::Command> _IterableCommands;
|
||||
std::unordered_map<Control::KeyChord, InternalActionID, KeyChordHash, KeyChordEquality> _KeyMap;
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Windows.Foundation.Collections.IMapView<String, Command> NameMap { get; };
|
||||
Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Command> KeyBindings { get; };
|
||||
Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Command> GlobalHotkeys { get; };
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, Command> ExpandedCommands { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ActionMap : IActionMapView
|
||||
|
||||
@@ -1214,3 +1214,8 @@ void CascadiaSettings::_validateThemeExists()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CascadiaSettings::ExpandCommands()
|
||||
{
|
||||
_globals->ExpandCommands(ActiveProfiles().GetView(), GlobalSettings().ColorSchemes());
|
||||
}
|
||||
|
||||
@@ -143,6 +143,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
Model::DefaultTerminal CurrentDefaultTerminal() noexcept;
|
||||
void CurrentDefaultTerminal(const Model::DefaultTerminal& terminal);
|
||||
|
||||
void ExpandCommands();
|
||||
|
||||
private:
|
||||
static const std::filesystem::path& _settingsPath();
|
||||
static const std::filesystem::path& _releaseSettingsPath();
|
||||
|
||||
@@ -53,5 +53,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
static Boolean IsDefaultTerminalSet { get; };
|
||||
IObservableVector<DefaultTerminal> DefaultTerminals { get; };
|
||||
DefaultTerminal CurrentDefaultTerminal;
|
||||
|
||||
void ExpandCommands();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
hstring IconPath() const noexcept;
|
||||
void IconPath(const hstring& val);
|
||||
|
||||
winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker propertyChangedRevoker;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None);
|
||||
WINRT_PROPERTY(Model::ActionAndArgs, ActionAndArgs);
|
||||
|
||||
|
||||
@@ -24,11 +24,14 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
ActionAndArgs();
|
||||
ActionAndArgs(ShortcutAction action, IActionArgs args);
|
||||
|
||||
static String Serialize(IVector<ActionAndArgs> args);
|
||||
static IVector<ActionAndArgs> Deserialize(String content);
|
||||
|
||||
IActionArgs Args;
|
||||
ShortcutAction Action;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Command : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[default_interface] runtimeclass Command
|
||||
{
|
||||
Command();
|
||||
|
||||
|
||||
@@ -239,3 +239,14 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
|
||||
{
|
||||
return _themes.GetView();
|
||||
}
|
||||
|
||||
void GlobalAppSettings::ExpandCommands(const winrt::Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
|
||||
const winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, Model::ColorScheme>& schemes)
|
||||
{
|
||||
_actionMap->ExpandCommands(profiles, schemes);
|
||||
}
|
||||
|
||||
bool GlobalAppSettings::ShouldUsePersistedLayout() const
|
||||
{
|
||||
return FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout && !IsolatedMode();
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
Windows::Foundation::Collections::IMapView<hstring, Model::Theme> Themes() noexcept;
|
||||
void AddTheme(const Model::Theme& theme);
|
||||
Model::Theme CurrentTheme() noexcept;
|
||||
bool ShouldUsePersistedLayout() const;
|
||||
|
||||
void ExpandCommands(const Windows::Foundation::Collections::IVectorView<Model::Profile>& profiles,
|
||||
const Windows::Foundation::Collections::IMapView<winrt::hstring, Model::ColorScheme>& schemes);
|
||||
|
||||
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L"");
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_SETTING(Boolean, ShowAdminShield);
|
||||
INHERITABLE_SETTING(IVector<NewTabMenuEntry>, NewTabMenu);
|
||||
INHERITABLE_SETTING(Boolean, EnableColorSelection);
|
||||
INHERITABLE_SETTING(Boolean, IsolatedMode);
|
||||
INHERITABLE_SETTING(Boolean, AllowHeadless);
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
|
||||
void AddColorScheme(ColorScheme scheme);
|
||||
@@ -108,5 +110,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
void AddTheme(Theme theme);
|
||||
INHERITABLE_SETTING(ThemePair, Theme);
|
||||
Theme CurrentTheme { get; };
|
||||
|
||||
Boolean ShouldUsePersistedLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,51 +18,53 @@ Author(s):
|
||||
// Macro format (defaultArgs are optional):
|
||||
// (type, name, jsonKey, defaultArgs)
|
||||
|
||||
#define MTSM_GLOBAL_SETTINGS(X) \
|
||||
X(int32_t, InitialRows, "initialRows", 30) \
|
||||
X(int32_t, InitialCols, "initialCols", 80) \
|
||||
X(hstring, WordDelimiters, "wordDelimiters", DEFAULT_WORD_DELIMITERS) \
|
||||
X(bool, CopyOnSelect, "copyOnSelect", false) \
|
||||
X(bool, FocusFollowMouse, "focusFollowMouse", false) \
|
||||
X(bool, ForceFullRepaintRendering, "experimental.rendering.forceFullRepaint", false) \
|
||||
X(bool, SoftwareRendering, "experimental.rendering.software", false) \
|
||||
X(bool, UseBackgroundImageForWindow, "experimental.useBackgroundImageForWindow", false) \
|
||||
X(bool, ForceVTInput, "experimental.input.forceVT", false) \
|
||||
X(bool, TrimBlockSelection, "trimBlockSelection", true) \
|
||||
X(bool, DetectURLs, "experimental.detectURLs", true) \
|
||||
X(bool, AlwaysShowTabs, "alwaysShowTabs", true) \
|
||||
X(Model::NewTabPosition, NewTabPosition, "newTabPosition", Model::NewTabPosition::AfterLastTab) \
|
||||
X(bool, ShowTitleInTitlebar, "showTerminalTitleInTitlebar", true) \
|
||||
X(bool, ConfirmCloseAllTabs, "confirmCloseAllTabs", true) \
|
||||
X(Model::ThemePair, Theme, "theme") \
|
||||
X(hstring, Language, "language") \
|
||||
X(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, "tabWidthMode", winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal) \
|
||||
X(bool, UseAcrylicInTabRow, "useAcrylicInTabRow", false) \
|
||||
X(bool, ShowTabsInTitlebar, "showTabsInTitlebar", true) \
|
||||
X(bool, InputServiceWarning, "inputServiceWarning", true) \
|
||||
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, "copyFormatting", 0) \
|
||||
X(bool, WarnAboutLargePaste, "largePasteWarning", true) \
|
||||
X(bool, WarnAboutMultiLinePaste, "multiLinePasteWarning", true) \
|
||||
X(Model::LaunchPosition, InitialPosition, "initialPosition", nullptr, nullptr) \
|
||||
X(bool, CenterOnLaunch, "centerOnLaunch", false) \
|
||||
X(Model::FirstWindowPreference, FirstWindowPreference, "firstWindowPreference", FirstWindowPreference::DefaultProfile) \
|
||||
X(Model::LaunchMode, LaunchMode, "launchMode", LaunchMode::DefaultMode) \
|
||||
X(bool, SnapToGridOnResize, "snapToGridOnResize", true) \
|
||||
X(bool, DebugFeaturesEnabled, "debugFeatures", debugFeaturesDefault) \
|
||||
X(bool, StartOnUserLogin, "startOnUserLogin", false) \
|
||||
X(bool, AlwaysOnTop, "alwaysOnTop", false) \
|
||||
X(bool, AutoHideWindow, "autoHideWindow", false) \
|
||||
X(Model::TabSwitcherMode, TabSwitcherMode, "tabSwitcherMode", Model::TabSwitcherMode::InOrder) \
|
||||
X(bool, DisableAnimations, "disableAnimations", false) \
|
||||
X(hstring, StartupActions, "startupActions", L"") \
|
||||
X(Model::WindowingMode, WindowingBehavior, "windowingBehavior", Model::WindowingMode::UseNew) \
|
||||
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
|
||||
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
|
||||
X(bool, ShowAdminShield, "showAdminShield", true) \
|
||||
X(bool, TrimPaste, "trimPaste", true) \
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} }))
|
||||
#define MTSM_GLOBAL_SETTINGS(X) \
|
||||
X(int32_t, InitialRows, "initialRows", 30) \
|
||||
X(int32_t, InitialCols, "initialCols", 80) \
|
||||
X(hstring, WordDelimiters, "wordDelimiters", DEFAULT_WORD_DELIMITERS) \
|
||||
X(bool, CopyOnSelect, "copyOnSelect", false) \
|
||||
X(bool, FocusFollowMouse, "focusFollowMouse", false) \
|
||||
X(bool, ForceFullRepaintRendering, "experimental.rendering.forceFullRepaint", false) \
|
||||
X(bool, SoftwareRendering, "experimental.rendering.software", false) \
|
||||
X(bool, UseBackgroundImageForWindow, "experimental.useBackgroundImageForWindow", false) \
|
||||
X(bool, ForceVTInput, "experimental.input.forceVT", false) \
|
||||
X(bool, TrimBlockSelection, "trimBlockSelection", true) \
|
||||
X(bool, DetectURLs, "experimental.detectURLs", true) \
|
||||
X(bool, AlwaysShowTabs, "alwaysShowTabs", true) \
|
||||
X(Model::NewTabPosition, NewTabPosition, "newTabPosition", Model::NewTabPosition::AfterLastTab) \
|
||||
X(bool, ShowTitleInTitlebar, "showTerminalTitleInTitlebar", true) \
|
||||
X(bool, ConfirmCloseAllTabs, "confirmCloseAllTabs", true) \
|
||||
X(Model::ThemePair, Theme, "theme") \
|
||||
X(hstring, Language, "language") \
|
||||
X(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, "tabWidthMode", winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal) \
|
||||
X(bool, UseAcrylicInTabRow, "useAcrylicInTabRow", false) \
|
||||
X(bool, ShowTabsInTitlebar, "showTabsInTitlebar", true) \
|
||||
X(bool, InputServiceWarning, "inputServiceWarning", true) \
|
||||
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, "copyFormatting", 0) \
|
||||
X(bool, WarnAboutLargePaste, "largePasteWarning", true) \
|
||||
X(bool, WarnAboutMultiLinePaste, "multiLinePasteWarning", true) \
|
||||
X(Model::LaunchPosition, InitialPosition, "initialPosition", nullptr, nullptr) \
|
||||
X(bool, CenterOnLaunch, "centerOnLaunch", false) \
|
||||
X(Model::FirstWindowPreference, FirstWindowPreference, "firstWindowPreference", FirstWindowPreference::DefaultProfile) \
|
||||
X(Model::LaunchMode, LaunchMode, "launchMode", LaunchMode::DefaultMode) \
|
||||
X(bool, SnapToGridOnResize, "snapToGridOnResize", true) \
|
||||
X(bool, DebugFeaturesEnabled, "debugFeatures", debugFeaturesDefault) \
|
||||
X(bool, StartOnUserLogin, "startOnUserLogin", false) \
|
||||
X(bool, AlwaysOnTop, "alwaysOnTop", false) \
|
||||
X(bool, AutoHideWindow, "autoHideWindow", false) \
|
||||
X(Model::TabSwitcherMode, TabSwitcherMode, "tabSwitcherMode", Model::TabSwitcherMode::InOrder) \
|
||||
X(bool, DisableAnimations, "disableAnimations", false) \
|
||||
X(hstring, StartupActions, "startupActions", L"") \
|
||||
X(Model::WindowingMode, WindowingBehavior, "windowingBehavior", Model::WindowingMode::UseNew) \
|
||||
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
|
||||
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
|
||||
X(bool, ShowAdminShield, "showAdminShield", true) \
|
||||
X(bool, TrimPaste, "trimPaste", true) \
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} })) \
|
||||
X(bool, AllowHeadless, "compatibility.allowHeadless", true) \
|
||||
X(bool, IsolatedMode, "compatibility.isolatedMode", false)
|
||||
|
||||
#define MTSM_PROFILE_SETTINGS(X) \
|
||||
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
|
||||
|
||||
@@ -166,6 +166,10 @@
|
||||
<value>Move tab {0}</value>
|
||||
<comment>{0} will be replaced with a "forward" / "backward"</comment>
|
||||
</data>
|
||||
<data name="MoveTabToWindowCommandKey" xml:space="preserve">
|
||||
<value>Move tab to window {0}</value>
|
||||
<comment>{0} will be replaced with a user-specified name of a window</comment>
|
||||
</data>
|
||||
<data name="MoveTabDirectionForward" xml:space="preserve">
|
||||
<value>forward</value>
|
||||
</data>
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace RemotingUnitTests
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, Remoting::QuitAllRequestedArgs);
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, Remoting::WindowRequestedArgs);
|
||||
};
|
||||
|
||||
class RemotingTests
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,10 @@
|
||||
class AppHost
|
||||
{
|
||||
public:
|
||||
AppHost() noexcept;
|
||||
AppHost(const winrt::TerminalApp::AppLogic& logic,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowManager& manager,
|
||||
const winrt::Microsoft::Terminal::Remoting::Peasant& peasant) noexcept;
|
||||
virtual ~AppHost();
|
||||
|
||||
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);
|
||||
@@ -19,25 +22,31 @@ public:
|
||||
void SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
bool HasWindow();
|
||||
winrt::TerminalApp::TerminalWindow Logic();
|
||||
|
||||
static void s_DisplayMessageBox(const winrt::TerminalApp::ParseCommandlineResult& message);
|
||||
|
||||
WINRT_CALLBACK(UpdateSettingsRequested, winrt::delegate<void()>);
|
||||
|
||||
private:
|
||||
std::unique_ptr<IslandWindow> _window;
|
||||
winrt::TerminalApp::App _app;
|
||||
winrt::TerminalApp::AppLogic _logic;
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager _windowManager{ nullptr };
|
||||
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::GlobalSummonArgs> _hotkeys;
|
||||
winrt::TerminalApp::AppLogic _appLogic;
|
||||
winrt::TerminalApp::TerminalWindow _windowLogic;
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager _windowManager{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
|
||||
|
||||
winrt::com_ptr<IVirtualDesktopManager> _desktopManager{ nullptr };
|
||||
|
||||
bool _shouldCreateWindow{ false };
|
||||
bool _useNonClientArea{ false };
|
||||
|
||||
std::optional<til::throttled_func_trailing<>> _getWindowLayoutThrottler;
|
||||
std::shared_ptr<ThrottledFuncTrailing<bool>> _showHideWindowThrottler;
|
||||
winrt::Windows::Foundation::IAsyncAction _SaveWindowLayouts();
|
||||
winrt::fire_and_forget _SaveWindowLayoutsRepeat();
|
||||
|
||||
void _HandleCommandlineArgs();
|
||||
void _preInit();
|
||||
|
||||
void _HandleCommandlineArgs(const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
winrt::Microsoft::Terminal::Settings::Model::LaunchPosition _GetWindowLaunchPosition();
|
||||
|
||||
void _HandleCreateWindow(const HWND hwnd, til::rect proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
@@ -64,12 +73,6 @@ private:
|
||||
|
||||
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> _GetWindowLayoutAsync();
|
||||
|
||||
void _FindTargetWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
|
||||
|
||||
void _BecomeMonarch(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _GlobalHotkeyPressed(const long hotkeyIndex);
|
||||
void _HandleSummon(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior& args);
|
||||
|
||||
@@ -84,11 +87,8 @@ private:
|
||||
|
||||
bool _LazyLoadDesktopManager();
|
||||
|
||||
void _listenForInboundConnections();
|
||||
winrt::fire_and_forget _setupGlobalHotkeys();
|
||||
winrt::fire_and_forget _createNewTerminalWindow(winrt::Microsoft::Terminal::Settings::Model::GlobalSummonArgs args);
|
||||
void _HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
const winrt::TerminalApp::SettingsLoadEventArgs& args);
|
||||
|
||||
void _IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
@@ -110,19 +110,9 @@ private:
|
||||
void _CloseRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _QuitAllRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& args);
|
||||
|
||||
void _ShowWindowChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Control::ShowWindowArgs& args);
|
||||
|
||||
void _CreateNotificationIcon();
|
||||
void _DestroyNotificationIcon();
|
||||
void _ShowNotificationIconRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _HideNotificationIconRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _updateTheme();
|
||||
|
||||
void _PropertyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
@@ -130,14 +120,22 @@ private:
|
||||
|
||||
void _initialResizeAndRepositionWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
|
||||
std::unique_ptr<NotificationIcon> _notificationIcon;
|
||||
winrt::event_token _ReAddNotificationIconToken;
|
||||
winrt::event_token _NotificationIconPressedToken;
|
||||
winrt::event_token _ShowNotificationIconContextMenuToken;
|
||||
winrt::event_token _NotificationIconMenuItemSelectedToken;
|
||||
void _handleMoveContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::TerminalApp::RequestMoveContentArgs args);
|
||||
void _handleAttach(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::Microsoft::Terminal::Remoting::AttachRequest args);
|
||||
|
||||
void _requestUpdateSettings();
|
||||
|
||||
// Page -> us -> monarch
|
||||
void _handleReceiveContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::TerminalApp::RequestReceiveContentArgs args);
|
||||
|
||||
// monarch -> us -> Page
|
||||
void _handleSendContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
winrt::event_token _GetWindowLayoutRequestedToken;
|
||||
winrt::event_token _WindowCreatedToken;
|
||||
winrt::event_token _WindowClosedToken;
|
||||
|
||||
// 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
|
||||
@@ -146,33 +144,38 @@ private:
|
||||
struct Revokers
|
||||
{
|
||||
// Event handlers to revoke in ~AppHost, before calling App.Close
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::BecameMonarch_revoker BecameMonarch;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::ExecuteCommandlineRequested_revoker peasantExecuteCommandlineRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::SummonRequested_revoker peasantSummonRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::DisplayWindowIdRequested_revoker peasantDisplayWindowIdRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::QuitRequested_revoker peasantQuitRequested;
|
||||
winrt::TerminalApp::AppLogic::CloseRequested_revoker CloseRequested;
|
||||
winrt::TerminalApp::AppLogic::RequestedThemeChanged_revoker RequestedThemeChanged;
|
||||
winrt::TerminalApp::AppLogic::FullscreenChanged_revoker FullscreenChanged;
|
||||
winrt::TerminalApp::AppLogic::FocusModeChanged_revoker FocusModeChanged;
|
||||
winrt::TerminalApp::AppLogic::AlwaysOnTopChanged_revoker AlwaysOnTopChanged;
|
||||
winrt::TerminalApp::AppLogic::RaiseVisualBell_revoker RaiseVisualBell;
|
||||
winrt::TerminalApp::AppLogic::SystemMenuChangeRequested_revoker SystemMenuChangeRequested;
|
||||
winrt::TerminalApp::AppLogic::ChangeMaximizeRequested_revoker ChangeMaximizeRequested;
|
||||
winrt::TerminalApp::AppLogic::TitleChanged_revoker TitleChanged;
|
||||
winrt::TerminalApp::AppLogic::LastTabClosed_revoker LastTabClosed;
|
||||
winrt::TerminalApp::AppLogic::SetTaskbarProgress_revoker SetTaskbarProgress;
|
||||
winrt::TerminalApp::AppLogic::IdentifyWindowsRequested_revoker IdentifyWindowsRequested;
|
||||
winrt::TerminalApp::AppLogic::RenameWindowRequested_revoker RenameWindowRequested;
|
||||
winrt::TerminalApp::AppLogic::SettingsChanged_revoker SettingsChanged;
|
||||
winrt::TerminalApp::AppLogic::IsQuakeWindowChanged_revoker IsQuakeWindowChanged;
|
||||
winrt::TerminalApp::AppLogic::SummonWindowRequested_revoker SummonWindowRequested;
|
||||
winrt::TerminalApp::AppLogic::OpenSystemMenu_revoker OpenSystemMenu;
|
||||
winrt::TerminalApp::AppLogic::QuitRequested_revoker QuitRequested;
|
||||
winrt::TerminalApp::AppLogic::ShowWindowChanged_revoker ShowWindowChanged;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::AttachRequested_revoker AttachRequested;
|
||||
|
||||
winrt::TerminalApp::TerminalWindow::CloseRequested_revoker CloseRequested;
|
||||
winrt::TerminalApp::TerminalWindow::RequestedThemeChanged_revoker RequestedThemeChanged;
|
||||
winrt::TerminalApp::TerminalWindow::FullscreenChanged_revoker FullscreenChanged;
|
||||
winrt::TerminalApp::TerminalWindow::FocusModeChanged_revoker FocusModeChanged;
|
||||
winrt::TerminalApp::TerminalWindow::AlwaysOnTopChanged_revoker AlwaysOnTopChanged;
|
||||
winrt::TerminalApp::TerminalWindow::RaiseVisualBell_revoker RaiseVisualBell;
|
||||
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::SetTaskbarProgress_revoker SetTaskbarProgress;
|
||||
winrt::TerminalApp::TerminalWindow::IdentifyWindowsRequested_revoker IdentifyWindowsRequested;
|
||||
winrt::TerminalApp::TerminalWindow::RenameWindowRequested_revoker RenameWindowRequested;
|
||||
winrt::TerminalApp::TerminalWindow::IsQuakeWindowChanged_revoker IsQuakeWindowChanged;
|
||||
winrt::TerminalApp::TerminalWindow::SummonWindowRequested_revoker SummonWindowRequested;
|
||||
winrt::TerminalApp::TerminalWindow::OpenSystemMenu_revoker OpenSystemMenu;
|
||||
winrt::TerminalApp::TerminalWindow::QuitRequested_revoker QuitRequested;
|
||||
winrt::TerminalApp::TerminalWindow::ShowWindowChanged_revoker ShowWindowChanged;
|
||||
winrt::TerminalApp::TerminalWindow::RequestMoveContent_revoker RequestMoveContent;
|
||||
winrt::TerminalApp::TerminalWindow::RequestReceiveContent_revoker RequestReceiveContent;
|
||||
winrt::TerminalApp::TerminalWindow::PropertyChanged_revoker PropertyChanged;
|
||||
winrt::TerminalApp::TerminalWindow::SettingsChanged_revoker SettingsChanged;
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::ShowNotificationIconRequested_revoker ShowNotificationIconRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::HideNotificationIconRequested_revoker HideNotificationIconRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::QuitAllRequested_revoker QuitAllRequested;
|
||||
winrt::TerminalApp::AppLogic::PropertyChanged_revoker PropertyChanged;
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant::SendContentRequested_revoker SendContentRequested;
|
||||
} _revokers{};
|
||||
};
|
||||
|
||||
@@ -27,8 +27,6 @@ using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
|
||||
#define IDM_SYSTEM_MENU_BEGIN 0x1000
|
||||
|
||||
const UINT WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
|
||||
|
||||
IslandWindow::IslandWindow() noexcept :
|
||||
_interopWindowHandle{ nullptr },
|
||||
_rootGrid{ nullptr },
|
||||
@@ -405,18 +403,19 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam
|
||||
// - The total dimension
|
||||
long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize)
|
||||
{
|
||||
return gsl::narrow_cast<int>(_pfnSnapDimensionCallback(isWidth, gsl::narrow_cast<float>(clientSize)) + nonClientSize);
|
||||
if (_pfnSnapDimensionCallback)
|
||||
{
|
||||
return gsl::narrow_cast<int>(_pfnSnapDimensionCallback(isWidth, gsl::narrow_cast<float>(clientSize)) + nonClientSize);
|
||||
}
|
||||
// We might have been called in WM_CREATE, before we've initialized XAML or
|
||||
// our page. That's okay.
|
||||
return clientSize + nonClientSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] LRESULT IslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_HOTKEY:
|
||||
{
|
||||
_HotkeyPressedHandlers(static_cast<long>(wparam));
|
||||
return 0;
|
||||
}
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
_OnGetMinMaxInfo(wparam, lparam);
|
||||
@@ -632,30 +631,6 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CM_NOTIFY_FROM_NOTIFICATION_AREA:
|
||||
{
|
||||
switch (LOWORD(lparam))
|
||||
{
|
||||
case NIN_SELECT:
|
||||
case NIN_KEYSELECT:
|
||||
{
|
||||
_NotifyNotificationIconPressedHandlers();
|
||||
return 0;
|
||||
}
|
||||
case WM_CONTEXTMENU:
|
||||
{
|
||||
const til::point eventPoint{ GET_X_LPARAM(wparam), GET_Y_LPARAM(wparam) };
|
||||
_NotifyShowNotificationIconContextMenuHandlers(eventPoint);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_MENUCOMMAND:
|
||||
{
|
||||
_NotifyNotificationIconMenuItemSelectedHandlers((HMENU)lparam, (UINT)wparam);
|
||||
return 0;
|
||||
}
|
||||
case WM_SYSCOMMAND:
|
||||
{
|
||||
// the low 4 bits contain additional information (that we don't care about)
|
||||
@@ -732,16 +707,6 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
_AutomaticShutdownRequestedHandlers();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
// We'll want to receive this message when explorer.exe restarts
|
||||
// so that we can re-add our icon to the notification area.
|
||||
// This unfortunately isn't a switch case because we register the
|
||||
// message at runtime.
|
||||
if (message == WM_TASKBARCREATED)
|
||||
{
|
||||
_NotifyReAddNotificationIconHandlers();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle messages here...
|
||||
@@ -1258,65 +1223,6 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Call UnregisterHotKey once for each previously registered hotkey.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::UnregisterHotKey(const int index) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hWindowsTerminalProvider,
|
||||
"UnregisterHotKey",
|
||||
TraceLoggingDescription("Emitted when clearing previously set hotkeys"),
|
||||
TraceLoggingInt64(index, "index", "the index of the hotkey to remove"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
LOG_IF_WIN32_BOOL_FALSE(::UnregisterHotKey(_window.get(), index));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Call RegisterHotKey to attempt to register that keybinding as a global hotkey.
|
||||
// - When these keys are pressed, we'll get a WM_HOTKEY message with the payload
|
||||
// containing the index we registered here.
|
||||
// - Call UnregisterHotKey() before registering your hotkeys.
|
||||
// See: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerhotkey#remarks
|
||||
// Arguments:
|
||||
// - hotkey: The key-combination to register.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool IslandWindow::RegisterHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept
|
||||
{
|
||||
const auto vkey = hotkey.Vkey();
|
||||
auto hotkeyFlags = MOD_NOREPEAT;
|
||||
{
|
||||
const auto modifiers = hotkey.Modifiers();
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_WIN, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Windows));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_ALT, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Menu));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_CONTROL, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Control));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_SHIFT, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Shift));
|
||||
}
|
||||
|
||||
// TODO GH#8888: We should display a warning of some kind if this fails.
|
||||
// This can fail if something else already bound this hotkey.
|
||||
const auto result = ::RegisterHotKey(_window.get(), index, hotkeyFlags, vkey);
|
||||
|
||||
TraceLoggingWrite(g_hWindowsTerminalProvider,
|
||||
"RegisterHotKey",
|
||||
TraceLoggingDescription("Emitted when setting hotkeys"),
|
||||
TraceLoggingInt64(index, "index", "the index of the hotkey to add"),
|
||||
TraceLoggingUInt64(vkey, "vkey", "the key"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_WIN), "win", "is WIN in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_ALT), "alt", "is ALT in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_CONTROL), "control", "is CONTROL in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_SHIFT), "shift", "is SHIFT in the modifiers"),
|
||||
TraceLoggingBool(result, "succeeded", "true if we succeeded"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Summon the window, or possibly dismiss it. If toggleVisibility is true,
|
||||
// then we'll dismiss (minimize) the window if it's currently active.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "BaseWindow.h"
|
||||
#include <winrt/TerminalApp.h>
|
||||
|
||||
void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept;
|
||||
|
||||
@@ -51,9 +50,6 @@ public:
|
||||
void FlashTaskbar();
|
||||
void SetTaskbarProgress(const size_t state, const size_t progress);
|
||||
|
||||
void UnregisterHotKey(const int index) noexcept;
|
||||
bool RegisterHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept;
|
||||
|
||||
winrt::fire_and_forget SummonWindow(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args);
|
||||
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
@@ -74,7 +70,6 @@ public:
|
||||
WINRT_CALLBACK(WindowCloseButtonClicked, winrt::delegate<>);
|
||||
WINRT_CALLBACK(MouseScrolled, winrt::delegate<void(til::point, int32_t)>);
|
||||
WINRT_CALLBACK(WindowActivated, winrt::delegate<void(bool)>);
|
||||
WINRT_CALLBACK(HotkeyPressed, winrt::delegate<void(long)>);
|
||||
WINRT_CALLBACK(NotifyNotificationIconPressed, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(NotifyWindowHidden, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(NotifyShowNotificationIconContextMenu, winrt::delegate<void(til::point)>);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#pragma once
|
||||
// This enumerates all the possible actions
|
||||
// that our notification icon context menu could do.
|
||||
enum class NotificationIconMenuItemAction
|
||||
|
||||
692
src/cascadia/WindowsTerminal/WindowEmperor.cpp
Normal file
692
src/cascadia/WindowsTerminal/WindowEmperor.cpp
Normal file
@@ -0,0 +1,692 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "WindowEmperor.h"
|
||||
|
||||
#include "../inc/WindowingBehavior.h"
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
#include "../WinRTUtils/inc/WtExeUtils.h"
|
||||
|
||||
#include "resource.h"
|
||||
#include "NotificationIcon.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace std::chrono_literals;
|
||||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
#define TERMINAL_MESSAGE_CLASS_NAME L"TERMINAL_MESSAGE_CLASS"
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
const UINT WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
|
||||
|
||||
WindowEmperor::WindowEmperor() noexcept :
|
||||
_app{}
|
||||
{
|
||||
_manager.FindTargetWindowRequested([this](const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& findWindowArgs) {
|
||||
{
|
||||
const auto targetWindow = _app.Logic().FindTargetWindow(findWindowArgs.Args().Commandline());
|
||||
findWindowArgs.ResultTargetWindow(targetWindow.WindowId());
|
||||
findWindowArgs.ResultTargetWindowName(targetWindow.WindowName());
|
||||
}
|
||||
});
|
||||
|
||||
_dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
|
||||
}
|
||||
|
||||
WindowEmperor::~WindowEmperor()
|
||||
{
|
||||
_app.Close();
|
||||
_app = nullptr;
|
||||
}
|
||||
|
||||
void _buildArgsFromCommandline(std::vector<winrt::hstring>& args)
|
||||
{
|
||||
if (auto commandline{ GetCommandLineW() })
|
||||
{
|
||||
auto argc = 0;
|
||||
|
||||
// Get the argv, and turn them into a hstring array to pass to the app.
|
||||
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(commandline, &argc) };
|
||||
if (argv)
|
||||
{
|
||||
for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
{
|
||||
args.emplace_back(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.empty())
|
||||
{
|
||||
args.emplace_back(L"wt.exe");
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowEmperor::HandleCommandlineArgs()
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
_buildArgsFromCommandline(args);
|
||||
auto cwd{ wil::GetCurrentDirectoryW<std::wstring>() };
|
||||
|
||||
Remoting::CommandlineArgs eventArgs{ { args }, { cwd } };
|
||||
|
||||
const auto isolatedMode{ _app.Logic().IsolatedMode() };
|
||||
|
||||
const auto result = _manager.ProposeCommandline(eventArgs, isolatedMode);
|
||||
|
||||
if (result.ShouldCreateWindow())
|
||||
{
|
||||
CreateNewWindowThread(Remoting::WindowRequestedArgs{ result, eventArgs }, true);
|
||||
|
||||
_manager.RequestNewWindow([this](auto&&, const Remoting::WindowRequestedArgs& args) {
|
||||
CreateNewWindowThread(args, false);
|
||||
});
|
||||
|
||||
_becomeMonarch();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto res = _app.Logic().GetParseCommandlineMessage(eventArgs.Commandline());
|
||||
if (!res.Message.empty())
|
||||
{
|
||||
AppHost::s_DisplayMessageBox(res);
|
||||
ExitThread(res.ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
return result.ShouldCreateWindow();
|
||||
}
|
||||
|
||||
void WindowEmperor::WaitForWindows()
|
||||
{
|
||||
MSG message;
|
||||
while (GetMessage(&message, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowEmperor::CreateNewWindowThread(Remoting::WindowRequestedArgs args, const bool /*firstWindow*/)
|
||||
{
|
||||
Remoting::Peasant peasant{ _manager.CreatePeasant(args) };
|
||||
|
||||
auto window{ std::make_shared<WindowThread>(_app.Logic(), args, _manager, peasant) };
|
||||
|
||||
window->Started([this, sender = window]() -> winrt::fire_and_forget {
|
||||
// Add a callback to the window's logic to let us know when the window's
|
||||
// quake mode state changes. We'll use this to check if we need to add
|
||||
// or remove the notification icon.
|
||||
sender->Logic().IsQuakeWindowChanged([this](auto&&, auto &&) -> winrt::fire_and_forget {
|
||||
co_await wil::resume_foreground(this->_dispatcher);
|
||||
this->_checkWindowsForNotificationIcon();
|
||||
});
|
||||
sender->UpdateSettingsRequested([this]() -> winrt::fire_and_forget {
|
||||
// We MUST be on the main thread to update the settings. We will crash when trying to enumerate fragment extensions otherwise.
|
||||
co_await wil::resume_foreground(this->_dispatcher);
|
||||
_app.Logic().ReloadSettings();
|
||||
});
|
||||
|
||||
// These come in on the sender's thread. Move back to our thread.
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
_windows.push_back(std::move(sender));
|
||||
});
|
||||
|
||||
window->Exited([this](uint64_t senderID) -> winrt::fire_and_forget {
|
||||
// These come in on the sender's thread. Move back to our thread.
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
// find the window in _windows who's peasant's Id matches the peasant's Id
|
||||
// and remove it
|
||||
_windows.erase(std::remove_if(_windows.begin(), _windows.end(), [&](const auto& w) {
|
||||
return w->Peasant().GetID() == senderID;
|
||||
}),
|
||||
_windows.end());
|
||||
|
||||
// When we run out of windows, exit our process if and only if:
|
||||
// * We're not allowed to run headless OR
|
||||
// * we've explicitly been told to "quit", which should fully exit the Terminal.
|
||||
if (_windows.size() == 0 &&
|
||||
(_quitting || !_app.Logic().AllowHeadless()))
|
||||
{
|
||||
_close();
|
||||
}
|
||||
});
|
||||
|
||||
window->Start();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set up all sorts of handlers now that we've determined that we're a process
|
||||
// that will end up hosting the windows. These include:
|
||||
// - Setting up a message window to handle hotkeys and notification icon
|
||||
// invokes.
|
||||
// - Setting up the global hotkeys.
|
||||
// - Setting up the notification icon.
|
||||
// - Setting up callbacks for when the settings change.
|
||||
// - Setting up callbacks for when the number of windows changes.
|
||||
// - Setting up the throttled func for layout persistence. Arguments:
|
||||
// - <none>
|
||||
void WindowEmperor::_becomeMonarch()
|
||||
{
|
||||
_createMessageWindow();
|
||||
|
||||
_setupGlobalHotkeys();
|
||||
|
||||
// When the settings change, we'll want to update our global hotkeys and our
|
||||
// notification icon based on the new settings.
|
||||
_app.Logic().SettingsChanged([this](auto&&, const TerminalApp::SettingsLoadEventArgs& args) {
|
||||
if (SUCCEEDED(args.Result()))
|
||||
{
|
||||
_setupGlobalHotkeys();
|
||||
_checkWindowsForNotificationIcon();
|
||||
}
|
||||
});
|
||||
|
||||
// On startup, immediately check if we need to show the notification icon.
|
||||
_checkWindowsForNotificationIcon();
|
||||
|
||||
// Set the number of open windows (so we know if we are the last window)
|
||||
// and subscribe for updates if there are any changes to that number.
|
||||
|
||||
_WindowCreatedToken = _manager.WindowCreated({ this, &WindowEmperor::_numberOfWindowsChanged });
|
||||
_WindowClosedToken = _manager.WindowClosed({ this, &WindowEmperor::_numberOfWindowsChanged });
|
||||
|
||||
// If the monarch receives a QuitAll event it will signal this event to be
|
||||
// ran before each peasant is closed.
|
||||
_revokers.QuitAllRequested = _manager.QuitAllRequested(winrt::auto_revoke, { this, &WindowEmperor::_quitAllRequested });
|
||||
|
||||
// The monarch should be monitoring if it should save the window layout.
|
||||
// We want at least some delay to prevent the first save from overwriting
|
||||
_getWindowLayoutThrottler.emplace(std::move(std::chrono::seconds(10)), std::move([this]() { _saveWindowLayoutsRepeat(); }));
|
||||
_getWindowLayoutThrottler.value()();
|
||||
}
|
||||
|
||||
// sender and args are always nullptr
|
||||
void WindowEmperor::_numberOfWindowsChanged(const winrt::Windows::Foundation::IInspectable&,
|
||||
const winrt::Windows::Foundation::IInspectable&)
|
||||
{
|
||||
if (_getWindowLayoutThrottler)
|
||||
{
|
||||
_getWindowLayoutThrottler.value()();
|
||||
}
|
||||
|
||||
const auto& numWindows{ _manager.GetNumberOfPeasants() };
|
||||
for (const auto& _windowThread : _windows)
|
||||
{
|
||||
_windowThread->Logic().SetNumberOfOpenWindows(numWindows);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
static WindowEmperor* GetThisFromHandle(HWND const window) noexcept
|
||||
{
|
||||
const auto data = GetWindowLongPtr(window, GWLP_USERDATA);
|
||||
return reinterpret_cast<WindowEmperor*>(data);
|
||||
}
|
||||
[[nodiscard]] static LRESULT __stdcall MessageWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
|
||||
{
|
||||
WINRT_ASSERT(window);
|
||||
|
||||
if (WM_NCCREATE == message)
|
||||
{
|
||||
auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
|
||||
WindowEmperor* that = static_cast<WindowEmperor*>(cs->lpCreateParams);
|
||||
WINRT_ASSERT(that);
|
||||
WINRT_ASSERT(!that->_window);
|
||||
that->_window = wil::unique_hwnd(window);
|
||||
SetWindowLongPtr(that->_window.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
}
|
||||
else if (WindowEmperor* that = GetThisFromHandle(window))
|
||||
{
|
||||
return that->MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
|
||||
return DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
void WindowEmperor::_createMessageWindow()
|
||||
{
|
||||
WNDCLASS wc{};
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
wc.lpszClassName = TERMINAL_MESSAGE_CLASS_NAME;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = MessageWndProc;
|
||||
wc.hIcon = LoadIconW(wc.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
|
||||
RegisterClass(&wc);
|
||||
WINRT_ASSERT(!_window);
|
||||
|
||||
WINRT_VERIFY(CreateWindow(wc.lpszClassName,
|
||||
L"Windows Terminal",
|
||||
0,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
HWND_MESSAGE,
|
||||
nullptr,
|
||||
wc.hInstance,
|
||||
this));
|
||||
}
|
||||
|
||||
LRESULT WindowEmperor::MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_HOTKEY:
|
||||
{
|
||||
_hotkeyPressed(static_cast<long>(wParam));
|
||||
return 0;
|
||||
}
|
||||
case CM_NOTIFY_FROM_NOTIFICATION_AREA:
|
||||
{
|
||||
switch (LOWORD(lParam))
|
||||
{
|
||||
case NIN_SELECT:
|
||||
case NIN_KEYSELECT:
|
||||
{
|
||||
_notificationIcon->NotificationIconPressed();
|
||||
return 0;
|
||||
}
|
||||
case WM_CONTEXTMENU:
|
||||
{
|
||||
const til::point eventPoint{ GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam) };
|
||||
_notificationIcon->ShowContextMenu(eventPoint, _manager.GetPeasantInfos());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_MENUCOMMAND:
|
||||
{
|
||||
_notificationIcon->MenuItemSelected((HMENU)lParam, (UINT)wParam);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// We'll want to receive this message when explorer.exe restarts
|
||||
// so that we can re-add our icon to the notification area.
|
||||
// This unfortunately isn't a switch case because we register the
|
||||
// message at runtime.
|
||||
if (message == WM_TASKBARCREATED)
|
||||
{
|
||||
_notificationIcon->ReAddNotificationIcon();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DefWindowProc(_window.get(), message, wParam, lParam);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget WindowEmperor::_close()
|
||||
{
|
||||
// Important! Switch back to the main thread for the emperor. That way, the
|
||||
// quit will go to the emperor's message pump.
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
#pragma region GlobalHotkeys
|
||||
|
||||
// Method Description:
|
||||
// - Called when the monarch failed to summon a window for a given set of
|
||||
// SummonWindowSelectionArgs. In this case, we should create the specified
|
||||
// window ourselves.
|
||||
// - This is to support the scenario like `globalSummon(Name="_quake")` being
|
||||
// used to summon the window if it already exists, or create it if it doesn't.
|
||||
// Arguments:
|
||||
// - args: Contains information on how we should name the window
|
||||
// Return Value:
|
||||
// - <none>
|
||||
static winrt::fire_and_forget _createNewTerminalWindow(Settings::Model::GlobalSummonArgs args)
|
||||
{
|
||||
// Hop to the BG thread
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// This will get us the correct exe for dev/preview/release. If you
|
||||
// don't stick this in a local, it'll get mangled by ShellExecute. I
|
||||
// have no idea why.
|
||||
const auto exePath{ GetWtExePath() };
|
||||
|
||||
// If we weren't given a name, then just use new to force the window to be
|
||||
// unnamed.
|
||||
winrt::hstring cmdline{
|
||||
fmt::format(L"-w {}",
|
||||
args.Name().empty() ? L"new" :
|
||||
args.Name())
|
||||
};
|
||||
|
||||
SHELLEXECUTEINFOW seInfo{ 0 };
|
||||
seInfo.cbSize = sizeof(seInfo);
|
||||
seInfo.fMask = SEE_MASK_NOASYNC;
|
||||
seInfo.lpVerb = L"open";
|
||||
seInfo.lpFile = exePath.c_str();
|
||||
seInfo.lpParameters = cmdline.c_str();
|
||||
seInfo.nShow = SW_SHOWNORMAL;
|
||||
LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo));
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
void WindowEmperor::_hotkeyPressed(const long hotkeyIndex)
|
||||
{
|
||||
if (hotkeyIndex < 0 || static_cast<size_t>(hotkeyIndex) > _hotkeys.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& summonArgs = til::at(_hotkeys, hotkeyIndex);
|
||||
Remoting::SummonWindowSelectionArgs args{ summonArgs.Name() };
|
||||
|
||||
// desktop:any - MoveToCurrentDesktop=false, OnCurrentDesktop=false
|
||||
// desktop:toCurrent - MoveToCurrentDesktop=true, OnCurrentDesktop=false
|
||||
// desktop:onCurrent - MoveToCurrentDesktop=false, OnCurrentDesktop=true
|
||||
args.OnCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::OnCurrent);
|
||||
args.SummonBehavior().MoveToCurrentDesktop(summonArgs.Desktop() == Settings::Model::DesktopBehavior::ToCurrent);
|
||||
args.SummonBehavior().ToggleVisibility(summonArgs.ToggleVisibility());
|
||||
args.SummonBehavior().DropdownDuration(summonArgs.DropdownDuration());
|
||||
|
||||
switch (summonArgs.Monitor())
|
||||
{
|
||||
case Settings::Model::MonitorBehavior::Any:
|
||||
args.SummonBehavior().ToMonitor(Remoting::MonitorBehavior::InPlace);
|
||||
break;
|
||||
case Settings::Model::MonitorBehavior::ToCurrent:
|
||||
args.SummonBehavior().ToMonitor(Remoting::MonitorBehavior::ToCurrent);
|
||||
break;
|
||||
case Settings::Model::MonitorBehavior::ToMouse:
|
||||
args.SummonBehavior().ToMonitor(Remoting::MonitorBehavior::ToMouse);
|
||||
break;
|
||||
}
|
||||
|
||||
_manager.SummonWindow(args);
|
||||
if (args.FoundMatch())
|
||||
{
|
||||
// Excellent, the window was found. We have nothing else to do here.
|
||||
}
|
||||
else
|
||||
{
|
||||
// We should make the window ourselves.
|
||||
_createNewTerminalWindow(summonArgs);
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowEmperor::_registerHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept
|
||||
{
|
||||
const auto vkey = hotkey.Vkey();
|
||||
auto hotkeyFlags = MOD_NOREPEAT;
|
||||
{
|
||||
const auto modifiers = hotkey.Modifiers();
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_WIN, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Windows));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_ALT, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Menu));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_CONTROL, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Control));
|
||||
WI_SetFlagIf(hotkeyFlags, MOD_SHIFT, WI_IsFlagSet(modifiers, VirtualKeyModifiers::Shift));
|
||||
}
|
||||
|
||||
// TODO GH#8888: We should display a warning of some kind if this fails.
|
||||
// This can fail if something else already bound this hotkey.
|
||||
const auto result = ::RegisterHotKey(_window.get(), index, hotkeyFlags, vkey);
|
||||
LOG_LAST_ERROR_IF(!result);
|
||||
TraceLoggingWrite(g_hWindowsTerminalProvider,
|
||||
"RegisterHotKey",
|
||||
TraceLoggingDescription("Emitted when setting hotkeys"),
|
||||
TraceLoggingInt64(index, "index", "the index of the hotkey to add"),
|
||||
TraceLoggingUInt64(vkey, "vkey", "the key"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_WIN), "win", "is WIN in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_ALT), "alt", "is ALT in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_CONTROL), "control", "is CONTROL in the modifiers"),
|
||||
TraceLoggingUInt64(WI_IsFlagSet(hotkeyFlags, MOD_SHIFT), "shift", "is SHIFT in the modifiers"),
|
||||
TraceLoggingBool(result, "succeeded", "true if we succeeded"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Call UnregisterHotKey once for each previously registered hotkey.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void WindowEmperor::_unregisterHotKey(const int index) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hWindowsTerminalProvider,
|
||||
"UnregisterHotKey",
|
||||
TraceLoggingDescription("Emitted when clearing previously set hotkeys"),
|
||||
TraceLoggingInt64(index, "index", "the index of the hotkey to remove"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
LOG_IF_WIN32_BOOL_FALSE(::UnregisterHotKey(_window.get(), index));
|
||||
}
|
||||
|
||||
winrt::fire_and_forget WindowEmperor::_setupGlobalHotkeys()
|
||||
{
|
||||
// The hotkey MUST be registered on the main thread. It will fail otherwise!
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
if (!_window)
|
||||
{
|
||||
// MSFT:36797001 There's a surprising number of hits of this callback
|
||||
// getting triggered during teardown. As a best practice, we really
|
||||
// should make sure _window exists before accessing it on any coroutine.
|
||||
// We might be getting called back after the app already began getting
|
||||
// cleaned up.
|
||||
co_return;
|
||||
}
|
||||
// Unregister all previously registered hotkeys.
|
||||
//
|
||||
// RegisterHotKey(), will not unregister hotkeys automatically.
|
||||
// If a hotkey with a given HWND and ID combination already exists
|
||||
// then a duplicate one will be added, which we don't want.
|
||||
// (Additionally we want to remove hotkeys that were removed from the settings.)
|
||||
for (auto i = 0, count = gsl::narrow_cast<int>(_hotkeys.size()); i < count; ++i)
|
||||
{
|
||||
_unregisterHotKey(i);
|
||||
}
|
||||
|
||||
_hotkeys.clear();
|
||||
|
||||
// Re-register all current hotkeys.
|
||||
for (const auto& [keyChord, cmd] : _app.Logic().GlobalHotkeys())
|
||||
{
|
||||
if (auto summonArgs = cmd.ActionAndArgs().Args().try_as<Settings::Model::GlobalSummonArgs>())
|
||||
{
|
||||
auto index = gsl::narrow_cast<int>(_hotkeys.size());
|
||||
const auto succeeded = _registerHotKey(index, keyChord);
|
||||
|
||||
TraceLoggingWrite(g_hWindowsTerminalProvider,
|
||||
"AppHost_setupGlobalHotkey",
|
||||
TraceLoggingDescription("Emitted when setting a single hotkey"),
|
||||
TraceLoggingInt64(index, "index", "the index of the hotkey to add"),
|
||||
TraceLoggingWideString(cmd.Name().c_str(), "name", "the name of the command"),
|
||||
TraceLoggingBoolean(succeeded, "succeeded", "true if we succeeded"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
_hotkeys.emplace_back(summonArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma region NotificationIcon
|
||||
// Method Description:
|
||||
// - Creates a Notification Icon and hooks up its handlers
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void WindowEmperor::_createNotificationIcon()
|
||||
{
|
||||
_notificationIcon = std::make_unique<NotificationIcon>(_window.get());
|
||||
_notificationIcon->SummonWindowRequested([this](auto& args) { _manager.SummonWindow(args); });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Deletes our notification icon if we have one.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void WindowEmperor::_destroyNotificationIcon()
|
||||
{
|
||||
_notificationIcon->RemoveIconFromNotificationArea();
|
||||
_notificationIcon = nullptr;
|
||||
}
|
||||
|
||||
void WindowEmperor::_checkWindowsForNotificationIcon()
|
||||
{
|
||||
// We need to check some conditions to show the notification icon.
|
||||
//
|
||||
// * If there's a Quake window somewhere, we'll want to keep the
|
||||
// notification icon.
|
||||
// * There's two settings - MinimizeToNotificationArea and
|
||||
// AlwaysShowNotificationIcon. If either one of them are true, we want to
|
||||
// make sure there's a notification icon.
|
||||
//
|
||||
// If both are false, we want to remove our icon from the notification area.
|
||||
// When we remove our icon from the notification area, we'll also want to
|
||||
// re-summon any hidden windows, but right now we're not keeping track of
|
||||
// who's hidden, so just summon them all. Tracking the work to do a "summon
|
||||
// all minimized" in GH#10448
|
||||
|
||||
bool needsIcon = false;
|
||||
for (const auto& _windowThread : _windows)
|
||||
{
|
||||
needsIcon |= _windowThread->Logic().RequestsTrayIcon();
|
||||
}
|
||||
|
||||
if (needsIcon)
|
||||
{
|
||||
_showNotificationIconRequested();
|
||||
}
|
||||
else
|
||||
{
|
||||
_hideNotificationIconRequested();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowEmperor::_showNotificationIconRequested()
|
||||
{
|
||||
if (!_notificationIcon)
|
||||
{
|
||||
_createNotificationIcon();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowEmperor::_hideNotificationIconRequested()
|
||||
{
|
||||
// Destroy it only if our settings allow it
|
||||
if (_notificationIcon)
|
||||
{
|
||||
// If we no longer want the tray icon, but we did have one, then quick
|
||||
// re-summon all our windows, so they don't get lost when the icon
|
||||
// disappears forever.
|
||||
_manager.SummonAllWindows();
|
||||
|
||||
_destroyNotificationIcon();
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
83
src/cascadia/WindowsTerminal/WindowEmperor.h
Normal file
83
src/cascadia/WindowsTerminal/WindowEmperor.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- WindowEmperor.h
|
||||
|
||||
Abstract:
|
||||
- The WindowEmperor is our class for managing the single Terminal process
|
||||
with all our windows. It will be responsible for handling the commandline
|
||||
arguments. It will initially try to find another terminal process to
|
||||
communicate with. If it does, it'll hand off to the existing process.
|
||||
- If it determines that it should create a window, it will set up a new thread
|
||||
for that window, and a message loop on the main thread for handling global
|
||||
state, such as hotkeys and the notification icon.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
#include "WindowThread.h"
|
||||
|
||||
class WindowEmperor
|
||||
{
|
||||
public:
|
||||
WindowEmperor() noexcept;
|
||||
~WindowEmperor();
|
||||
void WaitForWindows();
|
||||
|
||||
bool HandleCommandlineArgs();
|
||||
void CreateNewWindowThread(winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args, const bool firstWindow);
|
||||
|
||||
LRESULT MessageHandler(UINT const message, WPARAM const wParam, LPARAM const lParam) noexcept;
|
||||
wil::unique_hwnd _window;
|
||||
|
||||
private:
|
||||
winrt::TerminalApp::App _app;
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager _manager;
|
||||
|
||||
std::vector<std::shared_ptr<WindowThread>> _windows;
|
||||
std::vector<std::thread> _threads;
|
||||
|
||||
std::optional<til::throttled_func_trailing<>> _getWindowLayoutThrottler;
|
||||
|
||||
winrt::event_token _WindowCreatedToken;
|
||||
winrt::event_token _WindowClosedToken;
|
||||
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::GlobalSummonArgs> _hotkeys;
|
||||
|
||||
std::unique_ptr<NotificationIcon> _notificationIcon;
|
||||
bool _quitting{ false };
|
||||
|
||||
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::Windows::Foundation::IAsyncAction _saveWindowLayouts();
|
||||
winrt::fire_and_forget _saveWindowLayoutsRepeat();
|
||||
|
||||
void _createMessageWindow();
|
||||
|
||||
void _hotkeyPressed(const long hotkeyIndex);
|
||||
bool _registerHotKey(const int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept;
|
||||
void _unregisterHotKey(const int index) noexcept;
|
||||
winrt::fire_and_forget _setupGlobalHotkeys();
|
||||
|
||||
winrt::fire_and_forget _close();
|
||||
|
||||
void _createNotificationIcon();
|
||||
void _destroyNotificationIcon();
|
||||
void _checkWindowsForNotificationIcon();
|
||||
void _showNotificationIconRequested();
|
||||
void _hideNotificationIconRequested();
|
||||
|
||||
struct Revokers
|
||||
{
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::ShowNotificationIconRequested_revoker ShowNotificationIconRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::HideNotificationIconRequested_revoker HideNotificationIconRequested;
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager::QuitAllRequested_revoker QuitAllRequested;
|
||||
} _revokers{};
|
||||
};
|
||||
134
src/cascadia/WindowsTerminal/WindowThread.cpp
Normal file
134
src/cascadia/WindowsTerminal/WindowThread.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "WindowThread.h"
|
||||
|
||||
WindowThread::WindowThread(const winrt::TerminalApp::AppLogic& logic,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager manager,
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant peasant) :
|
||||
_peasant{ peasant },
|
||||
_appLogic{ logic },
|
||||
_args{ args },
|
||||
_manager{ manager }
|
||||
{
|
||||
// DO NOT start the AppHost here in the ctor, as that will start XAML on the wrong thread!
|
||||
}
|
||||
|
||||
void WindowThread::Start()
|
||||
{
|
||||
_thread = std::thread([this]() {
|
||||
// Start the AppHost HERE, on the actual thread we want XAML to run on
|
||||
_host = std::make_unique<::AppHost>(_appLogic,
|
||||
_args,
|
||||
_manager,
|
||||
_peasant);
|
||||
_host->UpdateSettingsRequested([this]() { _UpdateSettingsRequestedHandlers(); });
|
||||
// Enter the main window loop.
|
||||
const auto exitCode = WindowProc();
|
||||
_host = nullptr;
|
||||
|
||||
// !! LOAD BEARING !!
|
||||
//
|
||||
// Make sure to finish pumping all the messages for our thread here. We
|
||||
// may think we're all done, but we're not quite. XAML needs more time
|
||||
// to pump the remaining events through, even at the point we're
|
||||
// exiting. So do that now. If you don't, then the last tab to close
|
||||
// will never actually destruct the last tab / TermControl / ControlCore
|
||||
// / renderer.
|
||||
{
|
||||
MSG msg = {};
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
|
||||
{
|
||||
::DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
_ExitedHandlers(_peasant.GetID());
|
||||
return exitCode;
|
||||
});
|
||||
LOG_IF_FAILED(SetThreadDescription(_thread.native_handle(), L"Window Thread"));
|
||||
}
|
||||
|
||||
winrt::TerminalApp::TerminalWindow WindowThread::Logic()
|
||||
{
|
||||
return _host->Logic();
|
||||
}
|
||||
|
||||
static bool _messageIsF7Keypress(const MSG& message)
|
||||
{
|
||||
return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7;
|
||||
}
|
||||
static bool _messageIsAltKeyup(const MSG& message)
|
||||
{
|
||||
return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU;
|
||||
}
|
||||
static bool _messageIsAltSpaceKeypress(const MSG& message)
|
||||
{
|
||||
return message.message == WM_SYSKEYDOWN && message.wParam == VK_SPACE;
|
||||
}
|
||||
|
||||
int WindowThread::WindowProc()
|
||||
{
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
// Initialize the xaml content. This must be called AFTER the
|
||||
// WindowsXamlManager is initialized.
|
||||
_host->Initialize();
|
||||
|
||||
// Inform the emperor that we're ready to go. We need to do this after
|
||||
// Initialize, so that the windowLogic is ready to be used
|
||||
_StartedHandlers();
|
||||
|
||||
MSG message;
|
||||
|
||||
while (GetMessage(&message, nullptr, 0, 0))
|
||||
{
|
||||
// GH#638 (Pressing F7 brings up both the history AND a caret browsing message)
|
||||
// The Xaml input stack doesn't allow an application to suppress the "caret browsing"
|
||||
// dialog experience triggered when you press F7. Official recommendation from the Xaml
|
||||
// team is to catch F7 before we hand it off.
|
||||
// AppLogic contains an ad-hoc implementation of event bubbling for a runtime classes
|
||||
// implementing a custom IF7Listener interface.
|
||||
// If the recipient of IF7Listener::OnF7Pressed suggests that the F7 press has, in fact,
|
||||
// been handled we can discard the message before we even translate it.
|
||||
if (_messageIsF7Keypress(message))
|
||||
{
|
||||
if (_host->OnDirectKeyEvent(VK_F7, LOBYTE(HIWORD(message.lParam)), true))
|
||||
{
|
||||
// The application consumed the F7. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#6421 - System XAML will never send an Alt KeyUp event. So, similar
|
||||
// to how we'll steal the F7 KeyDown above, we'll steal the Alt KeyUp
|
||||
// here, and plumb it through.
|
||||
if (_messageIsAltKeyup(message))
|
||||
{
|
||||
// Let's pass <Alt> to the application
|
||||
if (_host->OnDirectKeyEvent(VK_MENU, LOBYTE(HIWORD(message.lParam)), false))
|
||||
{
|
||||
// The application consumed the Alt. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#7125 = System XAML will show a system dialog on Alt Space. We want to
|
||||
// explicitly prevent that because we handle that ourselves. So similar to
|
||||
// above, we steal the event and hand it off to the host.
|
||||
if (_messageIsAltSpaceKeypress(message))
|
||||
{
|
||||
_host->OnDirectKeyEvent(VK_SPACE, LOBYTE(HIWORD(message.lParam)), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant WindowThread::Peasant()
|
||||
{
|
||||
return _peasant;
|
||||
}
|
||||
33
src/cascadia/WindowsTerminal/WindowThread.h
Normal file
33
src/cascadia/WindowsTerminal/WindowThread.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "AppHost.h"
|
||||
|
||||
class WindowThread
|
||||
{
|
||||
public:
|
||||
WindowThread(const winrt::TerminalApp::AppLogic& logic,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs args,
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager manager,
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant peasant);
|
||||
int WindowProc();
|
||||
|
||||
winrt::TerminalApp::TerminalWindow Logic();
|
||||
void Start();
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant Peasant();
|
||||
|
||||
WINRT_CALLBACK(Started, winrt::delegate<>);
|
||||
WINRT_CALLBACK(Exited, winrt::delegate<uint64_t>);
|
||||
WINRT_CALLBACK(UpdateSettingsRequested, winrt::delegate<void()>);
|
||||
|
||||
private:
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant _peasant{ nullptr };
|
||||
|
||||
winrt::TerminalApp::AppLogic _appLogic{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs _args{ nullptr };
|
||||
winrt::Microsoft::Terminal::Remoting::WindowManager _manager{ nullptr };
|
||||
|
||||
std::thread _thread;
|
||||
std::unique_ptr<::AppHost> _host{ nullptr };
|
||||
};
|
||||
@@ -56,6 +56,8 @@
|
||||
<ClInclude Include="NonClientIslandWindow.h" />
|
||||
<ClInclude Include="NotificationIcon.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
<ClInclude Include="WindowEmperor.h" />
|
||||
<ClInclude Include="WindowThread.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@@ -67,6 +69,8 @@
|
||||
<ClCompile Include="NonClientIslandWindow.cpp" />
|
||||
<ClCompile Include="NotificationIcon.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="WindowEmperor.cpp" />
|
||||
<ClCompile Include="WindowThread.cpp" />
|
||||
<ClCompile Include="icon.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "AppHost.h"
|
||||
#include "WindowEmperor.h"
|
||||
#include "resource.h"
|
||||
#include "../types/inc/User32Utils.hpp"
|
||||
#include <WilErrorReporting.h>
|
||||
@@ -83,19 +83,6 @@ static void EnsureNativeArchitecture()
|
||||
}
|
||||
}
|
||||
|
||||
static bool _messageIsF7Keypress(const MSG& message)
|
||||
{
|
||||
return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7;
|
||||
}
|
||||
static bool _messageIsAltKeyup(const MSG& message)
|
||||
{
|
||||
return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU;
|
||||
}
|
||||
static bool _messageIsAltSpaceKeypress(const MSG& message)
|
||||
{
|
||||
return message.message == WM_SYSKEYDOWN && message.wParam == VK_SPACE;
|
||||
}
|
||||
|
||||
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
TraceLoggingRegister(g_hWindowsTerminalProvider);
|
||||
@@ -127,68 +114,9 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
// doing that, we can safely init as STA before any WinRT dispatches.
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
// Create the AppHost object, which will create both the window and the
|
||||
// Terminal App. This MUST BE constructed before the Xaml manager as TermApp
|
||||
// provides an implementation of Windows.UI.Xaml.Application.
|
||||
AppHost host;
|
||||
if (!host.HasWindow())
|
||||
::WindowEmperor emperor{};
|
||||
if (emperor.HandleCommandlineArgs())
|
||||
{
|
||||
// If we were told to not have a window, exit early. Make sure to use
|
||||
// ExitProcess to die here. If you try just `return 0`, then
|
||||
// the XAML app host will crash during teardown. ExitProcess avoids
|
||||
// that.
|
||||
ExitProcess(0);
|
||||
emperor.WaitForWindows();
|
||||
}
|
||||
|
||||
// Initialize the xaml content. This must be called AFTER the
|
||||
// WindowsXamlManager is initialized.
|
||||
host.Initialize();
|
||||
|
||||
MSG message;
|
||||
|
||||
while (GetMessage(&message, nullptr, 0, 0))
|
||||
{
|
||||
// GH#638 (Pressing F7 brings up both the history AND a caret browsing message)
|
||||
// The Xaml input stack doesn't allow an application to suppress the "caret browsing"
|
||||
// dialog experience triggered when you press F7. Official recommendation from the Xaml
|
||||
// team is to catch F7 before we hand it off.
|
||||
// AppLogic contains an ad-hoc implementation of event bubbling for a runtime classes
|
||||
// implementing a custom IF7Listener interface.
|
||||
// If the recipient of IF7Listener::OnF7Pressed suggests that the F7 press has, in fact,
|
||||
// been handled we can discard the message before we even translate it.
|
||||
if (_messageIsF7Keypress(message))
|
||||
{
|
||||
if (host.OnDirectKeyEvent(VK_F7, LOBYTE(HIWORD(message.lParam)), true))
|
||||
{
|
||||
// The application consumed the F7. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#6421 - System XAML will never send an Alt KeyUp event. So, similar
|
||||
// to how we'll steal the F7 KeyDown above, we'll steal the Alt KeyUp
|
||||
// here, and plumb it through.
|
||||
if (_messageIsAltKeyup(message))
|
||||
{
|
||||
// Let's pass <Alt> to the application
|
||||
if (host.OnDirectKeyEvent(VK_MENU, LOBYTE(HIWORD(message.lParam)), false))
|
||||
{
|
||||
// The application consumed the Alt. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#7125 = System XAML will show a system dialog on Alt Space. We want to
|
||||
// explicitly prevent that because we handle that ourselves. So similar to
|
||||
// above, we steal the event and hand it off to the host.
|
||||
if (_messageIsAltSpaceKeypress(message))
|
||||
{
|
||||
host.OnDirectKeyEvent(VK_SPACE, LOBYTE(HIWORD(message.lParam)), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@ constexpr int32_t WindowingBehaviorUseNew{ -1 };
|
||||
constexpr int32_t WindowingBehaviorUseExisting{ -2 };
|
||||
constexpr int32_t WindowingBehaviorUseAnyExisting{ -3 };
|
||||
constexpr int32_t WindowingBehaviorUseName{ -4 };
|
||||
constexpr int32_t WindowingBehaviorUseNone{ -5 };
|
||||
|
||||
static constexpr std::wstring_view QuakeWindowName{ L"_quake" };
|
||||
|
||||
@@ -102,6 +102,27 @@ public:
|
||||
winrt::event_token name(const Windows::Foundation::TypedEventHandler<sender, args>& h) { return handler.handlerName(h); } \
|
||||
void name(const winrt::event_token& token) noexcept { handler.handlerName(token); }
|
||||
|
||||
// This is a bit like *FORWARDED_TYPED_EVENT. When you use a forwarded event,
|
||||
// the handler gets added to the object that's raising the event. For example,
|
||||
// the TerminalPage might be the handler for the TermControl's
|
||||
// BackgroundColorChanged event, which is actually implemented by the
|
||||
// ControlCore. So when Core raises an event, it immediately calls the handler
|
||||
// on the Page.
|
||||
//
|
||||
// Instead, the BUBBLED event introduces an indirection layer. In the above
|
||||
// example, the Core would raise the event, but now the Control would handle it,
|
||||
// and raise an event with each of its own handlers.
|
||||
//
|
||||
// This allows us to detach the core from the control safely, without needing to
|
||||
// re-wire all the event handlers from page->control again.
|
||||
//
|
||||
// Implement like:
|
||||
//
|
||||
// _core.TitleChanged({ get_weak(), &TermControl::_bubbleTitleChanged });
|
||||
#define BUBBLED_FORWARDED_TYPED_EVENT(name, sender, args) \
|
||||
TYPED_EVENT(name, sender, args) \
|
||||
void _bubble##name(const sender& s, const args& a) { _##name##Handlers(s, a); }
|
||||
|
||||
// Use this macro to quick implement both the getter and setter for a property.
|
||||
// This should only be used for simple types where there's no logic in the
|
||||
// getter/setter beyond just accessing/updating the value.
|
||||
|
||||
@@ -341,6 +341,11 @@ void AtlasEngine::SetCallback(std::function<void(HANDLE)> pfn) noexcept
|
||||
_api.swapChainChangedCallback = std::move(pfn);
|
||||
}
|
||||
|
||||
HANDLE AtlasEngine::GetSwapChainHandle() noexcept
|
||||
{
|
||||
return _api.swapChainHandle.get();
|
||||
}
|
||||
|
||||
void AtlasEngine::EnableTransparentBackground(const bool isTransparent) noexcept
|
||||
{
|
||||
if (_api.enableTransparentBackground != isTransparent)
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace Microsoft::Console::Render
|
||||
// DxRenderer - setter
|
||||
void SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept override;
|
||||
void SetCallback(std::function<void(HANDLE)> pfn) noexcept override;
|
||||
HANDLE GetSwapChainHandle() noexcept override;
|
||||
void EnableTransparentBackground(const bool isTransparent) noexcept override;
|
||||
void SetForceFullRepaintRendering(bool enable) noexcept override;
|
||||
[[nodiscard]] HRESULT SetHwnd(HWND hwnd) noexcept override;
|
||||
|
||||
@@ -1306,6 +1306,20 @@ void Renderer::AddRenderEngine(_In_ IRenderEngine* const pEngine)
|
||||
THROW_HR_MSG(E_UNEXPECTED, "engines array is full");
|
||||
}
|
||||
|
||||
void Renderer::RemoveRenderEngine(_In_ IRenderEngine* const pEngine)
|
||||
{
|
||||
THROW_HR_IF_NULL(E_INVALIDARG, pEngine);
|
||||
|
||||
for (auto& p : _engines)
|
||||
{
|
||||
if (p == pEngine)
|
||||
{
|
||||
p = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Registers a callback for when the background color is changed
|
||||
// Arguments:
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace Microsoft::Console::Render
|
||||
void WaitUntilCanRender();
|
||||
|
||||
void AddRenderEngine(_In_ IRenderEngine* const pEngine);
|
||||
void RemoveRenderEngine(_In_ IRenderEngine* const pEngine);
|
||||
|
||||
void SetBackgroundColorChangedCallback(std::function<void()> pfn);
|
||||
void SetFrameColorChangedCallback(std::function<void()> pfn);
|
||||
|
||||
@@ -987,6 +987,10 @@ void DxEngine::SetCallback(std::function<void(const HANDLE)> pfn) noexcept
|
||||
{
|
||||
_pfn = std::move(pfn);
|
||||
}
|
||||
HANDLE DxEngine::GetSwapChainHandle() noexcept
|
||||
{
|
||||
return _swapChainHandle.get();
|
||||
}
|
||||
|
||||
void DxEngine::SetWarningCallback(std::function<void(const HRESULT)> pfn) noexcept
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT SetWindowSize(const til::size pixels) noexcept override;
|
||||
|
||||
void SetCallback(std::function<void(const HANDLE)> pfn) noexcept override;
|
||||
HANDLE GetSwapChainHandle() noexcept override;
|
||||
void SetWarningCallback(std::function<void(const HRESULT)> pfn) noexcept override;
|
||||
|
||||
bool GetRetroTerminalEffect() const noexcept override;
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace Microsoft::Console::Render
|
||||
// DxRenderer - setter
|
||||
virtual void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept {}
|
||||
virtual void SetCallback(std::function<void(HANDLE)> pfn) noexcept {}
|
||||
virtual HANDLE GetSwapChainHandle() noexcept { return nullptr; }
|
||||
virtual void EnableTransparentBackground(const bool isTransparent) noexcept {}
|
||||
virtual void SetForceFullRepaintRendering(bool enable) noexcept {}
|
||||
[[nodiscard]] virtual HRESULT SetHwnd(const HWND hwnd) noexcept { return E_NOTIMPL; }
|
||||
|
||||
Reference in New Issue
Block a user