mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 05:54:23 +00:00
Compare commits
363 Commits
dev/cazamo
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9da196da7d | ||
|
|
d7637ff33b | ||
|
|
7189228deb | ||
|
|
0fdb523072 | ||
|
|
19ccea53d5 | ||
|
|
bc76f3ada6 | ||
|
|
a04a51bbe4 | ||
|
|
12dbcf96fd | ||
|
|
5bb0818c0d | ||
|
|
edd9ab10bd | ||
|
|
c18466ae7c | ||
|
|
fcb8b59e6f | ||
|
|
cf1bc0a5b6 | ||
|
|
f9fbb8ab3d | ||
|
|
17e3ca5390 | ||
|
|
5040328a06 | ||
|
|
173e916bcd | ||
|
|
cedfd3f5bd | ||
|
|
8b96836e1d | ||
|
|
cf77c1758b | ||
|
|
dbe8e13c57 | ||
|
|
bd873fa0a2 | ||
|
|
a8ab6a4a43 | ||
|
|
c4597dec0d | ||
|
|
492c894b79 | ||
|
|
e23980c62a | ||
|
|
514556f018 | ||
|
|
6a0b1cdbdc | ||
|
|
c8ce5b4dc6 | ||
|
|
9957e5ce52 | ||
|
|
1138416dc9 | ||
|
|
6d043532fc | ||
|
|
22c94bf10d | ||
|
|
cd2db82515 | ||
|
|
339972ecea | ||
|
|
81140a530e | ||
|
|
f70775aca0 | ||
|
|
ca511c9cc9 | ||
|
|
073350e66f | ||
|
|
44b238e777 | ||
|
|
39a94503fc | ||
|
|
1b59eb9238 | ||
|
|
434abc2474 | ||
|
|
6dead99341 | ||
|
|
77218139d8 | ||
|
|
6e4b2e1048 | ||
|
|
99f19a9c0a | ||
|
|
3d04d37b3a | ||
|
|
f8e6884fac | ||
|
|
1dc243641c | ||
|
|
6f6880c017 | ||
|
|
daddcf171e | ||
|
|
33b3eac3d6 | ||
|
|
547b2c9e6a | ||
|
|
74af809b66 | ||
|
|
b0ca581b43 | ||
|
|
5fe3fa5ea8 | ||
|
|
3fa101731b | ||
|
|
b24cf615ea | ||
|
|
0efa5a9209 | ||
|
|
230d68b0de | ||
|
|
d545c4b4ca | ||
|
|
11ef8efbad | ||
|
|
9a9fa4392a | ||
|
|
35c7474abe | ||
|
|
a6c5e7a943 | ||
|
|
9e3e336275 | ||
|
|
ffc8b120bf | ||
|
|
6a9254ee18 | ||
|
|
dbdc672b56 | ||
|
|
654baa736e | ||
|
|
c4f3011297 | ||
|
|
796a02e0b0 | ||
|
|
491fa62a5a | ||
|
|
41827424db | ||
|
|
2d6fbc97bf | ||
|
|
9d5ef3a10b | ||
|
|
442413fc1e | ||
|
|
3aa083ba9a | ||
|
|
236912abab | ||
|
|
8c5bfb5756 | ||
|
|
59d6ff29a8 | ||
|
|
7591b0f404 | ||
|
|
2c15f97ee8 | ||
|
|
48aa555428 | ||
|
|
b983c69c8e | ||
|
|
fda16631cc | ||
|
|
88033246f1 | ||
|
|
08f6a53be5 | ||
|
|
8e2c7a7bdd | ||
|
|
1e331a037c | ||
|
|
5c852c3c4c | ||
|
|
7e2eb0d8e5 | ||
|
|
110bb7da9c | ||
|
|
de56d9e6c8 | ||
|
|
dcdb145500 | ||
|
|
20f5651224 | ||
|
|
a21c8155e7 | ||
|
|
e09379c64f | ||
|
|
173a830339 | ||
|
|
e544871893 | ||
|
|
e2cc27889a | ||
|
|
a172f53597 | ||
|
|
4eada04716 | ||
|
|
a94bf69c30 | ||
|
|
a811441e9d | ||
|
|
bdac748b8a | ||
|
|
83a323d7ea | ||
|
|
841a064401 | ||
|
|
17dbc7b5ce | ||
|
|
08acc90e5f | ||
|
|
4f8d64ec6f | ||
|
|
5164bffa78 | ||
|
|
ada3f427a0 | ||
|
|
5e23a72beb | ||
|
|
0199aba286 | ||
|
|
b589d092e9 | ||
|
|
74260ce6e1 | ||
|
|
01388c95b0 | ||
|
|
fa1140dc07 | ||
|
|
e1472095e2 | ||
|
|
b9dc8c3f5b | ||
|
|
055cdfedd0 | ||
|
|
257fe33269 | ||
|
|
34bc66f8bf | ||
|
|
6934bc8d05 | ||
|
|
cacb822cf6 | ||
|
|
b75fb24512 | ||
|
|
c79f27c3da | ||
|
|
57a53279ae | ||
|
|
5defde545f | ||
|
|
c9e7156a59 | ||
|
|
dc71f0c346 | ||
|
|
f4c310a154 | ||
|
|
f3796da794 | ||
|
|
c839bfa2ca | ||
|
|
06874ee321 | ||
|
|
36b5759604 | ||
|
|
273f2a84ef | ||
|
|
d2a5a4aab7 | ||
|
|
9a4739659b | ||
|
|
7649725150 | ||
|
|
84a41b4504 | ||
|
|
7988d89c08 | ||
|
|
a3c4776355 | ||
|
|
b1a867db6c | ||
|
|
614ec58c31 | ||
|
|
70450afe7e | ||
|
|
9ec9da3da2 | ||
|
|
b5dbae9244 | ||
|
|
d67815bf0c | ||
|
|
4516b4b1b3 | ||
|
|
6586c4a816 | ||
|
|
f5909d9baa | ||
|
|
0cf13d81b1 | ||
|
|
2537342ffb | ||
|
|
8feb9098b9 | ||
|
|
3cb7cd731f | ||
|
|
d7b3e494df | ||
|
|
90bd976c75 | ||
|
|
1b9498563f | ||
|
|
dbd9ef32ed | ||
|
|
5042d82b30 | ||
|
|
aa93940da9 | ||
|
|
d94183b897 | ||
|
|
c6cce0fd6b | ||
|
|
b41ae7115c | ||
|
|
c2a2caf029 | ||
|
|
2c66c32f97 | ||
|
|
ff5eead9ea | ||
|
|
026f342bc5 | ||
|
|
b8f8ef311a | ||
|
|
b6974f0de5 | ||
|
|
26ebc0a359 | ||
|
|
59f9c64ad6 | ||
|
|
951ece1f3e | ||
|
|
1f8766e972 | ||
|
|
091660e96d | ||
|
|
0e0d8572a3 | ||
|
|
48e7348f5c | ||
|
|
e785bfc8bb | ||
|
|
9da1192993 | ||
|
|
f9caf191a9 | ||
|
|
13257dafa0 | ||
|
|
ecab57fba1 | ||
|
|
091f32c575 | ||
|
|
62a4ee058b | ||
|
|
2bc578bc6c | ||
|
|
667b6586d2 | ||
|
|
bc80943fd9 | ||
|
|
aa8b0c564d | ||
|
|
118bffa6cd | ||
|
|
f10dfac20f | ||
|
|
d01cab370f | ||
|
|
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 | ||
|
|
985fcdbdb6 | ||
|
|
b0fa972ec1 | ||
|
|
c0658975b2 | ||
|
|
a76993365e | ||
|
|
dffb41601b | ||
|
|
e40575b18b | ||
|
|
cfa61088fe | ||
|
|
0ad5b596bd | ||
|
|
7660937139 | ||
|
|
45487294a0 | ||
|
|
f904e5d22d | ||
|
|
f361b6c879 | ||
|
|
7404dc3d35 | ||
|
|
0395dc40a3 | ||
|
|
7e91bdb289 | ||
|
|
c69f0bc444 | ||
|
|
e214624e1f | ||
|
|
b0726c2057 | ||
|
|
055da357b1 | ||
|
|
950ce6c4fc | ||
|
|
0b79e81ae9 | ||
|
|
a7379ca8e9 | ||
|
|
c97ac66d5d | ||
|
|
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 | ||
|
|
77e4289dcb | ||
|
|
2a6520dfef | ||
|
|
35b519a175 | ||
|
|
ee63aff320 | ||
|
|
ad1f331154 | ||
|
|
c82051ffdd | ||
|
|
11f6561153 | ||
|
|
380f0295ca | ||
|
|
828695ee8a | ||
|
|
ba7b5aec79 | ||
|
|
c282797cac | ||
|
|
a20201fff2 | ||
|
|
0e546a62e0 | ||
|
|
a1d532901c | ||
|
|
564102b36f | ||
|
|
9ff0abe834 | ||
|
|
559ecdb358 | ||
|
|
ab55a8df7b | ||
|
|
c77f959c05 | ||
|
|
40046c38dc | ||
|
|
427a4a51c5 | ||
|
|
17057d147d | ||
|
|
631f690e42 | ||
|
|
57d1dd4358 | ||
|
|
713ea71725 | ||
|
|
0f33913423 | ||
|
|
7aef3afef8 | ||
|
|
d6fe520843 | ||
|
|
08ae0ece68 | ||
|
|
0328b4f720 | ||
|
|
854335b8bb | ||
|
|
1f56807fa0 | ||
|
|
0a6c21fed0 | ||
|
|
ebe5fd8163 | ||
|
|
d143f312d3 | ||
|
|
3bd6957a6d | ||
|
|
6a2239d487 | ||
|
|
4dcc67b4d7 | ||
|
|
37a8fde29c | ||
|
|
2ee4111ca0 | ||
|
|
1b4f1efb09 | ||
|
|
e623299ac6 | ||
|
|
274d62d8a8 | ||
|
|
f655296c1e | ||
|
|
7a3e2e098d | ||
|
|
2c4613a494 | ||
|
|
2dd01fbb69 | ||
|
|
6a600533c6 | ||
|
|
f5b030c28c | ||
|
|
d456210f37 | ||
|
|
af14c2b751 | ||
|
|
ef7e2edfa5 | ||
|
|
5116ca1e77 | ||
|
|
2195515937 | ||
|
|
99bc280207 | ||
|
|
439b21f879 | ||
|
|
936c01f948 | ||
|
|
e6220b7fe7 | ||
|
|
a5255ba8ed | ||
|
|
581acd40d9 | ||
|
|
191bca8e57 | ||
|
|
ce6a2e79cb | ||
|
|
e76564eb9d | ||
|
|
d867a6179f | ||
|
|
dbb4db3cc8 | ||
|
|
23f9527280 | ||
|
|
5398ea3aa7 | ||
|
|
61a9c8090a | ||
|
|
dc2ebaf806 | ||
|
|
99b84a60b7 | ||
|
|
451d8f3609 | ||
|
|
29d454ba4c | ||
|
|
e6b33c3740 | ||
|
|
eb7d2be2e8 | ||
|
|
520c89f1fe | ||
|
|
b535a5f3f3 | ||
|
|
eb88cd3a2d | ||
|
|
7001e93550 | ||
|
|
eaf1a920e1 | ||
|
|
ccfc83443b | ||
|
|
0bda66fc2f | ||
|
|
d3b5533a1e | ||
|
|
1449088e80 | ||
|
|
c96799c6e9 |
1
.github/actions/spelling/allow/allow.txt
vendored
1
.github/actions/spelling/allow/allow.txt
vendored
@@ -93,6 +93,7 @@ slnt
|
||||
Sos
|
||||
ssh
|
||||
stakeholders
|
||||
sxn
|
||||
timeline
|
||||
timelines
|
||||
timestamped
|
||||
|
||||
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
|
||||
|
||||
3
.github/actions/spelling/expect/expect.txt
vendored
3
.github/actions/spelling/expect/expect.txt
vendored
@@ -311,6 +311,7 @@ CPLINFO
|
||||
cplusplus
|
||||
CPPCORECHECK
|
||||
cppcorecheckrules
|
||||
cpprest
|
||||
cpprestsdk
|
||||
cppwinrt
|
||||
CProc
|
||||
@@ -1436,6 +1437,7 @@ PPEB
|
||||
ppf
|
||||
ppguid
|
||||
ppidl
|
||||
pplx
|
||||
PPROC
|
||||
PPROCESS
|
||||
ppropvar
|
||||
@@ -2113,6 +2115,7 @@ WDDMCONSOLECONTEXT
|
||||
wdm
|
||||
webpage
|
||||
websites
|
||||
websockets
|
||||
wekyb
|
||||
wex
|
||||
wextest
|
||||
|
||||
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.",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<!--
|
||||
@@ -136,13 +141,14 @@
|
||||
<!-- **END VC LIBS HACK** -->
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
<!-- <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
</Target> -->
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,22 +28,60 @@ namespace winrt::SampleApp::implementation
|
||||
{
|
||||
auto settings = winrt::make_self<implementation::MySettings>();
|
||||
|
||||
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
|
||||
winrt::hstring{},
|
||||
L"",
|
||||
nullptr,
|
||||
32,
|
||||
80,
|
||||
winrt::guid()) };
|
||||
{
|
||||
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
|
||||
winrt::hstring{},
|
||||
L"",
|
||||
nullptr,
|
||||
32,
|
||||
80,
|
||||
winrt::guid()) };
|
||||
|
||||
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
|
||||
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
|
||||
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
|
||||
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
|
||||
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
|
||||
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
|
||||
|
||||
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
|
||||
Control::TermControl control{ *settings, *settings, conn };
|
||||
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
|
||||
Control::TermControl control{ *settings, *settings, conn };
|
||||
|
||||
InProcContent().Children().Append(control);
|
||||
InProcContent().Children().Append(control);
|
||||
}
|
||||
|
||||
{
|
||||
settings->DefaultBackground(til::color{ 0x25, 0x25, 0x25 });
|
||||
settings->AutoMarkPrompts(true);
|
||||
auto envMap = winrt::single_threaded_map<winrt::hstring, winrt::hstring>();
|
||||
envMap.Insert(L"PROMPT", L"$e]133;D$e\\$e]133;A$e\\$e]9;9;$P$e\\$P$G$e]133;B$e\\");
|
||||
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This is a BlockControl...",
|
||||
winrt::hstring{},
|
||||
L"",
|
||||
envMap.GetView(),
|
||||
32,
|
||||
80,
|
||||
winrt::guid()) };
|
||||
|
||||
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
|
||||
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
|
||||
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
|
||||
|
||||
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
|
||||
|
||||
Control::BlockContent content{ *settings, conn };
|
||||
Control::BlockControl control{ content };
|
||||
control.NewBlock({ get_weak(), &MyPage::_newBlockHandler });
|
||||
|
||||
control.Height(256);
|
||||
control.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
control.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
|
||||
WUX::Controls::Grid wrapper{};
|
||||
wrapper.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
wrapper.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
wrapper.CornerRadius(WUX::CornerRadiusHelper::FromRadii(6, 6, 6, 6));
|
||||
wrapper.Margin(WUX::ThicknessHelper::FromLengths(0, 4, 0, 4));
|
||||
wrapper.Children().Append(control);
|
||||
OutOfProcContent().Children().Append(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -58,4 +96,23 @@ namespace winrt::SampleApp::implementation
|
||||
return { L"Sample Application" };
|
||||
}
|
||||
|
||||
winrt::fire_and_forget MyPage::_newBlockHandler(IInspectable sender, Control::BlockContent content)
|
||||
{
|
||||
co_await winrt::resume_foreground(Dispatcher());
|
||||
|
||||
Control::BlockControl control{ content };
|
||||
// control.NewBlock({ get_weak(), &MyPage::_newBlockHandler });
|
||||
|
||||
control.Height(256);
|
||||
control.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
control.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
|
||||
WUX::Controls::Grid wrapper{};
|
||||
wrapper.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
wrapper.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
wrapper.CornerRadius(WUX::CornerRadiusHelper::FromRadii(6, 6, 6, 6));
|
||||
wrapper.Margin(WUX::ThicknessHelper::FromLengths(0, 4, 0, 4));
|
||||
wrapper.Children().Append(control);
|
||||
OutOfProcContent().Children().Append(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace winrt::SampleApp::implementation
|
||||
|
||||
private:
|
||||
friend struct MyPageT<MyPage>; // for Xaml to bind events
|
||||
|
||||
winrt::fire_and_forget _newBlockHandler(Windows::Foundation::IInspectable sender, Microsoft::Terminal::Control::BlockContent content);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,18 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#ff0000" />
|
||||
<ScrollViewer Grid.Column="1"
|
||||
Padding="4"
|
||||
Background="#fff00f">
|
||||
<StackPanel x:Name="OutOfProcContent"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#9090ff"
|
||||
CornerRadius="4"
|
||||
Orientation="Vertical" />
|
||||
|
||||
<Grid x:Name="OutOfProcContent"
|
||||
Grid.Column="1"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#0000ff" />
|
||||
</ScrollViewer>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -90,19 +91,26 @@
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
<OCResourceDirectory Include="Resources" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Other properties ======================== -->
|
||||
<PropertyGroup>
|
||||
<!-- This is a hack to get the ARM64 CI build working. See
|
||||
https://github.com/Microsoft/msbuild/issues/3746 - it looks like MsBuild
|
||||
just has a bug in it.-->
|
||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>Warning</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- ========================== Other References ========================= -->
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
@@ -156,13 +164,13 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<!-- <Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
</Target> -->
|
||||
|
||||
<!--
|
||||
By default, the PRI file will contain resource paths beginning with the
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
@@ -90,13 +91,13 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<!-- <Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
</Target> -->
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
|
||||
<TerminalVCRTForwarders>true</TerminalVCRTForwarders>
|
||||
<TerminalThemeHelpers>true</TerminalThemeHelpers>
|
||||
<TerminalMUX>true</TerminalMUX>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
@@ -144,13 +145,13 @@
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<!-- <Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
</Target> -->
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up all our dependencies.
|
||||
This ensures that when the WAP packaging project asks what files go into
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
#include "precomp.h"
|
||||
#include "Row.hpp"
|
||||
|
||||
#include <til/unicode.h>
|
||||
|
||||
#include "textBuffer.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
// The STL is missing a std::iota_n analogue for std::iota, so I made my own.
|
||||
template<typename OutIt, typename Diff, typename T>
|
||||
@@ -65,6 +68,65 @@ constexpr OutIt copy_n_small(InIt first, Diff count, OutIt dest)
|
||||
return dest;
|
||||
}
|
||||
|
||||
RowTextIterator::RowTextIterator(std::span<const wchar_t> chars, std::span<const uint16_t> charOffsets, uint16_t offset) noexcept :
|
||||
_chars{ chars },
|
||||
_charOffsets{ charOffsets },
|
||||
_beg{ offset },
|
||||
_end{ offset }
|
||||
{
|
||||
operator++();
|
||||
}
|
||||
|
||||
bool RowTextIterator::operator==(const RowTextIterator& other) const noexcept
|
||||
{
|
||||
return _beg == other._beg;
|
||||
}
|
||||
|
||||
RowTextIterator& RowTextIterator::operator++() noexcept
|
||||
{
|
||||
_beg = _end;
|
||||
while (++_end < _charOffsets.size() && _uncheckedIsTrailer(_end))
|
||||
{
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const RowTextIterator& RowTextIterator::operator*() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::wstring_view RowTextIterator::Text() const noexcept
|
||||
{
|
||||
const auto beg = _uncheckedCharOffset(_beg);
|
||||
const auto end = _uncheckedCharOffset(_end);
|
||||
return { _chars.begin() + beg, _chars.begin() + gsl::narrow_cast<size_t>(end - beg) };
|
||||
}
|
||||
|
||||
til::CoordType RowTextIterator::Cols() const noexcept
|
||||
{
|
||||
return _end - _beg;
|
||||
}
|
||||
|
||||
DbcsAttribute RowTextIterator::DbcsAttr() const noexcept
|
||||
{
|
||||
return Cols() == 2 ? DbcsAttribute::Leading : DbcsAttribute::Single;
|
||||
}
|
||||
|
||||
// Safety: col must be [0, _columnCount].
|
||||
uint16_t RowTextIterator::_uncheckedCharOffset(size_t col) const noexcept
|
||||
{
|
||||
assert(col <= _charOffsets.size());
|
||||
return til::at(_charOffsets, col) & CharOffsetsMask;
|
||||
}
|
||||
|
||||
// Safety: col must be [0, _columnCount].
|
||||
bool RowTextIterator::_uncheckedIsTrailer(size_t col) const noexcept
|
||||
{
|
||||
assert(col <= _charOffsets.size());
|
||||
return WI_IsFlagSet(til::at(_charOffsets, col), CharOffsetsTrailer);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - constructor
|
||||
// Arguments:
|
||||
@@ -128,6 +190,16 @@ LineRendition ROW::GetLineRendition() const noexcept
|
||||
return _lineRendition;
|
||||
}
|
||||
|
||||
RowTextIterator ROW::Begin() const noexcept
|
||||
{
|
||||
return { _chars, _charOffsets, 0 };
|
||||
}
|
||||
|
||||
RowTextIterator ROW::End() const noexcept
|
||||
{
|
||||
return { _chars, _charOffsets, _columnCount };
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets all properties of the ROW to default values
|
||||
// Arguments:
|
||||
@@ -229,6 +301,36 @@ void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& a
|
||||
_attr.resize_trailing_extent(gsl::narrow<uint16_t>(newWidth));
|
||||
}
|
||||
|
||||
til::CoordType ROW::NavigateToPrevious(til::CoordType column) const noexcept
|
||||
{
|
||||
return _adjustBackward(_clampedColumn(column - 1));
|
||||
}
|
||||
|
||||
til::CoordType ROW::NavigateToNext(til::CoordType column) const noexcept
|
||||
{
|
||||
return _adjustForward(_clampedColumn(column + 1));
|
||||
}
|
||||
|
||||
uint16_t ROW::_adjustBackward(uint16_t column) const noexcept
|
||||
{
|
||||
// Safety: This is a little bit more dangerous. The first column is supposed
|
||||
// to never be a trailer and so this loop should exit if column == 0.
|
||||
for (; _uncheckedIsTrailer(column); --column)
|
||||
{
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
uint16_t ROW::_adjustForward(uint16_t column) const noexcept
|
||||
{
|
||||
// Safety: This is a little bit more dangerous. The last column is supposed
|
||||
// to never be a trailer and so this loop should exit if column == _columnCount.
|
||||
for (; _uncheckedIsTrailer(column); ++column)
|
||||
{
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - clears char data in column in row
|
||||
// Arguments:
|
||||
@@ -375,90 +477,228 @@ void ROW::ReplaceAttributes(const til::CoordType beginIndex, const til::CoordTyp
|
||||
_attr.replace(_clampedColumnInclusive(beginIndex), _clampedColumnInclusive(endIndex), newAttr);
|
||||
}
|
||||
|
||||
void ROW::ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars)
|
||||
[[msvc::forceinline]] ROW::WriteHelper::WriteHelper(ROW& row, til::CoordType columnBegin, til::CoordType columnLimit, const std::wstring_view& chars) noexcept :
|
||||
row{ row },
|
||||
chars{ chars }
|
||||
{
|
||||
const auto colBeg = _clampedUint16(columnBegin);
|
||||
const auto colEnd = _clampedUint16(columnBegin + width);
|
||||
colBeg = row._clampedColumnInclusive(columnBegin);
|
||||
colLimit = row._clampedColumnInclusive(columnLimit);
|
||||
chExtBeg = row._uncheckedCharOffset(colBeg);
|
||||
colExtBeg = row._adjustBackward(colBeg);
|
||||
leadingSpaces = colBeg - colExtBeg;
|
||||
chBeg = chExtBeg + leadingSpaces;
|
||||
colEnd = colBeg;
|
||||
colExtEnd = 0;
|
||||
charsConsumed = 0;
|
||||
}
|
||||
|
||||
if (colBeg >= colEnd || colEnd > _columnCount || chars.empty())
|
||||
[[msvc::forceinline]] bool ROW::WriteHelper::IsValid() const noexcept
|
||||
{
|
||||
return colBeg < colLimit && !chars.empty();
|
||||
}
|
||||
|
||||
void ROW::ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars)
|
||||
try
|
||||
{
|
||||
WriteHelper h{ *this, columnBegin, _columnCount, chars };
|
||||
if (!h.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
h.ReplaceCharacters(width);
|
||||
h.Finish();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Due to this function writing _charOffsets first, then calling _resizeChars (which may throw) and only then finally
|
||||
// filling in _chars, we might end up in a situation were _charOffsets contains offsets outside of the _chars array.
|
||||
// --> Restore this row to a known "okay"-state.
|
||||
Reset(TextAttribute{});
|
||||
throw;
|
||||
}
|
||||
|
||||
// Safety:
|
||||
// * colBeg is now [0, _columnCount)
|
||||
// * colEnd is now (colBeg, _columnCount]
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::ReplaceCharacters(til::CoordType width) noexcept
|
||||
{
|
||||
const auto colEndNew = gsl::narrow_cast<uint16_t>(colEnd + width);
|
||||
if (colEndNew > colLimit)
|
||||
{
|
||||
colExtEnd = colLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
til::at(row._charOffsets, colEnd++) = chBeg;
|
||||
for (; colEnd < colEndNew; ++colEnd)
|
||||
{
|
||||
til::at(row._charOffsets, colEnd) = gsl::narrow_cast<uint16_t>(chBeg | CharOffsetsTrailer);
|
||||
}
|
||||
|
||||
// Algorithm explanation
|
||||
//
|
||||
// Task:
|
||||
// Replace the characters in cells [colBeg, colEnd) with a single `width`-wide glyph consisting of `chars`.
|
||||
//
|
||||
// Problem:
|
||||
// Imagine that we have the following ROW contents:
|
||||
// "xxyyzz"
|
||||
// xx, yy, zz are 2 cell wide glyphs. We want to insert a 2 cell wide glyph ww at colBeg 1:
|
||||
// ^^
|
||||
// ww
|
||||
// An incorrect result would be:
|
||||
// "xwwyzz"
|
||||
// The half cut off x and y glyph wouldn't make much sense, so we need to fill them with whitespace:
|
||||
// " ww zz"
|
||||
//
|
||||
// Solution:
|
||||
// Given the range we want to replace [colBeg, colEnd), we "extend" it to encompass leading (preceding)
|
||||
// and trailing wide glyphs we partially overwrite resulting in the range [colExtBeg, colExtEnd), where
|
||||
// colExtBeg <= colBeg and colExtEnd >= colEnd. In other words, the to be replaced range has been "extended".
|
||||
// The amount of leading whitespace we need to insert is thus colBeg - colExtBeg
|
||||
// and the amount of trailing whitespace colExtEnd - colEnd.
|
||||
colExtEnd = colEnd;
|
||||
charsConsumed = chars.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Extend range downwards (leading whitespace)
|
||||
uint16_t colExtBeg = colBeg;
|
||||
// Safety: colExtBeg is [0, _columnCount], because colBeg is.
|
||||
const uint16_t chExtBeg = _uncheckedCharOffset(colExtBeg);
|
||||
// Safety: colExtBeg remains [0, _columnCount] due to colExtBeg != 0.
|
||||
for (; colExtBeg != 0 && _uncheckedIsTrailer(colExtBeg); --colExtBeg)
|
||||
til::CoordType ROW::Write(til::CoordType columnBegin, til::CoordType columnLimit, std::wstring_view& chars)
|
||||
try
|
||||
{
|
||||
WriteHelper h{ *this, columnBegin, columnLimit, chars };
|
||||
if (!h.IsValid())
|
||||
{
|
||||
return h.colBeg;
|
||||
}
|
||||
h.Write();
|
||||
h.Finish();
|
||||
|
||||
chars = chars.substr(h.charsConsumed);
|
||||
return h.colExtEnd;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Reset(TextAttribute{});
|
||||
throw;
|
||||
}
|
||||
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::Write() noexcept
|
||||
{
|
||||
size_t ch = chBeg;
|
||||
|
||||
for (const auto& s : til::utf16_iterator{ chars })
|
||||
{
|
||||
const auto wide = til::at(s, 0) < 0x80 ? false : IsGlyphFullWidth(s);
|
||||
const auto colEndNew = gsl::narrow_cast<uint16_t>(colEnd + 1u + wide);
|
||||
if (colEndNew > colLimit)
|
||||
{
|
||||
colExtEnd = colLimit;
|
||||
break;
|
||||
}
|
||||
|
||||
til::at(row._charOffsets, colEnd++) = gsl::narrow_cast<uint16_t>(ch);
|
||||
if (wide)
|
||||
{
|
||||
til::at(row._charOffsets, colEnd++) = gsl::narrow_cast<uint16_t>(ch | CharOffsetsTrailer);
|
||||
}
|
||||
|
||||
colExtEnd = colEnd;
|
||||
ch += s.size();
|
||||
}
|
||||
|
||||
charsConsumed = ch - chBeg;
|
||||
}
|
||||
|
||||
til::CoordType ROW::CopyRangeFrom(til::CoordType columnBegin, til::CoordType columnLimit, const ROW& other, til::CoordType& otherBegin, til::CoordType otherLimit)
|
||||
try
|
||||
{
|
||||
const auto otherColBeg = other._clampedColumnInclusive(otherBegin);
|
||||
const auto otherColLimit = other._clampedColumnInclusive(otherLimit);
|
||||
std::span<uint16_t> charOffsets;
|
||||
std::wstring_view chars;
|
||||
|
||||
if (otherColBeg < otherColLimit)
|
||||
{
|
||||
charOffsets = other._charOffsets.subspan(otherColBeg, static_cast<size_t>(otherColLimit) - otherColBeg + 1);
|
||||
const auto charsOffset = charOffsets.front() & CharOffsetsMask;
|
||||
// _chars is a std::span (for performance and because it refers to raw, shared memory), whereas
|
||||
// chars is a std::wstring_view, because that's what we use everywhere else for sharing strings.
|
||||
// We can't trivially convert the two (C++ Committee be like: Having 2 span types is completely
|
||||
// reasonable and normal. Also, they're not convertible. Because fu.) so we do pointer stuff.
|
||||
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
chars = { other._chars.data() + charsOffset, other._chars.size() - charsOffset };
|
||||
}
|
||||
|
||||
WriteHelper h{ *this, columnBegin, columnLimit, chars };
|
||||
if (!h.IsValid())
|
||||
{
|
||||
return h.colBeg;
|
||||
}
|
||||
// Any valid charOffsets array is at least 2 elements long (the 1st element is the start offset and the 2nd
|
||||
// element is the length of the first glyph) and begins/ends with a non-trailer offset. We don't really
|
||||
// need to test for the end offset, since `WriteHelper::WriteWithOffsets` already takes care of that.
|
||||
if (charOffsets.size() < 2 || WI_IsFlagSet(charOffsets.front(), CharOffsetsTrailer) || WI_IsFlagSet(charOffsets.back(), CharOffsetsTrailer))
|
||||
{
|
||||
assert(false);
|
||||
otherBegin = other.size();
|
||||
return h.colBeg;
|
||||
}
|
||||
h.CopyRangeFrom(charOffsets);
|
||||
h.Finish();
|
||||
|
||||
otherBegin += h.colEnd - h.colBeg;
|
||||
return h.colExtEnd;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Reset(TextAttribute{});
|
||||
throw;
|
||||
}
|
||||
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::CopyRangeFrom(const std::span<const uint16_t>& charOffsets) noexcept
|
||||
{
|
||||
// Since our `charOffsets` input is already in columns (just like the `ROW::_charOffsets`),
|
||||
// we can directly look up the end char-offset, but...
|
||||
const auto colExtEndInput = std::min(gsl::narrow_cast<uint16_t>(colLimit - colBeg), gsl::narrow<uint16_t>(charOffsets.size() - 1));
|
||||
|
||||
// ...since the colLimit might intersect with a wide glyph in `charOffset`, we need to adjust our input-colEnd.
|
||||
auto colEndInput = colExtEndInput;
|
||||
for (; WI_IsFlagSet(til::at(charOffsets, colEndInput), CharOffsetsTrailer); --colEndInput)
|
||||
{
|
||||
}
|
||||
|
||||
// Extend range upwards (trailing whitespace)
|
||||
uint16_t colExtEnd = colEnd;
|
||||
// Safety: colExtEnd cannot be incremented past _columnCount, because the last
|
||||
// _charOffset at index _columnCount will never get the CharOffsetsTrailer flag.
|
||||
for (; _uncheckedIsTrailer(colExtEnd); ++colExtEnd)
|
||||
{
|
||||
}
|
||||
// Safety: After the previous loop colExtEnd is [0, _columnCount].
|
||||
const uint16_t chExtEnd = _uncheckedCharOffset(colExtEnd);
|
||||
const auto baseOffset = til::at(charOffsets, 0);
|
||||
const auto endOffset = til::at(charOffsets, colEndInput);
|
||||
const auto inToOutOffset = gsl::narrow_cast<uint16_t>(chBeg - baseOffset);
|
||||
|
||||
// Now with the `colEndInput` figured out, we can easily copy the `charOffsets` into the `_charOffsets`.
|
||||
// It's possible to use SIMD for this loop for extra perf gains. Something like this for SSE2 (~8x faster):
|
||||
// const auto in = _mm_loadu_si128(...);
|
||||
// const auto off = _mm_and_epi32(in, _mm_set1_epi16(CharOffsetsMask));
|
||||
// const auto trailer = _mm_and_epi32(in, _mm_set1_epi16(CharOffsetsTrailer));
|
||||
// const auto out = _mm_or_epi32(_mm_add_epi16(off, _mm_set1_epi16(inToOutOffset)), trailer);
|
||||
// _mm_store_si128(..., out);
|
||||
for (uint16_t i = 0; i < colEndInput; ++i, ++colEnd)
|
||||
{
|
||||
const auto ch = til::at(charOffsets, i);
|
||||
const auto off = ch & CharOffsetsMask;
|
||||
const auto trailer = ch & CharOffsetsTrailer;
|
||||
til::at(row._charOffsets, colEnd) = gsl::narrow_cast<uint16_t>((off + inToOutOffset) | trailer);
|
||||
}
|
||||
|
||||
colExtEnd = gsl::narrow_cast<uint16_t>(colExtEndInput + colBeg);
|
||||
charsConsumed = endOffset - baseOffset;
|
||||
}
|
||||
|
||||
[[msvc::forceinline]] void ROW::WriteHelper::Finish()
|
||||
{
|
||||
colExtEnd = row._adjustForward(colExtEnd);
|
||||
|
||||
const uint16_t leadingSpaces = colBeg - colExtBeg;
|
||||
const uint16_t trailingSpaces = colExtEnd - colEnd;
|
||||
const size_t chExtEndNew = chars.size() + leadingSpaces + trailingSpaces + chExtBeg;
|
||||
const uint16_t chExtEndOld = row._uncheckedCharOffset(colExtEnd);
|
||||
const size_t chExtEndNew = charsConsumed + leadingSpaces + trailingSpaces + chExtBeg;
|
||||
|
||||
if (chExtEndNew != chExtEnd)
|
||||
if (chExtEndNew != chExtEndOld)
|
||||
{
|
||||
_resizeChars(colExtEnd, chExtBeg, chExtEnd, chExtEndNew);
|
||||
row._resizeChars(colExtEnd, chExtBeg, chExtEndOld, chExtEndNew);
|
||||
}
|
||||
|
||||
// Add leading/trailing whitespace and copy chars
|
||||
{
|
||||
auto it = _chars.begin() + chExtBeg;
|
||||
auto it = row._chars.begin() + chExtBeg;
|
||||
it = fill_n_small(it, leadingSpaces, L' ');
|
||||
it = copy_n_small(chars.begin(), chars.size(), it);
|
||||
it = std::copy_n(chars.begin(), charsConsumed, it);
|
||||
it = fill_n_small(it, trailingSpaces, L' ');
|
||||
|
||||
iota_n(row._charOffsets.begin() + colExtBeg, leadingSpaces, chExtBeg);
|
||||
iota_n(row._charOffsets.begin() + colEnd, trailingSpaces, gsl::narrow_cast<uint16_t>(chBeg + charsConsumed));
|
||||
}
|
||||
// Update char offsets with leading/trailing whitespace and the chars columns.
|
||||
|
||||
// This updates `_doubleBytePadded` whenever we write the last column in the row. `_doubleBytePadded` tells our text
|
||||
// reflow algorithm whether it should ignore the last column. This is important when writing wide characters into
|
||||
// the terminal: If the last wide character in a row only fits partially, we should render whitespace, but
|
||||
// during text reflow pretend as if no whitespace exists. After all, the user didn't write any whitespace there.
|
||||
//
|
||||
// The way this is written, it'll set `_doubleBytePadded` to `true` no matter whether a wide character didn't fit,
|
||||
// or if the last 2 columns contain a wide character and a narrow character got written into the left half of it.
|
||||
// In both cases `trailingSpaces` is 1 and fills the last column and `_doubleBytePadded` will be `true`.
|
||||
if (colExtEnd == row._columnCount)
|
||||
{
|
||||
auto chPos = chExtBeg;
|
||||
auto it = _charOffsets.begin() + colExtBeg;
|
||||
|
||||
it = iota_n_mut(it, leadingSpaces, chPos);
|
||||
|
||||
*it++ = chPos;
|
||||
it = fill_small(it, _charOffsets.begin() + colEnd, gsl::narrow_cast<uint16_t>(chPos | CharOffsetsTrailer));
|
||||
chPos = gsl::narrow_cast<uint16_t>(chPos + chars.size());
|
||||
|
||||
it = iota_n_mut(it, trailingSpaces, chPos);
|
||||
row.SetDoubleBytePadded(colEnd < row._columnCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,15 +706,15 @@ void ROW::ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, co
|
||||
// as it reallocates the backing buffer and shifts the char offsets.
|
||||
// The parameters are difficult to explain, but their names are identical to
|
||||
// local variables in ReplaceCharacters() which I've attempted to document there.
|
||||
void ROW::_resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd, size_t chExtEndNew)
|
||||
void ROW::_resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEndOld, size_t chExtEndNew)
|
||||
{
|
||||
const auto diff = chExtEndNew - chExtEnd;
|
||||
const auto diff = chExtEndNew - chExtEndOld;
|
||||
const auto currentLength = _charSize();
|
||||
const auto newLength = currentLength + diff;
|
||||
|
||||
if (newLength <= _chars.size())
|
||||
{
|
||||
std::copy_n(_chars.begin() + chExtEnd, currentLength - chExtEnd, _chars.begin() + chExtEndNew);
|
||||
std::copy_n(_chars.begin() + chExtEndOld, currentLength - chExtEndOld, _chars.begin() + chExtEndNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -485,7 +725,7 @@ void ROW::_resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd,
|
||||
const std::span chars{ charsHeap.get(), newCapacity };
|
||||
|
||||
std::copy_n(_chars.begin(), chExtBeg, chars.begin());
|
||||
std::copy_n(_chars.begin() + chExtEnd, currentLength - chExtEnd, chars.begin() + chExtEndNew);
|
||||
std::copy_n(_chars.begin() + chExtEndOld, currentLength - chExtEndOld, chars.begin() + chExtEndNew);
|
||||
|
||||
_charsHeap = std::move(charsHeap);
|
||||
_chars = chars;
|
||||
@@ -499,6 +739,11 @@ void ROW::_resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd,
|
||||
}
|
||||
}
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() const noexcept
|
||||
{
|
||||
return _attr;
|
||||
@@ -681,11 +926,13 @@ uint16_t ROW::_charSize() const noexcept
|
||||
// Safety: col must be [0, _columnCount].
|
||||
uint16_t ROW::_uncheckedCharOffset(size_t col) const noexcept
|
||||
{
|
||||
assert(col < _charOffsets.size());
|
||||
return til::at(_charOffsets, col) & CharOffsetsMask;
|
||||
}
|
||||
|
||||
// Safety: col must be [0, _columnCount].
|
||||
bool ROW::_uncheckedIsTrailer(size_t col) const noexcept
|
||||
{
|
||||
assert(col < _charOffsets.size());
|
||||
return WI_IsFlagSet(til::at(_charOffsets, col), CharOffsetsTrailer);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ Revision History:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include <til/rle.h>
|
||||
|
||||
#include "LineRendition.hpp"
|
||||
@@ -37,6 +35,34 @@ enum class DelimiterClass
|
||||
RegularChar
|
||||
};
|
||||
|
||||
struct RowTextIterator
|
||||
{
|
||||
RowTextIterator(std::span<const wchar_t> chars, std::span<const uint16_t> charOffsets, uint16_t offset) noexcept;
|
||||
|
||||
bool operator==(const RowTextIterator& other) const noexcept;
|
||||
RowTextIterator& operator++() noexcept;
|
||||
const RowTextIterator& operator*() const noexcept;
|
||||
|
||||
std::wstring_view Text() const noexcept;
|
||||
til::CoordType Cols() const noexcept;
|
||||
DbcsAttribute DbcsAttr() const noexcept;
|
||||
|
||||
private:
|
||||
uint16_t _uncheckedCharOffset(size_t col) const noexcept;
|
||||
bool _uncheckedIsTrailer(size_t col) const noexcept;
|
||||
|
||||
// To simplify the detection of wide glyphs, we don't just store the simple character offset as described
|
||||
// for _charOffsets. Instead we use the most significant bit to indicate whether any column is the
|
||||
// trailing half of a wide glyph. This simplifies many implementation details via _uncheckedIsTrailer.
|
||||
static constexpr uint16_t CharOffsetsTrailer = 0x8000;
|
||||
static constexpr uint16_t CharOffsetsMask = 0x7fff;
|
||||
|
||||
std::span<const wchar_t> _chars;
|
||||
std::span<const uint16_t> _charOffsets;
|
||||
uint16_t _beg;
|
||||
uint16_t _end;
|
||||
};
|
||||
|
||||
class ROW final
|
||||
{
|
||||
public:
|
||||
@@ -57,17 +83,25 @@ public:
|
||||
bool WasDoubleBytePadded() const noexcept;
|
||||
void SetLineRendition(const LineRendition lineRendition) noexcept;
|
||||
LineRendition GetLineRendition() const noexcept;
|
||||
RowTextIterator Begin() const noexcept;
|
||||
RowTextIterator End() const noexcept;
|
||||
|
||||
void Reset(const TextAttribute& attr);
|
||||
void Resize(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute);
|
||||
void TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth);
|
||||
|
||||
til::CoordType NavigateToPrevious(til::CoordType column) const noexcept;
|
||||
til::CoordType NavigateToNext(til::CoordType column) const noexcept;
|
||||
|
||||
void ClearCell(til::CoordType column);
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, til::CoordType columnBegin, std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
bool SetAttrToEnd(til::CoordType columnBegin, TextAttribute attr);
|
||||
void ReplaceAttributes(til::CoordType beginIndex, til::CoordType endIndex, const TextAttribute& newAttr);
|
||||
void ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars);
|
||||
til::CoordType Write(til::CoordType columnBegin, til::CoordType columnLimit, std::wstring_view& chars);
|
||||
til::CoordType CopyRangeFrom(til::CoordType columnBegin, til::CoordType columnLimit, const ROW& other, til::CoordType& otherBegin, til::CoordType otherLimit);
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>& Attributes() noexcept;
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& Attributes() const noexcept;
|
||||
TextAttribute GetAttrByColumn(til::CoordType column) const;
|
||||
std::vector<uint16_t> GetHyperlinks() const;
|
||||
@@ -89,6 +123,30 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// WriteHelper exists because other forms of abstracting this functionality away (like templates with lambdas)
|
||||
// where only very poorly optimized by MSVC as it failed to inline the templates.
|
||||
struct WriteHelper
|
||||
{
|
||||
explicit WriteHelper(ROW& row, til::CoordType columnBegin, til::CoordType columnLimit, const std::wstring_view& chars) noexcept;
|
||||
bool IsValid() const noexcept;
|
||||
void ReplaceCharacters(til::CoordType width) noexcept;
|
||||
void Write() noexcept;
|
||||
void CopyRangeFrom(const std::span<const uint16_t>& charOffsets) noexcept;
|
||||
void Finish();
|
||||
|
||||
ROW& row;
|
||||
const std::wstring_view& chars;
|
||||
uint16_t colBeg;
|
||||
uint16_t colLimit;
|
||||
uint16_t chExtBeg;
|
||||
uint16_t colExtBeg;
|
||||
uint16_t leadingSpaces;
|
||||
uint16_t chBeg;
|
||||
uint16_t colEnd;
|
||||
uint16_t colExtEnd;
|
||||
size_t charsConsumed;
|
||||
};
|
||||
|
||||
// To simplify the detection of wide glyphs, we don't just store the simple character offset as described
|
||||
// for _charOffsets. Instead we use the most significant bit to indicate whether any column is the
|
||||
// trailing half of a wide glyph. This simplifies many implementation details via _uncheckedIsTrailer.
|
||||
@@ -102,13 +160,16 @@ private:
|
||||
template<typename T>
|
||||
constexpr uint16_t _clampedColumnInclusive(T v) const noexcept;
|
||||
|
||||
uint16_t _adjustBackward(uint16_t column) const noexcept;
|
||||
uint16_t _adjustForward(uint16_t column) const noexcept;
|
||||
|
||||
wchar_t _uncheckedChar(size_t off) const noexcept;
|
||||
uint16_t _charSize() const noexcept;
|
||||
uint16_t _uncheckedCharOffset(size_t col) const noexcept;
|
||||
bool _uncheckedIsTrailer(size_t col) const noexcept;
|
||||
|
||||
void _init() noexcept;
|
||||
void _resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd, size_t chExtEndNew);
|
||||
void _resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEndOld, size_t chExtEndNew);
|
||||
|
||||
// These fields are a bit "wasteful", but it makes all this a bit more robust against
|
||||
// programming errors during initial development (which is when this comment was written).
|
||||
|
||||
@@ -376,6 +376,25 @@ bool TextBuffer::_PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute
|
||||
return fSuccess;
|
||||
}
|
||||
|
||||
void TextBuffer::ConsumeGrapheme(std::wstring_view& chars) noexcept
|
||||
{
|
||||
// This function is supposed to mirror the behavior of ROW::Write, when it reads characters off of `chars`.
|
||||
// (I know that a UTF-16 code point is not a grapheme, but that's what we're working towards.)
|
||||
chars = til::utf16_pop(chars);
|
||||
}
|
||||
|
||||
til::CoordType TextBuffer::Write(til::CoordType row, til::CoordType columnBegin, til::CoordType columnLimit, bool wrapAtEOL, const TextAttribute& attributes, std::wstring_view& chars)
|
||||
{
|
||||
auto& r = GetRowByOffset(row);
|
||||
|
||||
const auto columnEnd = r.Write(columnBegin, columnLimit, chars);
|
||||
r.ReplaceAttributes(columnBegin, columnEnd, attributes);
|
||||
r.SetWrapForced(wrapAtEOL && columnEnd >= r.size());
|
||||
|
||||
TriggerRedraw(Viewport::FromExclusive({ columnBegin, row, columnEnd, row + 1 }));
|
||||
return columnEnd;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Writes cells to the output buffer. Writes at the cursor.
|
||||
// Arguments:
|
||||
@@ -901,6 +920,11 @@ void TextBuffer::SetCurrentLineRendition(const LineRendition lineRendition)
|
||||
}
|
||||
TriggerRedraw(Viewport::FromDimensions({ 0, rowIndex }, { GetSize().Width(), 1 }));
|
||||
}
|
||||
// There is some variation in how this was handled by the different DEC
|
||||
// terminals, but the STD 070 reference (on page D-13) makes it clear that
|
||||
// the delayed wrap (aka the Last Column Flag) was expected to be reset when
|
||||
// line rendition controls were executed.
|
||||
GetCursor().ResetDelayEOLWrap();
|
||||
}
|
||||
|
||||
void TextBuffer::ResetLineRenditionRange(const til::CoordType startRow, const til::CoordType endRow) noexcept
|
||||
|
||||
@@ -89,6 +89,9 @@ public:
|
||||
TextBufferTextIterator GetTextDataAt(const til::point at, const Microsoft::Console::Types::Viewport limit) const;
|
||||
|
||||
// Text insertion functions
|
||||
static void ConsumeGrapheme(std::wstring_view& chars) noexcept;
|
||||
til::CoordType Write(til::CoordType row, til::CoordType columnBegin, til::CoordType columnLimit, bool wrapAtEOL, const TextAttribute& attributes, std::wstring_view& chars);
|
||||
|
||||
OutputCellIterator Write(const OutputCellIterator givenIt);
|
||||
|
||||
OutputCellIterator Write(const OutputCellIterator givenIt,
|
||||
|
||||
@@ -98,6 +98,26 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
}
|
||||
}
|
||||
void _logCommands(winrt::Windows::Foundation::Collections::IVector<Command> commands, const int indentation = 1)
|
||||
{
|
||||
if (indentation == 1)
|
||||
{
|
||||
Log::Comment((commands.Size() == 0) ? L"Commands:\n <none>" : L"Commands:");
|
||||
}
|
||||
for (const auto& cmd : commands)
|
||||
{
|
||||
Log::Comment(fmt::format(L"{0:>{1}}* {2}",
|
||||
L"",
|
||||
indentation,
|
||||
cmd.Name())
|
||||
.c_str());
|
||||
|
||||
if (cmd.HasNestedCommands())
|
||||
{
|
||||
_logCommandNames(cmd.NestedCommands(), indentation + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void SettingsTests::TestIterateCommands()
|
||||
@@ -164,14 +184,15 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile0");
|
||||
auto command = expandedCommands.GetAt(0);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile0", command.Name());
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -189,7 +210,8 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile1");
|
||||
auto command = expandedCommands.GetAt(1);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile1", command.Name());
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -207,7 +229,8 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile2");
|
||||
auto command = expandedCommands.GetAt(2);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile2", command.Name());
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -287,14 +310,16 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"Split pane, profile: profile0");
|
||||
auto command = expandedCommands.GetAt(0);
|
||||
VERIFY_ARE_EQUAL(L"Split pane, profile: profile0", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -312,7 +337,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"Split pane, profile: profile1");
|
||||
auto command = expandedCommands.GetAt(1);
|
||||
VERIFY_ARE_EQUAL(L"Split pane, profile: profile1", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -330,7 +357,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"Split pane, profile: profile2");
|
||||
auto command = expandedCommands.GetAt(2);
|
||||
VERIFY_ARE_EQUAL(L"Split pane, profile: profile2", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -412,14 +441,16 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile0");
|
||||
auto command = expandedCommands.GetAt(0);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile0", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -437,7 +468,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile1\"");
|
||||
auto command = expandedCommands.GetAt(1);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile1\"", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -455,7 +488,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command profile2");
|
||||
auto command = expandedCommands.GetAt(2);
|
||||
VERIFY_ARE_EQUAL(L"iterable command profile2", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -527,14 +562,15 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
|
||||
auto rootCommand = expandedCommands.Lookup(L"Connect to ssh...");
|
||||
auto rootCommand = expandedCommands.GetAt(0);
|
||||
VERIFY_IS_NOT_NULL(rootCommand);
|
||||
VERIFY_ARE_EQUAL(L"Connect to ssh...", rootCommand.Name());
|
||||
auto rootActionAndArgs = rootCommand.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(rootActionAndArgs);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, rootActionAndArgs.Action());
|
||||
@@ -621,14 +657,16 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
|
||||
auto grandparentCommand = expandedCommands.Lookup(L"grandparent");
|
||||
auto grandparentCommand = expandedCommands.GetAt(0);
|
||||
VERIFY_IS_NOT_NULL(grandparentCommand);
|
||||
VERIFY_ARE_EQUAL(L"grandparent", grandparentCommand.Name());
|
||||
|
||||
auto grandparentActionAndArgs = grandparentCommand.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(grandparentActionAndArgs);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, grandparentActionAndArgs.Action());
|
||||
@@ -744,17 +782,22 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
for (auto name : std::vector<std::wstring>({ L"profile0", L"profile1", L"profile2" }))
|
||||
const std::vector<std::wstring> profileNames{ L"profile0", L"profile1", L"profile2" };
|
||||
for (auto i = 0u; i < profileNames.size(); i++)
|
||||
{
|
||||
winrt::hstring commandName{ name + L"..." };
|
||||
auto command = expandedCommands.Lookup(commandName);
|
||||
const auto& name{ profileNames[i] };
|
||||
winrt::hstring commandName{ profileNames[i] + L"..." };
|
||||
|
||||
auto command = expandedCommands.GetAt(i);
|
||||
VERIFY_ARE_EQUAL(commandName, command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -880,14 +923,16 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
|
||||
auto rootCommand = expandedCommands.Lookup(L"New Tab With Profile...");
|
||||
auto rootCommand = expandedCommands.GetAt(0);
|
||||
VERIFY_IS_NOT_NULL(rootCommand);
|
||||
VERIFY_ARE_EQUAL(L"New Tab With Profile...", rootCommand.Name());
|
||||
|
||||
auto rootActionAndArgs = rootCommand.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(rootActionAndArgs);
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::Invalid, rootActionAndArgs.Action());
|
||||
@@ -982,13 +1027,16 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings.Warnings().Size());
|
||||
VERIFY_ARE_EQUAL(1u, expandedCommands.Size());
|
||||
|
||||
auto rootCommand = expandedCommands.Lookup(L"New Pane...");
|
||||
auto rootCommand = expandedCommands.GetAt(0);
|
||||
VERIFY_IS_NOT_NULL(rootCommand);
|
||||
VERIFY_ARE_EQUAL(L"New Pane...", rootCommand.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(rootCommand);
|
||||
auto rootActionAndArgs = rootCommand.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(rootActionAndArgs);
|
||||
@@ -1205,8 +1253,8 @@ 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());
|
||||
const auto& expandedCommands{ settings.GlobalSettings().ActionMap().ExpandedCommands() };
|
||||
_logCommands(expandedCommands);
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, expandedCommands.Size());
|
||||
|
||||
@@ -1215,7 +1263,9 @@ namespace TerminalAppLocalTests
|
||||
// just easy tests to write.
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command Campbell");
|
||||
auto command = expandedCommands.GetAt(0);
|
||||
VERIFY_ARE_EQUAL(L"iterable command Campbell", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -1233,7 +1283,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command Campbell PowerShell");
|
||||
auto command = expandedCommands.GetAt(1);
|
||||
VERIFY_ARE_EQUAL(L"iterable command Campbell PowerShell", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
@@ -1251,7 +1303,9 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
|
||||
{
|
||||
auto command = expandedCommands.Lookup(L"iterable command Vintage");
|
||||
auto command = expandedCommands.GetAt(2);
|
||||
VERIFY_ARE_EQUAL(L"iterable command Vintage", command.Name());
|
||||
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
auto actionAndArgs = command.ActionAndArgs();
|
||||
VERIFY_IS_NOT_NULL(actionAndArgs);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "../TerminalApp/TerminalPage.h"
|
||||
#include "../TerminalApp/TerminalWindow.h"
|
||||
#include "../TerminalApp/MinMaxCloseControl.h"
|
||||
#include "../TerminalApp/TabRowControl.h"
|
||||
#include "../TerminalApp/ShortcutActionDispatch.h"
|
||||
@@ -110,6 +111,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<winrt::TerminalApp::implementation::WindowProperties> _windowProperties;
|
||||
};
|
||||
|
||||
template<typename TFunction>
|
||||
@@ -194,8 +196,11 @@ namespace TerminalAppLocalTests
|
||||
{
|
||||
winrt::com_ptr<winrt::TerminalApp::implementation::TerminalPage> page{ nullptr };
|
||||
|
||||
auto result = RunOnUIThread([&page]() {
|
||||
page = winrt::make_self<winrt::TerminalApp::implementation::TerminalPage>();
|
||||
_windowProperties = winrt::make_self<winrt::TerminalApp::implementation::WindowProperties>();
|
||||
winrt::TerminalApp::WindowProperties props = *_windowProperties;
|
||||
|
||||
auto result = RunOnUIThread([&page, props]() {
|
||||
page = winrt::make_self<winrt::TerminalApp::implementation::TerminalPage>(props);
|
||||
VERIFY_IS_NOT_NULL(page);
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
@@ -239,9 +244,11 @@ namespace TerminalAppLocalTests
|
||||
// it's weird.
|
||||
winrt::TerminalApp::TerminalPage projectedPage{ nullptr };
|
||||
|
||||
_windowProperties = winrt::make_self<winrt::TerminalApp::implementation::WindowProperties>();
|
||||
winrt::TerminalApp::WindowProperties props = *_windowProperties;
|
||||
Log::Comment(NoThrowString().Format(L"Construct the TerminalPage"));
|
||||
auto result = RunOnUIThread([&projectedPage, &page, initialSettings]() {
|
||||
projectedPage = winrt::TerminalApp::TerminalPage();
|
||||
auto result = RunOnUIThread([&projectedPage, &page, initialSettings, props]() {
|
||||
projectedPage = winrt::TerminalApp::TerminalPage(props);
|
||||
page.copy_from(winrt::get_self<winrt::TerminalApp::implementation::TerminalPage>(projectedPage));
|
||||
page->_settings = initialSettings;
|
||||
});
|
||||
@@ -1242,14 +1249,16 @@ 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());
|
||||
});
|
||||
|
||||
auto windowNameChanged = false;
|
||||
page->PropertyChanged([&page, &windowNameChanged](auto&&, const winrt::WUX::Data::PropertyChangedEventArgs& args) mutable {
|
||||
_windowProperties->PropertyChanged([&page, &windowNameChanged](auto&&, const winrt::WUX::Data::PropertyChangedEventArgs& args) mutable {
|
||||
if (args.PropertyName() == L"WindowNameForDisplay")
|
||||
{
|
||||
windowNameChanged = true;
|
||||
@@ -1260,7 +1269,7 @@ namespace TerminalAppLocalTests
|
||||
page->_RequestWindowRename(winrt::hstring{ L"Foo" });
|
||||
});
|
||||
TestOnUIThread([&]() {
|
||||
VERIFY_ARE_EQUAL(L"Foo", page->_WindowName);
|
||||
VERIFY_ARE_EQUAL(L"Foo", page->WindowProperties().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;
|
||||
@@ -658,6 +659,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
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.
|
||||
return winrt::make<Remoting::implementation::ProposeCommandlineResult>(false);
|
||||
}
|
||||
// If there's a valid ID returned, then let's try and find the peasant
|
||||
// that goes with it. Alternatively, if we were given a magic windowing
|
||||
// constant, we can use that to look up an appropriate peasant.
|
||||
@@ -687,6 +695,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 +737,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,6 +774,9 @@ 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;
|
||||
}
|
||||
}
|
||||
@@ -773,6 +791,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 +1055,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& windowInfo, const Remoting::CommandlineArgs& command) :
|
||||
_Id{ windowInfo.Id() ? windowInfo.Id().Value() : 0 }, // We'll use 0 as a sentinel, since no window will ever get to have that ID
|
||||
_WindowName{ windowInfo.WindowName() },
|
||||
_args{ command.Commandline() },
|
||||
_CurrentDirectory{ command.CurrentDirectory() } {};
|
||||
|
||||
WindowRequestedArgs(const winrt::hstring& window, const winrt::hstring& content, Windows::Foundation::IReference<Windows::Foundation::Rect> bounds) :
|
||||
_Id{ 0u },
|
||||
_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(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 windowInfo, CommandlineArgs command);
|
||||
|
||||
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,178 @@ 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.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)
|
||||
{
|
||||
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.
|
||||
|
||||
// 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>(false);
|
||||
}
|
||||
// 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.
|
||||
return winrt::make<ProposeCommandlineResult>(false);
|
||||
}
|
||||
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 +238,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 +277,75 @@ 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(const Remoting::WindowRequestedArgs& args)
|
||||
{
|
||||
auto p = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
if (givenID)
|
||||
// This will be false if the Id is 0, which is our sentinel for "no specific ID was requested"
|
||||
if (const auto id = args.Id())
|
||||
{
|
||||
p->AssignID(givenID.value());
|
||||
p->AssignID(id);
|
||||
}
|
||||
|
||||
// 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(const 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
|
||||
@@ -741,42 +379,16 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask the monarch to show a notification icon.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestShowNotificationIcon()
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestShowNotificationIcon();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask the monarch to hide its notification icon.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget WindowManager::RequestHideNotificationIcon()
|
||||
{
|
||||
auto strongThis{ get_strong() };
|
||||
co_await winrt::resume_background();
|
||||
_peasant.RequestHideNotificationIcon();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Ask the monarch to quit all windows.
|
||||
// Arguments:
|
||||
// - <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 +396,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return _monarch.DoesQuakeWindowExist();
|
||||
}
|
||||
|
||||
void WindowManager::UpdateActiveTabTitle(winrt::hstring title)
|
||||
void WindowManager::UpdateActiveTabTitle(const winrt::hstring& title, const 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 +413,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,65 +25,51 @@ 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(const Remoting::WindowRequestedArgs& args);
|
||||
|
||||
void ProposeCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
bool ShouldCreateWindow();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::Peasant CurrentWindow();
|
||||
bool IsMonarch();
|
||||
void SignalClose(const 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();
|
||||
|
||||
static winrt::fire_and_forget RequestQuitAll(Remoting::Peasant peasant);
|
||||
void UpdateActiveTabTitle(const winrt::hstring& title, const Remoting::Peasant& peasant);
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
|
||||
bool DoesQuakeWindowExist();
|
||||
|
||||
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
|
||||
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);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
|
||||
|
||||
private:
|
||||
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,36 @@ 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 UpdateActiveTabTitle(String title, Peasant p);
|
||||
static 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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
case ShortcutAction::SetColorScheme:
|
||||
case ShortcutAction::AdjustOpacity:
|
||||
case ShortcutAction::SendInput:
|
||||
{
|
||||
_RunRestorePreviews();
|
||||
break;
|
||||
@@ -140,6 +141,22 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
}
|
||||
|
||||
void TerminalPage::_PreviewSendInput(const Settings::Model::SendInputArgs& args)
|
||||
{
|
||||
const auto backup = _restorePreviewFuncs.empty();
|
||||
|
||||
_ApplyToActiveControls([&](const auto& control) {
|
||||
control.PreviewInput(args.Input());
|
||||
|
||||
if (backup)
|
||||
{
|
||||
_restorePreviewFuncs.emplace_back([=]() {
|
||||
// On dismiss:
|
||||
control.PreviewInput(L"");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
void TerminalPage::_PreviewAction(const Settings::Model::ActionAndArgs& args)
|
||||
{
|
||||
switch (args.Action())
|
||||
@@ -150,6 +167,9 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::AdjustOpacity:
|
||||
_PreviewAdjustOpacity(args.Args().try_as<AdjustOpacityArgs>());
|
||||
break;
|
||||
case ShortcutAction::SendInput:
|
||||
_PreviewSendInput(args.Args().try_as<SendInputArgs>());
|
||||
break;
|
||||
}
|
||||
|
||||
// GH#9818 Other ideas for actions that could be preview-able:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1131,6 +1122,35 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSelectCommand(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SelectCommandArgs>())
|
||||
{
|
||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||
control.SelectCommand(realArgs.Direction() == Settings::Model::SelectOutputDirection::Previous);
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
void TerminalPage::_HandleSelectOutput(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SelectOutputArgs>())
|
||||
{
|
||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||
control.SelectOutput(realArgs.Direction() == Settings::Model::SelectOutputDirection::Previous);
|
||||
});
|
||||
args.Handled(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
@@ -1161,6 +1181,32 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleSuggestions(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SuggestionsArgs>())
|
||||
{
|
||||
auto source = realArgs.Source();
|
||||
|
||||
switch (source)
|
||||
{
|
||||
case SuggestionsSource::CommandHistory:
|
||||
{
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
const auto context = control.CommandHistory();
|
||||
_OpenSuggestions(Command::HistoryToCommands(context.History(), context.CurrentCommandline(), false), SuggestionsMode::Palette);
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleColorSelection(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
||||
@@ -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,71 @@ 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();
|
||||
bool RequestsTrayIcon();
|
||||
|
||||
// -------------------------------- 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,30 @@ 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();
|
||||
|
||||
// Selected settings to expose
|
||||
Microsoft.Terminal.Settings.Model.Theme Theme { get; };
|
||||
Boolean IsolatedMode { get; };
|
||||
Boolean AllowHeadless { get; };
|
||||
Boolean RequestsTrayIcon { 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "ColorPickupFlyout.h"
|
||||
#include "ColorPickupFlyout.g.cpp"
|
||||
#include "winrt/Windows.UI.Xaml.Media.h"
|
||||
#include "winrt/Windows.UI.Xaml.Shapes.h"
|
||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
|
||||
@@ -225,15 +225,24 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_selectedCommandChanged(const IInspectable& /*sender*/,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
|
||||
{
|
||||
const auto currentlyVisible{ Visibility() == Visibility::Visible };
|
||||
|
||||
const auto selectedCommand = _filteredActionsView().SelectedItem();
|
||||
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
|
||||
if (_currentMode == CommandPaletteMode::TabSwitchMode)
|
||||
{
|
||||
_switchToTab(filteredCommand);
|
||||
}
|
||||
else if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand != nullptr)
|
||||
else if (_currentMode == CommandPaletteMode::ActionMode &&
|
||||
currentlyVisible)
|
||||
{
|
||||
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
|
||||
// If we don't have a selected command, then end any previews we
|
||||
// might currently be showing.
|
||||
if (filteredCommand == nullptr)
|
||||
{
|
||||
_PreviewActionHandlers(*this, nullptr);
|
||||
}
|
||||
else if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
|
||||
{
|
||||
_PreviewActionHandlers(*this, actionPaletteItem.Command());
|
||||
}
|
||||
@@ -1083,7 +1092,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
std::copy(begin(commandsToFilter), end(commandsToFilter), std::back_inserter(actions));
|
||||
}
|
||||
else if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::CommandlineMode)
|
||||
else if (_currentMode == CommandPaletteMode::TabSearchMode ||
|
||||
_currentMode == CommandPaletteMode::ActionMode ||
|
||||
_currentMode == CommandPaletteMode::CommandlineMode)
|
||||
{
|
||||
for (const auto& action : commandsToFilter)
|
||||
{
|
||||
|
||||
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 };
|
||||
|
||||
@@ -205,6 +205,15 @@
|
||||
<data name="TabClose" xml:space="preserve">
|
||||
<value>Close Tab</value>
|
||||
</data>
|
||||
<data name="PaneClose" xml:space="preserve">
|
||||
<value>Close Pane</value>
|
||||
</data>
|
||||
<data name="SplitTabText" xml:space="preserve">
|
||||
<value>Split Tab</value>
|
||||
</data>
|
||||
<data name="SplitPaneText" xml:space="preserve">
|
||||
<value>Split Pane</value>
|
||||
</data>
|
||||
<data name="TabColorChoose" xml:space="preserve">
|
||||
<value>Color...</value>
|
||||
</data>
|
||||
@@ -708,9 +717,6 @@
|
||||
<data name="DropPathTabRun.Text" xml:space="preserve">
|
||||
<value>Open a new tab in given starting directory</value>
|
||||
</data>
|
||||
<data name="SplitTabText" xml:space="preserve">
|
||||
<value>Split Tab</value>
|
||||
</data>
|
||||
<data name="DropPathTabNewWindow.Text" xml:space="preserve">
|
||||
<value>Open a new window with given starting directory</value>
|
||||
</data>
|
||||
@@ -795,4 +801,4 @@
|
||||
<data name="NewTabMenuFolderEmpty" xml:space="preserve">
|
||||
<value>Empty...</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
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,
|
||||
winrt::hstring exceptionText,
|
||||
winrt::Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> warnings,
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings newSettings) :
|
||||
_Reload{ reload },
|
||||
_Result{ result },
|
||||
_ExceptionText{ std::move(exceptionText) },
|
||||
_Warnings{ std::move(warnings) },
|
||||
_NewSettings{ std::move(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;
|
||||
|
||||
1167
src/cascadia/TerminalApp/SuggestionsControl.cpp
Normal file
1167
src/cascadia/TerminalApp/SuggestionsControl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
137
src/cascadia/TerminalApp/SuggestionsControl.h
Normal file
137
src/cascadia/TerminalApp/SuggestionsControl.h
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FilteredCommand.h"
|
||||
#include "SuggestionsControl.g.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
class TabTests;
|
||||
};
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SuggestionsControl : SuggestionsControlT<SuggestionsControl>
|
||||
{
|
||||
SuggestionsControl();
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
|
||||
|
||||
void SetCommands(const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command>& actions);
|
||||
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void SelectNextItem(const bool moveDown);
|
||||
|
||||
void ScrollPageUp();
|
||||
void ScrollPageDown();
|
||||
void ScrollToTop();
|
||||
void ScrollToBottom();
|
||||
|
||||
Windows::UI::Xaml::FrameworkElement SelectedItem();
|
||||
|
||||
TerminalApp::SuggestionsMode Mode() const;
|
||||
void Mode(TerminalApp::SuggestionsMode mode);
|
||||
void Anchor(Windows::Foundation::Point anchor, Windows::Foundation::Size space, float characterHeight);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
|
||||
|
||||
TYPED_EVENT(SwitchToTabRequested, winrt::TerminalApp::SuggestionsControl, winrt::TerminalApp::TabBase);
|
||||
TYPED_EVENT(CommandLineExecutionRequested, winrt::TerminalApp::SuggestionsControl, winrt::hstring);
|
||||
TYPED_EVENT(DispatchCommandRequested, winrt::TerminalApp::SuggestionsControl, Microsoft::Terminal::Settings::Model::Command);
|
||||
TYPED_EVENT(PreviewAction, Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command);
|
||||
|
||||
private:
|
||||
friend struct SuggestionsControlT<SuggestionsControl>; // for Xaml to bind events
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _allCommands{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _currentNestedCommands{ nullptr };
|
||||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> _filteredActions{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _nestedActionStack{ nullptr };
|
||||
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandsToFilter();
|
||||
|
||||
TerminalApp::SuggestionsMode _mode{ TerminalApp::SuggestionsMode::Palette };
|
||||
TerminalApp::SuggestionsDirection _direction{ TerminalApp::SuggestionsDirection::TopDown };
|
||||
|
||||
bool _lastFilterTextWasEmpty{ true };
|
||||
Windows::Foundation::Point _anchor;
|
||||
Windows::Foundation::Size _space;
|
||||
|
||||
void _filterTextChanged(const Windows::Foundation::IInspectable& sender,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void _previewKeyDownHandler(const Windows::Foundation::IInspectable& sender,
|
||||
const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
|
||||
void _keyUpHandler(const Windows::Foundation::IInspectable& sender,
|
||||
const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
|
||||
winrt::fire_and_forget _selectedCommandChanged(const Windows::Foundation::IInspectable& sender,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
void _updateUIForStackChange();
|
||||
|
||||
void _rootPointerPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
|
||||
void _lostFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
void _backdropPointerPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
|
||||
void _listItemClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::ItemClickEventArgs& e);
|
||||
|
||||
void _listItemSelectionChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& e);
|
||||
|
||||
void _moveBackButtonClicked(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs&);
|
||||
|
||||
void _updateFilteredActions();
|
||||
|
||||
void _updateCurrentNestedCommands(const winrt::Microsoft::Terminal::Settings::Model::Command& parentCommand);
|
||||
|
||||
std::vector<winrt::TerminalApp::FilteredCommand> _collectFilteredActions();
|
||||
|
||||
void _close();
|
||||
|
||||
void _switchToMode();
|
||||
|
||||
void _setDirection(TerminalApp::SuggestionsDirection direction);
|
||||
|
||||
std::wstring _getTrimmedInput();
|
||||
|
||||
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker;
|
||||
|
||||
void _dispatchCommand(const winrt::TerminalApp::FilteredCommand& command);
|
||||
static std::optional<winrt::TerminalApp::FilteredCommand> _buildCommandLineCommand(const winrt::hstring& commandLine);
|
||||
|
||||
void _dismissPalette();
|
||||
|
||||
void _scrollToIndex(uint32_t index);
|
||||
uint32_t _getNumVisibleItems();
|
||||
|
||||
winrt::fire_and_forget _openTooltip(Microsoft::Terminal::Settings::Model::Command cmd);
|
||||
|
||||
void _choosingItemContainer(const Windows::UI::Xaml::Controls::ListViewBase& sender, const Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs& args);
|
||||
void _containerContentChanging(const Windows::UI::Xaml::Controls::ListViewBase& sender, const Windows::UI::Xaml::Controls::ContainerContentChangingEventArgs& args);
|
||||
winrt::TerminalApp::PaletteItemTemplateSelector _itemTemplateSelector{ nullptr };
|
||||
std::unordered_map<Windows::UI::Xaml::DataTemplate, std::unordered_set<Windows::UI::Xaml::Controls::Primitives::SelectorItem>> _listViewItemsCache;
|
||||
Windows::UI::Xaml::DataTemplate _listItemTemplate;
|
||||
|
||||
friend class TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(SuggestionsControl);
|
||||
}
|
||||
49
src/cascadia/TerminalApp/SuggestionsControl.idl
Normal file
49
src/cascadia/TerminalApp/SuggestionsControl.idl
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TabBase.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "HighlightedTextControl.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
|
||||
enum SuggestionsMode
|
||||
{
|
||||
Palette = 0,
|
||||
Menu,
|
||||
// Inline,
|
||||
};
|
||||
|
||||
enum SuggestionsDirection {
|
||||
TopDown,
|
||||
BottomUp
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SuggestionsControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
{
|
||||
SuggestionsControl();
|
||||
|
||||
String NoMatchesText { get; };
|
||||
String SearchBoxPlaceholderText { get; };
|
||||
String ControlName { get; };
|
||||
String ParentCommandName { get; };
|
||||
String ParsedCommandLineText { get; };
|
||||
|
||||
Windows.UI.Xaml.FrameworkElement SelectedItem { get; };
|
||||
|
||||
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
|
||||
|
||||
SuggestionsMode Mode { get; set; };
|
||||
|
||||
void SetCommands(Windows.Foundation.Collections.IVector<Microsoft.Terminal.Settings.Model.Command> actions);
|
||||
void SetActionMap(Microsoft.Terminal.Settings.Model.IActionMapView actionMap);
|
||||
void SelectNextItem(Boolean moveDown);
|
||||
|
||||
void Anchor(Windows.Foundation.Point anchor, Windows.Foundation.Size space, Single characterHeight);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<SuggestionsControl, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Command> PreviewAction;
|
||||
}
|
||||
}
|
||||
339
src/cascadia/TerminalApp/SuggestionsControl.xaml
Normal file
339
src/cascadia/TerminalApp/SuggestionsControl.xaml
Normal file
@@ -0,0 +1,339 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="TerminalApp.SuggestionsControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:SettingsModel="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
AllowFocusOnInteraction="True"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||
IsTabStop="True"
|
||||
LostFocus="_lostFocusHandler"
|
||||
PointerPressed="_rootPointerPressed"
|
||||
PreviewKeyDown="_previewKeyDownHandler"
|
||||
PreviewKeyUp="_keyUpHandler"
|
||||
TabNavigation="Cycle"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<!-- This creates an instance of our CommandKeyChordVisibilityConverter we can reference below -->
|
||||
<local:EmptyStringVisibilityConverter x:Key="CommandKeyChordVisibilityConverter" />
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParsedCommandLineTextVisibilityConverter" />
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter" />
|
||||
<model:IconPathConverter x:Key="IconSourceConverter" />
|
||||
|
||||
<DataTemplate x:Key="ListItemTemplate"
|
||||
x:DataType="local:FilteredCommand">
|
||||
<ListViewItem Height="32"
|
||||
MinHeight="0"
|
||||
Padding="16,0,12,0"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}"
|
||||
FontSize="12" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="GeneralItemTemplate"
|
||||
x:DataType="local:FilteredCommand">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16" />
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- key chord -->
|
||||
<ColumnDefinition Width="16" />
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentPresenter Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
|
||||
|
||||
<local:HighlightedTextControl Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}" />
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="NestedItemTemplate"
|
||||
x:DataType="local:FilteredCommand">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16" />
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*" />
|
||||
<!-- key chord -->
|
||||
<ColumnDefinition Width="16" />
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentPresenter Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
|
||||
|
||||
<local:HighlightedTextControl Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}" />
|
||||
|
||||
<!--
|
||||
The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
it already did that because it was the list item's
|
||||
"AcceleratorKey". It's redundant.
|
||||
-->
|
||||
<Border Grid.Column="2"
|
||||
Padding="2,0,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Visibility="{x:Bind Item.KeyChordText, Mode=OneWay, Converter={StaticResource CommandKeyChordVisibilityConverter}}">
|
||||
|
||||
<TextBlock AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="12"
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}" />
|
||||
</Border>
|
||||
|
||||
<FontIcon Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<local:PaletteItemTemplateSelector x:Key="PaletteItemTemplateSelector"
|
||||
GeneralItemTemplate="{StaticResource GeneralItemTemplate}"
|
||||
NestedItemTemplate="{StaticResource NestedItemTemplate}" />
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
|
||||
<!-- KeyChordText styles -->
|
||||
<Style x:Key="KeyChordBorderStyle"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="KeyChordTextBlockStyle"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- ParsedCommandLineText styles -->
|
||||
<Style x:Key="ParsedCommandLineBorderStyle"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
|
||||
<!-- KeyChordText styles -->
|
||||
<Style x:Key="KeyChordBorderStyle"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="KeyChordTextBlockStyle"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- ParsedCommandLineText styles -->
|
||||
<Style x:Key="ParsedCommandLineBorderStyle"
|
||||
TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
|
||||
<!-- KeyChordText styles (use XAML defaults for High Contrast theme) -->
|
||||
<Style x:Key="KeyChordBorderStyle"
|
||||
TargetType="Border" />
|
||||
<Style x:Key="KeyChordTextBlockStyle"
|
||||
TargetType="TextBlock" />
|
||||
|
||||
<!-- ParsedCommandLineText styles (use XAML defaults for High Contrast theme) -->
|
||||
<Style x:Key="ParsedCommandLineBorderStyle"
|
||||
TargetType="Border" />
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle"
|
||||
TargetType="TextBlock" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="6*" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="8*" />
|
||||
<RowDefinition Height="2*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid x:Name="_backdrop"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
MaxWidth="300"
|
||||
MaxHeight="300"
|
||||
Margin="0"
|
||||
Padding="0,8,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{ThemeResource FlyoutPresenterBackground}"
|
||||
BorderBrush="{ThemeResource FlyoutBorderThemeBrush}"
|
||||
BorderThickness="{ThemeResource FlyoutBorderThemeThickness}"
|
||||
CornerRadius="{ThemeResource OverlayCornerRadius}"
|
||||
PointerPressed="_backdropPointerPressed"
|
||||
Shadow="{StaticResource SharedShadow}"
|
||||
Translation="0,0,32">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Top-down _searchBox -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Top-down ParentCommandName -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Top-down UNUSED???????? -->
|
||||
<RowDefinition Height="*" />
|
||||
<!-- _filteredActionsView -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- bottom-up _searchBox -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBox x:Name="_searchBox"
|
||||
Grid.Row="0"
|
||||
Margin="8,0,8,8"
|
||||
Padding="18,8,8,8"
|
||||
IsSpellCheckEnabled="False"
|
||||
PlaceholderText="{x:Bind SearchBoxPlaceholderText, Mode=OneWay}"
|
||||
Text=""
|
||||
TextChanged="_filterTextChanged"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
Orientation="Horizontal"
|
||||
Visibility="{x:Bind ParentCommandName, Mode=OneWay, Converter={StaticResource ParentCommandVisibilityConverter}}">
|
||||
|
||||
<Button x:Name="_parentCommandBackButton"
|
||||
x:Uid="ParentCommandBackButton"
|
||||
VerticalAlignment="Center"
|
||||
Click="_moveBackButtonClicked"
|
||||
ClickMode="Press">
|
||||
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
FontSize="11"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
|
||||
<TextBlock x:Name="_parentCommandText"
|
||||
Padding="16,4"
|
||||
VerticalAlignment="Center"
|
||||
FontStyle="Italic"
|
||||
Text="{x:Bind ParentCommandName, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<Border Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
Padding="16,12"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Style="{ThemeResource ParsedCommandLineBorderStyle}"
|
||||
Visibility="{x:Bind ParsedCommandLineText, Mode=OneWay, Converter={StaticResource ParsedCommandLineTextVisibilityConverter}}">
|
||||
|
||||
<ScrollViewer MaxHeight="200"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock FontStyle="Italic"
|
||||
Text="{x:Bind ParsedCommandLineText, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<Border x:Name="_noMatchesText"
|
||||
Grid.Row="3"
|
||||
Height="36"
|
||||
Margin="8,0,8,8"
|
||||
Visibility="Collapsed">
|
||||
<TextBlock Padding="12,0"
|
||||
VerticalAlignment="Center"
|
||||
FontStyle="Italic"
|
||||
Text="{x:Bind NoMatchesText, Mode=OneWay}" />
|
||||
</Border>
|
||||
|
||||
<ListView x:Name="_filteredActionsView"
|
||||
Grid.Row="3"
|
||||
Padding="4,-2,4,6"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AllowDrop="False"
|
||||
CanReorderItems="False"
|
||||
ChoosingItemContainer="_choosingItemContainer"
|
||||
ContainerContentChanging="_containerContentChanging"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="_listItemClicked"
|
||||
ItemsSource="{x:Bind FilteredActions}"
|
||||
SelectionChanged="_listItemSelectionChanged"
|
||||
SelectionMode="Single" />
|
||||
<mux:TeachingTip x:Name="DescriptionTip"
|
||||
Title=""
|
||||
IsOpen="False"
|
||||
PreferredPlacement="Right"
|
||||
ShouldConstrainToRootBounds="False"
|
||||
Subtitle="">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
|
||||
HorizontalScrollMode="Enabled">
|
||||
<TextBlock x:Name="_toolTipContent" />
|
||||
</ScrollViewer>
|
||||
</mux:TeachingTip>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -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,13 +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)
|
||||
{
|
||||
auto state = ApplicationState::SharedInstance();
|
||||
state.PersistedWindowLayouts(nullptr);
|
||||
}
|
||||
|
||||
_LastTabClosedHandlers(*this, nullptr);
|
||||
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
|
||||
}
|
||||
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
|
||||
{
|
||||
@@ -709,7 +708,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);
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
<Page Include="CommandPalette.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="SuggestionsControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -138,7 +141,19 @@
|
||||
<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" />
|
||||
<ClInclude Include="SuggestionsControl.h">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -231,8 +246,17 @@
|
||||
<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" />
|
||||
<ClCompile Include="SuggestionsControl.cpp">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -252,6 +276,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>
|
||||
@@ -292,6 +317,10 @@
|
||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="SuggestionsControl.idl">
|
||||
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="FilteredCommand.idl" />
|
||||
<Midl Include="EmptyStringVisibilityConverter.idl" />
|
||||
</ItemGroup>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,10 @@
|
||||
#include "TerminalTab.h"
|
||||
#include "AppKeyBindings.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "LastTabClosedEventArgs.g.h"
|
||||
#include "RenameWindowRequestedArgs.g.h"
|
||||
#include "RequestMoveContentArgs.g.h"
|
||||
#include "RequestReceiveContentArgs.g.h"
|
||||
#include "Toast.h"
|
||||
|
||||
#define DECLARE_ACTION_HANDLER(action) void _Handle##action(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
@@ -41,6 +44,15 @@ namespace winrt::TerminalApp::implementation
|
||||
ScrollDown = 1
|
||||
};
|
||||
|
||||
struct LastTabClosedEventArgs : LastTabClosedEventArgsT<LastTabClosedEventArgs>
|
||||
{
|
||||
WINRT_PROPERTY(bool, ClearPersistedState);
|
||||
|
||||
public:
|
||||
LastTabClosedEventArgs(const bool& shouldClear) :
|
||||
_ClearPersistedState{ shouldClear } {};
|
||||
};
|
||||
|
||||
struct RenameWindowRequestedArgs : RenameWindowRequestedArgsT<RenameWindowRequestedArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, ProposedName);
|
||||
@@ -50,10 +62,37 @@ 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(TerminalApp::WindowProperties properties, 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
|
||||
@@ -63,11 +102,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
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 +153,8 @@ 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);
|
||||
TerminalApp::WindowProperties WindowProperties() const noexcept { return _WindowProperties; };
|
||||
|
||||
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 +162,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
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,10 +222,8 @@ 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 };
|
||||
|
||||
bool _maintainStateOnTabClose{ false };
|
||||
bool _rearranging{ false };
|
||||
@@ -230,7 +258,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::WindowProperties _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 +311,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 +335,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 +427,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,
|
||||
@@ -429,6 +466,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void _RunRestorePreviews();
|
||||
void _PreviewColorScheme(const Microsoft::Terminal::Settings::Model::SetColorSchemeArgs& args);
|
||||
void _PreviewAdjustOpacity(const Microsoft::Terminal::Settings::Model::AdjustOpacityArgs& args);
|
||||
void _PreviewSendInput(const Microsoft::Terminal::Settings::Model::SendInputArgs& args);
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs _lastPreviewedAction{ nullptr };
|
||||
std::vector<std::function<void()>> _restorePreviewFuncs{};
|
||||
|
||||
@@ -459,8 +498,29 @@ 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 _ControlMenuChangedHandler(const winrt::Windows::Foundation::IInspectable sender, const winrt::Microsoft::Terminal::Control::MenuChangedEventArgs args);
|
||||
winrt::fire_and_forget _OpenSuggestions(Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::Command> commandsCollection, winrt::TerminalApp::SuggestionsMode mode);
|
||||
|
||||
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
winrt::fire_and_forget _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& 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);
|
||||
|
||||
void _ContextMenuOpened(const IInspectable& sender, const IInspectable& args);
|
||||
void _SelectionMenuOpened(const IInspectable& sender, const IInspectable& args);
|
||||
void _PopulateContextMenu(const IInspectable& sender, const bool withSelection);
|
||||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
@@ -477,4 +537,5 @@ namespace winrt::TerminalApp::implementation
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(TerminalPage);
|
||||
BASIC_FACTORY(RequestReceiveContentArgs);
|
||||
}
|
||||
|
||||
@@ -5,21 +5,60 @@ import "IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
delegate void LastTabClosedEventArgs();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass LastTabClosedEventArgs
|
||||
{
|
||||
Boolean ClearPersistedState { get; };
|
||||
};
|
||||
|
||||
[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);
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass WindowProperties : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
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(WindowProperties properties, ContentManager manager);
|
||||
|
||||
// XAML bound properties
|
||||
String ApplicationDisplayName { get; };
|
||||
@@ -29,13 +68,9 @@ namespace TerminalApp
|
||||
Boolean Fullscreen { get; };
|
||||
Boolean AlwaysOnTop { get; };
|
||||
|
||||
WindowProperties 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 +80,11 @@ 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);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
|
||||
@@ -59,10 +96,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,16 +195,23 @@
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<local:SuggestionsControl x:Name="SuggestionsUI"
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<!--
|
||||
A TeachingTip with IsLightDismissEnabled="True" will immediately
|
||||
dismiss itself if the window is unfocused (In Xaml Islands). This is
|
||||
tracked by MUX#4382
|
||||
-->
|
||||
<mux:TeachingTip x:Name="WindowIdToast"
|
||||
Title="{x:Bind WindowIdForDisplay}"
|
||||
Title="{x:Bind WindowProperties.WindowIdForDisplay}"
|
||||
x:Load="False"
|
||||
IsLightDismissEnabled="True"
|
||||
Subtitle="{x:Bind WindowNameForDisplay, Mode=OneWay}" />
|
||||
Subtitle="{x:Bind WindowProperties.WindowNameForDisplay, Mode=OneWay}" />
|
||||
|
||||
<mux:TeachingTip x:Name="RenameFailedToast"
|
||||
x:Uid="RenameFailedToast"
|
||||
@@ -213,7 +220,7 @@
|
||||
|
||||
<mux:TeachingTip x:Name="WindowRenamer"
|
||||
x:Uid="WindowRenamer"
|
||||
Title="{x:Bind WindowIdForDisplay}"
|
||||
Title="{x:Bind WindowProperties.WindowIdForDisplay}"
|
||||
x:Load="False"
|
||||
ActionButtonClick="_WindowRenamerActionClick"
|
||||
ActionButtonStyle="{ThemeResource AccentButtonStyle}"
|
||||
@@ -222,7 +229,7 @@
|
||||
<TextBox x:Name="WindowRenamerTextBox"
|
||||
KeyDown="_WindowRenamerKeyDown"
|
||||
KeyUp="_WindowRenamerKeyUp"
|
||||
Text="{x:Bind WindowName, Mode=OneWay}" />
|
||||
Text="{x:Bind WindowProperties.WindowName, Mode=OneWay}" />
|
||||
</mux:TeachingTip.Content>
|
||||
</mux:TeachingTip>
|
||||
</Grid>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
1372
src/cascadia/TerminalApp/TerminalWindow.cpp
Normal file
1372
src/cascadia/TerminalApp/TerminalWindow.cpp
Normal file
File diff suppressed because it is too large
Load Diff
238
src/cascadia/TerminalApp/TerminalWindow.h
Normal file
238
src/cascadia/TerminalApp/TerminalWindow.h
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TerminalWindow.g.h"
|
||||
#include "SystemMenuChangeArgs.g.h"
|
||||
#include "WindowProperties.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 WindowProperties : WindowPropertiesT<WindowProperties>
|
||||
{
|
||||
// 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;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
private:
|
||||
winrt::hstring _WindowName{};
|
||||
uint64_t _WindowId{ 0 };
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
void SetPersistedLayoutIdx(const uint32_t idx);
|
||||
void SetNumberOfOpenWindows(const uint64_t num);
|
||||
bool ShouldUsePersistedLayout() const;
|
||||
void ClearPersistedWindowState();
|
||||
|
||||
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, const bool isLastWindow);
|
||||
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();
|
||||
|
||||
Microsoft::Terminal::Settings::Model::Theme Theme();
|
||||
void UpdateSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::SettingsLoadEventArgs& arg);
|
||||
|
||||
void WindowName(const winrt::hstring& value);
|
||||
void WindowId(const uint64_t& value);
|
||||
|
||||
bool IsQuakeWindow() const noexcept { return _WindowProperties->IsQuakeWindow(); }
|
||||
TerminalApp::WindowProperties WindowProperties() { return *_WindowProperties; }
|
||||
|
||||
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::com_ptr<TerminalApp::implementation::WindowProperties> _WindowProperties{ nullptr };
|
||||
|
||||
std::optional<uint32_t> _loadFromPersistedLayoutIdx{};
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::WindowLayout> _cachedLayout{ std::nullopt };
|
||||
|
||||
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);
|
||||
}
|
||||
147
src/cascadia/TerminalApp/TerminalWindow.idl
Normal file
147
src/cascadia/TerminalApp/TerminalWindow.idl
Normal file
@@ -0,0 +1,147 @@
|
||||
// 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, 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 ClearPersistedWindowState();
|
||||
|
||||
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, Boolean isLastWindow);
|
||||
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 GetShowTitleInTitlebar();
|
||||
|
||||
// These already have accessors as a part of IWindowProperties, but we
|
||||
// also want to be able to set them.
|
||||
WindowProperties WindowProperties { get; };
|
||||
void WindowName(String name);
|
||||
void WindowId(UInt64 id);
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
2399
src/cascadia/TerminalControl/BlockContent.cpp
Normal file
2399
src/cascadia/TerminalControl/BlockContent.cpp
Normal file
File diff suppressed because it is too large
Load Diff
379
src/cascadia/TerminalControl/BlockContent.h
Normal file
379
src/cascadia/TerminalControl/BlockContent.h
Normal file
@@ -0,0 +1,379 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Module Name:
|
||||
// - BlockContent.h
|
||||
//
|
||||
// Abstract:
|
||||
// - This encapsulates a `Terminal` instance, a `DxEngine` and `Renderer`, and
|
||||
// an `ITerminalConnection`. This is intended to be everything that someone
|
||||
// might need to stand up a terminal instance in a control, but without any
|
||||
// regard for how the UX works.
|
||||
//
|
||||
// Author:
|
||||
// - Mike Griese (zadjii-msft) 01-Apr-2021
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockContent.g.h"
|
||||
|
||||
#include "ControlSettings.h"
|
||||
#include "../../audio/midi/MidiAudio.hpp"
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../buffer/out/search.h"
|
||||
#include "../buffer/out/TextColor.h"
|
||||
|
||||
#include <til/ticket_lock.h>
|
||||
|
||||
namespace ControlUnitTests
|
||||
{
|
||||
// class BlockContentTests;
|
||||
class ControlInteractivityTests;
|
||||
};
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
struct BlockContent : BlockContentT<BlockContent>
|
||||
{
|
||||
public:
|
||||
BlockContent(Control::IControlSettings settings,
|
||||
TerminalConnection::ITerminalConnection connection);
|
||||
~BlockContent();
|
||||
|
||||
bool Initialize(const double actualWidth,
|
||||
const double actualHeight,
|
||||
const double compositionScale);
|
||||
void EnablePainting();
|
||||
|
||||
Control::IControlSettings Settings() { return *_settings; };
|
||||
Control::IControlAppearance FocusedAppearance() const { return *_settings->FocusedAppearance(); };
|
||||
Control::IControlAppearance UnfocusedAppearance() const { return *_settings->UnfocusedAppearance(); };
|
||||
// bool HasUnfocusedAppearance() const;
|
||||
|
||||
// winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
// void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme);
|
||||
void UpdateSettings(const IControlSettings& settings /*, const IControlAppearance& newAppearance*/);
|
||||
|
||||
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();
|
||||
// FontInfo GetFont() const;
|
||||
// winrt::Windows::Foundation::Size FontSizeInDips() const;
|
||||
|
||||
winrt::Windows::Foundation::Size FontSize() const noexcept;
|
||||
// winrt::hstring FontFaceName() const noexcept;
|
||||
// uint16_t FontWeight() const noexcept;
|
||||
|
||||
til::color BackgroundColor() const;
|
||||
|
||||
// void SendInput(const winrt::hstring& wstr);
|
||||
// void PasteText(const winrt::hstring& hstr);
|
||||
// bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
|
||||
// void SelectAll();
|
||||
// void ClearSelection();
|
||||
// bool ToggleBlockSelection();
|
||||
// void ToggleMarkMode();
|
||||
// Control::SelectionInteractionMode SelectionMode() const;
|
||||
// bool SwitchSelectionEndpoint();
|
||||
// bool ExpandSelectionToWord();
|
||||
// bool TryMarkModeKeybinding(const WORD vkey,
|
||||
// const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
|
||||
|
||||
// void GotFocus();
|
||||
// void LostFocus();
|
||||
|
||||
// void ToggleShaderEffects();
|
||||
// void AdjustOpacity(const double adjustment);
|
||||
// void ResumeRendering();
|
||||
|
||||
// void SetHoveredCell(Core::Point terminalPosition);
|
||||
// void ClearHoveredCell();
|
||||
// winrt::hstring GetHyperlink(const Core::Point position) const;
|
||||
// winrt::hstring HoveredUriText() const;
|
||||
// Windows::Foundation::IReference<Core::Point> HoveredCell() const;
|
||||
|
||||
// ::Microsoft::Console::Render::IRenderData* GetRenderData() const;
|
||||
|
||||
// void ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode);
|
||||
|
||||
void Close();
|
||||
|
||||
// #pragma region ICoreState
|
||||
// const size_t TaskbarState() const noexcept;
|
||||
// const size_t TaskbarProgress() const noexcept;
|
||||
|
||||
// hstring Title();
|
||||
// Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() noexcept;
|
||||
// hstring WorkingDirectory() const;
|
||||
|
||||
TerminalConnection::ConnectionState ConnectionState() const;
|
||||
|
||||
int ScrollOffset();
|
||||
int ViewHeight() const;
|
||||
int BufferHeight() const;
|
||||
|
||||
// bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
// Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
// void AddMark(const Control::ScrollMark& mark);
|
||||
// void ClearMark();
|
||||
// void ClearAllMarks();
|
||||
// void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
// void SelectCommand(const bool goUp);
|
||||
// void SelectOutput(const bool goUp);
|
||||
// #pragma endregion
|
||||
|
||||
// #pragma region ITerminalInput
|
||||
bool TrySendKeyEvent(const WORD vkey,
|
||||
const WORD scanCode,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool keyDown);
|
||||
bool SendCharEvent(const wchar_t ch,
|
||||
const WORD scanCode,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
|
||||
// bool SendMouseEvent(const til::point viewportPos,
|
||||
// const unsigned int uiButton,
|
||||
// const ::Microsoft::Terminal::Core::ControlKeyStates states,
|
||||
// const short wheelDelta,
|
||||
// const ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state);
|
||||
// void UserScrollViewport(const int viewTop);
|
||||
|
||||
// void ClearBuffer(Control::ClearBufferType clearType);
|
||||
|
||||
// #pragma endregion
|
||||
|
||||
// void BlinkAttributeTick();
|
||||
// void BlinkCursor();
|
||||
bool CursorOn() const;
|
||||
void CursorOn(const bool isCursorOn);
|
||||
|
||||
// bool IsVtMouseModeEnabled() const;
|
||||
// bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const;
|
||||
// Core::Point CursorPosition() const;
|
||||
|
||||
// bool HasSelection() const;
|
||||
// bool CopyOnSelect() const;
|
||||
// Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
// Control::SelectionData SelectionInfo() const;
|
||||
// void SetSelectionAnchor(const til::point position);
|
||||
// void SetEndSelectionPoint(const til::point position);
|
||||
|
||||
// void Search(const winrt::hstring& text,
|
||||
// const bool goForward,
|
||||
// const bool caseSensitive);
|
||||
|
||||
// void LeftClickOnTerminal(const til::point terminalPosition,
|
||||
// const int numberOfClicks,
|
||||
// const bool altEnabled,
|
||||
// const bool shiftEnabled,
|
||||
// const bool isOnOriginalPosition,
|
||||
// bool& selectionNeedsToBeCopied);
|
||||
|
||||
// void AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
// void DetachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine);
|
||||
|
||||
// bool IsInReadOnlyMode() const;
|
||||
// void ToggleReadOnlyMode();
|
||||
|
||||
// hstring ReadEntireBuffer() const;
|
||||
// Control::CommandHistoryContext CommandHistory() const;
|
||||
|
||||
// static bool IsVintageOpacityAvailable() noexcept;
|
||||
|
||||
// void AdjustOpacity(const double opacity, const bool relative);
|
||||
|
||||
// void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
// uint64_t OwningHwnd();
|
||||
// void OwningHwnd(uint64_t owner);
|
||||
|
||||
// RUNTIME_SETTING(double, Opacity, _settings->Opacity());
|
||||
// RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// clang-format off
|
||||
// WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
||||
|
||||
// TYPED_EVENT(CopyToClipboard, IInspectable, Control::CopyToClipboardEventArgs);
|
||||
// TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs);
|
||||
// TYPED_EVENT(WarningBell, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(TabColorChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(BackgroundColorChanged, IInspectable, IInspectable);
|
||||
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
|
||||
// TYPED_EVENT(CursorPositionChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
|
||||
TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(HoveredHyperlinkChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(RendererEnteredErrorState, IInspectable, IInspectable);
|
||||
TYPED_EVENT(SwapChainChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(RendererWarning, IInspectable, Control::RendererWarningArgs);
|
||||
// TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
// TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
|
||||
// TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs);
|
||||
// TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
|
||||
// TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
// TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
// TYPED_EVENT(MenuChanged, IInspectable, Control::MenuChangedEventArgs);
|
||||
|
||||
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
// TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
bool _initializedTerminal{ false };
|
||||
bool _closing{ false };
|
||||
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
event_token _connectionOutputEventToken;
|
||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||
|
||||
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
|
||||
// NOTE: _renderEngine must be ordered before _renderer.
|
||||
//
|
||||
// As _renderer has a dependency on _renderEngine (through a raw pointer)
|
||||
// we must ensure the _renderer is deallocated first.
|
||||
// (C++ class members are destroyed in reverse order.)
|
||||
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
|
||||
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
winrt::hstring _actualFontFaceName;
|
||||
CSSLengthPercentage _cellWidth;
|
||||
CSSLengthPercentage _cellHeight;
|
||||
|
||||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
std::optional<wchar_t> _leadingSurrogate{ std::nullopt };
|
||||
|
||||
// std::optional<til::point> _lastHoveredCell{ std::nullopt };
|
||||
// // Track the last hyperlink ID we hovered over
|
||||
// uint16_t _lastHoveredId{ 0 };
|
||||
|
||||
// bool _isReadOnly{ false };
|
||||
|
||||
// std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _lastHoveredInterval{ std::nullopt };
|
||||
|
||||
// These members represent the size of the surface that we should be
|
||||
// rendering to.
|
||||
double _panelWidth{ 0 };
|
||||
double _panelHeight{ 0 };
|
||||
double _compositionScale{ 0 };
|
||||
|
||||
uint64_t _owningHwnd{ 0 };
|
||||
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
// std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
// std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// NEW STUFF HERE //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
bool _isRootBlock{ false };
|
||||
bool _gotFirstPrompt{ false };
|
||||
// mark?
|
||||
|
||||
winrt::com_ptr<BlockContent> _first{ this->get_strong() };
|
||||
winrt::com_ptr<BlockContent> _next{ nullptr };
|
||||
winrt::com_ptr<BlockContent> _last{ this->get_strong() };
|
||||
|
||||
winrt::fire_and_forget _newPromptHandler(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark);
|
||||
winrt::event_token _newPromptRevoker;
|
||||
|
||||
winrt::com_ptr<BlockContent> _fork();
|
||||
|
||||
public:
|
||||
BlockContent(TerminalConnection::ITerminalConnection connection,
|
||||
winrt::com_ptr<ControlSettings> settings,
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> terminal);
|
||||
TYPED_EVENT(NewBlock, IInspectable, Control::BlockContent);
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _setupDispatcherAndCallbacks();
|
||||
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
void _updateFont(const bool initialUpdate = false);
|
||||
void _refreshSizeUnderLock();
|
||||
// void _updateSelectionUI();
|
||||
// bool _shouldTryUpdateSelection(const WORD vkey);
|
||||
|
||||
void _handleControlC();
|
||||
void _sendInputToConnection(std::wstring_view wstr);
|
||||
|
||||
// #pragma region TerminalCoreCallbacks
|
||||
// void _terminalCopyToClipboard(std::wstring_view wstr);
|
||||
// void _terminalWarningBell();
|
||||
// void _terminalTitleChanged(std::wstring_view wstr);
|
||||
// void _terminalScrollPositionChanged(const int viewTop,
|
||||
// const int viewHeight,
|
||||
// const int bufferSize);
|
||||
// void _terminalCursorPositionChanged();
|
||||
// void _terminalTaskbarProgressChanged();
|
||||
// void _terminalShowWindowChanged(bool showOrHide);
|
||||
// void _terminalPlayMidiNote(const int noteNumber,
|
||||
// const int velocity,
|
||||
// const std::chrono::microseconds duration);
|
||||
|
||||
// void _terminalMenuChanged(std::wstring_view menuJson, int32_t replaceLength);
|
||||
|
||||
// #pragma endregion
|
||||
|
||||
// MidiAudio _midiAudio;
|
||||
// winrt::Windows::System::DispatcherQueueTimer _midiAudioSkipTimer{ nullptr };
|
||||
|
||||
// #pragma region RendererCallbacks
|
||||
// void _rendererWarning(const HRESULT hr);
|
||||
void _renderEngineSwapChainChanged(const HANDLE handle);
|
||||
// void _rendererBackgroundColorChanged();
|
||||
// void _rendererTabColorChanged();
|
||||
// #pragma endregion
|
||||
|
||||
// void _raiseReadOnlyWarning();
|
||||
void _updateAntiAliasingMode();
|
||||
void _connectionOutputHandler(const hstring& hstr);
|
||||
// void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
||||
// void _setOpacity(const double opacity);
|
||||
|
||||
// bool _isBackgroundTransparent();
|
||||
// void _focusChanged(bool focused);
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (_dispatcher)
|
||||
{
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
//
|
||||
// Though, the unit tests don't actually run in TAEF's main
|
||||
// thread, so we don't care when we're running in tests.
|
||||
assert(_inUnitTests || _dispatcher.HasThreadAccess());
|
||||
}
|
||||
#endif
|
||||
return _closing;
|
||||
}
|
||||
|
||||
// friend class ControlUnitTests::BlockContentTests;
|
||||
friend class ControlUnitTests::ControlInteractivityTests;
|
||||
bool _inUnitTests{ false };
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(BlockContent);
|
||||
// BASIC_FACTORY(SelectionColor);
|
||||
}
|
||||
207
src/cascadia/TerminalControl/BlockContent.idl
Normal file
207
src/cascadia/TerminalControl/BlockContent.idl
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ICoreState.idl";
|
||||
import "ControlCore.idl";
|
||||
import "IControlSettings.idl";
|
||||
import "EventArgs.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
|
||||
// // This is a mirror of
|
||||
// // ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState,
|
||||
// // but projectable.
|
||||
// // !! LOAD BEARING !! If you make this a struct with Booleans (like they
|
||||
// // make the most sense as), then the app will crash trying to toss one of
|
||||
// // these across the process boundary. I haven't the damndest idea why.
|
||||
// [flags] enum MouseButtonState {
|
||||
// IsLeftButtonDown = 0x1,
|
||||
// IsMiddleButtonDown = 0x2,
|
||||
// IsRightButtonDown = 0x4
|
||||
// };
|
||||
|
||||
// enum ClearBufferType
|
||||
// {
|
||||
// Screen,
|
||||
// Scrollback,
|
||||
// All
|
||||
// };
|
||||
|
||||
// enum SelectionInteractionMode
|
||||
// {
|
||||
// None,
|
||||
// Mouse,
|
||||
// Keyboard,
|
||||
// Mark
|
||||
// };
|
||||
|
||||
// [flags] enum SelectionEndpointTarget {
|
||||
// Start = 0x1,
|
||||
// End = 0x2
|
||||
// };
|
||||
|
||||
// struct SelectionData
|
||||
// {
|
||||
// Microsoft.Terminal.Core.Point StartPos;
|
||||
// Microsoft.Terminal.Core.Point EndPos;
|
||||
// SelectionEndpointTarget Endpoint;
|
||||
// Boolean StartAtLeftBoundary;
|
||||
// Boolean EndAtRightBoundary;
|
||||
// };
|
||||
|
||||
// [default_interface] runtimeclass SelectionColor
|
||||
// {
|
||||
// SelectionColor();
|
||||
// Microsoft.Terminal.Core.Color Color;
|
||||
// // If true, color.R is a value between 0 and 15, indicating an indexed color.
|
||||
// // This mirrors how TextColor works internally, which is the primary target of this interface.
|
||||
// Boolean IsIndex16;
|
||||
// };
|
||||
|
||||
// [default_interface] runtimeclass CommandHistoryContext
|
||||
// {
|
||||
// IVector<String> History;
|
||||
// String CurrentCommandline;
|
||||
// };
|
||||
|
||||
|
||||
[default_interface] runtimeclass BlockContent
|
||||
{
|
||||
BlockContent(IControlSettings settings,
|
||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
||||
Boolean Initialize(Double actualWidth,
|
||||
Double actualHeight,
|
||||
Double compositionScale);
|
||||
|
||||
UInt64 SwapChainHandle { get; };
|
||||
|
||||
// [default_interface] runtimeclass ControlCore : ICoreState
|
||||
// {
|
||||
// ControlCore(IControlSettings settings,
|
||||
// IControlAppearance unfocusedAppearance,
|
||||
// Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
||||
// Boolean Initialize(Double actualWidth,
|
||||
// Double actualHeight,
|
||||
// Double compositionScale);
|
||||
|
||||
// void UpdateSettings(IControlSettings settings, IControlAppearance appearance);
|
||||
void UpdateSettings(IControlSettings settings);
|
||||
// void ApplyAppearance(Boolean focused);
|
||||
|
||||
IControlSettings Settings { get; };
|
||||
IControlAppearance FocusedAppearance { get; };
|
||||
IControlAppearance UnfocusedAppearance { get; };
|
||||
// Boolean HasUnfocusedAppearance();
|
||||
|
||||
// UInt64 SwapChainHandle { get; };
|
||||
|
||||
Windows.Foundation.Size FontSize { get; };
|
||||
// String FontFaceName { get; };
|
||||
// UInt16 FontWeight { get; };
|
||||
// Double Opacity { get; };
|
||||
// Boolean UseAcrylic { get; };
|
||||
|
||||
// Boolean TryMarkModeKeybinding(Int16 vkey,
|
||||
// Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
Boolean TrySendKeyEvent(Int16 vkey,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Boolean keyDown);
|
||||
Boolean SendCharEvent(Char ch,
|
||||
Int16 scanCode,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers);
|
||||
// void SendInput(String text);
|
||||
// void PasteText(String text);
|
||||
// void SelectAll();
|
||||
// void ClearSelection();
|
||||
// Boolean ToggleBlockSelection();
|
||||
// void ToggleMarkMode();
|
||||
// Boolean SwitchSelectionEndpoint();
|
||||
// Boolean ExpandSelectionToWord();
|
||||
// void ClearBuffer(ClearBufferType clearType);
|
||||
|
||||
// void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition);
|
||||
// void ClearHoveredCell();
|
||||
|
||||
// void ResetFontSize();
|
||||
// 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();
|
||||
|
||||
// Microsoft.Terminal.Core.Point CursorPosition { get; };
|
||||
// void ResumeRendering();
|
||||
// void BlinkAttributeTick();
|
||||
// void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||
|
||||
// Boolean HasSelection { get; };
|
||||
// IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
// SelectionData SelectionInfo { get; };
|
||||
// SelectionInteractionMode SelectionMode();
|
||||
|
||||
// String HoveredUriText { get; };
|
||||
// Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
|
||||
|
||||
// void BlinkCursor();
|
||||
// Boolean IsInReadOnlyMode { get; };
|
||||
Boolean CursorOn;
|
||||
void EnablePainting();
|
||||
|
||||
// String ReadEntireBuffer();
|
||||
// CommandHistoryContext CommandHistory();
|
||||
|
||||
// void AdjustOpacity(Double Opacity, Boolean relative);
|
||||
// void WindowVisibilityChanged(Boolean showOrHide);
|
||||
|
||||
// void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
// event FontSizeChangedEventArgs FontSizeChanged;
|
||||
|
||||
// event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> CursorPositionChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> HoveredHyperlinkChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SwapChainChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, RendererWarningArgs> RendererWarning;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, FoundResultsArgs> FoundMatch;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
// 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, MenuChangedEventArgs> MenuChanged;
|
||||
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
|
||||
|
||||
|
||||
|
||||
// ICoreState
|
||||
|
||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||
Int32 ScrollOffset { get; };
|
||||
Int32 ViewHeight { get; };
|
||||
Int32 BufferHeight { get; };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
event Windows.Foundation.TypedEventHandler<Object, BlockContent> NewBlock;
|
||||
|
||||
};
|
||||
}
|
||||
3392
src/cascadia/TerminalControl/BlockControl.cpp
Normal file
3392
src/cascadia/TerminalControl/BlockControl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
393
src/cascadia/TerminalControl/BlockControl.h
Normal file
393
src/cascadia/TerminalControl/BlockControl.h
Normal file
@@ -0,0 +1,393 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockControl.g.h"
|
||||
#include "XamlLights.h"
|
||||
#include "EventArgs.h"
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../buffer/out/search.h"
|
||||
#include "SearchBoxControl.h"
|
||||
|
||||
#include "ControlInteractivity.h"
|
||||
#include "ControlSettings.h"
|
||||
|
||||
namespace Microsoft::Console::VirtualTerminal
|
||||
{
|
||||
struct MouseButtonState;
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
struct BlockControl : BlockControlT<BlockControl>
|
||||
{
|
||||
BlockControl(Control::BlockContent content);
|
||||
|
||||
// BlockControl(IControlSettings settings, Control::IControlAppearance unfocusedAppearance, TerminalConnection::ITerminalConnection connection);
|
||||
|
||||
// static Control::BlockControl 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);
|
||||
void PasteTextFromClipboard();
|
||||
// void SelectAll();
|
||||
// bool ToggleBlockSelection();
|
||||
// void ToggleMarkMode();
|
||||
// bool SwitchSelectionEndpoint();
|
||||
// bool ExpandSelectionToWord();
|
||||
void Close();
|
||||
Windows::Foundation::Size CharacterDimensions() const;
|
||||
// Windows::Foundation::Size MinimumSize();
|
||||
// float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
|
||||
|
||||
// void PreviewInput(const winrt::hstring& text);
|
||||
|
||||
// Microsoft::Terminal::Core::Point CursorPositionInDips();
|
||||
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
// void ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode);
|
||||
|
||||
// #pragma region ICoreState
|
||||
// const uint64_t TaskbarState() const noexcept;
|
||||
// const uint64_t TaskbarProgress() const noexcept;
|
||||
|
||||
// hstring Title();
|
||||
// Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() noexcept;
|
||||
// hstring WorkingDirectory() const;
|
||||
|
||||
TerminalConnection::ConnectionState ConnectionState() const;
|
||||
|
||||
// int ScrollOffset() const;
|
||||
// int ViewHeight() const;
|
||||
// int BufferHeight() const;
|
||||
|
||||
// bool BracketedPasteEnabled() const noexcept;
|
||||
|
||||
// double BackgroundOpacity() const;
|
||||
|
||||
// uint64_t OwningHwnd();
|
||||
// void OwningHwnd(uint64_t owner);
|
||||
|
||||
// Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
|
||||
// void AddMark(const Control::ScrollMark& mark);
|
||||
// void ClearMark();
|
||||
// void ClearAllMarks();
|
||||
// void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
// void SelectCommand(const bool goUp);
|
||||
// void SelectOutput(const bool goUp);
|
||||
|
||||
// #pragma endregion
|
||||
|
||||
// void ScrollViewport(int viewTop);
|
||||
|
||||
// void AdjustFontSize(float fontSizeDelta);
|
||||
// void ResetFontSize();
|
||||
// til::point GetFontSize() const;
|
||||
|
||||
// void SendInput(const winrt::hstring& input);
|
||||
// void ClearBuffer(Control::ClearBufferType clearType);
|
||||
|
||||
// void ToggleShaderEffects();
|
||||
|
||||
winrt::fire_and_forget RenderEngineSwapChainChanged(IInspectable sender, IInspectable args);
|
||||
void _AttachDxgiSwapChainToXaml(HANDLE swapChainHandle);
|
||||
winrt::fire_and_forget _RendererEnteredErrorState(IInspectable sender, IInspectable args);
|
||||
|
||||
// void _RenderRetryButton_Click(const IInspectable& button, const IInspectable& args);
|
||||
// winrt::fire_and_forget _RendererWarning(IInspectable sender,
|
||||
// Control::RendererWarningArgs args);
|
||||
|
||||
// void CreateSearchBoxControl();
|
||||
|
||||
// void SearchMatch(const bool goForward);
|
||||
|
||||
// bool SearchBoxEditInFocus() const;
|
||||
|
||||
// bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
bool OnMouseWheel(const Windows::Foundation::Point location, const int32_t delta, const bool leftButtonDown, const bool midButtonDown, const bool rightButtonDown);
|
||||
|
||||
~BlockControl();
|
||||
|
||||
// Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
|
||||
const Windows::UI::Xaml::Thickness GetPadding();
|
||||
|
||||
// static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings,
|
||||
// const uint32_t dpi,
|
||||
// int32_t commandlineCols,
|
||||
// int32_t commandlineRows);
|
||||
// static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
|
||||
|
||||
// void BellLightOn();
|
||||
|
||||
// bool ReadOnly() const noexcept;
|
||||
// void ToggleReadOnly();
|
||||
|
||||
static Control::MouseButtonState GetPressedMouseButtons(const winrt::Windows::UI::Input::PointerPoint point);
|
||||
static unsigned int GetPointerUpdateKind(const winrt::Windows::UI::Input::PointerPoint point);
|
||||
static Windows::UI::Xaml::Thickness ParseThicknessFromPadding(const hstring padding);
|
||||
|
||||
// hstring ReadEntireBuffer() const;
|
||||
// Control::CommandHistoryContext CommandHistory() const;
|
||||
|
||||
// winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
// void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme) const noexcept;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
// BUBBLED_FORWARDED_TYPED_EVENT(MenuChanged, IInspectable, Control::MenuChangedEventArgs);
|
||||
|
||||
// TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
// TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
// TYPED_EVENT(HidePointerCursor, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(RestorePointerCursor, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(ReadOnlyChanged, IInspectable, IInspectable);
|
||||
// TYPED_EVENT(FocusFollowMouseRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Initialized, Control::BlockControl, Windows::UI::Xaml::RoutedEventArgs);
|
||||
// TYPED_EVENT(WarningBell, IInspectable, IInspectable);
|
||||
|
||||
// clang-format on
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, BackgroundBrush, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
friend struct BlockControlT<BlockControl>; // friend our parent so it can bind private event handlers
|
||||
|
||||
// NOTE: _uiaEngine must be ordered before _core.
|
||||
//
|
||||
// ControlCore::AttachUiaEngine receives a IRenderEngine as a raw pointer, which we own.
|
||||
// We must ensure that we first destroy the ControlCore before the UiaEngine instance
|
||||
// in order to safely resolve this unsafe pointer dependency. Otherwise a deallocated
|
||||
// IRenderEngine is accessed when ControlCore calls Renderer::TriggerTeardown.
|
||||
// (C++ class members are destroyed in reverse order.)
|
||||
// Further, the BlockControlAutomationPeer must be destructed after _uiaEngine!
|
||||
// Control::BlockControlAutomationPeer _automationPeer{ nullptr };
|
||||
// Control::ControlInteractivity _interactivity{ nullptr };
|
||||
// Control::ControlCore _core{ nullptr };
|
||||
|
||||
Control::BlockContent _content{ nullptr };
|
||||
|
||||
winrt::com_ptr<SearchBoxControl> _searchBox;
|
||||
|
||||
bool _closing{ false };
|
||||
bool _focused{ false };
|
||||
bool _initializedTerminal{ false };
|
||||
|
||||
std::shared_ptr<ThrottledFuncLeading> _playWarningBell;
|
||||
|
||||
struct ScrollBarUpdate
|
||||
{
|
||||
std::optional<double> newValue;
|
||||
double newMaximum;
|
||||
double newMinimum;
|
||||
double newViewportSize;
|
||||
};
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<ScrollBarUpdate>> _updateScrollBar;
|
||||
|
||||
bool _isInternalScrollBarUpdate;
|
||||
|
||||
// Auto scroll occurs when user, while selecting, drags cursor outside
|
||||
// viewport. View is then scrolled to 'follow' the cursor.
|
||||
double _autoScrollVelocity;
|
||||
std::optional<Windows::UI::Input::PointerPoint> _autoScrollingPointerPoint;
|
||||
Windows::UI::Xaml::DispatcherTimer _autoScrollTimer;
|
||||
std::optional<std::chrono::high_resolution_clock::time_point> _lastAutoScrollUpdateTime;
|
||||
bool _pointerPressedInBounds{ false };
|
||||
|
||||
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellLightAnimation{ nullptr };
|
||||
winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellDarkAnimation{ nullptr };
|
||||
Windows::UI::Xaml::DispatcherTimer _bellLightTimer{ nullptr };
|
||||
|
||||
std::optional<Windows::UI::Xaml::DispatcherTimer> _cursorTimer;
|
||||
std::optional<Windows::UI::Xaml::DispatcherTimer> _blinkTimer;
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
bool _showMarksInScrollbar{ false };
|
||||
bool _useRightClickContextMenu{ false };
|
||||
bool _rightClickPressed{ false };
|
||||
|
||||
bool _isBackgroundLight{ false };
|
||||
bool _detached{ false };
|
||||
|
||||
// winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalPrimaryElements{ nullptr };
|
||||
// winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSecondaryElements{ nullptr };
|
||||
// winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSelectedPrimaryElements{ nullptr };
|
||||
// winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSelectedSecondaryElements{ nullptr };
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
// _closing isn't atomic and may only be accessed from the main thread.
|
||||
if (const auto dispatcher = Dispatcher())
|
||||
{
|
||||
assert(dispatcher.HasThreadAccess());
|
||||
}
|
||||
#endif
|
||||
return _closing;
|
||||
}
|
||||
|
||||
void _UpdateSettingsFromUIThread();
|
||||
void _UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance);
|
||||
void _ApplyUISettings();
|
||||
winrt::fire_and_forget UpdateAppearance(Control::IControlAppearance newAppearance);
|
||||
void _SetBackgroundImage(const IControlAppearance& newAppearance);
|
||||
|
||||
void _InitializeBackgroundBrush();
|
||||
winrt::fire_and_forget _coreBackgroundColorChanged(const IInspectable& sender, const IInspectable& args);
|
||||
void _changeBackgroundColor(til::color bg);
|
||||
static bool _isColorLight(til::color bg) noexcept;
|
||||
void _changeBackgroundOpacity();
|
||||
|
||||
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);
|
||||
void _KeyUpHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
|
||||
void _CharacterHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::CharacterReceivedRoutedEventArgs& e);
|
||||
void _PointerPressedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _PointerMovedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _PointerReleasedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _PointerExitedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _MouseWheelHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _ScrollbarChangeHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs& e);
|
||||
|
||||
void _GotFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void _LostFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
winrt::fire_and_forget _DragDropHandler(Windows::Foundation::IInspectable sender, Windows::UI::Xaml::DragEventArgs e);
|
||||
void _DragOverHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::DragEventArgs& e);
|
||||
|
||||
winrt::fire_and_forget _HyperlinkHandler(Windows::Foundation::IInspectable sender, Control::OpenHyperlinkEventArgs e);
|
||||
|
||||
void _CursorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
void _BlinkTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
void _BellLightOff(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
|
||||
void _SetEndSelectionPointAtCursor(const Windows::Foundation::Point& cursorPosition);
|
||||
|
||||
void _SwapChainSizeChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::SizeChangedEventArgs& e);
|
||||
void _SwapChainScaleChanged(const Windows::UI::Xaml::Controls::SwapChainPanel& sender, const Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _TerminalTabColorChanged(const std::optional<til::color> color);
|
||||
|
||||
void _ScrollPositionChanged(const IInspectable& sender, const Control::ScrollPositionChangedArgs& args);
|
||||
winrt::fire_and_forget _CursorPositionChanged(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
bool _CapturePointer(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
bool _ReleasePointerCapture(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
|
||||
void _TryStartAutoScroll(const Windows::UI::Input::PointerPoint& pointerPoint, const double scrollVelocity);
|
||||
void _TryStopAutoScroll(const uint32_t pointerId);
|
||||
void _UpdateAutoScroll(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
|
||||
|
||||
void _KeyHandler(const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e, const bool keyDown);
|
||||
static ::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() noexcept;
|
||||
bool _TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const;
|
||||
static void _ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept;
|
||||
bool _TrySendKeyEvent(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
|
||||
|
||||
const til::point _toTerminalOrigin(winrt::Windows::Foundation::Point cursorPosition);
|
||||
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
||||
|
||||
void _Search(const winrt::hstring& text, const bool goForward, const bool caseSensitive);
|
||||
void _CloseSearchBoxControl(const winrt::Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
// // TSFInputControl Handlers
|
||||
// void _CompositionCompleted(winrt::hstring text);
|
||||
// void _CurrentCursorPositionHandler(const IInspectable& sender, const CursorPositionEventArgs& eventArgs);
|
||||
// void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
|
||||
|
||||
// winrt::fire_and_forget _hoveredHyperlinkChanged(IInspectable sender, IInspectable args);
|
||||
// winrt::fire_and_forget _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args);
|
||||
|
||||
void _coreFontSizeChanged(const int fontWidth,
|
||||
const int fontHeight,
|
||||
const bool isInitialChange);
|
||||
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args);
|
||||
|
||||
til::point _toPosInDips(const Core::Point terminalCellPos);
|
||||
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
|
||||
|
||||
// void _contextMenuHandler(IInspectable sender, Control::ContextMenuRequestedEventArgs args);
|
||||
|
||||
// void _PasteCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
// void _CopyCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
// void _SearchCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(NewBlock, IInspectable, Control::BlockContent);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Revokers
|
||||
{
|
||||
Control::BlockContent::ScrollPositionChanged_revoker scrollPositionChanged;
|
||||
// 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::BlockContent::ConnectionStateChanged_revoker ConnectionStateChanged;
|
||||
// Control::ControlCore::ShowWindowChanged_revoker ShowWindowChanged;
|
||||
// Control::ControlCore::CloseTerminalRequested_revoker CloseTerminalRequested;
|
||||
// Control::ControlCore::MenuChanged_revoker MenuChanged;
|
||||
Control::BlockContent::NewBlock_revoker NewBlock;
|
||||
|
||||
// // These are set up in _InitializeTerminal
|
||||
// Control::ControlCore::RendererWarning_revoker RendererWarning;
|
||||
Control::BlockContent::SwapChainChanged_revoker SwapChainChanged;
|
||||
|
||||
// Control::ControlInteractivity::OpenHyperlink_revoker interactivityOpenHyperlink;
|
||||
// Control::ControlInteractivity::ScrollPositionChanged_revoker interactivityScrollPositionChanged;
|
||||
// Control::ControlInteractivity::PasteFromClipboard_revoker PasteFromClipboard;
|
||||
} _revokers{};
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(BlockControl);
|
||||
}
|
||||
127
src/cascadia/TerminalControl/BlockControl.idl
Normal file
127
src/cascadia/TerminalControl/BlockControl.idl
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "IMouseWheelListener.idl";
|
||||
import "IControlSettings.idl";
|
||||
import "ControlInteractivity.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "EventArgs.idl";
|
||||
import "ICoreState.idl";
|
||||
import "BlockContent.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Control
|
||||
{
|
||||
|
||||
[default_interface] runtimeclass BlockControl : Windows.UI.Xaml.Controls.UserControl,
|
||||
// IDirectKeyListener,
|
||||
// IMouseWheelListener,
|
||||
// ICoreState,
|
||||
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
BlockControl(BlockContent content);
|
||||
|
||||
// BlockControl(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,
|
||||
// Int32 commandlineRows);
|
||||
|
||||
// void UpdateControlSettings(IControlSettings settings);
|
||||
// void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
|
||||
|
||||
// Guid ContentGuid{ get; };
|
||||
|
||||
// Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
||||
|
||||
// event FontSizeChangedEventArgs FontSizeChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, CopyToClipboardEventArgs> CopyToClipboard;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> HidePointerCursor;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> RestorePointerCursor;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> FocusFollowMouseRequested;
|
||||
// event Windows.Foundation.TypedEventHandler<Object, MenuChangedEventArgs> MenuChanged;
|
||||
|
||||
// Windows.UI.Xaml.Controls.CommandBarFlyout ContextMenu { get; };
|
||||
// Windows.UI.Xaml.Controls.CommandBarFlyout SelectionContextMenu { get; };
|
||||
|
||||
// event Windows.Foundation.TypedEventHandler<TermControl, Windows.UI.Xaml.RoutedEventArgs> Initialized;
|
||||
// // This is an event handler forwarder for the underlying connection.
|
||||
// // We expose this and ConnectionState here so that it might eventually be data bound.
|
||||
// event Windows.Foundation.TypedEventHandler<Object, IInspectable> ConnectionStateChanged;
|
||||
|
||||
// event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
|
||||
// event Windows.Foundation.TypedEventHandler<Object, Object> CloseTerminalRequested;
|
||||
|
||||
// Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference<CopyFormat> formats);
|
||||
// void PasteTextFromClipboard();
|
||||
// void SelectAll();
|
||||
// Boolean ToggleBlockSelection();
|
||||
// void ToggleMarkMode();
|
||||
// Boolean SwitchSelectionEndpoint();
|
||||
// Boolean ExpandSelectionToWord();
|
||||
// void ClearBuffer(ClearBufferType clearType);
|
||||
// void Close();
|
||||
// Windows.Foundation.Size CharacterDimensions { get; };
|
||||
// Windows.Foundation.Size MinimumSize { get; };
|
||||
// Single SnapDimensionToGrid(Boolean widthOrHeight, Single dimension);
|
||||
|
||||
// void WindowVisibilityChanged(Boolean showOrHide);
|
||||
|
||||
// void ScrollViewport(Int32 viewTop);
|
||||
|
||||
// void CreateSearchBoxControl();
|
||||
// Boolean SearchBoxEditInFocus();
|
||||
|
||||
// void SearchMatch(Boolean goForward);
|
||||
|
||||
// void AdjustFontSize(Single fontSizeDelta);
|
||||
// void ResetFontSize();
|
||||
|
||||
// void ToggleShaderEffects();
|
||||
// void SendInput(String input);
|
||||
|
||||
// void BellLightOn();
|
||||
|
||||
// Boolean ReadOnly { get; };
|
||||
// void ToggleReadOnly();
|
||||
|
||||
// String ReadEntireBuffer();
|
||||
// CommandHistoryContext CommandHistory();
|
||||
|
||||
// void AdjustOpacity(Double Opacity, Boolean relative);
|
||||
|
||||
// // You'd think this should just be "Opacity", but UIElement already
|
||||
// // defines an "Opacity", which we're actually not setting at all. We're
|
||||
// // not overriding or changing _that_ value. Callers that want the
|
||||
// // opacity set by the settings should call this instead.
|
||||
// Double BackgroundOpacity { get; };
|
||||
|
||||
// void PreviewInput(String text);
|
||||
|
||||
// Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
// void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
// void Detach();
|
||||
|
||||
// Microsoft.Terminal.Core.Point CursorPositionInDips { get; };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
event Windows.Foundation.TypedEventHandler<Object, BlockContent> NewBlock;
|
||||
|
||||
}
|
||||
}
|
||||
200
src/cascadia/TerminalControl/BlockControl.xaml
Normal file
200
src/cascadia/TerminalControl/BlockControl.xaml
Normal file
@@ -0,0 +1,200 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="Microsoft.Terminal.Control.BlockControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
|
||||
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.Terminal.Control"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="768"
|
||||
d:DesignWidth="1024"
|
||||
AllowDrop="True"
|
||||
AllowFocusOnInteraction="True"
|
||||
Background="Transparent"
|
||||
CharacterReceived="_CharacterHandler"
|
||||
DragOver="_DragOverHandler"
|
||||
Drop="_DragDropHandler"
|
||||
GotFocus="_GotFocusHandler"
|
||||
IsTabStop="True"
|
||||
KeyUp="_KeyUpHandler"
|
||||
LostFocus="_LostFocusHandler"
|
||||
PointerWheelChanged="_MouseWheelHandler"
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
TabNavigation="Cycle"
|
||||
Tapped="_TappedHandler"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
|
||||
<!--
|
||||
BODGY: ControlsV2 changed the size of the scrollbars from 16dips to
|
||||
12dips. This is harder for folks to hit with the mouse, and isn't
|
||||
consistent with the rest of the scrollbars on the platform (as much
|
||||
as they can be).
|
||||
|
||||
To work around this, we have to entirely copy the template for the
|
||||
ScrollBar into our XAML file. We're then also re-defining
|
||||
ScrollBarSize here to 16, so that the new template will pick up on
|
||||
the new value.
|
||||
|
||||
This is kinda a pain, and we have to be careful to be sure to ingest
|
||||
an updated version of the template any time we update MUX. The
|
||||
latest ControlsV2 version of the template can be found at:
|
||||
https://github.com/microsoft/microsoft-ui-xaml/blob/main/dev/CommonStyles/ScrollBar_themeresources.xaml#L218
|
||||
|
||||
We're also removing the corner radius, cause that should be flush
|
||||
with the top of the window above the TermControl.
|
||||
|
||||
We're also planning on making this adjustable in the future
|
||||
(GH#9218), where we might need this anyways.
|
||||
-->
|
||||
|
||||
<x:Double x:Key="ScrollBarSize">16</x:Double>
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<!--
|
||||
TODO GH#4031: We've investigated whether we should be using KeyDown or PreviewKeyDown
|
||||
but not necessarily come to a consensus. It's possible that moving input to the SwapChainPanel
|
||||
will solve a bunch of the search input issues we found last time we switched.
|
||||
-->
|
||||
|
||||
<Grid x:Name="RootGrid">
|
||||
<Grid.Lights>
|
||||
<local:VisualBellLight x:Name="BellLight" />
|
||||
</Grid.Lights>
|
||||
|
||||
<Image x:Name="BackgroundImage"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0"
|
||||
Background="Transparent"
|
||||
PointerExited="_PointerExitedHandler"
|
||||
PointerMoved="_PointerMovedHandler"
|
||||
PointerPressed="_PointerPressedHandler"
|
||||
PointerReleased="_PointerReleasedHandler"
|
||||
Visibility="Visible">
|
||||
|
||||
<SwapChainPanel x:Name="SwapChainPanel"
|
||||
CompositionScaleChanged="_SwapChainScaleChanged"
|
||||
SizeChanged="_SwapChainSizeChanged">
|
||||
<Canvas x:Name="OverlayCanvas"
|
||||
Visibility="Visible">
|
||||
<Border x:Name="HyperlinkTooltipBorder"
|
||||
BorderBrush="Transparent">
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Name="LinkTip"
|
||||
Placement="Mouse">
|
||||
<TextBlock IsTextSelectionEnabled="True"
|
||||
TextWrapping="Wrap">
|
||||
<Run x:Name="HoveredUri" /> <LineBreak />
|
||||
<Run x:Uid="HowToOpenRun"
|
||||
FontStyle="Italic" />
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</ToolTipService.ToolTip>
|
||||
</Border>
|
||||
</Canvas>
|
||||
|
||||
<Canvas x:Name="SelectionCanvas"
|
||||
Visibility="Visible">
|
||||
<Path Name="SelectionStartMarker"
|
||||
Data="M 0 0 L 4 5.5996094 L 4 14 L 5 14 L 5 7 L 5 4.1992188 L 5 0 L 0 0 z "
|
||||
Visibility="Collapsed" />
|
||||
<Path Name="SelectionEndMarker"
|
||||
Data="M 0 0 L 0 4.1992188 L 0 7 L 0 14 L 1 14 L 1 5.5996094 L 5 0 L 0 0 z "
|
||||
Visibility="Collapsed" />
|
||||
</Canvas>
|
||||
</SwapChainPanel>
|
||||
|
||||
<!--
|
||||
Putting this in a grid w/ the SwapChainPanel
|
||||
ensures that it's always aligned w/ the scrollbar
|
||||
-->
|
||||
<local:SearchBoxControl x:Name="SearchBox"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
x:Load="False"
|
||||
Closed="_CloseSearchBoxControl"
|
||||
Search="_Search"
|
||||
Visibility="Collapsed" />
|
||||
</Grid>
|
||||
|
||||
<ScrollBar x:Name="ScrollBar"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch"
|
||||
IndicatorMode="MouseIndicator"
|
||||
IsTabStop="False"
|
||||
LargeChange="4"
|
||||
Maximum="1"
|
||||
Orientation="Vertical"
|
||||
PointerPressed="_CapturePointer"
|
||||
PointerReleased="_ReleasePointerCapture"
|
||||
SmallChange="1"
|
||||
ValueChanged="_ScrollbarChangeHandler"
|
||||
ViewportSize="10" />
|
||||
|
||||
<Grid x:Name="ScrollMarksGrid"
|
||||
Grid.Column="1"
|
||||
Width="{StaticResource ScrollBarSize}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Height="{StaticResource ScrollBarSize}" />
|
||||
<Canvas x:Name="ScrollBarCanvas"
|
||||
Grid.Row="1"
|
||||
Width="{StaticResource ScrollBarSize}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Stretch" />
|
||||
<Border Grid.Row="2"
|
||||
Height="{StaticResource ScrollBarSize}" />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- <local:TSFInputControl x:Name="TSFInputControl"
|
||||
CompositionCompleted="_CompositionCompleted"
|
||||
CurrentCursorPosition="_CurrentCursorPositionHandler"
|
||||
CurrentFontInfo="_FontInfoHandler" />-->
|
||||
|
||||
<Grid x:Name="RendererFailedNotice"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="False">
|
||||
<Border Margin="8,8,8,8"
|
||||
Padding="8,8,8,8"
|
||||
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
|
||||
BorderBrush="{ThemeResource SystemAccentColor}"
|
||||
BorderThickness="2,2,2,2"
|
||||
CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="TermControl_RendererFailedTextBlock"
|
||||
HorizontalAlignment="Center"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<Button x:Uid="TermControl_RendererRetryButton"
|
||||
HorizontalAlignment="Right" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -125,6 +125,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnPlayMidiNote = std::bind(&ControlCore::_terminalPlayMidiNote, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
_terminal->SetPlayMidiNoteCallback(pfnPlayMidiNote);
|
||||
|
||||
auto pfnMenuChanged = std::bind(&ControlCore::_terminalMenuChanged, this, std::placeholders::_1, std::placeholders::_2);
|
||||
_terminal->MenuChangedCallback(pfnMenuChanged);
|
||||
|
||||
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
|
||||
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
@@ -154,7 +157,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 +220,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
core->_ScrollPositionChangedHandlers(*core, update);
|
||||
}
|
||||
});
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
}
|
||||
|
||||
ControlCore::~ControlCore()
|
||||
@@ -225,6 +232,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 +605,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 +1005,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 +1014,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 +1399,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 +1409,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 +1451,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 +1701,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 +1728,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 +1740,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:
|
||||
@@ -1750,6 +1809,41 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return hstring{ str };
|
||||
}
|
||||
|
||||
// Get all of our recent commands. This will only really work if the user has enabled shell integration.
|
||||
Control::CommandHistoryContext ControlCore::CommandHistory() const
|
||||
{
|
||||
auto terminalLock = _terminal->LockForWriting();
|
||||
auto context = winrt::make_self<CommandHistoryContext>();
|
||||
const auto& textBuffer = _terminal->GetTextBuffer();
|
||||
|
||||
for (const auto& mark : _terminal->GetScrollMarks())
|
||||
{
|
||||
// The command text is between the `end` (which denotes the end of
|
||||
// the prompt) and the `commandEnd`.
|
||||
bool markHasCommand = mark.commandEnd.has_value() &&
|
||||
mark.commandEnd != mark.end;
|
||||
if (!markHasCommand)
|
||||
continue;
|
||||
|
||||
// Get the text of the command
|
||||
const auto line = mark.end.y;
|
||||
const auto& row = textBuffer.GetRowByOffset(line);
|
||||
const auto rowText = row.GetText();
|
||||
const auto commandText = rowText.substr(mark.end.x, mark.commandEnd->x);
|
||||
// Trim off trailing spaces. In my experimentation, especially with
|
||||
// cmd.exe, there was a lot of unexpected trailing whitespace.
|
||||
// Probably from using autoMarkPrompts to mark the end of the
|
||||
// commands
|
||||
const auto strEnd = commandText.find_last_not_of(UNICODE_SPACE);
|
||||
if (strEnd != std::string::npos)
|
||||
{
|
||||
const auto trimmed = commandText.substr(0, strEnd + 1);
|
||||
context->History().Append(winrt::hstring{ trimmed });
|
||||
}
|
||||
}
|
||||
return *context;
|
||||
}
|
||||
|
||||
Core::Scheme ControlCore::ColorScheme() const noexcept
|
||||
{
|
||||
Core::Scheme s;
|
||||
@@ -2097,6 +2191,120 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::_terminalMenuChanged(std::wstring_view menuJson,
|
||||
int32_t replaceLength)
|
||||
{
|
||||
auto args = winrt::make_self<MenuChangedEventArgs>(winrt::hstring{ menuJson },
|
||||
replaceLength);
|
||||
_MenuChangedHandlers(*this, *args);
|
||||
}
|
||||
|
||||
void ControlCore::SelectCommand(const bool goUp)
|
||||
{
|
||||
const til::point start = HasSelection() ? (goUp ? _terminal->GetSelectionAnchor() : _terminal->GetSelectionEnd()) :
|
||||
_terminal->GetTextBuffer().GetCursor().GetPosition();
|
||||
std::optional<DispatchTypes::ScrollMark> nearest{ std::nullopt };
|
||||
const auto& marks{ _terminal->GetScrollMarks() };
|
||||
auto it = marks.rbegin();
|
||||
const auto end = marks.rend();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
const auto& m = *it;
|
||||
// If this mark doesn't know anything about the position of its
|
||||
// command, OR it does but thinks that it was empty, then just skip
|
||||
// it.
|
||||
if (!m.HasCommand())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// If this mark is before/after the start of our search in the
|
||||
// buffer, ...
|
||||
|
||||
const auto inTheRightDirection = (goUp && (m.commandEnd < start)) || // prev
|
||||
(!goUp && (m.end > start)); // next
|
||||
// (If we're going down, we need to compare the end, not the
|
||||
// commandEnd, to actually find the next one. Otherwise we'll just
|
||||
// find the mark of the current selection again.
|
||||
if (inTheRightDirection)
|
||||
{
|
||||
// ... and we either haven't found a match, or the current nearest
|
||||
// is after/before this mark in the buffer
|
||||
if (!nearest.has_value() ||
|
||||
((goUp && (*m.commandEnd > *nearest->commandEnd)) || // prev
|
||||
(!goUp && (m.end < *nearest->commandEnd)))) // next
|
||||
{
|
||||
// stash this as the new match
|
||||
nearest = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.has_value())
|
||||
{
|
||||
const auto start = nearest->end;
|
||||
auto end = *nearest->commandEnd;
|
||||
|
||||
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
|
||||
bufferSize.DecrementInBounds(end);
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectNewRegion(start, end);
|
||||
_renderer->TriggerSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::SelectOutput(const bool goUp)
|
||||
{
|
||||
const til::point start = HasSelection() ? (goUp ? _terminal->GetSelectionAnchor() : _terminal->GetSelectionEnd()) :
|
||||
_terminal->GetTextBuffer().GetCursor().GetPosition();
|
||||
std::optional<DispatchTypes::ScrollMark> nearest{ std::nullopt };
|
||||
const auto& marks{ _terminal->GetScrollMarks() };
|
||||
auto it = marks.rbegin();
|
||||
const auto end = marks.rend();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
const auto& m = *it;
|
||||
// If this mark doesn't know anything about the position of its
|
||||
// output, OR it does but thinks that it was empty, then just skip
|
||||
// it.
|
||||
if (!m.HasOutput())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// If this mark is before/after the start of our search in the buffer, ...
|
||||
const auto inTheRightDirection = (goUp && (m.outputEnd < start)) || // prev
|
||||
(!goUp && (m.commandEnd > start)); // next
|
||||
// (If we're going down, we need to compare the commandEnd, not the
|
||||
// outputEnd, to actually find the next one. Otherwise we'll just
|
||||
// find the mark of the current selection again.)
|
||||
if (inTheRightDirection)
|
||||
{
|
||||
// .. and we either haven't found a match, or the current
|
||||
// nearest is after this mark in the buffer
|
||||
if (!nearest.has_value() ||
|
||||
((goUp && (*m.outputEnd > *nearest->outputEnd)) || // prev
|
||||
(!goUp && (*m.commandEnd < *nearest->outputEnd)))) // next
|
||||
{
|
||||
// stash this as the new match
|
||||
nearest = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest.has_value())
|
||||
{
|
||||
const auto start = *nearest->commandEnd;
|
||||
auto end = *nearest->outputEnd;
|
||||
|
||||
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
|
||||
bufferSize.DecrementInBounds(end);
|
||||
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SelectNewRegion(start, end);
|
||||
_renderer->TriggerSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlCore::ColorSelection(const Control::SelectionColor& fg, const Control::SelectionColor& bg, Core::MatchMode matchMode)
|
||||
{
|
||||
if (HasSelection())
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "ControlCore.g.h"
|
||||
#include "SelectionColor.g.h"
|
||||
#include "CommandHistoryContext.g.h"
|
||||
#include "ControlSettings.h"
|
||||
#include "../../audio/midi/MidiAudio.hpp"
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
@@ -49,6 +50,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
WINRT_PROPERTY(til::color, Color);
|
||||
WINRT_PROPERTY(bool, IsIndex16);
|
||||
};
|
||||
struct CommandHistoryContext : CommandHistoryContextT<CommandHistoryContext>
|
||||
{
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IVector<winrt::hstring>, History, winrt::single_threaded_vector<winrt::hstring>());
|
||||
WINRT_PROPERTY(winrt::hstring, CurrentCommandline);
|
||||
};
|
||||
|
||||
struct ControlCore : ControlCoreT<ControlCore>
|
||||
{
|
||||
@@ -63,6 +69,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 +81,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();
|
||||
@@ -140,7 +152,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
|
||||
void SelectCommand(const bool goUp);
|
||||
void SelectOutput(const bool goUp);
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ITerminalInput
|
||||
@@ -190,11 +203,13 @@ 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();
|
||||
|
||||
hstring ReadEntireBuffer() const;
|
||||
Control::CommandHistoryContext CommandHistory() const;
|
||||
|
||||
static bool IsVintageOpacityAvailable() noexcept;
|
||||
|
||||
@@ -232,7 +247,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
|
||||
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(MenuChanged, IInspectable, Control::MenuChangedEventArgs);
|
||||
|
||||
TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
@@ -285,6 +304,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();
|
||||
@@ -307,6 +328,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _terminalPlayMidiNote(const int noteNumber,
|
||||
const int velocity,
|
||||
const std::chrono::microseconds duration);
|
||||
|
||||
void _terminalMenuChanged(std::wstring_view menuJson, int32_t replaceLength);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
MidiAudio _midiAudio;
|
||||
|
||||
@@ -58,6 +58,12 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean IsIndex16;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass CommandHistoryContext
|
||||
{
|
||||
IVector<String> History;
|
||||
String CurrentCommandline;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ControlCore : ICoreState
|
||||
{
|
||||
ControlCore(IControlSettings settings,
|
||||
@@ -76,6 +82,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 +116,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,13 +135,13 @@ 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;
|
||||
void EnablePainting();
|
||||
|
||||
String ReadEntireBuffer();
|
||||
CommandHistoryContext CommandHistory();
|
||||
|
||||
void AdjustOpacity(Double Opacity, Boolean relative);
|
||||
void WindowVisibilityChanged(Boolean showOrHide);
|
||||
@@ -162,5 +171,9 @@ 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, MenuChangedEventArgs> MenuChanged;
|
||||
|
||||
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.
|
||||
@@ -205,7 +255,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// GH#9396: we prioritize hyper-link over VT mouse events
|
||||
auto hyperlink = _core->GetHyperlink(terminalPosition.to_core_point());
|
||||
if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) &&
|
||||
ctrlEnabled && !hyperlink.empty())
|
||||
ctrlEnabled &&
|
||||
!hyperlink.empty())
|
||||
{
|
||||
const auto clickCount = _numberOfClicks(pixelPosition, timestamp);
|
||||
// Handle hyper-link only on the first click to prevent multiple activations
|
||||
@@ -255,14 +306,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
else if (WI_IsFlagSet(buttonState, MouseButtonState::IsRightButtonDown))
|
||||
{
|
||||
// Try to copy the text and clear the selection
|
||||
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, nullptr);
|
||||
_core->ClearSelection();
|
||||
if (_core->CopyOnSelect() || !successfulCopy)
|
||||
if (_core->Settings().RightClickContextMenu())
|
||||
{
|
||||
// CopyOnSelect: right click always pastes!
|
||||
// Otherwise: no selection --> paste
|
||||
RequestPasteTextFromClipboard();
|
||||
auto contextArgs = winrt::make<ContextMenuRequestedEventArgs>(til::point{ pixelPosition }.to_winrt_point());
|
||||
_ContextMenuRequestedHandlers(*this, contextArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to copy the text and clear the selection
|
||||
const auto successfulCopy = CopySelectionToClipboard(shiftEnabled, nullptr);
|
||||
_core->ClearSelection();
|
||||
if (_core->CopyOnSelect() || !successfulCopy)
|
||||
{
|
||||
// CopyOnSelect: right click always pastes!
|
||||
// Otherwise: no selection --> paste
|
||||
RequestPasteTextFromClipboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,7 +708,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,9 +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(ContextMenuRequested, IInspectable, Control::ContextMenuRequestedEventArgs);
|
||||
|
||||
TYPED_EVENT(Attached, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Closed, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
// NOTE: _uiaEngine must be ordered before _core.
|
||||
@@ -129,6 +139,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,11 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||
|
||||
// Used to communicate to the TermControl, but not necessarily higher up in the stack
|
||||
event Windows.Foundation.TypedEventHandler<Object, ContextMenuRequestedEventArgs> ContextMenuRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Closed;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Attached;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "EventArgs.h"
|
||||
#include "TitleChangedEventArgs.g.cpp"
|
||||
#include "CopyToClipboardEventArgs.g.cpp"
|
||||
#include "ContextMenuRequestedEventArgs.g.cpp"
|
||||
#include "PasteFromClipboardEventArgs.g.cpp"
|
||||
#include "OpenHyperlinkEventArgs.g.cpp"
|
||||
#include "NoticeEventArgs.g.cpp"
|
||||
@@ -14,3 +15,4 @@
|
||||
#include "FoundResultsArgs.g.cpp"
|
||||
#include "ShowWindowArgs.g.cpp"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.cpp"
|
||||
#include "MenuChangedEventArgs.g.cpp"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "TitleChangedEventArgs.g.h"
|
||||
#include "CopyToClipboardEventArgs.g.h"
|
||||
#include "ContextMenuRequestedEventArgs.g.h"
|
||||
#include "PasteFromClipboardEventArgs.g.h"
|
||||
#include "OpenHyperlinkEventArgs.g.h"
|
||||
#include "NoticeEventArgs.g.h"
|
||||
@@ -14,6 +15,7 @@
|
||||
#include "FoundResultsArgs.g.h"
|
||||
#include "ShowWindowArgs.g.h"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.h"
|
||||
#include "MenuChangedEventArgs.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
@@ -53,6 +55,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Windows::Foundation::IReference<CopyFormat> _formats;
|
||||
};
|
||||
|
||||
struct ContextMenuRequestedEventArgs : public ContextMenuRequestedEventArgsT<ContextMenuRequestedEventArgs>
|
||||
{
|
||||
public:
|
||||
ContextMenuRequestedEventArgs(winrt::Windows::Foundation::Point point) :
|
||||
_Point(point) {}
|
||||
|
||||
WINRT_PROPERTY(winrt::Windows::Foundation::Point, Point);
|
||||
};
|
||||
|
||||
struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT<PasteFromClipboardEventArgs>
|
||||
{
|
||||
public:
|
||||
@@ -169,4 +180,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
WINRT_PROPERTY(bool, ClearMarkers, false);
|
||||
};
|
||||
|
||||
struct MenuChangedEventArgs : public MenuChangedEventArgsT<MenuChangedEventArgs>
|
||||
{
|
||||
public:
|
||||
MenuChangedEventArgs(const winrt::hstring menuJson, const int32_t replaceLength) :
|
||||
_MenuJson(menuJson),
|
||||
_ReplacementLength(replaceLength)
|
||||
{
|
||||
}
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, MenuJson, L"");
|
||||
WINRT_PROPERTY(int32_t, ReplacementLength, 0);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace Microsoft.Terminal.Control
|
||||
Windows.Foundation.IReference<CopyFormat> Formats { get; };
|
||||
}
|
||||
|
||||
runtimeclass ContextMenuRequestedEventArgs
|
||||
{
|
||||
Windows.Foundation.Point Point { get; };
|
||||
}
|
||||
|
||||
runtimeclass TitleChangedEventArgs
|
||||
{
|
||||
String Title;
|
||||
@@ -83,4 +88,10 @@ namespace Microsoft.Terminal.Control
|
||||
{
|
||||
Boolean ClearMarkers { get; };
|
||||
}
|
||||
|
||||
runtimeclass MenuChangedEventArgs
|
||||
{
|
||||
String MenuJson { get; };
|
||||
Int32 ReplacementLength { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,5 +61,6 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean SoftwareRendering { get; };
|
||||
Boolean ShowMarks { get; };
|
||||
Boolean UseBackgroundImageForWindow { get; };
|
||||
Boolean RightClickContextMenu { get; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace Microsoft.Terminal.Control
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(ScrollToMarkDirection direction);
|
||||
void SelectCommand(Boolean goUp);
|
||||
void SelectOutput(Boolean goUp);
|
||||
IVector<ScrollMark> ScrollMarks { get; };
|
||||
|
||||
};
|
||||
|
||||
@@ -208,4 +208,36 @@ Please either install the missing font or choose another one.</value>
|
||||
<value>No results found</value>
|
||||
<comment>Announced to a screen reader when the user searches for some text and there are no matches for that text in the terminal.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="PasteCommandButton.Label" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
<comment>The label of a button for pasting the contents of the clipboard.</comment>
|
||||
</data>
|
||||
<data name="PasteCommandButton.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
<comment>The tooltip for a paste button</comment>
|
||||
</data>
|
||||
<data name="CopyCommandButton.Label" xml:space="preserve">
|
||||
<value>Copy</value>
|
||||
<comment>The label of a button for copying the selected text to the clipboard.</comment>
|
||||
</data>
|
||||
<data name="CopyCommandButton.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Copy</value>
|
||||
<comment>The tooltip for a copy button</comment>
|
||||
</data>
|
||||
<data name="PasteWithSelectionCommandButton.Label" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
<comment>The label of a button for pasting the contents of the clipboard.</comment>
|
||||
</data>
|
||||
<data name="PasteWithSelectionCommandButton.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
<comment>The tooltip for a paste button</comment>
|
||||
</data>
|
||||
<data name="SearchCommandButton.Label" xml:space="preserve">
|
||||
<value>Find...</value>
|
||||
<comment>The label of a button for searching for the selected text</comment>
|
||||
</data>
|
||||
<data name="SearchCommandButton.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Find</value>
|
||||
<comment>The tooltip for a button for searching for the selected text</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -14,8 +14,6 @@ Author(s):
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "winrt/Windows.UI.Xaml.h"
|
||||
#include "winrt/Windows.UI.Xaml.Controls.h"
|
||||
|
||||
#include "SearchBoxControl.g.h"
|
||||
|
||||
|
||||
@@ -437,4 +437,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TSFInputControl::_formatUpdatingHandler(CoreTextEditContext sender, const CoreTextFormatUpdatingEventArgs& /*args*/)
|
||||
{
|
||||
}
|
||||
|
||||
void TSFInputControl::ManuallyDisplayText(const winrt::hstring& text)
|
||||
{
|
||||
_focused = !text.empty();
|
||||
Canvas().Visibility(text.empty() ? Visibility::Collapsed : Visibility::Visible);
|
||||
|
||||
_inputBuffer.clear();
|
||||
_activeTextStart = 0;
|
||||
_inComposition = false;
|
||||
|
||||
// HACK trim off leading DEL chars.
|
||||
std::wstring_view view{ text.c_str() };
|
||||
const auto strBegin = view.find_first_not_of(L"\x7f");
|
||||
if (strBegin != std::wstring::npos)
|
||||
{
|
||||
view = view.substr(strBegin * 2);
|
||||
}
|
||||
|
||||
TextBlock().Text(winrt::hstring{ view });
|
||||
TextBlock().UpdateLayout();
|
||||
TryRedrawCanvas();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ClearBuffer();
|
||||
void TryRedrawCanvas();
|
||||
|
||||
void ManuallyDisplayText(const winrt::hstring& text);
|
||||
|
||||
void Close();
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace Microsoft.Terminal.Control
|
||||
void ClearBuffer();
|
||||
void TryRedrawCanvas();
|
||||
|
||||
void ManuallyDisplayText(String text);
|
||||
|
||||
|
||||
void Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,38 @@ 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.MenuChanged = _core.MenuChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleMenuChanged });
|
||||
|
||||
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
||||
|
||||
_interactivity.ContextMenuRequested({ this, &TermControl::_contextMenuHandler });
|
||||
|
||||
// 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 +107,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,11 +141,101 @@ 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();
|
||||
|
||||
_originalPrimaryElements = winrt::single_threaded_observable_vector<Controls::ICommandBarElement>();
|
||||
_originalSecondaryElements = winrt::single_threaded_observable_vector<Controls::ICommandBarElement>();
|
||||
_originalSelectedPrimaryElements = winrt::single_threaded_observable_vector<Controls::ICommandBarElement>();
|
||||
_originalSelectedSecondaryElements = winrt::single_threaded_observable_vector<Controls::ICommandBarElement>();
|
||||
for (const auto& e : ContextMenu().PrimaryCommands())
|
||||
{
|
||||
_originalPrimaryElements.Append(e);
|
||||
}
|
||||
for (const auto& e : ContextMenu().SecondaryCommands())
|
||||
{
|
||||
_originalSecondaryElements.Append(e);
|
||||
}
|
||||
for (const auto& e : SelectionContextMenu().PrimaryCommands())
|
||||
{
|
||||
_originalSelectedPrimaryElements.Append(e);
|
||||
}
|
||||
for (const auto& e : SelectionContextMenu().SecondaryCommands())
|
||||
{
|
||||
_originalSelectedSecondaryElements.Append(e);
|
||||
}
|
||||
ContextMenu().Closed([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->ContextMenu().PrimaryCommands().Clear();
|
||||
control->ContextMenu().SecondaryCommands().Clear();
|
||||
for (const auto& e : control->_originalPrimaryElements)
|
||||
{
|
||||
control->ContextMenu().PrimaryCommands().Append(e);
|
||||
}
|
||||
for (const auto& e : control->_originalSecondaryElements)
|
||||
{
|
||||
control->ContextMenu().SecondaryCommands().Append(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
SelectionContextMenu().Closed([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto control{ weakThis.get() }; !control->_IsClosing())
|
||||
{
|
||||
control->SelectionContextMenu().PrimaryCommands().Clear();
|
||||
control->SelectionContextMenu().SecondaryCommands().Clear();
|
||||
for (const auto& e : control->_originalSelectedPrimaryElements)
|
||||
{
|
||||
control->SelectionContextMenu().PrimaryCommands().Append(e);
|
||||
}
|
||||
for (const auto& e : control->_originalSelectedSecondaryElements)
|
||||
{
|
||||
control->SelectionContextMenu().SecondaryCommands().Append(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -292,7 +393,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - Given Settings having been updated, applies the settings to the current terminal.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget TermControl::UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance)
|
||||
winrt::fire_and_forget TermControl::UpdateControlSettings(IControlSettings settings,
|
||||
IControlAppearance unfocusedAppearance)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
@@ -388,6 +490,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void TermControl::SendInput(const winrt::hstring& wstr)
|
||||
{
|
||||
PreviewInput(L"");
|
||||
_core.SendInput(wstr);
|
||||
}
|
||||
void TermControl::ClearBuffer(Control::ClearBufferType clearType)
|
||||
@@ -419,6 +522,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// settings might be out-of-proc in the future
|
||||
auto settings{ _core.Settings() };
|
||||
|
||||
_useRightClickContextMenu = settings.RightClickContextMenu();
|
||||
|
||||
// Apply padding as swapChainPanel's margin
|
||||
const auto newMargin = ParseThicknessFromPadding(settings.Padding());
|
||||
SwapChainPanel().Margin(newMargin);
|
||||
@@ -808,7 +913,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
nativePanel->SetSwapChainHandle(swapChainHandle);
|
||||
}
|
||||
|
||||
bool TermControl::_InitializeTerminal()
|
||||
bool TermControl::_InitializeTerminal(const bool reattach)
|
||||
{
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
@@ -832,18 +937,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 +1257,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 +2105,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 +2859,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 +3045,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 };
|
||||
@@ -3099,6 +3212,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return _core.ReadEntireBuffer();
|
||||
}
|
||||
Control::CommandHistoryContext TermControl::CommandHistory() const
|
||||
{
|
||||
return _core.CommandHistory();
|
||||
}
|
||||
|
||||
Core::Scheme TermControl::ColorScheme() const noexcept
|
||||
{
|
||||
@@ -3157,6 +3274,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.OwningHwnd();
|
||||
}
|
||||
|
||||
void TermControl::PreviewInput(const winrt::hstring& text)
|
||||
{
|
||||
TSFInputControl().ManuallyDisplayText(text);
|
||||
}
|
||||
|
||||
void TermControl::AddMark(const Control::ScrollMark& mark)
|
||||
{
|
||||
_core.AddMark(mark);
|
||||
@@ -3170,8 +3292,89 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.ScrollMarks();
|
||||
}
|
||||
|
||||
void TermControl::SelectCommand(const bool goUp)
|
||||
{
|
||||
_core.SelectCommand(goUp);
|
||||
}
|
||||
|
||||
void TermControl::SelectOutput(const bool goUp)
|
||||
{
|
||||
_core.SelectOutput(goUp);
|
||||
}
|
||||
|
||||
void TermControl::ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode)
|
||||
{
|
||||
_core.ColorSelection(fg, bg, matchMode);
|
||||
}
|
||||
|
||||
// Returns the text cursor's position relative to our origin, in DIPs.
|
||||
Microsoft::Terminal::Core::Point TermControl::CursorPositionInDips()
|
||||
{
|
||||
const til::point cursorPos{ _core.CursorPosition() };
|
||||
|
||||
const til::size fontSize{ til::math::flooring, CharacterDimensions() };
|
||||
|
||||
// Convert text buffer cursor position to client coordinate position
|
||||
// within the window. This point is in _pixels_
|
||||
const til::point clientCursorPos{ cursorPos * fontSize };
|
||||
|
||||
// Get scale factor for view
|
||||
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
|
||||
|
||||
const til::point clientCursorInDips{ til::math::flooring, clientCursorPos.x / scaleFactor, clientCursorPos.y / scaleFactor };
|
||||
|
||||
auto padding{ GetPadding() };
|
||||
til::point relativeToOrigin{ til::math::flooring,
|
||||
clientCursorInDips.x + padding.Left,
|
||||
clientCursorInDips.y + padding.Top };
|
||||
return relativeToOrigin.to_core_point();
|
||||
}
|
||||
|
||||
void TermControl::_contextMenuHandler(IInspectable /*sender*/,
|
||||
Control::ContextMenuRequestedEventArgs args)
|
||||
{
|
||||
Controls::Primitives::FlyoutShowOptions myOption{};
|
||||
myOption.ShowMode(Controls::Primitives::FlyoutShowMode::Standard);
|
||||
myOption.Placement(Controls::Primitives::FlyoutPlacementMode::TopEdgeAlignedLeft);
|
||||
|
||||
// Position the menu where the pointer is. This was the best way I found how.
|
||||
const til::point absolutePointerPos{ til::math::rounding, CoreWindow::GetForCurrentThread().PointerPosition() };
|
||||
const til::point absoluteWindowOrigin{ til::math::rounding,
|
||||
CoreWindow::GetForCurrentThread().Bounds().X,
|
||||
CoreWindow::GetForCurrentThread().Bounds().Y };
|
||||
// Get the offset (margin + tabs, etc..) of the control within the window
|
||||
const til::point controlOrigin{ til::math::flooring,
|
||||
this->TransformToVisual(nullptr).TransformPoint(Windows::Foundation::Point(0, 0)) };
|
||||
|
||||
const auto pos = (absolutePointerPos - absoluteWindowOrigin - controlOrigin).to_winrt_point();
|
||||
myOption.Position(pos);
|
||||
|
||||
(_core.HasSelection() ? SelectionContextMenu() :
|
||||
ContextMenu())
|
||||
.ShowAt(*this, myOption);
|
||||
}
|
||||
|
||||
void TermControl::_PasteCommandHandler(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*args*/)
|
||||
{
|
||||
_interactivity.RequestPasteTextFromClipboard();
|
||||
ContextMenu().Hide();
|
||||
SelectionContextMenu().Hide();
|
||||
}
|
||||
void TermControl::_CopyCommandHandler(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*args*/)
|
||||
{
|
||||
// formats = nullptr -> copy all formats
|
||||
_interactivity.CopySelectionToClipboard(false, nullptr);
|
||||
ContextMenu().Hide();
|
||||
SelectionContextMenu().Hide();
|
||||
}
|
||||
void TermControl::_SearchCommandHandler(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*args*/)
|
||||
{
|
||||
ContextMenu().Hide();
|
||||
SelectionContextMenu().Hide();
|
||||
SearchMatch(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -47,6 +51,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Windows::Foundation::Size MinimumSize();
|
||||
float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
|
||||
|
||||
void PreviewInput(const winrt::hstring& text);
|
||||
|
||||
Microsoft::Terminal::Core::Point CursorPositionInDips();
|
||||
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
void ColorSelection(Control::SelectionColor fg, Control::SelectionColor bg, Core::MatchMode matchMode);
|
||||
@@ -77,6 +85,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ClearMark();
|
||||
void ClearAllMarks();
|
||||
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
void SelectCommand(const bool goUp);
|
||||
void SelectOutput(const bool goUp);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
@@ -130,27 +140,32 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
static Windows::UI::Xaml::Thickness ParseThicknessFromPadding(const hstring padding);
|
||||
|
||||
hstring ReadEntireBuffer() const;
|
||||
Control::CommandHistoryContext CommandHistory() const;
|
||||
|
||||
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme) const noexcept;
|
||||
|
||||
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);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(MenuChanged, IInspectable, Control::MenuChangedEventArgs);
|
||||
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
@@ -160,6 +175,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TYPED_EVENT(FocusFollowMouseRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Initialized, Control::TermControl, Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(WarningBell, IInspectable, IInspectable);
|
||||
|
||||
// clang-format on
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::Media::Brush, BackgroundBrush, _PropertyChangedHandlers, nullptr);
|
||||
@@ -216,8 +232,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
bool _showMarksInScrollbar{ false };
|
||||
bool _useRightClickContextMenu{ false };
|
||||
bool _rightClickPressed{ false };
|
||||
|
||||
bool _isBackgroundLight{ false };
|
||||
bool _detached{ false };
|
||||
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalPrimaryElements{ nullptr };
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSecondaryElements{ nullptr };
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSelectedPrimaryElements{ nullptr };
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::UI::Xaml::Controls::ICommandBarElement> _originalSelectedSecondaryElements{ nullptr };
|
||||
|
||||
inline bool _IsClosing() const noexcept
|
||||
{
|
||||
@@ -243,7 +267,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 +339,43 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
til::point _toPosInDips(const Core::Point terminalCellPos);
|
||||
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
|
||||
|
||||
void _contextMenuHandler(IInspectable sender, Control::ContextMenuRequestedEventArgs args);
|
||||
|
||||
void _PasteCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
void _CopyCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
void _SearchCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
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;
|
||||
Control::ControlCore::MenuChanged_revoker MenuChanged;
|
||||
// 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;
|
||||
@@ -44,6 +51,10 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusFollowMouseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, MenuChangedEventArgs> MenuChanged;
|
||||
|
||||
Windows.UI.Xaml.Controls.CommandBarFlyout ContextMenu { get; };
|
||||
Windows.UI.Xaml.Controls.CommandBarFlyout SelectionContextMenu { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<TermControl, Windows.UI.Xaml.RoutedEventArgs> Initialized;
|
||||
// This is an event handler forwarder for the underlying connection.
|
||||
@@ -88,6 +99,7 @@ namespace Microsoft.Terminal.Control
|
||||
void ToggleReadOnly();
|
||||
|
||||
String ReadEntireBuffer();
|
||||
CommandHistoryContext CommandHistory();
|
||||
|
||||
void AdjustOpacity(Double Opacity, Boolean relative);
|
||||
|
||||
@@ -97,8 +109,15 @@ namespace Microsoft.Terminal.Control
|
||||
// opacity set by the settings should call this instead.
|
||||
Double BackgroundOpacity { get; };
|
||||
|
||||
void PreviewInput(String text);
|
||||
|
||||
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
void Detach();
|
||||
|
||||
Microsoft.Terminal.Core.Point CursorPositionInDips { get; };
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,30 @@
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
|
||||
<CommandBarFlyout x:Name="ContextMenu">
|
||||
<AppBarButton x:Name="PasteCommandButton"
|
||||
x:Uid="PasteCommandButton"
|
||||
Click="_PasteCommandHandler"
|
||||
Icon="Paste" />
|
||||
</CommandBarFlyout>
|
||||
|
||||
<CommandBarFlyout x:Name="SelectionContextMenu">
|
||||
<AppBarButton x:Name="CopyCommandButton"
|
||||
x:Uid="CopyCommandButton"
|
||||
Click="_CopyCommandHandler"
|
||||
Icon="Copy" />
|
||||
<AppBarButton x:Name="PasteWithSelectionCommandButton"
|
||||
x:Uid="PasteWithSelectionCommandButton"
|
||||
Click="_PasteCommandHandler"
|
||||
Icon="Paste" />
|
||||
<CommandBarFlyout.SecondaryCommands>
|
||||
<AppBarButton x:Name="SearchCommandButton"
|
||||
x:Uid="SearchCommandButton"
|
||||
Click="_SearchCommandHandler"
|
||||
Icon="Find" />
|
||||
</CommandBarFlyout.SecondaryCommands>
|
||||
</CommandBarFlyout>
|
||||
|
||||
<!--
|
||||
BODGY: ControlsV2 changed the size of the scrollbars from 16dips to
|
||||
12dips. This is harder for folks to hit with the mouse, and isn't
|
||||
@@ -1183,6 +1207,7 @@
|
||||
<Grid.Lights>
|
||||
<local:VisualBellLight x:Name="BellLight" />
|
||||
</Grid.Lights>
|
||||
|
||||
<Image x:Name="BackgroundImage"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
<Grid>
|
||||
@@ -1202,7 +1227,6 @@
|
||||
<SwapChainPanel x:Name="SwapChainPanel"
|
||||
CompositionScaleChanged="_SwapChainScaleChanged"
|
||||
SizeChanged="_SwapChainSizeChanged">
|
||||
|
||||
<Canvas x:Name="OverlayCanvas"
|
||||
Visibility="Visible">
|
||||
<Border x:Name="HyperlinkTooltipBorder"
|
||||
|
||||
@@ -68,6 +68,14 @@
|
||||
<DependentUpon>TSFInputControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XamlUiaTextRange.h" />
|
||||
|
||||
<ClInclude Include="BlockContent.h">
|
||||
<DependentUpon>BlockContent.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BlockControl.h">
|
||||
<DependentUpon>BlockControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -110,6 +118,14 @@
|
||||
<DependentUpon>InteractivityAutomationPeer.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XamlUiaTextRange.cpp" />
|
||||
|
||||
<ClCompile Include="BlockContent.cpp">
|
||||
<DependentUpon>BlockContent.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BlockControl.cpp">
|
||||
<DependentUpon>BlockControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -136,6 +152,12 @@
|
||||
<Midl Include="TSFInputControl.idl">
|
||||
<DependentUpon>TSFInputControl.xaml</DependentUpon>
|
||||
</Midl>
|
||||
|
||||
<Midl Include="BlockContent.idl" />
|
||||
<Midl Include="BlockControl.idl">
|
||||
<DependentUpon>BlockControl.xaml</DependentUpon>
|
||||
</Midl>
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= XAML Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -148,6 +170,11 @@
|
||||
<Page Include="TSFInputControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
|
||||
<Page Include="BlockControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
|
||||
@@ -490,9 +490,7 @@ void Terminal::Write(std::wstring_view stringView)
|
||||
const til::point cursorPosAfter{ cursor.GetPosition() };
|
||||
|
||||
// Firing the CursorPositionChanged event is very expensive so we try not to
|
||||
// do that when the cursor does not need to be redrawn. We don't do this
|
||||
// inside _AdjustCursorPosition, only once we're done writing the whole run
|
||||
// of output.
|
||||
// do that when the cursor does not need to be redrawn.
|
||||
if (cursorPosBefore != cursorPosAfter)
|
||||
{
|
||||
_NotifyTerminalCursorPositionChanged();
|
||||
@@ -1078,146 +1076,16 @@ Viewport Terminal::_GetVisibleViewport() const noexcept
|
||||
size);
|
||||
}
|
||||
|
||||
void Terminal::_AdjustCursorPosition(const til::point proposedPosition)
|
||||
void Terminal::_PreserveUserScrollOffset(const int viewportDelta) noexcept
|
||||
{
|
||||
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
|
||||
auto proposedCursorPosition = proposedPosition;
|
||||
auto& cursor = _activeBuffer().GetCursor();
|
||||
const auto bufferSize = _activeBuffer().GetSize();
|
||||
|
||||
// If we're about to scroll past the bottom of the buffer, instead cycle the
|
||||
// buffer.
|
||||
til::CoordType rowsPushedOffTopOfBuffer = 0;
|
||||
const auto newRows = std::max(0, proposedCursorPosition.y - bufferSize.Height() + 1);
|
||||
if (proposedCursorPosition.y >= bufferSize.Height())
|
||||
// When the mutable viewport is moved down, and there's an active selection,
|
||||
// or the visible viewport isn't already at the bottom, then we want to keep
|
||||
// the visible viewport where it is. To do this, we adjust the scroll offset
|
||||
// by the same amount that we've just moved down.
|
||||
if (viewportDelta > 0 && (IsSelectionActive() || _scrollOffset != 0))
|
||||
{
|
||||
for (auto dy = 0; dy < newRows; dy++)
|
||||
{
|
||||
_activeBuffer().IncrementCircularBuffer();
|
||||
proposedCursorPosition.y--;
|
||||
rowsPushedOffTopOfBuffer++;
|
||||
|
||||
// Update our selection too, so it doesn't move as the buffer is cycled
|
||||
if (_selection)
|
||||
{
|
||||
// Stash this, so we can make sure to update the pivot to match later
|
||||
const auto pivotWasStart = _selection->start == _selection->pivot;
|
||||
// If the start of the selection is above 0, we can reduce both the start and end by 1
|
||||
if (_selection->start.y > 0)
|
||||
{
|
||||
_selection->start.y -= 1;
|
||||
_selection->end.y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The start of the selection is at 0, if the end is greater than 0, then only reduce the end
|
||||
if (_selection->end.y > 0)
|
||||
{
|
||||
_selection->start.x = 0;
|
||||
_selection->end.y -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both the start and end of the selection are at 0, clear the selection
|
||||
_selection.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// If we still have a selection, make sure to sync the pivot
|
||||
// with whichever value is the right one.
|
||||
//
|
||||
// Failure to do this might lead to GH #14462
|
||||
if (_selection.has_value())
|
||||
{
|
||||
_selection->pivot = pivotWasStart ? _selection->start : _selection->end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// manually erase our pattern intervals since the locations have changed now
|
||||
_patternIntervalTree = {};
|
||||
}
|
||||
|
||||
// Update Cursor Position
|
||||
cursor.SetPosition(proposedCursorPosition);
|
||||
|
||||
// Move the viewport down if the cursor moved below the viewport.
|
||||
// Obviously, don't need to do this in the alt buffer.
|
||||
if (!_inAltBuffer())
|
||||
{
|
||||
auto updatedViewport = false;
|
||||
const auto scrollAmount = std::max(0, proposedCursorPosition.y - _mutableViewport.BottomInclusive());
|
||||
if (scrollAmount > 0)
|
||||
{
|
||||
const auto newViewTop = std::max(0, proposedCursorPosition.y - (_mutableViewport.Height() - 1));
|
||||
// In the alt buffer, we never need to adjust _mutableViewport, which is the viewport of the main buffer.
|
||||
if (newViewTop != _mutableViewport.Top())
|
||||
{
|
||||
_mutableViewport = Viewport::FromDimensions({ 0, newViewTop },
|
||||
_mutableViewport.Dimensions());
|
||||
updatedViewport = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the viewport moved, or we circled the buffer, we might need to update
|
||||
// our _scrollOffset
|
||||
if (updatedViewport || newRows != 0)
|
||||
{
|
||||
const auto oldScrollOffset = _scrollOffset;
|
||||
|
||||
// scroll if...
|
||||
// - no selection is active
|
||||
// - viewport is already at the bottom
|
||||
const auto scrollToOutput = !IsSelectionActive() && _scrollOffset == 0;
|
||||
|
||||
_scrollOffset = scrollToOutput ? 0 : _scrollOffset + scrollAmount + newRows;
|
||||
|
||||
// Clamp the range to make sure that we don't scroll way off the top of the buffer
|
||||
_scrollOffset = std::clamp(_scrollOffset,
|
||||
0,
|
||||
_activeBuffer().GetSize().Height() - _mutableViewport.Height());
|
||||
|
||||
// If the new scroll offset is different, then we'll still want to raise a scroll event
|
||||
updatedViewport = updatedViewport || (oldScrollOffset != _scrollOffset);
|
||||
}
|
||||
|
||||
// If the viewport moved, then send a scrolling notification.
|
||||
if (updatedViewport)
|
||||
{
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
}
|
||||
|
||||
if (rowsPushedOffTopOfBuffer != 0)
|
||||
{
|
||||
if (_scrollMarks.size() > 0)
|
||||
{
|
||||
for (auto& mark : _scrollMarks)
|
||||
{
|
||||
// Move the mark up
|
||||
mark.start.y -= rowsPushedOffTopOfBuffer;
|
||||
|
||||
// If the mark had sub-regions, then move those pointers too
|
||||
if (mark.commandEnd.has_value())
|
||||
{
|
||||
(*mark.commandEnd).y -= rowsPushedOffTopOfBuffer;
|
||||
}
|
||||
if (mark.outputEnd.has_value())
|
||||
{
|
||||
(*mark.outputEnd).y -= rowsPushedOffTopOfBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(),
|
||||
_scrollMarks.end(),
|
||||
[](const VirtualTerminal::DispatchTypes::ScrollMark& m) { return m.start.y < 0; }),
|
||||
_scrollMarks.end());
|
||||
}
|
||||
// We have to report the delta here because we might have circled the text buffer.
|
||||
// That didn't change the viewport and therefore the TriggerScroll(void)
|
||||
// method can't detect the delta on its own.
|
||||
const til::point delta{ 0, -rowsPushedOffTopOfBuffer };
|
||||
_activeBuffer().TriggerScroll(delta);
|
||||
const auto maxScrollOffset = _activeBuffer().GetSize().Height() - _mutableViewport.Height();
|
||||
_scrollOffset = std::min(_scrollOffset + viewportDelta, maxScrollOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1411,6 +1279,11 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe
|
||||
return _taskbarProgress;
|
||||
}
|
||||
|
||||
void Microsoft::Terminal::Core::Terminal::MenuChangedCallback(std::function<void(std::wstring_view, int32_t)> pfn) noexcept
|
||||
{
|
||||
_pfnMenuChanged.swap(pfn);
|
||||
}
|
||||
|
||||
Scheme Terminal::GetColorScheme() const
|
||||
{
|
||||
Scheme s;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include <til/ticket_lock.h>
|
||||
|
||||
#include "../../inc/cppwinrt_utils.h"
|
||||
|
||||
static constexpr std::wstring_view linkPattern{ LR"(\b(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|$!:,.;]*[A-Za-z0-9+&@#/%=~_|$])" };
|
||||
static constexpr size_t TaskbarMinProgress{ 10 };
|
||||
|
||||
@@ -113,10 +115,8 @@ public:
|
||||
void SetTextAttributes(const TextAttribute& attrs) noexcept override;
|
||||
void SetAutoWrapMode(const bool wrapAtEOL) noexcept override;
|
||||
bool GetAutoWrapMode() const noexcept override;
|
||||
void SetScrollingRegion(const til::inclusive_rect& scrollMargins) noexcept override;
|
||||
void WarningBell() override;
|
||||
bool GetLineFeedMode() const noexcept override;
|
||||
void LineFeed(const bool withReturn, const bool wrapForced) override;
|
||||
void SetWindowTitle(const std::wstring_view title) override;
|
||||
CursorType GetUserDefaultCursorStyle() const noexcept override;
|
||||
bool ResizeWindow(const til::CoordType width, const til::CoordType height) noexcept override;
|
||||
@@ -140,6 +140,11 @@ public:
|
||||
bool IsConsolePty() const noexcept override;
|
||||
bool IsVtInputEnabled() const noexcept override;
|
||||
void NotifyAccessibilityChange(const til::rect& changedRect) noexcept override;
|
||||
|
||||
void NotifyBufferRotation(const int delta) override;
|
||||
|
||||
void InvokeMenu(std::wstring_view menuJson, int32_t replaceLength) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void ClearMark();
|
||||
@@ -213,6 +218,7 @@ public:
|
||||
void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
|
||||
void SetShowWindowCallback(std::function<void(bool)> pfn) noexcept;
|
||||
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
|
||||
void MenuChangedCallback(std::function<void(std::wstring_view, int32_t)> pfn) noexcept;
|
||||
|
||||
void SetCursorOn(const bool isOn);
|
||||
bool IsCursorBlinkingAllowed() const noexcept;
|
||||
@@ -310,6 +316,7 @@ private:
|
||||
std::function<void()> _pfnTaskbarProgressChanged;
|
||||
std::function<void(bool)> _pfnShowWindowChanged;
|
||||
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
|
||||
std::function<void(std::wstring_view, int32_t)> _pfnMenuChanged;
|
||||
|
||||
RenderSettings _renderSettings;
|
||||
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
|
||||
@@ -333,7 +340,7 @@ private:
|
||||
|
||||
size_t _hyperlinkPatternId = 0;
|
||||
|
||||
std::wstring _workingDirectory;
|
||||
std::wstring _workingDirectory{};
|
||||
|
||||
// This default fake font value is only used to check if the font is a raster font.
|
||||
// Otherwise, the font is changed to a real value with the renderer via TriggerFontChange.
|
||||
@@ -351,7 +358,7 @@ private:
|
||||
};
|
||||
std::optional<SelectionAnchors> _selection;
|
||||
bool _blockSelection = false;
|
||||
std::wstring _wordDelimiters;
|
||||
std::wstring _wordDelimiters{};
|
||||
SelectionExpansion _multiClickSelectionMode = SelectionExpansion::Char;
|
||||
SelectionInteractionMode _selectionMode = SelectionInteractionMode::None;
|
||||
bool _selectionIsTargetingUrl = false;
|
||||
@@ -420,7 +427,7 @@ private:
|
||||
Microsoft::Console::Types::Viewport _GetMutableViewport() const noexcept;
|
||||
Microsoft::Console::Types::Viewport _GetVisibleViewport() const noexcept;
|
||||
|
||||
void _AdjustCursorPosition(const til::point proposedPosition);
|
||||
void _PreserveUserScrollOffset(const int viewportDelta) noexcept;
|
||||
|
||||
void _NotifyScrollEvent() noexcept;
|
||||
|
||||
@@ -444,6 +451,8 @@ private:
|
||||
void _MoveByBuffer(SelectionDirection direction, til::point& pos) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
WINRT_CALLBACK(NewPrompt, winrt::delegate<const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark&>);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalCoreUnitTests::TerminalBufferTests;
|
||||
friend class TerminalCoreUnitTests::TerminalApiTest;
|
||||
|
||||
@@ -48,9 +48,11 @@ void Terminal::SetViewportPosition(const til::point position) noexcept
|
||||
// The viewport is fixed at 0,0 for the alt buffer, so this is a no-op.
|
||||
if (!_inAltBuffer())
|
||||
{
|
||||
const auto viewportDelta = position.y - _GetMutableViewport().Origin().y;
|
||||
const auto dimensions = _GetMutableViewport().Dimensions();
|
||||
_mutableViewport = Viewport::FromDimensions(position, dimensions);
|
||||
Terminal::_NotifyScrollEvent();
|
||||
_PreserveUserScrollOffset(viewportDelta);
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +72,6 @@ bool Terminal::GetAutoWrapMode() const noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
void Terminal::SetScrollingRegion(const til::inclusive_rect& /*scrollMargins*/) noexcept
|
||||
{
|
||||
// TODO: This will be needed to fully support DECSTBM.
|
||||
}
|
||||
|
||||
void Terminal::WarningBell()
|
||||
{
|
||||
_pfnWarningBell();
|
||||
@@ -86,22 +83,6 @@ bool Terminal::GetLineFeedMode() const noexcept
|
||||
return false;
|
||||
}
|
||||
|
||||
void Terminal::LineFeed(const bool withReturn, const bool wrapForced)
|
||||
{
|
||||
auto cursorPos = _activeBuffer().GetCursor().GetPosition();
|
||||
|
||||
// If the line was forced to wrap, set the wrap status.
|
||||
// When explicitly moving down a row, clear the wrap status.
|
||||
_activeBuffer().GetRowByOffset(cursorPos.y).SetWrapForced(wrapForced);
|
||||
|
||||
cursorPos.y++;
|
||||
if (withReturn)
|
||||
{
|
||||
cursorPos.x = 0;
|
||||
}
|
||||
_AdjustCursorPosition(cursorPos);
|
||||
}
|
||||
|
||||
void Terminal::SetWindowTitle(const std::wstring_view title)
|
||||
{
|
||||
if (!_suppressApplicationTitle)
|
||||
@@ -349,6 +330,8 @@ void Terminal::MarkPrompt(const DispatchTypes::ScrollMark& mark)
|
||||
{
|
||||
_currentPromptState = PromptState::Prompt;
|
||||
}
|
||||
|
||||
_NewPromptHandlers(mark);
|
||||
}
|
||||
|
||||
void Terminal::MarkCommandStart()
|
||||
@@ -467,3 +450,70 @@ void Terminal::NotifyAccessibilityChange(const til::rect& /*changedRect*/) noexc
|
||||
{
|
||||
// This is only needed in conhost. Terminal handles accessibility in another way.
|
||||
}
|
||||
|
||||
void Terminal::NotifyBufferRotation(const int delta)
|
||||
{
|
||||
// Update our selection, so it doesn't move as the buffer is cycled
|
||||
if (_selection)
|
||||
{
|
||||
// If the end of the selection will be out of range after the move, we just
|
||||
// clear the selection. Otherwise we move both the start and end points up
|
||||
// by the given delta and clamp to the first row.
|
||||
if (_selection->end.y < delta)
|
||||
{
|
||||
_selection.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stash this, so we can make sure to update the pivot to match later.
|
||||
const auto pivotWasStart = _selection->start == _selection->pivot;
|
||||
_selection->start.y = std::max(_selection->start.y - delta, 0);
|
||||
_selection->end.y = std::max(_selection->end.y - delta, 0);
|
||||
// Make sure to sync the pivot with whichever value is the right one.
|
||||
_selection->pivot = pivotWasStart ? _selection->start : _selection->end;
|
||||
}
|
||||
}
|
||||
|
||||
// manually erase our pattern intervals since the locations have changed now
|
||||
_patternIntervalTree = {};
|
||||
|
||||
const auto hasScrollMarks = _scrollMarks.size() > 0;
|
||||
if (hasScrollMarks)
|
||||
{
|
||||
for (auto& mark : _scrollMarks)
|
||||
{
|
||||
// Move the mark up
|
||||
mark.start.y -= delta;
|
||||
|
||||
// If the mark had sub-regions, then move those pointers too
|
||||
if (mark.commandEnd.has_value())
|
||||
{
|
||||
(*mark.commandEnd).y -= delta;
|
||||
}
|
||||
if (mark.outputEnd.has_value())
|
||||
{
|
||||
(*mark.outputEnd).y -= delta;
|
||||
}
|
||||
}
|
||||
|
||||
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(),
|
||||
_scrollMarks.end(),
|
||||
[](const auto& m) { return m.start.y < 0; }),
|
||||
_scrollMarks.end());
|
||||
}
|
||||
|
||||
const auto oldScrollOffset = _scrollOffset;
|
||||
_PreserveUserScrollOffset(delta);
|
||||
if (_scrollOffset != oldScrollOffset || hasScrollMarks)
|
||||
{
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::InvokeMenu(std::wstring_view menuJson, int32_t replaceLength)
|
||||
{
|
||||
if (_pfnMenuChanged)
|
||||
{
|
||||
_pfnMenuChanged(menuJson, replaceLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
// it after some of our C++/WinRT headers.
|
||||
#define BLOCK_TIL
|
||||
#include <LibraryIncludes.h>
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
|
||||
#include "winrt/Microsoft.Terminal.Core.h"
|
||||
|
||||
@@ -52,6 +52,7 @@ static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
|
||||
static constexpr std::string_view TabSearchKey{ "tabSearch" };
|
||||
static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" };
|
||||
static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" };
|
||||
static constexpr std::string_view SuggestionsKey{ "suggestions" };
|
||||
static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" };
|
||||
static constexpr std::string_view SetFocusModeKey{ "setFocusMode" };
|
||||
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
|
||||
@@ -81,6 +82,8 @@ static constexpr std::string_view QuitKey{ "quit" };
|
||||
static constexpr std::string_view AdjustOpacityKey{ "adjustOpacity" };
|
||||
static constexpr std::string_view RestoreLastClosedKey{ "restoreLastClosed" };
|
||||
static constexpr std::string_view SelectAllKey{ "selectAll" };
|
||||
static constexpr std::string_view SelectCommandKey{ "selectCommand" };
|
||||
static constexpr std::string_view SelectOutputKey{ "selectOutput" };
|
||||
static constexpr std::string_view MarkModeKey{ "markMode" };
|
||||
static constexpr std::string_view ToggleBlockSelectionKey{ "toggleBlockSelection" };
|
||||
static constexpr std::string_view SwitchSelectionEndpointKey{ "switchSelectionEndpoint" };
|
||||
@@ -327,22 +330,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring ActionAndArgs::GenerateName() const
|
||||
{
|
||||
// Sentinel used to indicate this command must ALWAYS be generated by GenerateName
|
||||
static const winrt::hstring MustGenerate{ L"" };
|
||||
// Use a magic static to initialize this map, because we won't be able
|
||||
// to load the resources at _init_, only at runtime.
|
||||
static const auto GeneratedActionNames = []() {
|
||||
return std::unordered_map<ShortcutAction, winrt::hstring>{
|
||||
{ ShortcutAction::AdjustFontSize, RS_(L"AdjustFontSizeCommandKey") },
|
||||
{ ShortcutAction::CloseOtherPanes, RS_(L"CloseOtherPanesCommandKey") },
|
||||
{ ShortcutAction::CloseOtherTabs, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::CloseOtherTabs, MustGenerate },
|
||||
{ ShortcutAction::ClosePane, RS_(L"ClosePaneCommandKey") },
|
||||
{ ShortcutAction::CloseTab, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::CloseTabsAfter, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::CloseTab, MustGenerate },
|
||||
{ ShortcutAction::CloseTabsAfter, MustGenerate },
|
||||
{ ShortcutAction::CloseWindow, RS_(L"CloseWindowCommandKey") },
|
||||
{ ShortcutAction::CopyText, RS_(L"CopyTextCommandKey") },
|
||||
{ ShortcutAction::DuplicateTab, RS_(L"DuplicateTabCommandKey") },
|
||||
{ ShortcutAction::ExecuteCommandline, RS_(L"ExecuteCommandlineCommandKey") },
|
||||
{ ShortcutAction::Find, RS_(L"FindCommandKey") },
|
||||
{ ShortcutAction::Invalid, L"" },
|
||||
{ ShortcutAction::Invalid, MustGenerate },
|
||||
{ ShortcutAction::MoveFocus, RS_(L"MoveFocusCommandKey") },
|
||||
{ ShortcutAction::MovePane, RS_(L"MovePaneCommandKey") },
|
||||
{ ShortcutAction::SwapPane, RS_(L"SwapPaneCommandKey") },
|
||||
@@ -367,46 +372,49 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{ ShortcutAction::AddMark, RS_(L"AddMarkCommandKey") },
|
||||
{ ShortcutAction::ClearMark, RS_(L"ClearMarkCommandKey") },
|
||||
{ ShortcutAction::ClearAllMarks, RS_(L"ClearAllMarksCommandKey") },
|
||||
{ ShortcutAction::SendInput, L"" },
|
||||
{ ShortcutAction::SetColorScheme, L"" },
|
||||
{ ShortcutAction::SendInput, MustGenerate },
|
||||
{ ShortcutAction::SetColorScheme, MustGenerate },
|
||||
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
|
||||
{ ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") },
|
||||
{ ShortcutAction::SwitchToTab, RS_(L"SwitchToTabCommandKey") },
|
||||
{ ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") },
|
||||
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
|
||||
{ ShortcutAction::ToggleCommandPalette, L"" },
|
||||
{ ShortcutAction::ToggleCommandPalette, MustGenerate },
|
||||
{ ShortcutAction::Suggestions, MustGenerate },
|
||||
{ ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") },
|
||||
{ ShortcutAction::SetFocusMode, L"" },
|
||||
{ ShortcutAction::SetFocusMode, MustGenerate },
|
||||
{ ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") },
|
||||
{ ShortcutAction::SetFullScreen, L"" },
|
||||
{ ShortcutAction::SetMaximized, L"" },
|
||||
{ ShortcutAction::SetFullScreen, MustGenerate },
|
||||
{ ShortcutAction::SetMaximized, MustGenerate },
|
||||
{ ShortcutAction::TogglePaneZoom, RS_(L"TogglePaneZoomCommandKey") },
|
||||
{ ShortcutAction::ToggleSplitOrientation, RS_(L"ToggleSplitOrientationCommandKey") },
|
||||
{ ShortcutAction::ToggleShaderEffects, RS_(L"ToggleShaderEffectsCommandKey") },
|
||||
{ ShortcutAction::MoveTab, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::MoveTab, MustGenerate },
|
||||
{ ShortcutAction::BreakIntoDebugger, RS_(L"BreakIntoDebuggerCommandKey") },
|
||||
{ ShortcutAction::FindMatch, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::FindMatch, MustGenerate },
|
||||
{ ShortcutAction::TogglePaneReadOnly, RS_(L"TogglePaneReadOnlyCommandKey") },
|
||||
{ ShortcutAction::NewWindow, RS_(L"NewWindowCommandKey") },
|
||||
{ ShortcutAction::IdentifyWindow, RS_(L"IdentifyWindowCommandKey") },
|
||||
{ ShortcutAction::IdentifyWindows, RS_(L"IdentifyWindowsCommandKey") },
|
||||
{ ShortcutAction::RenameWindow, RS_(L"ResetWindowNameCommandKey") },
|
||||
{ ShortcutAction::OpenWindowRenamer, RS_(L"OpenWindowRenamerCommandKey") },
|
||||
{ ShortcutAction::GlobalSummon, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::GlobalSummon, MustGenerate },
|
||||
{ ShortcutAction::QuakeMode, RS_(L"QuakeModeCommandKey") },
|
||||
{ ShortcutAction::FocusPane, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::FocusPane, MustGenerate },
|
||||
{ ShortcutAction::OpenSystemMenu, RS_(L"OpenSystemMenuCommandKey") },
|
||||
{ ShortcutAction::ExportBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::ClearBuffer, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::MultipleActions, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::ExportBuffer, MustGenerate },
|
||||
{ ShortcutAction::ClearBuffer, MustGenerate },
|
||||
{ ShortcutAction::MultipleActions, MustGenerate },
|
||||
{ ShortcutAction::Quit, RS_(L"QuitCommandKey") },
|
||||
{ ShortcutAction::AdjustOpacity, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::AdjustOpacity, MustGenerate },
|
||||
{ ShortcutAction::RestoreLastClosed, RS_(L"RestoreLastClosedCommandKey") },
|
||||
{ ShortcutAction::SelectCommand, MustGenerate },
|
||||
{ ShortcutAction::SelectOutput, MustGenerate },
|
||||
{ ShortcutAction::SelectAll, RS_(L"SelectAllCommandKey") },
|
||||
{ ShortcutAction::MarkMode, RS_(L"MarkModeCommandKey") },
|
||||
{ ShortcutAction::ToggleBlockSelection, RS_(L"ToggleBlockSelectionCommandKey") },
|
||||
{ ShortcutAction::SwitchSelectionEndpoint, RS_(L"SwitchSelectionEndpointCommandKey") },
|
||||
{ ShortcutAction::ColorSelection, L"" }, // Intentionally omitted, must be generated by GenerateName
|
||||
{ ShortcutAction::ColorSelection, MustGenerate },
|
||||
{ ShortcutAction::ExpandSelectionToWord, RS_(L"ExpandSelectionToWordCommandKey") },
|
||||
};
|
||||
}();
|
||||
@@ -423,4 +431,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,11 +29,11 @@
|
||||
#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"
|
||||
#include "ToggleCommandPaletteArgs.g.cpp"
|
||||
#include "SuggestionsArgs.g.cpp"
|
||||
#include "NewWindowArgs.g.cpp"
|
||||
#include "PrevTabArgs.g.cpp"
|
||||
#include "NextTabArgs.g.cpp"
|
||||
@@ -43,6 +44,8 @@
|
||||
#include "ClearBufferArgs.g.cpp"
|
||||
#include "MultipleActionsArgs.g.cpp"
|
||||
#include "AdjustOpacityArgs.g.cpp"
|
||||
#include "SelectCommandArgs.g.cpp"
|
||||
#include "SelectOutputArgs.g.cpp"
|
||||
#include "ColorSelectionArgs.g.cpp"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
@@ -245,6 +248,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 +657,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())
|
||||
{
|
||||
@@ -673,6 +690,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
return RS_(L"ToggleCommandPaletteCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring SuggestionsArgs::GenerateName() const
|
||||
{
|
||||
switch (Source())
|
||||
{
|
||||
case SuggestionsSource::CommandHistory:
|
||||
return RS_(L"SuggestionsCommandHistoryCommandKey");
|
||||
}
|
||||
return RS_(L"SuggestionsCommandKey");
|
||||
}
|
||||
|
||||
winrt::hstring FindMatchArgs::GenerateName() const
|
||||
{
|
||||
switch (Direction())
|
||||
@@ -956,4 +983,27 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring SelectOutputArgs::GenerateName() const
|
||||
{
|
||||
switch (Direction())
|
||||
{
|
||||
case SelectOutputDirection::Next:
|
||||
return RS_(L"SelectOutputNextCommandKey");
|
||||
case SelectOutputDirection::Previous:
|
||||
return RS_(L"SelectOutputPreviousCommandKey");
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
winrt::hstring SelectCommandArgs::GenerateName() const
|
||||
{
|
||||
switch (Direction())
|
||||
{
|
||||
case SelectOutputDirection::Next:
|
||||
return RS_(L"SelectCommandNextCommandKey");
|
||||
case SelectOutputDirection::Previous:
|
||||
return RS_(L"SelectCommandPreviousCommandKey");
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "AddMarkArgs.g.h"
|
||||
#include "MoveTabArgs.g.h"
|
||||
#include "ToggleCommandPaletteArgs.g.h"
|
||||
#include "SuggestionsArgs.g.h"
|
||||
#include "FindMatchArgs.g.h"
|
||||
#include "NewWindowArgs.g.h"
|
||||
#include "PrevTabArgs.g.h"
|
||||
@@ -45,6 +46,8 @@
|
||||
#include "ClearBufferArgs.g.h"
|
||||
#include "MultipleActionsArgs.g.h"
|
||||
#include "AdjustOpacityArgs.g.h"
|
||||
#include "SelectCommandArgs.g.h"
|
||||
#include "SelectOutputArgs.g.h"
|
||||
#include "ColorSelectionArgs.g.h"
|
||||
|
||||
#include "JsonUtils.h"
|
||||
@@ -96,8 +99,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 +176,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) \
|
||||
@@ -195,6 +206,10 @@ private:
|
||||
#define TOGGLE_COMMAND_PALETTE_ARGS(X) \
|
||||
X(CommandPaletteLaunchMode, LaunchMode, "launchMode", false, CommandPaletteLaunchMode::Action)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SUGGESTIONS_ARGS(X) \
|
||||
X(SuggestionsSource, Source, "source", false, SuggestionsSource::Tasks)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define FIND_MATCH_ARGS(X) \
|
||||
X(FindMatchDirection, Direction, "direction", args->Direction() == FindMatchDirection::None, FindMatchDirection::None)
|
||||
@@ -236,6 +251,14 @@ private:
|
||||
X(int32_t, Opacity, "opacity", false, 0) \
|
||||
X(bool, Relative, "relative", false, true)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SELECT_COMMAND_ARGS(X) \
|
||||
X(SelectOutputDirection, Direction, "direction", false, SelectOutputDirection::Previous)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define SELECT_OUTPUT_ARGS(X) \
|
||||
X(SelectOutputDirection, Direction, "direction", false, SelectOutputDirection::Previous)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define COLOR_SELECTION_ARGS(X) \
|
||||
X(winrt::Microsoft::Terminal::Control::SelectionColor, Foreground, "foreground", false, nullptr) \
|
||||
@@ -276,6 +299,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 +310,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 +329,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 +347,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 +367,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 +382,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 +402,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
h.write(SuppressApplicationTitle());
|
||||
h.write(ColorScheme());
|
||||
h.write(Elevate());
|
||||
h.write(ContentGuid());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -649,6 +679,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
ACTION_ARGS_STRUCT(ToggleCommandPaletteArgs, TOGGLE_COMMAND_PALETTE_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(SuggestionsArgs, SUGGESTIONS_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(FindMatchArgs, FIND_MATCH_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(PrevTabArgs, PREV_TAB_ARGS);
|
||||
@@ -734,6 +766,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
ACTION_ARGS_STRUCT(AdjustOpacityArgs, ADJUST_OPACITY_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(SelectCommandArgs, SELECT_COMMAND_ARGS);
|
||||
ACTION_ARGS_STRUCT(SelectOutputArgs, SELECT_OUTPUT_ARGS);
|
||||
|
||||
ACTION_ARGS_STRUCT(ColorSelectionArgs, COLOR_SELECTION_ARGS);
|
||||
|
||||
}
|
||||
@@ -741,6 +776,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(ActionEventArgs);
|
||||
BASIC_FACTORY(CopyTextArgs);
|
||||
BASIC_FACTORY(SwitchToTabArgs);
|
||||
BASIC_FACTORY(NewTerminalArgs);
|
||||
BASIC_FACTORY(NewTabArgs);
|
||||
@@ -750,6 +786,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||
BASIC_FACTORY(RenameTabArgs);
|
||||
BASIC_FACTORY(SwapPaneArgs);
|
||||
BASIC_FACTORY(SplitPaneArgs);
|
||||
BASIC_FACTORY(SendInputArgs);
|
||||
BASIC_FACTORY(SetFocusModeArgs);
|
||||
BASIC_FACTORY(SetFullScreenArgs);
|
||||
BASIC_FACTORY(SetMaximizedArgs);
|
||||
@@ -770,4 +807,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||
BASIC_FACTORY(ClearBufferArgs);
|
||||
BASIC_FACTORY(MultipleActionsArgs);
|
||||
BASIC_FACTORY(AdjustOpacityArgs);
|
||||
BASIC_FACTORY(SuggestionsArgs);
|
||||
BASIC_FACTORY(SelectCommandArgs);
|
||||
BASIC_FACTORY(SelectOutputArgs);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,12 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Previous
|
||||
};
|
||||
|
||||
enum SelectOutputDirection
|
||||
{
|
||||
Previous = 0,
|
||||
Next,
|
||||
};
|
||||
|
||||
enum CommandPaletteLaunchMode
|
||||
{
|
||||
Action = 0,
|
||||
@@ -106,6 +112,12 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
ToCurrent,
|
||||
ToMouse,
|
||||
};
|
||||
enum SuggestionsSource
|
||||
{
|
||||
Tasks,
|
||||
CommandHistory,
|
||||
DirectoryHistory,
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass NewTerminalArgs {
|
||||
NewTerminalArgs();
|
||||
@@ -132,6 +144,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();
|
||||
@@ -146,6 +160,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass CopyTextArgs : IActionArgs
|
||||
{
|
||||
CopyTextArgs();
|
||||
Boolean SingleLine { get; };
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Control.CopyFormat> CopyFormatting { get; };
|
||||
};
|
||||
@@ -158,8 +173,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
|
||||
@@ -192,6 +208,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass SendInputArgs : IActionArgs
|
||||
{
|
||||
SendInputArgs(String input);
|
||||
|
||||
String Input { get; };
|
||||
};
|
||||
|
||||
@@ -276,8 +294,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
|
||||
@@ -306,6 +325,13 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
CommandPaletteLaunchMode LaunchMode { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SuggestionsArgs : IActionArgs
|
||||
{
|
||||
SuggestionsArgs();
|
||||
SuggestionsArgs(SuggestionsSource source);
|
||||
SuggestionsSource Source { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass FindMatchArgs : IActionArgs
|
||||
{
|
||||
FindMatchArgs(FindMatchDirection direction);
|
||||
@@ -384,4 +410,17 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Microsoft.Terminal.Control.SelectionColor Background;
|
||||
Microsoft.Terminal.Core.MatchMode MatchMode { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SelectCommandArgs : IActionArgs
|
||||
{
|
||||
SelectCommandArgs(SelectOutputDirection direction);
|
||||
SelectOutputDirection Direction { get; };
|
||||
}
|
||||
[default_interface] runtimeclass SelectOutputArgs : IActionArgs
|
||||
{
|
||||
SelectOutputArgs(SelectOutputDirection direction);
|
||||
SelectOutputDirection Direction { get; };
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
#include "pch.h"
|
||||
#include "AllShortcutActions.h"
|
||||
#include "ActionMap.h"
|
||||
#include "Command.h"
|
||||
#include "AllShortcutActions.h"
|
||||
|
||||
#include "ActionMap.g.cpp"
|
||||
|
||||
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 +120,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 +174,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 +285,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 +294,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 +856,79 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
cmd->ActionAndArgs(action);
|
||||
AddAction(*cmd);
|
||||
}
|
||||
|
||||
void ActionMap::_recursiveUpdateCommandKeybindingLabels()
|
||||
{
|
||||
const auto& commands{ _ExpandedCommandsCache };
|
||||
|
||||
for (const auto& command : commands)
|
||||
{
|
||||
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.
|
||||
|
||||
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 (auto nameAndCommand : commandsToExpand)
|
||||
{
|
||||
copyOfCommands.Insert(nameAndCommand.Key(), nameAndCommand.Value());
|
||||
}
|
||||
|
||||
implementation::Command::ExpandCommands(copyOfCommands,
|
||||
profiles,
|
||||
winrt::param::vector_view<Model::ColorScheme>{ sortedSchemes });
|
||||
|
||||
_ExpandedCommandsCache = winrt::single_threaded_vector<Model::Command>();
|
||||
for (const auto& [_, command] : copyOfCommands)
|
||||
{
|
||||
_ExpandedCommandsCache.Append(command);
|
||||
}
|
||||
}
|
||||
IVector<Model::Command> ActionMap::ExpandedCommands()
|
||||
{
|
||||
return _ExpandedCommandsCache;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user