diff --git a/.github/actions/spelling/allow/allow.txt b/.github/actions/spelling/allow/allow.txt
index 3452bf4a8..fcaaf797a 100644
--- a/.github/actions/spelling/allow/allow.txt
+++ b/.github/actions/spelling/allow/allow.txt
@@ -12,6 +12,7 @@ downsides
dze
dzhe
Enum'd
+formattings
ftp
geeksforgeeks
ghe
@@ -34,6 +35,7 @@ overlined
postmodern
ptys
qof
+qps
reimplementation
reserialization
reserialize
@@ -46,6 +48,7 @@ tokenizes
tonos
tshe
UIs
+und
versioned
We'd
wildcards
diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt
index 8252b10b7..56142fc56 100644
--- a/.github/actions/spelling/allow/apis.txt
+++ b/.github/actions/spelling/allow/apis.txt
@@ -45,6 +45,7 @@ IBind
IBox
IClass
IComparable
+IComparer
IConnection
ICustom
IDialog
@@ -85,6 +86,7 @@ NOREPEAT
ntprivapi
oaidl
ocidl
+ODR
osver
OSVERSIONINFOEXW
otms
diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt
index 722631b26..fc07e9d2a 100644
--- a/.github/actions/spelling/expect/expect.txt
+++ b/.github/actions/spelling/expect/expect.txt
@@ -163,6 +163,7 @@ BPBF
bpp
BPPF
branchconfig
+brandings
BRK
Browsable
bsearch
diff --git a/.github/actions/spelling/patterns/patterns.txt b/.github/actions/spelling/patterns/patterns.txt
index bee4446d4..882243396 100644
--- a/.github/actions/spelling/patterns/patterns.txt
+++ b/.github/actions/spelling/patterns/patterns.txt
@@ -23,3 +23,4 @@ VERIFY_ARE_EQUAL\(L"[^"]+"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
+TIL_FEATURE_[0-9A-Z_]+
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 2b746e3d1..142fa20f6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -100,6 +100,6 @@
"**/bin/**": true,
"**/obj/**": true,
"**/packages/**": true,
- "**/generated files/**": true
+ "**/Generated Files/**": true
}
}
\ No newline at end of file
diff --git a/Scratch.sln b/Scratch.sln
new file mode 100644
index 000000000..ac6caf341
--- /dev/null
+++ b/Scratch.sln
@@ -0,0 +1,221 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31205.134
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "scratch\ScratchIslandApp\Package\Package.wapproj", "{CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppLib", "scratch\ScratchIslandApp\SampleApp\SampleAppLib.vcxproj", "{A4394404-37F7-41C1-802B-49788D3720E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "scratch\ScratchIslandApp\SampleApp\dll\SampleApp.vcxproj", "{26C51792-41A3-4FE0-AB5E-8B69D557BF91}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A4394404-37F7-41C1-802B-49788D3720E3} = {A4394404-37F7-41C1-802B-49788D3720E3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowExe", "scratch\ScratchIslandApp\WindowExe\WindowExe.vcxproj", "{B4427499-9FDE-4208-B456-5BC580637633}"
+ ProjectSection(ProjectDependencies) = postProject
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91} = {26C51792-41A3-4FE0-AB5E-8B69D557BF91}
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Props", "Common Props", "{53DD5520-E64C-4C06-B472-7CE62CA539C9}"
+ ProjectSection(SolutionItems) = preProject
+ src\common.build.post.props = src\common.build.post.props
+ src\common.build.pre.props = src\common.build.pre.props
+ src\common.build.tests.props = src\common.build.tests.props
+ common.openconsole.props = common.openconsole.props
+ src\cppwinrt.build.post.props = src\cppwinrt.build.post.props
+ src\cppwinrt.build.pre.props = src\cppwinrt.build.pre.props
+ src\wap-common.build.post.props = src\wap-common.build.post.props
+ src\wap-common.build.pre.props = src\wap-common.build.pre.props
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ AuditMode|ARM64 = AuditMode|ARM64
+ AuditMode|x64 = AuditMode|x64
+ AuditMode|x86 = AuditMode|x86
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Fuzzing|ARM64 = Fuzzing|ARM64
+ Fuzzing|x64 = Fuzzing|x64
+ Fuzzing|x86 = Fuzzing|x86
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|ARM64.ActiveCfg = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|ARM64.Build.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|ARM64.Deploy.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x64.ActiveCfg = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x64.Build.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x64.Deploy.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x86.ActiveCfg = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x86.Build.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.AuditMode|x86.Deploy.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x64.ActiveCfg = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x64.Build.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x64.Deploy.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x86.ActiveCfg = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x86.Build.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Debug|x86.Deploy.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|ARM64.ActiveCfg = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|ARM64.Build.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|ARM64.Deploy.0 = Debug|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x64.ActiveCfg = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x64.Build.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x64.Deploy.0 = Debug|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x86.ActiveCfg = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x86.Build.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Fuzzing|x86.Deploy.0 = Debug|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|ARM64.Build.0 = Release|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|ARM64.Deploy.0 = Release|ARM64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x64.ActiveCfg = Release|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x64.Build.0 = Release|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x64.Deploy.0 = Release|x64
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x86.ActiveCfg = Release|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x86.Build.0 = Release|x86
+ {CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}.Release|x86.Deploy.0 = Release|x86
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|x64.Build.0 = AuditMode|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|x64.ActiveCfg = Debug|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|x64.Build.0 = Debug|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|x86.ActiveCfg = Debug|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Debug|x86.Build.0 = Debug|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|x64.Build.0 = Fuzzing|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Fuzzing|x86.Build.0 = Fuzzing|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|ARM64.Build.0 = Release|ARM64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|x64.ActiveCfg = Release|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|x64.Build.0 = Release|x64
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|x86.ActiveCfg = Release|Win32
+ {A4394404-37F7-41C1-802B-49788D3720E3}.Release|x86.Build.0 = Release|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|x64.Build.0 = AuditMode|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|ARM64.Build.0 = Debug|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|x64.ActiveCfg = Debug|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|x64.Build.0 = Debug|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|x86.ActiveCfg = Debug|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Debug|x86.Build.0 = Debug|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|x64.Build.0 = Fuzzing|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Fuzzing|x86.Build.0 = Fuzzing|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|ARM64.ActiveCfg = Release|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|ARM64.Build.0 = Release|ARM64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|x64.ActiveCfg = Release|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|x64.Build.0 = Release|x64
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|x86.ActiveCfg = Release|Win32
+ {26C51792-41A3-4FE0-AB5E-8B69D557BF91}.Release|x86.Build.0 = Release|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|x64.Build.0 = AuditMode|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|ARM64.Build.0 = Debug|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|x64.ActiveCfg = Debug|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|x64.Build.0 = Debug|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|x86.ActiveCfg = Debug|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Debug|x86.Build.0 = Debug|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|x64.Build.0 = Fuzzing|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Fuzzing|x86.Build.0 = Fuzzing|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|ARM64.Build.0 = Release|ARM64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|x64.ActiveCfg = Release|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|x64.Build.0 = Release|x64
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|x86.ActiveCfg = Release|Win32
+ {B4427499-9FDE-4208-B456-5BC580637633}.Release|x86.Build.0 = Release|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.Build.0 = Fuzzing|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x64.ActiveCfg = AuditMode|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x64.Build.0 = AuditMode|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x86.ActiveCfg = AuditMode|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x86.Build.0 = AuditMode|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|ARM64.Build.0 = Debug|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|x64.ActiveCfg = Debug|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|x64.Build.0 = Debug|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|x86.ActiveCfg = Debug|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Debug|x86.Build.0 = Debug|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|x64.Build.0 = Fuzzing|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Fuzzing|x86.Build.0 = Fuzzing|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|ARM64.ActiveCfg = Release|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|ARM64.Build.0 = Release|ARM64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x64.ActiveCfg = Release|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x64.Build.0 = Release|x64
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x86.ActiveCfg = Release|Win32
+ {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
+ {18D09A24-8240-42D6-8CB6-236EEE820263} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {05EAE315-9188-4D7B-B889-7D5F480A8915}
+ EndGlobalSection
+EndGlobal
diff --git a/build/rules/GenerateFeatureFlags.proj b/build/rules/GenerateFeatureFlags.proj
new file mode 100644
index 000000000..8a8b494a6
--- /dev/null
+++ b/build/rules/GenerateFeatureFlags.proj
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+ Release
+ AnyCPU
+
+
+ Fuzzing
+ AnyCPU
+
+
+ AuditMode
+ AnyCPU
+
+
+ Debug
+ AnyCPU
+
+
+
+
+ d97c3c61-53cd-4e72-919b-9a0940e038f9
+
+
+
+ $(SolutionDir)obj\$(Configuration)\GenerateFeatureFlags\
+ $(SolutionDir)bin\$(Configuration)\
+
+ <_WTBrandingName Condition="'$(WindowsTerminalBranding)'=='Preview'">Preview
+ <_WTBrandingName Condition="'$(WindowsTerminalBranding)'=='Release'">Release
+ <_WTBrandingName Condition="'$(_WTBrandingName)'==''">Dev
+
+
+
+
+
+
+
+
+ <_BrandingLines Include="$(_WTBrandingName)" />
+
+
+
+
+
+
+ <_BranchBrandingCacheFiles Include="$(IntermediateOutputPath)branch_branding_cache.txt" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/consolegit2gitfilters.json b/consolegit2gitfilters.json
index 5a760692b..5f5d0eb26 100644
--- a/consolegit2gitfilters.json
+++ b/consolegit2gitfilters.json
@@ -23,6 +23,8 @@
"/doc/cascadia/",
"/doc/user-docs/",
"/src/tools/MonarchPeasantSample/",
+ "/scratch/",
+ "Scratch.sln",
],
"SuffixFilters": [
".dbb",
diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json
index c5cb67540..66e914fa9 100644
--- a/doc/cascadia/profiles.schema.json
+++ b/doc/cascadia/profiles.schema.json
@@ -191,6 +191,7 @@
"find",
"findMatch",
"focusPane",
+ "globalSummon",
"identifyWindow",
"identifyWindows",
"moveFocus",
@@ -206,6 +207,7 @@
"prevTab",
"renameTab",
"openTabRenamer",
+ "quakeMode",
"resetFontSize",
"resizePane",
"renameWindow",
@@ -817,6 +819,63 @@
}
]
},
+ "GlobalSummonAction": {
+ "description": "This is a special action that works globally in the OS, rather than only in the context of the terminal window. When pressed, this action will summon the terminal window.",
+ "allOf": [
+ { "$ref": "#/definitions/ShortcutAction" },
+ {
+ "properties": {
+ "action": { "type": "string", "pattern": "globalSummon" },
+ "desktop": {
+ "type": "string",
+ "default": "toCurrent",
+ "description": "This controls how the terminal should interact with virtual desktops.\n- \"any\": Leave the window on whichever desktop it's already on - will switch to that desktop as the window is activated.\n- \"toCurrent\" (default): Move the window to the current virtual desktop.\n- \"onCurrent\": Only summon the window if it's already on the current virtual desktop. ",
+ "enum": [
+ "any",
+ "toCurrent",
+ "onCurrent"
+ ]
+ },
+ "monitor": {
+ "type": "string",
+ "default": "toMouse",
+ "description": "This controls the monitor that the window will be summoned from/to.\n- \"any\": Summon the most recently used window, regardless of which monitor it's currently on.\n- \"toCurrent\": Summon the most recently used window to the monitor with the current foreground window.\n- \"toMouse\" (default): Summon the most recently used window to the monitor where the mouse cursor is.",
+ "enum": [
+ "any",
+ "toCurrent",
+ "toMouse"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "When provided, summon the window whose name or ID matches the given name value. If no such window exists, then create a new window with that name."
+ },
+ "dropdownDuration": {
+ "type": "number",
+ "minimum": 0,
+ "default": 0,
+ "description": "When provided with a positive number, \"slide\" the window in from the top of the screen using an animation that lasts dropdownDuration milliseconds."
+ },
+ "toggleVisibility": {
+ "type": "boolean",
+ "default": true,
+ "description": "When true, pressing the assigned keys for this action will dismiss (minimize) the window when the window is currently the foreground window."
+ }
+ }
+ }
+ ]
+ },
+ "QuakeModeAction": {
+ "description": "This action is a special variation of the globalSummon action. It specifically summons a window called \"_quake\". If you would like to change the behavior of the quakeMode action, we recommended creating a new globalSummon entry.",
+ "allOf": [
+ { "$ref": "#/definitions/ShortcutAction" },
+ {
+ "properties": {
+ "action": { "type": "string", "pattern": "quakeMode" }
+ }
+ }
+ ]
+ },
"Keybinding": {
"additionalProperties": false,
"properties": {
@@ -848,6 +907,8 @@
{ "$ref": "#/definitions/RenameTabAction" },
{ "$ref": "#/definitions/RenameWindowAction" },
{ "$ref": "#/definitions/FocusPaneAction" },
+ { "$ref": "#/definitions/GlobalSummonAction" },
+ { "$ref": "#/definitions/QuakeModeAction" },
{ "type": "null" }
]
},
@@ -868,16 +929,38 @@
},
"icon": { "$ref": "#/definitions/Icon" },
"name": {
- "description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.",
+ "description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.\nIf name is a string, it will be the name of the command.\nIf name is a object, the key property of the object will be used to lookup a localized string resource for the command",
+ "properties": {
+ "key": {
+ "type": "string"
+ }
+ },
"type": [
"string",
+ "object",
"null"
]
+ },
+ "iterateOn": {
+ "type": "string",
+ "description": "Used to create iterable commands based on other objects in your settings. Possible values:\n- \"profiles\" \n- \"schemes\"",
+ "enum": [
+ "profiles",
+ "schemes"
+ ]
+ },
+ "commands": {
+ "description": "List of commands to execute",
+ "items": {
+ "$ref": "#/definitions/Keybinding/properties/command"
+ },
+ "minItems": 1,
+ "type": "array"
}
},
- "required": [
- "command",
- "keys"
+ "anyOf": [
+ {"required": ["name","commands"]},
+ {"required": ["command"]}
],
"type": "object"
},
@@ -1011,13 +1094,26 @@
"type": [ "integer", "string" ],
"deprecated": true
},
+ "actions": {
+ "description": "Properties are specific to each custom action.",
+ "items": {
+ "$ref": "#/definitions/Keybinding"
+ },
+ "type": "array"
+ },
"keybindings": {
- "description": "Properties are specific to each custom key binding.",
+ "description": "[deprecated] Use actions instead.",
+ "deprecated": true,
"items": {
"$ref": "#/definitions/Keybinding"
},
"type": "array"
},
+ "language": {
+ "default": "",
+ "description": "Sets an override for the app's preferred language, expressed as a BCP-47 language tag like en-US.",
+ "type": "string"
+ },
"theme": {
"default": "system",
"description": "Sets the theme of the application. The special value \"system\" refers to the active Windows system theme.",
diff --git a/doc/feature_flags.md b/doc/feature_flags.md
new file mode 100644
index 000000000..f4c2a7d68
--- /dev/null
+++ b/doc/feature_flags.md
@@ -0,0 +1,65 @@
+# til::feature
+
+Feature flags are controlled by an XML document stored at `src/features.xml`.
+
+## Example Document
+
+```xml
+
+
+
+
+ Feature_XYZ
+
+ Does a cool thing
+
+
+ 1234
+
+
+ AlwaysEnabled|AlwaysDisabled
+
+
+
+ branch/with/wildcard/*
+
+
+
+
+
+ ...
+
+
+
+
+
+ Release
+
+
+
+
+
+ ...
+
+
+
+
+
+
+```
+
+## Notes
+
+Features that are disabled for Release using `alwaysDisabledReleaseTokens` are
+*always* disabled in Release, even if they come from a branch that would have
+been enabled by the wildcard.
+
+### Precedence
+
+1. `alwaysDisabledReleaseTokens`
+2. Enabled branches
+3. Disabled branches
+ * The longest branch token that matches your branch will win.
+3. Enabled brandings
+4. Disabled brandings
+5. The feature's default state
diff --git a/scratch/ScratchIslandApp/Package/Package.appxmanifest b/scratch/ScratchIslandApp/Package/Package.appxmanifest
new file mode 100644
index 000000000..dcd54adca
--- /dev/null
+++ b/scratch/ScratchIslandApp/Package/Package.appxmanifest
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Sample App
+ A Lone Developer
+ Images\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/Package/Package.wapproj b/scratch/ScratchIslandApp/Package/Package.wapproj
new file mode 100644
index 000000000..262719541
--- /dev/null
+++ b/scratch/ScratchIslandApp/Package/Package.wapproj
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+ false
+ false
+
+
+ cf31505e-3bae-4c0a-81d7-f1eb279f40bb
+ ..\WindowExe\WindowExe.vcxproj
+ NativeOnly
+
+
+ false
+ Never
+
+
+ true
+ False
+ Package_TemporaryKey.pfx
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd
+ $(OpenConsoleCommonOutDir)TerminalConnection\TerminalConnection.dll
+ true
+ true
+ true
+
+
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.winmd
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.dll
+ true
+ true
+ true
+
+
+
+
+
+
+
+ <_TemporaryFilteredWapProjOutput Include="@(_FilteredNonWapProjProjectOutput)" />
+ <_FilteredNonWapProjProjectOutput Remove="@(_TemporaryFilteredWapProjOutput)" />
+ <_FilteredNonWapProjProjectOutput Include="@(_TemporaryFilteredWapProjOutput)">
+
+
+
+
+
+
+
+
+
+ <_GenerateProjectPriFileDependsOn Condition="$(MSBuildVersion) < '16.3.0'">OpenConsoleLiftDesktopBridgePriFiles;$(_GenerateProjectPriFileDependsOn)
+
+
+
+ <_PriFile Include="@(_NonWapProjProjectOutput)" Condition="'%(Extension)' == '.pri'" />
+
+
+
+
+
+
+
+ $([MSBuild]::Unescape('$(WapProjBeforeGenerateAppxManifestDependsOn.Replace('_RemoveAllNonWapUWPItems', '_OpenConsoleRemoveAllNonWapUWPItems'))'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/Package/Resources/Resources.resw b/scratch/ScratchIslandApp/Package/Resources/Resources.resw
new file mode 100644
index 000000000..872f430e7
--- /dev/null
+++ b/scratch/ScratchIslandApp/Package/Resources/Resources.resw
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Scratch XAML Island App
+
+
+ Scratch App
+
+
diff --git a/scratch/ScratchIslandApp/Package/Resources/en-US/Resources.resw b/scratch/ScratchIslandApp/Package/Resources/en-US/Resources.resw
new file mode 100644
index 000000000..4ffee428e
--- /dev/null
+++ b/scratch/ScratchIslandApp/Package/Resources/en-US/Resources.resw
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ A scratch app for XAML Islands tests
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/App.base.h b/scratch/ScratchIslandApp/SampleApp/App.base.h
new file mode 100644
index 000000000..d6da79f1b
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/App.base.h
@@ -0,0 +1,40 @@
+#pragma once
+
+namespace winrt::SampleApp::implementation
+{
+ template
+ struct App_baseWithProvider : public App_base
+ {
+ 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 _appProvider;
+ std::shared_ptr AppProvider()
+ {
+ if (!_appProvider)
+ {
+ _appProvider = std::make_shared();
+ }
+ return _appProvider;
+ }
+ };
+
+ template
+ using AppT2 = App_baseWithProvider;
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/App.cpp b/scratch/ScratchIslandApp/SampleApp/App.cpp
new file mode 100644
index 000000000..5a2ae523f
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/App.cpp
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "App.h"
+#include "App.g.cpp"
+
+using namespace winrt;
+using namespace winrt::Windows::ApplicationModel::Activation;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::SampleApp::implementation
+{
+ App::App()
+ {
+ // This is the same trick that Initialize() is about to use to figure out whether we're coming
+ // from a UWP context or from a Win32 context
+ // See https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/blob/52611c57d89554f357f281d0c79036426a7d9257/Microsoft.Toolkit.Win32.UI.XamlApplication/XamlApplication.cpp#L42
+ const auto dispatcherQueue = ::winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
+ if (dispatcherQueue)
+ {
+ _isUwp = true;
+ }
+
+ Initialize();
+
+ // Disable XAML's automatic backplating of text when in High Contrast
+ // mode: we want full control of and responsibility for the foreground
+ // and background colors that we draw in XAML.
+ HighContrastAdjustment(::winrt::Windows::UI::Xaml::ApplicationHighContrastAdjustment::None);
+ }
+
+ SampleAppLogic App::Logic()
+ {
+ static SampleAppLogic logic;
+ return logic;
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ void App::OnLaunched(LaunchActivatedEventArgs const& /*e*/)
+ {
+ // if this is a UWP... it means its our problem to hook up the content to the window here.
+ if (_isUwp)
+ {
+ auto content = Window::Current().Content();
+ if (content == nullptr)
+ {
+ auto logic = Logic();
+ logic.Create();
+
+ auto page = logic.GetRoot().as();
+
+ Window::Current().Content(page);
+ Window::Current().Activate();
+ }
+ }
+ }
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/App.h b/scratch/ScratchIslandApp/SampleApp/App.h
new file mode 100644
index 000000000..fb6235d75
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/App.h
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "App.g.h"
+#include "App.base.h"
+
+namespace winrt::SampleApp::implementation
+{
+ struct App : AppT2
+ {
+ public:
+ App();
+ void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&);
+
+ SampleApp::SampleAppLogic Logic();
+
+ private:
+ bool _isUwp = false;
+ };
+}
+
+namespace winrt::SampleApp::factory_implementation
+{
+ struct App : AppT
+ {
+ };
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/App.idl b/scratch/ScratchIslandApp/SampleApp/App.idl
new file mode 100644
index 000000000..e51a73332
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/App.idl
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import "SampleAppLogic.idl";
+
+namespace SampleApp
+{
+ // ADD ARBITRARY APP LOGIC TO SampleAppLogic.idl, NOT HERE.
+ // This is for XAML platform setup only.
+ [default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
+ {
+ App();
+
+ SampleAppLogic Logic { get; };
+ }
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/App.xaml b/scratch/ScratchIslandApp/SampleApp/App.xaml
new file mode 100644
index 000000000..c6a2328f4
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/App.xaml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8,0,8,0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/MyPage.cpp b/scratch/ScratchIslandApp/SampleApp/MyPage.cpp
new file mode 100644
index 000000000..d4af3d80e
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MyPage.cpp
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "MyPage.h"
+#include
+#include "MyPage.g.cpp"
+#include "..\..\..\src\cascadia\UnitTests_Control\MockControlSettings.h"
+
+using namespace std::chrono_literals;
+using namespace winrt::Microsoft::Terminal;
+
+namespace winrt
+{
+ namespace MUX = Microsoft::UI::Xaml;
+ namespace WUX = Windows::UI::Xaml;
+ using IInspectable = Windows::Foundation::IInspectable;
+}
+
+namespace winrt::SampleApp::implementation
+{
+ MyPage::MyPage()
+ {
+ InitializeComponent();
+ }
+
+ void MyPage::Create()
+ {
+ TerminalConnection::EchoConnection conn{};
+ auto settings = winrt::make_self();
+
+ Control::TermControl control{ *settings, conn };
+
+ InProcContent().Children().Append(control);
+
+ // Once the control loads (and not before that), write some text for debugging:
+ control.Initialized([conn](auto&&, auto&&) {
+ conn.WriteInput(L"This TermControl is hosted in-proc...");
+ });
+ }
+
+ // Method Description:
+ // - Gets the title of the currently focused terminal control. If there
+ // isn't a control selected for any reason, returns "Windows Terminal"
+ // Arguments:
+ // -
+ // Return Value:
+ // - the title of the focused control if there is one, else "Windows Terminal"
+ hstring MyPage::Title()
+ {
+ return { L"Sample Application" };
+ }
+
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/MyPage.h b/scratch/ScratchIslandApp/SampleApp/MyPage.h
new file mode 100644
index 000000000..c16c02bb3
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MyPage.h
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "MyPage.g.h"
+#include "../../../src/cascadia/inc/cppwinrt_utils.h"
+
+namespace winrt::SampleApp::implementation
+{
+ struct MyPage : MyPageT
+ {
+ public:
+ MyPage();
+
+ void Create();
+
+ hstring Title();
+
+ private:
+ friend struct MyPageT; // for Xaml to bind events
+ };
+}
+
+namespace winrt::SampleApp::factory_implementation
+{
+ BASIC_FACTORY(MyPage);
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/MyPage.idl b/scratch/ScratchIslandApp/SampleApp/MyPage.idl
new file mode 100644
index 000000000..d3d0645b5
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MyPage.idl
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace SampleApp
+{
+ [default_interface] runtimeclass MyPage : Windows.UI.Xaml.Controls.Page
+ {
+ MyPage();
+ }
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/MyPage.xaml b/scratch/ScratchIslandApp/SampleApp/MyPage.xaml
new file mode 100644
index 000000000..f6e129ee7
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MyPage.xaml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/MySettings.cpp b/scratch/ScratchIslandApp/SampleApp/MySettings.cpp
new file mode 100644
index 000000000..c042a34e7
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MySettings.cpp
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+
+#include "MySettings.h"
+#include "MySettings.g.cpp"
+
+namespace winrt::SampleApp::implementation
+{
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/MySettings.h b/scratch/ScratchIslandApp/SampleApp/MySettings.h
new file mode 100644
index 000000000..170c9b540
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MySettings.h
@@ -0,0 +1,97 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+--*/
+#pragma once
+#include "../../inc/cppwinrt_utils.h"
+#include
+#include
+#include "MySettings.g.h"
+
+namespace winrt::SampleApp::implementation
+{
+ struct MySettings : MySettingsT
+ {
+ public:
+ MySettings() = default;
+
+ // --------------------------- Core Settings ---------------------------
+ // All of these settings are defined in ICoreSettings.
+
+ WINRT_PROPERTY(til::color, DefaultForeground, DEFAULT_FOREGROUND);
+ WINRT_PROPERTY(til::color, DefaultBackground, DEFAULT_BACKGROUND);
+ WINRT_PROPERTY(til::color, SelectionBackground, DEFAULT_FOREGROUND);
+ WINRT_PROPERTY(int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
+ WINRT_PROPERTY(int32_t, InitialRows, 30);
+ WINRT_PROPERTY(int32_t, InitialCols, 80);
+
+ WINRT_PROPERTY(bool, SnapOnInput, true);
+ WINRT_PROPERTY(bool, AltGrAliasing, true);
+ WINRT_PROPERTY(til::color, CursorColor, DEFAULT_CURSOR_COLOR);
+ WINRT_PROPERTY(winrt::Microsoft::Terminal::Core::CursorStyle, CursorShape, winrt::Microsoft::Terminal::Core::CursorStyle::Vintage);
+ WINRT_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
+ WINRT_PROPERTY(winrt::hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
+ WINRT_PROPERTY(bool, CopyOnSelect, false);
+ WINRT_PROPERTY(bool, InputServiceWarning, true);
+ WINRT_PROPERTY(bool, FocusFollowMouse, false);
+
+ WINRT_PROPERTY(winrt::Windows::Foundation::IReference, TabColor, nullptr);
+
+ WINRT_PROPERTY(winrt::Windows::Foundation::IReference, StartingTabColor, nullptr);
+
+ winrt::Microsoft::Terminal::Core::ICoreAppearance UnfocusedAppearance() { return {}; };
+
+ WINRT_PROPERTY(bool, TrimBlockSelection, false);
+ // ------------------------ End of Core Settings -----------------------
+
+ WINRT_PROPERTY(winrt::hstring, ProfileName);
+ WINRT_PROPERTY(bool, UseAcrylic, false);
+ WINRT_PROPERTY(double, TintOpacity, 0.5);
+ WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
+ WINRT_PROPERTY(winrt::hstring, FontFace, L"Consolas");
+ WINRT_PROPERTY(int32_t, FontSize, DEFAULT_FONT_SIZE);
+
+ WINRT_PROPERTY(winrt::Windows::UI::Text::FontWeight, FontWeight);
+
+ WINRT_PROPERTY(winrt::hstring, BackgroundImage);
+ WINRT_PROPERTY(double, BackgroundImageOpacity, 1.0);
+
+ WINRT_PROPERTY(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill);
+ WINRT_PROPERTY(winrt::Windows::UI::Xaml::HorizontalAlignment, BackgroundImageHorizontalAlignment, winrt::Windows::UI::Xaml::HorizontalAlignment::Center);
+ WINRT_PROPERTY(winrt::Windows::UI::Xaml::VerticalAlignment, BackgroundImageVerticalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment::Center);
+
+ WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::IKeyBindings, KeyBindings, nullptr);
+
+ WINRT_PROPERTY(winrt::hstring, Commandline);
+ WINRT_PROPERTY(winrt::hstring, StartingDirectory);
+ WINRT_PROPERTY(winrt::hstring, StartingTitle);
+ WINRT_PROPERTY(bool, SuppressApplicationTitle);
+ WINRT_PROPERTY(winrt::hstring, EnvironmentVariables);
+
+ WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible);
+
+ WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);
+
+ WINRT_PROPERTY(bool, RetroTerminalEffect, false);
+ WINRT_PROPERTY(bool, ForceFullRepaintRendering, false);
+ WINRT_PROPERTY(bool, SoftwareRendering, false);
+ WINRT_PROPERTY(bool, ForceVTInput, false);
+
+ WINRT_PROPERTY(winrt::hstring, PixelShaderPath);
+
+ WINRT_PROPERTY(bool, DetectURLs, true);
+
+ private:
+ std::array _ColorTable;
+
+ public:
+ winrt::Microsoft::Terminal::Core::Color GetColorTableEntry(int32_t index) noexcept { return _ColorTable.at(index); }
+ std::array ColorTable() { return _ColorTable; }
+ void ColorTable(std::array /*colors*/) {}
+ };
+}
+
+namespace winrt::SampleApp::factory_implementation
+{
+ BASIC_FACTORY(MySettings);
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/MySettings.idl b/scratch/ScratchIslandApp/SampleApp/MySettings.idl
new file mode 100644
index 000000000..42422b21a
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/MySettings.idl
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace SampleApp
+{
+ [default_interface] runtimeclass MySettings : Microsoft.Terminal.Core.ICoreSettings,
+ Microsoft.Terminal.Control.IControlSettings,
+ Microsoft.Terminal.Core.ICoreAppearance,
+ Microsoft.Terminal.Control.IControlAppearance
+
+ {
+ MySettings();
+ }
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/Resources/en-US/Resources.resw b/scratch/ScratchIslandApp/SampleApp/Resources/en-US/Resources.resw
new file mode 100644
index 000000000..f4af46df5
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/Resources/en-US/Resources.resw
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj
new file mode 100644
index 000000000..c16d6be6f
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj
@@ -0,0 +1,181 @@
+
+
+
+ {a4394404-37f7-41c1-802b-49788d3720e3}
+ Win32Proj
+ SampleApp
+ SampleAppLib
+ SampleAppLib
+ StaticLibrary
+ Console
+ true
+
+ false
+ nested
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+ MyPage.xaml
+ Code
+
+
+ App.xaml
+
+
+ SampleAppLogic.idl
+
+
+
+
+
+
+
+ MyPage.xaml
+ Code
+
+
+ Create
+
+
+ App.xaml
+
+
+ SampleAppLogic.idl
+
+
+
+
+
+
+
+
+ App.xaml
+
+
+
+
+ MyPage.xaml
+ Code
+
+
+
+
+
+
+
+
+
+
+
+ Warning
+
+
+
+
+
+ $(OpenConsoleCommonOutDir)TerminalCore\Microsoft.Terminal.Core.winmd
+ true
+ false
+ false
+
+
+ $(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd
+ true
+ false
+ false
+
+
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.winmd
+ true
+ false
+ false
+
+
+
+
+
+ pch.h
+ ..;%(AdditionalIncludeDirectories);
+
+ 4702;%(DisableSpecificWarnings)
+
+
+ $(OpenConsoleCommonOutDir)\ConTypes.lib;WindowsApp.lib;shell32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
+
+ <_GenerateProjectPriFileDependsOn>OpenConsolePlaceAppXbfAtRootOfResourceTree;$(_GenerateProjectPriFileDependsOn)
+
+
+
+ <_RelocatedAppXamlData Include="@(PackagingOutputs)" Condition="'%(Filename)' == 'App' and ('%(Extension)' == '.xaml' or '%(Extension)' == '.xbf')" />
+
+
+ %(Filename)%(Extension)
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.cpp b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.cpp
new file mode 100644
index 000000000..4498f70df
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.cpp
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "SampleAppLogic.h"
+#include "SampleAppLogic.g.cpp"
+
+#include
+
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::System;
+
+namespace winrt
+{
+ namespace MUX = Microsoft::UI::Xaml;
+ using IInspectable = Windows::Foundation::IInspectable;
+}
+
+namespace winrt::SampleApp::implementation
+{
+ // Function Description:
+ // - Get the SampleAppLogic for the current active Xaml application, or null if there isn't one.
+ // Return value:
+ // - A pointer (bare) to the SampleAppLogic, or nullptr. The app logic outlives all other objects,
+ // unless the application is in a terrible way, so this is "safe."
+ SampleAppLogic* SampleAppLogic::Current() noexcept
+ try
+ {
+ if (auto currentXamlApp{ winrt::Windows::UI::Xaml::Application::Current().try_as() })
+ {
+ if (auto SampleAppLogicPointer{ winrt::get_self(currentXamlApp.Logic()) })
+ {
+ return SampleAppLogicPointer;
+ }
+ }
+ return nullptr;
+ }
+ catch (...)
+ {
+ LOG_CAUGHT_EXCEPTION();
+ return nullptr;
+ }
+
+ SampleAppLogic::SampleAppLogic()
+ {
+ // 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 App just failed to activate, which will
+ // cause you to chase down the rabbit hole of "why is App not
+ // registered?" when it definitely is.
+
+ // The MyPage has to be constructed during our construction, to
+ // make sure that there's a terminal page for callers of
+ // SetTitleBarContent
+ _root = winrt::make_self();
+ }
+
+ // Method Description:
+ // - Build the UI for the terminal app. Before this method is called, it
+ // should not be assumed that the SampleApp is usable. The Settings
+ // should be loaded before this is called, either with LoadSettings or
+ // GetLaunchDimensions (which will call LoadSettings)
+ // Arguments:
+ // -
+ // Return Value:
+ // -
+ void SampleAppLogic::Create()
+ {
+ _root->Create();
+ }
+
+ UIElement SampleAppLogic::GetRoot() noexcept
+ {
+ return _root.as();
+ }
+
+ hstring SampleAppLogic::Title()
+ {
+ return _root->Title();
+ }
+
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.h b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.h
new file mode 100644
index 000000000..8b8642a8e
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.h
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "SampleAppLogic.g.h"
+#include "MyPage.h"
+#include "../../../src/cascadia/inc/cppwinrt_utils.h"
+
+namespace winrt::SampleApp::implementation
+{
+ struct SampleAppLogic : SampleAppLogicT
+ {
+ public:
+ static SampleAppLogic* Current() noexcept;
+
+ SampleAppLogic();
+ ~SampleAppLogic() = default;
+
+ void Create();
+
+ Windows::UI::Xaml::UIElement GetRoot() noexcept;
+
+ winrt::hstring Title();
+
+ private:
+ // If you add controls here, but forget to null them either here or in
+ // the ctor, you're going to have a bad time. It'll mysteriously fail to
+ // activate the SampleAppLogic.
+ // ALSO: If you add any UIElements as roots here, make sure they're
+ // updated in _ApplyTheme. The root currently is _root.
+ winrt::com_ptr _root{ nullptr };
+ };
+}
+
+namespace winrt::SampleApp::factory_implementation
+{
+ struct SampleAppLogic : SampleAppLogicT
+ {
+ };
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.idl b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.idl
new file mode 100644
index 000000000..9b7d49e1a
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLogic.idl
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+
+namespace SampleApp
+{
+
+ [default_interface] runtimeclass SampleAppLogic
+ {
+ SampleAppLogic();
+
+ void Create();
+
+ Windows.UI.Xaml.UIElement GetRoot();
+
+ String Title { get; };
+
+ }
+}
diff --git a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.def b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.def
new file mode 100644
index 000000000..8c1a02932
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.def
@@ -0,0 +1,3 @@
+EXPORTS
+DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
+DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
diff --git a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj
new file mode 100644
index 000000000..1b1961fac
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj
@@ -0,0 +1,101 @@
+
+
+
+ {26c51792-41a3-4fe0-ab5e-8b69d557bf91}
+ SampleApp
+ SampleApp
+
+
+ DynamicLibrary
+ Console
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+ $(OpenConsoleCommonOutDir)TerminalCore\Microsoft.Terminal.Core.winmd
+ true
+ false
+ false
+
+
+ $(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd
+ true
+ false
+ false
+
+
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.winmd
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
+
+ $(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);
+
+
+ WindowsApp.lib;%(AdditionalDependencies)
+
+ /INCLUDE:_DllMain@12 %(AdditionalOptions)
+ /INCLUDE:DllMain %(AdditionalOptions)
+
+
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/dll/pch.cpp b/scratch/ScratchIslandApp/SampleApp/dll/pch.cpp
new file mode 100644
index 000000000..3c27d44d5
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/dll/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
diff --git a/scratch/ScratchIslandApp/SampleApp/dll/pch.h b/scratch/ScratchIslandApp/SampleApp/dll/pch.h
new file mode 100644
index 000000000..76004c88f
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/dll/pch.h
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+//
+// pch.h
+// Header for platform projection include files
+//
+
+#pragma once
+
+// This file can be empty - the pch.h in SampleApp/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.
diff --git a/scratch/ScratchIslandApp/SampleApp/init.cpp b/scratch/ScratchIslandApp/SampleApp/init.cpp
new file mode 100644
index 000000000..1c169d9d9
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/init.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include
+#include
+
+BOOL WINAPI DllMain(HINSTANCE /*hInstDll*/, DWORD /*reason*/, LPVOID /*reserved*/)
+{
+ return TRUE;
+}
+
+UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"SampleApp/Resources")
diff --git a/scratch/ScratchIslandApp/SampleApp/packages.config b/scratch/ScratchIslandApp/SampleApp/packages.config
new file mode 100644
index 000000000..a6c68340a
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/SampleApp/pch.cpp b/scratch/ScratchIslandApp/SampleApp/pch.cpp
new file mode 100644
index 000000000..3c27d44d5
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
diff --git a/scratch/ScratchIslandApp/SampleApp/pch.h b/scratch/ScratchIslandApp/SampleApp/pch.h
new file mode 100644
index 000000000..fd9d893f9
--- /dev/null
+++ b/scratch/ScratchIslandApp/SampleApp/pch.h
@@ -0,0 +1,71 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+//
+// pch.h
+// Header for platform projection include files
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMCX
+#define NOHELP
+#define NOCOMM
+
+// Manually include til after we include Windows.Foundation to give it winrt superpowers
+#define BLOCK_TIL
+#include
+// 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
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.ViewManagement.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+// Including TraceLogging essentials for the binary
+#include
+#include
+TRACELOGGING_DECLARE_PROVIDER(g_hSampleAppProvider);
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+// Manually include til after we include Windows.Foundation to give it winrt superpowers
+#include "til.h"
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleAppHost.cpp b/scratch/ScratchIslandApp/WindowExe/SampleAppHost.cpp
new file mode 100644
index 000000000..2d3afefc5
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleAppHost.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "SampleAppHost.h"
+#include "../types/inc/Viewport.hpp"
+#include "../types/inc/utils.hpp"
+#include "../types/inc/User32Utils.hpp"
+#include "resource.h"
+
+using namespace winrt::Windows::UI;
+using namespace winrt::Windows::UI::Composition;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Hosting;
+using namespace winrt::Windows::Foundation::Numerics;
+using namespace ::Microsoft::Console;
+using namespace ::Microsoft::Console::Types;
+
+SampleAppHost::SampleAppHost() noexcept :
+ _app{},
+ _logic{ nullptr }, // don't make one, we're going to take a ref on app's
+ _window{ nullptr }
+{
+ _logic = _app.Logic(); // get a ref to app's logic
+
+ _window = std::make_unique();
+ _window->MakeWindow();
+}
+
+SampleAppHost::~SampleAppHost()
+{
+ // destruction order is important for proper teardown here
+ _window = nullptr;
+ _app.Close();
+ _app = nullptr;
+}
+// Method Description:
+// - Initializes the XAML island, creates the terminal app, and sets the
+// island's content to that of the terminal app's content. Also registers some
+// callbacks with TermApp.
+// !!! IMPORTANT!!!
+// This must be called *AFTER* WindowsXamlManager::InitializeForCurrentThread.
+// If it isn't, then we won't be able to create the XAML island.
+// Arguments:
+// -
+// Return Value:
+// -
+void SampleAppHost::Initialize()
+{
+ _window->Initialize();
+
+ _logic.Create();
+
+ _window->UpdateTitle(_logic.Title());
+
+ // Set up the content of the application. If the app has a custom titlebar,
+ // set that content as well.
+ _window->SetContent(_logic.GetRoot());
+
+ _window->OnAppInitialized();
+
+ // THIS IS A HACK
+ //
+ // We've got a weird crash that happens terribly inconsistently, only in
+ // Debug mode. Apparently, there's some weird ref-counting magic that goes
+ // on during teardown, and our Application doesn't get closed quite right,
+ // which can cause us to crash into the debugger. This of course, only
+ // happens on exit, and happens somewhere in the XamlHost.dll code.
+ //
+ // Crazily, if we _manually leak the Application_ here, then the crash
+ // doesn't happen. This doesn't matter, because we really want the
+ // Application to live for _the entire lifetime of the process_, so the only
+ // time when this object would actually need to get cleaned up is _during
+ // exit_. So we can safely leak this Application object, and have it just
+ // get cleaned up normally when our process exits.
+ ::winrt::SampleApp::App a{ _app };
+ ::winrt::detach_abi(a);
+}
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleAppHost.h b/scratch/ScratchIslandApp/WindowExe/SampleAppHost.h
new file mode 100644
index 000000000..226f90a4b
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleAppHost.h
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+
+#include "SampleIslandWindow.h"
+
+class SampleAppHost
+{
+public:
+ SampleAppHost() noexcept;
+ virtual ~SampleAppHost();
+
+ void Initialize();
+
+private:
+ std::unique_ptr _window;
+ winrt::SampleApp::App _app;
+ winrt::SampleApp::SampleAppLogic _logic;
+};
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleBaseWindow.h b/scratch/ScratchIslandApp/WindowExe/SampleBaseWindow.h
new file mode 100644
index 000000000..5c25452b3
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleBaseWindow.h
@@ -0,0 +1,228 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+// Custom window messages
+#define CM_UPDATE_TITLE (WM_USER)
+
+#include
+
+template
+class BaseWindow
+{
+public:
+ virtual ~BaseWindow() = 0;
+ static T* GetThisFromHandle(HWND const window) noexcept
+ {
+ return reinterpret_cast(GetWindowLongPtr(window, GWLP_USERDATA));
+ }
+
+ [[nodiscard]] static LRESULT __stdcall WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
+ {
+ WINRT_ASSERT(window);
+
+ if (WM_NCCREATE == message)
+ {
+ auto cs = reinterpret_cast(lparam);
+ T* that = static_cast(cs->lpCreateParams);
+ WINRT_ASSERT(that);
+ WINRT_ASSERT(!that->_window);
+ that->_window = wil::unique_hwnd(window);
+
+ return that->_OnNcCreate(wparam, lparam);
+ }
+ else if (T* that = GetThisFromHandle(window))
+ {
+ return that->MessageHandler(message, wparam, lparam);
+ }
+
+ return DefWindowProc(window, message, wparam, lparam);
+ }
+
+ [[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
+ {
+ switch (message)
+ {
+ case WM_DPICHANGED:
+ {
+ return HandleDpiChange(_window.get(), wparam, lparam);
+ }
+
+ case WM_DESTROY:
+ {
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ case WM_SIZE:
+ {
+ UINT width = LOWORD(lparam);
+ UINT height = HIWORD(lparam);
+
+ switch (wparam)
+ {
+ case SIZE_MAXIMIZED:
+ [[fallthrough]];
+ case SIZE_RESTORED:
+ if (_minimized)
+ {
+ _minimized = false;
+ OnRestore();
+ }
+
+ // We always need to fire the resize event, even when we're transitioning from minimized.
+ // We might be transitioning directly from minimized to maximized, and we'll need
+ // to trigger any size-related content changes.
+ OnResize(width, height);
+ break;
+ case SIZE_MINIMIZED:
+ if (!_minimized)
+ {
+ _minimized = true;
+ OnMinimize();
+ }
+ break;
+ default:
+ // do nothing.
+ break;
+ }
+ break;
+ }
+ case CM_UPDATE_TITLE:
+ {
+ SetWindowTextW(_window.get(), _title.c_str());
+ break;
+ }
+ }
+
+ return DefWindowProc(_window.get(), message, wparam, lparam);
+ }
+
+ // DPI Change handler. on WM_DPICHANGE resize the window
+ [[nodiscard]] LRESULT HandleDpiChange(const HWND hWnd, const WPARAM wParam, const LPARAM lParam)
+ {
+ _inDpiChange = true;
+ const HWND hWndStatic = GetWindow(hWnd, GW_CHILD);
+ if (hWndStatic != nullptr)
+ {
+ const UINT uDpi = HIWORD(wParam);
+
+ // Resize the window
+ auto lprcNewScale = reinterpret_cast(lParam);
+
+ SetWindowPos(hWnd, nullptr, lprcNewScale->left, lprcNewScale->top, lprcNewScale->right - lprcNewScale->left, lprcNewScale->bottom - lprcNewScale->top, SWP_NOZORDER | SWP_NOACTIVATE);
+
+ _currentDpi = uDpi;
+ }
+ _inDpiChange = false;
+ return 0;
+ }
+
+ virtual void OnResize(const UINT width, const UINT height) = 0;
+ virtual void OnMinimize() = 0;
+ virtual void OnRestore() = 0;
+
+ RECT GetWindowRect() const noexcept
+ {
+ RECT rc = { 0 };
+ ::GetWindowRect(_window.get(), &rc);
+ return rc;
+ }
+
+ HWND GetHandle() const noexcept
+ {
+ return _window.get();
+ }
+
+ float GetCurrentDpiScale() const noexcept
+ {
+ const auto dpi = ::GetDpiForWindow(_window.get());
+ const auto scale = static_cast(dpi) / static_cast(USER_DEFAULT_SCREEN_DPI);
+ return scale;
+ }
+
+ // Gets the physical size of the client area of the HWND in _window
+ SIZE GetPhysicalSize() const noexcept
+ {
+ RECT rect = {};
+ GetClientRect(_window.get(), &rect);
+ const auto windowsWidth = rect.right - rect.left;
+ const auto windowsHeight = rect.bottom - rect.top;
+ return SIZE{ windowsWidth, windowsHeight };
+ }
+
+ // Gets the logical (in DIPs) size of a physical size specified by the parameter physicalSize
+ // Remarks:
+ // XAML coordinate system is always in Display Independent Pixels (a.k.a DIPs or Logical). However Win32 GDI (because of legacy reasons)
+ // in DPI mode "Per-Monitor and Per-Monitor (V2) DPI Awareness" is always in physical pixels.
+ // The formula to transform is:
+ // logical = (physical / dpi) + 0.5 // 0.5 is to ensure that we pixel snap correctly at the edges, this is necessary with odd DPIs like 1.25, 1.5, 1, .75
+ // See also:
+ // https://docs.microsoft.com/en-us/windows/desktop/LearnWin32/dpi-and-device-independent-pixels
+ // https://docs.microsoft.com/en-us/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows#per-monitor-and-per-monitor-v2-dpi-awareness
+ winrt::Windows::Foundation::Size GetLogicalSize(const SIZE physicalSize) const noexcept
+ {
+ const auto scale = GetCurrentDpiScale();
+ // 0.5 is to ensure that we pixel snap correctly at the edges, this is necessary with odd DPIs like 1.25, 1.5, 1, .75
+ const auto logicalWidth = (physicalSize.cx / scale) + 0.5f;
+ const auto logicalHeight = (physicalSize.cy / scale) + 0.5f;
+ return winrt::Windows::Foundation::Size(logicalWidth, logicalHeight);
+ }
+
+ winrt::Windows::Foundation::Size GetLogicalSize() const noexcept
+ {
+ return GetLogicalSize(GetPhysicalSize());
+ }
+
+ // Method Description:
+ // - Sends a message to our message loop to update the title of the window.
+ // Arguments:
+ // - newTitle: a string to use as the new title of the window.
+ // Return Value:
+ // -
+ void UpdateTitle(std::wstring_view newTitle)
+ {
+ _title = newTitle;
+ PostMessageW(_window.get(), CM_UPDATE_TITLE, 0, reinterpret_cast(nullptr));
+ }
+
+ // Method Description:
+ // Reset the current dpi of the window. This method is only called after we change the
+ // initial launch position. This makes sure the dpi is consistent with the monitor on which
+ // the window will launch
+ void RefreshCurrentDPI()
+ {
+ _currentDpi = GetDpiForWindow(_window.get());
+ }
+
+protected:
+ using base_type = BaseWindow;
+ wil::unique_hwnd _window;
+
+ unsigned int _currentDpi = 0;
+ bool _inDpiChange = false;
+
+ std::wstring _title = L"";
+
+ bool _minimized = false;
+
+ // Method Description:
+ // - This method is called when the window receives the WM_NCCREATE message.
+ // Return Value:
+ // - The value returned from the window proc.
+ virtual [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
+ {
+ SetWindowLongPtr(_window.get(), GWLP_USERDATA, reinterpret_cast(this));
+
+ EnableNonClientDpiScaling(_window.get());
+ _currentDpi = GetDpiForWindow(_window.get());
+
+ return DefWindowProc(_window.get(), WM_NCCREATE, wParam, lParam);
+ };
+};
+
+template
+inline BaseWindow::~BaseWindow()
+{
+}
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.cpp b/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.cpp
new file mode 100644
index 000000000..1c5cf10d0
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.cpp
@@ -0,0 +1,220 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "SampleIslandWindow.h"
+#include "../types/inc/Viewport.hpp"
+#include "resource.h"
+#include "icon.h"
+
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+using namespace winrt::Windows::UI;
+using namespace winrt::Windows::UI::Composition;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Hosting;
+using namespace winrt::Windows::Foundation::Numerics;
+using namespace ::Microsoft::Console::Types;
+
+#define XAML_HOSTING_WINDOW_CLASS_NAME L"SCRATCH_HOSTING_WINDOW_CLASS"
+
+SampleIslandWindow::SampleIslandWindow() noexcept :
+ _interopWindowHandle{ nullptr },
+ _rootGrid{ nullptr },
+ _source{ nullptr }
+{
+}
+
+SampleIslandWindow::~SampleIslandWindow()
+{
+ _source.Close();
+}
+
+// Method Description:
+// - Create the actual window that we'll use for the application.
+// Arguments:
+// -
+// Return Value:
+// -
+void SampleIslandWindow::MakeWindow() noexcept
+{
+ WNDCLASS wc{};
+ wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wc.hInstance = reinterpret_cast(&__ImageBase);
+ wc.lpszClassName = XAML_HOSTING_WINDOW_CLASS_NAME;
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = WndProc;
+ wc.hIcon = LoadIconW(wc.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
+ RegisterClass(&wc);
+ WINRT_ASSERT(!_window);
+
+ // Create the window with the default size here - During the creation of the
+ // window, the system will give us a chance to set its size in WM_CREATE.
+ // WM_CREATE will be handled synchronously, before CreateWindow returns.
+ WINRT_VERIFY(CreateWindowEx(0,
+ wc.lpszClassName,
+ L"ScratchApp",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ nullptr,
+ nullptr,
+ wc.hInstance,
+ this));
+
+ WINRT_ASSERT(_window);
+}
+
+// Method Description:
+// - Called when no tab is remaining to close the window.
+// Arguments:
+// -
+// Return Value:
+// -
+void SampleIslandWindow::Close()
+{
+ PostQuitMessage(0);
+}
+
+// Method Description:
+// - Handles a WM_CREATE message. Calls our create callback, if one's been set.
+// Arguments:
+// - wParam: unused
+// - lParam: the lParam of a WM_CREATE, which is a pointer to a CREATESTRUCTW
+// Return Value:
+// -
+void SampleIslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam) noexcept
+{
+ // Get proposed window rect from create structure
+ CREATESTRUCTW* pcs = reinterpret_cast(lParam);
+ RECT rc;
+ rc.left = pcs->x;
+ rc.top = pcs->y;
+ rc.right = rc.left + pcs->cx;
+ rc.bottom = rc.top + pcs->cy;
+
+ ShowWindow(_window.get(), SW_SHOW);
+
+ UpdateWindow(_window.get());
+
+ UpdateWindowIconForActiveMetrics(_window.get());
+}
+
+void SampleIslandWindow::Initialize()
+{
+ const bool initialized = (_interopWindowHandle != nullptr);
+
+ _source = DesktopWindowXamlSource{};
+
+ auto interop = _source.as();
+ winrt::check_hresult(interop->AttachToWindow(_window.get()));
+
+ // stash the child interop handle so we can resize it when the main hwnd is resized
+ interop->get_WindowHandle(&_interopWindowHandle);
+
+ _rootGrid = winrt::Windows::UI::Xaml::Controls::Grid();
+ _source.Content(_rootGrid);
+}
+
+void SampleIslandWindow::OnSize(const UINT width, const UINT height)
+{
+ // update the interop window size
+ SetWindowPos(_interopWindowHandle, nullptr, 0, 0, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
+
+ if (_rootGrid)
+ {
+ const auto size = GetLogicalSize();
+ _rootGrid.Width(size.Width);
+ _rootGrid.Height(size.Height);
+ }
+}
+
+[[nodiscard]] LRESULT SampleIslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ {
+ _HandleCreateWindow(wparam, lparam);
+ return 0;
+ }
+ case WM_SETFOCUS:
+ {
+ if (_interopWindowHandle != nullptr)
+ {
+ // send focus to the child window
+ SetFocus(_interopWindowHandle);
+ return 0;
+ }
+ break;
+ }
+ case WM_MENUCHAR:
+ {
+ // GH#891: return this LRESULT here to prevent the app from making a
+ // bell when alt+key is pressed. A menu is active and the user presses a
+ // key that does not correspond to any mnemonic or accelerator key,
+ return MAKELRESULT(0, MNC_CLOSE);
+ }
+ case WM_THEMECHANGED:
+ UpdateWindowIconForActiveMetrics(_window.get());
+ return 0;
+ }
+
+ return base_type::MessageHandler(message, wparam, lparam);
+}
+
+// Method Description:
+// - Called when the window has been resized (or maximized)
+// Arguments:
+// - width: the new width of the window _in pixels_
+// - height: the new height of the window _in pixels_
+void SampleIslandWindow::OnResize(const UINT width, const UINT height)
+{
+ if (_interopWindowHandle)
+ {
+ OnSize(width, height);
+ }
+}
+
+// Method Description:
+// - Called when the window is minimized to the taskbar.
+void SampleIslandWindow::OnMinimize()
+{
+}
+
+// Method Description:
+// - Called when the window is restored from having been minimized.
+void SampleIslandWindow::OnRestore()
+{
+}
+
+void SampleIslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
+{
+ _rootGrid.Children().Clear();
+ _rootGrid.Children().Append(content);
+}
+
+void SampleIslandWindow::OnAppInitialized()
+{
+ // Do a quick resize to force the island to paint
+ const auto size = GetPhysicalSize();
+ OnSize(size.cx, size.cy);
+}
+
+// Method Description:
+// - Called when the app wants to change its theme. We'll update the root UI
+// element of the entire XAML tree, so that all UI elements get the theme
+// applied.
+// Arguments:
+// - arg: the ElementTheme to use as the new theme for the UI
+// Return Value:
+// -
+void SampleIslandWindow::OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
+{
+ _rootGrid.RequestedTheme(requestedTheme);
+ // Invalidate the window rect, so that we'll repaint any elements we're
+ // drawing ourselves to match the new theme
+ ::InvalidateRect(_window.get(), nullptr, false);
+}
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.h b/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.h
new file mode 100644
index 000000000..14a62f13c
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleIslandWindow.h
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "SampleBaseWindow.h"
+#include "../../../src/cascadia/inc/cppwinrt_utils.h"
+
+class SampleIslandWindow :
+ public BaseWindow
+{
+public:
+ SampleIslandWindow() noexcept;
+ virtual ~SampleIslandWindow() override;
+
+ virtual void MakeWindow() noexcept;
+ void Close();
+
+ virtual void OnSize(const UINT width, const UINT height);
+
+ [[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
+ void OnResize(const UINT width, const UINT height) override;
+ void OnMinimize() override;
+ void OnRestore() override;
+ virtual void OnAppInitialized();
+ virtual void SetContent(winrt::Windows::UI::Xaml::UIElement content);
+ virtual void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
+
+ virtual void Initialize();
+
+protected:
+ void ForceResize()
+ {
+ // Do a quick resize to force the island to paint
+ const auto size = GetPhysicalSize();
+ OnSize(size.cx, size.cy);
+ }
+
+ HWND _interopWindowHandle;
+
+ winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _source;
+
+ winrt::Windows::UI::Xaml::Controls::Grid _rootGrid;
+
+ void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
+};
diff --git a/scratch/ScratchIslandApp/WindowExe/SampleMain.cpp b/scratch/ScratchIslandApp/WindowExe/SampleMain.cpp
new file mode 100644
index 000000000..4c09f262c
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/SampleMain.cpp
@@ -0,0 +1,122 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "SampleAppHost.h"
+#include "resource.h"
+#include "../types/inc/User32Utils.hpp"
+#include
+
+using namespace winrt;
+using namespace winrt::Windows::UI;
+using namespace winrt::Windows::UI::Composition;
+using namespace winrt::Windows::UI::Xaml::Hosting;
+using namespace winrt::Windows::Foundation::Numerics;
+
+// Routine Description:
+// - Takes an image architecture and locates a string resource that maps to that architecture.
+// Arguments:
+// - imageArchitecture - An IMAGE_FILE_MACHINE architecture enum value
+// - See https://docs.microsoft.com/en-us/windows/win32/sysinfo/image-file-machine-constants
+// Return Value:
+// - A string value representing the human-readable name of this architecture.
+static std::wstring ImageArchitectureToString(USHORT imageArchitecture)
+{
+ // clang-format off
+ const auto id = imageArchitecture == IMAGE_FILE_MACHINE_I386 ? IDS_X86_ARCHITECTURE :
+ imageArchitecture == IMAGE_FILE_MACHINE_AMD64 ? IDS_AMD64_ARCHITECTURE :
+ imageArchitecture == IMAGE_FILE_MACHINE_ARM64 ? IDS_ARM64_ARCHITECTURE :
+ imageArchitecture == IMAGE_FILE_MACHINE_ARM ? IDS_ARM_ARCHITECTURE :
+ IDS_UNKNOWN_ARCHITECTURE;
+ // clang-format on
+
+ return GetStringResource(id);
+}
+
+// Routine Description:
+// - Blocks the user from launching the application with a message box dialog and early exit
+// if the process architecture doesn't match the system platform native architecture.
+// - This is because the conhost.exe must match the condrv.sys on the system and the PTY
+// infrastructure that powers everything won't work if we have a mismatch.
+// Arguments:
+// -
+// Return Value:
+// -
+static void EnsureNativeArchitecture()
+{
+ USHORT processMachine{};
+ USHORT nativeMachine{};
+ THROW_IF_WIN32_BOOL_FALSE(IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine));
+ if (processMachine != IMAGE_FILE_MACHINE_UNKNOWN && processMachine != nativeMachine)
+ {
+ const auto formatPattern = GetStringResource(IDS_ERROR_ARCHITECTURE_FORMAT);
+
+ const auto nativeArchitecture = ImageArchitectureToString(nativeMachine);
+ const auto processArchitecture = ImageArchitectureToString(processMachine);
+
+ auto buffer{ wil::str_printf(formatPattern.data(), nativeArchitecture.data(), processArchitecture.data()) };
+
+ MessageBoxW(nullptr,
+ buffer.data(),
+ GetStringResource(IDS_ERROR_DIALOG_TITLE).data(),
+ MB_OK | MB_ICONERROR);
+
+ ExitProcess(0);
+ }
+}
+
+static bool _messageIsF7Keypress(const MSG& message)
+{
+ return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7;
+}
+static bool _messageIsAltKeyup(const MSG& message)
+{
+ return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU;
+}
+
+int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
+{
+ // If Terminal is spawned by a shortcut that requests that it run in a new process group
+ // while attached to a console session, that request is nonsense. That request will, however,
+ // cause WT to start with Ctrl-C disabled. This wouldn't matter, because it's a Windows-subsystem
+ // application. Unfortunately, that state is heritable. In short, if you start WT using cmd in
+ // a weird way, ^C stops working _inside_ the terminal. Mad.
+ SetConsoleCtrlHandler(NULL, FALSE);
+
+ // Block the user from starting if they launched the incorrect architecture version of the project.
+ // This should only be applicable to developer versions. The package installation process
+ // should choose and install the correct one from the bundle.
+ EnsureNativeArchitecture();
+
+ // Make sure to call this so we get WM_POINTER messages.
+ EnableMouseInPointer(true);
+
+ // !!! LOAD BEARING !!!
+ // We must initialize the main thread as a single-threaded apartment before
+ // constructing any Xaml objects. Failing to do so will cause some issues
+ // in accessibility somewhere down the line when a UIAutomation object will
+ // be queried on the wrong thread at the wrong time.
+ // We used to initialize as STA only _after_ initializing the application
+ // host, which loaded the settings. The settings needed to be loaded in MTA
+ // because we were using the Windows.Storage APIs. Since we're no longer
+ // doing that, we can safely init as STA before any WinRT dispatches.
+ winrt::init_apartment(winrt::apartment_type::single_threaded);
+
+ // Create the SampleAppHost object, which will create both the window and the
+ // Terminal App. This MUST BE constructed before the Xaml manager as TermApp
+ // provides an implementation of Windows.UI.Xaml.Application.
+ SampleAppHost host;
+
+ // Initialize the xaml content. This must be called AFTER the
+ // WindowsXamlManager is initialized.
+ host.Initialize();
+
+ MSG message;
+
+ while (GetMessage(&message, nullptr, 0, 0))
+ {
+ TranslateMessage(&message);
+ DispatchMessage(&message);
+ }
+ return 0;
+}
diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.def b/scratch/ScratchIslandApp/WindowExe/WindowExe.def
new file mode 100644
index 000000000..5f282702b
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.def
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.manifest b/scratch/ScratchIslandApp/WindowExe/WindowExe.manifest
new file mode 100644
index 000000000..9d91e543d
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.manifest
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PerMonitorV2
+ true
+
+
+
diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.rc b/scratch/ScratchIslandApp/WindowExe/WindowExe.rc
new file mode 100644
index 000000000..b11a8c88d
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.rc
@@ -0,0 +1,97 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+IDI_APPICON ICON "..\\..\\..\\res\\terminal.ico"
+IDI_APPICON_HC_BLACK ICON "..\\..\\..\\res\\terminal\\images\\terminal_contrast-black.ico"
+IDI_APPICON_HC_WHITE ICON "..\\..\\..\\res\\terminal\\images\\terminal_contrast-white.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_ERROR_DIALOG_TITLE "Error"
+ IDS_HELP_DIALOG_TITLE "Help"
+ IDS_ERROR_ARCHITECTURE_FORMAT
+ "This sample is designed to run on your system's native architecture (%s).\nYou are currently using the %s version.\n\nPlease use the version of this sample that matches your system's native architecture."
+ IDS_X86_ARCHITECTURE "i386"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_AMD64_ARCHITECTURE "AMD64"
+ IDS_ARM64_ARCHITECTURE "ARM64"
+ IDS_ARM_ARCHITECTURE "ARM"
+ IDS_UNKNOWN_ARCHITECTURE "Unknown"
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj
new file mode 100644
index 000000000..edd372c2f
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj
@@ -0,0 +1,220 @@
+
+
+
+
+
+ {b4427499-9fde-4208-b456-5bc580637633}
+ Win32Proj
+ WindowExe
+ WindowExe
+ WindowExe
+ Application
+ false
+ Windows Store
+ true
+ false
+ Windows
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+ $(OpenConsoleDir)\src\inc;$(OpenConsoleDir)\dep;$(OpenConsoleDir)\dep\Console;$(OpenConsoleDir)\dep\Win32K;$(OpenConsoleDir)\dep\gsl\include;%(AdditionalIncludeDirectories);
+
+
+ %(AdditionalDependencies)
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(OpenConsoleCommonOutDir)TerminalCore\Microsoft.Terminal.Core.winmd
+ true
+ true
+ true
+
+
+ $(OpenConsoleCommonOutDir)TerminalConnection\Microsoft.Terminal.TerminalConnection.winmd
+ $(OpenConsoleCommonOutDir)TerminalConnection\TerminalConnection.dll
+ true
+ true
+ true
+
+
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.winmd
+ $(OpenConsoleCommonOutDir)Microsoft.Terminal.Control\Microsoft.Terminal.Control.dll
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+ WindowsLocalDebugger
+
+
+
+
+
+
+
+
+
+ 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}.
+
+
+
+
+
+
+
+
+
+ <_ContinueOnError Condition="'$(BuildingProject)' == 'true'">true
+ <_ContinueOnError Condition="'$(BuildingProject)' != 'true'">false
+
+
+
+
+
+
+
+
+
+
+
+
+ x86
+ $(Platform)
+
+
+
+
+ <_OpenConsoleVCLibToCopy Include="$(VCToolsRedistInstallDir)\$(ReasonablePlatform)\Microsoft.VC142.CRT\*.dll" />
+
+
+ $(ProjectName)
+ BuiltProjectOutputGroup
+ %(Filename)%(Extension)
+
+
+
+
+
+
+
+
+ <_TerminalConnectionDlls Include="$(OpenConsoleCommonOutDir)\TerminalConnection\*.dll" />
+
+
+ $(ProjectName)
+ BuiltProjectOutputGroup
+ %(Filename)%(Extension)
+
+
+
+
+
+
+ <_WindowsTerminalExe Include="$(OpenConsoleCommonOutDir)\WindowsTerminal\*.exe" />
+
+
+ $(ProjectName)
+ BuiltProjectOutputGroup
+ %(Filename)%(Extension)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/WindowExe/icon.cpp b/scratch/ScratchIslandApp/WindowExe/icon.cpp
new file mode 100644
index 000000000..ca194de06
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/icon.cpp
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "resource.h"
+
+static int _GetActiveAppIconResource()
+{
+ auto iconResource{ IDI_APPICON };
+
+ HIGHCONTRASTW hcInfo{};
+ hcInfo.cbSize = sizeof(hcInfo);
+
+ if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(hcInfo), &hcInfo, 0))
+ {
+ if (WI_IsFlagSet(hcInfo.dwFlags, HCF_HIGHCONTRASTON))
+ {
+ iconResource = IDI_APPICON_HC_BLACK;
+
+ if (0x00FFFFFF == GetSysColor(COLOR_WINDOW)) // white window color == white high contrast
+ {
+ iconResource = IDI_APPICON_HC_WHITE;
+ }
+ }
+ }
+
+ return iconResource;
+}
+
+void UpdateWindowIconForActiveMetrics(HWND window)
+{
+ auto iconResource{ MAKEINTRESOURCEW(_GetActiveAppIconResource()) };
+
+ // These handles are loaded with LR_SHARED, so they are safe to "leak".
+ HANDLE smallIcon{ LoadImageW(wil::GetModuleInstanceHandle(), iconResource, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED) };
+ LOG_LAST_ERROR_IF_NULL(smallIcon);
+
+ HANDLE largeIcon{ LoadImageW(wil::GetModuleInstanceHandle(), iconResource, IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_SHARED) };
+ LOG_LAST_ERROR_IF_NULL(largeIcon);
+
+ if (smallIcon)
+ {
+ SendMessageW(window, WM_SETICON, ICON_SMALL, reinterpret_cast(smallIcon));
+ }
+ if (largeIcon)
+ {
+ SendMessageW(window, WM_SETICON, ICON_BIG, reinterpret_cast(largeIcon));
+ }
+}
diff --git a/scratch/ScratchIslandApp/WindowExe/icon.h b/scratch/ScratchIslandApp/WindowExe/icon.h
new file mode 100644
index 000000000..5e418fc28
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/icon.h
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+void UpdateWindowIconForActiveMetrics(HWND window);
diff --git a/scratch/ScratchIslandApp/WindowExe/packages.config b/scratch/ScratchIslandApp/WindowExe/packages.config
new file mode 100644
index 000000000..409baff13
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/packages.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/scratch/ScratchIslandApp/WindowExe/pch.cpp b/scratch/ScratchIslandApp/WindowExe/pch.cpp
new file mode 100644
index 000000000..398a99f66
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
diff --git a/scratch/ScratchIslandApp/WindowExe/pch.h b/scratch/ScratchIslandApp/WindowExe/pch.h
new file mode 100644
index 000000000..de08907f8
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/pch.h
@@ -0,0 +1,82 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+
+Module Name:
+- pch.h
+
+Abstract:
+- Contains external headers to include in the precompile phase of console build process.
+- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building).
+--*/
+
+#pragma once
+
+// Ignore checked iterators warning from VC compiler.
+#define _SCL_SECURE_NO_WARNINGS
+
+// Block minwindef.h min/max macros to prevent conflict
+#define NOMINMAX
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMCX
+#define NOHELP
+#define NOCOMM
+
+#include
+
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Manually include til after we include Windows.Foundation to give it winrt superpowers
+#define BLOCK_TIL
+#include "../inc/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
+
+// Needed just for XamlIslands to work at all:
+#include
+#include
+#include
+#include
+
+// Additional headers for various xaml features. We need:
+// * Core so we can resume_foreground with CoreDispatcher
+// * Controls for grid
+// * Media for ScaleTransform
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+// Including TraceLogging essentials for the binary
+#include
+#include
+TRACELOGGING_DECLARE_PROVIDER(g_hWindowsTerminalProvider);
+#include
+#include
+
+// For commandline argument processing
+#include
+#include
+#include
+#include "til.h"
diff --git a/scratch/ScratchIslandApp/WindowExe/resource.h b/scratch/ScratchIslandApp/WindowExe/resource.h
new file mode 100644
index 000000000..7e2918600
--- /dev/null
+++ b/scratch/ScratchIslandApp/WindowExe/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by WindowsTerminal.rc
+//
+#define IDI_APPICON 101
+#define IDI_APPICON_HC_BLACK 102
+#define IDI_APPICON_HC_WHITE 103
+
+#define IDS_ERROR_DIALOG_TITLE 105
+#define IDS_HELP_DIALOG_TITLE 106
+#define IDS_ERROR_ARCHITECTURE_FORMAT 110
+#define IDS_X86_ARCHITECTURE 111
+#define IDS_AMD64_ARCHITECTURE 112
+#define IDS_ARM64_ARCHITECTURE 113
+#define IDS_ARM_ARCHITECTURE 114
+#define IDS_UNKNOWN_ARCHITECTURE 115
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp
index 97251b8b2..164ac0bb8 100644
--- a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp
@@ -229,10 +229,12 @@ namespace SettingsModelLocalTests
void SerializationTests::Actions()
{
+ // simple command
const std::string actionsString1{ R"([
{ "command": "paste" }
])" };
+ // complex command
const std::string actionsString2A{ R"([
{ "command": { "action": "setTabColor" } }
])" };
@@ -244,29 +246,35 @@ namespace SettingsModelLocalTests
{ "command": { "action": "copy", "singleLine": true, "copyFormatting": "html" } }
])" };
+ // simple command with key chords
const std::string actionsString3{ R"([
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+a" },
{ "command": "toggleAlwaysOnTop", "keys": "ctrl+b" }
])" };
+ // complex command with key chords
const std::string actionsString4{ R"([
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" },
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" }
])" };
+ // command with name and icon and multiple key chords
const std::string actionsString5{ R"([
{ "icon": "image.png", "name": "Scroll To Top Name", "command": "scrollToTop", "keys": "ctrl+e" },
{ "command": "scrollToTop", "keys": "ctrl+f" }
])" };
+ // complex command with new terminal args
const std::string actionsString6{ R"([
{ "command": { "action": "newTab", "index": 0 }, "keys": "ctrl+g" },
])" };
+ // complex command with meaningful null arg
const std::string actionsString7{ R"([
{ "command": { "action": "renameWindow", "name": null }, "keys": "ctrl+h" }
])" };
+ // nested command
const std::string actionsString8{ R"([
{
"name": "Change font size...",
@@ -278,6 +286,7 @@ namespace SettingsModelLocalTests
}
])" };
+ // iterable command
const std::string actionsString9A{ R"([
{
"name": "New tab",
@@ -330,7 +339,20 @@ namespace SettingsModelLocalTests
"name": "Send Input (Evil) ..."
}
])"" };
+ const std::string actionsString9D{ R""([
+ {
+ "command":
+ {
+ "action": "newTab",
+ "profile": "${profile.name}"
+ },
+ "icon": "${profile.icon}",
+ "iterateOn": "profiles",
+ "name": "${profile.name}: New tab"
+ }
+ ])"" };
+ // unbound command
const std::string actionsString10{ R"([
{ "command": "unbound", "keys": "ctrl+c" }
])" };
@@ -365,6 +387,7 @@ namespace SettingsModelLocalTests
RoundtripTest(actionsString9A);
RoundtripTest(actionsString9B);
RoundtripTest(actionsString9C);
+ RoundtripTest(actionsString9D);
Log::Comment(L"unbound command");
RoundtripTest(actionsString10);
diff --git a/src/cascadia/TerminalApp/App.xaml b/src/cascadia/TerminalApp/App.xaml
index 88630a11c..a0678e05e 100644
--- a/src/cascadia/TerminalApp/App.xaml
+++ b/src/cascadia/TerminalApp/App.xaml
@@ -47,6 +47,9 @@
8,0,8,0
+
+ 12
+
diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp
index 449d19b6b..6d60c146b 100644
--- a/src/cascadia/TerminalApp/AppLogic.cpp
+++ b/src/cascadia/TerminalApp/AppLogic.cpp
@@ -306,7 +306,8 @@ namespace winrt::TerminalApp::implementation
});
_root->Create();
- _ApplyTheme(_settings.GlobalSettings().Theme());
+ _ApplyLanguageSettingChange();
+ _RefreshThemeRoutine();
_ApplyStartupTaskStateChange();
TraceLoggingWrite(
@@ -895,36 +896,38 @@ namespace winrt::TerminalApp::implementation
// this stops us from reloading too many times or too quickly.
fire_and_forget AppLogic::_DispatchReloadSettings()
{
- static constexpr auto FileActivityQuiesceTime{ std::chrono::milliseconds(50) };
- if (!_settingsReloadQueued.exchange(true))
+ if (_settingsReloadQueued.exchange(true))
+ {
+ co_return;
+ }
+
+ auto weakSelf = get_weak();
+
+ co_await winrt::resume_after(std::chrono::milliseconds(100));
+ co_await winrt::resume_foreground(_root->Dispatcher());
+
+ if (auto self{ weakSelf.get() })
{
- co_await winrt::resume_after(FileActivityQuiesceTime);
_ReloadSettings();
_settingsReloadQueued.store(false);
}
}
- fire_and_forget AppLogic::_LoadErrorsDialogRoutine()
+ void AppLogic::_ApplyLanguageSettingChange()
{
- co_await winrt::resume_foreground(_root->Dispatcher());
+ using ApplicationLanguages = winrt::Windows::Globalization::ApplicationLanguages;
- const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle");
- const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText");
- _ShowLoadErrorsDialog(titleKey, textKey, _settingsLoadedResult);
+ const auto language = _settings.GlobalSettings().Language();
+ const auto primaryLanguageOverride = ApplicationLanguages::PrimaryLanguageOverride();
+
+ if (primaryLanguageOverride != language)
+ {
+ ApplicationLanguages::PrimaryLanguageOverride(language);
+ }
}
- fire_and_forget AppLogic::_ShowLoadWarningsDialogRoutine()
+ void AppLogic::_RefreshThemeRoutine()
{
- co_await winrt::resume_foreground(_root->Dispatcher());
-
- _ShowLoadWarningsDialog();
- }
-
- fire_and_forget AppLogic::_RefreshThemeRoutine()
- {
- co_await winrt::resume_foreground(_root->Dispatcher());
-
- // Refresh the UI theme
_ApplyTheme(_settings.GlobalSettings().Theme());
}
@@ -959,39 +962,26 @@ namespace winrt::TerminalApp::implementation
return;
}
- auto weakThis{ get_weak() };
- co_await winrt::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Normal);
- if (auto page{ weakThis.get() })
- {
- StartupTaskState state;
- bool tryEnableStartupTask = _settings.GlobalSettings().StartOnUserLogin();
- StartupTask task = co_await StartupTask::GetAsync(StartupTaskName);
+ const auto tryEnableStartupTask = _settings.GlobalSettings().StartOnUserLogin();
+ const auto task = co_await StartupTask::GetAsync(StartupTaskName);
- state = task.State();
- switch (state)
+ switch (task.State())
+ {
+ case StartupTaskState::Disabled:
+ if (tryEnableStartupTask)
{
- case StartupTaskState::Disabled:
+ co_await task.RequestEnableAsync();
+ }
+ break;
+ case StartupTaskState::DisabledByUser:
+ // TODO: GH#6254: define UX for other StartupTaskStates
+ break;
+ case StartupTaskState::Enabled:
+ if (!tryEnableStartupTask)
{
- if (tryEnableStartupTask)
- {
- co_await task.RequestEnableAsync();
- }
- break;
- }
- case StartupTaskState::DisabledByUser:
- {
- // TODO: GH#6254: define UX for other StartupTaskStates
- break;
- }
- case StartupTaskState::Enabled:
- {
- if (!tryEnableStartupTask)
- {
- task.Disable();
- }
- break;
- }
+ task.Disable();
}
+ break;
}
}
CATCH_LOG();
@@ -1009,12 +999,15 @@ namespace winrt::TerminalApp::implementation
if (FAILED(_settingsLoadedResult))
{
- _LoadErrorsDialogRoutine();
+ const winrt::hstring titleKey = USES_RESOURCE(L"ReloadJsonParseErrorTitle");
+ const winrt::hstring textKey = USES_RESOURCE(L"ReloadJsonParseErrorText");
+ _ShowLoadErrorsDialog(titleKey, textKey, _settingsLoadedResult);
return;
}
- else if (_settingsLoadedResult == S_FALSE)
+
+ if (_settingsLoadedResult == S_FALSE)
{
- _ShowLoadWarningsDialogRoutine();
+ _ShowLoadWarningsDialog();
}
// Here, we successfully reloaded the settings, and created a new
@@ -1023,6 +1016,7 @@ namespace winrt::TerminalApp::implementation
// Update the settings in TerminalPage
_root->SetSettings(_settings, true);
+ _ApplyLanguageSettingChange();
_RefreshThemeRoutine();
_ApplyStartupTaskStateChange();
diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h
index 50b7b95f0..ad520894b 100644
--- a/src/cascadia/TerminalApp/AppLogic.h
+++ b/src/cascadia/TerminalApp/AppLogic.h
@@ -124,18 +124,15 @@ namespace winrt::TerminalApp::implementation
::TerminalApp::AppCommandlineArgs _appArgs;
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
- int _ParseArgs(winrt::array_view& args);
static TerminalApp::FindTargetWindowResult _doFindTargetWindow(winrt::array_view args,
const Microsoft::Terminal::Settings::Model::WindowingMode& windowingBehavior);
void _ShowLoadErrorsDialog(const winrt::hstring& titleKey, const winrt::hstring& contentKey, HRESULT settingsLoadedResult);
void _ShowLoadWarningsDialog();
bool _IsKeyboardServiceEnabled();
- void _ShowKeyboardServiceDisabledDialog();
- fire_and_forget _LoadErrorsDialogRoutine();
- fire_and_forget _ShowLoadWarningsDialogRoutine();
- fire_and_forget _RefreshThemeRoutine();
+ void _ApplyLanguageSettingChange();
+ void _RefreshThemeRoutine();
fire_and_forget _ApplyStartupTaskStateChange();
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
diff --git a/src/cascadia/TerminalApp/ColorPickupFlyout.cpp b/src/cascadia/TerminalApp/ColorPickupFlyout.cpp
index b1c15be48..ed1d20b83 100644
--- a/src/cascadia/TerminalApp/ColorPickupFlyout.cpp
+++ b/src/cascadia/TerminalApp/ColorPickupFlyout.cpp
@@ -96,7 +96,7 @@ namespace winrt::TerminalApp::implementation
Hide();
}
- void ColorPickupFlyout::ColorPicker_ColorChanged(const Windows::UI::Xaml::Controls::ColorPicker&, const Windows::UI::Xaml::Controls::ColorChangedEventArgs& args)
+ void ColorPickupFlyout::ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args)
{
_ColorSelectedHandlers(args.NewColor());
}
diff --git a/src/cascadia/TerminalApp/ColorPickupFlyout.h b/src/cascadia/TerminalApp/ColorPickupFlyout.h
index c73f68881..b124dfe43 100644
--- a/src/cascadia/TerminalApp/ColorPickupFlyout.h
+++ b/src/cascadia/TerminalApp/ColorPickupFlyout.h
@@ -12,7 +12,7 @@ namespace winrt::TerminalApp::implementation
void ShowColorPickerButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void CustomColorButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void ClearColorButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
- void ColorPicker_ColorChanged(const Windows::UI::Xaml::Controls::ColorPicker&, const Windows::UI::Xaml::Controls::ColorChangedEventArgs& args);
+ void ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args);
WINRT_CALLBACK(ColorCleared, TerminalApp::ColorClearedArgs);
WINRT_CALLBACK(ColorSelected, TerminalApp::ColorSelectedArgs);
diff --git a/src/cascadia/TerminalApp/ColorPickupFlyout.xaml b/src/cascadia/TerminalApp/ColorPickupFlyout.xaml
index 7674b357e..b7da875af 100644
--- a/src/cascadia/TerminalApp/ColorPickupFlyout.xaml
+++ b/src/cascadia/TerminalApp/ColorPickupFlyout.xaml
@@ -4,190 +4,200 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+ Content="Reset" />
+
+
-
+
+ Content="OK"
+ Style="{ThemeResource AccentButtonStyle}" />
diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
index 27b1460a9..2e35662e3 100644
--- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
@@ -634,4 +634,7 @@
Restore Down
+
+ Command Palette
+
\ No newline at end of file
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 18afb5962..7a836a23f 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -92,31 +92,26 @@ namespace winrt::TerminalApp::implementation
}
}
- winrt::fire_and_forget TerminalPage::SetSettings(CascadiaSettings settings, bool needRefreshUI)
+ void TerminalPage::SetSettings(CascadiaSettings settings, bool needRefreshUI)
{
_settings = settings;
- auto weakThis{ get_weak() };
- co_await winrt::resume_foreground(Dispatcher());
- if (auto page{ weakThis.get() })
+ // Make sure to _UpdateCommandsForPalette before
+ // _RefreshUIForSettingsReload. _UpdateCommandsForPalette will make
+ // sure the KeyChordText of Commands is updated, which needs to
+ // happen before the Settings UI is reloaded and tries to re-read
+ // those values.
+ _UpdateCommandsForPalette();
+ CommandPalette().SetActionMap(_settings.ActionMap());
+
+ if (needRefreshUI)
{
- // Make sure to _UpdateCommandsForPalette before
- // _RefreshUIForSettingsReload. _UpdateCommandsForPalette will make
- // sure the KeyChordText of Commands is updated, which needs to
- // happen before the Settings UI is reloaded and tries to re-read
- // those values.
- _UpdateCommandsForPalette();
- CommandPalette().SetActionMap(_settings.ActionMap());
-
- if (needRefreshUI)
- {
- _RefreshUIForSettingsReload();
- }
-
- // Upon settings update we reload the system settings for scrolling as well.
- // TODO: consider reloading this value periodically.
- _systemRowsToScroll = _ReadSystemRowsToScroll();
+ _RefreshUIForSettingsReload();
}
+
+ // Upon settings update we reload the system settings for scrolling as well.
+ // TODO: consider reloading this value periodically.
+ _systemRowsToScroll = _ReadSystemRowsToScroll();
}
void TerminalPage::Create()
@@ -553,7 +548,7 @@ namespace winrt::TerminalApp::implementation
// attaches it to the button. Populates the flyout with one entry per
// Profile, displaying the profile's name. Clicking each flyout item will
// open a new tab with that profile.
- // Below the profiles are the static menu items: settings, feedback
+ // Below the profiles are the static menu items: settings, command palette
void TerminalPage::_CreateNewTabFlyout()
{
auto newTabFlyout = WUX::Controls::MenuFlyout{};
@@ -703,17 +698,23 @@ namespace winrt::TerminalApp::implementation
_SetAcceleratorForMenuItem(settingsItem, settingsKeyChord);
}
- // Create the feedback button.
- auto feedbackFlyout = WUX::Controls::MenuFlyoutItem{};
- feedbackFlyout.Text(RS_(L"FeedbackMenuItem"));
+ // Create the command palette button.
+ auto commandPaletteFlyout = WUX::Controls::MenuFlyoutItem{};
+ commandPaletteFlyout.Text(RS_(L"CommandPaletteMenuItem"));
- WUX::Controls::FontIcon feedbackIcon{};
- feedbackIcon.Glyph(L"\xE939");
- feedbackIcon.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
- feedbackFlyout.Icon(feedbackIcon);
+ WUX::Controls::FontIcon commandPaletteIcon{};
+ commandPaletteIcon.Glyph(L"\xE945");
+ commandPaletteIcon.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
+ commandPaletteFlyout.Icon(commandPaletteIcon);
- feedbackFlyout.Click({ this, &TerminalPage::_FeedbackButtonOnClick });
- newTabFlyout.Items().Append(feedbackFlyout);
+ commandPaletteFlyout.Click({ this, &TerminalPage::_CommandPaletteButtonOnClick });
+ newTabFlyout.Items().Append(commandPaletteFlyout);
+
+ const auto commandPaletteKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::ToggleCommandPalette) };
+ if (commandPaletteKeyChord)
+ {
+ _SetAcceleratorForMenuItem(commandPaletteFlyout, commandPaletteKeyChord);
+ }
}
// Create the about button.
@@ -884,15 +885,12 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
- // - Called when the feedback button is clicked. Launches github in your
- // default browser, navigated to the "issues" page of the Terminal repo.
- void TerminalPage::_FeedbackButtonOnClick(const IInspectable&,
- const RoutedEventArgs&)
+ // - Called when the command palette button is clicked. Opens the command palette.
+ void TerminalPage::_CommandPaletteButtonOnClick(const IInspectable&,
+ const RoutedEventArgs&)
{
- const auto feedbackUriValue = RS_(L"FeedbackUriValue");
- winrt::Windows::Foundation::Uri feedbackUri{ feedbackUriValue };
-
- winrt::Windows::System::Launcher::LaunchUriAsync(feedbackUri);
+ CommandPalette().EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
+ CommandPalette().Visibility(Visibility::Visible);
}
// Method Description:
@@ -1830,7 +1828,7 @@ namespace winrt::TerminalApp::implementation
// This includes update the settings of all the tabs according
// to their profiles, update the title and icon of each tab, and
// finally create the tab flyout
- winrt::fire_and_forget TerminalPage::_RefreshUIForSettingsReload()
+ void TerminalPage::_RefreshUIForSettingsReload()
{
// Re-wire the keybindings to their handlers, as we'll have created a
// new AppKeyBindings object.
@@ -1885,17 +1883,10 @@ namespace winrt::TerminalApp::implementation
tabImpl->SetActionMap(_settings.ActionMap());
}
- auto weakThis{ get_weak() };
-
- co_await winrt::resume_foreground(Dispatcher());
-
// repopulate the new tab button's flyout with entries for each
// profile, which might have changed
- if (auto page{ weakThis.get() })
- {
- _UpdateTabWidthMode();
- _CreateNewTabFlyout();
- }
+ _UpdateTabWidthMode();
+ _CreateNewTabFlyout();
// Reload the current value of alwaysOnTop from the settings file. This
// will let the user hot-reload this setting, but any runtime changes to
diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h
index 9de1ded9b..1b08f8717 100644
--- a/src/cascadia/TerminalApp/TerminalPage.h
+++ b/src/cascadia/TerminalApp/TerminalPage.h
@@ -54,7 +54,7 @@ namespace winrt::TerminalApp::implementation
// put it in our inheritance graph. https://github.com/microsoft/microsoft-ui-xaml/issues/3331
STDMETHODIMP Initialize(HWND hwnd);
- winrt::fire_and_forget SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI);
+ void SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI);
void Create();
@@ -67,8 +67,6 @@ namespace winrt::TerminalApp::implementation
winrt::hstring ApplicationDisplayName();
winrt::hstring ApplicationVersion();
- winrt::hstring ThirdPartyNoticesLink();
-
winrt::fire_and_forget CloseWindow();
void ToggleFocusMode();
@@ -196,7 +194,7 @@ namespace winrt::TerminalApp::implementation
bool _displayingCloseDialog{ false };
void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
- void _FeedbackButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
+ void _CommandPaletteButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
@@ -296,7 +294,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
- winrt::fire_and_forget _RefreshUIForSettingsReload();
+ void _RefreshUIForSettingsReload();
void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor);
void _ClearNonClientAreaColors();
diff --git a/src/cascadia/TerminalApp/pch.h b/src/cascadia/TerminalApp/pch.h
index f2c566352..299d7de63 100644
--- a/src/cascadia/TerminalApp/pch.h
+++ b/src/cascadia/TerminalApp/pch.h
@@ -25,40 +25,39 @@
#include
-#include
-
-#include
-
+#include
+#include
#include
#include
#include
+#include
#include
-#include
-#include
+#include
+#include
+#include
#include
+#include
+#include
#include
#include
-#include
-#include
+#include
+#include
+#include
+#include
#include
-#include
-#include
-#include "winrt/Windows.UI.Xaml.Markup.h"
-#include "winrt/Windows.UI.Xaml.Documents.h"
-#include "winrt/Windows.UI.Xaml.Automation.h"
-#include "winrt/Windows.UI.Xaml.Automation.Peers.h"
-#include "winrt/Windows.UI.ViewManagement.h"
-#include
-#include
#include
#include
#include
#include
-#include
+#include
+#include
+#include
+#include
+#include
-#include
+#include
// Including TraceLogging essentials for the binary
#include
@@ -70,14 +69,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
#include
#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
#include
// Manually include til after we include Windows.Foundation to give it winrt superpowers
diff --git a/src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp b/src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp
index b4c7dcea3..3e4d39e6b 100644
--- a/src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp
+++ b/src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp
@@ -17,6 +17,13 @@ using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Media;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Microsoft::UI::Xaml::Controls;
+
+namespace winrt
+{
+ namespace MUX = Microsoft::UI::Xaml;
+ namespace WUX = Windows::UI::Xaml;
+}
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
@@ -217,10 +224,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Return Value:
// -
void ColorSchemes::ColorPickerChanged(IInspectable const& sender,
- ColorChangedEventArgs const& args)
+ MUX::Controls::ColorChangedEventArgs const& args)
{
const til::color newColor{ args.NewColor() };
- if (const auto& picker{ sender.try_as() })
+ if (const auto& picker{ sender.try_as() })
{
if (const auto& tag{ picker.Tag() })
{
diff --git a/src/cascadia/TerminalSettingsEditor/ColorSchemes.h b/src/cascadia/TerminalSettingsEditor/ColorSchemes.h
index c651e53dd..23da46f5f 100644
--- a/src/cascadia/TerminalSettingsEditor/ColorSchemes.h
+++ b/src/cascadia/TerminalSettingsEditor/ColorSchemes.h
@@ -27,7 +27,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void ColorSchemeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& args);
- void ColorPickerChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::ColorChangedEventArgs const& args);
+ void ColorPickerChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::ColorChangedEventArgs const& args);
void AddNew_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void Rename_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
diff --git a/src/cascadia/TerminalSettingsEditor/ColorSchemes.xaml b/src/cascadia/TerminalSettingsEditor/ColorSchemes.xaml
index fa43ef5c7..a381d6ee1 100644
--- a/src/cascadia/TerminalSettingsEditor/ColorSchemes.xaml
+++ b/src/cascadia/TerminalSettingsEditor/ColorSchemes.xaml
@@ -82,9 +82,9 @@
-
+
diff --git a/src/cascadia/TerminalSettingsEditor/Converters.idl b/src/cascadia/TerminalSettingsEditor/Converters.idl
index 58fb27db0..89eb05791 100644
--- a/src/cascadia/TerminalSettingsEditor/Converters.idl
+++ b/src/cascadia/TerminalSettingsEditor/Converters.idl
@@ -39,6 +39,11 @@ namespace Microsoft.Terminal.Settings.Editor
PercentageConverter();
};
+ runtimeclass PercentageSignConverter : [default] Windows.UI.Xaml.Data.IValueConverter
+ {
+ PercentageSignConverter();
+ };
+
runtimeclass StringIsEmptyConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
StringIsEmptyConverter();
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
index 7556dc067..1c53db7dd 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
@@ -2,10 +2,12 @@
// Licensed under the MIT license.
#include "pch.h"
+#include "EnumEntry.h"
#include "GlobalAppearance.h"
#include "GlobalAppearance.g.cpp"
#include "GlobalAppearancePageNavigationState.g.cpp"
-#include "EnumEntry.h"
+
+#include
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
@@ -16,6 +18,11 @@ using namespace winrt::Windows::Foundation::Collections;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
+ // For ComboBox an empty SelectedItem string denotes no selection.
+ // What we want instead is for "Use system language" to be selected by default.
+ // --> "und" is synonymous for "Use system language".
+ constexpr std::wstring_view systemLanguageTag{ L"und" };
+
GlobalAppearance::GlobalAppearance()
{
InitializeComponent();
@@ -28,4 +35,139 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_State = e.Parameter().as();
}
+
+ winrt::hstring GlobalAppearance::LanguageDisplayConverter(const winrt::hstring& tag)
+ {
+ if (tag == systemLanguageTag)
+ {
+ return RS_(L"Globals_LanguageDefault");
+ }
+
+ winrt::Windows::Globalization::Language language{ tag };
+ return language.NativeName();
+ }
+
+ // Returns the list of languages the user may override the application language with.
+ // The returned list are BCP 47 language tags like {"und", "en-US", "de-DE", "es-ES", ...}.
+ // "und" is short for "undefined" and is synonymous for "Use system language" in this code.
+ winrt::Windows::Foundation::Collections::IObservableVector GlobalAppearance::LanguageList()
+ {
+ if (_languageList)
+ {
+ return _languageList;
+ }
+
+ // In order to return the language list this code does the following:
+ // [1] Get all possible languages we want to allow the user to choose.
+ // We have to acquire languages from multiple sources, creating duplicates. See below at [1].
+ // [2] Sort languages by their ASCII tags, forcing the UI in a consistent/stable order.
+ // I wanted to sort the localized language names initially, but it turned out to be complex.
+ // [3] Remove potential duplicates in our language list from [1].
+ // We don't want to have en-US twice in the list, do we?
+ // [4] Optionally remove unwanted language tags (like pseudo-localizations).
+
+ std::vector tags;
+
+ // [1]:
+ {
+ // ManifestLanguages contains languages the app ships with.
+ //
+ // Languages is a computed list that merges the ManifestLanguages with the
+ // user's ranked list of preferred languages taken from the system settings.
+ // As is tradition the API documentation is incomplete though, as it can also
+ // contain regional language variants. If our app supports en-US, but the user
+ // has en-GB or en-DE in their system's preferred language list, Languages will
+ // contain those as well, as they're variants from a supported language. We should
+ // allow a user to select those, as regional formattings can vary significantly.
+ const std::array tagSources{
+ winrt::Windows::Globalization::ApplicationLanguages::ManifestLanguages(),
+ winrt::Windows::Globalization::ApplicationLanguages::Languages()
+ };
+
+ // tags will hold all the flattened results from tagSources.
+ // We resize() the vector to the proper size in order to efficiently GetMany() all items.
+ tags.resize(std::accumulate(
+ tagSources.begin(),
+ tagSources.end(),
+ // tags[0] will be "und" - the "Use system language" item
+ // tags[1..n] will contain tags from tagSources.
+ // --> totalTags is offset by 1
+ 1,
+ [](uint32_t sum, const auto& v) -> uint32_t {
+ return sum + v.Size();
+ }));
+
+ // As per the function definition, the first item
+ // is always "Use system language" ("und").
+ auto data = tags.data();
+ *data++ = systemLanguageTag;
+
+ // Finally GetMany() all the tags from tagSources.
+ for (const auto& v : tagSources)
+ {
+ const auto size = v.Size();
+ v.GetMany(0, winrt::array_view(data, size));
+ data += size;
+ }
+ }
+
+ // NOTE: The size of tags is always >0, due to tags[0] being hardcoded to "und".
+ const auto tagsBegin = ++tags.begin();
+ const auto tagsEnd = tags.end();
+
+ // [2]:
+ std::sort(tagsBegin, tagsEnd);
+
+ // I'd love for both, std::unique and std::remove_if, to occur in a single loop,
+ // but the code turned out to be complex and even less maintainable, so I gave up.
+ {
+ // [3] part 1:
+ auto it = std::unique(tagsBegin, tagsEnd);
+
+ // The qps- languages are useful for testing ("pseudo-localization").
+ // --> Leave them in if debug features are enabled.
+ if (!_State.Globals().DebugFeaturesEnabled())
+ {
+ // [4] part 1:
+ it = std::remove_if(tagsBegin, it, [](const winrt::hstring& tag) -> bool {
+ return til::starts_with(tag, L"qps-");
+ });
+ }
+
+ // [3], [4] part 2 (completing the so called "erase-remove idiom"):
+ tags.erase(it, tagsEnd);
+ }
+
+ _languageList = winrt::single_threaded_observable_vector(std::move(tags));
+ return _languageList;
+ }
+
+ winrt::Windows::Foundation::IInspectable GlobalAppearance::CurrentLanguage()
+ {
+ if (_currentLanguage.empty())
+ {
+ _currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
+ if (_currentLanguage.empty())
+ {
+ _currentLanguage = systemLanguageTag;
+ }
+ }
+
+ return winrt::box_value(_currentLanguage);
+ }
+
+ void GlobalAppearance::CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag)
+ {
+ _currentLanguage = winrt::unbox_value(tag);
+
+ const auto globals = _State.Globals();
+ if (_currentLanguage == systemLanguageTag)
+ {
+ globals.ClearLanguage();
+ }
+ else
+ {
+ globals.Language(_currentLanguage);
+ }
+ }
}
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
index dddbf23f5..484fb1441 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
@@ -26,9 +26,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
WINRT_PROPERTY(Editor::GlobalAppearancePageNavigationState, State, nullptr);
-
GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals, Theme);
GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals, TabWidthMode);
+
+ public:
+ // LanguageDisplayConverter maps the given BCP 47 tag to a localized string.
+ // For instance "en-US" produces "English (United States)", while "de-DE" produces
+ // "Deutsch (Deutschland)". This works independently of the user's locale.
+ static winrt::hstring LanguageDisplayConverter(const winrt::hstring& tag);
+
+ winrt::Windows::Foundation::Collections::IObservableVector LanguageList();
+ winrt::Windows::Foundation::IInspectable CurrentLanguage();
+ void CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag);
+
+ private:
+ std::vector _GetSupportedLanguageTags();
+
+ winrt::Windows::Foundation::Collections::IObservableVector _languageList{ nullptr };
+ winrt::hstring _currentLanguage;
};
}
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
index 294f73022..8901b9934 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-import "EnumEntry.idl";
+import "EnumEntry.idl";
namespace Microsoft.Terminal.Settings.Editor
{
@@ -15,6 +15,10 @@ namespace Microsoft.Terminal.Settings.Editor
GlobalAppearance();
GlobalAppearancePageNavigationState State { get; };
+ static String LanguageDisplayConverter(String tag);
+ Windows.Foundation.Collections.IObservableVector LanguageList { get; };
+ IInspectable CurrentLanguage;
+
IInspectable CurrentTheme;
Windows.Foundation.Collections.IObservableVector ThemeList { get; };
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
index 84c1408ae..7b33b45d0 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
@@ -28,9 +28,21 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.cpp b/src/cascadia/TerminalSettingsEditor/MainPage.cpp
index fc256a9f4..69d52294e 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.cpp
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.cpp
@@ -65,13 +65,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// - settings - the new settings source
// Return value:
// -
- fire_and_forget MainPage::UpdateSettings(Model::CascadiaSettings settings)
+ void MainPage::UpdateSettings(const Model::CascadiaSettings& settings)
{
_settingsSource = settings;
_settingsClone = settings.Copy();
- co_await winrt::resume_foreground(Dispatcher());
-
// Deduce information about the currently selected item
IInspectable selectedItemTag;
auto menuItems{ SettingsNav().MenuItems() };
@@ -83,34 +81,43 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
- // remove all profile-related NavViewItems by populating a std::vector
- // with the ones we want to keep.
- // NOTE: menuItems.Remove() causes an out-of-bounds crash. Using ReplaceAll()
- // gets around this crash.
- std::vector menuItemsSTL;
- for (const auto& item : menuItems)
- {
- if (const auto& navViewItem{ item.try_as() })
- {
- if (const auto& tag{ navViewItem.Tag() })
- {
- if (tag.try_as())
+ // We'll remove a bunch of items and iterate over it twice.
+ // --> Copy it into an STL vector to simplify our code and reduce COM overhead.
+ std::vector menuItemsSTL(menuItems.Size(), nullptr);
+ menuItems.GetMany(0, menuItemsSTL);
+
+ // We want to refresh the list of profiles in the NavigationView.
+ // In order to add profiles we can use _InitializeProfilesList();
+ // But before we can do that we have to remove existing profiles first of course.
+ // This "erase-remove" idiom will achieve just that.
+ menuItemsSTL.erase(
+ std::remove_if(
+ menuItemsSTL.begin(),
+ menuItemsSTL.end(),
+ [](const auto& item) -> bool {
+ if (const auto& navViewItem{ item.try_as() })
{
- // don't add NavViewItem pointing to a Profile
- continue;
- }
- else if (const auto& stringTag{ tag.try_as() })
- {
- if (stringTag == addProfileTag)
+ if (const auto& tag{ navViewItem.Tag() })
{
- // don't add the "Add Profile" item
- continue;
+ if (tag.try_as())
+ {
+ // remove NavViewItem pointing to a Profile
+ return true;
+ }
+ if (const auto& stringTag{ tag.try_as() })
+ {
+ if (stringTag == addProfileTag)
+ {
+ // remove the "Add Profile" item
+ return true;
+ }
+ }
}
}
- }
- }
- menuItemsSTL.emplace_back(item);
- }
+ return false;
+ }),
+ menuItemsSTL.end());
+
menuItems.ReplaceAll(menuItemsSTL);
// Repopulate profile-related menu items
@@ -123,7 +130,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// refresh the current page using the SelectedItem data we collected before the refresh
if (selectedItemTag)
{
- for (const auto& item : menuItems)
+ for (const auto& item : menuItemsSTL)
{
if (const auto& menuItem{ item.try_as() })
{
@@ -138,7 +145,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
_Navigate(*stringTag);
- co_return;
+ return;
}
}
}
@@ -151,7 +158,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
_Navigate(*profileTag);
- co_return;
+ return;
}
}
}
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.h b/src/cascadia/TerminalSettingsEditor/MainPage.h
index 677b7c6d1..401c2576e 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.h
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.h
@@ -13,7 +13,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
MainPage() = delete;
MainPage(const Model::CascadiaSettings& settings);
- fire_and_forget UpdateSettings(Model::CascadiaSettings settings);
+ void UpdateSettings(const Model::CascadiaSettings& settings);
void OpenJsonKeyDown(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& args);
void OpenJsonTapped(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs const& args);
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
index de8f8435b..a3df59932 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
@@ -60,6 +60,9 @@
Converters.idl
+
+ Converters.idl
+
Converters.idl
@@ -167,6 +170,9 @@
Converters.idl
+
+ Converters.idl
+
Converters.idl
@@ -332,4 +338,4 @@
-
+
\ No newline at end of file
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
index ba44e4844..4273f715d 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
@@ -10,10 +10,16 @@
+
+ Converters
+
+
+ Converters
+
@@ -43,4 +49,4 @@
{00f725c8-41b4-40a8-995e-8ee2e49a4a4c}
-
+
\ No newline at end of file
diff --git a/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.cpp b/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.cpp
new file mode 100644
index 000000000..a8acb84d1
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.cpp
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "PercentageSignConverter.h"
+#include "PercentageSignConverter.g.cpp"
+
+using namespace winrt::Windows;
+using namespace winrt::Windows::UI::Xaml;
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ Foundation::IInspectable PercentageSignConverter::Convert(Foundation::IInspectable const& value,
+ Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
+ Foundation::IInspectable const& /* parameter */,
+ hstring const& /* language */)
+ {
+ const auto number{ winrt::unbox_value(value) };
+ return winrt::box_value(to_hstring((int)number) + L"%");
+ }
+
+ Foundation::IInspectable PercentageSignConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
+ Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
+ Foundation::IInspectable const& /*parameter*/,
+ hstring const& /* language */)
+ {
+ throw hresult_not_implemented();
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.h b/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.h
new file mode 100644
index 000000000..08b4f13b3
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/PercentageSignConverter.h
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "PercentageSignConverter.g.h"
+#include "Utils.h"
+
+DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, PercentageSignConverter);
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.xaml b/src/cascadia/TerminalSettingsEditor/Profiles.xaml
index 68c592d5b..3ec1ab719 100644
--- a/src/cascadia/TerminalSettingsEditor/Profiles.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Profiles.xaml
@@ -35,6 +35,7 @@
+
@@ -626,7 +627,7 @@
Value="{x:Bind State.Profile.BackgroundImageOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
+ Text="{Binding ElementName=BIOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
@@ -664,7 +665,7 @@
Value="{x:Bind State.Profile.AcrylicOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
+ Text="{Binding ElementName=AcrylicOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
index a42629596..495191792 100644
--- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
@@ -215,6 +215,18 @@
Yellow
This is the header for a control that lets the user select the yellow color for text displayed on the screen.
+
+ Language
+ The header for a control allowing users to choose the app's language.
+
+
+ Sets an override for the app's preferred language.
+ A description explaining how this control changes the app's language.
+
+
+ Use system default
+ The app contains a control allowing users to choose the app's language. If this value is chosen, the language preference list of the system settings is used instead.
+
Always show tabs
Header for a control to toggle if the app should always show the tabs (similar to a website browser).
diff --git a/src/cascadia/TerminalSettingsEditor/pch.h b/src/cascadia/TerminalSettingsEditor/pch.h
index df45f6bd2..4ee6261bf 100644
--- a/src/cascadia/TerminalSettingsEditor/pch.h
+++ b/src/cascadia/TerminalSettingsEditor/pch.h
@@ -20,21 +20,14 @@
#undef GetCurrentTime
#endif
-#include
-
-#include
-
-#include
#include
#include
-#include
-#include
-
+#include
#include
#include
-#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.cpp b/src/cascadia/TerminalSettingsModel/ActionMap.cpp
index 433535dc5..a9ab094e7 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMap.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionMap.cpp
@@ -29,7 +29,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}
ActionMap::ActionMap() :
- _NestedCommands{ single_threaded_map() }
+ _NestedCommands{ single_threaded_map() },
+ _IterableCommands{ single_threaded_vector() }
{
}
@@ -87,7 +88,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
// populate _NameMapCache
std::unordered_map nameMap{};
- _PopulateNameMapWithNestedCommands(nameMap);
+ _PopulateNameMapWithSpecialCommands(nameMap);
_PopulateNameMapWithStandardCommands(nameMap);
_NameMapCache = single_threaded_map(std::move(nameMap));
@@ -96,18 +97,19 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}
// Method Description:
- // - Populates the provided nameMap with all of our nested commands and our parents nested commands
- // - Performs a top-down approach by going to the root first, then recursively adding the nested commands layer-by-layer
+ // - Populates the provided nameMap with all of our special commands and our parent's special commands.
+ // - Special commands include nested and iterable commands.
+ // - Performs a top-down approach by going to the root first, then recursively adding the nested commands layer-by-layer.
// Arguments:
// - nameMap: the nameMap we're populating. This maps the name (hstring) of a command to the command itself.
- void ActionMap::_PopulateNameMapWithNestedCommands(std::unordered_map& nameMap) const
+ void ActionMap::_PopulateNameMapWithSpecialCommands(std::unordered_map& nameMap) const
{
// Update NameMap with our parents.
// Starting with this means we're doing a top-down approach.
FAIL_FAST_IF(_parents.size() > 1);
for (const auto& parent : _parents)
{
- parent->_PopulateNameMapWithNestedCommands(nameMap);
+ parent->_PopulateNameMapWithSpecialCommands(nameMap);
}
// Add NestedCommands to NameMap _after_ we handle our parents.
@@ -125,6 +127,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
nameMap.erase(name);
}
}
+
+ // Add IterableCommands to NameMap
+ for (const auto& cmd : _IterableCommands)
+ {
+ nameMap.insert_or_assign(cmd.Name(), cmd);
+ }
}
// Method Description:
@@ -296,6 +304,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
actionMap->_NestedCommands.Insert(name, *(get_self(cmd)->Copy()));
}
+ // copy _IterableCommands
+ for (const auto& cmd : _IterableCommands)
+ {
+ actionMap->_IterableCommands.Append(*(get_self(cmd)->Copy()));
+ }
+
// repeat this for each of our parents
FAIL_FAST_IF(_parents.size() > 1);
for (const auto& parent : _parents)
@@ -336,6 +350,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return;
}
+ // Handle iterable commands
+ if (cmdImpl->IterateOn() != ExpandCommandType::None)
+ {
+ _IterableCommands.Append(cmd);
+ return;
+ }
+
// General Case:
// Add the new command to the KeyMap.
// This map directs you to an entry in the ActionMap.
diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.h b/src/cascadia/TerminalSettingsModel/ActionMap.h
index e33638cff..3435d120c 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMap.h
+++ b/src/cascadia/TerminalSettingsModel/ActionMap.h
@@ -81,7 +81,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
std::optional _GetActionByID(const InternalActionID actionID) const;
std::optional _GetActionByKeyChordInternal(Control::KeyChord const& keys) const;
- void _PopulateNameMapWithNestedCommands(std::unordered_map& nameMap) const;
+ void _PopulateNameMapWithSpecialCommands(std::unordered_map& nameMap) const;
void _PopulateNameMapWithStandardCommands(std::unordered_map& nameMap) const;
void _PopulateKeyBindingMapWithStandardCommands(std::unordered_map& keyBindingsMap, std::unordered_set& unboundKeys) const;
std::vector _GetCumulativeActions() const noexcept;
@@ -94,6 +94,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Windows::Foundation::Collections::IMap _GlobalHotkeysCache{ nullptr };
Windows::Foundation::Collections::IMap _KeyBindingMapCache{ nullptr };
Windows::Foundation::Collections::IMap _NestedCommands{ nullptr };
+ Windows::Foundation::Collections::IVector _IterableCommands{ nullptr };
std::unordered_map _KeyMap;
std::unordered_map _ActionMap;
diff --git a/src/cascadia/TerminalSettingsModel/ActionMapSerialization.cpp b/src/cascadia/TerminalSettingsModel/ActionMapSerialization.cpp
index 1358c7865..5956bf757 100644
--- a/src/cascadia/TerminalSettingsModel/ActionMapSerialization.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionMapSerialization.cpp
@@ -60,34 +60,40 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
Json::Value actionList{ Json::ValueType::arrayValue };
- // Serialize all standard Command objects in the current layer
- for (const auto& [_, cmd] : _ActionMap)
- {
- // Command serializes to an array of JSON objects.
- // This is because a Command may have multiple key chords associated with it.
- // The name and icon are only serialized in the first object.
- // Example:
- // { "name": "Custom Copy", "command": "copy", "keys": "ctrl+c" }
- // { "command": "copy", "keys": "ctrl+shift+c" }
- // { "command": "copy", "keys": "ctrl+ins" }
+ // Command serializes to an array of JSON objects.
+ // This is because a Command may have multiple key chords associated with it.
+ // The name and icon are only serialized in the first object.
+ // Example:
+ // { "name": "Custom Copy", "command": "copy", "keys": "ctrl+c" }
+ // { "command": "copy", "keys": "ctrl+shift+c" }
+ // { "command": "copy", "keys": "ctrl+ins" }
+ auto toJson = [&actionList](const Model::Command& cmd) {
const auto cmdImpl{ winrt::get_self(cmd) };
const auto& cmdJsonArray{ cmdImpl->ToJson() };
for (const auto& cmdJson : cmdJsonArray)
{
actionList.append(cmdJson);
}
+ };
+
+ // Serialize all standard Command objects in the current layer
+ for (const auto& [_, cmd] : _ActionMap)
+ {
+ toJson(cmd);
}
// Serialize all nested Command objects added in the current layer
for (const auto& [_, cmd] : _NestedCommands)
{
- const auto cmdImpl{ winrt::get_self(cmd) };
- const auto& cmdJsonArray{ cmdImpl->ToJson() };
- for (const auto& cmdJson : cmdJsonArray)
- {
- actionList.append(cmdJson);
- }
+ toJson(cmd);
}
+
+ // Serialize all iterable Command objects added in the current layer
+ for (const auto& cmd : _IterableCommands)
+ {
+ toJson(cmd);
+ }
+
return actionList;
}
diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h
index d0b08e9e2..cdcdc9613 100644
--- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h
+++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h
@@ -16,7 +16,6 @@ Author(s):
#pragma once
-#include "pch.h"
#include "AppearanceConfig.g.h"
#include "JsonUtils.h"
#include "../inc/cppwinrt_utils.h"
diff --git a/src/cascadia/TerminalSettingsModel/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp
index ee560b78d..dbdfd6e5c 100644
--- a/src/cascadia/TerminalSettingsModel/Command.cpp
+++ b/src/cascadia/TerminalSettingsModel/Command.cpp
@@ -394,10 +394,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
Json::Value cmdList{ Json::ValueType::arrayValue };
- if (_nestedCommand)
+ if (_nestedCommand || _IterateOn != ExpandCommandType::None)
{
- // handle nested command
- // For nested commands, we can trust _originalJson to be correct.
+ // handle special commands
+ // For these, we can trust _originalJson to be correct.
// In fact, we _need_ to use it here because we don't actually deserialize `iterateOn`
// until we expand the command.
cmdList.append(_originalJson);
diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp
index 39c370228..466031b05 100644
--- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp
+++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp
@@ -26,6 +26,7 @@ static constexpr std::string_view InitialColsKey{ "initialCols" };
static constexpr std::string_view InitialPositionKey{ "initialPosition" };
static constexpr std::string_view CenterOnLaunchKey{ "centerOnLaunch" };
static constexpr std::string_view ShowTitleInTitlebarKey{ "showTerminalTitleInTitlebar" };
+static constexpr std::string_view LanguageKey{ "language" };
static constexpr std::string_view ThemeKey{ "theme" };
static constexpr std::string_view TabWidthModeKey{ "tabWidthMode" };
static constexpr std::string_view ShowTabsInTitlebarKey{ "showTabsInTitlebar" };
@@ -101,6 +102,7 @@ winrt::com_ptr GlobalAppSettings::Copy() const
globals->_AlwaysShowTabs = _AlwaysShowTabs;
globals->_ShowTitleInTitlebar = _ShowTitleInTitlebar;
globals->_ConfirmCloseAllTabs = _ConfirmCloseAllTabs;
+ globals->_Language = _Language;
globals->_Theme = _Theme;
globals->_TabWidthMode = _TabWidthMode;
globals->_ShowTabsInTitlebar = _ShowTabsInTitlebar;
@@ -279,6 +281,8 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
+ JsonUtils::GetValueForKey(json, LanguageKey, _Language);
+
JsonUtils::GetValueForKey(json, ThemeKey, _Theme);
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
@@ -393,6 +397,7 @@ Json::Value GlobalAppSettings::ToJson() const
JsonUtils::SetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::SetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::SetValueForKey(json, LaunchModeKey, _LaunchMode);
+ JsonUtils::SetValueForKey(json, LanguageKey, _Language);
JsonUtils::SetValueForKey(json, ThemeKey, _Theme);
JsonUtils::SetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::SetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h
index f93bcd0e3..e11807b2a 100644
--- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h
+++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.h
@@ -65,6 +65,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowTabs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ShowTitleInTitlebar, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ConfirmCloseAllTabs, true);
+ INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, Language);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ShowTabsInTitlebar, true);
diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
index 9f3c8c745..fba59e1a4 100644
--- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
+++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl
@@ -43,6 +43,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_SETTING(Boolean, AlwaysShowTabs);
INHERITABLE_SETTING(Boolean, ShowTitleInTitlebar);
INHERITABLE_SETTING(Boolean, ConfirmCloseAllTabs);
+ INHERITABLE_SETTING(String, Language);
INHERITABLE_SETTING(Windows.UI.Xaml.ElementTheme, Theme);
INHERITABLE_SETTING(Microsoft.UI.Xaml.Controls.TabViewWidthMode, TabWidthMode);
INHERITABLE_SETTING(Boolean, ShowTabsInTitlebar);
diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp
index 00fe42c04..753166bf1 100644
--- a/src/cascadia/WindowsTerminal/AppHost.cpp
+++ b/src/cascadia/WindowsTerminal/AppHost.cpp
@@ -594,6 +594,7 @@ void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable send
summonArgs.MoveToCurrentDesktop(false);
summonArgs.DropdownDuration(0);
summonArgs.ToMonitor(Remoting::MonitorBehavior::InPlace);
+ summonArgs.ToggleVisibility(false); // Do not toggle, just make visible.
// Summon the window whenever we dispatch a commandline to it. This will
// make it obvious when a new tab/pane is created in a window.
_HandleSummon(sender, summonArgs);
@@ -935,5 +936,6 @@ void AppHost::_SummonWindowRequested(const winrt::Windows::Foundation::IInspecta
summonArgs.MoveToCurrentDesktop(false);
summonArgs.DropdownDuration(0);
summonArgs.ToMonitor(Remoting::MonitorBehavior::InPlace);
+ summonArgs.ToggleVisibility(false); // Do not toggle, just make visible.
_HandleSummon(sender, summonArgs);
}
diff --git a/src/common.build.post.props b/src/common.build.post.props
index 87416a898..e5bc2f5f3 100644
--- a/src/common.build.post.props
+++ b/src/common.build.post.props
@@ -64,4 +64,21 @@
+
+
+
+ OCCallFeatureFlagGenerator;
+ $(BuildDependsOn)
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)\bin\$(Configuration)\inc\TilFeatureStaging.h;%(ForcedIncludeFiles)
+
+
diff --git a/src/features.xml b/src/features.xml
new file mode 100644
index 000000000..7ad1db40c
--- /dev/null
+++ b/src/features.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ Feature_ReceiveIncomingHandoff
+ OpenConsole should be able to receive incoming connections
+ AlwaysEnabled
+
+ WindowsInbox
+
+
+
+
+ Feature_AttemptHandoff
+ conhost should try to hand connections over to OpenConsole
+ AlwaysDisabled
+
+ WindowsInbox
+
+
+
+
+ Feature_ConhostDxEngine
+ Controls whether conhost supports the DX engine and the UseDx registry key
+ AlwaysEnabled
+
+ WindowsInbox
+
+
+
+ Feature_DxEngineShaderSupport
+ Controls whether the DX engine is built with shader support.
+ AlwaysEnabled
+
+ WindowsInbox
+
+
+
+
+ Feature_UseNumpadEventsForClipboardInput
+ Controls whether the clipboard converter (and ConPTY InputStateMachine) uses Numpad events instead of UChar
+ AlwaysDisabled
+
+
+ WindowsInbox
+
+
+
diff --git a/src/host/exe/exemain.cpp b/src/host/exe/exemain.cpp
index d7ff119ff..a85c8a313 100644
--- a/src/host/exe/exemain.cpp
+++ b/src/host/exe/exemain.cpp
@@ -9,7 +9,7 @@
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../inc/conint.h"
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
#include "CConsoleHandoff.h"
#endif
@@ -247,7 +247,7 @@ int CALLBACK wWinMain(
// messages going forward.
// 7. The out-of-box `OpenConsole.exe` can then attempt to lookup and invoke a `CTerminalHandoff` to ask a registered
// Terminal to become the UI. This OpenConsole.exe will put itself in PTY mode and let the Terminal handle user interaction.
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
auto& module = OutOfProcModuleWithRegistrationFlag::Create(&_releaseNotifier);
#endif
@@ -264,7 +264,7 @@ int CALLBACK wWinMain(
if (SUCCEEDED(hr))
{
// Only try to register as a handoff target if we are NOT a part of Windows.
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
bool defAppEnabled = false;
if (args.ShouldRunAsComServer() && SUCCEEDED(Microsoft::Console::Internal::DefaultApp::CheckDefaultAppPolicy(defAppEnabled)) && defAppEnabled)
{
diff --git a/src/host/readDataCooked.cpp b/src/host/readDataCooked.cpp
index c723dcae1..458f351b3 100644
--- a/src/host/readDataCooked.cpp
+++ b/src/host/readDataCooked.cpp
@@ -1029,7 +1029,7 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline
LOG_IF_FAILED(_commandHistory->Add({ _backupLimit, StringLength / sizeof(wchar_t) },
WI_IsFlagSet(gci.Flags, CONSOLE_HISTORY_NODUP)));
}
-
+
Tracing::s_TraceCookedRead(_backupLimit);
// check for alias
diff --git a/src/host/srvinit.cpp b/src/host/srvinit.cpp
index c5283dca4..bebec95b2 100644
--- a/src/host/srvinit.cpp
+++ b/src/host/srvinit.cpp
@@ -27,9 +27,9 @@
#include "../inc/conint.h"
#include "../propslib/DelegationConfig.hpp"
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
#include "ITerminalHandoff.h"
-#endif // __INSIDE_WINDOWS
+#endif // TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
#pragma hdrstop
@@ -367,9 +367,9 @@ HRESULT ConsoleCreateIoThread(_In_ HANDLE Server,
[[maybe_unused]] PCONSOLE_API_MSG connectMessage)
try
{
-#ifdef __INSIDE_WINDOWS
+#if !TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
-#else // !__INSIDE_WINDOWS
+#else // TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
auto& g = ServiceLocator::LocateGlobals();
g.handoffTarget = true;
@@ -444,7 +444,7 @@ try
RETURN_IF_FAILED(consoleArgs.ParseCommandline());
return ConsoleCreateIoThread(Server, &consoleArgs, driverInputEvent, connectMessage);
-#endif // __INSIDE_WINDOWS
+#endif // TIL_FEATURE_RECEIVEINCOMINGHANDOFF_ENABLED
}
CATCH_RETURN()
diff --git a/src/host/ut_host/ClipboardTests.cpp b/src/host/ut_host/ClipboardTests.cpp
index 206559244..fb389757e 100644
--- a/src/host/ut_host/ClipboardTests.cpp
+++ b/src/host/ut_host/ClipboardTests.cpp
@@ -308,26 +308,29 @@ class ClipboardTests
wstr.size());
std::deque expectedEvents;
-#ifdef __INSIDE_WINDOWS
- // Inside Windows, where numpad events are enabled, this generated numpad events.
- // should be converted to:
- // 1. left alt keydown
- // 2. 1st numpad keydown
- // 3. 1st numpad keyup
- // 4. 2nd numpad keydown
- // 5. 2nd numpad keyup
- // 6. left alt keyup
- expectedEvents.push_back({ TRUE, 1, VK_MENU, altScanCode, L'\0', LEFT_ALT_PRESSED });
- expectedEvents.push_back({ TRUE, 1, 0x66, 0x4D, L'\0', LEFT_ALT_PRESSED });
- expectedEvents.push_back({ FALSE, 1, 0x66, 0x4D, L'\0', LEFT_ALT_PRESSED });
- expectedEvents.push_back({ TRUE, 1, 0x63, 0x51, L'\0', LEFT_ALT_PRESSED });
- expectedEvents.push_back({ FALSE, 1, 0x63, 0x51, L'\0', LEFT_ALT_PRESSED });
- expectedEvents.push_back({ FALSE, 1, VK_MENU, altScanCode, wstr[0], 0 });
-#else
- // Outside Windows, without numpad events, we just emit the key with a nonzero UnicodeChar
- expectedEvents.push_back({ TRUE, 1, 0, 0, wstr[0], 0 });
- expectedEvents.push_back({ FALSE, 1, 0, 0, wstr[0], 0 });
-#endif
+ if constexpr (Feature_UseNumpadEventsForClipboardInput::IsEnabled())
+ {
+ // Inside Windows, where numpad events are enabled, this generated numpad events.
+ // should be converted to:
+ // 1. left alt keydown
+ // 2. 1st numpad keydown
+ // 3. 1st numpad keyup
+ // 4. 2nd numpad keydown
+ // 5. 2nd numpad keyup
+ // 6. left alt keyup
+ expectedEvents.push_back({ TRUE, 1, VK_MENU, altScanCode, L'\0', LEFT_ALT_PRESSED });
+ expectedEvents.push_back({ TRUE, 1, 0x66, 0x4D, L'\0', LEFT_ALT_PRESSED });
+ expectedEvents.push_back({ FALSE, 1, 0x66, 0x4D, L'\0', LEFT_ALT_PRESSED });
+ expectedEvents.push_back({ TRUE, 1, 0x63, 0x51, L'\0', LEFT_ALT_PRESSED });
+ expectedEvents.push_back({ FALSE, 1, 0x63, 0x51, L'\0', LEFT_ALT_PRESSED });
+ expectedEvents.push_back({ FALSE, 1, VK_MENU, altScanCode, wstr[0], 0 });
+ }
+ else
+ {
+ // Outside Windows, without numpad events, we just emit the key with a nonzero UnicodeChar
+ expectedEvents.push_back({ TRUE, 1, 0, 0, wstr[0], 0 });
+ expectedEvents.push_back({ FALSE, 1, 0, 0, wstr[0], 0 });
+ }
VERIFY_ARE_EQUAL(expectedEvents.size(), events.size());
diff --git a/src/host/ut_host/VtIoTests.cpp b/src/host/ut_host/VtIoTests.cpp
index 6497cb6bc..f180d03e0 100644
--- a/src/host/ut_host/VtIoTests.cpp
+++ b/src/host/ut_host/VtIoTests.cpp
@@ -12,7 +12,7 @@
#include "../Settings.hpp"
#include "../VtIo.hpp"
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
#include "../../renderer/dx/DxRenderer.hpp"
#endif
@@ -38,7 +38,7 @@ class Microsoft::Console::VirtualTerminal::VtIoTests
TEST_METHOD(RendererDtorAndThread);
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
TEST_METHOD(RendererDtorAndThreadAndDx);
#endif
@@ -433,7 +433,7 @@ void VtIoTests::RendererDtorAndThread()
}
}
-#ifndef __INSIDE_WINDOWS
+#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
void VtIoTests::RendererDtorAndThreadAndDx()
{
Log::Comment(NoThrowString().Format(
diff --git a/src/inc/LibraryIncludes.h b/src/inc/LibraryIncludes.h
index 75bc23816..996f68d24 100644
--- a/src/inc/LibraryIncludes.h
+++ b/src/inc/LibraryIncludes.h
@@ -20,34 +20,35 @@
#include
#include
+#include
#include
+#include