mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 22:29:43 +00:00
Compare commits
8 Commits
release-0.
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d624070755 | ||
|
|
0f3d25cea3 | ||
|
|
443e06d836 | ||
|
|
8e05772329 | ||
|
|
f87454fa74 | ||
|
|
ba3247952a | ||
|
|
c636c2b121 | ||
|
|
c833c93c1d |
15
.github/ISSUE_TEMPLATE/Bug_Report.md
vendored
15
.github/ISSUE_TEMPLATE/Bug_Report.md
vendored
@@ -1,25 +1,12 @@
|
||||
---
|
||||
name: Bug report 🐛
|
||||
about: Report errors or unexpected behavior
|
||||
title: "Bug Report (IF I DO NOT CHANGE THIS THE ISSUE WILL BE AUTO-CLOSED)"
|
||||
title: "Bug Report"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
||||
|
||||
I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
|
||||
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
|
||||
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
|
||||
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
|
||||
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
|
||||
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.
|
||||
|
||||
All good? Then proceed!
|
||||
-->
|
||||
|
||||
<!--
|
||||
This bug tracker is monitored by Windows Terminal development team and other technical folks.
|
||||
|
||||
|
||||
15
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
15
.github/ISSUE_TEMPLATE/Feature_Request.md
vendored
@@ -7,20 +7,7 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
||||
|
||||
I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
|
||||
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
|
||||
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
|
||||
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
|
||||
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
|
||||
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.
|
||||
|
||||
All good? Then proceed!
|
||||
-->
|
||||
|
||||
# Description of the new feature/enhancement
|
||||
# Summary of the new feature/enhancement
|
||||
|
||||
<!--
|
||||
A clear and concise description of what the problem is that the new feature would solve.
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
|
||||
"Microsoft.VisualStudio.Component.VC.v142.x86.x64",
|
||||
"Microsoft.VisualStudio.Component.VC.v142.ARM64",
|
||||
"Microsoft.VisualStudio.Component.VC.v141.x86.x64",
|
||||
"Microsoft.VisualStudio.Component.VC.v141.ARM64",
|
||||
"Microsoft.VisualStudio.ComponentGroup.UWP.VC",
|
||||
"Microsoft.VisualStudio.ComponentGroup.UWP.VC.v142",
|
||||
"Microsoft.VisualStudio.ComponentGroup.UWP.VC.v141",
|
||||
"Microsoft.VisualStudio.Component.UWP.VC.ARM64"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
<!-- Add repositories here to the list of available repositories -->
|
||||
|
||||
<!-- Dependencies that we must carry because they're not on public nuget feeds right now. -->
|
||||
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
|
||||
|
||||
<!-- Use our own NuGet Feed -->
|
||||
<add key="Windows Terminal NuGet Feed" value="https://terminalnuget.blob.core.windows.net/feed/index.json" />
|
||||
<add key="Static Package Dependencies" value="dep\packages" />
|
||||
|
||||
<!-- Internal NuGet feeds that may not be accessible outside Microsoft corporate network -->
|
||||
<!--<add key="TAEF - internal" value="https://microsoft.pkgs.visualstudio.com/DefaultCollection/_packaging/Taef/nuget/v3/index.json" />
|
||||
|
||||
139
OpenConsole.sln
139
OpenConsole.sln
@@ -1,12 +1,8 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29001.49
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2008
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terminal", "Terminal", "{59840756-302F-44DF-AA47-441A9D673202}"
|
||||
EndProject
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CascadiaPackage", "src\cascadia\CascadiaPackage\CascadiaPackage.wapproj", "{CA5CAD1A-224A-4171-B13A-F16E576FDD12}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.EXE", "src\host\exe\Host.EXE.vcxproj", "{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {0CF235BD-2DA0-407E-90EE-C467E8BBC714}
|
||||
@@ -167,6 +163,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BufferOut", "src\buffer\out
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererDx", "src\renderer\dx\lib\dx.vcxproj", "{48D21369-3D7B-4431-9967-24E81292CF62}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terminal", "Terminal", "{59840756-302F-44DF-AA47-441A9D673202}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalConnection", "src\cascadia\TerminalConnection\TerminalConnection.vcxproj", "{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalCore", "src\cascadia\TerminalCore\lib\TerminalCore-lib.vcxproj", "{CA5CAD1A-ABCD-429C-B551-8562EC954746}"
|
||||
@@ -182,6 +180,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalControl", "src\casc
|
||||
{1CF55140-EF6A-4736-A403-957E4F7430BB} = {1CF55140-EF6A-4736-A403-957E4F7430BB}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CascadiaPackage", "src\cascadia\CascadiaPackage\CascadiaPackage.wapproj", "{CA5CAD1A-224A-4171-B13A-F16E576FDD12}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
@@ -193,7 +193,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\casc
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
@@ -203,6 +202,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalSettings", "src\cas
|
||||
EndProject
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "OpenConsolePackage", "pkg\appx\OpenConsolePackage.wapproj", "{2D310963-F3E0-4EE5-8AC6-FBC94DCC3310}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.UI.Xaml.Markup", "src\cascadia\Microsoft.UI.Xaml.Markup\Microsoft.UI.Xaml.Markup.vcxproj", "{015A0047-772D-4F1A-88C9-45C18F0ADFB6}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalCore", "src\cascadia\UnitTests_TerminalCore\UnitTests.vcxproj", "{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Internal", "src\internal\internal.vcxproj", "{EF3E32A7-5FF6-42B4-B6E2-96CD7D033F00}"
|
||||
@@ -232,17 +233,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89CDCC
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types.Unit.Tests", "src\types\ut_types\Types.Unit.Tests.vcxproj", "{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\cascadia\TerminalApp\lib\TerminalAppLib.vcxproj", "{CA5CAD1A-9A12-429C-B551-8562EC954746}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
AuditMode|ARM64 = AuditMode|ARM64
|
||||
@@ -256,33 +246,6 @@ Global
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.Deploy.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.ActiveCfg = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.Build.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.Deploy.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.Build.0 = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.ActiveCfg = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.Build.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.Deploy.0 = Release|x86
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
@@ -979,6 +942,33 @@ Global
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|ARM64.Deploy.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.ActiveCfg = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.Build.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.AuditMode|x86.Deploy.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.Build.0 = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.ActiveCfg = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.Build.0 = Release|x86
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12}.Release|x86.Deploy.0 = Release|x86
|
||||
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
@@ -1060,6 +1050,24 @@ Global
|
||||
{2D310963-F3E0-4EE5-8AC6-FBC94DCC3310}.Release|x86.ActiveCfg = Release|x86
|
||||
{2D310963-F3E0-4EE5-8AC6-FBC94DCC3310}.Release|x86.Build.0 = Release|x86
|
||||
{2D310963-F3E0-4EE5-8AC6-FBC94DCC3310}.Release|x86.Deploy.0 = Release|x86
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|x64.Build.0 = Release|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|x64.Build.0 = Debug|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Debug|x86.Build.0 = Debug|Win32
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|x64.ActiveCfg = Release|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|x64.Build.0 = Release|x64
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|x86.ActiveCfg = Release|Win32
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6}.Release|x86.Build.0 = Release|Win32
|
||||
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
@@ -1114,48 +1122,11 @@ Global
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x64.Build.0 = Release|x64
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x86.ActiveCfg = Release|Win32
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|x64.Build.0 = AuditMode|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
{345FD5A4-B32B-4F29-BD1C-B033BD2C35CC} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
{4C8E6BB0-4713-4ADB-BD04-81628ECEAF20} = {81C352DB-1818-45B7-A284-18E259F1CC87}
|
||||
@@ -1197,10 +1168,12 @@ Global
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-224A-4171-B13A-F16E576FDD12} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{2D310963-F3E0-4EE5-8AC6-FBC94DCC3310} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
{015A0047-772D-4F1A-88C9-45C18F0ADFB6} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{EF3E32A7-5FF6-42B4-B6E2-96CD7D033F00} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
|
||||
{16376381-CE22-42BE-B667-C6B35007008D} = {81C352DB-1818-45B7-A284-18E259F1CC87}
|
||||
@@ -1208,8 +1181,6 @@ Global
|
||||
{05500DEF-2294-41E3-AF9A-24E580B82836} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{1E4A062E-293B-4817-B20D-BF16B979E350} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
|
||||
{CA5CAD1A-9333-4D05-B12A-1905CBF112F9} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}
|
||||
|
||||
52
README.md
52
README.md
@@ -1,38 +1,14 @@
|
||||
# Welcome\!
|
||||
#### This repository contains the source code for:
|
||||
|
||||
* [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701)
|
||||
* Windows Terminal
|
||||
* The Windows console host (`conhost.exe`)
|
||||
* Components shared between the two projects
|
||||
* [ColorTool](https://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool)
|
||||
* [Sample projects](https://github.com/Microsoft/Terminal/tree/master/samples) that show how to consume the Windows Console APIs
|
||||
|
||||
#### Other related repositories include:
|
||||
* [Console API Documentation](https://github.com/MicrosoftDocs/Console-Docs)
|
||||
|
||||
## Installation
|
||||
|
||||
### Microsoft Store
|
||||
|
||||
Download the Microsoft Terminal free from the Microsoft Store and it'll be continuously updated. Or, feel free to side-load [releases](https://github.com/microsoft/terminal/releases) from GitHub, but note they won't auto-update.
|
||||
|
||||
<a href='//www.microsoft.com/store/apps/9n0dx20hk701?cid=storebadge&ocid=badge'><img src='https://assets.windowsphone.com/85864462-9c82-451e-9355-a3d5f874397a/English_get-it-from-MS_InvariantCulture_Default.png' alt='English badge' width="284" height="104" style='width: 284px; height: 104px;'/></a>
|
||||
|
||||
### Chocolatey (Unofficial)
|
||||
|
||||
Download and upgrade the Windows Terminal from [Chocolatey](https://chocolatey.org).
|
||||
|
||||
To install Windows Terminal, run the following command from the command line or from PowerShell:
|
||||
```powershell
|
||||
choco install microsoft-windows-terminal
|
||||
```
|
||||
|
||||
To upgrade Windows Terminal, run the following command from the command line or from PowerShell:
|
||||
```powershell
|
||||
choco upgrade microsoft-windows-terminal
|
||||
```
|
||||
|
||||
If you have any issues when installing/upgrading the package please go to the [package page](https://chocolatey.org/packages/microsoft-windows-terminal) and follow the [Chocolatey triage process](https://chocolatey.org/docs/package-triage-process)
|
||||
* [Console API Documentation](https://github.com/MicrosoftDocs/Console-Docs/issues)
|
||||
|
||||
### Build Status
|
||||
|
||||
@@ -79,14 +55,16 @@ Further, we realized that this would allow us to build the terminal's renderer a
|
||||
|
||||
## Where can I download Windows Terminal?
|
||||
|
||||
### The Windows Terminal preview can be downloaded from the Microsoft Store.
|
||||
### There are no binaries to download quite yet.
|
||||
|
||||
[https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701](https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701)
|
||||
The Windows Terminal is in the _very early_ alpha stage, and not ready for the general public quite yet. If you want to jump in early, you can try building it yourself from source.
|
||||
|
||||
Otherwise, you'll need to wait until Mid-June for an official preview build to drop.
|
||||
|
||||
## I built and ran the new Terminal, but I just get a blank window app!
|
||||
|
||||
Make sure you are building for your computer's architecture. If your box has a 64-bit Windows, change your Solution Platform to x64.
|
||||
To check your OS architecture go to Settings -> System -> About (or Win+X -> System) and under `Device specifications` check for the `System type`.
|
||||
Make sure you are building for your computer's architecture. If your box has a 64-bit Windows change your Solution Platform to x64.
|
||||
To check your OS architecture go to Settings -> System -> About (or Win+X -> System) and under `Device specifications` check for the `System type`
|
||||
|
||||
## I built and ran the new Terminal, but it looks just like the old console! What gives?
|
||||
|
||||
@@ -103,7 +81,7 @@ Secondly, try pressing <kbd>Ctrl</kbd> + <kbd>T</kbd>. The tabs are hidden when
|
||||
|
||||
## Debugging
|
||||
|
||||
* To debug in VS, right click on CascadiaPackage (from VS Solution Explorer) and go to properties, in the Debug menu, change "Application process" and "Background task process" to "Native Only".
|
||||
* To debug in VS, right click on CascadiaPackage (from VS Solution Explorer) and go to properties, in the Debug menu, change "Application process" and "Background task process" to "Native Only"
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -139,14 +117,14 @@ If you would like to ask a question that you feel doesn't warrant an issue (yet)
|
||||
|
||||
## Build Prerequisites
|
||||
|
||||
* You must be running Windows 1903 (build >= 10.0.18362.0) or above in order to run Windows Terminal.
|
||||
* You must have the [1903 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) (build 10.0.18362.0) installed.
|
||||
* You must have at least [VS 2019](https://visualstudio.microsoft.com/downloads/) installed.
|
||||
* You must install the following Workloads via the VS Installer. Opening the solution will [prompt you to install missing components automatically](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/).
|
||||
* You must be running Windows 1903 (build >= 10.0.18362.0) or above in order to run Windows Terminal
|
||||
* You must have the [1903 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) (build 10.0.18362.0) installed
|
||||
* You must have at least [VS 2017](https://visualstudio.microsoft.com/downloads/) installed.
|
||||
* You must install the following Workloads via the VS Installer. If you're running VS 2019, opening the solution will [prompt you to install missing components automatically](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/).
|
||||
- Desktop Development with C++
|
||||
- Universal Windows Platform Development
|
||||
- **The following Individual Components**
|
||||
- C++ (v142) Universal Windows Platform Tools
|
||||
- Also install the following Individual Component:
|
||||
- C++ (v141) Universal Windows Platform Tools
|
||||
|
||||
* You must also [enable Developer Mode in the Windows Settings app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) to locally install and run the Terminal app.
|
||||
|
||||
|
||||
@@ -19,11 +19,9 @@ pr:
|
||||
name: 0.0.$(Date:yyMM).$(Date:dd)$(Rev:rr)
|
||||
|
||||
jobs:
|
||||
# This is disabled because the build agents were running out of disk space.
|
||||
# We're pursuing that in the background, but the spice must flow in the meantime.
|
||||
# - template: ./templates/build-console-audit-job.yml
|
||||
# parameters:
|
||||
# platform: x64
|
||||
- template: ./templates/build-console-audit-job.yml
|
||||
parameters:
|
||||
platform: x64
|
||||
|
||||
- template: ./templates/build-console-ci.yml
|
||||
parameters:
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: AuditMode
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: { vmImage: vs2017-win2016 }
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
displayName: 'Build solution **\OpenConsole.sln'
|
||||
inputs:
|
||||
solution: '**\OpenConsole.sln'
|
||||
vsVersion: 16.0
|
||||
vsVersion: 15.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
variables:
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: { vmImage: vs2017-win2016 }
|
||||
|
||||
steps:
|
||||
- template: build-console-steps.yml
|
||||
|
||||
@@ -39,21 +39,13 @@ steps:
|
||||
displayName: 'Build solution **\OpenConsole.sln'
|
||||
inputs:
|
||||
solution: '**\OpenConsole.sln'
|
||||
vsVersion: 16.0
|
||||
vsVersion: 15.0
|
||||
platform: '$(BuildPlatform)'
|
||||
configuration: '$(BuildConfiguration)'
|
||||
msbuildArgs: ${{ parameters.additionalBuildArguments }}
|
||||
clean: true
|
||||
maximumCpuCount: true
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: 'Check MSIX for common regressions'
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: |
|
||||
$Package = Get-ChildItem -Recurse -Filter "CascadiaPackage_*.msix"
|
||||
.\build\scripts\Test-WindowsTerminalPackage.ps1 -Verbose -Path $Package.FullName
|
||||
|
||||
- task: VSTest@2
|
||||
displayName: 'Run Unit Tests'
|
||||
inputs:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
jobs:
|
||||
- job: CodeFormatCheck
|
||||
displayName: Proper Code Formatting Check
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: { vmImage: vs2017-win2016 }
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<BeforeLinkTargets Condition="'$(WindowsTargetPlatformVersion)' >= '10.0.18362.0'">
|
||||
$(BeforeLinkTargets);
|
||||
_ConsoleGenerateAdditionalWinmdManifests;
|
||||
</BeforeLinkTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="_ConsoleMapWinmdsToManifestFiles" DependsOnTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<!-- For each non-system .winmd file in References, generate a .manifest in IntDir for it. -->
|
||||
<_ConsoleWinmdManifest Include="@(ReferencePath->'$(IntDir)\%(FileName).manifest')" Condition="'%(ReferencePath.IsSystemReference)' != 'true' and '%(ReferencePath.WinMDFile)' == 'true' and '%(ReferencePath.ReferenceSourceTarget)' == 'ResolveAssemblyReference'">
|
||||
<WinMDPath>%(ReferencePath.FullPath)</WinMDPath>
|
||||
<Implementation>%(ReferencePath.Implementation)</Implementation>
|
||||
</_ConsoleWinmdManifest>
|
||||
<!-- For each referenced project that _produces_ a winmd, generate a temporary item that maps to
|
||||
the winmd, and use that temporary item to generate a .manifest in IntDir for it.
|
||||
We don't set Implementation here because it's inherited from the _ResolvedNativeProjectReferencePaths. -->
|
||||
<_ConsoleWinmdProjectReference Condition="'%(_ResolvedNativeProjectReferencePaths.ProjectType)' != 'StaticLibrary'" Include="@(_ResolvedNativeProjectReferencePaths->WithMetadataValue('FileType','winmd')->'%(RootDir)%(Directory)%(TargetPath)')" />
|
||||
<_ConsoleWinmdManifest Include="@(_ConsoleWinmdProjectReference->'$(IntDir)\%(FileName).manifest')">
|
||||
<WinMDPath>%(Identity)</WinMDPath>
|
||||
</_ConsoleWinmdManifest>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_ConsoleGenerateAdditionalWinmdManifests"
|
||||
Inputs="@(_ConsoleWinmdManifest.WinMDPath)"
|
||||
Outputs="@(_ConsoleWinmdManifest)"
|
||||
DependsOnTargets="_ConsoleMapWinmdsToManifestFiles">
|
||||
|
||||
<!-- This target is batched and a new Exec is spawned for each entry in _ConsoleWinmdManifest. -->
|
||||
<Exec Command="mt.exe -winmd:%(_ConsoleWinmdManifest.WinMDPath) -dll:%(_ConsoleWinmdManifest.Implementation) -out:%(_ConsoleWinmdManifest.Identity)" />
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Emit the generated manifest into the Link inputs. -->
|
||||
<Manifest Include="@(_ConsoleWinmdManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,79 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Mandatory=$true, ValueFromPipeline=$true,
|
||||
HelpMessage="Path to the .appx/.msix to validate")]
|
||||
[string]
|
||||
$Path,
|
||||
|
||||
[Parameter(HelpMessage="Path to Windows Kit")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
If ($null -Eq (Get-Item $WindowsKitPath -EA:SilentlyContinue)) {
|
||||
Write-Error "Could not find a windows SDK at at `"$WindowsKitPath`".`nMake sure that WindowsKitPath points to a valid SDK."
|
||||
Exit 1
|
||||
}
|
||||
|
||||
$makeAppx = "$WindowsKitPath\x86\MakeAppx.exe"
|
||||
$makePri = "$WindowsKitPath\x86\MakePri.exe"
|
||||
|
||||
Function Expand-ApplicationPackage {
|
||||
Param(
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
$sentinelFile = New-TemporaryFile
|
||||
$directory = New-Item -Type Directory "$($sentinelFile.FullName)_Package"
|
||||
Remove-Item $sentinelFile -Force -EA:Ignore
|
||||
|
||||
& $makeAppx unpack /p $Path /d $directory /nv /o
|
||||
|
||||
If ($LastExitCode -Ne 0) {
|
||||
Throw "Failed to expand AppX"
|
||||
}
|
||||
|
||||
$directory
|
||||
}
|
||||
|
||||
Write-Verbose "Expanding $Path"
|
||||
$AppxPackageRoot = Expand-ApplicationPackage $Path
|
||||
$AppxPackageRootPath = $AppxPackageRoot.FullName
|
||||
|
||||
Write-Verbose "Expanded to $AppxPackageRootPath"
|
||||
|
||||
Try {
|
||||
& $makePri dump /if "$AppxPackageRootPath\resources.pri" /of "$AppxPackageRootPath\resources.pri.xml" /o
|
||||
If ($LastExitCode -Ne 0) {
|
||||
Throw "Failed to dump PRI"
|
||||
}
|
||||
|
||||
$Manifest = [xml](Get-Content "$AppxPackageRootPath\AppxManifest.xml")
|
||||
$PRIFile = [xml](Get-Content "$AppxPackageRootPath\resources.pri.xml")
|
||||
|
||||
### Check the activatable class entries for a few DLLs we need.
|
||||
$inProcServers = $Manifest.Package.Extensions.Extension.InProcessServer.Path
|
||||
$RequiredInProcServers = ("TerminalApp.dll", "TerminalControl.dll", "TerminalConnection.dll")
|
||||
|
||||
Write-Verbose "InProc Servers: $inProcServers"
|
||||
|
||||
ForEach ($req in $RequiredInProcServers) {
|
||||
If ($req -NotIn $inProcServers) {
|
||||
Throw "Failed to find $req in InProcServer list $inProcServers"
|
||||
}
|
||||
}
|
||||
|
||||
### Check that we have an App.xbf (which is a proxy for our resources having been merged)
|
||||
$resourceXpath = '/PriInfo/ResourceMap/ResourceMapSubtree[@name="Files"]/NamedResource[@name="App.xbf"]'
|
||||
$AppXbf = $PRIFile.SelectSingleNode($resourceXpath)
|
||||
If ($null -eq $AppXbf) {
|
||||
Throw "Failed to find App.xbf (TerminalApp project) in resources.pri"
|
||||
}
|
||||
} Finally {
|
||||
Remove-Item -Recurse -Force $AppxPackageRootPath
|
||||
}
|
||||
7
dep/packages/README.md
Normal file
7
dep/packages/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
These packages are redistributed inside this folder because they are not yet available on a public NuGet feed.
|
||||
|
||||
## Microsoft.UI.XAML
|
||||
This package is a custom development build fork to help us light up tab support. It will eventually go onto the same public feed as the existing `Microsoft.UI.XAML` package that's currently available on NuGet.org
|
||||
|
||||
## TAEF.Redist.WLK
|
||||
This package is vetted for public redistribution and release, but the TAEF team hasn't set up a public feed to consume it yet. If/when they do, we'll move to that.
|
||||
BIN
dep/packages/microsoft.ui.xaml.2.1.190405001-prerelease.nupkg
Normal file
BIN
dep/packages/microsoft.ui.xaml.2.1.190405001-prerelease.nupkg
Normal file
Binary file not shown.
BIN
dep/packages/taef.redist.wlk.10.30.180808002.nupkg
Normal file
BIN
dep/packages/taef.redist.wlk.10.30.180808002.nupkg
Normal file
Binary file not shown.
147
doc/Niksa.md
147
doc/Niksa.md
@@ -1,147 +0,0 @@
|
||||
# Niksa's explanations
|
||||
|
||||
Sometimes @miniksa will write a big, long explanatory comment in an issue thread that turns out to be a decent bit of reference material.
|
||||
This document serves as a storage point for those posts.
|
||||
|
||||
- [Why do we avoid changing CMD.exe?](#cmd)
|
||||
- [Why is typing-to-screen performance better than every other app?](#screenPerf)
|
||||
- [How are the Windows graphics/messaging stack assembled?](#gfxMsgStack)
|
||||
- [Output Processing between "Far East" and "Western"](#fesb)
|
||||
- [Why do we not backport things?](#backport)
|
||||
|
||||
## <a name="cmd"></a>Why do we avoid changing CMD.exe?
|
||||
`setlocal` doesn't behave the same way as an environment variable. It's a thing that would have to be put in at the top of the batch script that is `somefile.cmd` as one of its first commands to adjust the way that one specific batch file is processed by the `cmd.exe` engine. That's probably not suitable for your needs, but that's the way we have to go.
|
||||
|
||||
I don't think anyone is disagreeing with you, @mikemaccana, that this would be a five minute development change to read that environment variable and change the behavior of `cmd.exe`. It absolutely would be a tiny development time.
|
||||
|
||||
It's just that from our experience, we know there's going to be a 3-24 month bug tail here where we get massive investigation callbacks by some billion dollar enterprise customer who for whatever reason was already using the environment variable we pick for another purpose. Their script that they give their rank-and-file folks will tell them to press Ctrl+C at some point in the batch script to do whatever happens, it will do something different, those people will notice the script doesn't match the computer anymore. They will then halt the production line and tell their supervisor. The supervisor tells some director. Their director comes screaming at their Microsoft enterprise support contract person that we've introduced a change to the OS that is costing them millions if not billions of dollars in shipments per month. Our directors at Microsoft then come bashing down our doors angry with us and make us fix it ASAP or revert it, we don't get to go home at 5pm to our families or friends because we're fixing it, we get stressed the heck out, we have to spin up servicing potentially for already shipped operating systems which is expensive and headache-causing...etc.
|
||||
|
||||
We can see this story coming a million miles away because it has happened before with other 'tiny' change we've been asked to make to `cmd.exe` in the past few years.
|
||||
|
||||
I would just ask you to understand that `cmd.exe` is very, very much in a maintenance mode and I just want to set expectations here. We maintain it, yes. We have a renewed interest in command-line development, yes. But our focuses are revolving around improving the terminal and platform itself and bringing modern, supported shells to be the best they can be on Windows. Paul will put this on the backlog of things that people want in `cmd.exe`, yes. But it will sink to the bottom of the backlog because changing `cmd.exe` is our worst nightmare as its compatibility story is among the heaviest of any piece of the operating system.
|
||||
|
||||
I would highly recommend that Gulp convert to using PowerShell scripts and that if such an issue exists with PowerShell, that we get their modern, supported, and better-engineered platform to support the scenario. I don't want you to sit around waiting for `cmd.exe` to change this because it's really not going to happen faster than that script could be converted to `ps1` and it fixed in PowerShell Core (if that's even a problem in that world.)
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/217#issuecomment-404240443
|
||||
|
||||
## <a name="screenPerf"></a>Why is typing-to-screen performance better than every other app?
|
||||
|
||||
I really do not mind when someone comes by and decides to tell us that we're doing a good job at something. We hear so many complaints every day that a post like this is a breath of fresh air. Thanks for your thanks!
|
||||
|
||||
Also, I'm happy to discuss this with you until you're utterly sick of reading it. Please ask any follow-ons you want. I thrive on blathering about my work. :P
|
||||
|
||||
If I had to take an educated guess as to what is making us faster than pretty much any other application on Windows at putting your text on the screen... I would say it is because that is literally our only job! Also probably because we are using darn near the oldest and lowest level APIs that Windows has to accomplish this work.
|
||||
|
||||
Pretty much everything else you've listed has some sort of layer or framework involved, or many, many layers and frameworks, when you start talking about Electron and Javascript. We don't.
|
||||
|
||||
We have one bare, super un-special window with no additional controls attached to it. We get our keys fed into us from just barely above the kernel given that we're processing them from window messages and not from some sort of eventing framework common to pretty much any other more complicated UI framework than ours (WPF, WinForms, UWP, Electron). And we dump our text straight onto the window surface using GDI's [PolyTextOut](https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-polytextoutw) with no frills.
|
||||
|
||||
Even `notepad.exe` has multiple controls on its window at the very least and is probably (I haven't looked) using some sort of library framework in the edit control to figure out its text layout (which probably is using another library framework for internationalization support...)
|
||||
|
||||
Of course this also means that we have trade offs. We don't support fully international text like pretty much every other application will. RTL? No go zone right now. Surrogate pairs and emoji? We're getting there but not there yet. Indic scripts? Nope.
|
||||
|
||||
Why are we like this? For one, `conhost.exe` is old as dirt. It has to use the bare metal bottom layer of everything because it was created before most of those other frameworks were created. And also it maintains as low/bottom level as possible because it is pretty much the first thing that one needs to bring up when bringing up a new operating system edition or device before you have all the nice things like frameworks or what those frameworks require to operate. Also it's written in C/C++ which is about as low and bare metal as we can get.
|
||||
|
||||
Will this UI enhancement come to other apps on Windows? Almost certainly not. They have too much going on which is both a good and a bad thing. I'm jealous of their ability to just call one method and layout text in an uncomplicated manner in any language without manually calculating pixels or caring about what styles apply to their font. But my manual pixel calculations, dirty region math, scroll region madness, and more makes it so we go faster than them. I'm also jealous that when someone says "hey can you add a status bar to the bottom of your window" that they can pretty much click and drag that into place with their UI Framework and it will just work where as for us, it's been a backlog item forever and gives me heartburn to think about implementing.
|
||||
|
||||
Will we try to keep it from regressing? Yes! Right now it's sort of a manual process. We identify that something is getting slow and then we go haul out [WPR](https://docs.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-recorder) and start taking traces. We stare down the hot paths and try to reason out what is going on and then improve them. For instance, in the last cycle or two, we focused on heap allocations as a major area where we could improve our end-to-end performance, changing a ton of our code to use stack-constructed iterator-like facades over the underlying request buffer instead of translating and allocating it into a new heap space for each level of processing.
|
||||
|
||||
As an aside, @bitcrazed wants us to automate performance tests in some conhost specific way, but I haven't quite figured out a controlled environment to do this in yet. The Windows Engineering System runs performance tests each night that give us a coarse grained way of knowing if we messed something up for the whole operating system, and they technically offer a fine grained way for us to insert our own performance tests... but I just haven't got around to that yet. If you have an idea for a way for us to do this in an automated fashion, I'm all ears.
|
||||
|
||||
If there's anything else you'd like to know, let me know. I could go on all day. I deleted like 15 tangents from this reply before posting it....
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/327#issuecomment-447391705
|
||||
|
||||
## <a name="gfxMsgStack"></a>How are the Windows graphics/messaging stack assembled?
|
||||
|
||||
@stakx, I am referring to USER32 and GDI32.
|
||||
|
||||
I'll give you a cursory overview of what I know off the top of my head without spending hours confirming the details. As such, some of this is subject to handwaving and could be mildly incorrect but is probably in the right direction. Consider every statement to be my personal knowledge on how the world works and subject to opinion or error.
|
||||
|
||||
For the graphics part of the pipeline (GDI32), the user-mode portions of GDI are pretty far down. The app calls GDI32, some work is done in that DLL on the user-mode side, then a kernel call jumps over to the kernel and drawing occurs.
|
||||
|
||||
The portion that you're thinking of regarding "silently converted to sit on top of other stuff" is probably that once we hit the kernel calls, a bunch of the kernel GDI stuff tends to be re-platformed on top of the same stuff as DirectX when it is actually handled by the NVIDIA/AMD/Intel/etc. graphics driver and the GPU at the bottom of the stack. I think this happened with the graphics driver re-architecture that came as a part of WDDM for Windows Vista. There's a document out there somewhere about what calls are still really fast in GDI and which are slower as a result of the re-platforming. Last time I found that document and checked, we were using the fast ones.
|
||||
|
||||
On top of GDI, I believe there are things like Common Controls or comctl32.dll which provided folks reusable sets of buttons and elements to make their UIs before we had nicer declarative frameworks. We don't use those in the console really (except in the property sheet off the right click menu).
|
||||
|
||||
As for DirectWrite and D2D and D3D and DXGI themselves, they're a separate set of commands and paths that are completely off to the side from GDI at all both in user and kernel mode. They're not really related other than that there's some interoperability provisions between the two. Most of our other UI frameworks tend to be built on top of the DirectX stack though. XAML is for sure. I think WPF is. Not sure about WinForms. And I believe the composition stack and the window manager are using DirectX as well.
|
||||
|
||||
As for the input/interaction part of the pipeline (USER32), I tend to find most other newer things (at least for desktop PCs) are built on top of what is already there. USER32's major concept is windows and window handles and everything is sent to a window handle. As long as you're on a desktop machine (or a laptop or whatever... I mean a classic-style Windows-powered machine), there's a window handle involved and messages floating around and that means we're talking USER32.
|
||||
|
||||
The window message queue is just a straight up FIFO (more or less) of whatever input has occurred relevant to that window while it's in the foreground + whatever has been sent to the window by other components in the system.
|
||||
|
||||
The newer technologies and the frameworks like XAML and WPF and WinForms tend to receive the messages from the window message queue one way or another and process them and turn them into event callbacks to various objects that they've provisioned within their world.
|
||||
|
||||
However, the newer technologies that also work on other non-desktop platforms like XAML tend to have the ability to process stuff off of a completely different non-USER32 stack as well. There's a separate parallel stack to USER32 with all of our new innovations and realizations on how input and interaction should occur that doesn't exactly deal with classic messaging queues and window handles the same way. This is the whole Core* family of things like CoreWindow and CoreMessaging. They also have a different concept of "what is a user" that isn't so centric around your butt in rolling chair in front of a screen with a keyboard and mouse on the desk.
|
||||
|
||||
Now, if you're on XAML or one of the other Frameworks... all this intricacy is handled for you. XAML figures out how to draw on DirectX for you and negotiates with the compositor and window manager for cool effects on your behalf. It figures out whether to get your input events from USER32 or Core* or whatever transparently depending on your platform and the input stacks can handle pen, touch, keyboard, mouse, and so on in a unified manner. It has provisions inside it embedded to do all the sorts of globalization, accessibility, input interaction, etc. stuff that make your life easy. But you could choose to go directly to the low-level and handle it yourself or skip handling what you don't care about.
|
||||
|
||||
The trick is that GDI32 and USER32 were designed for a limited world with a limited set of commands. Desktop PCs were the only thing that existed, single user at the keyboard and mouse, simple graphics output to a VGA monitor. So using them directly at the "low level" like conhost does is pretty easy. The new platforms could be used at the "low level" but they're orders of magnitude more complicated because they now account for everything that has happened with personal computing in 20+ years like different form factors, multiple active users, multiple graphics adapters, and on and on and on and on. So you tend to use a framework when using the new stuff so your head doesn't explode. They handle it for you, but they handle more than they ever did before so they're slower to some degree.
|
||||
|
||||
So are GDI32 and USER32 "lower" than the new stuff? Sort of.
|
||||
Can you get that low with the newer stuff? Mostly yes, but you probably shouldn't and don't want to.
|
||||
Does new live on top of old or is old replatformed on the new? Sometimes and/or partially.
|
||||
Basically... it's like the answer to anything software... "it's an unmitigated disaster and if we all stepped back a moment, we should be astounded that it works at all." :P
|
||||
|
||||
Anyway, that's enough ramble for one morning. Hopefully that somewhat answered your questions and gave you a bit more insight.
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/327#issuecomment-447926388
|
||||
|
||||
## <a name="fesb"></a>Output Processing between "Far East" and "Western"
|
||||
|
||||
>
|
||||
> ```
|
||||
> if (WI_IsFlagSet(CharType, C1_CNTRL))
|
||||
> ```
|
||||
|
||||
In short, this is probably fine to fix.
|
||||
|
||||
However, I would personally feed a few characters through `WriteCharsLegacy` under the debugger and assert that your theory is correct first (that multiple flags coming back are what the problem is) before making the change.
|
||||
|
||||
I am mildly terrified, less than Dustin, because it is freaking `WriteCharsLegacy` which is the spawn of hell and I fear some sort of regression in it.
|
||||
|
||||
In long, why is it fine to fix?
|
||||
|
||||
For reference, this particular segment of code https://github.com/microsoft/terminal/blob/9b92986b49bed8cc41fde4d6ef080921c41e6d9e/src/host/_stream.cpp#L514-L539 appears to only be used when the codepoint is < 0x20 or == 0x7F https://github.com/microsoft/terminal/blob/9b92986b49bed8cc41fde4d6ef080921c41e6d9e/src/host/_stream.cpp#L408 and ENABLE_PROCESSED_OUTPUT is off. https://github.com/microsoft/terminal/blob/9b92986b49bed8cc41fde4d6ef080921c41e6d9e/src/host/_stream.cpp#L320
|
||||
|
||||
I looked back at the console v1 code and this particular section had a divergence for "Western" countries and "Far East" countries (a geopolitically-charged term, but what it was, nonetheless.)
|
||||
|
||||
For "Western" countries, we would unconditionally run all the characters through `MultiByteToWideChar` with `MB_USEGLYPHCHARS` without the `C1_CNTRL` test and move the result into the buffer.
|
||||
|
||||
For "Eastern" countries, we did the `C1_CNTRL` test and then if true, we would run through `MultiByteToWideChar` with `MB_USEGLYPHCHARS`. Otherwise, we would just move the original character into the buffer and call it a day.
|
||||
|
||||
Note in both of these, there is a little bit of indirection before `MultiByteToWideChar` is called through some other helper methods like `ConvertOutputToUnicode`, but that's the effective conversion point, as far as I can tell. And that's where the control characters would turn into acceptable low ASCII symbols.
|
||||
|
||||
When we took over the console codebase, this variation between "Western" and "Eastern" countries was especially painful because `conhost.exe` would choose which one it was in based on the `Codepage for Non-Unicode Applications` set in the Control Panel's Regional > Administrative panel and it could only be changed with a reboot. It wouldn't even change properly when you `chcp` to a different codepage. Heck, `chcp` would deny you from switching into many codepages. There was a block in place to prevent going to an "Eastern" codepage if you booted up in a "Western" codepage. There was also a block preventing you from going between "Eastern" codepages, if I recall correctly.
|
||||
|
||||
In modernizing, I decided a few things:
|
||||
1. What's good for the "Far East" should be good for the rest of the world. CJK languages that encompassed the "Far East" code have to be able to handle "Western" text as well even if the reverse wasn't true.
|
||||
2. We need to scrub all usages of "Far East" from the code. Someone already started that and replaced them with "East Asia" except then they left behind the shorthand of "FE" prefixing dozens of functions which made it hard to follow the code. It took us months to realize "FE" and "East Asia" were the same thing.
|
||||
3. It's obnoxious that the way this was handled was to literally double-define every output function in the code base to have two definitions, compile them both into the conhost, then choose to run down the SB_ versions or the FE_ versions depending on the startup Non-Unicode codepage. It was a massive pile of complex pre-compilation `#ifdef` and `#else`s that would sometimes surround individual lines in the function bodies. Gross.
|
||||
4. The fact that the FE_ versions of the functions were way slower than the SB_ ones was unacceptable even for the same output of Latin-character text.
|
||||
5. Anyone should be free to switch between any codepage they want at any time and restricting it based on a value from OS startup or region/locale is not acceptable in the modern world.
|
||||
6. I concluded by all of the above that I was going to tank/delete/remove the SB_ versions of everything and force the entire world to use the FE_ versions as truth. I would fix the FE_ versions to handle everything correctly, I would fix the performance characteristics of the FE_ versions so they were only slower when things were legitimately more complicated and never otherwise, I would banish all usage of "Far East", "East Asia", "FE_", and "SB_" from the codebase, and codepages would be freely switchable.
|
||||
7. Oh. Also, the conhost used to rewrite its entire backing buffer into whatever your current codepage was whenever you switched codepages. I changed that to always hold it as UTF-16.
|
||||
|
||||
Now, after that backstory. This is where the problem comes in. It looks like the code you're pointing to that didn't check flags and instead checked direct equality... is the way that it was ALWAYS done for the "Eastern" copy of the code. So it was ALWAYS broken for the "Eastern" codepages and country variants of the OS.
|
||||
|
||||
I don't know why the "Eastern" copy was checking `C1_CNTRL` at all in the first place. There is no documentation. I presume it has to do with Shift-JIS or GB-2312 or Unified Hangul or something having a conflict < 0x20 || == 0x7F. Or alternatively, it's because someone wrote the code naively thinking it was a good idea in a hurry and never tested it. Very possible and even probable.
|
||||
|
||||
Presuming CJK codepages have no conflict in this range for their DBCS codepages... we could probably remove the check with `GetStringTypeW` entirely and always run everything through `ConvertOutputToUnicode`. More risky than just the flag test change... but theoretically an option as well.
|
||||
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/166#issuecomment-510953359
|
||||
|
||||
## <a name="backport"></a>Why do we not backport things?
|
||||
|
||||
Someone has to prove that this is costing millions to billions of dollars of lost productivity or revenue to outweigh the risks of shipping the fix to hundreds of millions of Windows machines and potentially breaking something.
|
||||
|
||||
Our team generally finds it pretty hard to prove that against the developer audience given that they're only a small portion of the total installed market of Windows machines.
|
||||
|
||||
Our only backport successes really come from corporations with massive addressable market (like OEMs shipping PCs) who complain that this is fouling up their manufacturing line (or something of that ilk). Otherwise, our management typically says that the risks don't outweigh the benefits.
|
||||
|
||||
It's also costly in terms of time, effort, and testing for us to validate a modification to a released OS. We have a mindbogglingly massive amount of automated machinery dedicated to processing and validating the things that we check in while developing the current OS builds. But it's a special costly ask to spin up some to all of those activities to validate backported fixes. We do it all the time for Patch Tuesday, but in those patches, they only pass through the minimum number of fixes required to maximize the restoration of productivity/security/revenue/etc. because every additional fix adds additional complexity and additional risk.
|
||||
|
||||
So from our little team working hard to make developers happy, we virtually never make the cut for servicing. We're sorry, but we hope you can understand. It's just the reality of the situation to say "nope" when people ask for a backport. In our team's ideal world, you would all be running the latest console bits everywhere everytime we make a change. But that's just not how it is today.
|
||||
|
||||
Original Source: https://github.com/microsoft/terminal/issues/279#issuecomment-439179675
|
||||
23
doc/bot.md
23
doc/bot.md
@@ -13,7 +13,7 @@ We'll be using tags, primarily, to help us understand what needs attention, what
|
||||
|
||||
### Tagging/Process Details
|
||||
1. When new issues arrive, or when issues are not properly tagged... we'll mark them as `Needs-Triage` automatically.
|
||||
- The core contributor team will then come through and mark them up as appropriate. The goal is to have a tag that fits the `Product`, `Area`, and `Issue` category.
|
||||
- The core contributor team will then come through and mark them up as appropriate. The goal is to have a tag that fits the `Product`, `Area`, and `Issue` category.
|
||||
- The `Needs-Triage` tag will be removed manually by the core contributor team during a triage meeting. (Exception, triage may also be done offline by senior team members during high-volume times.)
|
||||
- An issue may or may not be assigned to a contributor during triage. It is not necessary to assign someone to complete it.
|
||||
- We're not focusing on Projects yet.
|
||||
@@ -22,7 +22,7 @@ We'll be using tags, primarily, to help us understand what needs attention, what
|
||||
- When this tag drops off, the bot will apply the `Needs-Attention` tag to get the core contribution team's attention again. If an author cares enough to be active, we will attempt to prioritize engaging with that author.
|
||||
- If the author doesn't come back around in a while, this will become a `No-Recent-Activity` tag.
|
||||
- If there's activity on an issue, the `No-Recent-Activity` tag will automatically drop.
|
||||
- If the `No-Recent-Activity` stays, the issue will be closed as stale.
|
||||
- If the `No-Recent-Activity` stays, the issue will be closed as stale.
|
||||
1. PRs will automatically get a `Needs-Author-Feedback` tag when reviewers wait on the author
|
||||
- This follows a similar decay strategy to issues.
|
||||
- If the author responds, the `Needs-Author-Feedback` tag will drop.
|
||||
@@ -37,7 +37,7 @@ We'll be using tags, primarily, to help us understand what needs attention, what
|
||||
|
||||
#### Mark as Triage Needed
|
||||
- When an issue doesn't meet triage criteria, applies `Needs-Triage` tag. Right now, this is just when it's opened.
|
||||
|
||||
|
||||
#### Author Has Responded
|
||||
- When an issue with `Needs-Author-Feedback` gets an author response, drops that tag in favor of `Needs-Attention` to flag core contributors to drop by.
|
||||
|
||||
@@ -56,13 +56,6 @@ We'll be using tags, primarily, to help us understand what needs attention, what
|
||||
#### Enforce tag system
|
||||
- When an issue is opened or labels are changed in any way, we will check if the tagging matches the system. If not, it will get `Needs-Tag-Fix`. The system is to have an `Area-`, `Issue-`, and `Product-` tag for all open things, and also a `Resolution-` for closed ones.
|
||||
- When the tags from appropriate categories are applied, it will auto-remove the `Needs-Tag-Fix` tag.
|
||||
- `Resolution-Duplicate` is sufficient to fix all tagging. (`Area-`, `Issue-`, and `Product-` are not needed for a duplicate.)
|
||||
|
||||
#### Clean-up low quality issues
|
||||
- If an issue is filed with an incomplete title...
|
||||
- If an issue is filed with nothing in the body...
|
||||
- If an issue is filed matching a pattern that happens all the time (common duplicate phrase, obvious multiple-issues-in-one pattern)...
|
||||
- Then close the issue automatically informing the opener that they can resolve the problem and reopen the issue. (See Bug/Feature templates for example situations.)
|
||||
|
||||
### PR Management
|
||||
|
||||
@@ -87,16 +80,10 @@ We'll be using tags, primarily, to help us understand what needs attention, what
|
||||
#### Auto-Merge pull requests
|
||||
- When a pull request has the `AutoMerge` label...
|
||||
- If it has been at least 480 minutes and all the statuses pass, merge it in.
|
||||
- Will use Squash merge strategy
|
||||
- Will use Squash merge stratgy
|
||||
- Will attempt to delete branch after merge, if possible
|
||||
- Will automatically remove the `AutoMerge` label if changes are pushed by someone *without* Write Access.
|
||||
- More information on bot-logic that can be controlled with comments is [here](https://github.com/OfficeDev/office-ui-fabric-react/wiki/Advanced-auto-merge)
|
||||
|
||||
#### Mark issues with an active PR
|
||||
- If there is an active PR for an issue, label that issue with the `In-PR` label
|
||||
|
||||
#### Add committed fix tag for completed PRs
|
||||
- When a PR is finished and there's no outstanding work left on a linked issue, add the `Resolution-Fix-Committed` label
|
||||
|
||||
|
||||
## Admin Panel
|
||||
[Here](https://fabric-cp.azurewebsites.net/bot/)
|
||||
|
||||
@@ -3,51 +3,45 @@
|
||||
## Globals
|
||||
Properties listed below affect the entire window, regardless of the profile settings.
|
||||
|
||||
| Property | Necessity | Type | Default | Description |
|
||||
| -------- | --------- | ---- | ------- | ----------- |
|
||||
| `alwaysShowTabs` | _Required_ | Boolean | `true` | When set to `true`, tabs are always displayed. When set to `false` and `showTabsInTitlebar` is set to `false`, tabs only appear after typing <kbd>Ctrl</kbd> + <kbd>T</kbd>. |
|
||||
| `defaultProfile` | _Required_ | String | PowerShell guid | Sets the default profile. Opens by typing <kbd>Ctrl</kbd> + <kbd>T</kbd> or by clicking the '+' icon. The guid of the desired default profile is used as the value. |
|
||||
| `initialCols` | _Required_ | Integer | `120` | The number of columns displayed in the window upon first load. |
|
||||
| `initialRows` | _Required_ | Integer | `30` | The number of rows displayed in the window upon first load. |
|
||||
| `requestedTheme` | _Required_ | String | `system` | Sets the theme of the application. Possible values: `"light"`, `"dark"`, `"system"` |
|
||||
| `showTerminalTitleInTitlebar` | _Required_ | Boolean | `true` | When set to `true`, titlebar displays the title of the selected tab. When set to `false`, titlebar displays "Windows Terminal". |
|
||||
| `showTabsInTitlebar` | Optional | Boolean | `true` | When set to `true`, the tabs are moved into the titlebar and the titlebar disappears. When set to `false`, the titlebar sits above the tabs. |
|
||||
| `wordDelimiters` | Optional | String | <code> /\()"'-:,.;<>~!@#$%^&*|+=[]{}~?│</code><br>_(`│` is `U+2502 BOX DRAWINGS LIGHT VERTICAL`)_ | Determines the delimiters used in a double click selection. |
|
||||
| Property | Necessity | Type | Description |
|
||||
| -------- | ---- | ----------- | ----------- |
|
||||
| `alwaysShowTabs` | _Required_ | Boolean | When set to `true`, tabs are always displayed. When set to `false` and `showTabsInTitlebar` is set to `false`, tabs only appear after typing <kbd>Ctrl</kbd> + <kbd>T</kbd>. |
|
||||
| `defaultProfile` | _Required_ | String | Sets the default profile. Opens by typing <kbd>Ctrl</kbd> + <kbd>T</kbd> or by clicking the '+' icon. The guid of the desired default profile is used as the value. |
|
||||
| `initialCols` | _Required_ | Integer | The number of columns displayed in the window upon first load. |
|
||||
| `initialRows` | _Required_ | Integer | The number of rows displayed in the window upon first load. |
|
||||
| `requestedTheme` | _Required_ | String | Sets the theme of the application. Possible values: `"light"`, `"dark"`, `"system"` |
|
||||
| `showTerminalTitleInTitlebar` | _Required_ | Boolean | When set to `true`, titlebar displays the title of the selected tab. When set to `false`, titlebar displays "Windows Terminal". |
|
||||
| `showTabsInTitlebar` | Optional | Boolean | When set to `true`, the tabs are moved into the titlebar and the titlebar disappears. When set to `false`, the titlebar sits above the tabs. |
|
||||
|
||||
## Profiles
|
||||
Properties listed below are specific to each unique profile.
|
||||
|
||||
| Property | Necessity | Type | Default | Description |
|
||||
| -------- | --------- | ---- | ------- | ----------- |
|
||||
| `acrylicOpacity` | _Required_ | Number | `0.5` | When `useAcrylic` is set to `true`, it sets the transparency of the window for the profile. Accepts floating point values from 0-1. |
|
||||
| `closeOnExit` | _Required_ | Boolean | `true` | When set to `true`, the selected tab closes when `exit` is typed. When set to `false`, the tab will remain open when `exit` is typed. |
|
||||
| `colorScheme` | _Required_ | String | `Campbell` | Name of the terminal color scheme to use. Color schemes are defined under `schemes`. |
|
||||
| `commandline` | _Required_ | String | `powershell.exe` | Executable used in the profile. |
|
||||
| `cursorColor` | _Required_ | String | `#FFFFFF` | Sets the cursor color for the profile. Uses hex color format: `"#rrggbb"`. |
|
||||
| `cursorShape` | _Required_ | String | `bar` | Sets the cursor shape for the profile. Possible values: `"vintage"` ( ▃ ), `"bar"` ( ┃ ), `"underscore"` ( ▁ ), `"filledBox"` ( █ ), `"emptyBox"` ( ▯ ) |
|
||||
| `fontFace` | _Required_ | String | `Consolas` | Name of the font face used in the profile. We will try to fallback to Consolas if this can't be found or is invalid. |
|
||||
| `fontSize` | _Required_ | Integer | `10` | Sets the font size. |
|
||||
| `guid` | _Required_ | String | | Unique identifier of the profile. Written in registry format: `"{00000000-0000-0000-0000-000000000000}"`. |
|
||||
| `historySize` | _Required_ | Integer | `9001` | The number of lines above the ones displayed in the window you can scroll back to. |
|
||||
| `name` | _Required_ | String | `PowerShell Core` | Name of the profile. Displays in the dropdown menu. |
|
||||
| `padding` | _Required_ | String | `0, 0, 0, 0` | Sets the padding around the text within the window. Can have three different formats: `"#"` sets the same padding for all sides, `"#, #"` sets the same padding for left-right and top-bottom, and `"#, #, #, #"` sets the padding individually for left, top, right, and bottom. |
|
||||
| `snapOnInput` | _Required_ | Boolean | `true` | When set to `true`, the window will scroll to the command input line when typing. When set to `false`, the window will not scroll when you start typing. |
|
||||
| `startingDirectory` | _Required_ | String | `%USERPROFILE%` | The directory the shell starts in when it is loaded. |
|
||||
| `useAcrylic` | _Required_ | Boolean | `false` | When set to `true`, the window will have an acrylic background. When set to `false`, the window will have a plain, untextured background. |
|
||||
| `background` | Optional | String | | Sets the background color of the profile. Overrides `background` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
|
||||
| `backgroundImage` | Optional | String | | Sets the file location of the Image to draw over the window background. |
|
||||
| `backgroundImageAlignment` | Optional | String | `center` | Sets how the background image aligns to the boundaries of the window. Possible values: `"center"`, `"left"`, `"top"`, `"right"`, `"bottom"`, `"topLeft"`, `"topRight"`, `"bottomLeft"`, `"bottomRight"` |
|
||||
| `backgroundImageOpacity` | Optional | Number | `1.0` | Sets the transparency of the background image. Accepts floating point values from 0-1. |
|
||||
| `backgroundImageStretchMode` | Optional | String | `uniformToFill` | Sets how the background image is resized to fill the window. Possible values: `"none"`, `"fill"`, `"uniform"`, `"uniformToFill"` |
|
||||
| `colorTable` | Optional | Array[String] | | Array of colors used in the profile if `colorscheme` is not set. Colors use hex color format: `"#rrggbb"`. Ordering is as follows: `[black, red, green, yellow, blue, magenta, cyan, white, bright black, bright red, bright green, bright yellow, bright blue, bright magenta, bright cyan, bright white]` |
|
||||
| `cursorHeight` | Optional | Integer | | Sets the percentage height of the cursor starting from the bottom. Only works when `cursorShape` is set to `"vintage"`. Accepts values from 25-100. |
|
||||
| `foreground` | Optional | String | | Sets the foreground color of the profile. Overrides `foreground` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
|
||||
| `icon` | Optional | String | | Image file location of the icon used in the profile. Displays within the tab and the dropdown menu. |
|
||||
| `scrollbarState` | Optional | String | | Defines the visibility of the scrollbar. Possible values: `"visible"`, `"hidden"` |
|
||||
| `tabTitle` | Optional | String | | Overrides default title of the tab. |
|
||||
| Property | Necessity | Type | Description |
|
||||
| -------- | ---- | ----------- | ----------- |
|
||||
| `acrylicOpacity` | _Required_ | Number | When `useAcrylic` is set to `true`, it sets the transparency of the window for the profile. Accepts floating point values from 0-1. |
|
||||
| `background` | _Required_ | String | Sets the background color of the profile. Overrides `background` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
|
||||
| `closeOnExit` | _Required_ | Boolean | When set to `true`, the selected tab closes when `exit` is typed. When set to `false`, the tab will remain open when `exit` is typed. |
|
||||
| `colorScheme` | _Required_ | String | Name of the terminal color scheme to use. Color schemes are defined under `schemes`. |
|
||||
| `commandline` | _Required_ | String | Executable used in the profile. |
|
||||
| `cursorColor` | _Required_ | String | Sets the cursor color for the profile. Uses hex color format: `"#rrggbb"`. |
|
||||
| `cursorShape` | _Required_ | String | Sets the cursor shape for the profile. Possible values: `"vintage"` ( ▃ ), `"bar"` ( ┃ ), `"underscore"` ( ▁ ), `"filledBox"` ( █ ), `"emptyBox"` ( ▯ ) |
|
||||
| `fontFace` | _Required_ | String | Name of the font face used in the profile. |
|
||||
| `fontSize` | _Required_ | Integer | Sets the font size. |
|
||||
| `guid` | _Required_ | String | Unique identifier of the profile. Written in registry format: `"{00000000-0000-0000-0000-000000000000}"`. |
|
||||
| `historySize` | _Required_ | Integer | The number of lines above the ones displayed in the window you can scroll back to. |
|
||||
| `name` | _Required_ | String | Name of the profile. Displays in the dropdown menu. |
|
||||
| `padding` | _Required_ | String | Sets the padding around the text within the window. Can have three different formats: `"#"` sets the same padding for all sides, `"#, #"` sets the same padding for left-right and top-bottom, and `"#, #, #, #"` sets the padding individually for left, top, right, and bottom. |
|
||||
| `snapOnInput` | _Required_ | Boolean | When set to `true`, the window will scroll to the command input line when typing. When set to `false`, the window will not scroll when you start typing. |
|
||||
| `startingDirectory` | _Required_ | String | The directory the shell starts in when it is loaded. |
|
||||
| `useAcrylic` | _Required_ | Boolean | When set to `true`, the window will have an acrylic background. When set to `false`, the window will have a plain, untextured background. |
|
||||
| `colorTable` | Optional | Array[String] | Array of colors used in the profile if `colorscheme` is not set. Colors use hex color format: `"#rrggbb"`. Ordering is as follows: `[black, red, green, yellow, blue, magenta, cyan, white, bright black, bright red, bright green, bright yellow, bright blue, bright magenta, bright cyan, bright white]` |
|
||||
| `cursorHeight` | Optional | Integer | Sets the percentage height of the cursor starting from the bottom. Only works when `cursorShape` is set to `"vintage"`. Accepts values from 25-100. |
|
||||
| `foreground` | Optional | String | Sets the foreground color of the profile. Overrides `foreground` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
|
||||
| `icon` | Optional | String | Image file location of the icon used in the profile. Displays within the tab and the dropdown menu. |
|
||||
| `scrollbarState` | Optional | String | Defines the visibility of the scrollbar. Possible values: `"visible"`, `"hidden"` |
|
||||
|
||||
## Schemes
|
||||
Properties listed below are specific to each color scheme. [ColorTool](https://github.com/microsoft/terminal/tree/master/src/tools/ColorTool) is a great tool you can use to create and explore new color schemes. All colors use hex color format.
|
||||
Properties listed below are specific to each color scheme. ColorTool is a great tool you can use to create and explore new color schemes. All colors use hex color format.
|
||||
|
||||
| Property | Necessity | Type | Description |
|
||||
| -------- | ---- | ----------- | ----------- |
|
||||
|
||||
@@ -1,527 +0,0 @@
|
||||
# Getting TAEF unittests to work with a C++/WinRT XAML Islands application
|
||||
|
||||
* __Author__: Mike Griese @zadjii-msft
|
||||
* __Created on__: 2019-06-06
|
||||
|
||||
|
||||
So you've built a Win32 application that uses XAML Islands to display it's UI
|
||||
with C++/WinRT. How do you go about adding unittests to this application? I'm
|
||||
going to cover the steps that I took to get the Windows Terminal updated to be
|
||||
able to test not only our C++/WinRT components, but also pure c++ classes that
|
||||
were used in the application, and components that used XAML UI elements.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Make sure you're using at least the 2.0.190605.7 version of the CppWinRT nuget
|
||||
package. Prior to this version, there are some bugs with C++/WinRT's detection
|
||||
of static lib dependencies. You might be able to get your build working with
|
||||
Visual Studio on earlier versions, but not straight from MsBuild.
|
||||
|
||||
Also, if you're going to be running your tests in a CI build of some sort, make
|
||||
sure that your tests are running on a machine running at least Windows 18362. If
|
||||
your CI isn't running that version, then this doesn't matter at all.
|
||||
|
||||
Furthermore, you may need an updated TAEF package as well. Our CI uses the TAEF
|
||||
VsTest adapter to allow ADO to run TAEF tests in CI. However, there's a bug in
|
||||
the tests adapter that prevents it from running tests in a UAP context. The
|
||||
`10.38.190605002` TAEF is the most recent release at the time of writing,
|
||||
however, that doesn't have the fix necessary. Fortunately, the TAEF team was
|
||||
kind enough to prototype a fix for us, which is the version
|
||||
`10.38.190610001-uapadmin`, which we're using in this repo until an official
|
||||
release with the fix is available.
|
||||
|
||||
## Move the C++/WinRT implementation to a static lib
|
||||
|
||||
By default, most (newly authored) C++/WinRT components are authored as a dll
|
||||
that can be used to activate your types. However, you might have other classes
|
||||
in that binary that you want to be able to test, which aren't winrt types. If
|
||||
the implementation is sitting in a DLL, it'll be hard to write a TAEF unittest
|
||||
dll that can call the pure c++ types you've defined.
|
||||
|
||||
The first thing you're going to need to do is move the implementation of your
|
||||
winrt component from a dll to a static lib. Once you have the static lib, we'll
|
||||
be able to link it into the dll you were previously producing, as well as being
|
||||
able to link it into the dll we'll be using to test the types. Once this is
|
||||
complete, your dll project will exist as little more than some extra packaging
|
||||
for your new lib, as all your code will be built by the lib.
|
||||
|
||||
To aid in this description, I'll be referring to the projects that we changed.
|
||||
The dll project we changed to a lib was the `TerminalApp` project. From it, we
|
||||
created a new `TerminalAppLib` project, and changed `TerminalApp` to create a
|
||||
dll by linking the lib `TerminalAppLib` produced.
|
||||
|
||||
### Create the static lib project
|
||||
|
||||
We'll start by creating a new static lib project. The easiest way to do this is
|
||||
by copying your existing dll `vcxproj` file into a new file. Make sure to change
|
||||
the `ProjectGuid` and to add the new project to your `.sln` file. Then, change
|
||||
the `ConfigurationType` to `StaticLibrary`. This Lib should be responsible for
|
||||
building all of your headers, `.cpp` files, `.idl`s for your winrt types, and
|
||||
any `.xaml` files you might have.
|
||||
|
||||
You'll likely need to place this new file into a separate directory from the
|
||||
existing dll project, as C++/WinRT uses the project directory as the root of the
|
||||
intermediate build tree. Each directory should only have one `.vcxproj` file in
|
||||
it. For the Terminal project, we created a subdirectory `lib/` underneath
|
||||
`TerminalApp/`, and updated the `Include` paths to properly point at the
|
||||
original files. You could alternatively put all the source in one directory, and
|
||||
have separate `dll/` and `lib/` subdirectories from the source that are solely
|
||||
responsible for building their binary.
|
||||
|
||||
At this point, you might face some difficulty including the right wimnd
|
||||
references, especially from other C++/WinRT dependencies for this project that
|
||||
exist in your solution. I don't know why, but I had a fair amount of difficulty
|
||||
using a `ProjectReference` from a C++/WinRT StaticLibrary to another C++/WinRT
|
||||
project in my solution. If you're referring to any other projects, you'll need
|
||||
to set up a reference to their built `.winmd`'s manually.
|
||||
|
||||
As an example, here's how we've added a reference to the `TerminalSettings`
|
||||
project from our `TerminalAppLib` project:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
private=false and CopyLocalSatelliteAssemblies=false, so that we don't
|
||||
propogate them upwards (which can make referencing this project result in
|
||||
duplicate type definitions)-->
|
||||
|
||||
<Reference Include="Microsoft.Terminal.Settings">
|
||||
<HintPath>$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\Microsoft.Terminal.Settings.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
The `HintPath` may be different depending on your project structure - verify
|
||||
locally the right path to the `.winmd` file you're looking for.
|
||||
|
||||
Notably, you'll also need to put a `pch.h` and `pch.cpp` in the new lib's
|
||||
directory, and use them instead of the `pch.h` used by the dll. C++/WinRT will be
|
||||
very angry with you if you try to use a `pch.h` in another directory. Since
|
||||
we're putting all the code into the static lib project, take your existing
|
||||
`pch.h` and move it to the lib project's directory and create an empty `pch.h`
|
||||
in the dll project's directory.
|
||||
|
||||
### Update the dll project
|
||||
|
||||
Now that we havea lib that builds all your code, we can go ahead and tear out
|
||||
most of the dead code from the old dll project. Remove all the source files from
|
||||
the dll's `.vcxproj` file, save for the `pch.h` and `pch.cpp` files. You _may_
|
||||
need to leave the headers for any C++/WinRT types you've authored in this project
|
||||
- I'm not totally sure it's necessary.
|
||||
|
||||
Now, to link the static lib we've created. For whatever reason, adding a
|
||||
`ProjectReference` to the static lib doesn't work. So, we'll need to manually
|
||||
link the lib from the lib project. You can do that by adding the lib's output
|
||||
dir to your `AdditionalLibraryDirectories`, and adding the lib to your
|
||||
`AdditionalDependencies`, like so:
|
||||
|
||||
```xml
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<!-- Manually link with the TerminalAppLib.lib we've built. -->
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)\$(Platform)\$(Configuration)\TerminalAppLib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
|
||||
<AdditionalDependencies>TerminalAppLib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
```
|
||||
|
||||
We are NOT adding a reference to the static lib project's .winmd here. As of the
|
||||
2.0.190605.7 CppWinRT nuget package, this is enough for MsBuild and Visual
|
||||
Studio to be able to determine that the static lib's `.winmd` should be included
|
||||
in this package.
|
||||
|
||||
At this point, you might have some mdmerge errors, which complain about
|
||||
duplicate types in one of your dependencies. This might especially happen if one
|
||||
of your dependencies (ex `A.dll`) is also a dependency for one of your _other_
|
||||
dependencies (ex `B.dll`). In this example, your final output project `C.dll`
|
||||
depends on both `A.dll` and `B.dll`, and `B.dll` _also_ depends on `A.dll`. If
|
||||
you're seeing this, I recommend adding `Private=false` and
|
||||
`CopyLocalSatelliteAssemblies=false` to your dependent dlls. In this example,
|
||||
add similar code to `B.dll`:
|
||||
|
||||
```xml
|
||||
<ProjectReference Include="$(SolutionDir)src\cascadia\TerminalSettings\TerminalSettings.vcxproj">
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</ProjectReference>
|
||||
```
|
||||
|
||||
where `TerminalSettings` is your `A.dll`, which is included by both `B` and `C`.
|
||||
|
||||
We additionally had an `.exe` project that was including our `TerminalApp`
|
||||
project, and all its `.xbf` and `.pri` files. If you have a similar project
|
||||
aggregating all your resources, you might need to update the paths to point to
|
||||
the new static lib project.
|
||||
|
||||
At this point, you should be able to rebuild your solution, and everything
|
||||
should be working just the same as before.
|
||||
|
||||
|
||||
## Add TAEF Tests
|
||||
|
||||
Now that you have a static library project, you can start building your unittest
|
||||
dll. Start by creating a new directory for your unittest code, and creating a
|
||||
`.vcxproj` for a TAEF unittest dll. For the Terminal solution, we use the TAEF
|
||||
nuget package `Taef.Redist.Wlk`.
|
||||
|
||||
### Referencing your C++/WinRT static lib
|
||||
|
||||
This step is the easiest. Add a `ProjectReference` to your static lib project,
|
||||
and your lib will be linked into your unittest dll.
|
||||
|
||||
```xml
|
||||
<ProjectReference Include="$(SolutionDir)\src\cascadia\TerminalApp\lib\TerminalAppLib.vcxproj" />
|
||||
```
|
||||
|
||||
Congratulations, you can now instantiate the pure c++ types you've authored in
|
||||
your static lib. But what if you want to test your C++/WinRT types too?
|
||||
|
||||
### Using your C++/WinRT types
|
||||
|
||||
To be able to instantiate your C++/WinRT types in a TAEF unittest, you'll need
|
||||
to rely on a new feature to Windows in version 1903 which enables unpackaged
|
||||
activation of WinRT types. To do this, we'll need to author a SxS manifest that
|
||||
lists each of our types, and include it in the dll, and also activate it
|
||||
manually from TAEF.
|
||||
|
||||
#### Creating the manifest
|
||||
|
||||
First, you need to create a manifest file that lists each dll your test depends
|
||||
upon, and each of the types in that dll. For example, here's an excerpt from the
|
||||
Terminal's manifest:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<file name="TerminalSettings.dll" hashalg="SHA1">
|
||||
<activatableClass name="Microsoft.Terminal.Settings.KeyChord" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1"></activatableClass>
|
||||
<activatableClass name="Microsoft.Terminal.Settings.TerminalSettings" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1"></activatableClass>
|
||||
</file>
|
||||
<file name="TerminalApp.dll" hashalg="SHA1">
|
||||
<activatableClass name="TerminalApp.App" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1"></activatableClass>
|
||||
<activatableClass name="TerminalApp.AppKeyBindings" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1"></activatableClass>
|
||||
<activatableClass name="TerminalApp.XamlmetaDataProvider" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1"></activatableClass>
|
||||
</file>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
Here we have two dlls that we depend upon, `TerminalSettings.dll` and
|
||||
`TerminalApp.dll`. `TerminalSettings` implements two types,
|
||||
`Microsoft.Terminal.Settings.KeyChord` and
|
||||
`Microsoft.Terminal.Settings.TerminalSettings`.
|
||||
|
||||
#### Linking the manifest to the test dll
|
||||
|
||||
Now that we have a manifest file, we need to embed it in your unittest dll. This
|
||||
is done with the following properties in your `vcxproj` file:
|
||||
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<GenerateManifest>true</GenerateManifest>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="TerminalApp.Unit.Tests.manifest" />
|
||||
</ItemGroup>
|
||||
```
|
||||
where `TerminalApp.Unit.Tests.manifest` is the name of your manifest file.
|
||||
|
||||
Additionally, you'll need to binplace the manifest _adjacent to your test
|
||||
binary_, so TAEF can find it at runtime. I've done this in the following way,
|
||||
though I'm sure there's a better way:
|
||||
|
||||
```xml
|
||||
<ItemDefinitionGroup>
|
||||
<PostBuildEvent>
|
||||
<!-- Manually copy the manifest to our outdir, because the test will need
|
||||
to find it adjacent to us. -->
|
||||
<Command>
|
||||
(xcopy /Y "$(OpenConsoleDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.manifest" "$(OutDir)\TerminalApp.Unit.Tests.manifest*" )
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
```
|
||||
|
||||
#### Copying your dependencies
|
||||
|
||||
Additionally, any dlls that implement any types your test is dependent upon will
|
||||
also need to be in the output directory for the test. Manually copy those DLLs
|
||||
to the tests' output directory too. The updated `PostBuildEvent` looks like
|
||||
this:
|
||||
|
||||
```xml
|
||||
<ItemDefinitionGroup>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
echo OutDir=$(OutDir)
|
||||
(xcopy /Y "$(SolutionDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.manifest" "$(OutDir)\TerminalApp.Unit.Tests.manifest*" )
|
||||
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
```
|
||||
|
||||
Again, verify the correct paths to your dependant C++/WinRT dlls, as they may be
|
||||
different than the above
|
||||
|
||||
#### Activating the manifest from TAEF
|
||||
|
||||
Now that the manifest lives adjacent to your test dll, and all your dependent
|
||||
dlls are also adjacent to the unittest dll, there's only one thing left to do.
|
||||
TAEF will not use your dll's manifest by default, so you'll need to add a
|
||||
property to your test class/method to tell TAEF to do so. You can do this with
|
||||
the following:
|
||||
|
||||
```c++
|
||||
class SettingsTests
|
||||
{
|
||||
// Use a custom manifest to ensure that we can activate winrt types from
|
||||
// our test. This property will tell taef to manually use this as the
|
||||
// sxs manifest during this test class. It includes all the C++/WinRT
|
||||
// types we've defined, so if your test is crashing for an unknown
|
||||
// reason, make sure it's included in that file.
|
||||
BEGIN_TEST_CLASS(SettingsTests)
|
||||
TEST_CLASS_PROPERTY(L"ActivationContext", L"TerminalApp.Unit.Tests.manifest")
|
||||
END_TEST_CLASS()
|
||||
|
||||
// Other Test code here
|
||||
}
|
||||
```
|
||||
|
||||
Now, if you try to add any test methods that instantiate WinRT types you've
|
||||
authored, they'll work. That is of course, so long as they don't use XAML. If
|
||||
you want to use any XAML types, then you'll have to keep reading.
|
||||
|
||||
### Using Xaml Types (with XAML Islands)
|
||||
|
||||
To be able to instatiate XAML types in your unittest, we'll need to make use of
|
||||
the [XAML Hosting
|
||||
API](https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/using-the-xaml-hosting-api)
|
||||
(Xaml Islands). This enables you to use XAML APIs from a Win32 context.
|
||||
|
||||
|
||||
#### Adding XAML Hosting code
|
||||
|
||||
First and foremost, you'll need to add the following to your test's `precomp.h`:
|
||||
|
||||
```c++
|
||||
#include <winrt/Windows.system.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.UI.Xaml.Hosting.h>
|
||||
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
|
||||
```
|
||||
|
||||
If you hit a compile warning that refers to `GetCurrentTime`, you'll probably
|
||||
also need the following, after you've `#include`'d `Windows.h`:
|
||||
|
||||
```c++
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
```
|
||||
|
||||
Then, somewhere in your test code, you'll need to start up Xaml Islands. I've done this in my `TEST_CLASS_SETUP`, so that I only create it once, and re-use it for each method.
|
||||
|
||||
```c++
|
||||
|
||||
class TabTests
|
||||
{
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
// Initialize the Xaml Hosting Manager
|
||||
_manager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
|
||||
_source = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource{};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager _manager{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _source{ nullptr };
|
||||
```
|
||||
|
||||
#### Authoring your test's `AppxManifest.xml`
|
||||
|
||||
This alone however is not enough to get XAML Islands to work. There was a fairly
|
||||
substantial change to the XAML Hosting API around Windows build 18295, so it
|
||||
explicitly requires that you have your executable's manifest set
|
||||
`maxversiontested` to higher than that version. However, because TAEF's `te.exe`
|
||||
is not so manifested, we can't just use our SxS manifest from before to set that
|
||||
version. Instead, you'll need to make TAEF run your test binary in a packaged
|
||||
content, with our own appxmanifest.
|
||||
|
||||
To do this, we'll need to author an `Appxmanifest.xml` to use with the test, and
|
||||
associate that manifest with the test.
|
||||
|
||||
Here's the AppxManifest we're using:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap">
|
||||
|
||||
<Identity Name="TerminalApp.Unit.Tests.Package"
|
||||
ProcessorArchitecture="neutral"
|
||||
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
|
||||
Version="1.0.0.0"
|
||||
ResourceId="en-us" />
|
||||
<Properties>
|
||||
<DisplayName>TerminalApp.Unit.Tests.Package Host Process</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corp.</PublisherDisplayName>
|
||||
<Logo>taef.png</Logo>
|
||||
<Description>TAEF Packaged Cwa FullTrust Application Host Process</Description>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="en-us" />
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="TE.ProcessHost" Executable="TE.ProcessHost.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<uap:VisualElements DisplayName="TAEF Packaged Cwa FullTrust Application Host Process" Square150x150Logo="taef.png" Square44x44Logo="taef.png" Description="TAEF Packaged Cwa Application Host Process" BackgroundColor="#222222">
|
||||
<uap:SplashScreen Image="taef.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust"/>
|
||||
</Capabilities>
|
||||
|
||||
<Extensions>
|
||||
<Extension Category="windows.activatableClass.inProcessServer">
|
||||
<InProcessServer>
|
||||
<Path>TerminalSettings.dll</Path>
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Terminal.Settings.TerminalSettings" ThreadingModel="both" />
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Terminal.Settings.KeyChord" ThreadingModel="both" />
|
||||
</InProcessServer>
|
||||
</Extension>
|
||||
<!-- More extensions here -->
|
||||
</Extensions>
|
||||
</Package>
|
||||
```
|
||||
|
||||
Change the `Identity.Name` and `Properties.DisplayName` to be more appropriate
|
||||
for your test, as well as other properties if you feel the need. TAEF will
|
||||
deploy the test package and remove it from your machine during testing, so it
|
||||
doesn't terribly matter what these values are.
|
||||
|
||||
MAKE SURE that `MaxVersionTested` is higher than `10.0.18295.0`. If it isn't,
|
||||
XAML islands will still prevent you from activating it.
|
||||
|
||||
UNDER NO CIRCUMSTANCE should you change the `<Application Id="TE.ProcessHost"
|
||||
Executable="TE.ProcessHost.exe" EntryPoint="Windows.FullTrustApplication">`
|
||||
line. This is how TAEF activates the TAEF host for your test binary. You might
|
||||
get a warning about `TE.ProcessHost.exe` being deprecated in favor of
|
||||
`TE.ProcessHost.UAP.exe`, but I haven't had success with the UAP version.
|
||||
|
||||
Lower in the file, you'll see the `Extensions` block. In here you'll put each of
|
||||
the winrt dependencies that your test needs, much like we did for the previous
|
||||
manifest. Note that the syntax is _not_ exactly the same as the SxS manifest.
|
||||
|
||||
#### Copy the AppxManifest to your `$(OutDir)`
|
||||
|
||||
Again, we'll need to copy this appxmanifest adjacent to the test binary so we
|
||||
can load it from the test. We'll do this similar to how we did the SxS manifest
|
||||
before. The complete `PostBuildEvent` now looks like this:
|
||||
|
||||
```xml
|
||||
<ItemDefinitionGroup>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
(xcopy /Y "$(SolutionDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.manifest" "$(OutDir)\TerminalApp.Unit.Tests.manifest*" )
|
||||
|
||||
(xcopy /Y "$(SolutionDir)src\cascadia\ut_app\TerminalApp.Unit.Tests.AppxManifest.xml" "$(OutDir)\TerminalApp.Unit.Tests.AppxManifest.xml*" )
|
||||
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalConnection\TerminalConnection.dll" "$(OutDir)\TerminalConnection.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalSettings\TerminalSettings.dll" "$(OutDir)\TerminalSettings.dll*" )
|
||||
(xcopy /Y "$(SolutionDir)$(Platform)\$(Configuration)\TerminalControl\TerminalControl.dll" "$(OutDir)\TerminalControl.dll*" )
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
```
|
||||
|
||||
The new line here is the line referencing
|
||||
`TerminalApp.Unit.Tests.AppxManifest.xml`. You can only have one
|
||||
`PostBuildEvent` per project, so don't go re-defining it for each additional
|
||||
step - MsBuild will only use the last one. Again, this is probably not the best
|
||||
way of copying these files over, but it works.
|
||||
|
||||
#### Use the AppxManifest in the test code
|
||||
|
||||
Now that we have the AppxManifest being binplaced next to our test, we can
|
||||
finally reference it in the test. Instead of using the `ActivationContext` from
|
||||
before, we'll use two new properties to tell TAEF to run this test as a package,
|
||||
and to use our manifest as the AppxManifest for the package.
|
||||
|
||||
```c++
|
||||
BEGIN_TEST_CLASS(TabTests)
|
||||
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
||||
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TerminalApp.Unit.Tests.AppxManifest.xml")
|
||||
END_TEST_CLASS()
|
||||
```
|
||||
|
||||
The complete Xaml Hosting test now looks like this:
|
||||
|
||||
```c++
|
||||
class TabTests
|
||||
{
|
||||
BEGIN_TEST_CLASS(TabTests)
|
||||
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
||||
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TerminalApp.Unit.Tests.AppxManifest.xml")
|
||||
END_TEST_CLASS()
|
||||
|
||||
TEST_METHOD(TryCreateXamlObjects);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
// Initialize the Xaml Hosting Manager
|
||||
_manager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
|
||||
_source = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource{};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager _manager{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _source{ nullptr };
|
||||
};
|
||||
void TabTests::TryCreateXamlObjects(){ ... }
|
||||
```
|
||||
|
||||
Congratulations, you can now use XAML types from your unittest.
|
||||
|
||||
### Using types from `Microsoft.UI.Xaml`
|
||||
|
||||
Let's say you're extra crazy and you're using the `Microsoft.UI.Xaml` nuget
|
||||
package. If you've followed all the steps above exactly, you're probably already
|
||||
fine! You've already put the types in your appxmanifest (there are a lot of
|
||||
them). You should be able to call the `Microsoft.UI.Xaml` types without any
|
||||
problems.
|
||||
|
||||
This is because of a few key lines we already put in the appxmanifest:
|
||||
|
||||
```xml
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
```
|
||||
|
||||
Without these `PackageDependency` entries for the VCLibs, Microsoft.UI.Xaml.dll
|
||||
will not be able to load.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
@@ -1,78 +0,0 @@
|
||||
---
|
||||
author: Pankaj Bhojwani pankaj.d.bhoj@gmail.com
|
||||
created on: 2019-06-12
|
||||
last updated: 2019-06-12
|
||||
issue id: #1235
|
||||
---
|
||||
|
||||
# Azure cloud shell connector
|
||||
|
||||
## Abstract
|
||||
|
||||
This spec goes over the details of how a feature enabling Windows Terminal users to connect to the Azure cloud shell should behave. It includes implementation and design considerations.
|
||||
|
||||
## Inspiration
|
||||
|
||||
The idea is to give developers access to their Azure services smoothly within the Windows Terminal app, letting them engage with Azure technologies in a convenient manner. By integrating the Azure cloud shell into Windows Terminal, we can do just that.
|
||||
|
||||
## Solution Design
|
||||
|
||||
The flowchart below shows the process by which the Azure cloud shell will be integrated into Windows Terminal.
|
||||
|
||||

|
||||
|
||||
The first three steps - authenticating the user, requesting a cloud shell and requesting a terminal - will be done via http requests. These requests will use the [cpprestsdk](https://github.com/Microsoft/cpprestsdk) library as that library is also owned by Microsoft, making it easy to resolve issues should any arise.
|
||||
|
||||
Authenticating the user will use [device code flow](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Device-Code-Flow) since Windows Terminal does not support browser access (yet). As for the authentication endpoint, Azure AD v1.0 will be used because Azure AD v2.0 (also known as Microsoft Identity Platform) [does not support login to personal accounts with device code flow](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Device-Code-Flow#constraints) at this time. Furthermore, upon successful authentication, the login/token information will be stored so that users will not need to repeatedly go through device code flow for future logins. Since this is sensitive information, the tokens will be stored with [Windows Storage](https://docs.microsoft.com/en-us/uwp/api/windows.storage) and encrypted with [Windows Security Data Protection](https://docs.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider).
|
||||
|
||||
The last step - connecting to the terminal - will be done via a websocket connection to allow easier communication between the app and the server.
|
||||
|
||||
The entire feature will be implemented in an isolated manner - i.e. it should have little to no dependency on the Windows Terminal app itself. This will allow the feature to become a plugin/extension once Windows Terminal supports plugins. More specifically, the connector will ascribe to the existing ITerminalConnection interface, making this simply another type of connection that Windows Terminal can make.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
Upon successful implementation, a new profile option will appear for users as illustrated in the picture below (the profile will have its own unique icon when implemented).
|
||||
|
||||

|
||||
|
||||
As for the rest of the UI, the implementation will adopt the user's preferences from the Windows Terminal app.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
This feature will not impact accessibility of Windows Terminal.
|
||||
|
||||
### Security
|
||||
|
||||
Any feature that connects to a network introduces some security risks. However, with proper usage of Azure AD v1.0 and careful storage of tokens received from the server, these risks will be mitigated.
|
||||
|
||||
### Reliability
|
||||
|
||||
This feature will not impact reliability of Windows Terminal.
|
||||
|
||||
### Compatibility
|
||||
|
||||
With the implementation being mostly decoupled from the Windows Terminal app itself, no existing code/behaviours should break due to this feature.
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
This feature will not impact performance, power or efficiency of Windows Terminal.
|
||||
|
||||
## Potential Issues
|
||||
|
||||
1. This implementation depends on another open source project, [cpprestsdk](https://github.com/Microsoft/cpprestsdk). Thus, any issues with their code will affect this feature. However, given that cpprestsdk is a Microsoft project, we can expect a level of reliability and also solve issues internally if needed.
|
||||
2. The proposed authentication endpoint is Azure AD v1.0 instead of Azure AD v2.0 (also known as Microsoft Identity Platform). Azure AD v1.0 is still supported for now, but there is a risk of it becoming deprecated at some point in the future. However, given that it is once again another Microsoft-owned project, we can request support for it through an internal channel. In the worst case, our implementation can switch to Microsoft Identity Platform (which would only requires some minor edits to the http requests).
|
||||
3. The Azure cloud shell API is not public, meaning that implementing this feature in an official capacity would require app permissions from the Azure cloud shell team. This brings about another dependency, but once again issues can be resolved through internal Microsoft channels.
|
||||
|
||||
## Future considerations
|
||||
|
||||
This could potentially be the first plugin for Windows Terminal once the app allows for plugins/extensions!
|
||||
|
||||
## Resources
|
||||
|
||||
* [Azure AD v1.0](https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-overview)
|
||||
* [cpprestsdk](https://github.com/Microsoft/cpprestsdk)
|
||||
* [Device code flow](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Device-Code-Flow)
|
||||
* [Windows Storage](https://docs.microsoft.com/en-us/uwp/api/windows.storage)
|
||||
* [Windows Security Data Protection](https://docs.microsoft.com/en-us/uwp/api/windows.security.cryptography.dataprotection.dataprotectionprovider)
|
||||
@@ -1,128 +0,0 @@
|
||||
# Editing Windows Terminal JSON Settings
|
||||
|
||||
One way (currently the only way) to configure Windows Terminal is by editing the profiles.json settings file. At
|
||||
the time of writing you can open the settings file in your default editor by selecting
|
||||
`Settings` from the WT pull down menu.
|
||||
|
||||
The settings are stored in the file `$env:LocalAppData\Packages\Microsoft.WindowsTerminal_<randomString>\RoamingState\profiles.json`
|
||||
|
||||
Details of specific settings can be found [here](../cascadia/SettingsSchema.md). A general introduction is provided below.
|
||||
|
||||
The settings are grouped under four headings:
|
||||
|
||||
1. Global: Settings that apply to the whole application e.g. Default profile, initial size etc.
|
||||
2. Key Bindings: Actually a sub field of the global settings, but worth discussing separately
|
||||
3. Profiles: A group of settings to be applied to a tab when it is opened using that profile. E.g. shell to use, cursor shape etc.
|
||||
4. Schemes: Sets of colors for background, text etc. that can be used by profiles
|
||||
|
||||
## Global Settings
|
||||
|
||||
These settings define startup defaults.
|
||||
|
||||
* Theme
|
||||
* Title Bar options
|
||||
* Initial size
|
||||
* Default profile used when WT is started
|
||||
|
||||
Example settings include
|
||||
|
||||
```json
|
||||
"defaultProfile" : "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",
|
||||
"initialCols" : 120,
|
||||
"initialRows" : 50,
|
||||
"requestedTheme" : "system",
|
||||
"keybinding" : []
|
||||
...
|
||||
```
|
||||
|
||||
## Key Bindings
|
||||
|
||||
This is an array of key chords and shortcuts to invoke various commands.
|
||||
Each command can have more than one key binding.
|
||||
|
||||
NOTE: Key bindings is a subfield of the global settings and
|
||||
key bindings apply to all profiles in the same manner.
|
||||
|
||||
## Profiles
|
||||
|
||||
A profile contains the settings applied when a new WT tab is opened. Each profile is identified by a GUID and contains
|
||||
a number of other fields.
|
||||
|
||||
* Which command to execute on startup - this can include arguments.
|
||||
* Starting directory
|
||||
* Which color scheme to use (see Schemes below)
|
||||
* Font face and size
|
||||
* Various settings to control appearance. E.g. Opacity, icon, cursor appearance, display name etc.
|
||||
* Other behavioural settings. E.g. Close on exit, snap on input, .....
|
||||
|
||||
Example settings include
|
||||
|
||||
```json
|
||||
"closeOnExit" : true,
|
||||
"colorScheme" : "Campbell",
|
||||
"commandline" : "wsl.exe -d Debian",
|
||||
"cursorColor" : "#FFFFFF",
|
||||
"cursorShape" : "bar",
|
||||
"fontFace" : "Hack",
|
||||
"fontSize" : 9,
|
||||
"guid" : "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",
|
||||
"name" : "Debian",
|
||||
"startingDirectory" : "%USERPROFILE%/wslhome"
|
||||
....
|
||||
```
|
||||
|
||||
The profile GUID is used to reference the default profile in the global settings.
|
||||
|
||||
The values for background image stretch mode are documented [here](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.stretch)
|
||||
|
||||
## Color Schemes
|
||||
|
||||
Each scheme defines the color values to be used for various terminal escape sequences.
|
||||
Each schema is identified by the name field. Examples include
|
||||
|
||||
```json
|
||||
"name" : "Campbell",
|
||||
"background" : "#0C0C0C",
|
||||
"black" : "#0C0C0C",
|
||||
"blue" : "#0037DA",
|
||||
"foreground" : "#F2F2F2",
|
||||
"green" : "#13A10E",
|
||||
"red" : "#C50F1F",
|
||||
"white" : "#CCCCCC",
|
||||
"yellow" : "#C19C00"
|
||||
...
|
||||
```
|
||||
|
||||
The schema name can then be referenced in one or more profiles.
|
||||
|
||||
## Configuration Examples:
|
||||
|
||||
### Add a custom background to the WSL Debian terminal profile
|
||||
|
||||
1. Download the Debian SVG logo https://www.debian.org/logos/openlogo.svg
|
||||
2. Put the image in the
|
||||
`$env:LocalAppData\Packages\Microsoft.WindowsTerminal_<randomString>\RoamingState\`
|
||||
directory (same directory as your `profiles.json` file).
|
||||
|
||||
__NOTE__: You can put the image anywhere you like, the above suggestion happens to be convenient.
|
||||
3. Open your WT json properties file.
|
||||
4. Under the Debian Linux profile, add the following fields:
|
||||
```json
|
||||
"backgroundImage": "ms-appdata:///Roaming/openlogo.jpg",
|
||||
"backgroundImageOpacity": 0.3,
|
||||
"backgroundImageStretchMode": "fill",
|
||||
```
|
||||
5. Make sure that `useAcrylic` is `false`.
|
||||
6. Save the file.
|
||||
7. Jump over to WT and verify your changes.
|
||||
|
||||
Notes:
|
||||
1. You will need to experiment with different color settings
|
||||
and schemes to make your terminal text visible on top of your image
|
||||
2. If you store the image in the UWP directory (the same directory as your profiles.json file),
|
||||
then you should use the URI style path name given in the above example.
|
||||
More information about UWP URI schemes [here](https://docs.microsoft.com/en-us/windows/uwp/app-resources/uri-schemes).
|
||||
3. Instead of using a UWP URI you can use a:
|
||||
1. URL such as
|
||||
`http://open.esa.int/files/2017/03/Mayer_and_Bond_craters_seen_by_SMART-1-350x346.jpg`
|
||||
2. Local file location such as `C:\Users\Public\Pictures\openlogo.jpg`
|
||||
@@ -1,90 +0,0 @@
|
||||
# Windows Terminal User Documentation
|
||||
|
||||
NOTE: At the time of writing Windows Terminal is still under active development and many things will
|
||||
change. If you notice an error in the docs, please raise an issue. Or better yet, please file a PR with an appropriate update!
|
||||
|
||||
## Installing Windows Terminal
|
||||
|
||||
### From Source Code
|
||||
|
||||
Follow the instructions in this repo's [README](/README.md#developer-guidance).
|
||||
|
||||
### From the Microsoft Store
|
||||
|
||||
1. Make sure you have upgraded to the current Windows 10 release (at least 1903)
|
||||
2. Search for Windows Terminal in the Store
|
||||
3. Review the minimum system settings to ensure you can successfully install Windows Terminal
|
||||
4. Install in the normal fashion
|
||||
|
||||
## Starting Windows Terminal
|
||||
|
||||
From the Windows Start menu, select Windows Terminal and run the application.
|
||||
|
||||
Note: You can right click on the application item and run with Windows Administrator privilege if required.
|
||||
|
||||
The default shell is PowerShell.
|
||||
|
||||
|
||||
### Command line options
|
||||
|
||||
None at this time. See issue [#607](https://github.com/microsoft/terminal/issues/607)
|
||||
|
||||
## Multiple Tabs
|
||||
|
||||
Additional shells can be started by hitting the `+` button from the tab bar -- a new instance of the
|
||||
default shell is displayed (default shortcut `Ctrl+Shift+1`).
|
||||
|
||||
## Running a Different Shell
|
||||
|
||||
Note: The following text assumes you have WSL installed.
|
||||
|
||||
To choose a different shell (e.g. `cmd.exe` or WSL `bash`) then
|
||||
|
||||
1. Select the `down` button next to the `+` in the tab bar
|
||||
2. Choose your new shell from the list (more on how to extend the list in the config section)
|
||||
|
||||
## Starting a new PowerShell tab with admin privilege
|
||||
|
||||
There is no current plan to support this feature for security reaons. See issue [#623](https://github.com/microsoft/terminal/issues/632)
|
||||
|
||||
## Using cut and paste in the Terminal window
|
||||
|
||||
### With PowerShell
|
||||
|
||||
* Copy - Select the text with mouse (default left button), then right click with mouse
|
||||
* Paste - by default use `<ctrl>+v`>, or right click with mouse
|
||||
|
||||
### With Bash
|
||||
|
||||
* Copy - Select the text with mouse (default left button), then right click with mouse
|
||||
* Paste - Right click with mouse
|
||||
|
||||
## Add a "Open Windows Terminal Here" to File Explorer
|
||||
|
||||
Not currently supported "out of the box". See issue [#1060](https://github.com/microsoft/terminal/issues/1060)
|
||||
|
||||
## Configuring Windows Terminal
|
||||
|
||||
At the time of writing all Windows Terminal settings are managed via a json file.
|
||||
|
||||
From the `down` button in the top bar select Settings (default shortcut `Ctrl+,`).
|
||||
|
||||
Your default json editor will open up the Terminal settings file. The file can be found
|
||||
at `$env:LocalAppData\Packages\Microsoft.WindowsTerminal_<randomString>/RoamingState`
|
||||
|
||||
An introduction to the the various settings can be found [here](UsingJsonSettings.md).
|
||||
|
||||
The list of valid settings can be found in the [Profiles.json Documentation](../cascadia/SettingsSchema.md) doc.
|
||||
|
||||
## Tips and Tricks:
|
||||
|
||||
1. In PowerShell you can discover if the Windows Terminal is being used by checking for the existence of the environment variable `WT_SESSION`.
|
||||
|
||||
Under pwsh you can also use
|
||||
`(Get-Process -Id $pid).Parent.Parent.ProcessName -eq 'WindowsTerminal'`
|
||||
|
||||
(ref https://twitter.com/r_keith_hill/status/1142871145852440576)
|
||||
|
||||
2. Terminal zoom can be changed by holding `Ctrl` and scrolling with mouse.
|
||||
3. If `useAcrylic` is enabled in profiles.json, background opacity can be changed by holding `Ctrl+Shift` and scrolling with mouse.
|
||||
4. Please add more Tips and Tricks
|
||||
@@ -558,37 +558,22 @@ bool TextBuffer::IncrementCircularBuffer()
|
||||
|
||||
//Routine Description:
|
||||
// - Retrieves the position of the last non-space character on the final line of the text buffer.
|
||||
// - By default, we search the entire buffer to find the last non-space character
|
||||
//Arguments:
|
||||
// - <none>
|
||||
//Return Value:
|
||||
// - Coordinate position in screen coordinates (offset coordinates, not array index coordinates).
|
||||
COORD TextBuffer::GetLastNonSpaceCharacter() const
|
||||
{
|
||||
return GetLastNonSpaceCharacter(GetSize());
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
// - Retrieves the position of the last non-space character in the given viewport
|
||||
// - This is basically an optimized version of GetLastNonSpaceCharacter(), and can be called when
|
||||
// - we know the last character is within the given viewport (so we don't need to check the entire buffer)
|
||||
//Arguments:
|
||||
// - The viewport
|
||||
//Return value:
|
||||
// - Coordinate position (relative to the text buffer)
|
||||
COORD TextBuffer::GetLastNonSpaceCharacter(const Microsoft::Console::Types::Viewport viewport) const
|
||||
{
|
||||
COORD coordEndOfText = { 0 };
|
||||
// Search the given viewport by starting at the bottom.
|
||||
coordEndOfText.Y = viewport.BottomInclusive();
|
||||
COORD coordEndOfText;
|
||||
// Always search the whole buffer, by starting at the bottom.
|
||||
coordEndOfText.Y = GetSize().BottomInclusive();
|
||||
|
||||
const ROW* pCurrRow = &GetRowByOffset(coordEndOfText.Y);
|
||||
// The X position of the end of the valid text is the Right draw boundary (which is one beyond the final valid character)
|
||||
coordEndOfText.X = static_cast<short>(pCurrRow->GetCharRow().MeasureRight()) - 1;
|
||||
|
||||
// If the X coordinate turns out to be -1, the row was empty, we need to search backwards for the real end of text.
|
||||
const auto viewportTop = viewport.Top();
|
||||
bool fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > viewportTop); // this row is empty, and we're not at the top
|
||||
bool fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > 0); // this row is empty, and we're not at the top
|
||||
while (fDoBackUp)
|
||||
{
|
||||
coordEndOfText.Y--;
|
||||
@@ -596,7 +581,7 @@ COORD TextBuffer::GetLastNonSpaceCharacter(const Microsoft::Console::Types::View
|
||||
// We need to back up to the previous row if this line is empty, AND there are more rows
|
||||
|
||||
coordEndOfText.X = static_cast<short>(pCurrRow->GetCharRow().MeasureRight()) - 1;
|
||||
fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > viewportTop);
|
||||
fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > 0);
|
||||
}
|
||||
|
||||
// don't allow negative results
|
||||
|
||||
@@ -105,7 +105,6 @@ public:
|
||||
bool IncrementCircularBuffer();
|
||||
|
||||
COORD GetLastNonSpaceCharacter() const;
|
||||
COORD GetLastNonSpaceCharacter(const Microsoft::Console::Types::Viewport viewport) const;
|
||||
|
||||
Cursor& GetCursor();
|
||||
const Cursor& GetCursor() const;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
|
||||
|
||||
<PropertyGroup Label="Version">
|
||||
<!-- These fields are picked up by PackageES -->
|
||||
<VersionMajor>0</VersionMajor>
|
||||
<VersionMinor>3</VersionMinor>
|
||||
<VersionMinor>2</VersionMinor>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Configuration">
|
||||
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.17763.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<!--
|
||||
These two properties are very important!
|
||||
Without them, msbuild will stomp MinVersion and MaxVersionTested in the
|
||||
@@ -19,23 +22,27 @@
|
||||
<AppxOSMinVersionReplaceManifestVersion>false</AppxOSMinVersionReplaceManifestVersion>
|
||||
<AppxOSMaxVersionTestedReplaceManifestVersion>false</AppxOSMaxVersionTestedReplaceManifestVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>CA5CAD1A-224A-4171-B13A-F16E576FDD12</ProjectGuid>
|
||||
<EntryPointProjectUniqueName>..\WindowsTerminal\WindowsTerminal.vcxproj</EntryPointProjectUniqueName>
|
||||
<DebuggerType>NativeOnly</DebuggerType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="!Exists('CascadiaPackage_TemporaryKey.pfx')">
|
||||
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
|
||||
<AppxBundle>Never</AppxBundle>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="Exists('CascadiaPackage_TemporaryKey.pfx')">
|
||||
<AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
|
||||
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
|
||||
<PackageCertificateKeyFile>CascadiaPackage_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="Exists('CascadiaPackage_TemporaryKey.pfx')">
|
||||
<None Include="CascadiaPackage_TemporaryKey.pfx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest" Condition="'$(WindowsTerminalReleaseBuild)'=='true'">
|
||||
<SubType>Designer</SubType>
|
||||
@@ -44,6 +51,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(OpenConsoleDir)res\terminal\LargeTile.scale-100.png">
|
||||
<Link>Images\LargeTile.scale-100.png</Link>
|
||||
@@ -257,52 +265,64 @@
|
||||
<Content Include="ProfileIcons\{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.scale-200.png" />
|
||||
<Content Include="ProfileIcons\{9acb9455-ca41-5af7-950f-6bca1bc9722f}.scale-100.png" />
|
||||
<Content Include="ProfileIcons\{9acb9455-ca41-5af7-950f-6bca1bc9722f}.scale-200.png" />
|
||||
<Content Include="ProfileIcons\{b453ae62-4e3d-5e58-b989-0a998ec441b8}.scale-100.png" />
|
||||
<Content Include="ProfileIcons\{b453ae62-4e3d-5e58-b989-0a998ec441b8}.scale-200.png" />
|
||||
<PRIResource Include="Resources\en-US\Resources.resw" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.post.props" />
|
||||
|
||||
<!--
|
||||
This exists to work around Microsoft/microsoft-ui-xaml#494.
|
||||
https://github.com/Microsoft/microsoft-ui-xaml/issues/494
|
||||
|
||||
Because the MUX nuget package hardcodes a requirement that the consuming project
|
||||
be of type 'UAP', its resources are included in packaging and dependency resolution
|
||||
by default. Inject them here.
|
||||
|
||||
This does mean that version changes to Microsoft.UI.Xaml must be manually reflected
|
||||
here.
|
||||
-->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\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.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<WapProjBeforeGenerateAppxManifestDependsOn>
|
||||
$(WapProjBeforeGenerateAppxManifestDependsOn);
|
||||
_ConsoleInjectMUXWinmdIntoReferences;
|
||||
</WapProjBeforeGenerateAppxManifestDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="_ConsoleInjectMUXWinmdIntoReferences">
|
||||
<ItemGroup>
|
||||
<_WinmdFilesFromReferences Include="@(Reference)" Condition="'%(Reference.Filename)' == 'Microsoft.UI.Xaml' and '%(Reference.Extension)' == '.winmd'" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<!-- End workaround -->
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WindowsTerminal\WindowsTerminal.vcxproj" />
|
||||
<ProjectReference Include="..\..\host\exe\Host.EXE.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Stomp the path to conhost.exe.
|
||||
This task will copy OpenConsole.exe to the appx as conhost.exe, and place it
|
||||
adjacent to WindowsTerminal.exe.
|
||||
-->
|
||||
<Target Name="OpenConsoleStompSourceProjectForWapProject" BeforeTargets="_ConvertItems">
|
||||
<ItemGroup>
|
||||
<Target Name="OpenConsoleStompSourceProjectForWapProject" BeforeTargets="_ConvertItems">
|
||||
<ItemGroup>
|
||||
<!-- Stomp all "SourceProject" values for all incoming dependencies to flatten the package. -->
|
||||
<_TemporaryFilteredWapProjOutput Include="@(_FilteredNonWapProjProjectOutput)" />
|
||||
<_FilteredNonWapProjProjectOutput Remove="@(_TemporaryFilteredWapProjOutput)" />
|
||||
<_FilteredNonWapProjProjectOutput Include="@(_TemporaryFilteredWapProjOutput)">
|
||||
<_TemporaryFilteredWapProjOutput
|
||||
Include="@(_FilteredNonWapProjProjectOutput)" />
|
||||
<_FilteredNonWapProjProjectOutput Remove="@(_TemporaryFilteredWapProjOutput)" />
|
||||
<_FilteredNonWapProjProjectOutput Include="@(_TemporaryFilteredWapProjOutput)">
|
||||
<!-- Override the filename for OpenConsole.exe (only) -->
|
||||
<TargetPath Condition="'%(Filename)' == 'OpenConsole' and '%(Extension)' == '.exe'">conhost.exe</TargetPath>
|
||||
<!-- Blank the SourceProject here to vend all files into the root of the package. -->
|
||||
<SourceProject>
|
||||
</SourceProject>
|
||||
</_FilteredNonWapProjProjectOutput>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<!-- Move all the PRI files that would be packaged into the appx into _PriFile so that
|
||||
GenerateProjectPriFile catches them. This requires us to move payload collection
|
||||
up before GenerateProjectPriFile, when it is typically _after_ it (because the
|
||||
DesktopBridge project type is built to only prepare the payload during appx manifest
|
||||
generation.
|
||||
|
||||
Since PRI file generation is _before_ manifest generation (for possibly obvious or
|
||||
important reasons), that doesn't work for us.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<_GenerateProjectPriFileDependsOn>OpenConsoleLiftDesktopBridgePriFiles;$(_GenerateProjectPriFileDependsOn)</_GenerateProjectPriFileDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="OpenConsoleLiftDesktopBridgePriFiles" DependsOnTargets="_ConvertItems">
|
||||
<ItemGroup>
|
||||
<_PriFile Include="@(_NonWapProjProjectOutput)" Condition="'%(Extension)' == '.pri'" />
|
||||
<!-- Remove all other .pri files from the appx payload. -->
|
||||
<AppxPackagePayload Remove="@(AppxPackagePayload)" Condition="'%(Extension)' == '.pri'" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<!-- Blank the SourceProject here to vend all files into the root of the pacakge. -->
|
||||
<SourceProject></SourceProject>
|
||||
</_FilteredNonWapProjProjectOutput>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.18362.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 314 B |
Binary file not shown.
|
Before Width: | Height: | Size: 573 B |
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -123,16 +123,37 @@
|
||||
<data name="AppName" xml:space="preserve">
|
||||
<value>Windows Terminal (Preview)</value>
|
||||
</data>
|
||||
<data name="InitialJsonParseErrorText" xml:space="preserve">
|
||||
<value>Settings could not be loaded from file - temporarily using the default settings. Check for syntax errors, including trailing commas.</value>
|
||||
</data>
|
||||
<data name="InitialJsonParseErrorTitle" xml:space="preserve">
|
||||
<value>Failed to load settings</value>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
</data>
|
||||
<data name="ReloadJsonParseErrorText" xml:space="preserve">
|
||||
<value>Settings could not be reloaded from file. Check for syntax errors, including trailing commas.</value>
|
||||
</data>
|
||||
<data name="ReloadJsonParseErrorTitle" xml:space="preserve">
|
||||
<value>Failed to reload settings</value>
|
||||
</data>
|
||||
<data name="AppDescriptionDev" xml:space="preserve">
|
||||
<value>The Windows Terminal, but Unofficial</value>
|
||||
</data>
|
||||
<data name="AppNameDev" xml:space="preserve">
|
||||
<value>Windows Terminal (Dev Build)</value>
|
||||
</data>
|
||||
<data name="AboutTitleText" xml:space="preserve">
|
||||
<value>About</value>
|
||||
</data>
|
||||
<data name="VersionLabelText" xml:space="preserve">
|
||||
<value>Version:</value>
|
||||
</data>
|
||||
<data name="AppShortName" xml:space="preserve">
|
||||
<value>Terminal</value>
|
||||
</data>
|
||||
<data name="AppShortNameDev" xml:space="preserve">
|
||||
<value>Terminal (Dev)</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- cppwinrt.build.pre.props depends on these settings: -->
|
||||
<!-- build a dll, not exe (Application) -->
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<!-- sets a bunch of Windows Universal properties -->
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{015a0047-772d-4f1a-88c9-45c18f0adfb6}</ProjectGuid>
|
||||
<ProjectName>Microsoft.UI.Xaml.Markup</ProjectName>
|
||||
<RootNamespace>Microsoft.UI.Xaml.Markup</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<OutputFile>$(OutDir)\$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>WindowsApp.lib;Kernel32.lib;User32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="XamlApplication.h">
|
||||
<DependentUpon>XamlApplication.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XamlApplication.cpp">
|
||||
<DependentUpon>XamlApplication.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Midl Include="XamlApplication.idl" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Microsoft.UI.Xaml.Markup.def" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="ReadMe.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
DON'T REDIRECT OUR OUTPUT.
|
||||
Setting this will tell cppwinrt.build.post.props to copy our output from
|
||||
the default OutDir up one level, so the wapproj will be able to find it.
|
||||
-->
|
||||
<NoOutputRedirection>true</NoOutputRedirection>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
</Project>
|
||||
22
src/cascadia/Microsoft.UI.Xaml.Markup/ReadMe.md
Normal file
22
src/cascadia/Microsoft.UI.Xaml.Markup/ReadMe.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Xaml Application for Win32
|
||||
|
||||
This project implements an Xaml application that is suited for Win32 projects.
|
||||
A pseudo implementation of this object is:
|
||||
```
|
||||
namespace Microsoft.UI.Xaml.Markup
|
||||
{
|
||||
interface IXamlMetadataProviderContainer
|
||||
{
|
||||
Windows.Foundation.Collections.IVector<Windows.UI.Xaml.Markup.IXamlMetadataProvider> Providers { get; };
|
||||
};
|
||||
|
||||
class XamlApplication : Windows.UI.Xaml.Application, IXamlMetadataProviderContainer, IDisposable
|
||||
{
|
||||
XamlApplication()
|
||||
{
|
||||
WindowsXamlManager.InitializeForThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
130
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.cpp
Normal file
130
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "XamlApplication.h"
|
||||
|
||||
#include "XamlApplication.g.cpp"
|
||||
|
||||
namespace xaml = ::winrt::Windows::UI::Xaml;
|
||||
|
||||
extern "C" {
|
||||
WINBASEAPI HMODULE WINAPI LoadLibraryExW(_In_ LPCWSTR lpLibFileName, _Reserved_ HANDLE hFile, _In_ DWORD dwFlags);
|
||||
WINBASEAPI HMODULE WINAPI GetModuleHandleW(_In_opt_ LPCWSTR lpModuleName);
|
||||
WINUSERAPI BOOL WINAPI PeekMessageW(_Out_ LPMSG lpMsg, _In_opt_ HWND hWnd, _In_ UINT wMsgFilterMin, _In_ UINT wMsgFilterMax, _In_ UINT wRemoveMsg);
|
||||
WINUSERAPI LRESULT WINAPI DispatchMessageW(_In_ CONST MSG* lpMsg);
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::UI::Xaml::Markup::implementation
|
||||
{
|
||||
XamlApplication::XamlApplication(winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider parentProvider)
|
||||
{
|
||||
m_providers.Append(parentProvider);
|
||||
}
|
||||
|
||||
XamlApplication::XamlApplication()
|
||||
{
|
||||
}
|
||||
|
||||
void XamlApplication::Close()
|
||||
{
|
||||
if (m_bIsClosed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_bIsClosed = true;
|
||||
|
||||
m_providers.Clear();
|
||||
|
||||
Exit();
|
||||
{
|
||||
MSG msg = {};
|
||||
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
|
||||
{
|
||||
::DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XamlApplication::~XamlApplication()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
xaml::Markup::IXamlType XamlApplication::GetXamlType(xaml::Interop::TypeName const& type)
|
||||
{
|
||||
for (const auto& provider : m_providers)
|
||||
{
|
||||
const auto xamlType = provider.GetXamlType(type);
|
||||
if (xamlType != nullptr)
|
||||
{
|
||||
return xamlType;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
xaml::Markup::IXamlType XamlApplication::GetXamlType(winrt::hstring const& fullName)
|
||||
{
|
||||
for (const auto& provider : m_providers)
|
||||
{
|
||||
const auto xamlType = provider.GetXamlType(fullName);
|
||||
if (xamlType != nullptr)
|
||||
{
|
||||
return xamlType;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::com_array<xaml::Markup::XmlnsDefinition> XamlApplication::GetXmlnsDefinitions()
|
||||
{
|
||||
std::list<xaml::Markup::XmlnsDefinition> definitions;
|
||||
for (const auto& provider : m_providers)
|
||||
{
|
||||
auto defs = provider.GetXmlnsDefinitions();
|
||||
for (const auto& def : defs)
|
||||
{
|
||||
definitions.insert(definitions.begin(), def);
|
||||
}
|
||||
}
|
||||
|
||||
return winrt::com_array<xaml::Markup::XmlnsDefinition>(definitions.begin(), definitions.end());
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Collections::IVector<xaml::Markup::IXamlMetadataProvider> XamlApplication::Providers()
|
||||
{
|
||||
return m_providers;
|
||||
}
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::UI::Xaml::Markup::factory_implementation
|
||||
{
|
||||
XamlApplication::XamlApplication()
|
||||
{
|
||||
// Workaround a bug where twinapi.appcore.dll and threadpoolwinrt.dll gets loaded after it has been unloaded
|
||||
// because of a call to GetActivationFactory
|
||||
const wchar_t* preloadDlls[] = {
|
||||
L"twinapi.appcore.dll",
|
||||
L"threadpoolwinrt.dll",
|
||||
};
|
||||
for (auto dllName : preloadDlls)
|
||||
{
|
||||
const auto module = ::LoadLibraryExW(dllName, nullptr, 0);
|
||||
m_preloadInstances.push_back(module);
|
||||
}
|
||||
}
|
||||
|
||||
XamlApplication::~XamlApplication()
|
||||
{
|
||||
for (auto module : m_preloadInstances)
|
||||
{
|
||||
::FreeLibrary(module);
|
||||
}
|
||||
m_preloadInstances.clear();
|
||||
}
|
||||
}
|
||||
46
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.h
Normal file
46
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "XamlApplication.g.h"
|
||||
#include <winrt/Windows.UI.Xaml.Hosting.h>
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace winrt::Microsoft::UI::Xaml::Markup::implementation
|
||||
{
|
||||
class XamlApplication : public XamlApplicationT<XamlApplication, Windows::UI::Xaml::Markup::IXamlMetadataProvider>
|
||||
{
|
||||
public:
|
||||
XamlApplication();
|
||||
XamlApplication(winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider parentProvider);
|
||||
~XamlApplication();
|
||||
|
||||
void Close();
|
||||
|
||||
winrt::Windows::UI::Xaml::Markup::IXamlType GetXamlType(winrt::Windows::UI::Xaml::Interop::TypeName const& type);
|
||||
winrt::Windows::UI::Xaml::Markup::IXamlType GetXamlType(winrt::hstring const& fullName);
|
||||
winrt::com_array<winrt::Windows::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions();
|
||||
|
||||
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider> Providers();
|
||||
|
||||
private:
|
||||
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider> m_providers = winrt::single_threaded_vector<Windows::UI::Xaml::Markup::IXamlMetadataProvider>();
|
||||
bool m_bIsClosed = false;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::UI::Xaml::Markup::factory_implementation
|
||||
{
|
||||
class XamlApplication : public XamlApplicationT<XamlApplication, implementation::XamlApplication>
|
||||
{
|
||||
public:
|
||||
XamlApplication();
|
||||
~XamlApplication();
|
||||
|
||||
private:
|
||||
std::vector<HMODULE> m_preloadInstances;
|
||||
};
|
||||
}
|
||||
17
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.idl
Normal file
17
src/cascadia/Microsoft.UI.Xaml.Markup/XamlApplication.idl
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.UI.Xaml.Markup
|
||||
{
|
||||
interface IXamlMetadataProviderContainer
|
||||
{
|
||||
Windows.Foundation.Collections.IVector<Windows.UI.Xaml.Markup.IXamlMetadataProvider> Providers { get; };
|
||||
};
|
||||
|
||||
[default_interface]
|
||||
unsealed runtimeclass XamlApplication : Windows.UI.Xaml.Application, IXamlMetadataProviderContainer, Windows.Foundation.IClosable
|
||||
{
|
||||
XamlApplication();
|
||||
protected XamlApplication(Windows.UI.Xaml.Markup.IXamlMetadataProvider parentProvider);
|
||||
}
|
||||
}
|
||||
4
src/cascadia/Microsoft.UI.Xaml.Markup/packages.config
Normal file
4
src/cascadia/Microsoft.UI.Xaml.Markup/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.190417.3" targetFramework="native" />
|
||||
</packages>
|
||||
21
src/cascadia/Microsoft.UI.Xaml.Markup/pch.h
Normal file
21
src/cascadia/Microsoft.UI.Xaml.Markup/pch.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
// Exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
// To enable support for non-WinRT interfaces, unknwn.h must be included before any C++/WinRT headers.
|
||||
#include <unknwn.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
template<typename D, typename... I>
|
||||
struct App_baseWithProvider : public App_base<D, ::winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider>
|
||||
{
|
||||
using IXamlType = ::winrt::Windows::UI::Xaml::Markup::IXamlType;
|
||||
|
||||
IXamlType GetXamlType(::winrt::Windows::UI::Xaml::Interop::TypeName const& type)
|
||||
{
|
||||
return AppProvider()->GetXamlType(type);
|
||||
}
|
||||
|
||||
IXamlType GetXamlType(::winrt::hstring const& fullName)
|
||||
{
|
||||
return AppProvider()->GetXamlType(fullName);
|
||||
}
|
||||
|
||||
::winrt::com_array<::winrt::Windows::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions()
|
||||
{
|
||||
return AppProvider()->GetXmlnsDefinitions();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _contentLoaded{ false };
|
||||
std::shared_ptr<XamlMetaDataProvider> _appProvider;
|
||||
std::shared_ptr<XamlMetaDataProvider> AppProvider()
|
||||
{
|
||||
if (!_appProvider)
|
||||
{
|
||||
_appProvider = std::make_shared<XamlMetaDataProvider>();
|
||||
}
|
||||
return _appProvider;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename D, typename... I>
|
||||
using AppT2 = App_baseWithProvider<D, I...>;
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
||||
|
||||
#include "App.g.cpp"
|
||||
#include "TerminalPage.h"
|
||||
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -16,9 +15,16 @@ using namespace winrt::Windows::System;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace ::TerminalApp;
|
||||
|
||||
// Note: Generate GUID using TlgGuid.exe tool
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hTerminalAppProvider,
|
||||
"Microsoft.Windows.Terminal.App",
|
||||
// {24a1622f-7da7-5c77-3303-d850bd1ab2ed}
|
||||
(0x24a1622f, 0x7da7, 0x5c77, 0x33, 0x03, 0xd8, 0x50, 0xbd, 0x1a, 0xb2, 0xed),
|
||||
TraceLoggingOptionMicrosoftTelemetry());
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
@@ -28,12 +34,17 @@ namespace winrt
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
App::App() :
|
||||
App(winrt::TerminalApp::XamlMetaDataProvider())
|
||||
{
|
||||
}
|
||||
|
||||
App::App(Windows::UI::Xaml::Markup::IXamlMetadataProvider const& parentProvider) :
|
||||
base_type(parentProvider),
|
||||
_settings{},
|
||||
_tabs{},
|
||||
_loadedInitialSettings{ false },
|
||||
_settingsLoadedResult{ S_OK },
|
||||
_dialogLock{},
|
||||
_resourceLoader{ L"TerminalApp/Resources" }
|
||||
_dialogLock{}
|
||||
{
|
||||
// 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,
|
||||
@@ -41,8 +52,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// cause you to chase down the rabbit hole of "why is App not
|
||||
// registered?" when it definitely is.
|
||||
|
||||
// Initialize will become protected or be deleted when GH#1339 (workaround for MSFT:22116519) are fixed.
|
||||
Initialize();
|
||||
// See GH#1339. This is a workaround for MSFT:22116519
|
||||
// We need this to prevent an occasional crash on teardown
|
||||
AddRef();
|
||||
m_inner.as<::IUnknown>()->Release();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -59,58 +72,110 @@ namespace winrt::TerminalApp::implementation
|
||||
// Assert that we've already loaded our settings. We have to do
|
||||
// this as a MTA, before the app is Create()'d
|
||||
WINRT_ASSERT(_loadedInitialSettings);
|
||||
TraceLoggingRegister(g_hTerminalAppProvider);
|
||||
_Create();
|
||||
}
|
||||
|
||||
/* !!! TODO
|
||||
This is not the correct way to host a XAML page. This exists today because we valued
|
||||
getting a .xaml over tearing out all of the terminal logic and splitting it across App
|
||||
and Page.
|
||||
The work to clarify the boundary between app global state and "terminal page" state
|
||||
is tracked in GH#1878.
|
||||
*/
|
||||
auto terminalPage = winrt::make_self<TerminalPage>();
|
||||
_root = terminalPage.as<winrt::Windows::UI::Xaml::Controls::Control>();
|
||||
_tabContent = terminalPage->TabContent();
|
||||
_tabRow = terminalPage->TabRow();
|
||||
_tabView = _tabRow.TabView();
|
||||
_newTabButton = _tabRow.NewTabButton();
|
||||
App::~App()
|
||||
{
|
||||
TraceLoggingUnregister(g_hTerminalAppProvider);
|
||||
}
|
||||
|
||||
if (_settings->GlobalSettings().GetShowTabsInTitlebar())
|
||||
{
|
||||
// Remove the TabView from the page. We'll hang on to it, we need to
|
||||
// put it in the titlebar.
|
||||
uint32_t index = 0;
|
||||
if (terminalPage->Root().Children().IndexOf(_tabRow, index))
|
||||
{
|
||||
terminalPage->Root().Children().RemoveAt(index);
|
||||
}
|
||||
// Method Description:
|
||||
// - Create all of the initial UI elements of the Terminal app.
|
||||
// * Creates the tab bar, initially hidden.
|
||||
// * Creates the tab content area, which is where we'll display the tabs/panes.
|
||||
// * Initializes the first terminal control, using the default profile,
|
||||
// and adds it to our list of tabs.
|
||||
void App::_Create()
|
||||
{
|
||||
_tabView = MUX::Controls::TabView{};
|
||||
|
||||
// Inform the host that our titlebar content has changed.
|
||||
_setTitleBarContentHandlers(*this, _tabRow);
|
||||
}
|
||||
|
||||
// Event Bindings (Early)
|
||||
_newTabButton.Click([this](auto&&, auto&&) {
|
||||
this->_OpenNewTab(std::nullopt);
|
||||
});
|
||||
_tabView.SelectionChanged({ this, &App::_OnTabSelectionChanged });
|
||||
_tabView.TabClosing({ this, &App::_OnTabClosing });
|
||||
_tabView.Items().VectorChanged({ this, &App::_OnTabItemsChanged });
|
||||
_root.Loaded({ this, &App::_OnLoaded });
|
||||
|
||||
_root = Controls::Grid{};
|
||||
|
||||
_tabRow = Controls::Grid{};
|
||||
_tabRow.Name(L"Tab Row");
|
||||
_tabContent = Controls::Grid{};
|
||||
_tabContent.Name(L"Tab Content");
|
||||
|
||||
// Set up two columns in the tabs row - one for the tabs themselves, and
|
||||
// another for the settings button.
|
||||
auto tabsColDef = Controls::ColumnDefinition();
|
||||
auto newTabBtnColDef = Controls::ColumnDefinition();
|
||||
|
||||
newTabBtnColDef.Width(GridLengthHelper::Auto());
|
||||
|
||||
_tabRow.ColumnDefinitions().Append(tabsColDef);
|
||||
_tabRow.ColumnDefinitions().Append(newTabBtnColDef);
|
||||
|
||||
// Set up two rows - one for the tabs, the other for the tab content,
|
||||
// the terminal panes.
|
||||
auto tabBarRowDef = Controls::RowDefinition();
|
||||
tabBarRowDef.Height(GridLengthHelper::Auto());
|
||||
_root.RowDefinitions().Append(tabBarRowDef);
|
||||
_root.RowDefinitions().Append(Controls::RowDefinition{});
|
||||
|
||||
if (_settings->GlobalSettings().GetShowTabsInTitlebar() == false)
|
||||
{
|
||||
_root.Children().Append(_tabRow);
|
||||
Controls::Grid::SetRow(_tabRow, 0);
|
||||
}
|
||||
_root.Children().Append(_tabContent);
|
||||
Controls::Grid::SetRow(_tabContent, 1);
|
||||
Controls::Grid::SetColumn(_tabView, 0);
|
||||
|
||||
// Create the new tab button.
|
||||
_newTabButton = Controls::SplitButton{};
|
||||
Controls::SymbolIcon newTabIco{};
|
||||
newTabIco.Symbol(Controls::Symbol::Add);
|
||||
_newTabButton.Content(newTabIco);
|
||||
Controls::Grid::SetRow(_newTabButton, 0);
|
||||
Controls::Grid::SetColumn(_newTabButton, 1);
|
||||
_newTabButton.VerticalAlignment(VerticalAlignment::Stretch);
|
||||
_newTabButton.HorizontalAlignment(HorizontalAlignment::Left);
|
||||
|
||||
// When the new tab button is clicked, open the default profile
|
||||
_newTabButton.Click([this](auto&&, auto&&) {
|
||||
this->_OpenNewTab(std::nullopt);
|
||||
});
|
||||
|
||||
// Populate the new tab button's flyout with entries for each profile
|
||||
_CreateNewTabFlyout();
|
||||
_OpenNewTab(std::nullopt);
|
||||
|
||||
_tabContent.SizeChanged({ this, &App::_OnContentSizeChanged });
|
||||
_tabRow.Children().Append(_tabView);
|
||||
_tabRow.Children().Append(_newTabButton);
|
||||
|
||||
_tabContent.VerticalAlignment(VerticalAlignment::Stretch);
|
||||
_tabContent.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
|
||||
// Here, we're doing the equivalent of defining the _tabRow as the
|
||||
// following: <Grid Background="{ThemeResource
|
||||
// ApplicationPageBackgroundThemeBrush}"> We need to set the Background
|
||||
// to that ThemeResource, so it'll be colored appropriately regardless
|
||||
// of what theme the user has selected.
|
||||
// We're looking up the Style we've defined in App.xaml, and applying it
|
||||
// here. A ResourceDictionary is a Map<IInspectable, IInspectable>, so
|
||||
// you'll need to try_as to get the type we actually want.
|
||||
auto res = Resources();
|
||||
IInspectable key = winrt::box_value(L"BackgroundGridThemeStyle");
|
||||
if (res.HasKey(key))
|
||||
{
|
||||
IInspectable g = res.Lookup(key);
|
||||
winrt::Windows::UI::Xaml::Style style = g.try_as<winrt::Windows::UI::Xaml::Style>();
|
||||
_root.Style(style);
|
||||
_tabRow.Style(style);
|
||||
}
|
||||
|
||||
// Apply the UI theme from our settings to our UI elements
|
||||
_ApplyTheme(_settings->GlobalSettings().GetRequestedTheme());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
TraceLoggingDescription("Event emitted when the application is started"),
|
||||
TraceLoggingBool(_settings->GlobalSettings().GetShowTabsInTitlebar(), "TabsInTitlebar"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
_OpenNewTab(std::nullopt);
|
||||
|
||||
_root.Loaded({ this, &App::_OnLoaded });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -141,15 +206,9 @@ namespace winrt::TerminalApp::implementation
|
||||
dialog.Content(contentElement);
|
||||
dialog.CloseButtonText(closeButtonText);
|
||||
|
||||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
|
||||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
|
||||
// xaml tree somehow.
|
||||
dialog.XamlRoot(_root.XamlRoot());
|
||||
|
||||
// IMPORTANT: Set the requested theme of the dialog, because the
|
||||
// PopupRoot isn't directly in the Xaml tree of our root. So the dialog
|
||||
// won't inherit our RequestedTheme automagically.
|
||||
dialog.RequestedTheme(_settings->GlobalSettings().GetRequestedTheme());
|
||||
// IMPORTANT: Add the dialog to the _root UIElement before you show it,
|
||||
// so it knows how to attach to the XAML content.
|
||||
_root.Children().Append(dialog);
|
||||
|
||||
// Display the dialog.
|
||||
Controls::ContentDialogResult result = co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
|
||||
@@ -169,77 +228,42 @@ namespace winrt::TerminalApp::implementation
|
||||
void App::_ShowOkDialog(const winrt::hstring& titleKey,
|
||||
const winrt::hstring& contentKey)
|
||||
{
|
||||
auto title = _resourceLoader.GetLocalizedString(titleKey);
|
||||
auto message = _resourceLoader.GetLocalizedString(contentKey);
|
||||
auto buttonText = _resourceLoader.GetLocalizedString(L"Ok");
|
||||
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
|
||||
auto title = resourceLoader.GetString(titleKey);
|
||||
auto message = resourceLoader.GetString(contentKey);
|
||||
auto buttonText = resourceLoader.GetString(L"Ok");
|
||||
|
||||
_ShowDialog(winrt::box_value(title), winrt::box_value(message), buttonText);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Show a dialog with "About" information. Displays the app's Display
|
||||
// Name, version, getting started link, documentation link, and release
|
||||
// Notes link.
|
||||
// Name, and the version.
|
||||
void App::_ShowAboutDialog()
|
||||
{
|
||||
const auto title = _resourceLoader.GetLocalizedString(L"AboutTitleText");
|
||||
const auto versionLabel = _resourceLoader.GetLocalizedString(L"VersionLabelText");
|
||||
const auto gettingStartedLabel = _resourceLoader.GetLocalizedString(L"GettingStartedLabelText");
|
||||
const auto documentationLabel = _resourceLoader.GetLocalizedString(L"DocumentationLabelText");
|
||||
const auto releaseNotesLabel = _resourceLoader.GetLocalizedString(L"ReleaseNotesLabelText");
|
||||
const auto gettingStartedUriValue = _resourceLoader.GetLocalizedString(L"GettingStartedUriValue");
|
||||
const auto documentationUriValue = _resourceLoader.GetLocalizedString(L"DocumentationUriValue");
|
||||
const auto releaseNotesUriValue = _resourceLoader.GetLocalizedString(L"ReleaseNotesUriValue");
|
||||
auto resourceLoader = Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView();
|
||||
const auto title = resourceLoader.GetString(L"AboutTitleText");
|
||||
const auto versionLabel = resourceLoader.GetString(L"VersionLabelText");
|
||||
const auto package = winrt::Windows::ApplicationModel::Package::Current();
|
||||
const auto packageName = package.DisplayName();
|
||||
const auto version = package.Id().Version();
|
||||
winrt::Windows::UI::Xaml::Documents::Run about;
|
||||
winrt::Windows::UI::Xaml::Documents::Run gettingStarted;
|
||||
winrt::Windows::UI::Xaml::Documents::Run documentation;
|
||||
winrt::Windows::UI::Xaml::Documents::Run releaseNotes;
|
||||
winrt::Windows::UI::Xaml::Documents::Hyperlink gettingStartedLink;
|
||||
winrt::Windows::UI::Xaml::Documents::Hyperlink documentationLink;
|
||||
winrt::Windows::UI::Xaml::Documents::Hyperlink releaseNotesLink;
|
||||
std::wstringstream aboutTextStream;
|
||||
|
||||
gettingStarted.Text(gettingStartedLabel);
|
||||
documentation.Text(documentationLabel);
|
||||
releaseNotes.Text(releaseNotesLabel);
|
||||
|
||||
winrt::Windows::Foundation::Uri gettingStartedUri{ gettingStartedUriValue };
|
||||
winrt::Windows::Foundation::Uri documentationUri{ documentationUriValue };
|
||||
winrt::Windows::Foundation::Uri releaseNotesUri{ releaseNotesUriValue };
|
||||
|
||||
gettingStartedLink.NavigateUri(gettingStartedUri);
|
||||
documentationLink.NavigateUri(documentationUri);
|
||||
releaseNotesLink.NavigateUri(releaseNotesUri);
|
||||
|
||||
gettingStartedLink.Inlines().Append(gettingStarted);
|
||||
documentationLink.Inlines().Append(documentation);
|
||||
releaseNotesLink.Inlines().Append(releaseNotes);
|
||||
|
||||
// Format our about text. It will look like the following:
|
||||
// <Display Name>
|
||||
// Version: <Major>.<Minor>.<Build>.<Revision>
|
||||
// Getting Started
|
||||
// Documentation
|
||||
// Release Notes
|
||||
|
||||
aboutTextStream << packageName.c_str() << L"\n";
|
||||
|
||||
aboutTextStream << versionLabel.c_str() << L" ";
|
||||
aboutTextStream << version.Major << L"." << version.Minor << L"." << version.Build << L"." << version.Revision << L"\n";
|
||||
aboutTextStream << version.Major << L"." << version.Minor << L"." << version.Build << L"." << version.Revision;
|
||||
|
||||
winrt::hstring aboutText{ aboutTextStream.str() };
|
||||
about.Text(aboutText);
|
||||
|
||||
const auto buttonText = _resourceLoader.GetLocalizedString(L"Ok");
|
||||
const auto buttonText = resourceLoader.GetString(L"Ok");
|
||||
|
||||
Controls::TextBlock aboutTextBlock;
|
||||
aboutTextBlock.Inlines().Append(about);
|
||||
aboutTextBlock.Inlines().Append(gettingStartedLink);
|
||||
aboutTextBlock.Inlines().Append(documentationLink);
|
||||
aboutTextBlock.Inlines().Append(releaseNotesLink);
|
||||
aboutTextBlock.Text(aboutText);
|
||||
aboutTextBlock.IsTextSelectionEnabled(true);
|
||||
|
||||
_ShowDialog(winrt::box_value(title), aboutTextBlock, buttonText);
|
||||
@@ -362,7 +386,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Create the settings button.
|
||||
auto settingsItem = Controls::MenuFlyoutItem{};
|
||||
settingsItem.Text(_resourceLoader.GetLocalizedString(L"SettingsMenuItem"));
|
||||
settingsItem.Text(L"Settings");
|
||||
|
||||
Controls::SymbolIcon ico{};
|
||||
ico.Symbol(Controls::Symbol::Setting);
|
||||
@@ -379,7 +403,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Create the feedback button.
|
||||
auto feedbackFlyout = Controls::MenuFlyoutItem{};
|
||||
feedbackFlyout.Text(_resourceLoader.GetLocalizedString(L"FeedbackMenuItem"));
|
||||
feedbackFlyout.Text(L"Feedback");
|
||||
|
||||
Controls::FontIcon feedbackIco{};
|
||||
feedbackIco.Glyph(L"\xE939");
|
||||
@@ -391,7 +415,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Create the about button.
|
||||
auto aboutFlyout = Controls::MenuFlyoutItem{};
|
||||
aboutFlyout.Text(_resourceLoader.GetLocalizedString(L"AboutMenuItem"));
|
||||
aboutFlyout.Text(L"About");
|
||||
|
||||
Controls::SymbolIcon aboutIco{};
|
||||
aboutIco.Symbol(Controls::Symbol::Help);
|
||||
@@ -417,12 +441,7 @@ namespace winrt::TerminalApp::implementation
|
||||
co_await winrt::resume_background();
|
||||
|
||||
const auto settingsPath = CascadiaSettings::GetSettingsPath();
|
||||
|
||||
HINSTANCE res = ShellExecute(nullptr, nullptr, settingsPath.c_str(), nullptr, nullptr, SW_SHOW);
|
||||
if (static_cast<int>(reinterpret_cast<uintptr_t>(res)) <= 32)
|
||||
{
|
||||
ShellExecute(nullptr, nullptr, L"notepad", settingsPath.c_str(), nullptr, SW_SHOW);
|
||||
}
|
||||
ShellExecute(nullptr, L"open", settingsPath.c_str(), nullptr, nullptr, SW_SHOW);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -444,9 +463,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void App::_FeedbackButtonOnClick(const IInspectable&,
|
||||
const RoutedEventArgs&)
|
||||
{
|
||||
const auto feedbackUriValue = _resourceLoader.GetLocalizedString(L"FeedbackUriValue");
|
||||
|
||||
winrt::Windows::System::Launcher::LaunchUriAsync({ feedbackUriValue });
|
||||
winrt::Windows::System::Launcher::LaunchUriAsync({ L"https://github.com/microsoft/Terminal/issues" });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -474,9 +491,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// They should all be hooked up here, regardless of whether or not
|
||||
// there's an actual keychord for them.
|
||||
bindings.NewTab([this]() { _OpenNewTab(std::nullopt); });
|
||||
bindings.DuplicateTab([this]() { _DuplicateTabViewItem(); });
|
||||
bindings.CloseTab([this]() { _CloseFocusedTab(); });
|
||||
bindings.ClosePane([this]() { _CloseFocusedPane(); });
|
||||
bindings.NewTabWithProfile([this](const auto index) { _OpenNewTab({ index }); });
|
||||
bindings.ScrollUp([this]() { _Scroll(-1); });
|
||||
bindings.ScrollDown([this]() { _Scroll(1); });
|
||||
@@ -488,10 +503,6 @@ namespace winrt::TerminalApp::implementation
|
||||
bindings.ScrollDownPage([this]() { _ScrollPage(1); });
|
||||
bindings.SwitchToTab([this](const auto index) { _SelectTab({ index }); });
|
||||
bindings.OpenSettings([this]() { _OpenSettings(); });
|
||||
bindings.ResizePane([this](const auto direction) { _ResizePane(direction); });
|
||||
bindings.MoveFocus([this](const auto direction) { _MoveFocus(direction); });
|
||||
bindings.CopyText([this](const auto trimWhitespace) { _CopyText(trimWhitespace); });
|
||||
bindings.PasteText([this]() { _PasteText(); });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -661,7 +672,6 @@ namespace winrt::TerminalApp::implementation
|
||||
for (auto& tab : _tabs)
|
||||
{
|
||||
_UpdateTabIcon(tab);
|
||||
_UpdateTitle(tab);
|
||||
}
|
||||
|
||||
_root.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [this]() {
|
||||
@@ -707,38 +717,26 @@ namespace winrt::TerminalApp::implementation
|
||||
void App::_UpdateTitle(std::shared_ptr<Tab> tab)
|
||||
{
|
||||
auto newTabTitle = tab->GetFocusedTitle();
|
||||
const auto lastFocusedProfileOpt = tab->GetFocusedProfile();
|
||||
if (lastFocusedProfileOpt.has_value())
|
||||
|
||||
// TODO #608: If the settings don't want the terminal's text in the
|
||||
// tab, then display something else.
|
||||
tab->SetTabText(newTabTitle);
|
||||
if (_settings->GlobalSettings().GetShowTitleInTitlebar() &&
|
||||
tab->IsFocused())
|
||||
{
|
||||
const auto lastFocusedProfile = lastFocusedProfileOpt.value();
|
||||
const auto* const matchingProfile = _settings->FindProfile(lastFocusedProfile);
|
||||
|
||||
const auto tabTitle = matchingProfile->GetTabTitle();
|
||||
|
||||
// Checks if tab title has been set in the profile settings and
|
||||
// updates accordingly.
|
||||
|
||||
const auto newActualTitle = tabTitle.empty() ? newTabTitle : tabTitle;
|
||||
|
||||
tab->SetTabText(winrt::to_hstring(newActualTitle.data()));
|
||||
if (_settings->GlobalSettings().GetShowTitleInTitlebar() &&
|
||||
tab->IsFocused())
|
||||
{
|
||||
_titleChangeHandlers(newActualTitle);
|
||||
}
|
||||
_titleChangeHandlers(newTabTitle);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update the current theme of the application. This will trigger our
|
||||
// RequestedThemeChanged event, to have our host change the theme of the
|
||||
// root of the application.
|
||||
// - Update the current theme of the application. This will manually update
|
||||
// all of the elements in our UI to match the given theme.
|
||||
// Arguments:
|
||||
// - newTheme: The ElementTheme to apply to our elements.
|
||||
void App::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
|
||||
{
|
||||
// Propagate the event to the host layer, so it can update its own UI
|
||||
_requestedThemeChangedHandlers(*this, newTheme);
|
||||
_root.RequestedTheme(newTheme);
|
||||
_tabRow.RequestedTheme(newTheme);
|
||||
}
|
||||
|
||||
UIElement App::GetRoot() noexcept
|
||||
@@ -746,6 +744,11 @@ namespace winrt::TerminalApp::implementation
|
||||
return _root;
|
||||
}
|
||||
|
||||
UIElement App::GetTabs() noexcept
|
||||
{
|
||||
return _tabRow;
|
||||
}
|
||||
|
||||
void App::_SetFocusedTabIndex(int tabIndex)
|
||||
{
|
||||
// GH#1117: This is a workaround because _tabView.SelectedIndex(tabIndex)
|
||||
@@ -818,8 +821,6 @@ namespace winrt::TerminalApp::implementation
|
||||
"TabInformation",
|
||||
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
|
||||
TraceLoggingInt32(tabCount, "TabCount", "Count of tabs curently opened in TerminalApp"),
|
||||
TraceLoggingBool(profileIndex.has_value(), "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
|
||||
TraceLoggingGuid(profileGuid, "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
@@ -881,7 +882,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_UpdateTitle(tab);
|
||||
});
|
||||
|
||||
term.GotFocus([this, weakTabPtr](auto&&, auto&&) {
|
||||
term.GetControl().GotFocus([this, weakTabPtr](auto&&, auto&&) {
|
||||
auto tab = weakTabPtr.lock();
|
||||
if (!tab)
|
||||
{
|
||||
@@ -907,23 +908,19 @@ namespace winrt::TerminalApp::implementation
|
||||
void App::_CreateNewTabFromSettings(GUID profileGuid, TerminalSettings settings)
|
||||
{
|
||||
// Initialize the new tab
|
||||
|
||||
// Create a connection based on the values in our settings object.
|
||||
const auto connection = _CreateConnectionFromSettings(profileGuid, settings);
|
||||
|
||||
TermControl term{ settings, connection };
|
||||
TermControl term{ settings };
|
||||
|
||||
// Add the new tab to the list of our tabs.
|
||||
auto newTab = _tabs.emplace_back(std::make_shared<Tab>(profileGuid, term));
|
||||
|
||||
const auto* const profile = _settings->FindProfile(profileGuid);
|
||||
|
||||
// Hookup our event handlers to the new terminal
|
||||
_RegisterTerminalEvents(term, newTab);
|
||||
|
||||
auto tabViewItem = newTab->GetTabViewItem();
|
||||
_tabView.Items().Append(tabViewItem);
|
||||
|
||||
const auto* const profile = _settings->FindProfile(profileGuid);
|
||||
|
||||
// Set this profile's tab to the icon the user specified
|
||||
if (profile != nullptr && profile->HasIcon())
|
||||
{
|
||||
@@ -978,17 +975,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_RemoveTabViewItem(focusedTab->GetTabViewItem());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Close the currently focused pane. If the pane is the last pane in the
|
||||
// tab, the tab will also be closed. This will happen when we handle the
|
||||
// tab's Closed event.
|
||||
void App::_CloseFocusedPane()
|
||||
{
|
||||
int focusedTabIndex = _GetFocusedTabIndex();
|
||||
std::shared_ptr<Tab> focusedTab{ _tabs[focusedTabIndex] };
|
||||
focusedTab->ClosePane();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Move the viewport of the terminal of the currently focused tab up or
|
||||
// down a number of lines. Negative values of `delta` will move the
|
||||
@@ -1018,34 +1004,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_tabs[focusedTabIndex]->Scroll(termHeight * delta);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move a separator between panes, as to resize each child on
|
||||
// either size of the separator. See Pane::ResizePane for details.
|
||||
// - Moves a separator on the currently focused tab.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the separator in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void App::_ResizePane(const Direction& direction)
|
||||
{
|
||||
const auto focusedTabIndex = _GetFocusedTabIndex();
|
||||
_tabs[focusedTabIndex]->ResizePane(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move focus between panes, as to focus the child on
|
||||
// the other side of the separator. See Pane::NavigateFocus for details.
|
||||
// - Moves the focus of the currently focused tab.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void App::_MoveFocus(const Direction& direction)
|
||||
{
|
||||
const auto focusedTabIndex = _GetFocusedTabIndex();
|
||||
_tabs[focusedTabIndex]->NavigateFocus(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Copy text from the focused terminal to the Windows Clipboard
|
||||
// Arguments:
|
||||
@@ -1057,14 +1015,6 @@ namespace winrt::TerminalApp::implementation
|
||||
control.CopySelectionToClipboard(trimTrailingWhitespace);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Paste text from the Windows Clipboard to the focused terminal
|
||||
void App::_PasteText()
|
||||
{
|
||||
const auto control = _GetFocusedControl();
|
||||
control.PasteTextFromClipboard();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets focus to the tab to the right or left the currently selected tab.
|
||||
void App::_SelectNextTab(const bool bMoveRight)
|
||||
@@ -1190,19 +1140,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Duplicates the current focused tab
|
||||
void App::_DuplicateTabViewItem()
|
||||
{
|
||||
const int& focusedTabIndex = _GetFocusedTabIndex();
|
||||
const auto& _tab = _tabs.at(focusedTabIndex);
|
||||
|
||||
const auto& profileGuid = _tab->GetFocusedProfile();
|
||||
const auto& settings = _settings->MakeSettings(profileGuid);
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Removes the tab (both TerminalControl and XAML)
|
||||
// Arguments:
|
||||
@@ -1226,7 +1163,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (focusedTabIndex >= _tabs.size())
|
||||
{
|
||||
focusedTabIndex = static_cast<int>(_tabs.size()) - 1;
|
||||
focusedTabIndex = _tabs.size() - 1;
|
||||
}
|
||||
|
||||
if (focusedTabIndex < 0)
|
||||
@@ -1251,9 +1188,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (profile.HasIcon())
|
||||
{
|
||||
std::wstring path{ profile.GetIconPath() };
|
||||
const auto envExpandedPath{ wil::ExpandEnvironmentStringsW<std::wstring>(path.data()) };
|
||||
winrt::hstring iconPath{ envExpandedPath };
|
||||
auto path = profile.GetIconPath();
|
||||
winrt::hstring iconPath{ path };
|
||||
winrt::Windows::Foundation::Uri iconUri{ iconPath };
|
||||
Controls::BitmapIconSource iconSource;
|
||||
// Make sure to set this to false, so we keep the RGB data of the
|
||||
@@ -1320,10 +1256,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto realGuid = profileGuid ? profileGuid.value() :
|
||||
_settings->GlobalSettings().GetDefaultProfile();
|
||||
const auto controlSettings = _settings->MakeSettings(realGuid);
|
||||
|
||||
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings);
|
||||
|
||||
TermControl newControl{ controlSettings, controlConnection };
|
||||
TermControl newControl{ controlSettings };
|
||||
|
||||
const int focusedTabIndex = _GetFocusedTabIndex();
|
||||
auto focusedTab = _tabs[focusedTabIndex];
|
||||
@@ -1335,23 +1268,6 @@ namespace winrt::TerminalApp::implementation
|
||||
focusedTab->AddVerticalSplit(realGuid, newControl);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our tab content size changes. This updates each tab with
|
||||
// the new size, so they have a chance to update each of their panes with
|
||||
// the new size.
|
||||
// Arguments:
|
||||
// - e: the SizeChangedEventArgs with the new size of the tab content area.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void App::_OnContentSizeChanged(const IInspectable& /*sender*/, Windows::UI::Xaml::SizeChangedEventArgs const& e)
|
||||
{
|
||||
const auto newSize = e.NewSize();
|
||||
for (auto& tab : _tabs)
|
||||
{
|
||||
tab->ResizeContent(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Place `copiedData` into the clipboard as text. Triggered when a
|
||||
// terminal control raises it's CopyToClipboard event.
|
||||
@@ -1384,33 +1300,6 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handles the special case of providing a text override for the UI shortcut due to VK_OEM issue.
|
||||
// Looks at the flags from the KeyChord modifiers and provides a concatenated string value of all
|
||||
// in the same order that XAML would put them as well.
|
||||
// Return Value:
|
||||
// - a string representation of the key modifiers for the shortcut
|
||||
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
|
||||
static std::wstring _FormatOverrideShortcutText(Settings::KeyModifiers modifiers)
|
||||
{
|
||||
std::wstring buffer{ L"" };
|
||||
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Ctrl))
|
||||
{
|
||||
buffer += L"Ctrl+";
|
||||
}
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Shift))
|
||||
{
|
||||
buffer += L"Shift+";
|
||||
}
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Alt))
|
||||
{
|
||||
buffer += L"Alt+";
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Takes a MenuFlyoutItem and a corresponding KeyChord value and creates the accelerator for UI display.
|
||||
// Takes into account a special case for an error condition for a comma
|
||||
@@ -1418,7 +1307,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// - MenuFlyoutItem that will be displayed, and a KeyChord to map an accelerator
|
||||
void App::_SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Settings::KeyChord& keyChord)
|
||||
{
|
||||
#ifdef DEP_MICROSOFT_UI_XAML_708_FIXED
|
||||
// work around https://github.com/microsoft/microsoft-ui-xaml/issues/708 in case of VK_OEM_COMMA
|
||||
if (keyChord.Vkey() != VK_OEM_COMMA)
|
||||
{
|
||||
@@ -1438,63 +1326,16 @@ namespace winrt::TerminalApp::implementation
|
||||
menuItem.KeyboardAccelerators().Append(menuShortcut);
|
||||
}
|
||||
else // we've got a comma, so need to just use the alternate method
|
||||
#endif
|
||||
{
|
||||
// extract the modifier and key to a nice format
|
||||
auto overrideString = _FormatOverrideShortcutText(keyChord.Modifiers());
|
||||
auto mappedCh = MapVirtualKeyW(keyChord.Vkey(), MAPVK_VK_TO_CHAR);
|
||||
if (mappedCh != 0)
|
||||
{
|
||||
menuItem.KeyboardAcceleratorTextOverride(overrideString + gsl::narrow_cast<wchar_t>(mappedCh));
|
||||
}
|
||||
auto overrideString = AppKeyBindings::FormatOverrideShortcutText(keyChord.Modifiers());
|
||||
menuItem.KeyboardAcceleratorTextOverride(overrideString + L" ,");
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a new connection based on the profile settings
|
||||
// Arguments:
|
||||
// - the profile GUID we want the settings from
|
||||
// - the terminal settings
|
||||
// Return value:
|
||||
// - the desired connection
|
||||
TerminalConnection::ITerminalConnection App::_CreateConnectionFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings)
|
||||
{
|
||||
const auto* const profile = _settings->FindProfile(profileGuid);
|
||||
TerminalConnection::ITerminalConnection connection{ nullptr };
|
||||
// The Azure connection has a boost dependency, and boost does not support ARM64
|
||||
// so we make sure that we do not try to compile the Azure connection code if we are in ARM64 (we would get build errors otherwise)
|
||||
GUID connectionType{ 0 };
|
||||
if (profile->HasConnectionType())
|
||||
{
|
||||
connectionType = profile->GetConnectionType();
|
||||
}
|
||||
#ifndef _M_ARM64
|
||||
if (connectionType == AzureConnectionType)
|
||||
{
|
||||
connection = TerminalConnection::AzureConnection(settings.InitialRows(), settings.InitialCols());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
connection = TerminalConnection::ConhostConnection(settings.Commandline(), settings.StartingDirectory(), settings.InitialRows(), settings.InitialCols(), winrt::guid());
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"ConnectionCreated",
|
||||
TraceLoggingDescription("Event emitted upon the creation of a connection"),
|
||||
TraceLoggingGuid(connectionType, "ConnectionTypeGuid", "The type of the connection"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// Winrt events need a method for adding a callback to the event and removing the callback.
|
||||
// These macros will define them both for you.
|
||||
DEFINE_EVENT(App, TitleChanged, _titleChangeHandlers, TerminalControl::TitleChangedEventArgs);
|
||||
DEFINE_EVENT(App, LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(App, RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
#include "Tab.h"
|
||||
#include "CascadiaSettings.h"
|
||||
#include "App.g.h"
|
||||
#include "App.base.h"
|
||||
#include "ScopedResourceLoader.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
#include <winrt/Microsoft.Terminal.TerminalControl.h>
|
||||
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
|
||||
@@ -21,39 +18,43 @@
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct App : AppT2<App>
|
||||
// We dont use AppT as it does not provide access to protected constructors
|
||||
template<typename D, typename... I>
|
||||
using AppT_Override = App_base<D, I...>;
|
||||
|
||||
struct App : AppT_Override<App>
|
||||
{
|
||||
public:
|
||||
App();
|
||||
|
||||
Windows::UI::Xaml::UIElement GetRoot() noexcept;
|
||||
|
||||
Windows::UI::Xaml::UIElement GetTabs() noexcept;
|
||||
void Create();
|
||||
void LoadSettings();
|
||||
|
||||
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
|
||||
bool GetShowTabsInTitlebar();
|
||||
|
||||
~App() = default;
|
||||
~App();
|
||||
|
||||
hstring GetTitle();
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
DECLARE_EVENT(TitleChanged, _titleChangeHandlers, winrt::Microsoft::Terminal::TerminalControl::TitleChangedEventArgs);
|
||||
DECLARE_EVENT(LastTabClosed, _lastTabClosedHandlers, winrt::TerminalApp::LastTabClosedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTitleBarContent, _setTitleBarContentHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::UIElement);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
|
||||
|
||||
private:
|
||||
App(Windows::UI::Xaml::Markup::IXamlMetadataProvider const& parentProvider);
|
||||
|
||||
// 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 app.
|
||||
// ALSO: If you add any UIElements as roots here, make sure they're
|
||||
// updated in _ApplyTheme. The two roots currently are _root and _tabRow
|
||||
// (which is a root when the tabs are in the titlebar.)
|
||||
Windows::UI::Xaml::Controls::Control _root{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _root{ nullptr };
|
||||
Microsoft::UI::Xaml::Controls::TabView _tabView{ nullptr };
|
||||
TerminalApp::TabRowControl _tabRow{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabRow{ nullptr };
|
||||
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
|
||||
Windows::UI::Xaml::Controls::SplitButton _newTabButton{ nullptr };
|
||||
|
||||
@@ -66,12 +67,11 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _loadedInitialSettings;
|
||||
std::shared_mutex _dialogLock;
|
||||
|
||||
ScopedResourceLoader _resourceLoader;
|
||||
|
||||
wil::unique_folder_change_reader_nothrow _reader;
|
||||
|
||||
std::atomic<bool> _settingsReloadQueued{ false };
|
||||
|
||||
void _Create();
|
||||
void _CreateNewTabFlyout();
|
||||
|
||||
fire_and_forget _ShowDialog(const winrt::Windows::Foundation::IInspectable& titleElement,
|
||||
@@ -101,12 +101,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
||||
|
||||
void _CreateNewTabFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings);
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(GUID profileGuid, winrt::Microsoft::Terminal::Settings::TerminalSettings settings);
|
||||
|
||||
void _OpenNewTab(std::optional<int> profileIndex);
|
||||
void _DuplicateTabViewItem();
|
||||
void _CloseFocusedTab();
|
||||
void _CloseFocusedPane();
|
||||
void _SelectNextTab(const bool bMoveRight);
|
||||
void _SelectTab(const int tabIndex);
|
||||
|
||||
@@ -115,23 +112,18 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _Scroll(int delta);
|
||||
void _CopyText(const bool trimTrailingWhitespace);
|
||||
void _PasteText();
|
||||
void _SplitVertical(const std::optional<GUID>& profileGuid);
|
||||
void _SplitHorizontal(const std::optional<GUID>& profileGuid);
|
||||
void _SplitPane(const Pane::SplitState splitType, const std::optional<GUID>& profileGuid);
|
||||
|
||||
// Todo: add more event implementations here
|
||||
// MSFT:20641986: Add keybindings for New Window
|
||||
void _ScrollPage(int delta);
|
||||
void _ResizePane(const Direction& direction);
|
||||
void _MoveFocus(const Direction& direction);
|
||||
|
||||
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs);
|
||||
void _OnTabClosing(const IInspectable& sender, const Microsoft::UI::Xaml::Controls::TabViewTabClosingEventArgs& eventArgs);
|
||||
void _OnTabItemsChanged(const IInspectable& sender, const Windows::Foundation::Collections::IVectorChangedEventArgs& eventArgs);
|
||||
void _OnTabClick(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
void _OnContentSizeChanged(const IInspectable& sender, Windows::UI::Xaml::SizeChangedEventArgs const& e);
|
||||
|
||||
void _RemoveTabViewItem(const IInspectable& tabViewItem);
|
||||
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
namespace TerminalApp
|
||||
{
|
||||
delegate void LastTabClosedEventArgs();
|
||||
[default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
|
||||
[default_interface]
|
||||
runtimeclass App : Microsoft.UI.Xaml.Markup.XamlApplication
|
||||
{
|
||||
App();
|
||||
|
||||
void Initialize();
|
||||
|
||||
// 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
|
||||
@@ -20,15 +19,20 @@ namespace TerminalApp
|
||||
void LoadSettings();
|
||||
|
||||
Windows.UI.Xaml.UIElement GetRoot();
|
||||
Windows.UI.Xaml.UIElement GetTabs();
|
||||
|
||||
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean GetShowTabsInTitlebar();
|
||||
|
||||
event Microsoft.Terminal.TerminalControl.TitleChangedEventArgs TitleChanged;
|
||||
event LastTabClosedEventArgs LastTabClosed;
|
||||
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.UIElement> SetTitleBarContent;
|
||||
event Windows.Foundation.TypedEventHandler<App, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
|
||||
|
||||
String GetTitle();
|
||||
|
||||
// IXamlMetadataProvider, Xaml.Application:
|
||||
// Application's composing initializer will register the composing class
|
||||
// as the toplevel "active" Xaml application. This Application (through IXamlMetadataProvider)
|
||||
// will be queried for all unknown types during all Xaml and XBF (Xaml Binary Format) parse
|
||||
// operations.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Toolkit:XamlApplication
|
||||
<MSMarkup:XamlApplication
|
||||
x:Class="TerminalApp.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:Toolkit="using:Microsoft.Toolkit.Win32.UI.XamlHost"
|
||||
xmlns:MSMarkup="using:Microsoft.UI.Xaml.Markup"
|
||||
xmlns:TA="using:TerminalApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<!-- If you want to prove this works, then add `RequestedTheme="Light"` to
|
||||
the properties on the XamlApplication -->
|
||||
<Toolkit:XamlApplication.Resources>
|
||||
<MSMarkup:XamlApplication.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
@@ -60,5 +60,5 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
</ResourceDictionary>
|
||||
|
||||
|
||||
</Toolkit:XamlApplication.Resources>
|
||||
</Toolkit:XamlApplication>
|
||||
</MSMarkup:XamlApplication.Resources>
|
||||
</MSMarkup:XamlApplication>
|
||||
|
||||
@@ -47,10 +47,7 @@ namespace winrt::TerminalApp::implementation
|
||||
switch (action)
|
||||
{
|
||||
case ShortcutAction::CopyText:
|
||||
_CopyTextHandlers(true);
|
||||
return true;
|
||||
case ShortcutAction::CopyTextWithoutNewlines:
|
||||
_CopyTextHandlers(false);
|
||||
_CopyTextHandlers();
|
||||
return true;
|
||||
case ShortcutAction::PasteText:
|
||||
_PasteTextHandlers();
|
||||
@@ -58,9 +55,6 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::NewTab:
|
||||
_NewTabHandlers();
|
||||
return true;
|
||||
case ShortcutAction::DuplicateTab:
|
||||
_DuplicateTabHandlers();
|
||||
return true;
|
||||
case ShortcutAction::OpenSettings:
|
||||
_OpenSettingsHandlers();
|
||||
return true;
|
||||
@@ -102,9 +96,6 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::CloseTab:
|
||||
_CloseTabHandlers();
|
||||
return true;
|
||||
case ShortcutAction::ClosePane:
|
||||
_ClosePaneHandlers();
|
||||
return true;
|
||||
|
||||
case ShortcutAction::ScrollUp:
|
||||
_ScrollUpHandlers();
|
||||
@@ -160,30 +151,7 @@ namespace winrt::TerminalApp::implementation
|
||||
case ShortcutAction::SwitchToTab8:
|
||||
_SwitchToTabHandlers(8);
|
||||
return true;
|
||||
case ShortcutAction::ResizePaneLeft:
|
||||
_ResizePaneHandlers(Direction::Left);
|
||||
return true;
|
||||
case ShortcutAction::ResizePaneRight:
|
||||
_ResizePaneHandlers(Direction::Right);
|
||||
return true;
|
||||
case ShortcutAction::ResizePaneUp:
|
||||
_ResizePaneHandlers(Direction::Up);
|
||||
return true;
|
||||
case ShortcutAction::ResizePaneDown:
|
||||
_ResizePaneHandlers(Direction::Down);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusLeft:
|
||||
_MoveFocusHandlers(Direction::Left);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusRight:
|
||||
_MoveFocusHandlers(Direction::Right);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusUp:
|
||||
_MoveFocusHandlers(Direction::Up);
|
||||
return true;
|
||||
case ShortcutAction::MoveFocusDown:
|
||||
_MoveFocusHandlers(Direction::Down);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -215,21 +183,46 @@ namespace winrt::TerminalApp::implementation
|
||||
return keyModifiers;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handles the special case of providing a text override for the UI shortcut due to VK_OEM_COMMA issue.
|
||||
// Looks at the flags from the KeyChord modifiers and provides a concatenated string value of all
|
||||
// in the same order that XAML would put them as well.
|
||||
// Return Value:
|
||||
// - a WinRT hstring representation of the key modifiers for the shortcut
|
||||
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
|
||||
winrt::hstring AppKeyBindings::FormatOverrideShortcutText(Settings::KeyModifiers modifiers)
|
||||
{
|
||||
std::wstring buffer{ L"" };
|
||||
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Ctrl))
|
||||
{
|
||||
buffer += L"Ctrl+";
|
||||
}
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Shift))
|
||||
{
|
||||
buffer += L"Shift+";
|
||||
}
|
||||
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Alt))
|
||||
{
|
||||
buffer += L"Alt+";
|
||||
}
|
||||
|
||||
return winrt::hstring{ buffer };
|
||||
}
|
||||
|
||||
// -------------------------------- Events ---------------------------------
|
||||
// clang-format off
|
||||
DEFINE_EVENT(AppKeyBindings, CopyText, _CopyTextHandlers, TerminalApp::CopyTextEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, PasteText, _PasteTextHandlers, TerminalApp::PasteTextEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, NewTab, _NewTabHandlers, TerminalApp::NewTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, DuplicateTab, _DuplicateTabHandlers, TerminalApp::DuplicateTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, NewTabWithProfile, _NewTabWithProfileHandlers, TerminalApp::NewTabWithProfileEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, NewWindow, _NewWindowHandlers, TerminalApp::NewWindowEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, CloseWindow, _CloseWindowHandlers, TerminalApp::CloseWindowEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, CloseTab, _CloseTabHandlers, TerminalApp::CloseTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, ClosePane, _ClosePaneHandlers, TerminalApp::ClosePaneEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, SwitchToTab, _SwitchToTabHandlers, TerminalApp::SwitchToTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, NextTab, _NextTabHandlers, TerminalApp::NextTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, PrevTab, _PrevTabHandlers, TerminalApp::PrevTabEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, SplitVertical, _SplitVerticalHandlers, TerminalApp::SplitVerticalEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, SplitVertical, _SplitVerticalHandlers, TerminalApp::SplitVerticalEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, SplitHorizontal, _SplitHorizontalHandlers, TerminalApp::SplitHorizontalEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, IncreaseFontSize, _IncreaseFontSizeHandlers, TerminalApp::IncreaseFontSizeEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, DecreaseFontSize, _DecreaseFontSizeHandlers, TerminalApp::DecreaseFontSizeEventArgs);
|
||||
@@ -238,7 +231,5 @@ namespace winrt::TerminalApp::implementation
|
||||
DEFINE_EVENT(AppKeyBindings, ScrollUpPage, _ScrollUpPageHandlers, TerminalApp::ScrollUpPageEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
|
||||
DEFINE_EVENT(AppKeyBindings, MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -37,17 +37,16 @@ namespace winrt::TerminalApp::implementation
|
||||
Microsoft::Terminal::Settings::KeyChord GetKeyBinding(TerminalApp::ShortcutAction const& action);
|
||||
|
||||
static Windows::System::VirtualKeyModifiers ConvertVKModifiers(winrt::Microsoft::Terminal::Settings::KeyModifiers modifiers);
|
||||
static winrt::hstring FormatOverrideShortcutText(winrt::Microsoft::Terminal::Settings::KeyModifiers modifiers);
|
||||
|
||||
// clang-format off
|
||||
DECLARE_EVENT(CopyText, _CopyTextHandlers, TerminalApp::CopyTextEventArgs);
|
||||
DECLARE_EVENT(PasteText, _PasteTextHandlers, TerminalApp::PasteTextEventArgs);
|
||||
DECLARE_EVENT(NewTab, _NewTabHandlers, TerminalApp::NewTabEventArgs);
|
||||
DECLARE_EVENT(DuplicateTab, _DuplicateTabHandlers, TerminalApp::DuplicateTabEventArgs);
|
||||
DECLARE_EVENT(NewTabWithProfile, _NewTabWithProfileHandlers, TerminalApp::NewTabWithProfileEventArgs);
|
||||
DECLARE_EVENT(NewWindow, _NewWindowHandlers, TerminalApp::NewWindowEventArgs);
|
||||
DECLARE_EVENT(CloseWindow, _CloseWindowHandlers, TerminalApp::CloseWindowEventArgs);
|
||||
DECLARE_EVENT(CloseTab, _CloseTabHandlers, TerminalApp::CloseTabEventArgs);
|
||||
DECLARE_EVENT(ClosePane, _ClosePaneHandlers, TerminalApp::ClosePaneEventArgs);
|
||||
DECLARE_EVENT(SwitchToTab, _SwitchToTabHandlers, TerminalApp::SwitchToTabEventArgs);
|
||||
DECLARE_EVENT(NextTab, _NextTabHandlers, TerminalApp::NextTabEventArgs);
|
||||
DECLARE_EVENT(PrevTab, _PrevTabHandlers, TerminalApp::PrevTabEventArgs);
|
||||
@@ -60,8 +59,6 @@ namespace winrt::TerminalApp::implementation
|
||||
DECLARE_EVENT(ScrollUpPage, _ScrollUpPageHandlers, TerminalApp::ScrollUpPageEventArgs);
|
||||
DECLARE_EVENT(ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
|
||||
DECLARE_EVENT(OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
|
||||
DECLARE_EVENT(ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
|
||||
DECLARE_EVENT(MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
||||
@@ -3,21 +3,11 @@
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
enum Direction
|
||||
{
|
||||
Left = 0,
|
||||
Right,
|
||||
Up,
|
||||
Down
|
||||
};
|
||||
|
||||
enum ShortcutAction
|
||||
{
|
||||
CopyText = 0,
|
||||
CopyTextWithoutNewlines,
|
||||
PasteText,
|
||||
NewTab,
|
||||
DuplicateTab,
|
||||
NewTabProfile0,
|
||||
NewTabProfile1,
|
||||
NewTabProfile2,
|
||||
@@ -30,7 +20,6 @@ namespace TerminalApp
|
||||
NewWindow,
|
||||
CloseWindow,
|
||||
CloseTab,
|
||||
ClosePane,
|
||||
NextTab,
|
||||
PrevTab,
|
||||
SplitVertical,
|
||||
@@ -50,26 +39,16 @@ namespace TerminalApp
|
||||
ScrollDown,
|
||||
ScrollUpPage,
|
||||
ScrollDownPage,
|
||||
ResizePaneLeft,
|
||||
ResizePaneRight,
|
||||
ResizePaneUp,
|
||||
ResizePaneDown,
|
||||
MoveFocusLeft,
|
||||
MoveFocusRight,
|
||||
MoveFocusUp,
|
||||
MoveFocusDown,
|
||||
OpenSettings
|
||||
};
|
||||
|
||||
delegate void CopyTextEventArgs(Boolean trimWhitespace);
|
||||
delegate void CopyTextEventArgs();
|
||||
delegate void PasteTextEventArgs();
|
||||
delegate void NewTabEventArgs();
|
||||
delegate void DuplicateTabEventArgs();
|
||||
delegate void NewTabWithProfileEventArgs(Int32 profileIndex);
|
||||
delegate void NewWindowEventArgs();
|
||||
delegate void CloseWindowEventArgs();
|
||||
delegate void CloseTabEventArgs();
|
||||
delegate void ClosePaneEventArgs();
|
||||
delegate void NextTabEventArgs();
|
||||
delegate void PrevTabEventArgs();
|
||||
delegate void SplitVerticalEventArgs();
|
||||
@@ -82,10 +61,9 @@ namespace TerminalApp
|
||||
delegate void ScrollUpPageEventArgs();
|
||||
delegate void ScrollDownPageEventArgs();
|
||||
delegate void OpenSettingsEventArgs();
|
||||
delegate void ResizePaneEventArgs(Direction direction);
|
||||
delegate void MoveFocusEventArgs(Direction direction);
|
||||
|
||||
[default_interface] runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
|
||||
[default_interface]
|
||||
runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
|
||||
{
|
||||
AppKeyBindings();
|
||||
|
||||
@@ -95,12 +73,10 @@ namespace TerminalApp
|
||||
event CopyTextEventArgs CopyText;
|
||||
event PasteTextEventArgs PasteText;
|
||||
event NewTabEventArgs NewTab;
|
||||
event DuplicateTabEventArgs DuplicateTab;
|
||||
event NewTabWithProfileEventArgs NewTabWithProfile;
|
||||
event NewWindowEventArgs NewWindow;
|
||||
event CloseWindowEventArgs CloseWindow;
|
||||
event CloseTabEventArgs CloseTab;
|
||||
event ClosePaneEventArgs ClosePane;
|
||||
event SwitchToTabEventArgs SwitchToTab;
|
||||
event NextTabEventArgs NextTab;
|
||||
event PrevTabEventArgs PrevTab;
|
||||
@@ -113,7 +89,5 @@ namespace TerminalApp
|
||||
event ScrollUpPageEventArgs ScrollUpPage;
|
||||
event ScrollDownPageEventArgs ScrollDownPage;
|
||||
event OpenSettingsEventArgs OpenSettings;
|
||||
event ResizePaneEventArgs ResizePane;
|
||||
event MoveFocusEventArgs MoveFocus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,8 @@ static constexpr std::string_view KeysKey{ "keys" };
|
||||
static constexpr std::string_view CommandKey{ "command" };
|
||||
|
||||
static constexpr std::string_view CopyTextKey{ "copy" };
|
||||
static constexpr std::string_view CopyTextWithoutNewlinesKey{ "copyTextWithoutNewlines" };
|
||||
static constexpr std::string_view PasteTextKey{ "paste" };
|
||||
static constexpr std::string_view NewTabKey{ "newTab" };
|
||||
static constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
|
||||
static constexpr std::string_view NewTabWithProfile0Key{ "newTabProfile0" };
|
||||
static constexpr std::string_view NewTabWithProfile1Key{ "newTabProfile1" };
|
||||
static constexpr std::string_view NewTabWithProfile2Key{ "newTabProfile2" };
|
||||
@@ -30,7 +28,6 @@ static constexpr std::string_view NewTabWithProfile8Key{ "newTabProfile8" };
|
||||
static constexpr std::string_view NewWindowKey{ "newWindow" };
|
||||
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
|
||||
static constexpr std::string_view CloseTabKey{ "closeTab" };
|
||||
static constexpr std::string_view ClosePaneKey{ "closePane" };
|
||||
static constexpr std::string_view SwitchtoTabKey{ "switchToTab" };
|
||||
static constexpr std::string_view NextTabKey{ "nextTab" };
|
||||
static constexpr std::string_view PrevTabKey{ "prevTab" };
|
||||
@@ -52,14 +49,6 @@ static constexpr std::string_view SwitchToTab8Key{ "switchToTab8" };
|
||||
static constexpr std::string_view OpenSettingsKey{ "openSettings" };
|
||||
static constexpr std::string_view SplitHorizontalKey{ "splitHorizontal" };
|
||||
static constexpr std::string_view SplitVerticalKey{ "splitVertical" };
|
||||
static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
|
||||
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
|
||||
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
|
||||
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
|
||||
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
|
||||
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
|
||||
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
|
||||
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
|
||||
|
||||
// Specifically use a map here over an unordered_map. We want to be able to
|
||||
// iterate over these entries in-order when we're serializing the keybindings.
|
||||
@@ -71,10 +60,8 @@ static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };
|
||||
// about here.
|
||||
static const std::map<std::string_view, ShortcutAction, std::less<>> commandNames{
|
||||
{ CopyTextKey, ShortcutAction::CopyText },
|
||||
{ CopyTextWithoutNewlinesKey, ShortcutAction::CopyTextWithoutNewlines },
|
||||
{ PasteTextKey, ShortcutAction::PasteText },
|
||||
{ NewTabKey, ShortcutAction::NewTab },
|
||||
{ DuplicateTabKey, ShortcutAction::DuplicateTab },
|
||||
{ NewTabWithProfile0Key, ShortcutAction::NewTabProfile0 },
|
||||
{ NewTabWithProfile1Key, ShortcutAction::NewTabProfile1 },
|
||||
{ NewTabWithProfile2Key, ShortcutAction::NewTabProfile2 },
|
||||
@@ -87,7 +74,6 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
||||
{ NewWindowKey, ShortcutAction::NewWindow },
|
||||
{ CloseWindowKey, ShortcutAction::CloseWindow },
|
||||
{ CloseTabKey, ShortcutAction::CloseTab },
|
||||
{ ClosePaneKey, ShortcutAction::ClosePane },
|
||||
{ NextTabKey, ShortcutAction::NextTab },
|
||||
{ PrevTabKey, ShortcutAction::PrevTab },
|
||||
{ IncreaseFontSizeKey, ShortcutAction::IncreaseFontSize },
|
||||
@@ -107,14 +93,6 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
|
||||
{ SwitchToTab8Key, ShortcutAction::SwitchToTab8 },
|
||||
{ SplitHorizontalKey, ShortcutAction::SplitHorizontal },
|
||||
{ SplitVerticalKey, ShortcutAction::SplitVertical },
|
||||
{ ResizePaneLeftKey, ShortcutAction::ResizePaneLeft },
|
||||
{ ResizePaneRightKey, ShortcutAction::ResizePaneRight },
|
||||
{ ResizePaneUpKey, ShortcutAction::ResizePaneUp },
|
||||
{ ResizePaneDownKey, ShortcutAction::ResizePaneDown },
|
||||
{ MoveFocusLeftKey, ShortcutAction::MoveFocusLeft },
|
||||
{ MoveFocusRightKey, ShortcutAction::MoveFocusRight },
|
||||
{ MoveFocusUpKey, ShortcutAction::MoveFocusUp },
|
||||
{ MoveFocusDownKey, ShortcutAction::MoveFocusDown },
|
||||
{ OpenSettingsKey, ShortcutAction::OpenSettings },
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Module Name:
|
||||
// - AppKeyBindingsSerialization.h
|
||||
// - Profile.hpp
|
||||
//
|
||||
// Abstract:
|
||||
// - A couple helper functions for serializing/deserializing an AppKeyBindings
|
||||
|
||||
@@ -49,35 +49,6 @@ ColorScheme _CreateCampbellScheme()
|
||||
|
||||
// clang-format off
|
||||
|
||||
ColorScheme _CreateVintageScheme()
|
||||
{
|
||||
// as per https://github.com/microsoft/terminal/issues/1781
|
||||
ColorScheme vintageScheme { L"Vintage",
|
||||
RGB(192, 192, 192),
|
||||
RGB( 0, 0, 0) };
|
||||
auto& vintageTable = vintageScheme.GetTable();
|
||||
auto vintageSpan = gsl::span<COLORREF>(&vintageTable[0], gsl::narrow<ptrdiff_t>(COLOR_TABLE_SIZE));
|
||||
vintageTable[0] = RGB( 0, 0, 0); // black
|
||||
vintageTable[1] = RGB(128, 0, 0); // dark red
|
||||
vintageTable[2] = RGB( 0, 128, 0); // dark green
|
||||
vintageTable[3] = RGB(128, 128, 0); // dark yellow
|
||||
vintageTable[4] = RGB( 0, 0, 128); // dark blue
|
||||
vintageTable[5] = RGB(128, 0, 128); // dark magenta
|
||||
vintageTable[6] = RGB( 0, 128, 128); // dark cyan
|
||||
vintageTable[7] = RGB(192, 192, 192); // gray
|
||||
vintageTable[8] = RGB(128, 128, 128); // dark gray
|
||||
vintageTable[9] = RGB(255, 0, 0); // red
|
||||
vintageTable[10] = RGB( 0, 255, 0); // green
|
||||
vintageTable[11] = RGB(255, 255, 0); // yellow
|
||||
vintageTable[12] = RGB( 0, 0, 255); // blue
|
||||
vintageTable[13] = RGB(255, 0, 255); // magenta
|
||||
vintageTable[14] = RGB( 0, 255, 255); // cyan
|
||||
vintageTable[15] = RGB(255, 255, 255); // white
|
||||
Utils::SetColorTableAlpha(vintageSpan, 0xff);
|
||||
|
||||
return vintageScheme;
|
||||
}
|
||||
|
||||
ColorScheme _CreateOneHalfDarkScheme()
|
||||
{
|
||||
// First 8 dark colors per: https://github.com/sonph/onehalf/blob/master/putty/onehalf-dark.reg
|
||||
@@ -208,7 +179,6 @@ ColorScheme _CreateSolarizedLightScheme()
|
||||
void CascadiaSettings::_CreateDefaultSchemes()
|
||||
{
|
||||
_globals.GetColorSchemes().emplace_back(_CreateCampbellScheme());
|
||||
_globals.GetColorSchemes().emplace_back(_CreateVintageScheme());
|
||||
_globals.GetColorSchemes().emplace_back(_CreateOneHalfDarkScheme());
|
||||
_globals.GetColorSchemes().emplace_back(_CreateOneHalfLightScheme());
|
||||
_globals.GetColorSchemes().emplace_back(_CreateSolarizedDarkScheme());
|
||||
@@ -239,19 +209,6 @@ void CascadiaSettings::_CreateDefaultProfiles()
|
||||
powershellProfile.SetDefaultBackground(POWERSHELL_BLUE);
|
||||
powershellProfile.SetUseAcrylic(false);
|
||||
|
||||
// The Azure connection has a boost dependency, and boost does not support ARM64
|
||||
// so we don't create a default profile for the Azure cloud shell if we're in ARM64
|
||||
#ifndef _M_ARM64
|
||||
auto azureCloudShellProfile{ _CreateDefaultProfile(L"Azure Cloud Shell") };
|
||||
azureCloudShellProfile.SetCommandline(L"Azure");
|
||||
azureCloudShellProfile.SetStartingDirectory(DEFAULT_STARTING_DIRECTORY);
|
||||
azureCloudShellProfile.SetColorScheme({ L"Solarized Dark" });
|
||||
azureCloudShellProfile.SetAcrylicOpacity(0.85);
|
||||
azureCloudShellProfile.SetUseAcrylic(true);
|
||||
azureCloudShellProfile.SetCloseOnExit(false);
|
||||
azureCloudShellProfile.SetConnectionType(AzureConnectionType);
|
||||
#endif
|
||||
|
||||
// If the user has installed PowerShell Core, we add PowerShell Core as a default.
|
||||
// PowerShell Core default folder is "%PROGRAMFILES%\PowerShell\[Version]\".
|
||||
std::filesystem::path psCoreCmdline{};
|
||||
@@ -274,9 +231,6 @@ void CascadiaSettings::_CreateDefaultProfiles()
|
||||
|
||||
_profiles.emplace_back(powershellProfile);
|
||||
_profiles.emplace_back(cmdProfile);
|
||||
#ifndef _M_ARM64
|
||||
_profiles.emplace_back(azureCloudShellProfile);
|
||||
#endif
|
||||
try
|
||||
{
|
||||
_AppendWslProfiles(_profiles);
|
||||
@@ -293,26 +247,16 @@ void CascadiaSettings::_CreateDefaultProfiles()
|
||||
void CascadiaSettings::_CreateDefaultKeybindings()
|
||||
{
|
||||
AppKeyBindings keyBindings = _globals.GetKeybindings();
|
||||
// Set up some basic default keybindings
|
||||
// Set up spme basic default keybindings
|
||||
// TODO:MSFT:20700157 read our settings from some source, and configure
|
||||
// keychord,action pairings from that file
|
||||
keyBindings.SetKeyBinding(ShortcutAction::NewTab,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
KeyChord{ KeyModifiers::Ctrl,
|
||||
static_cast<int>('T') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::DuplicateTab,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
static_cast<int>('D') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::ClosePane,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
keyBindings.SetKeyBinding(ShortcutAction::CloseTab,
|
||||
KeyChord{ KeyModifiers::Ctrl,
|
||||
static_cast<int>('W') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::CopyText,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
static_cast<int>('C') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::PasteText,
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
static_cast<int>('V') });
|
||||
|
||||
keyBindings.SetKeyBinding(ShortcutAction::OpenSettings,
|
||||
KeyChord{ KeyModifiers::Ctrl,
|
||||
VK_OEM_COMMA });
|
||||
@@ -368,31 +312,31 @@ void CascadiaSettings::_CreateDefaultKeybindings()
|
||||
KeyChord{ KeyModifiers::Ctrl | KeyModifiers::Shift,
|
||||
VK_PRIOR });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab0,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('1') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab1,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('2') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab2,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('3') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab3,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('4') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab4,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('5') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab5,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('6') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab6,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('7') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab7,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('8') });
|
||||
keyBindings.SetKeyBinding(ShortcutAction::SwitchToTab8,
|
||||
KeyChord{ KeyModifiers::Alt | KeyModifiers::Ctrl,
|
||||
KeyChord{ KeyModifiers::Alt,
|
||||
static_cast<int>('9') });
|
||||
}
|
||||
|
||||
@@ -514,8 +458,7 @@ bool CascadiaSettings::_isPowerShellCoreInstalled(std::filesystem::path& cmdline
|
||||
// - true iff powershell core (pwsh.exe) is present in the given path
|
||||
bool CascadiaSettings::_isPowerShellCoreInstalledInPath(const std::wstring_view programFileEnv, std::filesystem::path& cmdline)
|
||||
{
|
||||
std::wstring programFileEnvNulTerm{ programFileEnv };
|
||||
std::filesystem::path psCorePath{ wil::ExpandEnvironmentStringsW<std::wstring>(programFileEnvNulTerm.data()) };
|
||||
std::filesystem::path psCorePath = ExpandEnvironmentVariableString(programFileEnv.data());
|
||||
psCorePath /= L"PowerShell";
|
||||
if (std::filesystem::exists(psCorePath))
|
||||
{
|
||||
@@ -612,7 +555,6 @@ void CascadiaSettings::_AppendWslProfiles(std::vector<TerminalApp::Profile>& pro
|
||||
auto WSLDistro{ _CreateDefaultProfile(distName) };
|
||||
WSLDistro.SetCommandline(L"wsl.exe -d " + distName);
|
||||
WSLDistro.SetColorScheme({ L"Campbell" });
|
||||
WSLDistro.SetStartingDirectory(DEFAULT_STARTING_DIRECTORY);
|
||||
std::wstring iconPath{ PACKAGED_PROFILE_ICON_PATH };
|
||||
iconPath.append(DEFAULT_LINUX_ICON_GUID);
|
||||
iconPath.append(PACKAGED_PROFILE_ICON_EXTENSION);
|
||||
@@ -622,6 +564,27 @@ void CascadiaSettings::_AppendWslProfiles(std::vector<TerminalApp::Profile>& pro
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Get a environment variable string.
|
||||
// Arguments:
|
||||
// - A string that contains an environment-variable string in the form: %variableName%.
|
||||
// Return Value:
|
||||
// - a string of the expending environment-variable string.
|
||||
std::wstring CascadiaSettings::ExpandEnvironmentVariableString(std::wstring_view source)
|
||||
{
|
||||
std::wstring result{};
|
||||
DWORD requiredSize = 0;
|
||||
do
|
||||
{
|
||||
result.resize(requiredSize);
|
||||
requiredSize = ::ExpandEnvironmentStringsW(source.data(), result.data(), gsl::narrow<DWORD>(result.size()));
|
||||
} while (requiredSize != result.size());
|
||||
|
||||
// Trim the terminating null character
|
||||
result.resize(requiredSize - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for creating a skeleton default profile with a pre-populated
|
||||
// guid and name.
|
||||
|
||||
@@ -20,8 +20,6 @@ Author(s):
|
||||
#include "GlobalAppSettings.h"
|
||||
#include "Profile.h"
|
||||
|
||||
static constexpr GUID AzureConnectionType = { 0xd9fcfdfa, 0xa479, 0x412c, { 0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62 } };
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
class CascadiaSettings;
|
||||
@@ -68,5 +66,6 @@ private:
|
||||
static bool _isPowerShellCoreInstalledInPath(const std::wstring_view programFileEnv, std::filesystem::path& cmdline);
|
||||
static bool _isPowerShellCoreInstalled(std::filesystem::path& cmdline);
|
||||
static void _AppendWslProfiles(std::vector<TerminalApp::Profile>& profileStorage);
|
||||
static std::wstring ExpandEnvironmentVariableString(std::wstring_view source);
|
||||
static Profile _CreateDefaultProfile(const std::wstring_view name);
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@ using namespace TerminalApp;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::TerminalApp;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
|
||||
static constexpr std::string_view NameKey{ "name" };
|
||||
static constexpr std::string_view TableKey{ "colors" };
|
||||
|
||||
@@ -17,6 +17,7 @@ Author(s):
|
||||
#pragma once
|
||||
#include <winrt/Microsoft.Terminal.Settings.h>
|
||||
#include <winrt/Microsoft.Terminal.TerminalControl.h>
|
||||
#include <winrt/TerminalApp.h>
|
||||
#include "../../inc/conattrs.hpp"
|
||||
|
||||
namespace TerminalApp
|
||||
|
||||
@@ -23,7 +23,6 @@ static constexpr std::string_view InitialColsKey{ "initialCols" };
|
||||
static constexpr std::string_view ShowTitleInTitlebarKey{ "showTerminalTitleInTitlebar" };
|
||||
static constexpr std::string_view RequestedThemeKey{ "requestedTheme" };
|
||||
static constexpr std::string_view ShowTabsInTitlebarKey{ "showTabsInTitlebar" };
|
||||
static constexpr std::string_view WordDelimitersKey{ "wordDelimiters" };
|
||||
|
||||
static constexpr std::wstring_view LightThemeValue{ L"light" };
|
||||
static constexpr std::wstring_view DarkThemeValue{ L"dark" };
|
||||
@@ -38,8 +37,7 @@ GlobalAppSettings::GlobalAppSettings() :
|
||||
_initialCols{ DEFAULT_COLS },
|
||||
_showTitleInTitlebar{ true },
|
||||
_showTabsInTitlebar{ true },
|
||||
_requestedTheme{ ElementTheme::Default },
|
||||
_wordDelimiters{ DEFAULT_WORD_DELIMITERS }
|
||||
_requestedTheme{ ElementTheme::Default }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -107,16 +105,6 @@ void GlobalAppSettings::SetRequestedTheme(const ElementTheme requestedTheme) noe
|
||||
_requestedTheme = requestedTheme;
|
||||
}
|
||||
|
||||
std::wstring GlobalAppSettings::GetWordDelimiters() const noexcept
|
||||
{
|
||||
return _wordDelimiters;
|
||||
}
|
||||
|
||||
void GlobalAppSettings::SetWordDelimiters(const std::wstring wordDelimiters) noexcept
|
||||
{
|
||||
_wordDelimiters = wordDelimiters;
|
||||
}
|
||||
|
||||
#pragma region ExperimentalSettings
|
||||
bool GlobalAppSettings::GetShowTabsInTitlebar() const noexcept
|
||||
{
|
||||
@@ -140,7 +128,6 @@ void GlobalAppSettings::ApplyToSettings(TerminalSettings& settings) const noexce
|
||||
settings.KeyBindings(GetKeybindings());
|
||||
settings.InitialRows(_initialRows);
|
||||
settings.InitialCols(_initialCols);
|
||||
settings.WordDelimiters(_wordDelimiters);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -159,7 +146,6 @@ Json::Value GlobalAppSettings::ToJson() const
|
||||
jsonObject[JsonKey(AlwaysShowTabsKey)] = _alwaysShowTabs;
|
||||
jsonObject[JsonKey(ShowTitleInTitlebarKey)] = _showTitleInTitlebar;
|
||||
jsonObject[JsonKey(ShowTabsInTitlebarKey)] = _showTabsInTitlebar;
|
||||
jsonObject[JsonKey(WordDelimitersKey)] = winrt::to_string(_wordDelimiters);
|
||||
jsonObject[JsonKey(RequestedThemeKey)] = winrt::to_string(_SerializeTheme(_requestedTheme));
|
||||
jsonObject[JsonKey(KeybindingsKey)] = AppKeyBindingsSerialization::ToJson(_keybindings);
|
||||
|
||||
@@ -205,11 +191,6 @@ GlobalAppSettings GlobalAppSettings::FromJson(const Json::Value& json)
|
||||
result._showTabsInTitlebar = showTabsInTitlebar.asBool();
|
||||
}
|
||||
|
||||
if (auto wordDelimiters{ json[JsonKey(WordDelimitersKey)] })
|
||||
{
|
||||
result._wordDelimiters = GetWstringFromJson(wordDelimiters);
|
||||
}
|
||||
|
||||
if (auto requestedTheme{ json[JsonKey(RequestedThemeKey)] })
|
||||
{
|
||||
result._requestedTheme = _ParseTheme(GetWstringFromJson(requestedTheme));
|
||||
|
||||
@@ -47,9 +47,6 @@ public:
|
||||
bool GetShowTabsInTitlebar() const noexcept;
|
||||
void SetShowTabsInTitlebar(const bool showTabsInTitlebar) noexcept;
|
||||
|
||||
std::wstring GetWordDelimiters() const noexcept;
|
||||
void SetWordDelimiters(const std::wstring wordDelimiters) noexcept;
|
||||
|
||||
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme() const noexcept;
|
||||
|
||||
Json::Value ToJson() const;
|
||||
@@ -71,7 +68,6 @@ private:
|
||||
bool _showTitleInTitlebar;
|
||||
|
||||
bool _showTabsInTitlebar;
|
||||
std::wstring _wordDelimiters;
|
||||
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
|
||||
|
||||
static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept;
|
||||
|
||||
@@ -68,7 +68,21 @@ static const std::unordered_map<int32_t, std::wstring_view> vkeyNamePairs {
|
||||
{ VK_F22 , L"f22" },
|
||||
{ VK_F23 , L"f23" },
|
||||
{ VK_F24 , L"f24" },
|
||||
{ VK_OEM_PLUS , L"plus" }
|
||||
{ VK_OEM_PLUS , L"plus" },
|
||||
{ VK_OEM_COMMA , L"," },
|
||||
{ VK_OEM_MINUS , L"-" },
|
||||
{ VK_OEM_PERIOD , L"." }
|
||||
// TODO:
|
||||
// These all look like they'd be good keybindings, but change based on keyboard
|
||||
// layout. How do we deal with that?
|
||||
// #define VK_OEM_NEC_EQUAL 0x92 // '=' key on numpad
|
||||
// #define VK_OEM_1 0xBA // ';:' for US
|
||||
// #define VK_OEM_2 0xBF // '/?' for US
|
||||
// #define VK_OEM_3 0xC0 // '`~' for US
|
||||
// #define VK_OEM_4 0xDB // '[{' for US
|
||||
// #define VK_OEM_5 0xDC // '\|' for US
|
||||
// #define VK_OEM_6 0xDD // ']}' for US
|
||||
// #define VK_OEM_7 0xDE // ''"' for US
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -164,25 +178,6 @@ winrt::Microsoft::Terminal::Settings::KeyChord KeyChordSerialization::FromString
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found a key, attempt a keyboard mapping
|
||||
if (!foundKey && part.size() == 1)
|
||||
{
|
||||
auto oemVk = VkKeyScanW(part[0]);
|
||||
if (oemVk != -1)
|
||||
{
|
||||
vkey = oemVk & 0xFF;
|
||||
auto oemModifiers = (oemVk & 0xFF00) >> 8;
|
||||
// We're using WI_SetFlagIf instead of WI_UpdateFlag because we want to be strictly additive
|
||||
// to the user's specified modifiers. ctrl+| should be the same as ctrl+shift+\,
|
||||
// but if we used WI_UpdateFlag, ctrl+shift+\ would turn _off_ Shift because \ doesn't
|
||||
// require it.
|
||||
WI_SetFlagIf(modifiers, KeyModifiers::Shift, WI_IsFlagSet(oemModifiers, 1U));
|
||||
WI_SetFlagIf(modifiers, KeyModifiers::Ctrl, WI_IsFlagSet(oemModifiers, 2U));
|
||||
WI_SetFlagIf(modifiers, KeyModifiers::Alt, WI_IsFlagSet(oemModifiers, 4U));
|
||||
foundKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we weren't able to find a match, throw an exception.
|
||||
if (!foundKey)
|
||||
{
|
||||
@@ -245,16 +240,6 @@ winrt::hstring KeyChordSerialization::ToString(const KeyChord& chord)
|
||||
buffer += vkeyNamePairs.at(vkey);
|
||||
serializedSuccessfully = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto mappedChar = MapVirtualKeyW(vkey, MAPVK_VK_TO_CHAR);
|
||||
if (mappedChar != 0)
|
||||
{
|
||||
wchar_t mappedWch = gsl::narrow_cast<wchar_t>(mappedChar);
|
||||
buffer += std::wstring_view{ &mappedWch, 1 };
|
||||
serializedSuccessfully = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!serializedSuccessfully)
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// MinMaxCloseControl.xaml.cpp
|
||||
// Implementation of the MinMaxCloseControl class
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "MinMaxCloseControl.h"
|
||||
|
||||
#include "MinMaxCloseControl.g.cpp"
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
MinMaxCloseControl::MinMaxCloseControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::Maximize()
|
||||
{
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateMaximized", false);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::RestoreDown()
|
||||
{
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"WindowStateNormal", false);
|
||||
}
|
||||
|
||||
// These event handlers simply forward each buttons click events up to the
|
||||
// events we've exposed.
|
||||
void MinMaxCloseControl::_MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
_minimizeClickHandlers(*this, e);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::_MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
_maximizeClickHandlers(*this, e);
|
||||
}
|
||||
void MinMaxCloseControl::_CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
RoutedEventArgs const& e)
|
||||
{
|
||||
_closeClickHandlers(*this, e);
|
||||
}
|
||||
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(MinMaxCloseControl, CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, RoutedEventArgs);
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Declaration of the MainUserControl class.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Windows.UI.Xaml.h"
|
||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
||||
#include "MinMaxCloseControl.g.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct MinMaxCloseControl : MinMaxCloseControlT<MinMaxCloseControl>
|
||||
{
|
||||
MinMaxCloseControl();
|
||||
|
||||
void Maximize();
|
||||
void RestoreDown();
|
||||
|
||||
void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void _CloseClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MinimizeClick, _minimizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(MaximizeClick, _maximizeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(CloseClick, _closeClickHandlers, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct MinMaxCloseControl : MinMaxCloseControlT<MinMaxCloseControl, implementation::MinMaxCloseControl>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
|
||||
{
|
||||
MinMaxCloseControl();
|
||||
|
||||
void Maximize();
|
||||
void RestoreDown();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> CloseClick;
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<StackPanel
|
||||
x:Class="TerminalApp.MinMaxCloseControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Horizontal"
|
||||
d:DesignHeight="36"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<StackPanel.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStroke" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver" Color="Red"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver" Color="White"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed" Color="#f1707a"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed" Color="Black"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="SystemControlBackgroundBaseLowBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStroke" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="SystemControlForegroundBaseHighBrush"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver" Color="Red"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver" Color="White"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed" Color="#f1707a"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed" Color="Black"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">3.0</x:Double>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground" Color="{ThemeResource SystemColorButtonFaceColor}"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackgroundPointerOver" Color="{ThemeResource SystemColorHighlightColor}"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonBackgroundPressed" Color="{ThemeResource SystemColorHighlightColor}"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonStroke" Color="{ThemeResource SystemColorButtonTextColor}"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePointerOver" Color="{ThemeResource SystemColorHighlightTextColor}"/>
|
||||
<SolidColorBrush x:Key="CaptionButtonStrokePressed" Color="{ThemeResource SystemColorHighlightTextColor}"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver" Color="{ThemeResource SystemColorHighlightColor}"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver" Color="{ThemeResource SystemColorHighlightTextColor}"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed" Color="{ThemeResource SystemColorHighlightColor}"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed" Color="{ThemeResource SystemColorHighlightTextColor}"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<x:String x:Key="CaptionButtonPath"></x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized"></x:String>
|
||||
|
||||
<Style x:Key="CaptionButton" TargetType="Button">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource CaptionButtonBackground}" />
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="ButtonBaseElement"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPressed}" />
|
||||
<Setter Target="Path.Stroke" Value="{ThemeResource CaptionButtonStrokePressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="MinMaxStates">
|
||||
<VisualState x:Name="WindowStateNormal" />
|
||||
|
||||
<VisualState x:Name="WindowStateMaximized">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Path.Data" Value="{ThemeResource CaptionButtonPathWindowMaximized}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<Path
|
||||
x:Name="Path"
|
||||
StrokeThickness="{ThemeResource CaptionButtonStrokeWidth}"
|
||||
Stroke="{ThemeResource CaptionButtonStroke}"
|
||||
Data="{ThemeResource CaptionButtonPath}"
|
||||
Stretch="Fill"
|
||||
UseLayoutRounding="True"
|
||||
Width="10"
|
||||
Height="10"
|
||||
StrokeEndLineCap="Square"
|
||||
StrokeStartLineCap="Square" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
</StackPanel.Resources>
|
||||
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="MinimizeButton" Style="{StaticResource CaptionButton}" Click="_MinimizeClick"
|
||||
AutomationProperties.Name="Minimize">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 H 10</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="MaximizeButton" Style="{StaticResource CaptionButton}" Click="_MaximizeClick"
|
||||
AutomationProperties.Name="Maximize">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 H 10 V 10 H 0 V 0</x:String>
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 0 2 h 8 v 8 h -8 v -8 M 2 2 v -2 h 8 v 8 h -2</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
<Button Height="36.0" MinWidth="45.0" Width="45.0" x:Name="CloseButton" Style="{StaticResource CaptionButton}" Click="_CloseClick"
|
||||
AutomationProperties.Name="Close">
|
||||
<Button.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="CloseButtonBackgroundPointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="CloseButtonBackgroundPressed"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="CloseButtonStrokePointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="CloseButtonStrokePressed"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="CloseButtonBackgroundPointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="CloseButtonBackgroundPressed"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="CloseButtonStrokePointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="CloseButtonStrokePressed"/>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="CloseButtonBackgroundPointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="CloseButtonBackgroundPressed"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="CloseButtonStrokePointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="CloseButtonStrokePressed"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
@@ -4,22 +4,19 @@
|
||||
#include "pch.h"
|
||||
#include "Pane.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::TerminalApp;
|
||||
|
||||
static const int PaneSeparatorSize = 4;
|
||||
static const float Half = 0.50f;
|
||||
|
||||
Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocused) :
|
||||
_control{ control },
|
||||
_lastFocused{ lastFocused },
|
||||
_profile{ profile }
|
||||
{
|
||||
_root.Children().Append(_control);
|
||||
_root.Children().Append(_control.GetControl());
|
||||
_connectionClosedToken = _control.ConnectionClosed({ this, &Pane::_ControlClosedHandler });
|
||||
|
||||
// Set the background of the pane to match that of the theme's default grid
|
||||
@@ -39,243 +36,6 @@ Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocus
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update the size of this pane. Resizes each of our columns so they have the
|
||||
// same relative sizes, given the newSize.
|
||||
// - Because we're just manually setting the row/column sizes in pixels, we have
|
||||
// to be told our new size, we can't just use our own OnSized event, because
|
||||
// that _won't fire when we get smaller_.
|
||||
// Arguments:
|
||||
// - newSize: the amount of space that this pane has to fill now.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::ResizeContent(const Size& newSize)
|
||||
{
|
||||
const auto width = newSize.Width;
|
||||
const auto height = newSize.Height;
|
||||
|
||||
_CreateRowColDefinitions(newSize);
|
||||
|
||||
if (_splitState == SplitState::Vertical)
|
||||
{
|
||||
const auto paneSizes = _GetPaneSizes(width);
|
||||
|
||||
const Size firstSize{ paneSizes.first, height };
|
||||
const Size secondSize{ paneSizes.second, height };
|
||||
_firstChild->ResizeContent(firstSize);
|
||||
_secondChild->ResizeContent(secondSize);
|
||||
}
|
||||
else if (_splitState == SplitState::Horizontal)
|
||||
{
|
||||
const auto paneSizes = _GetPaneSizes(height);
|
||||
|
||||
const Size firstSize{ width, paneSizes.first };
|
||||
const Size secondSize{ width, paneSizes.second };
|
||||
_firstChild->ResizeContent(firstSize);
|
||||
_secondChild->ResizeContent(secondSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Adjust our child percentages to increase the size of one of our children
|
||||
// and decrease the size of the other.
|
||||
// - Adjusts the separation amount by 5%
|
||||
// - Does nothing if the direction doesn't match our current split direction
|
||||
// Arguments:
|
||||
// - direction: the direction to move our separator. If it's down or right,
|
||||
// we'll be increasing the size of the first of our children. Else, we'll be
|
||||
// decreasing the size of our first child.
|
||||
// Return Value:
|
||||
// - false if we couldn't resize this pane in the given direction, else true.
|
||||
bool Pane::_Resize(const Direction& direction)
|
||||
{
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float amount = .05f;
|
||||
if (direction == Direction::Right || direction == Direction::Down)
|
||||
{
|
||||
amount = -amount;
|
||||
}
|
||||
|
||||
// Make sure we're not making a pane explode here by resizing it to 0 characters.
|
||||
const bool changeWidth = _splitState == SplitState::Vertical;
|
||||
|
||||
const Size actualSize{ gsl::narrow_cast<float>(_root.ActualWidth()),
|
||||
gsl::narrow_cast<float>(_root.ActualHeight()) };
|
||||
// actualDimension is the size in DIPs of this pane in the direction we're
|
||||
// resizing.
|
||||
auto actualDimension = changeWidth ? actualSize.Width : actualSize.Height;
|
||||
actualDimension -= PaneSeparatorSize;
|
||||
|
||||
const auto firstMinSize = _firstChild->_GetMinSize();
|
||||
const auto secondMinSize = _secondChild->_GetMinSize();
|
||||
|
||||
// These are the minimum amount of space we need for each of our children
|
||||
const auto firstMinDimension = changeWidth ? firstMinSize.Width : firstMinSize.Height;
|
||||
const auto secondMinDimension = changeWidth ? secondMinSize.Width : secondMinSize.Height;
|
||||
|
||||
const auto firstMinPercent = firstMinDimension / actualDimension;
|
||||
const auto secondMinPercent = secondMinDimension / actualDimension;
|
||||
|
||||
// Make sure that the first pane doesn't get bigger than the space we need
|
||||
// to reserve for the second.
|
||||
const auto firstMaxPercent = 1.0f - secondMinPercent;
|
||||
|
||||
_firstPercent = std::clamp(_firstPercent.value() - amount, firstMinPercent, firstMaxPercent);
|
||||
// Update the other child to fill the remaining percent
|
||||
_secondPercent = 1.0f - _firstPercent.value();
|
||||
|
||||
// Resize our columns to match the new percentages.
|
||||
ResizeContent(actualSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Moves the separator between panes, as to resize each child on either size
|
||||
// of the separator. Tries to move a separator in the given direction. The
|
||||
// separator moved is the separator that's closest depth-wise to the
|
||||
// currently focused pane, that's also in the correct direction to be moved.
|
||||
// If there isn't such a separator, then this method returns false, as we
|
||||
// couldn't handle the resize.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the separator in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this resize request.
|
||||
bool Pane::ResizePane(const Direction& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if either our first or second child is the currently focused leaf.
|
||||
// If it is, and the requested resize direction matches our separator, then
|
||||
// we're the pane that needs to adjust its separator.
|
||||
// If our separator is the wrong direction, then we can't handle it.
|
||||
const bool firstIsFocused = _firstChild->_IsLeaf() && _firstChild->_lastFocused;
|
||||
const bool secondIsFocused = _secondChild->_IsLeaf() && _secondChild->_lastFocused;
|
||||
if (firstIsFocused || secondIsFocused)
|
||||
{
|
||||
return _Resize(direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If neither of our children were the focused leaf, then recurse into
|
||||
// our children and see if they can handle the resize.
|
||||
// For each child, if it has a focused descendant, try having that child
|
||||
// handle the resize.
|
||||
// If the child wasn't able to handle the resize, it's possible that
|
||||
// there were no descendants with a separator the correct direction. If
|
||||
// our separator _is_ the correct direction, then we should be the pane
|
||||
// to resize. Otherwise, just return false, as we couldn't handle it
|
||||
// either.
|
||||
if ((!_firstChild->_IsLeaf()) && _firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->ResizePane(direction) || _Resize(direction);
|
||||
}
|
||||
else if ((!_secondChild->_IsLeaf()) && _secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->ResizePane(direction) || _Resize(direction);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to handle moving focus to one of our children. If our split
|
||||
// direction isn't appropriate for the move direction, then we'll return
|
||||
// false, to try and let our parent handle the move. If our child we'd move
|
||||
// focus to is already focused, we'll also return false, to again let our
|
||||
// parent try and handle the focus movement.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we handled this focus move request.
|
||||
bool Pane::_NavigateFocus(const Direction& direction)
|
||||
{
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool focusSecond = (direction == Direction::Right) || (direction == Direction::Down);
|
||||
|
||||
const auto newlyFocusedChild = focusSecond ? _secondChild : _firstChild;
|
||||
|
||||
// If the child we want to move focus to is _already_ focused, return false,
|
||||
// to try and let our parent figure it out.
|
||||
if (newlyFocusedChild->WasLastFocused())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Transfer focus to our child, and update the focus of our tree.
|
||||
newlyFocusedChild->_FocusFirstChild();
|
||||
UpdateFocus();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to move focus to one of our children. If we have a focused child,
|
||||
// we'll try to move the focus in the direction requested.
|
||||
// - If there isn't a pane that exists as a child of this pane in the correct
|
||||
// direction, we'll return false. This will indicate to our parent that they
|
||||
// should try and move the focus themselves. In this way, the focus can move
|
||||
// up and down the tree to the correct pane.
|
||||
// - This method is _very_ similar to ResizePane. Both are trying to find the
|
||||
// right separator to move (focus) in a direction.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this focus move request.
|
||||
bool Pane::NavigateFocus(const Direction& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if either our first or second child is the currently focused leaf.
|
||||
// If it is, and the requested move direction matches our separator, then
|
||||
// we're the pane that needs to handle this focus move.
|
||||
const bool firstIsFocused = _firstChild->_IsLeaf() && _firstChild->_lastFocused;
|
||||
const bool secondIsFocused = _secondChild->_IsLeaf() && _secondChild->_lastFocused;
|
||||
if (firstIsFocused || secondIsFocused)
|
||||
{
|
||||
return _NavigateFocus(direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If neither of our children were the focused leaf, then recurse into
|
||||
// our children and see if they can handle the focus move.
|
||||
// For each child, if it has a focused descendant, try having that child
|
||||
// handle the focus move.
|
||||
// If the child wasn't able to handle the focus move, it's possible that
|
||||
// there were no descendants with a separator the correct direction. If
|
||||
// our separator _is_ the correct direction, then we should be the pane
|
||||
// to move focus into our other child. Otherwise, just return false, as
|
||||
// we couldn't handle it either.
|
||||
if ((!_firstChild->_IsLeaf()) && _firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->NavigateFocus(direction) || _NavigateFocus(direction);
|
||||
}
|
||||
else if ((!_secondChild->_IsLeaf()) && _secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->NavigateFocus(direction) || _NavigateFocus(direction);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our attached control is closed. Triggers listeners to our close
|
||||
// event, if we're a leaf pane.
|
||||
@@ -308,18 +68,6 @@ void Pane::_ControlClosedHandler()
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Fire our Closed event to tell our parent that we should be removed.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::Close()
|
||||
{
|
||||
// Fire our Closed event to tell our parent that we should be removed.
|
||||
_closedHandlers();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the root UIElement of this pane. There may be a single TermControl as a
|
||||
// child, or an entire tree of grids and panes as children of this element.
|
||||
@@ -426,7 +174,7 @@ bool Pane::_HasFocusedChild() const noexcept
|
||||
// We're intentionally making this one giant expression, so the compiler
|
||||
// will skip the following lookups if one of the lookups before it returns
|
||||
// true
|
||||
return (_control && _control.FocusState() != FocusState::Unfocused) ||
|
||||
return (_control && _control.GetControl().FocusState() != FocusState::Unfocused) ||
|
||||
(_firstChild && _firstChild->_HasFocusedChild()) ||
|
||||
(_secondChild && _secondChild->_HasFocusedChild());
|
||||
}
|
||||
@@ -445,7 +193,7 @@ void Pane::UpdateFocus()
|
||||
if (_IsLeaf())
|
||||
{
|
||||
const auto controlFocused = _control &&
|
||||
_control.FocusState() != FocusState::Unfocused;
|
||||
_control.GetControl().FocusState() != FocusState::Unfocused;
|
||||
|
||||
_lastFocused = controlFocused;
|
||||
}
|
||||
@@ -468,7 +216,7 @@ void Pane::_FocusFirstChild()
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
_control.Focus(FocusState::Programmatic);
|
||||
_control.GetControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -564,11 +312,11 @@ void Pane::_CloseChild(const bool closeFirst)
|
||||
_separatorRoot = { nullptr };
|
||||
|
||||
// Reattach the TermControl to our grid.
|
||||
_root.Children().Append(_control);
|
||||
_root.Children().Append(_control.GetControl());
|
||||
|
||||
if (_lastFocused)
|
||||
{
|
||||
_control.Focus(FocusState::Programmatic);
|
||||
_control.GetControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
|
||||
_splitState = SplitState::None;
|
||||
@@ -667,61 +415,6 @@ void Pane::_SetupChildCloseHandlers()
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets up row/column definitions for this pane. There are three total
|
||||
// row/cols. The middle one is for the separator. The first and third are for
|
||||
// each of the child panes, and are given a size in pixels, based off the
|
||||
// availiable space, and the percent of the space they respectively consume,
|
||||
// which is stored in _firstPercent and _secondPercent.
|
||||
// - Does nothing if our split state is currently set to SplitState::None
|
||||
// Arguments:
|
||||
// - rootSize: The dimensions in pixels that this pane (and its children should consume.)
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::_CreateRowColDefinitions(const Size& rootSize)
|
||||
{
|
||||
if (_splitState == SplitState::Vertical)
|
||||
{
|
||||
_root.ColumnDefinitions().Clear();
|
||||
|
||||
// Create three columns in this grid: one for each pane, and one for the separator.
|
||||
auto separatorColDef = Controls::ColumnDefinition();
|
||||
separatorColDef.Width(GridLengthHelper::Auto());
|
||||
|
||||
const auto paneSizes = _GetPaneSizes(rootSize.Width);
|
||||
|
||||
auto firstColDef = Controls::ColumnDefinition();
|
||||
firstColDef.Width(GridLengthHelper::FromPixels(paneSizes.first));
|
||||
|
||||
auto secondColDef = Controls::ColumnDefinition();
|
||||
secondColDef.Width(GridLengthHelper::FromPixels(paneSizes.second));
|
||||
|
||||
_root.ColumnDefinitions().Append(firstColDef);
|
||||
_root.ColumnDefinitions().Append(separatorColDef);
|
||||
_root.ColumnDefinitions().Append(secondColDef);
|
||||
}
|
||||
else if (_splitState == SplitState::Horizontal)
|
||||
{
|
||||
_root.RowDefinitions().Clear();
|
||||
|
||||
// Create three rows in this grid: one for each pane, and one for the separator.
|
||||
auto separatorRowDef = Controls::RowDefinition();
|
||||
separatorRowDef.Height(GridLengthHelper::Auto());
|
||||
|
||||
const auto paneSizes = _GetPaneSizes(rootSize.Height);
|
||||
|
||||
auto firstRowDef = Controls::RowDefinition();
|
||||
firstRowDef.Height(GridLengthHelper::FromPixels(paneSizes.first));
|
||||
|
||||
auto secondRowDef = Controls::RowDefinition();
|
||||
secondRowDef.Height(GridLengthHelper::FromPixels(paneSizes.second));
|
||||
|
||||
_root.RowDefinitions().Append(firstRowDef);
|
||||
_root.RowDefinitions().Append(separatorRowDef);
|
||||
_root.RowDefinitions().Append(secondRowDef);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Initializes our UI for a new split in this pane. Sets up row/column
|
||||
// definitions, and initializes the separator grid. Does nothing if our split
|
||||
@@ -732,13 +425,16 @@ void Pane::_CreateRowColDefinitions(const Size& rootSize)
|
||||
// - <none>
|
||||
void Pane::_CreateSplitContent()
|
||||
{
|
||||
Size actualSize{ gsl::narrow_cast<float>(_root.ActualWidth()),
|
||||
gsl::narrow_cast<float>(_root.ActualHeight()) };
|
||||
|
||||
_CreateRowColDefinitions(actualSize);
|
||||
|
||||
if (_splitState == SplitState::Vertical)
|
||||
{
|
||||
// Create three columns in this grid: one for each pane, and one for the separator.
|
||||
auto separatorColDef = Controls::ColumnDefinition();
|
||||
separatorColDef.Width(GridLengthHelper::Auto());
|
||||
|
||||
_root.ColumnDefinitions().Append(Controls::ColumnDefinition{});
|
||||
_root.ColumnDefinitions().Append(separatorColDef);
|
||||
_root.ColumnDefinitions().Append(Controls::ColumnDefinition{});
|
||||
|
||||
// Create the pane separator
|
||||
_separatorRoot = Controls::Grid{};
|
||||
_separatorRoot.Width(PaneSeparatorSize);
|
||||
@@ -747,6 +443,14 @@ void Pane::_CreateSplitContent()
|
||||
}
|
||||
else if (_splitState == SplitState::Horizontal)
|
||||
{
|
||||
// Create three rows in this grid: one for each pane, and one for the separator.
|
||||
auto separatorRowDef = Controls::RowDefinition();
|
||||
separatorRowDef.Height(GridLengthHelper::Auto());
|
||||
|
||||
_root.RowDefinitions().Append(Controls::RowDefinition{});
|
||||
_root.RowDefinitions().Append(separatorRowDef);
|
||||
_root.RowDefinitions().Append(Controls::RowDefinition{});
|
||||
|
||||
// Create the pane separator
|
||||
_separatorRoot = Controls::Grid{};
|
||||
_separatorRoot.Height(PaneSeparatorSize);
|
||||
@@ -803,7 +507,7 @@ void Pane::SplitVertical(const GUID& profile, const TermControl& control)
|
||||
return;
|
||||
}
|
||||
|
||||
_Split(SplitState::Vertical, profile, control);
|
||||
_DoSplit(SplitState::Vertical, profile, control);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -831,7 +535,7 @@ void Pane::SplitHorizontal(const GUID& profile, const TermControl& control)
|
||||
return;
|
||||
}
|
||||
|
||||
_Split(SplitState::Horizontal, profile, control);
|
||||
_DoSplit(SplitState::Horizontal, profile, control);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -843,7 +547,7 @@ void Pane::SplitHorizontal(const GUID& profile, const TermControl& control)
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::_Split(SplitState splitType, const GUID& profile, const TermControl& control)
|
||||
void Pane::_DoSplit(SplitState splitType, const GUID& profile, const TermControl& control)
|
||||
{
|
||||
// Lock the create/close lock so that another operation won't concurrently
|
||||
// modify our tree
|
||||
@@ -855,9 +559,6 @@ void Pane::_Split(SplitState splitType, const GUID& profile, const TermControl&
|
||||
|
||||
_splitState = splitType;
|
||||
|
||||
_firstPercent = { Half };
|
||||
_secondPercent = { Half };
|
||||
|
||||
_CreateSplitContent();
|
||||
|
||||
// Remove any children we currently have. We can't add the existing
|
||||
@@ -884,52 +585,4 @@ void Pane::_Split(SplitState splitType, const GUID& profile, const TermControl&
|
||||
_lastFocused = false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the size in pixels of each of our children, given the full size they
|
||||
// should fill. Accounts for the size of the separator that should be between
|
||||
// them as well.
|
||||
// Arguments:
|
||||
// - fullSize: the amount of space in pixels that should be filled by our
|
||||
// children and their separator
|
||||
// Return Value:
|
||||
// - a pair with the size of our first child and the size of our second child,
|
||||
// respectively.
|
||||
std::pair<float, float> Pane::_GetPaneSizes(const float& fullSize)
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
THROW_HR(E_FAIL);
|
||||
}
|
||||
|
||||
const auto sizeMinusSeparator = fullSize - PaneSeparatorSize;
|
||||
const auto firstSize = sizeMinusSeparator * _firstPercent.value();
|
||||
const auto secondSize = sizeMinusSeparator * _secondPercent.value();
|
||||
return { firstSize, secondSize };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the absolute minimum size that this pane can be resized to and still
|
||||
// have 1x1 character visible, in each of its children. This includes the
|
||||
// space needed for the separator.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The minimum size that this pane can be resized to and still have a visible
|
||||
// character.
|
||||
Size Pane::_GetMinSize() const
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return _control.MinimumSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto firstSize = _firstChild->_GetMinSize();
|
||||
const auto secondSize = _secondChild->_GetMinSize();
|
||||
const auto newWidth = firstSize.Width + secondSize.Width + (_splitState == SplitState::Vertical ? PaneSeparatorSize : 0);
|
||||
const auto newHeight = firstSize.Height + secondSize.Height + (_splitState == SplitState::Horizontal ? PaneSeparatorSize : 0);
|
||||
return { newWidth, newHeight };
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_EVENT(Pane, Closed, _closedHandlers, ConnectionClosedEventArgs);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#pragma once
|
||||
#include <winrt/Microsoft.Terminal.TerminalControl.h>
|
||||
#include <winrt/TerminalApp.h>
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
class Pane : public std::enable_shared_from_this<Pane>
|
||||
@@ -45,15 +44,10 @@ public:
|
||||
void UpdateFocus();
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
bool ResizePane(const winrt::TerminalApp::Direction& direction);
|
||||
bool NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void SplitHorizontal(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
void SplitVertical(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
|
||||
void Close();
|
||||
|
||||
DECLARE_EVENT(Closed, _closedHandlers, winrt::Microsoft::Terminal::TerminalControl::ConnectionClosedEventArgs);
|
||||
|
||||
private:
|
||||
@@ -64,8 +58,6 @@ private:
|
||||
std::shared_ptr<Pane> _firstChild{ nullptr };
|
||||
std::shared_ptr<Pane> _secondChild{ nullptr };
|
||||
SplitState _splitState{ SplitState::None };
|
||||
std::optional<float> _firstPercent{ std::nullopt };
|
||||
std::optional<float> _secondPercent{ std::nullopt };
|
||||
|
||||
bool _lastFocused{ false };
|
||||
std::optional<GUID> _profile{ std::nullopt };
|
||||
@@ -79,54 +71,12 @@ private:
|
||||
bool _HasFocusedChild() const noexcept;
|
||||
void _SetupChildCloseHandlers();
|
||||
|
||||
void _Split(SplitState splitType, const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
void _CreateRowColDefinitions(const winrt::Windows::Foundation::Size& rootSize);
|
||||
void _DoSplit(SplitState splitType, const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
void _CreateSplitContent();
|
||||
void _ApplySplitDefinitions();
|
||||
|
||||
bool _Resize(const winrt::TerminalApp::Direction& direction);
|
||||
bool _NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void _CloseChild(const bool closeFirst);
|
||||
|
||||
void _FocusFirstChild();
|
||||
void _ControlClosedHandler();
|
||||
|
||||
std::pair<float, float> _GetPaneSizes(const float& fullSize);
|
||||
|
||||
winrt::Windows::Foundation::Size _GetMinSize() const;
|
||||
|
||||
// Function Description:
|
||||
// - Returns true if the given direction can be used with the given split
|
||||
// type.
|
||||
// - This is used for pane resizing (which will need a pane separator
|
||||
// that's perpendicular to the direction to be able to move the separator
|
||||
// in that direction).
|
||||
// - Additionally, it will be used for moving focus between panes, which
|
||||
// again happens _across_ a separator.
|
||||
// Arguments:
|
||||
// - direction: The Direction to compare
|
||||
// - splitType: The SplitState to compare
|
||||
// Return Value:
|
||||
// - true iff the direction is perpendicular to the splitType. False for
|
||||
// SplitState::None.
|
||||
static constexpr bool DirectionMatchesSplit(const winrt::TerminalApp::Direction& direction,
|
||||
const SplitState& splitType)
|
||||
{
|
||||
if (splitType == SplitState::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (splitType == SplitState::Horizontal)
|
||||
{
|
||||
return direction == winrt::TerminalApp::Direction::Up ||
|
||||
direction == winrt::TerminalApp::Direction::Down;
|
||||
}
|
||||
else if (splitType == SplitState::Vertical)
|
||||
{
|
||||
return direction == winrt::TerminalApp::Direction::Left ||
|
||||
direction == winrt::TerminalApp::Direction::Right;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
using namespace TerminalApp;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
using namespace winrt::TerminalApp;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
static constexpr std::string_view NameKey{ "name" };
|
||||
@@ -19,14 +21,12 @@ static constexpr std::string_view ColorSchemeKeyOld{ "colorscheme" };
|
||||
static constexpr std::string_view ForegroundKey{ "foreground" };
|
||||
static constexpr std::string_view BackgroundKey{ "background" };
|
||||
static constexpr std::string_view ColorTableKey{ "colorTable" };
|
||||
static constexpr std::string_view TabTitleKey{ "tabTitle" };
|
||||
static constexpr std::string_view HistorySizeKey{ "historySize" };
|
||||
static constexpr std::string_view SnapOnInputKey{ "snapOnInput" };
|
||||
static constexpr std::string_view CursorColorKey{ "cursorColor" };
|
||||
static constexpr std::string_view CursorShapeKey{ "cursorShape" };
|
||||
static constexpr std::string_view CursorHeightKey{ "cursorHeight" };
|
||||
|
||||
static constexpr std::string_view ConnectionTypeKey{ "connectionType" };
|
||||
static constexpr std::string_view CommandlineKey{ "commandline" };
|
||||
static constexpr std::string_view FontFaceKey{ "fontFace" };
|
||||
static constexpr std::string_view FontSizeKey{ "fontSize" };
|
||||
@@ -39,8 +39,7 @@ static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
|
||||
static constexpr std::string_view IconKey{ "icon" };
|
||||
static constexpr std::string_view BackgroundImageKey{ "backgroundImage" };
|
||||
static constexpr std::string_view BackgroundImageOpacityKey{ "backgroundImageOpacity" };
|
||||
static constexpr std::string_view BackgroundImageStretchModeKey{ "backgroundImageStretchMode" };
|
||||
static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageAlignment" };
|
||||
static constexpr std::string_view BackgroundimageStretchModeKey{ "backgroundImageStretchMode" };
|
||||
|
||||
// Possible values for Scrollbar state
|
||||
static constexpr std::wstring_view AlwaysVisible{ L"visible" };
|
||||
@@ -59,17 +58,6 @@ static constexpr std::string_view ImageStretchModeFill{ "fill" };
|
||||
static constexpr std::string_view ImageStretchModeUniform{ "uniform" };
|
||||
static constexpr std::string_view ImageStretchModeUniformTofill{ "uniformToFill" };
|
||||
|
||||
// Possible values for Image Alignment
|
||||
static constexpr std::string_view ImageAlignmentCenter{ "center" };
|
||||
static constexpr std::string_view ImageAlignmentLeft{ "left" };
|
||||
static constexpr std::string_view ImageAlignmentTop{ "top" };
|
||||
static constexpr std::string_view ImageAlignmentRight{ "right" };
|
||||
static constexpr std::string_view ImageAlignmentBottom{ "bottom" };
|
||||
static constexpr std::string_view ImageAlignmentTopLeft{ "topLeft" };
|
||||
static constexpr std::string_view ImageAlignmentTopRight{ "topRight" };
|
||||
static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" };
|
||||
static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" };
|
||||
|
||||
Profile::Profile() :
|
||||
Profile(Utils::CreateGuid())
|
||||
{
|
||||
@@ -83,14 +71,12 @@ Profile::Profile(const winrt::guid& guid) :
|
||||
_defaultForeground{},
|
||||
_defaultBackground{},
|
||||
_colorTable{},
|
||||
_tabTitle{},
|
||||
_historySize{ DEFAULT_HISTORY_SIZE },
|
||||
_snapOnInput{ true },
|
||||
_cursorColor{ DEFAULT_CURSOR_COLOR },
|
||||
_cursorShape{ CursorStyle::Bar },
|
||||
_cursorHeight{ DEFAULT_CURSOR_HEIGHT },
|
||||
|
||||
_connectionType{},
|
||||
_commandline{ L"cmd.exe" },
|
||||
_startingDirectory{},
|
||||
_fontFace{ DEFAULT_FONT_FACE },
|
||||
@@ -103,8 +89,7 @@ Profile::Profile(const winrt::guid& guid) :
|
||||
_icon{},
|
||||
_backgroundImage{},
|
||||
_backgroundImageOpacity{},
|
||||
_backgroundImageStretchMode{},
|
||||
_backgroundImageAlignment{}
|
||||
_backgroundImageStretchMode{}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -215,14 +200,6 @@ TerminalSettings Profile::CreateTerminalSettings(const std::vector<ColorScheme>&
|
||||
terminalSettings.BackgroundImageStretchMode(_backgroundImageStretchMode.value());
|
||||
}
|
||||
|
||||
if (_backgroundImageAlignment)
|
||||
{
|
||||
const auto imageHorizontalAlignment = std::get<winrt::Windows::UI::Xaml::HorizontalAlignment>(_backgroundImageAlignment.value());
|
||||
const auto imageVerticalAlignment = std::get<winrt::Windows::UI::Xaml::VerticalAlignment>(_backgroundImageAlignment.value());
|
||||
terminalSettings.BackgroundImageHorizontalAlignment(imageHorizontalAlignment);
|
||||
terminalSettings.BackgroundImageVerticalAlignment(imageVerticalAlignment);
|
||||
}
|
||||
|
||||
return terminalSettings;
|
||||
}
|
||||
|
||||
@@ -282,10 +259,6 @@ Json::Value Profile::ToJson() const
|
||||
root[JsonKey(CloseOnExitKey)] = _closeOnExit;
|
||||
root[JsonKey(PaddingKey)] = winrt::to_string(_padding);
|
||||
|
||||
if (_connectionType)
|
||||
{
|
||||
root[JsonKey(ConnectionTypeKey)] = winrt::to_string(Utils::GuidToString(_connectionType.value()));
|
||||
}
|
||||
if (_scrollbarState)
|
||||
{
|
||||
const auto scrollbarState = winrt::to_string(_scrollbarState.value());
|
||||
@@ -298,11 +271,6 @@ Json::Value Profile::ToJson() const
|
||||
root[JsonKey(IconKey)] = icon;
|
||||
}
|
||||
|
||||
if (_tabTitle)
|
||||
{
|
||||
root[JsonKey(TabTitleKey)] = winrt::to_string(_tabTitle.value());
|
||||
}
|
||||
|
||||
if (_startingDirectory)
|
||||
{
|
||||
root[JsonKey(StartingDirectoryKey)] = winrt::to_string(_startingDirectory.value());
|
||||
@@ -320,12 +288,7 @@ Json::Value Profile::ToJson() const
|
||||
|
||||
if (_backgroundImageStretchMode)
|
||||
{
|
||||
root[JsonKey(BackgroundImageStretchModeKey)] = SerializeImageStretchMode(_backgroundImageStretchMode.value()).data();
|
||||
}
|
||||
|
||||
if (_backgroundImageAlignment)
|
||||
{
|
||||
root[JsonKey(BackgroundImageAlignmentKey)] = SerializeImageAlignment(_backgroundImageAlignment.value()).data();
|
||||
root[JsonKey(BackgroundimageStretchModeKey)] = SerializeImageStretchMode(_backgroundImageStretchMode.value()).data();
|
||||
}
|
||||
|
||||
return root;
|
||||
@@ -350,17 +313,6 @@ Profile Profile::FromJson(const Json::Value& json)
|
||||
{
|
||||
result._guid = Utils::GuidFromString(GetWstringFromJson(guid));
|
||||
}
|
||||
else
|
||||
{
|
||||
result._guid = Utils::CreateGuid();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"SynthesizedGuidForProfile",
|
||||
TraceLoggingDescription("Event emitted when a profile is deserialized without a GUID"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
|
||||
// Core Settings
|
||||
if (auto foreground{ json[JsonKey(ForegroundKey)] })
|
||||
@@ -417,16 +369,8 @@ Profile Profile::FromJson(const Json::Value& json)
|
||||
{
|
||||
result._cursorShape = _ParseCursorShape(GetWstringFromJson(cursorShape));
|
||||
}
|
||||
if (auto tabTitle{ json[JsonKey(TabTitleKey)] })
|
||||
{
|
||||
result._tabTitle = GetWstringFromJson(tabTitle);
|
||||
}
|
||||
|
||||
// Control Settings
|
||||
if (auto connectionType{ json[JsonKey(ConnectionTypeKey)] })
|
||||
{
|
||||
result._connectionType = Utils::GuidFromString(GetWstringFromJson(connectionType));
|
||||
}
|
||||
if (auto commandline{ json[JsonKey(CommandlineKey)] })
|
||||
{
|
||||
result._commandline = GetWstringFromJson(commandline);
|
||||
@@ -475,14 +419,10 @@ Profile Profile::FromJson(const Json::Value& json)
|
||||
{
|
||||
result._backgroundImageOpacity = backgroundImageOpacity.asFloat();
|
||||
}
|
||||
if (auto backgroundImageStretchMode{ json[JsonKey(BackgroundImageStretchModeKey)] })
|
||||
if (auto backgroundImageStretchMode{ json[JsonKey(BackgroundimageStretchModeKey)] })
|
||||
{
|
||||
result._backgroundImageStretchMode = ParseImageStretchMode(backgroundImageStretchMode.asString());
|
||||
}
|
||||
if (auto backgroundImageAlignment{ json[JsonKey(BackgroundImageAlignmentKey)] })
|
||||
{
|
||||
result._backgroundImageAlignment = ParseImageAlignment(backgroundImageAlignment.asString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -532,28 +472,9 @@ void Profile::SetDefaultBackground(COLORREF defaultBackground) noexcept
|
||||
_defaultBackground = defaultBackground;
|
||||
}
|
||||
|
||||
void Profile::SetCloseOnExit(bool defaultClose) noexcept
|
||||
{
|
||||
_closeOnExit = defaultClose;
|
||||
}
|
||||
|
||||
void Profile::SetConnectionType(GUID connectionType) noexcept
|
||||
{
|
||||
_connectionType = connectionType;
|
||||
}
|
||||
|
||||
bool Profile::HasIcon() const noexcept
|
||||
{
|
||||
return _icon.has_value() && !_icon.value().empty();
|
||||
}
|
||||
|
||||
// Method Description
|
||||
// - Sets this profile's tab title.
|
||||
// Arguments:
|
||||
// - tabTitle: the tab title
|
||||
void Profile::SetTabTitle(std::wstring tabTitle) noexcept
|
||||
{
|
||||
_tabTitle = tabTitle;
|
||||
return _icon.has_value();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -587,38 +508,6 @@ std::wstring_view Profile::GetName() const noexcept
|
||||
return _name;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if profile's custom tab title is set, if one is set. Otherwise returns false.
|
||||
// Return Value:
|
||||
// - true if this profile's custom tab title is set. Otherwise returns false.
|
||||
bool Profile::HasTabTitle() const noexcept
|
||||
{
|
||||
return _tabTitle.has_value();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the custom tab title, if one is set. Otherwise returns the empty string.
|
||||
// Return Value:
|
||||
// - this profile's custom tab title, if one is set. Otherwise returns the empty string.
|
||||
std::wstring_view Profile::GetTabTitle() const noexcept
|
||||
{
|
||||
return HasTabTitle() ?
|
||||
std::wstring_view{ _tabTitle.value().c_str(), _tabTitle.value().size() } :
|
||||
std::wstring_view{ L"", 0 };
|
||||
}
|
||||
|
||||
bool Profile::HasConnectionType() const noexcept
|
||||
{
|
||||
return _connectionType.has_value();
|
||||
}
|
||||
|
||||
GUID Profile::GetConnectionType() const noexcept
|
||||
{
|
||||
return HasConnectionType() ?
|
||||
_connectionType.value() :
|
||||
_GUID{};
|
||||
}
|
||||
|
||||
bool Profile::GetCloseOnExit() const noexcept
|
||||
{
|
||||
return _closeOnExit;
|
||||
@@ -727,114 +616,6 @@ std::string_view Profile::SerializeImageStretchMode(const winrt::Windows::UI::Xa
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting a user-specified image horizontal and vertical
|
||||
// alignment to the appropriate enum values tuple
|
||||
// Arguments:
|
||||
// - The value from the profiles.json file
|
||||
// Return Value:
|
||||
// - The corresponding enum values tuple which maps to the string provided by the user
|
||||
std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> Profile::ParseImageAlignment(const std::string_view imageAlignment)
|
||||
{
|
||||
if (imageAlignment == ImageAlignmentTopLeft)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Left,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Top);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentBottomLeft)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Left,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Bottom);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentLeft)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Left,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Center);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentTopRight)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Right,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Top);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentBottomRight)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Right,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Bottom);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentRight)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Right,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Center);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentTop)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Center,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Top);
|
||||
}
|
||||
else if (imageAlignment == ImageAlignmentBottom)
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Center,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Bottom);
|
||||
}
|
||||
else // Fall through to default alignment
|
||||
{
|
||||
return std::make_tuple(winrt::Windows::UI::Xaml::HorizontalAlignment::Center,
|
||||
winrt::Windows::UI::Xaml::VerticalAlignment::Center);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting the HorizontalAlignment+VerticalAlignment tuple
|
||||
// to the correct string value.
|
||||
// Arguments:
|
||||
// - imageAlignment: The enum values tuple to convert to a string.
|
||||
// Return Value:
|
||||
// - The string value for the given ImageAlignment
|
||||
std::string_view Profile::SerializeImageAlignment(const std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> imageAlignment)
|
||||
{
|
||||
const auto imageHorizontalAlignment = std::get<winrt::Windows::UI::Xaml::HorizontalAlignment>(imageAlignment);
|
||||
const auto imageVerticalAlignment = std::get<winrt::Windows::UI::Xaml::VerticalAlignment>(imageAlignment);
|
||||
switch (imageHorizontalAlignment)
|
||||
{
|
||||
case winrt::Windows::UI::Xaml::HorizontalAlignment::Left:
|
||||
switch (imageVerticalAlignment)
|
||||
{
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Top:
|
||||
return ImageAlignmentTopLeft;
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Bottom:
|
||||
return ImageAlignmentBottomLeft;
|
||||
default:
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Center:
|
||||
return ImageAlignmentLeft;
|
||||
}
|
||||
|
||||
case winrt::Windows::UI::Xaml::HorizontalAlignment::Right:
|
||||
switch (imageVerticalAlignment)
|
||||
{
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Top:
|
||||
return ImageAlignmentTopRight;
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Bottom:
|
||||
return ImageAlignmentBottomRight;
|
||||
default:
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Center:
|
||||
return ImageAlignmentRight;
|
||||
}
|
||||
|
||||
default:
|
||||
case winrt::Windows::UI::Xaml::HorizontalAlignment::Center:
|
||||
switch (imageVerticalAlignment)
|
||||
{
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Top:
|
||||
return ImageAlignmentTop;
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Bottom:
|
||||
return ImageAlignmentBottom;
|
||||
default:
|
||||
case winrt::Windows::UI::Xaml::VerticalAlignment::Center:
|
||||
return ImageAlignmentCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper function for converting a user-specified cursor style corresponding
|
||||
// CursorStyle enum value
|
||||
|
||||
@@ -36,14 +36,9 @@ public:
|
||||
|
||||
GUID GetGuid() const noexcept;
|
||||
std::wstring_view GetName() const noexcept;
|
||||
bool HasTabTitle() const noexcept;
|
||||
std::wstring_view GetTabTitle() const noexcept;
|
||||
bool HasConnectionType() const noexcept;
|
||||
GUID GetConnectionType() const noexcept;
|
||||
|
||||
void SetFontFace(std::wstring fontFace) noexcept;
|
||||
void SetColorScheme(std::optional<std::wstring> schemeName) noexcept;
|
||||
void SetTabTitle(std::wstring tabTitle) noexcept;
|
||||
void SetAcrylicOpacity(double opacity) noexcept;
|
||||
void SetCommandline(std::wstring cmdline) noexcept;
|
||||
void SetStartingDirectory(std::wstring startingDirectory) noexcept;
|
||||
@@ -51,8 +46,6 @@ public:
|
||||
void SetUseAcrylic(bool useAcrylic) noexcept;
|
||||
void SetDefaultForeground(COLORREF defaultForeground) noexcept;
|
||||
void SetDefaultBackground(COLORREF defaultBackground) noexcept;
|
||||
void SetCloseOnExit(bool defaultClose) noexcept;
|
||||
void SetConnectionType(GUID connectionType) noexcept;
|
||||
|
||||
bool HasIcon() const noexcept;
|
||||
std::wstring_view GetIconPath() const noexcept;
|
||||
@@ -66,14 +59,11 @@ private:
|
||||
static winrt::Microsoft::Terminal::Settings::ScrollbarState ParseScrollbarState(const std::wstring& scrollbarState);
|
||||
static winrt::Windows::UI::Xaml::Media::Stretch ParseImageStretchMode(const std::string_view imageStretchMode);
|
||||
static std::string_view SerializeImageStretchMode(const winrt::Windows::UI::Xaml::Media::Stretch imageStretchMode);
|
||||
static std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> ParseImageAlignment(const std::string_view imageAlignment);
|
||||
static std::string_view SerializeImageAlignment(const std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment> imageAlignment);
|
||||
static winrt::Microsoft::Terminal::Settings::CursorStyle _ParseCursorShape(const std::wstring& cursorShapeString);
|
||||
static std::wstring_view _SerializeCursorStyle(const winrt::Microsoft::Terminal::Settings::CursorStyle cursorShape);
|
||||
|
||||
GUID _guid;
|
||||
std::wstring _name;
|
||||
std::optional<GUID> _connectionType;
|
||||
|
||||
// If this is set, then our colors should come from the associated color scheme
|
||||
std::optional<std::wstring> _schemeName;
|
||||
@@ -81,7 +71,6 @@ private:
|
||||
std::optional<uint32_t> _defaultForeground;
|
||||
std::optional<uint32_t> _defaultBackground;
|
||||
std::array<uint32_t, COLOR_TABLE_SIZE> _colorTable;
|
||||
std::optional<std::wstring> _tabTitle;
|
||||
int32_t _historySize;
|
||||
bool _snapOnInput;
|
||||
uint32_t _cursorColor;
|
||||
@@ -98,7 +87,6 @@ private:
|
||||
std::optional<std::wstring> _backgroundImage;
|
||||
std::optional<double> _backgroundImageOpacity;
|
||||
std::optional<winrt::Windows::UI::Xaml::Media::Stretch> _backgroundImageStretchMode;
|
||||
std::optional<std::tuple<winrt::Windows::UI::Xaml::HorizontalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment>> _backgroundImageAlignment;
|
||||
|
||||
std::optional<std::wstring> _scrollbarState;
|
||||
bool _closeOnExit;
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="InitialJsonParseErrorText" xml:space="preserve">
|
||||
<value>Settings could not be loaded from file - temporarily using the default settings. Check for syntax errors, including trailing commas.</value>
|
||||
</data>
|
||||
<data name="InitialJsonParseErrorTitle" xml:space="preserve">
|
||||
<value>Failed to load settings</value>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
</data>
|
||||
<data name="ReloadJsonParseErrorText" xml:space="preserve">
|
||||
<value>Settings could not be reloaded from file. Check for syntax errors, including trailing commas.</value>
|
||||
</data>
|
||||
<data name="ReloadJsonParseErrorTitle" xml:space="preserve">
|
||||
<value>Failed to reload settings</value>
|
||||
</data>
|
||||
<data name="AboutTitleText" xml:space="preserve">
|
||||
<value>About</value>
|
||||
</data>
|
||||
<data name="VersionLabelText" xml:space="preserve">
|
||||
<value>Version:</value>
|
||||
</data>
|
||||
<data name="DocumentationLabelText" xml:space="preserve">
|
||||
<value>Documentation
|
||||
</value>
|
||||
</data>
|
||||
<data name="GettingStartedLabelText" xml:space="preserve">
|
||||
<value>Getting Started
|
||||
</value>
|
||||
</data>
|
||||
<data name="ReleaseNotesLabelText" xml:space="preserve">
|
||||
<value>Release Notes
|
||||
</value>
|
||||
</data>
|
||||
<data name="DocumentationUriValue" xml:space="preserve">
|
||||
<value>https://aka.ms/terminal-documentation</value>
|
||||
</data>
|
||||
<data name="GettingStartedUriValue" xml:space="preserve">
|
||||
<value>https://aka.ms/terminal-getting-started</value>
|
||||
</data>
|
||||
<data name="ReleaseNotesUriValue" xml:space="preserve">
|
||||
<value>https://aka.ms/terminal-release-notes</value>
|
||||
</data>
|
||||
<data name="FeedbackUriValue" xml:space="preserve">
|
||||
<value>https://aka.ms/terminal-feedback</value>
|
||||
</data>
|
||||
<data name="AboutMenuItem" xml:space="preserve">
|
||||
<value>About</value>
|
||||
</data>
|
||||
<data name="FeedbackMenuItem" xml:space="preserve">
|
||||
<value>Feedback</value>
|
||||
</data>
|
||||
<data name="SettingsMenuItem" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "ScopedResourceLoader.h"
|
||||
|
||||
using namespace ::winrt::Windows::ApplicationModel::Resources::Core;
|
||||
|
||||
ScopedResourceLoader::ScopedResourceLoader(const std::wstring_view resourceLocatorBase) :
|
||||
_resourceMap{ ResourceManager::Current().MainResourceMap().GetSubtree(resourceLocatorBase) },
|
||||
_resourceContext{ ResourceContext::GetForViewIndependentUse() }
|
||||
{
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the resource map associated with the scoped resource subcompartment.
|
||||
// Return Value:
|
||||
// - the resource map associated with the scoped resource subcompartment.
|
||||
ResourceMap ScopedResourceLoader::GetResourceMap()
|
||||
{
|
||||
return _resourceMap;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Loads the localized string resource with the given key from the scoped
|
||||
// resource subcompartment.
|
||||
// - This resource loader is view-independent; it cannot take into account scale
|
||||
// factors and view themes. Strings should not vary based on those things.
|
||||
// Arguments:
|
||||
// - resourceName: the key up by which to look the resource
|
||||
// Return Value:
|
||||
// - The final localized string for the given key.
|
||||
winrt::hstring ScopedResourceLoader::GetLocalizedString(const std::wstring_view resourceName)
|
||||
{
|
||||
return _resourceMap.GetValue(resourceName, _resourceContext).ValueAsString();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
class ScopedResourceLoader
|
||||
{
|
||||
public:
|
||||
ScopedResourceLoader(const std::wstring_view resourceLocatorBase);
|
||||
winrt::Windows::ApplicationModel::Resources::Core::ResourceMap GetResourceMap();
|
||||
winrt::hstring GetLocalizedString(const std::wstring_view resourceName);
|
||||
|
||||
private:
|
||||
winrt::Windows::ApplicationModel::Resources::Core::ResourceMap _resourceMap;
|
||||
winrt::Windows::ApplicationModel::Resources::Core::ResourceContext _resourceContext;
|
||||
};
|
||||
@@ -124,7 +124,7 @@ void Tab::_Focus()
|
||||
auto lastFocusedControl = _rootPane->GetFocusedTerminalControl();
|
||||
if (lastFocusedControl)
|
||||
{
|
||||
lastFocusedControl.Focus(FocusState::Programmatic);
|
||||
lastFocusedControl.GetControl().Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ void Tab::SetTabText(const winrt::hstring& text)
|
||||
// Copy the hstring, so we don't capture a dead reference
|
||||
winrt::hstring textCopy{ text };
|
||||
_tabViewItem.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [text = std::move(textCopy), this]() {
|
||||
_tabViewItem.Header(winrt::box_value(text));
|
||||
_tabViewItem.Header(text);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ void Tab::SetTabText(const winrt::hstring& text)
|
||||
void Tab::Scroll(const int delta)
|
||||
{
|
||||
auto control = GetFocusedTerminalControl();
|
||||
control.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [control, delta]() {
|
||||
control.GetControl().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [control, delta]() {
|
||||
const auto currentOffset = control.GetScrollOffset();
|
||||
control.KeyboardScrollViewport(currentOffset + delta);
|
||||
});
|
||||
@@ -213,54 +213,4 @@ void Tab::AddHorizontalSplit(const GUID& profile, TermControl& control)
|
||||
_rootPane->SplitHorizontal(profile, control);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update the size of our panes to fill the new given size. This happens when
|
||||
// the window is resized.
|
||||
// Arguments:
|
||||
// - newSize: the amount of space that the panes have to fill now.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::ResizeContent(const winrt::Windows::Foundation::Size& newSize)
|
||||
{
|
||||
_rootPane->ResizeContent(newSize);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move a separator between panes, as to resize each child on
|
||||
// either size of the separator. See Pane::ResizePane for details.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the separator in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::ResizePane(const winrt::TerminalApp::Direction& direction)
|
||||
{
|
||||
_rootPane->ResizePane(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempt to move focus between panes, as to focus the child on
|
||||
// the other side of the separator. See Pane::NavigateFocus for details.
|
||||
// Arguments:
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::NavigateFocus(const winrt::TerminalApp::Direction& direction)
|
||||
{
|
||||
_rootPane->NavigateFocus(direction);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Closes the currently focused pane in this tab. If it's the last pane in
|
||||
// this tab, our Closed event will be fired (at a later time) for anyone
|
||||
// registered as a handler of our close event.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Tab::ClosePane()
|
||||
{
|
||||
auto focused = _rootPane->GetFocusedPane();
|
||||
focused->Close();
|
||||
}
|
||||
|
||||
DEFINE_EVENT(Tab, Closed, _closedHandlers, ConnectionClosedEventArgs);
|
||||
|
||||
@@ -23,16 +23,11 @@ public:
|
||||
void AddHorizontalSplit(const GUID& profile, winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
|
||||
void UpdateFocus();
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void ResizePane(const winrt::TerminalApp::Direction& direction);
|
||||
void NavigateFocus(const winrt::TerminalApp::Direction& direction);
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
|
||||
winrt::hstring GetFocusedTitle() const;
|
||||
void SetTabText(const winrt::hstring& text);
|
||||
|
||||
void ClosePane();
|
||||
|
||||
DECLARE_EVENT(Closed, _closedHandlers, winrt::Microsoft::Terminal::TerminalControl::ConnectionClosedEventArgs);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "TabRowControl.h"
|
||||
|
||||
#include "TabRowControl.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TabRowControl::TabRowControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Bound in the Xaml editor to the [+] button.
|
||||
// Arguments:
|
||||
// <unused>
|
||||
void TabRowControl::OnNewTabButtonClick(IInspectable const&, Controls::SplitButtonClickEventArgs const&)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Microsoft.UI.Xaml.Controls.h"
|
||||
|
||||
#include "TabRowControl.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TabRowControl : TabRowControlT<TabRowControl>
|
||||
{
|
||||
TabRowControl();
|
||||
|
||||
void OnNewTabButtonClick(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SplitButtonClickEventArgs const& args);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct TabRowControl : TabRowControlT<TabRowControl, implementation::TabRowControl>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TabRowControl : Windows.UI.Xaml.Controls.Grid
|
||||
{
|
||||
TabRowControl();
|
||||
Windows.UI.Xaml.Controls.SplitButton NewTabButton { get; };
|
||||
Microsoft.UI.Xaml.Controls.TabView TabView { get; };
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Grid
|
||||
x:Class="TerminalApp.TabRowControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<mux:TabView x:Name="TabView" VerticalAlignment="Bottom">
|
||||
|
||||
<mux:TabView.RightCustomContent>
|
||||
<SplitButton
|
||||
x:Name="NewTabButton"
|
||||
Click="OnNewTabButtonClick"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Left">
|
||||
<Viewbox MaxHeight="13"
|
||||
MaxWidth="13">
|
||||
<SymbolIcon Symbol="Add" />
|
||||
</Viewbox>
|
||||
</SplitButton>
|
||||
</mux:TabView.RightCustomContent>
|
||||
|
||||
</mux:TabView>
|
||||
|
||||
</Grid>
|
||||
@@ -1,8 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- cppwinrt.build.pre.props depends on these settings: -->
|
||||
<!-- build a dll, not exe (Application) -->
|
||||
@@ -17,39 +15,90 @@
|
||||
<ProjectName>TerminalApp</ProjectName>
|
||||
<RootNamespace>TerminalApp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- DON'T PUT XAML FILES HERE! Put them in TerminalAppLib.vcxproj -->
|
||||
<!-- HERE BE DRAGONS:
|
||||
For any types that use XAML information, if their .idl, .cpp, and .h
|
||||
aren't all marked DependentUpon the corresponding .xaml file,
|
||||
XamlTypeInfo.g.h won't pick it up correctly.
|
||||
-->
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
</ItemGroup>
|
||||
<!-- When we add other user controls, they should go in here as so: -->
|
||||
<!-- <ItemGroup>
|
||||
<Page Include="MyUserControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup> -->
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- Only put headers for winrt types in here. Don't put other header files
|
||||
in here - put them in TerminalAppLib.vcxproj instead! -->
|
||||
<ClInclude Include="Tab.h" />
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="ColorScheme.h" />
|
||||
<ClInclude Include="GlobalAppSettings.h" />
|
||||
<ClInclude Include="Profile.h" />
|
||||
<ClInclude Include="CascadiaSettings.h" />
|
||||
<ClInclude Include="AppKeyBindingsSerialization.h" />
|
||||
<ClInclude Include="KeyChordSerialization.h" />
|
||||
<ClInclude Include="Utils.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="TerminalPage.h" />
|
||||
<ClInclude Include="MinMaxCloseControl.h" />
|
||||
<ClInclude Include="AppKeyBindings.h" />
|
||||
<ClInclude Include="TitlebarControl.h" />
|
||||
<ClInclude Include="TabRowControl.h" />
|
||||
<ClInclude Include="App.h" />
|
||||
<ClInclude Include="AppKeyBindings.h">
|
||||
<DependentUpon>AppKeyBindings.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="App.h">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- Don't put source files in here - put them in TerminalAppLib.vcxproj instead! -->
|
||||
<ClCompile Include="Tab.cpp" />
|
||||
<ClCompile Include="Pane.cpp" />
|
||||
<ClCompile Include="ColorScheme.cpp" />
|
||||
<ClCompile Include="GlobalAppSettings.cpp" />
|
||||
<ClCompile Include="Profile.cpp" />
|
||||
<ClCompile Include="CascadiaSettings.cpp" />
|
||||
<ClCompile Include="CascadiaSettingsSerialization.cpp" />
|
||||
<ClCompile Include="AppKeyBindingsSerialization.cpp" />
|
||||
<ClCompile Include="KeyChordSerialization.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AppKeyBindings.cpp">
|
||||
<DependentUpon>AppKeyBindings.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="App.cpp">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
|
||||
<!-- You _NEED_ to include this file and the jsoncpp IncludePath (below) if
|
||||
you want to use jsoncpp -->
|
||||
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- DON'T PUT IDL FILES HERE! Put them in TerminalApp.vcxproj -->
|
||||
<Midl Include="App.idl">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Midl>
|
||||
<Midl Include="AppKeyBindings.idl" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="TerminalApp.def" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<!--
|
||||
@@ -60,31 +109,18 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\TerminalControl.vcxproj">
|
||||
<Project>{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
<!-- The midl compiler however, _will_ aggregate our winmd dependencies
|
||||
somehow. So make sure to only include top-level dependencies here (don't
|
||||
include Settings and Connection, since Control will include them for us) -->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettings\TerminalSettings.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\TerminalControl.vcxproj" />
|
||||
|
||||
<!-- Reference TerminalAppLib here, so we can use it's TerminalApp.winmd as
|
||||
our TerminalApp.winmd. This didn't work correctly in VS2017, you'd need to
|
||||
manually reference the lib -->
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalApp\lib\TerminalAppLib.vcxproj" >
|
||||
<!-- This is needed to be able to reference the XamlApplication type. -->
|
||||
<ProjectReference Include="..\Microsoft.UI.Xaml.Markup\Microsoft.UI.Xaml.Markup.vcxproj">
|
||||
<Project>{015a0047-772d-4f1a-88c9-45c18f0adfb6}</Project>
|
||||
<Private>true</Private>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
</ProjectReference>
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- A small helper for paths to the compiled cppwinrt projects -->
|
||||
<_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\</_BinRoot>
|
||||
<_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\</_BinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
DON'T REDIRECT OUR OUTPUT.
|
||||
@@ -97,44 +133,18 @@
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>User32.lib;WindowsApp.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
|
||||
<!-- TerminalAppLib contains a DllMain that we need to force the use of. -->
|
||||
<AdditionalOptions Condition="'$(Platform)'=='Win32'">/INCLUDE:_DllMain@12</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Platform)'!='Win32'">/INCLUDE:DllMain</AdditionalOptions>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<!--
|
||||
This is a terrible, terrible rule. There exists a bug in Visual Studio 2019 16.2 and 16.3 previews
|
||||
where ResolveAssemblyReferences will try and fail to parse a .lib when it produces a .winmd.
|
||||
To fix that, we have to _temporarily_ replace the %(Implementation) on any winmd-producing
|
||||
static library references with the empty string so as to make ResolveAssemblyReferences
|
||||
not try to read it.
|
||||
|
||||
Upstream problem report:
|
||||
https://developercommunity.visualstudio.com/content/problem/629524/static-library-reference-causes-there-was-a-proble.html
|
||||
-->
|
||||
<Target Name="_RemoveTerminalAppLibImplementationFromReference" BeforeTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_TerminalAppLibProjectReference Include="@(_ResolvedProjectReferencePaths)" Condition="'%(Filename)' == 'TerminalApp'" />
|
||||
<_ResolvedProjectReferencePaths Remove="@(_TerminalAppLibProjectReference)" />
|
||||
<_ResolvedProjectReferencePaths Include="@(_TerminalAppLibProjectReference)">
|
||||
<Implementation />
|
||||
</_ResolvedProjectReferencePaths>
|
||||
</ItemGroup>
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\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.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.1.190405001-prerelease\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_RestoreTerminalAppLibImplementationFromReference" AfterTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_ResolvedProjectReferencePaths Remove="@(_TerminalAppLibProjectReference)" />
|
||||
<_ResolvedProjectReferencePaths Include="@(_TerminalAppLibProjectReference)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<!-- End "terrible, terrible rule" -->
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "TerminalPage.h"
|
||||
|
||||
#include "TerminalPage.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TerminalPage::TerminalPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Microsoft.UI.Xaml.Controls.h"
|
||||
|
||||
#include "TerminalPage.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TerminalPage : TerminalPageT<TerminalPage>
|
||||
{
|
||||
TerminalPage();
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct TerminalPage : TerminalPageT<TerminalPage, implementation::TerminalPage>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TerminalPage : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
TerminalPage();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Page
|
||||
x:Class="TerminalApp.TerminalPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="Root" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<local:TabRowControl x:Name="TabRow" Grid.Row="0" />
|
||||
|
||||
<Grid x:Name="TabContent" Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,95 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// TitlebarControl.xaml.cpp
|
||||
// Implementation of the TitlebarControl class
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "TitlebarControl.h"
|
||||
|
||||
#include "TitlebarControl.g.cpp"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TitlebarControl::TitlebarControl(uint64_t handle) :
|
||||
_window{ reinterpret_cast<HWND>(handle) }
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// Register our event handlers on the MMC buttons.
|
||||
MinMaxCloseControl().MinimizeClick({ this, &TitlebarControl::Minimize_Click });
|
||||
MinMaxCloseControl().MaximizeClick({ this, &TitlebarControl::Maximize_Click });
|
||||
MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click });
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::UIElement TitlebarControl::Content()
|
||||
{
|
||||
return ContentRoot().Children().Size() > 0 ? ContentRoot().Children().GetAt(0) : nullptr;
|
||||
}
|
||||
|
||||
void TitlebarControl::Content(Windows::UI::Xaml::UIElement content)
|
||||
{
|
||||
ContentRoot().Children().Clear();
|
||||
ContentRoot().Children().Append(content);
|
||||
}
|
||||
|
||||
void TitlebarControl::Root_SizeChanged(const IInspectable& sender,
|
||||
const Windows::UI::Xaml::SizeChangedEventArgs& e)
|
||||
{
|
||||
const auto windowWidth = ActualWidth();
|
||||
const auto minMaxCloseWidth = MinMaxCloseControl().ActualWidth();
|
||||
const auto dragBarMinWidth = DragBar().MinWidth();
|
||||
const auto maxWidth = windowWidth - minMaxCloseWidth - dragBarMinWidth;
|
||||
// Only set our MaxWidth if it's greater than 0. Setting it to a
|
||||
// negative value will cause a crash.
|
||||
if (maxWidth >= 0)
|
||||
{
|
||||
ContentRoot().MaxWidth(maxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void TitlebarControl::_OnMaximizeOrRestore(byte flag)
|
||||
{
|
||||
POINT point1 = {};
|
||||
::GetCursorPos(&point1);
|
||||
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
|
||||
WINDOWPLACEMENT placement = { sizeof(placement) };
|
||||
::GetWindowPlacement(_window, &placement);
|
||||
if (placement.showCmd == SW_SHOWNORMAL)
|
||||
{
|
||||
MinMaxCloseControl().Maximize();
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
|
||||
}
|
||||
else if (placement.showCmd == SW_SHOWMAXIMIZED)
|
||||
{
|
||||
MinMaxCloseControl().RestoreDown();
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void TitlebarControl::Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximizeOrRestore(HTMAXBUTTON);
|
||||
}
|
||||
|
||||
void TitlebarControl::DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e)
|
||||
{
|
||||
_OnMaximizeOrRestore(HTCAPTION);
|
||||
}
|
||||
|
||||
void TitlebarControl::Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TitlebarControl::Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
|
||||
{
|
||||
::PostQuitMessage(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Declaration of the MainUserControl class.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "winrt/Windows.UI.Xaml.h"
|
||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
||||
#include "TitlebarControl.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TitlebarControl : TitlebarControlT<TitlebarControl>
|
||||
{
|
||||
TitlebarControl(uint64_t handle);
|
||||
|
||||
Windows::UI::Xaml::UIElement Content();
|
||||
void Content(Windows::UI::Xaml::UIElement content);
|
||||
|
||||
void Root_SizeChanged(const IInspectable& sender, Windows::UI::Xaml::SizeChangedEventArgs const& e);
|
||||
|
||||
void Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
void DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);
|
||||
|
||||
private:
|
||||
void _OnMaximizeOrRestore(byte flag);
|
||||
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
struct TitlebarControl : TitlebarControlT<TitlebarControl, implementation::TitlebarControl>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid
|
||||
{
|
||||
TitlebarControl(UInt64 parentWindowHandle);
|
||||
|
||||
Windows.UI.Xaml.UIElement Content;
|
||||
Windows.UI.Xaml.Controls.Border DragBar { get; };
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Grid
|
||||
x:Class="TerminalApp.TitlebarControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
x:Name="Root"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
SizeChanged="Root_SizeChanged"
|
||||
d:DesignHeight="36"
|
||||
Background="{ThemeResource SystemChromeLowColor}"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<!-- TODO:GH#1988
|
||||
This xaml should probably be a template thing, where the background is a
|
||||
resource that the app hosting this control can override. Then, it App.xaml,
|
||||
we'd make sure to set the resource for our background to the appropriate
|
||||
color. SystemControlForegroundAccentBrush also works nicely, to use the
|
||||
accent color. (which is GH#1963)-->
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid x:Name="ContentRoot" Grid.Column="0" />
|
||||
|
||||
<Border
|
||||
x:Name="DragBar"
|
||||
Grid.Column="1"
|
||||
MinWidth="45.0"
|
||||
DoubleTapped="DragBar_DoubleTapped"/>
|
||||
|
||||
<local:MinMaxCloseControl
|
||||
Grid.Column="2"
|
||||
x:Name="MinMaxCloseControl"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// Note: Generate GUID using TlgGuid.exe tool
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hTerminalAppProvider,
|
||||
"Microsoft.Windows.Terminal.App",
|
||||
// {24a1622f-7da7-5c77-3303-d850bd1ab2ed}
|
||||
(0x24a1622f, 0x7da7, 0x5c77, 0x33, 0x03, 0xd8, 0x50, 0xbd, 0x1a, 0xb2, 0xed),
|
||||
TraceLoggingOptionMicrosoftTelemetry());
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstDll);
|
||||
TraceLoggingRegister(g_hTerminalAppProvider);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (g_hTerminalAppProvider)
|
||||
{
|
||||
TraceLoggingUnregister(g_hTerminalAppProvider);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
|
||||
<!-- ========================= CppWinRT Metadata ======================== -->
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
<!--
|
||||
This is an override that, puzzlingly, _forces XBF (XAML binary) embedding_.
|
||||
We have to do this to overcome a layout issue in the WAP packaging project.
|
||||
When we do this, the XBF ends up in resources.pri.
|
||||
-->
|
||||
<DisableEmbeddedXbf>false</DisableEmbeddedXbf>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- HERE BE DRAGONS:
|
||||
For any types that use XAML information, if their .idl and .h aren't
|
||||
marked DependentUpon the corresponding .xaml file, XamlTypeInfo.g.h won't
|
||||
pick it up correctly. -->
|
||||
<ApplicationDefinition Include="..\App.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
</ItemGroup>
|
||||
<!-- When we add other user controls, they should go in here as so: -->
|
||||
<ItemGroup>
|
||||
<Page Include="../MinMaxCloseControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="../TerminalPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="../TitlebarControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="../TabRowControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="../App.base.h" />
|
||||
<ClInclude Include="../MinMaxCloseControl.h">
|
||||
<DependentUpon>../MinMaxCloseControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../TerminalPage.h">
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../TitlebarControl.h">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../TabRowControl.h">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="../Tab.h" />
|
||||
<ClInclude Include="../Pane.h" />
|
||||
<ClInclude Include="../ColorScheme.h" />
|
||||
<ClInclude Include="../GlobalAppSettings.h" />
|
||||
<ClInclude Include="../Profile.h" />
|
||||
<ClInclude Include="../CascadiaSettings.h" />
|
||||
<ClInclude Include="../AppKeyBindingsSerialization.h" />
|
||||
<ClInclude Include="../KeyChordSerialization.h" />
|
||||
<ClInclude Include="../Utils.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="../AppKeyBindings.h" />
|
||||
<ClInclude Include="../App.h" >
|
||||
<DependentUpon>../App.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="../init.cpp" />
|
||||
<ClCompile Include="../MinMaxCloseControl.cpp">
|
||||
<DependentUpon>../MinMaxCloseControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../TerminalPage.cpp">
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../TitlebarControl.cpp">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../TabRowControl.cpp">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../Tab.cpp" />
|
||||
<ClCompile Include="../Pane.cpp" />
|
||||
<ClCompile Include="../ColorScheme.cpp" />
|
||||
<ClCompile Include="../GlobalAppSettings.cpp" />
|
||||
<ClCompile Include="../Profile.cpp" />
|
||||
<ClCompile Include="../CascadiaSettings.cpp" />
|
||||
<ClCompile Include="../CascadiaSettingsSerialization.cpp" />
|
||||
<ClCompile Include="../AppKeyBindingsSerialization.cpp" />
|
||||
<ClCompile Include="../KeyChordSerialization.cpp" />
|
||||
<ClCompile Include="../Utils.cpp" />
|
||||
<ClCompile Include="../ScopedResourceLoader.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../AppKeyBindings.cpp" >
|
||||
<DependentUpon>../AppKeyBindings.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="../App.cpp" >
|
||||
<DependentUpon>../App.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
|
||||
<!-- You _NEED_ to include this file and the jsoncpp IncludePath (below) if
|
||||
you want to use jsoncpp -->
|
||||
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
<!-- If you add idl files here, make sure to include their implementation's
|
||||
header in TerminalApp.vcxproj (as well as in this file) -->
|
||||
<Midl Include="../App.idl" >
|
||||
<DependentUpon>../App.xaml</DependentUpon>
|
||||
</Midl>
|
||||
<Midl Include="../AppKeyBindings.idl" />
|
||||
<Midl Include="../MinMaxCloseControl.idl">
|
||||
<DependentUpon>../MinMaxCloseControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="../TerminalPage.idl">
|
||||
<DependentUpon>../TerminalPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="../TitlebarControl.idl">
|
||||
<DependentUpon>../TitlebarControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="../TabRowControl.idl">
|
||||
<DependentUpon>../TabRowControl.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
<PRIResource Include="../Resources/en-US/Resources.resw" />
|
||||
<None Include="../packages.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<!--
|
||||
the packaging project won't recurse through our dependencies, you have to
|
||||
make sure that if you add a cppwinrt dependency to any of these projects,
|
||||
you also update all the consumers
|
||||
-->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
|
||||
<!-- For whatever reason, we can't include the TerminalControl and
|
||||
TerminalSettings projects' winmds via project references. So we'll have to
|
||||
manually include the winmds as References below -->
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- A small helper for paths to the compiled cppwinrt projects -->
|
||||
<_BinRoot Condition="'$(Platform)' != 'Win32'">$(OpenConsoleDir)$(Platform)\$(Configuration)\</_BinRoot>
|
||||
<_BinRoot Condition="'$(Platform)' == 'Win32'">$(OpenConsoleDir)$(Configuration)\</_BinRoot>
|
||||
</PropertyGroup>
|
||||
|
||||
<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>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
private=false and CopyLocalSatelliteAssemblies=false, so that we don't
|
||||
propogate them upwards (which can make referencing this project result in
|
||||
duplicate type definitions)-->
|
||||
|
||||
<Reference Include="Microsoft.Terminal.Settings">
|
||||
<HintPath>$(_BinRoot)TerminalSettings\Microsoft.Terminal.Settings.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
|
||||
<Reference Include="Microsoft.Terminal.TerminalConnection">
|
||||
<HintPath>$(_BinRoot)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
|
||||
<Reference Include="Microsoft.Terminal.TerminalControl">
|
||||
<HintPath>$(_BinRoot)TerminalControl\Microsoft.Terminal.TerminalControl.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ====================== Compiler & Linker Flags ===================== -->
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..;$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<!-- Manually disable unreachable code warning, because jconcpp has a ton of that. -->
|
||||
<DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Globals ======================== -->
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CA5CAD1A-9A12-429C-B551-8562EC954746}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>TerminalApp</RootNamespace>
|
||||
<ProjectName>TerminalAppLib</ProjectName>
|
||||
<TargetName>TerminalAppLib</TargetName>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
DON'T REDIRECT OUR OUTPUT.
|
||||
Setting this will tell cppwinrt.build.post.props to copy our output from
|
||||
the default OutDir up one level, so the wapproj will be able to find it.
|
||||
-->
|
||||
<NoOutputRedirection>true</NoOutputRedirection>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<!-- Manually include MUX here, instead of importing its targets file. We need
|
||||
to reference its winmd, but very specifically with the
|
||||
CopyLocalSatelliteAssemblies and Private properties set to false, as to not
|
||||
have projects including us double-including MUX's .winmd. The following blob
|
||||
is taken straight from the MUX build targets, with the afformentioned
|
||||
changes.-->
|
||||
<PropertyGroup>
|
||||
<Native-Platform Condition="'$(Platform)' == 'Win32'">x86</Native-Platform>
|
||||
<Native-Platform Condition="'$(Platform)' != 'Win32'">$(Platform)</Native-Platform>
|
||||
<_MUXRoot>$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\</_MUXRoot>
|
||||
<_MUXAppRoot>$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\</_MUXAppRoot>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- Microsoft.UI.XAML -->
|
||||
<Reference Include="$(_MUXRoot)lib\uap10.0\Microsoft.UI.Xaml.winmd">
|
||||
<Implementation>Microsoft.UI.Xaml.dll</Implementation>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<Private>true</Private>
|
||||
</Reference>
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXRoot)runtimes\win10-$(Native-Platform)\native\Microsoft.UI.Xaml.dll" />
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXRoot)runtimes\win10-$(Native-Platform)\native\Microsoft.UI.Xaml.pri" />
|
||||
|
||||
<!-- Microsoft.UI.XAML.Application -->
|
||||
<Reference Include="$(_MUXAppRoot)lib\uap10.0\Microsoft.Toolkit.Win32.UI.XamlHost.winmd">
|
||||
<Implementation>Microsoft.Toolkit.Win32.UI.XamlHost.dll</Implementation>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
<Private>false</Private>
|
||||
</Reference>
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXAppRoot)lib\uap10.0\Microsoft.Toolkit.Win32.UI.XamlHost.*" />
|
||||
<ReferenceCopyLocalPaths Include="$(_MUXAppRoot)runtimes\win10-$(Native-Platform)\native\Microsoft.Toolkit.Win32.UI.XamlHost.*" />
|
||||
</ItemGroup>
|
||||
<!-- End MUX import -->
|
||||
|
||||
<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.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.2.190611001-prerelease\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0-preview6.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
||||
<!--
|
||||
By default, the PRI file will contain resource paths beginning with the
|
||||
project name. Since we enabled XBF embedding, this *also* includes App.xbf.
|
||||
Well, App.xbf is hardcoded by the framework to be found at the resource ROOT.
|
||||
To make that happen, we have to disable the prepending of the project name
|
||||
to the App xaml files.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<_GenerateProjectPriFileDependsOn>OpenConsolePlaceAppXbfAtRootOfResourceTree;$(_GenerateProjectPriFileDependsOn)</_GenerateProjectPriFileDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="OpenConsolePlaceAppXbfAtRootOfResourceTree" DependsOnTargets="GetPackagingOutputs">
|
||||
<ItemGroup>
|
||||
<_RelocatedAppXamlData Include="@(PackagingOutputs)" Condition="'%(Filename)' == 'App' and ('%(Extension)' == '.xaml' or '%(Extension)' == '.xbf')" />
|
||||
<PackagingOutputs Remove="@(_RelocatedAppXamlData)" />
|
||||
<PackagingOutputs Include="@(_RelocatedAppXamlData)">
|
||||
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
||||
</PackagingOutputs>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// pch.h
|
||||
// Header for platform projection include files
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
#include <hstring.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/windows.ui.core.h>
|
||||
#include <winrt/Windows.ui.input.h>
|
||||
#include <winrt/Windows.UI.Text.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Hosting.h>
|
||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
||||
#include "winrt/Windows.UI.Xaml.Documents.h"
|
||||
|
||||
#include <winrt/Microsoft.Toolkit.Win32.UI.XamlHost.h>
|
||||
|
||||
#include <windows.ui.xaml.media.dxinterop.h>
|
||||
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
// Including TraceLogging essentials for the binary
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <winmeta.h>
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
|
||||
#include <telemetry\ProjectTelemetry.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
|
||||
// JsonCpp
|
||||
#include <json.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <filesystem>
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.0.0-preview6.2" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.2.190611001-prerelease" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.190605.7" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.1.190405001-prerelease" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.190417.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -7,6 +7,47 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// This file can be empty - the pch.h in TerminalApp/lib does the heavy lifting
|
||||
// of including all the headers we need. As this project is just a dll wrapper,
|
||||
// we don't actually need anything in here.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
// SDK definition of this function, so the only fix is to undef it.
|
||||
// from WinBase.h
|
||||
// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
#include <hstring.h>
|
||||
|
||||
#include <winrt/coroutine.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.Resources.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/windows.ui.core.h>
|
||||
#include <winrt/Windows.ui.input.h>
|
||||
#include <winrt/Windows.UI.Text.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
|
||||
#include <windows.ui.xaml.media.dxinterop.h>
|
||||
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
// Including TraceLogging essentials for the binary
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <winmeta.h>
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hTerminalWin32Provider);
|
||||
#include <telemetry\ProjectTelemetry.h>
|
||||
#include <TraceLoggingActivity.h>
|
||||
|
||||
// JsonCpp
|
||||
#include <json.h>
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <filesystem>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cpprest/details/web_utilities.h>
|
||||
|
||||
const utility::string_t AzureClientID = U("0");
|
||||
@@ -1,889 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "AzureConnection.h"
|
||||
#include "AzureClientID.h"
|
||||
#include "AzureConnectionStrings.h"
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AzureConnection.g.cpp"
|
||||
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
using namespace utility;
|
||||
using namespace web;
|
||||
using namespace web::json;
|
||||
using namespace web::http;
|
||||
using namespace web::http::client;
|
||||
using namespace web::websockets::client;
|
||||
using namespace concurrency::streams;
|
||||
using namespace winrt::Windows::Security::Credentials;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
AzureConnection::AzureConnection(const uint32_t initialRows, const uint32_t initialCols) :
|
||||
_initialRows{ initialRows },
|
||||
_initialCols{ initialCols }
|
||||
{
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - registers an output event handler
|
||||
// Arguments:
|
||||
// - the handler
|
||||
// Return value:
|
||||
// - the event token for the handler
|
||||
winrt::event_token AzureConnection::TerminalOutput(Microsoft::Terminal::TerminalConnection::TerminalOutputEventArgs const& handler)
|
||||
{
|
||||
return _outputHandlers.add(handler);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - revokes an output event handler
|
||||
// Arguments:
|
||||
// - the event token for the handler
|
||||
void AzureConnection::TerminalOutput(winrt::event_token const& token) noexcept
|
||||
{
|
||||
_outputHandlers.remove(token);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - registers a terminal-disconnected event handler
|
||||
// Arguments:
|
||||
// - the handler
|
||||
// Return value:
|
||||
// - the event token for the handler
|
||||
winrt::event_token AzureConnection::TerminalDisconnected(Microsoft::Terminal::TerminalConnection::TerminalDisconnectedEventArgs const& handler)
|
||||
{
|
||||
return _disconnectHandlers.add(handler);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - revokes a terminal-disconnected event handler
|
||||
// Arguments:
|
||||
// - the event token for the handler
|
||||
void AzureConnection::TerminalDisconnected(winrt::event_token const& token) noexcept
|
||||
{
|
||||
_disconnectHandlers.remove(token);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - creates the output thread (where we will do the authentication and actually connect to Azure)
|
||||
void AzureConnection::Start()
|
||||
{
|
||||
// Create our own output handling thread
|
||||
// Each connection needs to make sure to drain the output from its backing host.
|
||||
_hOutputThread.reset(CreateThread(nullptr,
|
||||
0,
|
||||
StaticOutputThreadProc,
|
||||
this,
|
||||
0,
|
||||
nullptr));
|
||||
|
||||
THROW_LAST_ERROR_IF_NULL(_hOutputThread);
|
||||
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - handles the different possible inputs in the different states
|
||||
// Arguments:
|
||||
// the user's input
|
||||
void AzureConnection::WriteInput(hstring const& data)
|
||||
{
|
||||
if (!_connected || _closing.load())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the input differently depending on which state we're in
|
||||
switch (_state)
|
||||
{
|
||||
// The user has stored connection settings, let them choose one of them, create a new one or remove all stored ones
|
||||
case State::AccessStored:
|
||||
{
|
||||
const auto s = winrt::to_string(data);
|
||||
int storeNum = -1;
|
||||
try
|
||||
{
|
||||
storeNum = std::stoi(s);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (s != "n" && s != "r")
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(invalidAccessInput));
|
||||
return;
|
||||
}
|
||||
else if (s == "r")
|
||||
{
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_removeOrNew = true;
|
||||
_canProceed.notify_one();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_removeOrNew = false;
|
||||
_canProceed.notify_one();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (storeNum >= _maxStored)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(numOutOfBoundsError));
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_storedNumber = storeNum;
|
||||
_canProceed.notify_one();
|
||||
return;
|
||||
}
|
||||
// The user has multiple tenants in their Azure account, let them choose one of them
|
||||
case State::TenantChoice:
|
||||
{
|
||||
int tenantNum = -1;
|
||||
try
|
||||
{
|
||||
tenantNum = std::stoi(winrt::to_string(data));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(nonNumberError));
|
||||
return;
|
||||
}
|
||||
if (tenantNum >= _maxSize)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(numOutOfBoundsError));
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_tenantNumber = tenantNum;
|
||||
_canProceed.notify_one();
|
||||
return;
|
||||
}
|
||||
// User has the option to save their connection settings for future logins
|
||||
case State::StoreTokens:
|
||||
{
|
||||
std::string s = winrt::to_string(data);
|
||||
if (s != "y" && s != "n")
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(invalidStoreInput));
|
||||
}
|
||||
else if (s == "y")
|
||||
{
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_store = true;
|
||||
_canProceed.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lg{ _commonMutex };
|
||||
_store = false;
|
||||
_canProceed.notify_one();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// We are connected, send user's input over the websocket
|
||||
case State::TermConnected:
|
||||
{
|
||||
websocket_outgoing_message msg;
|
||||
const auto str = winrt::to_string(data);
|
||||
msg.set_utf8_message(str);
|
||||
|
||||
_cloudShellSocket.send(msg);
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - resizes the terminal
|
||||
// Arguments:
|
||||
// - the new rows/cols values
|
||||
void AzureConnection::Resize(uint32_t rows, uint32_t columns)
|
||||
{
|
||||
if (!_connected || !(_state == State::TermConnected))
|
||||
{
|
||||
_initialRows = rows;
|
||||
_initialCols = columns;
|
||||
}
|
||||
else if (!_closing.load())
|
||||
{
|
||||
// Initialize client
|
||||
http_client terminalClient(_cloudShellUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request terminalRequest(L"POST");
|
||||
terminalRequest.set_request_uri(L"terminals/" + _terminalID + L"/size?cols=" + std::to_wstring(columns) + L"&rows=" + std::to_wstring(rows) + L"&version=2019-01-01");
|
||||
_HeaderHelper(terminalRequest);
|
||||
terminalRequest.set_body(json::value(L""));
|
||||
|
||||
// Send the request
|
||||
_RequestHelper(terminalClient, terminalRequest);
|
||||
}
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - ascribes to the ITerminalConnection interface
|
||||
// - closes the websocket connection and the output thread
|
||||
void AzureConnection::Close()
|
||||
{
|
||||
if (!_connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_closing.exchange(true))
|
||||
{
|
||||
_canProceed.notify_all();
|
||||
if (_state == State::TermConnected)
|
||||
{
|
||||
// Close the websocket connection
|
||||
auto closedTask = _cloudShellSocket.close();
|
||||
closedTask.wait();
|
||||
}
|
||||
|
||||
// Tear down our output thread
|
||||
WaitForSingleObject(_hOutputThread.get(), INFINITE);
|
||||
_hOutputThread.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - this method bridges the thread to the Azure connection instance
|
||||
// Arguments:
|
||||
// - lpParameter: the Azure connection parameter
|
||||
// Return value:
|
||||
// - the exit code of the thread
|
||||
DWORD WINAPI AzureConnection::StaticOutputThreadProc(LPVOID lpParameter)
|
||||
{
|
||||
AzureConnection* const pInstance = (AzureConnection*)lpParameter;
|
||||
return pInstance->_OutputThread();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - this is the output thread, where we initiate the connection to Azure
|
||||
// and establish a websocket connection
|
||||
// Return value:
|
||||
// - return status
|
||||
DWORD AzureConnection::_OutputThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
// Initial state, check if the user has any stored connection settings and allow them to login with those
|
||||
// or allow them to login with a different account or allow them to remove the saved settings
|
||||
case State::AccessStored:
|
||||
{
|
||||
RETURN_IF_FAILED(_AccessHelper());
|
||||
break;
|
||||
}
|
||||
// User has no saved connection settings or has opted to login with a different account
|
||||
// Azure authentication happens here
|
||||
case State::DeviceFlow:
|
||||
{
|
||||
RETURN_IF_FAILED(_DeviceFlowHelper());
|
||||
break;
|
||||
}
|
||||
// User has multiple tenants in their Azure account, they need to choose which one to connect to
|
||||
case State::TenantChoice:
|
||||
{
|
||||
RETURN_IF_FAILED(_TenantChoiceHelper());
|
||||
break;
|
||||
}
|
||||
// Ask the user if they want to save these connection settings for future logins
|
||||
case State::StoreTokens:
|
||||
{
|
||||
RETURN_IF_FAILED(_StoreHelper());
|
||||
break;
|
||||
}
|
||||
// Connect to Azure, we only get here once we have everything we need (tenantID, accessToken, refreshToken)
|
||||
case State::TermConnecting:
|
||||
{
|
||||
RETURN_IF_FAILED(_ConnectHelper());
|
||||
break;
|
||||
}
|
||||
// We are connected, continuously read from the websocket until its closed
|
||||
case State::TermConnected:
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Read from websocket
|
||||
pplx::task<websocket_incoming_message> msgT;
|
||||
try
|
||||
{
|
||||
msgT = _cloudShellSocket.receive();
|
||||
msgT.wait();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Websocket has been closed
|
||||
if (!_closing.load())
|
||||
{
|
||||
_state = State::NoConnect;
|
||||
_disconnectHandlers();
|
||||
return S_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
auto msg = msgT.get();
|
||||
auto msgStringTask = msg.extract_string();
|
||||
auto msgString = msgStringTask.get();
|
||||
|
||||
// Convert to hstring
|
||||
const auto hstr = winrt::to_hstring(msgString);
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_outputHandlers(hstr);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
case State::NoConnect:
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(internetOrServerIssue));
|
||||
_disconnectHandlers();
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_state = State::NoConnect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to get the stored credentials (if any) and let the user choose what to do next
|
||||
// Return value:
|
||||
// - S_FALSE if there are no stored credentials
|
||||
// - S_OK if the user opts to login with a stored set of credentials or login with a different account
|
||||
// - E_FAIL if the user closes the tab
|
||||
HRESULT AzureConnection::_AccessHelper()
|
||||
{
|
||||
auto vault = PasswordVault();
|
||||
winrt::Windows::Foundation::Collections::IVectorView<PasswordCredential> credList;
|
||||
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
|
||||
try
|
||||
{
|
||||
credList = vault.FindAllByResource(resource);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// No credentials are stored, so start the device flow
|
||||
_state = State::DeviceFlow;
|
||||
return S_FALSE;
|
||||
}
|
||||
_maxStored = credList.Size();
|
||||
// Display the user's saved connection settings
|
||||
for (int i = 0; i < _maxStored; i++)
|
||||
{
|
||||
auto entry = credList.GetAt(i);
|
||||
auto nameJson = json::value::parse(entry.UserName().c_str());
|
||||
_outputHandlers(_StrFormatHelper(ithTenant, i, nameJson.at(L"displayName").as_string().c_str(), nameJson.at(L"tenantID").as_string().c_str()));
|
||||
}
|
||||
|
||||
_outputHandlers(winrt::to_hstring(enterTenant));
|
||||
_outputHandlers(winrt::to_hstring(newLogin));
|
||||
_outputHandlers(winrt::to_hstring(removeStored));
|
||||
|
||||
std::unique_lock<std::mutex> storedLock{ _commonMutex };
|
||||
_canProceed.wait(storedLock, [=]() {
|
||||
return (_storedNumber >= 0 && _storedNumber < _maxStored) || _removeOrNew.has_value() || _closing.load();
|
||||
});
|
||||
// User might have closed the tab while we waited for input
|
||||
if (_closing.load())
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
else if (_removeOrNew.has_value() && _removeOrNew.value())
|
||||
{
|
||||
// User wants to remove the stored settings
|
||||
_RemoveCredentials();
|
||||
_state = State::DeviceFlow;
|
||||
return S_OK;
|
||||
}
|
||||
else if (_removeOrNew.has_value() && !_removeOrNew.value())
|
||||
{
|
||||
// User wants to login with a different account
|
||||
_state = State::DeviceFlow;
|
||||
return S_OK;
|
||||
}
|
||||
// User wants to login with one of the saved connection settings
|
||||
auto desiredCredential = credList.GetAt(_storedNumber);
|
||||
desiredCredential.RetrievePassword();
|
||||
auto nameJson = json::value::parse(desiredCredential.UserName().c_str());
|
||||
auto passWordJson = json::value::parse(desiredCredential.Password().c_str());
|
||||
_displayName = nameJson.at(L"displayName").as_string();
|
||||
_tenantID = nameJson.at(L"tenantID").as_string();
|
||||
_accessToken = passWordJson.at(L"accessToken").as_string();
|
||||
_refreshToken = passWordJson.at(L"refreshToken").as_string();
|
||||
_expiry = std::stoi(passWordJson.at(L"expiry").as_string());
|
||||
|
||||
const auto t1 = std::chrono::system_clock::now();
|
||||
const auto timeNow = std::chrono::duration_cast<std::chrono::seconds>(t1.time_since_epoch()).count();
|
||||
|
||||
// Check if the token is close to expiring and refresh if so
|
||||
if (timeNow + _expireLimit > _expiry)
|
||||
{
|
||||
const auto refreshResponse = _RefreshTokens();
|
||||
_accessToken = refreshResponse.at(L"access_token").as_string();
|
||||
_refreshToken = refreshResponse.at(L"refresh_token").as_string();
|
||||
_expiry = std::stoi(refreshResponse.at(L"expires_on").as_string());
|
||||
// Store the updated tokens under the same username
|
||||
_StoreCredential();
|
||||
}
|
||||
|
||||
// We have everything we need, so go ahead and connect
|
||||
_state = State::TermConnecting;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to start the device code flow (required for authentication to Azure)
|
||||
// Return value:
|
||||
// - E_FAIL if the user closes the tab, does not authenticate in time or has no tenants in their Azure account
|
||||
// - S_OK otherwise
|
||||
HRESULT AzureConnection::_DeviceFlowHelper()
|
||||
{
|
||||
// Initiate device code flow
|
||||
const auto deviceCodeResponse = _GetDeviceCode();
|
||||
|
||||
// Print the message and store the device code, polling interval and expiry
|
||||
const auto message = deviceCodeResponse.at(L"message").as_string();
|
||||
_outputHandlers(message + codeExpiry);
|
||||
const auto devCode = deviceCodeResponse.at(L"device_code").as_string();
|
||||
const auto pollInterval = std::stoi(deviceCodeResponse.at(L"interval").as_string());
|
||||
const auto expiresIn = std::stoi(deviceCodeResponse.at(L"expires_in").as_string());
|
||||
|
||||
// Wait for user authentication and obtain the access/refresh tokens
|
||||
json::value authenticatedResponse;
|
||||
try
|
||||
{
|
||||
authenticatedResponse = _WaitForUser(devCode, pollInterval, expiresIn);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(exitStr));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
_accessToken = authenticatedResponse.at(L"access_token").as_string();
|
||||
_refreshToken = authenticatedResponse.at(L"refresh_token").as_string();
|
||||
|
||||
// Get the tenants and the required tenant id
|
||||
const auto tenantsResponse = _GetTenants();
|
||||
_tenantList = tenantsResponse.at(L"value");
|
||||
const auto tenantListAsArray = _tenantList.as_array();
|
||||
if (tenantListAsArray.size() == 0)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(noTenants));
|
||||
return E_FAIL;
|
||||
}
|
||||
else if (_tenantList.size() == 1)
|
||||
{
|
||||
_tenantID = tenantListAsArray.at(0).at(L"tenantId").as_string();
|
||||
_displayName = tenantListAsArray.at(0).at(L"displayName").as_string();
|
||||
|
||||
// We have to refresh now that we have the tenantID
|
||||
const auto refreshResponse = _RefreshTokens();
|
||||
_accessToken = refreshResponse.at(L"access_token").as_string();
|
||||
_refreshToken = refreshResponse.at(L"refresh_token").as_string();
|
||||
_expiry = std::stoi(refreshResponse.at(L"expires_on").as_string());
|
||||
|
||||
_state = State::StoreTokens;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = State::TenantChoice;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to list the user's tenants and let them decide which tenant they wish to connect to
|
||||
// Return value:
|
||||
// - E_FAIL if the user closes the tab
|
||||
// - S_OK otherwise
|
||||
HRESULT AzureConnection::_TenantChoiceHelper()
|
||||
{
|
||||
const auto tenantListAsArray = _tenantList.as_array();
|
||||
_maxSize = tenantListAsArray.size();
|
||||
for (int i = 0; i < _maxSize; i++)
|
||||
{
|
||||
_outputHandlers(_StrFormatHelper(ithTenant, i, tenantListAsArray.at(i).at(L"displayName").as_string().c_str(), tenantListAsArray.at(i).at(L"tenantId").as_string().c_str()));
|
||||
}
|
||||
_outputHandlers(winrt::to_hstring(enterTenant));
|
||||
// Use a lock to wait for the user to input a valid number
|
||||
std::unique_lock<std::mutex> tenantNumberLock{ _commonMutex };
|
||||
_canProceed.wait(tenantNumberLock, [=]() {
|
||||
return (_tenantNumber >= 0 && _tenantNumber < _maxSize) || _closing.load();
|
||||
});
|
||||
// User might have closed the tab while we waited for input
|
||||
if (_closing.load())
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
_tenantID = tenantListAsArray.at(_tenantNumber).at(L"tenantId").as_string();
|
||||
_displayName = tenantListAsArray.at(_tenantNumber).at(L"displayName").as_string();
|
||||
|
||||
// We have to refresh now that we have the tenantID
|
||||
const auto refreshResponse = _RefreshTokens();
|
||||
_accessToken = refreshResponse.at(L"access_token").as_string();
|
||||
_refreshToken = refreshResponse.at(L"refresh_token").as_string();
|
||||
_expiry = std::stoi(refreshResponse.at(L"expires_on").as_string());
|
||||
|
||||
_state = State::StoreTokens;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to ask the user if they wish to store their credentials
|
||||
// Return value:
|
||||
// - E_FAIL if the user closes the tab
|
||||
// - S_OK otherwise
|
||||
HRESULT AzureConnection::_StoreHelper()
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(storePrompt));
|
||||
// Wait for user input
|
||||
std::unique_lock<std::mutex> storeLock{ _commonMutex };
|
||||
_canProceed.wait(storeLock, [=]() {
|
||||
return _store.has_value() || _closing.load();
|
||||
});
|
||||
// User might have closed the tab while we waited for input
|
||||
if (_closing.load())
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (_store.value())
|
||||
{
|
||||
// User has opted to store the connection settings
|
||||
_StoreCredential();
|
||||
_outputHandlers(winrt::to_hstring(tokensStored));
|
||||
}
|
||||
|
||||
_state = State::TermConnecting;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to connect the user to the Azure cloud shell
|
||||
// Return value:
|
||||
// - E_FAIL if the user has not set up their cloud shell yet
|
||||
// - S_OK after successful connection
|
||||
HRESULT AzureConnection::_ConnectHelper()
|
||||
{
|
||||
// Get user's cloud shell settings
|
||||
const auto settingsResponse = _GetCloudShellUserSettings();
|
||||
if (settingsResponse.has_field(L"error"))
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(noCloudAccount));
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Request for a cloud shell
|
||||
_outputHandlers(winrt::to_hstring(requestingCloud));
|
||||
_cloudShellUri = _GetCloudShell();
|
||||
_outputHandlers(winrt::to_hstring(success));
|
||||
|
||||
// Request for a terminal for said cloud shell
|
||||
// We only support bash for now, so don't bother with the user's preferred shell
|
||||
// fyi: we can't call powershell yet because it sends VT sequences we don't support yet
|
||||
// TODO: GitHub #1883
|
||||
//const auto shellType = settingsResponse.at(L"properties").at(L"preferredShellType").as_string();
|
||||
const auto shellType = L"bash";
|
||||
_outputHandlers(winrt::to_hstring(requestingTerminal));
|
||||
const auto socketUri = _GetTerminal(shellType);
|
||||
_outputHandlers(winrt::to_hstring("\r\n"));
|
||||
|
||||
// Step 8: connecting to said terminal
|
||||
const auto connReqTask = _cloudShellSocket.connect(socketUri);
|
||||
connReqTask.wait();
|
||||
|
||||
_state = State::TermConnected;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to send requests and extract responses as json values
|
||||
// Arguments:
|
||||
// - a http_client
|
||||
// - a http_request for the client to send
|
||||
// Return value:
|
||||
// - the response from the server as a json value
|
||||
json::value AzureConnection::_RequestHelper(http_client theClient, http_request theRequest)
|
||||
{
|
||||
json::value jsonResult;
|
||||
try
|
||||
{
|
||||
const auto responseTask = theClient.request(theRequest);
|
||||
responseTask.wait();
|
||||
const auto response = responseTask.get();
|
||||
const auto responseJsonTask = response.extract_json();
|
||||
responseJsonTask.wait();
|
||||
jsonResult = responseJsonTask.get();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(internetOrServerIssue));
|
||||
}
|
||||
return jsonResult;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to start the device code flow
|
||||
// Return value:
|
||||
// - the response to the device code flow initiation
|
||||
json::value AzureConnection::_GetDeviceCode()
|
||||
{
|
||||
// Initialize the client
|
||||
http_client loginClient(_loginUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request commonRequest(L"POST");
|
||||
commonRequest.set_request_uri(L"common/oauth2/devicecode");
|
||||
const auto body = L"client_id=" + AzureClientID + L"&resource=" + _wantedResource;
|
||||
commonRequest.set_body(body, L"application/x-www-form-urlencoded");
|
||||
|
||||
// Send the request and receive the response as a json value
|
||||
return _RequestHelper(loginClient, commonRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to wait for the user to authenticate using their web browser
|
||||
// Arguments:
|
||||
// - the device code that would have been received when authentication was initiated
|
||||
// - the polling interval duration
|
||||
// - the duration the code is still valid for
|
||||
// Return value:
|
||||
// - if authentication is done successfully, then return the response from the server
|
||||
// - else, throw an exception
|
||||
json::value AzureConnection::_WaitForUser(const utility::string_t deviceCode, int pollInterval, int expiresIn)
|
||||
{
|
||||
// Initialize the client
|
||||
http_client pollingClient(_loginUri);
|
||||
|
||||
// Continuously send a poll request until the user authenticates
|
||||
const auto body = L"grant_type=device_code&resource=" + _wantedResource + L"&client_id=" + AzureClientID + L"&code=" + deviceCode;
|
||||
const auto requestUri = L"common/oauth2/token";
|
||||
json::value responseJson;
|
||||
for (int count = 0; count < expiresIn / pollInterval; count++)
|
||||
{
|
||||
// User might close the tab while we wait for them to authenticate, this case handles that
|
||||
if (_closing.load())
|
||||
{
|
||||
throw "Tab closed.";
|
||||
}
|
||||
http_request pollRequest(L"POST");
|
||||
pollRequest.set_request_uri(requestUri);
|
||||
pollRequest.set_body(body, L"application/x-www-form-urlencoded");
|
||||
|
||||
responseJson = _RequestHelper(pollingClient, pollRequest);
|
||||
|
||||
if (responseJson.has_field(L"error"))
|
||||
{
|
||||
Sleep(pollInterval * 1000); // Sleep takes arguments in milliseconds
|
||||
continue; // Still waiting for authentication
|
||||
}
|
||||
else
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring("Authenticated.\r\n"));
|
||||
break; // Authentication is done, break from loop
|
||||
}
|
||||
}
|
||||
if (responseJson.has_field(L"error"))
|
||||
{
|
||||
throw "Time out.";
|
||||
}
|
||||
return responseJson;
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to acquire the user's Azure tenants
|
||||
// Return value:
|
||||
// - the response which contains a list of the user's Azure tenants
|
||||
json::value AzureConnection::_GetTenants()
|
||||
{
|
||||
// Initialize the client
|
||||
http_client tenantClient(_resourceUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request tenantRequest(L"GET");
|
||||
tenantRequest.set_request_uri(L"tenants?api-version=2018-01-01");
|
||||
_HeaderHelper(tenantRequest);
|
||||
|
||||
// Send the request and return the response as a json value
|
||||
return _RequestHelper(tenantClient, tenantRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to refresh the access/refresh tokens
|
||||
// Return value:
|
||||
// - the response with the new tokens
|
||||
json::value AzureConnection::_RefreshTokens()
|
||||
{
|
||||
// Initialize the client
|
||||
http_client refreshClient(_loginUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request refreshRequest(L"POST");
|
||||
refreshRequest.set_request_uri(_tenantID + L"/oauth2/token");
|
||||
const auto body = L"client_id=" + AzureClientID + L"&resource=" + _wantedResource + L"&grant_type=refresh_token" + L"&refresh_token=" + _refreshToken;
|
||||
refreshRequest.set_body(body, L"application/x-www-form-urlencoded");
|
||||
refreshRequest.headers().add(L"User-Agent", userAgent);
|
||||
|
||||
// Send the request and return the response as a json value
|
||||
return _RequestHelper(refreshClient, refreshRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to get the user's cloud shell settings
|
||||
// Return value:
|
||||
// - the user's cloud shell settings
|
||||
json::value AzureConnection::_GetCloudShellUserSettings()
|
||||
{
|
||||
// Initialize client
|
||||
http_client settingsClient(_resourceUri);
|
||||
|
||||
// Initialize request
|
||||
http_request settingsRequest(L"GET");
|
||||
settingsRequest.set_request_uri(L"providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2018-10-01");
|
||||
_HeaderHelper(settingsRequest);
|
||||
|
||||
return _RequestHelper(settingsClient, settingsRequest);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to request for a cloud shell
|
||||
// Return value:
|
||||
// - the uri for the cloud shell
|
||||
utility::string_t AzureConnection::_GetCloudShell()
|
||||
{
|
||||
// Initialize client
|
||||
http_client cloudShellClient(_resourceUri);
|
||||
|
||||
// Initialize request
|
||||
http_request shellRequest(L"PUT");
|
||||
shellRequest.set_request_uri(L"providers/Microsoft.Portal/consoles/default?api-version=2018-10-01");
|
||||
_HeaderHelper(shellRequest);
|
||||
const auto innerBody = json::value::parse(U("{ \"osType\" : \"linux\" }"));
|
||||
json::value body;
|
||||
body[U("properties")] = innerBody;
|
||||
shellRequest.set_body(body);
|
||||
|
||||
// Send the request and get the response as a json value
|
||||
const auto cloudShell = _RequestHelper(cloudShellClient, shellRequest);
|
||||
|
||||
// Return the uri
|
||||
return cloudShell.at(L"properties").at(L"uri").as_string() + L"/";
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to request for a terminal
|
||||
// Return value:
|
||||
// - the uri for the terminal
|
||||
utility::string_t AzureConnection::_GetTerminal(utility::string_t shellType)
|
||||
{
|
||||
// Initialize client
|
||||
http_client terminalClient(_cloudShellUri);
|
||||
|
||||
// Initialize the request
|
||||
http_request terminalRequest(L"POST");
|
||||
terminalRequest.set_request_uri(L"terminals?cols=" + std::to_wstring(_initialCols) + L"&rows=" + std::to_wstring(_initialRows) + L"&version=2019-01-01&shell=" + shellType);
|
||||
_HeaderHelper(terminalRequest);
|
||||
|
||||
// Send the request and get the response as a json value
|
||||
const auto terminalResponse = _RequestHelper(terminalClient, terminalRequest);
|
||||
_terminalID = terminalResponse.at(L"id").as_string();
|
||||
|
||||
// Return the uri
|
||||
return terminalResponse.at(L"socketUri").as_string();
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to set the headers of a http_request
|
||||
// Arguments:
|
||||
// - the http_request
|
||||
void AzureConnection::_HeaderHelper(http_request theRequest)
|
||||
{
|
||||
theRequest.headers().add(L"Accept", L"application/json");
|
||||
theRequest.headers().add(L"Content-Type", L"application/json");
|
||||
theRequest.headers().add(L"Authorization", L"Bearer " + _accessToken);
|
||||
theRequest.headers().add(L"User-Agent", userAgent);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to store the credentials
|
||||
// - we store the display name, tenant ID, access/refresh tokens, and token expiry
|
||||
void AzureConnection::_StoreCredential()
|
||||
{
|
||||
auto vault = PasswordVault();
|
||||
json::value userName;
|
||||
userName[U("displayName")] = json::value::string(_displayName);
|
||||
userName[U("tenantID")] = json::value::string(_tenantID);
|
||||
json::value passWord;
|
||||
passWord[U("accessToken")] = json::value::string(_accessToken);
|
||||
passWord[U("refreshToken")] = json::value::string(_refreshToken);
|
||||
passWord[U("expiry")] = json::value::string(std::to_wstring(_expiry));
|
||||
auto newCredential = PasswordCredential(resource, userName.serialize(), passWord.serialize());
|
||||
vault.Add(newCredential);
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - helper function to remove all stored credentials
|
||||
void AzureConnection::_RemoveCredentials()
|
||||
{
|
||||
auto vault = PasswordVault();
|
||||
winrt::Windows::Foundation::Collections::IVectorView<PasswordCredential> credList;
|
||||
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
|
||||
try
|
||||
{
|
||||
credList = vault.FindAllByResource(resource);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// No credentials are stored, so just return
|
||||
_outputHandlers(winrt::to_hstring(noTokens));
|
||||
return;
|
||||
}
|
||||
while (credList.Size() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
vault.Remove(credList.GetAt(0));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
_outputHandlers(winrt::to_hstring(tokensRemoved));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring AzureConnection::_StrFormatHelper(const wchar_t* const format, int i, const wchar_t* name, const wchar_t* ID)
|
||||
{
|
||||
const auto lengthRequired = _scwprintf(ithTenant, i, name, ID);
|
||||
std::wstring buffer;
|
||||
buffer.resize(lengthRequired + 1);
|
||||
swprintf_s(buffer.data(), buffer.size(), ithTenant, i, name, ID);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AzureConnection.g.h"
|
||||
|
||||
#include <cpprest/http_client.h>
|
||||
#include <cpprest/http_listener.h>
|
||||
#include <cpprest/ws_client.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
{
|
||||
struct AzureConnection : AzureConnectionT<AzureConnection>
|
||||
{
|
||||
AzureConnection(const uint32_t rows, const uint32_t cols);
|
||||
|
||||
winrt::event_token TerminalOutput(TerminalConnection::TerminalOutputEventArgs const& handler);
|
||||
void TerminalOutput(winrt::event_token const& token) noexcept;
|
||||
winrt::event_token TerminalDisconnected(TerminalConnection::TerminalDisconnectedEventArgs const& handler);
|
||||
void TerminalDisconnected(winrt::event_token const& token) noexcept;
|
||||
void Start();
|
||||
void WriteInput(hstring const& data);
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void Close();
|
||||
|
||||
private:
|
||||
winrt::event<TerminalConnection::TerminalOutputEventArgs> _outputHandlers;
|
||||
winrt::event<TerminalConnection::TerminalDisconnectedEventArgs> _disconnectHandlers;
|
||||
|
||||
uint32_t _initialRows{};
|
||||
uint32_t _initialCols{};
|
||||
int _storedNumber{ -1 };
|
||||
int _maxStored;
|
||||
int _tenantNumber{ -1 };
|
||||
int _maxSize;
|
||||
std::condition_variable _canProceed;
|
||||
std::mutex _commonMutex;
|
||||
|
||||
enum class State
|
||||
{
|
||||
AccessStored,
|
||||
DeviceFlow,
|
||||
TenantChoice,
|
||||
StoreTokens,
|
||||
TermConnecting,
|
||||
TermConnected,
|
||||
NoConnect
|
||||
};
|
||||
|
||||
State _state{ State::AccessStored };
|
||||
|
||||
std::optional<bool> _store;
|
||||
std::optional<bool> _removeOrNew;
|
||||
|
||||
bool _connected{};
|
||||
std::atomic<bool> _closing{ false };
|
||||
|
||||
wil::unique_handle _hOutputThread;
|
||||
|
||||
static DWORD WINAPI StaticOutputThreadProc(LPVOID lpParameter);
|
||||
DWORD _OutputThread();
|
||||
HRESULT _AccessHelper();
|
||||
HRESULT _DeviceFlowHelper();
|
||||
HRESULT _TenantChoiceHelper();
|
||||
HRESULT _StoreHelper();
|
||||
HRESULT _ConnectHelper();
|
||||
|
||||
const utility::string_t _loginUri{ U("https://login.microsoftonline.com/") };
|
||||
const utility::string_t _resourceUri{ U("https://management.azure.com/") };
|
||||
const utility::string_t _wantedResource{ U("https://management.core.windows.net/") };
|
||||
int _expireLimit{ 2700 };
|
||||
web::json::value _tenantList;
|
||||
utility::string_t _displayName;
|
||||
utility::string_t _tenantID;
|
||||
utility::string_t _accessToken;
|
||||
utility::string_t _refreshToken;
|
||||
int _expiry;
|
||||
utility::string_t _cloudShellUri;
|
||||
utility::string_t _terminalID;
|
||||
|
||||
web::json::value _RequestHelper(web::http::client::http_client theClient, web::http::http_request theRequest);
|
||||
web::json::value _GetDeviceCode();
|
||||
web::json::value _WaitForUser(utility::string_t deviceCode, int pollInterval, int expiresIn);
|
||||
web::json::value _GetTenants();
|
||||
web::json::value _RefreshTokens();
|
||||
web::json::value _GetCloudShellUserSettings();
|
||||
utility::string_t _GetCloudShell();
|
||||
utility::string_t _GetTerminal(utility::string_t shellType);
|
||||
void _HeaderHelper(web::http::http_request theRequest);
|
||||
void _StoreCredential();
|
||||
void _RemoveCredentials();
|
||||
std::wstring _StrFormatHelper(const wchar_t* const format, int i, const wchar_t* name, const wchar_t* ID);
|
||||
|
||||
web::websockets::client::websocket_client _cloudShellSocket;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::TerminalConnection::factory_implementation
|
||||
{
|
||||
struct AzureConnection : AzureConnectionT<AzureConnection, implementation::AzureConnection>
|
||||
{
|
||||
};
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ITerminalConnection.idl";
|
||||
|
||||
namespace Microsoft.Terminal.TerminalConnection
|
||||
{
|
||||
[default_interface] runtimeclass AzureConnection : ITerminalConnection
|
||||
{
|
||||
AzureConnection(UInt32 rows, UInt32 columns);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Messages to the user
|
||||
const auto resource = L"Terminal";
|
||||
const auto userAgent = L"Terminal/0.0";
|
||||
const auto codeExpiry = L"\r\nThis code will expire in 15 minutes.\r\n";
|
||||
const auto enterTenant = L"Please enter the desired tenant number\r\n";
|
||||
const auto newLogin = L"or enter n to login with a different account\r\n";
|
||||
const auto removeStored = L"or enter r to remove the above saved connection settings.\r\n";
|
||||
const auto invalidAccessInput = L"Please enter a valid number to access the stored connection settings, n to make a new one, or r to remove the stored ones.\r\n";
|
||||
const auto nonNumberError = L"Please enter a number.\r\n";
|
||||
const auto numOutOfBoundsError = L"Number out of bounds. Please enter a valid number. \r\n";
|
||||
const auto noTenants = L"Could not find any tenants.\r\n";
|
||||
const auto noCloudAccount = L"You have not set up your cloud shell account yet. Please go to https://shell.azure.com to set it up.\r\n";
|
||||
const auto storePrompt = L"Do you want to save these connection settings for future logins? [y/n]\r\n";
|
||||
const auto invalidStoreInput = L"Please enter y or n\r\n";
|
||||
const auto requestingCloud = L"Requesting for a cloud shell...";
|
||||
const auto success = L"Succeeded.\r\n";
|
||||
const auto requestingTerminal = L"Requesting for a terminal (this might take a while)...";
|
||||
const auto tokensStored = L"Your connection settings have been saved for future logins.\r\n";
|
||||
const auto noTokens = L"No tokens to remove. \r\n";
|
||||
const auto tokensRemoved = L"Tokens removed!\r\n";
|
||||
const auto exitStr = L"Exit.\r\n";
|
||||
const auto authString = L"Authenticated.\r\n";
|
||||
const auto internetOrServerIssue = L"Could not connect to Azure. You may not have internet or the server might be down.\r\n";
|
||||
|
||||
const auto ithTenant = L"Tenant %d: %s (%s)\r\n";
|
||||
@@ -5,12 +5,16 @@
|
||||
#include "ConhostConnection.h"
|
||||
#include "windows.h"
|
||||
#include <sstream>
|
||||
// STARTF_USESTDHANDLES is only defined in WINAPI_PARTITION_DESKTOP
|
||||
// We're just gonna manually define it for this prototyping code
|
||||
#ifndef STARTF_USESTDHANDLES
|
||||
#define STARTF_USESTDHANDLES 0x00000100
|
||||
#endif
|
||||
|
||||
#include "ConhostConnection.g.cpp"
|
||||
|
||||
#include <conpty-universal.h>
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
#include "../../types/inc/UTF8OutPipeReader.hpp"
|
||||
|
||||
using namespace ::Microsoft::Console;
|
||||
|
||||
@@ -117,8 +121,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
0,
|
||||
nullptr));
|
||||
|
||||
THROW_LAST_ERROR_IF_NULL(_hOutputThread);
|
||||
|
||||
// Wind up the conhost! We only do this after we've got everything in place.
|
||||
THROW_LAST_ERROR_IF(-1 == ResumeThread(_piConhost.hThread));
|
||||
|
||||
@@ -187,37 +189,39 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
DWORD ConhostConnection::_OutputThread()
|
||||
{
|
||||
UTF8OutPipeReader pipeReader{ _outPipe.get() };
|
||||
std::string_view strView{};
|
||||
|
||||
// process the data of the output pipe in a loop
|
||||
const size_t bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
DWORD dwRead;
|
||||
while (true)
|
||||
{
|
||||
HRESULT result = pipeReader.Read(strView);
|
||||
if (FAILED(result) || result == S_FALSE)
|
||||
dwRead = 0;
|
||||
bool fSuccess = false;
|
||||
|
||||
fSuccess = !!ReadFile(_outPipe.get(), buffer, bufferSize, &dwRead, nullptr);
|
||||
if (!fSuccess)
|
||||
{
|
||||
if (_closing.load())
|
||||
{
|
||||
// This is okay, break out to kill the thread
|
||||
return 0;
|
||||
}
|
||||
|
||||
_disconnectHandlers();
|
||||
return (DWORD)-1;
|
||||
else
|
||||
{
|
||||
_disconnectHandlers();
|
||||
return (DWORD)-1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strView.empty())
|
||||
if (dwRead == 0)
|
||||
{
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert buffer to hstring
|
||||
auto hstr{ winrt::to_hstring(strView) };
|
||||
char* pchStr = (char*)(buffer);
|
||||
std::string str{ pchStr, dwRead };
|
||||
auto hstr = winrt::to_hstring(str);
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_outputHandlers(hstr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
@@ -7,24 +8,14 @@
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}</ProjectGuid>
|
||||
<ProjectName>TerminalConnection</ProjectName>
|
||||
<RootNamespace>Microsoft.Terminal.TerminalConnection</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' == 'x64'">
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)' == ''">x64-windows</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' == 'Win32'">
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)' == ''">x86-windows</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' == 'arm64'">
|
||||
<VcpkgTriplet Condition="'$(VcpkgTriplet)' == ''">arm64-windows</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AzureClientID.h" Condition="'$(Platform)'!='ARM64'" />
|
||||
<ClInclude Include="AzureConnection.h" Condition="'$(Platform)'!='ARM64'" />
|
||||
<ClInclude Include="AzureConnectionStrings.h" Condition="'$(Platform)'!='ARM64'" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="ConhostConnection.h">
|
||||
<DependentUpon>ConhostConnection.idl</DependentUpon>
|
||||
@@ -34,7 +25,6 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AzureConnection.cpp" Condition="'$(Platform)'!='ARM64'" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -50,16 +40,18 @@
|
||||
<Midl Include="ITerminalConnection.idl" />
|
||||
<Midl Include="ConhostConnection.idl" />
|
||||
<Midl Include="EchoConnection.idl" />
|
||||
<Midl Include="AzureConnection.idl" Condition="'$(Platform)'!='ARM64'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- ========================= Project References ======================== -->
|
||||
<ItemGroup>
|
||||
<!--
|
||||
@@ -70,6 +62,7 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
@@ -79,13 +72,7 @@
|
||||
-->
|
||||
<NoOutputRedirection>true</NoOutputRedirection>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\common.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<Import Project="..\..\..\packages\vcpkg-cpprestsdk.2.10.0\build\native\vcpkg-cpprestsdk.targets" Condition="Exists('..\..\..\packages\vcpkg-cpprestsdk.2.10.0\build\native\vcpkg-cpprestsdk.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\vcpkg-cpprestsdk.2.10.0\build\native\vcpkg-cpprestsdk.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\vcpkg-cpprestsdk.2.10.0\build\native\vcpkg-cpprestsdk.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -14,26 +14,22 @@
|
||||
<ClCompile Include="EchoConnection.cpp" />
|
||||
<ClCompile Include="ConhostConnection.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
<ClCompile Include="AzureConnection.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="EchoConnection.h" />
|
||||
<ClInclude Include="ConhostConnection.h" />
|
||||
<ClInclude Include="AzureConnection.h" />
|
||||
<ClInclude Include="AzureClientID.h" />
|
||||
<ClInclude Include="AzureConnectionStrings.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="ITerminalConnection.idl" />
|
||||
<Midl Include="ConhostConnection.idl" />
|
||||
<Midl Include="EchoConnection.idl" />
|
||||
<Midl Include="AzureConnection.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TerminalConnection.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
<Text Include="readme.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.190605.7" targetFramework="native" />
|
||||
<package id="vcpkg-cpprestsdk" version="2.10.0" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.190417.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -7,15 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Needs to be defined or we get redeclaration errors
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
|
||||
// Must be included before any WinRT headers.
|
||||
#include <unknwn.h>
|
||||
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/Windows.Security.Credentials.h"
|
||||
#include "winrt/Windows.Foundation.Collections.h"
|
||||
#include <Windows.h>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user